From: corinna Date: Mon, 27 Nov 2006 12:59:58 +0000 (+0000) Subject: * cyglsa.h: New header file. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=721130c607281a0c824e8e2d81517219230608bf;p=pf3gnuchains%2Fpf3gnuchains3x.git * 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. --- diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index e35ed57343..177e77c366 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,57 @@ +2006-11-27 Corinna Vinschen + + * 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. + 2006-11-23 Corinna Vinschen * security.h (DBGSID): Define for debugging purposes. diff --git a/winsup/cygwin/cyglsa.h b/winsup/cygwin/cyglsa.h new file mode 100644 index 0000000000..4af9e8cd02 --- /dev/null +++ b/winsup/cygwin/cyglsa.h @@ -0,0 +1,149 @@ +/* cyglsa.h: Header file for Cygwin LSA authentication + + Copyright 2006 Red Hat, Inc. + + Written by Corinna Vinschen + +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. */ + +#ifndef _CYGLSA_H +#define _CYGLSA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CYG_LSA_PKGNAME "CygwinLsa" + +#define CYG_LSA_MAGIC 0x0379f014LU + +/* Datastructures not defined in w32api. */ +typedef PVOID *PLSA_CLIENT_REQUEST; + +typedef struct _SECPKG_CLIENT_INFO +{ + LUID LogonId; + ULONG ProcessID; + ULONG ThreadID; + BOOLEAN HasTcbPrivilege; + BOOLEAN Impersonating; + BOOLEAN Restricted; +} SECPKG_CLIENT_INFO, *PSECPKG_CLIENT_INFO; + +/* The table returned by LsaApInitializePackage is actually a + LSA_SECPKG_FUNCTION_TABLE even though that's not documented. + We need only a subset of this table, basically the LSA_DISPATCH_TABLE + plus the pointer to the GetClientInfo function. */ +typedef struct _LSA_SECPKG_FUNCS +{ + NTSTATUS (NTAPI *CreateLogonSession)(PLUID); + NTSTATUS (NTAPI *DeleteLogonSession)(PLUID); + NTSTATUS (NTAPI *AddCredentials)(PVOID); /* wrong prototype, unused */ + NTSTATUS (NTAPI *GetCredentials)(PVOID); /* wrong prototype, unused */ + NTSTATUS (NTAPI *DeleteCredentials)(PVOID); /* wrong prototype, unused */ + PVOID (NTAPI *AllocateLsaHeap)(ULONG); + VOID (NTAPI *FreeLsaHeap)(PVOID); + NTSTATUS (NTAPI *AllocateClientBuffer)(PLSA_CLIENT_REQUEST, ULONG, PVOID *); + NTSTATUS (NTAPI *FreeClientBuffer)(PLSA_CLIENT_REQUEST, PVOID); + NTSTATUS (NTAPI *CopyToClientBuffer)(PLSA_CLIENT_REQUEST, ULONG, + PVOID, PVOID); + NTSTATUS (NTAPI *CopyFromClientBuffer)(PLSA_CLIENT_REQUEST, ULONG, + PVOID, PVOID); + NTSTATUS (NTAPI *ImpersonateClient)(VOID); + NTSTATUS (NTAPI *UnloadPackage)(VOID); + NTSTATUS (NTAPI *DuplicateHandle)(HANDLE,PHANDLE); + NTSTATUS (NTAPI *SaveSupplementalCredentials)(VOID); + NTSTATUS (NTAPI *CreateThread)(PVOID); /* wrong prototype, unused */ + NTSTATUS (NTAPI *GetClientInfo)(PSECPKG_CLIENT_INFO); +} LSA_SECPKG_FUNCS, *PLSA_SECPKG_FUNCS; + +typedef enum _LSA_TOKEN_INFORMATION_TYPE +{ + LsaTokenInformationNull, + LsaTokenInformationV1, + LsaTokenInformationV2 +} LSA_TOKEN_INFORMATION_TYPE, *PLSA_TOKEN_INFORMATION_TYPE; + +typedef struct _LSA_TOKEN_INFORMATION_V2 +{ + LARGE_INTEGER ExpirationTime; + TOKEN_USER User; + PTOKEN_GROUPS Groups; + TOKEN_PRIMARY_GROUP PrimaryGroup; + PTOKEN_PRIVILEGES Privileges; + TOKEN_OWNER Owner; + TOKEN_DEFAULT_DACL DefaultDacl; +} LSA_TOKEN_INFORMATION_V2, *PLSA_TOKEN_INFORMATION_V2; + +/* These structures are eqivalent to the appropriate Windows structures, + using 32 bit offsets instead of pointers. These datastructures are + used to transfer the logon information to the LSA authentication package. + We can't use the LSA_TOKEN_INFORMATION_V2 structure directly, because + its size differs between 32 bit and 64 bit Windows. */ + +typedef DWORD OFFSET; + +typedef struct _CYG_SID_AND_ATTRIBUTES +{ + OFFSET Sid; + DWORD Attributes; +} CYG_SID_AND_ATTRIBUTES, *PCYG_SID_AND_ATTRIBUTES; + +typedef struct _CYG_TOKEN_USER +{ + CYG_SID_AND_ATTRIBUTES User; +} CYG_TOKEN_USER, *PCYG_TOKEN_USER; + +typedef struct _CYG_TOKEN_GROUPS +{ + DWORD GroupCount; + CYG_SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; +} CYG_TOKEN_GROUPS, *PCYG_TOKEN_GROUPS; + +typedef struct _CYG_TOKEN_PRIMARY_GROUP +{ + OFFSET PrimaryGroup; +} CYG_TOKEN_PRIMARY_GROUP, *PCYG_TOKEN_PRIMARY_GROUP; + +typedef struct _CYG_TOKEN_OWNER +{ + OFFSET Owner; +} CYG_TOKEN_OWNER, *PCYG_TOKEN_OWNER; + +typedef struct _CYG_TOKEN_DEFAULT_DACL +{ + OFFSET DefaultDacl; +} CYG_TOKEN_DEFAULT_DACL, *PCYG_TOKEN_DEFAULT_DACL; + +typedef struct _CYG_LSA_TOKEN_INFORMATION +{ + LARGE_INTEGER ExpirationTime; + CYG_TOKEN_USER User; + OFFSET Groups; + CYG_TOKEN_PRIMARY_GROUP PrimaryGroup; + OFFSET Privileges; + CYG_TOKEN_OWNER Owner; + CYG_TOKEN_DEFAULT_DACL DefaultDacl; +} CYG_LSA_TOKEN_INFORMATION, *PCYG_LSA_TOKEN_INFORMATION; + +/* This is the structure created by security.cc:lsaauth(), which is given to + LsaApLogonUser to create the token information returned to the LSA. */ +typedef struct +{ + DWORD magic; + DWORD checksum; + CHAR username[UNLEN + 1]; + CHAR domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + ULONG inf_size; + CYG_LSA_TOKEN_INFORMATION inf; + BYTE data[1]; +} cyglsa_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _CYGLSA_H */ diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 58b1e50709..ec4edf5210 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -34,7 +34,9 @@ extern bool ignore_case_with_glob; extern bool allow_winsymlinks; extern bool strip_title_path; extern int pcheck_case; +#if 0 extern int subauth_id; +#endif bool reset_com = false; static bool envcache = true; #ifdef USE_SERVER @@ -530,6 +532,7 @@ codepage_init (const char *buf) debug_printf ("Wrong codepage name: %s", buf); } +#if 0 static void subauth_id_init (const char *buf) { @@ -542,6 +545,7 @@ subauth_id_init (const char *buf) if (i > 127 && i != 132 && i <= 255) subauth_id = i; } +#endif static void set_chunksize (const char *buf) @@ -620,7 +624,9 @@ static struct parse_thing #endif {"smbntsec", {func: set_smbntsec}, isfunc, NULL, {{0}, {s: "yes"}}}, {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}}, +#if 0 {"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}}, +#endif {"title", {&display_title}, justset, NULL, {{false}, {true}}}, {"traverse", {func: set_traverse}, isfunc, NULL, {{0}, {s: "yes"}}}, {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index 20698ad5fc..13d334a5de 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -348,7 +348,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid) cygsid sid; for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) if (sid.getfromgr (gr)) - for (int pg = 0; pg < cygheap->user.groups.sgsids.count; ++pg) + for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg) if (sid == cygheap->user.groups.sgsids.sids[pg] && sid != well_known_world_sid) { @@ -484,10 +484,10 @@ initgroups32 (const char *name, __gid32_t gid) if (!get_server_groups (tmp_gsids, usersid, pw)) goto out; tmp_gsids += grpsid; - cygsidlist new_gsids (cygsidlist_alloc, tmp_gsids.count); - for (int i = 0; i < tmp_gsids.count; i++) + cygsidlist new_gsids (cygsidlist_alloc, tmp_gsids.count ()); + for (int i = 0; i < tmp_gsids.count (); i++) new_gsids.sids[i] = tmp_gsids.sids[i]; - new_gsids.count = tmp_gsids.count; + new_gsids.count (tmp_gsids.count ()); cygheap->user.groups.update_supp (new_gsids); } ret = 0; diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index ecb19fc2b3..f1caf487da 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -67,15 +67,8 @@ MKSID (well_known_system_sid, "S-1-5-18", MKSID (well_known_admins_sid, "S-1-5-32-544", SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS); - -#define SECURITY_MANDATORY_INTEGRITY_AUTHORITY {0,0,0,0,0,16} - -MKSID (mandatory_medium_integrity_sid, "S-1-64-8192", - SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 8192); -MKSID (mandatory_high_integrity_sid, "S-1-64-12288", - SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 12288); -MKSID (mandatory_system_integrity_sid, "S-1-64-16384", - SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 16384); +MKSID (fake_logon_sid, "S-1-5-5-0-0", + SECURITY_NT_AUTHORITY, 3, SECURITY_LOGON_IDS_RID, 0, 0); bool cygpsid::operator== (const char *nsidstr) const @@ -135,7 +128,7 @@ cygpsid::string (char *nsidstr) const } PSID -cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r) +cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known) { DWORD i; SID_IDENTIFIER_AUTHORITY sid_auth = {0,0,0,0,0,0}; @@ -150,11 +143,12 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r) InitializeSid (psid, &sid_auth, cnt); for (i = 0; i < cnt; ++i) memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); + well_known_sid = well_known; return psid; } const PSID -cygsid::getfromstr (const char *nsidstr) +cygsid::getfromstr (const char *nsidstr, bool well_known) { char *lasts; DWORD s, cnt = 0; @@ -166,7 +160,7 @@ cygsid::getfromstr (const char *nsidstr) while (cnt < 8 && *lasts == '-') r[cnt++] = strtoul (lasts + 1, &lasts, 10); if (!*lasts) - return get_sid (s, cnt, r); + return get_sid (s, cnt, r, well_known); } return psid = NO_SID; } @@ -185,6 +179,48 @@ cygsid::getfromgr (const struct __group32 *gr) return (*this = sp) != NULL; } +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; + cnt = maxcnt = 0; + type = cygsidlist_empty; +} + +BOOL +cygsidlist::add (const PSID nsi, bool well_known) +{ + if (contains (nsi)) + return TRUE; + if (cnt >= maxcnt) + { + cygsid *tmp = new cygsid [2 * maxcnt]; + if (!tmp) + return FALSE; + maxcnt *= 2; + for (int i = 0; i < cnt; ++i) + tmp[i] = sids[i]; + delete [] sids; + sids = tmp; + } + if (well_known) + sids[cnt++] *= nsi; + else + sids[cnt++] = nsi; + return TRUE; +} + bool get_sids_info (cygpsid owner_sid, cygpsid group_sid, __uid32_t * uidret, __gid32_t * gidret) { diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 96d903f79b..79c3c2f508 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. diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 0f0fdb0497..9823ca2b4c 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -80,11 +80,12 @@ public: class cygsid : public cygpsid { char sbuf[MAX_SID_LEN]; + bool well_known_sid; - const PSID getfromstr (const char *nsidstr); - PSID get_sid (DWORD s, DWORD cnt, DWORD *r); + const PSID getfromstr (const char *nsidstr, bool well_known); + PSID get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known); - inline const PSID assign (const PSID nsid) + inline const PSID assign (const PSID nsid, bool well_known) { if (!nsid) psid = NO_SID; @@ -92,21 +93,32 @@ class cygsid : public cygpsid { { psid = (PSID) sbuf; CopySid (MAX_SID_LEN, psid, nsid); + well_known_sid = well_known; } return psid; } public: inline operator const PSID () { return psid; } + inline bool is_well_known_sid () { return well_known_sid; } + /* Both, = and *= are assignment operators. = creates a "normal" SID, + *= marks the SID as being a well-known SID. This difference is + important when creating a SID list for LSA authentication. */ inline const PSID operator= (cygsid &nsid) - { return assign (nsid); } + { return assign (nsid, nsid.well_known_sid); } inline const PSID operator= (const PSID nsid) - { return assign (nsid); } + { return assign (nsid, false); } inline const PSID operator= (const char *nsidstr) - { return getfromstr (nsidstr); } - - inline cygsid () : cygpsid ((PSID) sbuf) {} + { return getfromstr (nsidstr, false); } + inline const PSID operator*= (cygsid &nsid) + { return assign (nsid, true); } + inline const PSID operator*= (const PSID nsid) + { return assign (nsid, true); } + inline const PSID operator*= (const char *nsidstr) + { return getfromstr (nsidstr, true); } + + inline cygsid () : cygpsid ((PSID) sbuf), well_known_sid (false) {} inline cygsid (const PSID nsid) { *this = nsid; } inline cygsid (const char *nstrsid) { *this = nstrsid; } @@ -114,21 +126,28 @@ public: BOOL getfrompw (const struct passwd *pw); BOOL getfromgr (const struct __group32 *gr); + + void debug_print (const char *prefix = NULL) const + { + char buf[256] __attribute__ ((unused)); + debug_printf ("%s %s%s", prefix ?: "", string (buf) ?: "NULL", well_known_sid ? " (*)" : " (+)"); + } }; typedef enum { cygsidlist_empty, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type; class cygsidlist { - int maxcount; + int maxcnt; + int cnt; + + BOOL add (const PSID nsi, bool well_known); /* Only with auto for now */ + public: - int count; cygsid *sids; cygsidlist_type type; cygsidlist (cygsidlist_type t, int m) + : maxcnt (m), cnt (0), type (t) { - type = t; - count = 0; - maxcount = m; if (t == cygsidlist_alloc) sids = alloc_sids (m); else @@ -136,49 +155,56 @@ public: } ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; } - BOOL add (const PSID nsi) /* Only with auto for now */ + BOOL addfromgr (struct __group32 *gr) /* Only with alloc */ + { return sids[cnt].getfromgr (gr) && ++cnt; } + + /* += adds a "normal" SID, *= adds a well-known SID. See comment in class + cygsid above. */ + BOOL operator+= (cygsid &si) { return add ((PSID) si, false); } + BOOL operator+= (const char *sidstr) { cygsid nsi (sidstr); + return add ((PSID) nsi, false); } + BOOL operator+= (const PSID psid) { return add (psid, false); } + BOOL operator*= (cygsid &si) { return add ((PSID) si, true); } + BOOL operator*= (const char *sidstr) { cygsid nsi (sidstr); + return add ((PSID) nsi, true); } + BOOL operator*= (const PSID psid) { return add (psid, true); } + + void count (int ncnt) + { cnt = ncnt; } + int count () const { return cnt; } + int non_well_known_count () const { - if (count >= maxcount) - { - cygsid *tmp = new cygsid [ 2 * maxcount]; - if (!tmp) - return FALSE; - maxcount *= 2; - for (int i = 0; i < count; ++i) - tmp[i] = sids[i]; - delete [] sids; - sids = tmp; - } - sids[count++] = nsi; - return TRUE; + int wcnt = 0; + for (int i = 0; i < cnt; ++i) + if (!sids[i].is_well_known_sid ()) + ++wcnt; + return wcnt; } - BOOL add (cygsid &nsi) { return add ((PSID) nsi); } - BOOL add (const char *sidstr) - { cygsid nsi (sidstr); return add (nsi); } - BOOL addfromgr (struct __group32 *gr) /* Only with alloc */ - { return sids[count].getfromgr (gr) && ++count; } - - BOOL operator+= (cygsid &si) { return add (si); } - BOOL operator+= (const char *sidstr) { return add (sidstr); } - BOOL operator+= (const PSID psid) { return add (psid); } int position (const PSID sid) const { - for (int i = 0; i < count; ++i) + for (int i = 0; i < cnt; ++i) if (sids[i] == sid) return i; return -1; } + int next_non_well_known_sid (int idx) + { + while (++idx < cnt) + if (!sids[idx].is_well_known_sid ()) + return idx; + return -1; + } BOOL contains (const PSID sid) const { return position (sid) >= 0; } cygsid *alloc_sids (int n); void free_sids (); void debug_print (const char *prefix = NULL) const { debug_printf ("-- begin sidlist ---"); - if (!count) + if (!cnt) debug_printf ("No elements"); - for (int i = 0; i < count; ++i) + for (int i = 0; i < cnt; ++i) sids[i].debug_print (prefix); debug_printf ("-- ende sidlist ---"); } @@ -256,9 +282,7 @@ extern cygpsid well_known_authenticated_users_sid; extern cygpsid well_known_this_org_sid; extern cygpsid well_known_system_sid; extern cygpsid well_known_admins_sid; -extern cygpsid mandatory_medium_integrity_sid; -extern cygpsid mandatory_high_integrity_sid; -extern cygpsid mandatory_system_integrity_sid; +extern cygpsid fake_logon_sid; /* Order must be same as cygpriv in sec_helper.cc. */ enum cygpriv_idx { @@ -348,11 +372,15 @@ struct _UNICODE_STRING; void __stdcall str2buf2uni (_UNICODE_STRING &, WCHAR *, const char *) __attribute__ ((regparm (3))); void __stdcall str2uni_cat (_UNICODE_STRING &, const char *) __attribute__ ((regparm (2))); -/* Try a subauthentication. */ -HANDLE subauth (struct passwd *pw); -/* Try creating a token directly. */ +/* Function creating a token by calling NtCreateToken. */ HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw, HANDLE subauth_token); +#if 0 +/* Subauthentication function. */ +HANDLE subauth (struct passwd *pw); +#endif +/* LSA authentication function. */ +HANDLE lsaauth (cygsid &, user_groups &, struct passwd *); /* Verify an existing token */ bool verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern = NULL); /* Get groups of a user */ diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 241efd4902..91c6960730 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -2111,30 +2111,46 @@ seteuid32 (__uid32_t uid) debug_printf ("Found token %d", new_token); /* If no impersonation token is available, try to - authenticate using NtCreateToken () or subauthentication. */ + authenticate using NtCreateToken () or LSA authentication. */ if (new_token == INVALID_HANDLE_VALUE) { - new_token = subauth (pw_new); - debug_printf ("subauth %s, try create_token.", - new_token == INVALID_HANDLE_VALUE ? "failed" : "succeeded"); - HANDLE new_token2 = create_token (usersid, groups, pw_new, new_token); - if (new_token2 == INVALID_HANDLE_VALUE) - { + if (!(new_token = lsaauth (usersid, groups, pw_new))) + { +#if 0 + new_token = subauth (pw_new); + debug_printf ("subauth %s, try create_token.", + new_token == INVALID_HANDLE_VALUE ? "failed" : "succeeded"); + HANDLE new_token2 = create_token (usersid, groups, pw_new, new_token); + if (new_token2 == INVALID_HANDLE_VALUE) + { + if (new_token == INVALID_HANDLE_VALUE) + { + debug_printf ("create_token failed, bail out of here"); + cygheap->user.reimpersonate (); + return -1; + } + debug_printf ("create_token failed, use original subauth token"); + } + else + { + debug_printf ("create_token succeeded"); + if (new_token != INVALID_HANDLE_VALUE) + CloseHandle (new_token); + new_token = new_token2; + } +#else + debug_printf ("lsaauth failed, try create_token."); + new_token = create_token (usersid, groups, pw_new, + INVALID_HANDLE_VALUE); if (new_token == INVALID_HANDLE_VALUE) { debug_printf ("create_token failed, bail out of here"); cygheap->user.reimpersonate (); return -1; } - debug_printf ("create_token failed, use original subauth token"); - } - else - { - debug_printf ("create_token succeeded"); - if (new_token != INVALID_HANDLE_VALUE) - CloseHandle (new_token); - new_token = new_token2; +#endif } + /* Keep at most one internal token */ if (cygheap->user.internal_token != NO_IMPERSONATION) CloseHandle (cygheap->user.internal_token); diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 8879f9e06d..85405bae1e 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -69,6 +69,7 @@ static NO_COPY wincaps wincap_unknown = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_95 = { @@ -129,6 +130,7 @@ static NO_COPY wincaps wincap_95 = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_95osr2 = { @@ -189,6 +191,7 @@ static NO_COPY wincaps wincap_95osr2 = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_98 = { @@ -249,6 +252,7 @@ static NO_COPY wincaps wincap_98 = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_98se = { @@ -309,6 +313,7 @@ static NO_COPY wincaps wincap_98se = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_me = { @@ -369,6 +374,7 @@ static NO_COPY wincaps wincap_me = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_nt3 = { @@ -429,6 +435,7 @@ static NO_COPY wincaps wincap_nt3 = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:true, }; static NO_COPY wincaps wincap_nt4 = { @@ -489,6 +496,7 @@ static NO_COPY wincaps wincap_nt4 = { has_exclusiveaddruse:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:true, }; static NO_COPY wincaps wincap_nt4sp4 = { @@ -549,6 +557,7 @@ static NO_COPY wincaps wincap_nt4sp4 = { has_exclusiveaddruse:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:true, }; static NO_COPY wincaps wincap_2000 = { @@ -609,6 +618,7 @@ static NO_COPY wincaps wincap_2000 = { has_exclusiveaddruse:true, has_buggy_restart_scan:true, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:true, }; static NO_COPY wincaps wincap_xp = { @@ -669,6 +679,7 @@ static NO_COPY wincaps wincap_xp = { has_exclusiveaddruse:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_2003 = { @@ -729,6 +740,7 @@ static NO_COPY wincaps wincap_2003 = { has_exclusiveaddruse:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, + needs_logon_sid_in_sid_list:false, }; static NO_COPY wincaps wincap_vista = { @@ -789,6 +801,7 @@ static NO_COPY wincaps wincap_vista = { has_exclusiveaddruse:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:true, + needs_logon_sid_in_sid_list:false, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 63f87422b5..d40d12c1a2 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -70,6 +70,7 @@ struct wincaps unsigned has_exclusiveaddruse : 1; unsigned has_buggy_restart_scan : 1; unsigned has_mandatory_integrity_control : 1; + unsigned needs_logon_sid_in_sid_list : 1; }; class wincapc @@ -146,6 +147,7 @@ public: bool IMPLEMENT (has_exclusiveaddruse) bool IMPLEMENT (has_buggy_restart_scan) bool IMPLEMENT (has_mandatory_integrity_control) + bool IMPLEMENT (needs_logon_sid_in_sid_list) #undef IMPLEMENT };