OSDN Git Service

Partially revert change from 2005-04-03, always running under an
[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 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <pwd.h>
13 #include <unistd.h>
14 #include <winnls.h>
15 #include <wininet.h>
16 #include <utmp.h>
17 #include <limits.h>
18 #include <stdlib.h>
19 #include <lm.h>
20 #include <sys/cygwin.h>
21 #include "cygerrno.h"
22 #include "pinfo.h"
23 #include "security.h"
24 #include "path.h"
25 #include "fhandler.h"
26 #include "dtable.h"
27 #include "cygheap.h"
28 #include "registry.h"
29 #include "child_info.h"
30 #include "environ.h"
31 #include "pwdgrp.h"
32
33 /* Initialize the part of cygheap_user that does not depend on files.
34    The information is used in shared.cc for the user shared.
35    Final initialization occurs in uinfo_init */
36 void
37 cygheap_user::init ()
38 {
39   char user_name[UNLEN + 1];
40   DWORD user_name_len = UNLEN + 1;
41
42   set_name (GetUserName (user_name, &user_name_len) ? user_name : "unknown");
43
44   if (!wincap.has_security ())
45     return;
46
47   DWORD siz;
48   PSECURITY_DESCRIPTOR psd;
49
50   if (!GetTokenInformation (hProcToken, TokenPrimaryGroup,
51                             &groups.pgsid, sizeof (cygsid), &siz))
52     system_printf ("GetTokenInformation (TokenPrimaryGroup), %E");
53
54   /* Get the SID from current process and store it in effec_cygsid */
55   if (!GetTokenInformation (hProcToken, TokenUser, &effec_cygsid,
56                             sizeof (cygsid), &siz))
57     {
58       system_printf ("GetTokenInformation (TokenUser), %E");
59       return;
60     }
61
62   /* Set token owner to the same value as token user */
63   if (!SetTokenInformation (hProcToken, TokenOwner, &effec_cygsid,
64                             sizeof (cygsid)))
65     debug_printf ("SetTokenInformation(TokenOwner), %E");
66
67   /* Standard way to build a security descriptor with the usual DACL */
68   PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
69   psd = (PSECURITY_DESCRIPTOR)
70                 (sec_user_nih (sa_buf, sid()))->lpSecurityDescriptor;
71
72   BOOL acl_exists, dummy;
73   TOKEN_DEFAULT_DACL dacl;
74   if (GetSecurityDescriptorDacl (psd, &acl_exists, &dacl.DefaultDacl, &dummy)
75       && acl_exists && dacl.DefaultDacl)
76     {
77       /* Set the default DACL and the process DACL */
78       if (!SetTokenInformation (hProcToken, TokenDefaultDacl, &dacl,
79                                 sizeof (dacl)))
80         system_printf ("SetTokenInformation (TokenDefaultDacl), %E");
81       if (!SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION, psd))
82         system_printf ("SetKernelObjectSecurity, %E");
83     }
84   else
85     system_printf("Cannot get dacl, %E");
86 }
87
88 void
89 internal_getlogin (cygheap_user &user)
90 {
91   struct passwd *pw = NULL;
92
93   if (wincap.has_security ())
94     {
95       cygpsid psid = user.sid ();
96       pw = internal_getpwsid (psid);
97     }
98
99   if (!pw && !(pw = internal_getpwnam (user.name ()))
100       && !(pw = internal_getpwuid (DEFAULT_UID)))
101     debug_printf ("user not found in augmented /etc/passwd");
102   else
103     {
104       myself->uid = pw->pw_uid;
105       myself->gid = pw->pw_gid;
106       user.set_name (pw->pw_name);
107       if (wincap.has_security ())
108         {
109           cygsid gsid;
110           if (gsid.getfromgr (internal_getgrgid (pw->pw_gid)))
111             {
112               if (gsid != user.groups.pgsid)
113                 {
114                   /* Set primary group to the group in /etc/passwd. */
115                   if (!SetTokenInformation (hProcToken, TokenPrimaryGroup,
116                                             &gsid, sizeof gsid))
117                     debug_printf ("SetTokenInformation(TokenPrimaryGroup), %E");
118                   else
119                     user.groups.pgsid = gsid;
120                   clear_procimptoken ();
121                 }
122             }
123           else
124             debug_printf ("gsid not found in augmented /etc/group");
125         }
126     }
127   cygheap->user.ontherange (CH_HOME, pw);
128 }
129
130 void
131 uinfo_init ()
132 {
133   if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
134     return;
135
136   if (!child_proc_info)
137     internal_getlogin (cygheap->user); /* Set the cygheap->user. */
138   /* Conditions must match those in spawn to allow starting child
139      processes with ruid != euid and rgid != egid. */
140   else if (cygheap->user.issetuid ()
141            && cygheap->user.saved_uid == cygheap->user.real_uid
142            && cygheap->user.saved_gid == cygheap->user.real_gid
143            && !cygheap->user.groups.issetgroups ())
144     {
145       cygheap->user.reimpersonate ();
146       return;
147     }
148   else
149     cygheap->user.close_impersonation_tokens ();
150
151   cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid;
152   cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid;
153   cygheap->user.external_token = NO_IMPERSONATION;
154   cygheap->user.internal_token = NO_IMPERSONATION;
155   cygheap->user.curr_primary_token = NO_IMPERSONATION;
156   cygheap->user.current_token = NO_IMPERSONATION;
157   cygheap->user.set_saved_sid ();       /* Update the original sid */
158   cygheap->user.reimpersonate ();
159 }
160
161 extern "C" int
162 getlogin_r (char *name, size_t namesize)
163 {
164   char *login = getlogin ();
165   size_t len = strlen (login) + 1;
166   if (len > namesize)
167     return ERANGE;
168   myfault efault;
169   if (efault.faulted ())
170     return EFAULT;
171   strncpy (name, login, len);
172   return 0;
173 }
174
175 extern "C" char *
176 getlogin (void)
177 {
178   return strcpy (_my_tls.locals.username, cygheap->user.name ());
179 }
180
181 extern "C" __uid32_t
182 getuid32 (void)
183 {
184   return cygheap->user.real_uid;
185 }
186
187 extern "C" __uid16_t
188 getuid (void)
189 {
190   return cygheap->user.real_uid;
191 }
192
193 extern "C" __gid32_t
194 getgid32 (void)
195 {
196   return cygheap->user.real_gid;
197 }
198
199 extern "C" __gid16_t
200 getgid (void)
201 {
202   return cygheap->user.real_gid;
203 }
204
205 extern "C" __uid32_t
206 geteuid32 (void)
207 {
208   return myself->uid;
209 }
210
211 extern "C" __uid16_t
212 geteuid (void)
213 {
214   return myself->uid;
215 }
216
217 extern "C" __gid32_t
218 getegid32 (void)
219 {
220   return myself->gid;
221 }
222
223 extern "C" __gid16_t
224 getegid (void)
225 {
226   return myself->gid;
227 }
228
229 /* Not quite right - cuserid can change, getlogin can't */
230 extern "C" char *
231 cuserid (char *src)
232 {
233   if (!src)
234     return getlogin ();
235
236   strcpy (src, getlogin ());
237   return src;
238 }
239
240 const char *
241 cygheap_user::ontherange (homebodies what, struct passwd *pw)
242 {
243   LPUSER_INFO_3 ui = NULL;
244   WCHAR wuser[UNLEN + 1];
245   NET_API_STATUS ret;
246   char homepath_env_buf[CYG_MAX_PATH];
247   char homedrive_env_buf[3];
248   char *newhomedrive = NULL;
249   char *newhomepath = NULL;
250
251
252   debug_printf ("what %d, pw %p", what, pw);
253   if (what == CH_HOME)
254     {
255       char *p;
256       if (homedrive)
257         newhomedrive = homedrive;
258       else if ((p = getenv ("HOMEDRIVE")))
259         newhomedrive = p;
260
261       if (homepath)
262         newhomepath = homepath;
263       else if ((p = getenv ("HOMEPATH")))
264         newhomepath = p;
265
266       if ((p = getenv ("HOME")))
267         debug_printf ("HOME is already in the environment %s", p);
268       else
269         {
270           if (pw && pw->pw_dir && *pw->pw_dir)
271             {
272               debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
273               setenv ("HOME", pw->pw_dir, 1);
274             }
275           else if (!newhomedrive || !newhomepath)
276             setenv ("HOME", "/", 1);
277           else
278             {
279               char home[CYG_MAX_PATH];
280               char buf[CYG_MAX_PATH];
281               strcpy (buf, newhomedrive);
282               strcat (buf, newhomepath);
283               cygwin_conv_to_full_posix_path (buf, home);
284               debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home);
285               setenv ("HOME", home, 1);
286             }
287         }
288     }
289
290   if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
291     {
292       if (!pw)
293         pw = internal_getpwnam (name ());
294       if (pw && pw->pw_dir && *pw->pw_dir)
295         cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf);
296       else
297         {
298           homepath_env_buf[0] = homepath_env_buf[1] = '\0';
299           if (logsrv ())
300             {
301               WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
302               sys_mbstowcs (wlogsrv, logsrv (),
303                             sizeof (wlogsrv) / sizeof (*wlogsrv));
304              sys_mbstowcs (wuser, winname (), sizeof (wuser) / sizeof (*wuser));
305               if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui)))
306                 {
307                   sys_wcstombs (homepath_env_buf, CYG_MAX_PATH,
308                                 ui->usri3_home_dir);
309                   if (!homepath_env_buf[0])
310                     {
311                       sys_wcstombs (homepath_env_buf, CYG_MAX_PATH,
312                                     ui->usri3_home_dir_drive);
313                       if (homepath_env_buf[0])
314                         strcat (homepath_env_buf, "\\");
315                       else
316                         cygwin_conv_to_full_win32_path ("/", homepath_env_buf);
317                     }
318                 }
319             }
320           if (ui)
321             NetApiBufferFree (ui);
322         }
323
324       if (homepath_env_buf[1] != ':')
325         {
326           newhomedrive = almost_null;
327           newhomepath = homepath_env_buf;
328         }
329       else
330         {
331           homedrive_env_buf[0] = homepath_env_buf[0];
332           homedrive_env_buf[1] = homepath_env_buf[1];
333           homedrive_env_buf[2] = '\0';
334           newhomedrive = homedrive_env_buf;
335           newhomepath = homepath_env_buf + 2;
336         }
337     }
338
339   if (newhomedrive && newhomedrive != homedrive)
340     cfree_and_set (homedrive, (newhomedrive == almost_null)
341                               ? almost_null : cstrdup (newhomedrive));
342
343   if (newhomepath && newhomepath != homepath)
344     cfree_and_set (homepath, cstrdup (newhomepath));
345
346   switch (what)
347     {
348     case CH_HOMEDRIVE:
349       return homedrive;
350     case CH_HOMEPATH:
351       return homepath;
352     default:
353       return homepath;
354     }
355 }
356
357 const char *
358 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
359 {
360   if (!what && !issetuid ())
361     what = getwinenveq (name, namelen, HEAP_STR);
362   return what;
363 }
364
365 const char *
366 cygheap_user::env_logsrv (const char *name, size_t namelen)
367 {
368   if (test_uid (plogsrv, name, namelen))
369     return plogsrv;
370
371   const char *mydomain = domain ();
372   const char *myname = winname ();
373   if (!mydomain || strcasematch (myname, "SYSTEM"))
374     return almost_null;
375
376   char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
377   cfree_and_set (plogsrv, almost_null);
378   if (get_logon_server (mydomain, logsrv, NULL, false))
379     plogsrv = cstrdup (logsrv);
380   return plogsrv;
381 }
382
383 const char *
384 cygheap_user::env_domain (const char *name, size_t namelen)
385 {
386   if (pwinname && test_uid (pdomain, name, namelen))
387     return pdomain;
388
389   char username[UNLEN + 1];
390   DWORD ulen = sizeof (username);
391   char userdomain[DNLEN + 1];
392   DWORD dlen = sizeof (userdomain);
393   SID_NAME_USE use;
394
395   cfree_and_set (pwinname, almost_null);
396   cfree_and_set (pdomain, almost_null);
397   if (!LookupAccountSid (NULL, sid (), username, &ulen,
398                          userdomain, &dlen, &use))
399     __seterrno ();
400   else
401     {
402       pwinname = cstrdup (username);
403       pdomain = cstrdup (userdomain);
404     }
405   return pdomain;
406 }
407
408 const char *
409 cygheap_user::env_userprofile (const char *name, size_t namelen)
410 {
411   if (test_uid (puserprof, name, namelen))
412     return puserprof;
413
414   char userprofile_env_buf[CYG_MAX_PATH];
415   char win_id[UNLEN + 1]; /* Large enough for SID */
416
417   cfree_and_set (puserprof, almost_null);
418   if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf))
419     puserprof = cstrdup (userprofile_env_buf);
420
421   return puserprof;
422 }
423
424 const char *
425 cygheap_user::env_homepath (const char *name, size_t namelen)
426 {
427   return ontherange (CH_HOMEPATH);
428 }
429
430 const char *
431 cygheap_user::env_homedrive (const char *name, size_t namelen)
432 {
433   return ontherange (CH_HOMEDRIVE);
434 }
435
436 const char *
437 cygheap_user::env_name (const char *name, size_t namelen)
438 {
439   if (!test_uid (pwinname, name, namelen))
440     domain ();
441   return pwinname;
442 }
443
444 const char *
445 cygheap_user::env_systemroot (const char *name, size_t namelen)
446 {
447   if (!psystemroot)
448     {
449       int size = GetWindowsDirectory (NULL, 0);
450       if (size > 0)
451         {
452           psystemroot = (char *) cmalloc (HEAP_STR, ++size);
453           size = GetWindowsDirectory (psystemroot, size);
454           if (size <= 0)
455             {
456               cfree (psystemroot);
457               psystemroot = NULL;
458             }
459         }
460       if (size <= 0)
461         debug_printf ("GetWindowsDirectory(), %E");
462     }
463   return psystemroot;
464 }
465
466 char *
467 pwdgrp::next_str (char c)
468 {
469   char *res = lptr;
470   lptr = strechr (lptr, c);
471   if (*lptr)
472     *lptr++ = '\0';
473   return res;
474 }
475
476 bool
477 pwdgrp::next_num (unsigned long& n)
478 {
479   char *p = next_str (':');
480   char *cp;
481   n = strtoul (p, &cp, 10);
482   return p != cp && !*cp;
483 }
484
485 char *
486 pwdgrp::add_line (char *eptr)
487 {
488   if (eptr)
489     {
490       lptr = eptr;
491       eptr = strchr (lptr, '\n');
492       if (eptr)
493         {
494           if (eptr > lptr && eptr[-1] == '\r')
495             eptr[-1] = '\0';
496           else
497             *eptr = '\0';
498           eptr++;
499         }
500       if (curr_lines >= max_lines)
501         {
502           max_lines += 10;
503           *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
504         }
505       if ((this->*parse) ())
506         curr_lines++;
507     }
508   return eptr;
509 }
510
511 void
512 pwdgrp::load (const char *posix_fname)
513 {
514   const char *res;
515   static const char failed[] = "failed";
516   static const char succeeded[] = "succeeded";
517
518   if (buf)
519     free (buf);
520   buf = NULL;
521   curr_lines = 0;
522
523   pc.check (posix_fname);
524   etc_ix = etc::init (etc_ix, pc);
525
526   paranoid_printf ("%s", posix_fname);
527
528   if (pc.error || !pc.exists () || pc.isdir ())
529     {
530       paranoid_printf ("strange path_conv problem");
531       res = failed;
532     }
533   else
534     {
535       HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
536                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
537       if (fh == INVALID_HANDLE_VALUE)
538         {
539           paranoid_printf ("%s CreateFile failed, %E");
540           res = failed;
541         }
542       else
543         {
544           DWORD size = GetFileSize (fh, NULL), read_bytes;
545           buf = (char *) malloc (size + 1);
546           if (!ReadFile (fh, buf, size, &read_bytes, NULL))
547             {
548               paranoid_printf ("ReadFile failed, %E");
549               CloseHandle (fh);
550               if (buf)
551                 free (buf);
552               buf = NULL;
553               res = failed;
554             }
555           else
556             {
557               CloseHandle (fh);
558               buf[read_bytes] = '\0';
559               char *eptr = buf;
560               while ((eptr = add_line (eptr)))
561                 continue;
562               debug_printf ("%s curr_lines %d", posix_fname, curr_lines);
563               res = succeeded;
564             }
565         }
566     }
567
568   debug_printf ("%s load %s", posix_fname, res);
569   initialized = true;
570 }