diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b6d09af27..601ac2585 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,32 @@ +Mon Jun 19 19:35:00 2000 Corinna Vinschen + + * dcrt0.cc: Add load statements for `GetSidIdentifierAuthority' + and `RegLoadKeyA'. + * registry.cc (get_registry_hive_path): New function. + (load_registry_hive): Ditto. + * security.cc (convert_sid_to_string_sid): New function. + (get_ssid): Renamed to `convert_string_sid_to_sid'. + (get_pw_sid): Call `convert_string_sid_to_sid' instead of `get_ssid'. + (get_gr_sid): Ditto. + (get_admin_sid): Ditto. + (get_system_sid): Ditto. + (get_creator_owner_sid): Ditto. + (get_world_sid): Ditto. + * shared.h: New prototypes for `get_registry_hive_path' and + `load_registry_hive'. + * spawn.cc (spawn_guts): Set child->psid to NULL to force calling + `internal_getlogin' from child process in case of changing user context. + Call `load_registry_hive' in case of changing user context. + (_spawnve): Copy user infos only if user context remains the same. + * uinfo.cc: Add load statement for `NetUserGetInfo'. + Remove load statement for `NetGetDCName'. + (internal_getlogin): Rewrite to speed up process startup + and to correct user environment in case user context changes. + (uinfo_init): Call internal_getlogin only if myself->psid is NULL, + that is user context changes. + * winsup.h: Add prototypes for `convert_sid_to_string_sid', + `convert_string_sid_to_sid' and `get_pw_sid'. + Sun Jun 18 13:42:50 2000 Christopher Faylor * fhandler.h (set_name): Don't use 'unix' as name since this is defined diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 302207cec..801016a31 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1152,6 +1152,7 @@ LoadDLLfunc (GetLengthSid, 4, advapi32) LoadDLLfunc (GetSecurityDescriptorDacl, 16, advapi32) LoadDLLfunc (GetSecurityDescriptorGroup, 12, advapi32) LoadDLLfunc (GetSecurityDescriptorOwner, 12, advapi32) +LoadDLLfunc (GetSidIdentifierAuthority, 4, advapi32) LoadDLLfunc (GetSidSubAuthority, 8, advapi32) LoadDLLfunc (GetSidSubAuthorityCount, 4, advapi32) LoadDLLfunc (GetTokenInformation, 20, advapi32) @@ -1170,6 +1171,7 @@ LoadDLLfunc (OpenProcessToken, 12, advapi32) LoadDLLfunc (RegCloseKey, 4, advapi32) LoadDLLfunc (RegCreateKeyExA, 36, advapi32) LoadDLLfunc (RegDeleteKeyA, 8, advapi32) +LoadDLLfunc (RegLoadKeyA, 12, advapi32) LoadDLLfunc (RegEnumKeyExA, 32, advapi32) LoadDLLfunc (RegOpenKeyExA, 20, advapi32) LoadDLLfunc (RegQueryValueExA, 24, advapi32) diff --git a/winsup/cygwin/registry.cc b/winsup/cygwin/registry.cc index 47092f576..31ee183da 100644 --- a/winsup/cygwin/registry.cc +++ b/winsup/cygwin/registry.cc @@ -177,3 +177,57 @@ reg_key::~reg_key () RegCloseKey (key); key_is_invalid = 1; } + +char * +get_registry_hive_path (const PSID psid, char *path) +{ + char sid[256]; + char key[256]; + HKEY hkey; + + if (!psid || !path) + return NULL; + convert_sid_to_string_sid (psid, sid); + strcpy (key,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"); + strcat (key, sid); + if (!RegOpenKeyExA (HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hkey)) + { + char buf[256]; + DWORD type, siz; + + key[0] = '\0'; + if (!RegQueryValueExA (hkey, "ProfileImagePath", 0, &type, + (BYTE *)buf, (siz = 256, &siz))) + ExpandEnvironmentStringsA (buf, key, 256); + RegCloseKey (hkey); + if (key[0]) + return strcpy (path, key); + } + return NULL; +} + +void +load_registry_hive (PSID psid) +{ + char sid[256]; + char path[256]; + HKEY hkey; + + if (!psid) + return; + /* Check if user hive already exists */ + if (!RegOpenKeyExA (HKEY_LOCAL_MACHINE, convert_sid_to_string_sid (psid, sid), + 0, KEY_READ, &hkey)) + { + debug_printf ("User registry hive for %s already exists", sid); + RegCloseKey (hkey); + return; + } + if (get_registry_hive_path (psid, path)) + { + strcat (path, "\\NTUSER.DAT"); + if (RegLoadKeyA (HKEY_USERS, sid, path)) + debug_printf ("Loading user registry hive for %s failed: %E", sid); + } +} + diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index c468235fc..3dc6c5777 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -41,6 +41,25 @@ SID_IDENTIFIER_AUTHORITY sid_auth[] = { #define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) #define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) +char * +convert_sid_to_string_sid (PSID psid, char *sid_str) +{ + char t[32]; + DWORD i; + + if (!psid || !sid_str) + return NULL; + strcpy (sid_str, "S-1-"); + sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]); + strcat (sid_str, t); + for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i) + { + sprintf(t, "-%lu", *GetSidSubAuthority (psid, i)); + strcat (sid_str, t); + } + return sid_str; +} + PSID get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) { @@ -56,7 +75,7 @@ get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) } PSID -get_ssid (PSID psid, const char *sid_str) +convert_string_sid_to_sid (PSID psid, const char *sid_str) { char sid_buf[256]; char *t; @@ -85,13 +104,13 @@ get_pw_sid (PSID sid, struct passwd *pw) if (!sp) return FALSE; - return get_ssid (sid, ++sp) != NULL; + return convert_string_sid_to_sid (sid, ++sp) != NULL; } BOOL get_gr_sid (PSID sid, struct group *gr) { - return get_ssid (sid, gr->gr_passwd) != NULL; + return convert_string_sid_to_sid (sid, gr->gr_passwd) != NULL; } PSID @@ -103,7 +122,7 @@ get_admin_sid () if (!admin_sid) { admin_sid = (PSID) admin_sid_buf; - get_ssid (admin_sid, "S-1-5-32-544"); + convert_string_sid_to_sid (admin_sid, "S-1-5-32-544"); } return admin_sid; } @@ -117,7 +136,7 @@ get_system_sid () if (!system_sid) { system_sid = (PSID) system_sid_buf; - get_ssid (system_sid, "S-1-5-18"); + convert_string_sid_to_sid (system_sid, "S-1-5-18"); } return system_sid; } @@ -131,7 +150,7 @@ get_creator_owner_sid () if (!owner_sid) { owner_sid = (PSID) owner_sid_buf; - get_ssid (owner_sid, "S-1-3-0"); + convert_string_sid_to_sid (owner_sid, "S-1-3-0"); } return owner_sid; } @@ -145,7 +164,7 @@ get_world_sid () if (!world_sid) { world_sid = (PSID) world_sid_buf; - get_ssid (world_sid, "S-1-1-0"); + convert_string_sid_to_sid (world_sid, "S-1-1-0"); } return world_sid; } diff --git a/winsup/cygwin/shared.h b/winsup/cygwin/shared.h index 1b594d5d7..1c959eca8 100644 --- a/winsup/cygwin/shared.h +++ b/winsup/cygwin/shared.h @@ -252,6 +252,10 @@ public: ~reg_key (); }; +/* Evaluates path to the directory of the local user registry hive */ +char *__stdcall get_registry_hive_path (const PSID psid, char *path); +void __stdcall load_registry_hive (PSID psid); + /******** Mount Table ********/ /* Mount table entry */ diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 65e3bd665..7225c5377 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -543,6 +543,13 @@ skip_arg_parsing: if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) seteuid (myself->orig_uid); + /* Set child->psid to NULL to force calling internal_getlogin() + from child process. */ + child->psid = NULL; + + /* Load users registry hive. */ + load_registry_hive (sid); + rc = CreateProcessAsUser (hToken, real_path, /* image name - with full path */ one_line.buf, /* what was passed to exec */ @@ -837,11 +844,14 @@ _spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv, child->ctty = myself->ctty; child->umask = myself->umask; child->process_state |= PID_INITIALIZING; - memcpy (child->username, myself->username, MAX_USER_NAME); - child->psid = myself->psid; - memcpy (child->sidbuf, myself->sidbuf, 40); - memcpy (child->logsrv, myself->logsrv, 256); - memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + if (!hToken && !myself->token) + { + memcpy (child->username, myself->username, MAX_USER_NAME); + child->psid = myself->psid; + memcpy (child->sidbuf, myself->sidbuf, 40); + memcpy (child->logsrv, myself->logsrv, 256); + memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + } subproc_init (); ret = spawn_guts (hToken, path, argv, envp, child, mode); if (ret == -1) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 4e4a0c459..c2ca4e3f7 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -26,92 +26,135 @@ extern int group_in_memory_p; char * internal_getlogin (struct pinfo *pi) { - DWORD username_len = MAX_USER_NAME; - if (! pi) api_fatal ("pinfo pointer is NULL!\n"); + DWORD username_len = MAX_USER_NAME; + if (! GetUserName (pi->username, &username_len)) + strcpy (pi->username, "unknown"); if (os_being_run == winNT) { - LPWKSTA_USER_INFO_1 ui; - if (allow_ntsec && !NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&ui)) + LPWKSTA_USER_INFO_1 wui; + char buf[256], *env; + + /* First trying to get logon info from environment */ + buf[0] = '\0'; + if ((env = getenv ("USERNAME")) != NULL) + strcpy (buf, env); + if ((env = getenv ("LOGONSERVER")) != NULL) + strcpy (pi->logsrv, env + 2); /* filter leading double backslashes */ + if ((env = getenv ("USERDOMAIN")) != NULL) + strcpy (pi->domain, env); + /* Trust only if usernames are identical */ + if (!strcasecmp (pi->username, buf) && pi->domain[0] && pi->logsrv[0]) + debug_printf ("Domain: %s, Logon Server: %s", pi->domain, pi->logsrv); + /* If that failed, try to get that info from NetBIOS */ + else if (!NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)) { - wcstombs (pi->domain, - ui->wkui1_logon_domain, - (wcslen (ui->wkui1_logon_domain) + 1) * sizeof (WCHAR)); - debug_printf ("Domain: %s", pi->domain); - wcstombs (pi->logsrv, - ui->wkui1_logon_server, - (wcslen (ui->wkui1_logon_server) + 1) * sizeof (WCHAR)); - if (! *pi->logsrv) + wcstombs (pi->username, wui->wkui1_username, + (wcslen (wui->wkui1_username) + 1) * sizeof (WCHAR)); + wcstombs (pi->logsrv, wui->wkui1_logon_server, + (wcslen (wui->wkui1_logon_server) + 1) * sizeof (WCHAR)); + wcstombs (pi->domain, wui->wkui1_logon_domain, + (wcslen (wui->wkui1_logon_domain) + 1) * sizeof (WCHAR)); + /* Save values in environment */ + if (strcasecmp (pi->username, "SYSTEM") + && pi->domain[0] && pi->logsrv[0]) { - LPWSTR logon_srv = NULL; + LPUSER_INFO_3 ui = NULL; + WCHAR wbuf[256]; - if (!NetGetDCName (NULL, - ui->wkui1_logon_domain, - (LPBYTE *)&logon_srv)) - wcstombs (pi->logsrv, - logon_srv, // filter leading double backslashes - (wcslen (logon_srv) + 1) * sizeof (WCHAR)); - if (logon_srv) - NetApiBufferFree (logon_srv); - debug_printf ("DC Server: %s", pi->logsrv); + strcat (strcpy (buf, "\\\\"), pi->logsrv); + setenv ("USERNAME", pi->username, 1); + setenv ("LOGONSERVER", buf, 1); + setenv ("USERDOMAIN", pi->domain, 1); + /* HOMEDRIVE and HOMEPATH are wrong most of the time, too, + after changing user context! */ + mbstowcs (wbuf, buf, 256); + if (!NetUserGetInfo (NULL, wui->wkui1_username, 3, (LPBYTE *)&ui) + || !NetUserGetInfo (wbuf,wui->wkui1_username,3,(LPBYTE *)&ui)) + { + wcstombs (buf, ui->usri3_home_dir, 256); + if (!buf[0]) + { + wcstombs (buf, ui->usri3_home_dir_drive, 256); + if (buf[0]) + strcat (buf, "\\"); + } + if (!buf[0]) + strcat (strcpy (buf, getenv ("SYSTEMDRIVE")), "\\"); + setenv ("HOMEPATH", buf + 2, 1); + buf[2] = '\0'; + setenv ("HOMEDRIVE", buf, 1); + NetApiBufferFree (ui); + } } - else - debug_printf ("Logon Server: %s", pi->logsrv); - wcstombs (pi->username, - ui->wkui1_username, - (wcslen (ui->wkui1_username) + 1) * sizeof (WCHAR)); - debug_printf ("Windows Username: %s", pi->username); - NetApiBufferFree (ui); + debug_printf ("Domain: %s, Logon Server: %s, Windows Username: %s", + pi->domain, pi->logsrv, pi->username); + NetApiBufferFree (wui); } - else if (! GetUserName (pi->username, &username_len)) - strcpy (pi->username, "unknown"); - if (!lookup_name (pi->username, pi->logsrv, pi->psid)) + if (allow_ntsec) { - debug_printf ("myself->psid = NULL"); - pi->psid = NULL; - } - else if (allow_ntsec) - { - extern BOOL get_pw_sid (PSID, struct passwd*); - struct passwd *pw; - char psidbuf[40]; - PSID psid = (PSID) psidbuf; + /* Try to get the SID from localhost first. This can only + be done if a domain is given because there's a chance that + a local and a domain user may have the same name. */ + int ret = 0; - while ((pw = getpwent ()) != NULL) - if (get_pw_sid (psid, pw) && EqualSid (pi->psid, psid)) - { - strcpy (pi->username, pw->pw_name); - break; - } - endpwent (); + if (pi->domain[0]) + { + /* Concat DOMAIN\USERNAME for the next lookup */ + strcat (strcat (strcpy (buf, pi->domain), "\\"), pi->username); + if (!(ret = lookup_name (buf, NULL, (PSID) pi->sidbuf))) + debug_printf ("Couldn't retrieve SID locally!"); + } + if (!ret && !(ret = lookup_name(pi->username, pi->logsrv, + (PSID)pi->sidbuf))) + debug_printf ("Couldn't retrieve SID from '%s'!", pi->logsrv); + if (ret) + { + struct passwd *pw; + char psidbuf[40]; + PSID psid = (PSID) psidbuf; + + pi->psid = (PSID) pi->sidbuf; + if (strcasecmp (pi->username, "SYSTEM") + && pi->domain[0] && pi->logsrv[0]) + { + if (get_registry_hive_path (pi->psid, buf)) + setenv ("USERPROFILE", buf, 1); + } + while ((pw = getpwent ()) != NULL) + if (get_pw_sid (psid, pw) && EqualSid (pi->psid, psid)) + { + strcpy (pi->username, pw->pw_name); + break; + } + endpwent (); + } } } - else - { - debug_printf ("myself->psid = NULL"); - pi->psid = NULL; - if (! GetUserName (pi->username, &username_len)) - strcpy (pi->username, "unknown"); - } - debug_printf ("Cygwins Username: %s\n", pi->username); + debug_printf ("Cygwins Username: %s", pi->username); return pi->username; } void uinfo_init () { + char *username; struct passwd *p; - myself->psid = (PSID) myself->sidbuf; - if ((p = getpwnam (internal_getlogin (myself))) != NULL) + /* If psid is non null, the process is forked or spawned from + another cygwin process without changing the user context. + So all user infos in myself as well as the environment are + (perhaps) valid. */ + username = myself->psid ? myself->username : internal_getlogin (myself); + if ((p = getpwnam (username)) != NULL) { /* calling getpwnam assures us that /etc/password has been - read in, but we can't be sure about /etc/group */ + read in, but we can't be sure about /etc/group */ if (!group_in_memory_p) - read_etc_group (); + read_etc_group (); myself->uid = p->pw_uid; myself->gid = p->pw_gid; @@ -197,7 +240,7 @@ dummy_autoload (void) { LoadDLLinit (netapi32) LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32) -LoadDLLfunc (NetGetDCName, 12, netapi32) +LoadDLLfunc (NetUserGetInfo, 16, netapi32) LoadDLLfunc (NetApiBufferFree, 4, netapi32) } } diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index db7774b48..f9569f2aa 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -429,7 +429,10 @@ extern BOOL allow_ntsec; /* `lookup_name' should be called instead of LookupAccountName. * logsrv may be NULL, in this case only the local system is used for lookup. * The buffer for ret_sid (40 Bytes) has to be allocated by the caller! */ -BOOL __stdcall lookup_name (const char *name, const char *logsrv, PSID ret_sid); +BOOL __stdcall lookup_name (const char *, const char *, PSID); +char *__stdcall convert_sid_to_string_sid (PSID, char *); +PSID __stdcall convert_string_sid_to_sid (PSID, const char *); +BOOL __stdcall get_pw_sid (PSID, struct passwd *); unsigned long __stdcall hash_path_name (unsigned long hash, const char *name); void __stdcall nofinalslash (const char *src, char *dst);