]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* uinfo.cc: user info (uid, gid, etc...) |
2 | ||
bc837d22 CF |
3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
4 | 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. | |
1fd5e000 CF |
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 | ||
1fd5e000 | 12 | #include "winsup.h" |
84c7d409 | 13 | #include <unistd.h> |
17db1105 | 14 | #include <wininet.h> |
1fd5e000 | 15 | #include <stdlib.h> |
520fcc97 | 16 | #include <wchar.h> |
1fd5e000 | 17 | #include <lm.h> |
9a512577 | 18 | #include <iptypes.h> |
eb79d041 | 19 | #include <sys/cygwin.h> |
169c465a | 20 | #include "cygerrno.h" |
e2ebe117 | 21 | #include "pinfo.h" |
47063f00 | 22 | #include "path.h" |
7ac61736 | 23 | #include "fhandler.h" |
0381fec6 | 24 | #include "dtable.h" |
1f0f8e12 | 25 | #include "cygheap.h" |
520fcc97 | 26 | #include "shared_info.h" |
f0338f54 | 27 | #include "registry.h" |
9a771b29 | 28 | #include "child_info.h" |
094d5193 | 29 | #include "environ.h" |
d6ffc075 | 30 | #include "pwdgrp.h" |
edab6053 | 31 | #include "tls_pbuf.h" |
5f9c8e2a | 32 | #include "ntdll.h" |
1fd5e000 | 33 | |
0efafbfb CF |
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 */ | |
9a771b29 | 37 | void |
9a4d574b | 38 | cygheap_user::init () |
1fd5e000 | 39 | { |
ebdc75d9 | 40 | WCHAR user_name[UNLEN + 1]; |
2a9b4b7a | 41 | DWORD user_name_len = UNLEN + 1; |
0efafbfb | 42 | |
3f74d8d5 CV |
43 | /* This code is only run if a Cygwin process gets started by a native |
44 | Win32 process. We try to get the username from the environment, | |
45 | first USERNAME (Win32), then USER (POSIX). If that fails (which is | |
46 | very unlikely), it only has an impact if we don't have an entry in | |
47 | /etc/passwd for this user either. In that case the username sticks | |
48 | to "unknown". Since this is called early in initialization, and | |
49 | since we don't want pull in a dependency to any other DLL except | |
50 | ntdll and kernel32 at this early stage, don't call GetUserName, | |
51 | GetUserNameEx, NetWkstaUserGetInfo, etc. */ | |
52 | if (GetEnvironmentVariableW (L"USERNAME", user_name, user_name_len) | |
53 | || GetEnvironmentVariableW (L"USER", user_name, user_name_len)) | |
54 | { | |
55 | char mb_user_name[user_name_len = sys_wcstombs (NULL, 0, user_name)]; | |
56 | sys_wcstombs (mb_user_name, user_name_len, user_name); | |
57 | set_name (mb_user_name); | |
58 | } | |
59 | else | |
60 | set_name ("unknown"); | |
1f0f8e12 | 61 | |
12eac211 CV |
62 | NTSTATUS status; |
63 | ULONG size; | |
043878df | 64 | PSECURITY_DESCRIPTOR psd; |
6806a8b5 | 65 | |
12eac211 CV |
66 | status = NtQueryInformationToken (hProcToken, TokenPrimaryGroup, |
67 | &groups.pgsid, sizeof (cygsid), &size); | |
68 | if (!NT_SUCCESS (status)) | |
69 | system_printf ("NtQueryInformationToken (TokenPrimaryGroup), %p", status); | |
6806a8b5 PH |
70 | |
71 | /* Get the SID from current process and store it in effec_cygsid */ | |
12eac211 CV |
72 | status = NtQueryInformationToken (hProcToken, TokenUser, &effec_cygsid, |
73 | sizeof (cygsid), &size); | |
74 | if (!NT_SUCCESS (status)) | |
6806a8b5 | 75 | { |
12eac211 | 76 | system_printf ("NtQueryInformationToken (TokenUser), %p", status); |
f4a1f8a1 | 77 | return; |
6806a8b5 PH |
78 | } |
79 | ||
80 | /* Set token owner to the same value as token user */ | |
12eac211 CV |
81 | status = NtSetInformationToken (hProcToken, TokenOwner, &effec_cygsid, |
82 | sizeof (cygsid)); | |
83 | if (!NT_SUCCESS (status)) | |
84 | debug_printf ("NtSetInformationToken(TokenOwner), %p", status); | |
6806a8b5 | 85 | |
043878df | 86 | /* Standard way to build a security descriptor with the usual DACL */ |
7311cc1f | 87 | PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024); |
f4a1f8a1 | 88 | psd = (PSECURITY_DESCRIPTOR) |
b86f999a | 89 | (sec_user_nih (sa_buf, sid()))->lpSecurityDescriptor; |
6806a8b5 | 90 | |
1838d97b | 91 | BOOLEAN acl_exists, dummy; |
043878df | 92 | TOKEN_DEFAULT_DACL dacl; |
1838d97b CV |
93 | |
94 | status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &dacl.DefaultDacl, | |
95 | &dummy); | |
96 | if (NT_SUCCESS (status) && acl_exists && dacl.DefaultDacl) | |
043878df | 97 | { |
5f9c8e2a | 98 | |
043878df | 99 | /* Set the default DACL and the process DACL */ |
12eac211 CV |
100 | status = NtSetInformationToken (hProcToken, TokenDefaultDacl, &dacl, |
101 | sizeof (dacl)); | |
102 | if (!NT_SUCCESS (status)) | |
103 | system_printf ("NtSetInformationToken (TokenDefaultDacl), %p", status); | |
f16706de CV |
104 | if ((status = NtSetSecurityObject (NtCurrentProcess (), |
105 | DACL_SECURITY_INFORMATION, psd))) | |
5f9c8e2a | 106 | system_printf ("NtSetSecurityObject, %lx", status); |
0efafbfb | 107 | } |
043878df | 108 | else |
0cd9f74f | 109 | system_printf("Cannot get dacl, %E"); |
0efafbfb CF |
110 | } |
111 | ||
112 | void | |
113 | internal_getlogin (cygheap_user &user) | |
114 | { | |
115 | struct passwd *pw = NULL; | |
116 | ||
2a9b4b7a CV |
117 | cygpsid psid = user.sid (); |
118 | pw = internal_getpwsid (psid); | |
39b553b8 | 119 | |
2a9b4b7a | 120 | if (!pw && !(pw = internal_getpwnam (user.name ())) |
d6ffc075 | 121 | && !(pw = internal_getpwuid (DEFAULT_UID))) |
9a4d574b | 122 | debug_printf ("user not found in augmented /etc/passwd"); |
647b92a7 | 123 | else |
9a771b29 | 124 | { |
a76877e9 CV |
125 | cygsid gsid; |
126 | ||
1fd072b6 CV |
127 | myself->uid = pw->pw_uid; |
128 | myself->gid = pw->pw_gid; | |
efcaf042 | 129 | user.set_name (pw->pw_name); |
a76877e9 | 130 | if (gsid.getfromgr (internal_getgrgid (pw->pw_gid))) |
eb6d2e2f | 131 | { |
a76877e9 | 132 | if (gsid != user.groups.pgsid) |
647b92a7 | 133 | { |
a76877e9 | 134 | /* Set primary group to the group in /etc/passwd. */ |
12eac211 CV |
135 | NTSTATUS status = NtSetInformationToken (hProcToken, |
136 | TokenPrimaryGroup, | |
137 | &gsid, sizeof gsid); | |
138 | if (!NT_SUCCESS (status)) | |
139 | debug_printf ("NtSetInformationToken (TokenPrimaryGroup), %p", | |
140 | status); | |
a76877e9 CV |
141 | else |
142 | user.groups.pgsid = gsid; | |
143 | clear_procimptoken (); | |
647b92a7 | 144 | } |
647b92a7 | 145 | } |
a76877e9 CV |
146 | else |
147 | debug_printf ("gsid not found in augmented /etc/group"); | |
9a771b29 | 148 | } |
0c55f6ed | 149 | cygheap->user.ontherange (CH_HOME, pw); |
1fd5e000 CF |
150 | } |
151 | ||
152 | void | |
153 | uinfo_init () | |
154 | { | |
70249d56 | 155 | if (child_proc_info && !cygheap->user.has_impersonation_tokens ()) |
271c1935 CV |
156 | return; |
157 | ||
158 | if (!child_proc_info) | |
159 | internal_getlogin (cygheap->user); /* Set the cygheap->user. */ | |
160 | /* Conditions must match those in spawn to allow starting child | |
161 | processes with ruid != euid and rgid != egid. */ | |
162 | else if (cygheap->user.issetuid () | |
e3778517 | 163 | && cygheap->user.saved_uid == cygheap->user.real_uid |
1498189c | 164 | && cygheap->user.saved_gid == cygheap->user.real_gid |
0191627a CV |
165 | && !cygheap->user.groups.issetgroups () |
166 | && !cygheap->user.setuid_to_restricted) | |
4f7e12dd | 167 | { |
70249d56 | 168 | cygheap->user.reimpersonate (); |
271c1935 | 169 | return; |
4f7e12dd | 170 | } |
271c1935 | 171 | else |
70249d56 | 172 | cygheap->user.close_impersonation_tokens (); |
271c1935 | 173 | |
1498189c CV |
174 | cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid; |
175 | cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid; | |
53197923 PH |
176 | cygheap->user.external_token = NO_IMPERSONATION; |
177 | cygheap->user.internal_token = NO_IMPERSONATION; | |
f4a1f8a1 | 178 | cygheap->user.curr_primary_token = NO_IMPERSONATION; |
77ee8805 | 179 | cygheap->user.curr_imp_token = NO_IMPERSONATION; |
0191627a CV |
180 | cygheap->user.ext_token_is_restricted = false; |
181 | cygheap->user.curr_token_is_restricted = false; | |
182 | cygheap->user.setuid_to_restricted = false; | |
1498189c | 183 | cygheap->user.set_saved_sid (); /* Update the original sid */ |
a6f3658d | 184 | cygheap->user.deimpersonate (); |
1fd5e000 CF |
185 | } |
186 | ||
68509b30 CV |
187 | extern "C" int |
188 | getlogin_r (char *name, size_t namesize) | |
189 | { | |
553f0805 | 190 | const char *login = cygheap->user.name (); |
68509b30 CV |
191 | size_t len = strlen (login) + 1; |
192 | if (len > namesize) | |
193 | return ERANGE; | |
893ac8e0 CF |
194 | myfault efault; |
195 | if (efault.faulted ()) | |
196 | return EFAULT; | |
68509b30 CV |
197 | strncpy (name, login, len); |
198 | return 0; | |
199 | } | |
200 | ||
1fd5e000 CF |
201 | extern "C" char * |
202 | getlogin (void) | |
203 | { | |
553f0805 CV |
204 | static char username[UNLEN]; |
205 | int ret = getlogin_r (username, UNLEN); | |
206 | if (ret) | |
207 | { | |
208 | set_errno (ret); | |
209 | return NULL; | |
210 | } | |
211 | return username; | |
1fd5e000 CF |
212 | } |
213 | ||
a8d7ae61 CV |
214 | extern "C" __uid32_t |
215 | getuid32 (void) | |
216 | { | |
217 | return cygheap->user.real_uid; | |
218 | } | |
219 | ||
de4e0d30 | 220 | extern "C" __uid16_t |
1fd5e000 CF |
221 | getuid (void) |
222 | { | |
1f0f8e12 | 223 | return cygheap->user.real_uid; |
1fd5e000 CF |
224 | } |
225 | ||
57196405 CV |
226 | extern "C" __gid32_t |
227 | getgid32 (void) | |
228 | { | |
229 | return cygheap->user.real_gid; | |
230 | } | |
231 | ||
de4e0d30 | 232 | extern "C" __gid16_t |
1fd5e000 CF |
233 | getgid (void) |
234 | { | |
1f0f8e12 | 235 | return cygheap->user.real_gid; |
1fd5e000 CF |
236 | } |
237 | ||
a8d7ae61 CV |
238 | extern "C" __uid32_t |
239 | geteuid32 (void) | |
240 | { | |
241 | return myself->uid; | |
242 | } | |
243 | ||
de4e0d30 | 244 | extern "C" __uid16_t |
1fd5e000 CF |
245 | geteuid (void) |
246 | { | |
64b30629 | 247 | return myself->uid; |
1fd5e000 CF |
248 | } |
249 | ||
57196405 CV |
250 | extern "C" __gid32_t |
251 | getegid32 (void) | |
252 | { | |
253 | return myself->gid; | |
254 | } | |
255 | ||
de4e0d30 | 256 | extern "C" __gid16_t |
1fd5e000 CF |
257 | getegid (void) |
258 | { | |
64b30629 | 259 | return myself->gid; |
1fd5e000 CF |
260 | } |
261 | ||
262 | /* Not quite right - cuserid can change, getlogin can't */ | |
263 | extern "C" char * | |
264 | cuserid (char *src) | |
265 | { | |
da086d02 CF |
266 | if (!src) |
267 | return getlogin (); | |
268 | ||
269 | strcpy (src, getlogin ()); | |
270 | return src; | |
271 | } | |
272 | ||
273 | const char * | |
274 | cygheap_user::ontherange (homebodies what, struct passwd *pw) | |
275 | { | |
da086d02 CF |
276 | LPUSER_INFO_3 ui = NULL; |
277 | WCHAR wuser[UNLEN + 1]; | |
278 | NET_API_STATUS ret; | |
179cae11 CF |
279 | char homedrive_env_buf[3]; |
280 | char *newhomedrive = NULL; | |
281 | char *newhomepath = NULL; | |
edab6053 | 282 | tmp_pathbuf tp; |
da086d02 | 283 | |
094d5193 | 284 | debug_printf ("what %d, pw %p", what, pw); |
da086d02 CF |
285 | if (what == CH_HOME) |
286 | { | |
287 | char *p; | |
5f25e1d1 | 288 | |
da086d02 CF |
289 | if ((p = getenv ("HOME"))) |
290 | debug_printf ("HOME is already in the environment %s", p); | |
291 | else | |
292 | { | |
da086d02 CF |
293 | if (pw && pw->pw_dir && *pw->pw_dir) |
294 | { | |
da086d02 | 295 | debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir); |
8297bda0 | 296 | setenv ("HOME", pw->pw_dir, 1); |
da086d02 | 297 | } |
8297bda0 | 298 | else |
da086d02 | 299 | { |
764d88e4 CV |
300 | char home[strlen (name ()) + 8]; |
301 | ||
302 | debug_printf ("Set HOME to default /home/USER"); | |
303 | __small_sprintf (home, "/home/%s", name ()); | |
8297bda0 | 304 | setenv ("HOME", home, 1); |
da086d02 CF |
305 | } |
306 | } | |
307 | } | |
308 | ||
094d5193 | 309 | if (what != CH_HOME && homepath == NULL && newhomepath == NULL) |
1fd5e000 | 310 | { |
edab6053 | 311 | char *homepath_env_buf = tp.c_get (); |
da086d02 | 312 | if (!pw) |
d6ffc075 | 313 | pw = internal_getpwnam (name ()); |
da086d02 | 314 | if (pw && pw->pw_dir && *pw->pw_dir) |
edab6053 CV |
315 | cygwin_conv_path (CCP_POSIX_TO_WIN_A, pw->pw_dir, homepath_env_buf, |
316 | NT_MAX_PATH); | |
da086d02 CF |
317 | else |
318 | { | |
179cae11 | 319 | homepath_env_buf[0] = homepath_env_buf[1] = '\0'; |
094d5193 | 320 | if (logsrv ()) |
da086d02 | 321 | { |
834224ab | 322 | WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3]; |
5ab0b5cf CV |
323 | sys_mbstowcs (wlogsrv, sizeof (wlogsrv) / sizeof (*wlogsrv), |
324 | logsrv ()); | |
325 | sys_mbstowcs (wuser, sizeof (wuser) / sizeof (*wuser), winname ()); | |
9a4d574b | 326 | if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui))) |
da086d02 | 327 | { |
edab6053 | 328 | sys_wcstombs (homepath_env_buf, NT_MAX_PATH, |
b86f999a | 329 | ui->usri3_home_dir); |
834224ab CV |
330 | if (!homepath_env_buf[0]) |
331 | { | |
edab6053 | 332 | sys_wcstombs (homepath_env_buf, NT_MAX_PATH, |
03a49a00 | 333 | ui->usri3_home_dir_drive); |
834224ab CV |
334 | if (homepath_env_buf[0]) |
335 | strcat (homepath_env_buf, "\\"); | |
db57a363 | 336 | else |
edab6053 CV |
337 | cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, |
338 | "/", homepath_env_buf, NT_MAX_PATH); | |
834224ab | 339 | } |
da086d02 CF |
340 | } |
341 | } | |
342 | if (ui) | |
343 | NetApiBufferFree (ui); | |
344 | } | |
345 | ||
a77d35f7 | 346 | if (homepath_env_buf[1] != ':') |
da086d02 | 347 | { |
179cae11 CF |
348 | newhomedrive = almost_null; |
349 | newhomepath = homepath_env_buf; | |
da086d02 CF |
350 | } |
351 | else | |
352 | { | |
a77d35f7 CF |
353 | homedrive_env_buf[0] = homepath_env_buf[0]; |
354 | homedrive_env_buf[1] = homepath_env_buf[1]; | |
179cae11 CF |
355 | homedrive_env_buf[2] = '\0'; |
356 | newhomedrive = homedrive_env_buf; | |
357 | newhomepath = homepath_env_buf + 2; | |
da086d02 | 358 | } |
1fd5e000 | 359 | } |
da086d02 | 360 | |
8297bda0 | 361 | if (newhomedrive && newhomedrive != homedrive) |
179cae11 | 362 | cfree_and_set (homedrive, (newhomedrive == almost_null) |
5bf785a0 | 363 | ? almost_null : cstrdup (newhomedrive)); |
179cae11 | 364 | |
8297bda0 | 365 | if (newhomepath && newhomepath != homepath) |
179cae11 CF |
366 | cfree_and_set (homepath, cstrdup (newhomepath)); |
367 | ||
da086d02 | 368 | switch (what) |
1fd5e000 | 369 | { |
da086d02 CF |
370 | case CH_HOMEDRIVE: |
371 | return homedrive; | |
372 | case CH_HOMEPATH: | |
373 | return homepath; | |
374 | default: | |
375 | return homepath; | |
1fd5e000 CF |
376 | } |
377 | } | |
da086d02 CF |
378 | |
379 | const char * | |
094d5193 | 380 | cygheap_user::test_uid (char *&what, const char *name, size_t namelen) |
da086d02 | 381 | { |
8297bda0 | 382 | if (!what && !issetuid ()) |
38bc1196 | 383 | what = getwinenveq (name, namelen, HEAP_STR); |
094d5193 CF |
384 | return what; |
385 | } | |
386 | ||
387 | const char * | |
388 | cygheap_user::env_logsrv (const char *name, size_t namelen) | |
389 | { | |
390 | if (test_uid (plogsrv, name, namelen)) | |
9a771b29 | 391 | return plogsrv; |
da086d02 | 392 | |
efc1575e CF |
393 | const char *mydomain = domain (); |
394 | const char *myname = winname (); | |
c69d873f | 395 | if (!mydomain || ascii_strcasematch (myname, "SYSTEM")) |
e97962b9 | 396 | return almost_null; |
5f25e1d1 | 397 | |
9a512577 | 398 | WCHAR wdomain[MAX_DOMAIN_NAME_LEN + 1]; |
5558de95 | 399 | WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3]; |
9a512577 | 400 | sys_mbstowcs (wdomain, MAX_DOMAIN_NAME_LEN + 1, mydomain); |
179cae11 | 401 | cfree_and_set (plogsrv, almost_null); |
5558de95 CV |
402 | if (get_logon_server (wdomain, wlogsrv, false)) |
403 | sys_wcstombs_alloc (&plogsrv, HEAP_STR, wlogsrv); | |
179cae11 | 404 | return plogsrv; |
9a771b29 CF |
405 | } |
406 | ||
407 | const char * | |
094d5193 | 408 | cygheap_user::env_domain (const char *name, size_t namelen) |
9a771b29 | 409 | { |
38bc1196 | 410 | if (pwinname && test_uid (pdomain, name, namelen)) |
9a771b29 CF |
411 | return pdomain; |
412 | ||
91d30570 CV |
413 | DWORD ulen = UNLEN + 1; |
414 | WCHAR username[ulen]; | |
3f74d8d5 | 415 | DWORD dlen = MAX_DOMAIN_NAME_LEN + 1; |
91d30570 | 416 | WCHAR userdomain[dlen]; |
9a771b29 CF |
417 | SID_NAME_USE use; |
418 | ||
094d5193 | 419 | cfree_and_set (pwinname, almost_null); |
179cae11 | 420 | cfree_and_set (pdomain, almost_null); |
91d30570 CV |
421 | if (!LookupAccountSidW (NULL, sid (), username, &ulen, |
422 | userdomain, &dlen, &use)) | |
179cae11 CF |
423 | __seterrno (); |
424 | else | |
9a771b29 | 425 | { |
91d30570 CV |
426 | sys_wcstombs_alloc (&pwinname, HEAP_STR, username); |
427 | sys_wcstombs_alloc (&pdomain, HEAP_STR, userdomain); | |
9a771b29 | 428 | } |
179cae11 | 429 | return pdomain; |
da086d02 CF |
430 | } |
431 | ||
432 | const char * | |
094d5193 | 433 | cygheap_user::env_userprofile (const char *name, size_t namelen) |
da086d02 | 434 | { |
094d5193 CF |
435 | if (test_uid (puserprof, name, namelen)) |
436 | return puserprof; | |
437 | ||
793371f5 CV |
438 | /* User hive path is never longer than MAX_PATH. */ |
439 | WCHAR userprofile_env_buf[MAX_PATH]; | |
7b4b41ab | 440 | WCHAR win_id[UNLEN + 1]; /* Large enough for SID */ |
e70bea19 | 441 | |
179cae11 | 442 | cfree_and_set (puserprof, almost_null); |
e70bea19 | 443 | if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf)) |
793371f5 | 444 | sys_wcstombs_alloc (&puserprof, HEAP_STR, userprofile_env_buf); |
5f25e1d1 | 445 | |
179cae11 | 446 | return puserprof; |
da086d02 CF |
447 | } |
448 | ||
449 | const char * | |
094d5193 | 450 | cygheap_user::env_homepath (const char *name, size_t namelen) |
da086d02 CF |
451 | { |
452 | return ontherange (CH_HOMEPATH); | |
453 | } | |
454 | ||
455 | const char * | |
094d5193 | 456 | cygheap_user::env_homedrive (const char *name, size_t namelen) |
da086d02 CF |
457 | { |
458 | return ontherange (CH_HOMEDRIVE); | |
459 | } | |
9a771b29 CF |
460 | |
461 | const char * | |
094d5193 | 462 | cygheap_user::env_name (const char *name, size_t namelen) |
9a771b29 | 463 | { |
094d5193 | 464 | if (!test_uid (pwinname, name, namelen)) |
0c55f6ed | 465 | domain (); |
094d5193 | 466 | return pwinname; |
9a771b29 | 467 | } |
14ea5029 | 468 | |
60cb120f CV |
469 | const char * |
470 | cygheap_user::env_systemroot (const char *name, size_t namelen) | |
471 | { | |
472 | if (!psystemroot) | |
473 | { | |
ba6aad1d | 474 | int size = GetSystemWindowsDirectoryW (NULL, 0); |
60cb120f | 475 | if (size > 0) |
05726ddd | 476 | { |
ba6aad1d CV |
477 | WCHAR wsystemroot[size]; |
478 | size = GetSystemWindowsDirectoryW (wsystemroot, size); | |
479 | if (size > 0) | |
480 | sys_wcstombs_alloc (&psystemroot, HEAP_STR, wsystemroot); | |
60cb120f CV |
481 | } |
482 | if (size <= 0) | |
ba6aad1d | 483 | debug_printf ("GetSystemWindowsDirectoryW(), %E"); |
60cb120f CV |
484 | } |
485 | return psystemroot; | |
486 | } | |
487 | ||
7905c4f1 | 488 | char * |
ac413374 | 489 | pwdgrp::next_str (char c) |
14ea5029 | 490 | { |
ac413374 | 491 | char *res = lptr; |
f71f133b | 492 | lptr = strchrnul (lptr, c); |
fea48988 CF |
493 | if (*lptr) |
494 | *lptr++ = '\0'; | |
ac413374 | 495 | return res; |
7905c4f1 | 496 | } |
14ea5029 | 497 | |
65037056 CF |
498 | bool |
499 | pwdgrp::next_num (unsigned long& n) | |
ac413374 | 500 | { |
fea48988 | 501 | char *p = next_str (':'); |
ac413374 | 502 | char *cp; |
65037056 CF |
503 | n = strtoul (p, &cp, 10); |
504 | return p != cp && !*cp; | |
ac413374 CF |
505 | } |
506 | ||
507 | char * | |
508 | pwdgrp::add_line (char *eptr) | |
7905c4f1 | 509 | { |
ac413374 | 510 | if (eptr) |
7905c4f1 | 511 | { |
ac413374 | 512 | lptr = eptr; |
03dba1de CF |
513 | eptr = strchr (lptr, '\n'); |
514 | if (eptr) | |
ac413374 CF |
515 | { |
516 | if (eptr > lptr && eptr[-1] == '\r') | |
fea48988 CF |
517 | eptr[-1] = '\0'; |
518 | else | |
519 | *eptr = '\0'; | |
ac413374 CF |
520 | eptr++; |
521 | } | |
522 | if (curr_lines >= max_lines) | |
523 | { | |
524 | max_lines += 10; | |
525 | *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size); | |
526 | } | |
65037056 CF |
527 | if ((this->*parse) ()) |
528 | curr_lines++; | |
7905c4f1 | 529 | } |
ac413374 | 530 | return eptr; |
14ea5029 CF |
531 | } |
532 | ||
65037056 | 533 | void |
520fcc97 | 534 | pwdgrp::load (const wchar_t *rel_path) |
14ea5029 | 535 | { |
65037056 CF |
536 | static const char failed[] = "failed"; |
537 | static const char succeeded[] = "succeeded"; | |
e1e4b104 CV |
538 | const char *res = failed; |
539 | HANDLE fh = NULL; | |
e1e4b104 CV |
540 | |
541 | NTSTATUS status; | |
542 | OBJECT_ATTRIBUTES attr; | |
543 | IO_STATUS_BLOCK io; | |
544 | FILE_STANDARD_INFORMATION fsi; | |
65037056 | 545 | |
7905c4f1 CF |
546 | if (buf) |
547 | free (buf); | |
548 | buf = NULL; | |
981f9625 | 549 | curr_lines = 0; |
7905c4f1 | 550 | |
520fcc97 | 551 | if (!path && |
8895d962 | 552 | !(path = (PWCHAR) malloc ((wcslen (cygheap->installation_root) |
520fcc97 | 553 | + wcslen (rel_path) + 1) * sizeof (WCHAR)))) |
65037056 | 554 | { |
520fcc97 | 555 | paranoid_printf ("malloc (%W) failed", rel_path); |
e1e4b104 | 556 | goto out; |
65037056 | 557 | } |
8895d962 | 558 | wcpcpy (wcpcpy (path, cygheap->installation_root), rel_path); |
520fcc97 CV |
559 | RtlInitUnicodeString (&upath, path); |
560 | ||
561 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); | |
562 | etc_ix = etc::init (etc_ix, &attr); | |
563 | ||
564 | paranoid_printf ("%S", &upath); | |
565 | ||
e9982f2a | 566 | status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io, |
93e88498 CV |
567 | FILE_SHARE_VALID_FLAGS, |
568 | FILE_SYNCHRONOUS_IO_NONALERT | |
569 | | FILE_OPEN_FOR_BACKUP_INTENT); | |
e1e4b104 | 570 | if (!NT_SUCCESS (status)) |
7905c4f1 | 571 | { |
520fcc97 | 572 | paranoid_printf ("NtOpenFile(%S) failed, status %p", &upath, status); |
e1e4b104 | 573 | goto out; |
14ea5029 | 574 | } |
e1e4b104 CV |
575 | status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi, |
576 | FileStandardInformation); | |
577 | if (!NT_SUCCESS (status)) | |
578 | { | |
579 | paranoid_printf ("NtQueryInformationFile(%S) failed, status %p", | |
520fcc97 | 580 | &upath, status); |
e1e4b104 CV |
581 | goto out; |
582 | } | |
583 | /* FIXME: Should we test for HighPart set? If so, the | |
584 | passwd or group file is way beyond what we can handle. */ | |
585 | /* FIXME 2: It's still ugly that we keep the file in memory. | |
586 | Big organizations have naturally large passwd files. */ | |
587 | buf = (char *) malloc (fsi.EndOfFile.LowPart + 1); | |
588 | if (!buf) | |
589 | { | |
590 | paranoid_printf ("malloc (%d) failed", fsi.EndOfFile.LowPart); | |
591 | goto out; | |
592 | } | |
e9982f2a CV |
593 | status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart, |
594 | NULL, NULL); | |
e1e4b104 CV |
595 | if (!NT_SUCCESS (status)) |
596 | { | |
520fcc97 | 597 | paranoid_printf ("NtReadFile(%S) failed, status %p", &upath, status); |
e1e4b104 CV |
598 | free (buf); |
599 | goto out; | |
600 | } | |
601 | buf[fsi.EndOfFile.LowPart] = '\0'; | |
7b9e380f | 602 | for (char *eptr = buf; (eptr = add_line (eptr)); ) |
e1e4b104 | 603 | continue; |
520fcc97 | 604 | debug_printf ("%W curr_lines %d", rel_path, curr_lines); |
e1e4b104 CV |
605 | res = succeeded; |
606 | ||
607 | out: | |
608 | if (fh) | |
609 | NtClose (fh); | |
520fcc97 | 610 | debug_printf ("%W load %s", rel_path, res); |
57394495 | 611 | initialized = true; |
14ea5029 | 612 | } |