Run SSHD as NetworkService (#121)

PowerShell/Win32-OpenSSH#681
This commit is contained in:
Manoj Ampalam 2017-04-24 22:02:03 -07:00 committed by GitHub
parent bc3f21a6a3
commit 1ff1b07410
9 changed files with 282 additions and 361 deletions

Binary file not shown.

View File

@ -11,70 +11,6 @@ $logsdir = Join-Path $scriptdir "logs"
$sshdAccount = "NT SERVICE\SSHD" $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)) { if (-not (Test-Path $sshdpath)) {
throw "sshd.exe is not present in script path" 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)' 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 New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
sc.exe config sshd obj= $sshdAccount sc.exe config sshd obj= "NT AUTHORITY\NetworkService"
sc.exe sidtype sshd unrestricted
Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege
Add-Privilege -Account $sshdAccount -Privilege SeServiceLogonRight
if(-not (test-path $logsdir -PathType Container)) if(-not (test-path $logsdir -PathType Container))
{ {

View File

@ -1,6 +1,7 @@
/* /*
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com> * Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
* ssh-agent implementation on Windows * ssh-agent implementation on Windows
* NT Service routines
* *
* Copyright (c) 2015 Microsoft Corp. * Copyright (c) 2015 Microsoft Corp.
* All rights reserved * All rights reserved
@ -43,7 +44,8 @@ static SERVICE_STATUS_HANDLE service_status_handle;
static SERVICE_STATUS service_status; 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.dwCurrentState = dwCurrentState;
service_status.dwWin32ExitCode = dwWin32ExitCode; service_status.dwWin32ExitCode = dwWin32ExitCode;
@ -62,7 +64,8 @@ static VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD d
SetServiceStatus(service_status_handle, &service_status); SetServiceStatus(service_status_handle, &service_status);
} }
static VOID WINAPI service_handler(DWORD dwControl) static VOID WINAPI
service_handler(DWORD dwControl)
{ {
switch (dwControl) switch (dwControl)
{ {
@ -81,22 +84,27 @@ static VOID WINAPI service_handler(DWORD dwControl)
ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0); ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0);
} }
BOOL WINAPI ctrl_c_handler( BOOL WINAPI
_In_ DWORD dwCtrlType ctrl_c_handler(_In_ DWORD dwCtrlType)
) { {
/* for any Ctrl type, shutdown agent*/ /* for any Ctrl type, shutdown agent*/
debug("Ctrl+C received"); debug("Ctrl+C received");
agent_shutdown(); agent_shutdown();
return TRUE; return TRUE;
} }
int wmain(int argc, wchar_t **argv) { int
wmain(int argc, wchar_t **argv)
{
w32posix_initialize(); w32posix_initialize();
/* this exits() on failure*/
load_config(); load_config();
if (!StartServiceCtrlDispatcherW(dispatch_table)) { if (!StartServiceCtrlDispatcherW(dispatch_table)) {
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { 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 (argc == 2) {
if (wcsncmp(argv[1], L"-ddd", 4) == 0) if (wcsncmp(argv[1], L"-ddd", 4) == 0)
log_init("ssh-agent", 7, 1, 1); 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) else if (wcsncmp(argv[1], L"-d", 2) == 0)
log_init("ssh-agent", 5, 1, 1); log_init("ssh-agent", 5, 1, 1);
/* Set Ctrl+C handler if starting in debug mode */
if (wcsncmp(argv[1], L"-d", 2) == 0) { if (wcsncmp(argv[1], L"-d", 2) == 0) {
SetConsoleCtrlHandler(ctrl_c_handler, TRUE); SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
agent_start(TRUE, FALSE, 0); agent_start(TRUE);
return 0; return 0;
} }
@ -116,7 +125,7 @@ int wmain(int argc, wchar_t **argv) {
h += _wtoi(*(argv + 1)); h += _wtoi(*(argv + 1));
if (h != 0) { if (h != 0) {
log_init("ssh-agent", config_log_level(), 1, 0); log_init("ssh-agent", config_log_level(), 1, 0);
agent_start(FALSE, TRUE, h); agent_process_connection(h);
return 0; return 0;
} }
} }
@ -146,14 +155,16 @@ int wmain(int argc, wchar_t **argv) {
return 0; 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); service_status_handle = RegisterServiceCtrlHandlerW(L"ssh-agent", service_handler);
ZeroMemory(&service_status, sizeof(service_status)); ZeroMemory(&service_status, sizeof(service_status));
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300); ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300);
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
log_init("ssh-agent", config_log_level(), 1, 0); log_init("ssh-agent", config_log_level(), 1, 0);
agent_start(FALSE, FALSE, 0); agent_start(FALSE);
return 0; return 0;
} }

View File

@ -44,40 +44,21 @@ static OVERLAPPED ol;
static HANDLE pipe; static HANDLE pipe;
static SECURITY_ATTRIBUTES sa; 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 static void
agent_cleanup() { agent_cleanup()
{ {
if (ol.hEvent != NULL) if (ol.hEvent != NULL)
CloseHandle(ol.hEvent); CloseHandle(ol.hEvent);
if (pipe != INVALID_HANDLE_VALUE) if (pipe != INVALID_HANDLE_VALUE)
CloseHandle(pipe); CloseHandle(pipe);
}
if (ioc_port) if (ioc_port)
CloseHandle(ioc_port); CloseHandle(ioc_port);
return; return;
} }
static DWORD WINAPI static DWORD WINAPI
iocp_work(LPVOID lpParam) { iocp_work(LPVOID lpParam)
{
DWORD bytes; DWORD bytes;
struct agent_connection* con = NULL; struct agent_connection* con = NULL;
OVERLAPPED *p_ol; OVERLAPPED *p_ol;
@ -85,7 +66,7 @@ iocp_work(LPVOID lpParam) {
con = NULL; con = NULL;
p_ol = NULL; p_ol = NULL;
if (GetQueuedCompletionStatus(ioc_port, &bytes, &(ULONG_PTR)con, &p_ol, INFINITE) == FALSE) { 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) if (con)
agent_connection_on_error(con, GetLastError()); agent_connection_on_error(con, GetLastError());
else else
@ -93,38 +74,19 @@ iocp_work(LPVOID lpParam) {
} }
else else
agent_connection_on_io(con, bytes, p_ol); agent_connection_on_io(con, bytes, p_ol);
} }
} }
static void static void
process_connection(HANDLE pipe) { agent_listen_loop()
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() {
DWORD r; DWORD r;
HANDLE wait_events[2]; HANDLE wait_events[2];
wait_events[0] = event_stop_agent; wait_events[0] = event_stop_agent;
wait_events[1] = ol.hEvent; wait_events[1] = ol.hEvent;
while (1) { while (1) {
{
{
pipe = CreateNamedPipeW( pipe = CreateNamedPipeW(
AGENT_PIPE_ID, // pipe name AGENT_PIPE_ID, // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
@ -140,8 +102,7 @@ agent_listen_loop() {
if (pipe == INVALID_HANDLE_VALUE) { if (pipe == INVALID_HANDLE_VALUE) {
verbose("cannot create listener pipe ERROR:%d", GetLastError()); verbose("cannot create listener pipe ERROR:%d", GetLastError());
SetEvent(event_stop_agent); SetEvent(event_stop_agent);
} } else if (ConnectNamedPipe(pipe, &ol) != FALSE) {
else if (ConnectNamedPipe(pipe, &ol) != FALSE) {
verbose("ConnectNamedPipe returned TRUE unexpectedly "); verbose("ConnectNamedPipe returned TRUE unexpectedly ");
SetEvent(event_stop_agent); SetEvent(event_stop_agent);
} }
@ -156,17 +117,13 @@ agent_listen_loop() {
SetEvent(event_stop_agent); SetEvent(event_stop_agent);
} }
}
}
r = WaitForMultipleObjects(2, wait_events, FALSE, INFINITE); r = WaitForMultipleObjects(2, wait_events, FALSE, INFINITE);
if (r == WAIT_OBJECT_0) { if (r == WAIT_OBJECT_0) {
//received signal to shutdown /*received signal to shutdown*/
debug("shutting down"); debug("shutting down");
agent_cleanup(); agent_cleanup();
return; 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 */ /* process incoming connection */
HANDLE con = pipe; HANDLE con = pipe;
DWORD client_pid = 0; DWORD client_pid = 0;
@ -174,11 +131,10 @@ agent_listen_loop() {
GetNamedPipeClientProcessId(con, &client_pid); GetNamedPipeClientProcessId(con, &client_pid);
verbose("client pid %d connected", client_pid); verbose("client pid %d connected", client_pid);
if (debug_mode) { if (debug_mode) {
process_connection(con); agent_process_connection(con);
agent_cleanup(); agent_cleanup();
return; return;
} } else {
else {
/* spawn a child to take care of this*/ /* spawn a child to take care of this*/
wchar_t path[PATH_MAX], module_path[PATH_MAX]; wchar_t path[PATH_MAX], module_path[PATH_MAX];
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
@ -193,8 +149,7 @@ agent_listen_loop() {
DETACHED_PROCESS, NULL, NULL, DETACHED_PROCESS, NULL, NULL,
&si, &pi) == FALSE)) { &si, &pi) == FALSE)) {
verbose("Failed to create child process %ls ERROR:%d", module_path, GetLastError()); 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); debug("spawned worker %d for agent client pid %d ", pi.dwProcessId, client_pid);
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
@ -203,17 +158,18 @@ agent_listen_loop() {
CloseHandle(con); CloseHandle(con);
} }
} } else {
else {
fatal("wait on events ended with %d ERROR:%d", r, GetLastError()); 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); debug("connection %p clean up", con);
CloseHandle(con->connection); CloseHandle(con->pipe_handle);
if (con->hProfile) if (con->hProfile)
UnloadUserProfile(con->auth_token, con->hProfile); UnloadUserProfile(con->auth_token, con->hProfile);
if (con->auth_token) if (con->auth_token)
@ -223,45 +179,59 @@ void agent_cleanup_connection(struct agent_connection* con) {
ioc_port = NULL; ioc_port = NULL;
} }
void agent_shutdown() { void
verbose("shutdown"); agent_shutdown()
{
SetEvent(event_stop_agent); SetEvent(event_stop_agent);
} }
#define REG_AGENT_SDDL L"D:P(A;; GR;;; AU)(A;; GA;;; SY)(A;; GA;;; BA)"
void void
agent_start(BOOL dbg_mode, BOOL child, HANDLE pipe) { agent_start(BOOL dbg_mode)
{
int r; int r;
HKEY agent_root = NULL; HKEY agent_root = NULL;
DWORD process_id = GetCurrentProcessId(); 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; debug_mode = dbg_mode;
if ((ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0)) == NULL)
fatal("cannot create ioc port ERROR:%d", GetLastError());
if (child == FALSE) {
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(sa); sa.nLength = sizeof(sa);
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(REG_AGENT_SDDL, SDDL_REVISION_1, &sa.lpSecurityDescriptor, &sa.nLength)) /* allow access to Authenticated users and Network Service */
fatal("ConvertStringSecurityDescriptorToSecurityDescriptorW failed"); 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) 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); 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) 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); fatal("cannot publish agent master process id ERROR:%d", r);
if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
fatal("cannot create global stop event ERROR:%d", GetLastError()); fatal("cannot create global stop event ERROR:%d", GetLastError());
if ((r = init_listener()) != 0) if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
fatal("failed to create server pipes ERROR:%d", r); fatal("cannot create event ERROR:%d", GetLastError());
pipe = INVALID_HANDLE_VALUE;
sa.bInheritHandle = FALSE;
agent_listen_loop(); agent_listen_loop();
} }
else { /* this is a child process that processes one connection */
process_connection(pipe); 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");
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);
} }

