Optimized group membership resolution (#327)
Current group membership resolution though very effective, is very slow. In a typical domain joined enterprise machine, adding a simple entry like the following in sshd_config AllowGroups administrators will incur a long delay in remote session establishment as sshd tried to pull all groups associated with the domain user. Changes in this PR optimize the general case scenarios where no wild cards are in use. Specifically rules like this are processed promptly: AllowGroups group1, group2, group3 //with no wild cards Match Group group1 //single group with no negation and wild cards Optimization is done by resolve the groupname in rule immediately to SID and checking its membership against user token. Enumerating the entire group membership is done on a lazy on-demand basis. Beyond the optimization, there are 2 functional changes - removed domain prefix for builtin groups - removed domain prefix'ed versions of local groups since we are strictly following the convention that local principals shouldn't have any domain qualification.
This commit is contained in:
parent
856078b7fd
commit
8bb672aa4d
|
@ -226,43 +226,7 @@ sys_auth_passwd(struct ssh *ssh, const char *password)
|
|||
#elif defined(WINDOWS)
|
||||
HANDLE password_auth_token = NULL;
|
||||
HANDLE process_custom_lsa_auth(const char*, const char*, const char*);
|
||||
|
||||
void
|
||||
sys_auth_passwd_lsa(Authctxt *authctxt, const char *password)
|
||||
{
|
||||
char *lsa_auth_pkg = NULL;
|
||||
wchar_t *lsa_auth_pkg_w = NULL;
|
||||
int domain_len = 0, lsa_auth_pkg_len = 0;
|
||||
HKEY reg_key = 0;
|
||||
REGSAM mask = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY;
|
||||
|
||||
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\OpenSSH", 0, mask, ®_key) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, NULL, &lsa_auth_pkg_len) == ERROR_SUCCESS)) {
|
||||
lsa_auth_pkg_w = (wchar_t *) malloc(lsa_auth_pkg_len); // lsa_auth_pkg_len includes the null terminating character.
|
||||
if (!lsa_auth_pkg_w)
|
||||
fatal("%s: out of memory", __func__);
|
||||
|
||||
memset(lsa_auth_pkg_w, 0, lsa_auth_pkg_len);
|
||||
if (RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, (LPBYTE)lsa_auth_pkg_w, &lsa_auth_pkg_len) == ERROR_SUCCESS) {
|
||||
lsa_auth_pkg = utf16_to_utf8(lsa_auth_pkg_w);
|
||||
if (!lsa_auth_pkg)
|
||||
fatal("utf16_to_utf8 failed to convert lsa_auth_pkg_w:%ls", lsa_auth_pkg_w);
|
||||
|
||||
password_auth_token = process_custom_lsa_auth(authctxt->pw->pw_name, password, lsa_auth_pkg);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (lsa_auth_pkg_w)
|
||||
free(lsa_auth_pkg_w);
|
||||
|
||||
if (lsa_auth_pkg)
|
||||
free(lsa_auth_pkg);
|
||||
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
}
|
||||
|
||||
char* get_custom_lsa_package();
|
||||
/*
|
||||
* Authenticate on Windows
|
||||
* - Call LogonUser and retrieve user token
|
||||
|
@ -327,7 +291,8 @@ sys_auth_passwd(struct ssh *ssh, const char *password)
|
|||
unam_utf16, udom_utf16, GetLastError());
|
||||
|
||||
/* If LSA authentication package is configured then it will return the auth_token */
|
||||
sys_auth_passwd_lsa(authctxt, password);
|
||||
if (get_custom_lsa_package())
|
||||
password_auth_token = process_custom_lsa_auth(authctxt->pw->pw_name, password, get_custom_lsa_package());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="paths.targets" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
|
@ -438,7 +438,6 @@
|
|||
<ClCompile Include="$(OpenSSH-Src-Path)auth2-passwd.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)auth2-pubkey.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)auth2.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)groupaccess.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)gss-serv-krb5.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)gss-serv.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)kexdhs.c" />
|
||||
|
@ -460,6 +459,7 @@
|
|||
<ClCompile Include="$(OpenSSH-Src-Path)sftp-common.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)sshd.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)sshlogin.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_groupaccess.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\wmain_sshd.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\spawn-ext.c" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
|
@ -144,18 +144,9 @@
|
|||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\wmain_sshd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)groupaccess.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\logonuser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_usertoken_utils.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\spawn-ext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -365,7 +365,7 @@ createFile_flags_setup(int flags, mode_t mode, struct createFile_flags* cf_flags
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((owner_sid = get_user_sid(NULL)) == NULL || (!ConvertSidToStringSidW(owner_sid, &sid_utf16))) {
|
||||
if ((owner_sid = get_sid(NULL)) == NULL || (!ConvertSidToStringSidW(owner_sid, &sid_utf16))) {
|
||||
debug3("cannot retrieve current user's SID");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
#ifndef COMPAT_GRP_H
|
||||
#define COMPAT_GRP_H 1
|
||||
#include <Windows.h>
|
||||
#include "sys/types.h"
|
||||
|
||||
char ** getusergroups(const char *user, int *numgroups);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1211,135 +1211,6 @@ invalid_parameter_handler(const wchar_t* expression, const wchar_t* function, co
|
|||
debug3("Expression: %s", expression);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method will fetch all the groups (listed below) even if the user is indirectly a member.
|
||||
* - Local machine groups
|
||||
* - Domain groups
|
||||
* - global group
|
||||
* - universal groups
|
||||
*/
|
||||
char **
|
||||
getusergroups(const char *user, int *ngroups)
|
||||
{
|
||||
/* early declarations and initializations to support cleanup */
|
||||
HANDLE logon_token = NULL;
|
||||
PTOKEN_GROUPS group_buf = NULL;
|
||||
|
||||
/* initialize return values */
|
||||
errno = 0;
|
||||
*ngroups = 0;
|
||||
char ** user_groups = NULL;
|
||||
|
||||
/* fetch the computer name so we can determine if the specified user is local or not */
|
||||
wchar_t computer_name[CNLEN + 1];
|
||||
DWORD computer_name_size = ARRAYSIZE(computer_name);
|
||||
if (GetComputerNameW(computer_name, &computer_name_size) == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get token that can be used for getting group information */
|
||||
if ((logon_token = get_user_token((char *)user, 0)) == NULL) {
|
||||
debug3("%s: get_user_token() failed for user %s.", __FUNCTION__, user);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate area for group information */
|
||||
DWORD group_size = 0;
|
||||
if (GetTokenInformation(logon_token, TokenGroups, NULL, 0, &group_size) == 0
|
||||
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
||||
(group_buf = (PTOKEN_GROUPS)malloc(group_size)) == NULL) {
|
||||
debug3("%s: GetTokenInformation() failed: %d", __FUNCTION__, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* read group sids from logon token -- this will return a list of groups
|
||||
* similar to the data returned when you do a whoami /groups command */
|
||||
if (GetTokenInformation(logon_token, TokenGroups, group_buf, group_size, &group_size) == 0) {
|
||||
debug3("%s: GetTokenInformation() failed for user '%s'.", __FUNCTION__, user);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate memory to hold points to all group names; we double the value
|
||||
* in order to account for local groups that we trim the domain qualifier */
|
||||
if ((user_groups = (char**)malloc(sizeof(char*) * group_buf->GroupCount * 2)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < group_buf->GroupCount; i++) {
|
||||
|
||||
/* only bother with group thats are 'enabled' from a security perspective */
|
||||
if ((group_buf->Groups[i].Attributes & SE_GROUP_ENABLED) == 0 ||
|
||||
!IsValidSid(group_buf->Groups[i].Sid))
|
||||
continue;
|
||||
|
||||
/* only bother with groups that are builtin or classic domain/local groups */
|
||||
SID * sid = group_buf->Groups[i].Sid;
|
||||
DWORD sub = sid->SubAuthority[0];
|
||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||
if (memcmp(&nt_authority, GetSidIdentifierAuthority(sid), sizeof(SID_IDENTIFIER_AUTHORITY)) == 0 && (
|
||||
sub == SECURITY_NT_NON_UNIQUE || sub == SECURITY_BUILTIN_DOMAIN_RID)) {
|
||||
|
||||
/* lookup the account name for this sid */
|
||||
wchar_t name[GNLEN + 1];
|
||||
DWORD name_len = ARRAYSIZE(name);
|
||||
wchar_t domain[DNLEN + 1];
|
||||
DWORD domain_len = ARRAYSIZE(domain);
|
||||
SID_NAME_USE name_use = 0;
|
||||
if (LookupAccountSidW(NULL, sid, name, &name_len, domain, &domain_len, &name_use) == 0) {
|
||||
errno = ENOENT;
|
||||
debug("%s: LookupAccountSid() failed: %d.", __FUNCTION__, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* add group name in netbios\\name format */
|
||||
int current_group = (*ngroups)++;
|
||||
wchar_t formatted_group[DNLEN + 1 + GNLEN + 1];
|
||||
swprintf_s(formatted_group, ARRAYSIZE(formatted_group), L"%s\\%s", domain, name);
|
||||
_wcslwr_s(formatted_group, ARRAYSIZE(formatted_group));
|
||||
debug3("Added group '%ls' for user '%s'.", formatted_group, user);
|
||||
user_groups[current_group] = utf16_to_utf8(formatted_group);
|
||||
if (user_groups[current_group] == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* for local accounts trim the domain qualifier */
|
||||
if (_wcsicmp(computer_name, domain) == 0)
|
||||
{
|
||||
current_group = (*ngroups)++;
|
||||
swprintf_s(formatted_group, ARRAYSIZE(formatted_group), L"%s", name);
|
||||
_wcslwr_s(formatted_group, ARRAYSIZE(formatted_group));
|
||||
debug3("Added group '%ls' for user '%s'.", formatted_group, user);
|
||||
user_groups[current_group] = utf16_to_utf8(formatted_group);
|
||||
if (user_groups[current_group] == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
if (group_buf)
|
||||
free(group_buf);
|
||||
if (logon_token)
|
||||
CloseHandle(logon_token);
|
||||
|
||||
/* special cleanup - if ran out of memory while allocating groups */
|
||||
if (user_groups && errno == ENOMEM || *ngroups == 0) {
|
||||
for (int group = 0; group < *ngroups; group++)
|
||||
if (user_groups[group]) free(user_groups[group]);
|
||||
*ngroups = 0;
|
||||
free(user_groups);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* downsize the array to the actual size and return */
|
||||
return (char**)realloc(user_groups, sizeof(char*) * (*ngroups));
|
||||
}
|
||||
|
||||
void
|
||||
to_lower_case(char *s)
|
||||
{
|
||||
|
@ -1636,9 +1507,12 @@ am_system()
|
|||
return running_as_system;
|
||||
}
|
||||
|
||||
/* returns SID of user or current user if (user = NULL) */
|
||||
/*
|
||||
* returns SID of user/group or current user if (user = NULL)
|
||||
* caller should free() return value
|
||||
*/
|
||||
PSID
|
||||
get_user_sid(char* name)
|
||||
get_sid(const char* name)
|
||||
{
|
||||
HANDLE token = NULL;
|
||||
TOKEN_USER* info = NULL;
|
||||
|
|
|
@ -47,11 +47,12 @@ void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *
|
|||
void to_lower_case(char *s);
|
||||
void to_wlower_case(wchar_t *s);
|
||||
wchar_t* get_program_data_path();
|
||||
HANDLE get_user_token(char* user, int impersonation);
|
||||
HANDLE get_user_token(const char* user, int impersonation);
|
||||
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_sid(const char*);
|
||||
int am_system();
|
||||
char* build_session_commandline(const char *, const char *, const char *, int );
|
||||
char* get_custom_lsa_package();
|
||||
|
|
|
@ -305,18 +305,9 @@ w32_getpwnam(const char *user_utf8)
|
|||
return ret;
|
||||
|
||||
/* check if custom passwd auth is enabled */
|
||||
{
|
||||
int lsa_auth_pkg_len = 0;
|
||||
HKEY reg_key = 0;
|
||||
if (get_custom_lsa_package())
|
||||
ret = getpwnam_placeholder(user_utf8);
|
||||
|
||||
REGSAM mask = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY;
|
||||
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\OpenSSH", 0, mask, ®_key) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, NULL, &lsa_auth_pkg_len) == ERROR_SUCCESS))
|
||||
ret = getpwnam_placeholder(user_utf8);
|
||||
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -326,7 +317,7 @@ w32_getpwuid(uid_t uid)
|
|||
struct passwd* ret = NULL;
|
||||
PSID cur_user_sid = NULL;
|
||||
|
||||
if ((cur_user_sid = get_user_sid(NULL)) == NULL)
|
||||
if ((cur_user_sid = get_sid(NULL)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
ret = get_passwd(NULL, cur_user_sid);
|
||||
|
|
|
@ -57,7 +57,7 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||
char *bad_user = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((user_sid = get_user_sid(pw ? pw->pw_name : NULL)) == NULL)
|
||||
if ((user_sid = get_sid(pw ? pw->pw_name : NULL)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if ((path_utf16 = resolved_path_utf16(input_path)) == NULL) {
|
||||
|
|
|
@ -93,6 +93,7 @@ load_secur32()
|
|||
return s_hm_secur32;
|
||||
}
|
||||
|
||||
static HMODULE
|
||||
load_ntdll()
|
||||
{
|
||||
static HMODULE s_hm_ntdll = NULL;
|
||||
|
|
|
@ -16,6 +16,7 @@ BOOL pLogonUserExExW(wchar_t *, wchar_t *, wchar_t *, DWORD, DWORD, PTOKEN_GROUP
|
|||
BOOLEAN pTranslateNameW(LPCWSTR, EXTENDED_NAME_FORMAT, EXTENDED_NAME_FORMAT, LPWSTR, PULONG);
|
||||
NTSTATUS pLsaOpenPolicy(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, PLSA_HANDLE);
|
||||
NTSTATUS pLsaAddAccountRights(LSA_HANDLE, PSID, PLSA_UNICODE_STRING, ULONG);
|
||||
ULONG pRtlNtStatusToDosError(NTSTATUS);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
*
|
||||
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
|
||||
* groupaccess interface implementation for Windows
|
||||
*
|
||||
* Author: Bryan Berns <berns@uwalumni.com>
|
||||
* Added support for running configuration rules against nested groups
|
||||
* spawning multiple domains/forests.
|
||||
* Core logic implemented in get_user_groups()
|
||||
*
|
||||
* Copyright (c) 2018 Microsoft Corp.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define UMDF_USING_NTSTATUS
|
||||
#define SECURITY_WIN32
|
||||
#include <Windows.h>
|
||||
#include <LM.h>
|
||||
#include <Sddl.h>
|
||||
#include <Aclapi.h>
|
||||
#include <Ntsecapi.h>
|
||||
#include <security.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#define __attribute__(a)
|
||||
#include "inc/sys/types.h"
|
||||
#include "..\..\..\xmalloc.h"
|
||||
#include "..\..\..\groupaccess.h"
|
||||
#include "..\..\..\match.h"
|
||||
#include "..\..\..\log.h"
|
||||
|
||||
#include "misc_internal.h"
|
||||
|
||||
static int ngroups;
|
||||
static char **groups_byname;
|
||||
static char *user_name;
|
||||
static HANDLE user_token;
|
||||
|
||||
/*
|
||||
* This method will fetch all the groups (listed below) even if the user is indirectly a member.
|
||||
* - Local machine groups
|
||||
* - Domain groups
|
||||
* - global group
|
||||
* - universal groups
|
||||
*/
|
||||
static int
|
||||
get_user_groups()
|
||||
{
|
||||
/* early declarations and initializations to support cleanup */
|
||||
HANDLE logon_token = user_token;
|
||||
PTOKEN_GROUPS group_buf = NULL;
|
||||
int ret = -1, num_groups = 0;
|
||||
static int processed = 0;
|
||||
|
||||
if (processed)
|
||||
return 0;
|
||||
|
||||
/* initialize return values */
|
||||
errno = 0;
|
||||
char ** user_groups = NULL;
|
||||
|
||||
debug2("%s: extracting all groups of user %s", __func__, user_name);
|
||||
|
||||
/* fetch the computer name so we can determine if the specified user is local or not */
|
||||
wchar_t computer_name[CNLEN + 1];
|
||||
DWORD computer_name_size = ARRAYSIZE(computer_name);
|
||||
if (GetComputerNameW(computer_name, &computer_name_size) == 0) {
|
||||
debug3("%s: GetComputerNameW() failed: %d", __FUNCTION__, GetLastError());
|
||||
errno = EOTHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate area for group information */
|
||||
DWORD group_size = 0;
|
||||
if (GetTokenInformation(logon_token, TokenGroups, NULL, 0, &group_size) == 0
|
||||
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
||||
(group_buf = (PTOKEN_GROUPS)malloc(group_size)) == NULL) {
|
||||
debug3("%s: GetTokenInformation() failed: %d", __FUNCTION__, GetLastError());
|
||||
errno = EOTHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* read group sids from logon token -- this will return a list of groups
|
||||
* similar to the data returned when you do a whoami /groups command */
|
||||
if (GetTokenInformation(logon_token, TokenGroups, group_buf, group_size, &group_size) == 0) {
|
||||
debug3("%s: GetTokenInformation() failed with error %d", __FUNCTION__, GetLastError());
|
||||
errno = EOTHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate memory to hold points to all group names */
|
||||
if ((user_groups = (char**)malloc(sizeof(char*) * group_buf->GroupCount)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < group_buf->GroupCount; i++) {
|
||||
|
||||
/* only bother with group thats are 'enabled' from a security perspective */
|
||||
if ((group_buf->Groups[i].Attributes & SE_GROUP_ENABLED) == 0 ||
|
||||
!IsValidSid(group_buf->Groups[i].Sid))
|
||||
continue;
|
||||
|
||||
/* only bother with groups that are builtin or classic domain/local groups */
|
||||
SID * sid = group_buf->Groups[i].Sid;
|
||||
DWORD sub = sid->SubAuthority[0];
|
||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||
if (memcmp(&nt_authority, GetSidIdentifierAuthority(sid), sizeof(SID_IDENTIFIER_AUTHORITY)) == 0 && (
|
||||
sub == SECURITY_NT_NON_UNIQUE || sub == SECURITY_BUILTIN_DOMAIN_RID)) {
|
||||
|
||||
/* lookup the account name for this sid */
|
||||
wchar_t name[GNLEN + 1];
|
||||
DWORD name_len = ARRAYSIZE(name);
|
||||
wchar_t domain[DNLEN + 1];
|
||||
DWORD domain_len = ARRAYSIZE(domain);
|
||||
SID_NAME_USE name_use = 0;
|
||||
if (LookupAccountSidW(NULL, sid, name, &name_len, domain, &domain_len, &name_use) == 0) {
|
||||
errno = ENOENT;
|
||||
debug("%s: LookupAccountSid() failed: %d.", __FUNCTION__, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int current_group = num_groups++;
|
||||
wchar_t formatted_group[DNLEN + 1 + GNLEN + 1];
|
||||
/* for local accounts trim the domain qualifier */
|
||||
if (sub == SECURITY_BUILTIN_DOMAIN_RID || _wcsicmp(computer_name, domain) == 0)
|
||||
swprintf_s(formatted_group, ARRAYSIZE(formatted_group), L"%s", name);
|
||||
else /* add group name in netbios\\name format */
|
||||
swprintf_s(formatted_group, ARRAYSIZE(formatted_group), L"%s\\%s", domain, name);
|
||||
|
||||
_wcslwr_s(formatted_group, ARRAYSIZE(formatted_group));
|
||||
debug3("Added group '%ls' for user %s", formatted_group, user_name);
|
||||
user_groups[current_group] = utf16_to_utf8(formatted_group);
|
||||
if (user_groups[current_group] == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngroups = num_groups;
|
||||
/* downsize the array to the actual size */
|
||||
groups_byname = (char**)realloc(user_groups, sizeof(char*) * num_groups);;
|
||||
user_groups = NULL;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (group_buf)
|
||||
free(group_buf);
|
||||
|
||||
if (user_groups && num_groups) {
|
||||
for (int group = 0; group < num_groups; group++)
|
||||
if (user_groups[group]) free(user_groups[group]);
|
||||
free(user_groups);
|
||||
}
|
||||
|
||||
debug2("%s: done extracting all groups of user %s", __func__, user_name);
|
||||
processed = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* checks if user_token has "group" membership, fatal exits on error
|
||||
* returns 1 if true, 0 otherwise
|
||||
*/
|
||||
static int
|
||||
check_group_membership(const char* group)
|
||||
{
|
||||
PSID sid = NULL;
|
||||
BOOL is_member = 0;
|
||||
|
||||
if ((sid = get_sid(group)) == NULL) {
|
||||
error("unable to resolve group %s", group);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!CheckTokenMembership(user_token, sid, &is_member))
|
||||
fatal("%s CheckTokenMembership for user %s failed with %d for group %s", __func__, user_name, GetLastError(), group);
|
||||
|
||||
cleanup:
|
||||
if (sid)
|
||||
free(sid);
|
||||
return is_member? 1: 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize group access list for user with primary (base) and
|
||||
* supplementary groups. Return the number of groups in the list.
|
||||
*/
|
||||
int
|
||||
ga_init(const char *user, gid_t base)
|
||||
{
|
||||
ngroups = 0;
|
||||
groups_byname = NULL;
|
||||
user_token = NULL;
|
||||
|
||||
user_name = xstrdup(user);
|
||||
|
||||
if ((user_token = get_user_token(user_name, 0)) == NULL)
|
||||
fatal("%s, unable to resolve user %s", __func__, user_name);
|
||||
|
||||
/*
|
||||
* supposed to retun number of groups associated with user
|
||||
* since we do lazy group evaluation, returning 1 here
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if one of user's groups is contained in groups.
|
||||
* Return 0 otherwise. Use match_pattern() for string comparison.
|
||||
*/
|
||||
int
|
||||
ga_match(char * const *groups, int n)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* group retrieval is expensive, optmizing the common case scenario with no wild cards */
|
||||
for (j = 0; j < n; j++)
|
||||
if (strchr(groups[j], '?') || strchr(groups[j], '*'))
|
||||
goto fetch_all;
|
||||
|
||||
for (j = 0; j < n; j++)
|
||||
if (check_group_membership(groups[j]))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
fetch_all:
|
||||
if (get_user_groups() == -1)
|
||||
fatal("unable to retrieve group info for user %s", user_name);
|
||||
|
||||
for (i = 0; i < ngroups; i++)
|
||||
for (j = 0; j < n; j++)
|
||||
if (match_pattern(groups_byname[i], groups[j]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if one of user's groups matches group_pattern list.
|
||||
* Return 0 on negated or no match.
|
||||
*/
|
||||
int
|
||||
ga_match_pattern_list(const char *group_pattern)
|
||||
{
|
||||
int i, found = 0;
|
||||
|
||||
/* group retrieval is expensive, optmizing the common case scenario - only one group with no wild cards and no negation */
|
||||
if (!strchr(group_pattern, ',') && !strchr(group_pattern, '?') &&
|
||||
!strchr(group_pattern, '*') && !strchr(group_pattern, '!'))
|
||||
return check_group_membership(group_pattern);
|
||||
|
||||
if (get_user_groups() == -1)
|
||||
fatal("unable to retrieve group info for user %s", user_name);
|
||||
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
switch (match_pattern_list(groups_byname[i], group_pattern, 0)) {
|
||||
case -1:
|
||||
return 0; /* Negated match wins */
|
||||
case 0:
|
||||
continue;
|
||||
case 1:
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free memory allocated for group access list.
|
||||
*/
|
||||
void
|
||||
ga_free(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ngroups > 0) {
|
||||
for (i = 0; i < ngroups; i++)
|
||||
free(groups_byname[i]);
|
||||
ngroups = 0;
|
||||
free(groups_byname);
|
||||
}
|
||||
groups_byname = NULL;
|
||||
|
||||
if (user_name)
|
||||
free(user_name);
|
||||
user_name = NULL;
|
||||
CloseHandle(user_token);
|
||||
user_token = NULL;
|
||||
}
|
|
@ -144,7 +144,7 @@ generate_s4u_user_token(wchar_t* user_cpn, int impersonation) {
|
|||
wcscpy_s(domain_upn, ARRAYSIZE(domain_upn), user_cpn);
|
||||
}
|
||||
else
|
||||
debug3("%s: Successfully discovered principal name: '%ls'=>'%ls'", user_cpn, domain_upn);
|
||||
debug3("%s: Successfully discovered principal name: '%ls'=>'%ls'", __FUNCTION__, user_cpn, domain_upn);
|
||||
|
||||
KERB_S4U_LOGON *s4u_logon;
|
||||
logon_info_size = sizeof(KERB_S4U_LOGON);
|
||||
|
@ -314,9 +314,10 @@ HANDLE generate_sshd_virtual_token();
|
|||
HANDLE generate_sshd_token_as_nonsystem();
|
||||
|
||||
HANDLE
|
||||
get_user_token(char* user, int impersonation) {
|
||||
get_user_token(const char* user, int impersonation) {
|
||||
HANDLE token = NULL;
|
||||
wchar_t *user_utf16 = NULL;
|
||||
PSID user_sid = NULL, process_sid = NULL;
|
||||
|
||||
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
|
||||
debug("out of memory");
|
||||
|
@ -329,36 +330,68 @@ get_user_token(char* user, int impersonation) {
|
|||
goto done;
|
||||
|
||||
if ((token = generate_sshd_virtual_token()) == 0)
|
||||
error("unable to generate sshd virtual token, ensure sshd service has TCB privileges");
|
||||
error("%s - unable to generate sshd virtual token, ensure sshd service has TCB privileges", __func__);
|
||||
|
||||
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);
|
||||
process_sid = get_sid(NULL);
|
||||
user_sid = get_sid(user);
|
||||
HANDLE t1;
|
||||
|
||||
if (user_sid == NULL && get_custom_lsa_package())
|
||||
debug3("%s - i am running as %s, returning process token since custom lsa is configured", __func__, user);
|
||||
else if (EqualSid(process_sid, user_sid))
|
||||
debug3("%s - i am running as %s, returning process token", __func__, user);
|
||||
else {
|
||||
debug("%s - unable to generate user token for %s as i am not running as system", __func__, user);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS_P, &t1)) {
|
||||
error("%s - OpenProcessToken failed with %d", __func__, GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (impersonation) {
|
||||
token = t1;
|
||||
goto done;
|
||||
} else if (!DuplicateToken(t1, SecurityIdentification, &token))
|
||||
error("%s - DuplicateToken failed with %d", __func__, GetLastError());
|
||||
|
||||
CloseHandle(t1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* is this is a virtual user to be authenticated via custom lsa provider ? */
|
||||
if ((user_sid = get_sid(user)) == NULL && get_custom_lsa_package() && !impersonation) {
|
||||
if ((token = process_custom_lsa_auth(user, "", get_custom_lsa_package())) == NULL)
|
||||
error("%s - unable to generate identity token for %s from custom lsa provider: %s",
|
||||
__func__, user, get_custom_lsa_package());
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((token = generate_s4u_user_token(user_utf16, impersonation)) == 0) {
|
||||
debug3("unable to generate token for user %ls", user_utf16);
|
||||
debug3("%s - unable to generate token for user %ls", __func__, user_utf16);
|
||||
/* work around for https://github.com/PowerShell/Win32-OpenSSH/issues/727 by doing a fake login */
|
||||
pLogonUserExExW(L"FakeUser", L"FakeDomain", L"FakePasswd",
|
||||
LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL);
|
||||
if ((token = generate_s4u_user_token(user_utf16, impersonation)) == 0) {
|
||||
error("unable to generate token on 2nd attempt for user %ls", user_utf16);
|
||||
goto done;
|
||||
}
|
||||
if ((token = generate_s4u_user_token(user_utf16, impersonation)) == 0)
|
||||
error("%s - unable to generate token on 2nd attempt for user %ls", __func__, user_utf16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (user_utf16)
|
||||
free(user_utf16);
|
||||
|
||||
if (user_sid)
|
||||
free(user_sid);
|
||||
|
||||
if (process_sid)
|
||||
free(process_sid);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -428,7 +461,7 @@ char* LSAMappingErrorDetails[] = {
|
|||
|
||||
/* returns 0 on success -1 on failure */
|
||||
int
|
||||
AddSidMappingToLsa(PUNICODE_STRING domain_name,
|
||||
add_sid_mapping_to_lsa(PUNICODE_STRING domain_name,
|
||||
PUNICODE_STRING account_name,
|
||||
PSID sid)
|
||||
{
|
||||
|
@ -470,7 +503,7 @@ AddSidMappingToLsa(PUNICODE_STRING domain_name,
|
|||
}
|
||||
|
||||
|
||||
int RemoveVirtualAccountLSAMapping(PUNICODE_STRING domain_name,
|
||||
int remove_virtual_account_lsa_mapping(PUNICODE_STRING domain_name,
|
||||
PUNICODE_STRING account_name)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -498,7 +531,7 @@ int RemoveVirtualAccountLSAMapping(PUNICODE_STRING domain_name,
|
|||
}
|
||||
|
||||
void
|
||||
InitUnicodeString(PUNICODE_STRING dest, PWSTR source)
|
||||
init_unicode_string(PUNICODE_STRING dest, PWSTR source)
|
||||
{
|
||||
dest->Buffer = source;
|
||||
dest->Length = (USHORT)(wcslen(source) * sizeof(wchar_t));
|
||||
|
@ -546,10 +579,10 @@ HANDLE generate_sshd_virtual_token()
|
|||
|
||||
StringCchPrintfW(va_name, 32, L"%s_%d", L"sshd", GetCurrentProcessId());
|
||||
|
||||
InitUnicodeString(&svcLogonRight, L"SeServiceLogonRight");
|
||||
InitUnicodeString(&domain, VIRTUALUSER_DOMAIN);
|
||||
InitUnicodeString(&group, VIRTUALUSER_GROUP_NAME);
|
||||
InitUnicodeString(&account, va_name);
|
||||
init_unicode_string(&svcLogonRight, L"SeServiceLogonRight");
|
||||
init_unicode_string(&domain, VIRTUALUSER_DOMAIN);
|
||||
init_unicode_string(&group, VIRTUALUSER_GROUP_NAME);
|
||||
init_unicode_string(&account, va_name);
|
||||
|
||||
/* Initialize SIDs */
|
||||
/* domain SID - S-1-5-111 */
|
||||
|
@ -577,20 +610,20 @@ HANDLE generate_sshd_virtual_token()
|
|||
}
|
||||
|
||||
/* Map the domain SID */
|
||||
if (AddSidMappingToLsa(&domain, NULL, sid_domain) != 0) {
|
||||
debug3("AddSidMappingToLsa failed to map the domain Sid");
|
||||
if (add_sid_mapping_to_lsa(&domain, NULL, sid_domain) != 0) {
|
||||
debug3("add_sid_mapping_to_lsa failed to map the domain Sid");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Map the group SID */
|
||||
if (AddSidMappingToLsa(&domain, &group, sid_group) != 0) {
|
||||
debug3("AddSidMappingToLsa failed to map the group Sid");
|
||||
if (add_sid_mapping_to_lsa(&domain, &group, sid_group) != 0) {
|
||||
debug3("add_sid_mapping_to_lsa failed to map the group Sid");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Map the user SID */
|
||||
if (AddSidMappingToLsa(&domain, &account, sid_user) != 0) {
|
||||
debug3("AddSidMappingToLsa failed to map the user Sid");
|
||||
if (add_sid_mapping_to_lsa(&domain, &account, sid_user) != 0) {
|
||||
debug3("add_sid_mapping_to_lsa failed to map the user Sid");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -625,7 +658,7 @@ HANDLE generate_sshd_virtual_token()
|
|||
CloseHandle(va_token);
|
||||
|
||||
cleanup:
|
||||
RemoveVirtualAccountLSAMapping(&domain, &account);
|
||||
remove_virtual_account_lsa_mapping(&domain, &account);
|
||||
|
||||
/* attempt to remove virtual account permissions if previous add succeeded */
|
||||
if (lsa_add_ret == STATUS_SUCCESS)
|
||||
|
@ -645,5 +678,41 @@ cleanup:
|
|||
}
|
||||
|
||||
|
||||
/* returns NULL if not configured, fatal exists on error */
|
||||
char *
|
||||
get_custom_lsa_package()
|
||||
{
|
||||
static char *s_lsa_auth_pkg = NULL;
|
||||
static int s_processed = 0;
|
||||
wchar_t *lsa_auth_pkg_w = NULL;
|
||||
int lsa_auth_pkg_len = 0;
|
||||
HKEY reg_key = 0;
|
||||
REGSAM mask = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY;
|
||||
|
||||
if (s_processed)
|
||||
return s_lsa_auth_pkg;
|
||||
|
||||
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\OpenSSH", 0, mask, ®_key) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, NULL, &lsa_auth_pkg_len) == ERROR_SUCCESS)) {
|
||||
lsa_auth_pkg_w = (wchar_t *)malloc(lsa_auth_pkg_len); // lsa_auth_pkg_len includes the null terminating character.
|
||||
if (!lsa_auth_pkg_w)
|
||||
fatal("%s: out of memory", __func__);
|
||||
|
||||
memset(lsa_auth_pkg_w, 0, lsa_auth_pkg_len);
|
||||
if (RegQueryValueExW(reg_key, L"LSAAuthenticationPackage", 0, NULL, (LPBYTE)lsa_auth_pkg_w, &lsa_auth_pkg_len) == ERROR_SUCCESS) {
|
||||
s_lsa_auth_pkg = utf16_to_utf8(lsa_auth_pkg_w);
|
||||
if (!s_lsa_auth_pkg)
|
||||
fatal("utf16_to_utf8 failed to convert lsa_auth_pkg_w:%ls", lsa_auth_pkg_w);
|
||||
}
|
||||
}
|
||||
|
||||
if (lsa_auth_pkg_w)
|
||||
free(lsa_auth_pkg_w);
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
|
||||
s_processed = 1;
|
||||
return s_lsa_auth_pkg;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
|
@ -33,10 +33,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#ifdef WINDOWS
|
||||
#include <lm.h>
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "groupaccess.h"
|
||||
|
@ -53,14 +49,6 @@ static char **groups_byname;
|
|||
int
|
||||
ga_init(const char *user, gid_t base)
|
||||
{
|
||||
#ifdef WINDOWS
|
||||
ngroups = 0;
|
||||
groups_byname = NULL;
|
||||
|
||||
groups_byname = getusergroups(user, &ngroups);
|
||||
return ngroups;
|
||||
#else /* !WINDOWS */
|
||||
|
||||
gid_t *groups_bygid;
|
||||
int i, j;
|
||||
struct group *gr;
|
||||
|
@ -83,7 +71,6 @@ ga_init(const char *user, gid_t base)
|
|||
groups_byname[j++] = xstrdup(gr->gr_name);
|
||||
free(groups_bygid);
|
||||
return (ngroups = j);
|
||||
#endif /* !WINDOWS */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -577,8 +577,10 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
|
|||
if (!in_chroot)
|
||||
chdir(s->pw->pw_dir);
|
||||
|
||||
if (s->is_subsystem >= SUBSYSTEM_INT_SFTP_ERROR)
|
||||
if (s->is_subsystem >= SUBSYSTEM_INT_SFTP_ERROR) {
|
||||
command = "echo This service allows sftp connections only.";
|
||||
pty = 0;
|
||||
}
|
||||
|
||||
exec_command = build_session_commandline(s->pw->pw_shell, shell_command_option, command, pty);
|
||||
if (exec_command == NULL)
|
||||
|
|
44
sshd.c
44
sshd.c
|
@ -712,6 +712,40 @@ recv_hostkeys_state(int fd)
|
|||
buffer_free(m);
|
||||
}
|
||||
|
||||
static void
|
||||
send_autxctx_state(Authctxt *auth, int fd)
|
||||
{
|
||||
struct sshbuf *m;
|
||||
int r;
|
||||
|
||||
if ((m = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if ((r = sshbuf_put_cstring(m, auth->pw->pw_name)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
|
||||
if (ssh_msg_send(fd, 0, m) == -1)
|
||||
fatal("%s: ssh_msg_send failed", __func__);
|
||||
|
||||
sshbuf_free(m);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_autxctx_state(Authctxt *auth, int fd)
|
||||
{
|
||||
Buffer m;
|
||||
u_int len;
|
||||
|
||||
buffer_init(&m);
|
||||
|
||||
if (ssh_msg_recv(fd, &m) == -1)
|
||||
fatal("%s: ssh_msg_recv failed", __func__);
|
||||
if (buffer_get_char(&m) != 0)
|
||||
fatal("%s: recv_keystate version mismatch", __func__);
|
||||
|
||||
auth->user = xstrdup(buffer_get_cstring(&m, &len));
|
||||
buffer_free(&m);
|
||||
}
|
||||
|
||||
static char**
|
||||
privsep_child_cmdline(int authenticated)
|
||||
{
|
||||
|
@ -739,13 +773,8 @@ privsep_preauth(Authctxt *authctxt)
|
|||
|
||||
#ifdef FORK_NOT_SUPPORTED
|
||||
if (privsep_auth_child) {
|
||||
struct connection_info *ci = get_connection_info(1, options.use_dns);
|
||||
|
||||
authctxt->pw = getpwuid(geteuid());
|
||||
ci->user = authctxt->pw->pw_name;
|
||||
parse_server_match_config(&options, ci);
|
||||
log_change_level(options.log_level);
|
||||
process_permitopen(active_state, &options);
|
||||
recv_autxctx_state(authctxt, PRIVSEP_MONITOR_FD);
|
||||
authctxt->pw = getpwnamallow(authctxt->user);
|
||||
authctxt->valid = 1;
|
||||
return 1;
|
||||
}
|
||||
|
@ -907,6 +936,7 @@ privsep_postauth(Authctxt *authctxt)
|
|||
send_config_state(pmonitor->m_sendfd, &cfg);
|
||||
send_hostkeys_state(pmonitor->m_sendfd);
|
||||
send_idexch_state(pmonitor->m_sendfd);
|
||||
send_autxctx_state(authctxt, pmonitor->m_sendfd);
|
||||
monitor_send_keystate(pmonitor);
|
||||
monitor_clear_keystate(pmonitor);
|
||||
monitor_child_postauth(pmonitor);
|
||||
|
|
Loading…
Reference in New Issue