OSDN Git Service

* uinfo.cc (pwdgrp::load): Regularize strace output. Add warning for
[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 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 <errno.h>
21 #include <sys/cygwin.h>
22 #include "pinfo.h"
23 #include "security.h"
24 #include "fhandler.h"
25 #include "path.h"
26 #include "dtable.h"
27 #include "cygerrno.h"
28 #include "cygheap.h"
29 #include "registry.h"
30 #include "child_info.h"
31 #include "environ.h"
32 #include "pwdgrp.h"
33
34 void
35 internal_getlogin (cygheap_user &user)
36 {
37   struct passwd *pw = NULL;
38   HANDLE ptok = INVALID_HANDLE_VALUE;
39
40   myself->gid = DEFAULT_GID;
41   if (wincap.has_security ())
42     {
43       DWORD siz;
44       cygsid tu;
45       DWORD ret = 0;
46
47       /* Try to get the SID either from current process and
48          store it in user.psid */
49       if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
50                              &ptok))
51         system_printf ("OpenProcessToken(): %E");
52       else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
53         system_printf ("GetTokenInformation (TokenUser): %E");
54       else if (!(ret = user.set_sid (tu)))
55         system_printf ("Couldn't retrieve SID from access token!");
56       else if (!GetTokenInformation (ptok, TokenPrimaryGroup,
57                                      &user.groups.pgsid, sizeof tu, &siz))
58         system_printf ("GetTokenInformation (TokenPrimaryGroup): %E");
59        /* We must set the user name, uid and gid.
60          If we have a SID, try to get the corresponding Cygwin
61          password entry. Set user name which can be different
62          from the Windows user name */
63       if (ret)
64         {
65           pw = internal_getpwsid (tu);
66           /* Set token owner to the same value as token user */
67           if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
68             debug_printf ("SetTokenInformation(TokenOwner): %E");
69          }
70     }
71
72   if (!pw && !(pw = internal_getpwnam (user.name ()))
73       && !(pw = internal_getpwuid (DEFAULT_UID)))
74     debug_printf("user not found in augmented /etc/passwd");
75   else
76     {
77       myself->uid = pw->pw_uid;
78       myself->gid = pw->pw_gid;
79       user.set_name (pw->pw_name);
80       if (wincap.has_security ())
81         {
82           cygsid gsid;
83           if (gsid.getfromgr (internal_getgrgid (pw->pw_gid)))
84             {
85               /* Set primary group to the group in /etc/passwd. */
86               user.groups.pgsid = gsid;
87               if (!SetTokenInformation (ptok, TokenPrimaryGroup,
88                                         &gsid, sizeof gsid))
89                 debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
90             }
91           else
92             debug_printf ("gsid not found in augmented /etc/group");
93         }
94     }
95   if (ptok != INVALID_HANDLE_VALUE)
96     CloseHandle (ptok);
97   (void) cygheap->user.ontherange (CH_HOME, pw);
98
99   return;
100 }
101
102 void
103 uinfo_init ()
104 {
105   if (!child_proc_info || cygheap->user.token != INVALID_HANDLE_VALUE)
106     {
107       if (!child_proc_info)
108         internal_getlogin (cygheap->user); /* Set the cygheap->user. */
109       else
110         CloseHandle (cygheap->user.token);
111       cygheap->user.set_orig_sid ();    /* Update the original sid */
112       cygheap->user.token = INVALID_HANDLE_VALUE; /* No token present */
113     }
114   /* Real and effective uid/gid are identical on process start up. */
115   cygheap->user.orig_uid = cygheap->user.real_uid = myself->uid;
116   cygheap->user.orig_gid = cygheap->user.real_gid = myself->gid;
117 }
118
119 extern "C" char *
120 getlogin (void)
121 {
122 #ifdef _MT_SAFE
123   char *this_username=_reent_winsup ()->_username;
124 #else
125   static char this_username[UNLEN + 1] NO_COPY;
126 #endif
127
128   return strcpy (this_username, cygheap->user.name ());
129 }
130
131 extern "C" __uid32_t
132 getuid32 (void)
133 {
134   return cygheap->user.real_uid;
135 }
136
137 extern "C" __uid16_t
138 getuid (void)
139 {
140   return cygheap->user.real_uid;
141 }
142
143 extern "C" __gid32_t
144 getgid32 (void)
145 {
146   return cygheap->user.real_gid;
147 }
148
149 extern "C" __gid16_t
150 getgid (void)
151 {
152   return cygheap->user.real_gid;
153 }
154
155 extern "C" __uid32_t
156 geteuid32 (void)
157 {
158   return myself->uid;
159 }
160
161 extern "C" __uid16_t
162 geteuid (void)
163 {
164   return myself->uid;
165 }
166
167 extern "C" __gid32_t
168 getegid32 (void)
169 {
170   return myself->gid;
171 }
172
173 extern "C" __gid16_t
174 getegid (void)
175 {
176   return myself->gid;
177 }
178
179 /* Not quite right - cuserid can change, getlogin can't */
180 extern "C" char *
181 cuserid (char *src)
182 {
183   if (!src)
184     return getlogin ();
185
186   strcpy (src, getlogin ());
187   return src;
188 }
189
190 const char *
191 cygheap_user::ontherange (homebodies what, struct passwd *pw)
192 {
193   LPUSER_INFO_3 ui = NULL;
194   WCHAR wuser[UNLEN + 1];
195   NET_API_STATUS ret;
196   char homepath_env_buf[MAX_PATH + 1];
197   char homedrive_env_buf[3];
198   char *newhomedrive = NULL;
199   char *newhomepath = NULL;
200
201
202   debug_printf ("what %d, pw %p", what, pw);
203   if (what == CH_HOME)
204     {
205       char *p;
206       if (homedrive)
207         newhomedrive = homedrive;
208       else if ((p = getenv ("HOMEDRIVE")))
209         newhomedrive = p;
210
211       if (homepath)
212         newhomepath = homepath;
213       else if ((p = getenv ("HOMEPATH")))
214         newhomepath = p;
215
216       if ((p = getenv ("HOME")))
217         debug_printf ("HOME is already in the environment %s", p);
218       else
219         {
220           if (pw && pw->pw_dir && *pw->pw_dir)
221             {
222               debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
223               setenv ("HOME", pw->pw_dir, 1);
224             }
225           else if (!newhomedrive || !newhomepath)
226             setenv ("HOME", "/", 1);
227           else
228             {
229               char home[MAX_PATH];
230               char buf[MAX_PATH + 1];
231               strcpy (buf, newhomedrive);
232               strcat (buf, newhomepath);
233               cygwin_conv_to_full_posix_path (buf, home);
234               debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home);
235               setenv ("HOME", home, 1);
236             }
237         }
238     }
239
240   if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
241     {
242       if (!pw)
243         pw = internal_getpwnam (name ());
244       if (pw && pw->pw_dir && *pw->pw_dir)
245         cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf);
246       else
247         {
248           homepath_env_buf[0] = homepath_env_buf[1] = '\0';
249           if (logsrv ())
250             {
251               WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
252               sys_mbstowcs (wlogsrv, logsrv (),
253                             sizeof (wlogsrv) / sizeof (*wlogsrv));
254              sys_mbstowcs (wuser, winname (), sizeof (wuser) / sizeof (*wuser));
255               if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3,(LPBYTE *)&ui)))
256                 {
257                   sys_wcstombs (homepath_env_buf, ui->usri3_home_dir, MAX_PATH);
258                   if (!homepath_env_buf[0])
259                     {
260                       sys_wcstombs (homepath_env_buf, ui->usri3_home_dir_drive,
261                                     MAX_PATH);
262                       if (homepath_env_buf[0])
263                         strcat (homepath_env_buf, "\\");
264                       else
265                         cygwin_conv_to_full_win32_path ("/", homepath_env_buf);
266                     }
267                 }
268             }
269           if (ui)
270             NetApiBufferFree (ui);
271         }
272
273       if (homepath_env_buf[1] != ':')
274         {
275           newhomedrive = almost_null;
276           newhomepath = homepath_env_buf;
277         }
278       else
279         {
280           homedrive_env_buf[0] = homepath_env_buf[0];
281           homedrive_env_buf[1] = homepath_env_buf[1];
282           homedrive_env_buf[2] = '\0';
283           newhomedrive = homedrive_env_buf;
284           newhomepath = homepath_env_buf + 2;
285         }
286     }
287
288   if (newhomedrive && newhomedrive != homedrive)
289     cfree_and_set (homedrive, (newhomedrive == almost_null)
290                               ? almost_null : cstrdup (newhomedrive));
291
292   if (newhomepath && newhomepath != homepath)
293     cfree_and_set (homepath, cstrdup (newhomepath));
294
295   switch (what)
296     {
297     case CH_HOMEDRIVE:
298       return homedrive;
299     case CH_HOMEPATH:
300       return homepath;
301     default:
302       return homepath;
303     }
304 }
305
306 const char *
307 cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
308 {
309   if (!what && !issetuid ())
310     what = getwinenveq (name, namelen, HEAP_STR);
311   return what;
312 }
313
314 const char *
315 cygheap_user::env_logsrv (const char *name, size_t namelen)
316 {
317   if (test_uid (plogsrv, name, namelen))
318     return plogsrv;
319
320   const char *mydomain = domain ();
321   const char *myname = winname ();
322   if (!mydomain || strcasematch (myname, "SYSTEM"))
323     return almost_null;
324
325   char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
326   cfree_and_set (plogsrv, almost_null);
327   if (get_logon_server (mydomain, logsrv, NULL))
328     plogsrv = cstrdup (logsrv);
329   return plogsrv;
330 }
331
332 const char *
333 cygheap_user::env_domain (const char *name, size_t namelen)
334 {
335   if (pwinname && test_uid (pdomain, name, namelen))
336     return pdomain;
337
338   char username[UNLEN + 1];
339   DWORD ulen = sizeof (username);
340   char userdomain[DNLEN + 1];
341   DWORD dlen = sizeof (userdomain);
342   SID_NAME_USE use;
343
344   cfree_and_set (pwinname, almost_null);
345   cfree_and_set (pdomain, almost_null);
346   if (!LookupAccountSid (NULL, sid (), username, &ulen,
347                          userdomain, &dlen, &use))
348     __seterrno ();
349   else
350     {
351       pwinname = cstrdup (username);
352       pdomain = cstrdup (userdomain);
353     }
354   return pdomain;
355 }
356
357 const char *
358 cygheap_user::env_userprofile (const char *name, size_t namelen)
359 {
360   if (test_uid (puserprof, name, namelen))
361     return puserprof;
362
363   char userprofile_env_buf[MAX_PATH + 1];
364   cfree_and_set (puserprof, almost_null);
365   /* FIXME: Should this just be setting a puserprofile like everything else? */
366   const char *myname = winname ();
367   if (myname && strcasematch (myname, "SYSTEM")
368       && get_registry_hive_path (sid (), userprofile_env_buf))
369     puserprof = cstrdup (userprofile_env_buf);
370
371   return puserprof;
372 }
373
374 const char *
375 cygheap_user::env_homepath (const char *name, size_t namelen)
376 {
377   return ontherange (CH_HOMEPATH);
378 }
379
380 const char *
381 cygheap_user::env_homedrive (const char *name, size_t namelen)
382 {
383   return ontherange (CH_HOMEDRIVE);
384 }
385
386 const char *
387 cygheap_user::env_name (const char *name, size_t namelen)
388 {
389   if (!test_uid (pwinname, name, namelen))
390     (void) domain ();
391   return pwinname;
392 }
393
394 char *
395 pwdgrp::next_str (char c)
396 {
397   if (!lptr)
398     return NULL;
399   char search[] = ":\n\0\0";
400   search[2] = c;
401   char *res = lptr;
402   char *p = strpbrk (lptr, search);
403   if (p)
404     {
405       lptr = (*p == '\n') ? p : p + 1;
406       *p = '\0';
407     }
408   return res;
409 }
410
411 bool
412 pwdgrp::next_num (unsigned long& n)
413 {
414   char *p = next_str ();
415   if (!p)
416     return -1;
417   char *cp;
418   n = strtoul (p, &cp, 10);
419   return p != cp && !*cp;
420 }
421
422 char *
423 pwdgrp::add_line (char *eptr)
424 {
425   if (eptr)
426     {
427       lptr = eptr;
428       eptr = strchr (lptr, '\n');
429       if (eptr)
430         {
431           if (eptr > lptr && eptr[-1] == '\r')
432             eptr[-1] = '\n';
433           eptr++;
434         }
435       if (curr_lines >= max_lines)
436         {
437           max_lines += 10;
438           *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
439         }
440       if ((this->*parse) ())
441         curr_lines++;
442     }
443   return eptr;
444 }
445
446 void
447 pwdgrp::load (const char *posix_fname)
448 {
449   const char *res;
450   static const char failed[] = "failed";
451   static const char succeeded[] = "succeeded";
452
453   if (buf)
454     free (buf);
455   buf = NULL;
456
457   pc.check (posix_fname);
458   etc_ix = etc::init (etc_ix, pc);
459
460   paranoid_printf ("%s", posix_fname);
461
462   if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
463     {
464       paranoid_printf ("strange path_conv problem");
465       res = failed;
466     }
467   else
468     {
469       HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
470                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
471       if (fh == INVALID_HANDLE_VALUE)
472         {
473           paranoid_printf ("%s CreateFile failed, %E");
474           res = failed;
475         }
476       else
477         {
478           DWORD size = GetFileSize (fh, NULL), read_bytes;
479           buf = (char *) malloc (size + 1);
480           if (!ReadFile (fh, buf, size, &read_bytes, NULL))
481             {
482               paranoid_printf ("ReadFile failed, %E");
483               CloseHandle (fh);
484               if (buf)
485                 free (buf);
486               buf = NULL;
487               res = failed;
488             }
489           else
490             {
491               CloseHandle (fh);
492               buf[read_bytes] = '\0';
493               char *eptr = buf;
494               curr_lines = 0;
495               while ((eptr = add_line (eptr)))
496                 continue;
497               debug_printf ("%s curr_lines %d", posix_fname, curr_lines);
498               res = succeeded;
499             }
500         }
501     }
502
503   debug_printf ("%s load %s", posix_fname, res);
504   initialized = true;
505   return;
506 }