Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion contrib/win32/win32compat/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ fileio_connect(struct w32_io* pio, char* name)
break;

debug4("waiting for agent connection, retrying after 1 sec");
if ((ret = wait_for_any_event(NULL, 0, 1000) != 0) != 0)
ret = wait_for_any_event(NULL, 0, 1000);
if (ret != 0)
goto cleanup;
} while(1);

Expand Down
52 changes: 37 additions & 15 deletions contrib/win32/win32compat/socketio.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ socketio_acceptEx(struct w32_io* pio)
{
struct acceptEx_context *context;
struct sockaddr_storage addr; int addrlen = sizeof addr;

debug5("acceptEx - io:%p", pio);
context = (struct acceptEx_context *)pio->internal.context;
ResetEvent(pio->read_overlapped.hEvent);

if (getsockname(pio->sock, (struct sockaddr*)&addr, &addrlen) == SOCKET_ERROR) {
errno = errno_from_WSALastError();
debug("acceptEx - getsockname() ERROR:%d, io:%p", WSAGetLastError(), pio);
return -1;
return -1;
}

/* create accepting socket */
Expand Down Expand Up @@ -165,6 +165,8 @@ CALLBACK WSARecvCompletionRoutine(IN DWORD dwError,
pio->read_details.remaining = cbTransferred;
pio->read_details.completed = 0;
pio->read_details.pending = FALSE;
if (pio->read_overlapped.hEvent)
SetEvent(pio->read_overlapped.hEvent);
}

/* initiates async receive operation*/
Expand Down Expand Up @@ -198,6 +200,16 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed, int len)
if (len)
wsabuf.len = min((ULONG)len, wsabuf.len);

if (pio->read_overlapped.hEvent == NULL) {
pio->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (pio->read_overlapped.hEvent == NULL) {
errno = ENOMEM;
debug3("WSARecv - CreateEvent() ERROR:%d, io:%p", errno, pio);
return -1;
}
}
ResetEvent(pio->read_overlapped.hEvent);

ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, &WSARecvCompletionRoutine);
if (ret == 0) {
pio->read_details.pending = TRUE;
Expand Down Expand Up @@ -251,7 +263,7 @@ socketio_socket(int domain, int type, int protocol)
debug3("%s - ERROR:%d", __FUNCTION__, WSAGetLastError()); \
} \
return ret; \
} while (0)
} while (0)

/* implements setsockopt() */
int
Expand Down Expand Up @@ -363,7 +375,7 @@ int
socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags)
{
BOOL completed = FALSE;
errno_t r = 0;
errno_t r;
debug5("recv - io:%p state:%d", pio, pio->internal.state);

if ((buf == NULL) || (len == 0)) {
Expand Down Expand Up @@ -393,7 +405,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags)
debug4("recv - io is already pending, io:%p", pio);
return -1;
}
}
}

/* if we have some buffer copy it and return #bytes copied */
if (pio->read_details.remaining) {
Expand Down Expand Up @@ -511,14 +523,20 @@ CALLBACK WSASendCompletionRoutine(IN DWORD dwError,
pio->write_details.pending = FALSE;
}

static BOOL
socketio_write_is_pending(struct w32_io* pio)
{
return pio->write_details.pending;
}

/* implementation of send() */
int
socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags)
{
int ret = 0;
WSABUF wsabuf;
errno_t r = 0;

debug5("send - io:%p state:%d", pio, pio->internal.state);

if ((buf == NULL) || (len == 0)) {
Expand Down Expand Up @@ -550,7 +568,11 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags)

if (pio->write_details.error) {
errno = errno_from_WSAError(pio->write_details.error);
debug3("ERROR:%d, io:%p", pio->write_details.error, pio);
/*
* Logging can write through the Win32 fd table. A socket
* write-error path must return before logging so the log writer
* cannot re-enter socketio_send on the failed writer.
*/
return -1;
}

Expand Down Expand Up @@ -600,10 +622,10 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags)
if (w32_io_is_blocking(pio)) {
/* wait until io is done */
debug5("send - waiting as socket is in blocking mode, io:%p", pio);
while (pio->write_details.pending)
while (socketio_write_is_pending(pio))
if (wait_for_any_event(NULL, 0, INFINITE) == -1) {
/* if interrupted but send has completed, we are good*/
if ((errno != EINTR) || (pio->write_details.pending))
if ((errno != EINTR) || socketio_write_is_pending(pio))
return -1;
errno = 0;
}
Expand Down Expand Up @@ -653,6 +675,10 @@ socketio_close(struct w32_io* pio)
if (pio->write_overlapped.hEvent)
CloseHandle(pio->write_overlapped.hEvent);
} else {
if (pio->read_overlapped.hEvent)
CloseHandle(pio->read_overlapped.hEvent);
if (pio->write_overlapped.hEvent)
CloseHandle(pio->write_overlapped.hEvent);
if (pio->read_details.buf)
free(pio->read_details.buf);

Expand All @@ -669,7 +695,6 @@ struct w32_io*
socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen)
{
struct w32_io *accept_io = NULL;
int iResult = 0;
struct acceptEx_context* context;
struct sockaddr *local_address, *remote_address;
int local_address_len, remote_address_len;
Expand Down Expand Up @@ -786,7 +811,7 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen)

