From 42fad6ffa56f4627f414c8b76758bd71592e8400 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 17 Aug 2015 18:29:24 +0200 Subject: [PATCH] Add Authz class to compute exact POSIX user perms in a security descriptor * autoload.cc (AuthzAccessCheck): Import. (AuthzFreeContext): Import. (AuthzInitializeContextFromSid): Import. (AuthzInitializeContextFromToken): Import. (AuthzInitializeResourceManager): Import. * sec_helper.cc (get_sids_info): Remove. (class authz_ctx_cache_entry): New class. (class authz_ctx_cache): New class. (class authz_ctx): New class. (authz_get_user_attribute): New function. * security.h (get_sids_info): Drop prototype. (authz_get_user_attribute): Add prototype. * winlean.h (_AUTHZ_): Define. Signed-off-by: Corinna Vinschen --- winsup/cygwin/ChangeLog | 16 +++ winsup/cygwin/autoload.cc | 6 ++ winsup/cygwin/sec_helper.cc | 191 +++++++++++++++++++++++++++++++----- winsup/cygwin/security.h | 3 +- winsup/cygwin/winlean.h | 3 +- 5 files changed, 194 insertions(+), 25 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 987b4c008..6d0f91afe 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,19 @@ +2015-11-18 Corinna Vinschen + + * autoload.cc (AuthzAccessCheck): Import. + (AuthzFreeContext): Import. + (AuthzInitializeContextFromSid): Import. + (AuthzInitializeContextFromToken): Import. + (AuthzInitializeResourceManager): Import. + * sec_helper.cc (get_sids_info): Remove. + (class authz_ctx_cache_entry): New class. + (class authz_ctx_cache): New class. + (class authz_ctx): New class. + (authz_get_user_attribute): New function. + * security.h (get_sids_info): Drop prototype. + (authz_get_user_attribute): Add prototype. + * winlean.h (_AUTHZ_): Define. + 2015-11-18 Corinna Vinschen * sec_acl.cc (get_posix_access): Fix class_perm in !new_style case. diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 0192c6d64..e14647c2d 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -558,6 +558,12 @@ LoadDLLfunc (RegisterEventSourceW, 8, advapi32) LoadDLLfunc (ReportEventW, 36, advapi32) LoadDLLfunc (SystemFunction036, 8, advapi32) /* Aka "RtlGenRandom" */ +LoadDLLfunc (AuthzAccessCheck, 36, authz) +LoadDLLfunc (AuthzFreeContext, 4, authz) +LoadDLLfunc (AuthzInitializeContextFromSid, 32, authz) +LoadDLLfunc (AuthzInitializeContextFromToken, 32, authz) +LoadDLLfunc (AuthzInitializeResourceManager, 24, authz) + LoadDLLfunc (DnsQuery_A, 24, dnsapi) LoadDLLfunc (DnsRecordListFree, 8, dnsapi) diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index ab86aa7a4..40b8017d1 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -14,6 +14,8 @@ details. */ #include "winsup.h" #include #include +#include +#include #include #include "cygerrno.h" #include "security.h" @@ -324,29 +326,6 @@ cygsidlist::add (const PSID nsi, bool well_known) return TRUE; } -bool -get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gidret) -{ - BOOL ret = false; - cyg_ldap cldap; - - owner_sid.debug_print ("get_sids_info: owner SID ="); - group_sid.debug_print ("get_sids_info: group SID ="); - - *uidret = owner_sid.get_uid (&cldap); - *gidret = group_sid.get_gid (&cldap); - if (*uidret == myself->uid) - { - if (*gidret == myself->gid) - ret = TRUE; - else - CheckTokenMembership (cygheap->user.issetuid () - ? cygheap->user.imp_token () : NULL, - group_sid, &ret); - } - return (bool) ret; -} - PSECURITY_DESCRIPTOR security_descriptor::malloc (size_t nsize) { @@ -690,3 +669,169 @@ _everyone_sd (void *buf, ACCESS_MASK access) return psd; } +static NO_COPY muto authz_guard; +static LUID authz_dummy_luid = { 0 }; + +class authz_ctx_cache_entry +{ + SLIST_ENTRY (authz_ctx_cache_entry) ctx_next; + cygsid sid; + AUTHZ_CLIENT_CONTEXT_HANDLE ctx_hdl; + + authz_ctx_cache_entry () + : sid (NO_SID), ctx_hdl (NULL) + { + ctx_next.sle_next = NULL; + } + authz_ctx_cache_entry (bool) + : sid (NO_SID), ctx_hdl (NULL) + { + ctx_next.sle_next = NULL; + } + void set (PSID psid, AUTHZ_CLIENT_CONTEXT_HANDLE hdl) + { + sid = psid; + ctx_hdl = hdl; + } + bool is (PSID psid) const { return RtlEqualSid (sid, psid); } + AUTHZ_CLIENT_CONTEXT_HANDLE context () const { return ctx_hdl; } + + friend class authz_ctx_cache; +}; + +class authz_ctx_cache +{ + SLIST_HEAD (, authz_ctx_cache_entry) ctx_list; + + AUTHZ_CLIENT_CONTEXT_HANDLE context (PSID); + + friend class authz_ctx; +}; + +class authz_ctx +{ + AUTHZ_RESOURCE_MANAGER_HANDLE authz_hdl; + AUTHZ_CLIENT_CONTEXT_HANDLE user_ctx_hdl; + authz_ctx_cache ctx_cache; + operator AUTHZ_RESOURCE_MANAGER_HANDLE (); + + friend class authz_ctx_cache; +public: + void get_user_attribute (mode_t *, PSECURITY_DESCRIPTOR, PSID); +}; + +/* Authz handles are not inheritable. */ +static NO_COPY authz_ctx authz; + +authz_ctx::operator AUTHZ_RESOURCE_MANAGER_HANDLE () +{ + if (!authz_hdl) + { + /* Create handle to Authz resource manager */ + authz_guard.init ("authz_guard")->acquire (); + if (!authz_hdl + && !AuthzInitializeResourceManager (AUTHZ_RM_FLAG_NO_AUDIT, + NULL, NULL, NULL, NULL, + &authz_hdl)) + debug_printf ("AuthzInitializeResourceManager, %E"); + authz_guard.release (); + } + return authz_hdl; +} + +AUTHZ_CLIENT_CONTEXT_HANDLE +authz_ctx_cache::context (PSID user_sid) +{ + authz_ctx_cache_entry *entry; + AUTHZ_CLIENT_CONTEXT_HANDLE ctx_hdl = NULL; + + SLIST_FOREACH (entry, &ctx_list, ctx_next) + { + if (entry->is (user_sid)) + return entry->context (); + } + entry = new authz_ctx_cache_entry (true); + /* If the user is the current user, prefer to create the context from the + token, as outlined in MSDN. */ + if (RtlEqualSid (user_sid, cygheap->user.sid ()) + && !AuthzInitializeContextFromToken (0, cygheap->user.issetuid () + ? cygheap->user.primary_token () + : hProcToken, + authz, NULL, authz_dummy_luid, + NULL, &ctx_hdl)) + debug_printf ("AuthzInitializeContextFromToken, %E"); + /* In any other case, create the context from the user SID. */ + else if (!AuthzInitializeContextFromSid (0, user_sid, authz, NULL, + authz_dummy_luid, NULL, &ctx_hdl)) + debug_printf ("AuthzInitializeContextFromSid, %E"); + else + { + entry->set (user_sid, ctx_hdl); + authz_guard.acquire (); + SLIST_INSERT_HEAD (&ctx_list, entry, ctx_next); + authz_guard.release (); + return entry->context (); + } + delete entry; + return NULL; +} + +/* Ask Authz for the effective user permissions of the user with SID user_sid + on the object with security descriptor psd. We're caching the handles for + the Authz resource manager and the user contexts. */ +void +authz_ctx::get_user_attribute (mode_t *attribute, PSECURITY_DESCRIPTOR psd, + PSID user_sid) +{ + /* If the owner is the main user of the process token (not some impersonated + user), cache the user context in the global user_ctx_hdl variable. */ + AUTHZ_CLIENT_CONTEXT_HANDLE ctx_hdl = NULL; + if (RtlEqualSid (user_sid, cygheap->user.sid ()) + && !cygheap->user.issetuid ()) + { + if (!user_ctx_hdl) + { + authz_guard.acquire (); + if (!AuthzInitializeContextFromToken (0, hProcToken, authz, NULL, + authz_dummy_luid, NULL, + &user_ctx_hdl)) + debug_printf ("AuthzInitializeContextFromToken, %E"); + authz_guard.release (); + } + if (user_ctx_hdl) + ctx_hdl = user_ctx_hdl; + } + if (!ctx_hdl && !(ctx_hdl = ctx_cache.context (user_sid))) + return; + /* All set, check access. */ + ACCESS_MASK access = 0; + DWORD error = 0; + AUTHZ_ACCESS_REQUEST req = { + .DesiredAccess = MAXIMUM_ALLOWED, + .PrincipalSelfSid = NULL, + .ObjectTypeList = NULL, + .ObjectTypeListLength = 0, + .OptionalArguments = NULL + }; + AUTHZ_ACCESS_REPLY repl = { + .ResultListLength = 1, + .GrantedAccessMask = &access, + .SaclEvaluationResults = NULL, + .Error = &error + }; + if (AuthzAccessCheck (0, ctx_hdl, &req, NULL, psd, NULL, 0, &repl, NULL)) + { + if (access & FILE_READ_BITS) + *attribute |= S_IRUSR; + if (access & FILE_WRITE_BITS) + *attribute |= S_IWUSR; + if (access & FILE_EXEC_BITS) + *attribute |= S_IXUSR; + } +} + +void authz_get_user_attribute (mode_t *attribute, PSECURITY_DESCRIPTOR psd, + PSID user_sid) +{ + authz.get_user_attribute (attribute, psd, user_sid); +} diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 5378b2a45..9c70121ae 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -456,7 +456,8 @@ void set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa, security_descriptor &sd_buf); -bool get_sids_info (cygpsid, cygpsid, uid_t * , gid_t *); +void authz_get_user_attribute (mode_t *attribute, PSECURITY_DESCRIPTOR psd, + PSID user_sid); /* sec_acl.cc */ struct acl; diff --git a/winsup/cygwin/winlean.h b/winsup/cygwin/winlean.h index 329199a28..cb9b07cd7 100644 --- a/winsup/cygwin/winlean.h +++ b/winsup/cygwin/winlean.h @@ -1,6 +1,6 @@ /* winlean.h - Standard "lean" windows include - Copyright 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. + Copyright 2010, 2011, 2012, 2013, 2014, 2015 Red Hat, Inc. This file is part of Cygwin. @@ -20,6 +20,7 @@ details. */ autoloaded symbols, which in turn clashes with the definition in the w32api library exporting the symbols. */ #define _ADVAPI32_ +#define _AUTHZ_ #define _DSGETDCAPI_ #define _GDI32_ #define _KERNEL32_