1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security manager infrastructure
5 * COPYRIGHT: Copyright Timo Kreuzer <timo.kreuzer@reactos.org>
6 * Copyright Eric Kohl
7 * Copyright Aleksey Bragin
8 * Copyright Alex Ionescu <alex@relsoft.net>
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 PTOKEN SeAnonymousLogonToken = NULL;
20 PTOKEN SeAnonymousLogonTokenNoEveryone = NULL;
21 PSE_EXPORTS SeExports = NULL;
22 SE_EXPORTS SepExports;
23 ULONG SidInTokenCalls = 0;
24
25 extern ULONG ExpInitializationPhase;
26 extern ERESOURCE SepSubjectContextLock;
27
28 /* PRIVATE FUNCTIONS **********************************************************/
29
30 /**
31 * @brief
32 * Initializes all the security exports upon initialization phase of
33 * the module.
34 *
35 * @return
36 * Returns TRUE.
37 */
38 static
39 CODE_SEG("INIT")
40 BOOLEAN
SepInitExports(VOID)41 SepInitExports(VOID)
42 {
43 SepExports.SeCreateTokenPrivilege = SeCreateTokenPrivilege;
44 SepExports.SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
45 SepExports.SeLockMemoryPrivilege = SeLockMemoryPrivilege;
46 SepExports.SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
47 SepExports.SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
48 SepExports.SeTcbPrivilege = SeTcbPrivilege;
49 SepExports.SeSecurityPrivilege = SeSecurityPrivilege;
50 SepExports.SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
51 SepExports.SeLoadDriverPrivilege = SeLoadDriverPrivilege;
52 SepExports.SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
53 SepExports.SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
54 SepExports.SeSystemProfilePrivilege = SeSystemProfilePrivilege;
55 SepExports.SeSystemtimePrivilege = SeSystemtimePrivilege;
56 SepExports.SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
57 SepExports.SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
58 SepExports.SeBackupPrivilege = SeBackupPrivilege;
59 SepExports.SeRestorePrivilege = SeRestorePrivilege;
60 SepExports.SeShutdownPrivilege = SeShutdownPrivilege;
61 SepExports.SeDebugPrivilege = SeDebugPrivilege;
62 SepExports.SeAuditPrivilege = SeAuditPrivilege;
63 SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
64 SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
65 SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
66
67 SepExports.SeNullSid = SeNullSid;
68 SepExports.SeWorldSid = SeWorldSid;
69 SepExports.SeLocalSid = SeLocalSid;
70 SepExports.SeCreatorOwnerSid = SeCreatorOwnerSid;
71 SepExports.SeCreatorGroupSid = SeCreatorGroupSid;
72 SepExports.SeNtAuthoritySid = SeNtAuthoritySid;
73 SepExports.SeDialupSid = SeDialupSid;
74 SepExports.SeNetworkSid = SeNetworkSid;
75 SepExports.SeBatchSid = SeBatchSid;
76 SepExports.SeInteractiveSid = SeInteractiveSid;
77 SepExports.SeLocalSystemSid = SeLocalSystemSid;
78 SepExports.SeAliasAdminsSid = SeAliasAdminsSid;
79 SepExports.SeAliasUsersSid = SeAliasUsersSid;
80 SepExports.SeAliasGuestsSid = SeAliasGuestsSid;
81 SepExports.SeAliasPowerUsersSid = SeAliasPowerUsersSid;
82 SepExports.SeAliasAccountOpsSid = SeAliasAccountOpsSid;
83 SepExports.SeAliasSystemOpsSid = SeAliasSystemOpsSid;
84 SepExports.SeAliasPrintOpsSid = SeAliasPrintOpsSid;
85 SepExports.SeAliasBackupOpsSid = SeAliasBackupOpsSid;
86 SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid;
87 SepExports.SeRestrictedSid = SeRestrictedSid;
88 SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid;
89 SepExports.SeLocalServiceSid = SeLocalServiceSid;
90 SepExports.SeNetworkServiceSid = SeNetworkServiceSid;
91
92 SepExports.SeUndockPrivilege = SeUndockPrivilege;
93 SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege;
94 SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege;
95 SepExports.SeManageVolumePrivilege = SeManageVolumePrivilege;
96 SepExports.SeImpersonatePrivilege = SeImpersonatePrivilege;
97 SepExports.SeCreateGlobalPrivilege = SeCreateGlobalPrivilege;
98
99 SeExports = &SepExports;
100 return TRUE;
101 }
102
103 /**
104 * @brief
105 * Handles the phase 0 procedure of the SRM initialization.
106 *
107 * @return
108 * Returns TRUE if the phase 0 initialization has succeeded and that
109 * we can proceed further with next initialization phase, FALSE
110 * otherwise.
111 */
112 CODE_SEG("INIT")
113 BOOLEAN
114 NTAPI
SepInitializationPhase0(VOID)115 SepInitializationPhase0(VOID)
116 {
117 PAGED_CODE();
118
119 if (!ExLuidInitialization()) return FALSE;
120 if (!SepInitSecurityIDs()) return FALSE;
121 if (!SepInitDACLs()) return FALSE;
122 if (!SepInitSDs()) return FALSE;
123 SepInitPrivileges();
124 if (!SepInitExports()) return FALSE;
125
126 /* Initialize the subject context lock */
127 ExInitializeResource(&SepSubjectContextLock);
128
129 /* Initialize token objects */
130 SepInitializeTokenImplementation();
131
132 /* Initialize logon sessions */
133 if (!SeRmInitPhase0()) return FALSE;
134
135 /* Clear impersonation info for the idle thread */
136 PsGetCurrentThread()->ImpersonationInfo = NULL;
137 PspClearCrossThreadFlag(PsGetCurrentThread(),
138 CT_ACTIVE_IMPERSONATION_INFO_BIT);
139
140 /* Initialize the boot token */
141 ObInitializeFastReference(&PsGetCurrentProcess()->Token, NULL);
142 ObInitializeFastReference(&PsGetCurrentProcess()->Token,
143 SepCreateSystemProcessToken());
144
145 /* Initialise the anonymous logon tokens */
146 SeAnonymousLogonToken = SepCreateSystemAnonymousLogonToken();
147 if (!SeAnonymousLogonToken)
148 return FALSE;
149
150 SeAnonymousLogonTokenNoEveryone = SepCreateSystemAnonymousLogonTokenNoEveryone();
151 if (!SeAnonymousLogonTokenNoEveryone)
152 return FALSE;
153
154 return TRUE;
155 }
156
157 /**
158 * @brief
159 * Handles the phase 1 procedure of the SRM initialization.
160 *
161 * @return
162 * Returns TRUE if the phase 1 initialization has succeeded, FALSE
163 * otherwise.
164 */
165 CODE_SEG("INIT")
166 BOOLEAN
167 NTAPI
SepInitializationPhase1(VOID)168 SepInitializationPhase1(VOID)
169 {
170 OBJECT_ATTRIBUTES ObjectAttributes;
171 UNICODE_STRING Name;
172 HANDLE SecurityHandle;
173 HANDLE EventHandle;
174 NTSTATUS Status;
175 SECURITY_DESCRIPTOR SecurityDescriptor;
176 PACL Dacl;
177 ULONG DaclLength;
178
179 PAGED_CODE();
180
181 /* Insert the system token into the tree */
182 Status = ObInsertObject((PVOID)(PsGetCurrentProcess()->Token.Value &
183 ~MAX_FAST_REFS),
184 NULL,
185 0,
186 0,
187 NULL,
188 NULL);
189 ASSERT(NT_SUCCESS(Status));
190
191 /* Create a security descriptor for the directory */
192 RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
193
194 /* Setup the ACL */
195 DaclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
196 RtlLengthSid(SeLocalSystemSid) +
197 RtlLengthSid(SeAliasAdminsSid) +
198 RtlLengthSid(SeWorldSid);
199 Dacl = ExAllocatePoolWithTag(NonPagedPool, DaclLength, TAG_SE);
200 if (Dacl == NULL)
201 {
202 return FALSE;
203 }
204
205 Status = RtlCreateAcl(Dacl, DaclLength, ACL_REVISION);
206 ASSERT(NT_SUCCESS(Status));
207
208 /* Grant full access to SYSTEM */
209 Status = RtlAddAccessAllowedAce(Dacl,
210 ACL_REVISION,
211 DIRECTORY_ALL_ACCESS,
212 SeLocalSystemSid);
213 ASSERT(NT_SUCCESS(Status));
214
215 /* Allow admins to traverse and query */
216 Status = RtlAddAccessAllowedAce(Dacl,
217 ACL_REVISION,
218 READ_CONTROL | DIRECTORY_TRAVERSE | DIRECTORY_QUERY,
219 SeAliasAdminsSid);
220 ASSERT(NT_SUCCESS(Status));
221
222 /* Allow anyone to traverse */
223 Status = RtlAddAccessAllowedAce(Dacl,
224 ACL_REVISION,
225 DIRECTORY_TRAVERSE,
226 SeWorldSid);
227 ASSERT(NT_SUCCESS(Status));
228
229 /* And link ACL and SD */
230 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
231 ASSERT(NT_SUCCESS(Status));
232
233 /* Create '\Security' directory */
234 RtlInitUnicodeString(&Name, L"\\Security");
235 InitializeObjectAttributes(&ObjectAttributes,
236 &Name,
237 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
238 0,
239 &SecurityDescriptor);
240
241 Status = ZwCreateDirectoryObject(&SecurityHandle,
242 DIRECTORY_ALL_ACCESS,
243 &ObjectAttributes);
244 ASSERT(NT_SUCCESS(Status));
245
246 /* Free the DACL */
247 ExFreePoolWithTag(Dacl, TAG_SE);
248
249 /* Create 'LSA_AUTHENTICATION_INITIALIZED' event */
250 RtlInitUnicodeString(&Name, L"LSA_AUTHENTICATION_INITIALIZED");
251 InitializeObjectAttributes(&ObjectAttributes,
252 &Name,
253 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
254 SecurityHandle,
255 SePublicDefaultSd);
256
257 Status = ZwCreateEvent(&EventHandle,
258 GENERIC_WRITE,
259 &ObjectAttributes,
260 NotificationEvent,
261 FALSE);
262 ASSERT(NT_SUCCESS(Status));
263
264 Status = ZwClose(EventHandle);
265 ASSERT(NT_SUCCESS(Status));
266
267 Status = ZwClose(SecurityHandle);
268 ASSERT(NT_SUCCESS(Status));
269
270 return TRUE;
271 }
272
273 /**
274 * @brief
275 * Main security manager initialization function.
276 *
277 * @return
278 * Returns a boolean value according to the phase initialization
279 * routine that handles it. If TRUE, the routine deems the initialization
280 * phase as complete, FALSE otherwise.
281 */
282 CODE_SEG("INIT")
283 BOOLEAN
284 NTAPI
SeInitSystem(VOID)285 SeInitSystem(VOID)
286 {
287 /* Check the initialization phase */
288 switch (ExpInitializationPhase)
289 {
290 case 0:
291
292 /* Do Phase 0 */
293 return SepInitializationPhase0();
294
295 case 1:
296
297 /* Do Phase 1 */
298 return SepInitializationPhase1();
299
300 default:
301
302 /* Don't know any other phase! Bugcheck! */
303 KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL,
304 0,
305 ExpInitializationPhase,
306 0,
307 0);
308 return FALSE;
309 }
310 }
311
312 /**
313 * @brief
314 * Internal function that is responsible for querying, deleting, assigning and
315 * setting a security descriptor for an object in the NT kernel. It is the default
316 * security method for objects regarding the security context of objects.
317 *
318 * @param[in] Object
319 * The object that has the default security method, which the function has been
320 * called upon.
321 *
322 * @param[in] OperationType
323 * Operation type to perform to that object.
324 *
325 * @param[in] SecurityInformation
326 * Auxiliary security information of the object.
327 *
328 * @param[in,out] SecurityDescriptor
329 * A security descriptor. This SD is used accordingly to the operation type
330 * requested by the caller.
331 *
332 * @param[in,out] ReturnLength
333 * The length size of the queried security descriptor, in bytes.
334 *
335 * @param[in,out] OldSecurityDescriptor
336 * The old SD that belonged to the object, in case we're either deleting
337 * or replacing it.
338 *
339 * @param[in] PoolType
340 * Pool type allocation for the security descriptor.
341 *
342 * @param[in] GenericMapping
343 * The generic mapping of access rights masks for the object.
344 *
345 * @return
346 * Returns STATUS_SUCCESS if the specific operation tasked has been
347 * completed. Otherwise a failure NTSTATUS code is returned.
348 */
349 NTSTATUS
350 NTAPI
SeDefaultObjectMethod(_In_ PVOID Object,_In_ SECURITY_OPERATION_CODE OperationType,_In_ PSECURITY_INFORMATION SecurityInformation,_Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,_Inout_opt_ PULONG ReturnLength,_Inout_ PSECURITY_DESCRIPTOR * OldSecurityDescriptor,_In_ POOL_TYPE PoolType,_In_ PGENERIC_MAPPING GenericMapping)351 SeDefaultObjectMethod(
352 _In_ PVOID Object,
353 _In_ SECURITY_OPERATION_CODE OperationType,
354 _In_ PSECURITY_INFORMATION SecurityInformation,
355 _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
356 _Inout_opt_ PULONG ReturnLength,
357 _Inout_ PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
358 _In_ POOL_TYPE PoolType,
359 _In_ PGENERIC_MAPPING GenericMapping)
360 {
361 PAGED_CODE();
362
363 /* Select the operation type */
364 switch (OperationType)
365 {
366 /* Setting a new descriptor */
367 case SetSecurityDescriptor:
368
369 /* Sanity check */
370 ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
371
372 /* Set the information */
373 return ObSetSecurityDescriptorInfo(Object,
374 SecurityInformation,
375 SecurityDescriptor,
376 OldSecurityDescriptor,
377 PoolType,
378 GenericMapping);
379
380 case QuerySecurityDescriptor:
381
382 /* Query the information */
383 return ObQuerySecurityDescriptorInfo(Object,
384 SecurityInformation,
385 SecurityDescriptor,
386 ReturnLength,
387 OldSecurityDescriptor);
388
389 case DeleteSecurityDescriptor:
390
391 /* De-assign it */
392 return ObDeassignSecurity(OldSecurityDescriptor);
393
394 case AssignSecurityDescriptor:
395
396 /* Assign it */
397 ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType);
398 return STATUS_SUCCESS;
399
400 default:
401
402 /* Bug check */
403 KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
404 }
405
406 /* Should never reach here */
407 ASSERT(FALSE);
408 return STATUS_SUCCESS;
409 }
410
411 /**
412 * @brief
413 * Queries the access mask from a security information context.
414 *
415 * @param[in] SecurityInformation
416 * The security information context where the access mask is to be
417 * gathered.
418 *
419 * @param[out] DesiredAccess
420 * The queried access mask right.
421 *
422 * @return
423 * Nothing.
424 */
425 VOID
426 NTAPI
SeQuerySecurityAccessMask(_In_ SECURITY_INFORMATION SecurityInformation,_Out_ PACCESS_MASK DesiredAccess)427 SeQuerySecurityAccessMask(
428 _In_ SECURITY_INFORMATION SecurityInformation,
429 _Out_ PACCESS_MASK DesiredAccess)
430 {
431 *DesiredAccess = 0;
432
433 if (SecurityInformation & (OWNER_SECURITY_INFORMATION |
434 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
435 {
436 *DesiredAccess |= READ_CONTROL;
437 }
438
439 if (SecurityInformation & SACL_SECURITY_INFORMATION)
440 {
441 *DesiredAccess |= ACCESS_SYSTEM_SECURITY;
442 }
443 }
444
445 /**
446 * @brief
447 * Sets the access mask for a security information context.
448 *
449 * @param[in] SecurityInformation
450 * The security information context to apply a new access right.
451 *
452 * @param[out] DesiredAccess
453 * The returned access mask right.
454 *
455 * @return
456 * Nothing.
457 */
458 VOID
459 NTAPI
SeSetSecurityAccessMask(_In_ SECURITY_INFORMATION SecurityInformation,_Out_ PACCESS_MASK DesiredAccess)460 SeSetSecurityAccessMask(
461 _In_ SECURITY_INFORMATION SecurityInformation,
462 _Out_ PACCESS_MASK DesiredAccess)
463 {
464 *DesiredAccess = 0;
465
466 if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
467 {
468 *DesiredAccess |= WRITE_OWNER;
469 }
470
471 if (SecurityInformation & DACL_SECURITY_INFORMATION)
472 {
473 *DesiredAccess |= WRITE_DAC;
474 }
475
476 if (SecurityInformation & SACL_SECURITY_INFORMATION)
477 {
478 *DesiredAccess |= ACCESS_SYSTEM_SECURITY;
479 }
480 }
481
482 /**
483 * @unimplemented
484 * @brief
485 * Report a security event to the security manager.
486 *
487 * @param[in] Flags
488 * Flags that influence how the event should be reported.
489 *
490 * @param[in] SourceName
491 * A Unicode string that represents the source name of the event.
492 *
493 * @param[in] UserSid
494 * The SID that represents a user that initiated the reporting.
495 *
496 * @param[in] AuditParameters
497 * An array of parameters for auditing purposes. This is used
498 * for reporting the event which the security manager will take
499 * care subsequently of doing eventual security auditing.
500 *
501 * @return
502 * Returns STATUS_SUCCESS if the security event has been reported.
503 * STATUS_INVALID_PARAMETER is returned if one of the parameters
504 * do not satisfy the requirements expected by the function.
505 */
506 NTSTATUS
507 NTAPI
SeReportSecurityEvent(_In_ ULONG Flags,_In_ PUNICODE_STRING SourceName,_In_opt_ PSID UserSid,_In_ PSE_ADT_PARAMETER_ARRAY AuditParameters)508 SeReportSecurityEvent(
509 _In_ ULONG Flags,
510 _In_ PUNICODE_STRING SourceName,
511 _In_opt_ PSID UserSid,
512 _In_ PSE_ADT_PARAMETER_ARRAY AuditParameters)
513 {
514 SECURITY_SUBJECT_CONTEXT SubjectContext;
515 PTOKEN EffectiveToken;
516 PISID Sid;
517 NTSTATUS Status;
518
519 /* Validate parameters */
520 if ((Flags != 0) ||
521 (SourceName == NULL) ||
522 (SourceName->Buffer == NULL) ||
523 (SourceName->Length == 0) ||
524 (AuditParameters == NULL) ||
525 (AuditParameters->ParameterCount > SE_MAX_AUDIT_PARAMETERS - 4))
526 {
527 return STATUS_INVALID_PARAMETER;
528 }
529
530 /* Validate the source name */
531 Status = RtlValidateUnicodeString(0, SourceName);
532 if (!NT_SUCCESS(Status))
533 {
534 return Status;
535 }
536
537 /* Check if we have a user SID */
538 if (UserSid != NULL)
539 {
540 /* Validate it */
541 if (!RtlValidSid(UserSid))
542 {
543 return STATUS_INVALID_PARAMETER;
544 }
545
546 /* Use the user SID */
547 Sid = UserSid;
548 }
549 else
550 {
551 /* No user SID, capture the security subject context */
552 SeCaptureSubjectContext(&SubjectContext);
553
554 /* Extract the effective token */
555 EffectiveToken = SubjectContext.ClientToken ?
556 SubjectContext.ClientToken : SubjectContext.PrimaryToken;
557
558 /* Use the user-and-groups SID */
559 Sid = EffectiveToken->UserAndGroups->Sid;
560 }
561
562 UNIMPLEMENTED;
563
564 /* Check if we captured the subject context */
565 if (Sid != UserSid)
566 {
567 /* Release it */
568 SeReleaseSubjectContext(&SubjectContext);
569 }
570
571 /* Return success */
572 return STATUS_SUCCESS;
573 }
574
575 /**
576 * @unimplemented
577 * @brief
578 * Sets an array of audit parameters for later security auditing use.
579 *
580 * @param[in,out] AuditParameters
581 * An array of audit parameters to be set.
582 *
583 * @param[in] Type
584 * The type of audit parameters to be set.
585 *
586 * @param[in] Index
587 * Index number that represents an instance of an audit parameters.
588 * Such index must be within the maximum range of audit parameters.
589 *
590 * @param[in] Data
591 * An arbitrary buffer data that is bounds to what kind of audit parameter
592 * type must be set.
593 *
594 * @return
595 * To be added...
596 */
597 _Const_
598 NTSTATUS
599 NTAPI
600 SeSetAuditParameter(
601 _Inout_ PSE_ADT_PARAMETER_ARRAY AuditParameters,
602 _In_ SE_ADT_PARAMETER_TYPE Type,
603 _In_range_(<, SE_MAX_AUDIT_PARAMETERS) ULONG Index,
604 _In_reads_(_Inexpressible_("depends on SE_ADT_PARAMETER_TYPE")) PVOID Data)
605 {
606 UNIMPLEMENTED;
607 return STATUS_SUCCESS;
608 }
609
610 /* EOF */
611