diff --git a/authfd.c b/authfd.c index 63614c941..2fd857d19 100644 --- a/authfd.c +++ b/authfd.c @@ -94,54 +94,6 @@ ssh_get_authentication_socket(int *fdp) if (fdp != NULL) *fdp = -1; -#ifdef WINDOWS - /* Auth socket in Windows is a static-named pipe listener in ssh-agent */ - { - HKEY agent_root = 0; - DWORD agent_pid = 0, tmp_size = 4, pipe_server_pid = 0xff; - DWORD connection_attempts = 0; - HANDLE h; - RegOpenKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_REG_ROOT, - 0, KEY_QUERY_VALUE, &agent_root); - if (agent_root) { - RegQueryValueEx(agent_root, "ProcessId", 0, - NULL, (LPBYTE)&agent_pid, &tmp_size); - RegCloseKey(agent_root); - } - - do { - h = CreateFileW(SSH_AGENT_PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (h != INVALID_HANDLE_VALUE || GetLastError() != ERROR_PIPE_BUSY || - ++connection_attempts > 10) - break; - Sleep(100); - } while(1); - - if (h == INVALID_HANDLE_VALUE) { - debug("ssh_get_authentication_socket - CreateFileW failed error %d", - GetLastError()); - return SSH_ERR_AGENT_NOT_PRESENT; - } - - /* - * ensure that connected server pid matches published pid. - * this provides service side auth and prevents mitm - */ - if (!GetNamedPipeServerProcessId(h, &pipe_server_pid) || - (agent_pid != pipe_server_pid)) { - debug("agent pid mismatch"); - CloseHandle(h); - return SSH_ERR_AGENT_COMMUNICATION; - } - - /* alloc fd for pipe handle */ - if ((sock = w32_allocate_fd_for_handle(h, FALSE)) < 0) { - CloseHandle(h); - return SSH_ERR_SYSTEM_ERROR; - } - } -#else /* !WINDOWS */ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); if (!authsocket) return SSH_ERR_AGENT_NOT_PRESENT; @@ -161,7 +113,6 @@ ssh_get_authentication_socket(int *fdp) errno = oerrno; return SSH_ERR_SYSTEM_ERROR; } -#endif /* !WINDOWS */ if (fdp != NULL) *fdp = sock; diff --git a/authfd.h b/authfd.h index 468147915..38cffaf0e 100644 --- a/authfd.h +++ b/authfd.h @@ -96,7 +96,5 @@ int ssh_agent_sign(int sock, struct sshkey *key, #define SSH_AGENT_AUTHENTICATE 200 #define PUBKEY_AUTH_REQUEST "pubkey" #define PASSWD_AUTH_REQUEST "password" -#define SSH_AGENT_REG_ROOT L"SOFTWARE\\SSH\\Agent" -#define SSH_AGENT_PIPE_NAME L"\\\\.\\pipe\\ssh-agent" #endif /* AUTHFD_H */ diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index b4d487838..28592f719 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1080,7 +1080,7 @@ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UN_H */ +#define HAVE_SYS_UN_H 1 /* Define to 1 if you have the `tcgetpgrp' function. */ /* #undef HAVE_TCGETPGRP */ @@ -1641,7 +1641,6 @@ #undef HAVE_SYS_CDEFS_H #undef HAVE_SYS_SYSMACROS_H #undef HAVE_SYS_MMAN_H -#undef HAVE_SYS_UN_H #define _STRUCT_WINSIZE 1 #define HAVE_TCGETPGRP 1 diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index 06745d16c..5fb40c822 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -37,6 +37,7 @@ #include "w32fd.h" #include "inc\utf.h" +#include "inc\fcntl.h" #include "misc_internal.h" /* internal read buffer size */ @@ -74,6 +75,76 @@ errno_from_Win32Error(int win32_error) } } +struct w32_io* +fileio_afunix_socket() +{ + struct w32_io* ret = (struct w32_io*)malloc(sizeof(struct w32_io)); + if (ret == NULL) { + errno = ENOMEM; + return NULL; + } + + memset(ret, 0, sizeof(struct w32_io)); + return ret; +} + +int +fileio_connect(struct w32_io* pio, char* name) +{ + wchar_t* name_w = NULL; + wchar_t pipe_name[PATH_MAX]; + HANDLE h = INVALID_HANDLE_VALUE; + int ret = 0; + + if (pio->handle != 0 && pio->handle != INVALID_HANDLE_VALUE) { + debug("fileio_connect called in unexpected state, pio = %p", pio); + errno = EOTHER; + ret = -1; + goto cleanup; + } + + if ((name_w = utf8_to_utf16(name)) == NULL) { + errno = ENOMEM; + return -1; + } + _snwprintf(pipe_name, PATH_MAX, L"\\\\.\\pipe\\%ls", name_w); + h = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + /* TODO - support nonblocking connect */ + /* wait until we have a server pipe instance to connect */ + while (h == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) { + debug2("waiting for agent connection, retrying after 1 sec"); + if ((ret = wait_for_any_event(NULL, 0, 1000) != 0) != 0) + goto cleanup; + } + + if (h == INVALID_HANDLE_VALUE) { + debug("unable to connect to pipe %ls, error: %d", name_w, GetLastError()); + errno = errno_from_Win32LastError(); + ret = -1; + goto cleanup; + } + + if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, + pio->fd_flags & FD_CLOEXEC ? 0 : HANDLE_FLAG_INHERIT) == FALSE) { + errno = errno_from_Win32LastError(); + debug("SetHandleInformation failed, error = %d, pio = %p", GetLastError(), pio); + ret = -1; + goto cleanup; + } + + pio->handle = h; + h = NULL; + +cleanup: + if (name_w) + free(name_w); + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + return ret; +} + /* used to name named pipes used to implement pipe() */ static int pipe_counter = 0; @@ -663,6 +734,12 @@ fileio_close(struct w32_io* pio) { debug2("fileclose - pio:%p", pio); + /* handle can be null on AF_UNIX sockets that are not yet connected */ + if (WINHANDLE(pio) == 0 || WINHANDLE(pio) == INVALID_HANDLE_VALUE) { + free(pio); + return 0; + } + CancelIo(WINHANDLE(pio)); /* let queued APCs (if any) drain */ SleepEx(0, TRUE); diff --git a/contrib/win32/win32compat/inc/sys/un.h b/contrib/win32/win32compat/inc/sys/un.h index fff9d7891..42f09b8ce 100644 --- a/contrib/win32/win32compat/inc/sys/un.h +++ b/contrib/win32/win32compat/inc/sys/un.h @@ -1,7 +1,7 @@ -#ifndef COMPAT_UN_H -#define COMPAT_UN_H 1 +#pragma once +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; -/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ - -#endif diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 3cefb5b57..52fcbb750 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -35,6 +35,7 @@ #include "inc\sys\types.h" #include "inc\unistd.h" #include "inc\fcntl.h" +#include "inc\sys\un.h" #include "w32fd.h" #include "signal_internal.h" @@ -206,14 +207,21 @@ w32_socket(int domain, int type, int protocol) errno = 0; if (min_index == -1) return -1; + + if (domain == AF_UNIX && type == SOCK_STREAM) { + pio = fileio_afunix_socket(); + if (pio == NULL) + return -1; + pio->type = NONSOCK_FD; + } else { + pio = socketio_socket(domain, type, protocol); + if (pio == NULL) + return -1; + pio->type = SOCK_FD; + } - pio = socketio_socket(domain, type, protocol); - if (pio == NULL) - return -1; - - pio->type = SOCK_FD; fd_table_set(pio, min_index); - debug("socket:%d, io:%p, fd:%d ", pio->sock, pio, min_index); + debug("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); return min_index; } @@ -290,6 +298,12 @@ int w32_connect(int fd, const struct sockaddr* name, int namelen) { CHECK_FD(fd); + + if (fd_table.w32_ios[fd]->type == NONSOCK_FD) { + struct sockaddr_un* addr = (struct sockaddr_un*)name; + return fileio_connect(fd_table.w32_ios[fd], addr->sun_path); + } + CHECK_SOCK_IO(fd_table.w32_ios[fd]); return socketio_connect(fd_table.w32_ios[fd], name, namelen); } @@ -298,6 +312,7 @@ int w32_recv(int fd, void *buf, size_t len, int flags) { CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); return socketio_recv(fd_table.w32_ios[fd], buf, len, flags); } @@ -503,10 +518,16 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags) shi_flags = (flags & FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT; if (SetHandleInformation(WINHANDLE(pio), HANDLE_FLAG_INHERIT, shi_flags) == FALSE) { - debug("fcntl - SetHandleInformation failed %d, io:%p", - GetLastError(), pio); - errno = EOTHER; - return -1; + /* + * Ignore if handle is not valid yet. It will not be valid for + * UF_UNIX sockets that are not connected yet + */ + if (GetLastError() != ERROR_INVALID_HANDLE) { + debug("fcntl - SetHandleInformation failed %d, io:%p", + GetLastError(), pio); + errno = EOTHER; + return -1; + } } pio->fd_flags = flags; diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h index 1aad34a7a..0387a00f4 100644 --- a/contrib/win32/win32compat/w32fd.h +++ b/contrib/win32/win32compat/w32fd.h @@ -127,6 +127,8 @@ BOOL fileio_is_io_available(struct w32_io* pio, BOOL rd); void fileio_on_select(struct w32_io* pio, BOOL rd); int fileio_close(struct w32_io* pio); int fileio_pipe(struct w32_io* pio[2]); +struct w32_io* fileio_afunix_socket(); +int fileio_connect(struct w32_io*, char*); struct w32_io* fileio_open(const char *pathname, int flags, int mode); int fileio_read(struct w32_io* pio, void *dst, unsigned int max); int fileio_write(struct w32_io* pio, const void *buf, unsigned int max); diff --git a/contrib/win32/win32compat/wmain_common.c b/contrib/win32/win32compat/wmain_common.c index 7addd95c6..a23ff647e 100644 --- a/contrib/win32/win32compat/wmain_common.c +++ b/contrib/win32/win32compat/wmain_common.c @@ -48,6 +48,9 @@ wmain(int argc, wchar_t **wargv) { argv[i] = utf16_to_utf8(wargv[i]); } + if (getenv("SSH_AUTH_SOCK") == NULL) + _putenv("SSH_AUTH_SOCK=ssh-agent"); + w32posix_initialize(); r = main(argc, argv); w32posix_done(); diff --git a/contrib/win32/win32compat/wmain_sshd.c b/contrib/win32/win32compat/wmain_sshd.c index 5e75d01b2..3f1bc583f 100644 --- a/contrib/win32/win32compat/wmain_sshd.c +++ b/contrib/win32/win32compat/wmain_sshd.c @@ -108,6 +108,9 @@ int sshd_main(int argc, wchar_t **wargv) { argv[i] = utf16_to_utf8(wargv[i]); } + if (getenv("SSH_AUTH_SOCK") == NULL) + _putenv("SSH_AUTH_SOCK=ssh-agent"); + w32posix_initialize(); if (getenv("SSHD_REMSOC")) is_child = 1;