View File

@ -11,7 +11,7 @@
struct agent_connection { struct agent_connection {
OVERLAPPED ol; OVERLAPPED ol;
HANDLE connection; HANDLE pipe_handle;
struct { struct {
DWORD num_bytes; DWORD num_bytes;
DWORD transferred; DWORD transferred;
@ -27,11 +27,9 @@ struct agent_connection {
} state; } state;
enum { enum {
UNKNOWN = 0, UNKNOWN = 0,
OTHER, USER, /* client is running as some user */
LOCAL_SYSTEM, MACHINE /* clinet is running as machine - System, NS or LS */
SSHD, } client_type;
NETWORK_SERVICE
} client_process;
HANDLE auth_token; HANDLE auth_token;
HANDLE hProfile; 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_on_error(struct agent_connection* , DWORD);
void agent_connection_disconnect(struct agent_connection*); 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_shutdown();
void agent_cleanup_connection(struct agent_connection*); void agent_cleanup_connection(struct agent_connection*);

View File

@ -96,7 +96,6 @@ int load_config() {
wchar_t basePath[PATH_MAX] = { 0 }; wchar_t basePath[PATH_MAX] = { 0 };
wchar_t path[PATH_MAX] = { 0 }; wchar_t path[PATH_MAX] = { 0 };
/* TODO - account for UNICODE paths*/
if (GetCurrentModulePath(basePath, PATH_MAX) == -1) if (GetCurrentModulePath(basePath, PATH_MAX) == -1)
return -1; return -1;

View File

@ -243,7 +243,7 @@ int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response
goto done; 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) || ((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)) || (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)) { (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; 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) || ( (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)) || (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)) { (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)) {

View File

@ -39,21 +39,22 @@ int process_request(struct agent_connection*);
return; \ return; \
} while (0) } 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); 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 */ /* process error */
debug3("connection io %p #bytes:%d state:%d", con, bytes, con->state); 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); ABORT_CONNECTION_RETURN(con);
if (con->state == DONE) if (con->state == DONE)
DebugBreak(); DebugBreak();
{
switch (con->state) { switch (con->state) {
case LISTENING: case LISTENING:
case WRITING: case WRITING:
@ -63,7 +64,7 @@ void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPE
DebugBreak(); DebugBreak();
con->state = READING_HEADER; con->state = READING_HEADER;
ZeroMemory(&con->io_buf, sizeof(con->io_buf)); ZeroMemory(&con->io_buf, sizeof(con->io_buf));
if (!ReadFile(con->connection, con->io_buf.buf, if (!ReadFile(con->pipe_handle, con->io_buf.buf,
HEADER_SIZE, NULL, &con->ol) && (GetLastError() != ERROR_IO_PENDING)) HEADER_SIZE, NULL, &con->ol) && (GetLastError() != ERROR_IO_PENDING))
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
break; break;
@ -76,12 +77,11 @@ void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPE
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
con->state = READING; con->state = READING;
if (!ReadFile(con->connection, con->io_buf.buf, if (!ReadFile(con->pipe_handle, con->io_buf.buf,
con->io_buf.num_bytes, NULL, &con->ol)&&(GetLastError() != ERROR_IO_PENDING)) con->io_buf.num_bytes, NULL, &con->ol)&&(GetLastError() != ERROR_IO_PENDING))
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
} } else {
else { if (!ReadFile(con->pipe_handle, con->io_buf.buf + con->io_buf.num_bytes,
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)) HEADER_SIZE - con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING))
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
} }
@ -93,12 +93,11 @@ void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPE
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
} }
con->state = WRITING; con->state = WRITING;
if (!WriteFile(con->connection, con->io_buf.buf, if (!WriteFile(con->pipe_handle, con->io_buf.buf,
con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING) ) con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING) )
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
} } else {
else { if (!ReadFile(con->pipe_handle, con->io_buf.buf + con->io_buf.transferred,
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)) con->io_buf.num_bytes - con->io_buf.transferred, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING))
ABORT_CONNECTION_RETURN(con); ABORT_CONNECTION_RETURN(con);
} }
@ -106,34 +105,32 @@ void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPE
default: default:
DebugBreak(); DebugBreak();
} }
}
} }
void agent_connection_disconnect(struct agent_connection* con) { void
CancelIoEx(con->connection, NULL); agent_connection_disconnect(struct agent_connection* con)
DisconnectNamedPipe(con->connection); {
CancelIoEx(con->pipe_handle, NULL);
DisconnectNamedPipe(con->pipe_handle);
} }
static int static int
get_con_client_type(HANDLE pipe) { get_con_client_type(struct agent_connection* con)
{
int r = -1; 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 system_sid[SECURITY_MAX_SID_SIZE];
char ns_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; SID_NAME_USE nuse;
HANDLE token; HANDLE token;
TOKEN_USER* info = NULL; TOKEN_USER* info = NULL;
HANDLE pipe = con->pipe_handle;
if (ImpersonateNamedPipeClient(pipe) == FALSE) if (ImpersonateNamedPipeClient(pipe) == FALSE)
return -1; return -1;
if (LookupAccountNameW(NULL, sshd_act, NULL, &sshd_sid_len, NULL, &reg_dom_len, &nuse) == TRUE || if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE ||
(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, &reg_dom_len, &nuse) == FALSE ||
OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE ||
GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE ||
(info = (TOKEN_USER*)malloc(info_len)) == NULL || (info = (TOKEN_USER*)malloc(info_len)) == NULL ||
GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE) GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE)
@ -145,22 +142,20 @@ get_con_client_type(HANDLE pipe) {
sid_size = SECURITY_MAX_SID_SIZE; sid_size = SECURITY_MAX_SID_SIZE;
if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE) if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE)
goto done; 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)) if (EqualSid(info->User.Sid, system_sid) ||
r = LOCAL_SYSTEM; EqualSid(info->User.Sid, ls_sid) ||
else if (EqualSid(info->User.Sid, sshd_sid)) EqualSid(info->User.Sid, ns_sid))
r = SSHD; con->client_type = MACHINE;
else if (EqualSid(info->User.Sid, ns_sid))
r = NETWORK_SERVICE;
else 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: done:
if (sshd_sid)
free(sshd_sid);
if (ref_dom)
free(ref_dom);
if (info) if (info)
free(info); free(info);
RevertToSelf(); RevertToSelf();
@ -168,23 +163,22 @@ done:
} }
static int static int
process_request(struct agent_connection* con) { process_request(struct agent_connection* con)
{
int r = -1; int r = -1;
struct sshbuf *request = NULL, *response = NULL; struct sshbuf *request = NULL, *response = NULL;
u_char type;
if (con->client_process == UNKNOWN) if (con->client_type == UNKNOWN && get_con_client_type(con) == -1) {
if ((con->client_process = get_con_client_type(con->connection)) == -1) debug("unable to get client process type");
goto done; goto done;
}
//Sleep(30 * 1000);
request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes);
response = sshbuf_new(); response = sshbuf_new();
if ((request == NULL) || (response == NULL)) if ((request == NULL) || (response == NULL))
goto done; goto done;
{
u_char type;
if (sshbuf_get_u8(request, &type) != 0) if (sshbuf_get_u8(request, &type) != 0)
return -1; return -1;
debug("process agent request type %d", type); debug("process agent request type %d", type);
@ -213,7 +207,6 @@ process_request(struct agent_connection* con) {
r = -1; r = -1;
break; break;
} }
}
done: done:
if (request) if (request)

