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:
Manoj Ampalam 2018-05-22 22:24:23 -07:00 committed by GitHub
parent 3fb0c252c3
commit 236b04b335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 21 deletions

View File

@ -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);

View File

@ -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)

View File

@ -53,3 +53,4 @@ 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*);
int am_system();

View File

@ -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;

View File

@ -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);
}
/*