newlib/winsup/cygwin/uinfo.cc

277 lines
8.8 KiB
C++
Raw Normal View History

2000-02-17 20:38:33 +01:00
/* uinfo.cc: user info (uid, gid, etc...)
Copyright 1996, 1997, 1998 Cygnus Solutions.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <pwd.h>
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-29 18:24:59 +02:00
#include <unistd.h>
#include <winnls.h>
2000-02-17 20:38:33 +01:00
#include <utmp.h>
#include <limits.h>
#include "autoload.h"
#include <stdlib.h>
#include <wchar.h>
#include <lm.h>
#include "thread.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
2000-02-17 20:38:33 +01:00
char *
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-29 18:24:59 +02:00
internal_getlogin (_pinfo *pi)
2000-02-17 20:38:33 +01:00
{
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");
2000-02-17 20:38:33 +01:00
if (os_being_run == winNT)
{
LPWKSTA_USER_INFO_1 wui;
char buf[MAX_PATH], *env;
char *un = NULL;
/* First trying to get logon info from environment */
if ((env = getenv ("USERNAME")) != NULL)
un = 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 (un && strcasematch (pi->username, un)
&& 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))
2000-02-17 20:38:33 +01:00
{
sys_wcstombs (pi->username, wui->wkui1_username, MAX_USER_NAME);
sys_wcstombs (pi->logsrv, wui->wkui1_logon_server, MAX_HOST_NAME);
sys_wcstombs (pi->domain, wui->wkui1_logon_domain,
MAX_COMPUTERNAME_LENGTH + 1);
/* Save values in environment */
if (!strcasematch (pi->username, "SYSTEM")
&& pi->domain[0] && pi->logsrv[0])
2000-02-17 20:38:33 +01:00
{
LPUSER_INFO_3 ui = NULL;
WCHAR wbuf[MAX_HOST_NAME + 2];
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! */
sys_mbstowcs (wbuf, buf, MAX_HOST_NAME + 2);
if (!NetUserGetInfo (NULL, wui->wkui1_username, 3, (LPBYTE *)&ui)
|| !NetUserGetInfo (wbuf,wui->wkui1_username,3,(LPBYTE *)&ui))
{
sys_wcstombs (buf, ui->usri3_home_dir, MAX_PATH);
if (!buf[0])
{
sys_wcstombs (buf, ui->usri3_home_dir_drive, MAX_PATH);
if (buf[0])
strcat (buf, "\\");
else
{
env = getenv ("SYSTEMDRIVE");
if (env && *env)
strcat (strcpy (buf, env), "\\");
else
GetSystemDirectoryA (buf, MAX_PATH);
}
}
setenv ("HOMEPATH", buf + 2, 1);
buf[2] = '\0';
setenv ("HOMEDRIVE", buf, 1);
NetApiBufferFree (ui);
}
2000-02-17 20:38:33 +01:00
}
debug_printf ("Domain: %s, Logon Server: %s, Windows Username: %s",
pi->domain, pi->logsrv, pi->username);
NetApiBufferFree (wui);
2000-02-17 20:38:33 +01:00
}
if (allow_ntsec)
2000-02-17 20:38:33 +01:00
{
HANDLE ptok = pi->token; /* Which is INVALID_HANDLE_VALUE if no
impersonation took place. */
DWORD siz;
char tu[1024];
int ret = 0;
/* 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_QUERY, &ptok))
debug_printf ("OpenProcessToken(): %E\n");
else if (!GetTokenInformation (ptok, TokenUser, (LPVOID) &tu,
sizeof tu, &siz))
debug_printf ("GetTokenInformation(): %E");
else if (!(ret = CopySid (MAX_SID_LEN, (PSID) pi->psid,
((TOKEN_USER *) &tu)->User.Sid)))
debug_printf ("Couldn't retrieve SID from access token!");
/* Close token only if it's a result from OpenProcessToken(). */
if (ptok != INVALID_HANDLE_VALUE && pi->token == INVALID_HANDLE_VALUE)
CloseHandle (ptok);
/* 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 && 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->psid)))
debug_printf ("Couldn't retrieve SID locally!");
}
/* If that failes, too, as a last resort try to get the SID from
the logon server. */
if (!ret && !(ret = lookup_name(pi->username, pi->logsrv,
(PSID)pi->psid)))
debug_printf ("Couldn't retrieve SID from '%s'!", pi->logsrv);
/* If we have a SID, try to get the corresponding Cygwin user name
which can be different from the Windows user name. */
if (ret)
{
struct passwd *pw;
char psidbuf[MAX_SID_LEN];
PSID psid = (PSID) psidbuf;
pi->use_psid = 1;
if (!strcasematch (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 ();
}
}
2000-02-17 20:38:33 +01:00
}
debug_printf ("Cygwins Username: %s", pi->username);
2000-02-17 20:38:33 +01:00
return pi->username;
}
void
uinfo_init ()
{
char *username;
2000-02-17 20:38:33 +01:00
struct passwd *p;
/* Initialize to non impersonated values.
Setting `impersonated' to TRUE seems to be wrong but it
isn't. Impersonated is thought as "Current User and `token'
are coincident". See seteuid() for the mechanism behind that. */
myself->token = INVALID_HANDLE_VALUE;
myself->impersonated = TRUE;
/* If uid is USHRT_MAX, the process is started from a non cygwin
process or the user context was changed in spawn.cc */
if (myself->uid == USHRT_MAX)
if ((p = getpwnam (username = internal_getlogin (myself))) != NULL)
{
myself->uid = p->pw_uid;
myself->gid = p->pw_gid;
}
else
{
myself->uid = DEFAULT_UID;
myself->gid = DEFAULT_GID;
}
/* Real and effective uid/gid are always identical on process start up.
This is at least true for NT/W2K. */
myself->orig_uid = myself->real_uid = myself->uid;
myself->orig_gid = myself->real_gid = myself->gid;
2000-02-17 20:38:33 +01:00
}
extern "C" char *
getlogin (void)
{
#ifdef _MT_SAFE
char *this_username=_reent_winsup()->_username;
#else
static NO_COPY char this_username[MAX_USER_NAME];
#endif
return strcpy (this_username, myself->username);
}
extern "C" uid_t
getuid (void)
{
return myself->real_uid;
2000-02-17 20:38:33 +01:00
}
extern "C" gid_t
getgid (void)
{
return myself->real_gid;
2000-02-17 20:38:33 +01:00
}
extern "C" uid_t
geteuid (void)
{
return myself->uid;
2000-02-17 20:38:33 +01:00
}
extern "C" gid_t
getegid (void)
{
return myself->gid;
2000-02-17 20:38:33 +01:00
}
/* Not quite right - cuserid can change, getlogin can't */
extern "C" char *
cuserid (char *src)
{
if (src)
{
strcpy (src, getlogin ());
return src;
}
else
{
return getlogin ();
}
}
extern "C" {
2000-02-17 20:38:33 +01:00
LoadDLLinitfunc (netapi32)
{
HANDLE h;
if ((h = LoadLibrary ("netapi32.dll")) != NULL)
netapi32_handle = h;
else if (! netapi32_handle)
api_fatal ("could not load netapi32.dll. %d", GetLastError ());
return 0;
}
static void dummy_autoload (void) __attribute__ ((unused));
static void
dummy_autoload (void)
{
2000-02-17 20:38:33 +01:00
LoadDLLinit (netapi32)
LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32)
LoadDLLfunc (NetUserGetInfo, 16, netapi32)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
}
}