[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 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
240 if (*Dest == NULL)
241 {
242 return STATUS_INSUFFICIENT_RESOURCES;
243 }
244 }
245
246 /* copy the array to the buffer */
247 _SEH2_TRY
248 {
249 RtlCopyMemory(*Dest,
250 Src,
251 BufferSize);
252 }
253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
254 {
255 Status = _SEH2_GetExceptionCode();
256 }
257 _SEH2_END;
258
259 if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
260 {
261 ExFreePool(*Dest);
262 }
263
264 return Status;
265 }
266
267 VOID
268 NTAPI
269 SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
270 KPROCESSOR_MODE PreviousMode,
271 BOOLEAN CaptureIfKernel)
272 {
273 PAGED_CODE();
274
275 if (Privilege != NULL &&
276 (PreviousMode != KernelMode || CaptureIfKernel))
277 {
278 ExFreePool(Privilege);
279 }
280 }
281
282 /* PUBLIC FUNCTIONS ***********************************************************/
283
284 /*
285 * @unimplemented
286 */
287 NTSTATUS
288 NTAPI
289 SeAppendPrivileges(PACCESS_STATE AccessState,
290 PPRIVILEGE_SET Privileges)
291 {
292 UNIMPLEMENTED;
293 return STATUS_NOT_IMPLEMENTED;
294 }
295
296 /*
297 * @implemented
298 */
299 VOID
300 NTAPI
301 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
302 {
303 PAGED_CODE();
304 ExFreePool(Privileges);
305 }
306
307 /*
308 * @implemented
309 */
310 BOOLEAN NTAPI
311 SePrivilegeCheck (PPRIVILEGE_SET Privileges,
312 PSECURITY_SUBJECT_CONTEXT SubjectContext,
313 KPROCESSOR_MODE PreviousMode)
314 {
315 PACCESS_TOKEN Token = NULL;
316
317 PAGED_CODE();
318
319 if (SubjectContext->ClientToken == NULL)
320 {
321 Token = SubjectContext->PrimaryToken;
322 }
323 else
324 {
325 Token = SubjectContext->ClientToken;
326 if (SubjectContext->ImpersonationLevel < 2)
327 {
328 return FALSE;
329 }
330 }
331
332 return SepPrivilegeCheck (Token,
333 Privileges->Privilege,
334 Privileges->PrivilegeCount,
335 Privileges->Control,
336 PreviousMode);
337 }
338
339 /*
340 * @implemented
341 */
342 BOOLEAN NTAPI
343 SeSinglePrivilegeCheck (IN LUID PrivilegeValue,
344 IN KPROCESSOR_MODE PreviousMode)
345 {
346 SECURITY_SUBJECT_CONTEXT SubjectContext;
347 PRIVILEGE_SET Priv;
348 BOOLEAN Result;
349
350 PAGED_CODE();
351
352 SeCaptureSubjectContext (&SubjectContext);
353
354 Priv.PrivilegeCount = 1;
355 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
356 Priv.Privilege[0].Luid = PrivilegeValue;
357 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
358
359 Result = SePrivilegeCheck (&Priv,
360 &SubjectContext,
361 PreviousMode);
362
363 if (PreviousMode != KernelMode)
364 {
365 #if 0
366 SePrivilegedServiceAuditAlarm (0,
367 &SubjectContext,
368 &PrivilegeValue);
369 #endif
370 }
371
372 SeReleaseSubjectContext (&SubjectContext);
373
374 return Result;
375 }
376
377 /* SYSTEM CALLS ***************************************************************/
378
379 NTSTATUS NTAPI
380 NtPrivilegeCheck (IN HANDLE ClientToken,
381 IN PPRIVILEGE_SET RequiredPrivileges,
382 OUT PBOOLEAN Result)
383 {
384 PLUID_AND_ATTRIBUTES Privileges;
385 PTOKEN Token;
386 ULONG PrivilegeCount = 0;
387 ULONG PrivilegeControl = 0;
388 ULONG Length;
389 BOOLEAN CheckResult;
390 KPROCESSOR_MODE PreviousMode;
391 NTSTATUS Status;
392
393 PAGED_CODE();
394
395 PreviousMode = KeGetPreviousMode();
396
397 /* probe the buffers */
398 if (PreviousMode != KernelMode)
399 {
400 _SEH2_TRY
401 {
402 ProbeForWrite(RequiredPrivileges,
403 FIELD_OFFSET(PRIVILEGE_SET,
404 Privilege),
405 sizeof(ULONG));
406
407 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
408 PrivilegeControl = RequiredPrivileges->Control;
409
410 /* Check PrivilegeCount to avoid an integer overflow! */
411 if (FIELD_OFFSET(PRIVILEGE_SET,
412 Privilege[PrivilegeCount]) /
413 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
414 {
415 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
416 }
417
418 /* probe all of the array */
419 ProbeForWrite(RequiredPrivileges,
420 FIELD_OFFSET(PRIVILEGE_SET,
421 Privilege[PrivilegeCount]),
422 sizeof(ULONG));
423
424 ProbeForWriteBoolean(Result);
425 }
426 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
427 {
428 /* Return the exception code */
429 _SEH2_YIELD(return _SEH2_GetExceptionCode());
430 }
431 _SEH2_END;
432 }
433 else
434 {
435 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
436 PrivilegeControl = RequiredPrivileges->Control;
437 }
438
439 /* reference the token and make sure we're
440 not doing an anonymous impersonation */
441 Status = ObReferenceObjectByHandle (ClientToken,
442 TOKEN_QUERY,
443 SepTokenObjectType,
444 PreviousMode,
445 (PVOID*)&Token,
446 NULL);
447 if (!NT_SUCCESS(Status))
448 {
449 return Status;
450 }
451
452 if (Token->TokenType == TokenImpersonation &&
453 Token->ImpersonationLevel < SecurityIdentification)
454 {
455 ObDereferenceObject (Token);
456 return STATUS_BAD_IMPERSONATION_LEVEL;
457 }
458
459 /* capture the privileges */
460 Status = SeCaptureLuidAndAttributesArray (RequiredPrivileges->Privilege,
461 PrivilegeCount,
462 PreviousMode,
463 NULL,
464 0,
465 PagedPool,
466 TRUE,
467 &Privileges,
468 &Length);
469 if (!NT_SUCCESS(Status))
470 {
471 ObDereferenceObject (Token);
472 return Status;
473 }
474
475 CheckResult = SepPrivilegeCheck (Token,
476 Privileges,
477 PrivilegeCount,
478 PrivilegeControl,
479 PreviousMode);
480
481 ObDereferenceObject (Token);
482
483 /* return the array */
484 _SEH2_TRY
485 {
486 RtlCopyMemory(RequiredPrivileges->Privilege,
487 Privileges,
488 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
489 *Result = CheckResult;
490 Status = STATUS_SUCCESS;
491 }
492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
493 {
494 Status = _SEH2_GetExceptionCode();
495 }
496 _SEH2_END;
497
498 SeReleaseLuidAndAttributesArray (Privileges,
499 PreviousMode,
500 TRUE);
501
502 return Status;
503 }
504
505
506 /* EOF */