diff --git a/contrib/win32/openssh/Win32-OpenSSh-design.pptx b/contrib/win32/openssh/Win32-OpenSSh-design.pptx new file mode 100644 index 000000000..4c95fb823 Binary files /dev/null and b/contrib/win32/openssh/Win32-OpenSSh-design.pptx differ diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 index fbdc56574..39078d1ab 100644 --- a/contrib/win32/openssh/install-sshd.ps1 +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -11,70 +11,6 @@ $logsdir = Join-Path $scriptdir "logs" $sshdAccount = "NT SERVICE\SSHD" -#Idea borrowed from http://sqldbamusings.blogspot.com/2012/03/powershell-adding-accounts-to-local.html -function Add-Privilege -{ - param( - [string] $Account, - - [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeServiceLogonRight")] - [string] $Privilege - ) - - #Get $Account SID - $account_sid = $null - try - { - $ntprincipal = new-object System.Security.Principal.NTAccount "$Account" - $sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier]) - $account_sid = $sid.Value.ToString() - } - catch - { - Throw 'Unable to resolve '+ $Account - } - - #Prepare policy settings file to be applied - $settings_to_export = [System.IO.Path]::GetTempFileName() - "[Unicode]" | Set-Content $settings_to_export -Encoding Unicode - "Unicode=yes" | Add-Content $settings_to_export -Force -WhatIf:$false - "[Version]" | Add-Content $settings_to_export -Force -WhatIf:$false - "signature=`"`$CHICAGO`$`"" | Add-Content $settings_to_export -Force -WhatIf:$false - "Revision=1" | Add-Content $settings_to_export -Force -WhatIf:$false - "[Privilege Rights]" | Add-Content $settings_to_export -Force -WhatIf:$false - - #Get Current policy settings - $imported_settings = [System.IO.Path]::GetTempFileName() - secedit.exe /export /areas USER_RIGHTS /cfg "$($imported_settings)" > $null - - if (-not(Test-Path $imported_settings)) { - Throw "Unable to import current security policy settings" - } - - #find current assigned accounts to $Privilege and add it to $settings_to_export - $current_settings = Get-Content $imported_settings -Encoding Unicode - $existing_setting = $null - foreach ($setting in $current_settings) { - if ($setting -like "$Privilege`*") { - $existing_setting = $setting - } - } - - #Add $account_sid to list - if ($existing_setting -eq $null) { - $Privilege + " = *" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false - } - else - { - $existing_setting + ",*" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false - } - - #export - secedit.exe /configure /db "secedit.sdb" /cfg "$($settings_to_export)" /areas USER_RIGHTS > $null - -} - - if (-not (Test-Path $sshdpath)) { throw "sshd.exe is not present in script path" } @@ -95,10 +31,8 @@ New-Service -Name ssh-agent -BinaryPathName $sshagentpath -Description "SSH Agen cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)' New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null -sc.exe config sshd obj= $sshdAccount - -Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege -Add-Privilege -Account $sshdAccount -Privilege SeServiceLogonRight +sc.exe config sshd obj= "NT AUTHORITY\NetworkService" +sc.exe sidtype sshd unrestricted if(-not (test-path $logsdir -PathType Container)) { diff --git a/contrib/win32/win32compat/ssh-agent/agent-main.c b/contrib/win32/win32compat/ssh-agent/agent-main.c index e7634bfa8..e962aebd6 100644 --- a/contrib/win32/win32compat/ssh-agent/agent-main.c +++ b/contrib/win32/win32compat/ssh-agent/agent-main.c @@ -1,6 +1,7 @@ /* * Author: Manoj Ampalam <manoj.ampalam@microsoft.com> * ssh-agent implementation on Windows + * NT Service routines * * Copyright (c) 2015 Microsoft Corp. * All rights reserved @@ -43,7 +44,8 @@ static SERVICE_STATUS_HANDLE service_status_handle; static SERVICE_STATUS service_status; -static VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) +static VOID +ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { service_status.dwCurrentState = dwCurrentState; service_status.dwWin32ExitCode = dwWin32ExitCode; @@ -62,7 +64,8 @@ static VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD d SetServiceStatus(service_status_handle, &service_status); } -static VOID WINAPI service_handler(DWORD dwControl) +static VOID WINAPI +service_handler(DWORD dwControl) { switch (dwControl) { @@ -81,22 +84,27 @@ static VOID WINAPI service_handler(DWORD dwControl) ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0); } -BOOL WINAPI ctrl_c_handler( - _In_ DWORD dwCtrlType -) { +BOOL WINAPI +ctrl_c_handler(_In_ DWORD dwCtrlType) +{ /* for any Ctrl type, shutdown agent*/ debug("Ctrl+C received"); agent_shutdown(); return TRUE; } -int wmain(int argc, wchar_t **argv) { - +int +wmain(int argc, wchar_t **argv) +{ w32posix_initialize(); + /* this exits() on failure*/ load_config(); if (!StartServiceCtrlDispatcherW(dispatch_table)) { if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { - + /* + * agent is not spawned by SCM + * Its either started in debug mode or a worker child + */ if (argc == 2) { if (wcsncmp(argv[1], L"-ddd", 4) == 0) log_init("ssh-agent", 7, 1, 1); @@ -105,9 +113,10 @@ int wmain(int argc, wchar_t **argv) { else if (wcsncmp(argv[1], L"-d", 2) == 0) log_init("ssh-agent", 5, 1, 1); + /* Set Ctrl+C handler if starting in debug mode */ if (wcsncmp(argv[1], L"-d", 2) == 0) { SetConsoleCtrlHandler(ctrl_c_handler, TRUE); - agent_start(TRUE, FALSE, 0); + agent_start(TRUE); return 0; } @@ -116,7 +125,7 @@ int wmain(int argc, wchar_t **argv) { h += _wtoi(*(argv + 1)); if (h != 0) { log_init("ssh-agent", config_log_level(), 1, 0); - agent_start(FALSE, TRUE, h); + agent_process_connection(h); return 0; } } @@ -146,14 +155,16 @@ int wmain(int argc, wchar_t **argv) { return 0; } -int scm_start_service(DWORD num, LPWSTR* args) { +int +scm_start_service(DWORD num, LPWSTR* args) +{ service_status_handle = RegisterServiceCtrlHandlerW(L"ssh-agent", service_handler); ZeroMemory(&service_status, sizeof(service_status)); service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300); ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); log_init("ssh-agent", config_log_level(), 1, 0); - agent_start(FALSE, FALSE, 0); + agent_start(FALSE); return 0; } diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index b97227a76..beeb3c0d3 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -44,40 +44,21 @@ static OVERLAPPED ol; static HANDLE pipe; static SECURITY_ATTRIBUTES sa; -static int -init_listener() { - { - if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { - debug("cannot create event ERROR:%d", GetLastError()); - return GetLastError(); - } - pipe = INVALID_HANDLE_VALUE; - sa.bInheritHandle = FALSE; - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:P(A;; GA;;; AU)", SDDL_REVISION_1, - &sa.lpSecurityDescriptor, &sa.nLength)) { - debug("cannot convert sddl ERROR:%d", GetLastError()); - return GetLastError(); - } - } - - return 0; -} - static void -agent_cleanup() { - { - if (ol.hEvent != NULL) - CloseHandle(ol.hEvent); - if (pipe != INVALID_HANDLE_VALUE) - CloseHandle(pipe); - } +agent_cleanup() +{ + if (ol.hEvent != NULL) + CloseHandle(ol.hEvent); + if (pipe != INVALID_HANDLE_VALUE) + CloseHandle(pipe); if (ioc_port) CloseHandle(ioc_port); return; } static DWORD WINAPI -iocp_work(LPVOID lpParam) { +iocp_work(LPVOID lpParam) +{ DWORD bytes; struct agent_connection* con = NULL; OVERLAPPED *p_ol; @@ -85,7 +66,7 @@ iocp_work(LPVOID lpParam) { con = NULL; p_ol = NULL; if (GetQueuedCompletionStatus(ioc_port, &bytes, &(ULONG_PTR)con, &p_ol, INFINITE) == FALSE) { - debug("iocp error: %d on %p \n", GetLastError(), con); + debug("iocp error: %d on %p", GetLastError(), con); if (con) agent_connection_on_error(con, GetLastError()); else @@ -93,80 +74,56 @@ iocp_work(LPVOID lpParam) { } else agent_connection_on_io(con, bytes, p_ol); - } } -static void -process_connection(HANDLE pipe) { - struct agent_connection* con; - - if ((con = malloc(sizeof(struct agent_connection))) == NULL) - fatal("failed to alloc"); - - memset(con, 0, sizeof(struct agent_connection)); - con->connection = pipe; - if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port) - fatal("failed to assign pipe to ioc_port"); - - agent_connection_on_io(con, 0, &con->ol); - iocp_work(NULL); -} - static void -agent_listen_loop() { +agent_listen_loop() +{ DWORD r; HANDLE wait_events[2]; wait_events[0] = event_stop_agent; - wait_events[1] = ol.hEvent; while (1) { - { - { - pipe = CreateNamedPipeW( - AGENT_PIPE_ID, // pipe name - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access - PIPE_TYPE_BYTE | // message type pipe - PIPE_READMODE_BYTE | // message-read mode - PIPE_WAIT, // blocking mode - PIPE_UNLIMITED_INSTANCES, // max. instances - BUFSIZE, // output buffer size - BUFSIZE, // input buffer size - 0, // client time-out - &sa); + pipe = CreateNamedPipeW( + AGENT_PIPE_ID, // pipe name + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access + PIPE_TYPE_BYTE | // message type pipe + PIPE_READMODE_BYTE | // message-read mode + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + BUFSIZE, // output buffer size + BUFSIZE, // input buffer size + 0, // client time-out + &sa); - if (pipe == INVALID_HANDLE_VALUE) { - verbose("cannot create listener pipe ERROR:%d", GetLastError()); - SetEvent(event_stop_agent); - } - else if (ConnectNamedPipe(pipe, &ol) != FALSE) { - verbose("ConnectNamedPipe returned TRUE unexpectedly "); - SetEvent(event_stop_agent); - } + if (pipe == INVALID_HANDLE_VALUE) { + verbose("cannot create listener pipe ERROR:%d", GetLastError()); + SetEvent(event_stop_agent); + } else if (ConnectNamedPipe(pipe, &ol) != FALSE) { + verbose("ConnectNamedPipe returned TRUE unexpectedly "); + SetEvent(event_stop_agent); + } - if (GetLastError() == ERROR_PIPE_CONNECTED) { - debug("Client has already connected"); - SetEvent(ol.hEvent); - } + if (GetLastError() == ERROR_PIPE_CONNECTED) { + debug("Client has already connected"); + SetEvent(ol.hEvent); + } - if (GetLastError() != ERROR_IO_PENDING) { - debug("ConnectNamedPipe failed ERROR: %d", GetLastError()); - SetEvent(event_stop_agent); - } - - } + if (GetLastError() != ERROR_IO_PENDING) { + debug("ConnectNamedPipe failed ERROR: %d", GetLastError()); + SetEvent(event_stop_agent); } r = WaitForMultipleObjects(2, wait_events, FALSE, INFINITE); if (r == WAIT_OBJECT_0) { - //received signal to shutdown + /*received signal to shutdown*/ debug("shutting down"); agent_cleanup(); return; - } - else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + 1))) { + } else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + 1))) { /* process incoming connection */ HANDLE con = pipe; DWORD client_pid = 0; @@ -174,11 +131,10 @@ agent_listen_loop() { GetNamedPipeClientProcessId(con, &client_pid); verbose("client pid %d connected", client_pid); if (debug_mode) { - process_connection(con); + agent_process_connection(con); agent_cleanup(); return; - } - else { + } else { /* spawn a child to take care of this*/ wchar_t path[PATH_MAX], module_path[PATH_MAX]; PROCESS_INFORMATION pi; @@ -193,8 +149,7 @@ agent_listen_loop() { DETACHED_PROCESS, NULL, NULL, &si, &pi) == FALSE)) { verbose("Failed to create child process %ls ERROR:%d", module_path, GetLastError()); - } - else { + } else { debug("spawned worker %d for agent client pid %d ", pi.dwProcessId, client_pid); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -203,17 +158,18 @@ agent_listen_loop() { CloseHandle(con); } - } - else { + } else { fatal("wait on events ended with %d ERROR:%d", r, GetLastError()); } } } -void agent_cleanup_connection(struct agent_connection* con) { +void +agent_cleanup_connection(struct agent_connection* con) +{ debug("connection %p clean up", con); - CloseHandle(con->connection); + CloseHandle(con->pipe_handle); if (con->hProfile) UnloadUserProfile(con->auth_token, con->hProfile); if (con->auth_token) @@ -223,45 +179,59 @@ void agent_cleanup_connection(struct agent_connection* con) { ioc_port = NULL; } -void agent_shutdown() { - verbose("shutdown"); +void +agent_shutdown() +{ SetEvent(event_stop_agent); } -#define REG_AGENT_SDDL L"D:P(A;; GR;;; AU)(A;; GA;;; SY)(A;; GA;;; BA)" - void -agent_start(BOOL dbg_mode, BOOL child, HANDLE pipe) { +agent_start(BOOL dbg_mode) +{ int r; HKEY agent_root = NULL; DWORD process_id = GetCurrentProcessId(); - - verbose("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg_mode, child, pipe); + + verbose("%s pid:%d, dbg:%d", __FUNCTION__, process_id, dbg_mode); debug_mode = dbg_mode; + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(sa); + /* allow access to Authenticated users and Network Service */ + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:P(A;;GA;;;AU)(A;;GA;;;NS)", SDDL_REVISION_1, + &sa.lpSecurityDescriptor, &sa.nLength)) + fatal("cannot convert sddl ERROR:%d", GetLastError()); + if ((r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, &sa, &agent_root, 0)) != ERROR_SUCCESS) + fatal("cannot create agent root reg key, ERROR:%d", r); + if ((r = RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4)) != ERROR_SUCCESS) + fatal("cannot publish agent master process id ERROR:%d", r); + if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + fatal("cannot create global stop event ERROR:%d", GetLastError()); + if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + fatal("cannot create event ERROR:%d", GetLastError()); + pipe = INVALID_HANDLE_VALUE; + sa.bInheritHandle = FALSE; + agent_listen_loop(); +} + +void +agent_process_connection(HANDLE pipe) +{ + struct agent_connection* con; + verbose("%s pipe:%p", __FUNCTION__, pipe); + if ((ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0)) == NULL) fatal("cannot create ioc port ERROR:%d", GetLastError()); + if ((con = malloc(sizeof(struct agent_connection))) == NULL) + fatal("failed to alloc"); - if (child == FALSE) { - SECURITY_ATTRIBUTES sa; - memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); - sa.nLength = sizeof(sa); - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(REG_AGENT_SDDL, SDDL_REVISION_1, &sa.lpSecurityDescriptor, &sa.nLength)) - fatal("ConvertStringSecurityDescriptorToSecurityDescriptorW failed"); - if ((r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, &sa, &agent_root, 0)) != ERROR_SUCCESS) - fatal("cannot create agent root reg key, ERROR:%d", r); - if ((r = RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4)) != ERROR_SUCCESS) - fatal("cannot publish agent master process id ERROR:%d", r); - if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) - fatal("cannot create global stop event ERROR:%d", GetLastError()); - if ((r = init_listener()) != 0) - fatal("failed to create server pipes ERROR:%d", r); - agent_listen_loop(); - } - else { /* this is a child process that processes one connection */ - process_connection(pipe); - } - + memset(con, 0, sizeof(struct agent_connection)); + con->pipe_handle = pipe; + if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port) + fatal("failed to assign pipe to ioc_port"); + + agent_connection_on_io(con, 0, &con->ol); + iocp_work(NULL); } diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h index e919cfc4a..d6aaaa825 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.h +++ b/contrib/win32/win32compat/ssh-agent/agent.h @@ -11,7 +11,7 @@ struct agent_connection { OVERLAPPED ol; - HANDLE connection; + HANDLE pipe_handle; struct { DWORD num_bytes; DWORD transferred; @@ -27,11 +27,9 @@ struct agent_connection { } state; enum { UNKNOWN = 0, - OTHER, - LOCAL_SYSTEM, - SSHD, - NETWORK_SERVICE - } client_process; + USER, /* client is running as some user */ + MACHINE /* clinet is running as machine - System, NS or LS */ + } client_type; HANDLE auth_token; HANDLE hProfile; }; @@ -40,7 +38,8 @@ void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*); void agent_connection_on_error(struct agent_connection* , DWORD); void agent_connection_disconnect(struct agent_connection*); -void agent_start(BOOL, BOOL, HANDLE); +void agent_start(BOOL); +void agent_process_connection(HANDLE); void agent_shutdown(); void agent_cleanup_connection(struct agent_connection*); diff --git a/contrib/win32/win32compat/ssh-agent/agentconfig.c b/contrib/win32/win32compat/ssh-agent/agentconfig.c index 155fd2c01..c3db1f8cd 100644 --- a/contrib/win32/win32compat/ssh-agent/agentconfig.c +++ b/contrib/win32/win32compat/ssh-agent/agentconfig.c @@ -96,7 +96,6 @@ int load_config() { wchar_t basePath[PATH_MAX] = { 0 }; wchar_t path[PATH_MAX] = { 0 }; - /* TODO - account for UNICODE paths*/ if (GetCurrentModulePath(basePath, PATH_MAX) == -1) return -1; diff --git a/contrib/win32/win32compat/ssh-agent/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c index 291f332fa..af7ba68d1 100644 --- a/contrib/win32/win32compat/ssh-agent/authagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c @@ -243,7 +243,7 @@ int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response goto done; } - if ((FALSE == GetNamedPipeClientProcessId(con->connection, &client_pid)) || + if ((FALSE == GetNamedPipeClientProcessId(con->pipe_handle, &client_pid)) || ((client_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL) || (FALSE == DuplicateHandle(GetCurrentProcess(), token, client_proc, &dup_token, TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, DUPLICATE_SAME_ACCESS)) || (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)) { @@ -317,7 +317,7 @@ int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response, goto done; } - if ((FALSE == GetNamedPipeClientProcessId(con->connection, &client_pid)) || + if ((FALSE == GetNamedPipeClientProcessId(con->pipe_handle, &client_pid)) || ( (client_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL) || (FALSE == DuplicateHandle(GetCurrentProcess(), token, client_proc, &dup_token, TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, DUPLICATE_SAME_ACCESS)) || (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)) { diff --git a/contrib/win32/win32compat/ssh-agent/connection.c b/contrib/win32/win32compat/ssh-agent/connection.c index d95973236..77233eed4 100644 --- a/contrib/win32/win32compat/ssh-agent/connection.c +++ b/contrib/win32/win32compat/ssh-agent/connection.c @@ -39,104 +39,101 @@ int process_request(struct agent_connection*); return; \ } while (0) -void agent_connection_on_error(struct agent_connection* con, DWORD error) { +void +agent_connection_on_error(struct agent_connection* con, DWORD error) +{ ABORT_CONNECTION_RETURN(con); } -void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPED* ol) { - +void +agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPED* ol) +{ /* process error */ debug3("connection io %p #bytes:%d state:%d", con, bytes, con->state); - if ((bytes == 0) && (GetOverlappedResult(con->connection, ol, &bytes, FALSE) == FALSE)) + if ((bytes == 0) && (GetOverlappedResult(con->pipe_handle, ol, &bytes, FALSE) == FALSE)) ABORT_CONNECTION_RETURN(con); - if (con->state == DONE) DebugBreak(); - { - switch (con->state) { - case LISTENING: - case WRITING: - /* Writing is done, read next request */ - /* assert on assumption that write always completes on sending all bytes*/ - if (bytes != con->io_buf.num_bytes) - DebugBreak(); - con->state = READING_HEADER; - ZeroMemory(&con->io_buf, sizeof(con->io_buf)); - if (!ReadFile(con->connection, con->io_buf.buf, - HEADER_SIZE, NULL, &con->ol) && (GetLastError() != ERROR_IO_PENDING)) - ABORT_CONNECTION_RETURN(con); - break; - case READING_HEADER: - con->io_buf.transferred += bytes; - if (con->io_buf.transferred == HEADER_SIZE) { - con->io_buf.num_bytes = PEEK_U32(con->io_buf.buf); - con->io_buf.transferred = 0; - if (con->io_buf.num_bytes > MAX_MESSAGE_SIZE) - ABORT_CONNECTION_RETURN(con); - - con->state = READING; - if (!ReadFile(con->connection, con->io_buf.buf, - con->io_buf.num_bytes, NULL, &con->ol)&&(GetLastError() != ERROR_IO_PENDING)) - ABORT_CONNECTION_RETURN(con); - } - else { - if (!ReadFile(con->connection, con->io_buf.buf + con->io_buf.num_bytes, - HEADER_SIZE - con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) - ABORT_CONNECTION_RETURN(con); - } - break; - case READING: - con->io_buf.transferred += bytes; - if (con->io_buf.transferred == con->io_buf.num_bytes) { - if (process_request(con) != 0) { - ABORT_CONNECTION_RETURN(con); - } - con->state = WRITING; - if (!WriteFile(con->connection, con->io_buf.buf, - con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING) ) - ABORT_CONNECTION_RETURN(con); - } - else { - if (!ReadFile(con->connection, con->io_buf.buf + con->io_buf.transferred, - con->io_buf.num_bytes - con->io_buf.transferred, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) - ABORT_CONNECTION_RETURN(con); - } - break; - default: + switch (con->state) { + case LISTENING: + case WRITING: + /* Writing is done, read next request */ + /* assert on assumption that write always completes on sending all bytes*/ + if (bytes != con->io_buf.num_bytes) DebugBreak(); - } - } + con->state = READING_HEADER; + ZeroMemory(&con->io_buf, sizeof(con->io_buf)); + if (!ReadFile(con->pipe_handle, con->io_buf.buf, + HEADER_SIZE, NULL, &con->ol) && (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + break; + case READING_HEADER: + con->io_buf.transferred += bytes; + if (con->io_buf.transferred == HEADER_SIZE) { + con->io_buf.num_bytes = PEEK_U32(con->io_buf.buf); + con->io_buf.transferred = 0; + if (con->io_buf.num_bytes > MAX_MESSAGE_SIZE) + ABORT_CONNECTION_RETURN(con); + + con->state = READING; + if (!ReadFile(con->pipe_handle, con->io_buf.buf, + con->io_buf.num_bytes, NULL, &con->ol)&&(GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } else { + if (!ReadFile(con->pipe_handle, con->io_buf.buf + con->io_buf.num_bytes, + HEADER_SIZE - con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } + break; + case READING: + con->io_buf.transferred += bytes; + if (con->io_buf.transferred == con->io_buf.num_bytes) { + if (process_request(con) != 0) { + ABORT_CONNECTION_RETURN(con); + } + con->state = WRITING; + if (!WriteFile(con->pipe_handle, con->io_buf.buf, + con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING) ) + ABORT_CONNECTION_RETURN(con); + } else { + if (!ReadFile(con->pipe_handle, con->io_buf.buf + con->io_buf.transferred, + con->io_buf.num_bytes - con->io_buf.transferred, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } + break; + default: + DebugBreak(); + } } -void agent_connection_disconnect(struct agent_connection* con) { - CancelIoEx(con->connection, NULL); - DisconnectNamedPipe(con->connection); +void +agent_connection_disconnect(struct agent_connection* con) +{ + CancelIoEx(con->pipe_handle, NULL); + DisconnectNamedPipe(con->pipe_handle); } static int -get_con_client_type(HANDLE pipe) { +get_con_client_type(struct agent_connection* con) +{ int r = -1; - wchar_t *sshd_act = L"NT SERVICE\\SSHD", *ref_dom = NULL; - PSID sshd_sid = NULL; char system_sid[SECURITY_MAX_SID_SIZE]; char ns_sid[SECURITY_MAX_SID_SIZE]; - DWORD sshd_sid_len = 0, reg_dom_len = 0, info_len = 0, sid_size; + char ls_sid[SECURITY_MAX_SID_SIZE]; + DWORD reg_dom_len = 0, info_len = 0, sid_size; SID_NAME_USE nuse; HANDLE token; TOKEN_USER* info = NULL; + HANDLE pipe = con->pipe_handle; if (ImpersonateNamedPipeClient(pipe) == FALSE) return -1; - if (LookupAccountNameW(NULL, sshd_act, NULL, &sshd_sid_len, NULL, ®_dom_len, &nuse) == TRUE || - (sshd_sid = malloc(sshd_sid_len)) == NULL || - (ref_dom = (wchar_t*)malloc(reg_dom_len * 2)) == NULL || - LookupAccountNameW(NULL, sshd_act, sshd_sid, &sshd_sid_len, ref_dom, ®_dom_len, &nuse) == FALSE || - OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE || - GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || - (info = (TOKEN_USER*)malloc(info_len)) == NULL || - GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE) + if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE || + GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || + (info = (TOKEN_USER*)malloc(info_len)) == NULL || + GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE) goto done; sid_size = SECURITY_MAX_SID_SIZE; @@ -145,22 +142,20 @@ get_con_client_type(HANDLE pipe) { sid_size = SECURITY_MAX_SID_SIZE; if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE) goto done; + sid_size = SECURITY_MAX_SID_SIZE; + if (CreateWellKnownSid(WinLocalServiceSid, NULL, ls_sid, &sid_size) == FALSE) + goto done; - if (EqualSid(info->User.Sid, system_sid)) - r = LOCAL_SYSTEM; - else if (EqualSid(info->User.Sid, sshd_sid)) - r = SSHD; - else if (EqualSid(info->User.Sid, ns_sid)) - r = NETWORK_SERVICE; + if (EqualSid(info->User.Sid, system_sid) || + EqualSid(info->User.Sid, ls_sid) || + EqualSid(info->User.Sid, ns_sid)) + con->client_type = MACHINE; else - r = OTHER; + con->client_type = USER; - debug2("client type: %d", r); + debug2("client type: %s", con->client_type == MACHINE? "machine" : "user"); + r = 0; done: - if (sshd_sid) - free(sshd_sid); - if (ref_dom) - free(ref_dom); if (info) free(info); RevertToSelf(); @@ -168,51 +163,49 @@ done: } static int -process_request(struct agent_connection* con) { +process_request(struct agent_connection* con) +{ int r = -1; struct sshbuf *request = NULL, *response = NULL; + u_char type; - if (con->client_process == UNKNOWN) - if ((con->client_process = get_con_client_type(con->connection)) == -1) - goto done; + if (con->client_type == UNKNOWN && get_con_client_type(con) == -1) { + debug("unable to get client process type"); + goto done; + } - //Sleep(30 * 1000); request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); response = sshbuf_new(); if ((request == NULL) || (response == NULL)) goto done; - { - u_char type; + if (sshbuf_get_u8(request, &type) != 0) + return -1; + debug("process agent request type %d", type); - if (sshbuf_get_u8(request, &type) != 0) - return -1; - debug("process agent request type %d", type); - - switch (type) { - case SSH2_AGENTC_ADD_IDENTITY: - r = process_add_identity(request, response, con); - break; - case SSH2_AGENTC_REQUEST_IDENTITIES: - r = process_request_identities(request, response, con); - break; - case SSH2_AGENTC_SIGN_REQUEST: - r = process_sign_request(request, response, con); - break; - case SSH2_AGENTC_REMOVE_IDENTITY: - r = process_remove_key(request, response, con); - break; - case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: - r = process_remove_all(request, response, con); - break; - case SSH_AGENT_AUTHENTICATE: - r = process_authagent_request(request, response, con); - break; - default: - debug("unknown agent request %d", type); - r = -1; - break; - } + switch (type) { + case SSH2_AGENTC_ADD_IDENTITY: + r = process_add_identity(request, response, con); + break; + case SSH2_AGENTC_REQUEST_IDENTITIES: + r = process_request_identities(request, response, con); + break; + case SSH2_AGENTC_SIGN_REQUEST: + r = process_sign_request(request, response, con); + break; + case SSH2_AGENTC_REMOVE_IDENTITY: + r = process_remove_key(request, response, con); + break; + case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: + r = process_remove_all(request, response, con); + break; + case SSH_AGENT_AUTHENTICATE: + r = process_authagent_request(request, response, con); + break; + default: + debug("unknown agent request %d", type); + r = -1; + break; } done: diff --git a/contrib/win32/win32compat/ssh-agent/keyagent-request.c b/contrib/win32/win32compat/ssh-agent/keyagent-request.c index 08225ac27..4c253e7c4 100644 --- a/contrib/win32/win32compat/ssh-agent/keyagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/keyagent-request.c @@ -36,21 +36,33 @@ #define MAX_KEY_LENGTH 255 #define MAX_VALUE_NAME 16383 +/* + * get registry root where keys are stored + * user keys are stored in user's hive + * while system keys (host keys) in HKLM + */ static int -get_user_root(struct agent_connection* con, HKEY *root){ +get_user_root(struct agent_connection* con, HKEY *root) +{ int r = 0; - *root = NULL; - if (ImpersonateNamedPipeClient(con->connection) == FALSE) - return -1; + LONG ret; + *root = HKEY_LOCAL_MACHINE; - if (con->client_process > OTHER) - *root = HKEY_LOCAL_MACHINE; - else if (RegOpenCurrentUser(KEY_ALL_ACCESS, root) != ERROR_SUCCESS) - r = -1; - - if (*root == NULL) - debug("cannot connect to user's registry root"); - RevertToSelf(); + if (con->client_type == USER) { + if (ImpersonateNamedPipeClient(con->pipe_handle) == FALSE) + return -1; + *root = NULL; + /* + * TODO - check that user profile is loaded, + * otherwise, this will return default profile + */ + if ((ret = RegOpenCurrentUser(KEY_ALL_ACCESS, root)) != ERROR_SUCCESS) { + debug("unable to open user's registry hive, ERROR - %d", ret); + r = -1; + } + + RevertToSelf(); + } return r; } @@ -59,8 +71,8 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char ** int success = 0; DATA_BLOB in, out; - if (con->client_process == OTHER) - if (ImpersonateNamedPipeClient(con->connection) == FALSE) + if (con->client_type == USER) + if (ImpersonateNamedPipeClient(con->pipe_handle) == FALSE) return -1; in.cbData = blen; @@ -73,8 +85,7 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char ** debug("cannot encrypt data"); goto done; } - } - else { + } else { if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) { debug("cannot decrypt data"); goto done; @@ -91,7 +102,7 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char ** done: if (out.pbData) LocalFree(out.pbData); - if (con->client_process == OTHER) + if (con->client_type == USER) RevertToSelf(); return success? 0: -1; } @@ -99,7 +110,8 @@ done: #define REG_KEY_SDDL L"D:P(A;; GA;;; SY)(A;; GA;;; BA)" int -process_add_identity(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +process_add_identity(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ struct sshkey* key = NULL; int r = 0, blob_len, eblob_len, request_invalid = 0, success = 0; size_t comment_len, pubkey_blob_len; @@ -170,7 +182,8 @@ done: } static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen, - const u_char *blob, size_t blen, u_int flags, struct agent_connection* con) { + const u_char *blob, size_t blen, u_int flags, struct agent_connection* con) +{ HKEY reg = 0, sub = 0, user_root = 0; int r = 0, success = 0; struct sshkey* prikey = NULL; @@ -225,7 +238,8 @@ done: } int -process_sign_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +process_sign_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ u_char *blob, *data, *signature = NULL; size_t blen, dlen, slen = 0; u_int flags = 0; @@ -257,8 +271,7 @@ done: sshbuf_put_string(response, signature, slen) != 0) { r = -1; } - } - else + } else if (sshbuf_put_u8(response, SSH_AGENT_FAILURE) != 0) r = -1; } @@ -271,7 +284,8 @@ done: } int -process_remove_key(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +process_remove_key(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ HKEY user_root = 0, root = 0; char *blob, *thumbprint = NULL; size_t blen; @@ -285,10 +299,10 @@ process_remove_key(struct sshbuf* request, struct sshbuf* response, struct agent } if ((thumbprint = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL || - get_user_root(con, &user_root) != 0 || - RegOpenKeyExW(user_root, SSH_KEYS_ROOT, 0, - DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_64KEY, &root) != 0 || - RegDeleteTreeA(root, thumbprint) != 0) + get_user_root(con, &user_root) != 0 || + RegOpenKeyExW(user_root, SSH_KEYS_ROOT, 0, + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_64KEY, &root) != 0 || + RegDeleteTreeA(root, thumbprint) != 0) goto done; success = 1; done: @@ -309,7 +323,8 @@ done: return r; } int -process_remove_all(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +process_remove_all(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ HKEY user_root = 0, root = 0; int r = 0; @@ -333,7 +348,8 @@ done: } int -process_request_identities(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +process_request_identities(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ int count = 0, index = 0, success = 0, r = 0; HKEY root = NULL, sub = NULL, user_root = 0; char* count_ptr = NULL; @@ -379,8 +395,7 @@ process_request_identities(struct sshbuf* request, struct sshbuf* response, stru key_count++; } - } - else + } else break; } @@ -393,8 +408,7 @@ done: sshbuf_put_u32(response, key_count) != 0 || sshbuf_putb(response, identities) != 0) goto done; - } - else + } else r = -1; if (pkblob) @@ -413,7 +427,8 @@ done: } -int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { +int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) +{ u_char type; if (sshbuf_get_u8(request, &type) != 0)