Sync up with trunk r61578.
[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 #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 && Required > 0; 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
112 /* Leave the inner loop */
113 break;
114 }
115 }
116 }
117
118 /* Return whether we found all required privileges */
119 return (Required == 0);
120 }
121
122 NTSTATUS
123 NTAPI
124 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,
125 ULONG PrivilegeCount,
126 KPROCESSOR_MODE PreviousMode,
127 PLUID_AND_ATTRIBUTES AllocatedMem,
128 ULONG AllocatedLength,
129 POOL_TYPE PoolType,
130 BOOLEAN CaptureIfKernel,
131 PLUID_AND_ATTRIBUTES *Dest,
132 PULONG Length)
133 {
134 ULONG BufferSize;
135 NTSTATUS Status = STATUS_SUCCESS;
136
137 PAGED_CODE();
138
139 if (PrivilegeCount == 0)
140 {
141 *Dest = 0;
142 *Length = 0;
143 return STATUS_SUCCESS;
144 }
145
146 if (PreviousMode == KernelMode && !CaptureIfKernel)
147 {
148 *Dest = Src;
149 return STATUS_SUCCESS;
150 }
151
152 /* FIXME - check PrivilegeCount for a valid number so we don't
153 cause an integer overflow or exhaust system resources! */
154
155 BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
156 *Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
157
158 /* probe the buffer */
159 if (PreviousMode != KernelMode)
160 {
161 _SEH2_TRY
162 {
163 ProbeForRead(Src,
164 BufferSize,
165 sizeof(ULONG));
166 }
167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
168 {
169 /* Return the exception code */
170 _SEH2_YIELD(return _SEH2_GetExceptionCode());
171 }
172 _SEH2_END;
173 }
174
175 /* allocate enough memory or check if the provided buffer is
176 large enough to hold the array */
177 if (AllocatedMem != NULL)
178 {
179 if (AllocatedLength < BufferSize)
180 {
181 return STATUS_BUFFER_TOO_SMALL;
182 }
183
184 *Dest = AllocatedMem;
185 }
186 else
187 {
188 *Dest = ExAllocatePool(PoolType,
189 BufferSize);
190 if (*Dest == NULL)
191 {
192 return STATUS_INSUFFICIENT_RESOURCES;
193 }
194 }
195
196 /* copy the array to the buffer */
197 _SEH2_TRY
198 {
199 RtlCopyMemory(*Dest,
200 Src,
201 BufferSize);
202 }
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
204 {
205 Status = _SEH2_GetExceptionCode();
206 }
207 _SEH2_END;
208
209 if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
210 {
211 ExFreePool(*Dest);
212 }
213
214 return Status;
215 }
216
217 VOID
218 NTAPI
219 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
220 KPROCESSOR_MODE PreviousMode,
221 BOOLEAN CaptureIfKernel)
222 {
223 PAGED_CODE();
224
225 if (Privilege != NULL &&
226 (PreviousMode != KernelMode || CaptureIfKernel))
227 {
228 ExFreePool(Privilege);
229 }
230 }
231
232 /* PUBLIC FUNCTIONS ***********************************************************/
233
234 /*
235 * @implemented
236 */
237 NTSTATUS
238 NTAPI
239 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState,
240 IN PPRIVILEGE_SET Privileges)
241 {
242 PAUX_ACCESS_DATA AuxData;
243 ULONG OldPrivilegeSetSize;
244 ULONG NewPrivilegeSetSize;
245 PPRIVILEGE_SET PrivilegeSet;
246
247 PAGED_CODE();
248
249 /* Get the Auxiliary Data */
250 AuxData = AccessState->AuxData;
251
252 /* Calculate the size of the old privilege set */
253 OldPrivilegeSetSize = sizeof(PRIVILEGE_SET) +
254 (AuxData->PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
255
256 if (AuxData->PrivilegeSet->PrivilegeCount +
257 Privileges->PrivilegeCount > INITIAL_PRIVILEGE_COUNT)
258 {
259 /* Calculate the size of the new privilege set */
260 NewPrivilegeSetSize = OldPrivilegeSetSize +
261 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
262
263 /* Allocate a new privilege set */
264 PrivilegeSet = ExAllocatePool(PagedPool, NewPrivilegeSetSize);
265 if (PrivilegeSet == NULL)
266 return STATUS_INSUFFICIENT_RESOURCES;
267
268 /* Copy original privileges from the acess state */
269 RtlCopyMemory(PrivilegeSet,
270 AuxData->PrivilegeSet,
271 OldPrivilegeSetSize);
272
273 /* Append privileges from the privilege set*/
274 RtlCopyMemory((PVOID)((ULONG_PTR)PrivilegeSet + OldPrivilegeSetSize),
275 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
276 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
277
278 /* Adjust the number of privileges in the new privilege set */
279 PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
280
281 /* Free the old privilege set if it was allocated */
282 if (AccessState->PrivilegesAllocated == TRUE)
283 ExFreePool(AuxData->PrivilegeSet);
284
285 /* Now we are using an allocated privilege set */
286 AccessState->PrivilegesAllocated = TRUE;
287
288 /* Assign the new privileges to the access state */
289 AuxData->PrivilegeSet = PrivilegeSet;
290 }
291 else
292 {
293 /* Append privileges */
294 RtlCopyMemory((PVOID)((ULONG_PTR)AuxData->PrivilegeSet + OldPrivilegeSetSize),
295 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
296 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
297
298 /* Adjust the number of privileges in the target privilege set */
299 AuxData->PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
300 }
301
302 return STATUS_SUCCESS;
303 }
304
305 /*
306 * @implemented
307 */
308 VOID
309 NTAPI
310 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
311 {
312 PAGED_CODE();
313 ExFreePool(Privileges);
314 }
315
316 /*
317 * @implemented
318 */
319 BOOLEAN
320 NTAPI
321 SePrivilegeCheck(PPRIVILEGE_SET Privileges,
322 PSECURITY_SUBJECT_CONTEXT SubjectContext,
323 KPROCESSOR_MODE PreviousMode)
324 {
325 PACCESS_TOKEN Token = NULL;
326
327 PAGED_CODE();
328
329 if (SubjectContext->ClientToken == NULL)
330 {
331 Token = SubjectContext->PrimaryToken;
332 }
333 else
334 {
335 Token = SubjectContext->ClientToken;
336 if (SubjectContext->ImpersonationLevel < 2)
337 {
338 return FALSE;
339 }
340 }
341
342 return SepPrivilegeCheck(Token,
343 Privileges->Privilege,
344 Privileges->PrivilegeCount,
345 Privileges->Control,
346 PreviousMode);
347 }
348
349 /*
350 * @implemented
351 */
352 BOOLEAN
353 NTAPI
354 SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
355 IN KPROCESSOR_MODE PreviousMode)
356 {
357 SECURITY_SUBJECT_CONTEXT SubjectContext;
358 PRIVILEGE_SET Priv;
359 BOOLEAN Result;
360
361 PAGED_CODE();
362
363 SeCaptureSubjectContext(&SubjectContext);
364
365 Priv.PrivilegeCount = 1;
366 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
367 Priv.Privilege[0].Luid = PrivilegeValue;
368 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
369
370 Result = SePrivilegeCheck(&Priv,
371 &SubjectContext,
372 PreviousMode);
373
374 if (PreviousMode != KernelMode)
375 {
376 #if 0
377 SePrivilegedServiceAuditAlarm(0,
378 &SubjectContext,
379 &PrivilegeValue);
380 #endif
381 }
382
383 SeReleaseSubjectContext(&SubjectContext);
384
385 return Result;
386 }
387
388 BOOLEAN
389 NTAPI
390 SeCheckPrivilegedObject(IN LUID PrivilegeValue,
391 IN HANDLE ObjectHandle,
392 IN ACCESS_MASK DesiredAccess,
393 IN KPROCESSOR_MODE PreviousMode)
394 {
395 SECURITY_SUBJECT_CONTEXT SubjectContext;
396 PRIVILEGE_SET Priv;
397 BOOLEAN Result;
398
399 PAGED_CODE();
400
401 SeCaptureSubjectContext(&SubjectContext);
402
403 Priv.PrivilegeCount = 1;
404 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
405 Priv.Privilege[0].Luid = PrivilegeValue;
406 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
407
408 Result = SePrivilegeCheck(&Priv, &SubjectContext, PreviousMode);
409 if (PreviousMode != KernelMode)
410 {
411 #if 0
412 SePrivilegeObjectAuditAlarm(ObjectHandle,
413 &SubjectContext,
414 DesiredAccess,
415 &PrivilegeValue,
416 Result,
417 PreviousMode);
418 #endif
419 }
420
421 SeReleaseSubjectContext(&SubjectContext);
422
423 return Result;
424 }
425
426 /* SYSTEM CALLS ***************************************************************/
427
428 NTSTATUS
429 NTAPI
430 NtPrivilegeCheck(IN HANDLE ClientToken,
431 IN PPRIVILEGE_SET RequiredPrivileges,
432 OUT PBOOLEAN Result)
433 {
434 PLUID_AND_ATTRIBUTES Privileges;
435 PTOKEN Token;
436 ULONG PrivilegeCount = 0;
437 ULONG PrivilegeControl = 0;
438 ULONG Length;
439 BOOLEAN CheckResult;
440 KPROCESSOR_MODE PreviousMode;
441 NTSTATUS Status;
442
443 PAGED_CODE();
444
445 PreviousMode = KeGetPreviousMode();
446
447 /* probe the buffers */
448 if (PreviousMode != KernelMode)
449 {
450 _SEH2_TRY
451 {
452 ProbeForWrite(RequiredPrivileges,
453 FIELD_OFFSET(PRIVILEGE_SET,
454 Privilege),
455 sizeof(ULONG));
456
457 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
458 PrivilegeControl = RequiredPrivileges->Control;
459
460 /* Check PrivilegeCount to avoid an integer overflow! */
461 if (FIELD_OFFSET(PRIVILEGE_SET,
462 Privilege[PrivilegeCount]) /
463 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
464 {
465 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
466 }
467
468 /* probe all of the array */
469 ProbeForWrite(RequiredPrivileges,
470 FIELD_OFFSET(PRIVILEGE_SET,
471 Privilege[PrivilegeCount]),
472 sizeof(ULONG));
473
474 ProbeForWriteBoolean(Result);
475 }
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
477 {
478 /* Return the exception code */
479 _SEH2_YIELD(return _SEH2_GetExceptionCode());
480 }
481 _SEH2_END;
482 }
483 else
484 {
485 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
486 PrivilegeControl = RequiredPrivileges->Control;
487 }
488
489 /* reference the token and make sure we're
490 not doing an anonymous impersonation */
491 Status = ObReferenceObjectByHandle(ClientToken,
492 TOKEN_QUERY,
493 SeTokenObjectType,
494 PreviousMode,
495 (PVOID*)&Token,
496 NULL);
497 if (!NT_SUCCESS(Status))
498 {
499 return Status;
500 }
501
502 if (Token->TokenType == TokenImpersonation &&
503 Token->ImpersonationLevel < SecurityIdentification)
504 {
505 ObDereferenceObject(Token);
506 return STATUS_BAD_IMPERSONATION_LEVEL;
507 }
508
509 /* capture the privileges */
510 Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
511 PrivilegeCount,
512 PreviousMode,
513 NULL,
514 0,
515 PagedPool,
516 TRUE,
517 &Privileges,
518 &Length);
519 if (!NT_SUCCESS(Status))
520 {
521 ObDereferenceObject (Token);
522 return Status;
523 }
524
525 CheckResult = SepPrivilegeCheck(Token,
526 Privileges,
527 PrivilegeCount,
528 PrivilegeControl,
529 PreviousMode);
530
531 ObDereferenceObject(Token);
532
533 /* return the array */
534 _SEH2_TRY
535 {
536 RtlCopyMemory(RequiredPrivileges->Privilege,
537 Privileges,
538 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
539 *Result = CheckResult;
540 Status = STATUS_SUCCESS;
541 }
542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
543 {
544 Status = _SEH2_GetExceptionCode();
545 }
546 _SEH2_END;
547
548 SeReleaseLuidAndAttributesArray(Privileges,
549 PreviousMode,
550 TRUE);
551
552 return Status;
553 }
554
555 /* EOF */