- Remove autoupdated "$Id:" lines from the kernel source code.
[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 <internal/debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitPrivileges)
18 #endif
19
20
21 /* GLOBALS *******************************************************************/
22
23 LUID SeCreateTokenPrivilege;
24 LUID SeAssignPrimaryTokenPrivilege;
25 LUID SeLockMemoryPrivilege;
26 LUID SeIncreaseQuotaPrivilege;
27 LUID SeUnsolicitedInputPrivilege;
28 LUID SeTcbPrivilege;
29 LUID SeSecurityPrivilege;
30 LUID SeTakeOwnershipPrivilege;
31 LUID SeLoadDriverPrivilege;
32 LUID SeCreatePagefilePrivilege;
33 LUID SeIncreaseBasePriorityPrivilege;
34 LUID SeSystemProfilePrivilege;
35 LUID SeSystemtimePrivilege;
36 LUID SeProfileSingleProcessPrivilege;
37 LUID SeCreatePermanentPrivilege;
38 LUID SeBackupPrivilege;
39 LUID SeRestorePrivilege;
40 LUID SeShutdownPrivilege;
41 LUID SeDebugPrivilege;
42 LUID SeAuditPrivilege;
43 LUID SeSystemEnvironmentPrivilege;
44 LUID SeChangeNotifyPrivilege;
45 LUID SeRemoteShutdownPrivilege;
46 LUID SeUndockPrivilege;
47 LUID SeSyncAgentPrivilege;
48 LUID SeEnableDelegationPrivilege;
49
50
51 /* FUNCTIONS ***************************************************************/
52
53 VOID
54 INIT_FUNCTION
55 NTAPI
56 SepInitPrivileges (VOID)
57 {
58 SeCreateTokenPrivilege.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
59 SeCreateTokenPrivilege.HighPart = 0;
60 SeAssignPrimaryTokenPrivilege.LowPart = SE_ASSIGNPRIMARYTOKEN_PRIVILEGE;
61 SeAssignPrimaryTokenPrivilege.HighPart = 0;
62 SeLockMemoryPrivilege.LowPart = SE_LOCK_MEMORY_PRIVILEGE;
63 SeLockMemoryPrivilege.HighPart = 0;
64 SeIncreaseQuotaPrivilege.LowPart = SE_INCREASE_QUOTA_PRIVILEGE;
65 SeIncreaseQuotaPrivilege.HighPart = 0;
66 SeUnsolicitedInputPrivilege.LowPart = SE_UNSOLICITED_INPUT_PRIVILEGE;
67 SeUnsolicitedInputPrivilege.HighPart = 0;
68 SeTcbPrivilege.LowPart = SE_TCB_PRIVILEGE;
69 SeTcbPrivilege.HighPart = 0;
70 SeSecurityPrivilege.LowPart = SE_SECURITY_PRIVILEGE;
71 SeSecurityPrivilege.HighPart = 0;
72 SeTakeOwnershipPrivilege.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
73 SeTakeOwnershipPrivilege.HighPart = 0;
74 SeLoadDriverPrivilege.LowPart = SE_LOAD_DRIVER_PRIVILEGE;
75 SeLoadDriverPrivilege.HighPart = 0;
76 SeSystemProfilePrivilege.LowPart = SE_SYSTEM_PROFILE_PRIVILEGE;
77 SeSystemProfilePrivilege.HighPart = 0;
78 SeSystemtimePrivilege.LowPart = SE_SYSTEMTIME_PRIVILEGE;
79 SeSystemtimePrivilege.HighPart = 0;
80 SeProfileSingleProcessPrivilege.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE;
81 SeProfileSingleProcessPrivilege.HighPart = 0;
82 SeIncreaseBasePriorityPrivilege.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE;
83 SeIncreaseBasePriorityPrivilege.HighPart = 0;
84 SeCreatePagefilePrivilege.LowPart = SE_CREATE_PAGEFILE_PRIVILEGE;
85 SeCreatePagefilePrivilege.HighPart = 0;
86 SeCreatePermanentPrivilege.LowPart = SE_CREATE_PERMANENT_PRIVILEGE;
87 SeCreatePermanentPrivilege.HighPart = 0;
88 SeBackupPrivilege.LowPart = SE_BACKUP_PRIVILEGE;
89 SeBackupPrivilege.HighPart = 0;
90 SeRestorePrivilege.LowPart = SE_RESTORE_PRIVILEGE;
91 SeRestorePrivilege.HighPart = 0;
92 SeShutdownPrivilege.LowPart = SE_SHUTDOWN_PRIVILEGE;
93 SeShutdownPrivilege.HighPart = 0;
94 SeDebugPrivilege.LowPart = SE_DEBUG_PRIVILEGE;
95 SeDebugPrivilege.HighPart = 0;
96 SeAuditPrivilege.LowPart = SE_AUDIT_PRIVILEGE;
97 SeAuditPrivilege.HighPart = 0;
98 SeSystemEnvironmentPrivilege.LowPart = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
99 SeSystemEnvironmentPrivilege.HighPart = 0;
100 SeChangeNotifyPrivilege.LowPart = SE_CHANGE_NOTIFY_PRIVILEGE;
101 SeChangeNotifyPrivilege.HighPart = 0;
102 SeRemoteShutdownPrivilege.LowPart = SE_REMOTE_SHUTDOWN_PRIVILEGE;
103 SeRemoteShutdownPrivilege.HighPart = 0;
104 SeUndockPrivilege.LowPart = SE_UNDOCK_PRIVILEGE;
105 SeUndockPrivilege.HighPart = 0;
106 SeSyncAgentPrivilege.LowPart = SE_SYNC_AGENT_PRIVILEGE;
107 SeSyncAgentPrivilege.HighPart = 0;
108 SeEnableDelegationPrivilege.LowPart = SE_ENABLE_DELEGATION_PRIVILEGE;
109 SeEnableDelegationPrivilege.HighPart = 0;
110 }
111
112
113 BOOLEAN
114 NTAPI
115 SepPrivilegeCheck (PTOKEN Token,
116 PLUID_AND_ATTRIBUTES Privileges,
117 ULONG PrivilegeCount,
118 ULONG PrivilegeControl,
119 KPROCESSOR_MODE PreviousMode)
120 {
121 ULONG i;
122 ULONG j;
123 ULONG k;
124
125 DPRINT ("SepPrivilegeCheck() called\n");
126
127 PAGED_CODE();
128
129 if (PreviousMode == KernelMode)
130 {
131 return TRUE;
132 }
133
134 k = 0;
135 if (PrivilegeCount > 0)
136 {
137 for (i = 0; i < Token->PrivilegeCount; i++)
138 {
139 for (j = 0; j < PrivilegeCount; j++)
140 {
141 if (Token->Privileges[i].Luid.LowPart == Privileges[j].Luid.LowPart &&
142 Token->Privileges[i].Luid.HighPart == Privileges[j].Luid.HighPart)
143 {
144 DPRINT ("Found privilege\n");
145 DPRINT ("Privilege attributes %lx\n",
146 Token->Privileges[i].Attributes);
147
148 if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
149 {
150 Privileges[j].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
151 k++;
152 }
153 }
154 }
155 }
156 }
157
158 if ((PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) &&
159 PrivilegeCount == k)
160 {
161 return TRUE;
162 }
163
164 if (k > 0 &&
165 !(PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY))
166 {
167 return TRUE;
168 }
169
170 return FALSE;
171 }
172
173
174 NTSTATUS
175 NTAPI
176 SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
177 ULONG PrivilegeCount,
178 KPROCESSOR_MODE PreviousMode,
179 PLUID_AND_ATTRIBUTES AllocatedMem,
180 ULONG AllocatedLength,
181 POOL_TYPE PoolType,
182 BOOLEAN CaptureIfKernel,
183 PLUID_AND_ATTRIBUTES* Dest,
184 PULONG Length)
185 {
186 ULONG BufferSize;
187 NTSTATUS Status = STATUS_SUCCESS;
188
189 PAGED_CODE();
190
191 if (PrivilegeCount == 0)
192 {
193 *Dest = 0;
194 *Length = 0;
195 return STATUS_SUCCESS;
196 }
197
198 if (PreviousMode == KernelMode && !CaptureIfKernel)
199 {
200 *Dest = Src;
201 return STATUS_SUCCESS;
202 }
203
204 /* FIXME - check PrivilegeCount for a valid number so we don't
205 cause an integer overflow or exhaust system resources! */
206
207 BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
208 *Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
209
210 /* probe the buffer */
211 if (PreviousMode != KernelMode)
212 {
213 _SEH_TRY
214 {
215 ProbeForRead(Src,
216 BufferSize,
217 sizeof(ULONG));
218 }
219 _SEH_HANDLE
220 {
221 Status = _SEH_GetExceptionCode();
222 }
223 _SEH_END;
224
225 if (!NT_SUCCESS(Status))
226 {
227 return Status;
228 }
229 }
230
231 /* allocate enough memory or check if the provided buffer is
232 large enough to hold the array */
233 if (AllocatedMem != NULL)
234 {
235 if (AllocatedLength < BufferSize)
236 {
237 return STATUS_BUFFER_TOO_SMALL;
238 }
239
240 *Dest = AllocatedMem;
241 }
242 else
243 {
244 *Dest = ExAllocatePool(PoolType,
245 BufferSize);
246
247 if (&Dest == NULL)
248 {
249 return STATUS_INSUFFICIENT_RESOURCES;
250 }
251 }
252
253 /* copy the array to the buffer */
254 _SEH_TRY
255 {
256 RtlCopyMemory(*Dest,
257 Src,
258 BufferSize);
259 }
260 _SEH_HANDLE
261 {
262 Status = _SEH_GetExceptionCode();
263 }
264 _SEH_END;
265
266 if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
267 {
268 ExFreePool(*Dest);
269 }
270
271 return Status;
272 }
273
274
275 VOID
276 NTAPI
277 SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
278 KPROCESSOR_MODE PreviousMode,
279 BOOLEAN CaptureIfKernel)
280 {
281 PAGED_CODE();
282
283 if (Privilege != NULL &&
284 (PreviousMode != KernelMode || CaptureIfKernel))
285 {
286 ExFreePool(Privilege);
287 }
288 }
289
290
291 NTSTATUS STDCALL
292 NtPrivilegeCheck (IN HANDLE ClientToken,
293 IN PPRIVILEGE_SET RequiredPrivileges,
294 OUT PBOOLEAN Result)
295 {
296 PLUID_AND_ATTRIBUTES Privileges;
297 PTOKEN Token;
298 ULONG PrivilegeCount = 0;
299 ULONG PrivilegeControl = 0;
300 ULONG Length;
301 BOOLEAN CheckResult;
302 KPROCESSOR_MODE PreviousMode;
303 NTSTATUS Status = STATUS_SUCCESS;
304
305 PAGED_CODE();
306
307 PreviousMode = KeGetPreviousMode();
308
309 /* probe the buffers */
310 if (PreviousMode != KernelMode)
311 {
312 _SEH_TRY
313 {
314 ProbeForWrite(RequiredPrivileges,
315 FIELD_OFFSET(PRIVILEGE_SET,
316 Privilege),
317 sizeof(ULONG));
318
319 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
320 PrivilegeControl = RequiredPrivileges->Control;
321
322 /* Check PrivilegeCount to avoid an integer overflow! */
323 if (FIELD_OFFSET(PRIVILEGE_SET,
324 Privilege[PrivilegeCount]) /
325 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
326 {
327 Status = STATUS_INVALID_PARAMETER;
328 _SEH_LEAVE;
329 }
330
331 /* probe all of the array */
332 ProbeForWrite(RequiredPrivileges,
333 FIELD_OFFSET(PRIVILEGE_SET,
334 Privilege[PrivilegeCount]),
335 sizeof(ULONG));
336
337 ProbeForWriteBoolean(Result);
338 }
339 _SEH_HANDLE
340 {
341 Status = _SEH_GetExceptionCode();
342 }
343 _SEH_END;
344
345 if (!NT_SUCCESS(Status))
346 {
347 return Status;
348 }
349 }
350 else
351 {
352 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
353 PrivilegeControl = RequiredPrivileges->Control;
354 }
355
356 /* reference the token and make sure we're
357 not doing an anonymous impersonation */
358 Status = ObReferenceObjectByHandle (ClientToken,
359 TOKEN_QUERY,
360 SepTokenObjectType,
361 PreviousMode,
362 (PVOID*)&Token,
363 NULL);
364 if (!NT_SUCCESS(Status))
365 {
366 return Status;
367 }
368
369 if (Token->TokenType == TokenImpersonation &&
370 Token->ImpersonationLevel < SecurityIdentification)
371 {
372 ObDereferenceObject (Token);
373 return STATUS_BAD_IMPERSONATION_LEVEL;
374 }
375
376 /* capture the privileges */
377 Status = SeCaptureLuidAndAttributesArray (RequiredPrivileges->Privilege,
378 PrivilegeCount,
379 PreviousMode,
380 NULL,
381 0,
382 PagedPool,
383 TRUE,
384 &Privileges,
385 &Length);
386 if (!NT_SUCCESS(Status))
387 {
388 ObDereferenceObject (Token);
389 return Status;
390 }
391
392 CheckResult = SepPrivilegeCheck (Token,
393 Privileges,
394 PrivilegeCount,
395 PrivilegeControl,
396 PreviousMode);
397
398 ObDereferenceObject (Token);
399
400 /* return the array */
401 _SEH_TRY
402 {
403 RtlCopyMemory(RequiredPrivileges->Privilege,
404 Privileges,
405 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
406 *Result = CheckResult;
407 Status = STATUS_SUCCESS;
408 }
409 _SEH_HANDLE
410 {
411 Status = _SEH_GetExceptionCode();
412 }
413 _SEH_END;
414
415 SeReleaseLuidAndAttributesArray (Privileges,
416 PreviousMode,
417 TRUE);
418
419 return Status;
420 }
421
422
423 /*
424 * @implemented
425 */
426 BOOLEAN STDCALL
427 SePrivilegeCheck (PPRIVILEGE_SET Privileges,
428 PSECURITY_SUBJECT_CONTEXT SubjectContext,
429 KPROCESSOR_MODE PreviousMode)
430 {
431 PACCESS_TOKEN Token = NULL;
432
433 PAGED_CODE();
434
435 if (SubjectContext->ClientToken == NULL)
436 {
437 Token = SubjectContext->PrimaryToken;
438 }
439 else
440 {
441 Token = SubjectContext->ClientToken;
442 if (SubjectContext->ImpersonationLevel < 2)
443 {
444 return FALSE;
445 }
446 }
447
448 return SepPrivilegeCheck (Token,
449 Privileges->Privilege,
450 Privileges->PrivilegeCount,
451 Privileges->Control,
452 PreviousMode);
453 }
454
455
456 /*
457 * @implemented
458 */
459 BOOLEAN STDCALL
460 SeSinglePrivilegeCheck (IN LUID PrivilegeValue,
461 IN KPROCESSOR_MODE PreviousMode)
462 {
463 SECURITY_SUBJECT_CONTEXT SubjectContext;
464 PRIVILEGE_SET Priv;
465 BOOLEAN Result;
466
467 PAGED_CODE();
468
469 SeCaptureSubjectContext (&SubjectContext);
470
471 Priv.PrivilegeCount = 1;
472 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
473 Priv.Privilege[0].Luid = PrivilegeValue;
474 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
475
476 Result = SePrivilegeCheck (&Priv,
477 &SubjectContext,
478 PreviousMode);
479
480 if (PreviousMode != KernelMode)
481 {
482 #if 0
483 SePrivilegedServiceAuditAlarm (0,
484 &SubjectContext,
485 &PrivilegeValue);
486 #endif
487 }
488
489 SeReleaseSubjectContext (&SubjectContext);
490
491 return Result;
492 }
493
494 /* EOF */