7cdbd613d1d758d97f98d64184a0f5091357ad2d
[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 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 * @unimplemented
285 */
286 NTSTATUS
287 NTAPI
288 SeAppendPrivileges(PACCESS_STATE AccessState,
289 PPRIVILEGE_SET Privileges)
290 {
291 UNIMPLEMENTED;
292 return STATUS_NOT_IMPLEMENTED;
293 }
294
295 /*
296 * @implemented
297 */
298 VOID
299 NTAPI
300 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
301 {
302 PAGED_CODE();
303 ExFreePool(Privileges);
304 }
305
306 /*
307 * @implemented
308 */
309 BOOLEAN
310 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
343 NTAPI
344 SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
345 IN KPROCESSOR_MODE PreviousMode)
346 {
347 SECURITY_SUBJECT_CONTEXT SubjectContext;
348 PRIVILEGE_SET Priv;
349 BOOLEAN Result;
350
351 PAGED_CODE();
352
353 SeCaptureSubjectContext(&SubjectContext);
354
355 Priv.PrivilegeCount = 1;
356 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
357 Priv.Privilege[0].Luid = PrivilegeValue;
358 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
359
360 Result = SePrivilegeCheck(&Priv,
361 &SubjectContext,
362 PreviousMode);
363
364 if (PreviousMode != KernelMode)
365 {
366 #if 0
367 SePrivilegedServiceAuditAlarm(0,
368 &SubjectContext,
369 &PrivilegeValue);
370 #endif
371 }
372
373 SeReleaseSubjectContext(&SubjectContext);
374
375 return Result;
376 }
377
378 /* SYSTEM CALLS ***************************************************************/
379
380 NTSTATUS
381 NTAPI
382 NtPrivilegeCheck(IN HANDLE ClientToken,
383 IN PPRIVILEGE_SET RequiredPrivileges,
384 OUT PBOOLEAN Result)
385 {
386 PLUID_AND_ATTRIBUTES Privileges;
387 PTOKEN Token;
388 ULONG PrivilegeCount = 0;
389 ULONG PrivilegeControl = 0;
390 ULONG Length;
391 BOOLEAN CheckResult;
392 KPROCESSOR_MODE PreviousMode;
393 NTSTATUS Status;
394
395 PAGED_CODE();
396
397 PreviousMode = KeGetPreviousMode();
398
399 /* probe the buffers */
400 if (PreviousMode != KernelMode)
401 {
402 _SEH2_TRY
403 {
404 ProbeForWrite(RequiredPrivileges,
405 FIELD_OFFSET(PRIVILEGE_SET,
406 Privilege),
407 sizeof(ULONG));
408
409 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
410 PrivilegeControl = RequiredPrivileges->Control;
411
412 /* Check PrivilegeCount to avoid an integer overflow! */
413 if (FIELD_OFFSET(PRIVILEGE_SET,
414 Privilege[PrivilegeCount]) /
415 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
416 {
417 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
418 }
419
420 /* probe all of the array */
421 ProbeForWrite(RequiredPrivileges,
422 FIELD_OFFSET(PRIVILEGE_SET,
423 Privilege[PrivilegeCount]),
424 sizeof(ULONG));
425
426 ProbeForWriteBoolean(Result);
427 }
428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
429 {
430 /* Return the exception code */
431 _SEH2_YIELD(return _SEH2_GetExceptionCode());
432 }
433 _SEH2_END;
434 }
435 else
436 {
437 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
438 PrivilegeControl = RequiredPrivileges->Control;
439 }
440
441 /* reference the token and make sure we're
442 not doing an anonymous impersonation */
443 Status = ObReferenceObjectByHandle(ClientToken,
444 TOKEN_QUERY,
445 SepTokenObjectType,
446 PreviousMode,
447 (PVOID*)&Token,
448 NULL);
449 if (!NT_SUCCESS(Status))
450 {
451 return Status;
452 }
453
454 if (Token->TokenType == TokenImpersonation &&
455 Token->ImpersonationLevel < SecurityIdentification)
456 {
457 ObDereferenceObject(Token);
458 return STATUS_BAD_IMPERSONATION_LEVEL;
459 }
460
461 /* capture the privileges */
462 Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
463 PrivilegeCount,
464 PreviousMode,
465 NULL,
466 0,
467 PagedPool,
468 TRUE,
469 &Privileges,
470 &Length);
471 if (!NT_SUCCESS(Status))
472 {
473 ObDereferenceObject (Token);
474 return Status;
475 }
476
477 CheckResult = SepPrivilegeCheck(Token,
478 Privileges,
479 PrivilegeCount,
480 PrivilegeControl,
481 PreviousMode);
482
483 ObDereferenceObject(Token);
484
485 /* return the array */
486 _SEH2_TRY
487 {
488 RtlCopyMemory(RequiredPrivileges->Privilege,
489 Privileges,
490 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
491 *Result = CheckResult;
492 Status = STATUS_SUCCESS;
493 }
494 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
495 {
496 Status = _SEH2_GetExceptionCode();
497 }
498 _SEH2_END;
499
500 SeReleaseLuidAndAttributesArray(Privileges,
501 PreviousMode,
502 TRUE);
503
504 return Status;
505 }
506
507 /* EOF */