setgroups

Pierre A. Humblet Pierre.Humblet@ieee.org
Thu Jul 25 21:07:00 GMT 2002


Corinna,

Here is setgroups.
I still need to declare it in an .h file.
Should it be in src/newlib/libc/include/sys/unistd.h ?

Note the update of cygwin.din

Pierre
  
2002-07-25 Pierre Humblet <Pierre.Humblet@ieee.org>

	* cygheap.h (class cygheap_user): Add member gsids and methods
	gsids_set, gsids_alloc, gsids_free, gsids_update and issetgroups.
	* cygheap.cc (cygheap_user::gsids_set): New.
	(cygheap_user::gsids_alloc): New.
	(cygheap_user::gsids_free): New.
	(cygheap_user::gsids_update): New.
	* security.h (class cygsidarray): Create.
	(class cygsidlist): Add member maxcount and use it in method add.
	Change argument of methods add and contains to PSID. 
	Add operator+= (const PSID psid).
	Update declarations of verify_token and create_token.
	* security.cc * (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 four group sid lists uniformly.
	* syscalls.cc (seteuid32): Modify to use cygheap->user.gsids.
	(setegid32): Update cygheap->user.gsids.
	* grp.cc (setgroups): New.
	(setgroups32): New.
	* uinfo.cc (internal_getlogin): Initialize and update user.gsids.
	* cygwin.din: Add setgroups and setgroups32.
-------------- next part --------------
diff -u cygwin.orig/cygheap.cc cygwin/cygheap.cc
--- cygwin.orig/cygheap.cc	2002-07-25 22:40:50.000000000 -0400
+++ cygwin/cygheap.cc	2002-07-24 21:21:20.000000000 -0400
@@ -491,3 +491,51 @@
     }
   return FALSE;
 }
+
+BOOL
+cygheap_user::gsids_set (PSID pgpsid)
+{
+  if (gsids == NULL)
+    {
+      gsids = (cygsidarray *) cmalloc (HEAP_STR, gsids->size (0));
+      if (gsids != NULL)
+        {
+	  gsids->suppcount = -1;
+	  gsids->sids[0] = pgpsid;
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+BOOL
+cygheap_user::gsids_alloc (cygsidarray * & gsids, int scount)
+    {
+      gsids = (cygsidarray *) cmalloc (HEAP_STR,
+				       gsids->size (scount));
+      if (gsids != NULL)
+        {
+	  gsids->suppcount = 0;
+	  return TRUE;
+	}
+      return FALSE;
+    }
+void
+cygheap_user::gsids_free (cygsidarray * gsids)
+{
+  return cfree (gsids);
+}
+BOOL
+cygheap_user::gsids_update (cygsidarray * newgsids)
+{
+  if (gsids)
+    {
+      newgsids->sids[0] = gsids->sids[0];
+      cfree (gsids);
+      gsids = newgsids;
+      return TRUE;
+    }
+  return FALSE;
+}
+
+
diff -u cygwin.orig/cygheap.h cygwin/cygheap.h
--- cygwin.orig/cygheap.h	2002-07-25 22:40:50.000000000 -0400
+++ cygwin/cygheap.h	2002-07-25 22:54:48.000000000 -0400
@@ -113,6 +113,7 @@
   __gid32_t orig_gid;      /* Ditto */
   __uid32_t real_uid;      /* Remains intact on seteuid, replaced by setuid */
   __gid32_t real_gid;      /* Ditto */
+  cygsidarray *gsids;      /* buffer for primary and supp SIDs */

   /* token is needed if set(e)uid should be called. It can be set by a call
      to `set_impersonation_token()'. */
@@ -141,6 +142,11 @@
   const char *env_userprofile (const char *, size_t);
   const char *env_domain (const char *, size_t);
   const char *env_name (const char *, size_t);
+  BOOL gsids_set (PSID pgsid);
+  BOOL gsids_alloc (cygsidarray * & gsids, int scount);
+  void gsids_free (cygsidarray *gsids);
+  BOOL gsids_update (cygsidarray *newgsids);
+  BOOL issetgroups () const { return gsids && gsids->issetgroups (); }

   const char *logsrv ()
   {
diff -u cygwin.orig/cygwin.din cygwin/cygwin.din
--- cygwin.orig/cygwin.din	2002-07-25 22:40:50.000000000 -0400
+++ cygwin/cygwin.din	2002-07-25 22:49:08.000000000 -0400
@@ -678,6 +678,9 @@
 setgid
 _setgid = setgid
 setgid32
+setgroups
+_setgroups = setgroups
+setgroups32
 setjmp
 _setjmp = setjmp
 setlocale
diff -u cygwin.orig/grp.cc cygwin/grp.cc
--- cygwin.orig/grp.cc	2002-07-25 22:40:50.000000000 -0400
+++ cygwin/grp.cc	2002-07-25 22:41:34.000000000 -0400
@@ -457,3 +457,64 @@
 {
   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;
+
+  cygsidarray * gsids;
+  struct __group32 *gr;
+
+  if (!cygheap->user.gsids_alloc(gsids, ngroups))
+    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->addsuppfromgr (gr))
+	      goto found;
+	    break;
+	  }
+      debug_printf ("No sid found for gid %d", grouplist[gidx]);
+      cygheap->user.gsids_free(gsids);
+      set_errno (EINVAL);
+      return -1;
+    found:
+      continue;
+    }
+  cygheap->user.gsids_update(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);
+
+}
diff -u cygwin.orig/security.cc cygwin/security.cc
--- cygwin.orig/security.cc	2002-07-25 22:40:50.000000000 -0400
+++ cygwin/security.cc	2002-07-25 23:14:12.000000000 -0400
@@ -473,57 +473,63 @@
     }
 }

-static BOOL
-get_group_sidlist (cygsidlist &grp_list,
-		   cygsid &usersid, cygsid &pgrpsid, struct passwd *pw,
-		   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;
-
+static void
+get_token_group_sidlist(cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
+			LUID auth_luid, int &auth_pos)
+{
   auth_pos = -1;
+  if (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;
+      if (sid_in_token_groups (my_grps, 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;
+      if (sid_in_token_groups (my_grps, 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;
+    }
+  else
+    {
+      grp_list += well_known_local_sid;
+      grp_list += well_known_interactive_sid;
+    }
+  if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
+    {
+      char buf[64];
+      __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
+		       auth_luid.LowPart);
+      grp_list += buf;
+      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
     {
-      if (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;
-	  if (sid_in_token_groups (my_grps, 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;
-	  if (sid_in_token_groups (my_grps, 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;
-	}
-      else
-	{
-	  grp_list += well_known_local_sid;
-	  grp_list += well_known_interactive_sid;
-	}
-      if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
-	{
-	  char buf[64];
-	  __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
-						 auth_luid.LowPart);
-	  grp_list += buf;
-	  auth_pos = grp_list.count - 1;
-	}
+      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);
       if (get_logon_server (domain, server, wserver))
 	get_user_groups (wserver, grp_list, user, domain);
@@ -531,16 +537,26 @@
       if (!get_user_local_groups (grp_list, usersid))
 	return FALSE;
     }
-  /* special_pgrp true if pgrpsid is not null and not in normal groups */
-  *special_pgrp = FALSE;
-  if (pgrpsid && !grp_list.contains (pgrpsid))
-    {
-       *special_pgrp = TRUE;
-       grp_list += pgrpsid;
-    }
+  /* special_pgrp true if pgrpsid is not in normal groups */
+  if ((special_pgrp = !grp_list.contains (pgrpsid)))
+    grp_list += pgrpsid;
   return TRUE;
 }

+static void
+get_setgroups_sidlist(cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
+		      cygsidarray &gsids, LUID auth_luid, int &auth_pos)
+{
+  PSID pgpsid = gsids.pgpsid ();
+  grp_list += well_known_world_sid;
+  grp_list += well_known_authenticated_users_sid;
+  get_token_group_sidlist(grp_list, my_grps, auth_luid, auth_pos);
+  for (int gidx = 1; gidx <= gsids.suppcount; gidx++)
+    grp_list += gsids.sids[gidx];
+  if (gsids.position (1, pgpsid) < 0)
+    grp_list += pgpsid;
+}
+
 static const char *sys_privs[] = {
   SE_TCB_NAME,
   SE_ASSIGNPRIMARYTOKEN_NAME,
@@ -654,8 +670,21 @@
   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
-verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL *pintern)
+verify_token (HANDLE token, cygsid &usersid, cygsidarray &gsids, BOOL * pintern)
 {
   DWORD size;
   BOOL intern = FALSE;
@@ -675,9 +704,9 @@
       debug_printf ("GetTokenInformation(): %E");
   if (usersid != tok_usersid) return FALSE;

-  /* In an internal token, if the sd group is not well_known_null_sid,
-     it must match pgrpsid */
-  if (intern)
+  /* For an internal token, if setgroups was not called and if the sd group
+     is not well_known_null_sid, it must match pgrpsid */
+  if (intern && !gsids.issetgroups ())
     {
        char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)];
        PSID gsid = NO_SID;
@@ -688,14 +717,14 @@
        else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf,
 					    &gsid, (BOOL *) &size))
 	   debug_printf ("GetSecurityDescriptorGroup(): %E");
-       if (well_known_null_sid != gsid) return pgrpsid == gsid;
+       if (well_known_null_sid != gsid) return gsid == gsids.pgpsid ();
     }
-  /* See if the pgrpsid is the tok_usersid in the token groups */
+
   PTOKEN_GROUPS my_grps = NULL;
   BOOL ret = FALSE;
-
-  if ( pgrpsid == tok_usersid)
-    return TRUE;
+  char saw_buf[NGROUPS_MAX + 1] = {};
+  char *saw = saw_buf;
+
   if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
       GetLastError () != ERROR_INSUFFICIENT_BUFFER)
     debug_printf ("GetTokenInformation(token, TokenGroups): %E\n");
@@ -703,34 +732,63 @@
     debug_printf ("malloc (my_grps) failed.");
   else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
     debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
-  else
-    ret = sid_in_token_groups (my_grps, pgrpsid);
-  if (my_grps)
-    free (my_grps);
+  else if (!gsids.issetgroups ()) /* setgroups was never called */
+    {
+      ret = sid_in_token_groups (my_grps, *(gsids.pgcygsidptr ()));
+      if (ret == FALSE) ret = (gsids.pgpsid () == tok_usersid);
+    }
+  else /* setgroups was called */
+    {
+      struct __group32 *gr;
+      cygsid gsid;
+      if (gsids.suppcount + 1 > (int) sizeof (saw_buf) &&
+	  !(saw = (char *) calloc (gsids.suppcount + 1, sizeof(char))))
+	goto done;
+
+      /* See if the pgid is also a supplementary group */
+      int first = (gsids.position (1, gsids.pgpsid ()) >= 0)?1:0;
+
+      /* 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 = gsids.position (first, gsid);
+	    if (pos < 0)
+	      goto done;
+	    saw[pos] = TRUE;
+          }
+      for (int gidx = first; gidx <= gsids.suppcount; gidx++)
+        if (!saw[gidx])
+	  goto done;
+      ret = TRUE;
+    }
+ done:
+  if (my_grps) free (my_grps);
+  if (saw != saw_buf) free(saw);
   return ret;
 }

 HANDLE
-create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd *pw)
+create_token (cygsid &usersid, cygsidarray &new_gsids, struct passwd *pw)
 {
   NTSTATUS ret;
   LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
   int old_priv_state;

-  cygsidlist grpsids;
+  cygsidlist tmp_gsids;

   SECURITY_QUALITY_OF_SERVICE sqos =
     { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
   OBJECT_ATTRIBUTES oa =
     { sizeof oa, 0, 0, 0, 0, &sqos };
   PSECURITY_ATTRIBUTES psa;
-  BOOL special_pgrp;
+  BOOL special_pgrp = FALSE;
   char sa_buf[1024];
   LUID auth_luid = SYSTEM_LUID;
   LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL  };

   TOKEN_USER user;
-  PTOKEN_GROUPS grps = NULL;
+  PTOKEN_GROUPS new_tok_gsids = NULL;
   PTOKEN_PRIVILEGES privs = NULL;
   TOKEN_OWNER owner;
   TOKEN_PRIMARY_GROUP pgrp;
@@ -746,7 +804,7 @@
   HANDLE primary_token = INVALID_HANDLE_VALUE;

   HANDLE my_token = INVALID_HANDLE_VALUE;
-  PTOKEN_GROUPS my_grps = NULL;
+  PTOKEN_GROUPS my_tok_gsids = NULL;
   DWORD size;

   /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
@@ -781,54 +839,56 @@
       if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
 	  GetLastError () != ERROR_INSUFFICIENT_BUFFER)
 	debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
-      else if (!(my_grps = (PTOKEN_GROUPS) malloc (size)))
-	debug_printf ("malloc (my_grps) failed.");
-      else if (!GetTokenInformation (my_token, TokenGroups, my_grps,
+      else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
+	debug_printf ("malloc (my_tok_gsids) failed.");
+      else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids,
 				     size, &size))
 	{
 	  debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
-	  free (my_grps);
-	  my_grps = NULL;
+	  free (my_tok_gsids);
+	  my_tok_gsids = NULL;
 	}
       CloseHandle (my_token);
     }

   /* Create list of groups, the user is member in. */
   int auth_pos;
-  if (!get_group_sidlist (grpsids, usersid, pgrpsid, pw,
-			  my_grps, auth_luid, auth_pos, &special_pgrp))
+  if (new_gsids.issetgroups ())
+    get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_gsids, auth_luid, auth_pos);
+  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_gsids.pgpsid (), pw,
+				    my_tok_gsids, auth_luid, auth_pos, special_pgrp))
     goto out;

   /* Primary group. */
-  pgrp.PrimaryGroup = pgrpsid;
+  pgrp.PrimaryGroup = new_gsids.pgpsid ();

   /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
-  char grps_buf[sizeof (ULONG) + grpsids.count * sizeof (SID_AND_ATTRIBUTES)];
-  grps = (PTOKEN_GROUPS) grps_buf;
-  grps->GroupCount = grpsids.count;
-  for (DWORD i = 0; i < grps->GroupCount; ++i)
+  char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)];
+  new_tok_gsids = (PTOKEN_GROUPS) grps_buf;
+  new_tok_gsids->GroupCount = tmp_gsids.count;
+  for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
     {
-      grps->Groups[i].Sid = grpsids.sids[i];
-      grps->Groups[i].Attributes = SE_GROUP_MANDATORY |
+      new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
+      new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY |
 				   SE_GROUP_ENABLED_BY_DEFAULT |
 				   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. */
-  if (!(privs = get_priv_list (lsa, usersid, grpsids)))
+  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids)))
     goto out;

   /* Create default dacl. */
   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;
   dacl.DefaultDacl = (PACL) acl_buf;

   /* Let's be heroic... */
   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, &pgrp,
 		       &dacl, &source);
   if (ret)
     __seterrno_from_win_error (RtlNtStatusToDosError (ret));
