diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 index cd02164dd..59da1df62 100644 --- a/contrib/win32/openssh/install-sshd.ps1 +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -90,7 +90,7 @@ wevtutil im `"$etwman`" $agentDesc = "Agent to hold private keys used for public key authentication." New-Service -Name ssh-agent -DisplayName "OpenSSH Authentication Agent" -BinaryPathName `"$sshagentpath`" -Description $agentDesc -StartupType Manual | Out-Null sc.exe sdset ssh-agent "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)" -sc.exe privs ssh-agent SeImpersonatePrivilege +sc.exe privs ssh-agent SeAssignPrimaryTokenPrivilege/SeTcbPrivilege/SeBackupPrivilege/SeRestorePrivilege/SeImpersonatePrivilege $sshdDesc = "SSH protocol based service to provide secure encrypted communications between two untrusted hosts over an insecure network." New-Service -Name sshd -DisplayName "OpenSSH SSH Server" -BinaryPathName `"$sshdpath`" -Description $sshdDesc -StartupType Manual | Out-Null diff --git a/contrib/win32/win32compat/inc/pwd.h b/contrib/win32/win32compat/inc/pwd.h index c2e6b16be..98964db02 100644 --- a/contrib/win32/win32compat/inc/pwd.h +++ b/contrib/win32/win32compat/inc/pwd.h @@ -32,7 +32,7 @@ int setgid(gid_t gid); int seteuid(uid_t uid); int setegid(gid_t gid); char *user_from_uid(uid_t uid, int nouser); -struct passwd *getpwent(void); +struct passwd *getpwent(void); void setpwent(void); /*end - declarations not applicable in Windows */ @@ -41,6 +41,7 @@ struct passwd *w32_getpwuid(uid_t uid); struct passwd *w32_getpwnam(const char *username); struct passwd *getpwent(void); void endpwent(void); +char *get_username(const PSID sid); #define getpwuid w32_getpwuid #define getpwnam w32_getpwnam diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c index 89dcef0b2..e7a8025c5 100644 --- a/contrib/win32/win32compat/pwd.c +++ b/contrib/win32/win32compat/pwd.c @@ -330,6 +330,21 @@ cleanup: return ret; } +char * +get_username(const PSID sid) +{ + if (!sid) { + error_f("sid is NULL"); + return NULL; + } + + struct passwd *p = get_passwd(NULL, sid); + if (p && p->pw_name) + return strdup(p->pw_name); + else + return NULL; +} + struct passwd* w32_getpwnam(const char *user_utf8) { diff --git a/contrib/win32/win32compat/ssh-agent/agent-main.c b/contrib/win32/win32compat/ssh-agent/agent-main.c index 20733ee00..2db3aeb82 100644 --- a/contrib/win32/win32compat/ssh-agent/agent-main.c +++ b/contrib/win32/win32compat/ssh-agent/agent-main.c @@ -121,6 +121,9 @@ wmain(int argc, wchar_t **argv) fix_cwd(); 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 */ + sanitise_stdfd(); + /* * agent is not spawned by SCM * Its either started in debug mode or a worker child diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index 1286ebd27..c1f8bdd8c 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -32,8 +32,12 @@ #include #include #include "..\misc_internal.h" +#include + #define BUFSIZE 5 * 1024 +char* sshagent_con_username; + static HANDLE ioc_port = NULL; static BOOL debug_mode = FALSE; @@ -182,13 +186,18 @@ agent_cleanup_connection(struct agent_connection* con) { debug("connection %p clean up", con); CloseHandle(con->pipe_handle); - if (con->client_impersonation_token) - CloseHandle(con->client_impersonation_token); + if (con->client_impersonation_token) + CloseHandle(con->client_impersonation_token); if (con->client_process_handle) CloseHandle(con->client_process_handle); free(con); CloseHandle(ioc_port); ioc_port = NULL; + + if(sshagent_con_username) { + free(sshagent_con_username); + sshagent_con_username = NULL; + } } void @@ -289,6 +298,13 @@ get_con_client_info(struct agent_connection* con) goto done; } + // Get username + sshagent_con_username= get_username(info->User.Sid); + if (sshagent_con_username) + debug_f("sshagent_con_username: %s", sshagent_con_username); + else + error_f("Failed to get the userName"); + /* check if its admin */ { sid_size = SECURITY_MAX_SID_SIZE; diff --git a/contrib/win32/win32compat/win32_usertoken_utils.c b/contrib/win32/win32compat/win32_usertoken_utils.c index 78609d470..2b8ede0d4 100644 --- a/contrib/win32/win32compat/win32_usertoken_utils.c +++ b/contrib/win32/win32compat/win32_usertoken_utils.c @@ -118,9 +118,13 @@ generate_s4u_user_token(wchar_t* user_cpn, int impersonation) { /* trusted mode - used for impersonation */ LSA_OPERATIONAL_MODE mode; - InitLsaString(&logon_process_name, "sshd"); - if ((ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode)) != STATUS_SUCCESS) + InitLsaString(&logon_process_name, __progname); + if ((ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode)) != STATUS_SUCCESS) { + ULONG winError = LsaNtStatusToWinError(ret); + error_f("LsaRegisterLogonProcess failed with error:%d", winError); + goto done; + } } else { /* untrusted mode - used for information lookup */ @@ -490,8 +494,8 @@ add_sid_mapping_to_lsa(PUNICODE_STRING domain_name, } if (p_output) { - status = pLsaFreeMemory(p_output); - if (status != STATUS_SUCCESS) + status = pLsaFreeMemory(p_output); + if (status != STATUS_SUCCESS) debug3("LsaFreeMemory failed with ntstatus: %d", status); } @@ -519,8 +523,8 @@ int remove_virtual_account_lsa_mapping(PUNICODE_STRING domain_name, ret = -1; if (p_output) { - status = pLsaFreeMemory(p_output); - if (status != STATUS_SUCCESS) + status = pLsaFreeMemory(p_output); + if (status != STATUS_SUCCESS) debug3("LsaFreeMemory failed with ntstatus: %d", status); } return ret; @@ -566,8 +570,8 @@ HANDLE generate_sshd_virtual_token() SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; UNICODE_STRING domain, group, account, svcLogonRight; WCHAR va_name[16]; /* enough to accommodate sshd_ + log10(MAXDWORD) */ - LSA_OBJECT_ATTRIBUTES ObjectAttributes; - LSA_HANDLE lsa_policy = NULL; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_HANDLE lsa_policy = NULL; NTSTATUS lsa_ret = 0, lsa_add_ret = (NTSTATUS)-1; PSID sid_domain = NULL, sid_group = NULL, sid_user = NULL; @@ -623,21 +627,21 @@ HANDLE generate_sshd_virtual_token() goto cleanup; } - /* assign service logon privilege to virtual account */ - ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); - if ((lsa_ret = pLsaOpenPolicy(NULL, &ObjectAttributes, - POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, - &lsa_policy)) != STATUS_SUCCESS) { - error("%s: unable to open policy handle, error: %d", - __FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_ret)); - goto cleanup; + /* assign service logon privilege to virtual account */ + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + if ((lsa_ret = pLsaOpenPolicy(NULL, &ObjectAttributes, + POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, + &lsa_policy)) != STATUS_SUCCESS) { + error("%s: unable to open policy handle, error: %d", + __FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_ret)); + goto cleanup; } - - /* alter security to allow policy to account to logon as a service */ - if ((lsa_add_ret = pLsaAddAccountRights(lsa_policy, sid_user, &svcLogonRight, 1)) != STATUS_SUCCESS) { - error("%s: unable to assign SE_SERVICE_LOGON_NAME privilege, error: %d", - __FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_add_ret)); - goto cleanup; + + /* alter security to allow policy to account to logon as a service */ + if ((lsa_add_ret = pLsaAddAccountRights(lsa_policy, sid_user, &svcLogonRight, 1)) != STATUS_SUCCESS) { + error("%s: unable to assign SE_SERVICE_LOGON_NAME privilege, error: %d", + __FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_add_ret)); + goto cleanup; } /* Logon virtual and create token */ @@ -657,8 +661,8 @@ cleanup: remove_virtual_account_lsa_mapping(&domain, &account); /* attempt to remove virtual account permissions if previous add succeeded */ - if (lsa_add_ret == STATUS_SUCCESS) - if ((lsa_ret = pLsaRemoveAccountRights(lsa_policy, sid_user, FALSE, &svcLogonRight, 1)) != STATUS_SUCCESS) + if (lsa_add_ret == STATUS_SUCCESS) + if ((lsa_ret = pLsaRemoveAccountRights(lsa_policy, sid_user, FALSE, &svcLogonRight, 1)) != STATUS_SUCCESS) debug("%s: unable to remove SE_SERVICE_LOGON_NAME privilege, error: %d", __FUNCTION__, pRtlNtStatusToDosError(lsa_ret)); if (sid_domain) @@ -744,8 +748,8 @@ int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_princ /* try explicit lookup */ if (pTranslateNameW(sam_account_name, NameSamCompatible, NameUserPrincipal, domain_upn, &domain_upn_len) != 0) { - wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn); - debug3("%s: Successfully discovered explicit principal name: '%ls'=>'%ls'", + wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn); + debug3("%s: Successfully discovered explicit principal name: '%ls'=>'%ls'", __FUNCTION__, sam_account_name, user_principal_name); return 0; } @@ -753,19 +757,19 @@ int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_princ /* try implicit lookup */ lookup_error = GetLastError(); domain_upn_len = ARRAYSIZE(domain_upn); - if (pTranslateNameW(sam_account_name, NameSamCompatible, NameCanonical, domain_upn, &domain_upn_len) != 0) { - /* construct an implicit upn using the samaccountname from the passed parameter - * and the fully qualified domain portion of the canonical name */ - wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, seperator + 1); - wcscat_s(user_principal_name, MAX_UPN_LEN + 1, L"@"); - wcsncat_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn, wcschr(domain_upn, L'/') - domain_upn); - debug3("%s: Successfully discovered implicit principal name: '%ls'=>'%ls'", + if (pTranslateNameW(sam_account_name, NameSamCompatible, NameCanonical, domain_upn, &domain_upn_len) != 0) { + /* construct an implicit upn using the samaccountname from the passed parameter + * and the fully qualified domain portion of the canonical name */ + wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, seperator + 1); + wcscat_s(user_principal_name, MAX_UPN_LEN + 1, L"@"); + wcsncat_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn, wcschr(domain_upn, L'/') - domain_upn); + debug3("%s: Successfully discovered implicit principal name: '%ls'=>'%ls'", __FUNCTION__, sam_account_name, user_principal_name); return 0; } /* report error */ - error("%s: User principal name lookup failed for user '%ls' (explicit: %d, implicit: %d)", + error("%s: User principal name lookup failed for user '%ls' (explicit: %d, implicit: %d)", __FUNCTION__, sam_account_name, lookup_error, GetLastError()); return -1; } diff --git a/regress/pesterTests/Setup.Tests.ps1 b/regress/pesterTests/Setup.Tests.ps1 index 4c62ce148..96074759c 100644 --- a/regress/pesterTests/Setup.Tests.ps1 +++ b/regress/pesterTests/Setup.Tests.ps1 @@ -423,11 +423,17 @@ Describe "Setup Tests" -Tags "Setup" { ($sshdSvc.RequiredServices).Count | Should Be 0 } - It "$tC.$tI - Validate RequiredPrivileges of ssh-agent" { + It "$tC.$tI - Validate RequiredPrivileges of ssh-agent" { + $expected = @("SeAssignPrimaryTokenPrivilege", "SeTcbPrivilege", "SeBackupPrivilege", "SeRestorePrivilege", "SeImpersonatePrivilege") $a = sc.exe qprivs ssh-agent 256 $p = @($a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}}) - $p.count | Should Be 1 - $p[0] | Should Be "SeImpersonatePrivilege" + $expected | % { + $p -contains $_ | Should be $true + } + + $p | % { + $expected -contains $_ | Should be $true + } } It "$tC.$tI - Validate RequiredPrivileges of sshd" { diff --git a/ssh-sk-client.c b/ssh-sk-client.c index 431b672ef..12a43ce65 100644 --- a/ssh-sk-client.c +++ b/ssh-sk-client.c @@ -44,6 +44,7 @@ /* #define DEBUG_SK 1 */ #ifdef WINDOWS +extern char *sshagent_con_username = NULL; static char module_path[PATH_MAX + 1]; static char * @@ -167,9 +168,18 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int)) av[0] = helper; av[1] = verbosity; av[2] = NULL; - if (posix_spawnp((pid_t *)&pid, av[0], &actions, NULL, av, NULL) != 0) { - error_f("posix_spawnp failed"); - goto out; + + if (sshagent_con_username) { + debug_f("sshagent_con_username:%s", sshagent_con_username); + if (__posix_spawn_asuser((pid_t *)&pid, av[0], &actions, NULL, av, NULL, sshagent_con_username) != 0) { + error_f("__posix_spawn_asuser failed for username:%s", sshagent_con_username); + goto out; + } + } else { + if (posix_spawnp((pid_t *)&pid, av[0], &actions, NULL, av, NULL) != 0) { + error_f("posix_spawnp failed"); + goto out; + } } r = 0; #else