diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 31 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 2 | ||||
-rw-r--r-- | winsup/cygwin/dcrt0.cc | 8 | ||||
-rw-r--r-- | winsup/cygwin/fork.cc | 34 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/version.h | 7 | ||||
-rw-r--r-- | winsup/cygwin/include/sys/cygwin.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/security.cc | 67 | ||||
-rw-r--r-- | winsup/cygwin/shared.h | 9 | ||||
-rw-r--r-- | winsup/cygwin/spawn.cc | 11 | ||||
-rw-r--r-- | winsup/cygwin/syscalls.cc | 84 | ||||
-rw-r--r-- | winsup/cygwin/uinfo.cc | 13 |
11 files changed, 233 insertions, 36 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a9e3980..3324b61 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,34 @@ +Thu Jun 16 20:55:00 2000 Corinna Vinschen <corinna@vinschen.de> + + * cygwin.din: Define symbols for `cygwin_logon_user' and + `cygwin_set_impersonation_token'. + * dcrt0.cc (dll_crt0_1): Eliminate superfluous conditional + statements. + Add load statements for `ImpersonateLoggedOnUser', `LogonUserA' + and `RevertToSelf'. + * fork.cc (fork): Care for correct impersonation of parent + and child process. + * security.cc (cygwin_set_impersonation_token): New function. + (cygwin_logon_user): Ditto. + shared.h (class pinfo): New members `orig_uid', `orig_gid', + `real_uid' nad `real_gid'. + spawn.cc (spawn_guts): Care for impersonation when starting + child process in a different user context. + * syscalls.cc (setgid): Call `setegid' now. Set real_gid. + (setuid): Call `seteuid' now. Set real_uid. + (seteuid): Functionality moved from setuid to here. Care for + correct impersonation. + (setegid): Functionality moved from setgid to here. + * uinfo.cc (uinfo_init): Initialization of additional pinfo + members. + (getuid): Return real uid. + (getgid): Return real gid. + (geteuid): Return effective uid. + (getegid): Return effective gid. + include/sys/cygwin.h: Add prototypes for `cygwin_logon_user' and + `cygwin_set_impersonation_token'. + include/cygwin/version.h: Bumb API minor version to 22. + Thu Jun 15 18:12:36 2000 Christopher Faylor <cgf@cygnus.com> * path.cc (chdir): Don't set cache to offending chdir. Change comment diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index a8c0006..84f7519 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -988,6 +988,8 @@ cygwin32_posix_to_win32_path_list = cygwin_posix_to_win32_path_list cygwin32_split_path = cygwin_split_path cygwin_winpid_to_pid cygwin32_winpid_to_pid = cygwin_winpid_to_pid +cygwin_logon_user +cygwin_set_impersonation_token realpath reent_data DATA getenv diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 4b87905..302207c 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -763,10 +763,9 @@ dll_crt0_1 () /* Flush signals and ensure that signal thread is up and running. Can't do this for noncygwin case since the signal thread is blocked due to LoadLibrary serialization. */ - if (!dynamically_loaded) - sig_send (NULL, __SIGFLUSH); /* also initializes uid, gid */ + sig_send (NULL, __SIGFLUSH); /* also initializes uid, gid */ - if (user_data->main && !dynamically_loaded) + if (user_data->main) exit (user_data->main (argc, argv, *user_data->envptr)); } @@ -1157,10 +1156,12 @@ LoadDLLfunc (GetSidSubAuthority, 8, advapi32) LoadDLLfunc (GetSidSubAuthorityCount, 4, advapi32) LoadDLLfunc (GetTokenInformation, 20, advapi32) LoadDLLfunc (GetUserNameA, 8, advapi32) +LoadDLLfunc (ImpersonateLoggedOnUser, 4, advapi32) LoadDLLfunc (InitializeAcl, 12, advapi32) LoadDLLfunc (InitializeSecurityDescriptor, 8, advapi32) LoadDLLfunc (InitializeSid, 12, advapi32) LoadDLLfunc (IsValidSid, 4, advapi32) +LoadDLLfunc (LogonUserA, 24, advapi32) LoadDLLfunc (LookupAccountNameA, 28, advapi32) LoadDLLfunc (LookupAccountSidA, 28, advapi32) LoadDLLfunc (LookupPrivilegeValueA, 12, advapi32) @@ -1175,6 +1176,7 @@ LoadDLLfunc (RegQueryValueExA, 24, advapi32) LoadDLLfunc (RegSetValueExA, 24, advapi32) LoadDLLfunc (RegisterEventSourceA, 8, advapi32) LoadDLLfunc (ReportEventA, 36, advapi32) +LoadDLLfunc (RevertToSelf, 0, advapi32) LoadDLLfunc (SetKernelObjectSecurity, 12, advapi32) LoadDLLfunc (SetSecurityDescriptorDacl, 16, advapi32) LoadDLLfunc (SetSecurityDescriptorGroup, 12, advapi32) diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index baa5a95..b024802 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -363,10 +363,16 @@ fork () goto cleanup; } + /* Remove impersonation */ + uid_t uid = geteuid(); + if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) + seteuid (myself->orig_uid); + + char sa_buf[1024]; rc = CreateProcessA (myself->progname, /* image to run */ myself->progname, /* what we send in arg0 */ - &sec_none_nih, /* process security attrs */ - &sec_none_nih, /* thread security attrs */ + allow_ntsec ? sec_user (sa_buf) : &sec_none_nih, + allow_ntsec ? sec_user (sa_buf) : &sec_none_nih, TRUE, /* inherit handles from parent */ c_flags, NULL, /* environment filled in later */ @@ -384,9 +390,16 @@ fork () ForceCloseHandle(subproc_ready); ForceCloseHandle(forker_finished); subproc_ready = forker_finished = NULL; + /* Restore impersonation */ + if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) + seteuid (uid); return -1; } + /* Restore impersonation */ + if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) + seteuid (uid); + ProtectHandle (pi.hThread); /* Protect the handle but name it similarly to the way it will be called in subproc handling. */ @@ -410,6 +423,12 @@ fork () memcpy (child->sidbuf, myself->sidbuf, 40); memcpy (child->logsrv, myself->logsrv, 256); memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + child->token = myself->token; + child->impersonated = myself->impersonated; + child->orig_uid = myself->orig_uid; + child->orig_gid = myself->orig_gid; + child->real_uid = myself->real_uid; + child->real_gid = myself->real_gid; set_child_mmap_ptr (child); /* Wait for subproc to initialize itself. */ @@ -494,6 +513,17 @@ fork () debug_printf ("self %p, pid %d, ppid %d", myself, x, myself ? myself->ppid : -1); + /* Restore the inheritance state as in parent + Don't call setuid here! The flags are already set. */ + if (myself->impersonated) + { + debug_printf ("Impersonation of child, token: %d", myself->token); + if (myself->token == INVALID_HANDLE_VALUE) + RevertToSelf (); // probably not needed + else if (!ImpersonateLoggedOnUser (myself->token)) + system_printf ("Impersonate for forked child failed: %E"); + } + sync_with_parent ("after longjmp.", TRUE); ProtectHandle (hParent); diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index ffa17d0..2143bbb 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -106,10 +106,15 @@ details. */ 19: Export fchown, lchown, lacl 20: regsub, inet_network 21: incompatible change to stdio cr/lf and buffering + 22: Export cygwin_logon_user, cygwin_set_impersonation_token. + geteuid, getegid return effective uid/gid. + getuid, getgid return real uid/gid. + seteuid, setegid set only effective uid/gid. + setuid, setgid set effective and real uid/gid. */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 21 +#define CYGWIN_VERSION_API_MINOR 22 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index ff891cc..6354f0f 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -31,6 +31,9 @@ extern int cygwin_conv_to_full_posix_path (const char *, char *); extern int cygwin_posix_path_list_p (const char *); extern void cygwin_split_path (const char *, char *, char *); +extern HANDLE cygwin_logon_user (const struct passwd *, const char *); +extern void cygwin_set_impersonation_token (const HANDLE); + #ifdef _GNU_H_WINDOWS32_BASE /* included if <windows.h> is included */ extern int cygwin32_attach_handle_to_fd (char *, int, HANDLE, int, int); diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 8537a6d..c468235 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -374,6 +374,73 @@ got_it: return TRUE; } +extern "C" +void +cygwin_set_impersonation_token (const HANDLE hToken) +{ + debug_printf ("set_impersonation_token (%d)", hToken); + if (myself->token != hToken) + { + if (myself->token != INVALID_HANDLE_VALUE) + CloseHandle (myself->token); + myself->token = hToken; + myself->impersonated = FALSE; + } +} + +extern "C" +HANDLE +cygwin_logon_user (const struct passwd *pw, const char *password) +{ + if (os_being_run != winNT) + { + set_errno (ENOSYS); + return INVALID_HANDLE_VALUE; + } + if (!pw) + { + set_errno (EINVAL); + return INVALID_HANDLE_VALUE; + } + + char *c, *nt_user, *nt_domain = NULL; + char usernamebuf[256]; + HANDLE hToken; + + strcpy (usernamebuf, pw->pw_name); + if (pw->pw_gecos) + { + if ((c = strstr (pw->pw_gecos, "U-")) != NULL && + (c == pw->pw_gecos || c[-1] == ',')) + { + usernamebuf[0] = '\0'; + strncat (usernamebuf, c + 2, 255); + if ((c = strchr (usernamebuf, ',')) != NULL) + *c = '\0'; + } + } + nt_user = usernamebuf; + if ((c = strchr (nt_user, '\\')) != NULL) + { + nt_domain = nt_user; + *c = '\0'; + nt_user = c + 1; + } + if (! LogonUserA (nt_user, nt_domain, (char *) password, + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hToken) + || !SetHandleInformation (hToken, + HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) + { + __seterrno (); + return INVALID_HANDLE_VALUE; + } + debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name); + return hToken; +} + /* read_sd reads a security descriptor from a file. In case of error, -1 is returned and errno is set. If sd_buf is too small, 0 is returned and sd_size diff --git a/winsup/cygwin/shared.h b/winsup/cygwin/shared.h index 5c6eff5..1b594d5 100644 --- a/winsup/cygwin/shared.h +++ b/winsup/cygwin/shared.h @@ -93,6 +93,15 @@ class pinfo char logsrv[256]; /* Logon server, may be fully qualified DNS name */ char domain[MAX_COMPUTERNAME_LENGTH+1]; /* Logon domain of the user */ + /* token is needed if sexec should be called. It can be set by a call + to `set_impersonation_token()'. */ + HANDLE token; + BOOL impersonated; + uid_t orig_uid; /* Remains intact also after impersonation */ + uid_t orig_gid; /* Ditto */ + uid_t real_uid; /* Remains intact on seteuid, replaced by setuid */ + gid_t real_gid; /* Ditto */ + /* Non-zero if process was stopped by a signal. */ char stopsig; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 1ff08e4..65e3bd6 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -503,6 +503,9 @@ skip_arg_parsing: /* Preallocated buffer for `sec_user' call */ char sa_buf[1024]; + if (!hToken && myself->token != INVALID_HANDLE_VALUE) + hToken = myself->token; + if (hToken) { /* allow the child to interact with our window station/desktop */ @@ -535,6 +538,11 @@ skip_arg_parsing: else system_printf ("GetTokenInformation: %E"); + /* Remove impersonation */ + uid_t uid = geteuid(); + if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) + seteuid (myself->orig_uid); + rc = CreateProcessAsUser (hToken, real_path, /* image name - with full path */ one_line.buf, /* what was passed to exec */ @@ -550,6 +558,9 @@ skip_arg_parsing: 0, /* use current drive/directory */ &si, &pi); + /* Restore impersonation */ + if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) + seteuid (uid); } else rc = CreateProcessA (real_path, /* image name - with full path */ diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index d2eeab0..6c40cc1 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1797,30 +1797,31 @@ extern "C" int setgid (gid_t gid) { - if (os_being_run == winNT) - { - if (gid != (gid_t) -1) - { - if (!getgrgid (gid)) - { - set_errno (EINVAL); - return -1; - } - myself->gid = gid; - } - } - else - set_errno (ENOSYS); - return 0; + int ret = setegid (gid); + if (!ret) + myself->real_gid = myself->gid; + return ret; } -extern char *internal_getlogin (struct pinfo *pi); - /* setuid: POSIX 4.2.2.1 */ extern "C" int setuid (uid_t uid) { + int ret = seteuid (uid); + if (!ret) + myself->real_uid = myself->uid; + debug_printf ("real: %d, effective: %d", myself->real_uid, myself->uid); + return ret; +} + +extern char *internal_getlogin (struct pinfo *pi); + +/* seteuid: standards? */ +extern "C" +int +seteuid (uid_t uid) +{ if (os_being_run == winNT) { if (uid != (uid_t) -1) @@ -1832,11 +1833,35 @@ setuid (uid_t uid) return -1; } + if (uid != myself->uid) + if (uid == myself->orig_uid) + { + debug_printf ("RevertToSelf() (uid == orig_uid, token=%d)", + myself->token); + RevertToSelf(); + if (myself->token != INVALID_HANDLE_VALUE) + myself->impersonated = FALSE; + } + else if (!myself->impersonated) + { + debug_printf ("Impersonate(uid == %d)", uid); + RevertToSelf(); + if (myself->token != INVALID_HANDLE_VALUE) + if (!ImpersonateLoggedOnUser (myself->token)) + system_printf ("Impersonate(%d) in set(e)uid failed: %E", + myself->token); + else + myself->impersonated = TRUE; + } + struct pinfo pi; pi.psid = (PSID) pi.sidbuf; struct passwd *pw_cur = getpwnam (internal_getlogin (&pi)); if (pw_cur != pw_new) { + debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d", + myself->token, pw_cur->pw_uid, + pw_new->pw_uid, myself->orig_uid); set_errno (EPERM); return -1; } @@ -1849,23 +1874,30 @@ setuid (uid_t uid) } else set_errno (ENOSYS); + debug_printf ("real: %d, effective: %d", myself->real_uid, myself->uid); return 0; } -/* seteuid: standards? */ -extern "C" -int -seteuid (uid_t uid) -{ - return setuid (uid); -} - /* setegid: from System V. */ extern "C" int setegid (gid_t gid) { - return setgid (gid); + if (os_being_run == winNT) + { + if (gid != (gid_t) -1) + { + if (!getgrgid (gid)) + { + set_errno (EINVAL); + return -1; + } + myself->gid = gid; + } + } + else + set_errno (ENOSYS); + return 0; } /* chroot: privileged Unix system call. */ diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 90bb727..b50f155 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -126,6 +126,11 @@ uinfo_init () myself->uid = DEFAULT_UID; myself->gid = DEFAULT_GID; } + /* Set to non impersonated value. */ + myself->token = INVALID_HANDLE_VALUE; + myself->impersonated = TRUE; + myself->orig_uid = myself->real_uid = myself->uid; + myself->orig_gid = myself->real_gid = myself->gid; } extern "C" char * @@ -143,25 +148,25 @@ getlogin (void) extern "C" uid_t getuid (void) { - return myself->uid; + return myself->real_uid; } extern "C" gid_t getgid (void) { - return myself->gid; + return myself->real_gid; } extern "C" uid_t geteuid (void) { - return getuid (); + return myself->uid; } extern "C" gid_t getegid (void) { - return getgid (); + return myself->gid; } /* Not quite right - cuserid can change, getlogin can't */ |