OSDN Git Service

* cygheap.h (enum impersonation): New enum.
authorcorinna <corinna>
Mon, 30 Jun 2003 13:07:36 +0000 (13:07 +0000)
committercorinna <corinna>
Mon, 30 Jun 2003 13:07:36 +0000 (13:07 +0000)
(cygheap_user::token): Delete.
(cygheap_user::impersonated): Delete.
(cygheap_user::external_token): New member.
(cygheap_user::internal_token): New member.
(cygheap_user::impersonation_state): New member.
(cygheap_user::issetuid): Modify.
(cygheap_user::token): New method.
(cygheap_user::deimpersonate): New method.
(cygheap_user::reimpersonate): New method.
(cygheap_user::has_impersonation_tokens): New method.
(cygheap_user::close_impersonation_tokens): New method.
* dtable.cc (dtable::vfork_child_dup): Use new cygheap_user methods.
* fhandler_socket.cc (fhandler_socket::dup): Ditto.
* fork.cc (fork_child): Ditto.
(fork_parent): Ditto.
* grp.cc (internal_getgroups): Ditto.
* security.cc (verify_token): Ditto.
(check_file_access): Ditto.
(cygwin_set_impersonation_token): Detect conflicts. Set
user.external_token.
* spawn.cc (spawn_guts): Use new cygheap_user methods.
* syscalls.cc (seteuid32): Rearrange to use the two tokens
in cygheap_user.
(setegid32): Use new cygheap_user methods.
* uinfo.cc: (internal_getlogin): Ditto.

winsup/cygwin/ChangeLog
winsup/cygwin/cygheap.h
winsup/cygwin/dtable.cc
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/fork.cc
winsup/cygwin/grp.cc
winsup/cygwin/security.cc
winsup/cygwin/spawn.cc
winsup/cygwin/syscalls.cc
winsup/cygwin/uinfo.cc

index d41f7ab..8284089 100644 (file)
@@ -1,3 +1,32 @@
+2003-06-30  Pierre Humblet  <pierre.humblet@ieee.org>
+
+       * cygheap.h (enum impersonation): New enum.
+       (cygheap_user::token): Delete.
+       (cygheap_user::impersonated): Delete.
+       (cygheap_user::external_token): New member.
+       (cygheap_user::internal_token): New member.
+       (cygheap_user::impersonation_state): New member.
+       (cygheap_user::issetuid): Modify.
+       (cygheap_user::token): New method.   
+       (cygheap_user::deimpersonate): New method.
+       (cygheap_user::reimpersonate): New method.
+       (cygheap_user::has_impersonation_tokens): New method.
+       (cygheap_user::close_impersonation_tokens): New method.
+       * dtable.cc (dtable::vfork_child_dup): Use new cygheap_user methods.
+       * fhandler_socket.cc (fhandler_socket::dup): Ditto.
+       * fork.cc (fork_child): Ditto.
+       (fork_parent): Ditto.
+       * grp.cc (internal_getgroups): Ditto.
+       * security.cc (verify_token): Ditto.
+       (check_file_access): Ditto.
+       (cygwin_set_impersonation_token): Detect conflicts. Set
+       user.external_token.
+       * spawn.cc (spawn_guts): Use new cygheap_user methods.
+       * syscalls.cc (seteuid32): Rearrange to use the two tokens
+       in cygheap_user.
+       (setegid32): Use new cygheap_user methods.
+       * uinfo.cc: (internal_getlogin): Ditto.
+
 2003-06-25  Doru Carastan  <doru.carastan@mvista.com>
 
        * Makefile.in: Use INSTALL_PROGRAM to install the cygwin DLL.
index bfa7a93..963d9c4 100644 (file)
@@ -92,7 +92,13 @@ enum homebodies
   CH_HOME
 };
 
