Index: cygheap.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/cygheap.h,v retrieving revision 1.57 diff -u -p -r1.57 cygheap.h --- cygheap.h 17 Jan 2003 05:18:29 -0000 1.57 +++ cygheap.h 12 Jun 2003 02:44:33 -0000 @@ -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: dtable.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/dtable.cc,v retrieving revision 1.111 diff -u -p -r1.111 dtable.cc --- dtable.cc 2 Mar 2003 18:37:17 -0000 1.111 +++ dtable.cc 12 Jun 2003 02:44:35 -0000 @@ -635,8 +635,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)) @@ -655,8 +654,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: fhandler_socket.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_socket.cc,v retrieving revision 1.104 diff -u -p -r1.104 fhandler_socket.cc --- fhandler_socket.cc 7 Jun 2003 11:05:35 -0000 1.104 +++ fhandler_socket.cc 12 Jun 2003 02:44:37 -0000 @@ -331,12 +331,10 @@ fhandler_socket::dup (fhandler_base *chi 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: fork.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fork.cc,v retrieving revision 1.107 diff -u -p -r1.107 fork.cc --- fork.cc 24 Apr 2003 01:57:07 -0000 1.107 +++ fork.cc 12 Jun 2003 02:44:38 -0000 @@ -237,14 +237,7 @@ fork_child (HANDLE& hParent, dll *&first /* 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, @@ -437,8 +430,7 @@ fork_parent (HANDLE& hParent, dll *&firs si.cbReserved2 = sizeof (ch); /* Remove impersonation */ - if (cygheap->user.issetuid ()) - RevertToSelf (); + cygheap->user.deimpersonate (); ch.parent = hParent; #ifdef DEBUGGING @@ -486,8 +478,7 @@ fork_parent (HANDLE& hParent, dll *&firs 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; } @@ -514,8 +505,7 @@ fork_parent (HANDLE& hParent, dll *&firs 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: grp.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/grp.cc,v retrieving revision 1.79 diff -u -p -r1.79 grp.cc --- grp.cc 17 Apr 2003 20:05:15 -0000 1.79 +++ grp.cc 12 Jun 2003 02:44:39 -0000 @@ -262,7 +262,7 @@ internal_getgroups (int gidsetsize, __gi { /* 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; } @@ -296,7 +296,7 @@ internal_getgroups (int gidsetsize, __gi ++cnt; if (gidsetsize && cnt > gidsetsize) { - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); goto error; } @@ -306,7 +306,7 @@ internal_getgroups (int gidsetsize, __gi } else debug_printf ("%d = GetTokenInformation(NULL) %E", size); - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); return cnt; } Index: security.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/security.cc,v retrieving revision 1.144 diff -u -p -r1.144 security.cc --- security.cc 11 Apr 2003 09:38:07 -0000 1.144 +++ security.cc 12 Jun 2003 02:44:46 -0000 @@ -71,10 +71,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; } } @@ -718,7 +724,7 @@ verify_token (HANDLE token, cygsid &user if (pintern) { TOKEN_SOURCE ts; - if (!GetTokenInformation (cygheap->user.token, TokenSource, + if (!GetTokenInformation (token, TokenSource, &ts, sizeof ts, &size)) debug_printf ("GetTokenInformation(): %E"); else @@ -1907,7 +1913,7 @@ check_file_access (const char *fn, int f goto done; if (cygheap->user.issetuid ()) - hToken = cygheap->user.token; + hToken = cygheap->user.token (); else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken)) { __seterrno (); @@ -1915,7 +1921,7 @@ check_file_access (const char *fn, int f } if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken))) __seterrno (); - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); if (!status) goto done; Index: spawn.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/spawn.cc,v retrieving revision 1.123 diff -u -p -r1.123 spawn.cc --- spawn.cc 9 Jun 2003 13:29:12 -0000 1.123 +++ spawn.cc 12 Jun 2003 02:44:48 -0000 @@ -622,8 +622,7 @@ spawn_guts (const char * prog_arg, const 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. @@ -679,7 +678,7 @@ spawn_guts (const char * prog_arg, const 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 */ @@ -693,8 +692,8 @@ spawn_guts (const char * prog_arg, const } /* 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: syscalls.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/syscalls.cc,v retrieving revision 1.271 diff -u -p -r1.271 syscalls.cc --- syscalls.cc 26 May 2003 16:52:58 -0000 1.271 +++ syscalls.cc 12 Jun 2003 02:44:52 -0000 @@ -2058,66 +2058,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; - } - /* 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) - { - if (cygheap->user.issetuid ()) - cygheap->user.impersonated = FALSE; - else - { - CloseHandle (ptok); - goto success; /* No change */ - } + goto failed_ptok;; } - if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) + /* 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)) { - /* 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 */ - } - } + 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; + } + + debug_printf ("New token %d, state %d", new_token, new_state); + /* Return if current token is valid */ + if (cygheap->user.impersonation_state == new_state) + { + cygheap->user.reimpersonate (); + goto success; /* No change */ } /* Set process def dacl to allow access to impersonated token */ @@ -2133,72 +2119,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; } @@ -2279,7 +2265,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, " @@ -2297,7 +2283,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: uinfo.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/uinfo.cc,v retrieving revision 1.113 diff -u -p -r1.113 uinfo.cc --- uinfo.cc 9 Jun 2003 13:29:12 -0000 1.113 +++ uinfo.cc 12 Jun 2003 02:44:54 -0000 @@ -103,7 +103,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) @@ -115,17 +115,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 *