OSDN Git Service

Replace valid memory checks with new myfault class "exception handling", almost
[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                   if (!SetTokenInformation (hProcImpToken, TokenPrimaryGroup,
119                                             &gsid, sizeof gsid))
120                     debug_printf ("SetTokenInformation(TokenPrimaryGroup), %E");
121                   else
122                     user.groups.pgsid = gsid;
123                 }
124             }
125           else
126             debug_printf ("gsid not found in augmented /etc/group");
127         }
128     }
129   (void) cygheap->user.ontherange (CH_HOME, pw);
130
131   return;
132 }
133
134 void
135 uinfo_init ()
136 {
137   if (child_proc_info && !cygheap->user.has_impersonation_tokens ())
138     return;
139
140   if (!child_proc_info)
141     internal_getlogin (cygheap->user); /* Set the cygheap->user. */
142   /* Conditions must match those in spawn to allow starting child
143      processes with ruid != euid and rgid != egid. */
144   else if (cygheap->user.issetuid ()
145            && cygheap->user.saved_uid == cygheap->user.real_uid
146            && cygheap->user.saved_gid == cygheap->user.real_gid
147            && !cygheap->user.groups.issetgroups ())
148     {
149       cygheap->user.reimpersonate ();
150       return;
151     }
152   else
153     cygheap->user.close_impersonation_tokens ();
154
155   cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid;
156   cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid;
157   cygheap->user.external_token = NO_IMPERSONATION;
158   cygheap->user.internal_token = NO_IMPERSONATION;
159   cygheap->user.curr_primary_token = NO_IMPERSONATION;
160   cygheap->user.current_token = NO_IMPERSONATION;
161   cygheap->user.set_saved_sid ();       /* Update the original sid */
162   cygheap->user.reimpersonate ();
163 }
164
165 extern "C" int
166 getlogin_r (char *name, size_t namesize)
167 {
168   char *login = getlogin ();
169   size_t len = strlen (login) + 1;
170   if (len > namesize)
171     return ERANGE;
172   myfault efault;
173   if (efault.faulted ())
174     return EFAULT;
175   strncpy (name, login, len);
176   return 0;
177 }
178
179 extern "C" char *
180 getlogin (void)
181 {
182   return strcpy (_my_tls.locals.username, cygheap->user.name ());
183 }
184
185 extern "C" __uid32_t
186 getuid32 (void)
187 {
188   return cygheap->user.real_uid;
189 }
190
191 extern "C" __uid16_t
192 getuid (void)
193 {
194   return cygheap->user.real_uid;
195 }
196
197 extern "C" __gid32_t
198 getgid32 (void)
199 {
200   return cygheap->user.real_gid;
201 }
202
203 extern "C" __gid16_t
204 getgid (void)
205 {
206   return cygheap->user.real_gid;
207 }
208
209 extern "C" __uid32_t
210 geteuid32 (void)
211 {
212   return myself->uid;
213 }
214
215 extern "C" __uid16_t
216 geteuid (void)
217 {
218   return myself->uid;
219 }
220
221 extern "C" __gid32_t
222 getegid32 (void)
223 {
224   return myself->gid;
225 }
226
227 extern "C" __gid16_t
228 getegid (void)
229 {
230   return myself->gid;
231 }
232
233 /* Not quite right - cuserid can change, getlogin can't */
234 extern "C" char *
235 cuserid (char *src)
236 {
237   if (!src)
238     return getlogin ();
239
240   strcpy (src, getlogin ());
241   return src;
242 }
243
244 const char *
245 cygheap_user::ontherange (homebodies what, struct passwd *pw)
246 {
247   LPUSER_INFO_3 ui = NULL;
248   WCHAR wuser[UNLEN + 1];
249   NET_API_STATUS ret;
250   char homepath_env_buf[CYG_MAX_PATH];
251   char homedrive_env_buf[3];
252   char *newhomedrive = NULL;
253   char *newhomepath = NULL;
254
255
256   debug_printf ("what %d, pw %p", what, pw);
257   if (what == CH_HOME)
258     {
259       char *p;
260       if (homedrive)
261         newhomedrive = homedrive;
262       else if ((p = getenv ("HOMEDRIVE")))
263         newhomedrive = p;
264
265       if (homepath)
266         newhomepath = homepath;
267       else if ((p = getenv ("HOMEPATH")))
268         newhomepath = p;
269
270       if ((p = getenv ("HOME")))
271         debug_printf ("HOME is already in the environment %s", p);
272       else
273         {
274           if (pw && pw->pw_dir && *pw->pw_dir)
275             {
276               debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
277               setenv ("HOME", pw->pw_dir, 1);
278             }
279           else if (!newhomedrive || !newhomepath)
280             setenv ("HOME", "/", 1);
281           else
282             {
283               char home[CYG_MAX_PATH];
284               char buf[CYG_MAX_PATH];
285               strcpy (buf, newhomedrive);
286               strcat (buf, newhomepath);
287               cygwin_conv_to_full_posix_path (buf, home);
288               debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home);
289               setenv ("HOME", home, 1);
290             }
291         }
292     }
293
294   if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
295     {
296       if (!pw)
297         pw = internal_getpwnam (name ());
298       if (pw && pw->pw_dir && *pw->pw_dir)
299         cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf);
300       else
301         {
302           homepath_env_buf[0] = homepath_env_buf[1] = '\0';
303           if (logsrv ())
304             {
305               WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
306               sys_mbstowcs (wlogsrv, logsrv (),
307                             sizeof (wlogsrv) / sizeof (*wlogsrv));
308              sys_mbstowcs (wuser, winname (), sizeof (wuser) / sizeof (*wuser));
309               if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui)))
310                 {
311                   sys_wcstombs (homepath_env_buf, ui->usri3_home_dir, CYG_MAX_PATH);
312                   if (!homepath_env_buf[0])
313                     {
314                       sys_wcstombs (homepath_env_buf, ui->usri3_home_dir_drive,
315                                     CYG_MAX_PATH);
316                       if (homepath_env_buf[0])
317                         strcat (homepath_env_buf, "\\");
318                       else
319                         cygwin_conv_to_full_win32_path ("/", homepath_env_buf);
320                     }
321                 }
322             }
323           if (ui)
324             NetApiBufferFree (ui);
325         }
326
327       if (homepath_env_buf[1] != ':')
328         {
329           newhomedrive = almost_null;
330           newhomepath = homepath_env_buf;
331         }
332       else
333         {
334           homedrive_env_buf[0] = homepath_env_buf[0];
335           homedrive_env_buf[1] = homepath_env_buf[1];
336           homedrive_env_buf[2] = '\0';
337           newhomedrive = homedrive_env_buf;
338           newhomepath = homepath_env_buf + 2;
339         }
340     }
341
342   if (newhomedrive && newhomedrive != homedrive)
343     cfree_and_set (homedrive, (newhomedrive == almost_null)
344                               ? almost_null : cstrdup (newhomedrive));
345
346   if (newhomepath && newhomepath != homepath)
347     cfree_and_set (homepath, cstrdup (newhomepath));
348
349   switch (what)
350     {
351     case CH_HOMEDRIVE:
352       return homedrive;
353     case CH_HOMEPATH:
354       return homepath;
355     default:
356       return homepath;
357     }
358 }
359
360 const char *
361 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
362 {
363   if (!what && !issetuid ())
364     what = getwinenveq (name, namelen, HEAP_STR);
365   return what;
366 }
367
368 const char *
369 cygheap_user::env_logsrv (const char *name, size_t namelen)
370 {
371   if (test_uid (plogsrv, name, namelen))
372     return plogsrv;
373
374   const char *mydomain = domain ();
375   const char *myname = winname ();
376   if (!mydomain || strcasematch (myname, "SYSTEM"))
377     return almost_null;
378
379   char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
380   cfree_and_set (plogsrv, almost_null);
381   if (get_logon_server (mydomain, logsrv, NULL))
382     plogsrv = cstrdup (logsrv);
383   return plogsrv;
384 }
385
386 const char *
387 cygheap_user::env_domain (const char *name, size_t namelen)
388 {
389   if (pwinname && test_uid (pdomain, name, namelen))
390     return pdomain;
391
392   char username[UNLEN + 1];
393   DWORD ulen = sizeof (username);
394   char userdomain[DNLEN + 1];
395   DWORD dlen = sizeof (userdomain);
396   SID_NAME_USE use;
397
398   cfree_and_set (pwinname, almost_null);
399   cfree_and_set (pdomain, almost_null);
400   if (!LookupAccountSid (NULL, sid (), username, &ulen,
401                          userdomain, &dlen, &use))
402     __seterrno ();
403   else
404     {
405       pwinname = cstrdup (username);
406       pdomain = cstrdup (userdomain);
407     }
408   return pdomain;
409 }
410
411 const char *
412 cygheap_user::env_userprofile (const char *name, size_t namelen)
413 {
414   if (test_uid (puserprof, name, namelen))
415     return puserprof;
416
417   char userprofile_env_buf[CYG_MAX_PATH];
418   char win_id[UNLEN + 1]; /* Large enough for SID */
419
420   cfree_and_set (puserprof, almost_null);
421   if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf))
422     puserprof = cstrdup (userprofile_env_buf);
423
424   return puserprof;
425 }
426
427 const char *
428 cygheap_user::env_homepath (const char *name, size_t namelen)
429 {
430   return ontherange (CH_HOMEPATH);
431 }
432
433 const char *
434 cygheap_user::env_homedrive (const char *name, size_t namelen)
435 {
436   return ontherange (CH_HOMEDRIVE);
437 }
438
439 const char *
440 cygheap_user::env_name (const char *name, size_t namelen)
441 {
442   if (!test_uid (pwinname, name, namelen))
443     (void) domain ();
444   return pwinname;
445 }
446
447 const char *
448 cygheap_user::env_systemroot (const char *name, size_t namelen)
449 {
450   if (!psystemroot)
451     {
452       int size = GetWindowsDirectory (NULL, 0);
453       if (size > 0)
454         {
455           psystemroot = (char *) cmalloc (HEAP_STR, ++size);
456           size = GetWindowsDirectory (psystemroot, size);
457           if (size <= 0)
458             {
459               cfree (psystemroot);
460               psystemroot = NULL;
461             }
462         }
463       if (size <= 0)
464         debug_printf ("GetWindowsDirectory(), %E");
465     }
466   return psystemroot;
467 }
468
469 char *
470 pwdgrp::next_str (char c)
471 {
472   char *res = lptr;
473   lptr = strechr (lptr, c);
474   if (*lptr)
475     *lptr++ = '\0';
476   return res;
477 }
478
479 bool
480 pwdgrp::next_num (unsigned long& n)
481 {
482   char *p = next_str (':');
483   char *cp;
484   n = strtoul (p, &cp, 10);
485   return p != cp && !*cp;
486 }
487
488 char *
489 pwdgrp::add_line (char *eptr)
490 {
491   if (eptr)
492     {
493       lptr = eptr;
494       eptr = strchr (lptr, '\n');
495       if (eptr)
496         {
497           if (eptr > lptr && eptr[-1] == '\r')
498             eptr[-1] = '\0';
499           else
500             *eptr = '\0';
501           eptr++;
502         }
503       if (curr_lines >= max_lines)
504         {
505           max_lines += 10;
506           *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
507         }
508       if ((this->*parse) ())
509         curr_lines++;
510     }
511   return eptr;
512 }
513
514 void
515 pwdgrp::load (const char *posix_fname)
516 {
517   const char *res;
518   static const char failed[] = "failed";
519   static const char succeeded[] = "succeeded";
520
521   if (buf)
522     free (buf);
523   buf = NULL;
524   curr_lines = 0;
525
526   pc.check (posix_fname);
527   etc_ix = etc::init (etc_ix, pc);
528
529   paranoid_printf ("%s", posix_fname);
530
531   if (pc.error || !pc.exists () || pc.isdir ())
532     {
533       paranoid_printf ("strange path_conv problem");
534       res = failed;
535     }
536   else
537     {
538       HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
539                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
540       if (fh == INVALID_HANDLE_VALUE)
541         {
542           paranoid_printf ("%s CreateFile failed, %E");
543           res = failed;
544         }
545       else
546         {
547           DWORD size = GetFileSize (fh, NULL), read_bytes;
548           buf = (char *) malloc (size + 1);
549           if (!ReadFile (fh, buf, size, &read_bytes, NULL))
550             {
551               paranoid_printf ("ReadFile failed, %E");
552               CloseHandle (fh);
553               if (buf)
554                 free (buf);
555               buf = NULL;
556               res = failed;
557             }
558           else
559             {
560               CloseHandle (fh);
561               buf[read_bytes] = '\0';
562               char *eptr = buf;
563               while ((eptr = add_line (eptr)))
564                 continue;
565               debug_printf ("%s curr_lines %d", posix_fname, curr_lines);
566               res = succeeded;
567             }
568         }
569     }
570
571   debug_printf ("%s load %s", posix_fname, res);
572   initialized = true;
573   return;
574 }