-struct passwd;
+enum impersonation
+{
+  IMP_BAD = -1,
+  IMP_NONE = 0,
+  IMP_EXTERNAL,
+  IMP_INTERNAL
+};
 
 class cygheap_user
 {
@@ -117,8 +123,9 @@ public:
 
   /* token is needed if set(e)uid should be called. It can be set by a call
      to `set_impersonation_token()'. */
-  HANDLE token;
-  BOOL   impersonated;
+  HANDLE external_token;
+  HANDLE internal_token;
+  enum impersonation impersonation_state;
 
   /* CGF 2002-06-27.  I removed the initializaton from this constructor
      since this class is always allocated statically.  That means that everything
@@ -165,7 +172,40 @@ public:
   const char *ontherange (homebodies what, struct passwd * = NULL);
   bool issetuid () const
   {
-    return impersonated && token != INVALID_HANDLE_VALUE;
+    return impersonation_state > IMP_NONE;
+  }
+  HANDLE token ()
+  {
+    if (impersonation_state == IMP_EXTERNAL)
+      return external_token;
+    if (impersonation_state == IMP_INTERNAL)
+      return internal_token;
+    return INVALID_HANDLE_VALUE;
+  }
+  void deimpersonate ()
+  {
+    if (impersonation_state > IMP_NONE)
+      RevertToSelf ();
+  }
+  void reimpersonate ()
+  {
+    if (impersonation_state > IMP_NONE
+       && !ImpersonateLoggedOnUser (token ()))
+      system_printf ("ImpersonateLoggedOnUser: %E");
+  }
+  bool has_impersonation_tokens () { return external_token || internal_token; }
+  void close_impersonation_tokens ()
+  {
+    if (external_token)
+      {
+       CloseHandle (external_token);
+       external_token = 0;
+      }
+    if (internal_token)
+      {
+       CloseHandle (internal_token);
+       internal_token = 0;
+      }
   }
   const char *cygheap_user::test_uid (char *&, const char *, size_t)
     __attribute__ ((regparm (3)));
index 315505b..973b3c4 100644 (file)
@@ -634,8 +634,7 @@ dtable::vfork_child_dup ()
   int res = 1;
 
   /* Remove impersonation */
-  if (cygheap->user.issetuid ())
-    RevertToSelf ();
+  cygheap->user.deimpersonate ();
 
   for (size_t i = 0; i < size; i++)
     if (not_open (i))
@@ -654,8 +653,7 @@ dtable::vfork_child_dup ()
 
 out:
   /* Restore impersonation */
-  if (cygheap->user.issetuid ())
-    ImpersonateLoggedOnUser (cygheap->user.token);
+  cygheap->user.reimpersonate ();
 
   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
   return 1;
index 18cc018..4c66f9e 100644 (file)
@@ -330,12 +330,10 @@ fhandler_socket::dup (fhandler_base *child)
         If WSADuplicateSocket() still fails for some reason, we fall back
         to DuplicateHandle(). */
       WSASetLastError (0);
-      if (cygheap->user.issetuid ())
-       RevertToSelf ();
+      cygheap->user.deimpersonate ();
       fhs->set_io_handle (get_io_handle ());
       fhs->fixup_before_fork_exec (GetCurrentProcessId ());
-      if (cygheap->user.issetuid ())
-       ImpersonateLoggedOnUser (cygheap->user.token);
+      cygheap->user.reimpersonate ();
       if (!WSAGetLastError ())
        {
          fhs->fixup_after_fork (hMainProc);
index 184e566..efda722 100644 (file)
@@ -236,14 +236,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
 
   /* Restore the inheritance state as in parent
      Don't call setuid here! The flags are already set. */
-  if (cygheap->user.impersonated)
-    {
-      debug_printf ("Impersonation of child, token: %d", cygheap->user.token);
-      if (cygheap->user.token == INVALID_HANDLE_VALUE)
-       RevertToSelf (); // probably not needed
-      else if (!ImpersonateLoggedOnUser (cygheap->user.token))
-       system_printf ("Impersonate for forked child failed: %E");
-    }
+  cygheap->user.reimpersonate ();
 
   sync_with_parent ("after longjmp.", TRUE);
   sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent,
@@ -436,8 +429,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
   si.cbReserved2 = sizeof (ch);
 
   /* Remove impersonation */
-  if (cygheap->user.issetuid ())
-    RevertToSelf ();
+  cygheap->user.deimpersonate ();
 
   ch.parent = hParent;
 #ifdef DEBUGGING
@@ -485,8 +477,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
       ForceCloseHandle (subproc_ready);
       ForceCloseHandle (forker_finished);
       /* Restore impersonation */
-      if (cygheap->user.issetuid ())
-       ImpersonateLoggedOnUser (cygheap->user.token);
+      cygheap->user.reimpersonate ();
       cygheap_setup_for_child_cleanup (newheap, &ch, 0);
       return -1;
     }
@@ -513,8 +504,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
   strcpy (forked->progname, myself->progname);
 
   /* Restore impersonation */
-  if (cygheap->user.issetuid ())
-    ImpersonateLoggedOnUser (cygheap->user.token);
+  cygheap->user.reimpersonate ();
 
   ProtectHandle (pi.hThread);
   /* Protect the handle but name it similarly to the way it will
index 19b7fe9..c83c1e5 100644 (file)
@@ -261,7 +261,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid)
     {
       /* If impersonated, use impersonation token. */
       if (cygheap->user.issetuid ())
-       hToken = cygheap->user.token;
+       hToken = cygheap->user.token ();
       else if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &hToken))
        hToken = NULL;
     }
