xref: /reactos/ntoskrnl/se/semgr.c (revision ea6e7740)
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
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
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
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
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
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
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
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
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