PowerShell / Win32-OpenSSH

Win32 port of OpenSSH
7.43k stars 761 forks source link

Error creating/writing public key file on network drive "Bad file descriptor" -- tested on 9.5.0.0 and 9.8.1.0 #2298

Open Saxomania opened 5 days ago

Saxomania commented 5 days ago

Prerequisites

Steps to reproduce

Windows: creating pub/priv key file works on default folder (if you dont enter any path) and for example on D drive (just a local volume) will work but will not work on a mapped network share.

Write rights are there so this should not be problem otherwise it couldnt write into my userprofile folder as well

Expected behavior

ssh-keygen -t ed25519 -C "Test"
Generating public/private ed25519 key pair.
Enter file in which to save the key (C:\Users\username/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\username/.ssh/id_ed25519
Your public key has been saved in C:\Users\username/.ssh/id_ed25519.pub

Actual behavior

ssh-keygen -t ed25519 -C "Test"
Generating public/private ed25519 key pair.
Enter file in which to save the key (C:\Users\username/.ssh/id_ed25519): Q:\documents\key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in q:\documents\key
Unable to save public key to Q:\\documents\\key.pub: Bad file descriptor

Error details

Q is my mapped home drive on a network share
Documents is a folder inside it and its accessible 

an extract of "set" shows following variables:

HOMEDRIVE=Q:
HOMEPATH=\
HOMESHARE=\\server.domain.de\share\somefoldername\username

Environment data

PS Q:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.19041.5007
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.5007
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Version

9.8.1.0

Visuals

No response

mgkuhn commented 5 days ago

I can reproduce this.

Creates and leaves an empty key.pub file on the intended network folder.

I suspect the problem is that this fdopen() call fails if path is on a network drive:

        int fd, oerrno;
        FILE *f = NULL;
        int r = SSH_ERR_INTERNAL_ERROR;

        if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
                return SSH_ERR_SYSTEM_ERROR;
        if ((f = fdopen(fd, "w")) == NULL) {
                r = SSH_ERR_SYSTEM_ERROR;
                close(fd);
                goto fail;
        }

May be too much paranoid Unix-specific file-opening trickery for Windows libc to handle on a network drive?

mgkuhn commented 5 days ago

It looks like this has previously been noted elsewhere, judging from e.g. this comment in auth2-pubkeyfile.c:

#ifdef WINDOWS
        /* Windows POSIX adapter does not support fdopen() on open(file)*/
        if ((f = fopen(file, "r")) == NULL) {
[...]
#else  /* !WINDOWS */
        if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {

I guess the thing to do is to review all uses of fdopen() after open(), and then introduce a proper abstraction for what they actually try to achieve.

mgkuhn commented 5 days ago

I don't really understand why upstream isn't simply using

        if ((f = fopen(fd, "w")) == NULL)
                return SSH_ERR_SYSTEM_ERROR;

here.

It's not about the flags bits, because according to the Linux fopen() man page and the POSIX standard:

The file descriptor associated with the stream is opened as if by a call to open(2) with the following flags: | w │ O_WRONLY | O_CREAT | O_TRUNC |

I suspect this is merely done to mask out u+x,go+wx permissions.