@@ -295,7 +295,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid)
                          ++cnt;
                          if (gidsetsize && cnt > gidsetsize)
                            {
-                             if (hToken != cygheap->user.token)
+                             if (!cygheap->user.issetuid ())
                                CloseHandle (hToken);
                              goto error;
                            }
@@ -305,7 +305,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid)
        }
       else
        debug_printf ("%d = GetTokenInformation(NULL) %E", size);
-      if (hToken != cygheap->user.token)
+      if (!cygheap->user.issetuid ())
        CloseHandle (hToken);
       return cnt;
     }
index 7bae8f4..5ccf37e 100644 (file)
@@ -70,10 +70,16 @@ extern "C" void
 cygwin_set_impersonation_token (const HANDLE hToken)
 {
   debug_printf ("set_impersonation_token (%d)", hToken);
-  if (cygheap->user.token != hToken)
+  if (cygheap->user.impersonation_state == IMP_EXTERNAL
+      && cygheap->user.external_token != hToken)
     {
-      cygheap->user.token = hToken;
-      cygheap->user.impersonated = FALSE;
+      set_errno (EPERM);
+      return;
+    }
+  else
+    {
+      cygheap->user.external_token = hToken;
+      return;
     }
 }
 
@@ -717,7 +723,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern)
   if (pintern)
     {
       TOKEN_SOURCE ts;
-      if (!GetTokenInformation (cygheap->user.token, TokenSource,
+      if (!GetTokenInformation (token, TokenSource,
                                &ts, sizeof ts, &size))
        debug_printf ("GetTokenInformation(): %E");
       else
@@ -1906,7 +1912,7 @@ check_file_access (const char *fn, int flags)
     goto done;
 
   if (cygheap->user.issetuid ())
-    hToken = cygheap->user.token;
+    hToken = cygheap->user.token ();
   else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken))
     {
       __seterrno ();
@@ -1914,7 +1920,7 @@ check_file_access (const char *fn, int flags)
     }
   if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken)))
     __seterrno ();
-  if (hToken != cygheap->user.token)
+  if (!cygheap->user.issetuid ())
     CloseHandle (hToken);
   if (!status)
     goto done;
index eeee13c..be469ef 100644 (file)
@@ -621,8 +621,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   cygbench ("spawn-guts");
 
   cygheap->fdtab.set_file_pointers_for_exec ();
-  if (cygheap->user.issetuid ())
-    RevertToSelf ();
+  cygheap->user.deimpersonate ();
   /* When ruid != euid we create the new process under the current original
      account and impersonate in child, this way maintaining the different
      effective vs. real ids.
@@ -678,7 +677,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
       ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc,
                                          real_path.iscygexec ());
       newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ());
-      rc = CreateProcessAsUser (cygheap->user.token,
+      rc = CreateProcessAsUser (cygheap->user.token (),
                       runpath,         /* image name - with full path */
                       one_line.buf,    /* what was passed to exec */
                       sec_attribs,     /* process security attrs */
@@ -692,8 +691,8 @@ spawn_guts (const char * prog_arg, const char *const *argv,
     }
   /* Restore impersonation. In case of _P_OVERLAY this isn't
      allowed since it would overwrite child data. */
-  if (mode != _P_OVERLAY && cygheap->user.issetuid ())
-    ImpersonateLoggedOnUser (cygheap->user.token);
+  if (mode != _P_OVERLAY)
+      cygheap->user.reimpersonate ();
 
   MALLOC_CHECK;
   if (envblock)
