OSDN Git Service

* select.cc (select_stuff::wait): Temporarily disallow APCS.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / sec_helper.cc
1 /* sec_helper.cc: NT security helper functions
2
3    Copyright 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009,
4    2010, 2011 Red Hat, Inc.
5
6    Written 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 <stdlib.h>
16 #include <sys/acl.h>
17 #include <wchar.h>
18 #include "cygerrno.h"
19 #include "security.h"
20 #include "path.h"
21 #include "fhandler.h"
22 #include "dtable.h"
23 #include "pinfo.h"
24 #include "cygheap.h"
25 #include "pwdgrp.h"
26 #include "ntdll.h"
27
28 /* General purpose security attribute objects for global use. */
29 SECURITY_ATTRIBUTES NO_COPY sec_none;
30 SECURITY_ATTRIBUTES NO_COPY sec_none_nih;
31 SECURITY_ATTRIBUTES NO_COPY sec_all;
32 SECURITY_ATTRIBUTES NO_COPY sec_all_nih;
33
34 MKSID (well_known_null_sid, "S-1-0-0",
35        SECURITY_NULL_SID_AUTHORITY, 1, SECURITY_NULL_RID);
36 MKSID (well_known_world_sid, "S-1-1-0",
37        SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID);
38 MKSID (well_known_local_sid, "S-1-2-0",
39        SECURITY_LOCAL_SID_AUTHORITY, 1, SECURITY_LOCAL_RID);
40 MKSID (well_known_console_logon_sid, "S-1-2-1",
41        SECURITY_LOCAL_SID_AUTHORITY, 1, 1);
42 MKSID (well_known_creator_owner_sid, "S-1-3-0",
43        SECURITY_CREATOR_SID_AUTHORITY, 1, SECURITY_CREATOR_OWNER_RID);
44 MKSID (well_known_creator_group_sid, "S-1-3-1",
45        SECURITY_CREATOR_SID_AUTHORITY, 1, SECURITY_CREATOR_GROUP_RID);
46 MKSID (well_known_dialup_sid, "S-1-5-1",
47        SECURITY_NT_AUTHORITY, 1, SECURITY_DIALUP_RID);
48 MKSID (well_known_network_sid, "S-1-5-2",
49        SECURITY_NT_AUTHORITY, 1, SECURITY_NETWORK_RID);
50 MKSID (well_known_batch_sid, "S-1-5-3",
51        SECURITY_NT_AUTHORITY, 1, SECURITY_BATCH_RID);
52 MKSID (well_known_interactive_sid, "S-1-5-4",
53        SECURITY_NT_AUTHORITY, 1, SECURITY_INTERACTIVE_RID);
54 MKSID (well_known_service_sid, "S-1-5-6",
55        SECURITY_NT_AUTHORITY, 1, SECURITY_SERVICE_RID);
56 MKSID (well_known_authenticated_users_sid, "S-1-5-11",
57        SECURITY_NT_AUTHORITY, 1, SECURITY_AUTHENTICATED_USER_RID);
58 MKSID (well_known_this_org_sid, "S-1-5-15",
59        SECURITY_NT_AUTHORITY, 1, 15);
60 MKSID (well_known_system_sid, "S-1-5-18",
61        SECURITY_NT_AUTHORITY, 1, SECURITY_LOCAL_SYSTEM_RID);
62 MKSID (well_known_builtin_sid, "S-1-5-32",
63        SECURITY_NT_AUTHORITY, 1, SECURITY_BUILTIN_DOMAIN_RID);
64 MKSID (well_known_admins_sid, "S-1-5-32-544",
65        SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID,
66                                  DOMAIN_ALIAS_RID_ADMINS);
67 MKSID (well_known_users_sid, "S-1-5-32-545",
68        SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID,
69                                  DOMAIN_ALIAS_RID_USERS);
70 MKSID (fake_logon_sid, "S-1-5-5-0-0",
71        SECURITY_NT_AUTHORITY, 3, SECURITY_LOGON_IDS_RID, 0, 0);
72 MKSID (mandatory_medium_integrity_sid, "S-1-16-8192",
73        SECURITY_MANDATORY_LABEL_AUTHORITY, 1, SECURITY_MANDATORY_MEDIUM_RID);
74 MKSID (mandatory_high_integrity_sid, "S-1-16-12288",
75        SECURITY_MANDATORY_LABEL_AUTHORITY, 1, SECURITY_MANDATORY_HIGH_RID);
76 MKSID (mandatory_system_integrity_sid, "S-1-16-16384",
77        SECURITY_MANDATORY_LABEL_AUTHORITY, 1, SECURITY_MANDATORY_SYSTEM_RID);
78 /* UNIX accounts on a Samba server have the SID prefix "S-1-22-1" */
79 #define SECURITY_SAMBA_UNIX_AUTHORITY {0,0,0,0,0,22}
80 MKSID (well_known_samba_unix_user_fake_sid, "S-1-22-1-0",
81        SECURITY_SAMBA_UNIX_AUTHORITY, 2, 1, 0);
82
83 bool
84 cygpsid::operator== (const char *nsidstr) const
85 {
86   cygsid nsid (nsidstr);
87   return psid == nsid;
88 }
89
90 __uid32_t
91 cygpsid::get_id (BOOL search_grp, int *type)
92 {
93     /* First try to get SID from group, then passwd */
94   __uid32_t id = ILLEGAL_UID;
95
96   if (search_grp)
97     {
98       struct __group32 *gr;
99       if (cygheap->user.groups.pgsid == psid)
100         id = myself->gid;
101       else if ((gr = internal_getgrsid (*this)))
102         id = gr->gr_gid;
103       if (id != ILLEGAL_UID)
104         {
105           if (type)
106             *type = GROUP;
107           return id;
108         }
109     }
110   if (!search_grp || type)
111     {
112       struct passwd *pw;
113       if (*this == cygheap->user.sid ())
114         id = myself->uid;
115       else if ((pw = internal_getpwsid (*this)))
116         id = pw->pw_uid;
117       if (id != ILLEGAL_UID && type)
118         *type = USER;
119     }
120   return id;
121 }
122
123 PWCHAR
124 cygpsid::string (PWCHAR nsidstr) const
125 {
126   UNICODE_STRING sid;
127
128   if (!psid || !nsidstr)
129     return NULL;
130   RtlInitEmptyUnicodeString (&sid, nsidstr, 256);
131   RtlConvertSidToUnicodeString (&sid, psid, FALSE);
132   return nsidstr;
133 }
134
135 char *
136 cygpsid::string (char *nsidstr) const
137 {
138   char *t;
139   DWORD i;
140
141   if (!psid || !nsidstr)
142     return NULL;
143   strcpy (nsidstr, "S-1-");
144   t = nsidstr + sizeof ("S-1-") - 1;
145   t += __small_sprintf (t, "%u", RtlIdentifierAuthoritySid (psid)->Value[5]);
146   for (i = 0; i < *RtlSubAuthorityCountSid (psid); ++i)
147     t += __small_sprintf (t, "-%lu", *RtlSubAuthoritySid (psid, i));
148   return nsidstr;
149 }
150
151 PSID
152 cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known)
153 {
154   DWORD i;
155   SID_IDENTIFIER_AUTHORITY sid_auth = { SECURITY_NULL_SID_AUTHORITY };
156 # define SECURITY_NT_AUTH 5
157
158   if (s > 255 || cnt < 1 || cnt > 8)
159     {
160       psid = NO_SID;
161       return NULL;
162     }
163   sid_auth.Value[5] = s;
164   set ();
165   RtlInitializeSid (psid, &sid_auth, cnt);
166   for (i = 0; i < cnt; ++i)
167     memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD));
168   /* If the well_known flag isn't set explicitely, we check the SID
169      for being a well-known SID ourselves. That's necessary because this
170      cygsid is created from a SID string, usually from /etc/passwd or
171      /etc/group.  The calling code just doesn't know if the SID is well-known
172      or not.  All SIDs are well-known SIDs, except those in the non-unique NT
173      authority range. */
174   if (well_known)
175     well_known_sid = well_known;
176   else
177     well_known_sid = (s != SECURITY_NT_AUTH
178                       || r[0] != SECURITY_NT_NON_UNIQUE_RID);
179   return psid;
180 }
181
182 const PSID
183 cygsid::getfromstr (const char *nsidstr, bool well_known)
184 {
185   char *lasts;
186   DWORD s, cnt = 0;
187   DWORD r[8];
188
189   if (nsidstr && !strncmp (nsidstr, "S-1-", 4))
190     {
191       s = strtoul (nsidstr + 4, &lasts, 10);
192       while (cnt < 8 && *lasts == '-')
193         r[cnt++] = strtoul (lasts + 1, &lasts, 10);
194       if (!*lasts)
195         return get_sid (s, cnt, r, well_known);
196     }
197   return psid = NO_SID;
198 }
199
200 BOOL
201 cygsid::getfrompw (const struct passwd *pw)
202 {
203   char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL;
204   return (*this = sp ? sp + 1 : sp) != NULL;
205 }
206
207 BOOL
208 cygsid::getfromgr (const struct __group32 *gr)
209 {
210   char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL;
211   return (*this = sp) != NULL;
212 }
213
214 cygsid *
215 cygsidlist::alloc_sids (int n)
216 {
217   if (n > 0)
218     return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
219   else
220     return NULL;
221 }
222
223 void
224 cygsidlist::free_sids ()
225 {
226   if (sids)
227     cfree (sids);
228   sids = NULL;
229   cnt = maxcnt = 0;
230   type = cygsidlist_empty;
231 }
232
233 BOOL
234 cygsidlist::add (const PSID nsi, bool well_known)
235 {
236   if (contains (nsi))
237     return TRUE;
238   if (cnt >= maxcnt)
239     {
240       cygsid *tmp = new cygsid [2 * maxcnt];
241       if (!tmp)
242         return FALSE;
243       maxcnt *= 2;
244       for (int i = 0; i < cnt; ++i)
245         tmp[i] = sids[i];
246       delete [] sids;
247       sids = tmp;
248     }
249   if (well_known)
250     sids[cnt++] *= nsi;
251   else
252     sids[cnt++] = nsi;
253   return TRUE;
254 }
255
256 bool
257 get_sids_info (cygpsid owner_sid, cygpsid group_sid, __uid32_t * uidret, __gid32_t * gidret)
258 {
259   struct passwd *pw;
260   struct __group32 *gr = NULL;
261   bool ret = false;
262
263   owner_sid.debug_print ("get_sids_info: owner SID =");
264   group_sid.debug_print ("get_sids_info: group SID =");
265
266   if (group_sid == cygheap->user.groups.pgsid)
267     *gidret = myself->gid;
268   else if ((gr = internal_getgrsid (group_sid)))
269     *gidret = gr->gr_gid;
270   else
271     *gidret = ILLEGAL_GID;
272
273   if (owner_sid == cygheap->user.sid ())
274     {
275       *uidret = myself->uid;
276       if (*gidret == myself->gid)
277         ret = true;
278       else
279         ret = (internal_getgroups (0, NULL, &group_sid) > 0);
280     }
281   else if ((pw = internal_getpwsid (owner_sid)))
282     {
283       *uidret = pw->pw_uid;
284       if (gr || (*gidret != ILLEGAL_GID
285                  && (gr = internal_getgrgid (*gidret))))
286         for (int idx = 0; gr->gr_mem[idx]; ++idx)
287           if ((ret = strcasematch (pw->pw_name, gr->gr_mem[idx])))
288             break;
289     }
290   else
291     *uidret = ILLEGAL_UID;
292
293   return ret;
294 }
295
296 PSECURITY_DESCRIPTOR
297 security_descriptor::malloc (size_t nsize)
298 {
299   free ();
300   if ((psd = (PSECURITY_DESCRIPTOR) ::malloc (nsize)))
301     sd_size = nsize;
302   return psd;
303 }
304
305 PSECURITY_DESCRIPTOR
306 security_descriptor::realloc (size_t nsize)
307 {
308   PSECURITY_DESCRIPTOR tmp;
309
310   /* Can't re-use buffer allocated by GetSecurityInfo. */
311   if (psd && !sd_size)
312     free ();
313   if (!(tmp = (PSECURITY_DESCRIPTOR) ::realloc (psd, nsize)))
314     return NULL;
315   sd_size = nsize;
316   return psd = tmp;
317 }
318
319 void
320 security_descriptor::free ()
321 {
322   if (psd)
323     {
324       if (!sd_size)
325         LocalFree (psd);
326       else
327         ::free (psd);
328     }
329   psd = NULL;
330   sd_size = 0;
331 }
332
333 #undef TEXT
334 #define TEXT(q) L##q
335
336 /* Index must match the corresponding foo_PRIVILEGE value, see security.h. */
337 static const struct {
338   const wchar_t *name;
339   bool           high_integrity; /* UAC: High Mandatory Label required to 
340                                     be allowed to enable this privilege in
341                                     the user token. */
342 } cygpriv[] =
343 {
344   { L"",                                false },
345   { L"",                                false },
346   { SE_CREATE_TOKEN_NAME,               true  },
347   { SE_ASSIGNPRIMARYTOKEN_NAME,         true  },
348   { SE_LOCK_MEMORY_NAME,                false },
349   { SE_INCREASE_QUOTA_NAME,             true  },
350   { SE_MACHINE_ACCOUNT_NAME,            false },
351   { SE_TCB_NAME,                        true  },
352   { SE_SECURITY_NAME,                   true  },
353   { SE_TAKE_OWNERSHIP_NAME,             true  },
354   { SE_LOAD_DRIVER_NAME,                true  },
355   { SE_SYSTEM_PROFILE_NAME,             true  },
356   { SE_SYSTEMTIME_NAME,                 true  },
357   { SE_PROF_SINGLE_PROCESS_NAME,        true  },
358   { SE_INC_BASE_PRIORITY_NAME,          true  },
359   { SE_CREATE_PAGEFILE_NAME,            true  },
360   { SE_CREATE_PERMANENT_NAME,           false },
361   { SE_BACKUP_NAME,                     true  },
362   { SE_RESTORE_NAME,                    true  },
363   { SE_SHUTDOWN_NAME,                   false },
364   { SE_DEBUG_NAME,                      true  },
365   { SE_AUDIT_NAME,                      false },
366   { SE_SYSTEM_ENVIRONMENT_NAME,         true  },
367   { SE_CHANGE_NOTIFY_NAME,              false },
368   { SE_REMOTE_SHUTDOWN_NAME,            true  },
369   { SE_UNDOCK_NAME,                     false },
370   { SE_SYNC_AGENT_NAME,                 false },
371   { SE_ENABLE_DELEGATION_NAME,          false },
372   { SE_MANAGE_VOLUME_NAME,              true  },
373   { SE_IMPERSONATE_NAME,                true  },
374   { SE_CREATE_GLOBAL_NAME,              false },
375   { SE_TRUSTED_CREDMAN_ACCESS_NAME,     false },
376   { SE_RELABEL_NAME,                    true  },
377   { SE_INCREASE_WORKING_SET_NAME,       false },
378   { SE_TIME_ZONE_NAME,                  true  },
379   { SE_CREATE_SYMBOLIC_LINK_NAME,       true  }
380 };
381
382 bool
383 privilege_luid (const PWCHAR pname, LUID &luid, bool &high_integrity)
384 {
385   ULONG idx;
386   for (idx = SE_CREATE_TOKEN_PRIVILEGE;
387        idx <= SE_MAX_WELL_KNOWN_PRIVILEGE;
388        ++idx)
389     if (!wcscmp (cygpriv[idx].name, pname))
390       {
391         luid.HighPart = 0;
392         luid.LowPart = idx;
393         high_integrity = cygpriv[idx].high_integrity;
394         return true;
395       }
396   return false;
397 }
398
399 static const wchar_t *
400 privilege_name (const LUID &priv_luid)
401 {
402   if (priv_luid.HighPart || priv_luid.LowPart < SE_CREATE_TOKEN_PRIVILEGE
403       || priv_luid.LowPart > SE_MAX_WELL_KNOWN_PRIVILEGE)
404     return L"<unknown privilege>";
405   return cygpriv[priv_luid.LowPart].name;
406 }
407
408 int
409 set_privilege (HANDLE token, DWORD privilege, bool enable)
410 {
411   int ret = -1;
412   TOKEN_PRIVILEGES new_priv, orig_priv;
413   ULONG size;
414   NTSTATUS status;
415
416   new_priv.PrivilegeCount = 1;
417   new_priv.Privileges[0].Luid.HighPart = 0L;
418   new_priv.Privileges[0].Luid.LowPart = privilege;
419   new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
420
421   status = NtAdjustPrivilegesToken (token, FALSE, &new_priv, sizeof orig_priv,
422                                     &orig_priv, &size);
423   if (!NT_SUCCESS (status))
424     {
425       __seterrno_from_nt_status (status);
426       goto out;
427     }
428
429   /* If orig_priv.PrivilegeCount is 0, the privilege hasn't been changed. */
430   if (!orig_priv.PrivilegeCount)
431     ret = enable ? 1 : 0;
432   else
433     ret = (orig_priv.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) ? 1 : 0;
434
435 out:
436   if (ret < 0)
437     debug_printf ("%d = set_privilege((token %x) %W, %d)", ret, token,
438                   privilege_name (new_priv.Privileges[0].Luid), enable);
439   return ret;
440 }
441
442 /* This is called very early in process initialization.  The code must
443    not depend on anything. */
444 void
445 set_cygwin_privileges (HANDLE token)
446 {
447   /* Setting these rights at process startup allows processes running under
448      user tokens which are in the administrstors group to have root-like
449      permissions. */
450   /* Allow to access all files, independent of their ACL settings. */
451   set_privilege (token, SE_RESTORE_PRIVILEGE, true);
452   set_privilege (token, SE_BACKUP_PRIVILEGE, true);
453   /* Allow full access to other user's processes. */
454   set_privilege (token, SE_DEBUG_PRIVILEGE, true);
455 #if 0
456   /* Allow to create global shared memory.  This isn't required anymore since
457      Cygwin 1.7.  It uses its own subdirectories in the global NT namespace
458      which isn't affected by the SE_CREATE_GLOBAL_PRIVILEGE restriction. */
459   if (wincap.has_create_global_privilege ())
460     set_privilege (token, SE_CREATE_GLOBAL_PRIVILEGE, true);
461 #endif
462 }
463
464 /* Function to return a common SECURITY_DESCRIPTOR that
465    allows all access.  */
466
467 static inline PSECURITY_DESCRIPTOR
468 get_null_sd ()
469 {
470   static NO_COPY SECURITY_DESCRIPTOR sd;
471   static NO_COPY PSECURITY_DESCRIPTOR null_sdp;
472
473   if (!null_sdp)
474     {
475       RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
476       RtlSetDaclSecurityDescriptor (&sd, TRUE, NULL, FALSE);
477       null_sdp = &sd;
478     }
479   return null_sdp;
480 }
481
482 /* Initialize global security attributes.
483    Called from dcrt0.cc (_dll_crt0).  */
484
485 void
486 init_global_security ()
487 {
488   sec_none.nLength = sec_none_nih.nLength =
489   sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
490   sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE;
491   sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE;
492   sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL;
493   sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor =
494     get_null_sd ();
495 }
496
497 bool
498 sec_acl (PACL acl, bool original, bool admins, PSID sid1, PSID sid2, DWORD access2)
499 {
500   NTSTATUS status;
501   size_t acl_len = MAX_DACL_LEN (5);
502   LPVOID pAce;
503   cygpsid psid;
504
505 #ifdef DEBUGGING
506   if ((unsigned long) acl % 4)
507     api_fatal ("Incorrectly aligned incoming ACL buffer!");
508 #endif
509   status = RtlCreateAcl (acl, acl_len, ACL_REVISION);
510   if (!NT_SUCCESS (status))
511     {
512       debug_printf ("RtlCreateAcl: %p", status);
513       return false;
514     }
515   if (sid1)
516     {
517       status = RtlAddAccessAllowedAce (acl, ACL_REVISION, GENERIC_ALL, sid1);
518       if (!NT_SUCCESS (status))
519         debug_printf ("RtlAddAccessAllowedAce(sid1) %p", status);
520     }
521   if (original && (psid = cygheap->user.saved_sid ())
522       && psid != sid1 && psid != well_known_system_sid)
523     {
524       status = RtlAddAccessAllowedAce (acl, ACL_REVISION, GENERIC_ALL, psid);
525       if (!NT_SUCCESS (status))
526         debug_printf ("RtlAddAccessAllowedAce(original) %p", status);
527     }
528   if (sid2)
529     {
530       status = RtlAddAccessAllowedAce (acl, ACL_REVISION, access2, sid2);
531       if (!NT_SUCCESS (status))
532         debug_printf ("RtlAddAccessAllowedAce(sid2) %p", status);
533     }
534   if (admins)
535     {
536       status = RtlAddAccessAllowedAce (acl, ACL_REVISION, GENERIC_ALL,
537                                        well_known_admins_sid);
538       if (!NT_SUCCESS (status))
539         debug_printf ("RtlAddAccessAllowedAce(admin) %p", status);
540     }
541   status = RtlAddAccessAllowedAce (acl, ACL_REVISION, GENERIC_ALL,
542                                    well_known_system_sid);
543   if (!NT_SUCCESS (status))
544     debug_printf ("RtlAddAccessAllowedAce(system) %p", status);
545   status = RtlFirstFreeAce (acl, &pAce);
546   if (NT_SUCCESS (status) && pAce)
547     acl->AclSize = (char *) pAce - (char *) acl;
548   else
549     debug_printf ("RtlFirstFreeAce: %p", status);
550
551   return true;
552 }
553
554 PSECURITY_ATTRIBUTES __stdcall
555 __sec_user (PVOID sa_buf, PSID sid1, PSID sid2, DWORD access2, BOOL inherit)
556 {
557   PSECURITY_ATTRIBUTES psa = (PSECURITY_ATTRIBUTES) sa_buf;
558   PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)
559                              ((char *) sa_buf + sizeof (*psa));
560   PACL acl = (PACL) ((char *) sa_buf + sizeof (*psa) + sizeof (*psd));
561   NTSTATUS status;
562
563 #ifdef DEBUGGING
564   if ((unsigned long) sa_buf % 4)
565     api_fatal ("Incorrectly aligned incoming SA buffer!");
566 #endif
567   if (!sec_acl (acl, true, true, sid1, sid2, access2))
568     return inherit ? &sec_none : &sec_none_nih;
569
570   RtlCreateSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION);
571   status = RtlSetDaclSecurityDescriptor (psd, TRUE, acl, FALSE);
572   if (!NT_SUCCESS (status))
573     debug_printf ("RtlSetDaclSecurityDescriptor %p", status);
574
575   psa->nLength = sizeof (SECURITY_ATTRIBUTES);
576   psa->lpSecurityDescriptor = psd;
577   psa->bInheritHandle = inherit;
578   return psa;
579 }
580
581 /* Helper function to create an event security descriptor which only allows
582    specific access to everyone.  Only the creating process has all access
583    rights. */
584
585 PSECURITY_DESCRIPTOR
586 _everyone_sd (void *buf, ACCESS_MASK access)
587 {
588   NTSTATUS status;
589   PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) buf;
590
591   if (psd)
592     {
593       RtlCreateSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION);
594       PACL dacl = (PACL) (psd + 1);
595       RtlCreateAcl (dacl, MAX_DACL_LEN (1), ACL_REVISION);
596       status = RtlAddAccessAllowedAce (dacl, ACL_REVISION, access,
597                                        well_known_world_sid);
598       if (!NT_SUCCESS (status))
599         {
600           debug_printf ("RtlAddAccessAllowedAce: %p", status);
601           return NULL;
602         }
603       LPVOID ace;
604       status = RtlFirstFreeAce (dacl, &ace);
605       if (!NT_SUCCESS (status))
606         {
607           debug_printf ("RtlFirstFreeAce: %p", status);
608           return NULL;
609         }
610       dacl->AclSize = (char *) ace - (char *) dacl;
611       RtlSetDaclSecurityDescriptor (psd, TRUE, dacl, FALSE);
612     }
613   return psd;
614 }
615