From b825c587ba9e851002570b81f9f35196b7a96100 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 27 Nov 2006 12:59:59 +0000 Subject: * cyglsa.h: New header file. * environ.cc: Disable subauth settings. * grp.cc: Accomodate cygsidlist's count now being a method. * sec_helper.cc (SECURITY_MANDATORY_INTEGRITY_AUTHORITY): Remove. (mandatory_medium_integrity_sid): Remove. (mandatory_high_integrity_sid): Remove. (mandatory_system_integrity_sid): Remove. (fake_logon_sid): Add. (cygsid::get_sid): Add well_known parameter. Set well_known_sid accordingly. (cygsid::getfromstr): Ditto. (cygsidlist::alloc_sids): Move here from security.cc. (cygsidlist::free_sids): Ditto. (cygsidlist::add): Move here from security.h. Add well_known parameter. Set well_known_sid accordingly. Don't allow duplicate SIDs. * security.cc: Include cyglsa.h and cygwin/version.h. Throughout accomodate cygsidlist's count now being a method. Throughout drop redundant "contains" tests. (get_user_local_groups): Add local groups as well known SIDs. (get_token_group_sidlist): Add well known groups as well known SIDs. (get_server_groups): Ditto. Only call get_unix_group_sidlist after get_user_local_groups to maintain "well_known_sid" attribute. (get_initgroups_sidlist): Add well known groups as well known SIDs. (get_setgroups_sidlist): Add usersid and struct passwd parameter to allow calling get_server_groups from here. (get_system_priv_list): Make static. Return size of TOKEN_PRIVILEGES structure. (get_priv_list): Ditto. (create_token): Accomodate above changes. Drop misguided attempt to add MIC SIDs to created user token. Print returned token as hex value. (subauth): Disable. (lsaauth): New function implementing client side of LSA authentication. * security.h (class cygsid): Add well_known_sid attribute. Accomodate throughout. Add *= operator to create a well known SID. (class cygsidlist): Rename count to cnt. Make count a method. (cygsidlist::add): Move to sec_helper.cc. (cygsidlist::operator *=): New method to add well known SID. (cygsidlist::non_well_known_count): New method returning number of non well known SIDs in list. (cygsidlist::next_non_well_known_sid): New method returning next non well known SID by index. (mandatory_medium_integrity_sid): Drop declaration. (mandatory_high_integrity_sid): Drop declaration. (mandatory_system_integrity_sid): Drop declaration. (fake_logon_sid): Add declaration. (subauth): Disable declaration. (lsaauth): Add declaration. * syscalls.cc (seteuid32): Disable subauthentication. Add LSA authentication. * wincap.h: Define needs_logon_sid_in_sid_list throughout. * wincap.cc: Ditto. --- winsup/cygwin/security.cc | 415 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 306 insertions(+), 109 deletions(-) (limited to 'winsup/cygwin/security.cc') diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 96d903f79..79c3c2f50 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -41,6 +41,8 @@ details. */ #include "ntdll.h" #include "lm.h" #include "pwdgrp.h" +#include "cyglsa.h" +#include bool allow_ntsec; /* allow_smbntsec is handled exclusively in path.cc (path_conv::check). @@ -48,25 +50,6 @@ bool allow_ntsec; bool allow_smbntsec; bool allow_traverse; -cygsid * -cygsidlist::alloc_sids (int n) -{ - if (n > 0) - return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid)); - else - return NULL; -} - -void -cygsidlist::free_sids () -{ - if (sids) - cfree (sids); - sids = NULL; - count = maxcount = 0; - type = cygsidlist_empty; -} - extern "C" void cygwin_set_impersonation_token (const HANDLE hToken) { @@ -346,7 +329,7 @@ is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list) Note: Allowing those groups in our group list renders external tokens invalid, so that it becomes impossible to logon with password and valid logon token. */ - for (int glidx = 0; glidx < grp_list.count; ++glidx) + for (int glidx = 0; glidx < grp_list.count (); ++glidx) if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup) && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid)) @@ -409,8 +392,7 @@ get_user_local_groups (cygsidlist &grp_list, PSID pusersid) } if (!legal_sid_type (use)) debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use); - else if (!grp_list.contains (gsid)) - grp_list += gsid; + grp_list *= gsid; } NetApiBufferFree (buf); return true; @@ -480,7 +462,7 @@ get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list) goto found; continue; found: - if (gsid.getfromgr (gr) && !grp_list.contains (gsid)) + if (gsid.getfromgr (gr)) grp_list += gsid; } @@ -498,26 +480,26 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, /*if (sid_in_token_groups (my_grps, well_known_local_sid))*/ grp_list += well_known_local_sid; if (sid_in_token_groups (my_grps, well_known_dialup_sid)) - grp_list += 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; + 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_batch_sid; /* This is a problem on 2K3 (only domain controllers?!?) which only enables tools for selected special groups. A subauth token is only NETWORK, but NETWORK has no access to these tools. Therefore we always add INTERACTIVE here. */ /*if (sid_in_token_groups (my_grps, well_known_interactive_sid))*/ - grp_list += well_known_interactive_sid; + grp_list *= well_known_interactive_sid; if (sid_in_token_groups (my_grps, well_known_service_sid)) - grp_list += well_known_service_sid; + grp_list *= well_known_service_sid; if (sid_in_token_groups (my_grps, well_known_this_org_sid)) - grp_list += well_known_this_org_sid; + grp_list *= well_known_this_org_sid; } else { grp_list += well_known_local_sid; - grp_list += well_known_interactive_sid; + grp_list *= well_known_interactive_sid; } if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */ { @@ -525,7 +507,7 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID) { grp_list += my_grps->Groups[i].Sid; - auth_pos = grp_list.count - 1; + auth_pos = grp_list.count () - 1; break; } } @@ -541,22 +523,24 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw) if (well_known_system_sid == usersid) { - grp_list += well_known_admins_sid; + grp_list *= well_known_admins_sid; get_unix_group_sidlist (pw, grp_list); return true; } - if (!grp_list.contains (well_known_world_sid)) - grp_list += well_known_world_sid; - if (!grp_list.contains (well_known_authenticated_users_sid)) - grp_list += well_known_authenticated_users_sid; + grp_list *= well_known_world_sid; + grp_list *= well_known_authenticated_users_sid; extract_nt_dom_user (pw, domain, user); if (get_logon_server (domain, server, wserver, false) && !get_user_groups (wserver, grp_list, user, domain) && get_logon_server (domain, server, wserver, true)) get_user_groups (wserver, grp_list, user, domain); - get_unix_group_sidlist (pw, grp_list); - return get_user_local_groups (grp_list, usersid); + if (get_user_local_groups (grp_list, usersid)) + { + get_unix_group_sidlist (pw, grp_list); + return true; + } + return false; } static bool @@ -564,8 +548,8 @@ 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; + grp_list *= well_known_world_sid; + grp_list *= well_known_authenticated_users_sid; if (well_known_system_sid == usersid) auth_pos = -1; else @@ -574,24 +558,22 @@ get_initgroups_sidlist (cygsidlist &grp_list, return false; /* special_pgrp true if pgrpsid is not in normal groups */ - if (!grp_list.contains (pgrpsid)) - grp_list += pgrpsid; + grp_list += pgrpsid; return true; } static void -get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps, - user_groups &groups, LUID auth_luid, int &auth_pos) +get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw, + PTOKEN_GROUPS my_grps, user_groups &groups, + LUID auth_luid, int &auth_pos) { - PSID pgpsid = groups.pgsid; - tmp_list += well_known_world_sid; - tmp_list += well_known_authenticated_users_sid; + 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); - for (int gidx = 0; gidx < groups.sgsids.count; gidx++) - if (!tmp_list.contains (groups.sgsids.sids[gidx])) - tmp_list += groups.sgsids.sids[gidx]; - if (!groups.sgsids.contains (pgpsid)) - tmp_list += pgpsid; + 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 const cygpriv_idx sys_privs[] = { @@ -628,13 +610,13 @@ static const cygpriv_idx sys_privs[] = { #define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs) -PTOKEN_PRIVILEGES -get_system_priv_list (cygsidlist &grp_list) +static PTOKEN_PRIVILEGES +get_system_priv_list (cygsidlist &grp_list, size_t &size) { const LUID *priv; - PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) - malloc (sizeof (ULONG) - + SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES)); + size = sizeof (ULONG) + + SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES); + PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size); if (!privs) { debug_printf ("malloc (system_privs) failed."); @@ -653,8 +635,9 @@ get_system_priv_list (cygsidlist &grp_list) return privs; } -PTOKEN_PRIVILEGES -get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) +static PTOKEN_PRIVILEGES +get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, + size_t &size) { PLSA_UNICODE_STRING privstrs; ULONG cnt; @@ -663,9 +646,9 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; if (usersid == well_known_system_sid) - return get_system_priv_list (grp_list); + return get_system_priv_list (grp_list, size); - for (int grp = -1; grp < grp_list.count; ++grp) + for (int grp = -1; grp < grp_list.count (); ++grp) { if (grp == -1) { @@ -699,9 +682,9 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) } tmp_count = privs ? privs->PrivilegeCount : 0; - tmp = (PTOKEN_PRIVILEGES) - realloc (privs, sizeof (ULONG) + - (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); + size = sizeof (DWORD) + + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES); + tmp = (PTOKEN_PRIVILEGES) realloc (privs, size); if (!tmp) { if (privs) @@ -794,7 +777,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) { cygsid gsid; struct __group32 *gr; - bool saw[groups.sgsids.count]; + bool saw[groups.sgsids.count ()]; memset (saw, 0, sizeof(saw)); /* token groups found in /etc/group match the user.gsids ? */ @@ -811,7 +794,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) goto done; } /* user.sgsids groups must be in the token */ - for (int gidx = 0; gidx < groups.sgsids.count; gidx++) + for (int gidx = 0; gidx < groups.sgsids.count (); gidx++) if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx])) goto done; } @@ -857,6 +840,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw, PTOKEN_GROUPS my_tok_gsids = NULL; DWORD size; + size_t psize = 0; /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ push_self_privilege (SE_CREATE_TOKEN_PRIV, true); @@ -929,8 +913,8 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw, /* Create list of groups, the user is member in. */ int auth_pos; if (new_groups.issetgroups ()) - get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid, - auth_pos); + 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; @@ -940,9 +924,9 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw, /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ new_tok_gsids = (PTOKEN_GROUPS) - alloca (sizeof (ULONG) + (tmp_gsids.count + 1 ) + alloca (sizeof (DWORD) + tmp_gsids.count () * sizeof (SID_AND_ATTRIBUTES)); - new_tok_gsids->GroupCount = tmp_gsids.count; + 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]; @@ -952,42 +936,8 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw, } if (auth_pos >= 0) new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; - - /* On systems supporting Mandatory Integrity Control, add a MIC SID. */ - if (wincap.has_mandatory_integrity_control ()) - { - bool add_mic_sid = true; - new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes = 0; - - /* The subauth token usually contains a MIC SID. Copy it into our - group SID list. */ - if (my_tok_gsids) - for (DWORD i = 0; i < my_tok_gsids->GroupCount; ++i) - if (EqualPrefixSid (mandatory_medium_integrity_sid, - my_tok_gsids->Groups[i].Sid)) - { - new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid - = my_tok_gsids->Groups[i].Sid; - add_mic_sid = false; - break; - } - /* If no MIC SID was available add a matching one for the account type. */ - if (add_mic_sid) - { - if (usersid == well_known_system_sid) - new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid - = mandatory_system_integrity_sid; - else if (tmp_gsids.contains (well_known_admins_sid)) - new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid - = mandatory_high_integrity_sid; - else - new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid - = mandatory_medium_integrity_sid; - } - } - /* Retrieve list of privileges of that user. */ - if (!privs && !(privs = get_priv_list (lsa, usersid, tmp_gsids))) + if (!privs && !(privs = get_priv_list (lsa, usersid, tmp_gsids, psize))) goto out; /* Let's be heroic... */ @@ -1023,10 +973,16 @@ out: free (my_tok_gsids); close_local_policy (lsa); - debug_printf ("%d = create_token ()", primary_token); + debug_printf ("0x%x = create_token ()", primary_token); return primary_token; } +/* Subauthentication gets useless now that real LSA authentication is + available. The accompanying code in seteuid32 and environ.cc is + also disabled. + TODO: Deprecate and delete code entirely. + TODO: Delete from documentation. */ +#if 0 extern "C" { BOOL WINAPI Wow64DisableWow64FsRedirection (PVOID *); @@ -1047,7 +1003,7 @@ HANDLE subauth (struct passwd *pw) { LSA_STRING name; - HANDLE lsa_hdl; + HANDLE lsa_hdl = NULL; LSA_OPERATIONAL_MODE sec_mode; NTSTATUS ret, ret2; ULONG package_id, size; @@ -1141,7 +1097,6 @@ subauth (struct passwd *pw) { debug_printf ("LsaLookupAuthenticationPackage: %d", ret); __seterrno_from_win_error (LsaNtStatusToWinError (ret)); - LsaDeregisterLogonProcess (lsa_hdl); goto out; } /* Create origin. */ @@ -1170,7 +1125,6 @@ subauth (struct passwd *pw) { debug_printf ("LsaLogonUser: %d", ret); __seterrno_from_win_error (LsaNtStatusToWinError (ret)); - LsaDeregisterLogonProcess (lsa_hdl); goto out; } LsaFreeReturnBuffer (profile); @@ -1180,11 +1134,254 @@ subauth (struct passwd *pw) __seterrno (); out: + if (lsa_hdl) + LsaDeregisterLogonProcess (lsa_hdl); pop_self_privilege (); if (user_token) CloseHandle (user_token); return primary_token; } +#endif + +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; + LSA_OPERATIONAL_MODE sec_mode; + NTSTATUS ret, ret2; + ULONG package_id, size; + LUID auth_luid = SYSTEM_LUID; + struct { + LSA_STRING str; + CHAR buf[16]; + } origin; + 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_PRIV, true); + + /* Register as logon process. */ + str2lsa (name, "Cygwin"); + SetLastError (0); + ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaRegisterLogonProcess: %p", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + 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. */ + str2lsa (name, CYG_LSA_PKGNAME); + ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaLookupAuthenticationPackage: %p", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + goto out; + } + + /* Open policy object. */ + if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE) + goto out; + + /* Create origin. */ + str2buf2lsa (origin.str, origin.buf, "Cygwin"); + /* 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; + /* The logon SID entry is not generated automatically on Windows 2000 + and earlier for some reason. So add fake logon sid here, which is + filled with logon id values in the authentication package. */ + if (wincap.needs_logon_sid_in_sid_list ()) + tmp_gsids += fake_logon_sid; + + 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 += GetLengthSid (tmp_gsids.sids[tmpidx]); + + /* Retrieve list of privileges of that user. */ + if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize))) + goto out; + + /* Create DefaultDacl. */ + dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE) + + GetLengthSid (usersid) + + GetLengthSid (well_known_admins_sid) + + GetLengthSid (well_known_system_sid); + dacl = (PACL) alloca (dsize); + if (!InitializeAcl (dacl, dsize, ACL_REVISION)) + goto out; + if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid)) + goto out; + if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, + well_known_admins_sid)) + goto out; + if (!AddAccessAllowedAce (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 += GetLengthSid (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. First, this adds the otherwise + missing "Local" group to the group list and second, seteuid32 + sets the primary group to the group set in /etc/passwd anyway. */ + pgrpsid = well_known_local_sid; + authinf_size += GetLengthSid (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; + + extract_nt_dom_user (pw, authinf->domain, authinf->username); + + /* 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; + CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset), + usersid); + offset += GetLengthSid (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; + /* Mark logon SID as logon SID :) */ + if (wincap.needs_logon_sid_in_sid_list () + && tmp_gsids.sids[tmpidx] == fake_logon_sid) + gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID; + CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]), + (PSID) ((PBYTE) &authinf->inf + sids_offset), + tmp_gsids.sids[tmpidx]); + sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]); + } + offset += gsize; + /* Primary Group SID */ + authinf->inf.PrimaryGroup.PrimaryGroup = offset; + CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset), + pgrpsid); + offset += GetLengthSid (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 = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR, + CYGWIN_VERSION_DLL_MINOR); + PDWORD csp = (PDWORD) &authinf->username; + PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size); + while (csp < csp_end) + authinf->checksum += *csp++; + + /* Try to logon... */ + ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id, + authinf, authinf_size, NULL, &ts, &profile, &size, &luid, + &user_token, "a, &ret2); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaLogonUser: %p", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + goto out; + } + if (profile) + LsaFreeReturnBuffer (profile); + + if (wincap.has_mandatory_integrity_control ()) + { + typedef struct _TOKEN_LINKED_TOKEN + { + HANDLE LinkedToken; + } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN; +# define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19) + + TOKEN_LINKED_TOKEN linked; + + if (GetTokenInformation (user_token, TokenLinkedToken, + (PVOID) &linked, sizeof linked, &size)) + { + debug_printf ("Linked Token: %lu", linked.LinkedToken); + if (linked.LinkedToken) + user_token = linked.LinkedToken; + } + } + +out: + if (privs) + free (privs); + close_local_policy (lsa); + if (lsa_hdl) + LsaDeregisterLogonProcess (lsa_hdl); + pop_self_privilege (); + + debug_printf ("0x%x = lsaauth ()", user_token); + return user_token; +} /* read_sd reads a security descriptor from a file. In case of error, -1 is returned and errno is set. -- cgit v1.2.3