xref: /reactos/sdk/lib/rtl/security.c (revision 50cf16b3)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS system libraries
4  * FILE:              lib/rtl/security.c
5  * PURPOSE:           Security related functions and Security Objects
6  * PROGRAMMER:        Eric Kohl
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <rtl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* PRIVATE FUNCTIONS **********************************************************/
16 
17 NTSTATUS
18 NTAPI
19 RtlpSetSecurityObject(IN PVOID Object OPTIONAL,
20                       IN SECURITY_INFORMATION SecurityInformation,
21                       IN PSECURITY_DESCRIPTOR ModificationDescriptor,
22                       IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
23                       IN ULONG AutoInheritFlags,
24                       IN ULONG PoolType,
25                       IN PGENERIC_MAPPING GenericMapping,
26                       IN HANDLE Token OPTIONAL)
27 {
28     PISECURITY_DESCRIPTOR_RELATIVE pNewSd = NULL;
29     PSID pOwnerSid = NULL;
30     PSID pGroupSid = NULL;
31     PACL pDacl = NULL;
32     PACL pSacl = NULL;
33     BOOLEAN Defaulted;
34     BOOLEAN Present;
35     ULONG ulOwnerSidSize = 0, ulGroupSidSize = 0;
36     ULONG ulDaclSize = 0, ulSaclSize = 0;
37     ULONG ulNewSdSize;
38     SECURITY_DESCRIPTOR_CONTROL Control = SE_SELF_RELATIVE;
39     PUCHAR pDest;
40     NTSTATUS Status = STATUS_SUCCESS;
41 
42     DPRINT("RtlpSetSecurityObject()\n");
43 
44     /* Change the Owner SID */
45     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
46     {
47         Status = RtlGetOwnerSecurityDescriptor(ModificationDescriptor, &pOwnerSid, &Defaulted);
48         if (!NT_SUCCESS(Status))
49             return Status;
50     }
51     else
52     {
53         Status = RtlGetOwnerSecurityDescriptor(*ObjectsSecurityDescriptor, &pOwnerSid, &Defaulted);
54         if (!NT_SUCCESS(Status))
55             return Status;
56     }
57 
58     if (pOwnerSid == NULL || !RtlValidSid(pOwnerSid))
59         return STATUS_INVALID_OWNER;
60 
61     ulOwnerSidSize = RtlLengthSid(pOwnerSid);
62 
63     /* Change the Group SID */
64     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
65     {
66         Status = RtlGetGroupSecurityDescriptor(ModificationDescriptor, &pGroupSid, &Defaulted);
67         if (!NT_SUCCESS(Status))
68             return Status;
69     }
70     else
71     {
72         Status = RtlGetGroupSecurityDescriptor(*ObjectsSecurityDescriptor, &pGroupSid, &Defaulted);
73         if (!NT_SUCCESS(Status))
74             return Status;
75     }
76 
77     if (pGroupSid == NULL || !RtlValidSid(pGroupSid))
78         return STATUS_INVALID_PRIMARY_GROUP;
79 
80     ulGroupSidSize = ROUND_UP(RtlLengthSid(pGroupSid), sizeof(ULONG));
81 
82     /* Change the DACL */
83     if (SecurityInformation & DACL_SECURITY_INFORMATION)
84     {
85         Status = RtlGetDaclSecurityDescriptor(ModificationDescriptor, &Present, &pDacl, &Defaulted);
86         if (!NT_SUCCESS(Status))
87             return Status;
88 
89         Control |= SE_DACL_PRESENT;
90     }
91     else
92     {
93         Status = RtlGetDaclSecurityDescriptor(*ObjectsSecurityDescriptor, &Present, &pDacl, &Defaulted);
94         if (!NT_SUCCESS(Status))
95             return Status;
96 
97         if (Present)
98             Control |= SE_DACL_PRESENT;
99 
100         if (Defaulted)
101             Control |= SE_DACL_DEFAULTED;
102     }
103 
104     if (pDacl != NULL)
105         ulDaclSize = pDacl->AclSize;
106 
107     /* Change the SACL */
108     if (SecurityInformation & SACL_SECURITY_INFORMATION)
109     {
110         Status = RtlGetSaclSecurityDescriptor(ModificationDescriptor, &Present, &pSacl, &Defaulted);
111         if (!NT_SUCCESS(Status))
112             return Status;
113 
114         Control |= SE_SACL_PRESENT;
115     }
116     else
117     {
118         Status = RtlGetSaclSecurityDescriptor(*ObjectsSecurityDescriptor, &Present, &pSacl, &Defaulted);
119         if (!NT_SUCCESS(Status))
120             return Status;
121 
122         if (Present)
123             Control |= SE_SACL_PRESENT;
124 
125         if (Defaulted)
126             Control |= SE_SACL_DEFAULTED;
127     }
128 
129     if (pSacl != NULL)
130         ulSaclSize = pSacl->AclSize;
131 
132     /* Calculate the size of the new security descriptor */
133     ulNewSdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
134                   ROUND_UP(ulOwnerSidSize, sizeof(ULONG)) +
135                   ROUND_UP(ulGroupSidSize, sizeof(ULONG)) +
136                   ROUND_UP(ulDaclSize, sizeof(ULONG)) +
137                   ROUND_UP(ulSaclSize, sizeof(ULONG));
138 
139     /* Allocate the new security descriptor */
140     pNewSd = RtlAllocateHeap(RtlGetProcessHeap(), 0, ulNewSdSize);
141     if (pNewSd == NULL)
142     {
143         Status = STATUS_NO_MEMORY;
144         DPRINT1("New security descriptor allocation failed (Status 0x%08lx)\n", Status);
145         goto done;
146     }
147 
148     /* Initialize the new security descriptor */
149     Status = RtlCreateSecurityDescriptorRelative(pNewSd, SECURITY_DESCRIPTOR_REVISION);
150     if (!NT_SUCCESS(Status))
151     {
152         DPRINT1("New security descriptor creation failed (Status 0x%08lx)\n", Status);
153         goto done;
154     }
155 
156     /* Set the security descriptor control flags */
157     pNewSd->Control = Control;
158 
159     pDest = (PUCHAR)((ULONG_PTR)pNewSd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
160 
161     /* Copy the SACL */
162     if (pSacl != NULL)
163     {
164         RtlCopyMemory(pDest, pSacl, ulSaclSize);
165         pNewSd->Sacl = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
166         pDest = pDest + ROUND_UP(ulSaclSize, sizeof(ULONG));
167     }
168 
169     /* Copy the DACL */
170     if (pDacl != NULL)
171     {
172         RtlCopyMemory(pDest, pDacl, ulDaclSize);
173         pNewSd->Dacl = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
174         pDest = pDest + ROUND_UP(ulDaclSize, sizeof(ULONG));
175     }
176 
177     /* Copy the Owner SID */
178     RtlCopyMemory(pDest, pOwnerSid, ulOwnerSidSize);
179     pNewSd->Owner = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
180     pDest = pDest + ROUND_UP(ulOwnerSidSize, sizeof(ULONG));
181 
182     /* Copy the Group SID */
183     RtlCopyMemory(pDest, pGroupSid, ulGroupSidSize);
184     pNewSd->Group = (ULONG_PTR)pDest - (ULONG_PTR)pNewSd;
185 
186     /* Free the old security descriptor */
187     RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID)*ObjectsSecurityDescriptor);
188 
189     /* Return the new security descriptor */
190     *ObjectsSecurityDescriptor = (PSECURITY_DESCRIPTOR)pNewSd;
191 
192 done:
193     if (!NT_SUCCESS(Status))
194     {
195         if (pNewSd != NULL)
196             RtlFreeHeap(RtlGetProcessHeap(), 0, pNewSd);
197     }
198 
199     return Status;
200 }
201 
202 NTSTATUS
203 NTAPI
204 RtlpNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
205                       IN PSECURITY_DESCRIPTOR CreatorDescriptor,
206                       OUT PSECURITY_DESCRIPTOR *NewDescriptor,
207                       IN LPGUID *ObjectTypes,
208                       IN ULONG GuidCount,
209                       IN BOOLEAN IsDirectoryObject,
210                       IN ULONG AutoInheritFlags,
211                       IN HANDLE Token,
212                       IN PGENERIC_MAPPING GenericMapping)
213 {
214     UNIMPLEMENTED;
215     return STATUS_NOT_IMPLEMENTED;
216 }
217 
218 NTSTATUS
219 NTAPI
220 RtlpConvertToAutoInheritSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
221                                        IN PSECURITY_DESCRIPTOR CreatorDescriptor,
222                                        OUT PSECURITY_DESCRIPTOR *NewDescriptor,
223                                        IN LPGUID ObjectType,
224                                        IN BOOLEAN IsDirectoryObject,
225                                        IN PGENERIC_MAPPING GenericMapping)
226 {
227     UNIMPLEMENTED;
228     return STATUS_NOT_IMPLEMENTED;
229 }
230 
231 /* PUBLIC FUNCTIONS ***********************************************************/
232 
233 /*
234  * @implemented
235  */
236 NTSTATUS
237 NTAPI
238 RtlDefaultNpAcl(OUT PACL *pAcl)
239 {
240     NTSTATUS Status;
241     HANDLE TokenHandle;
242     PTOKEN_OWNER OwnerSid;
243     ULONG ReturnLength = 0;
244     ULONG AclSize;
245     SID_IDENTIFIER_AUTHORITY NtAuthority    = {SECURITY_NT_AUTHORITY};
246     SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
247 
248     /*
249      * Temporary buffer large enough to hold a maximum of two SIDs.
250      * An alternative is to call RtlAllocateAndInitializeSid many times...
251      */
252     UCHAR SidBuffer[16];
253     PSID Sid = (PSID)&SidBuffer;
254 
255     ASSERT(RtlLengthRequiredSid(2) == 16);
256 
257     /* Initialize the user ACL pointer */
258     *pAcl = NULL;
259 
260     /*
261      * Try to retrieve the SID of the current owner. For that,
262      * we first attempt to get the current thread level token.
263      */
264     Status = NtOpenThreadToken(NtCurrentThread(),
265                                TOKEN_QUERY,
266                                TRUE,
267                                &TokenHandle);
268     if (Status == STATUS_NO_TOKEN)
269     {
270         /*
271          * No thread level token, so use the process level token.
272          * This is the common case since the only time a thread
273          * has a token is when it is impersonating.
274          */
275         Status = NtOpenProcessToken(NtCurrentProcess(),
276                                     TOKEN_QUERY,
277                                     &TokenHandle);
278     }
279     /* Fail if we didn't succeed in retrieving a handle to the token */
280     if (!NT_SUCCESS(Status)) return Status;
281 
282     /*
283      * Retrieve the owner SID from the token.
284      */
285 
286     /* Query the needed size... */
287     Status = NtQueryInformationToken(TokenHandle,
288                                      TokenOwner,
289                                      NULL, 0,
290                                      &ReturnLength);
291     /* ... so that we must fail with STATUS_BUFFER_TOO_SMALL error */
292     if (Status != STATUS_BUFFER_TOO_SMALL) goto Cleanup1;
293 
294     /* Allocate space for the owner SID */
295     OwnerSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
296     if (OwnerSid == NULL)
297     {
298         Status = STATUS_NO_MEMORY;
299         goto Cleanup1;
300     }
301 
302     /* Retrieve the owner SID; we must succeed */
303     Status = NtQueryInformationToken(TokenHandle,
304                                      TokenOwner,
305                                      OwnerSid,
306                                      ReturnLength,
307                                      &ReturnLength);
308     if (!NT_SUCCESS(Status)) goto Cleanup2;
309 
310     /*
311      * Allocate one ACL with 5 ACEs.
312      *
313      * NOTE: sizeof(ACE) == sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)NULL)->SidStart)
314      * (see kernel32/client/debugger.c line 54).
315      */
316     AclSize = sizeof(ACL) +                     // Header
317               5 * sizeof(ACE /*ACCESS_ALLOWED_ACE*/) +  // 5 ACEs:
318               RtlLengthRequiredSid(1) +         // LocalSystem
319               RtlLengthRequiredSid(2) +         // Administrators
320               RtlLengthRequiredSid(1) +         // Anonymous
321               RtlLengthRequiredSid(1) +         // World
322               RtlLengthSid(OwnerSid->Owner);    // Owner
323 
324     *pAcl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclSize);
325     if (*pAcl == NULL)
326     {
327         Status = STATUS_NO_MEMORY;
328         goto Cleanup2;
329     }
330 
331     /*
332      * Build the ACL and add the five ACEs.
333      */
334     Status = RtlCreateAcl(*pAcl, AclSize, ACL_REVISION2);
335     ASSERT(NT_SUCCESS(Status));
336 
337     /* Local System SID - Generic All */
338     Status = RtlInitializeSid(Sid, &NtAuthority, 1);
339     ASSERT(NT_SUCCESS(Status));
340     *RtlSubAuthoritySid(Sid, 0) = SECURITY_LOCAL_SYSTEM_RID;
341     Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
342     ASSERT(NT_SUCCESS(Status));
343 
344     /* Administrators SID - Generic All */
345     Status = RtlInitializeSid(Sid, &NtAuthority, 2);
346     ASSERT(NT_SUCCESS(Status));
347     *RtlSubAuthoritySid(Sid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
348     *RtlSubAuthoritySid(Sid, 1) = DOMAIN_ALIAS_RID_ADMINS;
349     Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
350     ASSERT(NT_SUCCESS(Status));
351 
352     /* Owner SID - Generic All */
353     RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, OwnerSid->Owner);
354     ASSERT(NT_SUCCESS(Status));
355 
356     /* Anonymous SID - Generic Read */
357     Status = RtlInitializeSid(Sid, &NtAuthority, 1);
358     ASSERT(NT_SUCCESS(Status));
359     *RtlSubAuthoritySid(Sid, 0) = SECURITY_ANONYMOUS_LOGON_RID;
360     Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
361     ASSERT(NT_SUCCESS(Status));
362 
363     /* World SID - Generic Read */
364     Status = RtlInitializeSid(Sid, &WorldAuthority, 1);
365     ASSERT(NT_SUCCESS(Status));
366     *RtlSubAuthoritySid(Sid, 0) = SECURITY_WORLD_RID;
367     Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
368     ASSERT(NT_SUCCESS(Status));
369 
370     /* If some problem happened, cleanup everything */
371     if (!NT_SUCCESS(Status))
372     {
373         RtlFreeHeap(RtlGetProcessHeap(), 0, *pAcl);
374         *pAcl = NULL;
375     }
376 
377 Cleanup2:
378     /* Get rid of the owner SID */
379     RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
380 
381 Cleanup1:
382     /* Close the token handle */
383     NtClose(TokenHandle);
384 
385     /* Done */
386     return Status;
387 }
388 
389 /*
390  * @unimplemented
391  */
392 NTSTATUS
393 NTAPI
394 RtlCreateAndSetSD(IN PVOID AceData,
395                   IN ULONG AceCount,
396                   IN PSID OwnerSid OPTIONAL,
397                   IN PSID GroupSid OPTIONAL,
398                   OUT PSECURITY_DESCRIPTOR *NewDescriptor)
399 {
400     UNIMPLEMENTED;
401     return STATUS_NOT_IMPLEMENTED;
402 }
403 
404 /*
405  * @implemented
406  */
407 NTSTATUS
408 NTAPI
409 RtlDeleteSecurityObject(IN PSECURITY_DESCRIPTOR *ObjectDescriptor)
410 {
411     DPRINT1("RtlDeleteSecurityObject(%p)\n", ObjectDescriptor);
412 
413     /* Free the object from the heap */
414     RtlFreeHeap(RtlGetProcessHeap(), 0, *ObjectDescriptor);
415     return STATUS_SUCCESS;
416 }
417 
418 /*
419  * @implemented
420  */
421 NTSTATUS
422 NTAPI
423 RtlNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
424                      IN PSECURITY_DESCRIPTOR CreatorDescriptor,
425                      OUT PSECURITY_DESCRIPTOR *NewDescriptor,
426                      IN BOOLEAN IsDirectoryObject,
427                      IN HANDLE Token,
428                      IN PGENERIC_MAPPING GenericMapping)
429 {
430     DPRINT1("RtlNewSecurityObject(%p)\n", ParentDescriptor);
431 
432     /* Call the internal API */
433     return RtlpNewSecurityObject(ParentDescriptor,
434                                  CreatorDescriptor,
435                                  NewDescriptor,
436                                  NULL,
437                                  0,
438                                  IsDirectoryObject,
439                                  0,
440                                  Token,
441                                  GenericMapping);
442 }
443 
444 /*
445  * @implemented
446  */
447 NTSTATUS
448 NTAPI
449 RtlNewSecurityObjectEx(IN PSECURITY_DESCRIPTOR ParentDescriptor,
450                        IN PSECURITY_DESCRIPTOR CreatorDescriptor,
451                        OUT PSECURITY_DESCRIPTOR *NewDescriptor,
452                        IN LPGUID ObjectType,
453                        IN BOOLEAN IsDirectoryObject,
454                        IN ULONG AutoInheritFlags,
455                        IN HANDLE Token,
456                        IN PGENERIC_MAPPING GenericMapping)
457 {
458     DPRINT1("RtlNewSecurityObjectEx(%p)\n", ParentDescriptor);
459 
460     /* Call the internal API */
461     return RtlpNewSecurityObject(ParentDescriptor,
462                                  CreatorDescriptor,
463                                  NewDescriptor,
464                                  ObjectType ? &ObjectType : NULL,
465                                  ObjectType ? 1 : 0,
466                                  IsDirectoryObject,
467                                  AutoInheritFlags,
468                                  Token,
469                                  GenericMapping);
470 }
471 
472 /*
473  * @implemented
474  */
475 NTSTATUS
476 NTAPI
477 RtlNewSecurityObjectWithMultipleInheritance(IN PSECURITY_DESCRIPTOR ParentDescriptor,
478                                             IN PSECURITY_DESCRIPTOR CreatorDescriptor,
479                                             OUT PSECURITY_DESCRIPTOR *NewDescriptor,
480                                             IN LPGUID *ObjectTypes,
481                                             IN ULONG GuidCount,
482                                             IN BOOLEAN IsDirectoryObject,
483                                             IN ULONG AutoInheritFlags,
484                                             IN HANDLE Token,
485                                             IN PGENERIC_MAPPING GenericMapping)
486 {
487     DPRINT1("RtlNewSecurityObjectWithMultipleInheritance(%p)\n", ParentDescriptor);
488 
489     /* Call the internal API */
490     return RtlpNewSecurityObject(ParentDescriptor,
491                                  CreatorDescriptor,
492                                  NewDescriptor,
493                                  ObjectTypes,
494                                  GuidCount,
495                                  IsDirectoryObject,
496                                  AutoInheritFlags,
497                                  Token,
498                                  GenericMapping);
499 }
500 
501 /*
502  * @implemented
503  */
504 NTSTATUS
505 NTAPI
506 RtlNewInstanceSecurityObject(IN BOOLEAN ParentDescriptorChanged,
507                              IN BOOLEAN CreatorDescriptorChanged,
508                              IN PLUID OldClientTokenModifiedId,
509                              OUT PLUID NewClientTokenModifiedId,
510                              IN PSECURITY_DESCRIPTOR ParentDescriptor,
511                              IN PSECURITY_DESCRIPTOR CreatorDescriptor,
512                              OUT PSECURITY_DESCRIPTOR *NewDescriptor,
513                              IN BOOLEAN IsDirectoryObject,
514                              IN HANDLE Token,
515                              IN PGENERIC_MAPPING GenericMapping)
516 {
517     TOKEN_STATISTICS TokenStats;
518     ULONG Size;
519     NTSTATUS Status;
520     DPRINT1("RtlNewInstanceSecurityObject(%p)\n", ParentDescriptor);
521 
522     /* Query the token statistics */
523     Status = NtQueryInformationToken(Token,
524                                      TokenStatistics,
525                                      &TokenStats,
526                                      sizeof(TokenStats),
527                                      &Size);
528     if (!NT_SUCCESS(Status)) return Status;
529 
530     /* Return the LUID */
531     *NewClientTokenModifiedId = TokenStats.ModifiedId;
532 
533     /* Check if the LUID changed */
534     if (RtlEqualLuid(NewClientTokenModifiedId, OldClientTokenModifiedId))
535     {
536         /* Did nothing change? */
537         if (!(ParentDescriptorChanged) && !(CreatorDescriptorChanged))
538         {
539             /* There's no new descriptor, we're done */
540             *NewDescriptor = NULL;
541             return STATUS_SUCCESS;
542         }
543     }
544 
545     /* Call the standard API */
546     return RtlNewSecurityObject(ParentDescriptor,
547                                 CreatorDescriptor,
548                                 NewDescriptor,
549                                 IsDirectoryObject,
550                                 Token,
551                                 GenericMapping);
552 }
553 
554 /*
555  * @implemented
556  */
557 NTSTATUS
558 NTAPI
559 RtlCreateUserSecurityObject(IN PVOID AceData,
560                             IN ULONG AceCount,
561                             IN PSID OwnerSid,
562                             IN PSID GroupSid,
563                             IN BOOLEAN IsDirectoryObject,
564                             IN PGENERIC_MAPPING GenericMapping,
565                             OUT PSECURITY_DESCRIPTOR *NewDescriptor)
566 {
567     NTSTATUS Status;
568     PSECURITY_DESCRIPTOR Sd;
569     HANDLE TokenHandle;
570     DPRINT1("RtlCreateUserSecurityObject(%p)\n", AceData);
571 
572     /* Create the security descriptor based on the ACE Data */
573     Status = RtlCreateAndSetSD(AceData,
574                                AceCount,
575                                OwnerSid,
576                                GroupSid,
577                                &Sd);
578     if (!NT_SUCCESS(Status)) return Status;
579 
580     /* Open the process token */
581     Status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &TokenHandle);
582     if (!NT_SUCCESS(Status)) goto Quickie;
583 
584     /* Create the security object */
585     Status = RtlNewSecurityObject(NULL,
586                                   Sd,
587                                   NewDescriptor,
588                                   IsDirectoryObject,
589                                   TokenHandle,
590                                   GenericMapping);
591 
592     /* We're done, close the token handle */
593     NtClose(TokenHandle);
594 
595 Quickie:
596     /* Free the SD and return status */
597     RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
598     return Status;
599 }
600 
601 /*
602  * @implemented
603  */
604 NTSTATUS
605 NTAPI
606 RtlNewSecurityGrantedAccess(IN ACCESS_MASK DesiredAccess,
607                             OUT PPRIVILEGE_SET Privileges,
608                             IN OUT PULONG Length,
609                             IN HANDLE Token,
610                             IN PGENERIC_MAPPING GenericMapping,
611                             OUT PACCESS_MASK RemainingDesiredAccess)
612 {
613     NTSTATUS Status;
614     BOOLEAN Granted, CallerToken;
615     TOKEN_STATISTICS TokenStats;
616     ULONG Size;
617     DPRINT1("RtlNewSecurityGrantedAccess(%lx)\n", DesiredAccess);
618 
619     /* Has the caller passed a token? */
620     if (!Token)
621     {
622         /* Remember that we'll have to close the handle */
623         CallerToken = FALSE;
624 
625         /* Nope, open it */
626         Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, TRUE, &Token);
627         if (!NT_SUCCESS(Status)) return Status;
628     }
629     else
630     {
631         /* Yep, use it */
632         CallerToken = TRUE;
633     }
634 
635     /* Get information on the token */
636     Status = NtQueryInformationToken(Token,
637                                      TokenStatistics,
638                                      &TokenStats,
639                                      sizeof(TokenStats),
640                                      &Size);
641     ASSERT(NT_SUCCESS(Status));
642 
643     /* Windows doesn't do anything with the token statistics! */
644 
645     /* Map the access and return it back decoded */
646     RtlMapGenericMask(&DesiredAccess, GenericMapping);
647     *RemainingDesiredAccess = DesiredAccess;
648 
649     /* Check if one of the rights requested was the SACL right */
650     if (DesiredAccess & ACCESS_SYSTEM_SECURITY)
651     {
652         /* Pretend that it's allowed FIXME: Do privilege check */
653         DPRINT1("Missing privilege check for SE_SECURITY_PRIVILEGE");
654         Granted = TRUE;
655         *RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY;
656     }
657     else
658     {
659         /* Nothing to grant */
660         Granted = FALSE;
661     }
662 
663     /* If the caller did not pass in a token, close the handle to ours */
664     if (!CallerToken) NtClose(Token);
665 
666     /* We need space to return only 1 privilege -- already part of the struct */
667     Size = sizeof(PRIVILEGE_SET);
668     if (Size > *Length)
669     {
670         /* Tell the caller how much space we need and fail */
671         *Length = Size;
672         return STATUS_BUFFER_TOO_SMALL;
673     }
674 
675     /* Check if the SACL right was granted... */
676     RtlZeroMemory(Privileges, Size);
677     if (Granted)
678     {
679         /* Yes, return it in the structure */
680         Privileges->PrivilegeCount = 1;
681         Privileges->Privilege[0].Luid.LowPart = SE_SECURITY_PRIVILEGE;
682         Privileges->Privilege[0].Luid.HighPart = 0;
683         Privileges->Privilege[0].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
684     }
685 
686     /* All done */
687     return STATUS_SUCCESS;
688 }
689 
690 /*
691  * @unimplemented
692  */
693 NTSTATUS
694 NTAPI
695 RtlQuerySecurityObject(IN PSECURITY_DESCRIPTOR ObjectDescriptor,
696                        IN SECURITY_INFORMATION SecurityInformation,
697                        OUT PSECURITY_DESCRIPTOR ResultantDescriptor,
698                        IN ULONG DescriptorLength,
699                        OUT PULONG ReturnLength)
700 {
701     NTSTATUS Status;
702     SECURITY_DESCRIPTOR desc;
703     BOOLEAN defaulted, present;
704     PACL pacl;
705     PSID psid;
706 
707     Status = RtlCreateSecurityDescriptor(&desc, SECURITY_DESCRIPTOR_REVISION);
708     if (!NT_SUCCESS(Status)) return Status;
709 
710     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
711     {
712         Status = RtlGetOwnerSecurityDescriptor(ObjectDescriptor, &psid, &defaulted);
713         if (!NT_SUCCESS(Status)) return Status;
714         Status = RtlSetOwnerSecurityDescriptor(&desc, psid, defaulted);
715         if (!NT_SUCCESS(Status)) return Status;
716     }
717 
718     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
719     {
720         Status = RtlGetGroupSecurityDescriptor(ObjectDescriptor, &psid, &defaulted);
721         if (!NT_SUCCESS(Status)) return Status;
722         Status = RtlSetGroupSecurityDescriptor(&desc, psid, defaulted);
723         if (!NT_SUCCESS(Status)) return Status;
724     }
725 
726     if (SecurityInformation & DACL_SECURITY_INFORMATION)
727     {
728         Status = RtlGetDaclSecurityDescriptor(ObjectDescriptor, &present, &pacl, &defaulted);
729         if (!NT_SUCCESS(Status)) return Status;
730         Status = RtlSetDaclSecurityDescriptor(&desc, present, pacl, defaulted);
731         if (!NT_SUCCESS(Status)) return Status;
732     }
733 
734     if (SecurityInformation & SACL_SECURITY_INFORMATION)
735     {
736         Status = RtlGetSaclSecurityDescriptor(ObjectDescriptor, &present, &pacl, &defaulted);
737         if (!NT_SUCCESS(Status)) return Status;
738         Status = RtlSetSaclSecurityDescriptor(&desc, present, pacl, defaulted);
739         if (!NT_SUCCESS(Status)) return Status;
740     }
741 
742     *ReturnLength = DescriptorLength;
743     return RtlAbsoluteToSelfRelativeSD(&desc, ResultantDescriptor, ReturnLength);
744 }
745 
746 
747 /*
748  * @implemented
749  */
750 NTSTATUS
751 NTAPI
752 RtlSetSecurityObject(IN SECURITY_INFORMATION SecurityInformation,
753                      IN PSECURITY_DESCRIPTOR ModificationDescriptor,
754                      IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
755                      IN PGENERIC_MAPPING GenericMapping,
756                      IN HANDLE Token OPTIONAL)
757 {
758     /* Call the internal API */
759     return RtlpSetSecurityObject(NULL,
760                                  SecurityInformation,
761                                  ModificationDescriptor,
762                                  ObjectsSecurityDescriptor,
763                                  0,
764                                  PagedPool,
765                                  GenericMapping,
766                                  Token);
767 }
768 
769 /*
770  * @implemented
771  */
772 NTSTATUS
773 NTAPI
774 RtlSetSecurityObjectEx(IN SECURITY_INFORMATION SecurityInformation,
775                        IN PSECURITY_DESCRIPTOR ModificationDescriptor,
776                        IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
777                        IN ULONG AutoInheritFlags,
778                        IN PGENERIC_MAPPING GenericMapping,
779                        IN HANDLE Token OPTIONAL)
780 {
781     /* Call the internal API */
782     return RtlpSetSecurityObject(NULL,
783                                  SecurityInformation,
784                                  ModificationDescriptor,
785                                  ObjectsSecurityDescriptor,
786                                  AutoInheritFlags,
787                                  PagedPool,
788                                  GenericMapping,
789                                  Token);
790 
791 }
792 
793 /*
794  * @implemented
795  */
796 NTSTATUS
797 NTAPI
798 RtlConvertToAutoInheritSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
799                                       IN PSECURITY_DESCRIPTOR CreatorDescriptor,
800                                       OUT PSECURITY_DESCRIPTOR *NewDescriptor,
801                                       IN LPGUID ObjectType,
802                                       IN BOOLEAN IsDirectoryObject,
803                                       IN PGENERIC_MAPPING GenericMapping)
804 {
805     /* Call the internal API */
806     return RtlpConvertToAutoInheritSecurityObject(ParentDescriptor,
807                                                   CreatorDescriptor,
808                                                   NewDescriptor,
809                                                   ObjectType,
810                                                   IsDirectoryObject,
811                                                   GenericMapping);
812 }
813 
814 /*
815  * @unimplemented
816  */
817 NTSTATUS
818 NTAPI
819 RtlRegisterSecureMemoryCacheCallback(IN PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback)
820 {
821     UNIMPLEMENTED;
822     return STATUS_NOT_IMPLEMENTED;
823 }
824 
825 /*
826  * @unimplemented
827  */
828 BOOLEAN
829 NTAPI
830 RtlFlushSecureMemoryCache(IN PVOID MemoryCache,
831                           IN OPTIONAL SIZE_T MemoryLength)
832 {
833     UNIMPLEMENTED;
834     return FALSE;
835 }
836