index ad6a66f..8e545c4 100644 (file)
@@ -2057,66 +2057,52 @@ seteuid32 (__uid32_t uid)
   sigframe thisframe (mainthread);
   cygsid usersid;
   user_groups &groups = cygheap->user.groups;
-  HANDLE ptok, sav_token;
-  BOOL sav_impersonated, sav_token_is_internal_token;
-  BOOL process_ok, explicitly_created_token = FALSE;
+  HANDLE ptok, new_token = INVALID_HANDLE_VALUE;
   struct passwd * pw_new;
   PSID origpsid, psid2 = NO_SID;
+  enum impersonation new_state = IMP_BAD;
+  BOOL token_is_internal;
 
   pw_new = internal_getpwuid (uid);
   if (!wincap.has_security () && pw_new)
-    goto success;
+    goto success_9x;
   if (!usersid.getfrompw (pw_new))
     {
       set_errno (EINVAL);
       return -1;
     }
-  /* Save current information */
-  sav_token = cygheap->user.token;
-  sav_impersonated = cygheap->user.impersonated;
 
   RevertToSelf ();
   if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok))
     {
       __seterrno ();
-      goto failed;
+      goto failed_ptok;;
     }
-  /* 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, groups);
-  debug_printf ("Process token %sverified", process_ok ? "" : "not ");
-  if (process_ok)
+
+  /* Verify if the process token is suitable. */
+  if (verify_token (ptok, usersid, groups))
+    new_state = IMP_NONE;
+  /* Verify if a current token is suitable */
+  else if (cygheap->user.external_token
+          && verify_token (cygheap->user.external_token, usersid, groups))
     {
-      if (cygheap->user.issetuid ())
-       cygheap->user.impersonated = FALSE;
-      else
-       {
-         CloseHandle (ptok);
-         goto success; /* No change */
-       }
+      new_token = cygheap->user.external_token;
+      new_state = IMP_EXTERNAL;
+    }
+  else if (cygheap->user.internal_token
+          && verify_token (cygheap->user.internal_token, usersid, groups,
+                           &token_is_internal))
+    {
+      new_token = cygheap->user.internal_token;
+      new_state = IMP_INTERNAL;
     }
 
-  if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE)
+  debug_printf ("New token %d, state %d", new_token, new_state);
+  /* Return if current token is valid */
+  if (cygheap->user.impersonation_state == new_state)
     {
-      /* Verify if the current tokem is suitable */
-      BOOL token_ok = verify_token (cygheap->user.token, usersid, groups,
-                                   &sav_token_is_internal_token);
-      debug_printf ("Thread token %d %sverified",
-                  cygheap->user.token, token_ok?"":"not ");
-      if (!token_ok)
-       cygheap->user.token = INVALID_HANDLE_VALUE;
-      else
-       {
-         /* Return if current token is valid */
-         if (cygheap->user.impersonated)
-           {
-             CloseHandle (ptok);
-             if (!ImpersonateLoggedOnUser (cygheap->user.token))
-               system_printf ("Impersonating in seteuid failed: %E");
-             goto success; /* No change */
-           }
-       }
+      cygheap->user.reimpersonate ();
+      goto success; /* No change */
     }
 
   /* Set process def dacl to allow access to impersonated token */
@@ -2132,72 +2118,72 @@ seteuid32 (__uid32_t uid)
        debug_printf ("SetTokenInformation"
                      "(TokenDefaultDacl): %E");
     }
-  CloseHandle (ptok);
 
