OSDN Git Service

Revert accidental previous login.
[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 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   if (!GetUserNameW (user_name, &user_name_len))
44     wcpcpy (user_name, L"unknown");
45
46   char mb_user_name[user_name_len = sys_wcstombs (NULL, 0, user_name)];
47   sys_wcstombs (mb_user_name, user_name_len, user_name);
48   set_name (mb_user_name);
49
50   DWORD siz;
51   PSECURITY_DESCRIPTOR psd;
52
53   if (!GetTokenInformation (hProcToken, TokenPrimaryGroup,
54                             &groups.pgsid, sizeof (cygsid), &siz))
55     system_printf ("GetTokenInformation (TokenPrimaryGroup), %E");
56
57   /* Get the SID from current process and store it in effec_cygsid */
58   if (!GetTokenInformation (hProcToken, TokenUser, &effec_cygsid,
59                             sizeof (cygsid), &siz))
60     {
61       system_printf ("GetTokenInformation (TokenUser), %E");
62       return;
63     }
64
65   /* Set token owner to the same value as token user */
66   if (!SetTokenInformation (hProcToken, TokenOwner, &effec_cygsid,
67                             sizeof (cygsid)))
68     debug_printf ("SetTokenInformation(TokenOwner), %E");
69
70   /* Standard way to build a security descriptor with the usual DACL */
71   PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
72   psd = (PSECURITY_DESCRIPTOR)
73                 (sec_user_nih (sa_buf, sid()))->lpSecurityDescriptor;
74
75   BOOL acl_exists, dummy;
76   TOKEN_DEFAULT_DACL dacl;
77   if (GetSecurityDescriptorDacl (psd, &acl_exists, &dacl.DefaultDacl, &dummy)
78       && acl_exists && dacl.DefaultDacl)
79     {
80       NTSTATUS status;
81
82       /* Set the default DACL and the process DACL */
83       if (!SetTokenInformation (hProcToken, TokenDefaultDacl, &dacl,
84                                 sizeof (dacl)))
85         system_printf ("SetTokenInformation (TokenDefaultDacl), %E");
86       if ((status = NtSetSecurityObject (NtCurrentProcess (),
87                                          DACL_SECURITY_INFORMATION, psd)))
88         system_printf ("NtSetSecurityObject, %lx", status);
89     }
90   else
91     system_printf("Cannot get dacl, %E");
92 }
93
94 void
95 internal_getlogin (cygheap_user &user)
96 {
97   struct passwd *pw = NULL;
98
99   cygpsid psid = user.sid ();
100   pw = internal_getpwsid (psid);
101
102   if (!pw && !(pw = internal_getpwnam (user.name ()))
103       && !(pw = internal_getpwuid (DEFAULT_UID)))
104     debug_printf ("user not found in augmented /etc/passwd");
105   else
106     {
107       cygsid gsid;
108
109       myself->uid = pw->pw_uid;
110       myself->gid = pw->pw_gid;
111       user.set_name (pw->pw_name);
112       if (gsid.getfromgr (internal_getgrgid (pw->pw_gid)))
113         {
114           if (gsid != user.groups.pgsid)
115             {
116               /* Set primary group to the group in /etc/passwd. */
117               if (!SetTokenInformation (hProcToken, TokenPrimaryGroup,
118                                         &gsid, sizeof gsid))
119                 debug_printf ("SetTokenInformation(TokenPrimaryGroup), %E");
120               else
121                 user.groups.pgsid = gsid;
122               clear_procimptoken ();
123             }
124         }
125       else
126         debug_printf ("gsid not found in augmented /etc/group");
127     }
128   cygheap->user.ontherange (CH_HOME, pw);
129 }
130
131 void
132 uinfo_init ()
133 {
134   if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
135     return;
136
137   if (!child_proc_info)
138     internal_getlogin (cygheap->user); /* Set the cygheap->user. */
139   /* Conditions must match those in spawn to allow starting child
140      processes with ruid != euid and rgid != egid. */
141   else if (cygheap->user.issetuid ()
142            && cygheap->user.saved_uid == cygheap->user.real_uid
143            && cygheap->user.saved_gid == cygheap->user.real_gid
144            && !cygheap->user.groups.issetgroups ()
145            && !cygheap->user.setuid_to_restricted)
146     {
147       cygheap->user.reimpersonate ();
148       return;
149     }
150   else
151     cygheap->user.close_impersonation_tokens ();
152
153   cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid;
154   cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid;
155   cygheap->user.external_token = NO_IMPERSONATION;
156   cygheap->user.internal_token = NO_IMPERSONATION;
157   cygheap->user.curr_primary_token = NO_IMPERSONATION;
158   cygheap->user.curr_imp_token = NO_IMPERSONATION;
159   cygheap->user.ext_token_is_restricted = false;
160   cygheap->user.curr_token_is_restricted = false;
161   cygheap->user.setuid_to_restricted = false;
162   cygheap->user.set_saved_sid ();       /* Update the original sid */
163   cygheap->user.deimpersonate ();
164 }
165
166 extern "C" int
167 getlogin_r (char *name, size_t namesize)
168 {
169   char *login = getlogin ();
170   size_t len = strlen (login) + 1;
171   if (len > namesize)
172     return ERANGE;
173   myfault efault;
174   if (efault.faulted ())
175     return EFAULT;
176   strncpy (name, login, len);
177   return 0;
178 }
179
180 extern "C" char *
181 getlogin (void)
182 {
183   return strcpy (_my_tls.locals.username, cygheap->user.name ());
184 }
185
186 extern "C" __uid32_t
187 getuid32 (void)
188 {
189   return cygheap->user.real_uid;
190 }
191
192 extern "C" __uid16_t
193 getuid (void)
194 {
195   return cygheap->user.real_uid;
196 }
197
198 extern "C" __gid32_t
199 getgid32 (void)
200 {
201   return cygheap->user.real_gid;
202 }
203
204 extern "C" __gid16_t
205 getgid (void)
206 {
207   return cygheap->user.real_gid;
208 }
209
210 extern "C" __uid32_t
211 geteuid32 (void)
212 {
213   return myself->uid;
214 }
215
216 extern "C" __uid16_t
217 geteuid (void)
218 {
219   return myself->uid;
220 }
221
222 extern "C" __gid32_t
223 getegid32 (void)
224 {
225   return myself->gid;
226 }
227
228 extern "C" __gid16_t
229 getegid (void)
230 {
231   return myself->gid;
232 }
233
234 /* Not quite right - cuserid can change, getlogin can't */
235 extern "C" char *
236 cuserid (char *src)
237 {
238   if (!src)
239     return getlogin ();
240
241   strcpy (src, getlogin ());
242   return src;
243 }
244
245 const char *
246 cygheap_user::ontherange (homebodies what, struct passwd *pw)
247 {
248   LPUSER_INFO_3 ui = NULL;
249   WCHAR wuser[UNLEN + 1];
250   NET_API_STATUS ret;
251   char homedrive_env_buf[3];
252   char *newhomedrive = NULL;
253   char *newhomepath = NULL;
254   tmp_pathbuf tp;
255
256   debug_printf ("what %d, pw %p", what, pw);
257   if (what == CH_HOME)
258     {
259       char *p;
260
261       if ((p = getenv ("HOME")))
262         debug_printf ("HOME is already in the environment %s", p);
263       else
264         {
265           if (pw && pw->pw_dir && *pw->pw_dir)
266             {
267               debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
268               setenv ("HOME", pw->pw_dir, 1);
269             }
270           else
271             {
272               char home[strlen (name ()) + 8];
273
274               debug_printf ("Set HOME to default /home/USER");
275               __small_sprintf (home, "/home/%s", name ());
276               setenv ("HOME", home, 1);
277             }
278         }
279     }
280
281   if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
282     {
283       char *homepath_env_buf = tp.c_get ();
284       if (!pw)
285         pw = internal_getpwnam (name ());
286       if (pw && pw->pw_dir && *pw->pw_dir)
287         cygwin_conv_path (CCP_POSIX_TO_WIN_A, pw->pw_dir, homepath_env_buf,
288                           NT_MAX_PATH);
289       else
290         {
291           homepath_env_buf[0] = homepath_env_buf[1] = '\0';
292           if (logsrv ())
293             {
294               WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
295               sys_mbstowcs (wlogsrv, sizeof (wlogsrv) / sizeof (*wlogsrv),
296                             logsrv ());
297              sys_mbstowcs (wuser, sizeof (wuser) / sizeof (*wuser), winname ());
298               if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui)))
299                 {
300                   sys_wcstombs (homepath_env_buf, NT_MAX_PATH,
301                                 ui->usri3_home_dir);
302                   if (!homepath_env_buf[0])
303                     {
304                       sys_wcstombs (homepath_env_buf, NT_MAX_PATH,
305                                     ui->usri3_home_dir_drive);
306                       if (homepath_env_buf[0])
307                         strcat (homepath_env_buf, "\\");
308                       else
309                         cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE,
310                                           "/", homepath_env_buf, NT_MAX_PATH);
311                     }
312                 }
313             }
314           if (ui)
315             NetApiBufferFree (ui);
316         }
317
318       if (homepath_env_buf[1] != ':')
319         {
320           newhomedrive = almost_null;
321           newhomepath = homepath_env_buf;
322         }
323       else
324         {
325           homedrive_env_buf[0] = homepath_env_buf[0];
326           homedrive_env_buf[1] = homepath_env_buf[1];
327           homedrive_env_buf[2] = '\0';
328           newhomedrive = homedrive_env_buf;
329           newhomepath = homepath_env_buf + 2;
330         }
331     }
332
333   if (newhomedrive && newhomedrive != homedrive)
334     cfree_and_set (homedrive, (newhomedrive == almost_null)
335                               ? almost_null : cstrdup (newhomedrive));
336
337   if (newhomepath && newhomepath != homepath)
338     cfree_and_set (homepath, cstrdup (newhomepath));
339
340   switch (what)
341     {
342     case CH_HOMEDRIVE:
343       return homedrive;
344     case CH_HOMEPATH:
345       return homepath;
346     default:
347       return homepath;
348     }
349 }
350
351 const char *
352 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
353 {
354   if (!what && !issetuid ())
355     what = getwinenveq (name, namelen, HEAP_STR);
356   return what;
357 }
358
359 const char *
360 cygheap_user::env_logsrv (const char *name, size_t namelen)
361 {
362   if (test_uid (plogsrv, name, namelen))
363     return plogsrv;
364
365   const char *mydomain = domain ();
366   const char *myname = winname ();
367   if (!mydomain || ascii_strcasematch (myname, "SYSTEM"))
368     return almost_null;
369
370   WCHAR wdomain[MAX_DOMAIN_NAME_LEN + 1];
371   WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
372   sys_mbstowcs (wdomain, MAX_DOMAIN_NAME_LEN + 1, mydomain);
373   cfree_and_set (plogsrv, almost_null);
374   if (get_logon_server (wdomain, wlogsrv, false))
375     sys_wcstombs_alloc (&plogsrv, HEAP_STR, wlogsrv);
376   return plogsrv;
377 }
378
379 const char *
380 cygheap_user::env_domain (const char *name, size_t namelen)
381 {
382   if (pwinname && test_uid (pdomain, name, namelen))
383     return pdomain;
384
385   char username[UNLEN + 1];
386   DWORD ulen = sizeof (username);
387   char userdomain[DNLEN + 1];
388   DWORD dlen = sizeof (userdomain);
389   SID_NAME_USE use;
390
391   cfree_and_set (pwinname, almost_null);
392   cfree_and_set (pdomain, almost_null);
393   if (!LookupAccountSid (NULL, sid (), username, &ulen,
394                          userdomain, &dlen, &use))
395     __seterrno ();
396   else
397     {
398       pwinname = cstrdup (username);
399       pdomain = cstrdup (userdomain);
400     }
401   return pdomain;
402 }
403
404 const char *
405 cygheap_user::env_userprofile (const char *name, size_t namelen)
406 {
407   if (test_uid (puserprof, name, namelen))
408     return puserprof;
409
410   WCHAR userprofile_env_buf[NT_MAX_PATH];
411   WCHAR win_id[UNLEN + 1]; /* Large enough for SID */
412
413   cfree_and_set (puserprof, almost_null);
414   if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf))
415     sys_wcstombs_alloc (&puserprof, HEAP_STR, userprofile_env_buf);
416
417   return puserprof;
418 }
419
420 const char *
421 cygheap_user::env_homepath (const char *name, size_t namelen)
422 {
423   return ontherange (CH_HOMEPATH);
424 }
425
426 const char *
427 cygheap_user::env_homedrive (const char *name, size_t namelen)
428 {
429   return ontherange (CH_HOMEDRIVE);
430 }
431
432 const char *
433 cygheap_user::env_name (const char *name, size_t namelen)
434 {
435   if (!test_uid (pwinname, name, namelen))
436     domain ();
437   return pwinname;
438 }
439
440 const char *
441 cygheap_user::env_systemroot (const char *name, size_t namelen)
442 {
443   if (!psystemroot)
444     {
445       int size = GetWindowsDirectory (NULL, 0);
446       if (size > 0)
447         {
448           psystemroot = (char *) cmalloc_abort (HEAP_STR, ++size);
449           size = GetWindowsDirectory (psystemroot, size);
450           if (size <= 0)
451             {
452               cfree (psystemroot);
453               psystemroot = NULL;
454             }
455         }
456       if (size <= 0)
457         debug_printf ("GetWindowsDirectory(), %E");
458     }
459   return psystemroot;
460 }
461
462 char *
463 pwdgrp::next_str (char c)
464 {
465   char *res = lptr;
466   lptr = strechr (lptr, c);
467   if (*lptr)
468     *lptr++ = '\0';
469   return res;
470 }
471
472 bool
473 pwdgrp::next_num (unsigned long& n)
474 {
475   char *p = next_str (':');
476   char *cp;
477   n = strtoul (p, &cp, 10);
478   return p != cp && !*cp;
479 }
480
481 char *
482 pwdgrp::add_line (char *eptr)
483 {
484   if (eptr)
485     {
486       lptr = eptr;
487       eptr = strchr (lptr, '\n');
488       if (eptr)
489         {
490           if (eptr > lptr && eptr[-1] == '\r')
491             eptr[-1] = '\0';
492           else
493             *eptr = '\0';
494           eptr++;
495         }
496       if (curr_lines >= max_lines)
497         {
498           max_lines += 10;
499           *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
500         }
501       if ((this->*parse) ())
502         curr_lines++;
503     }
504   return eptr;
505 }
506
507 void
508 pwdgrp::load (const wchar_t *rel_path)
509 {
510   static const char failed[] = "failed";
511   static const char succeeded[] = "succeeded";
512   const char *res = failed;
513   HANDLE fh = NULL;
514
515   NTSTATUS status;
516   OBJECT_ATTRIBUTES attr;
517   IO_STATUS_BLOCK io;
518   FILE_STANDARD_INFORMATION fsi;
519
520   if (buf)
521     free (buf);
522   buf = NULL;
523   curr_lines = 0;
524
525   if (!path &&
526       !(path = (PWCHAR) malloc ((wcslen (installation_root)
527                                  + wcslen (rel_path) + 1) * sizeof (WCHAR))))
528     {
529       paranoid_printf ("malloc (%W) failed", rel_path);
530       goto out;
531     }
532   wcpcpy (wcpcpy (path, installation_root), rel_path);
533   RtlInitUnicodeString (&upath, path);
534
535   InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
536   etc_ix = etc::init (etc_ix, &attr);
537
538   paranoid_printf ("%S", &upath);
539
540   status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io,
541                        FILE_SHARE_VALID_FLAGS,
542                        FILE_SYNCHRONOUS_IO_NONALERT
543                        | FILE_OPEN_FOR_BACKUP_INTENT);
544   if (!NT_SUCCESS (status))
545     {
546       paranoid_printf ("NtOpenFile(%S) failed, status %p", &upath, status);
547       goto out;
548     }
549   status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi,
550                                    FileStandardInformation);
551   if (!NT_SUCCESS (status))
552     {
553       paranoid_printf ("NtQueryInformationFile(%S) failed, status %p",
554                        &upath, status);
555       goto out;
556     }
557   /* FIXME: Should we test for HighPart set?  If so, the
558      passwd or group file is way beyond what we can handle. */
559   /* FIXME 2: It's still ugly that we keep the file in memory.
560      Big organizations have naturally large passwd files. */
561   buf = (char *) malloc (fsi.EndOfFile.LowPart + 1);
562   if (!buf)
563     {
564       paranoid_printf ("malloc (%d) failed", fsi.EndOfFile.LowPart);
565       goto out;
566     }
567   status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
568                        NULL, NULL);
569   if (!NT_SUCCESS (status))
570     {
571       paranoid_printf ("NtReadFile(%S) failed, status %p", &upath, status);
572       free (buf);
573       goto out;
574     }
575   buf[fsi.EndOfFile.LowPart] = '\0';
576   for (char *eptr = buf; (eptr = add_line (eptr)); )
577     continue;
578   debug_printf ("%W curr_lines %d", rel_path, curr_lines);
579   res = succeeded;
580
581 out:
582   if (fh)
583     NtClose (fh);
584   debug_printf ("%W load %s", rel_path, res);
585   initialized = true;
586 }