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