mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 08:14:24 +02:00
Spin up ssh-sk-helper in user context when called from ssh-agent (#560)
This commit is contained in:
parent
f82b197a3e
commit
0d88c342a5
@ -90,7 +90,7 @@ wevtutil im `"$etwman`"
|
|||||||
$agentDesc = "Agent to hold private keys used for public key authentication."
|
$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
|
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 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."
|
$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
|
New-Service -Name sshd -DisplayName "OpenSSH SSH Server" -BinaryPathName `"$sshdpath`" -Description $sshdDesc -StartupType Manual | Out-Null
|
||||||
|
@ -32,7 +32,7 @@ int setgid(gid_t gid);
|
|||||||
int seteuid(uid_t uid);
|
int seteuid(uid_t uid);
|
||||||
int setegid(gid_t gid);
|
int setegid(gid_t gid);
|
||||||
char *user_from_uid(uid_t uid, int nouser);
|
char *user_from_uid(uid_t uid, int nouser);
|
||||||
struct passwd *getpwent(void);
|
struct passwd *getpwent(void);
|
||||||
void setpwent(void);
|
void setpwent(void);
|
||||||
|
|
||||||
/*end - declarations not applicable in Windows */
|
/*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 *w32_getpwnam(const char *username);
|
||||||
struct passwd *getpwent(void);
|
struct passwd *getpwent(void);
|
||||||
void endpwent(void);
|
void endpwent(void);
|
||||||
|
char *get_username(const PSID sid);
|
||||||
|
|
||||||
#define getpwuid w32_getpwuid
|
#define getpwuid w32_getpwuid
|
||||||
#define getpwnam w32_getpwnam
|
#define getpwnam w32_getpwnam
|
||||||
|
@ -330,6 +330,21 @@ cleanup:
|
|||||||
return ret;
|
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*
|
struct passwd*
|
||||||
w32_getpwnam(const char *user_utf8)
|
w32_getpwnam(const char *user_utf8)
|
||||||
{
|
{
|
||||||
|
@ -121,6 +121,9 @@ wmain(int argc, wchar_t **argv)
|
|||||||
fix_cwd();
|
fix_cwd();
|
||||||
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
|
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
|
||||||
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
|
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
|
* agent is not spawned by SCM
|
||||||
* Its either started in debug mode or a worker child
|
* Its either started in debug mode or a worker child
|
||||||
|
@ -32,8 +32,12 @@
|
|||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
#include <UserEnv.h>
|
#include <UserEnv.h>
|
||||||
#include "..\misc_internal.h"
|
#include "..\misc_internal.h"
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#define BUFSIZE 5 * 1024
|
#define BUFSIZE 5 * 1024
|
||||||
|
|
||||||
|
char* sshagent_con_username;
|
||||||
|
|
||||||
static HANDLE ioc_port = NULL;
|
static HANDLE ioc_port = NULL;
|
||||||
static BOOL debug_mode = FALSE;
|
static BOOL debug_mode = FALSE;
|
||||||
|
|
||||||
@ -182,13 +186,18 @@ agent_cleanup_connection(struct agent_connection* con)
|
|||||||
{
|
{
|
||||||
debug("connection %p clean up", con);
|
debug("connection %p clean up", con);
|
||||||
CloseHandle(con->pipe_handle);
|
CloseHandle(con->pipe_handle);
|
||||||
if (con->client_impersonation_token)
|
if (con->client_impersonation_token)
|
||||||
CloseHandle(con->client_impersonation_token);
|
CloseHandle(con->client_impersonation_token);
|
||||||
if (con->client_process_handle)
|
if (con->client_process_handle)
|
||||||
CloseHandle(con->client_process_handle);
|
CloseHandle(con->client_process_handle);
|
||||||
free(con);
|
free(con);
|
||||||
CloseHandle(ioc_port);
|
CloseHandle(ioc_port);
|
||||||
ioc_port = NULL;
|
ioc_port = NULL;
|
||||||
|
|
||||||
|
if(sshagent_con_username) {
|
||||||
|
free(sshagent_con_username);
|
||||||
|
sshagent_con_username = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -289,6 +298,13 @@ get_con_client_info(struct agent_connection* con)
|
|||||||
goto done;
|
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 */
|
/* check if its admin */
|
||||||
{
|
{
|
||||||
sid_size = SECURITY_MAX_SID_SIZE;
|
sid_size = SECURITY_MAX_SID_SIZE;
|
||||||
|
@ -118,9 +118,13 @@ generate_s4u_user_token(wchar_t* user_cpn, int impersonation) {
|
|||||||
|
|
||||||
/* trusted mode - used for impersonation */
|
/* trusted mode - used for impersonation */
|
||||||
LSA_OPERATIONAL_MODE mode;
|
LSA_OPERATIONAL_MODE mode;
|
||||||
InitLsaString(&logon_process_name, "sshd");
|
InitLsaString(&logon_process_name, __progname);
|
||||||
if ((ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode)) != STATUS_SUCCESS)
|
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;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* untrusted mode - used for information lookup */
|
/* untrusted mode - used for information lookup */
|
||||||
@ -490,8 +494,8 @@ add_sid_mapping_to_lsa(PUNICODE_STRING domain_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p_output) {
|
if (p_output) {
|
||||||
status = pLsaFreeMemory(p_output);
|
status = pLsaFreeMemory(p_output);
|
||||||
if (status != STATUS_SUCCESS)
|
if (status != STATUS_SUCCESS)
|
||||||
debug3("LsaFreeMemory failed with ntstatus: %d", status);
|
debug3("LsaFreeMemory failed with ntstatus: %d", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,8 +523,8 @@ int remove_virtual_account_lsa_mapping(PUNICODE_STRING domain_name,
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
if (p_output) {
|
if (p_output) {
|
||||||
status = pLsaFreeMemory(p_output);
|
status = pLsaFreeMemory(p_output);
|
||||||
if (status != STATUS_SUCCESS)
|
if (status != STATUS_SUCCESS)
|
||||||
debug3("LsaFreeMemory failed with ntstatus: %d", status);
|
debug3("LsaFreeMemory failed with ntstatus: %d", status);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -566,8 +570,8 @@ HANDLE generate_sshd_virtual_token()
|
|||||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||||
UNICODE_STRING domain, group, account, svcLogonRight;
|
UNICODE_STRING domain, group, account, svcLogonRight;
|
||||||
WCHAR va_name[16]; /* enough to accommodate sshd_ + log10(MAXDWORD) */
|
WCHAR va_name[16]; /* enough to accommodate sshd_ + log10(MAXDWORD) */
|
||||||
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
LSA_HANDLE lsa_policy = NULL;
|
LSA_HANDLE lsa_policy = NULL;
|
||||||
NTSTATUS lsa_ret = 0, lsa_add_ret = (NTSTATUS)-1;
|
NTSTATUS lsa_ret = 0, lsa_add_ret = (NTSTATUS)-1;
|
||||||
|
|
||||||
PSID sid_domain = NULL, sid_group = NULL, sid_user = NULL;
|
PSID sid_domain = NULL, sid_group = NULL, sid_user = NULL;
|
||||||
@ -623,21 +627,21 @@ HANDLE generate_sshd_virtual_token()
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assign service logon privilege to virtual account */
|
/* assign service logon privilege to virtual account */
|
||||||
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
||||||
if ((lsa_ret = pLsaOpenPolicy(NULL, &ObjectAttributes,
|
if ((lsa_ret = pLsaOpenPolicy(NULL, &ObjectAttributes,
|
||||||
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
|
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
|
||||||
&lsa_policy)) != STATUS_SUCCESS) {
|
&lsa_policy)) != STATUS_SUCCESS) {
|
||||||
error("%s: unable to open policy handle, error: %d",
|
error("%s: unable to open policy handle, error: %d",
|
||||||
__FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_ret));
|
__FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_ret));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alter security to allow policy to account to logon as a service */
|
/* 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) {
|
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",
|
error("%s: unable to assign SE_SERVICE_LOGON_NAME privilege, error: %d",
|
||||||
__FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_add_ret));
|
__FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_add_ret));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Logon virtual and create token */
|
/* Logon virtual and create token */
|
||||||
@ -657,8 +661,8 @@ cleanup:
|
|||||||
remove_virtual_account_lsa_mapping(&domain, &account);
|
remove_virtual_account_lsa_mapping(&domain, &account);
|
||||||
|
|
||||||
/* attempt to remove virtual account permissions if previous add succeeded */
|
/* attempt to remove virtual account permissions if previous add succeeded */
|
||||||
if (lsa_add_ret == STATUS_SUCCESS)
|
if (lsa_add_ret == STATUS_SUCCESS)
|
||||||
if ((lsa_ret = pLsaRemoveAccountRights(lsa_policy, sid_user, FALSE, &svcLogonRight, 1)) != 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));
|
debug("%s: unable to remove SE_SERVICE_LOGON_NAME privilege, error: %d", __FUNCTION__, pRtlNtStatusToDosError(lsa_ret));
|
||||||
|
|
||||||
if (sid_domain)
|
if (sid_domain)
|
||||||
@ -744,8 +748,8 @@ int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_princ
|
|||||||
|
|
||||||
/* try explicit lookup */
|
/* try explicit lookup */
|
||||||
if (pTranslateNameW(sam_account_name, NameSamCompatible, NameUserPrincipal, domain_upn, &domain_upn_len) != 0) {
|
if (pTranslateNameW(sam_account_name, NameSamCompatible, NameUserPrincipal, domain_upn, &domain_upn_len) != 0) {
|
||||||
wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn);
|
wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, domain_upn);
|
||||||
debug3("%s: Successfully discovered explicit principal name: '%ls'=>'%ls'",
|
debug3("%s: Successfully discovered explicit principal name: '%ls'=>'%ls'",
|
||||||
__FUNCTION__, sam_account_name, user_principal_name);
|
__FUNCTION__, sam_account_name, user_principal_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -753,19 +757,19 @@ int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_princ
|
|||||||
/* try implicit lookup */
|
/* try implicit lookup */
|
||||||
lookup_error = GetLastError();
|
lookup_error = GetLastError();
|
||||||
domain_upn_len = ARRAYSIZE(domain_upn);
|
domain_upn_len = ARRAYSIZE(domain_upn);
|
||||||
if (pTranslateNameW(sam_account_name, NameSamCompatible, NameCanonical, domain_upn, &domain_upn_len) != 0) {
|
if (pTranslateNameW(sam_account_name, NameSamCompatible, NameCanonical, domain_upn, &domain_upn_len) != 0) {
|
||||||
/* construct an implicit upn using the samaccountname from the passed parameter
|
/* construct an implicit upn using the samaccountname from the passed parameter
|
||||||
* and the fully qualified domain portion of the canonical name */
|
* and the fully qualified domain portion of the canonical name */
|
||||||
wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, seperator + 1);
|
wcscpy_s(user_principal_name, MAX_UPN_LEN + 1, seperator + 1);
|
||||||
wcscat_s(user_principal_name, MAX_UPN_LEN + 1, L"@");
|
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);
|
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'",
|
debug3("%s: Successfully discovered implicit principal name: '%ls'=>'%ls'",
|
||||||
__FUNCTION__, sam_account_name, user_principal_name);
|
__FUNCTION__, sam_account_name, user_principal_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* report error */
|
/* 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());
|
__FUNCTION__, sam_account_name, lookup_error, GetLastError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -423,11 +423,17 @@ Describe "Setup Tests" -Tags "Setup" {
|
|||||||
($sshdSvc.RequiredServices).Count | Should Be 0
|
($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
|
$a = sc.exe qprivs ssh-agent 256
|
||||||
$p = @($a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}})
|
$p = @($a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}})
|
||||||
$p.count | Should Be 1
|
$expected | % {
|
||||||
$p[0] | Should Be "SeImpersonatePrivilege"
|
$p -contains $_ | Should be $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$p | % {
|
||||||
|
$expected -contains $_ | Should be $true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
It "$tC.$tI - Validate RequiredPrivileges of sshd" {
|
It "$tC.$tI - Validate RequiredPrivileges of sshd" {
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
/* #define DEBUG_SK 1 */
|
/* #define DEBUG_SK 1 */
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
extern char *sshagent_con_username = NULL;
|
||||||
static char module_path[PATH_MAX + 1];
|
static char module_path[PATH_MAX + 1];
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -167,9 +168,18 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
|
|||||||
av[0] = helper;
|
av[0] = helper;
|
||||||
av[1] = verbosity;
|
av[1] = verbosity;
|
||||||
av[2] = NULL;
|
av[2] = NULL;
|
||||||
if (posix_spawnp((pid_t *)&pid, av[0], &actions, NULL, av, NULL) != 0) {
|
|
||||||
error_f("posix_spawnp failed");
|
if (sshagent_con_username) {
|
||||||
goto out;
|
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;
|
r = 0;
|
||||||
#else
|
#else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user