View File

@ -36,21 +36,33 @@
#define MAX_KEY_LENGTH 255 #define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383 #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 static int
get_user_root(struct agent_connection* con, HKEY *root){ get_user_root(struct agent_connection* con, HKEY *root)
{
int r = 0; int r = 0;
*root = NULL; LONG ret;
if (ImpersonateNamedPipeClient(con->connection) == FALSE)
return -1;
if (con->client_process > OTHER)
*root = HKEY_LOCAL_MACHINE; *root = HKEY_LOCAL_MACHINE;
else if (RegOpenCurrentUser(KEY_ALL_ACCESS, root) != ERROR_SUCCESS)
r = -1;
if (*root == NULL) if (con->client_type == USER) {
debug("cannot connect to user's registry root"); 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(); RevertToSelf();
}
return r; return r;
} }
@ -59,8 +71,8 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **
int success = 0; int success = 0;
DATA_BLOB in, out; DATA_BLOB in, out;
if (con->client_process == OTHER) if (con->client_type == USER)
if (ImpersonateNamedPipeClient(con->connection) == FALSE) if (ImpersonateNamedPipeClient(con->pipe_handle) == FALSE)
return -1; return -1;
in.cbData = blen; in.cbData = blen;
@ -73,8 +85,7 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **
debug("cannot encrypt data"); debug("cannot encrypt data");
goto done; goto done;
} }
} } else {
else {
if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) { if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) {
debug("cannot decrypt data"); debug("cannot decrypt data");
goto done; goto done;
@ -91,7 +102,7 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **
done: done:
if (out.pbData) if (out.pbData)
LocalFree(out.pbData); LocalFree(out.pbData);
if (con->client_process == OTHER) if (con->client_type == USER)
RevertToSelf(); RevertToSelf();
return success? 0: -1; return success? 0: -1;
} }
@ -99,7 +110,8 @@ done:
#define REG_KEY_SDDL L"D:P(A;; GA;;; SY)(A;; GA;;; BA)" #define REG_KEY_SDDL L"D:P(A;; GA;;; SY)(A;; GA;;; BA)"
int 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; struct sshkey* key = NULL;
int r = 0, blob_len, eblob_len, request_invalid = 0, success = 0; int r = 0, blob_len, eblob_len, request_invalid = 0, success = 0;
size_t comment_len, pubkey_blob_len; 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, 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; HKEY reg = 0, sub = 0, user_root = 0;
int r = 0, success = 0; int r = 0, success = 0;
struct sshkey* prikey = NULL; struct sshkey* prikey = NULL;
@ -225,7 +238,8 @@ done:
} }
int 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; u_char *blob, *data, *signature = NULL;
size_t blen, dlen, slen = 0; size_t blen, dlen, slen = 0;
u_int flags = 0; u_int flags = 0;
@ -257,8 +271,7 @@ done:
sshbuf_put_string(response, signature, slen) != 0) { sshbuf_put_string(response, signature, slen) != 0) {
r = -1; r = -1;
} }
} } else
else
if (sshbuf_put_u8(response, SSH_AGENT_FAILURE) != 0) if (sshbuf_put_u8(response, SSH_AGENT_FAILURE) != 0)
r = -1; r = -1;
} }
@ -271,7 +284,8 @@ done:
} }
int 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; HKEY user_root = 0, root = 0;
char *blob, *thumbprint = NULL; char *blob, *thumbprint = NULL;
size_t blen; size_t blen;
@ -309,7 +323,8 @@ done:
return r; return r;
} }
int 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; HKEY user_root = 0, root = 0;
int r = 0; int r = 0;
@ -333,7 +348,8 @@ done:
} }
int 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; int count = 0, index = 0, success = 0, r = 0;
HKEY root = NULL, sub = NULL, user_root = 0; HKEY root = NULL, sub = NULL, user_root = 0;
char* count_ptr = NULL; char* count_ptr = NULL;
@ -379,8 +395,7 @@ process_request_identities(struct sshbuf* request, struct sshbuf* response, stru
key_count++; key_count++;
} }
} } else
else
break; break;
} }
@ -393,8 +408,7 @@ done:
sshbuf_put_u32(response, key_count) != 0 || sshbuf_put_u32(response, key_count) != 0 ||
sshbuf_putb(response, identities) != 0) sshbuf_putb(response, identities) != 0)
goto done; goto done;
} } else
else
r = -1; r = -1;
if (pkblob) 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; u_char type;
if (sshbuf_get_u8(request, &type) != 0) if (sshbuf_get_u8(request, &type) != 0)