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