Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/sec_auth.cc')
-rw-r--r--winsup/cygwin/sec_auth.cc1348
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, &quota,
- &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;
-}