Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can command history be accessed? #9

Closed
rasa opened this issue Jan 24, 2020 · 10 comments
Closed

Can command history be accessed? #9

rasa opened this issue Jan 24, 2020 · 10 comments

Comments

@rasa
Copy link

rasa commented Jan 24, 2020

After typing gsudo and getting a
C:\#
prompt, pressing the up arrow key or the F7 key doesn’t appear to do anything. I’ve tried working around it, by typing gsudo cmd /k but no luck. Any ideas?

@gerardog
Copy link
Owner

gerardog commented Jan 24, 2020

In the default attached mode the elevated gsudo instance happens to run in a different (hidden) console, then disconnects from it and attaches to the non-elevated one. We don't have access to the non-elevated history when doing that. So, at this point the answer is no: This is the expected current behavior.
Right now, you have full history only within the elevated session. If you elevate several times during the same elevated gsudo service instance running, you have a shared command history (elevated commands only).

Nonetheless there are APIs to read and write the command history of the console, so, theoretically (I should prototype to be sure) I could read the console history and stream it to the elevated instance.

But for the user perspective to be 'flawless' this should work in both directions: When the elevated session ends, the more recent history (the one in the elevated session) should be migrated back to the non-elevated console. (or shouldn't?)

Also, this wouldn't work for shells that handle the history by themselves, such as (I believe) PowerShell.

Also, from a security standpoint: Could this be an additional security risk? What does *nix sudo does? At a glance, the su root shell has it's independent /root/.bash_history.

I can prototype this feature and make it optional (gsudo config ShareHistory true), but it will take some time.

Thanks for the suggestion. I will let you know how the prototype goes.

@rasa
Copy link
Author

rasa commented Jan 24, 2020

I wouldn’t expect the non-elevated history to be available in the elevated session, and visa-versa, as this is how Linux works. root’s history is separate, and should be, for security reasons.

Right now, you have full history only within the elevated session. If you elevate several times during the same elevated gsudo service instance running, you have a shared command history (elevated commands only).

That wasn’t my experience. What I found is that after running a command in the elevated shell, up arrow and F7 didn’t show me that command I just typed. What am I doing wrong?

@gerardog
Copy link
Owner

gerardog commented Jan 24, 2020

Oh, sorry I misunderstood your question. You can't even access the history of the currently active session.

I can reproduce this while using gsudo via the Scoop Shim. This is an issue with the shim itself, not gsudo. See ScoopInstaller/Scoop#3634

If you run doskey /history you will see the commands that should be available when pressing Up/Down arrows or F7. The shim is somehow interferring with the arrow keys.

The right fix would be to fix the shim itself. I tried make the propsed fix move forward, with no luck. See ScoopInstaller/Shim/pull/3.

I can only propose a not very elegant workaround: Replace the shims with symbolic links.

del %userprofile%\scoop\shims\gsudo.exe
del %userprofile%\scoop\shims\sudo.exe
mklink %userprofile%\scoop\shims\gsudo.exe %userprofile%\scoop\apps\gsudo\current\gsudo.exe
mklink %userprofile%\scoop\shims\sudo.exe %userprofile%\scoop\apps\gsudo\current\gsudo.exe

In my experience this does not affect scoop ability to uninstall or update gsudo.

@gerardog
Copy link
Owner

This also happens with the new proposed scoop shim 71/scoop-better-shimexe.
However, both shims pass simple arrow tests using gsudo C:\git\gsudo\src\KeyPressTester\bin\Debug\KeyPressTester.exe.

And the issue doesn't happen when running under Cmder, or when using symbolic links instead of shims.
Further investigation required.

@rasa
Copy link
Author

rasa commented Jan 25, 2020

Symlinks make a lot of sense. In fact, it would trivial to add a flag to a scoop manifest to use symlinks instead of shims.

@gerardog
Copy link
Owner

The issue with file Symlinks is that Windows requires elevation to create them.
Other option would be to add gsudo to the path folder.

@rasa
Copy link
Author

rasa commented Jan 25, 2020

The issue with file Symlinks is that Windows requires elevation to create them.

That’s true for Windows 7, not 10. See
https://www.wintellect.com/non-admin-users-can-now-create-symlinks-windows-10/
We could certainly try to symlink, and if it fails fallback to creating shims.

What is true, is they can only be created on certain file systems, such as NTFS. But since scoop already has this limitation, since it creates symlinks to current under the apps folder, that’s a non-issue.

@gerardog
Copy link
Owner

Great news! Thats a game changer! Scoop can use CreateSymbolicLink API without elevation or enabling Windows Developer Mode!

@gerardog
Copy link
Owner

Just tested it. Great disappointment.
Both mklink and CreateSymbolicLink Api requires Windows Developer Mode enabled, or elevation.
To enable developer mode you need elevation again.

This is what I used. But according to PowerShell/PowerShell#7968 (that got closed, not merged) an if windows verions <= should be added to conditionally set the values of $Flag.

# based on https://learn-powershell.net/2013/07/16/creating-a-symbolic-link-using-powershell/
Function New-SymLink {
    <#
        .SYNOPSIS
            Creates a Symbolic link to a file or directory without requiring admin rights.

        .DESCRIPTION
            Creates a Symbolic link to a file or directory as an alternative to mklink.exe and New-Item.

        .PARAMETER Target
            Name of the File or Directory that the new symbolic link will reference.

        .PARAMETER SymName
            Name of the symbolic link to create. Can be a full path/unc or just the name.
            If only a name is given, the symbolic link will be created on the current directory that the
            function is being run on.

        .PARAMETER File
            Create a file symbolic link

        .PARAMETER Directory
            Create a directory symbolic link

        .NOTES
            Based on original: New-SymLink by Boe Prox
            
        .EXAMPLE
            New-SymLink -Target "C:\users\admin\downloads" -SymName "C:\users\admin\desktop\downloads" -Directory

            SymLink                          Target                   Type
            -------                          ------                   ----
            C:\Users\admin\Desktop\Downloads C:\Users\admin\Downloads Directory

            Description
            -----------
            Creates a symbolic link to downloads folder that resides on C:\users\admin\desktop.

        .EXAMPLE
            New-SymLink -Target "C:\users\admin\downloads\document.txt" -SymName "SomeDocument" -File

            SymLink                             Target                                Type
            -------                             ------                                ----
            C:\users\admin\desktop\SomeDocument C:\users\admin\downloads\document.txt File

            Description
            -----------
            Creates a symbolic link to document.txt file under the current directory called SomeDocument.
    #>
    [cmdletbinding(
        DefaultParameterSetName = 'Directory',
        SupportsShouldProcess=$True
    )]
    Param (
        [parameter(Position=0,ParameterSetName='Directory',ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,Mandatory=$True)]
        [parameter(Position=0,ParameterSetName='File',ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,Mandatory=$True)]
        [ValidateScript({
            If (Test-Path $_) {$True} Else {
                Throw "`'$_`' doesn't exist!"
            }
        })]
        [string]$Target,
        [parameter(Position=1,ParameterSetName='Directory')]
        [parameter(Position=1,ParameterSetName='File')]
        [string]$SymName,
        [parameter(Position=2,ParameterSetName='File')]
        [switch]$File,
        [parameter(Position=2,ParameterSetName='Directory')]
        [switch]$Directory
    )
    Begin {
        Try {
            $null = [mklink.symlink]
        } Catch {
            Add-Type @"
            using System;
            using System.Runtime.InteropServices;
 
            namespace mklink
            {
                public class symlink
                {
                    [DllImport("kernel32.dll")]
                    public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
                }
            }
"@
        }
    }
    Process {
        #Assume target Symlink is on current directory if not giving full path or UNC
        If ($SymName -notmatch "^(?:[a-z]:\\)|(?:\\\\\w+\\[a-z]\$)") {
            $SymName = "{0}\{1}" -f $pwd,$SymName
        }
        $Flag = @{
            File = 2
            Directory = 3
        }
        If ($PScmdlet.ShouldProcess($Target,'Create Symbolic Link')) {
            Try {
                $return = [mklink.symlink]::CreateSymbolicLink($SymName,$Target,$Flag[$PScmdlet.ParameterSetName])
                If ($return) {
                    $object = New-Object PSObject -Property @{
                        SymLink = $SymName
                        Target = $Target
                        Type = $PScmdlet.ParameterSetName
                    }
                    $object.pstypenames.insert(0,'System.File.SymbolicLink')
                    $object
                } Else {
                    Throw "Unable to create symbolic link!"
                }
            } Catch {
                Write-warning ("{0}: {1}" -f $Target,$_.Exception.Message)
            }
        }
    }
}

@gerardog
Copy link
Owner

gerardog commented Feb 4, 2020

@rasa.

I don't think Scoop should enable Windows Development mode. It breaks the whole concept of "Scoop doesn't requires elevation". Also, I don't like the idea that the installation method be different depending on that mode enabled or not. Would be hard to support.

So, the alternatives that I see are:

  • Change gsudo Scoop manifest: No more shims. Add scoop/apps/gsudo/current to PATH. This would also fix other issues with the Shim, specially CTRL-C.
  • Hardcode a fix, something like gsudo FixShim that should be run after scoop install. Or run automatically on first time use... Mmmm, it smells ...
  • Try to fix the shim? I know the shim is part of the problem but I'm no longer sure it's the culprit. It works on Cmder even with shim, or with Powershell.
  • Close this issue with the list of possible workarounds?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants