Patches to seteuid() etc...

Pierre A. Humblet Pierre.Humblet@ieee.org
Wed May 22 20:55:00 GMT 2002


Hello Corinna,

Here are the patches to seteuid etc.. discussed recently.

Pierre

2002-05-22  Pierre Humblet <pierre.humblet@ieee.org>

	* syscalls.cc (seteuid): Do not take allow_ntsec into account. 
	Attempt to use an existing or new token even when the uid
	matches orig_uid, but the gid is not in the process token. 
	Major reorganization after several incremental changes.
	(setegid): Do not take allow_ntsec into account. Minor
	reorganization after several incremental changes.
	* security.cc (create_token): Call __sec_user() instead of
	sec_user() to remove dependence on allow_ntsec. Verify that
	the returned sd is non-null.
-------------- next part --------------
--- syscalls.cc.orig	2002-05-16 05:30:48.000000000 -0400
+++ syscalls.cc	2002-05-21 20:30:22.000000000 -0400
@@ -1947,274 +1947,248 @@
 extern "C" int
 seteuid (__uid16_t uid)
 {
+  if (!wincap.has_security ()) return 0;
+
+  if (uid == ILLEGAL_UID)
+    {
+      debug_printf ("new euid == illegal euid, nothing happens");
+      return 0;
+    }
+
   sigframe thisframe (mainthread);
-  if (wincap.has_security ())
+  DWORD ulen = UNLEN + 1;
+  DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+  char orig_username[UNLEN + 1];
+  char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+  char username[UNLEN + 1];
+  char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+  cygsid usersid, pgrpsid;
+  HANDLE ptok, sav_token;
+  BOOL sav_impersonated, sav_token_is_internal_token;
+  BOOL process_ok, explicitly_created_token = FALSE;
+  struct passwd * pw_new, * pw_cur;
+  cygheap_user user;
+  PSID origpsid, psid2 = NO_SID;
+
+  debug_printf ("uid: %d myself->gid: %d", uid, myself->gid);
+
+  pw_new = getpwuid (uid);
+  if (!usersid.getfrompw (pw_new) ||
+      (!pgrpsid.getfromgr (getgrgid (myself->gid))))
     {
-      char orig_username[UNLEN + 1];
-      char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-      char username[UNLEN + 1];
-      DWORD ulen = UNLEN + 1;
-      char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-      DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
-      SID_NAME_USE use;
-
-      if (uid == ILLEGAL_UID || uid == myself->uid)
-	{
-	  debug_printf ("new euid == current euid, nothing happens");
-	  return 0;
-	}
-      struct passwd *pw_new = getpwuid (uid);
-      if (!pw_new)
-	{
-	  set_errno (EINVAL);
-	  return -1;
+      set_errno (EINVAL);
+      return -1;
+    }
+  /* Save current information */
+  sav_token = cygheap->user.token;
+  sav_impersonated = cygheap->user.impersonated;
+  char *env;
+  orig_username[0] = orig_domain[0] = '\0';
+  if ((env = getenv ("USERNAME")))
+    strlcpy (orig_username, env, sizeof(orig_username));
+  if ((env = getenv ("USERDOMAIN")))
+    strlcpy (orig_domain, env, sizeof(orig_domain));
+
+  RevertToSelf();
+  if (!OpenProcessToken (GetCurrentProcess (),
+			 TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok))
+    {
+      __seterrno ();
+      goto failed;
+    }
+  /* 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);
+  debug_printf("Process token %sverified", process_ok?"":"not ");
+  if (process_ok)
+    {
+      if (cygheap->user.token == INVALID_HANDLE_VALUE ||
+	  ! cygheap->user.impersonated )
+        {
+	  CloseHandle (ptok);
+	  return 0; /* No change */
 	}
+      else cygheap->user.impersonated = FALSE;
+    }

-      cygsid tok_usersid;
-      DWORD siz;
-
-      char *env;
-      orig_username[0] = orig_domain[0] = '\0';
-      if ((env = getenv ("USERNAME")))
-	strncat (orig_username, env, UNLEN + 1);
-      if ((env = getenv ("USERDOMAIN")))
-	strncat (orig_domain, env, INTERNET_MAX_HOST_NAME_LENGTH + 1);
-      if (uid == cygheap->user.orig_uid)
-	{
-
-	  debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
-			cygheap->user.token);
-	  RevertToSelf ();
-	  if (cygheap->user.token != INVALID_HANDLE_VALUE)
-	    cygheap->user.impersonated = FALSE;
-
-	  HANDLE ptok = INVALID_HANDLE_VALUE;
-	  if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok))
-	    debug_printf ("OpenProcessToken(): %E\n");
-	  else if (!GetTokenInformation (ptok, TokenUser, &tok_usersid,
-					 sizeof tok_usersid, &siz))
-	    debug_printf ("GetTokenInformation(): %E");
-	  else if (!LookupAccountSid (NULL, tok_usersid, username, &ulen,
-				      domain, &dlen, &use))
-	    debug_printf ("LookupAccountSid(): %E");
-	  else
-	    {
-	      setenv ("USERNAME", username, 1);
-	      setenv ("USERDOMAIN", domain, 1);
-	    }
-	  if (ptok != INVALID_HANDLE_VALUE)
+  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,
+				    & sav_token_is_internal_token);
+      debug_printf("Thread token %d %sverified",
+		   cygheap->user.token, token_ok?"":"not ");
+      if (token_ok)
+        {
+	  /* Return if current token is valid */
+	  if (cygheap->user.impersonated)
+	  {
 	    CloseHandle (ptok);
+	    if (!ImpersonateLoggedOnUser (cygheap->user.token))
+	      system_printf ("Impersonating in seteuid failed: %E");
+	    return 0; /* No change */
+	  }
 	}
+      else cygheap->user.token = INVALID_HANDLE_VALUE;
+    }
+
+  /* Set process def dacl to allow access to impersonated token */
+  char dacl_buf[MAX_DACL_LEN(5)];
+  if (usersid != (origpsid =  cygheap->user.orig_sid())) psid2 = usersid;
+  if (sec_acl ((PACL) dacl_buf, FALSE, origpsid, psid2))
+    {
+      TOKEN_DEFAULT_DACL tdacl;
+      tdacl.DefaultDacl = (PACL) dacl_buf;
+      if (!SetTokenInformation (ptok, TokenDefaultDacl,
+				&tdacl, sizeof dacl_buf))
+	debug_printf ("SetTokenInformation"
+		      "(TokenDefaultDacl): %E");
+    }
+  CloseHandle (ptok);
+
+  if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE)
+    {
+      /* If no impersonation token is available, try to
+	 authenticate using NtCreateToken() or subauthentication. */
+      cygheap->user.token = create_token (usersid, pgrpsid);
+      if (cygheap->user.token != INVALID_HANDLE_VALUE)
+	explicitly_created_token = TRUE;
       else
-	{
-	  cygsid usersid, pgrpsid, origsid;
-	  HANDLE sav_token = INVALID_HANDLE_VALUE;
-	  BOOL sav_impersonation;
-	  BOOL current_token_is_internal_token = FALSE;
-	  BOOL explicitely_created_token = FALSE;
-
-	  struct __group16 *gr = getgrgid (myself->gid);
-	  debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr);
-
-	  usersid.getfrompw (pw_new);
-	  pgrpsid.getfromgr (gr);
-
-	  /* Only when ntsec is ON! */
-	  /* Check if new user == user of impersonation token and
-	     - if reasonable - new pgrp == pgrp of impersonation token. */
-	  if (allow_ntsec && cygheap->user.token != INVALID_HANDLE_VALUE)
-	    {
-	      if (!verify_token(cygheap->user.token, usersid, pgrpsid,
-				& current_token_is_internal_token))
-		{
-		  /* If not, RevertToSelf and close old token. */
-		  debug_printf ("tsid != usersid");
-		  RevertToSelf ();
-		  sav_token = cygheap->user.token;
-		  sav_impersonation = cygheap->user.impersonated;
-		  cygheap->user.token = INVALID_HANDLE_VALUE;
-		  cygheap->user.impersonated = FALSE;
-		}
-	    }
-
-	  /* Only when ntsec is ON! */
-	  /* If no impersonation token is available, try to
-	     authenticate using NtCreateToken() or subauthentication. */
-	  if (allow_ntsec && cygheap->user.token == INVALID_HANDLE_VALUE)
-	    {
-	      HANDLE ptok = INVALID_HANDLE_VALUE;
-
-	      ptok = create_token (usersid, pgrpsid);
-	      if (ptok != INVALID_HANDLE_VALUE)
-		explicitely_created_token = TRUE;
-	      else
-		{
-		  /* create_token failed. Try subauthentication. */
-		  debug_printf ("create token failed, try subauthentication.");
-		  ptok = subauth (pw_new);
-		}
-	      if (ptok != INVALID_HANDLE_VALUE)
-		{
-		  cygwin_set_impersonation_token (ptok);
-		  /* If sav_token was internally created, destroy it. */
-		  if (sav_token != INVALID_HANDLE_VALUE &&
-		      current_token_is_internal_token)
-		    CloseHandle (sav_token);
-		}
-	      else if (sav_token != INVALID_HANDLE_VALUE)
-		cygheap->user.token = sav_token;
-	    }
-	  /* If no impersonation is active but an impersonation
-	     token is available, try to impersonate. */
-	  if (cygheap->user.token != INVALID_HANDLE_VALUE &&
-	      !cygheap->user.impersonated)
-	    {
-	      debug_printf ("Impersonate (uid == %d)", uid);
-	      RevertToSelf ();
-
-	      /* If the token was explicitely created, all information has
-		 already been set correctly. */
-	      if (!explicitely_created_token)
-		{
-		  /* Try setting owner to same value as user. */
-		  if (usersid &&
-		      !SetTokenInformation (cygheap->user.token, TokenOwner,
-					    &usersid, sizeof usersid))
-		    debug_printf ("SetTokenInformation(user.token, "
-				  "TokenOwner): %E");
-		  /* Try setting primary group in token to current group
-		     if token not explicitely created. */
-		  if (pgrpsid &&
-		      !SetTokenInformation (cygheap->user.token,
-					    TokenPrimaryGroup,
-					    &pgrpsid, sizeof pgrpsid))
-		    debug_printf ("SetTokenInformation(user.token, "
-				  "TokenPrimaryGroup): %E");
-		}
-	      /* Set process def dacl to allow access to impersonated token */
-	      char dacl_buf[MAX_DACL_LEN(5)];
-	      origsid = cygheap->user.orig_sid ();
-	      if (usersid && origsid &&
-		  sec_acl((PACL) dacl_buf, FALSE, origsid, usersid))
-	        {
-		  HANDLE ptok = INVALID_HANDLE_VALUE;
-		  TOKEN_DEFAULT_DACL tdacl;
-		  tdacl.DefaultDacl = (PACL) dacl_buf;
-		  if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_DEFAULT,
-					 &ptok))
-		    debug_printf ("OpenProcessToken(): %E");
-		  else
-		    {
-		      if (!SetTokenInformation (ptok, TokenDefaultDacl,
-						&tdacl, sizeof dacl_buf))
-			debug_printf ("SetTokenInformation"
-				      "(TokenDefaultDacl): %E");
-		    }
-		  if (ptok != INVALID_HANDLE_VALUE) CloseHandle (ptok);
-		}
-	      /* Now try to impersonate. */
-	      if (!LookupAccountSid (NULL, usersid, username, &ulen,
-				     domain, &dlen, &use))
-		debug_printf ("LookupAccountSid (): %E");
-	      else if (!ImpersonateLoggedOnUser (cygheap->user.token))
-		system_printf ("Impersonating (%d) in set(e)uid failed: %E",
-			       cygheap->user.token);
-	      else
-		{
-		  cygheap->user.impersonated = TRUE;
-		  setenv ("USERNAME", username, 1);
-		  setenv ("USERDOMAIN", domain, 1);
-		}
-	    }
+        {
+	  /* create_token failed. Try subauthentication. */
+	  debug_printf ("create token failed, try subauthentication.");
+	  cygheap->user.token = subauth (pw_new);
+	  if (cygheap->user.token == INVALID_HANDLE_VALUE) goto failed;
 	}
+    }