if (SOCKET_ERROR == bind(pio->sock, tmp_addr, (int)tmp_addr_len)) {
errno = errno_from_WSALastError();
/*
/*
* When use bind_address or bind_interface, this bind will return WSAEINVAL. But it doesn't matter.
* https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind
*/
Expand Down Expand Up @@ -975,8 +1000,6 @@ socketio_on_select(struct w32_io* pio, BOOL rd)
int
w32_gethostname(char *name_utf8, size_t len)
{
char* tmp_name_utf8 = NULL;

if (IsWindows8OrGreater()) {
/* TODO - GetHostNameW not present in Win7, do GetProcAddr on Win8+*/
/*
Expand All @@ -1003,9 +1026,8 @@ w32_gethostname(char *name_utf8, size_t len)
void
w32_freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *cur;
while (ai) {
cur = ai;
struct addrinfo *cur = ai;
ai = ai->ai_next;
if (cur->ai_addr)
free(cur->ai_addr);
Expand Down
30 changes: 24 additions & 6 deletions contrib/win32/win32compat/w32-doexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
#define SUBSYSTEM_INT_SFTP_ERROR 3
#endif

#ifndef SSHD_ENABLE_JOB_OBJECTS
#define SSHD_ENABLE_JOB_OBJECTS 1
#endif

/* import */
extern ServerOptions options;
extern struct sshauthopt *auth_opts;
Expand All @@ -78,6 +82,10 @@ do_setup_env_proxy(struct ssh *, Session *, const char *);
goto cleanup; \
} while(0)

#define SSHD_CHILD_PROCESS_ACCESS \
(PROCESS_TERMINATE | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA | \
PROCESS_QUERY_INFORMATION | SYNCHRONIZE)


static char*
get_registry_operation_error_message(const LONG error_code)
Expand Down Expand Up @@ -161,8 +169,8 @@ setup_session_user_vars(wchar_t* pw_dir_w)
wchar_t* user_path = NULL;
wchar_t* hklm_path = get_registry_key_value(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", L"PATH", &hklm_path_sz);
wchar_t* hkcu_path = get_registry_key_value(HKEY_CURRENT_USER, L"Environment", L"PATH", &hkcu_path_sz);
DWORD user_path_sz = hklm_path_sz + hkcu_path_sz;
if (hklm_path && hkcu_path) {
DWORD user_path_sz = hklm_path_sz + hkcu_path_sz;
user_path = malloc(user_path_sz);
if (user_path) {
memcpy_s(user_path, user_path_sz, hklm_path, hklm_path_sz);
Expand Down Expand Up @@ -194,8 +202,8 @@ setup_session_env(struct ssh *ssh, Session* s)
_snprintf(buf, ARRAYSIZE(buf), "%s@%s", s->pw->pw_name, getenv("COMPUTERNAME"));
UTF8_TO_UTF16_WITH_CLEANUP(tmp, buf);
/* escape $ characters as $$ to distinguish from special prompt characters */
for (size_t i = 0, j = 0; i < wcslen(tmp) && j < ARRAYSIZE(wbuf) - 1; i++) {
wbuf[j] = tmp[i];
for (size_t tmp_index = 0, j = 0; tmp_index < wcslen(tmp) && j < ARRAYSIZE(wbuf) - 1; tmp_index++) {
wbuf[j] = tmp[tmp_index];
if (wbuf[j++] == L'$')
wbuf[j++] = L'$';
}
Expand Down Expand Up @@ -367,7 +375,12 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
exec_command = build_exec_command(command);
debug3("exec_command: %s", exec_command);

if (shell_type == SH_PS || shell_type == SH_BASH ||
if (s->is_subsystem && exec_command &&
strstr(exec_command, "sftp-server.exe")) {
spawn_argv[0] = exec_command;
debug3("spawning sftp subsystem directly");
}
else if (shell_type == SH_PS || shell_type == SH_BASH ||
shell_type == SH_CYGWIN || (shell_type == SH_OTHER) && arg_escape) {
spawn_argv[0] = shell;

Expand Down Expand Up @@ -439,12 +452,13 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
memset(&job_info, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK;

if ((process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) == NULL) {
if ((process_handle = OpenProcess(SSHD_CHILD_PROCESS_ACCESS, FALSE, pid)) == NULL) {
errno = EOTHER;
error("cannot get process handle: %d", GetLastError());
goto cleanup;
}

#if SSHD_ENABLE_JOB_OBJECTS
/*
* assign job object to control processes spawned
* 1. create job object
Expand All @@ -461,6 +475,10 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
CloseHandle(process_handle);
goto cleanup;
}
#else
CloseHandle(process_handle);
process_handle = NULL;
#endif
s->pid = pid;

/* Close the child sides of the socket pairs. */
Expand Down Expand Up @@ -510,4 +528,4 @@ do_exec_no_pty(struct ssh *ssh, Session *s, const char *command) {
int
do_exec_pty(struct ssh *ssh, Session *s, const char *command) {
return do_exec_windows(ssh, s, command, 1);
}
}
Loading