@@ -843,8 +903,8 @@
       psa = __sec_user (sa_buf, usersid, TRUE);
       if (psa->lpSecurityDescriptor &&
 	  !SetSecurityDescriptorGroup (
-	      (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
-	      special_pgrp ? pgrpsid : well_known_null_sid, FALSE))
+	    (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
+	    special_pgrp ? *(new_gsids.pgcygsidptr ()): well_known_null_sid, FALSE))
 	  debug_printf ("SetSecurityDescriptorGroup %E");
       /* Convert to primary token. */
       if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa,
@@ -862,8 +922,8 @@
     CloseHandle (token);
   if (privs)
     free (privs);
-  if (my_grps)
-    free (my_grps);
+  if (my_tok_gsids)
+    free (my_tok_gsids);
   close_local_policy (lsa);

   debug_printf ("%d = create_token ()", primary_token);
@@ -1828,3 +1888,4 @@
 			     myself->uid, myself->gid,
 			     attribute);
 }
+
diff -u cygwin.orig/security.h cygwin/security.h
--- cygwin.orig/security.h	2002-07-25 22:40:52.000000000 -0400
+++ cygwin/security.h	2002-07-25 22:37:24.000000000 -0400
@@ -87,33 +87,39 @@
 };

 class cygsidlist {
+  int maxcount;
 public:
   int count;
   cygsid *sids;

-  cygsidlist () : count (0), sids (NULL) {}
+  cygsidlist () : maxcount(12), count (0), sids (new cygsid [12]) {}
   ~cygsidlist () { delete [] sids; }

-  BOOL add (cygsid &nsi)
+  BOOL add (PSID nsi)
     {
-      cygsid *tmp = new cygsid [count + 1];
-      if (!tmp)
-	return FALSE;
-      for (int i = 0; i < count; ++i)
-	tmp[i] = sids[i];
-      delete [] sids;
-      sids = tmp;
+      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;
     }
-  BOOL add (const PSID nsid) { return add (nsid); }
+  BOOL add (cygsid &nsi) { return add ((PSID) nsi); }
   BOOL add (const char *sidstr)
     { cygsid nsi (sidstr); return add (nsi); }

   BOOL operator+= (cygsid &si) { return add (si); }
   BOOL operator+= (const char *sidstr) { return add (sidstr); }
+  BOOL operator+= (const PSID psid) { return add (psid); }

-  BOOL contains (cygsid &sid) const
+  BOOL contains (PSID sid) const
     {
       for (int i = 0; i < count; ++i)
 	if (sids[i] == sid)
@@ -131,6 +137,34 @@
     }
 };

