diff --git a/contrib/win32/win32compat/ssh-agent/agent-main.c b/contrib/win32/win32compat/ssh-agent/agent-main.c index 2b001cd00..92da1bf83 100644 --- a/contrib/win32/win32compat/ssh-agent/agent-main.c +++ b/contrib/win32/win32compat/ssh-agent/agent-main.c @@ -37,6 +37,9 @@ #pragma warning(push, 3) +/* Pattern-list of allowed PKCS#11/Security key paths */ +char* allowed_providers = NULL; + int remote_add_provider; int scm_start_service(DWORD, LPWSTR*); @@ -134,8 +137,25 @@ wmain(int argc, wchar_t **wargv) fatal("Unknown -O option; only allow-remote-pkcs11 is supported"); } } + else if (wcsncmp(wargv[i], L"-P", 2) == 0) { + if (allowed_providers != NULL) + fatal("-P option already specified"); + if ((i + 1) < argc) { + i++; + if ((allowed_providers = utf16_to_utf8(wargv[i])) == NULL) + fatal("Invalid argument for -P option"); + } + else { + fatal("Missing argument for -P option"); + } + } } } + + if (allowed_providers == NULL) { + agent_initialize_allow_list(); + } + if (!StartServiceCtrlDispatcherW(dispatch_table)) { if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index adac352c9..9f3400004 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -34,9 +34,11 @@ #include #include "..\misc_internal.h" #include +#include "xmalloc.h" #define BUFSIZE 5 * 1024 +extern char* allowed_providers; extern int remote_add_provider; char* sshagent_con_username; @@ -170,11 +172,11 @@ agent_listen_loop() GetModuleFileNameW(NULL, module_path, PATH_MAX); SetHandleInformation(con, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); if (remote_add_provider == 1) { - if (swprintf_s(path, PATH_MAX, L"%s %d %s", module_path, (int)(intptr_t)con, L"-Oallow-remote-pkcs11") == -1) + if (swprintf_s(path, PATH_MAX, L"%s %d %s -P \"%S\"", module_path, (int)(intptr_t)con, L"-Oallow-remote-pkcs11", allowed_providers) == -1) verbose("Failed to create child process %ls ERROR:%d", module_path, GetLastError()); } else { - if (swprintf_s(path, PATH_MAX, L"%s %d", module_path, (int)(intptr_t)con) == -1) + if (swprintf_s(path, PATH_MAX, L"%s %d -P \"%S\"", module_path, (int)(intptr_t)con, allowed_providers) == -1) verbose("Failed to create child process %ls ERROR:%d", module_path, GetLastError()); } if (CreateProcessW(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi) == FALSE) { @@ -408,3 +410,30 @@ agent_process_connection(HANDLE pipe) iocp_work(NULL); } +void +agent_initialize_allow_list() { + /* + * allowed paths for PKCS11 libraries, + * initialize to ProgramFiles and ProgramFiles(x86) by default + * upstream uses /usr/lib/* and /usr/local/lib/* + */ + size_t prog_files_len = 0, prog_files_x86_len = 0; + char* prog_files = NULL, * prog_files_x86 = NULL; + + _dupenv_s(&prog_files, &prog_files_len, "ProgramFiles"); + if (!prog_files) + fatal("couldn't find ProgramFiles environment variable"); + convertToForwardslash(prog_files); + + _dupenv_s(&prog_files_x86, &prog_files_x86_len, "ProgramFiles(x86)"); + if (!prog_files_x86) + fatal("couldn't find ProgramFiles environment variable"); + convertToForwardslash(prog_files_x86); + + size_t allowed_providers_len = 1 + prog_files_len + 4 + prog_files_x86_len + 3; + allowed_providers = xmalloc(allowed_providers_len); + sprintf_s(allowed_providers, allowed_providers_len, "/%s/*,/%s/*", prog_files, prog_files_x86); + + free(prog_files); + free(prog_files_x86); +} diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h index 5313d7e6e..3437d4656 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.h +++ b/contrib/win32/win32compat/ssh-agent/agent.h @@ -63,3 +63,4 @@ void agent_start(BOOL); void agent_process_connection(HANDLE); void agent_shutdown(); void agent_cleanup_connection(struct agent_connection*); +void agent_initialize_allow_list(); diff --git a/contrib/win32/win32compat/ssh-agent/keyagent-request.c b/contrib/win32/win32compat/ssh-agent/keyagent-request.c index 0304f589f..add0bc380 100644 --- a/contrib/win32/win32compat/ssh-agent/keyagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/keyagent-request.c @@ -32,6 +32,7 @@ #include "agent.h" #include "agent-request.h" #include "config.h" +#include "match.h" #include #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -44,6 +45,7 @@ #define MAX_VALUE_NAME_LENGTH 16383 #define MAX_VALUE_DATA_LENGTH 2048 +extern char* allowed_providers; extern int remote_add_provider; /* @@ -675,6 +677,12 @@ int process_add_smartcard_key(struct sshbuf* request, struct sshbuf* response, s goto done; } + if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) { + verbose("refusing PKCS#11 add of \"%.100s\": " + "provider not allowed", canonical_provider); + goto done; + } + // Remove 'drive root' if exists if (canonical_provider[0] == '/') memmove(canonical_provider, canonical_provider + 1, strlen(canonical_provider)); @@ -766,6 +774,8 @@ done: free(pubkey_blob); if (provider) free(provider); + if (allowed_providers) + free(allowed_providers); if (pin) { SecureZeroMemory(pin, (DWORD)pin_len); free(pin); diff --git a/scp.c b/scp.c index 7134dfecb..ff0f9b275 100644 --- a/scp.c +++ b/scp.c @@ -2117,7 +2117,11 @@ sink(int argc, char **argv, const char *src) SCREWUP("size out of range"); size = (off_t)ull; +#ifdef WINDOWS + if (*cp == '\0' || strchr(cp, '/') != NULL || strchr(cp, '\\') != NULL || +#else if (*cp == '\0' || strchr(cp, '/') != NULL || +#endif strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) { run_err("error: unexpected filename: %s", cp); exit(1); diff --git a/sftp-client.c b/sftp-client.c index 7efbe04b1..9ffcddff6 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -84,7 +84,12 @@ extern int showprogress; #ifdef HAVE_CYGWIN # define SFTP_DIRECTORY_CHARS "/\\" #else /* HAVE_CYGWIN */ +#ifdef WINDOWS +// Win32-OpenSSH converts all '/' to '\\' so search for '\\' instead +# define SFTP_DIRECTORY_CHARS "\\" +#else # define SFTP_DIRECTORY_CHARS "/" +#endif /* WINDOWS */ #endif /* HAVE_CYGWIN */ struct sftp_conn {