* security.cc: Change some formatting.
* include/cygwin/version.h: Bump API minor version.
        * cygheap.h (class cygheap_user): Add member groups.
        * security.h (class cygsidlist): Add members type and maxcount,
        methods position, addfromgr, alloc_sids and free_sids and
        operator+= (const PSID psid). Modify contains () to call
        position () and optimize add () to use maxcount.
        (class user_groups): Create.
        Update declarations of verify_token and create_token.
        * security.cc (cygsidlist::alloc_sids): New.
        (cygsidlist::free_sids): New.
        (get_token_group_sidlist): Create from get_group_sidlist.
        (get_initgroups_sidlist): Create from get_group_sidlist.
        (get_group_sidlist): Suppress.
        (get_setgroups_sidlist): Create.
        (verify_token): Modify arguments. Add setgroups case.
        (create_token): Modify arguments. Call get_initgroups_sidlist and
        get_setgroups_sidlist as needed. Set SE_GROUP_LOGON_ID from auth_pos
        outside of the loop. Rename the various group sid lists consistently.
        * syscalls.cc (seteuid32): Modify to use cygheap->user.groups.
        (setegid32): Call cygheap->user.groups.update_pgrp.
        * grp.cc (setgroups): Create.
        (setgroups32): Create.
        * uinfo.cc (internal_getlogin): Initialize and update user.groups.pgsid.
        * cygwin.din: Add setgroups and setgroups32.
			
			
This commit is contained in:
		| @@ -1,3 +1,34 @@ | |||||||
