1 /* uinfo.cc: user info (uid, gid, etc...)
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
19 #include <sys/cygwin.h>
26 #include "shared_info.h"
28 #include "child_info.h"
34 /* Initialize the part of cygheap_user that does not depend on files.
35 The information is used in shared.cc for the user shared.
36 Final initialization occurs in uinfo_init */
40 WCHAR user_name[UNLEN + 1];
41 DWORD user_name_len = UNLEN + 1;
43 /* This code is only run if a Cygwin process gets started by a native
44 Win32 process. We try to get the username from the environment,
45 first USERNAME (Win32), then USER (POSIX). If that fails (which is
46 very unlikely), it only has an impact if we don't have an entry in
47 /etc/passwd for this user either. In that case the username sticks
48 to "unknown". Since this is called early in initialization, and
49 since we don't want pull in a dependency to any other DLL except
50 ntdll and kernel32 at this early stage, don't call GetUserName,
51 GetUserNameEx, NetWkstaUserGetInfo, etc. */
52 if (GetEnvironmentVariableW (L"USERNAME", user_name, user_name_len)
53 || GetEnvironmentVariableW (L"USER", user_name, user_name_len))
55 char mb_user_name[user_name_len = sys_wcstombs (NULL, 0, user_name)];
56 sys_wcstombs (mb_user_name, user_name_len, user_name);
57 set_name (mb_user_name);
64 PSECURITY_DESCRIPTOR psd;
66 status = NtQueryInformationToken (hProcToken, TokenPrimaryGroup,
67 &groups.pgsid, sizeof (cygsid), &size);
68 if (!NT_SUCCESS (status))
69 system_printf ("NtQueryInformationToken (TokenPrimaryGroup), %p", status);
71 /* Get the SID from current process and store it in effec_cygsid */
72 status = NtQueryInformationToken (hProcToken, TokenUser, &effec_cygsid,
73 sizeof (cygsid), &size);
74 if (!NT_SUCCESS (status))
76 system_printf ("NtQueryInformationToken (TokenUser), %p", status);
80 /* Set token owner to the same value as token user */
81 status = NtSetInformationToken (hProcToken, TokenOwner, &effec_cygsid,
83 if (!NT_SUCCESS (status))
84 debug_printf ("NtSetInformationToken(TokenOwner), %p", status);
86 /* Standard way to build a security descriptor with the usual DACL */
87 PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
88 psd = (PSECURITY_DESCRIPTOR)
89 (sec_user_nih (sa_buf, sid()))->lpSecurityDescriptor;
91 BOOLEAN acl_exists, dummy;
92 TOKEN_DEFAULT_DACL dacl;
94 status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &dacl.DefaultDacl,
96 if (NT_SUCCESS (status) && acl_exists && dacl.DefaultDacl)
99 /* Set the default DACL and the process DACL */
100 status = NtSetInformationToken (hProcToken, TokenDefaultDacl, &dacl,
102 if (!NT_SUCCESS (status))
103 system_printf ("NtSetInformationToken (TokenDefaultDacl), %p", status);
104 if ((status = NtSetSecurityObject (NtCurrentProcess (),
105 DACL_SECURITY_INFORMATION, psd)))
106 system_printf ("NtSetSecurityObject, %lx", status);
109 system_printf("Cannot get dacl, %E");
113 internal_getlogin (cygheap_user &user)
115 struct passwd *pw = NULL;
117 cygpsid psid = user.sid ();
118 pw = internal_getpwsid (psid);
120 if (!pw && !(pw = internal_getpwnam (user.name ()))
121 && !(pw = internal_getpwuid (DEFAULT_UID)))
122 debug_printf ("user not found in augmented /etc/passwd");
127 myself->uid = pw->pw_uid;
128 myself->gid = pw->pw_gid;
129 user.set_name (pw->pw_name);
130 if (gsid.getfromgr (internal_getgrgid (pw->pw_gid)))
132 if (gsid != user.groups.pgsid)
134 /* Set primary group to the group in /etc/passwd. */
135 NTSTATUS status = NtSetInformationToken (hProcToken,
138 if (!NT_SUCCESS (status))
139 debug_printf ("NtSetInformationToken (TokenPrimaryGroup), %p",
142 user.groups.pgsid = gsid;
143 clear_procimptoken ();
147 debug_printf ("gsid not found in augmented /etc/group");
149 cygheap->user.ontherange (CH_HOME, pw);
155 if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
158 if (!child_proc_info)
159 internal_getlogin (cygheap->user); /* Set the cygheap->user. */
160 /* Conditions must match those in spawn to allow starting child
161 processes with ruid != euid and rgid != egid. */
162 else if (cygheap->user.issetuid ()
163 && cygheap->user.saved_uid == cygheap->user.real_uid
164 && cygheap->user.saved_gid == cygheap->user.real_gid
165 && !cygheap->user.groups.issetgroups ()
166 && !cygheap->user.setuid_to_restricted)
168 cygheap->user.reimpersonate ();
172 cygheap->user.close_impersonation_tokens ();
174 cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid;
175 cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid;
176 cygheap->user.external_token = NO_IMPERSONATION;
177 cygheap->user.internal_token = NO_IMPERSONATION;
178 cygheap->user.curr_primary_token = NO_IMPERSONATION;
179 cygheap->user.curr_imp_token = NO_IMPERSONATION;
180 cygheap->user.ext_token_is_restricted = false;
181 cygheap->user.curr_token_is_restricted = false;
182 cygheap->user.setuid_to_restricted = false;
183 cygheap->user.set_saved_sid (); /* Update the original sid */
184 cygheap->user.deimpersonate ();
188 getlogin_r (char *name, size_t namesize)
190 const char *login = cygheap->user.name ();
191 size_t len = strlen (login) + 1;
195 if (efault.faulted ())
197 strncpy (name, login, len);
204 static char username[UNLEN];
205 int ret = getlogin_r (username, UNLEN);
217 return cygheap->user.real_uid;
223 return cygheap->user.real_uid;
229 return cygheap->user.real_gid;
235 return cygheap->user.real_gid;
262 /* Not quite right - cuserid can change, getlogin can't */
269 strcpy (src, getlogin ());
274 cygheap_user::ontherange (homebodies what, struct passwd *pw)
276 LPUSER_INFO_3 ui = NULL;
277 WCHAR wuser[UNLEN + 1];
279 char homedrive_env_buf[3];
280 char *newhomedrive = NULL;
281 char *newhomepath = NULL;
284 debug_printf ("what %d, pw %p", what, pw);
289 if ((p = getenv ("HOME")))
290 debug_printf ("HOME is already in the environment %s", p);
293 if (pw && pw->pw_dir && *pw->pw_dir)
295 debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
296 setenv ("HOME", pw->pw_dir, 1);
300 char home[strlen (name ()) + 8];
302 debug_printf ("Set HOME to default /home/USER");
303 __small_sprintf (home, "/home/%s", name ());
304 setenv ("HOME", home, 1);
309 if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
311 char *homepath_env_buf = tp.c_get ();
313 pw = internal_getpwnam (name ());
314 if (pw && pw->pw_dir && *pw->pw_dir)
315 cygwin_conv_path (CCP_POSIX_TO_WIN_A, pw->pw_dir, homepath_env_buf,
319 homepath_env_buf[0] = homepath_env_buf[1] = '\0';
322 WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
323 sys_mbstowcs (wlogsrv, sizeof (wlogsrv) / sizeof (*wlogsrv),
325 sys_mbstowcs (wuser, sizeof (wuser) / sizeof (*wuser), winname ());
326 if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui)))
328 sys_wcstombs (homepath_env_buf, NT_MAX_PATH,
330 if (!homepath_env_buf[0])
332 sys_wcstombs (homepath_env_buf, NT_MAX_PATH,
333 ui->usri3_home_dir_drive);
334 if (homepath_env_buf[0])
335 strcat (homepath_env_buf, "\\");
337 cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE,
338 "/", homepath_env_buf, NT_MAX_PATH);
343 NetApiBufferFree (ui);
346 if (homepath_env_buf[1] != ':')
348 newhomedrive = almost_null;
349 newhomepath = homepath_env_buf;
353 homedrive_env_buf[0] = homepath_env_buf[0];
354 homedrive_env_buf[1] = homepath_env_buf[1];
355 homedrive_env_buf[2] = '\0';
356 newhomedrive = homedrive_env_buf;
357 newhomepath = homepath_env_buf + 2;
361 if (newhomedrive && newhomedrive != homedrive)
362 cfree_and_set (homedrive, (newhomedrive == almost_null)
363 ? almost_null : cstrdup (newhomedrive));
365 if (newhomepath && newhomepath != homepath)
366 cfree_and_set (homepath, cstrdup (newhomepath));
380 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
382 if (!what && !issetuid ())
383 what = getwinenveq (name, namelen, HEAP_STR);
388 cygheap_user::env_logsrv (const char *name, size_t namelen)
390 if (test_uid (plogsrv, name, namelen))
393 const char *mydomain = domain ();
394 const char *myname = winname ();
395 if (!mydomain || ascii_strcasematch (myname, "SYSTEM"))
398 WCHAR wdomain[MAX_DOMAIN_NAME_LEN + 1];
399 WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
400 sys_mbstowcs (wdomain, MAX_DOMAIN_NAME_LEN + 1, mydomain);
401 cfree_and_set (plogsrv, almost_null);
402 if (get_logon_server (wdomain, wlogsrv, false))
403 sys_wcstombs_alloc (&plogsrv, HEAP_STR, wlogsrv);
408 cygheap_user::env_domain (const char *name, size_t namelen)
410 if (pwinname && test_uid (pdomain, name, namelen))
413 DWORD ulen = UNLEN + 1;
414 WCHAR username[ulen];
415 DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
416 WCHAR userdomain[dlen];
419 cfree_and_set (pwinname, almost_null);
420 cfree_and_set (pdomain, almost_null);
421 if (!LookupAccountSidW (NULL, sid (), username, &ulen,
422 userdomain, &dlen, &use))
426 sys_wcstombs_alloc (&pwinname, HEAP_STR, username);
427 sys_wcstombs_alloc (&pdomain, HEAP_STR, userdomain);
433 cygheap_user::env_userprofile (const char *name, size_t namelen)
435 if (test_uid (puserprof, name, namelen))
438 WCHAR userprofile_env_buf[NT_MAX_PATH];
439 WCHAR win_id[UNLEN + 1]; /* Large enough for SID */
441 cfree_and_set (puserprof, almost_null);
442 if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf))
443 sys_wcstombs_alloc (&puserprof, HEAP_STR, userprofile_env_buf);
449 cygheap_user::env_homepath (const char *name, size_t namelen)
451 return ontherange (CH_HOMEPATH);
455 cygheap_user::env_homedrive (const char *name, size_t namelen)
457 return ontherange (CH_HOMEDRIVE);
461 cygheap_user::env_name (const char *name, size_t namelen)
463 if (!test_uid (pwinname, name, namelen))
469 cygheap_user::env_systemroot (const char *name, size_t namelen)
473 int size = GetSystemWindowsDirectoryW (NULL, 0);
476 WCHAR wsystemroot[size];
477 size = GetSystemWindowsDirectoryW (wsystemroot, size);
479 sys_wcstombs_alloc (&psystemroot, HEAP_STR, wsystemroot);
482 debug_printf ("GetSystemWindowsDirectoryW(), %E");
488 pwdgrp::next_str (char c)
491 lptr = strechr (lptr, c);
498 pwdgrp::next_num (unsigned long& n)
500 char *p = next_str (':');
502 n = strtoul (p, &cp, 10);
503 return p != cp && !*cp;
507 pwdgrp::add_line (char *eptr)
512 eptr = strchr (lptr, '\n');
515 if (eptr > lptr && eptr[-1] == '\r')
521 if (curr_lines >= max_lines)
524 *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
526 if ((this->*parse) ())
533 pwdgrp::load (const wchar_t *rel_path)
535 static const char failed[] = "failed";
536 static const char succeeded[] = "succeeded";
537 const char *res = failed;
541 OBJECT_ATTRIBUTES attr;
543 FILE_STANDARD_INFORMATION fsi;
551 !(path = (PWCHAR) malloc ((wcslen (installation_root)
552 + wcslen (rel_path) + 1) * sizeof (WCHAR))))
554 paranoid_printf ("malloc (%W) failed", rel_path);
557 wcpcpy (wcpcpy (path, installation_root), rel_path);
558 RtlInitUnicodeString (&upath, path);
560 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
561 etc_ix = etc::init (etc_ix, &attr);
563 paranoid_printf ("%S", &upath);
565 status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io,
566 FILE_SHARE_VALID_FLAGS,
567 FILE_SYNCHRONOUS_IO_NONALERT
568 | FILE_OPEN_FOR_BACKUP_INTENT);
569 if (!NT_SUCCESS (status))
571 paranoid_printf ("NtOpenFile(%S) failed, status %p", &upath, status);
574 status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi,
575 FileStandardInformation);
576 if (!NT_SUCCESS (status))
578 paranoid_printf ("NtQueryInformationFile(%S) failed, status %p",
582 /* FIXME: Should we test for HighPart set? If so, the
583 passwd or group file is way beyond what we can handle. */
584 /* FIXME 2: It's still ugly that we keep the file in memory.
585 Big organizations have naturally large passwd files. */
586 buf = (char *) malloc (fsi.EndOfFile.LowPart + 1);
589 paranoid_printf ("malloc (%d) failed", fsi.EndOfFile.LowPart);
592 status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
594 if (!NT_SUCCESS (status))
596 paranoid_printf ("NtReadFile(%S) failed, status %p", &upath, status);
600 buf[fsi.EndOfFile.LowPart] = '\0';
601 for (char *eptr = buf; (eptr = add_line (eptr)); )
603 debug_printf ("%W curr_lines %d", rel_path, curr_lines);
609 debug_printf ("%W load %s", rel_path, res);