1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security descriptors (SDs) implementation support
5 * COPYRIGHT: Copyright David Welch <welch@cwcom.net>
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <debug.h>
13
14 /* GLOBALS ********************************************************************/
15
16 PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
17 PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
18 PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
19 PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
20 PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
21 PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;
22 PSECURITY_DESCRIPTOR SeSystemAnonymousLogonSd = NULL;
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /**
27 * @brief
28 * Initializes the known security descriptors in the system.
29 *
30 * @return
31 * Returns TRUE if all the security descriptors have been initialized,
32 * FALSE otherwise.
33 */
34 CODE_SEG("INIT")
35 BOOLEAN
36 NTAPI
SepInitSDs(VOID)37 SepInitSDs(VOID)
38 {
39 /* Create PublicDefaultSd */
40 SePublicDefaultSd = ExAllocatePoolWithTag(PagedPool,
41 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
42 if (SePublicDefaultSd == NULL)
43 return FALSE;
44
45 RtlCreateSecurityDescriptor(SePublicDefaultSd,
46 SECURITY_DESCRIPTOR_REVISION);
47 RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
48 TRUE,
49 SePublicDefaultDacl,
50 FALSE);
51
52 /* Create PublicDefaultUnrestrictedSd */
53 SePublicDefaultUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
54 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
55 if (SePublicDefaultUnrestrictedSd == NULL)
56 return FALSE;
57
58 RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
59 SECURITY_DESCRIPTOR_REVISION);
60 RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
61 TRUE,
62 SePublicDefaultUnrestrictedDacl,
63 FALSE);
64
65 /* Create PublicOpenSd */
66 SePublicOpenSd = ExAllocatePoolWithTag(PagedPool,
67 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
68 if (SePublicOpenSd == NULL)
69 return FALSE;
70
71 RtlCreateSecurityDescriptor(SePublicOpenSd,
72 SECURITY_DESCRIPTOR_REVISION);
73 RtlSetDaclSecurityDescriptor(SePublicOpenSd,
74 TRUE,
75 SePublicOpenDacl,
76 FALSE);
77
78 /* Create PublicOpenUnrestrictedSd */
79 SePublicOpenUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
80 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
81 if (SePublicOpenUnrestrictedSd == NULL)
82 return FALSE;
83
84 RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
85 SECURITY_DESCRIPTOR_REVISION);
86 RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
87 TRUE,
88 SePublicOpenUnrestrictedDacl,
89 FALSE);
90
91 /* Create SystemDefaultSd */
92 SeSystemDefaultSd = ExAllocatePoolWithTag(PagedPool,
93 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
94 if (SeSystemDefaultSd == NULL)
95 return FALSE;
96
97 RtlCreateSecurityDescriptor(SeSystemDefaultSd,
98 SECURITY_DESCRIPTOR_REVISION);
99 RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
100 TRUE,
101 SeSystemDefaultDacl,
102 FALSE);
103
104 /* Create UnrestrictedSd */
105 SeUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
106 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
107 if (SeUnrestrictedSd == NULL)
108 return FALSE;
109
110 RtlCreateSecurityDescriptor(SeUnrestrictedSd,
111 SECURITY_DESCRIPTOR_REVISION);
112 RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
113 TRUE,
114 SeUnrestrictedDacl,
115 FALSE);
116
117 /* Create SystemAnonymousLogonSd */
118 SeSystemAnonymousLogonSd = ExAllocatePoolWithTag(PagedPool,
119 sizeof(SECURITY_DESCRIPTOR), TAG_SD);
120 if (SeSystemAnonymousLogonSd == NULL)
121 return FALSE;
122
123 RtlCreateSecurityDescriptor(SeSystemAnonymousLogonSd,
124 SECURITY_DESCRIPTOR_REVISION);
125 RtlSetDaclSecurityDescriptor(SeSystemAnonymousLogonSd,
126 TRUE,
127 SeSystemAnonymousLogonDacl,
128 FALSE);
129
130 return TRUE;
131 }
132
133 /**
134 * @brief
135 * Sets a "World" security descriptor.
136 *
137 * @param[in] SecurityInformation
138 * Security information details, alongside with the security
139 * descriptor to set the World SD.
140 *
141 * @param[in] SecurityDescriptor
142 * A security descriptor buffer.
143 *
144 * @param[in] BufferLength
145 * Length size of the buffer.
146 *
147 * @return
148 * Returns STATUS_SUCCESS if the World security descriptor has been
149 * set. STATUS_ACCESS_DENIED is returned if the caller hasn't
150 * provided security information details thus the SD cannot
151 * be set.
152 */
153 NTSTATUS
154 NTAPI
SeSetWorldSecurityDescriptor(_In_ SECURITY_INFORMATION SecurityInformation,_In_ PISECURITY_DESCRIPTOR SecurityDescriptor,_In_ PULONG BufferLength)155 SeSetWorldSecurityDescriptor(
156 _In_ SECURITY_INFORMATION SecurityInformation,
157 _In_ PISECURITY_DESCRIPTOR SecurityDescriptor,
158 _In_ PULONG BufferLength)
159 {
160 ULONG Current;
161 ULONG SidSize;
162 ULONG SdSize;
163 NTSTATUS Status;
164 PISECURITY_DESCRIPTOR_RELATIVE SdRel = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
165
166 DPRINT("SeSetWorldSecurityDescriptor() called\n");
167
168 if (SecurityInformation == 0)
169 {
170 return STATUS_ACCESS_DENIED;
171 }
172
173 /* calculate the minimum size of the buffer */
174 SidSize = RtlLengthSid(SeWorldSid);
175 SdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
176 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
177 SdSize += SidSize;
178 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
179 SdSize += SidSize;
180 if (SecurityInformation & DACL_SECURITY_INFORMATION)
181 {
182 SdSize += sizeof(ACL) + sizeof(ACE) + SidSize;
183 }
184 if (SecurityInformation & SACL_SECURITY_INFORMATION)
185 {
186 SdSize += sizeof(ACL) + sizeof(ACE) + SidSize;
187 }
188
189 if (*BufferLength < SdSize)
190 {
191 *BufferLength = SdSize;
192 return STATUS_BUFFER_TOO_SMALL;
193 }
194
195 *BufferLength = SdSize;
196
197 Status = RtlCreateSecurityDescriptorRelative(SdRel,
198 SECURITY_DESCRIPTOR_REVISION);
199 if (!NT_SUCCESS(Status))
200 {
201 return Status;
202 }
203
204 Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
205
206 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
207 {
208 RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
209 SdRel->Owner = Current;
210 Current += SidSize;
211 }
212
213 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
214 {
215 RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
216 SdRel->Group = Current;
217 Current += SidSize;
218 }
219
220 if (SecurityInformation & DACL_SECURITY_INFORMATION)
221 {
222 PACL Dacl = (PACL)((PUCHAR)SdRel + Current);
223
224 Status = RtlCreateAcl(Dacl,
225 sizeof(ACL) + sizeof(ACE) + SidSize,
226 ACL_REVISION);
227 if (!NT_SUCCESS(Status))
228 return Status;
229
230 Status = RtlAddAccessAllowedAce(Dacl,
231 ACL_REVISION,
232 GENERIC_ALL,
233 SeWorldSid);
234 if (!NT_SUCCESS(Status))
235 return Status;
236
237 SdRel->Control |= SE_DACL_PRESENT;
238 SdRel->Dacl = Current;
239 Current += SidSize;
240 }
241
242 if (SecurityInformation & SACL_SECURITY_INFORMATION)
243 {
244 PACL Sacl = (PACL)((PUCHAR)SdRel + Current);
245
246 Status = RtlCreateAcl(Sacl,
247 sizeof(ACL) + sizeof(ACE) + SidSize,
248 ACL_REVISION);
249 if (!NT_SUCCESS(Status))
250 return Status;
251
252 Status = RtlAddAuditAccessAce(Sacl,
253 ACL_REVISION,
254 ACCESS_SYSTEM_SECURITY | STANDARD_RIGHTS_ALL,
255 SeWorldSid,
256 TRUE,
257 TRUE);
258 if (!NT_SUCCESS(Status))
259 return Status;
260
261 SdRel->Control |= SE_SACL_PRESENT;
262 SdRel->Sacl = Current;
263 Current += SidSize;
264 }
265
266 return STATUS_SUCCESS;
267 }
268
269 /* PUBLIC FUNCTIONS ***********************************************************/
270
271 /**
272 * @brief
273 * Determines the size of a SID.
274 *
275 * @param[in] Sid
276 * A security identifier where its size is to be determined.
277 *
278 * @param[in,out] OutSAC
279 * The returned sub authority count of the security
280 * identifier.
281 *
282 * @param[in] ProcessorMode
283 * Processor level access mode.
284 *
285 * @return
286 * Returns the size length of a security identifier (SID).
287 */
288 static
289 ULONG
DetermineSIDSize(_In_ PISID Sid,_Inout_ PULONG OutSAC,_In_ KPROCESSOR_MODE ProcessorMode)290 DetermineSIDSize(
291 _In_ PISID Sid,
292 _Inout_ PULONG OutSAC,
293 _In_ KPROCESSOR_MODE ProcessorMode)
294 {
295 ULONG Size;
296
297 if (!Sid)
298 {
299 *OutSAC = 0;
300 return 0;
301 }
302
303 if (ProcessorMode != KernelMode)
304 {
305 /* Securely access the buffers! */
306 *OutSAC = ProbeForReadUchar(&Sid->SubAuthorityCount);
307 Size = RtlLengthRequiredSid(*OutSAC);
308 ProbeForRead(Sid, Size, sizeof(ULONG));
309 }
310 else
311 {
312 *OutSAC = Sid->SubAuthorityCount;
313 Size = RtlLengthRequiredSid(*OutSAC);
314 }
315
316 return Size;
317 }
318
319 /**
320 * @brief
321 * Determines the size of an ACL.
322 *
323 * @param[in] Acl
324 * An access control list where its size is to be
325 * determined.
326 *
327 * @param[in] ProcessorMode
328 * Processor level access mode.
329 *
330 * @return
331 * Returns the size length of a an access control
332 * list (ACL).
333 */
334 static
335 ULONG
DetermineACLSize(_In_ PACL Acl,_In_ KPROCESSOR_MODE ProcessorMode)336 DetermineACLSize(
337 _In_ PACL Acl,
338 _In_ KPROCESSOR_MODE ProcessorMode)
339 {
340 ULONG Size;
341
342 if (!Acl) return 0;
343
344 if (ProcessorMode == KernelMode) return Acl->AclSize;
345
346 /* Probe the buffers! */
347 Size = ProbeForReadUshort(&Acl->AclSize);
348 ProbeForRead(Acl, Size, sizeof(ULONG));
349
350 return Size;
351 }
352
353 /**
354 * @brief
355 * Captures a security descriptor.
356 *
357 * @param[in] _OriginalSecurityDescriptor
358 * An already existing and valid security descriptor
359 * to be captured.
360 *
361 * @param[in] CurrentMode
362 * Processor level access mode.
363 *
364 * @param[in] PoolType
365 * Pool type to be used when allocating the captured
366 * buffer.
367 *
368 * @param[in] CaptureIfKernel
369 * Set this to TRUE if capturing is done within the
370 * kernel.
371 *
372 * @param[out] CapturedSecurityDescriptor
373 * The captured security descriptor.
374 *
375 * @return
376 * Returns STATUS_SUCCESS if the operations have been
377 * completed successfully and that the security descriptor
378 * has been captured. STATUS_UNKNOWN_REVISION is returned
379 * if the security descriptor has an unknown revision.
380 * STATUS_INSUFFICIENT_RESOURCES is returned if memory
381 * pool allocation for the captured buffer has failed.
382 * A failure NTSTATUS code is returned otherwise.
383 */
384 NTSTATUS
385 NTAPI
SeCaptureSecurityDescriptor(_In_ PSECURITY_DESCRIPTOR _OriginalSecurityDescriptor,_In_ KPROCESSOR_MODE CurrentMode,_In_ POOL_TYPE PoolType,_In_ BOOLEAN CaptureIfKernel,_Out_ PSECURITY_DESCRIPTOR * CapturedSecurityDescriptor)386 SeCaptureSecurityDescriptor(
387 _In_ PSECURITY_DESCRIPTOR _OriginalSecurityDescriptor,
388 _In_ KPROCESSOR_MODE CurrentMode,
389 _In_ POOL_TYPE PoolType,
390 _In_ BOOLEAN CaptureIfKernel,
391 _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor)
392 {
393 PISECURITY_DESCRIPTOR OriginalDescriptor = _OriginalSecurityDescriptor;
394 SECURITY_DESCRIPTOR DescriptorCopy;
395 PISECURITY_DESCRIPTOR_RELATIVE NewDescriptor;
396 ULONG OwnerSAC = 0, GroupSAC = 0;
397 ULONG OwnerSize = 0, GroupSize = 0;
398 ULONG SaclSize = 0, DaclSize = 0;
399 ULONG DescriptorSize = 0;
400 ULONG Offset;
401
402 if (!OriginalDescriptor)
403 {
404 /* Nothing to do... */
405 *CapturedSecurityDescriptor = NULL;
406 return STATUS_SUCCESS;
407 }
408
409 /* Quick path */
410 if (CurrentMode == KernelMode && !CaptureIfKernel)
411 {
412 /* Check descriptor version */
413 if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
414 {
415 return STATUS_UNKNOWN_REVISION;
416 }
417
418 *CapturedSecurityDescriptor = _OriginalSecurityDescriptor;
419 return STATUS_SUCCESS;
420 }
421
422 _SEH2_TRY
423 {
424 if (CurrentMode != KernelMode)
425 {
426 ProbeForRead(OriginalDescriptor,
427 sizeof(SECURITY_DESCRIPTOR_RELATIVE),
428 sizeof(ULONG));
429 }
430
431 /* Check the descriptor version */
432 if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
433 {
434 _SEH2_YIELD(return STATUS_UNKNOWN_REVISION);
435 }
436
437 if (CurrentMode != KernelMode)
438 {
439 /* Get the size of the descriptor */
440 DescriptorSize = (OriginalDescriptor->Control & SE_SELF_RELATIVE) ?
441 sizeof(SECURITY_DESCRIPTOR_RELATIVE) : sizeof(SECURITY_DESCRIPTOR);
442
443 /* Probe the entire security descriptor structure. The SIDs
444 * and ACLs will be probed and copied later though */
445 ProbeForRead(OriginalDescriptor, DescriptorSize, sizeof(ULONG));
446 }
447
448 /* Now capture all fields and convert to an absolute descriptor */
449 DescriptorCopy.Revision = OriginalDescriptor->Revision;
450 DescriptorCopy.Sbz1 = OriginalDescriptor->Sbz1;
451 DescriptorCopy.Control = OriginalDescriptor->Control & ~SE_SELF_RELATIVE;
452 DescriptorCopy.Owner = SepGetOwnerFromDescriptor(OriginalDescriptor);
453 DescriptorCopy.Group = SepGetGroupFromDescriptor(OriginalDescriptor);
454 DescriptorCopy.Sacl = SepGetSaclFromDescriptor(OriginalDescriptor);
455 DescriptorCopy.Dacl = SepGetDaclFromDescriptor(OriginalDescriptor);
456 DescriptorSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
457
458 /* Determine owner and group sizes */
459 OwnerSize = DetermineSIDSize(DescriptorCopy.Owner, &OwnerSAC, CurrentMode);
460 DescriptorSize += ROUND_UP(OwnerSize, sizeof(ULONG));
461 GroupSize = DetermineSIDSize(DescriptorCopy.Group, &GroupSAC, CurrentMode);
462 DescriptorSize += ROUND_UP(GroupSize, sizeof(ULONG));
463
464 /* Determine the size of the ACLs */
465 if (DescriptorCopy.Control & SE_SACL_PRESENT)
466 {
467 /* Get the size and probe if user mode */
468 SaclSize = DetermineACLSize(DescriptorCopy.Sacl, CurrentMode);
469 DescriptorSize += ROUND_UP(SaclSize, sizeof(ULONG));
470 }
471
472 if (DescriptorCopy.Control & SE_DACL_PRESENT)
473 {
474 /* Get the size and probe if user mode */
475 DaclSize = DetermineACLSize(DescriptorCopy.Dacl, CurrentMode);
476 DescriptorSize += ROUND_UP(DaclSize, sizeof(ULONG));
477 }
478 }
479 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
480 {
481 _SEH2_YIELD(return _SEH2_GetExceptionCode());
482 }
483 _SEH2_END;
484
485 /*
486 * Allocate enough memory to store a complete copy of a self-relative
487 * security descriptor
488 */
489 NewDescriptor = ExAllocatePoolWithTag(PoolType,
490 DescriptorSize,
491 TAG_SD);
492 if (!NewDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
493
494 RtlZeroMemory(NewDescriptor, DescriptorSize);
495 NewDescriptor->Revision = DescriptorCopy.Revision;
496 NewDescriptor->Sbz1 = DescriptorCopy.Sbz1;
497 NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE;
498
499 _SEH2_TRY
500 {
501 /*
502 * Setup the offsets and copy the SIDs and ACLs to the new
503 * self-relative security descriptor. Probing the pointers is not
504 * neccessary anymore as we did that when collecting the sizes!
505 * Make sure to validate the SIDs and ACLs *again* as they could have
506 * been modified in the meanwhile!
507 */
508 Offset = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
509
510 if (DescriptorCopy.Owner)
511 {
512 if (!RtlValidSid(DescriptorCopy.Owner)) RtlRaiseStatus(STATUS_INVALID_SID);
513 NewDescriptor->Owner = Offset;
514 RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
515 DescriptorCopy.Owner,
516 OwnerSize);
517 Offset += ROUND_UP(OwnerSize, sizeof(ULONG));
518 }
519
520 if (DescriptorCopy.Group)
521 {
522 if (!RtlValidSid(DescriptorCopy.Group)) RtlRaiseStatus(STATUS_INVALID_SID);
523 NewDescriptor->Group = Offset;
524 RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
525 DescriptorCopy.Group,
526 GroupSize);
527 Offset += ROUND_UP(GroupSize, sizeof(ULONG));
528 }
529
530 if (DescriptorCopy.Sacl)
531 {
532 if (!RtlValidAcl(DescriptorCopy.Sacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
533 NewDescriptor->Sacl = Offset;
534 RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
535 DescriptorCopy.Sacl,
536 SaclSize);
537 Offset += ROUND_UP(SaclSize, sizeof(ULONG));
538 }
539
540 if (DescriptorCopy.Dacl)
541 {
542 if (!RtlValidAcl(DescriptorCopy.Dacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
543 NewDescriptor->Dacl = Offset;
544 RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
545 DescriptorCopy.Dacl,
546 DaclSize);
547 Offset += ROUND_UP(DaclSize, sizeof(ULONG));
548 }
549
550 /* Make sure the size was correct */
551 ASSERT(Offset == DescriptorSize);
552 }
553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
554 {
555 /* We failed to copy the data to the new descriptor */
556 ExFreePoolWithTag(NewDescriptor, TAG_SD);
557 _SEH2_YIELD(return _SEH2_GetExceptionCode());
558 }
559 _SEH2_END;
560
561 /*
562 * We're finally done!
563 * Copy the pointer to the captured descriptor to to the caller.
564 */
565 *CapturedSecurityDescriptor = NewDescriptor;
566 return STATUS_SUCCESS;
567 }
568
569 /**
570 * @brief
571 * Queries information details about a security
572 * descriptor.
573 *
574 * @param[in] SecurityInformation
575 * Security information details to be queried
576 * from a security descriptor.
577 *
578 * @param[out] SecurityDescriptor
579 * The returned security descriptor with security information
580 * data.
581 *
582 * @param[in,out] Length
583 * The returned length of a security descriptor.
584 *
585 * @param[in,out] ObjectsSecurityDescriptor
586 * The returned object security descriptor.
587 *
588 * @return
589 * Returns STATUS_SUCCESS if the operations have been
590 * completed successfully and that the specific information
591 * about the security descriptor has been queried.
592 * STATUS_BUFFER_TOO_SMALL is returned if the buffer size
593 * is too small to contain the queried info about the
594 * security descriptor.
595 */
_IRQL_requires_max_(PASSIVE_LEVEL)596 _IRQL_requires_max_(PASSIVE_LEVEL)
597 NTSTATUS
598 NTAPI
599 SeQuerySecurityDescriptorInfo(
600 _In_ PSECURITY_INFORMATION SecurityInformation,
601 _Out_writes_bytes_(*Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
602 _Inout_ PULONG Length,
603 _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor)
604 {
605 PISECURITY_DESCRIPTOR ObjectSd;
606 PISECURITY_DESCRIPTOR_RELATIVE RelSD;
607 PSID Owner = NULL;
608 PSID Group = NULL;
609 PACL Dacl = NULL;
610 PACL Sacl = NULL;
611 ULONG OwnerLength = 0;
612 ULONG GroupLength = 0;
613 ULONG DaclLength = 0;
614 ULONG SaclLength = 0;
615 SECURITY_DESCRIPTOR_CONTROL Control = 0;
616 ULONG_PTR Current;
617 ULONG SdLength;
618
619 PAGED_CODE();
620
621 RelSD = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
622
623 if (*ObjectsSecurityDescriptor == NULL)
624 {
625 if (*Length < sizeof(SECURITY_DESCRIPTOR_RELATIVE))
626 {
627 *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
628 return STATUS_BUFFER_TOO_SMALL;
629 }
630
631 *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
632 RtlCreateSecurityDescriptorRelative(RelSD,
633 SECURITY_DESCRIPTOR_REVISION);
634 return STATUS_SUCCESS;
635 }
636
637 ObjectSd = *ObjectsSecurityDescriptor;
638
639 /* Calculate the required security descriptor length */
640 Control = SE_SELF_RELATIVE;
641 if (*SecurityInformation & OWNER_SECURITY_INFORMATION)
642 {
643 Owner = SepGetOwnerFromDescriptor(ObjectSd);
644 if (Owner != NULL)
645 {
646 OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
647 Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
648 }
649 }
650
651 if (*SecurityInformation & GROUP_SECURITY_INFORMATION)
652 {
653 Group = SepGetGroupFromDescriptor(ObjectSd);
654 if (Group != NULL)
655 {
656 GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
657 Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
658 }
659 }
660
661 if ((*SecurityInformation & DACL_SECURITY_INFORMATION) &&
662 (ObjectSd->Control & SE_DACL_PRESENT))
663 {
664 Dacl = SepGetDaclFromDescriptor(ObjectSd);
665 if (Dacl != NULL)
666 {
667 DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
668 }
669
670 Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
671 }
672
673 if ((*SecurityInformation & SACL_SECURITY_INFORMATION) &&
674 (ObjectSd->Control & SE_SACL_PRESENT))
675 {
676 Sacl = SepGetSaclFromDescriptor(ObjectSd);
677 if (Sacl != NULL)
678 {
679 SaclLength = ROUND_UP(Sacl->AclSize, 4);
680 }
681
682 Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
683 }
684
685 SdLength = OwnerLength + GroupLength + DaclLength +
686 SaclLength + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
687 if (*Length < SdLength)
688 {
689 *Length = SdLength;
690 return STATUS_BUFFER_TOO_SMALL;
691 }
692
693 /* Build the new security descrtiptor */
694 RtlCreateSecurityDescriptorRelative(RelSD,
695 SECURITY_DESCRIPTOR_REVISION);
696 RelSD->Control = Control;
697
698 Current = (ULONG_PTR)(RelSD + 1);
699
700 if (OwnerLength != 0)
701 {
702 RtlCopyMemory((PVOID)Current,
703 Owner,
704 OwnerLength);
705 RelSD->Owner = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
706 Current += OwnerLength;
707 }
708
709 if (GroupLength != 0)
710 {
711 RtlCopyMemory((PVOID)Current,
712 Group,
713 GroupLength);
714 RelSD->Group = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
715 Current += GroupLength;
716 }
717
718 if (DaclLength != 0)
719 {
720 RtlCopyMemory((PVOID)Current,
721 Dacl,
722 DaclLength);
723 RelSD->Dacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
724 Current += DaclLength;
725 }
726
727 if (SaclLength != 0)
728 {
729 RtlCopyMemory((PVOID)Current,
730 Sacl,
731 SaclLength);
732 RelSD->Sacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
733 Current += SaclLength;
734 }
735
736 *Length = SdLength;
737
738 return STATUS_SUCCESS;
739 }
740
741 /**
742 * @brief
743 * Releases a captured security descriptor buffer.
744 *
745 * @param[in] CapturedSecurityDescriptor
746 * The captured security descriptor to be freed.
747 *
748 * @param[in] CurrentMode
749 * Processor level access mode.
750 *
751 * @param[in] CaptureIfKernelMode
752 * Set this to TRUE if the releasing is to be done within
753 * the kernel.
754 *
755 * @return
756 * Returns STATUS_SUCCESS.
757 */
758 NTSTATUS
759 NTAPI
SeReleaseSecurityDescriptor(_In_ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,_In_ KPROCESSOR_MODE CurrentMode,_In_ BOOLEAN CaptureIfKernelMode)760 SeReleaseSecurityDescriptor(
761 _In_ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,
762 _In_ KPROCESSOR_MODE CurrentMode,
763 _In_ BOOLEAN CaptureIfKernelMode)
764 {
765 PAGED_CODE();
766
767 /*
768 * WARNING! You need to call this function with the same value for CurrentMode
769 * and CaptureIfKernelMode that you previously passed to
770 * SeCaptureSecurityDescriptor() in order to avoid memory leaks!
771 */
772 if (CapturedSecurityDescriptor != NULL &&
773 (CurrentMode != KernelMode ||
774 (CurrentMode == KernelMode && CaptureIfKernelMode)))
775 {
776 /* Only delete the descriptor when SeCaptureSecurityDescriptor() allocated one! */
777 ExFreePoolWithTag(CapturedSecurityDescriptor, TAG_SD);
778 }
779
780 return STATUS_SUCCESS;
781 }
782
783 /**
784 * @brief
785 * Modifies some information data about a security
786 * descriptor.
787 *
788 * @param[in] Object
789 * If specified, the function will use this arbitrary
790 * object that points to an object security descriptor.
791 *
792 * @param[in] SecurityInformation
793 * Security information details to be set.
794 *
795 * @param[in] SecurityDescriptor
796 * A security descriptor where its info is to be changed.
797 *
798 * @param[in,out] ObjectsSecurityDescriptor
799 * The returned pointer to security descriptor objects.
800 *
801 * @param[in] PoolType
802 * Pool type for the new security descriptor to allocate.
803 *
804 * @param[in] GenericMapping
805 * The generic mapping of access rights masks.
806 *
807 * @return
808 * See SeSetSecurityDescriptorInfoEx.
809 */
_IRQL_requires_max_(PASSIVE_LEVEL)810 _IRQL_requires_max_(PASSIVE_LEVEL)
811 NTSTATUS
812 NTAPI
813 SeSetSecurityDescriptorInfo(
814 _In_opt_ PVOID Object,
815 _In_ PSECURITY_INFORMATION SecurityInformation,
816 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
817 _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
818 _In_ POOL_TYPE PoolType,
819 _In_ PGENERIC_MAPPING GenericMapping)
820 {
821 PAGED_CODE();
822
823 return SeSetSecurityDescriptorInfoEx(Object,
824 SecurityInformation,
825 SecurityDescriptor,
826 ObjectsSecurityDescriptor,
827 0,
828 PoolType,
829 GenericMapping);
830 }
831
832 /**
833 * @brief
834 * An extended function that sets new information data to
835 * a security descriptor.
836 *
837 * @param[in] Object
838 * If specified, the function will use this arbitrary
839 * object that points to an object security descriptor.
840 *
841 * @param[in] SecurityInformation
842 * Security information details to be set.
843 *
844 * @param[in] SecurityDescriptor
845 * A security descriptor where its info is to be changed.
846 *
847 * @param[in,out] ObjectsSecurityDescriptor
848 * The returned pointer to security descriptor objects.
849 *
850 * @param[in] AutoInheritFlags
851 * Flags bitmask inheritation, influencing how the security
852 * descriptor can be inherited and if it can be in the first
853 * place.
854 *
855 * @param[in] PoolType
856 * Pool type for the new security descriptor to allocate.
857 *
858 * @param[in] GenericMapping
859 * The generic mapping of access rights masks.
860 *
861 * @return
862 * Returns STATUS_SUCCESS if the operations have been
863 * completed without problems and that new info has been
864 * set to the security descriptor. STATUS_NO_SECURITY_ON_OBJECT
865 * is returned if the object does not have a security descriptor.
866 * STATUS_INSUFFICIENT_RESOURCES is returned if memory pool allocation
867 * for the new security descriptor with new info set has failed.
868 */
_IRQL_requires_max_(PASSIVE_LEVEL)869 _IRQL_requires_max_(PASSIVE_LEVEL)
870 NTSTATUS
871 NTAPI
872 SeSetSecurityDescriptorInfoEx(
873 _In_opt_ PVOID Object,
874 _In_ PSECURITY_INFORMATION _SecurityInformation,
875 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor,
876 _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
877 _In_ ULONG AutoInheritFlags,
878 _In_ POOL_TYPE PoolType,
879 _In_ PGENERIC_MAPPING GenericMapping)
880 {
881 PISECURITY_DESCRIPTOR_RELATIVE ObjectSd;
882 PISECURITY_DESCRIPTOR_RELATIVE NewSd;
883 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
884 PSID Owner;
885 PSID Group;
886 PACL Dacl;
887 PACL Sacl;
888 ULONG OwnerLength;
889 ULONG GroupLength;
890 ULONG DaclLength;
891 ULONG SaclLength;
892 SECURITY_DESCRIPTOR_CONTROL Control = 0;
893 ULONG Current;
894 SECURITY_INFORMATION SecurityInformation;
895
896 PAGED_CODE();
897
898 ObjectSd = *ObjectsSecurityDescriptor;
899
900 /* The object does not have a security descriptor. */
901 if (!ObjectSd)
902 return STATUS_NO_SECURITY_ON_OBJECT;
903
904 ASSERT(ObjectSd->Control & SE_SELF_RELATIVE);
905
906 SecurityInformation = *_SecurityInformation;
907
908 /* Get owner and owner size */
909 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
910 {
911 Owner = SepGetOwnerFromDescriptor(SecurityDescriptor);
912 Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
913 }
914 else
915 {
916 Owner = SepGetOwnerFromDescriptor(ObjectSd);
917 Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
918 }
919 OwnerLength = Owner ? RtlLengthSid(Owner) : 0;
920 ASSERT(OwnerLength % sizeof(ULONG) == 0);
921
922 /* Get group and group size */
923 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
924 {
925 Group = SepGetGroupFromDescriptor(SecurityDescriptor);
926 Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
927 }
928 else
929 {
930 Group = SepGetGroupFromDescriptor(ObjectSd);
931 Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
932 }
933 GroupLength = Group ? RtlLengthSid(Group) : 0;
934 ASSERT(GroupLength % sizeof(ULONG) == 0);
935
936 /* Get DACL and DACL size */
937 if (SecurityInformation & DACL_SECURITY_INFORMATION)
938 {
939 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
940 Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
941 }
942 else
943 {
944 Dacl = SepGetDaclFromDescriptor(ObjectSd);
945 Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
946 }
947 DaclLength = Dacl ? ROUND_UP((ULONG)Dacl->AclSize, 4) : 0;
948
949 /* Get SACL and SACL size */
950 if (SecurityInformation & SACL_SECURITY_INFORMATION)
951 {
952 Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
953 Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
954 }
955 else
956 {
957 Sacl = SepGetSaclFromDescriptor(ObjectSd);
958 Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
959 }
960 SaclLength = Sacl ? ROUND_UP((ULONG)Sacl->AclSize, 4) : 0;
961
962 NewSd = ExAllocatePoolWithTag(PoolType,
963 sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
964 OwnerLength + GroupLength +
965 DaclLength + SaclLength,
966 TAG_SD);
967 if (NewSd == NULL)
968 {
969 return STATUS_INSUFFICIENT_RESOURCES;
970 }
971
972 RtlCreateSecurityDescriptorRelative(NewSd, SECURITY_DESCRIPTOR_REVISION1);
973
974 Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
975
976 if (OwnerLength != 0)
977 {
978 RtlCopyMemory((PUCHAR)NewSd + Current, Owner, OwnerLength);
979 NewSd->Owner = Current;
980 Current += OwnerLength;
981 }
982
983 if (GroupLength != 0)
984 {
985 RtlCopyMemory((PUCHAR)NewSd + Current, Group, GroupLength);
986 NewSd->Group = Current;
987 Current += GroupLength;
988 }
989
990 if (DaclLength != 0)
991 {
992 RtlCopyMemory((PUCHAR)NewSd + Current, Dacl, DaclLength);
993 NewSd->Dacl = Current;
994 Current += DaclLength;
995 }
996
997 if (SaclLength != 0)
998 {
999 RtlCopyMemory((PUCHAR)NewSd + Current, Sacl, SaclLength);
1000 NewSd->Sacl = Current;
1001 Current += SaclLength;
1002 }
1003
1004 NewSd->Control |= Control;
1005 *ObjectsSecurityDescriptor = NewSd;
1006 return STATUS_SUCCESS;
1007 }
1008
1009 /**
1010 * @brief
1011 * Determines if a security descriptor is valid according
1012 * to the general security requirements and conditions
1013 * set by the kernel.
1014 *
1015 * @param[in] Length
1016 * The length of a security descriptor.
1017 *
1018 * @param[in] _SecurityDescriptor
1019 * A security descriptor where its properties are to be
1020 * checked for validity.
1021 *
1022 * @return
1023 * Returns TRUE if the given security descriptor is valid,
1024 * FALSE otherwise.
1025 */
1026 BOOLEAN NTAPI
SeValidSecurityDescriptor(_In_ ULONG Length,_In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)1027 SeValidSecurityDescriptor(
1028 _In_ ULONG Length,
1029 _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)
1030 {
1031 ULONG SdLength;
1032 PISID Sid;
1033 PACL Acl;
1034 PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor = _SecurityDescriptor;
1035
1036 if (Length < SECURITY_DESCRIPTOR_MIN_LENGTH)
1037 {
1038 DPRINT1("Invalid Security Descriptor revision\n");
1039 return FALSE;
1040 }
1041
1042 if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
1043 {
1044 DPRINT1("Invalid Security Descriptor revision\n");
1045 return FALSE;
1046 }
1047
1048 if (!(SecurityDescriptor->Control & SE_SELF_RELATIVE))
1049 {
1050 DPRINT1("No self-relative Security Descriptor\n");
1051 return FALSE;
1052 }
1053
1054 SdLength = sizeof(SECURITY_DESCRIPTOR);
1055
1056 /* Check Owner SID */
1057 if (!SecurityDescriptor->Owner)
1058 {
1059 DPRINT1("No Owner SID\n");
1060 return FALSE;
1061 }
1062
1063 if (SecurityDescriptor->Owner % sizeof(ULONG))
1064 {
1065 DPRINT1("Invalid Owner SID alignment\n");
1066 return FALSE;
1067 }
1068
1069 /* Ensure the Owner SID is within the bounds of the security descriptor */
1070 if ((SecurityDescriptor->Owner > Length) ||
1071 (Length - SecurityDescriptor->Owner < sizeof(SID)))
1072 {
1073 DPRINT1("Owner SID not within bounds\n");
1074 return FALSE;
1075 }
1076
1077 /* Reference it */
1078 Sid = (PISID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Owner);
1079 if (Sid->Revision != SID_REVISION)
1080 {
1081 DPRINT1("Invalid Owner SID revision\n");
1082 return FALSE;
1083 }
1084
1085 // NOTE: Same as SeLengthSid(Sid); but doesn't use hardcoded values.
1086 SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1087 if (Length < SdLength)
1088 {
1089 DPRINT1("Invalid Owner SID size\n");
1090 return FALSE;
1091 }
1092
1093 /* Check Group SID */
1094 if (SecurityDescriptor->Group)
1095 {
1096 if (SecurityDescriptor->Group % sizeof(ULONG))
1097 {
1098 DPRINT1("Invalid Group SID alignment\n");
1099 return FALSE;
1100 }
1101
1102 /* Ensure the Group SID is within the bounds of the security descriptor */
1103 if ((SecurityDescriptor->Group > Length) ||
1104 (Length - SecurityDescriptor->Group < sizeof(SID)))
1105 {
1106 DPRINT1("Group SID not within bounds\n");
1107 return FALSE;
1108 }
1109
1110 /* Reference it */
1111 Sid = (PSID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Group);
1112 if (Sid->Revision != SID_REVISION)
1113 {
1114 DPRINT1("Invalid Group SID revision\n");
1115 return FALSE;
1116 }
1117
1118 // NOTE: Same as SeLengthSid(Sid); but doesn't use hardcoded values.
1119 SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1120 if (Length < SdLength)
1121 {
1122 DPRINT1("Invalid Group SID size\n");
1123 return FALSE;
1124 }
1125 }
1126
1127 /* Check DACL */
1128 if (SecurityDescriptor->Dacl)
1129 {
1130 if (SecurityDescriptor->Dacl % sizeof(ULONG))
1131 {
1132 DPRINT1("Invalid DACL alignment\n");
1133 return FALSE;
1134 }
1135
1136 /* Ensure the DACL is within the bounds of the security descriptor */
1137 if ((SecurityDescriptor->Dacl > Length) ||
1138 (Length - SecurityDescriptor->Dacl < sizeof(ACL)))
1139 {
1140 DPRINT1("DACL not within bounds\n");
1141 return FALSE;
1142 }
1143
1144 /* Reference it */
1145 Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Dacl);
1146
1147 SdLength += Acl->AclSize;
1148 if (Length < SdLength)
1149 {
1150 DPRINT1("Invalid DACL size\n");
1151 return FALSE;
1152 }
1153
1154 if (!RtlValidAcl(Acl))
1155 {
1156 DPRINT1("Invalid DACL\n");
1157 return FALSE;
1158 }
1159 }
1160
1161 /* Check SACL */
1162 if (SecurityDescriptor->Sacl)
1163 {
1164 if (SecurityDescriptor->Sacl % sizeof(ULONG))
1165 {
1166 DPRINT1("Invalid SACL alignment\n");
1167 return FALSE;
1168 }
1169
1170 /* Ensure the SACL is within the bounds of the security descriptor */
1171 if ((SecurityDescriptor->Sacl > Length) ||
1172 (Length - SecurityDescriptor->Sacl < sizeof(ACL)))
1173 {
1174 DPRINT1("SACL not within bounds\n");
1175 return FALSE;
1176 }
1177
1178 /* Reference it */
1179 Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Sacl);
1180
1181 SdLength += Acl->AclSize;
1182 if (Length < SdLength)
1183 {
1184 DPRINT1("Invalid SACL size\n");
1185 return FALSE;
1186 }
1187
1188 if (!RtlValidAcl(Acl))
1189 {
1190 DPRINT1("Invalid SACL\n");
1191 return FALSE;
1192 }
1193 }
1194
1195 return TRUE;
1196 }
1197
1198 /**
1199 * @brief
1200 * Frees a security descriptor.
1201 *
1202 * @param[in] SecurityDescriptor
1203 * A security descriptor to be freed from memory.
1204 *
1205 * @return
1206 * Returns STATUS_SUCCESS.
1207 */
_IRQL_requires_max_(PASSIVE_LEVEL)1208 _IRQL_requires_max_(PASSIVE_LEVEL)
1209 NTSTATUS
1210 NTAPI
1211 SeDeassignSecurity(
1212 _Inout_ PSECURITY_DESCRIPTOR *SecurityDescriptor)
1213 {
1214 PAGED_CODE();
1215
1216 if (*SecurityDescriptor != NULL)
1217 {
1218 ExFreePoolWithTag(*SecurityDescriptor, TAG_SD);
1219 *SecurityDescriptor = NULL;
1220 }
1221
1222 return STATUS_SUCCESS;
1223 }
1224
1225 /**
1226 * @brief
1227 * An extended function that assigns a security descriptor for a new
1228 * object.
1229 *
1230 * @param[in] _ParentDescriptor
1231 * A security descriptor of the parent object that is being
1232 * created.
1233 *
1234 * @param[in] _ExplicitDescriptor
1235 * An explicit security descriptor that is applied to a new
1236 * object.
1237 *
1238 * @param[out] NewDescriptor
1239 * The new allocated security descriptor.
1240 *
1241 * @param[in] ObjectType
1242 * The type of the new object.
1243 *
1244 * @param[in] IsDirectoryObject
1245 * Set this to TRUE if the newly created object is a directory
1246 * object, otherwise set this to FALSE.
1247 *
1248 * @param[in] AutoInheritFlags
1249 * Automatic inheritance flags that influence how access control
1250 * entries within ACLs from security descriptors are inherited.
1251 *
1252 * @param[in] SubjectContext
1253 * Security subject context of the new object.
1254 *
1255 * @param[in] GenericMapping
1256 * Generic mapping of access mask rights.
1257 *
1258 * @param[in] PoolType
1259 * This parameter is unused.
1260 *
1261 * @return
1262 * Returns STATUS_SUCCESS if the operations have been completed
1263 * successfully and that the security descriptor has been
1264 * assigned to the new object. STATUS_NO_TOKEN is returned
1265 * if the caller hasn't supplied a valid argument to a security
1266 * subject context. STATUS_INVALID_OWNER is returned if the caller
1267 * hasn't supplied a parent descriptor that belongs to the main
1268 * user (owner). STATUS_INVALID_PRIMARY_GROUP is returned
1269 * by the same reason as with the previous NTSTATUS code.
1270 * The two NTSTATUS codes are returned if the calling thread
1271 * stated that the owner and/or group is defaulted to the
1272 * parent descriptor (SEF_DEFAULT_OWNER_FROM_PARENT and/or
1273 * SEF_DEFAULT_GROUP_FROM_PARENT respectively).
1274 * STATUS_INSUFFICIENT_RESOURCES is returned if memory pool allocation
1275 * for the descriptor buffer has failed. A failure NTSTATUS is returned
1276 * otherwise.
1277 */
_IRQL_requires_max_(PASSIVE_LEVEL)1278 _IRQL_requires_max_(PASSIVE_LEVEL)
1279 NTSTATUS
1280 NTAPI
1281 SeAssignSecurityEx(
1282 _In_opt_ PSECURITY_DESCRIPTOR _ParentDescriptor,
1283 _In_opt_ PSECURITY_DESCRIPTOR _ExplicitDescriptor,
1284 _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1285 _In_opt_ GUID *ObjectType,
1286 _In_ BOOLEAN IsDirectoryObject,
1287 _In_ ULONG AutoInheritFlags,
1288 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1289 _In_ PGENERIC_MAPPING GenericMapping,
1290 _In_ POOL_TYPE PoolType)
1291 {
1292 PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
1293 PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
1294 PISECURITY_DESCRIPTOR_RELATIVE Descriptor;
1295 PTOKEN Token;
1296 ULONG OwnerLength;
1297 ULONG GroupLength;
1298 ULONG DaclLength;
1299 ULONG SaclLength;
1300 ULONG Length;
1301 SECURITY_DESCRIPTOR_CONTROL Control = 0;
1302 ULONG Current;
1303 PSID Owner = NULL;
1304 PSID Group = NULL;
1305 PACL ExplicitAcl;
1306 BOOLEAN ExplicitPresent;
1307 BOOLEAN ExplicitDefaulted;
1308 PACL ParentAcl;
1309 PACL Dacl = NULL;
1310 PACL Sacl = NULL;
1311 BOOLEAN DaclIsInherited;
1312 BOOLEAN SaclIsInherited;
1313 BOOLEAN DaclPresent;
1314 BOOLEAN SaclPresent;
1315 NTSTATUS Status;
1316
1317 DBG_UNREFERENCED_PARAMETER(ObjectType);
1318 DBG_UNREFERENCED_PARAMETER(AutoInheritFlags);
1319 UNREFERENCED_PARAMETER(PoolType);
1320
1321 PAGED_CODE();
1322
1323 *NewDescriptor = NULL;
1324
1325 if (!ARGUMENT_PRESENT(SubjectContext))
1326 {
1327 return STATUS_NO_TOKEN;
1328 }
1329
1330 /* Lock subject context */
1331 SeLockSubjectContext(SubjectContext);
1332
1333 if (SubjectContext->ClientToken != NULL)
1334 {
1335 Token = SubjectContext->ClientToken;
1336 }
1337 else
1338 {
1339 Token = SubjectContext->PrimaryToken;
1340 }
1341
1342 /* Inherit the Owner SID */
1343 if (ExplicitDescriptor != NULL)
1344 {
1345 DPRINT("Use explicit owner sid!\n");
1346 Owner = SepGetOwnerFromDescriptor(ExplicitDescriptor);
1347 }
1348 if (!Owner)
1349 {
1350 if (AutoInheritFlags & SEF_DEFAULT_OWNER_FROM_PARENT)
1351 {
1352 DPRINT("Use parent owner sid!\n");
1353 if (!ARGUMENT_PRESENT(ParentDescriptor))
1354 {
1355 SeUnlockSubjectContext(SubjectContext);
1356 return STATUS_INVALID_OWNER;
1357 }
1358
1359 Owner = SepGetOwnerFromDescriptor(ParentDescriptor);
1360 if (!Owner)
1361 {
1362 SeUnlockSubjectContext(SubjectContext);
1363 return STATUS_INVALID_OWNER;
1364 }
1365 }
1366 else
1367 {
1368 DPRINT("Use token owner sid!\n");
1369 Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
1370 }
1371 }
1372 OwnerLength = RtlLengthSid(Owner);
1373 ASSERT(OwnerLength % sizeof(ULONG) == 0);
1374
1375 /* Inherit the Group SID */
1376 if (ExplicitDescriptor != NULL)
1377 {
1378 Group = SepGetGroupFromDescriptor(ExplicitDescriptor);
1379 }
1380 if (!Group)
1381 {
1382 if (AutoInheritFlags & SEF_DEFAULT_GROUP_FROM_PARENT)
1383 {
1384 DPRINT("Use parent group sid!\n");
1385 if (!ARGUMENT_PRESENT(ParentDescriptor))
1386 {
1387 SeUnlockSubjectContext(SubjectContext);
1388 return STATUS_INVALID_PRIMARY_GROUP;
1389 }
1390
1391 Group = SepGetGroupFromDescriptor(ParentDescriptor);
1392 if (!Group)
1393 {
1394 SeUnlockSubjectContext(SubjectContext);
1395 return STATUS_INVALID_PRIMARY_GROUP;
1396 }
1397 }
1398 else
1399 {
1400 DPRINT("Use token group sid!\n");
1401 Group = Token->PrimaryGroup;
1402 }
1403 }
1404 if (!Group)
1405 {
1406 SeUnlockSubjectContext(SubjectContext);
1407 return STATUS_INVALID_PRIMARY_GROUP;
1408 }
1409 GroupLength = RtlLengthSid(Group);
1410 ASSERT(GroupLength % sizeof(ULONG) == 0);
1411
1412 /* Inherit the DACL */
1413 DaclLength = 0;
1414 ExplicitAcl = NULL;
1415 ExplicitPresent = FALSE;
1416 ExplicitDefaulted = FALSE;
1417 if (ExplicitDescriptor != NULL &&
1418 (ExplicitDescriptor->Control & SE_DACL_PRESENT))
1419 {
1420 ExplicitAcl = SepGetDaclFromDescriptor(ExplicitDescriptor);
1421 ExplicitPresent = TRUE;
1422 if (ExplicitDescriptor->Control & SE_DACL_DEFAULTED)
1423 ExplicitDefaulted = TRUE;
1424 }
1425 ParentAcl = NULL;
1426 if (ParentDescriptor != NULL &&
1427 (ParentDescriptor->Control & SE_DACL_PRESENT))
1428 {
1429 ParentAcl = SepGetDaclFromDescriptor(ParentDescriptor);
1430 }
1431 Dacl = SepSelectAcl(ExplicitAcl,
1432 ExplicitPresent,
1433 ExplicitDefaulted,
1434 ParentAcl,
1435 Token->DefaultDacl,
1436 &DaclLength,
1437 Owner,
1438 Group,
1439 &DaclPresent,
1440 &DaclIsInherited,
1441 IsDirectoryObject,
1442 GenericMapping);
1443 if (DaclPresent)
1444 Control |= SE_DACL_PRESENT;
1445 ASSERT(DaclLength % sizeof(ULONG) == 0);
1446
1447 /* Inherit the SACL */
1448 SaclLength = 0;
1449 ExplicitAcl = NULL;
1450 ExplicitPresent = FALSE;
1451 ExplicitDefaulted = FALSE;
1452 if (ExplicitDescriptor != NULL &&
1453 (ExplicitDescriptor->Control & SE_SACL_PRESENT))
1454 {
1455 ExplicitAcl = SepGetSaclFromDescriptor(ExplicitDescriptor);
1456 ExplicitPresent = TRUE;
1457 if (ExplicitDescriptor->Control & SE_SACL_DEFAULTED)
1458 ExplicitDefaulted = TRUE;
1459 }
1460 ParentAcl = NULL;
1461 if (ParentDescriptor != NULL &&
1462 (ParentDescriptor->Control & SE_SACL_PRESENT))
1463 {
1464 ParentAcl = SepGetSaclFromDescriptor(ParentDescriptor);
1465 }
1466 Sacl = SepSelectAcl(ExplicitAcl,
1467 ExplicitPresent,
1468 ExplicitDefaulted,
1469 ParentAcl,
1470 NULL,
1471 &SaclLength,
1472 Owner,
1473 Group,
1474 &SaclPresent,
1475 &SaclIsInherited,
1476 IsDirectoryObject,
1477 GenericMapping);
1478 if (SaclPresent)
1479 Control |= SE_SACL_PRESENT;
1480 ASSERT(SaclLength % sizeof(ULONG) == 0);
1481
1482 /* Allocate and initialize the new security descriptor */
1483 Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
1484 OwnerLength + GroupLength + DaclLength + SaclLength;
1485
1486 DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %u OwnerLength %lu GroupLength %lu DaclLength %lu SaclLength %lu\n",
1487 sizeof(SECURITY_DESCRIPTOR),
1488 OwnerLength,
1489 GroupLength,
1490 DaclLength,
1491 SaclLength);
1492
1493 Descriptor = ExAllocatePoolWithTag(PagedPool, Length, TAG_SD);
1494 if (Descriptor == NULL)
1495 {
1496 DPRINT1("ExAlloctePool() failed\n");
1497 SeUnlockSubjectContext(SubjectContext);
1498 return STATUS_INSUFFICIENT_RESOURCES;
1499 }
1500
1501 RtlZeroMemory(Descriptor, Length);
1502 RtlCreateSecurityDescriptor(Descriptor, SECURITY_DESCRIPTOR_REVISION);
1503
1504 Descriptor->Control = Control | SE_SELF_RELATIVE;
1505
1506 Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
1507
1508 if (SaclLength != 0)
1509 {
1510 Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1511 &SaclLength,
1512 Sacl,
1513 Owner,
1514 Group,
1515 SaclIsInherited,
1516 IsDirectoryObject,
1517 GenericMapping);
1518 ASSERT(Status == STATUS_SUCCESS);
1519 Descriptor->Sacl = Current;
1520 Current += SaclLength;
1521 }
1522
1523 if (DaclLength != 0)
1524 {
1525 Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1526 &DaclLength,
1527 Dacl,
1528 Owner,
1529 Group,
1530 DaclIsInherited,
1531 IsDirectoryObject,
1532 GenericMapping);
1533 ASSERT(Status == STATUS_SUCCESS);
1534 Descriptor->Dacl = Current;
1535 Current += DaclLength;
1536 }
1537
1538 if (OwnerLength != 0)
1539 {
1540 RtlCopyMemory((PUCHAR)Descriptor + Current, Owner, OwnerLength);
1541 Descriptor->Owner = Current;
1542 Current += OwnerLength;
1543 DPRINT("Owner of %p at %x\n", Descriptor, Descriptor->Owner);
1544 }
1545 else
1546 {
1547 DPRINT("Owner of %p is zero length\n", Descriptor);
1548 }
1549
1550 if (GroupLength != 0)
1551 {
1552 RtlCopyMemory((PUCHAR)Descriptor + Current, Group, GroupLength);
1553 Descriptor->Group = Current;
1554 }
1555
1556 /* Unlock subject context */
1557 SeUnlockSubjectContext(SubjectContext);
1558
1559 *NewDescriptor = Descriptor;
1560
1561 DPRINT("Descriptor %p\n", Descriptor);
1562 ASSERT(RtlLengthSecurityDescriptor(Descriptor));
1563
1564 return STATUS_SUCCESS;
1565 }
1566
1567 /**
1568 * @brief
1569 * Assigns a security descriptor for a new object.
1570 *
1571 * @param[in] ParentDescriptor
1572 * A security descriptor of the parent object that is being
1573 * created.
1574 *
1575 * @param[in] ExplicitDescriptor
1576 * An explicit security descriptor that is applied to a new
1577 * object.
1578 *
1579 * @param[out] NewDescriptor
1580 * The new allocated security descriptor.
1581 *
1582 * @param[in] IsDirectoryObject
1583 * Set this to TRUE if the newly created object is a directory
1584 * object, otherwise set this to FALSE.
1585 *
1586 * @param[in] SubjectContext
1587 * Security subject context of the new object.
1588 *
1589 * @param[in] GenericMapping
1590 * Generic mapping of access mask rights.
1591 *
1592 * @param[in] PoolType
1593 * This parameter is unused.
1594 *
1595 * @return
1596 * See SeAssignSecurityEx.
1597 */
_IRQL_requires_max_(PASSIVE_LEVEL)1598 _IRQL_requires_max_(PASSIVE_LEVEL)
1599 NTSTATUS
1600 NTAPI
1601 SeAssignSecurity(
1602 _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,
1603 _In_opt_ PSECURITY_DESCRIPTOR ExplicitDescriptor,
1604 _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1605 _In_ BOOLEAN IsDirectoryObject,
1606 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1607 _In_ PGENERIC_MAPPING GenericMapping,
1608 _In_ POOL_TYPE PoolType)
1609 {
1610 PAGED_CODE();
1611
1612 return SeAssignSecurityEx(ParentDescriptor,
1613 ExplicitDescriptor,
1614 NewDescriptor,
1615 NULL,
1616 IsDirectoryObject,
1617 0,
1618 SubjectContext,
1619 GenericMapping,
1620 PoolType);
1621 }
1622
1623 /**
1624 * @brief
1625 * Computes the quota size of a security descriptor.
1626 *
1627 * @param[in] SecurityDescriptor
1628 * A security descriptor.
1629 *
1630 * @param[out] QuotaInfoSize
1631 * The returned quota size of the given security descriptor to
1632 * the caller. The function may return 0 to this parameter if
1633 * the descriptor doesn't have a group or a discretionary
1634 * access control list (DACL) even.
1635 *
1636 * @return
1637 * Returns STATUS_SUCCESS if the quota size of a security
1638 * descriptor has been computed successfully. STATUS_UNKNOWN_REVISION
1639 * is returned if the security descriptor has an invalid revision.
1640 */
_IRQL_requires_max_(PASSIVE_LEVEL)1641 _IRQL_requires_max_(PASSIVE_LEVEL)
1642 NTSTATUS
1643 NTAPI
1644 SeComputeQuotaInformationSize(
1645 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1646 _Out_ PULONG QuotaInfoSize)
1647 {
1648 PSID Group;
1649 PACL Dacl;
1650
1651 PAGED_CODE();
1652
1653 *QuotaInfoSize = 0;
1654
1655 /* Validate security descriptor revision */
1656 if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION1)
1657 {
1658 return STATUS_UNKNOWN_REVISION;
1659 }
1660
1661 /* Get group and DACL, if any */
1662 Group = SepGetGroupFromDescriptor(SecurityDescriptor);
1663 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
1664
1665 /* Return SID length if any */
1666 if (Group != NULL)
1667 {
1668 *QuotaInfoSize = ALIGN_UP_BY(RtlLengthSid(Group), sizeof(ULONG));
1669 }
1670
1671 /* Return DACL if any */
1672 if (Dacl != NULL)
1673 {
1674 *QuotaInfoSize += ALIGN_UP_BY(Dacl->AclSize, sizeof(ULONG));
1675 }
1676
1677 return STATUS_SUCCESS;
1678 }
1679
1680 /* EOF */
1681