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