+class cygsidarray {
+public:
+  int suppcount;
+  cygsid sids[];
+
+  int size (int suppcount) const
+    { return sizeof(int) + (suppcount + 1) * sizeof(cygsid); }
+  BOOL addsuppfromgr(const struct __group32 *gr)
+    {
+      if (sids[1 + suppcount].getfromgr(gr))
+        {
+	  suppcount++;
+	  return TRUE;
+	}
+      return FALSE;
+    }
+  int position (int from, PSID psid) const
+    {
+      for (int i = from; i <= suppcount; ++i)
+	if (sids[i] == psid)
+	  return i;
+      return -1;
+    }
+  BOOL issetgroups () const { return (suppcount >= 0); }
+  PSID pgpsid () { return (PSID) sids[0]; }
+  cygsid * pgcygsidptr () { return &sids[0]; }
+};
+
 extern cygsid well_known_null_sid;
 extern cygsid well_known_world_sid;
 extern cygsid well_known_local_sid;
@@ -180,9 +214,9 @@
 /* Try a subauthentication. */
 HANDLE subauth (struct passwd *pw);
 /* Try creating a token directly. */
-HANDLE create_token (cygsid &usersid, cygsid &pgrpsid, struct passwd * pw);
+HANDLE create_token (cygsid &usersid, cygsidarray &gsids, struct passwd * pw);
 /* Verify an existing token */
-BOOL verify_token (HANDLE token, cygsid &usersid, cygsid &pgrpsid, BOOL * pintern = NULL);
+BOOL verify_token (HANDLE token, cygsid &usersid, cygsidarray &gsids, BOOL * pintern = NULL);

 /* Extract U-domain\user field from passwd entry. */
 void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user);
diff -u cygwin.orig/syscalls.cc cygwin/syscalls.cc
--- cygwin.orig/syscalls.cc	2002-07-25 22:40:52.000000000 -0400
+++ cygwin/syscalls.cc	2002-07-24 21:37:18.000000000 -0400
@@ -1960,6 +1960,7 @@

   if (!wincap.has_security ()
       || (!cygheap->user.issetuid ()
+	  && !cygheap->user.issetgroups ()
 	  && uid == myself->uid
 	  && myself->gid == cygheap->user.orig_gid)
       || uid == ILLEGAL_UID)
@@ -1969,7 +1970,8 @@
     }

   sigframe thisframe (mainthread);
-  cygsid usersid, pgrpsid;
+  cygsid usersid;
+  cygsidarray *gsids = cygheap->user.gsids;
   HANDLE ptok, sav_token;
   BOOL sav_impersonated, sav_token_is_internal_token;
   BOOL process_ok, explicitly_created_token = FALSE;
@@ -1977,8 +1979,7 @@
   PSID origpsid, psid2 = NO_SID;

   pw_new = getpwuid32 (uid);
