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