OSDN Git Service

* path.cc (conv_path_list): Take cygwin_conv_path_t as third parameter.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / uinfo.cc
1 /* uinfo.cc: user info (uid, gid, etc...)
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4    2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <unistd.h>
14 #include <wininet.h>
15 #include <stdlib.h>
16 #include <wchar.h>
17 #include <lm.h>
18 #include <iptypes.h>
19 #include <sys/cygwin.h>
20 #include "cygerrno.h"
21 #include "pinfo.h"
22 #include "path.h"
23 #include "fhandler.h"
24 #include "dtable.h"
25 #include "cygheap.h"
26 #include "shared_info.h"
27 #include "registry.h"
28 #include "child_info.h"
29 #include "environ.h"
30 #include "pwdgrp.h"
31 #include "tls_pbuf.h"
32 #include "ntdll.h"
33
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 */
37 void
38 cygheap_user::init ()
39 {
40   WCHAR user_name[UNLEN + 1];
41   DWORD user_name_len = UNLEN + 1;
42
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))
54     {
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);
58     }
59   else
60     set_name ("unknown");
61
62   NTSTATUS status;
63   ULONG size;
64   PSECURITY_DESCRIPTOR psd;
65
66   status = NtQueryInformationToken (hProcToken, TokenPrimaryGroup,
67                                     &groups.pgsid, sizeof (cygsid), &size);
68   if (!NT_SUCCESS (status))
69     system_printf ("NtQueryInformationToken (TokenPrimaryGroup), %p", status);
70
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))
75     {
76       system_printf ("NtQueryInformationToken (TokenUser), %p", status);
77       return;
78     }
79
80   /* Set token owner to the same value as token user */
81   status = NtSetInformationToken (hProcToken, TokenOwner, &effec_cygsid,
82                                   sizeof (cygsid));
83   if (!NT_SUCCESS (status))
84     debug_printf ("NtSetInformationToken(TokenOwner), %p", status);
85
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;
90
91   BOOLEAN acl_exists, dummy;
92   TOKEN_DEFAULT_DACL dacl;
93
94   status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &dacl.DefaultDacl,
95                                          &dummy);
96   if (NT_SUCCESS (status) && acl_exists && dacl.DefaultDacl)
97     {
98
99       /* Set the default DACL and the process DACL */
100       status = NtSetInformationToken (hProcToken, TokenDefaultDacl, &dacl,
101                                       sizeof (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);
107     }
108   else
109     system_printf("Cannot get dacl, %E");
110 }
111
112 void
113 internal_getlogin (cygheap_user &user)
114 {
115   struct passwd *pw = NULL;
116
117   cygpsid psid = user.sid ();
118   pw = internal_getpwsid (psid);
119
120   if (!pw && !(pw = internal_getpwnam (user.name ()))
121       && !(pw = internal_getpwuid (DEFAULT_UID)))
122     debug_printf ("user not found in augmented /etc/passwd");
123   else
124     {
125       cygsid gsid;
126
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)))
131         {
132           if (gsid != user.groups.pgsid)
133             {
134               /* Set primary group to the group in /etc/passwd. */
135               NTSTATUS status = NtSetInformationToken (hProcToken,
136                                                        TokenPrimaryGroup,
137                                                        &gsid, sizeof gsid);
138               if (!NT_SUCCESS (status))
139                 debug_printf ("NtSetInformationToken (TokenPrimaryGroup), %p",
140                               status);
141               else
142                 user.groups.pgsid = gsid;
143               clear_procimptoken ();
144             }
145         }
146       else
147         debug_printf ("gsid not found in augmented /etc/group");
148     }
149   cygheap->user.ontherange (CH_HOME, pw);
150 }
151
152 void
153 uinfo_init ()
154 {
155   if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
156     return;
157
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)
167     {
168       cygheap->user.reimpersonate ();
169       return;
170     }
171   else
172     cygheap->user.close_impersonation_tokens ();
173
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 ();
185 }
186
187 extern "C" int
188 getlogin_r (char *name, size_t namesize)
189 {
190   const char *login = cygheap->user.name ();
191   size_t len = strlen (login) + 1;
192   if (len > namesize)
193     return ERANGE;
194   myfault efault;
195   if (efault.faulted ())
196     return EFAULT;
197   strncpy (name, login, len);
198   return 0;
199 }
200
201 extern "C" char *
202 getlogin (void)
203 {
204   static char username[UNLEN];
205   int ret = getlogin_r (username, UNLEN);
206   if (ret)
207     {
208       set_errno (ret);
209       return NULL;
210     }
211   return username;
212 }
213
214 extern "C" __uid32_t
215 getuid32 (void)
216 {
217   return cygheap->user.real_uid;
218 }
219
220 extern "C" __uid16_t
221 getuid (void)
222 {
223   return cygheap->user.real_uid;
224 }
225
226 extern "C" __gid32_t
227 getgid32 (void)
228 {
229   return cygheap->user.real_gid;
230 }
231
232 extern "C" __gid16_t
233 getgid (void)
234 {
235   return cygheap->user.real_gid;
236 }
237
238 extern "C" __uid32_t
239 geteuid32 (void)
240 {
241   return myself->uid;
242 }
243
244 extern "C" __uid16_t
245 geteuid (void)
246 {
247   return myself->uid;
248 }
249
250 extern "C" __gid32_t
251 getegid32 (void)
252 {
253   return myself->gid;
254 }
255
256 extern "C" __gid16_t
257 getegid (void)
258 {
259   return myself->gid;
260 }
261
262 /* Not quite right - cuserid can change, getlogin can't */
263 extern "C" char *
264 cuserid (char *src)
265 {
266   if (!src)
267     return getlogin ();
268
269   strcpy (src, getlogin ());
270   return src;
271 }
272
273 const char *
274 cygheap_user::ontherange (homebodies what, struct passwd *pw)
275 {
276   LPUSER_INFO_3 ui = NULL;
277   WCHAR wuser[UNLEN + 1];
278   NET_API_STATUS ret;
279   char homedrive_env_buf[3];
280   char *newhomedrive = NULL;
281   char *newhomepath = NULL;
282   tmp_pathbuf tp;
283
284   debug_printf ("what %d, pw %p", what, pw);
285   if (what == CH_HOME)
286     {
287       char *p;
288
289       if ((p = getenv ("HOME")))
290         debug_printf ("HOME is already in the environment %s", p);
291       else
292         {
293           if (pw && pw->pw_dir && *pw->pw_dir)
294             {
295               debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
296               setenv ("HOME", pw->pw_dir, 1);
297             }
298           else
299             {
300               char home[strlen (name ()) + 8];
301
302               debug_printf ("Set HOME to default /home/USER");
303               __small_sprintf (home, "/home/%s", name ());
304               setenv ("HOME", home, 1);
305             }
306         }
307     }
308
309   if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
310     {
311       char *homepath_env_buf = tp.c_get ();
312       if (!pw)
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,
316                           NT_MAX_PATH);
317       else
318         {
319           homepath_env_buf[0] = homepath_env_buf[1] = '\0';
320           if (logsrv ())
321             {
322               WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
323               sys_mbstowcs (wlogsrv, sizeof (wlogsrv) / sizeof (*wlogsrv),
324                             logsrv ());
325              sys_mbstowcs (wuser, sizeof (wuser) / sizeof (*wuser), winname ());
326               if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui)))
327                 {
328                   sys_wcstombs (homepath_env_buf, NT_MAX_PATH,
329                                 ui->usri3_home_dir);
330                   if (!homepath_env_buf[0])
331                     {
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, "\\");
336                       else
337                         cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE,
338                                           "/", homepath_env_buf, NT_MAX_PATH);
339                     }
340                 }
341             }
342           if (ui)
343             NetApiBufferFree (ui);
344         }
345
346       if (homepath_env_buf[1] != ':')
347         {
348           newhomedrive = almost_null;
349           newhomepath = homepath_env_buf;
350         }
351       else
352         {
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;
358         }
359     }
360
361   if (newhomedrive && newhomedrive != homedrive)
362     cfree_and_set (homedrive, (newhomedrive == almost_null)
363                               ? almost_null : cstrdup (newhomedrive));
364
365   if (newhomepath && newhomepath != homepath)
366     cfree_and_set (homepath, cstrdup (newhomepath));
367
368   switch (what)
369     {
370     case CH_HOMEDRIVE:
371       return homedrive;
372     case CH_HOMEPATH:
373       return homepath;
374     default:
375       return homepath;
376     }
377 }
378
379 const char *
380 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
381 {
382   if (!what && !issetuid ())
383     what = getwinenveq (name, namelen, HEAP_STR);
384   return what;
385 }
386
387 const char *
388 cygheap_user::env_logsrv (const char *name, size_t namelen)
389 {
390   if (test_uid (plogsrv, name, namelen))
391     return plogsrv;
392
393   const char *mydomain = domain ();
394   const char *myname = winname ();
395   if (!mydomain || ascii_strcasematch (myname, "SYSTEM"))
396     return almost_null;
397
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);
404   return plogsrv;
405 }
406
407 const char *
408 cygheap_user::env_domain (const char *name, size_t namelen)
409 {
410   if (pwinname && test_uid (pdomain, name, namelen))
411     return pdomain;
412
413   DWORD ulen = UNLEN + 1;
414   WCHAR username[ulen];
415   DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
416   WCHAR userdomain[dlen];
417   SID_NAME_USE use;
418
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))
423     __seterrno ();
424   else
425     {
426       sys_wcstombs_alloc (&pwinname, HEAP_STR, username);
427       sys_wcstombs_alloc (&pdomain, HEAP_STR, userdomain);
428     }
429   return pdomain;
430 }
431
432 const char *
433 cygheap_user::env_userprofile (const char *name, size_t namelen)
434 {
435   if (test_uid (puserprof, name, namelen))
436     return puserprof;
437
438   WCHAR userprofile_env_buf[NT_MAX_PATH];
439   WCHAR win_id[UNLEN + 1]; /* Large enough for SID */
440
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);
444
445   return puserprof;
446 }
447
448 const char *
449 cygheap_user::env_homepath (const char *name, size_t namelen)
450 {
451   return ontherange (CH_HOMEPATH);
452 }
453
454 const char *
455 cygheap_user::env_homedrive (const char *name, size_t namelen)
456 {
457   return ontherange (CH_HOMEDRIVE);
458 }
459
460 const char *
461 cygheap_user::env_name (const char *name, size_t namelen)
462 {
463   if (!test_uid (pwinname, name, namelen))
464     domain ();
465   return pwinname;
466 }
467
468 const char *
469 cygheap_user::env_systemroot (const char *name, size_t namelen)
470 {
471   if (!psystemroot)
472     {
473       int size = GetSystemWindowsDirectoryW (NULL, 0);
474       if (size > 0)
475         {
476           WCHAR wsystemroot[size];
477           size = GetSystemWindowsDirectoryW (wsystemroot, size);
478           if (size > 0)
479             sys_wcstombs_alloc (&psystemroot, HEAP_STR, wsystemroot);
480         }
481       if (size <= 0)
482         debug_printf ("GetSystemWindowsDirectoryW(), %E");
483     }
484   return psystemroot;
485 }
486
487 char *
488 pwdgrp::next_str (char c)
489 {
490   char *res = lptr;
491   lptr = strechr (lptr, c);
492   if (*lptr)
493     *lptr++ = '\0';
494   return res;
495 }
496
497 bool
498 pwdgrp::next_num (unsigned long& n)
499 {
500   char *p = next_str (':');
501   char *cp;
502   n = strtoul (p, &cp, 10);
503   return p != cp && !*cp;
504 }
505
506 char *
507 pwdgrp::add_line (char *eptr)
508 {
509   if (eptr)
510     {
511       lptr = eptr;
512       eptr = strchr (lptr, '\n');
513       if (eptr)
514         {
515           if (eptr > lptr && eptr[-1] == '\r')
516             eptr[-1] = '\0';
517           else
518             *eptr = '\0';
519           eptr++;
520         }
521       if (curr_lines >= max_lines)
522         {
523           max_lines += 10;
524           *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
525         }
526       if ((this->*parse) ())
527         curr_lines++;
528     }
529   return eptr;
530 }
531
532 void
533 pwdgrp::load (const wchar_t *rel_path)
534 {
535   static const char failed[] = "failed";
536   static const char succeeded[] = "succeeded";
537   const char *res = failed;
538   HANDLE fh = NULL;
539
540   NTSTATUS status;
541   OBJECT_ATTRIBUTES attr;
542   IO_STATUS_BLOCK io;
543   FILE_STANDARD_INFORMATION fsi;
544
545   if (buf)
546     free (buf);
547   buf = NULL;
548   curr_lines = 0;
549
550   if (!path &&
551       !(path = (PWCHAR) malloc ((wcslen (installation_root)
552                                  + wcslen (rel_path) + 1) * sizeof (WCHAR))))
553     {
554       paranoid_printf ("malloc (%W) failed", rel_path);
555       goto out;
556     }
557   wcpcpy (wcpcpy (path, installation_root), rel_path);
558   RtlInitUnicodeString (&upath, path);
559
560   InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
561   etc_ix = etc::init (etc_ix, &attr);
562
563   paranoid_printf ("%S", &upath);
564
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))
570     {
571       paranoid_printf ("NtOpenFile(%S) failed, status %p", &upath, status);
572       goto out;
573     }
574   status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi,
575                                    FileStandardInformation);
576   if (!NT_SUCCESS (status))
577     {
578       paranoid_printf ("NtQueryInformationFile(%S) failed, status %p",
579                        &upath, status);
580       goto out;
581     }
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);
587   if (!buf)
588     {
589       paranoid_printf ("malloc (%d) failed", fsi.EndOfFile.LowPart);
590       goto out;
591     }
592   status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
593                        NULL, NULL);
594   if (!NT_SUCCESS (status))
595     {
596       paranoid_printf ("NtReadFile(%S) failed, status %p", &upath, status);
597       free (buf);
598       goto out;
599     }
600   buf[fsi.EndOfFile.LowPart] = '\0';
601   for (char *eptr = buf; (eptr = add_line (eptr)); )
602     continue;
603   debug_printf ("%W curr_lines %d", rel_path, curr_lines);
604   res = succeeded;
605
606 out:
607   if (fh)
608     NtClose (fh);
609   debug_printf ("%W load %s", rel_path, res);
610   initialized = true;
611 }