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

cmd/age: use CONIN$ instead of /dev/tty on Windows #274

Closed
wants to merge 1 commit into from

Conversation

codesoap
Copy link
Contributor

@codesoap codesoap commented May 31, 2021

I'm intending to solve #128 with this pull request.

The solution for Windows was kindly provided to me by @alexbrainman at golang/go#46164 (comment).

I have to admit, though, that I do not fully understand what is going on, because I am unfamiliar with Windows and it's APIs. As far as I understood, using CONIN$ is also what is recommended by Microsoft:

The CreateFile function enables a process to get a handle to its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle to a console's input buffer, specify the CONIN$ value in a call to CreateFile. Specify the CONOUT$ value in a call to CreateFile to open a handle to a console's active screen buffer. CreateFile enables you to specify the read/write access of the handle that it returns.

@alexbrainman
Copy link

Given that this command is security sensitive, you should have real Windows developer, like @zx2c4, not me review this change.

Alex

@FiloSottile
Copy link
Owner

Awesome, thank you both, this is something that kept biting Windows users! It's kind of unfortunate cmd/age needs to know so much about open terminals. Maybe there's space in x/term for an OpenTerminal function.

If @zx2c4 has time to take a look that'd be great, but otherwise I am fairly comfortable with this, the failure mode is not particularly security-sensitive: we don't use this to store a secret, only to read one interactively, so if it doesn't work at most we'll fail to get terminal input. (I guess if permissions are wrong some other user on the system might be able to intercept the input?)

I am getting a decent Windows VM set up so I can test these things properly.

@zx2c4
Copy link

zx2c4 commented Jun 1, 2021

CONIN$ is fine and is probably what you want here indeed. What exactly is the security concern here? That it'd read from the wrong console or something like that?

if err != nil {
return nil, err
}
tty, err := windows.CreateFile(conin, windows.GENERIC_READ|windows.GENERIC_WRITE, windows.FILE_SHARE_READ, nil, windows.OPEN_EXISTING, 0, 0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need x/sys/windows. os.Open should work too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tried it in age, but in another program and it didn't work. See golang/go#46164 (comment) for more info.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codesoap os.OpenFile works for me (windows 10, go 1.12)

See https://play.golang.org/p/FTJwXE0o6AP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting, thanks. This may even be relevant for golang/go#46164. I'll play around with it a bit as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can now confirm that using os.OpenFile("CONIN$", os.O_RDWR, 0777) works and os.OpenFile("CONIN$", os.O_RDONLY, 0777) does not. Cool find! However, this seems quite odd to me, since CONIN$ is only supposed to read anyway. Is this to be considered a bug of Windows?!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's odd, SetConsoleMode says it only needs GENERIC_READ access. It would be nice to know which syscall in term.ReadPassword was throwing the access denied error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I use the "long way" of reading a password with x/term, we can see, that the error seems to originate from MakeRaw's implementation on Windows. So I guess you are correct and SetConsoleMode probably is the culprit. Here is a demo: https://play.golang.org/p/qRpuBKj2poq

@FiloSottile
Copy link
Owner

FiloSottile commented Jun 1, 2021 via email

@magical
Copy link

magical commented Jun 1, 2021 via email

@FiloSottile
Copy link
Owner

FiloSottile commented Jun 1, 2021 via email

@codesoap
Copy link
Contributor Author

codesoap commented Jun 1, 2021

Sounds good. I haven't tried OpenFile yet.

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

Successfully merging this pull request may close these issues.

None yet

5 participants