-      cygheap_user user;
-      /* user.token is used in internal_getlogin () to determine if
-	 impersonation is active. If so, the token is used for
-	 retrieving user's SID. */
-      user.token = cygheap->user.impersonated ? cygheap->user.token
-					      : INVALID_HANDLE_VALUE;
-      /* Unsetting these both env vars is necessary to get NetUserGetInfo()
-	 called in internal_getlogin ().  Otherwise the wrong path is used
-	 after a user switch, probably. */
-      unsetenv ("HOMEDRIVE");
-      unsetenv ("HOMEPATH");
-      struct passwd *pw_cur = internal_getlogin (user);
-      if (pw_cur != pw_new)
-	{
-	  debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
-			cygheap->user.token, pw_cur->pw_uid,
-			pw_new->pw_uid, cygheap->user.orig_uid);
-	  setenv ("USERNAME", orig_username, 1);
-	  setenv ("USERDOMAIN", orig_domain, 1);
-	  set_errno (EPERM);
-	  return -1;
+  /* Lookup username and domain before impersonating,
+     LookupAccountSid() returns a different answer afterwards. */
+  SID_NAME_USE use;
+  if (!LookupAccountSid (NULL, usersid, username, &ulen,
+			 domain, &dlen, &use))
+    {
+      debug_printf ("LookupAccountSid (): %E");
+      __seterrno ();
+      goto failed;
+    }
+  /* If using the token, set info and impersonate */
+  if (! process_ok )
+    {
+      /* If the token was explicitly created, all information has
+	 already been set correctly. */
+      if (!explicitly_created_token)
+        {
+	  /* Try setting owner to same value as user. */
+	  if (!SetTokenInformation (cygheap->user.token, TokenOwner,
+				    &usersid, sizeof usersid))
+	    debug_printf ("SetTokenInformation(user.token, "
+			  "TokenOwner): %E");
+	  /* Try setting primary group in token to current group */
+	  if (!SetTokenInformation (cygheap->user.token,
+				    TokenPrimaryGroup,
+				    &pgrpsid, sizeof pgrpsid))
+	    debug_printf ("SetTokenInformation(user.token, "
+			  "TokenPrimaryGroup): %E");
+	}
+      /* Now try to impersonate. */
+      if (!ImpersonateLoggedOnUser (cygheap->user.token))
+        {
+	  debug_printf ("ImpersonateLoggedOnUser %E");
+	  __seterrno ();
+	  goto failed;
 	}
+      cygheap->user.impersonated = TRUE;
+    }
+
+  /* user.token is used in internal_getlogin () to determine if
+     impersonation is active. If so, the token is used for
+     retrieving user's SID. */
+  user.token = cygheap->user.impersonated ? cygheap->user.token
+                                          : INVALID_HANDLE_VALUE;
+  /* Unsetting these two env vars is necessary to get NetUserGetInfo()
+     called in internal_getlogin ().  Otherwise the wrong path is used
+     after a user switch, probably. */
+  unsetenv ("HOMEDRIVE");
+  unsetenv ("HOMEPATH");
+  setenv ("USERDOMAIN", domain, 1);
+  setenv ("USERNAME", username, 1);
+  pw_cur = internal_getlogin (user);
+  if (pw_cur == pw_new)
+    {
+      /* If sav_token was internally created and is replaced, destroy it. */
+      if (sav_token != INVALID_HANDLE_VALUE &&
+	  sav_token != cygheap->user.token &&
+	  sav_token_is_internal_token)
+	CloseHandle (sav_token);
       myself->uid = uid;
       cygheap->user = user;
+      return 0;
     }
