[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / priv.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/priv.c
5 * PURPOSE: Security manager
6 *
7 * PROGRAMMERS: No programmer listed.
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitPrivileges)
18 #endif
19
20 /* GLOBALS ********************************************************************/
21
22 #define CONST_LUID(x1, x2) {x1, x2}
23 const LUID SeCreateTokenPrivilege = CONST_LUID(SE_CREATE_TOKEN_PRIVILEGE, 0);
24 const LUID SeAssignPrimaryTokenPrivilege = CONST_LUID(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 0);
25 const LUID SeLockMemoryPrivilege = CONST_LUID(SE_LOCK_MEMORY_PRIVILEGE, 0);
26 const LUID SeIncreaseQuotaPrivilege = CONST_LUID(SE_INCREASE_QUOTA_PRIVILEGE, 0);
27 const LUID SeUnsolicitedInputPrivilege = CONST_LUID(6, 0);
28 const LUID SeTcbPrivilege = CONST_LUID(SE_TCB_PRIVILEGE, 0);
29 const LUID SeSecurityPrivilege = CONST_LUID(SE_SECURITY_PRIVILEGE, 0);
30 const LUID SeTakeOwnershipPrivilege = CONST_LUID(SE_TAKE_OWNERSHIP_PRIVILEGE, 0);
31 const LUID SeLoadDriverPrivilege = CONST_LUID(SE_LOAD_DRIVER_PRIVILEGE, 0);
32 const LUID SeSystemProfilePrivilege = CONST_LUID(SE_SYSTEM_PROFILE_PRIVILEGE, 0);
33 const LUID SeSystemtimePrivilege = CONST_LUID(SE_SYSTEMTIME_PRIVILEGE, 0);
34 const LUID SeProfileSingleProcessPrivilege = CONST_LUID(SE_PROF_SINGLE_PROCESS_PRIVILEGE, 0);
35 const LUID SeIncreaseBasePriorityPrivilege = CONST_LUID(SE_INC_BASE_PRIORITY_PRIVILEGE, 0);
36 const LUID SeCreatePagefilePrivilege = CONST_LUID(SE_CREATE_PAGEFILE_PRIVILEGE, 0);
37 const LUID SeCreatePermanentPrivilege = CONST_LUID(SE_CREATE_PERMANENT_PRIVILEGE, 0);
38 const LUID SeBackupPrivilege = CONST_LUID(SE_BACKUP_PRIVILEGE, 0);
39 const LUID SeRestorePrivilege = CONST_LUID(SE_RESTORE_PRIVILEGE, 0);
40 const LUID SeShutdownPrivilege = CONST_LUID(SE_SHUTDOWN_PRIVILEGE, 0);
41 const LUID SeDebugPrivilege = CONST_LUID(SE_DEBUG_PRIVILEGE, 0);
42 const LUID SeAuditPrivilege = CONST_LUID(SE_AUDIT_PRIVILEGE, 0);
43 const LUID SeSystemEnvironmentPrivilege = CONST_LUID(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, 0);
44 const LUID SeChangeNotifyPrivilege = CONST_LUID(SE_CHANGE_NOTIFY_PRIVILEGE, 0);
45 const LUID SeRemoteShutdownPrivilege = CONST_LUID(SE_REMOTE_SHUTDOWN_PRIVILEGE, 0);
46 const LUID SeUndockPrivilege = CONST_LUID(SE_UNDOCK_PRIVILEGE, 0);
47 const LUID SeSyncAgentPrivilege = CONST_LUID(SE_SYNC_AGENT_PRIVILEGE, 0);
48 const LUID SeEnableDelegationPrivilege = CONST_LUID(SE_ENABLE_DELEGATION_PRIVILEGE, 0);
49 const LUID SeManageVolumePrivilege = CONST_LUID(SE_MANAGE_VOLUME_PRIVILEGE, 0);
50 const LUID SeImpersonatePrivilege = CONST_LUID(SE_IMPERSONATE_PRIVILEGE, 0);
51 const LUID SeCreateGlobalPrivilege = CONST_LUID(SE_CREATE_GLOBAL_PRIVILEGE, 0);
52 const LUID SeTrustedCredmanPrivilege = CONST_LUID(SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE, 0);
53 const LUID SeRelabelPrivilege = CONST_LUID(SE_RELABEL_PRIVILEGE, 0);
54 const LUID SeIncreaseWorkingSetPrivilege = CONST_LUID(SE_INC_WORKING_SET_PRIVILEGE, 0);
55 const LUID SeTimeZonePrivilege = CONST_LUID(SE_TIME_ZONE_PRIVILEGE, 0);
56 const LUID SeCreateSymbolicLinkPrivilege = CONST_LUID(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE, 0);
57
58
59 /* PRIVATE FUNCTIONS **********************************************************/
60
61 VOID
62 INIT_FUNCTION
63 NTAPI
64 SepInitPrivileges(VOID)
65 {
66
67 }
68
69
70 BOOLEAN
71 NTAPI
72 SepPrivilegeCheck(PTOKEN Token,
73 PLUID_AND_ATTRIBUTES Privileges,
74 ULONG PrivilegeCount,
75 ULONG PrivilegeControl,
76 KPROCESSOR_MODE PreviousMode)
77 {
78 ULONG i;
79 ULONG j;
80 ULONG Required;
81
82 DPRINT("SepPrivilegeCheck() called\n");
83
84 PAGED_CODE();
85
86 if (PreviousMode == KernelMode)
87 return TRUE;
88
89 /* Get the number of privileges that are required to match */
90 Required = (PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) ? PrivilegeCount : 1;
91
92 /* Loop all requested privileges until we found the required ones */
93 for (i = 0; i < PrivilegeCount; i++)
94 {
95 /* Loop the privileges of the token */
96 for (j = 0; j < Token->PrivilegeCount; j++)
97 {
98 /* Check if the LUIDs match */
99 if (Token->Privileges[j].Luid.LowPart == Privileges[i].Luid.LowPart &&
100 Token->Privileges[j].Luid.HighPart == Privileges[i].Luid.HighPart)
101 {
102 DPRINT("Found privilege. Attributes: %lx\n",
103 Token->Privileges[j].Attributes);
104
105 /* Check if the privilege is enabled */
106 if (Token->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED)
107 {
108 Privileges[i].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
109 Required--;
110
111 /* Check if we have found all privileges */
112 if (Required == 0)
113 {
114 /* We're done! */
115 return TRUE;
116 }
117 }
118
119 /* Leave the inner loop */
120 break;
121 }
122 }
123 }
124
125 /* When we reached this point, we did not find all privileges */
126 NT_ASSERT(Required > 0);
127 return FALSE;
128 }
129
130 NTSTATUS
131 NTAPI
132 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,
133 ULONG PrivilegeCount,
134 KPROCESSOR_MODE PreviousMode,
135 PLUID_AND_ATTRIBUTES AllocatedMem,
136 ULONG AllocatedLength,
137 POOL_TYPE PoolType,
138 BOOLEAN CaptureIfKernel,
139 PLUID_AND_ATTRIBUTES *Dest,
140 PULONG Length)
141 {
142 ULONG BufferSize;
143 NTSTATUS Status = STATUS_SUCCESS;
144
145 PAGED_CODE();
146
147 if (PrivilegeCount == 0)
148 {
149 *Dest = 0;
150 *Length = 0;
151 return STATUS_SUCCESS;
152 }
153
154 if (PreviousMode == KernelMode && !CaptureIfKernel)
155 {
156 *Dest = Src;
157 return STATUS_SUCCESS;
158 }
159
160 /* FIXME - check PrivilegeCount for a valid number so we don't
161 cause an integer overflow or exhaust system resources! */
162
163 BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
164 *Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
165
166 /* probe the buffer */
167 if (PreviousMode != KernelMode)
168 {
169 _SEH2_TRY
170 {
171 ProbeForRead(Src,
172 BufferSize,
173 sizeof(ULONG));
174 }
175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
176 {
177 /* Return the exception code */
178 _SEH2_YIELD(return _SEH2_GetExceptionCode());
179 }
180 _SEH2_END;
181 }
182
183 /* allocate enough memory or check if the provided buffer is
184 large enough to hold the array */
185 if (AllocatedMem != NULL)
186 {
187 if (AllocatedLength < BufferSize)
188 {
189 return STATUS_BUFFER_TOO_SMALL;
190 }
191
192 *Dest = AllocatedMem;
193 }
194 else
195 {
196 *Dest = ExAllocatePool(PoolType,
197 BufferSize);
198 if (*Dest == NULL)
199 {
200 return STATUS_INSUFFICIENT_RESOURCES;
201 }
202 }
203
204 /* copy the array to the buffer */
205 _SEH2_TRY
206 {
207 RtlCopyMemory(*Dest,
208 Src,
209 BufferSize);
210 }
211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
212 {
213 Status = _SEH2_GetExceptionCode();
214 }
215 _SEH2_END;
216
217 if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
218 {
219 ExFreePool(*Dest);
220 }
221
222 return Status;
223 }
224
225 VOID
226 NTAPI
227 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
228 KPROCESSOR_MODE PreviousMode,
229 BOOLEAN CaptureIfKernel)
230 {
231 PAGED_CODE();
232
233 if (Privilege != NULL &&
234 (PreviousMode != KernelMode || CaptureIfKernel))
235 {
236 ExFreePool(Privilege);
237 }
238 }
239
240 /* PUBLIC FUNCTIONS ***********************************************************/
241
242 /*
243 * @implemented
244 */
245 NTSTATUS
246 NTAPI
247 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState,
248 IN PPRIVILEGE_SET Privileges)
249 {
250 PAUX_ACCESS_DATA AuxData;
251 ULONG OldPrivilegeSetSize;
252 ULONG NewPrivilegeSetSize;
253 PPRIVILEGE_SET PrivilegeSet;
254
255 PAGED_CODE();
256
257 /* Get the Auxiliary Data */
258 AuxData = AccessState->AuxData;
259
260 /* Calculate the size of the old privilege set */
261 OldPrivilegeSetSize = sizeof(PRIVILEGE_SET) +
262 (AuxData->PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
263
264 if (AuxData->PrivilegeSet->PrivilegeCount +
265 Privileges->PrivilegeCount > INITIAL_PRIVILEGE_COUNT)
266 {
267 /* Calculate the size of the new privilege set */
268 NewPrivilegeSetSize = OldPrivilegeSetSize +
269 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
270
271 /* Allocate a new privilege set */
272 PrivilegeSet = ExAllocatePool(PagedPool, NewPrivilegeSetSize);
273 if (PrivilegeSet == NULL)
274 return STATUS_INSUFFICIENT_RESOURCES;
275
276 /* Copy original privileges from the acess state */
277 RtlCopyMemory(PrivilegeSet,
278 AuxData->PrivilegeSet,
279 OldPrivilegeSetSize);
280
281 /* Append privileges from the privilege set*/
282 RtlCopyMemory((PVOID)((ULONG_PTR)PrivilegeSet + OldPrivilegeSetSize),
283 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
284 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
285
286 /* Adjust the number of privileges in the new privilege set */
287 PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
288
289 /* Free the old privilege set if it was allocated */
290 if (AccessState->PrivilegesAllocated == TRUE)
291 ExFreePool(AuxData->PrivilegeSet);
292
293 /* Now we are using an allocated privilege set */
294 AccessState->PrivilegesAllocated = TRUE;
295
296 /* Assign the new privileges to the access state */
297 AuxData->PrivilegeSet = PrivilegeSet;
298 }
299 else
300 {
301 /* Append privileges */
302 RtlCopyMemory((PVOID)((ULONG_PTR)AuxData->PrivilegeSet + OldPrivilegeSetSize),
303 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
304 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
305
306 /* Adjust the number of privileges in the target privilege set */
307 AuxData->PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
308 }
309
310 return STATUS_SUCCESS;
311 }
312
313 /*
314 * @implemented
315 */
316 VOID
317 NTAPI
318 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
319 {
320 PAGED_CODE();
321 ExFreePool(Privileges);
322 }
323
324 /*
325 * @implemented
326 */
327 BOOLEAN
328 NTAPI
329 SePrivilegeCheck(PPRIVILEGE_SET Privileges,
330 PSECURITY_SUBJECT_CONTEXT SubjectContext,
331 KPROCESSOR_MODE PreviousMode)
332 {
333 PACCESS_TOKEN Token = NULL;
334
335 PAGED_CODE();
336
337 if (SubjectContext->ClientToken == NULL)
338 {
339 Token = SubjectContext->PrimaryToken;
340 }
341 else
342 {
343 Token = SubjectContext->ClientToken;
344 if (SubjectContext->ImpersonationLevel < 2)
345 {
346 return FALSE;
347 }
348 }
349
350 return SepPrivilegeCheck(Token,
351 Privileges->Privilege,
352 Privileges->PrivilegeCount,
353 Privileges->Control,
354 PreviousMode);
355 }
356
357 /*
358 * @implemented
359 */
360 BOOLEAN
361 NTAPI
362 SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
363 IN KPROCESSOR_MODE PreviousMode)
364 {
365 SECURITY_SUBJECT_CONTEXT SubjectContext;
366 PRIVILEGE_SET Priv;
367 BOOLEAN Result;
368
369 PAGED_CODE();
370
371 SeCaptureSubjectContext(&SubjectContext);
372
373 Priv.PrivilegeCount = 1;
374 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
375 Priv.Privilege[0].Luid = PrivilegeValue;
376 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
377
378 Result = SePrivilegeCheck(&Priv,
379 &SubjectContext,
380 PreviousMode);
381
382 if (PreviousMode != KernelMode)
383 {
384 #if 0
385 SePrivilegedServiceAuditAlarm(0,
386 &SubjectContext,
387 &PrivilegeValue);
388 #endif
389 }
390
391 SeReleaseSubjectContext(&SubjectContext);
392
393 return Result;
394 }
395
396 BOOLEAN
397 NTAPI
398 SeCheckPrivilegedObject(IN LUID PrivilegeValue,
399 IN HANDLE ObjectHandle,
400 IN ACCESS_MASK DesiredAccess,
401 IN KPROCESSOR_MODE PreviousMode)
402 {
403 SECURITY_SUBJECT_CONTEXT SubjectContext;
404 PRIVILEGE_SET Priv;
405 BOOLEAN Result;
406
407 PAGED_CODE();
408
409 SeCaptureSubjectContext(&SubjectContext);
410
411 Priv.PrivilegeCount = 1;
412 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
413 Priv.Privilege[0].Luid = PrivilegeValue;
414 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
415
416 Result = SePrivilegeCheck(&Priv, &SubjectContext, PreviousMode);
417 if (PreviousMode != KernelMode)
418 {
419 #if 0
420 SePrivilegeObjectAuditAlarm(ObjectHandle,
421 &SubjectContext,
422 DesiredAccess,
423 &PrivilegeValue,
424 Result,
425 PreviousMode);
426 #endif
427 }
428
429 SeReleaseSubjectContext(&SubjectContext);
430
431 return Result;
432 }
433
434 /* SYSTEM CALLS ***************************************************************/
435
436 NTSTATUS
437 NTAPI
438 NtPrivilegeCheck(IN HANDLE ClientToken,
439 IN PPRIVILEGE_SET RequiredPrivileges,
440 OUT PBOOLEAN Result)
441 {
442 PLUID_AND_ATTRIBUTES Privileges;
443 PTOKEN Token;
444 ULONG PrivilegeCount = 0;
445 ULONG PrivilegeControl = 0;
446 ULONG Length;
447 BOOLEAN CheckResult;
448 KPROCESSOR_MODE PreviousMode;
449 NTSTATUS Status;
450
451 PAGED_CODE();
452
453 PreviousMode = KeGetPreviousMode();
454
455 /* probe the buffers */
456 if (PreviousMode != KernelMode)
457 {
458 _SEH2_TRY
459 {
460 ProbeForWrite(RequiredPrivileges,
461 FIELD_OFFSET(PRIVILEGE_SET,
462 Privilege),
463 sizeof(ULONG));
464
465 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
466 PrivilegeControl = RequiredPrivileges->Control;
467
468 /* Check PrivilegeCount to avoid an integer overflow! */
469 if (FIELD_OFFSET(PRIVILEGE_SET,
470 Privilege[PrivilegeCount]) /
471 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
472 {
473 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
474 }
475
476 /* probe all of the array */
477 ProbeForWrite(RequiredPrivileges,
478 FIELD_OFFSET(PRIVILEGE_SET,
479 Privilege[PrivilegeCount]),
480 sizeof(ULONG));
481
482 ProbeForWriteBoolean(Result);
483 }
484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
485 {
486 /* Return the exception code */
487 _SEH2_YIELD(return _SEH2_GetExceptionCode());
488 }
489 _SEH2_END;
490 }
491 else
492 {
493 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
494 PrivilegeControl = RequiredPrivileges->Control;
495 }
496
497 /* reference the token and make sure we're
498 not doing an anonymous impersonation */
499 Status = ObReferenceObjectByHandle(ClientToken,
500 TOKEN_QUERY,
501 SeTokenObjectType,
502 PreviousMode,
503 (PVOID*)&Token,
504 NULL);
505 if (!NT_SUCCESS(Status))
506 {
507 return Status;
508 }
509
510 if (Token->TokenType == TokenImpersonation &&
511 Token->ImpersonationLevel < SecurityIdentification)
512 {
513 ObDereferenceObject(Token);
514 return STATUS_BAD_IMPERSONATION_LEVEL;
515 }
516
517 /* capture the privileges */
518 Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
519 PrivilegeCount,
520 PreviousMode,
521 NULL,
522 0,
523 PagedPool,
524 TRUE,
525 &Privileges,
526 &Length);
527 if (!NT_SUCCESS(Status))
528 {
529 ObDereferenceObject (Token);
530 return Status;
531 }
532
533 CheckResult = SepPrivilegeCheck(Token,
534 Privileges,
535 PrivilegeCount,
536 PrivilegeControl,
537 PreviousMode);
538
539 ObDereferenceObject(Token);
540
541 /* return the array */
542 _SEH2_TRY
543 {
544 RtlCopyMemory(RequiredPrivileges->Privilege,
545 Privileges,
546 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
547 *Result = CheckResult;
548 Status = STATUS_SUCCESS;
549 }
550 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
551 {
552 Status = _SEH2_GetExceptionCode();
553 }
554 _SEH2_END;
555
556 SeReleaseLuidAndAttributesArray(Privileges,
557 PreviousMode,
558 TRUE);
559
560 return Status;
561 }
562
563 /* EOF */