-  if (!usersid.getfrompw (pw_new) ||
-      (!pgrpsid.getfromgr (getgrgid32 (myself->gid))))
+  if (!usersid.getfrompw (pw_new) || !gsids)
     {
       set_errno (EINVAL);
       return -1;
@@ -1996,7 +1997,7 @@
   /* Verify if the process token is suitable.
      Currently we do not try to differentiate between
 	 internal tokens and others */
-  process_ok = verify_token (ptok, usersid, pgrpsid);
+  process_ok = verify_token (ptok, usersid, *gsids);
   debug_printf("Process token %sverified", process_ok ? "" : "not ");
   if (process_ok)
     {
@@ -2012,7 +2013,7 @@
   if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE)
     {
       /* 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, *gsids,
 				    & sav_token_is_internal_token);
       debug_printf("Thread token %d %sverified",
 		   cygheap->user.token, token_ok?"":"not ");
@@ -2049,7 +2050,7 @@
     {
       /* If no impersonation token is available, try to
 	 authenticate using NtCreateToken() or subauthentication. */
-      cygheap->user.token = create_token (usersid, pgrpsid, pw_new);
+      cygheap->user.token = create_token (usersid, *gsids, pw_new);
       if (cygheap->user.token != INVALID_HANDLE_VALUE)
 	explicitly_created_token = TRUE;
       else
@@ -2077,7 +2078,7 @@
 	  /* Try setting primary group in token to current group */
 	  if (!SetTokenInformation (cygheap->user.token,
 				    TokenPrimaryGroup,
-				    &pgrpsid, sizeof pgrpsid))
+				    gsids->pgcygsidptr (), sizeof(cygsid)))
 	    debug_printf ("SetTokenInformation(user.token, "
 			  "TokenPrimaryGroup): %E");
 	}
@@ -2143,17 +2144,19 @@
     return 0;

   sigframe thisframe (mainthread);
+  cygsidarray *gsids = cygheap->user.gsids;
   cygsid gsid;
   HANDLE ptok;

   struct __group32 * gr = getgrgid32 (gid);
-  if (!gr || gr->gr_gid != gid || !gsid.getfromgr (gr))
+  if (!gr || gr->gr_gid != gid || !gsid.getfromgr (gr) || !gsids)
     {
       set_errno (EINVAL);
       return -1;
     }
   myself->gid = gid;

+  *(gsids->pgcygsidptr ()) = gsid;
   /* If impersonated, update primary group and revert */
   if (cygheap->user.issetuid ())
     {
diff -u cygwin.orig/uinfo.cc cygwin/uinfo.cc
--- cygwin.orig/uinfo.cc	2002-07-25 22:40:54.000000000 -0400
+++ cygwin/uinfo.cc	2002-07-24 21:38:46.000000000 -0400
@@ -39,7 +39,7 @@
     {
       HANDLE ptok = INVALID_HANDLE_VALUE;
       DWORD siz;
-      cygsid tu;
+      cygsid tu, tpg;
       DWORD ret = 0;

       /* Try to get the SID either from current process and
@@ -50,7 +50,11 @@
       else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
 	system_printf ("GetTokenInformation(): %E");
       else if (!(ret = user.set_sid (tu)))
-	system_printf ("Couldn't retrieve SID from access token!");
+	system_printf ("Couldn't retrieve user SID from access token!");
+      else if (!GetTokenInformation (ptok, TokenPrimaryGroup, &tpg, sizeof tu, &siz))
+	system_printf ("GetTokenInformation(): %E");
+      else if (!(ret = user.gsids_set (tpg)))
+	system_printf ("Couldn't retrieve primary group SID from access token!");
        /* We must set the user name, uid and gid.
 	 If we have a SID, try to get the corresponding Cygwin
 	 password entry. Set user name which can be different
@@ -75,11 +79,14 @@
 	     primary group to the group in /etc/passwd. */
 	  if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
 	    debug_printf ("SetTokenInformation(TokenOwner): %E");
-	  if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup,
-					    &gsid, sizeof gsid))
-	    debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
+	  if (gsid)
+	    {
+	      *(user.gsids->pgcygsidptr ()) = gsid;
+	      if (!SetTokenInformation (ptok, TokenPrimaryGroup,
+					&gsid, sizeof gsid))
+		debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
+	    }
 	 }
-
       if (ptok != INVALID_HANDLE_VALUE)
 	CloseHandle (ptok);
     }


More information about the Cygwin-patches mailing list