AF_UNIX IPC sockets client side support (#84)
AF_UNIX kind of sockets are now supported. socket() and connect() calls are implemented. Windows specific logic in authfd.c is now removed. https://github.com/PowerShell/Win32-OpenSSH/issues/532 is created to keep track of ssh-agent end point authentication
This commit is contained in:
parent
71dd8145f3
commit
0ed1ef55f7
49
authfd.c
49
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;
|
||||
|
|
2
authfd.h
2
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 */
|
||||
|
|
|
@ -1080,7 +1080,7 @@
|
|||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue