OSDN Git Service

Add "path.h" include throughout, where needed. Use new path_conv methods and
[pf3gnuchains/sourceware.git] / winsup / cygwin / uinfo.cc
1 /* uinfo.cc: user info (uid, gid, etc...)
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001 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 "sync.h"
22 #include "sigproc.h"
23 #include "pinfo.h"
24 #include "security.h"
25 #include "fhandler.h"
26 #include "path.h"
27 #include "dtable.h"
28 #include "cygheap.h"
29 #include "registry.h"
30
31 struct passwd *
32 internal_getlogin (cygheap_user &user)
33 {
34   char username[UNLEN + 1];
35   DWORD username_len = UNLEN + 1;
36   struct passwd *pw = NULL;
37
38   if (!GetUserName (username, &username_len))
39     user.set_name ("unknown");
40   else
41     user.set_name (username);
42   debug_printf ("GetUserName() = %s", user.name ());
43
44   if (wincap.has_security ())
45     {
46       LPWKSTA_USER_INFO_1 wui;
47       NET_API_STATUS ret;
48       char buf[512];
49       char *env;
50
51       user.set_logsrv (NULL);
52       /* First trying to get logon info from environment */
53       if ((env = getenv ("USERNAME")) != NULL)
54         user.set_name (env);
55       if ((env = getenv ("USERDOMAIN")) != NULL)
56         user.set_domain (env);
57       if ((env = getenv ("LOGONSERVER")) != NULL)
58         user.set_logsrv (env + 2); /* filter leading double backslashes */
59       if (user.name () && user.domain ())
60         debug_printf ("User: %s, Domain: %s, Logon Server: %s",
61                       user.name (), user.domain (), user.logsrv ());
62       else if (!(ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)))
63         {
64           sys_wcstombs (buf, wui->wkui1_username, UNLEN + 1);
65           user.set_name (buf);
66           sys_wcstombs (buf, wui->wkui1_logon_server,
67                         INTERNET_MAX_HOST_NAME_LENGTH + 1);
68           user.set_logsrv (buf);
69           sys_wcstombs (buf, wui->wkui1_logon_domain,
70                         INTERNET_MAX_HOST_NAME_LENGTH + 1);
71           user.set_domain (buf);
72           NetApiBufferFree (wui);
73         }
74       if (!user.logsrv () && get_logon_server_and_user_domain (buf, NULL))
75         {
76           user.set_logsrv (buf + 2);
77           setenv ("LOGONSERVER", buf, 1);
78         }
79       LPUSER_INFO_3 ui = NULL;
80       WCHAR wuser[UNLEN + 1];
81       WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
82
83       /* HOMEDRIVE and HOMEPATH are wrong most of the time, too,
84          after changing user context! */
85       sys_mbstowcs (wuser, user.name (), UNLEN + 1);
86       wlogsrv[0] = '\0';
87       if (user.logsrv ())
88         {
89           strcat (strcpy (buf, "\\\\"), user.logsrv ());
90           sys_mbstowcs (wlogsrv, buf, INTERNET_MAX_HOST_NAME_LENGTH + 3);
91         }
92       if (!NetUserGetInfo (NULL, wuser, 3, (LPBYTE *)&ui)
93           || (wlogsrv[0] && !NetUserGetInfo (wlogsrv, wuser, 3,(LPBYTE *)&ui)))
94         {
95           sys_wcstombs (buf, ui->usri3_home_dir, MAX_PATH);
96           if (!buf[0])
97             {
98               sys_wcstombs (buf, ui->usri3_home_dir_drive, MAX_PATH);
99               if (buf[0])
100                 strcat (buf, "\\");
101               else
102                 {
103                   env = getenv ("SYSTEMDRIVE");
104                   if (env && *env)
105                     strcat (strcpy (buf, env), "\\");
106                   else
107                     GetSystemDirectoryA (buf, MAX_PATH);
108                 }
109             }
110           setenv ("HOMEPATH", buf + 2, 1);
111           buf[2] = '\0';
112           setenv ("HOMEDRIVE", buf, 1);
113           NetApiBufferFree (ui);
114         }
115       debug_printf ("Domain: %s, Logon Server: %s, Windows Username: %s",
116                     user.domain (), user.logsrv (), user.name ());
117
118       if (allow_ntsec)
119         {
120           HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no
121                                        impersonation took place. */
122           DWORD siz;
123           cygsid tu;
124           int ret = 0;
125
126           /* Try to get the SID either from already impersonated token
127              or from current process first. To differ that two cases is
128              important, because you can't rely on the user information
129              in a process token of a currently impersonated process. */
130           if (ptok == INVALID_HANDLE_VALUE
131               && !OpenProcessToken (GetCurrentProcess (),
132                                     TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
133                                     &ptok))
134             debug_printf ("OpenProcessToken(): %E\n");
135           else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
136             debug_printf ("GetTokenInformation(): %E");
137           else if (!(ret = user.set_sid (tu)))
138             debug_printf ("Couldn't retrieve SID from access token!");
139           /* If that failes, try to get the SID from localhost. This can only
140              be done if a domain is given because there's a chance that a local
141              and a domain user may have the same name. */
142           if (!ret && user.domain ())
143             {
144               /* Concat DOMAIN\USERNAME for the next lookup */
145               strcat (strcat (strcpy (buf, user.domain ()), "\\"), user.name ());
146               if (!(ret = lookup_name (buf, NULL, user.sid ())))
147                 debug_printf ("Couldn't retrieve SID locally!");
148             }
149
150           /* If that fails, too, as a last resort try to get the SID from
151              the logon server. */
152           if (!ret && !(ret = lookup_name (user.name (), user.logsrv (),
153                                            user.sid ())))
154             debug_printf ("Couldn't retrieve SID from '%s'!", user.logsrv ());
155
156           /* If we have a SID, try to get the corresponding Cygwin user name
157              which can be different from the Windows user name. */
158           cygsid gsid (NO_SID);
159           if (ret)
160             {
161               cygsid psid;
162
163               for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
164                 if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
165                   {
166                     user.set_name (pw->pw_name);
167                     struct group *gr = getgrgid (pw->pw_gid);
168                     if (gr)
169                       if (!gsid.getfromgr (gr))
170                           gsid = NO_SID;
171                     break;
172                   }
173               if (!strcasematch (user.name (), "SYSTEM")
174                   && user.domain () && user.logsrv ())
175                 {
176                   if (get_registry_hive_path (user.sid (), buf))
177                     setenv ("USERPROFILE", buf, 1);
178                   else
179                     unsetenv ("USERPROFILE");
180                 }
181             }
182
183           /* If this process is started from a non Cygwin process,
184              set token owner to the same value as token user and
185              primary group to the group which is set as primary group
186              in /etc/passwd. */
187           if (ptok != INVALID_HANDLE_VALUE && myself->ppid == 1)
188             {
189               if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
190                 debug_printf ("SetTokenInformation(TokenOwner): %E");
191               if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup,
192                                                 &gsid, sizeof gsid))
193                 debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
194             }
195
196           /* Close token only if it's a result from OpenProcessToken(). */
197           if (ptok != INVALID_HANDLE_VALUE
198               && user.token == INVALID_HANDLE_VALUE)
199             CloseHandle (ptok);
200         }
201     }
202   debug_printf ("Cygwins Username: %s", user.name ());
203   return pw ?: getpwnam(user.name ());
204 }
205
206 void
207 uinfo_init ()
208 {
209   struct passwd *p;
210
211   /* Initialize to non impersonated values.
212      Setting `impersonated' to TRUE seems to be wrong but it
213      isn't. Impersonated is thought as "Current User and `token'
214      are coincident". See seteuid() for the mechanism behind that. */
215   if (cygheap->user.token != INVALID_HANDLE_VALUE)
216     CloseHandle (cygheap->user.token);
217   cygheap->user.token = INVALID_HANDLE_VALUE;
218   cygheap->user.impersonated = TRUE;
219
220   /* If uid is USHRT_MAX, the process is started from a non cygwin
221      process or the user context was changed in spawn.cc */
222   if (myself->uid == USHRT_MAX)
223     if ((p = internal_getlogin (cygheap->user)) != NULL)
224       {
225         myself->uid = p->pw_uid;
226         /* Set primary group only if ntsec is off or the process has been
227            started from a non cygwin process. */
228         if (!allow_ntsec || myself->ppid == 1)
229           myself->gid = p->pw_gid;
230       }
231     else
232       {
233         myself->uid = DEFAULT_UID;
234         myself->gid = DEFAULT_GID;
235       }
236   /* Real and effective uid/gid are always identical on process start up.
237      This is at least true for NT/W2K. */
238   cygheap->user.orig_uid = cygheap->user.real_uid = myself->uid;
239   cygheap->user.orig_gid = cygheap->user.real_gid = myself->gid;
240 }
241
242 extern "C" char *
243 getlogin (void)
244 {
245 #ifdef _MT_SAFE
246   char *this_username=_reent_winsup ()->_username;
247 #else
248   static NO_COPY char this_username[UNLEN + 1];
249 #endif
250
251   return strcpy (this_username, cygheap->user.name ());
252 }
253
254 extern "C" uid_t
255 getuid (void)
256 {
257   return cygheap->user.real_uid;
258 }
259
260 extern "C" gid_t
261 getgid (void)
262 {
263   return cygheap->user.real_gid;
264 }
265
266 extern "C" uid_t
267 geteuid (void)
268 {
269   return myself->uid;
270 }
271
272 extern "C" gid_t
273 getegid (void)
274 {
275   return myself->gid;
276 }
277
278 /* Not quite right - cuserid can change, getlogin can't */
279 extern "C" char *
280 cuserid (char *src)
281 {
282   if (src)
283     {
284       strcpy (src, getlogin ());
285       return src;
286     }
287   else
288     {
289       return getlogin ();
290     }
291 }