1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security access check control implementation
5 * COPYRIGHT: Copyright 2014 Timo Kreuzer <timo.kreuzer@reactos.org>
6 * Copyright 2014 Eric Kohl
7 * Copyright 2022-2023 George Bișoc <george.bisoc@reactos.org>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* PRIVATE FUNCTIONS **********************************************************/
17
18 /**
19 * @brief
20 * Denies access of a target object and the children objects
21 * in an object type list.
22 *
23 * @param[in,out] ObjectTypeList
24 * A pointer to an object type list where access is to be
25 * denied for the target object and its children in the
26 * hierarchy list.
27 *
28 * @param[in] ObjectTypeListLength
29 * The length of the object type list. This length represents
30 * the number of object elements in the list.
31 *
32 * @param[in] AccessMask
33 * The access mask right that is to be denied for the object.
34 *
35 * @param[in] ObjectTypeGuid
36 * A pointer to a object type GUID, that identifies the object.
37 * This GUID is used to search for the target object in the list.
38 * If this parameter is set to NULL, the function will deny access
39 * starting from the object itself in the list (aka the root).
40 */
41 static
42 VOID
SepDenyAccessObjectTypeResultList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid)43 SepDenyAccessObjectTypeResultList(
44 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
45 _In_ ULONG ObjectTypeListLength,
46 _In_ ACCESS_MASK AccessMask,
47 _In_opt_ PGUID ObjectTypeGuid)
48 {
49 ULONG ObjectTypeIndex;
50 ULONG ReturnedObjectIndex;
51 USHORT Level;
52
53 PAGED_CODE();
54
55 DPRINT("Access rights 0x%08lx\n", AccessMask);
56
57 /*
58 * The object type of interest is the one that was supplied
59 * by the creator who made the ACE. If the object type was
60 * not supplied then we have no clear indication from where
61 * shall we start updating the access rights of objects on
62 * this list, so we have to begin from the root (aka the
63 * object itself).
64 */
65 if (!ObjectTypeGuid)
66 {
67 DPRINT("No object type provided, updating access rights from root\n");
68 ReturnedObjectIndex = 0;
69 goto LoopAndUpdateRightsObjects;
70 }
71
72 /* Check if that object exists in the list */
73 if (SepObjectTypeGuidInList(ObjectTypeList,
74 ObjectTypeListLength,
75 ObjectTypeGuid,
76 &ReturnedObjectIndex))
77 {
78 LoopAndUpdateRightsObjects:
79 /* Update the access rights of the target object */
80 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
81 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
82 DPRINT("Denied rights 0x%08lx of target object at index %lu\n",
83 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
84
85 /* And update the children of the target object */
86 for (ObjectTypeIndex = ReturnedObjectIndex + 1;
87 ObjectTypeIndex < ObjectTypeListLength;
88 ObjectTypeIndex++)
89 {
90 /*
91 * Stop looking for children objects if we hit an object that has
92 * the same level as the target object or less.
93 */
94 Level = ObjectTypeList[ObjectTypeIndex].Level;
95 if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
96 {
97 DPRINT("We looked for all children objects, stop looking\n");
98 break;
99 }
100
101 /* Update the access right of the child */
102 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights |=
103 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights);
104 DPRINT("Denied rights 0x%08lx of child object at index %lu\n",
105 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights, ObjectTypeIndex);
106 }
107 }
108 }
109
110 /**
111 * @brief
112 * Allows access of a target object and the children objects
113 * in an object type list.
114 *
115 * @param[in,out] ObjectTypeList
116 * A pointer to an object type list where access is to be
117 * allowed for the target object and its children in the
118 * hierarchy list.
119 *
120 * @param[in] ObjectTypeListLength
121 * The length of the object type list. This length represents
122 * the number of object elements in the list.
123 *
124 * @param[in] AccessMask
125 * The access mask right that is to be allowed for the object.
126 *
127 * @param[in] ObjectTypeGuid
128 * A pointer to a object type GUID, that identifies the object.
129 * This GUID is used to search for the target object in the list.
130 * If this parameter is set to NULL, the function will allow access
131 * starting from the object itself in the list (aka the root).
132 */
133 static
134 VOID
SepAllowAccessObjectTypeResultList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid)135 SepAllowAccessObjectTypeResultList(
136 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
137 _In_ ULONG ObjectTypeListLength,
138 _In_ ACCESS_MASK AccessMask,
139 _In_opt_ PGUID ObjectTypeGuid)
140 {
141 ULONG ObjectTypeIndex;
142 ULONG ReturnedObjectIndex;
143 USHORT Level;
144
145 PAGED_CODE();
146
147 DPRINT("Access rights 0x%08lx\n", AccessMask);
148
149 /*
150 * Begin updating the access rights from the root object
151 * (see comment in SepDenyAccessObjectTypeListMaximum).
152 */
153 if (!ObjectTypeGuid)
154 {
155 DPRINT("No object type provided, updating access rights from root\n");
156 ReturnedObjectIndex = 0;
157 goto LoopAndUpdateRightsObjects;
158 }
159
160 /* Check if that object exists in the list */
161 if (SepObjectTypeGuidInList(ObjectTypeList,
162 ObjectTypeListLength,
163 ObjectTypeGuid,
164 &ReturnedObjectIndex))
165 {
166 LoopAndUpdateRightsObjects:
167 /* Update the access rights of the target object */
168 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
169 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
170 DPRINT("Granted rights 0x%08lx of target object at index %lu\n",
171 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
172
173 /* And update the children of the target object */
174 for (ObjectTypeIndex = ReturnedObjectIndex + 1;
175 ObjectTypeIndex < ObjectTypeListLength;
176 ObjectTypeIndex++)
177 {
178 /*
179 * Stop looking for children objects if we hit an object that has
180 * the same level as the target object or less.
181 */
182 Level = ObjectTypeList[ObjectTypeIndex].Level;
183 if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
184 {
185 break;
186 }
187
188 /* Update the access right of the child */
189 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights |=
190 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights);
191 DPRINT("Granted rights 0x%08lx of child object at index %lu\n",
192 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights, ObjectTypeIndex);
193 }
194 }
195 }
196
197 /**
198 * @brief
199 * Denies access of a target object in the object type
200 * list. This access is denied for the whole hierarchy
201 * in the list.
202 *
203 * @param[in,out] ObjectTypeList
204 * A pointer to an object type list where access is to be
205 * denied for the target object. This operation applies
206 * for the entire hierarchy of the object type list.
207 *
208 * @param[in] ObjectTypeListLength
209 * The length of the object type list. This length represents
210 * the number of object elements in the list.
211 *
212 * @param[in] AccessMask
213 * The access mask right that is to be denied for the object.
214 *
215 * @param[in] ObjectTypeGuid
216 * A pointer to a object type GUID, that identifies the object.
217 * This GUID is used to search for the target object in the list.
218 * If this parameter is set to NULL, the function will deny access
219 * to the object itself in the list (aka the root).
220 *
221 * @param[out] BreakOnDeny
222 * A pointer returned boolean value to the caller. The function
223 * will return TRUE if the requested remaining right is denied
224 * by the ACE, otherwise it returns FALSE.
225 */
226 static
227 VOID
SepDenyAccessObjectTypeList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid,_Out_opt_ PBOOLEAN BreakOnDeny)228 SepDenyAccessObjectTypeList(
229 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
230 _In_ ULONG ObjectTypeListLength,
231 _In_ ACCESS_MASK AccessMask,
232 _In_opt_ PGUID ObjectTypeGuid,
233 _Out_opt_ PBOOLEAN BreakOnDeny)
234 {
235 ULONG ReturnedObjectIndex;
236 BOOLEAN MustBreak;
237
238 PAGED_CODE();
239
240 DPRINT("Access rights 0x%08lx\n", AccessMask);
241
242 /* Assume we do not want to break at first */
243 MustBreak = FALSE;
244
245 /*
246 * If no object type was supplied then tell the caller it has to break on
247 * searching for other ACEs if the requested remaining access right is
248 * denied by the deny ACE itself. Track down that denied right too.
249 */
250 if (!ObjectTypeGuid)
251 {
252 if (ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights & AccessMask)
253 {
254 DPRINT("Root object requests remaining access right that is denied 0x%08lx\n", AccessMask);
255 MustBreak = TRUE;
256 }
257
258 ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights |=
259 (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
260 DPRINT("Denied rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
261 goto Quit;
262 }
263
264 /*
265 * If the object exists tell the caller it has to break down if the requested
266 * remaining access right is denied by the ACE. Track down the denied right too.
267 */
268 if (SepObjectTypeGuidInList(ObjectTypeList,
269 ObjectTypeListLength,
270 ObjectTypeGuid,
271 &ReturnedObjectIndex))
272 {
273 if (ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights & AccessMask)
274 {
275 DPRINT("Object at index %lu requests remaining access right that is denied 0x%08lx\n", ReturnedObjectIndex, AccessMask);
276 MustBreak = TRUE;
277 }
278
279 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
280 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
281 DPRINT("Denied rights 0x%08lx of object at index %lu\n",
282 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
283 }
284
285 Quit:
286 /* Signal the caller he has to break if he wants to */
287 if (BreakOnDeny)
288 {
289 *BreakOnDeny = MustBreak;
290 }
291 }
292
293 /**
294 * @brief
295 * Allows access of a target object in the object type
296 * list. This access is allowed for the whole hierarchy
297 * in the list.
298 *
299 * @param[in,out] ObjectTypeList
300 * A pointer to an object type list where access is to be
301 * allowed for the target object. This operation applies
302 * for the entire hierarchy of the object type list.
303 *
304 * @param[in] ObjectTypeListLength
305 * The length of the object type list. This length represents
306 * the number of object elements in the list.
307 *
308 * @param[in] AccessMask
309 * The access mask right that is to be allowed for the object.
310 *
311 * @param[in] RemoveRemainingRights
312 * If set to TRUE, the function will remove the remaining rights
313 * of a target object. It will also grant access of the said object.
314 * Otherwise if set to FALSE, the function will only grant access.
315 *
316 * @param[in] ObjectTypeGuid
317 * A pointer to a object type GUID, that identifies the object.
318 * This GUID is used to search for the target object in the list.
319 * If this parameter is set to NULL, the function will allow access
320 * to the object itself in the list (aka the root).
321 */
322 static
323 VOID
SepAllowAccessObjectTypeList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_ BOOLEAN RemoveRemainingRights,_In_opt_ PGUID ObjectTypeGuid)324 SepAllowAccessObjectTypeList(
325 _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
326 _In_ ULONG ObjectTypeListLength,
327 _In_ ACCESS_MASK AccessMask,
328 _In_ BOOLEAN RemoveRemainingRights,
329 _In_opt_ PGUID ObjectTypeGuid)
330 {
331 ULONG ReturnedObjectIndex;
332
333 PAGED_CODE();
334
335 DPRINT("Access rights 0x%08lx\n", AccessMask);
336
337 /*
338 * If no object type was supplied then remove the remaining rights
339 * of the object itself, the root. Track down that right to the
340 * granted rights as well.
341 */
342 if (!ObjectTypeGuid)
343 {
344 if (RemoveRemainingRights)
345 {
346 ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
347 DPRINT("Remaining rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights);
348 }
349
350 ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights |=
351 (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
352 DPRINT("Granted rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
353 return;
354 }
355
356 /*
357 * Grant access to the object if it exists by removing the remaining
358 * rights. Unlike the NtAccessCheckByTypeResultList variant we do not
359 * care about the children of the target object beccause NtAccessCheckByType
360 * will either grant or deny access to the entire hierarchy of the list.
361 */
362 if (SepObjectTypeGuidInList(ObjectTypeList,
363 ObjectTypeListLength,
364 ObjectTypeGuid,
365 &ReturnedObjectIndex))
366 {
367 /* Remove the remaining rights of that object */
368 if (RemoveRemainingRights)
369 {
370 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
371 DPRINT("Remaining rights of object 0x%08lx at index %lu\n",
372 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights, ReturnedObjectIndex);
373 }
374
375 /* And track it down to the granted access rights */
376 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
377 (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
378 DPRINT("Granted rights of object 0x%08lx at index %lu\n",
379 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
380 }
381 }
382
383 /**
384 * @brief
385 * Analyzes an access control entry that is present in a discretionary
386 * access control list (DACL) for access right masks of each entry with
387 * the purpose to judge whether the calling thread can be warranted
388 * access check to a certain object or not.
389 *
390 * @param[in] ActionType
391 * The type of analysis to be done against an access entry. This type
392 * influences how access rights are gathered. This can either be AccessCheckMaximum
393 * which means the algorithm will perform analysis against ACEs on behalf of the
394 * requestor that gave us the acknowledgement that he desires MAXIMUM_ALLOWED access
395 * right or AccessCheckRegular if the requestor wants a subset of access rights.
396 *
397 * @param[in] RemainingAccess
398 * The remaining access rights that have yet to be granted to the calling thread
399 * whomst requests access to a certain object. This parameter mustn't be 0 as
400 * the remaining rights are left to be addressed. This is the case if we have
401 * to address the remaining rights on a regular subset basis (the requestor
402 * didn't ask for MAXIMUM_ALLOWED). Otherwise this parameter can be 0.
403 *
404 * @param[in] Dacl
405 * The discretionary access control list to be given to this function. This DACL
406 * must have at least one ACE currently present in the list.
407 *
408 * @param[in] AccessToken
409 * A pointer to an access token, where an equality comparison check is performed if
410 * the security identifier (SID) from a ACE of a certain object is present in this
411 * token. This token represents the effective (calling thread) token of the caller.
412 *
413 * @param[in] PrimaryAccessToken
414 * A pointer to an access token, represented as an access token associated with the
415 * primary calling process. This token describes the primary security context of the
416 * main process.
417 *
418 * @param[in] IsTokenRestricted
419 * If this parameter is set to TRUE, the function considers the token pointed by
420 * AccessToken parameter argument as restricted. That is, the token has restricted
421 * SIDs therefore the function will act accordingly against that token by checking
422 * for restricted SIDs only when doing an equaility comparison check between the
423 * two identifiers.
424 *
425 * @param[in] PrincipalSelfSid
426 * A pointer to a security identifier that represents a principal. A principal
427 * identifies a user object which is associated with its own security descriptor.
428 *
429 * @param[in] GenericMapping
430 * A pointer to a generic mapping that is associated with the object in question
431 * being checked for access. If certain set of desired access rights have
432 * a generic access right, this parameter is needed to map generic rights.
433 *
434 * @param[in] ObjectTypeList
435 * A pointer to a list array of object types. If such array is provided to the
436 * function, the algorithm will perform a different approach by doing analysis
437 * against ACEs each sub-object of an object of primary level (level 0) or sub-objects
438 * of a sub-object of an object. If this parameter is NULL, the function will normally
439 * analyze the ACEs of a DACL of the target object itself.
440 *
441 * @param[in] ObjectTypeListLength
442 * The length of the object type list array, pointed by ObjectTypeList. This length in
443 * question represents the number of elements in such array. This parameter must be 0
444 * if no array list is provided.
445 *
446 * @param[in] UseResultList
447 * This parameter is to used to determine how to perform an object type access check.
448 * If set to TRUE, the function will either grant or deny access to the object and sub-objects
449 * in the hierarchy list. If set to FALSE, the function will either grant or deny access to
450 * the target that will affect the entire hierarchy of the list. This parameter is used
451 * if the access action type is AccessCheckMaximum.
452 *
453 * @param[in,out] AccessCheckRights
454 * A pointer to a structure that contains the access check rights. This function fills
455 * up this structure with remaining, granted and denied rights to the caller for
456 * access check. Henceforth, this parameter must not be NULL!
457 */
458 static
459 VOID
SepAnalyzeAcesFromDacl(_In_ ACCESS_CHECK_RIGHT_TYPE ActionType,_In_ ACCESS_MASK RemainingAccess,_In_ PACL Dacl,_In_ PACCESS_TOKEN AccessToken,_In_ PACCESS_TOKEN PrimaryAccessToken,_In_ BOOLEAN IsTokenRestricted,_In_opt_ PSID PrincipalSelfSid,_In_ PGENERIC_MAPPING GenericMapping,_In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ BOOLEAN UseResultList,_Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights)460 SepAnalyzeAcesFromDacl(
461 _In_ ACCESS_CHECK_RIGHT_TYPE ActionType,
462 _In_ ACCESS_MASK RemainingAccess,
463 _In_ PACL Dacl,
464 _In_ PACCESS_TOKEN AccessToken,
465 _In_ PACCESS_TOKEN PrimaryAccessToken,
466 _In_ BOOLEAN IsTokenRestricted,
467 _In_opt_ PSID PrincipalSelfSid,
468 _In_ PGENERIC_MAPPING GenericMapping,
469 _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
470 _In_ ULONG ObjectTypeListLength,
471 _In_ BOOLEAN UseResultList,
472 _Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights)
473 {
474 NTSTATUS Status;
475 PACE CurrentAce;
476 ULONG AceIndex;
477 ULONG ObjectTypeIndex;
478 PSID Sid;
479 PGUID ObjectTypeGuid;
480 ACCESS_MASK Access;
481 BOOLEAN BreakOnDeny;
482
483 PAGED_CODE();
484
485 /* These parameters are really needed */
486 ASSERT(Dacl);
487 ASSERT(AccessToken);
488
489 /* TODO: To be removed once we support compound ACEs handling in Se */
490 DBG_UNREFERENCED_PARAMETER(PrimaryAccessToken);
491
492 /* Determine how we should analyze the ACEs */
493 switch (ActionType)
494 {
495 /*
496 * We got the acknowledgement the calling thread desires
497 * maximum rights (as according to MAXIMUM_ALLOWED access
498 * mask). Analyze the ACE of the given DACL.
499 */
500 case AccessCheckMaximum:
501 {
502 /* Loop over the DACL to retrieve ACEs */
503 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++)
504 {
505 /* Obtain a ACE now */
506 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce);
507
508 /* Getting this ACE is important, otherwise something is seriously wrong */
509 ASSERT(NT_SUCCESS(Status));
510
511 /*
512 * Now it's time to analyze it based upon the
513 * type of this ACE we're being given.
514 */
515 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
516 {
517 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
518 {
519 /* Get the SID from this ACE */
520 Sid = SepGetSidFromAce(CurrentAce);
521 ASSERT(Sid);
522
523 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
524 {
525 /* Get this access right from the ACE */
526 Access = CurrentAce->AccessMask;
527
528 /* Map this access right if it has a generic mask right */
529 if ((Access & GENERIC_ACCESS) && GenericMapping)
530 {
531 RtlMapGenericMask(&Access, GenericMapping);
532 }
533
534 /* Deny access rights that have not been granted yet */
535 AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
536 DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
537 }
538 }
539 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
540 {
541 /* Get the SID from this ACE */
542 Sid = SepGetSidFromAce(CurrentAce);
543 ASSERT(Sid);
544
545 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
546 {
547 /* Get this access right from the ACE */
548 Access = CurrentAce->AccessMask;
549
550 /* Map this access right if it has a generic mask right */
551 if ((Access & GENERIC_ACCESS) && GenericMapping)
552 {
553 RtlMapGenericMask(&Access, GenericMapping);
554 }
555
556 /* Grant access rights that have not been denied yet */
557 AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
558 DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
559 }
560 }
561 else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
562 {
563 /* Get the SID and object type from this ACE */
564 Sid = SepGetSidFromAce(CurrentAce);
565 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
566 ASSERT(Sid);
567
568 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
569 {
570 /* Get this access right from the ACE */
571 Access = CurrentAce->AccessMask;
572
573 /* Map this access right if it has a generic mask right */
574 if ((Access & GENERIC_ACCESS) && GenericMapping)
575 {
576 RtlMapGenericMask(&Access, GenericMapping);
577 }
578
579 /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
580 if (!ObjectTypeList && !ObjectTypeListLength)
581 {
582 AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
583 DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
584 }
585 else if (!UseResultList)
586 {
587 /*
588 * We have an object type list but the caller wants to deny access
589 * to the entire hierarchy list. Evaluate the rights of the object
590 * for the whole list. Ignore what the function tells us if we have
591 * to break on deny or not because we only want to keep track of
592 * denied rights.
593 */
594 SepDenyAccessObjectTypeList(ObjectTypeList,
595 ObjectTypeListLength,
596 Access,
597 ObjectTypeGuid,
598 NULL);
599 }
600 else
601 {
602 /* Otherwise evaluate the access rights for each sub-object */
603 SepDenyAccessObjectTypeResultList(ObjectTypeList,
604 ObjectTypeListLength,
605 Access,
606 ObjectTypeGuid);
607 }
608 }
609 }
610 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
611 {
612 /* Get the SID and object type from this ACE */
613 Sid = SepGetSidFromAce(CurrentAce);
614 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
615 ASSERT(Sid);
616
617 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
618 {
619 /* Get this access right from the ACE */
620 Access = CurrentAce->AccessMask;
621
622 /* Map this access right if it has a generic mask right */
623 if ((Access & GENERIC_ACCESS) && GenericMapping)
624 {
625 RtlMapGenericMask(&Access, GenericMapping);
626 }
627
628 /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
629 if (!ObjectTypeList && !ObjectTypeListLength)
630 {
631 AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
632 DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
633 }
634 else if (!UseResultList)
635 {
636 /*
637 * We have an object type list but the caller wants to allow access
638 * to the entire hierarchy list. Evaluate the rights of the object
639 * for the whole list.
640 */
641 SepAllowAccessObjectTypeList(ObjectTypeList,
642 ObjectTypeListLength,
643 Access,
644 FALSE,
645 ObjectTypeGuid);
646 }
647 else
648 {
649 /* Otherwise evaluate the access rights for each sub-object */
650 SepAllowAccessObjectTypeResultList(ObjectTypeList,
651 ObjectTypeListLength,
652 Access,
653 ObjectTypeGuid);
654 }
655 }
656 }
657 else
658 {
659 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
660 }
661 }
662 }
663
664 /* We're done here */
665 break;
666 }
667
668 /*
669 * We got the acknowledgement the calling thread desires
670 * only a subset of rights therefore we have to act a little
671 * different here.
672 */
673 case AccessCheckRegular:
674 {
675 /* Cache the remaining access rights to be addressed */
676 ASSERT(RemainingAccess != 0);
677 AccessCheckRights->RemainingAccessRights = RemainingAccess;
678
679 /* Fill the remaining rights of each object in the list if we have one */
680 if (ObjectTypeList && (ObjectTypeListLength != 0))
681 {
682 for (ObjectTypeIndex = 0;
683 ObjectTypeIndex < ObjectTypeListLength;
684 ObjectTypeIndex++)
685 {
686 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights = RemainingAccess;
687 }
688 }
689
690 /* Loop over the DACL to retrieve ACEs */
691 for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++)
692 {
693 /* Obtain a ACE now */
694 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce);
695
696 /* Getting this ACE is important, otherwise something is seriously wrong */
697 ASSERT(NT_SUCCESS(Status));
698
699 /*
700 * Now it's time to analyze it based upon the
701 * type of this ACE we're being given.
702 */
703 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
704 {
705 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
706 {
707 /* Get the SID from this ACE */
708 Sid = SepGetSidFromAce(CurrentAce);
709 ASSERT(Sid);
710
711 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
712 {
713 /* Get this access right from the ACE */
714 Access = CurrentAce->AccessMask;
715
716 /* Map this access right if it has a generic mask right */
717 if ((Access & GENERIC_ACCESS) && GenericMapping)
718 {
719 RtlMapGenericMask(&Access, GenericMapping);
720 }
721
722 /*
723 * The caller requests a right that cannot be
724 * granted. Access is implicitly denied for
725 * the calling thread. Track this access right.
726 */
727 if (AccessCheckRights->RemainingAccessRights & Access)
728 {
729 DPRINT("Refuted access 0x%08lx\n", Access);
730 AccessCheckRights->DeniedAccessRights |= Access;
731 break;
732 }
733 }
734 }
735 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
736 {
737 /* Get the SID from this ACE */
738 Sid = SepGetSidFromAce(CurrentAce);
739 ASSERT(Sid);
740
741 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
742 {
743 /* Get this access right from the ACE */
744 Access = CurrentAce->AccessMask;
745
746 /* Map this access right if it has a generic mask right */
747 if ((Access & GENERIC_ACCESS) && GenericMapping)
748 {
749 RtlMapGenericMask(&Access, GenericMapping);
750 }
751
752 /* Remove the remaining rights */
753 DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
754 AccessCheckRights->RemainingAccessRights &= ~Access;
755 DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
756
757 /* Track the granted access right */
758 AccessCheckRights->GrantedAccessRights |= Access;
759 }
760 }
761 else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
762 {
763 /* Get the SID and object type from this ACE */
764 Sid = SepGetSidFromAce(CurrentAce);
765 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
766 ASSERT(Sid);
767
768 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
769 {
770 /* Get this access right from the ACE */
771 Access = CurrentAce->AccessMask;
772
773 /* Map this access right if it has a generic mask right */
774 if ((Access & GENERIC_ACCESS) && GenericMapping)
775 {
776 RtlMapGenericMask(&Access, GenericMapping);
777 }
778
779 /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
780 if (!ObjectTypeList && !ObjectTypeListLength)
781 {
782 if (AccessCheckRights->RemainingAccessRights & Access)
783 {
784 DPRINT("Refuted access 0x%08lx\n", Access);
785 AccessCheckRights->DeniedAccessRights |= Access;
786 break;
787 }
788 }
789 else
790 {
791 /*
792 * Otherwise evaluate the rights of the object for the entire list.
793 * The function will signal us if the caller requested a right that is
794 * denied by the ACE of an object in the list.
795 */
796 SepDenyAccessObjectTypeList(ObjectTypeList,
797 ObjectTypeListLength,
798 Access,
799 ObjectTypeGuid,
800 &BreakOnDeny);
801
802 /* We are acknowledged the caller requested a denied right */
803 if (BreakOnDeny)
804 {
805 DPRINT("Refuted access 0x%08lx\n", Access);
806 break;
807 }
808 }
809 }
810 }
811 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
812 {
813 /* Get the SID and object type from this ACE */
814 Sid = SepGetSidFromAce(CurrentAce);
815 ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
816 ASSERT(Sid);
817
818 if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
819 {
820 /* Get this access right from the ACE */
821 Access = CurrentAce->AccessMask;
822
823 /* Map this access right if it has a generic mask right */
824 if ((Access & GENERIC_ACCESS) && GenericMapping)
825 {
826 RtlMapGenericMask(&Access, GenericMapping);
827 }
828
829 /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
830 if (!ObjectTypeList && !ObjectTypeListLength)
831 {
832 /* Remove the remaining rights */
833 DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
834 AccessCheckRights->RemainingAccessRights &= ~Access;
835 DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
836
837 /* Track the granted access right */
838 AccessCheckRights->GrantedAccessRights |= Access;
839 }
840 else
841 {
842 /* Otherwise evaluate the rights of the object for the entire list */
843 SepAllowAccessObjectTypeList(ObjectTypeList,
844 ObjectTypeListLength,
845 Access,
846 TRUE,
847 ObjectTypeGuid);
848 }
849 }
850 }
851 else
852 {
853 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
854 }
855 }
856 }
857
858 /* We're done here */
859 break;
860 }
861
862 /* We shouldn't reach here */
863 DEFAULT_UNREACHABLE;
864 }
865 }
866
867 /**
868 * @brief
869 * Private worker function that determines whether security access rights can be
870 * givento the calling thread in order to access an object depending on the
871 * security descriptor and other security context entities, such as an owner. This
872 * function is the heart and brain of the whole access check algorithm in the kernel.
873 *
874 * @param[in] ClientAccessToken
875 * A pointer to a client (thread) access token that requests access rights
876 * of an object or subset of multiple objects.
877 *
878 * @param[in] PrimaryAccessToken
879 * A pointer to a primary access token that describes the primary security
880 * context of the main calling process.
881 *
882 * @param[in] PrincipalSelfSid
883 * A pointer to a security identifier that represents a security principal,
884 * that is, a user object associated with its security descriptor.
885 *
886 * @param[in] DesiredAccess
887 * The access rights desired by the calling thread to acquire in order to
888 * access an object.
889 *
890 * @param[in] ObjectTypeList
891 * An array list of object types to be checked against for access. The function
892 * will act accordingly in this case by checking each sub-object of an object
893 * of primary level and such. If this parameter is NULL, the function will
894 * perform a normal access check against the target object itself.
895 *
896 * @param[in] ObjectTypeListLength
897 * The length of a object type list. Such length represents the number of
898 * elements in this list.
899 *
900 * @param[in] PreviouslyGrantedAccess
901 * The access rights previously acquired in the past. If this parameter is 0,
902 * it is deemed that the calling thread hasn't acquired any rights. Access checks
903 * are more tighten in this case.
904 *
905 * @param[in] GenericMapping
906 * A pointer to a generic mapping of access rights of the target object.
907 *
908 * @param[in] AccessMode
909 * The processor request level mode.
910 *
911 * @param[in] UseResultList
912 * If set to TRUE, the function will return a list of granted access rights
913 * of each sub-object as well as status code for each. If this parameter is
914 * set to FALSE, then the function will just return only the granted access
915 * rights and status code for single object that's been target for access
916 * checks.
917 *
918 * @param[out] Privileges
919 * A pointer to a definite set of privileges that have been audited
920 * whilst doing access check procedures. Such set of privileges are
921 * optionally returned to the caller. This can be set to NULL if
922 * the caller doesn't want to obtain a set of privileges.
923 *
924 * @param[out] GrantedAccessList
925 * A list of granted access rights returned to the caller. This list
926 * can comprehend multiple elements which represent the sub-objects
927 * that have been checked or a single element which is the target
928 * object itself.
929 *
930 * @param[out] AccessStatusList
931 * A list of access status codes returned to the caller. This list
932 * can comprehend multiple elements which represent the sub-objects
933 * that have been checked or a single element which is the target
934 * object itself.
935 *
936 * @return
937 * Returns TRUE if access onto the specific object is allowed, FALSE
938 * otherwise.
939 */
940 static
941 BOOLEAN
SepAccessCheckWorker(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PACCESS_TOKEN ClientAccessToken,_In_ PACCESS_TOKEN PrimaryAccessToken,_In_opt_ PSID PrincipalSelfSid,_In_ ACCESS_MASK DesiredAccess,_In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK PreviouslyGrantedAccess,_In_ PGENERIC_MAPPING GenericMapping,_In_ KPROCESSOR_MODE AccessMode,_In_ BOOLEAN UseResultList,_Out_opt_ PPRIVILEGE_SET * Privileges,_Out_ PACCESS_MASK GrantedAccessList,_Out_ PNTSTATUS AccessStatusList)942 SepAccessCheckWorker(
943 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
944 _In_opt_ PACCESS_TOKEN ClientAccessToken,
945 _In_ PACCESS_TOKEN PrimaryAccessToken,
946 _In_opt_ PSID PrincipalSelfSid,
947 _In_ ACCESS_MASK DesiredAccess,
948 _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
949 _In_ ULONG ObjectTypeListLength,
950 _In_ ACCESS_MASK PreviouslyGrantedAccess,
951 _In_ PGENERIC_MAPPING GenericMapping,
952 _In_ KPROCESSOR_MODE AccessMode,
953 _In_ BOOLEAN UseResultList,
954 _Out_opt_ PPRIVILEGE_SET* Privileges,
955 _Out_ PACCESS_MASK GrantedAccessList,
956 _Out_ PNTSTATUS AccessStatusList)
957 {
958 ACCESS_MASK RemainingAccess;
959 ACCESS_MASK WantedRights;
960 ACCESS_MASK MaskDesired;
961 ACCESS_MASK GrantedRights = 0;
962 ULONG ResultListIndex;
963 ULONG ObjectTypeIndex;
964 PACL Dacl;
965 BOOLEAN Present;
966 BOOLEAN Defaulted;
967 NTSTATUS Status;
968 BOOLEAN AccessIsGranted = FALSE;
969 PACCESS_TOKEN Token = NULL;
970 ACCESS_CHECK_RIGHTS AccessCheckRights = {0};
971
972 PAGED_CODE();
973
974 /* A security descriptor must be expected for access checks */
975 ASSERT(SecurityDescriptor);
976
977 /* Check for no access desired */
978 if (!DesiredAccess)
979 {
980 /* Check if we had no previous access */
981 if (!PreviouslyGrantedAccess)
982 {
983 /* Then there's nothing to give */
984 DPRINT1("The caller has no previously granted access gained!\n");
985 Status = STATUS_ACCESS_DENIED;
986 goto ReturnCommonStatus;
987 }
988
989 /* Return the previous access only */
990 Status = STATUS_SUCCESS;
991 *Privileges = NULL;
992 goto ReturnCommonStatus;
993 }
994
995 /* Map given accesses */
996 RtlMapGenericMask(&DesiredAccess, GenericMapping);
997 if (PreviouslyGrantedAccess)
998 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
999
1000 /* Initialize remaining access rights */
1001 RemainingAccess = DesiredAccess;
1002
1003 /*
1004 * Initialize the required rights if the caller wants to know access
1005 * for the object and each sub-object in the list.
1006 */
1007 if (UseResultList)
1008 {
1009 if (DesiredAccess & MAXIMUM_ALLOWED)
1010 {
1011 WantedRights = (DesiredAccess | PreviouslyGrantedAccess) & ~MAXIMUM_ALLOWED;
1012 MaskDesired = ~MAXIMUM_ALLOWED;
1013 }
1014 else
1015 {
1016 WantedRights = MaskDesired = DesiredAccess | PreviouslyGrantedAccess;
1017 }
1018 }
1019
1020 /*
1021 * Obtain the token provided by the caller. Client (or also
1022 * called impersonation or thread) token takes precedence over
1023 * the primary token which is the token associated with the security
1024 * context of the main calling process. This is because it is the
1025 * client itself that requests access of an object or subset of
1026 * multiple objects. Otherwise obtain the security context of the
1027 * main process (the actual primary token).
1028 */
1029 Token = ClientAccessToken ? ClientAccessToken : PrimaryAccessToken;
1030
1031 /*
1032 * We should at least expect a primary token
1033 * to be present if client token is not
1034 * available.
1035 */
1036 ASSERT(Token);
1037
1038 /*
1039 * Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access.
1040 * Write down a set of privileges that have been checked
1041 * if the caller wants it.
1042 */
1043 Status = SePrivilegePolicyCheck(&RemainingAccess,
1044 &PreviouslyGrantedAccess,
1045 NULL,
1046 Token,
1047 Privileges,
1048 AccessMode);
1049 if (!NT_SUCCESS(Status))
1050 {
1051 goto ReturnCommonStatus;
1052 }
1053
1054 /* Succeed if there are no more rights to grant */
1055 if (RemainingAccess == 0)
1056 {
1057 Status = STATUS_SUCCESS;
1058 goto ReturnCommonStatus;
1059 }
1060
1061 /*
1062 * HACK: Temporary hack that checks if the caller passed an empty
1063 * generic mapping. In such cases we cannot mask out the remaining
1064 * access rights without a proper mapping so the only option we
1065 * can do is to check if the client is an administrator,
1066 * since they are powerful users.
1067 *
1068 * See CORE-18576 for information.
1069 */
1070 if (GenericMapping->GenericRead == 0 &&
1071 GenericMapping->GenericWrite == 0 &&
1072 GenericMapping->GenericExecute == 0 &&
1073 GenericMapping->GenericAll == 0)
1074 {
1075 if (SeTokenIsAdmin(Token))
1076 {
1077 /* Grant him access */
1078 PreviouslyGrantedAccess |= RemainingAccess;
1079 Status = STATUS_SUCCESS;
1080 goto ReturnCommonStatus;
1081 }
1082
1083 /* It's not an admin so bail out */
1084 PreviouslyGrantedAccess = 0;
1085 Status = STATUS_ACCESS_DENIED;
1086 goto ReturnCommonStatus;
1087 }
1088
1089 /* Get the DACL */
1090 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
1091 &Present,
1092 &Dacl,
1093 &Defaulted);
1094 if (!NT_SUCCESS(Status))
1095 {
1096 goto ReturnCommonStatus;
1097 }
1098
1099 /* Grant desired access if the object is unprotected */
1100 if (Present == FALSE || Dacl == NULL)
1101 {
1102 PreviouslyGrantedAccess |= RemainingAccess;
1103 if (RemainingAccess & MAXIMUM_ALLOWED)
1104 {
1105 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED;
1106 PreviouslyGrantedAccess |= GenericMapping->GenericAll;
1107 }
1108
1109 Status = STATUS_SUCCESS;
1110 goto ReturnCommonStatus;
1111 }
1112
1113 /* Deny access if the DACL is empty */
1114 if (Dacl->AceCount == 0)
1115 {
1116 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
1117 {
1118 Status = STATUS_SUCCESS;
1119 }
1120 else
1121 {
1122 DPRINT1("The DACL has no ACEs and the caller has no previously granted access!\n");
1123 PreviouslyGrantedAccess = 0;
1124 Status = STATUS_ACCESS_DENIED;
1125 }
1126 goto ReturnCommonStatus;
1127 }
1128
1129 /*
1130 * Determine the MAXIMUM_ALLOWED access rights according to the DACL.
1131 * Or if the caller is supplying a list of object types then determine
1132 * the rights of each object on that list.
1133 */
1134 if ((DesiredAccess & MAXIMUM_ALLOWED) || UseResultList)
1135 {
1136 /* Perform access checks against ACEs from this DACL */
1137 SepAnalyzeAcesFromDacl(AccessCheckMaximum,
1138 0,
1139 Dacl,
1140 Token,
1141 PrimaryAccessToken,
1142 FALSE,
1143 PrincipalSelfSid,
1144 GenericMapping,
1145 ObjectTypeList,
1146 ObjectTypeListLength,
1147 UseResultList,
1148 &AccessCheckRights);
1149
1150 /*
1151 * Perform further access checks if this token
1152 * has restricted SIDs.
1153 */
1154 if (SeTokenIsRestricted(Token))
1155 {
1156 SepAnalyzeAcesFromDacl(AccessCheckMaximum,
1157 0,
1158 Dacl,
1159 Token,
1160 PrimaryAccessToken,
1161 TRUE,
1162 PrincipalSelfSid,
1163 GenericMapping,
1164 ObjectTypeList,
1165 ObjectTypeListLength,
1166 UseResultList,
1167 &AccessCheckRights);
1168 }
1169
1170 /* The caller did not provide an object type list, check access only for that object */
1171 if (!ObjectTypeList && !ObjectTypeListLength)
1172 {
1173 /* Fail if some rights have not been granted */
1174 RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights.GrantedAccessRights);
1175 if (RemainingAccess != 0)
1176 {
1177 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
1178 PreviouslyGrantedAccess = 0;
1179 Status = STATUS_ACCESS_DENIED;
1180 goto ReturnCommonStatus;
1181 }
1182
1183 /* Set granted access right and access status */
1184 PreviouslyGrantedAccess |= AccessCheckRights.GrantedAccessRights;
1185 if (PreviouslyGrantedAccess != 0)
1186 {
1187 Status = STATUS_SUCCESS;
1188 }
1189 else
1190 {
1191 DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
1192 Status = STATUS_ACCESS_DENIED;
1193 }
1194
1195 /* We are done here */
1196 goto ReturnCommonStatus;
1197 }
1198 else if (!UseResultList)
1199 {
1200 /*
1201 * We have a list but the caller wants to know if access can be granted
1202 * to an object in the list. Access will either be granted or denied
1203 * to the whole hierarchy of the list. Look for every object in the list
1204 * that has granted access rights and collect them.
1205 */
1206 for (ObjectTypeIndex = 0;
1207 ObjectTypeIndex < ObjectTypeListLength;
1208 ObjectTypeIndex++)
1209 {
1210 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights != 0)
1211 {
1212 GrantedRights |= ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights;
1213 }
1214 }
1215
1216 /* Now check if acccess can be granted */
1217 RemainingAccess &= ~(MAXIMUM_ALLOWED | GrantedRights);
1218 if (RemainingAccess != 0)
1219 {
1220 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n",
1221 RemainingAccess, DesiredAccess);
1222 PreviouslyGrantedAccess = 0;
1223 Status = STATUS_ACCESS_DENIED;
1224 goto ReturnCommonStatus;
1225 }
1226
1227 /* Set granted access right and access status */
1228 PreviouslyGrantedAccess |= GrantedRights;
1229 if (PreviouslyGrantedAccess != 0)
1230 {
1231 Status = STATUS_SUCCESS;
1232 }
1233 else
1234 {
1235 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n",
1236 DesiredAccess);
1237 Status = STATUS_ACCESS_DENIED;
1238 }
1239
1240 /* We are done here */
1241 goto ReturnCommonStatus;
1242 }
1243 else
1244 {
1245 /*
1246 * We have a list and the caller wants to know access for each
1247 * sub-object in the list. Report the access status and granted
1248 * rights for the object and each sub-object in the list.
1249 */
1250 for (ObjectTypeIndex = 0;
1251 ObjectTypeIndex < ObjectTypeListLength;
1252 ObjectTypeIndex++)
1253 {
1254 /* Check if we have some rights */
1255 GrantedRights = (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights | PreviouslyGrantedAccess) & MaskDesired;
1256 if (GrantedRights != 0)
1257 {
1258 /*
1259 * If we still have some remaining rights to grant the ultimate
1260 * conclusion is that the caller has no access to the object itself.
1261 */
1262 RemainingAccess = (~GrantedRights & WantedRights);
1263 if (RemainingAccess != 0)
1264 {
1265 DPRINT("Failed to grant access rights at specific object at index %lu, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n",
1266 ObjectTypeIndex, RemainingAccess, DesiredAccess);
1267 AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
1268 }
1269 else
1270 {
1271 AccessStatusList[ObjectTypeIndex] = STATUS_SUCCESS;
1272 }
1273 }
1274 else
1275 {
1276 /* No access is given */
1277 DPRINT("Failed to grant access rights at specific object at index %lu. No access is given\n", ObjectTypeIndex);
1278 AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
1279 }
1280
1281 /* Return the access rights to the caller */
1282 GrantedAccessList[ObjectTypeIndex] = GrantedRights;
1283 }
1284
1285 /*
1286 * We have built a list of access statuses for each object but
1287 * we still need to figure out the common status for the
1288 * function. The same status code will be used to check if
1289 * we should report any security debug stuff once we are done.
1290 */
1291 Status = STATUS_SUCCESS;
1292 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1293 {
1294 /* There is at least one sub-object of which access cannot be granted */
1295 if (AccessStatusList[ResultListIndex] == STATUS_ACCESS_DENIED)
1296 {
1297 Status = AccessStatusList[ResultListIndex];
1298 break;
1299 }
1300 }
1301
1302 /* We are done here */
1303 goto ReturnCommonStatus;
1304 }
1305 }
1306
1307 /* Grant rights according to the DACL */
1308 SepAnalyzeAcesFromDacl(AccessCheckRegular,
1309 RemainingAccess,
1310 Dacl,
1311 Token,
1312 PrimaryAccessToken,
1313 FALSE,
1314 PrincipalSelfSid,
1315 GenericMapping,
1316 ObjectTypeList,
1317 ObjectTypeListLength,
1318 UseResultList,
1319 &AccessCheckRights);
1320
1321 /* The caller did not provide an object type list, check access only for that object */
1322 if (!ObjectTypeList && !ObjectTypeListLength)
1323 {
1324 /* Fail if some rights have not been granted */
1325 if (AccessCheckRights.RemainingAccessRights != 0)
1326 {
1327 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
1328 PreviouslyGrantedAccess = 0;
1329 Status = STATUS_ACCESS_DENIED;
1330 goto ReturnCommonStatus;
1331 }
1332 }
1333 else
1334 {
1335 /*
1336 * We have an object type list, look for the object of which
1337 * remaining rights are all granted.
1338 */
1339 for (ObjectTypeIndex = 0;
1340 ObjectTypeIndex < ObjectTypeListLength;
1341 ObjectTypeIndex++)
1342 {
1343 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
1344 {
1345 AccessIsGranted = TRUE;
1346 break;
1347 }
1348 }
1349
1350 if (!AccessIsGranted)
1351 {
1352 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess);
1353 PreviouslyGrantedAccess = 0;
1354 Status = STATUS_ACCESS_DENIED;
1355 goto ReturnCommonStatus;
1356 }
1357 }
1358
1359 /*
1360 * Perform further access checks if this token
1361 * has restricted SIDs.
1362 */
1363 if (SeTokenIsRestricted(Token))
1364 {
1365 SepAnalyzeAcesFromDacl(AccessCheckRegular,
1366 RemainingAccess,
1367 Dacl,
1368 Token,
1369 PrimaryAccessToken,
1370 TRUE,
1371 PrincipalSelfSid,
1372 GenericMapping,
1373 ObjectTypeList,
1374 ObjectTypeListLength,
1375 UseResultList,
1376 &AccessCheckRights);
1377
1378 /* The caller did not provide an object type list, check access only for that object */
1379 if (!ObjectTypeList && !ObjectTypeListLength)
1380 {
1381 /* Fail if some rights have not been granted */
1382 if (AccessCheckRights.RemainingAccessRights != 0)
1383 {
1384 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
1385 PreviouslyGrantedAccess = 0;
1386 Status = STATUS_ACCESS_DENIED;
1387 goto ReturnCommonStatus;
1388 }
1389 }
1390 else
1391 {
1392 /*
1393 * We have an object type list, look for the object of which remaining
1394 * rights are all granted. The user may have access to the requested
1395 * object but on a restricted token case the user is only granted partial
1396 * access. If access is denied to restricted SIDs, the bottom line is that
1397 * access is denied to the user.
1398 */
1399 AccessIsGranted = FALSE;
1400 for (ObjectTypeIndex = 0;
1401 ObjectTypeIndex < ObjectTypeListLength;
1402 ObjectTypeIndex++)
1403 {
1404 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
1405 {
1406 AccessIsGranted = TRUE;
1407 break;
1408 }
1409 }
1410
1411 if (!AccessIsGranted)
1412 {
1413 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess);
1414 PreviouslyGrantedAccess = 0;
1415 Status = STATUS_ACCESS_DENIED;
1416 goto ReturnCommonStatus;
1417 }
1418 }
1419 }
1420
1421 /* Set granted access rights */
1422 PreviouslyGrantedAccess |= DesiredAccess;
1423
1424 /* Fail if no rights have been granted */
1425 if (PreviouslyGrantedAccess == 0)
1426 {
1427 DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
1428 Status = STATUS_ACCESS_DENIED;
1429 goto ReturnCommonStatus;
1430 }
1431
1432 /*
1433 * If we're here then we granted all the desired
1434 * access rights the caller wanted.
1435 */
1436 Status = STATUS_SUCCESS;
1437
1438 ReturnCommonStatus:
1439 if (!UseResultList)
1440 {
1441 *GrantedAccessList = PreviouslyGrantedAccess;
1442 *AccessStatusList = Status;
1443 }
1444
1445 #if DBG
1446 /* Dump security debug info on access denied case */
1447 if (Status == STATUS_ACCESS_DENIED)
1448 {
1449 SepDumpSdDebugInfo(SecurityDescriptor);
1450 SepDumpTokenDebugInfo(Token);
1451
1452 if (ObjectTypeList && (ObjectTypeListLength != 0))
1453 {
1454 SepDumpAccessAndStatusList(GrantedAccessList,
1455 AccessStatusList,
1456 UseResultList,
1457 ObjectTypeList,
1458 ObjectTypeListLength);
1459 }
1460 else
1461 {
1462 SepDumpAccessRightsStats(&AccessCheckRights);
1463 }
1464 }
1465 #endif
1466
1467 return NT_SUCCESS(Status);
1468 }
1469
1470 /**
1471 * @brief
1472 * Retrieves the length size of a set list of privileges structure.
1473 *
1474 * @param[in] PrivilegeSet
1475 * A valid set of privileges.
1476 *
1477 * @return
1478 * Returns the total length of a set of privileges.
1479 */
1480 static
1481 ULONG
SepGetPrivilegeSetLength(_In_ PPRIVILEGE_SET PrivilegeSet)1482 SepGetPrivilegeSetLength(
1483 _In_ PPRIVILEGE_SET PrivilegeSet)
1484 {
1485 if (PrivilegeSet == NULL)
1486 return 0;
1487
1488 if (PrivilegeSet->PrivilegeCount == 0)
1489 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES));
1490
1491 return (ULONG)(sizeof(PRIVILEGE_SET) +
1492 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
1493 }
1494
1495 /**
1496 * @brief
1497 * Internal function that performs a security check against the
1498 * client who requests access on a resource object. This function
1499 * is used by access check NT system calls.
1500 *
1501 * @param[in] SecurityDescriptor
1502 * A pointer to a security descriptor that identifies the security
1503 * information of an object being accessed. This function walks
1504 * through this descriptor for any ACLs and respective access
1505 * rights if access can be granted.
1506 *
1507 * @param[in] ClientToken
1508 * A handle to an access token, that identifies the client of which
1509 * requests access to the target object.
1510 *
1511 * @param[in] PrincipalSelfSid
1512 * A pointer to a principal self SID. This parameter can be NULL if
1513 * the associated object being checked for access does not represent
1514 * a principal.
1515 *
1516 * @param[in] DesiredAccess
1517 * The access right bitmask where the client wants to acquire. This
1518 * can be an OR'ed set of multiple access rights or MAXIMUM_ALLOWED
1519 * to request all of possible access rights the target object allows.
1520 * If only some rights were granted but not all the access is deemed
1521 * as denied.
1522 *
1523 * @param[in] GenericMapping
1524 * The generic mapping of access rights of an object type.
1525 *
1526 * @param[out] PrivilegeSet
1527 * A pointer to a set of privileges that were used to perform the
1528 * access check, returned to caller. This function will return no
1529 * privileges (privilege count set to 0) if no privileges were used
1530 * to accomplish the access check. This parameter must not be NULL!
1531 *
1532 * @param[in,out] PrivilegeSetLength
1533 * The total length size of a set of privileges. This length represents
1534 * the count of elements in the privilege set array.
1535 *
1536 * @param[in] ObjectTypeList
1537 * A pointer to a given object type list. If this parameter is not NULL
1538 * the function will perform an access check against the main object
1539 * and sub-objects of this list. If this parameter is NULL and
1540 * ObjectTypeListLength is 0, the function will perform a normal
1541 * access check instead.
1542 *
1543 * @param[in] ObjectTypeListLength
1544 * The length of the object type list array, pointed by ObjectTypeList.
1545 * This length in question represents the number of elements in such array.
1546 * This parameter must be 0 if no array list is provided.
1547 *
1548 * @param[in] UseResultList
1549 * If this parameter is set to TRUE, the function will return the GrantedAccess
1550 * and AccessStatus parameter as arrays of granted rights and status value for
1551 * each individual object element pointed by ObjectTypeList.
1552 *
1553 * @param[out] GrantedAccess
1554 * A pointer to granted access rights, returned to the caller. If ObjectTypeList
1555 * is not NULL this paramater is an array of granted access rights for the object
1556 * and each individual sub-object of the list.
1557 *
1558 * @param[out] AccessStatus
1559 * A pointer to a status code, returned to the caller. This status code
1560 * represents whether access is granted or denied to the client on the
1561 * target object. The difference between the status code of the function
1562 * is that code indicates whether the function has successfully completed
1563 * the access check operation. If ObjectTypeList is not NULL, this
1564 * parameter is an array of access status for the object and each individual
1565 * sub-object of the list.
1566 *
1567 * @return
1568 * Returns STATUS_SUCCESS if access check has been done without problems
1569 * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned
1570 * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned
1571 * if the token from the handle is not an impersonation token.
1572 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated
1573 * because the current security impersonation level doesn't permit so.
1574 * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given
1575 * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if
1576 * the buffer to the captured privileges has a length that is less than the required
1577 * size of the set of privileges. STATUS_INVALID_PARAMETER is returned if the caller
1578 * did not provide an object type list but the caller wanted to invoke an object type
1579 * result list access check, or if the list is out of order or the list is invalid.
1580 * A failure NTSTATUS code is returned otherwise.
1581 *
1582 * @remarks
1583 * The function performs an access check against the object type list,
1584 * if provided, depending on the UseResultList parameter. That is, if that
1585 * parameter was set to TRUE the function will either grant or deny access
1586 * to each individual sub-object and return an array of access status and
1587 * granted rights for the corresponding object type list. Otherwise the function
1588 * will grant or deny access to the object type list hierarchy as a whole.
1589 */
1590 static
1591 NTSTATUS
SepAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ HANDLE ClientToken,_In_opt_ PSID PrincipalSelfSid,_In_ ACCESS_MASK DesiredAccess,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_In_reads_opt_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ BOOLEAN UseResultList,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)1592 SepAccessCheck(
1593 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1594 _In_ HANDLE ClientToken,
1595 _In_opt_ PSID PrincipalSelfSid,
1596 _In_ ACCESS_MASK DesiredAccess,
1597 _In_ PGENERIC_MAPPING GenericMapping,
1598 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
1599 _Inout_ PULONG PrivilegeSetLength,
1600 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
1601 _In_ ULONG ObjectTypeListLength,
1602 _In_ BOOLEAN UseResultList,
1603 _Out_ PACCESS_MASK GrantedAccess,
1604 _Out_ PNTSTATUS AccessStatus)
1605 {
1606 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
1607 POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList = NULL;
1608 PSID CapturedPrincipalSelfSid = NULL;
1609 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
1610 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1611 ACCESS_MASK PreviouslyGrantedAccess = 0;
1612 PPRIVILEGE_SET Privileges = NULL;
1613 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
1614 ULONG ResultListIndex;
1615 PTOKEN Token;
1616 NTSTATUS Status;
1617
1618 PAGED_CODE();
1619
1620 /* Check if this is kernel mode */
1621 if (PreviousMode == KernelMode)
1622 {
1623 /* Check if kernel wants everything */
1624 if (DesiredAccess & MAXIMUM_ALLOWED)
1625 {
1626 /* Give it */
1627 *GrantedAccess = GenericMapping->GenericAll;
1628 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
1629 }
1630 else
1631 {
1632 /* Just give the desired access */
1633 *GrantedAccess = DesiredAccess;
1634 }
1635
1636 /* Success */
1637 *AccessStatus = STATUS_SUCCESS;
1638 return STATUS_SUCCESS;
1639 }
1640
1641 /* Protect probe in SEH */
1642 _SEH2_TRY
1643 {
1644 /* Probe all pointers */
1645 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
1646 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
1647 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
1648
1649 /*
1650 * Probe the access and status list based on the way
1651 * we are going to fill data in.
1652 */
1653 if (UseResultList)
1654 {
1655 /* Bail out on an empty list */
1656 if (!ObjectTypeListLength)
1657 {
1658 DPRINT1("The object type list is empty\n");
1659 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
1660 }
1661
1662 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK) * ObjectTypeListLength, sizeof(ULONG));
1663 ProbeForWrite(AccessStatus, sizeof(NTSTATUS) * ObjectTypeListLength, sizeof(ULONG));
1664 }
1665 else
1666 {
1667 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
1668 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
1669 }
1670
1671 /* Capture the privilege set length and the mapping */
1672 CapturedPrivilegeSetLength = *PrivilegeSetLength;
1673 }
1674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1675 {
1676 /* Return the exception code */
1677 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1678 }
1679 _SEH2_END;
1680
1681 /* Check for unmapped access rights */
1682 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
1683 {
1684 DPRINT1("Some generic rights are not mapped\n");
1685 return STATUS_GENERIC_NOT_MAPPED;
1686 }
1687
1688 /* Reference the token */
1689 Status = ObReferenceObjectByHandle(ClientToken,
1690 TOKEN_QUERY,
1691 SeTokenObjectType,
1692 PreviousMode,
1693 (PVOID*)&Token,
1694 NULL);
1695 if (!NT_SUCCESS(Status))
1696 {
1697 DPRINT1("Failed to reference token (Status 0x%08lx)\n", Status);
1698 return Status;
1699 }
1700
1701 /* Check token type */
1702 if (Token->TokenType != TokenImpersonation)
1703 {
1704 DPRINT("No impersonation token\n");
1705 ObDereferenceObject(Token);
1706 return STATUS_NO_IMPERSONATION_TOKEN;
1707 }
1708
1709 /* Check the impersonation level */
1710 if (Token->ImpersonationLevel < SecurityIdentification)
1711 {
1712 DPRINT1("Impersonation level < SecurityIdentification\n");
1713 ObDereferenceObject(Token);
1714 return STATUS_BAD_IMPERSONATION_LEVEL;
1715 }
1716
1717 /* Capture the object type list, the list is probed by the function itself */
1718 Status = SeCaptureObjectTypeList(ObjectTypeList,
1719 ObjectTypeListLength,
1720 PreviousMode,
1721 &CapturedObjectTypeList);
1722 if (!NT_SUCCESS(Status))
1723 {
1724 DPRINT1("Failed to capture the object type list (Status 0x%08lx)\n", Status);
1725 ObDereferenceObject(Token);
1726 return Status;
1727 }
1728
1729 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
1730 Status = SePrivilegePolicyCheck(&DesiredAccess,
1731 &PreviouslyGrantedAccess,
1732 NULL,
1733 Token,
1734 &Privileges,
1735 PreviousMode);
1736 if (!NT_SUCCESS(Status))
1737 {
1738 DPRINT1("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
1739 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1740 ObDereferenceObject(Token);
1741
1742 /*
1743 * The caller does not have the required access to do an access check.
1744 * Propagate the access and status for the whole hierarchy of the list
1745 * or just to single target object.
1746 */
1747 if (UseResultList)
1748 {
1749 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1750 {
1751 AccessStatus[ResultListIndex] = Status;
1752 GrantedAccess[ResultListIndex] = 0;
1753 }
1754 }
1755 else
1756 {
1757 *AccessStatus = Status;
1758 *GrantedAccess = 0;
1759 }
1760
1761 return STATUS_SUCCESS;
1762 }
1763
1764 /* Check the size of the privilege set and return the privileges */
1765 if (Privileges != NULL)
1766 {
1767 DPRINT("Privileges != NULL\n");
1768
1769 /* Calculate the required privilege set buffer size */
1770 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges);
1771
1772 /* Fail if the privilege set buffer is too small */
1773 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
1774 {
1775 SeFreePrivileges(Privileges);
1776 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1777 ObDereferenceObject(Token);
1778 *PrivilegeSetLength = RequiredPrivilegeSetLength;
1779 return STATUS_BUFFER_TOO_SMALL;
1780 }
1781
1782 /* Copy the privilege set to the caller */
1783 RtlCopyMemory(PrivilegeSet,
1784 Privileges,
1785 RequiredPrivilegeSetLength);
1786
1787 /* Free the local privilege set */
1788 SeFreePrivileges(Privileges);
1789 }
1790 else
1791 {
1792 DPRINT("Privileges == NULL\n");
1793
1794 /* Fail if the privilege set buffer is too small */
1795 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
1796 {
1797 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1798 ObDereferenceObject(Token);
1799 *PrivilegeSetLength = sizeof(PRIVILEGE_SET);
1800 return STATUS_BUFFER_TOO_SMALL;
1801 }
1802
1803 /* Initialize the privilege set */
1804 PrivilegeSet->PrivilegeCount = 0;
1805 PrivilegeSet->Control = 0;
1806 }
1807
1808 /* Capture the security descriptor */
1809 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
1810 PreviousMode,
1811 PagedPool,
1812 FALSE,
1813 &CapturedSecurityDescriptor);
1814 if (!NT_SUCCESS(Status))
1815 {
1816 DPRINT1("Failed to capture the Security Descriptor\n");
1817 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1818 ObDereferenceObject(Token);
1819 return Status;
1820 }
1821
1822 /* Check the captured security descriptor */
1823 if (CapturedSecurityDescriptor == NULL)
1824 {
1825 DPRINT1("Security Descriptor is NULL\n");
1826 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1827 ObDereferenceObject(Token);
1828 return STATUS_INVALID_SECURITY_DESCR;
1829 }
1830
1831 /* Check security descriptor for valid owner and group */
1832 if (SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL ||
1833 SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL)
1834 {
1835 DPRINT1("Security Descriptor does not have a valid group or owner\n");
1836 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1837 PreviousMode,
1838 FALSE);
1839 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1840 ObDereferenceObject(Token);
1841 return STATUS_INVALID_SECURITY_DESCR;
1842 }
1843
1844 /* Capture the principal self SID if we have one */
1845 if (PrincipalSelfSid)
1846 {
1847 Status = SepCaptureSid(PrincipalSelfSid,
1848 PreviousMode,
1849 PagedPool,
1850 TRUE,
1851 &CapturedPrincipalSelfSid);
1852 if (!NT_SUCCESS(Status))
1853 {
1854 DPRINT1("Failed to capture the principal self SID (Status 0x%08lx)\n", Status);
1855 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1856 PreviousMode,
1857 FALSE);
1858 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1859 ObDereferenceObject(Token);
1860 return Status;
1861 }
1862 }
1863
1864 /* Set up the subject context, and lock it */
1865 SeCaptureSubjectContext(&SubjectSecurityContext);
1866
1867 /* Lock the token */
1868 SepAcquireTokenLockShared(Token);
1869
1870 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
1871 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
1872 {
1873 if (SepTokenIsOwner(Token, CapturedSecurityDescriptor, FALSE))
1874 {
1875 if (DesiredAccess & MAXIMUM_ALLOWED)
1876 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
1877 else
1878 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
1879
1880 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
1881 }
1882 }
1883
1884 if (DesiredAccess == 0)
1885 {
1886 /*
1887 * Propagate the access and status for the whole hierarchy
1888 * of the list or just to single target object.
1889 */
1890 if (UseResultList)
1891 {
1892 for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1893 {
1894 AccessStatus[ResultListIndex] = STATUS_SUCCESS;
1895 GrantedAccess[ResultListIndex] = PreviouslyGrantedAccess;
1896 }
1897 }
1898 else
1899 {
1900 *GrantedAccess = PreviouslyGrantedAccess;
1901 *AccessStatus = STATUS_SUCCESS;
1902 }
1903 }
1904 else
1905 {
1906 /* Now perform the access check */
1907 SepAccessCheckWorker(CapturedSecurityDescriptor,
1908 Token,
1909 &SubjectSecurityContext.PrimaryToken,
1910 CapturedPrincipalSelfSid,
1911 DesiredAccess,
1912 CapturedObjectTypeList,
1913 ObjectTypeListLength,
1914 PreviouslyGrantedAccess,
1915 GenericMapping,
1916 PreviousMode,
1917 UseResultList,
1918 NULL,
1919 GrantedAccess,
1920 AccessStatus);
1921 }
1922
1923 /* Release subject context and unlock the token */
1924 SeReleaseSubjectContext(&SubjectSecurityContext);
1925 SepReleaseTokenLock(Token);
1926
1927 /* Release the caputed principal self SID */
1928 SepReleaseSid(CapturedPrincipalSelfSid,
1929 PreviousMode,
1930 TRUE);
1931
1932 /* Release the captured security descriptor */
1933 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1934 PreviousMode,
1935 FALSE);
1936
1937 /* Release the object type list */
1938 SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1939
1940 /* Dereference the token */
1941 ObDereferenceObject(Token);
1942
1943 /* Check succeeded */
1944 return STATUS_SUCCESS;
1945 }
1946
1947 /* PUBLIC FUNCTIONS ***********************************************************/
1948
1949 /**
1950 * @brief
1951 * Determines whether security access rights can be given to an object
1952 * depending on the security descriptor and other security context
1953 * entities, such as an owner.
1954 *
1955 * @param[in] SecurityDescriptor
1956 * Security descriptor of the object that is being accessed.
1957 *
1958 * @param[in] SubjectSecurityContext
1959 * The captured subject security context.
1960 *
1961 * @param[in] SubjectContextLocked
1962 * If set to TRUE, the caller acknowledges that the subject context
1963 * has already been locked by the caller himself. If set to FALSE,
1964 * the function locks the subject context.
1965 *
1966 * @param[in] DesiredAccess
1967 * Access right bitmask that the calling thread wants to acquire.
1968 *
1969 * @param[in] PreviouslyGrantedAccess
1970 * The access rights previously acquired in the past.
1971 *
1972 * @param[out] Privileges
1973 * The returned set of privileges.
1974 *
1975 * @param[in] GenericMapping
1976 * The generic mapping of access rights of an object type.
1977 *
1978 * @param[in] AccessMode
1979 * The processor request level mode.
1980 *
1981 * @param[out] GrantedAccess
1982 * A list of granted access rights.
1983 *
1984 * @param[out] AccessStatus
1985 * The returned status code specifying why access cannot be made
1986 * onto an object (if said access is denied in the first place).
1987 *
1988 * @return
1989 * Returns TRUE if access onto the specific object is allowed, FALSE
1990 * otherwise.
1991 */
1992 BOOLEAN
1993 NTAPI
SeAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,_In_ BOOLEAN SubjectContextLocked,_In_ ACCESS_MASK DesiredAccess,_In_ ACCESS_MASK PreviouslyGrantedAccess,_Out_ PPRIVILEGE_SET * Privileges,_In_ PGENERIC_MAPPING GenericMapping,_In_ KPROCESSOR_MODE AccessMode,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)1994 SeAccessCheck(
1995 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1996 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
1997 _In_ BOOLEAN SubjectContextLocked,
1998 _In_ ACCESS_MASK DesiredAccess,
1999 _In_ ACCESS_MASK PreviouslyGrantedAccess,
2000 _Out_ PPRIVILEGE_SET* Privileges,
2001 _In_ PGENERIC_MAPPING GenericMapping,
2002 _In_ KPROCESSOR_MODE AccessMode,
2003 _Out_ PACCESS_MASK GrantedAccess,
2004 _Out_ PNTSTATUS AccessStatus)
2005 {
2006 BOOLEAN ret;
2007
2008 PAGED_CODE();
2009
2010 /* Check if this is kernel mode */
2011 if (AccessMode == KernelMode)
2012 {
2013 /* Check if kernel wants everything */
2014 if (DesiredAccess & MAXIMUM_ALLOWED)
2015 {
2016 /* Give it */
2017 *GrantedAccess = GenericMapping->GenericAll;
2018 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
2019 *GrantedAccess |= PreviouslyGrantedAccess;
2020 }
2021 else
2022 {
2023 /* Give the desired and previous access */
2024 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
2025 }
2026
2027 /* Success */
2028 *AccessStatus = STATUS_SUCCESS;
2029 return TRUE;
2030 }
2031
2032 /* Check if we didn't get an SD */
2033 if (!SecurityDescriptor)
2034 {
2035 /* Automatic failure */
2036 *AccessStatus = STATUS_ACCESS_DENIED;
2037 return FALSE;
2038 }
2039
2040 /* Check for invalid impersonation */
2041 if ((SubjectSecurityContext->ClientToken) &&
2042 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
2043 {
2044 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
2045 return FALSE;
2046 }
2047
2048 /* Acquire the lock if needed */
2049 if (!SubjectContextLocked)
2050 SeLockSubjectContext(SubjectSecurityContext);
2051
2052 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
2053 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
2054 {
2055 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
2056 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
2057
2058 if (SepTokenIsOwner(Token,
2059 SecurityDescriptor,
2060 FALSE))
2061 {
2062 if (DesiredAccess & MAXIMUM_ALLOWED)
2063 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
2064 else
2065 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
2066
2067 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
2068 }
2069 }
2070
2071 if (DesiredAccess == 0)
2072 {
2073 *GrantedAccess = PreviouslyGrantedAccess;
2074 if (PreviouslyGrantedAccess == 0)
2075 {
2076 DPRINT1("Request for zero access to an object. Denying.\n");
2077 *AccessStatus = STATUS_ACCESS_DENIED;
2078 ret = FALSE;
2079 }
2080 else
2081 {
2082 *AccessStatus = STATUS_SUCCESS;
2083 ret = TRUE;
2084 }
2085 }
2086 else
2087 {
2088 /* Call the internal function */
2089 ret = SepAccessCheckWorker(SecurityDescriptor,
2090 SubjectSecurityContext->ClientToken,
2091 SubjectSecurityContext->PrimaryToken,
2092 NULL,
2093 DesiredAccess,
2094 NULL,
2095 0,
2096 PreviouslyGrantedAccess,
2097 GenericMapping,
2098 AccessMode,
2099 FALSE,
2100 Privileges,
2101 GrantedAccess,
2102 AccessStatus);
2103 }
2104
2105 /* Release the lock if needed */
2106 if (!SubjectContextLocked)
2107 SeUnlockSubjectContext(SubjectSecurityContext);
2108
2109 return ret;
2110 }
2111
2112 /**
2113 * @brief
2114 * Determines whether security access rights can be given to an object
2115 * depending on the security descriptor. Unlike the regular access check
2116 * procedure in the NT kernel, the fast traverse check is a faster way
2117 * to quickly check if access can be made into an object.
2118 *
2119 * @param[in] SecurityDescriptor
2120 * Security descriptor of the object that is being accessed.
2121 *
2122 * @param[in] AccessState
2123 * An access state to determine if the access token in the current
2124 * security context of the object is an restricted token.
2125 *
2126 * @param[in] DesiredAccess
2127 * The access right bitmask where the calling thread wants to acquire.
2128 *
2129 * @param[in] AccessMode
2130 * Process level request mode.
2131 *
2132 * @return
2133 * Returns TRUE if access onto the specific object is allowed, FALSE
2134 * otherwise.
2135 */
2136 BOOLEAN
2137 NTAPI
SeFastTraverseCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PACCESS_STATE AccessState,_In_ ACCESS_MASK DesiredAccess,_In_ KPROCESSOR_MODE AccessMode)2138 SeFastTraverseCheck(
2139 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2140 _In_ PACCESS_STATE AccessState,
2141 _In_ ACCESS_MASK DesiredAccess,
2142 _In_ KPROCESSOR_MODE AccessMode)
2143 {
2144 PACL Dacl;
2145 ULONG AceIndex;
2146 PKNOWN_ACE Ace;
2147
2148 PAGED_CODE();
2149
2150 ASSERT(AccessMode != KernelMode);
2151
2152 if (SecurityDescriptor == NULL)
2153 return FALSE;
2154
2155 /* Get DACL */
2156 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
2157 /* If no DACL, grant access */
2158 if (Dacl == NULL)
2159 return TRUE;
2160
2161 /* No ACE -> Deny */
2162 if (!Dacl->AceCount)
2163 return FALSE;
2164
2165 /* Can't perform the check on restricted token */
2166 if (AccessState->Flags & TOKEN_IS_RESTRICTED)
2167 return FALSE;
2168
2169 /* Browse the ACEs */
2170 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
2171 AceIndex < Dacl->AceCount;
2172 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
2173 {
2174 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
2175 continue;
2176
2177 /* If access-allowed ACE */
2178 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
2179 {
2180 /* Check if all accesses are granted */
2181 if (!(Ace->Mask & DesiredAccess))
2182 continue;
2183
2184 /* Check SID and grant access if matching */
2185 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
2186 return TRUE;
2187 }
2188 /* If access-denied ACE */
2189 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
2190 {
2191 /* Here, only check if it denies any access wanted and deny if so */
2192 if (Ace->Mask & DesiredAccess)
2193 return FALSE;
2194 }
2195 }
2196
2197 /* Faulty, deny */
2198 return FALSE;
2199 }
2200
2201 /* SYSTEM CALLS ***************************************************************/
2202
2203 /**
2204 * @brief
2205 * Determines whether security access can be granted to a client
2206 * that requests such access on an object.
2207 *
2208 * @remarks
2209 * For more documentation details about the parameters and
2210 * overall function behavior, see SepAccessCheck.
2211 */
2212 NTSTATUS
2213 NTAPI
NtAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)2214 NtAccessCheck(
2215 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2216 _In_ HANDLE ClientToken,
2217 _In_ ACCESS_MASK DesiredAccess,
2218 _In_ PGENERIC_MAPPING GenericMapping,
2219 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2220 _Inout_ PULONG PrivilegeSetLength,
2221 _Out_ PACCESS_MASK GrantedAccess,
2222 _Out_ PNTSTATUS AccessStatus)
2223 {
2224 PAGED_CODE();
2225
2226 /* Invoke the internal function to do the job */
2227 return SepAccessCheck(SecurityDescriptor,
2228 ClientToken,
2229 NULL,
2230 DesiredAccess,
2231 GenericMapping,
2232 PrivilegeSet,
2233 PrivilegeSetLength,
2234 NULL,
2235 0,
2236 FALSE,
2237 GrantedAccess,
2238 AccessStatus);
2239 }
2240
2241 /**
2242 * @brief
2243 * Determines whether security access can be granted to a client
2244 * that requests such access on the object type list. The access
2245 * is either granted or denied for the whole object hierarchy
2246 * in the list.
2247 *
2248 * @remarks
2249 * For more documentation details about the parameters and
2250 * overall function behavior, see SepAccessCheck.
2251 */
2252 NTSTATUS
2253 NTAPI
NtAccessCheckByType(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSID PrincipalSelfSid,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_reads_opt_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)2254 NtAccessCheckByType(
2255 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2256 _In_opt_ PSID PrincipalSelfSid,
2257 _In_ HANDLE ClientToken,
2258 _In_ ACCESS_MASK DesiredAccess,
2259 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2260 _In_ ULONG ObjectTypeListLength,
2261 _In_ PGENERIC_MAPPING GenericMapping,
2262 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2263 _Inout_ PULONG PrivilegeSetLength,
2264 _Out_ PACCESS_MASK GrantedAccess,
2265 _Out_ PNTSTATUS AccessStatus)
2266 {
2267 PAGED_CODE();
2268
2269 /* Invoke the internal function to do the job */
2270 return SepAccessCheck(SecurityDescriptor,
2271 ClientToken,
2272 PrincipalSelfSid,
2273 DesiredAccess,
2274 GenericMapping,
2275 PrivilegeSet,
2276 PrivilegeSetLength,
2277 ObjectTypeList,
2278 ObjectTypeListLength,
2279 FALSE,
2280 GrantedAccess,
2281 AccessStatus);
2282 }
2283
2284 /**
2285 * @brief
2286 * Determines whether security access can be granted to a client
2287 * that requests such access on the object type list. Unlike the
2288 * NtAccessCheckByType variant, this function will grant or deny
2289 * access to each individual object and sub-object in the list.
2290 *
2291 * @remarks
2292 * For more documentation details about the parameters and
2293 * overall function behavior, see SepAccessCheck.
2294 */
2295 NTSTATUS
2296 NTAPI
NtAccessCheckByTypeResultList(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSID PrincipalSelfSid,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_reads_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_writes_ (ObjectTypeListLength)PACCESS_MASK GrantedAccess,_Out_writes_ (ObjectTypeListLength)PNTSTATUS AccessStatus)2297 NtAccessCheckByTypeResultList(
2298 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2299 _In_opt_ PSID PrincipalSelfSid,
2300 _In_ HANDLE ClientToken,
2301 _In_ ACCESS_MASK DesiredAccess,
2302 _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2303 _In_ ULONG ObjectTypeListLength,
2304 _In_ PGENERIC_MAPPING GenericMapping,
2305 _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2306 _Inout_ PULONG PrivilegeSetLength,
2307 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,
2308 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus)
2309 {
2310 PAGED_CODE();
2311
2312 /* Invoke the internal function to do the job */
2313 return SepAccessCheck(SecurityDescriptor,
2314 ClientToken,
2315 PrincipalSelfSid,
2316 DesiredAccess,
2317 GenericMapping,
2318 PrivilegeSet,
2319 PrivilegeSetLength,
2320 ObjectTypeList,
2321 ObjectTypeListLength,
2322 TRUE,
2323 GrantedAccess,
2324 AccessStatus);
2325 }
2326
2327 /* EOF */
2328