|  | 2002-07-29  Corinna Vinschen  <corinna@vinschen.de> | ||||||
|  |  | ||||||
|  | 	* security.cc: Change some formatting. | ||||||
|  | 	* include/cygwin/version.h: Bump API minor version. | ||||||
|  |  | ||||||
|  | 2002-07-28 Pierre Humblet <Pierre.Humblet@ieee.org> | ||||||
|  |  | ||||||
|  |         * cygheap.h (class cygheap_user): Add member groups. | ||||||
|  |         * security.h (class cygsidlist): Add members type and maxcount, | ||||||
|  |         methods position, addfromgr, alloc_sids and free_sids and | ||||||
|  |         operator+= (const PSID psid). Modify contains () to call | ||||||
|  |         position () and optimize add () to use maxcount. | ||||||
|  |         (class user_groups): Create. | ||||||
|  |         Update declarations of verify_token and create_token. | ||||||
|  |         * security.cc (cygsidlist::alloc_sids): New. | ||||||
|  |         (cygsidlist::free_sids): New. | ||||||
|  |         (get_token_group_sidlist): Create from get_group_sidlist. | ||||||
|  |         (get_initgroups_sidlist): Create from get_group_sidlist. | ||||||
|  |         (get_group_sidlist): Suppress. | ||||||
|  |         (get_setgroups_sidlist): Create. | ||||||
|  |         (verify_token): Modify arguments. Add setgroups case. | ||||||
|  |         (create_token): Modify arguments. Call get_initgroups_sidlist and | ||||||
|  |         get_setgroups_sidlist as needed. Set SE_GROUP_LOGON_ID from auth_pos | ||||||
|  |         outside of the loop. Rename the various group sid lists consistently. | ||||||
|  |         * syscalls.cc (seteuid32): Modify to use cygheap->user.groups. | ||||||
|  |         (setegid32): Call cygheap->user.groups.update_pgrp. | ||||||
|  |         * grp.cc (setgroups): Create. | ||||||
|  |         (setgroups32): Create. | ||||||
|  |         * uinfo.cc (internal_getlogin): Initialize and update user.groups.pgsid. | ||||||
|  |         * cygwin.din: Add setgroups and setgroups32. | ||||||
|  |  | ||||||
| 2002-07-28  Christopher Faylor  <cgf@redhat.com> | 2002-07-28  Christopher Faylor  <cgf@redhat.com> | ||||||
|  |  | ||||||
| 	* fhandler_console.cc (fhandler_console::read): Use appropriate | 	* fhandler_console.cc (fhandler_console::read): Use appropriate | ||||||
|   | |||||||
| @@ -113,6 +113,7 @@ public: | |||||||
|   __gid32_t orig_gid;      /* Ditto */ |   __gid32_t orig_gid;      /* Ditto */ | ||||||
|   __uid32_t real_uid;      /* Remains intact on seteuid, replaced by setuid */ |   __uid32_t real_uid;      /* Remains intact on seteuid, replaced by setuid */ | ||||||
|   __gid32_t real_gid;      /* Ditto */ |   __gid32_t real_gid;      /* Ditto */ | ||||||
|  |   user_groups groups;      /* Primary and supp SIDs */ | ||||||
|  |  | ||||||
|   /* token is needed if set(e)uid should be called. It can be set by a call |   /* token is needed if set(e)uid should be called. It can be set by a call | ||||||
|      to `set_impersonation_token()'. */ |      to `set_impersonation_token()'. */ | ||||||
|   | |||||||
| @@ -678,6 +678,9 @@ _setdtablesize = setdtablesize | |||||||
| setgid | setgid | ||||||
| _setgid = setgid | _setgid = setgid | ||||||
| setgid32 | setgid32 | ||||||
|  | setgroups | ||||||
|  | _setgroups = setgroups | ||||||
|  | setgroups32 | ||||||
| setjmp | setjmp | ||||||
| _setjmp = setjmp | _setjmp = setjmp | ||||||
| setlocale | setlocale | ||||||
|   | |||||||
| @@ -457,3 +457,64 @@ initgroups (const char *, __gid16_t) | |||||||
| { | { | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* setgroups32: standards? */ | ||||||
|  | extern "C" | ||||||
|  | int | ||||||
|  | setgroups32 (int ngroups, const __gid32_t *grouplist) | ||||||
|  | { | ||||||
|  |   if (ngroups < 0 || (ngroups > 0 && !grouplist)) | ||||||
|  |     { | ||||||
|  |       set_errno (EINVAL); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   if (!wincap.has_security ()) | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |   cygsidlist gsids (cygsidlist_alloc, ngroups); | ||||||
|  |   struct __group32 *gr; | ||||||
|  |  | ||||||
|  |   if (ngroups && !gsids.sids) | ||||||
|  |     return -1; | ||||||
|  |  | ||||||
|  |   for (int gidx = 0; gidx < ngroups; ++gidx) | ||||||
|  |     { | ||||||
|  |       for (int gidy = 0; gidy < gidx; gidy++) | ||||||
|  | 	if (grouplist[gidy] == grouplist[gidx]) | ||||||
|  | 	  goto found; /* Duplicate */ | ||||||
|  |       for (int gidy = 0; (gr = internal_getgrent (gidy)); ++gidy) | ||||||
|  | 	if (gr->gr_gid == (__gid32_t) grouplist[gidx]) | ||||||
|  | 	  { | ||||||
|  | 	    if (gsids.addfromgr (gr)) | ||||||
|  | 	      goto found; | ||||||
|  | 	    break; | ||||||
|  | 	  } | ||||||
|  |       debug_printf ("No sid found for gid %d", grouplist[gidx]); | ||||||
|  |       gsids.free_sids (); | ||||||
|  |       set_errno (EINVAL); | ||||||
|  |       return -1; | ||||||
|  |     found: | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |   cygheap->user.groups.update_supp (gsids); | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | extern "C" | ||||||
|  | int | ||||||
|  | setgroups (int ngroups, const __gid16_t *grouplist) | ||||||
|  | { | ||||||
|  |   __gid32_t *grouplist32 = NULL; | ||||||
|  |  | ||||||
|  |   if (ngroups > 0 && grouplist) | ||||||
|  |     { | ||||||
|  |       grouplist32 = (__gid32_t *) alloca (ngroups * sizeof (__gid32_t)); | ||||||
|  |       if (grouplist32 == NULL) | ||||||
|  | 	return -1; | ||||||
|  |       for (int i = 0; i < ngroups; i++) | ||||||
|  |         grouplist32[i] = grouplist[i]; | ||||||
|  |     } | ||||||
|  |   return setgroups32 (ngroups, grouplist32); | ||||||
|  |  | ||||||
|  | } | ||||||
|   | |||||||
| @@ -154,12 +154,13 @@ details. */ | |||||||
|        54: Export __fpclassifyd, __fpclassifyf, __signbitd, __signbitf. |        54: Export __fpclassifyd, __fpclassifyf, __signbitd, __signbitf. | ||||||
|        55: Export fcloseall, fcloseall_r. |        55: Export fcloseall, fcloseall_r. | ||||||
|        56: Make ntsec on by default. |        56: Make ntsec on by default. | ||||||
|  |        57: Export setgroups. | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ |      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ | ||||||
|  |  | ||||||
| #define CYGWIN_VERSION_API_MAJOR 0 | #define CYGWIN_VERSION_API_MAJOR 0 | ||||||
| #define CYGWIN_VERSION_API_MINOR 56 | #define CYGWIN_VERSION_API_MINOR 57 | ||||||
|  |  | ||||||
|      /* There is also a compatibity version number associated with the |      /* There is also a compatibity version number associated with the | ||||||
| 	shared memory regions.  It is incremented when incompatible | 	shared memory regions.  It is incremented when incompatible | ||||||
|   | |||||||
| @@ -47,6 +47,22 @@ BOOL allow_ntsec = true; | |||||||
|    The default is TRUE to reflect the old behaviour. */ |    The default is TRUE to reflect the old behaviour. */ | ||||||
| BOOL allow_smbntsec; | BOOL allow_smbntsec; | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  | } | ||||||
|  |  | ||||||
| extern "C" void | extern "C" void | ||||||
| cygwin_set_impersonation_token (const HANDLE hToken) | cygwin_set_impersonation_token (const HANDLE hToken) | ||||||
| { | { | ||||||
| @@ -152,7 +168,7 @@ str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr) | |||||||
|   sys_mbstowcs (buf, srcstr, tgt.MaximumLength); |   sys_mbstowcs (buf, srcstr, tgt.MaximumLength); | ||||||
| } | } | ||||||
|  |  | ||||||
| #if 0 //unused | #if 0				/* unused */ | ||||||
| static void | static void | ||||||
| lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size) | lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size) | ||||||
| { | { | ||||||
| @@ -194,7 +210,7 @@ close_local_policy (LSA_HANDLE &lsa) | |||||||
|   lsa = INVALID_HANDLE_VALUE; |   lsa = INVALID_HANDLE_VALUE; | ||||||
| } | } | ||||||
|  |  | ||||||
| #if 0 // unused | #if 0 /* unused */ | ||||||
| static BOOL | static BOOL | ||||||
| get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) | get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) | ||||||
| { | { | ||||||
| @@ -226,7 +242,8 @@ get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) | |||||||
|      not member of a domain.  The name in the primary domain info is the |      not member of a domain.  The name in the primary domain info is the | ||||||
|      name of the workgroup then. */ |      name of the workgroup then. */ | ||||||
|   if (pdi->Sid && |   if (pdi->Sid && | ||||||
|       (ret = NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS) |       (ret = | ||||||
|  |        NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS) | ||||||
|     { |     { | ||||||
|       sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); |       sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); | ||||||
|       strcpy (logonserver, name); |       strcpy (logonserver, name); | ||||||
| @@ -271,7 +288,8 @@ get_logon_server (const char *domain, char *server, WCHAR *wserver) | |||||||
|     { |     { | ||||||
|       sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); |       sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); | ||||||
|       if (wserver) |       if (wserver) | ||||||
| 	for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++); ) {} | 	for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);) | ||||||
|  | 	  ; | ||||||
|       NetApiBufferFree (buf); |       NetApiBufferFree (buf); | ||||||
|       return TRUE; |       return TRUE; | ||||||
|     } |     } | ||||||
| @@ -280,7 +298,8 @@ get_logon_server (const char *domain, char *server, WCHAR *wserver) | |||||||
| } | } | ||||||
|  |  | ||||||
| static BOOL | static BOOL | ||||||
| get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, char *domain) | get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, | ||||||
|  | 		 char *domain) | ||||||
| { | { | ||||||
|   char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; |   char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; | ||||||
|   WCHAR wuser[UNLEN + 1]; |   WCHAR wuser[UNLEN + 1]; | ||||||
| @@ -316,7 +335,8 @@ get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, char *do | |||||||
| 	debug_printf ("LookupAccountName(%s): %E", dgroup); | 	debug_printf ("LookupAccountName(%s): %E", dgroup); | ||||||
|       else if (legal_sid_type (use)) |       else if (legal_sid_type (use)) | ||||||
| 	grp_list += gsid; | 	grp_list += gsid; | ||||||
|       else debug_printf ("Global group %s invalid. Domain: %s Use: %d", |       else | ||||||
|  | 	debug_printf ("Global group %s invalid. Domain: %s Use: %d", | ||||||
| 		      dgroup, domain, use); | 		      dgroup, domain, use); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -441,7 +461,8 @@ get_user_primary_group (WCHAR *wlogonserver, const char *user, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|   pgrpsid = pusersid; |   pgrpsid = pusersid; | ||||||
|   if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) |   if (IsValidSid (pgrpsid) | ||||||
|  |       && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) | ||||||
|     { |     { | ||||||
|       *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; |       *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; | ||||||
|       retval = TRUE; |       retval = TRUE; | ||||||
| @@ -473,29 +494,11 @@ get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static BOOL | static void | ||||||
| get_group_sidlist (cygsidlist &grp_list, | get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, | ||||||
| 		   cygsid &usersid, cygsid &pgrpsid, struct passwd *pw, | 			 LUID auth_luid, int &auth_pos) | ||||||
| 		   PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos, |  | ||||||
| 		   BOOL *special_pgrp) |  | ||||||
| { | { | ||||||
|   char user[UNLEN + 1]; |  | ||||||
|   char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |  | ||||||
|   WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; |  | ||||||
|   char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; |  | ||||||
|   cygsidlist sup_list; |  | ||||||
|  |  | ||||||
|   auth_pos = -1; |   auth_pos = -1; | ||||||
|  |  | ||||||
|   grp_list += well_known_world_sid; |  | ||||||
|   grp_list += well_known_authenticated_users_sid; |  | ||||||
|   if (usersid == well_known_system_sid) |  | ||||||
|     { |  | ||||||
|       grp_list += well_known_admins_sid; |  | ||||||
|       get_unix_group_sidlist (pw, grp_list); |  | ||||||
|     } |  | ||||||
|   else |  | ||||||
|     { |  | ||||||
|   if (my_grps) |   if (my_grps) | ||||||
|     { |     { | ||||||
|       if (sid_in_token_groups (my_grps, well_known_local_sid)) |       if (sid_in_token_groups (my_grps, well_known_local_sid)) | ||||||
| @@ -524,6 +527,30 @@ get_group_sidlist (cygsidlist &grp_list, | |||||||
|       grp_list += buf; |       grp_list += buf; | ||||||
|       auth_pos = grp_list.count - 1; |       auth_pos = grp_list.count - 1; | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static BOOL | ||||||
|  | get_initgroups_sidlist (cygsidlist &grp_list, | ||||||
|  | 			PSID usersid, PSID pgrpsid, struct passwd *pw, | ||||||
|  | 			PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos, | ||||||
|  | 			BOOL &special_pgrp) | ||||||
|  | { | ||||||
|  |   grp_list += well_known_world_sid; | ||||||
|  |   grp_list += well_known_authenticated_users_sid; | ||||||
|  |   if (usersid == well_known_system_sid) | ||||||
|  |     { | ||||||
|  |       auth_pos = -1; | ||||||
|  |       grp_list += well_known_admins_sid; | ||||||
|  |       get_unix_group_sidlist (pw, grp_list); | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       char user[UNLEN + 1]; | ||||||
|  |       char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | ||||||
|  |       WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; | ||||||
|  |       char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; | ||||||
|  |  | ||||||
|  |       get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos); | ||||||
|       extract_nt_dom_user (pw, domain, user); |       extract_nt_dom_user (pw, domain, user); | ||||||
|       if (get_logon_server (domain, server, wserver)) |       if (get_logon_server (domain, server, wserver)) | ||||||
| 	get_user_groups (wserver, grp_list, user, domain); | 	get_user_groups (wserver, grp_list, user, domain); | ||||||
| @@ -531,16 +558,26 @@ get_group_sidlist (cygsidlist &grp_list, | |||||||
|       if (!get_user_local_groups (grp_list, usersid)) |       if (!get_user_local_groups (grp_list, usersid)) | ||||||
| 	return FALSE; | 	return FALSE; | ||||||
|     } |     } | ||||||
|   /* special_pgrp true if pgrpsid is not null and not in normal groups */ |   /* special_pgrp true if pgrpsid is not in normal groups */ | ||||||
|   *special_pgrp = FALSE; |   if ((special_pgrp = !grp_list.contains (pgrpsid))) | ||||||
|   if (pgrpsid && !grp_list.contains (pgrpsid)) |  | ||||||
|     { |  | ||||||
|        *special_pgrp = TRUE; |  | ||||||
|     grp_list += pgrpsid; |     grp_list += pgrpsid; | ||||||
|     } |  | ||||||
|   return TRUE; |   return TRUE; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | get_setgroups_sidlist (cygsidlist &tmp_list, 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; | ||||||
|  |   get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos); | ||||||
|  |   for (int gidx = 0; gidx < groups.sgsids.count; gidx++) | ||||||
|  |     tmp_list += groups.sgsids.sids[gidx]; | ||||||
|  |   if (!groups.sgsids.contains (pgpsid)) | ||||||
|  |     tmp_list += pgpsid; | ||||||
|  | } | ||||||
|  |  | ||||||
| static const char *sys_privs[] = { | static const char *sys_privs[] = { | ||||||
|   SE_TCB_NAME, |   SE_TCB_NAME, | ||||||
|   SE_ASSIGNPRIMARYTOKEN_NAME, |   SE_ASSIGNPRIMARYTOKEN_NAME, | ||||||
| @@ -569,8 +606,8 @@ PTOKEN_PRIVILEGES | |||||||
| get_system_priv_list (cygsidlist &grp_list) | get_system_priv_list (cygsidlist &grp_list) | ||||||
| { | { | ||||||
|   LUID priv; |   LUID priv; | ||||||
|   PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (sizeof (ULONG) + |   PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) | ||||||
| 					    20 * sizeof (LUID_AND_ATTRIBUTES)); |     malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES)); | ||||||
|   if (!privs) |   if (!privs) | ||||||
|     { |     { | ||||||
|       debug_printf ("malloc (system_privs) failed."); |       debug_printf ("malloc (system_privs) failed."); | ||||||
| @@ -605,8 +642,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) | |||||||
|     { |     { | ||||||
|       if (grp == -1) |       if (grp == -1) | ||||||
| 	{ | 	{ | ||||||
| 	  if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt)) | 	  if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, | ||||||
| 	      != STATUS_SUCCESS) | 						&cnt)) != STATUS_SUCCESS) | ||||||
| 	    continue; | 	    continue; | ||||||
| 	} | 	} | ||||||
|       else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], |       else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], | ||||||
| @@ -654,8 +691,21 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) | |||||||
|   return privs; |   return privs; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Accept a token if | ||||||
|  |    - the requested usersid matches the TokenUser and | ||||||
|  |    - if setgroups has been called: | ||||||
|  |         the token groups that are listed in /etc/group match the union of | ||||||
|  | 	the requested primary and supplementary groups in gsids. | ||||||
|  |    - else the (unknown) implicitly requested supplementary groups and those | ||||||
|  |         in the token are the groups associated with the usersid. We assume | ||||||
|  | 	they match and verify only the primary groups. | ||||||
|  | 	The requested primary group must appear in the token. | ||||||
|  | 	The primary group in the token is a group associated with the usersid, | ||||||
|  | 	except if the token is internal and the group is in the token SD | ||||||
|  | 	(see create_token). In that latter case that group must match the | ||||||
|  | 	requested primary group.  */ | ||||||
| BOOL | BOOL | ||||||
| verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) | verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern) | ||||||
| { | { | ||||||
|   DWORD size; |   DWORD size; | ||||||
|   BOOL intern = FALSE; |   BOOL intern = FALSE; | ||||||
| @@ -666,18 +716,20 @@ verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) | |||||||
|       if (!GetTokenInformation (cygheap->user.token, TokenSource, |       if (!GetTokenInformation (cygheap->user.token, TokenSource, | ||||||
| 				&ts, sizeof ts, &size)) | 				&ts, sizeof ts, &size)) | ||||||
| 	debug_printf ("GetTokenInformation(): %E"); | 	debug_printf ("GetTokenInformation(): %E"); | ||||||
|       else *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); |       else | ||||||
|  | 	*pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); | ||||||
|     } |     } | ||||||
|   /* Verify usersid */ |   /* Verify usersid */ | ||||||
|   cygsid tok_usersid = NO_SID; |   cygsid tok_usersid = NO_SID; | ||||||
|   if (!GetTokenInformation (token, TokenUser, |   if (!GetTokenInformation (token, TokenUser, | ||||||
| 			    &tok_usersid, sizeof tok_usersid, &size)) | 			    &tok_usersid, sizeof tok_usersid, &size)) | ||||||
|     debug_printf ("GetTokenInformation(): %E"); |     debug_printf ("GetTokenInformation(): %E"); | ||||||
|   if (usersid != tok_usersid) return FALSE; |   if (usersid != tok_usersid) | ||||||
|  |     return FALSE; | ||||||
|  |  | ||||||
|   /* In an internal token, if the sd group is not well_known_null_sid, |   /* For an internal token, if setgroups was not called and if the sd group | ||||||
|      it must match pgrpsid */ |      is not well_known_null_sid, it must match pgrpsid */ | ||||||
|   if (intern) |   if (intern && !groups.issetgroups ()) | ||||||
|     { |     { | ||||||
|       char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)]; |       char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)]; | ||||||
|       PSID gsid = NO_SID; |       PSID gsid = NO_SID; | ||||||
| @@ -688,14 +740,15 @@ verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) | |||||||
|       else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf, |       else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf, | ||||||
| 					    &gsid, (BOOL *) &size)) | 					    &gsid, (BOOL *) &size)) | ||||||
| 	debug_printf ("GetSecurityDescriptorGroup(): %E"); | 	debug_printf ("GetSecurityDescriptorGroup(): %E"); | ||||||
|        if (well_known_null_sid != gsid) return pgrpsid == gsid; |       if (well_known_null_sid != gsid) | ||||||
|  | 	return gsid == groups.pgsid; | ||||||
|     } |     } | ||||||
|   /* See if the pgrpsid is the tok_usersid in the token groups */ |  | ||||||
|   PTOKEN_GROUPS my_grps = NULL; |   PTOKEN_GROUPS my_grps = NULL; | ||||||
|   BOOL ret = FALSE; |   BOOL ret = FALSE; | ||||||
|  |   char saw_buf[NGROUPS_MAX] = {}; | ||||||
|  |   char *saw = saw_buf, sawpg = FALSE; | ||||||
|  |  | ||||||
|   if ( pgrpsid == tok_usersid) |  | ||||||
|     return TRUE; |  | ||||||
|   if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) && |   if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) && | ||||||
|       GetLastError () != ERROR_INSUFFICIENT_BUFFER) |       GetLastError () != ERROR_INSUFFICIENT_BUFFER) | ||||||
|     debug_printf ("GetTokenInformation(token, TokenGroups): %E\n"); |     debug_printf ("GetTokenInformation(token, TokenGroups): %E\n"); | ||||||
| @@ -703,34 +756,66 @@ verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern) | |||||||
|     debug_printf ("malloc (my_grps) failed."); |     debug_printf ("malloc (my_grps) failed."); | ||||||
|   else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size)) |   else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size)) | ||||||
|     debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); |     debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); | ||||||
|  |   else if (!groups.issetgroups ()) /* setgroups was never called */ | ||||||
|  |     { | ||||||
|  |       ret = sid_in_token_groups (my_grps, groups.pgsid); | ||||||
|  |       if (ret == FALSE) | ||||||
|  | 	ret = (groups.pgsid == tok_usersid); | ||||||
|  |     } | ||||||
|  |   else /* setgroups was called */ | ||||||
|  |     { | ||||||
|  |       struct __group32 *gr; | ||||||
|  |       cygsid gsid; | ||||||
|  |       if (groups.sgsids.count > (int) sizeof (saw_buf) && | ||||||
|  | 	  !(saw = (char *) calloc (groups.sgsids.count, sizeof (char)))) | ||||||
|  | 	goto done; | ||||||
|  |  | ||||||
|  |       /* token groups found in /etc/group match the user.gsids ? */ | ||||||
|  |       for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) | ||||||
|  | 	if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid)) | ||||||
|  | 	  { | ||||||
|  | 	    int pos = groups.sgsids.position (gsid); | ||||||
|  | 	    if (pos >= 0) | ||||||
|  | 	      saw[pos] = TRUE; | ||||||
|  | 	    else if (groups.pgsid == gsid) | ||||||
|  | 	      sawpg = TRUE; | ||||||
| 	    else | 	    else | ||||||
|     ret = sid_in_token_groups (my_grps, pgrpsid); | 	      goto done; | ||||||
|  | 	  } | ||||||
|  |       for (int gidx = 0; gidx < groups.sgsids.count; gidx++) | ||||||
|  | 	if (!saw[gidx]) | ||||||
|  | 	  goto done; | ||||||
|  |       if (sawpg || groups.sgsids.contains (groups.pgsid)) | ||||||
|  | 	ret = TRUE; | ||||||
|  |     } | ||||||
|  | done: | ||||||
|   if (my_grps) |   if (my_grps) | ||||||
|     free (my_grps); |     free (my_grps); | ||||||
|  |   if (saw != saw_buf) | ||||||
|  |     free (saw); | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| HANDLE | HANDLE | ||||||
| create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) | create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) | ||||||
| { | { | ||||||
|   NTSTATUS ret; |   NTSTATUS ret; | ||||||
|   LSA_HANDLE lsa = INVALID_HANDLE_VALUE; |   LSA_HANDLE lsa = INVALID_HANDLE_VALUE; | ||||||
|   int old_priv_state; |   int old_priv_state; | ||||||
|  |  | ||||||
|   cygsidlist grpsids; |   cygsidlist tmp_gsids (cygsidlist_auto, 12); | ||||||
|  |  | ||||||
|   SECURITY_QUALITY_OF_SERVICE sqos = |   SECURITY_QUALITY_OF_SERVICE sqos = | ||||||
|     { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; |     { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; | ||||||
|   OBJECT_ATTRIBUTES oa = |   OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos }; | ||||||
|     { sizeof oa, 0, 0, 0, 0, &sqos }; |  | ||||||
|   PSECURITY_ATTRIBUTES psa; |   PSECURITY_ATTRIBUTES psa; | ||||||
|   BOOL special_pgrp; |   BOOL special_pgrp = FALSE; | ||||||
|   char sa_buf[1024]; |   char sa_buf[1024]; | ||||||
|   LUID auth_luid = SYSTEM_LUID; |   LUID auth_luid = SYSTEM_LUID; | ||||||
|   LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL }; |   LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL }; | ||||||
|  |  | ||||||
|   TOKEN_USER user; |   TOKEN_USER user; | ||||||
|   PTOKEN_GROUPS grps = NULL; |   PTOKEN_GROUPS new_tok_gsids = NULL; | ||||||
|   PTOKEN_PRIVILEGES privs = NULL; |   PTOKEN_PRIVILEGES privs = NULL; | ||||||
|   TOKEN_OWNER owner; |   TOKEN_OWNER owner; | ||||||
|   TOKEN_PRIMARY_GROUP pgrp; |   TOKEN_PRIMARY_GROUP pgrp; | ||||||
| @@ -746,7 +831,7 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) | |||||||
|   HANDLE primary_token = INVALID_HANDLE_VALUE; |   HANDLE primary_token = INVALID_HANDLE_VALUE; | ||||||
|  |  | ||||||
|   HANDLE my_token = INVALID_HANDLE_VALUE; |   HANDLE my_token = INVALID_HANDLE_VALUE; | ||||||
|   PTOKEN_GROUPS my_grps = NULL; |   PTOKEN_GROUPS my_tok_gsids = NULL; | ||||||
|   DWORD size; |   DWORD size; | ||||||
|  |  | ||||||
|   /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ |   /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ | ||||||
| @@ -772,7 +857,8 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) | |||||||
|       if (usersid != well_known_system_sid) |       if (usersid != well_known_system_sid) | ||||||
| 	if (!GetTokenInformation (my_token, TokenStatistics, | 	if (!GetTokenInformation (my_token, TokenStatistics, | ||||||
| 				  &stats, sizeof stats, &size)) | 				  &stats, sizeof stats, &size)) | ||||||
| 	  debug_printf ("GetTokenInformation(my_token, TokenStatistics): %E\n"); | 	  debug_printf | ||||||
|  | 	    ("GetTokenInformation(my_token, TokenStatistics): %E\n"); | ||||||
| 	else | 	else | ||||||
| 	  auth_luid = stats.AuthenticationId; | 	  auth_luid = stats.AuthenticationId; | ||||||
|  |  | ||||||
| @@ -781,55 +867,59 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) | |||||||
|       if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) && |       if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) && | ||||||
| 	  GetLastError () != ERROR_INSUFFICIENT_BUFFER) | 	  GetLastError () != ERROR_INSUFFICIENT_BUFFER) | ||||||
| 	debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); | 	debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); | ||||||
|       else if (!(my_grps = (PTOKEN_GROUPS) malloc (size))) |       else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size))) | ||||||
| 	debug_printf ("malloc (my_grps) failed."); | 	debug_printf ("malloc (my_tok_gsids) failed."); | ||||||
|       else if (!GetTokenInformation (my_token, TokenGroups, my_grps, |       else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids, | ||||||
| 				     size, &size)) | 				     size, &size)) | ||||||
| 	{ | 	{ | ||||||
| 	  debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); | 	  debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n"); | ||||||
| 	  free (my_grps); | 	  free (my_tok_gsids); | ||||||
| 	  my_grps = NULL; | 	  my_tok_gsids = NULL; | ||||||
| 	} | 	} | ||||||
|       CloseHandle (my_token); |       CloseHandle (my_token); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   /* Create list of groups, the user is member in. */ |   /* Create list of groups, the user is member in. */ | ||||||
|   int auth_pos; |   int auth_pos; | ||||||
|   if (!get_group_sidlist (grpsids, usersid, pgrpsid, pw, |   if (new_groups.issetgroups ()) | ||||||
| 			  my_grps, auth_luid, auth_pos, &special_pgrp)) |     get_setgroups_sidlist (tmp_gsids, 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, | ||||||
|  | 				    special_pgrp)) | ||||||
|     goto out; |     goto out; | ||||||
|  |  | ||||||
|   /* Primary group. */ |   /* Primary group. */ | ||||||
|   pgrp.PrimaryGroup = pgrpsid; |   pgrp.PrimaryGroup = new_groups.pgsid; | ||||||
|  |  | ||||||
|   /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ |   /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ | ||||||
|   char grps_buf[sizeof (ULONG) + grpsids.count * sizeof (SID_AND_ATTRIBUTES)]; |   char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)]; | ||||||
|   grps = (PTOKEN_GROUPS) grps_buf; |   new_tok_gsids = (PTOKEN_GROUPS) grps_buf; | ||||||
|   grps->GroupCount = grpsids.count; |   new_tok_gsids->GroupCount = tmp_gsids.count; | ||||||
|   for (DWORD i = 0; i < grps->GroupCount; ++i) |   for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i) | ||||||
|     { |     { | ||||||
|       grps->Groups[i].Sid = grpsids.sids[i]; |       new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i]; | ||||||
|       grps->Groups[i].Attributes = SE_GROUP_MANDATORY | |       new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY | | ||||||
| 				   SE_GROUP_ENABLED_BY_DEFAULT | | 	SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; | ||||||
| 				   SE_GROUP_ENABLED; |  | ||||||
|       if (auth_pos >= 0 && i == (DWORD) auth_pos) |  | ||||||
| 	grps->Groups[i].Attributes |= SE_GROUP_LOGON_ID; |  | ||||||
|     } |     } | ||||||
|  |   if (auth_pos >= 0) | ||||||
|  |     new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; | ||||||
|  |  | ||||||
|   /* Retrieve list of privileges of that user. */ |   /* Retrieve list of privileges of that user. */ | ||||||
|   if (!(privs = get_priv_list (lsa, usersid, grpsids))) |   if (!(privs = get_priv_list (lsa, usersid, tmp_gsids))) | ||||||
|     goto out; |     goto out; | ||||||
|  |  | ||||||
|   /* Create default dacl. */ |   /* Create default dacl. */ | ||||||
|   if (!sec_acl ((PACL) acl_buf, FALSE, |   if (!sec_acl ((PACL) acl_buf, FALSE, | ||||||
| 		grpsids.contains (well_known_admins_sid)?well_known_admins_sid:usersid)) | 		tmp_gsids.contains (well_known_admins_sid) ? | ||||||
|  | 		well_known_admins_sid : usersid)) | ||||||
|     goto out; |     goto out; | ||||||
|   dacl.DefaultDacl = (PACL) acl_buf; |   dacl.DefaultDacl = (PACL) acl_buf; | ||||||
|  |  | ||||||
|   /* Let's be heroic... */ |   /* Let's be heroic... */ | ||||||
|   ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, |   ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, | ||||||
| 		       &auth_luid, &exp, &user, grps, privs, &owner, &pgrp, | 		       &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, | ||||||
| 		       &dacl, &source); | 		       &pgrp, &dacl, &source); | ||||||
|   if (ret) |   if (ret) | ||||||
|     __seterrno_from_win_error (RtlNtStatusToDosError (ret)); |     __seterrno_from_win_error (RtlNtStatusToDosError (ret)); | ||||||
|   else if (GetLastError () == ERROR_PROC_NOT_FOUND) |   else if (GetLastError () == ERROR_PROC_NOT_FOUND) | ||||||
| @@ -842,13 +932,15 @@ create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw) | |||||||
|       /* Set security descriptor and primary group */ |       /* Set security descriptor and primary group */ | ||||||
|       psa = __sec_user (sa_buf, usersid, TRUE); |       psa = __sec_user (sa_buf, usersid, TRUE); | ||||||
|       if (psa->lpSecurityDescriptor && |       if (psa->lpSecurityDescriptor && | ||||||
| 	  !SetSecurityDescriptorGroup ( | 	  !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) | ||||||
| 	      (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor, | 				       psa->lpSecurityDescriptor, | ||||||
| 	      special_pgrp ? pgrpsid : well_known_null_sid, FALSE)) | 				       special_pgrp ? new_groups.pgsid | ||||||
|  | 						    : well_known_null_sid, | ||||||
|  | 				       FALSE)) | ||||||
| 	debug_printf ("SetSecurityDescriptorGroup %E"); | 	debug_printf ("SetSecurityDescriptorGroup %E"); | ||||||
|       /* Convert to primary token. */ |       /* Convert to primary token. */ | ||||||
|       if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, |       if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation, | ||||||
| 			     SecurityImpersonation, TokenPrimary, &primary_token)) | 			     TokenPrimary, &primary_token)) | ||||||
| 	{ | 	{ | ||||||
| 	  __seterrno (); | 	  __seterrno (); | ||||||
| 	  debug_printf ("DuplicateTokenEx %E"); | 	  debug_printf ("DuplicateTokenEx %E"); | ||||||
| @@ -862,8 +954,8 @@ out: | |||||||
|     CloseHandle (token); |     CloseHandle (token); | ||||||
|   if (privs) |   if (privs) | ||||||
|     free (privs); |     free (privs); | ||||||
|   if (my_grps) |   if (my_tok_gsids) | ||||||
|     free (my_grps); |     free (my_tok_gsids); | ||||||
|   close_local_policy (lsa); |   close_local_policy (lsa); | ||||||
|  |  | ||||||
|   debug_printf ("%d = create_token ()", primary_token); |   debug_printf ("%d = create_token ()", primary_token); | ||||||
| @@ -963,8 +1055,7 @@ subauth (struct passwd *pw) | |||||||
|   LsaFreeReturnBuffer (profile); |   LsaFreeReturnBuffer (profile); | ||||||
|   /* Convert to primary token. */ |   /* Convert to primary token. */ | ||||||
|   if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, |   if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, | ||||||
| 			 SecurityImpersonation, TokenPrimary, | 			 SecurityImpersonation, TokenPrimary, &primary_token)) | ||||||
| 			 &primary_token)) |  | ||||||
|     __seterrno (); |     __seterrno (); | ||||||
|  |  | ||||||
| out: | out: | ||||||
| @@ -1296,8 +1387,8 @@ get_file_attribute (int use_ntsec, const char *file, | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribute, | get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, | ||||||
| 		  __uid32_t *uidret, __gid32_t *gidret) | 			 int *attribute, __uid32_t *uidret, __gid32_t *gidret) | ||||||
| { | { | ||||||
|   if (!wincap.has_security ()) |   if (!wincap.has_security ()) | ||||||
|     return 0; |     return 0; | ||||||
| @@ -1311,11 +1402,8 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu | |||||||
| 					DACL_SECURITY_INFORMATION | | 					DACL_SECURITY_INFORMATION | | ||||||
| 					GROUP_SECURITY_INFORMATION | | 					GROUP_SECURITY_INFORMATION | | ||||||
| 					OWNER_SECURITY_INFORMATION, | 					OWNER_SECURITY_INFORMATION, | ||||||
|                                         &owner_sid, | 					&owner_sid, &group_sid, | ||||||
|                                         &group_sid, | 					&acl, NULL, &psd)) | ||||||
|                                         &acl, |  | ||||||
|                                         NULL, |  | ||||||
|                                         &psd)) |  | ||||||
|     { |     { | ||||||
|       __seterrno (); |       __seterrno (); | ||||||
|       debug_printf ("GetSecurityInfo %E"); |       debug_printf ("GetSecurityInfo %E"); | ||||||
| @@ -1341,8 +1429,7 @@ get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *attribu | |||||||
|   if (!acl) |   if (!acl) | ||||||
|     { |     { | ||||||
|       *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; |       *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; | ||||||
|       syscall_printf ("No ACL = %x, uid %d, gid %d", |       syscall_printf ("No ACL = %x, uid %d, gid %d", *attribute, uid, gid); | ||||||
| 		      *attribute, uid, gid); |  | ||||||
|       LocalFree (psd); |       LocalFree (psd); | ||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
| @@ -1442,7 +1529,8 @@ get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, | |||||||
| { | { | ||||||
|   if (allow_ntsec) |   if (allow_ntsec) | ||||||
|     { |     { | ||||||
|       int res = get_nt_object_attribute (handle, object_type, attribute, uidret, gidret); |       int res = get_nt_object_attribute (handle, object_type, attribute, | ||||||
|  |       					 uidret, gidret); | ||||||
|       if (attribute && (*attribute & S_IFLNK) == S_IFLNK) |       if (attribute && (*attribute & S_IFLNK) == S_IFLNK) | ||||||
| 	*attribute |= S_IRWXU | S_IRWXG | S_IRWXO; | 	*attribute |= S_IRWXU | S_IRWXG | S_IRWXO; | ||||||
|       return res; |       return res; | ||||||
| @@ -1475,8 +1563,7 @@ add_access_allowed_ace (PACL acl, int offset, DWORD attributes, | |||||||
|   ACCESS_ALLOWED_ACE *ace; |   ACCESS_ALLOWED_ACE *ace; | ||||||
|   if (GetAce (acl, offset, (PVOID *) &ace)) |   if (GetAce (acl, offset, (PVOID *) &ace)) | ||||||
|     ace->Header.AceFlags |= inherit; |     ace->Header.AceFlags |= inherit; | ||||||
|   len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) |   len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); | ||||||
| 	     + GetLengthSid (sid); |  | ||||||
|   return TRUE; |   return TRUE; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1492,8 +1579,7 @@ add_access_denied_ace (PACL acl, int offset, DWORD attributes, | |||||||
|   ACCESS_DENIED_ACE *ace; |   ACCESS_DENIED_ACE *ace; | ||||||
|   if (GetAce (acl, offset, (PVOID *) &ace)) |   if (GetAce (acl, offset, (PVOID *) &ace)) | ||||||
|     ace->Header.AceFlags |= inherit; |     ace->Header.AceFlags |= inherit; | ||||||
|   len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) |   len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); | ||||||
| 	     + GetLengthSid (sid); |  | ||||||
|   return TRUE; |   return TRUE; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1614,8 +1700,7 @@ alloc_sd (__uid32_t uid, __gid32_t gid, int attribute, | |||||||
|   if (attribute & S_IXGRP) |   if (attribute & S_IXGRP) | ||||||
|     group_allow |= FILE_GENERIC_EXECUTE; |     group_allow |= FILE_GENERIC_EXECUTE; | ||||||
|   if ((attribute & (S_IFDIR | S_IWGRP | S_IXGRP)) |   if ((attribute & (S_IFDIR | S_IWGRP | S_IXGRP)) | ||||||
|       == (S_IFDIR | S_IWGRP | S_IXGRP) |       == (S_IFDIR | S_IWGRP | S_IXGRP) && !(attribute & S_ISVTX)) | ||||||
|       && !(attribute & S_ISVTX)) |  | ||||||
|     group_allow |= FILE_DELETE_CHILD; |     group_allow |= FILE_DELETE_CHILD; | ||||||
|  |  | ||||||
|   /* Construct allow attribute for everyone. */ |   /* Construct allow attribute for everyone. */ | ||||||
| @@ -1771,8 +1856,8 @@ set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, | |||||||
|   psa->lpSecurityDescriptor = sd_buf; |   psa->lpSecurityDescriptor = sd_buf; | ||||||
|   InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf, |   InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf, | ||||||
| 				SECURITY_DESCRIPTOR_REVISION); | 				SECURITY_DESCRIPTOR_REVISION); | ||||||
|   psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), |   psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute, | ||||||
| 					attribute, (PSECURITY_DESCRIPTOR)sd_buf, | 					(PSECURITY_DESCRIPTOR) sd_buf, | ||||||
| 					&sd_buf_size); | 					&sd_buf_size); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1803,8 +1888,7 @@ set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid, | |||||||
|  |  | ||||||
| int | int | ||||||
| set_file_attribute (int use_ntsec, const char *file, | set_file_attribute (int use_ntsec, const char *file, | ||||||
| 		    __uid32_t uid, __gid32_t gid, | 		    __uid32_t uid, __gid32_t gid, int attribute) | ||||||
| 		    int attribute) |  | ||||||
| { | { | ||||||
|   int ret = 0; |   int ret = 0; | ||||||
|  |  | ||||||
| @@ -1825,6 +1909,5 @@ int | |||||||
| set_file_attribute (int use_ntsec, const char *file, int attribute) | set_file_attribute (int use_ntsec, const char *file, int attribute) | ||||||
| { | { | ||||||
|   return set_file_attribute (use_ntsec, file, |   return set_file_attribute (use_ntsec, file, | ||||||
| 			     myself->uid, myself->gid, | 			     myself->uid, myself->gid, attribute); | ||||||
| 			     attribute); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -86,40 +86,63 @@ public: | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | typedef enum { cygsidlist_unknown, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type; | ||||||
| class cygsidlist { | class cygsidlist { | ||||||
|  |   int maxcount; | ||||||
| public: | public: | ||||||
|   int count; |   int count; | ||||||
|   cygsid *sids; |   cygsid *sids; | ||||||
|  |   cygsidlist_type type; | ||||||
|  |  | ||||||
|   cygsidlist () : count (0), sids (NULL) {} |   cygsidlist (cygsidlist_type t, int m) | ||||||
|   ~cygsidlist () { delete [] sids; } |  | ||||||
|  |  | ||||||
|   BOOL add (cygsid &nsi) |  | ||||||
|     { |     { | ||||||
|       cygsid *tmp = new cygsid [count + 1]; |       type = t; | ||||||
|  |       count = 0; | ||||||
|  |       maxcount = m; | ||||||
|  |       if (t == cygsidlist_alloc) | ||||||
|  | 	sids = alloc_sids (m); | ||||||
|  |       else | ||||||
|  | 	sids = new cygsid [m]; | ||||||
|  |     } | ||||||
|  |   ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; } | ||||||
|  |  | ||||||
|  |   BOOL add (const PSID nsi) /* Only with auto for now */ | ||||||
|  |     { | ||||||
|  |       if (count >= maxcount) | ||||||
|  |         { | ||||||
|  | 	  cygsid *tmp = new cygsid [ 2 * maxcount]; | ||||||
| 	  if (!tmp) | 	  if (!tmp) | ||||||
| 	    return FALSE; | 	    return FALSE; | ||||||
|  | 	  maxcount *= 2; | ||||||
| 	  for (int i = 0; i < count; ++i) | 	  for (int i = 0; i < count; ++i) | ||||||
| 	    tmp[i] = sids[i]; | 	    tmp[i] = sids[i]; | ||||||
| 	  delete [] sids; | 	  delete [] sids; | ||||||
| 	  sids = tmp; | 	  sids = tmp; | ||||||
|  | 	} | ||||||
|       sids[count++] = nsi; |       sids[count++] = nsi; | ||||||
|       return TRUE; |       return TRUE; | ||||||
|     } |     } | ||||||
|   BOOL add (const PSID nsid) { return add (nsid); } |   BOOL add (cygsid &nsi) { return add ((PSID) nsi); } | ||||||
|   BOOL add (const char *sidstr) |   BOOL add (const char *sidstr) | ||||||
|     { cygsid nsi (sidstr); return add (nsi); } |     { cygsid nsi (sidstr); return add (nsi); } | ||||||
|  |   BOOL addfromgr (struct __group32 *gr) /* Only with alloc */ | ||||||
|  |     { return sids[count++].getfromgr (gr); } | ||||||
|  |  | ||||||
|   BOOL operator+= (cygsid &si) { return add (si); } |   BOOL operator+= (cygsid &si) { return add (si); } | ||||||
|   BOOL operator+= (const char *sidstr) { return add (sidstr); } |   BOOL operator+= (const char *sidstr) { return add (sidstr); } | ||||||
|  |   BOOL operator+= (const PSID psid) { return add (psid); } | ||||||
|  |  | ||||||
|   BOOL contains (cygsid &sid) const |   int position (const PSID sid) const | ||||||
|     { |     { | ||||||
|       for (int i = 0; i < count; ++i) |       for (int i = 0; i < count; ++i) | ||||||
| 	if (sids[i] == sid) | 	if (sids[i] == sid) | ||||||
| 	  return TRUE; | 	  return i; | ||||||
|       return FALSE; |       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 |   void debug_print (const char *prefix = NULL) const | ||||||
|     { |     { | ||||||
|       debug_printf ("-- begin sidlist ---"); |       debug_printf ("-- begin sidlist ---"); | ||||||
| @@ -131,6 +154,26 @@ public: | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class user_groups { | ||||||
|  | public: | ||||||
|  |   cygsid pgsid; | ||||||
|  |   cygsidlist sgsids; | ||||||
|  |   BOOL ischanged; | ||||||
|  |  | ||||||
|  |   BOOL issetgroups () const { return (sgsids.type == cygsidlist_alloc); } | ||||||
|  |   void update_supp (const cygsidlist &newsids) | ||||||
|  |     { | ||||||
|  |       sgsids.free_sids (); | ||||||
|  |       sgsids = newsids; | ||||||
|  |       ischanged = TRUE; | ||||||
|  |     } | ||||||
|  |   void update_pgrp (const PSID sid) | ||||||
|  |     { | ||||||
|  |       pgsid = sid; | ||||||
|  |       ischanged = TRUE; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
| extern cygsid well_known_null_sid; | extern cygsid well_known_null_sid; | ||||||
| extern cygsid well_known_world_sid; | extern cygsid well_known_world_sid; | ||||||
| extern cygsid well_known_local_sid; | extern cygsid well_known_local_sid; | ||||||
| @@ -180,9 +223,9 @@ void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, | |||||||
| /* Try a subauthentication. */ | /* Try a subauthentication. */ | ||||||
| HANDLE subauth (struct passwd *pw); | HANDLE subauth (struct passwd *pw); | ||||||
| /* Try creating a token directly. */ | /* Try creating a token directly. */ | ||||||
| HANDLE create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd * pw); | HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw); | ||||||
| /* Verify an existing token */ | /* Verify an existing token */ | ||||||
| BOOL verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL * pintern = NULL); | BOOL verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL * pintern = NULL); | ||||||
|  |  | ||||||
| /* Extract U-domain\user field from passwd entry. */ | /* Extract U-domain\user field from passwd entry. */ | ||||||
| void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user); | void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user); | ||||||
|   | |||||||
| @@ -1958,9 +1958,8 @@ seteuid32 (__uid32_t uid) | |||||||
|   debug_printf ("uid: %d myself->gid: %d", uid, myself->gid); |   debug_printf ("uid: %d myself->gid: %d", uid, myself->gid); | ||||||
|  |  | ||||||
|   if (!wincap.has_security () |   if (!wincap.has_security () | ||||||
|       || (!cygheap->user.issetuid () |       || (uid == myself->uid | ||||||
| 	  && uid == myself->uid | 	  && !cygheap->user.groups.ischanged) | ||||||
| 	  && myself->gid == cygheap->user.orig_gid) |  | ||||||
|       || uid == ILLEGAL_UID) |       || uid == ILLEGAL_UID) | ||||||
|     { |     { | ||||||
|       debug_printf ("Nothing happens"); |       debug_printf ("Nothing happens"); | ||||||
| @@ -1968,7 +1967,8 @@ seteuid32 (__uid32_t uid) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|   sigframe thisframe (mainthread); |   sigframe thisframe (mainthread); | ||||||
|   cygsid usersid, pgrpsid; |   cygsid usersid; | ||||||
|  |   user_groups &groups = cygheap->user.groups; | ||||||
|   HANDLE ptok, sav_token; |   HANDLE ptok, sav_token; | ||||||
|   BOOL sav_impersonated, sav_token_is_internal_token; |   BOOL sav_impersonated, sav_token_is_internal_token; | ||||||
|   BOOL process_ok, explicitly_created_token = FALSE; |   BOOL process_ok, explicitly_created_token = FALSE; | ||||||
| @@ -1976,8 +1976,7 @@ seteuid32 (__uid32_t uid) | |||||||
|   PSID origpsid, psid2 = NO_SID; |   PSID origpsid, psid2 = NO_SID; | ||||||
|  |  | ||||||
|   pw_new = getpwuid32 (uid); |   pw_new = getpwuid32 (uid); | ||||||
|   if (!usersid.getfrompw (pw_new) || |   if (!usersid.getfrompw (pw_new)) | ||||||
|       (!pgrpsid.getfromgr (getgrgid32 (myself->gid)))) |  | ||||||
|     { |     { | ||||||
|       set_errno (EINVAL); |       set_errno (EINVAL); | ||||||
|       return -1; |       return -1; | ||||||
| @@ -1995,7 +1994,7 @@ seteuid32 (__uid32_t uid) | |||||||
|   /* Verify if the process token is suitable. |   /* Verify if the process token is suitable. | ||||||
|      Currently we do not try to differentiate between |      Currently we do not try to differentiate between | ||||||
| 	 internal tokens and others */ | 	 internal tokens and others */ | ||||||
|   process_ok = verify_token (ptok, usersid, pgrpsid); |   process_ok = verify_token (ptok, usersid, groups); | ||||||
|   debug_printf("Process token %sverified", process_ok ? "" : "not "); |   debug_printf("Process token %sverified", process_ok ? "" : "not "); | ||||||
|   if (process_ok) |   if (process_ok) | ||||||
|     { |     { | ||||||
| @@ -2011,7 +2010,7 @@ seteuid32 (__uid32_t uid) | |||||||
|   if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) |   if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) | ||||||
|     { |     { | ||||||
|       /* Verify if the current tokem is suitable */ |       /* Verify if the current tokem is suitable */ | ||||||
|       BOOL token_ok = verify_token (cygheap->user.token, usersid, pgrpsid, |       BOOL token_ok = verify_token (cygheap->user.token, usersid, groups, | ||||||
| 				    &sav_token_is_internal_token); | 				    &sav_token_is_internal_token); | ||||||
|       debug_printf("Thread token %d %sverified", |       debug_printf("Thread token %d %sverified", | ||||||
| 		   cygheap->user.token, token_ok?"":"not "); | 		   cygheap->user.token, token_ok?"":"not "); | ||||||
| @@ -2048,7 +2047,7 @@ seteuid32 (__uid32_t uid) | |||||||
|     { |     { | ||||||
|       /* If no impersonation token is available, try to |       /* If no impersonation token is available, try to | ||||||
| 	 authenticate using NtCreateToken() or subauthentication. */ | 	 authenticate using NtCreateToken() or subauthentication. */ | ||||||
|       cygheap->user.token = create_token (usersid, pgrpsid, pw_new); |       cygheap->user.token = create_token (usersid, groups, pw_new); | ||||||
|       if (cygheap->user.token != INVALID_HANDLE_VALUE) |       if (cygheap->user.token != INVALID_HANDLE_VALUE) | ||||||
| 	explicitly_created_token = TRUE; | 	explicitly_created_token = TRUE; | ||||||
|       else |       else | ||||||
| @@ -2076,7 +2075,7 @@ seteuid32 (__uid32_t uid) | |||||||
| 	  /* Try setting primary group in token to current group */ | 	  /* Try setting primary group in token to current group */ | ||||||
| 	  if (!SetTokenInformation (cygheap->user.token, | 	  if (!SetTokenInformation (cygheap->user.token, | ||||||
| 				    TokenPrimaryGroup, | 				    TokenPrimaryGroup, | ||||||
| 				    &pgrpsid, sizeof pgrpsid)) | 				    &groups.pgsid, sizeof(cygsid))) | ||||||
| 	    debug_printf ("SetTokenInformation(user.token, " | 	    debug_printf ("SetTokenInformation(user.token, " | ||||||
| 			  "TokenPrimaryGroup): %E"); | 			  "TokenPrimaryGroup): %E"); | ||||||
| 	} | 	} | ||||||
| @@ -2098,6 +2097,7 @@ seteuid32 (__uid32_t uid) | |||||||
|   cygheap->user.set_name (pw_new->pw_name); |   cygheap->user.set_name (pw_new->pw_name); | ||||||
|   cygheap->user.set_sid (usersid); |   cygheap->user.set_sid (usersid); | ||||||
|   myself->uid = uid; |   myself->uid = uid; | ||||||
|  |   groups.ischanged = FALSE; | ||||||
|   return 0; |   return 0; | ||||||
|  |  | ||||||
|  failed: |  failed: | ||||||
| @@ -2142,6 +2142,7 @@ setegid32 (__gid32_t gid) | |||||||
|     return 0; |     return 0; | ||||||
|  |  | ||||||
|   sigframe thisframe (mainthread); |   sigframe thisframe (mainthread); | ||||||
|  |   user_groups * groups = &cygheap->user.groups; | ||||||
|   cygsid gsid; |   cygsid gsid; | ||||||
|   HANDLE ptok; |   HANDLE ptok; | ||||||
|  |  | ||||||
| @@ -2153,6 +2154,7 @@ setegid32 (__gid32_t gid) | |||||||
|     } |     } | ||||||
|   myself->gid = gid; |   myself->gid = gid; | ||||||
|  |  | ||||||
|  |   groups->update_pgrp (gsid); | ||||||
|   /* If impersonated, update primary group and revert */ |   /* If impersonated, update primary group and revert */ | ||||||
|   if (cygheap->user.issetuid ()) |   if (cygheap->user.issetuid ()) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -48,9 +48,12 @@ internal_getlogin (cygheap_user &user) | |||||||
| 			     &ptok)) | 			     &ptok)) | ||||||
| 	system_printf ("OpenProcessToken(): %E\n"); | 	system_printf ("OpenProcessToken(): %E\n"); | ||||||
|       else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz)) |       else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz)) | ||||||
| 	system_printf ("GetTokenInformation(): %E"); | 	system_printf ("GetTokenInformation (TokenUser): %E"); | ||||||
|       else if (!(ret = user.set_sid (tu))) |       else if (!(ret = user.set_sid (tu))) | ||||||
| 	system_printf ("Couldn't retrieve SID from access token!"); | 	system_printf ("Couldn't retrieve SID from access token!"); | ||||||
|  |       else if (!GetTokenInformation (ptok, TokenPrimaryGroup, | ||||||
|  | 				     &user.groups.pgsid, sizeof tu, &siz)) | ||||||
|  | 	system_printf ("GetTokenInformation (TokenPrimaryGroup): %E"); | ||||||
|        /* We must set the user name, uid and gid. |        /* We must set the user name, uid and gid. | ||||||
| 	 If we have a SID, try to get the corresponding Cygwin | 	 If we have a SID, try to get the corresponding Cygwin | ||||||
| 	 password entry. Set user name which can be different | 	 password entry. Set user name which can be different | ||||||
| @@ -75,11 +78,14 @@ internal_getlogin (cygheap_user &user) | |||||||
| 	     primary group to the group in /etc/passwd. */ | 	     primary group to the group in /etc/passwd. */ | ||||||
| 	  if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu)) | 	  if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu)) | ||||||
| 	    debug_printf ("SetTokenInformation(TokenOwner): %E"); | 	    debug_printf ("SetTokenInformation(TokenOwner): %E"); | ||||||
| 	  if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup, | 	  if (gsid) | ||||||
|  | 	    { | ||||||
|  | 	      user.groups.pgsid = gsid; | ||||||
|  | 	      if (!SetTokenInformation (ptok, TokenPrimaryGroup, | ||||||
| 					&gsid, sizeof gsid)) | 					&gsid, sizeof gsid)) | ||||||
| 		debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); | 		debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E"); | ||||||
| 	    } | 	    } | ||||||
|  | 	 } | ||||||
|       if (ptok != INVALID_HANDLE_VALUE) |       if (ptok != INVALID_HANDLE_VALUE) | ||||||
| 	CloseHandle (ptok); | 	CloseHandle (ptok); | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user