-  if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE)
+  if (new_state == IMP_BAD)
     {
       /* If no impersonation token is available, try to
         authenticate using NtCreateToken () or subauthentication. */
-      cygheap->user.token = create_token (usersid, groups, pw_new);
-      if (cygheap->user.token != INVALID_HANDLE_VALUE)
-       explicitly_created_token = TRUE;
-      else
+      new_token = create_token (usersid, groups, pw_new);
+      if (new_token == INVALID_HANDLE_VALUE)
        {
          /* 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)
+         new_token = subauth (pw_new);
+         if (new_token == INVALID_HANDLE_VALUE)
            goto failed;
        }
+      new_state = IMP_INTERNAL;
     }
 
   /* If using the token, set info and impersonate */
-  if (!process_ok)
+  if (new_state != IMP_NONE)
     {
       /* If the token was explicitly created, all information has
         already been set correctly. */
-      if (!explicitly_created_token)
+      if (new_state == IMP_EXTERNAL)
        {
          /* Try setting owner to same value as user. */
-         if (!SetTokenInformation (cygheap->user.token, TokenOwner,
+         if (!SetTokenInformation (new_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,
+         if (!SetTokenInformation (new_token,
                                    TokenPrimaryGroup,
                                    &groups.pgsid, sizeof (cygsid)))
            debug_printf ("SetTokenInformation(user.token, "
                          "TokenPrimaryGroup): %E");
        }
-      /* Now try to impersonate. */
-      if (!ImpersonateLoggedOnUser (cygheap->user.token))
+      /* Try to impersonate. */
+      if (!ImpersonateLoggedOnUser (new_token))
        {
          debug_printf ("ImpersonateLoggedOnUser %E");
          __seterrno ();
          goto failed;
        }
-      cygheap->user.impersonated = TRUE;
+      /* Keep at most one internal token */
+      if (new_state == IMP_INTERNAL)
+        {
+         if (cygheap->user.internal_token)
+           CloseHandle (cygheap->user.internal_token);
+         cygheap->user.internal_token = new_token;
+       }
     }
-
-  /* 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);
   cygheap->user.set_sid (usersid);
+
 success:
+  CloseHandle (ptok);
+  cygheap->user.impersonation_state = new_state;
+success_9x:
   cygheap->user.set_name (pw_new->pw_name);
   myself->uid = uid;
   groups.ischanged = FALSE;
   return 0;
 
 failed:
-  cygheap->user.token = sav_token;
-  cygheap->user.impersonated = sav_impersonated;
-  if (cygheap->user.issetuid ()
-      && !ImpersonateLoggedOnUser (cygheap->user.token))
-    system_printf ("Impersonating in seteuid failed: %E");
+  CloseHandle (ptok);
+failed_ptok:
+  cygheap->user.reimpersonate ();
   return -1;
 }
 
@@ -2278,7 +2264,7 @@ setegid32 (__gid32_t gid)
   /* If impersonated, update primary group and revert */
   if (cygheap->user.issetuid ())
     {
-      if (!SetTokenInformation (cygheap->user.token,
+      if (!SetTokenInformation (cygheap->user.token (),
                                TokenPrimaryGroup,
                                &gsid, sizeof gsid))
        debug_printf ("SetTokenInformation(thread, "
@@ -2296,7 +2282,7 @@ setegid32 (__gid32_t gid)
       CloseHandle (ptok);
     }
   if (cygheap->user.issetuid ()
-      && !ImpersonateLoggedOnUser (cygheap->user.token))
+      && !ImpersonateLoggedOnUser (cygheap->user.token ()))
     system_printf ("Impersonating in setegid failed: %E");
   return 0;
 }
index 4e688a3..f63230d 100644 (file)
@@ -102,7 +102,7 @@ internal_getlogin (cygheap_user &user)
 void
 uinfo_init ()
 {
-  if (child_proc_info && cygheap->user.token == INVALID_HANDLE_VALUE)
+  if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
     return;
 
   if (!child_proc_info)
@@ -114,17 +114,16 @@ uinfo_init ()
           && cygheap->user.orig_gid == cygheap->user.real_gid
           && !cygheap->user.groups.issetgroups ())
     {
-      if (!ImpersonateLoggedOnUser (cygheap->user.token))
-       system_printf ("ImpersonateLoggedOnUser: %E");
+      cygheap->user.reimpersonate ();
       return;
     }
   else
-    CloseHandle (cygheap->user.token);
+    cygheap->user.close_impersonation_tokens ();
 
   cygheap->user.orig_uid = cygheap->user.real_uid = myself->uid;
   cygheap->user.orig_gid = cygheap->user.real_gid = myself->gid;
+  cygheap->user.impersonation_state = IMP_NONE;
   cygheap->user.set_orig_sid ();       /* Update the original sid */
-  cygheap->user.token = INVALID_HANDLE_VALUE; /* No token present */
 }
 
 extern "C" char *