summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog10
-rw-r--r--winsup/cygwin/syscalls.cc52
-rw-r--r--winsup/cygwin/uinfo.cc207
3 files changed, 185 insertions, 84 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index bfee67960..c0a87d546 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,13 @@
+Sat Jun 9 23:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
+
+ * syscalls.cc (seteuid): Set environment variables USERNAME and
+ USERDOMAIN before impersonation to workaround a LookupAccountSid()
+ misbehaviour.
+ * uinfo.cc (internal_getlogin): Revert most of the previous change.
+ Don't set environment variables USERNAME and USERDOMAIN. That's
+ the job of seteuid() now. Try to get logon server from Lsa
+ only if logon server isn't already known.
+
Thu Jun 7 15:54:32 2001 Robert Collins <rbtcollins@hotmail.com>
* thread.cc (pthread_cond::Broadcast): Don't print error messages on
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 788adc1e8..e6e48f3fc 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -22,6 +22,7 @@ details. */
#include <errno.h>
#include <limits.h>
#include <winnls.h>
+#include <wininet.h>
#include <lmcons.h> /* for UNLEN */
#include <cygwin/version.h>
#include <sys/cygwin.h>
@@ -1971,6 +1972,14 @@ seteuid (uid_t uid)
sigframe thisframe (mainthread);
if (os_being_run == winNT)
{
+ 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 == (uid_t) -1 || uid == myself->uid)
{
debug_printf ("new euid == current euid, nothing happens");
@@ -1983,18 +1992,44 @@ seteuid (uid_t uid)
return -1;
}
+ 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)
+ CloseHandle (ptok);
}
else
{
- cygsid usersid, pgrpsid, tok_usersid, tok_pgrpsid;
- DWORD siz;
+ cygsid usersid, pgrpsid, tok_pgrpsid;
HANDLE sav_token = INVALID_HANDLE_VALUE;
BOOL sav_impersonation;
BOOL current_token_is_internal_token = FALSE;
@@ -2104,11 +2139,18 @@ seteuid (uid_t uid)
}
/* Now try to impersonate. */
- if (!ImpersonateLoggedOnUser (cygheap->user.token))
+ 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;
+ {
+ cygheap->user.impersonated = TRUE;
+ setenv ("USERNAME", username, 1);
+ setenv ("USERDOMAIN", domain, 1);
+ }
}
}
@@ -2124,6 +2166,8 @@ seteuid (uid_t uid)
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;
}
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index a3b734ebf..867f3cee1 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -31,61 +31,61 @@ struct passwd *
internal_getlogin (cygheap_user &user)
{
char username[UNLEN + 1];
- DWORD ulen = UNLEN + 1;
+ DWORD username_len = UNLEN + 1;
struct passwd *pw = NULL;
- if (!GetUserName (username, &ulen))
+ if (!GetUserName (username, &username_len))
user.set_name ("unknown");
else
user.set_name (username);
+ debug_printf ("GetUserName() = %s", user.name ());
if (os_being_run == winNT)
{
- HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no
- impersonation took place. */
- DWORD siz;
- cygsid tu;
- NET_API_STATUS ret = 0;
- char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- SID_NAME_USE use;
- char buf[MAX_PATH];
-
- /* Try to get the SID either from already impersonated token
- or from current process first. To differ that two cases is
- important, because you can't rely on the user information
- in a process token of a currently impersonated process. */
- user.set_sid (NO_SID);
- if (ptok == INVALID_HANDLE_VALUE
- && !OpenProcessToken (GetCurrentProcess (),
- TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
- &ptok))
- debug_printf ("OpenProcessToken(): %E");
- else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
- debug_printf ("GetTokenInformation(): %E");
- else if (!(ret = user.set_sid (tu)))
- debug_printf ("Couldn't retrieve SID from access token!");
- else if (!LookupAccountSid (NULL, user.sid (), username, &ulen,
- domain, &dlen, &use))
- debug_printf ("LookupAccountSid (): %E");
- else
+ LPWKSTA_USER_INFO_1 wui;
+ NET_API_STATUS ret;
+ char buf[512];
+ char *env;
+
+ user.set_logsrv (NULL);
+ /* First trying to get logon info from environment */
+ if ((env = getenv ("USERNAME")) != NULL)
+ user.set_name (env);
+ if ((env = getenv ("USERDOMAIN")) != NULL)
+ user.set_domain (env);
+ if ((env = getenv ("LOGONSERVER")) != NULL)
+ user.set_logsrv (env + 2); /* filter leading double backslashes */
+ if (user.name () && user.domain ())
+ debug_printf ("User: %s, Domain: %s, Logon Server: %s",
+ user.name (), user.domain (), user.logsrv ());
+ else if (!(ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)))
+ {
+ sys_wcstombs (buf, wui->wkui1_username, UNLEN + 1);
+ user.set_name (buf);
+ sys_wcstombs (buf, wui->wkui1_logon_server,
+ INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ user.set_logsrv (buf);
+ sys_wcstombs (buf, wui->wkui1_logon_domain,
+ INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ user.set_domain (buf);
+ NetApiBufferFree (wui);
+ }
+ if (!user.logsrv () && get_logon_server_and_user_domain (buf, NULL))
{
- user.set_name (username);
- user.set_domain (domain);
+ user.set_logsrv (buf + 2);
+ setenv ("LOGONSERVER", buf, 1);
}
- if (get_logon_server_and_user_domain (domain, NULL))
- user.set_logsrv (domain + 2);
- setenv ("USERNAME", user.name (), 1);
- setenv ("LOGONSERVER", user.logsrv (), 1);
- setenv ("USERDOMAIN", user.domain (), 1);
-
- LPUSER_INFO_3 ui;
- WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ LPUSER_INFO_3 ui = NULL;
WCHAR wuser[UNLEN + 1];
- sys_mbstowcs (wlogsrv, user.logsrv (), INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+
+ /* HOMEDRIVE and HOMEPATH are wrong most of the time, too,
+ after changing user context! */
sys_mbstowcs (wuser, user.name (), UNLEN + 1);
- if (!NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *)&ui) ||
- !NetUserGetInfo (NULL, wuser, 3, (LPBYTE *)&ui))
+ strcat (strcpy (buf, "\\\\"), user.logsrv ());
+ sys_mbstowcs (wlogsrv, buf, INTERNET_MAX_HOST_NAME_LENGTH + 3);
+ if (!NetUserGetInfo (NULL, wuser, 3, (LPBYTE *)&ui)
+ || !NetUserGetInfo (wlogsrv, wuser, 3,(LPBYTE *)&ui))
{
sys_wcstombs (buf, ui->usri3_home_dir, MAX_PATH);
if (!buf[0])
@@ -95,7 +95,7 @@ internal_getlogin (cygheap_user &user)
strcat (buf, "\\");
else
{
- char *env = getenv ("SYSTEMDRIVE");
+ env = getenv ("SYSTEMDRIVE");
if (env && *env)
strcat (strcpy (buf, env), "\\");
else
@@ -107,46 +107,93 @@ internal_getlogin (cygheap_user &user)
setenv ("HOMEDRIVE", buf, 1);
NetApiBufferFree (ui);
}
+ debug_printf ("Domain: %s, Logon Server: %s, Windows Username: %s",
+ user.domain (), user.logsrv (), user.name ());
- /* If we have a SID, try to get the corresponding Cygwin user name
- which can be different from the Windows user name. */
- cygsid gsid (NO_SID);
- if (user.sid ())
+ if (allow_ntsec)
{
- cygsid psid;
-
- for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
- if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
- {
- user.set_name (pw->pw_name);
- struct group *gr = getgrgid (pw->pw_gid);
- if (gr && !gsid.getfromgr (gr))
- gsid = NO_SID;
- }
- if (!strcasematch (user.name (), "SYSTEM"))
- if (get_registry_hive_path (user.sid (), buf))
- setenv ("USERPROFILE", buf, 1);
- else
- unsetenv ("USERPROFILE");
- }
+ HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no
+ impersonation took place. */
+ DWORD siz;
+ cygsid tu;
+ int ret = 0;
- /* If this process is started from a non Cygwin process,
- set token owner to the same value as token user and
- primary group to the group which is set as primary group
- in /etc/passwd. */
- if (ptok != INVALID_HANDLE_VALUE && myself->ppid == 1)
- {
- if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
- debug_printf ("SetTokenInformation(TokenOwner): %E");
- if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup,
- &gsid, sizeof gsid))
- debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
- }
+ /* Try to get the SID either from already impersonated token
+ or from current process first. To differ that two cases is
+ important, because you can't rely on the user information
+ in a process token of a currently impersonated process. */
+ if (ptok == INVALID_HANDLE_VALUE
+ && !OpenProcessToken (GetCurrentProcess (),
+ TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
+ &ptok))
+ debug_printf ("OpenProcessToken(): %E\n");
+ else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
+ debug_printf ("GetTokenInformation(): %E");
+ else if (!(ret = user.set_sid (tu)))
+ debug_printf ("Couldn't retrieve SID from access token!");
+ /* If that failes, try to get the SID from localhost. 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. */
+ if (!ret && user.domain ())
+ {
+ /* Concat DOMAIN\USERNAME for the next lookup */
+ strcat (strcat (strcpy (buf, user.domain ()), "\\"), user.name ());
+ if (!(ret = lookup_name (buf, NULL, user.sid ())))
+ debug_printf ("Couldn't retrieve SID locally!");
+ }
+
+ /* If that fails, too, as a last resort try to get the SID from
+ the logon server. */
+ if (!ret && !(ret = lookup_name (user.name (), user.logsrv (),
+ user.sid ())))
+ debug_printf ("Couldn't retrieve SID from '%s'!", user.logsrv ());
+
+ /* If we have a SID, try to get the corresponding Cygwin user name
+ which can be different from the Windows user name. */
+ cygsid gsid (NO_SID);
+ if (ret)
+ {
+ char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ cygsid psid;
+
+ for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
+ if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
+ {
+ user.set_name (pw->pw_name);
+ struct group *gr = getgrgid (pw->pw_gid);
+ if (gr)
+ if (!gsid.getfromgr (gr))
+ gsid = NO_SID;
+ break;
+ }
+ if (!strcasematch (user.name (), "SYSTEM")
+ && user.domain () && user.logsrv ())
+ {
+ if (get_registry_hive_path (user.sid (), buf))
+ setenv ("USERPROFILE", buf, 1);
+ else
+ unsetenv ("USERPROFILE");
+ }
+ }
- /* Close token only if it's a result from OpenProcessToken(). */
- if (ptok != INVALID_HANDLE_VALUE
- && user.token == INVALID_HANDLE_VALUE)
- CloseHandle (ptok);
+ /* If this process is started from a non Cygwin process,
+ set token owner to the same value as token user and
+ primary group to the group which is set as primary group
+ in /etc/passwd. */
+ if (ptok != INVALID_HANDLE_VALUE && myself->ppid == 1)
+ {
+ if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
+ debug_printf ("SetTokenInformation(TokenOwner): %E");
+ if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup,
+ &gsid, sizeof gsid))
+ debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
+ }
+
+ /* Close token only if it's a result from OpenProcessToken(). */
+ if (ptok != INVALID_HANDLE_VALUE
+ && user.token == INVALID_HANDLE_VALUE)
+ CloseHandle (ptok);
+ }
}
debug_printf ("Cygwins Username: %s", user.name ());
return pw ?: getpwnam(user.name ());