From c52fd6cd475b1e65f7c5e1eda4b1f4600553ae30 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 15 Oct 2011 16:31:57 +0000 Subject: [PATCH] * sec_auth.cc (get_token_group_sidlist): Add CONSOLE LOGON SID on systems supporting it. Never add SERVICE SID but keep code in for future reference. Explain why. (get_priv_list): Add cygpsid pointer parameter. Point it to the mandatory integrity SID which matches account and privileges. (create_token): Fetch mandatory integrity SID from call to get_priv_list. (lsaauth): Call get_priv_list with additional NULL pointer. Change comment accordingly. * sec_helper.cc (well_known_console_logon_sid): New static SID. (cygpriv): Change to structure containing extra flag to store info about required integrity level. (privilege_luid): Accommodate changes to cygpriv. Return integrity level in new high_integrity parameter. (privilege_name): Accommodate changes to cygpriv. (set_privilege): Drop trailing \n from debug output. (set_cygwin_privileges): Don't set SE_CREATE_GLOBAL_PRIVILEGE anymore since it's just not needed, but keep code in for future reference. Change comment accordingly. * security.h (well_known_console_logon_sid): Declare. (privilege_luid): Align declaration to above change. * wincap.h (wincaps::has_console_logon_sid): New element. * wincap.cc: Implement above element throughout. --- winsup/cygwin/ChangeLog | 26 +++++++++ winsup/cygwin/sec_auth.cc | 55 ++++++++++++------- winsup/cygwin/sec_helper.cc | 103 ++++++++++++++++++++---------------- winsup/cygwin/security.h | 3 +- winsup/cygwin/wincap.cc | 8 +++ winsup/cygwin/wincap.h | 2 + 6 files changed, 130 insertions(+), 67 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index afd6fdebb..d715b5139 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,29 @@ +2011-10-15 Corinna Vinschen + + * sec_auth.cc (get_token_group_sidlist): Add CONSOLE LOGON SID on + systems supporting it. Never add SERVICE SID but keep code in for + future reference. Explain why. + (get_priv_list): Add cygpsid pointer parameter. Point it to the + mandatory integrity SID which matches account and privileges. + (create_token): Fetch mandatory integrity SID from call to + get_priv_list. + (lsaauth): Call get_priv_list with additional NULL pointer. Change + comment accordingly. + * sec_helper.cc (well_known_console_logon_sid): New static SID. + (cygpriv): Change to structure containing extra flag to store info + about required integrity level. + (privilege_luid): Accommodate changes to cygpriv. Return integrity + level in new high_integrity parameter. + (privilege_name): Accommodate changes to cygpriv. + (set_privilege): Drop trailing \n from debug output. + (set_cygwin_privileges): Don't set SE_CREATE_GLOBAL_PRIVILEGE anymore + since it's just not needed, but keep code in for future reference. + Change comment accordingly. + * security.h (well_known_console_logon_sid): Declare. + (privilege_luid): Align declaration to above change. + * wincap.h (wincaps::has_console_logon_sid): New element. + * wincap.cc: Implement above element throughout. + 2011-10-13 Corinna Vinschen * path.cc (find_fast_cwd_pointer): Allow 'push crit-sect-addr' instead diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc index 6fc3f5ada..545f7d336 100644 --- a/winsup/cygwin/sec_auth.cc +++ b/winsup/cygwin/sec_auth.cc @@ -416,6 +416,8 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, 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)) @@ -423,8 +425,15 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, 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; @@ -578,7 +587,7 @@ get_system_priv_list (size_t &size) static PTOKEN_PRIVILEGES get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, - size_t &size) + size_t &size, cygpsid *mandatory_integrity_sid) { PLSA_UNICODE_STRING privstrs; ULONG cnt; @@ -586,7 +595,14 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, NTSTATUS ret; if (usersid == well_known_system_sid) - return get_system_priv_list (size); + { + 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) { @@ -605,8 +621,9 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, LUID priv; PTOKEN_PRIVILEGES tmp; DWORD tmp_count; + bool high_integrity; - if (!privilege_luid (privstrs[i].Buffer, &priv)) + if (!privilege_luid (privstrs[i].Buffer, priv, high_integrity)) continue; if (privs) @@ -637,6 +654,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list, 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: ; @@ -805,6 +824,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) HANDLE primary_token = INVALID_HANDLE_VALUE; PTOKEN_GROUPS my_tok_gsids = NULL; + cygpsid mandatory_integrity_sid; ULONG size; size_t psize = 0; @@ -888,26 +908,22 @@ 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. */ + /* 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; - 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; + new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid + = mandatory_integrity_sid; } - /* Retrieve list of privileges of that user. */ - if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize))) - goto out; - /* Let's be heroic... */ status = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, @@ -1035,8 +1051,9 @@ lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw) if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0) gsize += RtlLengthSid (tmp_gsids.sids[tmpidx]); - /* Retrieve list of privileges of that user. */ - if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize))) + /* 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. */ diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index c3531d321..d72c66b48 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -37,6 +37,8 @@ MKSID (well_known_world_sid, "S-1-1-0", SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID); MKSID (well_known_local_sid, "S-1-2-0", SECURITY_LOCAL_SID_AUTHORITY, 1, SECURITY_LOCAL_RID); +MKSID (well_known_console_logon_sid, "S-1-2-1", + SECURITY_LOCAL_SID_AUTHORITY, 1, 1); MKSID (well_known_creator_owner_sid, "S-1-3-0", SECURITY_CREATOR_SID_AUTHORITY, 1, SECURITY_CREATOR_OWNER_RID); MKSID (well_known_creator_group_sid, "S-1-3-1", @@ -331,58 +333,64 @@ security_descriptor::free () #undef TEXT #define TEXT(q) L##q -/* Index must match the correspoding foo_PRIVILEGE value, see security.h. */ -static const wchar_t *cygpriv[] = +/* Index must match the corresponding foo_PRIVILEGE value, see security.h. */ +static const struct { + const wchar_t *name; + bool high_integrity; /* UAC: High Mandatory Label required to + be allowed to enable this privilege in + the user token. */ +} cygpriv[] = { - L"", - L"", - SE_CREATE_TOKEN_NAME, - SE_ASSIGNPRIMARYTOKEN_NAME, - SE_LOCK_MEMORY_NAME, - SE_INCREASE_QUOTA_NAME, - SE_MACHINE_ACCOUNT_NAME, - SE_TCB_NAME, - SE_SECURITY_NAME, - SE_TAKE_OWNERSHIP_NAME, - SE_LOAD_DRIVER_NAME, - SE_SYSTEM_PROFILE_NAME, - SE_SYSTEMTIME_NAME, - SE_PROF_SINGLE_PROCESS_NAME, - SE_INC_BASE_PRIORITY_NAME, - SE_CREATE_PAGEFILE_NAME, - SE_CREATE_PERMANENT_NAME, - SE_BACKUP_NAME, - SE_RESTORE_NAME, - SE_SHUTDOWN_NAME, - SE_DEBUG_NAME, - SE_AUDIT_NAME, - SE_SYSTEM_ENVIRONMENT_NAME, - SE_CHANGE_NOTIFY_NAME, - SE_REMOTE_SHUTDOWN_NAME, - SE_UNDOCK_NAME, - SE_SYNC_AGENT_NAME, - SE_ENABLE_DELEGATION_NAME, - SE_MANAGE_VOLUME_NAME, - SE_IMPERSONATE_NAME, - SE_CREATE_GLOBAL_NAME, - SE_TRUSTED_CREDMAN_ACCESS_NAME, - SE_RELABEL_NAME, - SE_INCREASE_WORKING_SET_NAME, - SE_TIME_ZONE_NAME, - SE_CREATE_SYMBOLIC_LINK_NAME + { L"", false }, + { L"", false }, + { SE_CREATE_TOKEN_NAME, true }, + { SE_ASSIGNPRIMARYTOKEN_NAME, true }, + { SE_LOCK_MEMORY_NAME, false }, + { SE_INCREASE_QUOTA_NAME, true }, + { SE_MACHINE_ACCOUNT_NAME, false }, + { SE_TCB_NAME, true }, + { SE_SECURITY_NAME, true }, + { SE_TAKE_OWNERSHIP_NAME, true }, + { SE_LOAD_DRIVER_NAME, true }, + { SE_SYSTEM_PROFILE_NAME, true }, + { SE_SYSTEMTIME_NAME, true }, + { SE_PROF_SINGLE_PROCESS_NAME, true }, + { SE_INC_BASE_PRIORITY_NAME, true }, + { SE_CREATE_PAGEFILE_NAME, true }, + { SE_CREATE_PERMANENT_NAME, false }, + { SE_BACKUP_NAME, true }, + { SE_RESTORE_NAME, true }, + { SE_SHUTDOWN_NAME, false }, + { SE_DEBUG_NAME, true }, + { SE_AUDIT_NAME, false }, + { SE_SYSTEM_ENVIRONMENT_NAME, true }, + { SE_CHANGE_NOTIFY_NAME, false }, + { SE_REMOTE_SHUTDOWN_NAME, true }, + { SE_UNDOCK_NAME, false }, + { SE_SYNC_AGENT_NAME, false }, + { SE_ENABLE_DELEGATION_NAME, false }, + { SE_MANAGE_VOLUME_NAME, true }, + { SE_IMPERSONATE_NAME, true }, + { SE_CREATE_GLOBAL_NAME, false }, + { SE_TRUSTED_CREDMAN_ACCESS_NAME, false }, + { SE_RELABEL_NAME, true }, + { SE_INCREASE_WORKING_SET_NAME, false }, + { SE_TIME_ZONE_NAME, true }, + { SE_CREATE_SYMBOLIC_LINK_NAME, true } }; bool -privilege_luid (const PWCHAR pname, LUID *luid) +privilege_luid (const PWCHAR pname, LUID &luid, bool &high_integrity) { ULONG idx; for (idx = SE_CREATE_TOKEN_PRIVILEGE; idx <= SE_MAX_WELL_KNOWN_PRIVILEGE; ++idx) - if (!wcscmp (cygpriv[idx], pname)) + if (!wcscmp (cygpriv[idx].name, pname)) { - luid->HighPart = 0; - luid->LowPart = idx; + luid.HighPart = 0; + luid.LowPart = idx; + high_integrity = cygpriv[idx].high_integrity; return true; } return false; @@ -394,7 +402,7 @@ privilege_name (const LUID &priv_luid) if (priv_luid.HighPart || priv_luid.LowPart < SE_CREATE_TOKEN_PRIVILEGE || priv_luid.LowPart > SE_MAX_WELL_KNOWN_PRIVILEGE) return L""; - return cygpriv[priv_luid.LowPart]; + return cygpriv[priv_luid.LowPart].name; } int @@ -426,7 +434,7 @@ set_privilege (HANDLE token, DWORD privilege, bool enable) out: if (ret < 0) - debug_printf ("%d = set_privilege ((token %x) %W, %d)\n", ret, token, + debug_printf ("%d = set_privilege ((token %x) %W, %d)", ret, token, privilege_name (new_priv.Privileges[0].Luid), enable); return ret; } @@ -444,12 +452,13 @@ set_cygwin_privileges (HANDLE token) set_privilege (token, SE_BACKUP_PRIVILEGE, true); /* Allow full access to other user's processes. */ set_privilege (token, SE_DEBUG_PRIVILEGE, true); - /* Allow to create global shared memory. This shouldn't be required since +#if 0 + /* Allow to create global shared memory. This isn't required anymore since Cygwin 1.7. It uses its own subdirectories in the global NT namespace - which isn't affected by the SE_CREATE_GLOBAL_PRIVILEGE restriction. - Anyway, better safe than sorry. */ + which isn't affected by the SE_CREATE_GLOBAL_PRIVILEGE restriction. */ if (wincap.has_create_global_privilege ()) set_privilege (token, SE_CREATE_GLOBAL_PRIVILEGE, true); +#endif } /* Function to return a common SECURITY_DESCRIPTOR that diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 0a71221e2..6629260d2 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -330,6 +330,7 @@ public: extern cygpsid well_known_null_sid; extern cygpsid well_known_world_sid; extern cygpsid well_known_local_sid; +extern cygpsid well_known_console_logon_sid; extern cygpsid well_known_creator_owner_sid; extern cygpsid well_known_creator_group_sid; extern cygpsid well_known_dialup_sid; @@ -349,7 +350,7 @@ extern cygpsid mandatory_high_integrity_sid; extern cygpsid mandatory_system_integrity_sid; extern cygpsid well_known_samba_unix_user_fake_sid; -bool privilege_luid (const PWCHAR pname, LUID *luid); +bool privilege_luid (const PWCHAR pname, LUID &luid, bool &high_integrity); inline BOOL well_known_sid_type (SID_NAME_USE type) diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 25acbf3f4..338350f72 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -51,6 +51,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:false, use_dont_resolve_hack:false, has_stack_size_param_is_a_reservation:false, + has_console_logon_sid:false, }; wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -81,6 +82,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_restricted_raw_disk_access:false, use_dont_resolve_hack:false, has_stack_size_param_is_a_reservation:false, + has_console_logon_sid:false, }; wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -111,6 +113,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:false, use_dont_resolve_hack:true, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:false, }; wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -141,6 +144,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:false, use_dont_resolve_hack:true, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:false, }; wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -171,6 +175,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:false, use_dont_resolve_hack:true, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:false, }; wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -201,6 +206,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:false, use_dont_resolve_hack:true, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:false, }; wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -231,6 +237,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:true, use_dont_resolve_hack:false, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:false, }; wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -261,6 +268,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { has_restricted_raw_disk_access:true, use_dont_resolve_hack:false, has_stack_size_param_is_a_reservation:true, + has_console_logon_sid:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index eab78fd03..32f958686 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -41,6 +41,7 @@ struct wincaps unsigned has_restricted_raw_disk_access : 1; unsigned use_dont_resolve_hack : 1; unsigned has_stack_size_param_is_a_reservation : 1; + unsigned has_console_logon_sid : 1; }; class wincapc @@ -90,6 +91,7 @@ public: bool IMPLEMENT (has_restricted_raw_disk_access) bool IMPLEMENT (use_dont_resolve_hack) bool IMPLEMENT (has_stack_size_param_is_a_reservation) + bool IMPLEMENT (has_console_logon_sid) #undef IMPLEMENT };