Tentative changes to support sshd in interactive mode (#313)
Added support to run sshd as non-system. In this mode, sshd can authenticate only the user that sshd is running as, and only via public key authentication. PowerShell/Win32-OpenSSH#1153
This commit is contained in:
parent
3fb0c252c3
commit
236b04b335
|
@ -326,7 +326,7 @@ sys_auth_passwd(struct ssh *ssh, const char *password)
|
|||
*/
|
||||
error("password for user %s has expired", authctxt->pw->pw_name);
|
||||
else {
|
||||
debug("Windows authentication failed for user: %ls domain: %ls error:%d", user_utf16, udom_utf16, GetLastError());
|
||||
debug("Windows authentication failed for user: %ls domain: %ls error:%d", unam_utf16, udom_utf16, GetLastError());
|
||||
|
||||
/* If LSA authentication package is configured then it will return the auth_token */
|
||||
sys_auth_passwd_lsa(authctxt, password);
|
||||
|
|
|
@ -1638,6 +1638,37 @@ chroot(const char *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Am I running as SYSTEM ?
|
||||
* a security sensitive call - fatal exits if it cannot definitively conclude
|
||||
*/
|
||||
int
|
||||
am_system()
|
||||
{
|
||||
HANDLE proc_token = NULL;
|
||||
DWORD info_len;
|
||||
TOKEN_USER* info = NULL;
|
||||
static int running_as_system = -1;
|
||||
|
||||
if (running_as_system != -1)
|
||||
return running_as_system;
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &proc_token) == FALSE ||
|
||||
GetTokenInformation(proc_token, TokenUser, NULL, 0, &info_len) == TRUE ||
|
||||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
||||
GetTokenInformation(proc_token, TokenUser, info, info_len, &info_len) == FALSE)
|
||||
fatal("unable to know if I am running as system");
|
||||
|
||||
if (IsWellKnownSid(info->User.Sid, WinLocalSystemSid))
|
||||
running_as_system = 1;
|
||||
else
|
||||
running_as_system = 0;
|
||||
|
||||
CloseHandle(proc_token);
|
||||
free(info);
|
||||
return running_as_system;
|
||||
}
|
||||
|
||||
/* returns SID of user or current user if (user = NULL) */
|
||||
PSID
|
||||
get_user_sid(char* name)
|
||||
|
|
|
@ -52,4 +52,5 @@ int load_user_profile(HANDLE user_token, char* user);
|
|||
int create_directory_withsddl(wchar_t *path, wchar_t *sddl);
|
||||
int is_absolute_path(const char *);
|
||||
int file_in_chroot_jail(HANDLE, const char*);
|
||||
PSID get_user_sid(char*);
|
||||
PSID get_user_sid(char*);
|
||||
int am_system();
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "misc_internal.h"
|
||||
#include "lsa_missingdefs.h"
|
||||
#include "Debug.h"
|
||||
#include "inc\pwd.h"
|
||||
|
||||
#pragma warning(push, 3)
|
||||
|
||||
|
@ -307,6 +308,7 @@ done:
|
|||
}
|
||||
|
||||
HANDLE generate_sshd_virtual_token();
|
||||
HANDLE generate_sshd_token_as_nonsystem();
|
||||
|
||||
HANDLE
|
||||
get_user_token(char* user, int impersonation) {
|
||||
|
@ -319,13 +321,28 @@ get_user_token(char* user, int impersonation) {
|
|||
}
|
||||
|
||||
if (wcscmp(user_utf16, L"sshd") == 0) {
|
||||
if ((token = generate_sshd_virtual_token()) != 0)
|
||||
/* not running as system, try generating sshd token as admin */
|
||||
if (!am_system() && (token = generate_sshd_token_as_nonsystem()) != 0)
|
||||
goto done;
|
||||
debug3("unable to generate sshd virtual token, falling back to s4u");
|
||||
|
||||
if ((token = generate_sshd_virtual_token()) == 0)
|
||||
error("unable to generate sshd virtual token, ensure sshd service has TCB privileges");
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!am_system()) {
|
||||
struct passwd* pwd = w32_getpwuid(0);
|
||||
if (strcmp(pwd->pw_name, user) == 0)
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS_P, &token);
|
||||
else
|
||||
debug("unable to generate user token for %s as I am not running as system", user);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((token = generate_s4u_user_token(user_utf16, impersonation)) == 0) {
|
||||
error("unable to generate token for user %ls", user_utf16);
|
||||
debug3("unable to generate token for user %ls", user_utf16);
|
||||
/* work around for https://github.com/PowerShell/Win32-OpenSSH/issues/727 by doing a fake login */
|
||||
LogonUserExExWHelper(L"FakeUser", L"FakeDomain", L"FakePasswd",
|
||||
LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL);
|
||||
|
@ -346,6 +363,12 @@ int
|
|||
load_user_profile(HANDLE user_token, char* user)
|
||||
{
|
||||
wchar_t * user_utf16 = NULL;
|
||||
|
||||
if (!am_system()) {
|
||||
debug("Not running as SYSTEM: skipping loading user profile");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
|
||||
fatal("out of memory");
|
||||
return -1;
|
||||
|
@ -476,6 +499,33 @@ InitUnicodeString(PUNICODE_STRING dest, PWSTR source)
|
|||
dest->MaximumLength = dest->Length + 2;
|
||||
}
|
||||
|
||||
HANDLE generate_sshd_token_as_nonsystem()
|
||||
{
|
||||
/*
|
||||
* This logic tries to reset sshd account password and generate sshd token via logon user
|
||||
* however this token cannot be used to spawn child processes in typical interactive
|
||||
* scenarios, without modifying ACLs on desktop station.
|
||||
* Since sshd is run in interactive mode primarily for debugging/testing purposes, we are
|
||||
* simply returing the process token (to be used for spawning unprivileged worker)
|
||||
{
|
||||
UUID uuid;
|
||||
RPC_CWSTR rpc_str;
|
||||
USER_INFO_1003 info;
|
||||
HANDLE token = 0;
|
||||
UuidCreate(&uuid);
|
||||
UuidToStringW(&uuid, (RPC_WSTR*)&rpc_str);
|
||||
|
||||
info.usri1003_password = (LPWSTR)rpc_str;
|
||||
NetUserSetInfo(NULL, L"sshd", 1003, (LPBYTE)&info, NULL);
|
||||
|
||||
LogonUserW(L"sshd", NULL, (LPCWSTR)rpc_str, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &token);
|
||||
}
|
||||
*/
|
||||
HANDLE token = 0;
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS_P , &token);
|
||||
return token;
|
||||
}
|
||||
|
||||
HANDLE generate_sshd_virtual_token()
|
||||
{
|
||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||
|
|
|
@ -103,9 +103,7 @@ static VOID WINAPI service_handler(DWORD dwControl)
|
|||
static void
|
||||
generate_host_keys()
|
||||
{
|
||||
TOKEN_USER* info = NULL;
|
||||
DWORD info_len = 0, dwError = 0;
|
||||
HANDLE proc_token = NULL;
|
||||
DWORD dwError = 0;
|
||||
UUID uuid;
|
||||
RPC_CWSTR rpc_str;
|
||||
USER_INFO_1 ui;
|
||||
|
@ -114,13 +112,8 @@ generate_host_keys()
|
|||
PROCESS_INFORMATION pi;
|
||||
wchar_t cmdline[MAX_PATH];
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &proc_token) == FALSE ||
|
||||
GetTokenInformation(proc_token, TokenUser, NULL, 0, &info_len) == TRUE ||
|
||||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
|
||||
GetTokenInformation(proc_token, TokenUser, info, info_len, &info_len) == FALSE)
|
||||
goto cleanup;
|
||||
|
||||
if (IsWellKnownSid(info->User.Sid, WinLocalSystemSid)) {
|
||||
if (am_system()) {
|
||||
/* create sshd account if it does not exist */
|
||||
UuidCreate(&uuid);
|
||||
UuidToStringW(&uuid, (RPC_WSTR*)&rpc_str);
|
||||
|
@ -146,11 +139,6 @@ generate_host_keys()
|
|||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
if (proc_token)
|
||||
CloseHandle(proc_token);
|
||||
if (info)
|
||||
free(info);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -259,13 +247,13 @@ int wmain(int argc, wchar_t **wargv) {
|
|||
wchar_t* path_utf16;
|
||||
argc_original = argc;
|
||||
wargv_original = wargv;
|
||||
|
||||
|
||||
/* change current directory to sshd.exe root */
|
||||
if ( (path_utf16 = utf8_to_utf16(w32_programdir())) == NULL)
|
||||
return -1;
|
||||
_wchdir(path_utf16);
|
||||
free(path_utf16);
|
||||
|
||||
|
||||
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
|
||||
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
|
||||
return sshd_main(argc, wargv); /* sshd running NOT as service*/
|
||||
|
|
Loading…
Reference in New Issue