2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/srm.c
5 * PURPOSE: Security Reference Monitor Server
7 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES *******************************************************************/
16 extern LUID SeSystemAuthenticationId
;
17 extern LUID SeAnonymousAuthenticationId
;
19 /* PRIVATE DEFINITIONS ********************************************************/
21 #define SEP_LOGON_SESSION_TAG 'sLeS'
25 RmAuditSetCommand
= 1,
26 RmCreateLogonSession
= 2,
27 RmDeleteLogonSession
= 3
30 typedef struct _SEP_RM_API_MESSAGE
36 UCHAR Fill
[PORT_MAXIMUM_MESSAGE_LENGTH
- sizeof(PORT_MESSAGE
)];
37 NTSTATUS ResultStatus
;
45 } SEP_RM_API_MESSAGE
, *PSEP_RM_API_MESSAGE
;
47 typedef struct _SEP_LOGON_SESSION_REFERENCES
49 struct _SEP_LOGON_SESSION_REFERENCES
*Next
;
53 PDEVICE_MAP pDeviceMap
;
55 } SEP_LOGON_SESSION_REFERENCES
, *PSEP_LOGON_SESSION_REFERENCES
;
59 SepRmCommandServerThread(
64 SepRmCreateLogonSession(
68 /* GLOBALS ********************************************************************/
70 HANDLE SeRmCommandPort
;
71 HANDLE SeLsaInitEvent
;
73 PVOID SepCommandPortViewBase
;
74 PVOID SepCommandPortViewRemoteBase
;
75 ULONG_PTR SepCommandPortViewBaseOffset
;
77 static HANDLE SepRmCommandMessagePort
;
79 BOOLEAN SepAdtAuditingEnabled
;
80 ULONG SepAdtMinListLength
= 0x2000;
81 ULONG SepAdtMaxListLength
= 0x3000;
83 #define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1)
84 UCHAR SeAuditingState
[POLICY_AUDIT_EVENT_TYPE_COUNT
];
86 KGUARDED_MUTEX SepRmDbLock
;
87 PSEP_LOGON_SESSION_REFERENCES SepLogonSessions
;
90 /* PRIVATE FUNCTIONS **********************************************************/
101 UNICODE_STRING ValueNameString
;
102 UNICODE_STRING KeyNameString
;
104 OBJECT_ATTRIBUTES ObjectAttributes
;
105 HANDLE KeyHandle
= NULL
;
108 KEY_VALUE_PARTIAL_INFORMATION Partial
;
110 } KeyValueInformation
;
111 NTSTATUS Status
, CloseStatus
;
114 RtlInitUnicodeString(&KeyNameString
, KeyName
);
115 InitializeObjectAttributes(&ObjectAttributes
,
117 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
121 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
122 if (!NT_SUCCESS(Status
))
127 RtlInitUnicodeString(&ValueNameString
, ValueName
);
128 Status
= ZwQueryValueKey(KeyHandle
,
130 KeyValuePartialInformation
,
131 &KeyValueInformation
.Partial
,
132 sizeof(KeyValueInformation
),
134 if (!NT_SUCCESS(Status
))
139 if ((KeyValueInformation
.Partial
.Type
!= ValueType
) ||
140 (KeyValueInformation
.Partial
.DataLength
!= DataLength
))
142 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
147 if (ValueType
== REG_BINARY
)
149 RtlCopyMemory(ValueData
, KeyValueInformation
.Partial
.Data
, DataLength
);
151 else if (ValueType
== REG_DWORD
)
153 *(PULONG
)ValueData
= *(PULONG
)KeyValueInformation
.Partial
.Data
;
157 Status
= STATUS_INVALID_PARAMETER
;
161 CloseStatus
= ZwClose(KeyHandle
);
162 ASSERT(NT_SUCCESS( CloseStatus
));
173 OBJECT_ATTRIBUTES ObjectAttributes
;
177 // Windows does this in SeRmInitPhase0, but it should not matter
178 KeInitializeGuardedMutex(&SepRmDbLock
);
180 Status
= SepRmCreateLogonSession(&SeSystemAuthenticationId
);
181 if (!NT_VERIFY(NT_SUCCESS(Status
)))
186 Status
= SepRmCreateLogonSession(&SeAnonymousAuthenticationId
);
187 if (!NT_VERIFY(NT_SUCCESS(Status
)))
192 /* Create the SeRm command port */
193 RtlInitUnicodeString(&Name
, L
"\\SeRmCommandPort");
194 InitializeObjectAttributes(&ObjectAttributes
, &Name
, 0, NULL
, NULL
);
195 Status
= ZwCreatePort(&SeRmCommandPort
,
198 PORT_MAXIMUM_MESSAGE_LENGTH
,
200 if (!NT_SUCCESS(Status
))
202 DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status
);
206 /* Create SeLsaInitEvent */
207 RtlInitUnicodeString(&Name
, L
"\\SeLsaInitEvent");
208 InitializeObjectAttributes(&ObjectAttributes
, &Name
, 0, NULL
, NULL
);
209 Status
= ZwCreateEvent(&SeLsaInitEvent
,
214 if (!NT_VERIFY((NT_SUCCESS(Status
))))
216 DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status
);
220 /* Create the SeRm server thread */
221 Status
= PsCreateSystemThread(&ThreadHandle
,
226 SepRmCommandServerThread
,
228 if (!NT_SUCCESS(Status
))
230 DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status
);
234 ObCloseHandle(ThreadHandle
, KernelMode
);
241 SepAdtInitializeBounds(VOID
)
251 Status
= SepRegQueryHelper(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa",
256 if (!NT_SUCCESS(Status
))
258 /* No registry values, so keep hardcoded defaults */
262 /* Check if the bounds are valid */
263 if ((ListBounds
.MaxLength
< ListBounds
.MinLength
) ||
264 (ListBounds
.MinLength
< 16) ||
265 (ListBounds
.MaxLength
- ListBounds
.MinLength
< 16))
267 DPRINT1("ListBounds are invalid: %u, %u\n",
268 ListBounds
.MinLength
, ListBounds
.MaxLength
);
272 /* Set the new bounds globally */
273 SepAdtMinListLength
= ListBounds
.MinLength
;
274 SepAdtMaxListLength
= ListBounds
.MaxLength
;
281 PSEP_RM_API_MESSAGE Message
)
286 /* First re-initialize the bounds from the registry */
287 SepAdtInitializeBounds();
289 /* Make sure we have the right message and clear */
290 ASSERT(Message
->ApiNumber
== RmAuditSetCommand
);
291 Message
->ApiNumber
= 0;
293 /* Store the enable flag in the global variable */
294 SepAdtAuditingEnabled
= Message
->u
.SetAuditEvent
.Enabled
;
296 /* Loop all audit event types */
297 for (i
= 0; i
< POLICY_AUDIT_EVENT_TYPE_COUNT
; i
++)
299 /* Save the provided flags in the global array */
300 SeAuditingState
[i
] = (UCHAR
)Message
->u
.SetAuditEvent
.Flags
[i
];
303 return STATUS_SUCCESS
;
309 SepRmCreateLogonSession(
312 PSEP_LOGON_SESSION_REFERENCES CurrentSession
, NewSession
;
316 DPRINT1("SepRmCreateLogonSession(<0x%lx,0x%lx>)\n",
317 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
319 /* Allocate a new session structure */
320 NewSession
= ExAllocatePoolWithTag(PagedPool
,
321 sizeof(SEP_LOGON_SESSION_REFERENCES
),
322 SEP_LOGON_SESSION_TAG
);
323 if (NewSession
== NULL
)
325 return STATUS_INSUFFICIENT_RESOURCES
;
329 NewSession
->LogonId
= *LogonLuid
;
330 NewSession
->ReferenceCount
= 0;
331 NewSession
->Flags
= 0;
332 NewSession
->pDeviceMap
= NULL
;
333 InitializeListHead(&NewSession
->TokenList
);
335 /* Acquire the database lock */
336 KeAcquireGuardedMutex(&SepRmDbLock
);
338 /* Loop all existing sessions */
339 for (CurrentSession
= SepLogonSessions
;
340 CurrentSession
!= NULL
;
341 CurrentSession
= CurrentSession
->Next
)
343 /* Check if the LUID matches the new one */
344 if (RtlEqualLuid(&CurrentSession
->LogonId
, LogonLuid
))
346 Status
= STATUS_LOGON_SESSION_EXISTS
;
351 /* Insert the new session */
352 NewSession
->Next
= SepLogonSessions
;
353 SepLogonSessions
= NewSession
;
355 Status
= STATUS_SUCCESS
;
358 /* Release the database lock */
359 KeReleaseGuardedMutex(&SepRmDbLock
);
361 if (!NT_SUCCESS(Status
))
363 ExFreePoolWithTag(NewSession
, SEP_LOGON_SESSION_TAG
);
371 SepRmDeleteLogonSession(
374 DPRINT1("SepRmDeleteLogonSession(<0x%lx,0x%lx>)\n",
375 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
379 return STATUS_NOT_IMPLEMENTED
;
385 SepRmCommandServerThreadInit(VOID
)
387 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
388 SEP_RM_API_MESSAGE Message
;
389 UNICODE_STRING PortName
;
390 REMOTE_PORT_VIEW RemotePortView
;
392 LARGE_INTEGER SectionSize
;
393 HANDLE SectionHandle
;
398 SectionHandle
= NULL
;
404 /* Wait until LSASS is ready */
405 Status
= ZwWaitForSingleObject(SeLsaInitEvent
, FALSE
, NULL
);
406 if (!NT_SUCCESS(Status
))
408 DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status
);
412 /* We don't need this event anymore */
413 ObCloseHandle(SeLsaInitEvent
, KernelMode
);
415 /* Initialize the connection message */
416 Message
.Header
.u1
.s1
.TotalLength
= sizeof(Message
);
417 Message
.Header
.u1
.s1
.DataLength
= 0;
419 /* Only LSASS can connect, so handle the connection right now */
420 Status
= ZwListenPort(SeRmCommandPort
, &Message
.Header
);
421 if (!NT_SUCCESS(Status
))
423 DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status
);
427 /* Set the Port View structure length */
428 RemotePortView
.Length
= sizeof(RemotePortView
);
430 /* Accept the connection */
431 Status
= ZwAcceptConnectPort(&SepRmCommandMessagePort
,
437 if (!NT_SUCCESS(Status
))
439 DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status
);
443 /* Complete the connection */
444 Status
= ZwCompleteConnectPort(SepRmCommandMessagePort
);
445 if (!NT_SUCCESS(Status
))
447 DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status
);
451 /* Create a section for messages */
452 SectionSize
.QuadPart
= PAGE_SIZE
;
453 Status
= ZwCreateSection(&SectionHandle
,
460 if (!NT_SUCCESS(Status
))
462 DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status
);
466 /* Setup the PORT_VIEW structure */
467 PortView
.Length
= sizeof(PortView
);
468 PortView
.SectionHandle
= SectionHandle
;
469 PortView
.SectionOffset
= 0;
470 PortView
.ViewSize
= SectionSize
.LowPart
;
471 PortView
.ViewBase
= NULL
;
472 PortView
.ViewRemoteBase
= NULL
;
474 /* Setup security QOS */
475 SecurityQos
.Length
= sizeof(SecurityQos
);
476 SecurityQos
.ImpersonationLevel
= SecurityImpersonation
;
477 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
478 SecurityQos
.EffectiveOnly
= TRUE
;
480 /* Connect to LSASS */
481 RtlInitUnicodeString(&PortName
, L
"\\SeLsaCommandPort");
482 Status
= ZwConnectPort(&PortHandle
,
490 if (!NT_SUCCESS(Status
))
492 DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status
);
496 /* Remember section base and view offset */
497 SepCommandPortViewBase
= PortView
.ViewBase
;
498 SepCommandPortViewRemoteBase
= PortView
.ViewRemoteBase
;
499 SepCommandPortViewBaseOffset
= (ULONG_PTR
)SepCommandPortViewRemoteBase
-
500 (ULONG_PTR
)SepCommandPortViewBase
;
502 DPRINT("SepRmCommandServerThreadInit: done\n");
505 /* Check for failure */
506 if (!NT_SUCCESS(Status
))
508 if (PortHandle
!= NULL
)
510 ObCloseHandle(PortHandle
, KernelMode
);
516 /* Did we create a section? */
517 if (SectionHandle
!= NULL
)
519 ObCloseHandle(SectionHandle
, KernelMode
);
527 SepRmCommandServerThread(
530 SEP_RM_API_MESSAGE Message
;
531 PPORT_MESSAGE ReplyMessage
;
532 HANDLE DummyPortHandle
;
535 /* Initialize the server thread */
536 if (!SepRmCommandServerThreadInit())
538 DPRINT1("Security: Terminating Rm Command Server Thread\n");
548 /* Wait for a message */
549 Status
= ZwReplyWaitReceivePort(SepRmCommandMessagePort
,
553 if (!NT_SUCCESS(Status
))
555 DPRINT1("Failed to get message: 0x%lx", Status
);
560 /* Check if this is a connection request */
561 if (Message
.Header
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
563 /* Reject connection request */
564 ZwAcceptConnectPort(&DummyPortHandle
,
576 /* Check if the port died */
577 if ((Message
.Header
.u2
.s2
.Type
== LPC_PORT_CLOSED
) ||
578 (Message
.Header
.u2
.s2
.Type
== LPC_CLIENT_DIED
))
580 /* LSASS is dead, so let's quit as well */
584 /* Check if this is an actual request */
585 if (Message
.Header
.u2
.s2
.Type
!= LPC_REQUEST
)
587 DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n",
588 Message
.Header
.u2
.s2
.Type
);
590 /* Restart without replying */
595 ReplyMessage
= &Message
.Header
;
597 switch (Message
.ApiNumber
)
599 case RmAuditSetCommand
:
600 Status
= SepRmSetAuditEvent(&Message
);
603 case RmCreateLogonSession
:
604 Status
= SepRmCreateLogonSession(&Message
.u
.LogonLuid
);
607 case RmDeleteLogonSession
:
608 Status
= SepRmDeleteLogonSession(&Message
.u
.LogonLuid
);
612 DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n",
617 Message
.u
.ResultStatus
= Status
;
620 /* Close the port handles */
621 ObCloseHandle(SepRmCommandMessagePort
, KernelMode
);
622 ObCloseHandle(SeRmCommandPort
, KernelMode
);