diff options
Diffstat (limited to 'winsup/cygwin/sec_auth.cc')
-rw-r--r-- | winsup/cygwin/sec_auth.cc | 1348 |
1 files changed, 0 insertions, 1348 deletions
diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc deleted file mode 100644 index 2906b715d..000000000 --- a/winsup/cygwin/sec_auth.cc +++ /dev/null @@ -1,1348 +0,0 @@ -/* sec_auth.cc: NT authentication functions - - Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include <stdlib.h> -#include <wchar.h> -#include <wininet.h> -#include <ntsecapi.h> -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "cygheap.h" -#include "registry.h" -#include "ntdll.h" -#include "tls_pbuf.h" -#include <lm.h> -#include <iptypes.h> -#include <wininet.h> -#include <userenv.h> -#include "cyglsa.h" -#include "cygserver_setpwd.h" -#include <cygwin/version.h> - -/* Starting with Windows Vista, the token returned by system functions - is a restricted token. The full admin token is linked to it and can - be fetched with NtQueryInformationToken. This function returns the original - token on pre-Vista, and the elevated token on Vista++ if it's available, - the original token otherwise. The token handle is also made inheritable - since that's necessary anyway. */ -static HANDLE -get_full_privileged_inheritable_token (HANDLE token) -{ - if (wincap.has_mandatory_integrity_control ()) - { - TOKEN_LINKED_TOKEN linked; - ULONG size; - - /* When fetching the linked token without TCB privs, then the linked - token is not a primary token, only an impersonation token, which is - not suitable for CreateProcessAsUser. Converting it to a primary - token using DuplicateTokenEx does NOT work for the linked token in - this case. So we have to switch on TCB privs to get a primary token. - This is generally performed in the calling functions. */ - if (NT_SUCCESS (NtQueryInformationToken (token, TokenLinkedToken, - (PVOID) &linked, sizeof linked, - &size))) - { - debug_printf ("Linked Token: %p", linked.LinkedToken); - if (linked.LinkedToken) - { - TOKEN_TYPE type; - - /* At this point we don't know if the user actually had TCB - privileges. Check if the linked token is a primary token. - If not, just return the original token. */ - if (NT_SUCCESS (NtQueryInformationToken (linked.LinkedToken, - TokenType, (PVOID) &type, - sizeof type, &size)) - && type != TokenPrimary) - debug_printf ("Linked Token is not a primary token!"); - else - { - CloseHandle (token); - token = linked.LinkedToken; - } - } - } - } - if (!SetHandleInformation (token, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) - { - __seterrno (); - CloseHandle (token); - token = NULL; - } - return token; -} - -void -set_imp_token (HANDLE token, int type) -{ - debug_printf ("set_imp_token (%p, %d)", token, type); - cygheap->user.external_token = (token == INVALID_HANDLE_VALUE - ? NO_IMPERSONATION : token); - cygheap->user.ext_token_is_restricted = (type == CW_TOKEN_RESTRICTED); -} - -extern "C" void -cygwin_set_impersonation_token (const HANDLE hToken) -{ - set_imp_token (hToken, CW_TOKEN_IMPERSONATION); -} - -void -extract_nt_dom_user (const struct passwd *pw, PWCHAR domain, PWCHAR user) -{ - - cygsid psid; - DWORD ulen = UNLEN + 1; - DWORD dlen = MAX_DOMAIN_NAME_LEN + 1; - SID_NAME_USE use; - - debug_printf ("pw_gecos %p (%s)", pw->pw_gecos, pw->pw_gecos); - - if (psid.getfrompw (pw) - && LookupAccountSidW (NULL, psid, user, &ulen, domain, &dlen, &use)) - return; - - char *d, *u, *c; - domain[0] = L'\0'; - sys_mbstowcs (user, UNLEN + 1, pw->pw_name); - if ((d = strstr (pw->pw_gecos, "U-")) != NULL && - (d == pw->pw_gecos || d[-1] == ',')) - { - c = strchrnul (d + 2, ','); - if ((u = strchrnul (d + 2, '\\')) >= c) - u = d + 1; - else if (u - d <= MAX_DOMAIN_NAME_LEN + 2) - sys_mbstowcs (domain, MAX_DOMAIN_NAME_LEN + 1, d + 2, u - d - 1); - if (c - u <= UNLEN + 1) - sys_mbstowcs (user, UNLEN + 1, u + 1, c - u); - } -} - -extern "C" HANDLE -cygwin_logon_user (const struct passwd *pw, const char *password) -{ - if (!pw || !password) - { - set_errno (EINVAL); - return INVALID_HANDLE_VALUE; - } - - WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1]; - WCHAR nt_user[UNLEN + 1]; - PWCHAR passwd; - HANDLE hToken; - tmp_pathbuf tp; - - extract_nt_dom_user (pw, nt_domain, nt_user); - debug_printf ("LogonUserW (%W, %W, ...)", nt_user, nt_domain); - sys_mbstowcs (passwd = tp.w_get (), NT_MAX_PATH, password); - /* CV 2005-06-08: LogonUser should run under the primary process token, - otherwise it returns with ERROR_ACCESS_DENIED. */ - cygheap->user.deimpersonate (); - if (!LogonUserW (nt_user, *nt_domain ? nt_domain : NULL, passwd, - LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, - &hToken)) - { - __seterrno (); - hToken = INVALID_HANDLE_VALUE; - } - else - { - /* See the comment in get_full_privileged_inheritable_token for a - description why we enable TCB privileges here. */ - push_self_privilege (SE_TCB_PRIVILEGE, true); - hToken = get_full_privileged_inheritable_token (hToken); - pop_self_privilege (); - if (!hToken) - hToken = INVALID_HANDLE_VALUE; - } - RtlSecureZeroMemory (passwd, NT_MAX_PATH); - cygheap->user.reimpersonate (); - debug_printf ("%R = logon_user(%s,...)", hToken, pw->pw_name); - return hToken; -} - -/* The buffer path points to should be at least MAX_PATH bytes. */ -PWCHAR -get_user_profile_directory (PCWSTR sidstr, PWCHAR path, SIZE_T path_len) -{ - if (!sidstr || !path) - return NULL; - - UNICODE_STRING buf; - tmp_pathbuf tp; - tp.u_get (&buf); - NTSTATUS status; - - RTL_QUERY_REGISTRY_TABLE tab[2] = { - { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT - | RTL_QUERY_REGISTRY_REQUIRED, - L"ProfileImagePath", &buf, REG_NONE, NULL, 0 }, - { NULL, 0, NULL, NULL, 0, NULL, 0 } - }; - - WCHAR key[wcslen (sidstr) + 16]; - wcpcpy (wcpcpy (key, L"ProfileList\\"), sidstr); - status = RtlQueryRegistryValues (RTL_REGISTRY_WINDOWS_NT, key, tab, - NULL, NULL); - if (!NT_SUCCESS (status) || buf.Length == 0) - { - debug_printf ("ProfileImagePath for %W not found, status %y", sidstr, - status); - return NULL; - } - ExpandEnvironmentStringsW (buf.Buffer, path, path_len); - debug_printf ("ProfileImagePath for %W: %W", sidstr, path); - return path; -} - -/* The CreateProfile prototype is for some reason missing in our w32api headers, - even though it's defined upstream since Dec-2013. */ -extern "C" { - HRESULT WINAPI CreateProfile (LPCWSTR pszUserSid, LPCWSTR pszUserName, - LPWSTR pszProfilePath, DWORD cchProfilePath); -} - -/* Load user profile if it's not already loaded. If the user profile doesn't - exist on the machine, and if we're running Vista or later, try to create it. - - Return a handle to the loaded user registry hive only if it got actually - loaded here, not if it already existed. There's no reliable way to know - when to unload the hive yet, so we're leaking this registry handle for now. - TODO: Try to find a way to reliably unload the user profile again. */ -HANDLE -load_user_profile (HANDLE token, struct passwd *pw, cygpsid &usersid) -{ - WCHAR domain[DNLEN + 1]; - WCHAR username[UNLEN + 1]; - WCHAR sid[128]; - HKEY hkey; - WCHAR userpath[MAX_PATH]; - PROFILEINFOW pi; - WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; - NET_API_STATUS nas = NERR_UserNotFound; - PUSER_INFO_3 ui; - - extract_nt_dom_user (pw, domain, username); - usersid.string (sid); - debug_printf ("user: <%W> <%W>", username, sid); - /* Check if user hive is already loaded. */ - if (!RegOpenKeyExW (HKEY_USERS, sid, 0, KEY_READ, &hkey)) - { - debug_printf ("User registry hive for %W already exists", username); - RegCloseKey (hkey); - return NULL; - } - /* Check if the local profile dir has already been created. */ - if (!get_user_profile_directory (sid, userpath, MAX_PATH)) - { - /* No, try to create it. This function exists only on Vista and later. */ - HRESULT res = CreateProfile (sid, username, userpath, MAX_PATH); - if (res != S_OK) - { - /* If res is 1 (S_FALSE), autoloading failed (XP or 2K3). */ - if (res != S_FALSE) - debug_printf ("CreateProfile, HRESULT %x", res); - return NULL; - } - } - /* Fill PROFILEINFO */ - memset (&pi, 0, sizeof pi); - pi.dwSize = sizeof pi; - pi.dwFlags = PI_NOUI; - pi.lpUserName = username; - /* Check if user has a roaming profile and fill in lpProfilePath, if so. */ - if (get_logon_server (domain, server, DS_IS_FLAT_NAME)) - { - nas = NetUserGetInfo (server, username, 3, (PBYTE *) &ui); - if (NetUserGetInfo (server, username, 3, (PBYTE *) &ui) != NERR_Success) - debug_printf ("NetUserGetInfo, %u", nas); - else if (ui->usri3_profile && *ui->usri3_profile) - pi.lpProfilePath = ui->usri3_profile; - } - - if (!LoadUserProfileW (token, &pi)) - debug_printf ("LoadUserProfileW, %E"); - /* Free buffer created by NetUserGetInfo */ - if (nas == NERR_Success) - NetApiBufferFree (ui); - return pi.hProfile; -} - -HANDLE -lsa_open_policy (PWCHAR server, ACCESS_MASK access) -{ - LSA_UNICODE_STRING srvbuf; - PLSA_UNICODE_STRING srv = NULL; - static LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 }; - HANDLE lsa; - - if (server) - { - srv = &srvbuf; - RtlInitUnicodeString (srv, server); - } - NTSTATUS status = LsaOpenPolicy (srv, &oa, access, &lsa); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - lsa = NULL; - } - return lsa; -} - -void -lsa_close_policy (HANDLE lsa) -{ - if (lsa) - LsaClose (lsa); -} - -bool -get_logon_server (PWCHAR domain, WCHAR *server, ULONG flags) -{ - DWORD ret; - PDOMAIN_CONTROLLER_INFOW pci; - - /* Empty domain is interpreted as local system */ - if (cygheap->dom.init () - && (!domain[0] - || !wcscasecmp (domain, cygheap->dom.account_flat_name ()))) - { - wcpcpy (wcpcpy (server, L"\\\\"), cygheap->dom.account_flat_name ()); - return true; - } - - /* Try to get any available domain controller for this domain */ - ret = DsGetDcNameW (NULL, domain, NULL, NULL, flags, &pci); - if (ret == ERROR_SUCCESS) - { - wcscpy (server, pci->DomainControllerName); - NetApiBufferFree (pci); - debug_printf ("DC: server: %W", server); - return true; - } - __seterrno_from_win_error (ret); - return false; -} - -static bool -get_user_groups (WCHAR *logonserver, cygsidlist &grp_list, - PWCHAR user, PWCHAR domain) -{ - WCHAR dgroup[MAX_DOMAIN_NAME_LEN + GNLEN + 2]; - LPGROUP_USERS_INFO_0 buf; - DWORD cnt, tot, len; - NET_API_STATUS ret; - - /* Look only on logonserver */ - ret = NetUserGetGroups (logonserver, user, 0, (LPBYTE *) &buf, - MAX_PREFERRED_LENGTH, &cnt, &tot); - if (ret) - { - __seterrno_from_win_error (ret); - /* It's no error when the user name can't be found. - It's also no error if access has been denied. Yes, sounds weird, but - keep in mind that ERROR_ACCESS_DENIED means the current user has no - permission to access the AD user information. However, if we return - an error, Cygwin will call DsGetDcName with DS_FORCE_REDISCOVERY set - to ask for another server. This is not only time consuming, it's also - useless; the next server will return access denied again. */ - return ret == NERR_UserNotFound || ret == ERROR_ACCESS_DENIED; - } - - len = wcslen (domain); - wcscpy (dgroup, domain); - dgroup[len++] = L'\\'; - - for (DWORD i = 0; i < cnt; ++i) - { - cygsid gsid; - DWORD glen = SECURITY_MAX_SID_SIZE; - WCHAR dom[MAX_DOMAIN_NAME_LEN + 1]; - DWORD dlen = sizeof (dom); - SID_NAME_USE use = SidTypeInvalid; - - wcscpy (dgroup + len, buf[i].grui0_name); - if (!LookupAccountNameW (NULL, dgroup, gsid, &glen, dom, &dlen, &use)) - debug_printf ("LookupAccountName(%W), %E", dgroup); - else if (well_known_sid_type (use)) - grp_list *= gsid; - else if (legal_sid_type (use)) - grp_list += gsid; - else - debug_printf ("Global group %W invalid. Use: %u", dgroup, use); - } - - NetApiBufferFree (buf); - return true; -} - -static bool -get_user_local_groups (PWCHAR logonserver, PWCHAR domain, - cygsidlist &grp_list, PWCHAR user) -{ - LPLOCALGROUP_INFO_0 buf; - DWORD cnt, tot; - NET_API_STATUS ret; - - ret = NetUserGetLocalGroups (logonserver, user, 0, LG_INCLUDE_INDIRECT, - (LPBYTE *) &buf, MAX_PREFERRED_LENGTH, - &cnt, &tot); - if (ret) - { - __seterrno_from_win_error (ret); - return false; - } - - WCHAR domlocal_grp[MAX_DOMAIN_NAME_LEN + GNLEN + 2]; - WCHAR builtin_grp[2 * GNLEN + 2]; - PWCHAR dg_ptr, bg_ptr = NULL; - SID_NAME_USE use; - - dg_ptr = wcpcpy (domlocal_grp, domain); - *dg_ptr++ = L'\\'; - - for (DWORD i = 0; i < cnt; ++i) - { - cygsid gsid; - DWORD glen = SECURITY_MAX_SID_SIZE; - WCHAR dom[MAX_DOMAIN_NAME_LEN + 1]; - DWORD domlen = MAX_DOMAIN_NAME_LEN + 1; - - use = SidTypeInvalid; - wcscpy (dg_ptr, buf[i].lgrpi0_name); - if (LookupAccountNameW (NULL, domlocal_grp, gsid, &glen, - dom, &domlen, &use)) - { - if (well_known_sid_type (use)) - grp_list *= gsid; - else if (legal_sid_type (use)) - grp_list += gsid; - else - debug_printf ("Rejecting local %W. use: %u", dg_ptr, use); - } - else if (GetLastError () == ERROR_NONE_MAPPED) - { - /* Check if it's a builtin group. */ - if (!bg_ptr) - { - /* Retrieve name of builtin group from system since it's - localized. */ - glen = 2 * GNLEN + 2; - if (!LookupAccountSidW (NULL, well_known_builtin_sid, - builtin_grp, &glen, domain, &domlen, &use)) - debug_printf ("LookupAccountSid(BUILTIN), %E"); - else - { - bg_ptr = builtin_grp + wcslen (builtin_grp); - bg_ptr = wcpcpy (builtin_grp, L"\\"); - } - } - if (bg_ptr) - { - wcscpy (bg_ptr, dg_ptr); - glen = SECURITY_MAX_SID_SIZE; - domlen = MAX_DOMAIN_NAME_LEN + 1; - if (LookupAccountNameW (NULL, builtin_grp, gsid, &glen, - dom, &domlen, &use)) - { - if (!legal_sid_type (use)) - debug_printf ("Rejecting local %W. use: %u", dg_ptr, use); - else - grp_list *= gsid; - } - else - debug_printf ("LookupAccountName(%W), %E", builtin_grp); - } - } - else - debug_printf ("LookupAccountName(%W), %E", domlocal_grp); - } - NetApiBufferFree (buf); - return true; -} - -static bool -sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid) -{ - if (!grps) - return false; - for (DWORD i = 0; i < grps->GroupCount; ++i) - if (sid == grps->Groups[i].Sid) - return true; - return false; -} - -static void -get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, - LUID auth_luid, int &auth_pos) -{ - auth_pos = -1; - if (my_grps) - { - grp_list += well_known_local_sid; - if (wincap.has_console_logon_sid ()) - grp_list += well_known_console_logon_sid; - if (sid_in_token_groups (my_grps, well_known_dialup_sid)) - grp_list *= well_known_dialup_sid; - if (sid_in_token_groups (my_grps, well_known_network_sid)) - grp_list *= well_known_network_sid; - if (sid_in_token_groups (my_grps, well_known_batch_sid)) - grp_list *= well_known_batch_sid; - grp_list *= well_known_interactive_sid; -#if 0 - /* Don't add the SERVICE group when switching the user context. - That's much too dangerous, since the service group adds the - SE_IMPERSONATE_NAME privilege to the user. After all, the - process started with this token is not the service process - anymore anyway. */ - if (sid_in_token_groups (my_grps, well_known_service_sid)) - grp_list *= well_known_service_sid; -#endif - if (sid_in_token_groups (my_grps, well_known_this_org_sid)) - grp_list *= well_known_this_org_sid; - grp_list *= well_known_users_sid; - } - else - { - grp_list += well_known_local_sid; - grp_list *= well_known_interactive_sid; - grp_list *= well_known_users_sid; - } - if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */ - { - for (DWORD i = 0; i < my_grps->GroupCount; ++i) - if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID) - { - grp_list += my_grps->Groups[i].Sid; - auth_pos = grp_list.count () - 1; - break; - } - } -} - -bool -get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw) -{ - WCHAR user[UNLEN + 1]; - WCHAR domain[MAX_DOMAIN_NAME_LEN + 1]; - WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; - DWORD ulen = UNLEN + 1; - DWORD dlen = MAX_DOMAIN_NAME_LEN + 1; - SID_NAME_USE use; - - if (well_known_system_sid == usersid) - { - grp_list *= well_known_admins_sid; - return true; - } - - grp_list *= well_known_world_sid; - grp_list *= well_known_authenticated_users_sid; - - if (!LookupAccountSidW (NULL, usersid, user, &ulen, domain, &dlen, &use)) - { - __seterrno (); - return false; - } - /* If the SID does NOT start with S-1-5-21, the domain is some builtin - domain. The search for a logon server and fetching group accounts - is moot. */ - if (sid_id_auth (usersid) == 5 /* SECURITY_NT_AUTHORITY */ - && sid_sub_auth (usersid, 0) == SECURITY_NT_NON_UNIQUE - && get_logon_server (domain, server, DS_IS_FLAT_NAME)) - { - get_user_groups (server, grp_list, user, domain); - get_user_local_groups (server, domain, grp_list, user); - } - return true; -} - -static bool -get_initgroups_sidlist (cygsidlist &grp_list, - PSID usersid, PSID pgrpsid, struct passwd *pw, - PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos) -{ - grp_list *= well_known_world_sid; - grp_list *= well_known_authenticated_users_sid; - if (well_known_system_sid == usersid) - auth_pos = -1; - else - get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos); - if (!get_server_groups (grp_list, usersid, pw)) - return false; - - /* special_pgrp true if pgrpsid is not in normal groups */ - grp_list += pgrpsid; - return true; -} - -static void -get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw, - PTOKEN_GROUPS my_grps, user_groups &groups, - LUID auth_luid, int &auth_pos) -{ - tmp_list *= well_known_world_sid; - tmp_list *= well_known_authenticated_users_sid; - get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos); - get_server_groups (tmp_list, usersid, pw); - for (int gidx = 0; gidx < groups.sgsids.count (); gidx++) - tmp_list += groups.sgsids.sids[gidx]; - tmp_list += groups.pgsid; -} - -static ULONG sys_privs[] = { - SE_CREATE_TOKEN_PRIVILEGE, - SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, - SE_LOCK_MEMORY_PRIVILEGE, - SE_INCREASE_QUOTA_PRIVILEGE, - SE_TCB_PRIVILEGE, - SE_SECURITY_PRIVILEGE, - SE_TAKE_OWNERSHIP_PRIVILEGE, - SE_LOAD_DRIVER_PRIVILEGE, - SE_SYSTEM_PROFILE_PRIVILEGE, /* Vista ONLY */ - SE_SYSTEMTIME_PRIVILEGE, - SE_PROF_SINGLE_PROCESS_PRIVILEGE, - SE_INC_BASE_PRIORITY_PRIVILEGE, - SE_CREATE_PAGEFILE_PRIVILEGE, - SE_CREATE_PERMANENT_PRIVILEGE, - SE_BACKUP_PRIVILEGE, - SE_RESTORE_PRIVILEGE, - SE_SHUTDOWN_PRIVILEGE, - SE_DEBUG_PRIVILEGE, - SE_AUDIT_PRIVILEGE, - SE_SYSTEM_ENVIRONMENT_PRIVILEGE, - SE_CHANGE_NOTIFY_PRIVILEGE, - SE_UNDOCK_PRIVILEGE, - SE_MANAGE_VOLUME_PRIVILEGE, - SE_IMPERSONATE_PRIVILEGE, - SE_CREATE_GLOBAL_PRIVILEGE, - SE_INCREASE_WORKING_SET_PRIVILEGE, - SE_TIME_ZONE_PRIVILEGE, - SE_CREATE_SYMBOLIC_LINK_PRIVILEGE -}; - -#define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs) - -static PTOKEN_PRIVILEGES -get_system_priv_list (size_t &size) -{ - ULONG max_idx = 0; - while (max_idx < SYSTEM_PRIVILEGES_COUNT - && sys_privs[max_idx] != wincap.max_sys_priv ()) - ++max_idx; - if (max_idx >= SYSTEM_PRIVILEGES_COUNT) - api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs", - wincap.max_sys_priv ()); - size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES); - PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size); - if (!privs) - { - debug_printf ("malloc (system_privs) failed."); - return NULL; - } - privs->PrivilegeCount = 0; - for (ULONG i = 0; i <= max_idx; ++i) - { - privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L; - privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i]; - privs->Privileges[privs->PrivilegeCount].Attributes = - SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; - ++privs->PrivilegeCount; - } - return privs; -} - -static PTOKEN_PRIVILEGES -get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, - size_t &size, cygpsid *mandatory_integrity_sid) -{ - PLSA_UNICODE_STRING privstrs; - ULONG cnt; - PTOKEN_PRIVILEGES privs = NULL; - - if (usersid == well_known_system_sid) - { - if (mandatory_integrity_sid) - *mandatory_integrity_sid = mandatory_system_integrity_sid; - return get_system_priv_list (size); - } - - if (mandatory_integrity_sid) - *mandatory_integrity_sid = mandatory_medium_integrity_sid; - - for (int grp = -1; grp < grp_list.count (); ++grp) - { - if (grp == -1) - { - if (LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt) - != STATUS_SUCCESS) - continue; - } - else if (LsaEnumerateAccountRights (lsa, grp_list.sids[grp], - &privstrs, &cnt) != STATUS_SUCCESS) - continue; - for (ULONG i = 0; i < cnt; ++i) - { - LUID priv; - PTOKEN_PRIVILEGES tmp; - DWORD tmp_count; - bool high_integrity; - - if (!privilege_luid (privstrs[i].Buffer, priv, high_integrity)) - continue; - - if (privs) - { - DWORD pcnt = privs->PrivilegeCount; - LUID_AND_ATTRIBUTES *p = privs->Privileges; - for (; pcnt > 0; --pcnt, ++p) - if (priv.HighPart == p->Luid.HighPart - && priv.LowPart == p->Luid.LowPart) - goto next_account_right; - } - - tmp_count = privs ? privs->PrivilegeCount : 0; - size = sizeof (DWORD) - + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES); - tmp = (PTOKEN_PRIVILEGES) realloc (privs, size); - if (!tmp) - { - if (privs) - free (privs); - LsaFreeMemory (privstrs); - debug_printf ("realloc (privs) failed."); - return NULL; - } - tmp->PrivilegeCount = tmp_count; - privs = tmp; - privs->Privileges[privs->PrivilegeCount].Luid = priv; - privs->Privileges[privs->PrivilegeCount].Attributes = - SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; - ++privs->PrivilegeCount; - if (mandatory_integrity_sid && high_integrity) - *mandatory_integrity_sid = mandatory_high_integrity_sid; - - next_account_right: - ; - } - LsaFreeMemory (privstrs); - } - return privs; -} - -/* Accept a token if - - the requested usersid matches the TokenUser and - - if setgroups has been called: - the token groups that are listed in /etc/group match the union of - the requested primary and supplementary groups in gsids. - - else the (unknown) implicitly requested supplementary groups and those - in the token are the groups associated with the usersid. We assume - they match and verify only the primary groups. - The requested primary group must appear in the token. - The primary group in the token is a group associated with the usersid, - except if the token is internal and the group is in the token SD - (see create_token). In that latter case that group must match the - requested primary group. */ -bool -verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) -{ - NTSTATUS status; - ULONG size; - bool intern = false; - - if (pintern) - { - TOKEN_SOURCE ts; - status = NtQueryInformationToken (token, TokenSource, &ts, sizeof ts, - &size); - if (!NT_SUCCESS (status)) - debug_printf ("NtQueryInformationToken(), %y", status); - else - *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); - } - /* Verify usersid */ - cygsid tok_usersid (NO_SID); - status = NtQueryInformationToken (token, TokenUser, &tok_usersid, - sizeof tok_usersid, &size); - if (!NT_SUCCESS (status)) - debug_printf ("NtQueryInformationToken(), %y", status); - if (usersid != tok_usersid) - return false; - - /* For an internal token, if setgroups was not called and if the sd group - is not well_known_null_sid, it must match pgrpsid */ - if (intern && !groups.issetgroups ()) - { - const DWORD sd_buf_siz = SECURITY_MAX_SID_SIZE - + sizeof (SECURITY_DESCRIPTOR); - PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz); - cygpsid gsid (NO_SID); - NTSTATUS status; - status = NtQuerySecurityObject (token, GROUP_SECURITY_INFORMATION, - sd_buf, sd_buf_siz, &size); - if (!NT_SUCCESS (status)) - debug_printf ("NtQuerySecurityObject(), %y", status); - else - { - BOOLEAN dummy; - status = RtlGetGroupSecurityDescriptor (sd_buf, (PSID *) &gsid, - &dummy); - if (!NT_SUCCESS (status)) - debug_printf ("RtlGetGroupSecurityDescriptor(), %y", status); - } - if (well_known_null_sid != gsid) - return gsid == groups.pgsid; - } - - PTOKEN_GROUPS my_grps; - - status = NtQueryInformationToken (token, TokenGroups, NULL, 0, &size); - if (!NT_SUCCESS (status) && status != STATUS_BUFFER_TOO_SMALL) - { - debug_printf ("NtQueryInformationToken(token, TokenGroups), %y", status); - return false; - } - my_grps = (PTOKEN_GROUPS) alloca (size); - status = NtQueryInformationToken (token, TokenGroups, my_grps, size, &size); - if (!NT_SUCCESS (status)) - { - debug_printf ("NtQueryInformationToken(my_token, TokenGroups), %y", - status); - return false; - } - - bool sawpg = false; - - if (groups.issetgroups ()) /* setgroups was called */ - { - cygpsid gsid; - bool saw[groups.sgsids.count ()]; - - /* Check that all groups in the setgroups () list are in the token. - A token created through ADVAPI should be allowed to contain more - groups than requested through setgroups(), especially since Vista - and the addition of integrity groups. */ - memset (saw, 0, sizeof(saw)); - for (int gidx = 0; gidx < groups.sgsids.count (); gidx++) - { - gsid = groups.sgsids.sids[gidx]; - if (sid_in_token_groups (my_grps, gsid)) - { - int pos = groups.sgsids.position (gsid); - if (pos >= 0) - saw[pos] = true; - else if (groups.pgsid == gsid) - sawpg = true; - } - } - /* user.sgsids groups must be in the token, except for builtin groups. - These can be different on domain member machines compared to - domain controllers, so these builtin groups may be validly missing - from a token created through password or lsaauth logon. */ - for (int gidx = 0; gidx < groups.sgsids.count (); gidx++) - if (!saw[gidx] - && !groups.sgsids.sids[gidx].is_well_known_sid () - && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx])) - return false; - } - /* The primary group must be in the token */ - return sawpg - || sid_in_token_groups (my_grps, groups.pgsid) - || groups.pgsid == usersid; -} - -HANDLE -create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) -{ - NTSTATUS status; - LSA_HANDLE lsa = NULL; - - cygsidlist tmp_gsids (cygsidlist_auto, 12); - - SECURITY_QUALITY_OF_SERVICE sqos = - { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; - OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos }; - LUID auth_luid = SYSTEM_LUID; - LARGE_INTEGER exp = { QuadPart:INT64_MAX }; - - TOKEN_USER user; - PTOKEN_GROUPS new_tok_gsids = NULL; - PTOKEN_PRIVILEGES privs = NULL; - TOKEN_OWNER owner; - TOKEN_PRIMARY_GROUP pgrp; - TOKEN_DEFAULT_DACL dacl = {}; - TOKEN_SOURCE source; - TOKEN_STATISTICS stats; - memcpy (source.SourceName, "Cygwin.1", 8); - source.SourceIdentifier.HighPart = 0; - source.SourceIdentifier.LowPart = 0x0101; - - HANDLE token = INVALID_HANDLE_VALUE; - HANDLE primary_token = INVALID_HANDLE_VALUE; - - PTOKEN_GROUPS my_tok_gsids = NULL; - cygpsid mandatory_integrity_sid; - ULONG size; - size_t psize = 0; - - /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ - push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true); - - /* Open policy object. */ - if (!(lsa = lsa_open_policy (NULL, POLICY_EXECUTE))) - goto out; - - /* User, owner, primary group. */ - user.User.Sid = usersid; - user.User.Attributes = 0; - owner.Owner = usersid; - - /* Retrieve authentication id and group list from own process. */ - if (hProcToken) - { - /* Switching user context to SYSTEM doesn't inherit the authentication - id of the user account running current process. */ - if (usersid == well_known_system_sid) - /* nothing to do */; - else - { - status = NtQueryInformationToken (hProcToken, TokenStatistics, - &stats, sizeof stats, &size); - if (!NT_SUCCESS (status)) - debug_printf ("NtQueryInformationToken(hProcToken, " - "TokenStatistics), %y", status); - else - auth_luid = stats.AuthenticationId; - } - - /* Retrieving current processes group list to be able to inherit - some important well known group sids. */ - status = NtQueryInformationToken (hProcToken, TokenGroups, NULL, 0, - &size); - if (!NT_SUCCESS (status) && status != STATUS_BUFFER_TOO_SMALL) - debug_printf ("NtQueryInformationToken(hProcToken, TokenGroups), %y", - status); - else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size))) - debug_printf ("malloc (my_tok_gsids) failed."); - else - { - status = NtQueryInformationToken (hProcToken, TokenGroups, - my_tok_gsids, size, &size); - if (!NT_SUCCESS (status)) - { - debug_printf ("NtQueryInformationToken(hProcToken, TokenGroups), " - "%y", status); - free (my_tok_gsids); - my_tok_gsids = NULL; - } - } - } - - /* Create list of groups, the user is member in. */ - int auth_pos; - if (new_groups.issetgroups ()) - get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups, - auth_luid, auth_pos); - else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw, - my_tok_gsids, auth_luid, auth_pos)) - goto out; - - /* Primary group. */ - pgrp.PrimaryGroup = new_groups.pgsid; - - /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ - new_tok_gsids = (PTOKEN_GROUPS) - alloca (sizeof (DWORD) + (tmp_gsids.count () + 1) - * sizeof (SID_AND_ATTRIBUTES)); - new_tok_gsids->GroupCount = tmp_gsids.count (); - for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i) - { - new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i]; - new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY - | SE_GROUP_ENABLED_BY_DEFAULT - | SE_GROUP_ENABLED; - } - if (auth_pos >= 0) - new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; - - /* Retrieve list of privileges of that user. Based on the usersid and - the returned privileges, get_priv_list sets the mandatory_integrity_sid - pointer to the correct MIC SID for UAC. */ - if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize, - &mandatory_integrity_sid))) - goto out; - - /* On systems supporting Mandatory Integrity Control, add the MIC SID. */ - if (wincap.has_mandatory_integrity_control ()) - { - new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes = - SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED; - new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid - = mandatory_integrity_sid; - } - - /* Let's be heroic... */ - status = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, - &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, - &pgrp, &dacl, &source); - if (status) - __seterrno_from_nt_status (status); - else - { - /* Convert to primary token. */ - if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none, - SecurityImpersonation, TokenPrimary, - &primary_token)) - { - __seterrno (); - debug_printf ("DuplicateTokenEx %E"); - } - } - -out: - pop_self_privilege (); - if (token != INVALID_HANDLE_VALUE) - CloseHandle (token); - if (privs) - free (privs); - if (my_tok_gsids) - free (my_tok_gsids); - lsa_close_policy (lsa); - - debug_printf ("%p = create_token ()", primary_token); - return primary_token; -} - -HANDLE -lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw) -{ - cygsidlist tmp_gsids (cygsidlist_auto, 12); - cygpsid pgrpsid; - LSA_STRING name; - HANDLE lsa_hdl = NULL, lsa = NULL; - LSA_OPERATIONAL_MODE sec_mode; - NTSTATUS status, sub_status; - ULONG package_id, size; - LUID auth_luid = SYSTEM_LUID; - struct { - LSA_STRING str; - CHAR buf[16]; - } origin; - DWORD ulen = UNLEN + 1; - DWORD dlen = MAX_DOMAIN_NAME_LEN + 1; - SID_NAME_USE use; - cyglsa_t *authinf = NULL; - ULONG authinf_size; - TOKEN_SOURCE ts; - PCYG_TOKEN_GROUPS gsids = NULL; - PTOKEN_PRIVILEGES privs = NULL; - PACL dacl = NULL; - PVOID profile = NULL; - LUID luid; - QUOTA_LIMITS quota; - size_t psize = 0, gsize = 0, dsize = 0; - OFFSET offset, sids_offset; - int tmpidx, non_well_known_cnt; - - HANDLE user_token = NULL; - - push_self_privilege (SE_TCB_PRIVILEGE, true); - - /* Register as logon process. */ - RtlInitAnsiString (&name, "Cygwin"); - SetLastError (0); - status = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); - if (status != STATUS_SUCCESS) - { - debug_printf ("LsaRegisterLogonProcess: %y", status); - __seterrno_from_nt_status (status); - goto out; - } - else if (GetLastError () == ERROR_PROC_NOT_FOUND) - { - debug_printf ("Couldn't load Secur32.dll"); - goto out; - } - /* Get handle to our own LSA package. */ - RtlInitAnsiString (&name, CYG_LSA_PKGNAME); - status = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id); - if (status != STATUS_SUCCESS) - { - debug_printf ("LsaLookupAuthenticationPackage: %y", status); - __seterrno_from_nt_status (status); - goto out; - } - - /* Open policy object. */ - if (!(lsa = lsa_open_policy (NULL, POLICY_EXECUTE))) - goto out; - - /* Create origin. */ - stpcpy (origin.buf, "Cygwin"); - RtlInitAnsiString (&origin.str, origin.buf); - /* Create token source. */ - memcpy (ts.SourceName, "Cygwin.1", 8); - ts.SourceIdentifier.HighPart = 0; - ts.SourceIdentifier.LowPart = 0x0103; - - /* Create list of groups, the user is member in. */ - int auth_pos; - if (new_groups.issetgroups ()) - get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid, - auth_pos); - else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw, - NULL, auth_luid, auth_pos)) - goto out; - - tmp_gsids.debug_print ("tmp_gsids"); - - /* Evaluate size of TOKEN_GROUPS list */ - non_well_known_cnt = tmp_gsids.non_well_known_count (); - gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES); - tmpidx = -1; - for (int i = 0; i < non_well_known_cnt; ++i) - if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0) - gsize += RtlLengthSid (tmp_gsids.sids[tmpidx]); - - /* Retrieve list of privileges of that user. The MIC SID is created by - the LSA here. */ - if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize, NULL))) - goto out; - - /* Create DefaultDacl. */ - dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE) - + RtlLengthSid (usersid) - + RtlLengthSid (well_known_admins_sid) - + RtlLengthSid (well_known_system_sid); - dacl = (PACL) alloca (dsize); - if (!NT_SUCCESS (RtlCreateAcl (dacl, dsize, ACL_REVISION))) - goto out; - if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, - usersid))) - goto out; - if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, - well_known_admins_sid))) - goto out; - if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, - well_known_system_sid))) - goto out; - - /* Evaluate authinf size and allocate authinf. */ - authinf_size = (authinf->data - (PBYTE) authinf); - authinf_size += RtlLengthSid (usersid); /* User SID */ - authinf_size += gsize; /* Groups + Group SIDs */ - /* When trying to define the admins group as primary group on Vista, - LsaLogonUser fails with error STATUS_INVALID_OWNER. As workaround - we define "Local" as primary group here. Seteuid32 sets the primary - group to the group set in /etc/passwd anyway. */ - if (new_groups.pgsid == well_known_admins_sid) - pgrpsid = well_known_local_sid; - else - pgrpsid = new_groups.pgsid; - - authinf_size += RtlLengthSid (pgrpsid); /* Primary Group SID */ - - authinf_size += psize; /* Privileges */ - authinf_size += 0; /* Owner SID */ - authinf_size += dsize; /* Default DACL */ - - authinf = (cyglsa_t *) alloca (authinf_size); - authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf); - - authinf->magic = CYG_LSA_MAGIC; - - if (!LookupAccountSidW (NULL, usersid, authinf->username, &ulen, - authinf->domain, &dlen, &use)) - { - __seterrno (); - goto out; - } - - /* Store stuff in authinf with offset relative to start of "inf" member, - instead of using pointers. */ - offset = authinf->data - (PBYTE) &authinf->inf; - - authinf->inf.ExpirationTime.LowPart = 0xffffffffL; - authinf->inf.ExpirationTime.HighPart = 0x7fffffffL; - /* User SID */ - authinf->inf.User.User.Sid = offset; - authinf->inf.User.User.Attributes = 0; - RtlCopySid (RtlLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset), - usersid); - offset += RtlLengthSid (usersid); - /* Groups */ - authinf->inf.Groups = offset; - gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset); - sids_offset = offset + sizeof (ULONG) + non_well_known_cnt - * sizeof (SID_AND_ATTRIBUTES); - gsids->GroupCount = non_well_known_cnt; - /* Group SIDs */ - tmpidx = -1; - for (int i = 0; i < non_well_known_cnt; ++i) - { - if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0) - break; - gsids->Groups[i].Sid = sids_offset; - gsids->Groups[i].Attributes = SE_GROUP_MANDATORY - | SE_GROUP_ENABLED_BY_DEFAULT - | SE_GROUP_ENABLED; - RtlCopySid (RtlLengthSid (tmp_gsids.sids[tmpidx]), - (PSID) ((PBYTE) &authinf->inf + sids_offset), - tmp_gsids.sids[tmpidx]); - sids_offset += RtlLengthSid (tmp_gsids.sids[tmpidx]); - } - offset += gsize; - /* Primary Group SID */ - authinf->inf.PrimaryGroup.PrimaryGroup = offset; - RtlCopySid (RtlLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset), - pgrpsid); - offset += RtlLengthSid (pgrpsid); - /* Privileges */ - authinf->inf.Privileges = offset; - memcpy ((PBYTE) &authinf->inf + offset, privs, psize); - offset += psize; - /* Owner */ - authinf->inf.Owner.Owner = 0; - /* Default DACL */ - authinf->inf.DefaultDacl.DefaultDacl = offset; - memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize); - - authinf->checksum = CYG_LSA_MAGIC; - PDWORD csp; - PDWORD csp_end; - csp = (PDWORD) &authinf->username; - csp_end = (PDWORD) ((PBYTE) authinf + authinf_size); - while (csp < csp_end) - authinf->checksum += *csp++; - - /* Try to logon... */ - status = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, - package_id, authinf, authinf_size, NULL, &ts, - &profile, &size, &luid, &user_token, "a, - &sub_status); - if (status != STATUS_SUCCESS) - { - debug_printf ("LsaLogonUser: %y (sub-status %y)", status, sub_status); - __seterrno_from_nt_status (status); - goto out; - } - if (profile) - { -#ifdef JUST_ANOTHER_NONWORKING_SOLUTION - /* See ../lsaauth/cyglsa.c. */ - cygprf_t *prf = (cygprf_t *) profile; - if (prf->magic_pre == MAGIC_PRE && prf->magic_post == MAGIC_POST - && prf->token) - { - CloseHandle (user_token); - user_token = prf->token; - system_printf ("Got token through profile: %p", user_token); - } -#endif /* JUST_ANOTHER_NONWORKING_SOLUTION */ - LsaFreeReturnBuffer (profile); - } - user_token = get_full_privileged_inheritable_token (user_token); - -out: - if (privs) - free (privs); - lsa_close_policy (lsa); - if (lsa_hdl) - LsaDeregisterLogonProcess (lsa_hdl); - pop_self_privilege (); - - debug_printf ("%p = lsaauth ()", user_token); - return user_token; -} - -#define SFU_LSA_KEY_SUFFIX L"_microsoft_sfu_utility" - -HANDLE -lsaprivkeyauth (struct passwd *pw) -{ - NTSTATUS status; - HANDLE lsa = NULL; - HANDLE token = NULL; - WCHAR sid[256]; - WCHAR domain[MAX_DOMAIN_NAME_LEN + 1]; - WCHAR user[UNLEN + 1]; - WCHAR key_name[MAX_DOMAIN_NAME_LEN + UNLEN + wcslen (SFU_LSA_KEY_SUFFIX) + 2]; - UNICODE_STRING key; - PUNICODE_STRING data = NULL; - cygsid psid; - BOOL ret; - - push_self_privilege (SE_TCB_PRIVILEGE, true); - - /* Open policy object. */ - if (!(lsa = lsa_open_policy (NULL, POLICY_GET_PRIVATE_INFORMATION))) - goto out; - - /* Needed for Interix key and LogonUser. */ - extract_nt_dom_user (pw, domain, user); - - /* First test for a Cygwin entry. */ - if (psid.getfrompw (pw) && psid.string (sid)) - { - wcpcpy (wcpcpy (key_name, CYGWIN_LSA_KEY_PREFIX), sid); - RtlInitUnicodeString (&key, key_name); - status = LsaRetrievePrivateData (lsa, &key, &data); - if (!NT_SUCCESS (status)) - data = NULL; - } - /* No Cygwin key, try Interix key. */ - if (!data && *domain) - { - __small_swprintf (key_name, L"%W_%W%W", - domain, user, SFU_LSA_KEY_SUFFIX); - RtlInitUnicodeString (&key, key_name); - status = LsaRetrievePrivateData (lsa, &key, &data); - if (!NT_SUCCESS (status)) - data = NULL; - } - /* Found an entry? Try to logon. */ - if (data) - { - /* The key is not 0-terminated. */ - PWCHAR passwd; - size_t pwdsize = data->Length + sizeof (WCHAR); - - passwd = (PWCHAR) alloca (pwdsize); - *wcpncpy (passwd, data->Buffer, data->Length / sizeof (WCHAR)) = L'\0'; - /* Weird: LsaFreeMemory invalidates the content of the UNICODE_STRING - structure, but it does not invalidate the Buffer content. */ - RtlSecureZeroMemory (data->Buffer, data->Length); - LsaFreeMemory (data); - debug_printf ("Try logon for %W\\%W", domain, user); - ret = LogonUserW (user, domain, passwd, LOGON32_LOGON_INTERACTIVE, - LOGON32_PROVIDER_DEFAULT, &token); - RtlSecureZeroMemory (passwd, pwdsize); - if (!ret) - { - __seterrno (); - token = NULL; - } - else - token = get_full_privileged_inheritable_token (token); - } - lsa_close_policy (lsa); - -out: - pop_self_privilege (); - return token; -} |