]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/security.cc
2003-09-15 Pierre Humblet <pierre.humblet@ieee.org>
[newlib-cygwin.git] / winsup / cygwin / security.cc
1 /* security.cc: NT security functions
2
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
4
5 Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
6 Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
7
8 This file is part of Cygwin.
9
10 This software is a copyrighted work licensed under the terms of the
11 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 details. */
13
14 #include "winsup.h"
15 #include <grp.h>
16 #include <pwd.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <limits.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/acl.h>
23 #include <ctype.h>
24 #include <winnls.h>
25 #include <wingdi.h>
26 #include <winuser.h>
27 #include <wininet.h>
28 #include <ntsecapi.h>
29 #include <subauth.h>
30 #include <aclapi.h>
31 #include "cygerrno.h"
32 #include "security.h"
33 #include "fhandler.h"
34 #include "path.h"
35 #include "dtable.h"
36 #include "pinfo.h"
37 #include "cygheap.h"
38 #include <ntdef.h>
39 #include "ntdll.h"
40 #include "lm.h"
41 #include "pwdgrp.h"
42
43 bool allow_ntsec;
44 /* allow_smbntsec is handled exclusively in path.cc (path_conv::check).
45 It's defined here because of it's strong relationship to allow_ntsec.
46 The default is TRUE to reflect the old behaviour. */
47 bool allow_smbntsec;
48
49 cygsid *
50 cygsidlist::alloc_sids (int n)
51 {
52 if (n > 0)
53 return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
54 else
55 return NULL;
56 }
57
58 void
59 cygsidlist::free_sids ()
60 {
61 if (sids)
62 cfree (sids);
63 sids = NULL;
64 count = maxcount = 0;
65 type = cygsidlist_empty;
66 }
67
68 extern "C" void
69 cygwin_set_impersonation_token (const HANDLE hToken)
70 {
71 debug_printf ("set_impersonation_token (%d)", hToken);
72 cygheap->user.external_token = hToken;
73 return;
74 }
75
76 void
77 extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
78 {
79 char *d, *u, *c;
80
81 domain[0] = 0;
82 strlcpy (user, pw->pw_name, UNLEN + 1);
83 debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos);
84
85 if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
86 (d == pw->pw_gecos || d[-1] == ','))
87 {
88 c = strechr (d + 2, ',');
89 if ((u = strechr (d + 2, '\\')) >= c)
90 u = d + 1;
91 else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
92 strlcpy (domain, d + 2, u - d - 1);
93 if (c - u <= UNLEN + 1)
94 strlcpy (user, u + 1, c - u);
95 }
96 if (domain[0])
97 return;
98
99 cygsid psid;
100 DWORD ulen = UNLEN + 1;
101 DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
102 SID_NAME_USE use;
103 if (psid.getfrompw (pw))
104 LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
105 }
106
107 extern "C" HANDLE
108 cygwin_logon_user (const struct passwd *pw, const char *password)
109 {
110 if (!wincap.has_security ())
111 {
112 set_errno (ENOSYS);
113 return INVALID_HANDLE_VALUE;
114 }
115 if (!pw)
116 {
117 set_errno (EINVAL);
118 return INVALID_HANDLE_VALUE;
119 }
120
121 char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
122 char nt_user[UNLEN + 1];
123 HANDLE hToken;
124
125 extract_nt_dom_user (pw, nt_domain, nt_user);
126 debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
127 if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
128 LOGON32_LOGON_INTERACTIVE,
129 LOGON32_PROVIDER_DEFAULT,
130 &hToken)
131 || !SetHandleInformation (hToken,
132 HANDLE_FLAG_INHERIT,
133 HANDLE_FLAG_INHERIT))
134 {
135 __seterrno ();
136 return INVALID_HANDLE_VALUE;
137 }
138 debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
139 return hToken;
140 }
141
142 static void
143 str2lsa (LSA_STRING &tgt, const char *srcstr)
144 {
145 tgt.Length = strlen (srcstr);
146 tgt.MaximumLength = tgt.Length + 1;
147 tgt.Buffer = (PCHAR) srcstr;
148 }
149
150 static void
151 str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
152 {
153 tgt.Length = strlen (srcstr);
154 tgt.MaximumLength = tgt.Length + 1;
155 tgt.Buffer = (PCHAR) buf;
156 memcpy (buf, srcstr, tgt.MaximumLength);
157 }
158
159 void
160 str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
161 {
162 tgt.Length = strlen (srcstr) * sizeof (WCHAR);
163 tgt.MaximumLength = tgt.Length + sizeof (WCHAR);
164 tgt.Buffer = (PWCHAR) buf;
165 sys_mbstowcs (buf, srcstr, tgt.MaximumLength);
166 }
167
168 #if 0 /* unused */
169 static void
170 lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size)
171 {
172 size = (size - 1) * sizeof (WCHAR);
173 if (src.Length < size)
174 size = src.Length;
175 memcpy (tgt, src.Buffer, size);
176 size >>= 1;
177 tgt[size] = 0;
178 }
179 #endif
180
181 static void
182 lsa2str (char *tgt, LSA_UNICODE_STRING &src, int size)
183 {
184 if (src.Length / 2 < size)
185 size = src.Length / 2;
186 sys_wcstombs (tgt, src.Buffer, size);
187 tgt[size] = 0;
188 }
189
190 static LSA_HANDLE
191 open_local_policy ()
192 {
193 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
194 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
195
196 NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
197 if (ret != STATUS_SUCCESS)
198 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
199 return lsa;
200 }
201
202 static void
203 close_local_policy (LSA_HANDLE &lsa)
204 {
205 if (lsa != INVALID_HANDLE_VALUE)
206 LsaClose (lsa);
207 lsa = INVALID_HANDLE_VALUE;
208 }
209
210 #if 0 /* unused */
211 static BOOL
212 get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
213 {
214 NET_API_STATUS ret;
215 WCHAR *buf;
216 char name[INTERNET_MAX_HOST_NAME_LENGTH + 1];
217 WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1];
218 WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1];
219 PPOLICY_ACCOUNT_DOMAIN_INFO adi;
220 PPOLICY_PRIMARY_DOMAIN_INFO pdi;
221
222 if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation,
223 (PVOID *) &adi)) != STATUS_SUCCESS)
224 {
225 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
226 return FALSE;
227 }
228 lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1);
229 LsaFreeMemory (adi);
230 if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation,
231 (PVOID *) &pdi)) != STATUS_SUCCESS)
232 {
233 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
234 return FALSE;
235 }
236 lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
237 LsaFreeMemory (pdi);
238 /* If the SID given in the primary domain info is NULL, the machine is
239 not member of a domain. The name in the primary domain info is the
240 name of the workgroup then. */
241 if (pdi->Sid &&
242 (ret =
243 NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS)
244 {
245 sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
246 strcpy (logonserver, name);
247 if (domain)
248 sys_wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1);
249 }
250 else
251 {
252 sys_wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
253 strcpy (logonserver, "\\\\");
254 strcat (logonserver, name);
255 if (domain)
256 sys_wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
257 }
258 if (ret == STATUS_SUCCESS)
259 NetApiBufferFree (buf);
260 return TRUE;
261 }
262 #endif
263
264 BOOL
265 get_logon_server (const char *domain, char *server, WCHAR *wserver)
266 {
267 WCHAR wdomain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
268 NET_API_STATUS ret;
269 WCHAR *buf;
270 DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
271
272 /* Empty domain is interpreted as local system */
273 if ((GetComputerName (server + 2, &size)) &&
274 (strcasematch (domain, server + 2) || !domain[0]))
275 {
276 server[0] = server[1] = '\\';
277 if (wserver)
278 sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
279 return TRUE;
280 }
281
282 /* Try to get the primary domain controller for the domain */
283 sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
284 if ((ret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf)) == STATUS_SUCCESS)
285 {
286 sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
287 if (wserver)
288 for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
289 ;
290 NetApiBufferFree (buf);
291 return TRUE;
292 }
293 __seterrno_from_win_error (ret);
294 return FALSE;
295 }
296
297 static BOOL
298 get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
299 char *domain)
300 {
301 char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
302 WCHAR wuser[UNLEN + 1];
303 sys_mbstowcs (wuser, user, UNLEN + 1);
304 LPGROUP_USERS_INFO_0 buf;
305 DWORD cnt, tot, len;
306 NET_API_STATUS ret;
307
308 /* Look only on logonserver */
309 ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
310 MAX_PREFERRED_LENGTH, &cnt, &tot);
311 if (ret)
312 {
313 __seterrno_from_win_error (ret);
314 /* It's no error when the user name can't be found. */
315 return ret == NERR_UserNotFound;
316 }
317
318 len = strlen (domain);
319 strcpy (dgroup, domain);
320 dgroup[len++] = '\\';
321
322 for (DWORD i = 0; i < cnt; ++i)
323 {
324 cygsid gsid;
325 DWORD glen = MAX_SID_LEN;
326 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
327 DWORD dlen = sizeof (domain);
328 SID_NAME_USE use = SidTypeInvalid;
329
330 sys_wcstombs (dgroup + len, buf[i].grui0_name, GNLEN + 1);
331 if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
332 debug_printf ("LookupAccountName(%s): %E", dgroup);
333 else if (legal_sid_type (use))
334 grp_list += gsid;
335 else
336 debug_printf ("Global group %s invalid. Domain: %s Use: %d",
337 dgroup, domain, use);
338 }
339
340 NetApiBufferFree (buf);
341 return TRUE;
342 }
343
344 static BOOL
345 is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
346 {
347 LPLOCALGROUP_MEMBERS_INFO_0 buf;
348 DWORD cnt, tot;
349 NET_API_STATUS ret;
350 BOOL retval = FALSE;
351
352 /* Members can be users or global groups */
353 ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf,
354 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
355 if (ret)
356 return FALSE;
357
358 for (DWORD bidx = 0; !retval && bidx < cnt; ++bidx)
359 if (EqualSid (pusersid, buf[bidx].lgrmi0_sid))
360 retval = TRUE;
361 else
362 for (int glidx = 0; !retval && glidx < grp_list.count; ++glidx)
363 if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid))
364 retval = TRUE;
365
366 NetApiBufferFree (buf);
367 return retval;
368 }
369
370 static BOOL
371 get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
372 {
373 LPLOCALGROUP_INFO_0 buf;
374 DWORD cnt, tot;
375 NET_API_STATUS ret;
376
377 ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
378 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
379 if (ret)
380 {
381 __seterrno_from_win_error (ret);
382 return FALSE;
383 }
384
385 char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
386 char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
387 DWORD blen, llen;
388 SID_NAME_USE use;
389
390 blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
391 if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
392 || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
393 {
394 __seterrno ();
395 return FALSE;
396 }
397 bgroup[blen++] = lgroup[llen++] = '\\';
398
399 for (DWORD i = 0; i < cnt; ++i)
400 if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
401 {
402 cygsid gsid;
403 DWORD glen = MAX_SID_LEN;
404 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
405 DWORD dlen = sizeof (domain);
406
407 use = SidTypeInvalid;
408 sys_wcstombs (bgroup + blen, buf[i].lgrpi0_name, GNLEN + 1);
409 if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
410 {
411 if (GetLastError () != ERROR_NONE_MAPPED)
412 debug_printf ("LookupAccountName(%s): %E", bgroup);
413 strcpy (lgroup + llen, bgroup + blen);
414 if (!LookupAccountName (NULL, lgroup, gsid, &glen,
415 domain, &dlen, &use))
416 debug_printf ("LookupAccountName(%s): %E", lgroup);
417 }
418 if (!legal_sid_type (use))
419 debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
420 else if (!grp_list.contains (gsid))
421 grp_list += gsid;
422 }
423 NetApiBufferFree (buf);
424 return TRUE;
425 }
426
427 static BOOL
428 sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid)
429 {
430 if (!grps)
431 return FALSE;
432 for (DWORD i = 0; i < grps->GroupCount; ++i)
433 if (sid == grps->Groups[i].Sid)
434 return TRUE;
435 return FALSE;
436 }
437
438 #if 0 /* Unused */
439 static BOOL
440 get_user_primary_group (WCHAR *wlogonserver, const char *user,
441 PSID pusersid, cygsid &pgrpsid)
442 {
443 LPUSER_INFO_3 buf;
444 WCHAR wuser[UNLEN + 1];
445 NET_API_STATUS ret;
446 BOOL retval = FALSE;
447 UCHAR count = 0;
448
449 if (well_known_system_sid == pusersid)
450 {
451 pgrpsid = well_known_system_sid;
452 return TRUE;
453 }
454
455 sys_mbstowcs (wuser, user, UNLEN + 1);
456 ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf);
457 if (ret)
458 {
459 __seterrno_from_win_error (ret);
460 return FALSE;
461 }
462
463 pgrpsid = pusersid;
464 if (IsValidSid (pgrpsid)
465 && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
466 {
467 *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id;
468 retval = TRUE;
469 }
470 NetApiBufferFree (buf);
471 return retval;
472 }
473 #endif
474
475 static void
476 get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
477 {
478 struct __group32 *gr;
479 cygsid gsid;
480
481 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
482 {
483 if (gr->gr_gid == (__gid32_t) pw->pw_gid)
484 goto found;
485 else if (gr->gr_mem)
486 for (int gi = 0; gr->gr_mem[gi]; ++gi)
487 if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
488 goto found;
489 continue;
490 found:
491 if (gsid.getfromgr (gr) && !grp_list.contains (gsid))
492 grp_list += gsid;
493
494 }
495 }
496
497 static void
498 get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
499 LUID auth_luid, int &auth_pos)
500 {
501 auth_pos = -1;
502 if (my_grps)
503 {
504 if (sid_in_token_groups (my_grps, well_known_local_sid))
505 grp_list += well_known_local_sid;
506 if (sid_in_token_groups (my_grps, well_known_dialup_sid))
507 grp_list += well_known_dialup_sid;
508 if (sid_in_token_groups (my_grps, well_known_network_sid))
509 grp_list += well_known_network_sid;
510 if (sid_in_token_groups (my_grps, well_known_batch_sid))
511 grp_list += well_known_batch_sid;
512 if (sid_in_token_groups (my_grps, well_known_interactive_sid))
513 grp_list += well_known_interactive_sid;
514 if (sid_in_token_groups (my_grps, well_known_service_sid))
515 grp_list += well_known_service_sid;
516 }
517 else
518 {
519 grp_list += well_known_local_sid;
520 grp_list += well_known_interactive_sid;
521 }
522 if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
523 {
524 char buf[64];
525 __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
526 auth_luid.LowPart);
527 grp_list += buf;
528 auth_pos = grp_list.count - 1;
529 }
530 }
531
532 static BOOL
533 get_initgroups_sidlist (cygsidlist &grp_list,
534 PSID usersid, PSID pgrpsid, struct passwd *pw,
535 PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos,
536 BOOL &special_pgrp)
537 {
538 grp_list += well_known_world_sid;
539 grp_list += well_known_authenticated_users_sid;
540 if (well_known_system_sid == usersid)
541 {
542 auth_pos = -1;
543 grp_list += well_known_admins_sid;
544 get_unix_group_sidlist (pw, grp_list);
545 }
546 else
547 {
548 char user[UNLEN + 1];
549 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
550 WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
551 char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
552
553 get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
554 extract_nt_dom_user (pw, domain, user);
555 if (get_logon_server (domain, server, wserver))
556 get_user_groups (wserver, grp_list, user, domain);
557 get_unix_group_sidlist (pw, grp_list);
558 if (!get_user_local_groups (grp_list, usersid))
559 return FALSE;
560 }
561 /* special_pgrp true if pgrpsid is not in normal groups */
562 if ((special_pgrp = !grp_list.contains (pgrpsid)))
563 grp_list += pgrpsid;
564 return TRUE;
565 }
566
567 static void
568 get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps,
569 user_groups &groups, LUID auth_luid, int &auth_pos)
570 {
571 PSID pgpsid = groups.pgsid;
572 tmp_list += well_known_world_sid;
573 tmp_list += well_known_authenticated_users_sid;
574 get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
575 for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
576 tmp_list += groups.sgsids.sids[gidx];
577 if (!groups.sgsids.contains (pgpsid))
578 tmp_list += pgpsid;
579 }
580
581 static const char *sys_privs[] = {
582 SE_TCB_NAME,
583 SE_ASSIGNPRIMARYTOKEN_NAME,
584 SE_CREATE_TOKEN_NAME,
585 SE_CHANGE_NOTIFY_NAME,
586 SE_SECURITY_NAME,
587 SE_BACKUP_NAME,
588 SE_RESTORE_NAME,
589 SE_SYSTEMTIME_NAME,
590 SE_SHUTDOWN_NAME,
591 SE_REMOTE_SHUTDOWN_NAME,
592 SE_TAKE_OWNERSHIP_NAME,
593 SE_DEBUG_NAME,
594 SE_SYSTEM_ENVIRONMENT_NAME,
595 SE_SYSTEM_PROFILE_NAME,
596 SE_PROF_SINGLE_PROCESS_NAME,
597 SE_INC_BASE_PRIORITY_NAME,
598 SE_LOAD_DRIVER_NAME,
599 SE_CREATE_PAGEFILE_NAME,
600 SE_INCREASE_QUOTA_NAME
601 };
602
603 #define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *))
604
605 PTOKEN_PRIVILEGES
606 get_system_priv_list (cygsidlist &grp_list)
607 {
608 LUID priv;
609 PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES)
610 malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES));
611 if (!privs)
612 {
613 debug_printf ("malloc (system_privs) failed.");
614 return NULL;
615 }
616 privs->PrivilegeCount = 0;
617
618 for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i)
619 if (LookupPrivilegeValue (NULL, sys_privs[i], &priv))
620 {
621 privs->Privileges[privs->PrivilegeCount].Luid = priv;
622 privs->Privileges[privs->PrivilegeCount].Attributes =
623 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
624 ++privs->PrivilegeCount;
625 }
626 return privs;
627 }
628
629 PTOKEN_PRIVILEGES
630 get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
631 {
632 PLSA_UNICODE_STRING privstrs;
633 ULONG cnt;
634 PTOKEN_PRIVILEGES privs = NULL;
635 NTSTATUS ret;
636 char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
637
638 if (usersid == well_known_system_sid)
639 return get_system_priv_list (grp_list);
640
641 for (int grp = -1; grp < grp_list.count; ++grp)
642 {
643 if (grp == -1)
644 {
645 if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
646 &cnt)) != STATUS_SUCCESS)
647 continue;
648 }
649 else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
650 &privstrs, &cnt))
651 != STATUS_SUCCESS)
652 continue;
653 for (ULONG i = 0; i < cnt; ++i)
654 {
655 LUID priv;
656 PTOKEN_PRIVILEGES tmp;
657 DWORD tmp_count;
658
659 lsa2str (buf, privstrs[i], sizeof (buf) - 1);
660 if (!LookupPrivilegeValue (NULL, buf, &priv))
661 continue;
662
663 for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p)
664 if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID)))
665 goto next_account_right;
666
667 tmp_count = privs ? privs->PrivilegeCount : 0;
668 tmp = (PTOKEN_PRIVILEGES)
669 realloc (privs, sizeof (ULONG) +
670 (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
671 if (!tmp)
672 {
673 if (privs)
674 free (privs);
675 LsaFreeMemory (privstrs);
676 debug_printf ("realloc (privs) failed.");
677 return NULL;
678 }
679 tmp->PrivilegeCount = tmp_count;
680 privs = tmp;
681 privs->Privileges[privs->PrivilegeCount].Luid = priv;
682 privs->Privileges[privs->PrivilegeCount].Attributes =
683 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
684 ++privs->PrivilegeCount;
685
686 next_account_right:
687 ;
688 }
689 LsaFreeMemory (privstrs);
690 }
691 return privs;
692 }
693
694 /* Accept a token if
695 - the requested usersid matches the TokenUser and
696 - if setgroups has been called:
697 the token groups that are listed in /etc/group match the union of
698 the requested primary and supplementary groups in gsids.
699 - else the (unknown) implicitly requested supplementary groups and those
700 in the token are the groups associated with the usersid. We assume
701 they match and verify only the primary groups.
702 The requested primary group must appear in the token.
703 The primary group in the token is a group associated with the usersid,
704 except if the token is internal and the group is in the token SD
705 (see create_token). In that latter case that group must match the
706 requested primary group. */
707 BOOL
708 verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern)
709 {
710 DWORD size;
711 BOOL intern = FALSE;
712
713 if (pintern)
714 {
715 TOKEN_SOURCE ts;
716 if (!GetTokenInformation (token, TokenSource,
717 &ts, sizeof ts, &size))
718 debug_printf ("GetTokenInformation(): %E");
719 else
720 *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
721 }
722 /* Verify usersid */
723 cygsid tok_usersid = NO_SID;
724 if (!GetTokenInformation (token, TokenUser,
725 &tok_usersid, sizeof tok_usersid, &size))
726 debug_printf ("GetTokenInformation(): %E");
727 if (usersid != tok_usersid)
728 return FALSE;
729
730 /* For an internal token, if setgroups was not called and if the sd group
731 is not well_known_null_sid, it must match pgrpsid */
732 if (intern && !groups.issetgroups ())
733 {
734 char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)];
735 cygpsid gsid (NO_SID);
736 if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
737 (PSECURITY_DESCRIPTOR) sd_buf,
738 sizeof sd_buf, &size))
739 debug_printf ("GetKernelObjectSecurity(): %E");
740 else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf,
741 (PSID *) &gsid, (BOOL *) &size))
742 debug_printf ("GetSecurityDescriptorGroup(): %E");
743 if (well_known_null_sid != gsid)
744 return gsid == groups.pgsid;
745 }
746
747 PTOKEN_GROUPS my_grps;
748 bool saw_buf[NGROUPS_MAX] = {};
749 bool *saw = saw_buf, sawpg = false, ret = false;
750
751 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
752 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
753 debug_printf ("GetTokenInformation(token, TokenGroups): %E");
754 else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
755 debug_printf ("alloca (my_grps) failed.");
756 else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
757 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
758 else if (!groups.issetgroups ()) /* setgroups was never called */
759 ret = sid_in_token_groups (my_grps, groups.pgsid)
760 || groups.pgsid == usersid;
761 else /* setgroups was called */
762 {
763 struct __group32 *gr;
764 cygsid gsid;
765 if (groups.sgsids.count > (int) (sizeof (saw_buf) / sizeof (*saw_buf))
766 && !(saw = (bool *) calloc (groups.sgsids.count, sizeof (bool))))
767 goto done;
768
769 /* token groups found in /etc/group match the user.gsids ? */
770 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
771 if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
772 {
773 int pos = groups.sgsids.position (gsid);
774 if (pos >= 0)
775 saw[pos] = true;
776 else if (groups.pgsid == gsid)
777 sawpg = true;
778 else if (gsid != well_known_world_sid
779 && gsid != usersid)
780 goto done;
781 }
782 for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
783 if (!saw[gidx])
784 goto done;
785 ret = sawpg
786 || groups.sgsids.contains (groups.pgsid)
787 || groups.pgsid == usersid;
788 }
789 done:
790 if (saw != saw_buf)
791 free (saw);
792 return ret;
793 }
794
795 HANDLE
796 create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
797 {
798 NTSTATUS ret;
799 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
800 int old_priv_state;
801
802 cygsidlist tmp_gsids (cygsidlist_auto, 12);
803
804 SECURITY_QUALITY_OF_SERVICE sqos =
805 { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
806 OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
807 PSECURITY_ATTRIBUTES psa;
808 BOOL special_pgrp = FALSE;
809 char sa_buf[1024];
810 LUID auth_luid = SYSTEM_LUID;
811 LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL };
812
813 TOKEN_USER user;
814 PTOKEN_GROUPS new_tok_gsids = NULL;
815 PTOKEN_PRIVILEGES privs = NULL;
816 TOKEN_OWNER owner;
817 TOKEN_PRIMARY_GROUP pgrp;
818 char acl_buf[MAX_DACL_LEN (5)];
819 TOKEN_DEFAULT_DACL dacl;
820 TOKEN_SOURCE source;
821 TOKEN_STATISTICS stats;
822 memcpy (source.SourceName, "Cygwin.1", 8);
823 source.SourceIdentifier.HighPart = 0;
824 source.SourceIdentifier.LowPart = 0x0101;
825
826 HANDLE token = INVALID_HANDLE_VALUE;
827 HANDLE primary_token = INVALID_HANDLE_VALUE;
828
829 HANDLE my_token = INVALID_HANDLE_VALUE;
830 PTOKEN_GROUPS my_tok_gsids = NULL;
831 DWORD size;
832
833 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
834 if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0)
835 goto out;
836
837 /* Open policy object. */
838 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
839 goto out;
840
841 /* User, owner, primary group. */
842 user.User.Sid = usersid;
843 user.User.Attributes = 0;
844 owner.Owner = usersid;
845
846 /* Retrieve authentication id and group list from own process. */
847 if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &my_token))
848 debug_printf ("OpenProcessToken(my_token): %E");
849 else
850 {
851 /* Switching user context to SYSTEM doesn't inherit the authentication
852 id of the user account running current process. */
853 if (usersid != well_known_system_sid)
854 if (!GetTokenInformation (my_token, TokenStatistics,
855 &stats, sizeof stats, &size))
856 debug_printf
857 ("GetTokenInformation(my_token, TokenStatistics): %E");
858 else
859 auth_luid = stats.AuthenticationId;
860
861 /* Retrieving current processes group list to be able to inherit
862 some important well known group sids. */
863 if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
864 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
865 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
866 else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
867 debug_printf ("malloc (my_tok_gsids) failed.");
868 else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids,
869 size, &size))
870 {
871 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
872 free (my_tok_gsids);
873 my_tok_gsids = NULL;
874 }
875 CloseHandle (my_token);
876 }
877
878 /* Create list of groups, the user is member in. */
879 int auth_pos;
880 if (new_groups.issetgroups ())
881 get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid,
882 auth_pos);
883 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
884 my_tok_gsids, auth_luid, auth_pos,
885 special_pgrp))
886 goto out;
887
888 /* Primary group. */
889 pgrp.PrimaryGroup = new_groups.pgsid;
890
891 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
892 char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)];
893 new_tok_gsids = (PTOKEN_GROUPS) grps_buf;
894 new_tok_gsids->GroupCount = tmp_gsids.count;
895 for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
896 {
897 new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
898 new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY |
899 SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
900 }
901 if (auth_pos >= 0)
902 new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
903
904 /* Retrieve list of privileges of that user. */
905 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids)))
906 goto out;
907
908 /* Create default dacl. */
909 if (!sec_acl ((PACL) acl_buf, false, false,
910 tmp_gsids.contains (well_known_admins_sid) ?
911 well_known_admins_sid : usersid))
912 goto out;
913 dacl.DefaultDacl = (PACL) acl_buf;
914
915 /* Let's be heroic... */
916 ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
917 &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
918 &pgrp, &dacl, &source);
919 if (ret)
920 __seterrno_from_win_error (RtlNtStatusToDosError (ret));
921 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
922 {
923 __seterrno ();
924 debug_printf ("Loading NtCreateToken failed.");
925 }
926 else
927 {
928 /* Set security descriptor and primary group */
929 psa = sec_user (sa_buf, usersid);
930 if (psa->lpSecurityDescriptor &&
931 !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR)
932 psa->lpSecurityDescriptor,
933 special_pgrp ? new_groups.pgsid
934 : well_known_null_sid,
935 FALSE))
936 debug_printf ("SetSecurityDescriptorGroup %E");
937 /* Convert to primary token. */
938 if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation,
939 TokenPrimary, &primary_token))
940 {
941 __seterrno ();
942 debug_printf ("DuplicateTokenEx %E");
943 }
944 }
945
946 out:
947 if (old_priv_state >= 0)
948 set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state);
949 if (token != INVALID_HANDLE_VALUE)
950 CloseHandle (token);
951 if (privs)
952 free (privs);
953 if (my_tok_gsids)
954 free (my_tok_gsids);
955 close_local_policy (lsa);
956
957 debug_printf ("%d = create_token ()", primary_token);
958 return primary_token;
959 }
960
961 int subauth_id = 255;
962
963 HANDLE
964 subauth (struct passwd *pw)
965 {
966 LSA_STRING name;
967 HANDLE lsa_hdl;
968 LSA_OPERATIONAL_MODE sec_mode;
969 NTSTATUS ret, ret2;
970 ULONG package_id, size;
971 struct {
972 LSA_STRING str;
973 CHAR buf[16];
974 } origin;
975 struct {
976 MSV1_0_LM20_LOGON auth;
977 WCHAR dombuf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
978 WCHAR usrbuf[UNLEN + 1];
979 WCHAR wkstbuf[1];
980 CHAR authinf1[1];
981 CHAR authinf2[1];
982 } subbuf;
983 TOKEN_SOURCE ts;
984 PMSV1_0_LM20_LOGON_PROFILE profile;
985 LUID luid;
986 QUOTA_LIMITS quota;
987 char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
988 char nt_user[UNLEN + 1];
989 SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
990 HANDLE user_token = INVALID_HANDLE_VALUE;
991 HANDLE primary_token = INVALID_HANDLE_VALUE;
992 int old_tcb_state;
993
994 if ((old_tcb_state = set_process_privilege (SE_TCB_NAME)) < 0)
995 return INVALID_HANDLE_VALUE;
996
997 /* Register as logon process. */
998 str2lsa (name, "Cygwin");
999 SetLastError (0);
1000 ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
1001 if (ret != STATUS_SUCCESS)
1002 {
1003 debug_printf ("LsaRegisterLogonProcess: %d", ret);
1004 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1005 goto out;
1006 }
1007 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
1008 {
1009 debug_printf ("Couldn't load Secur32.dll");
1010 goto out;
1011 }
1012 /* Get handle to MSV1_0 package. */
1013 str2lsa (name, MSV1_0_PACKAGE_NAME);
1014 ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
1015 if (ret != STATUS_SUCCESS)
1016 {
1017 debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
1018 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1019 LsaDeregisterLogonProcess (lsa_hdl);
1020 goto out;
1021 }
1022 /* Create origin. */
1023 str2buf2lsa (origin.str, origin.buf, "Cygwin");
1024 /* Create token source. */
1025 memcpy (ts.SourceName, "Cygwin.1", 8);
1026 ts.SourceIdentifier.HighPart = 0;
1027 ts.SourceIdentifier.LowPart = 0x0100;
1028 /* Get user information. */
1029 extract_nt_dom_user (pw, nt_domain, nt_user);
1030 /* Fill subauth with values. */
1031 subbuf.auth.MessageType = MsV1_0NetworkLogon;
1032 str2buf2uni (subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain);
1033 str2buf2uni (subbuf.auth.UserName, subbuf.usrbuf, nt_user);
1034 str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, "");
1035 memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH);
1036 str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, "");
1037 str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,"");
1038 subbuf.auth.ParameterControl = 0 | (subauth_id << 24);
1039 /* Try to logon... */
1040 ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network,
1041 package_id, &subbuf, sizeof subbuf,
1042 NULL, &ts, (PVOID *) &profile, &size,
1043 &luid, &user_token, &quota, &ret2);
1044 if (ret != STATUS_SUCCESS)
1045 {
1046 debug_printf ("LsaLogonUser: %d", ret);
1047 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1048 LsaDeregisterLogonProcess (lsa_hdl);
1049 goto out;
1050 }
1051 LsaFreeReturnBuffer (profile);
1052 /* Convert to primary token. */
1053 if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa,
1054 SecurityImpersonation, TokenPrimary, &primary_token))
1055 __seterrno ();
1056
1057 out:
1058 set_process_privilege (SE_TCB_NAME, old_tcb_state);
1059 if (user_token != INVALID_HANDLE_VALUE)
1060 CloseHandle (user_token);
1061 return primary_token;
1062 }
1063
1064 /* read_sd reads a security descriptor from a file.
1065 In case of error, -1 is returned and errno is set.
1066 If sd_buf is too small, 0 is returned and sd_size
1067 is set to the needed buffer size.
1068 On success, 1 is returned.
1069
1070 GetFileSecurity() is used instead of BackupRead()
1071 to avoid access denied errors if the caller has
1072 not the permission to open that file for read.
1073
1074 Originally the function should return the size
1075 of the SD on success. Unfortunately NT returns
1076 0 in `len' on success, while W2K returns the
1077 correct size!
1078 */
1079
1080 LONG
1081 read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
1082 {
1083 /* Check parameters */
1084 if (!sd_size)
1085 {
1086 set_errno (EINVAL);
1087 return -1;
1088 }
1089
1090 debug_printf ("file = %s", file);
1091
1092 DWORD len = 0;
1093 const char *pfile = file;
1094 char fbuf[PATH_MAX];
1095 if (current_codepage == oem_cp)
1096 {
1097 DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file));
1098 bzero (fbuf, sizeof (fbuf));
1099 OemToCharBuff (file, fbuf, fname_len);
1100 pfile = fbuf;
1101 }
1102
1103 if (!GetFileSecurity (pfile,
1104 OWNER_SECURITY_INFORMATION
1105 | GROUP_SECURITY_INFORMATION
1106 | DACL_SECURITY_INFORMATION,
1107 sd_buf, *sd_size, &len))
1108 {
1109 __seterrno ();
1110 return -1;
1111 }
1112 debug_printf ("file = %s: len=%d", file, len);
1113 if (len > *sd_size)
1114 {
1115 *sd_size = len;
1116 return 0;
1117 }
1118 return 1;
1119 }
1120
1121 LONG
1122 write_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size)
1123 {
1124 /* Check parameters */
1125 if (!sd_buf || !sd_size)
1126 {
1127 set_errno (EINVAL);
1128 return -1;
1129 }
1130
1131 BOOL dummy;
1132 cygpsid owner;
1133
1134 if (!GetSecurityDescriptorOwner (sd_buf, (PSID *) &owner, &dummy))
1135 {
1136 __seterrno ();
1137 return -1;
1138 }
1139 /* Try turning privilege on, may not have WRITE_OWNER or WRITE_DAC access.
1140 Must have privilege to set different owner, else BackupWrite misbehaves */
1141 static int NO_COPY saved_res; /* 0: never, 1: failed, 2 & 3: OK */
1142 int res;
1143 if (!saved_res || cygheap->user.issetuid ())
1144 {
1145 res = 2 + set_process_privilege (SE_RESTORE_NAME, true,
1146 cygheap->user.issetuid ());
1147 if (!cygheap->user.issetuid ())
1148 saved_res = res;
1149 }
1150 else
1151 res = saved_res;
1152 if (res == 1 && owner != cygheap->user.sid ())
1153 return -1;
1154
1155 HANDLE fh;
1156 fh = CreateFile (file,
1157 WRITE_OWNER | WRITE_DAC,
1158 FILE_SHARE_READ | FILE_SHARE_WRITE,
1159 &sec_none_nih,
1160 OPEN_EXISTING,
1161 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
1162 NULL);
1163
1164 if (fh == INVALID_HANDLE_VALUE)
1165 {
1166 __seterrno ();
1167 return -1;
1168 }
1169
1170 LPVOID context = NULL;
1171 DWORD bytes_written = 0;
1172 WIN32_STREAM_ID header;
1173
1174 memset (&header, 0, sizeof (header));
1175 /* write new security info header */
1176 header.dwStreamId = BACKUP_SECURITY_DATA;
1177 header.dwStreamAttributes = STREAM_CONTAINS_SECURITY;
1178 header.Size.HighPart = 0;
1179 header.Size.LowPart = sd_size;
1180 header.dwStreamNameSize = 0;
1181 if (!BackupWrite (fh, (LPBYTE) &header,
1182 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER),
1183 &bytes_written, FALSE, TRUE, &context))
1184 {
1185 __seterrno ();
1186 CloseHandle (fh);
1187 return -1;
1188 }
1189
1190 /* write new security descriptor */
1191 if (!BackupWrite (fh, (LPBYTE) sd_buf,
1192 header.Size.LowPart + header.dwStreamNameSize,
1193 &bytes_written, FALSE, TRUE, &context))
1194 {
1195 /* Samba returns ERROR_NOT_SUPPORTED.
1196 FAT returns ERROR_INVALID_SECURITY_DESCR.
1197 This shouldn't return as error, but better be ignored. */
1198 DWORD ret = GetLastError ();
1199 if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR)
1200 {
1201 __seterrno ();
1202 BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context);
1203 CloseHandle (fh);
1204 return -1;
1205 }
1206 }
1207
1208 /* terminate the restore process */
1209 BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context);
1210 CloseHandle (fh);
1211 return 0;
1212 }
1213
1214 static void
1215 get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
1216 PSID group_sid, BOOL grp_member)
1217 {
1218 ACCESS_ALLOWED_ACE *ace;
1219 int allow = 0;
1220 int deny = 0;
1221 int *flags, *anti;
1222
1223 for (DWORD i = 0; i < acl->AceCount; ++i)
1224 {
1225 if (!GetAce (acl, i, (PVOID *) &ace))
1226 continue;
1227 if (ace->Header.AceFlags & INHERIT_ONLY)
1228 continue;
1229 switch (ace->Header.AceType)
1230 {
1231 case ACCESS_ALLOWED_ACE_TYPE:
1232 flags = &allow;
1233 anti = &deny;
1234 break;
1235 case ACCESS_DENIED_ACE_TYPE:
1236 flags = &deny;
1237 anti = &allow;
1238 break;
1239 default:
1240 continue;
1241 }
1242
1243 cygpsid ace_sid ((PSID) &ace->SidStart);
1244 if (ace_sid == well_known_world_sid)
1245 {
1246 if (ace->Mask & FILE_READ_DATA)
1247 *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0)
1248 | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
1249 | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
1250 if (ace->Mask & FILE_WRITE_DATA)
1251 *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0)
1252 | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
1253 | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
1254 if (ace->Mask & FILE_EXECUTE)
1255 *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0)
1256 | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
1257 | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
1258 if ((S_ISDIR (*attribute)) &&
1259 (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD))
1260 == (FILE_WRITE_DATA | FILE_EXECUTE))
1261 *flags |= S_ISVTX;
1262 }
1263 else if (ace_sid == well_known_null_sid)
1264 {
1265 /* Read SUID, SGID and VTX bits from NULL ACE. */
1266 if (ace->Mask & FILE_READ_DATA)
1267 *flags |= S_ISVTX;
1268 if (ace->Mask & FILE_WRITE_DATA)
1269 *flags |= S_ISGID;
1270 if (ace->Mask & FILE_APPEND_DATA)
1271 *flags |= S_ISUID;
1272 }
1273 else if (ace_sid == owner_sid)
1274 {
1275 if (ace->Mask & FILE_READ_DATA)
1276 *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
1277 if (ace->Mask & FILE_WRITE_DATA)
1278 *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
1279 if (ace->Mask & FILE_EXECUTE)
1280 *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
1281 }
1282 else if (ace_sid == group_sid)
1283 {
1284 if (ace->Mask & FILE_READ_DATA)
1285 *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
1286 | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
1287 if (ace->Mask & FILE_WRITE_DATA)
1288 *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
1289 | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
1290 if (ace->Mask & FILE_EXECUTE)
1291 *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
1292 | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
1293 }
1294 }
1295 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
1296 if (owner_sid && group_sid && EqualSid (owner_sid, group_sid)
1297 /* FIXME: temporary exception for /var/empty */
1298 && well_known_system_sid != group_sid)
1299 {
1300 allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
1301 allow |= (((allow & S_IRUSR) ? S_IRGRP : 0)
1302 | ((allow & S_IWUSR) ? S_IWGRP : 0)
1303 | ((allow & S_IXUSR) ? S_IXGRP : 0));
1304 }
1305 *attribute |= allow;
1306 return;
1307 }
1308
1309 static void
1310 get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute,
1311 __uid32_t *uidret, __gid32_t *gidret)
1312 {
1313 if (!psd)
1314 {
1315 /* If reading the security descriptor failed, treat the object
1316 as unreadable. */
1317 if (attribute)
1318 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
1319 if (uidret)
1320 *uidret = ILLEGAL_UID;
1321 if (gidret)
1322 *gidret = ILLEGAL_GID;
1323 return;
1324 }
1325
1326 cygpsid owner_sid;
1327 cygpsid group_sid;
1328 BOOL dummy;
1329
1330 if (!GetSecurityDescriptorOwner (psd, (PSID *) &owner_sid, &dummy))
1331 debug_printf ("GetSecurityDescriptorOwner %E");
1332 if (!GetSecurityDescriptorGroup (psd, (PSID *) &group_sid, &dummy))
1333 debug_printf ("GetSecurityDescriptorGroup %E");
1334
1335 __uid32_t uid;
1336 __gid32_t gid;
1337 BOOL grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid);
1338 if (uidret)
1339 *uidret = uid;
1340 if (gidret)
1341 *gidret = gid;
1342
1343 if (!attribute)
1344 {
1345 syscall_printf ("uid %d, gid %d", uid, gid);
1346 return;
1347 }
1348
1349 PACL acl;
1350 BOOL acl_exists;
1351
1352 if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy))
1353 {
1354 __seterrno ();
1355 debug_printf ("GetSecurityDescriptorDacl %E");
1356 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
1357 }
1358 else if (!acl_exists || !acl)
1359 *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
1360 else
1361 get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
1362
1363 syscall_printf ("%sACL = %x, uid %d, gid %d",
1364 (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid);
1365 return;
1366 }
1367
1368 static void
1369 get_nt_attribute (const char *file, mode_t *attribute,
1370 __uid32_t *uidret, __gid32_t *gidret)
1371 {
1372 /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */
1373 DWORD sd_size = 4096;
1374 char sd_buf[4096];
1375 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1376
1377 if (read_sd (file, psd, &sd_size) <= 0)
1378 {
1379 debug_printf ("read_sd %E");
1380 psd = NULL;
1381 }
1382
1383 get_info_from_sd (psd, attribute, uidret, gidret);
1384 return;
1385 }
1386
1387 int
1388 get_file_attribute (int use_ntsec, const char *file,
1389 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
1390 {
1391 int res;
1392 syscall_printf ("file: %s", file);
1393
1394 if (use_ntsec && allow_ntsec && wincap.has_security ())
1395 {
1396 get_nt_attribute (file, attribute, uidret, gidret);
1397 return 0;
1398 }
1399
1400 if (uidret)
1401 *uidret = myself->uid;
1402 if (gidret)
1403 *gidret = myself->gid;
1404
1405 if (!attribute)
1406 return 0;
1407
1408 if (allow_ntea)
1409 {
1410 int oatt = *attribute;
1411 res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute));
1412 *attribute |= oatt;
1413 }
1414 else
1415 res = 0;
1416
1417 return res > 0 ? 0 : -1;
1418 }
1419
1420 static void
1421 get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
1422 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
1423 {
1424 PSECURITY_DESCRIPTOR psd;
1425 char sd_buf[4096];
1426
1427 if (object_type == SE_REGISTRY_KEY)
1428 {
1429 /* use different code for registry handles, for performance reasons */
1430 psd = (PSECURITY_DESCRIPTOR) & sd_buf[0];
1431 DWORD len = sizeof (sd_buf);
1432 if (ERROR_SUCCESS != RegGetKeySecurity ((HKEY) handle,
1433 DACL_SECURITY_INFORMATION |
1434 GROUP_SECURITY_INFORMATION |
1435 OWNER_SECURITY_INFORMATION,
1436 psd, &len))
1437 {
1438 __seterrno ();
1439 debug_printf ("RegGetKeySecurity %E");
1440 psd = NULL;
1441 }
1442 }
1443 else
1444 {
1445 if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type,
1446 DACL_SECURITY_INFORMATION |
1447 GROUP_SECURITY_INFORMATION |
1448 OWNER_SECURITY_INFORMATION,
1449 NULL, NULL, NULL, NULL, &psd))
1450 {
1451 __seterrno ();
1452 debug_printf ("GetSecurityInfo %E");
1453 psd = NULL;
1454 }
1455 }
1456
1457 get_info_from_sd (psd, attribute, uidret, gidret);
1458 if (psd != (PSECURITY_DESCRIPTOR) & sd_buf[0])
1459 LocalFree (psd);
1460
1461 return;
1462 }
1463
1464 int
1465 get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
1466 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
1467 {
1468 if (allow_ntsec && wincap.has_security ())
1469 {
1470 get_nt_object_attribute (handle, object_type, attribute, uidret, gidret);
1471 return 0;
1472 }
1473 /* The entries are already set to default values */
1474 return -1;
1475 }
1476
1477 BOOL
1478 add_access_allowed_ace (PACL acl, int offset, DWORD attributes,
1479 PSID sid, size_t &len_add, DWORD inherit)
1480 {
1481 if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid))
1482 {
1483 __seterrno ();
1484 return FALSE;
1485 }
1486 ACCESS_ALLOWED_ACE *ace;
1487 if (inherit && GetAce (acl, offset, (PVOID *) &ace))
1488 ace->Header.AceFlags |= inherit;
1489 len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
1490 return TRUE;
1491 }
1492
1493 BOOL
1494 add_access_denied_ace (PACL acl, int offset, DWORD attributes,
1495 PSID sid, size_t &len_add, DWORD inherit)
1496 {
1497 if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid))
1498 {
1499 __seterrno ();
1500 return FALSE;
1501 }
1502 ACCESS_DENIED_ACE *ace;
1503 if (inherit && GetAce (acl, offset, (PVOID *) &ace))
1504 ace->Header.AceFlags |= inherit;
1505 len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
1506 return TRUE;
1507 }
1508
1509 PSECURITY_DESCRIPTOR
1510 alloc_sd (__uid32_t uid, __gid32_t gid, int attribute,
1511 PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret)
1512 {
1513 BOOL dummy;
1514
1515 debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute);
1516 if (!sd_ret || !sd_size_ret)
1517 {
1518 set_errno (EINVAL);
1519 return NULL;
1520 }
1521
1522 /* Get owner and group from current security descriptor. */
1523 PSID cur_owner_sid = NULL;
1524 PSID cur_group_sid = NULL;
1525 if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy))
1526 debug_printf ("GetSecurityDescriptorOwner %E");
1527 if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy))
1528 debug_printf ("GetSecurityDescriptorGroup %E");
1529
1530 /* Get SID of owner. */
1531 cygsid owner_sid;
1532 /* Check for current user first */
1533 if (uid == myself->uid)
1534 owner_sid = cygheap->user.sid ();
1535 else if (uid == ILLEGAL_UID)
1536 owner_sid = cur_owner_sid;
1537 else if (!owner_sid.getfrompw (internal_getpwuid (uid)))
1538 {
1539 set_errno (EINVAL);
1540 return NULL;
1541 }
1542 owner_sid.debug_print ("alloc_sd: owner SID =");
1543
1544 /* Get SID of new group. */
1545 cygsid group_sid;
1546 /* Check for current user first */
1547 if (gid == myself->gid)
1548 group_sid = cygheap->user.groups.pgsid;
1549 else if (gid == ILLEGAL_GID)
1550 group_sid = cur_group_sid;
1551 else if (!group_sid.getfromgr (internal_getgrgid (gid)))
1552 {
1553 set_errno (EINVAL);
1554 return NULL;
1555 }
1556 group_sid.debug_print ("alloc_sd: group SID =");
1557
1558 /* Initialize local security descriptor. */
1559 SECURITY_DESCRIPTOR sd;
1560 if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
1561 {
1562 __seterrno ();
1563 return NULL;
1564 }
1565
1566 /*
1567 * We set the SE_DACL_PROTECTED flag here to prevent the DACL from being
1568 * modified by inheritable ACEs.
1569 * This flag as well as the SetSecurityDescriptorControl call are available
1570 * only since Win2K.
1571 */
1572 if (wincap.has_security_descriptor_control ())
1573 SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
1574
1575 /* Create owner for local security descriptor. */
1576 if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE))
1577 {
1578 __seterrno ();
1579 return NULL;
1580 }
1581
1582 /* Create group for local security descriptor. */
1583 if (!SetSecurityDescriptorGroup (&sd, group_sid, FALSE))
1584 {
1585 __seterrno ();
1586 return NULL;
1587 }
1588
1589 /* Initialize local access control list. */
1590 char acl_buf[3072];
1591 PACL acl = (PACL) acl_buf;
1592 if (!InitializeAcl (acl, 3072, ACL_REVISION))
1593 {
1594 __seterrno ();
1595 return NULL;
1596 }
1597
1598 /* From here fill ACL. */
1599 size_t acl_len = sizeof (ACL);
1600 int ace_off = 0;
1601
1602 /* Construct allow attribute for owner. */
1603 DWORD owner_allow = STANDARD_RIGHTS_ALL
1604 | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
1605 if (attribute & S_IRUSR)
1606 owner_allow |= FILE_GENERIC_READ;
1607 if (attribute & S_IWUSR)
1608 owner_allow |= FILE_GENERIC_WRITE;
1609 if (attribute & S_IXUSR)
1610 owner_allow |= FILE_GENERIC_EXECUTE;
1611 if (S_ISDIR (attribute)
1612 && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR))
1613 owner_allow |= FILE_DELETE_CHILD;
1614
1615 /* Construct allow attribute for group. */
1616 DWORD group_allow = STANDARD_RIGHTS_READ
1617 | FILE_READ_ATTRIBUTES | FILE_READ_EA;
1618 if (attribute & S_IRGRP)
1619 group_allow |= FILE_GENERIC_READ;
1620 if (attribute & S_IWGRP)
1621 group_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
1622 if (attribute & S_IXGRP)
1623 group_allow |= FILE_GENERIC_EXECUTE;
1624 if (S_ISDIR (attribute)
1625 && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP)
1626 && !(attribute & S_ISVTX))
1627 group_allow |= FILE_DELETE_CHILD;
1628
1629 /* Construct allow attribute for everyone. */
1630 DWORD other_allow = STANDARD_RIGHTS_READ
1631 | FILE_READ_ATTRIBUTES | FILE_READ_EA;
1632 if (attribute & S_IROTH)
1633 other_allow |= FILE_GENERIC_READ;
1634 if (attribute & S_IWOTH)
1635 other_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
1636 if (attribute & S_IXOTH)
1637 other_allow |= FILE_GENERIC_EXECUTE;
1638 if (S_ISDIR (attribute)
1639 && (attribute & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
1640 && !(attribute & S_ISVTX))
1641 other_allow |= FILE_DELETE_CHILD;
1642
1643 /* Construct SUID, SGID and VTX bits in NULL ACE. */
1644 DWORD null_allow = 0L;
1645 if (attribute & (S_ISUID | S_ISGID | S_ISVTX))
1646 {
1647 if (attribute & S_ISUID)
1648 null_allow |= FILE_APPEND_DATA;
1649 if (attribute & S_ISGID)
1650 null_allow |= FILE_WRITE_DATA;
1651 if (attribute & S_ISVTX)
1652 null_allow |= FILE_READ_DATA;
1653 }
1654
1655 /* Add owner and group permissions if SIDs are equal
1656 and construct deny attributes for group and owner. */
1657 BOOL isownergroup;
1658 if ((isownergroup = (owner_sid == group_sid)))
1659 owner_allow |= group_allow;
1660
1661 DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
1662 owner_deny &= ~(STANDARD_RIGHTS_READ
1663 | FILE_READ_ATTRIBUTES | FILE_READ_EA
1664 | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA);
1665
1666 DWORD group_deny = ~group_allow & other_allow;
1667 group_deny &= ~(STANDARD_RIGHTS_READ
1668 | FILE_READ_ATTRIBUTES | FILE_READ_EA);
1669
1670 /* Set deny ACE for owner. */
1671 if (owner_deny
1672 && !add_access_denied_ace (acl, ace_off++, owner_deny,
1673 owner_sid, acl_len, NO_INHERITANCE))
1674 return NULL;
1675 /* Set deny ACE for group here to respect the canonical order,
1676 if this does not impact owner */
1677 if (group_deny && !(group_deny & owner_allow) && !isownergroup
1678 && !add_access_denied_ace (acl, ace_off++, group_deny,
1679 group_sid, acl_len, NO_INHERITANCE))
1680 return NULL;
1681 /* Set allow ACE for owner. */
1682 if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
1683 owner_sid, acl_len, NO_INHERITANCE))
1684 return NULL;
1685 /* Set deny ACE for group, if still needed. */
1686 if (group_deny & owner_allow && !isownergroup
1687 && !add_access_denied_ace (acl, ace_off++, group_deny,
1688 group_sid, acl_len, NO_INHERITANCE))
1689 return NULL;
1690 /* Set allow ACE for group. */
1691 if (!isownergroup
1692 && !add_access_allowed_ace (acl, ace_off++, group_allow,
1693 group_sid, acl_len, NO_INHERITANCE))
1694 return NULL;
1695
1696 /* Set allow ACE for everyone. */
1697 if (!add_access_allowed_ace (acl, ace_off++, other_allow,
1698 well_known_world_sid, acl_len, NO_INHERITANCE))
1699 return NULL;
1700 /* Set null ACE for special bits. */
1701 if (null_allow
1702 && !add_access_allowed_ace (acl, ace_off++, null_allow,
1703 well_known_null_sid, acl_len, NO_INHERITANCE))
1704 return NULL;
1705
1706 /* Fill ACL with unrelated ACEs from current security descriptor. */
1707 PACL oacl;
1708 BOOL acl_exists = FALSE;
1709 ACCESS_ALLOWED_ACE *ace;
1710 if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy)
1711 && acl_exists && oacl)
1712 for (DWORD i = 0; i < oacl->AceCount; ++i)
1713 if (GetAce (oacl, i, (PVOID *) &ace))
1714 {
1715 cygpsid ace_sid ((PSID) &ace->SidStart);
1716
1717 /* Check for related ACEs. */
1718 if (ace_sid == well_known_null_sid)
1719 continue;
1720 if ((ace_sid == cur_owner_sid)
1721 || (ace_sid == owner_sid)
1722 || (ace_sid == cur_group_sid)
1723 || (ace_sid == group_sid)
1724 || (ace_sid == well_known_world_sid))
1725 {
1726 if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
1727 ace->Header.AceFlags |= INHERIT_ONLY;
1728 else
1729 continue;
1730 }
1731 /*
1732 * Add unrelated ACCESS_DENIED_ACE to the beginning but
1733 * behind the owner_deny, ACCESS_ALLOWED_ACE to the end.
1734 * FIXME: this would break the order of the inherit_only ACEs
1735 */
1736 if (!AddAce (acl, ACL_REVISION,
1737 ace->Header.AceType == ACCESS_DENIED_ACE_TYPE?
1738 (owner_deny ? 1 : 0) : MAXDWORD,
1739 (LPVOID) ace, ace->Header.AceSize))
1740 {
1741 __seterrno ();
1742 return NULL;
1743 }
1744 acl_len += ace->Header.AceSize;
1745 }
1746
1747 /* Construct appropriate inherit attribute for new directories */
1748 if (S_ISDIR (attribute) && !acl_exists )
1749 {
1750 const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY;
1751
1752 #if 0 /* FIXME: Not done currently as this breaks the canonical order */
1753 /* Set deny ACE for owner. */
1754 if (owner_deny
1755 && !add_access_denied_ace (acl, ace_off++, owner_deny,
1756 well_known_creator_owner_sid, acl_len, inherit))
1757 return NULL;
1758 /* Set deny ACE for group here to respect the canonical order,
1759 if this does not impact owner */
1760 if (group_deny && !(group_deny & owner_allow)
1761 && !add_access_denied_ace (acl, ace_off++, group_deny,
1762 well_known_creator_group_sid, acl_len, inherit))
1763 return NULL;
1764 #endif
1765 /* Set allow ACE for owner. */
1766 if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
1767 well_known_creator_owner_sid, acl_len, inherit))
1768 return NULL;
1769 #if 0 /* FIXME: Not done currently as this breaks the canonical order and
1770 won't be preserved on chown and chmod */
1771 /* Set deny ACE for group, conflicting with owner_allow. */
1772 if (group_deny & owner_allow
1773 && !add_access_denied_ace (acl, ace_off++, group_deny,
1774 well_known_creator_group_sid, acl_len, inherit))
1775 return NULL;
1776 #endif
1777 /* Set allow ACE for group. */
1778 if (!add_access_allowed_ace (acl, ace_off++, group_allow,
1779 well_known_creator_group_sid, acl_len, inherit))
1780 return NULL;
1781 /* Set allow ACE for everyone. */
1782 if (!add_access_allowed_ace (acl, ace_off++, other_allow,
1783 well_known_world_sid, acl_len, inherit))
1784 return NULL;
1785 }
1786
1787 /* Set AclSize to computed value. */
1788 acl->AclSize = acl_len;
1789 debug_printf ("ACL-Size: %d", acl_len);
1790
1791 /* Create DACL for local security descriptor. */
1792 if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
1793 {
1794 __seterrno ();
1795 return NULL;
1796 }
1797
1798 /* Make self relative security descriptor. */
1799 *sd_size_ret = 0;
1800 MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret);
1801 if (*sd_size_ret <= 0)
1802 {
1803 __seterrno ();
1804 return NULL;
1805 }
1806 if (!MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret))
1807 {
1808 __seterrno ();
1809 return NULL;
1810 }
1811 debug_printf ("Created SD-Size: %d", *sd_size_ret);
1812
1813 return sd_ret;
1814 }
1815
1816 void
1817 set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
1818 void *sd_buf, DWORD sd_buf_size)
1819 {
1820 psa->lpSecurityDescriptor = sd_buf;
1821 InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf,
1822 SECURITY_DESCRIPTOR_REVISION);
1823 psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute,
1824 (PSECURITY_DESCRIPTOR) sd_buf,
1825 &sd_buf_size);
1826 }
1827
1828 static int
1829 set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid,
1830 int attribute)
1831 {
1832 if (!wincap.has_security ())
1833 return 0;
1834
1835 DWORD sd_size = 4096;
1836 char sd_buf[4096];
1837 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1838
1839 int ret;
1840 if ((ret = read_sd (file, psd, &sd_size)) <= 0)
1841 {
1842 debug_printf ("read_sd %E");
1843 return -1;
1844 }
1845
1846 sd_size = 4096;
1847 if (!(psd = alloc_sd (uid, gid, attribute, psd, &sd_size)))
1848 return -1;
1849
1850 return write_sd (file, psd, sd_size);
1851 }
1852
1853 int
1854 set_file_attribute (int use_ntsec, const char *file,
1855 __uid32_t uid, __gid32_t gid, int attribute)
1856 {
1857 int ret = 0;
1858
1859 if (use_ntsec && allow_ntsec)
1860 ret = set_nt_attribute (file, uid, gid, attribute);
1861 else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute,
1862 sizeof (attribute)))
1863 {
1864 __seterrno ();
1865 ret = -1;
1866 }
1867 syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)",
1868 ret, file, uid, gid, attribute);
1869 return ret;
1870 }
1871
1872 int
1873 set_file_attribute (int use_ntsec, const char *file, int attribute)
1874 {
1875 return set_file_attribute (use_ntsec, file,
1876 myself->uid, myself->gid, attribute);
1877 }
1878
1879 int
1880 check_file_access (const char *fn, int flags)
1881 {
1882 int ret = -1;
1883 char sd_buf[4096];
1884 DWORD sd_size = sizeof sd_buf;
1885 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1886 HANDLE hToken, hIToken;
1887 BOOL status;
1888 char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)];
1889 DWORD desired = 0, granted, plength = sizeof pbuf;
1890 static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ,
1891 FILE_GENERIC_WRITE,
1892 FILE_GENERIC_EXECUTE,
1893 FILE_ALL_ACCESS };
1894 if (read_sd (fn, psd, &sd_size) <= 0)
1895 goto done;
1896
1897 if (cygheap->user.issetuid ())
1898 hToken = cygheap->user.token ();
1899 else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken))
1900 {
1901 __seterrno ();
1902 goto done;
1903 }
1904 if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken)))
1905 __seterrno ();
1906 if (!cygheap->user.issetuid ())
1907 CloseHandle (hToken);
1908 if (!status)
1909 goto done;
1910
1911 if (flags & R_OK)
1912 desired |= FILE_READ_DATA;
1913 if (flags & W_OK)
1914 desired |= FILE_WRITE_DATA;
1915 if (flags & X_OK)
1916 desired |= FILE_EXECUTE;
1917 if (!AccessCheck (psd, hIToken, desired, &mapping,
1918 (PPRIVILEGE_SET) pbuf, &plength, &granted, &status))
1919 __seterrno ();
1920 else if (!status)
1921 set_errno (EACCES);
1922 else
1923 ret = 0;
1924 CloseHandle (hIToken);
1925 done:
1926 debug_printf ("flags %x, ret %d", flags, ret);
1927 return ret;
1928 }
This page took 0.144118 seconds and 5 git commands to generate.