-  else
-    set_errno (ENOSYS);
-  debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
-  return 0;
+  debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
+		cygheap->user.token, pw_cur->pw_uid,
+		pw_new->pw_uid, cygheap->user.orig_uid);
+  set_errno (EPERM);
+
+ failed:
+  setenv ("USERNAME", orig_username, 1);
+  setenv ("USERDOMAIN", orig_domain, 1);
+  cygheap->user.token = sav_token;
+  cygheap->user.impersonated = sav_impersonated;
+  if ( cygheap->user.token != INVALID_HANDLE_VALUE &&
+       cygheap->user.impersonated &&
+       !ImpersonateLoggedOnUser (cygheap->user.token))
+    system_printf ("Impersonating in seteuid failed: %E");
+  return -1;
 }

 /* setegid: from System V.  */
 extern "C" int
 setegid (__gid16_t gid)
 {
+  if ((!wincap.has_security ()) ||
+      (gid == ILLEGAL_GID))
+    return 0;
+
   sigframe thisframe (mainthread);
-  if (wincap.has_security ())
-    {
-      if (gid != ILLEGAL_GID)
-	{
-	  struct __group16 *gr;
+  cygsid gsid;
+  HANDLE ptok;

-	  if (!(gr = getgrgid (gid)))
-	    {
-	      set_errno (EINVAL);
-	      return -1;
-	    }
-	  myself->gid = gid;
-	  if (allow_ntsec)
-	    {
-	      cygsid gsid;
-	      HANDLE ptok;
-
-	      if (gsid.getfromgr (gr))
-		{
-		  /* Remove impersonation */
-		  if (cygheap->user.token != INVALID_HANDLE_VALUE
-		      && cygheap->user.impersonated)
-		    {
-		      if (!SetTokenInformation (cygheap->user.token,
-						TokenPrimaryGroup,
-						&gsid, sizeof gsid))
-			debug_printf ("SetTokenInformation(primary, "
-				      "TokenPrimaryGroup): %E");
-		      RevertToSelf ();
-		    }
-		  if (!OpenProcessToken (GetCurrentProcess (),
-					 TOKEN_ADJUST_DEFAULT,
-					 &ptok))
-		    debug_printf ("OpenProcessToken(): %E\n");
-		  else
-		    {
-		      if (!SetTokenInformation (ptok, TokenPrimaryGroup,
-						&gsid, sizeof gsid))
-			debug_printf ("SetTokenInformation(process, "
-				      "TokenPrimaryGroup): %E");
-		      CloseHandle (ptok);
-		    }
-		  if (cygheap->user.token != INVALID_HANDLE_VALUE
-		      && cygheap->user.impersonated)
-		    ImpersonateLoggedOnUser (cygheap->user.token);
-		}
-	    }
-	}
+  if (!(gsid.getfromgr (getgrgid (gid))))
+    {
+      set_errno (EINVAL);
+      return -1;
     }
+  myself->gid = gid;
+
+  /* If impersonated, update primary group and revert */
+  if (cygheap->user.token != INVALID_HANDLE_VALUE
+      && cygheap->user.impersonated)
+    {
+      if (!SetTokenInformation (cygheap->user.token,
+				TokenPrimaryGroup,
+				&gsid, sizeof gsid))
+	debug_printf ("SetTokenInformation(thread, "
+		      "TokenPrimaryGroup): %E");
+      RevertToSelf ();
+    }
+  if (!OpenProcessToken (GetCurrentProcess (),
+			 TOKEN_ADJUST_DEFAULT,
+			 &ptok))
+    debug_printf ("OpenProcessToken(): %E\n");
   else
-    set_errno (ENOSYS);
+    {
+      if (!SetTokenInformation (ptok, TokenPrimaryGroup,
+				&gsid, sizeof gsid))
+	debug_printf ("SetTokenInformation(process, "
+		      "TokenPrimaryGroup): %E");
+      CloseHandle (ptok);
+    }
+  if (cygheap->user.token != INVALID_HANDLE_VALUE
+      && cygheap->user.impersonated
+      && !ImpersonateLoggedOnUser (cygheap->user.token))
+    system_printf ("Impersonating in setegid failed: %E");
   return 0;
 }

-------------- next part --------------
--- security.cc.orig	2002-05-21 19:34:44.000000000 -0400
+++ security.cc	2002-05-21 19:39:12.000000000 -0400
@@ -854,10 +854,11 @@
   else
     {
       /* Set security descriptor and primary group */
-      psa = sec_user (sa_buf, usersid);
-      if (!SetSecurityDescriptorGroup (
-                   (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
-                   special_pgrp?pgrpsid:well_known_null_sid, FALSE))
+      psa = __sec_user (sa_buf, usersid, TRUE);
+      if (psa->lpSecurityDescriptor && 
+	  !SetSecurityDescriptorGroup (
+	      (PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
+	      special_pgrp?pgrpsid:well_known_null_sid, FALSE))
           debug_printf ("SetSecurityDescriptorGroup %E");
       /* Convert to primary token. */
       if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa,


More information about the Cygwin-patches mailing list