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'
23 typedef struct _SEP_LOGON_SESSION_REFERENCES
25 struct _SEP_LOGON_SESSION_REFERENCES
*Next
;
29 PDEVICE_MAP pDeviceMap
;
31 } SEP_LOGON_SESSION_REFERENCES
, *PSEP_LOGON_SESSION_REFERENCES
;
35 SepRmCommandServerThread(
40 SepRmCreateLogonSession(
44 /* GLOBALS ********************************************************************/
46 HANDLE SeRmCommandPort
;
47 HANDLE SeLsaInitEvent
;
49 PVOID SepCommandPortViewBase
;
50 PVOID SepCommandPortViewRemoteBase
;
51 ULONG_PTR SepCommandPortViewBaseOffset
;
53 static HANDLE SepRmCommandMessagePort
;
55 BOOLEAN SepAdtAuditingEnabled
;
56 ULONG SepAdtMinListLength
= 0x2000;
57 ULONG SepAdtMaxListLength
= 0x3000;
59 #define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1)
60 UCHAR SeAuditingState
[POLICY_AUDIT_EVENT_TYPE_COUNT
];
62 KGUARDED_MUTEX SepRmDbLock
;
63 PSEP_LOGON_SESSION_REFERENCES SepLogonSessions
;
66 /* PRIVATE FUNCTIONS **********************************************************/
77 UNICODE_STRING ValueNameString
;
78 UNICODE_STRING KeyNameString
;
80 OBJECT_ATTRIBUTES ObjectAttributes
;
81 HANDLE KeyHandle
= NULL
;
84 KEY_VALUE_PARTIAL_INFORMATION Partial
;
86 } KeyValueInformation
;
87 NTSTATUS Status
, CloseStatus
;
90 RtlInitUnicodeString(&KeyNameString
, KeyName
);
91 InitializeObjectAttributes(&ObjectAttributes
,
93 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
97 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
98 if (!NT_SUCCESS(Status
))
103 RtlInitUnicodeString(&ValueNameString
, ValueName
);
104 Status
= ZwQueryValueKey(KeyHandle
,
106 KeyValuePartialInformation
,
107 &KeyValueInformation
.Partial
,
108 sizeof(KeyValueInformation
),
110 if (!NT_SUCCESS(Status
))
115 if ((KeyValueInformation
.Partial
.Type
!= ValueType
) ||
116 (KeyValueInformation
.Partial
.DataLength
!= DataLength
))
118 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
123 if (ValueType
== REG_BINARY
)
125 RtlCopyMemory(ValueData
, KeyValueInformation
.Partial
.Data
, DataLength
);
127 else if (ValueType
== REG_DWORD
)
129 *(PULONG
)ValueData
= *(PULONG
)KeyValueInformation
.Partial
.Data
;
133 Status
= STATUS_INVALID_PARAMETER
;
137 CloseStatus
= ZwClose(KeyHandle
);
138 ASSERT(NT_SUCCESS( CloseStatus
));
150 /* Initialize the database lock */
151 KeInitializeGuardedMutex(&SepRmDbLock
);
153 /* Create the system logon session */
154 Status
= SepRmCreateLogonSession(&SeSystemAuthenticationId
);
155 if (!NT_VERIFY(NT_SUCCESS(Status
)))
160 /* Create the anonymous logon session */
161 Status
= SepRmCreateLogonSession(&SeAnonymousAuthenticationId
);
162 if (!NT_VERIFY(NT_SUCCESS(Status
)))
176 OBJECT_ATTRIBUTES ObjectAttributes
;
180 /* Create the SeRm command port */
181 RtlInitUnicodeString(&Name
, L
"\\SeRmCommandPort");
182 InitializeObjectAttributes(&ObjectAttributes
, &Name
, 0, NULL
, NULL
);
183 Status
= ZwCreatePort(&SeRmCommandPort
,
186 PORT_MAXIMUM_MESSAGE_LENGTH
,
188 if (!NT_SUCCESS(Status
))
190 DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status
);
194 /* Create SeLsaInitEvent */
195 RtlInitUnicodeString(&Name
, L
"\\SeLsaInitEvent");
196 InitializeObjectAttributes(&ObjectAttributes
, &Name
, 0, NULL
, NULL
);
197 Status
= ZwCreateEvent(&SeLsaInitEvent
,
202 if (!NT_VERIFY((NT_SUCCESS(Status
))))
204 DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status
);
208 /* Create the SeRm server thread */
209 Status
= PsCreateSystemThread(&ThreadHandle
,
214 SepRmCommandServerThread
,
216 if (!NT_SUCCESS(Status
))
218 DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status
);
222 ObCloseHandle(ThreadHandle
, KernelMode
);
229 SepAdtInitializeBounds(VOID
)
239 Status
= SepRegQueryHelper(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa",
244 if (!NT_SUCCESS(Status
))
246 /* No registry values, so keep hardcoded defaults */
250 /* Check if the bounds are valid */
251 if ((ListBounds
.MaxLength
< ListBounds
.MinLength
) ||
252 (ListBounds
.MinLength
< 16) ||
253 (ListBounds
.MaxLength
- ListBounds
.MinLength
< 16))
255 DPRINT1("ListBounds are invalid: %u, %u\n",
256 ListBounds
.MinLength
, ListBounds
.MaxLength
);
260 /* Set the new bounds globally */
261 SepAdtMinListLength
= ListBounds
.MinLength
;
262 SepAdtMaxListLength
= ListBounds
.MaxLength
;
269 PSEP_RM_API_MESSAGE Message
)
274 /* First re-initialize the bounds from the registry */
275 SepAdtInitializeBounds();
277 /* Make sure we have the right message and clear */
278 ASSERT(Message
->ApiNumber
== RmAuditSetCommand
);
279 Message
->ApiNumber
= 0;
281 /* Store the enable flag in the global variable */
282 SepAdtAuditingEnabled
= Message
->u
.SetAuditEvent
.Enabled
;
284 /* Loop all audit event types */
285 for (i
= 0; i
< POLICY_AUDIT_EVENT_TYPE_COUNT
; i
++)
287 /* Save the provided flags in the global array */
288 SeAuditingState
[i
] = (UCHAR
)Message
->u
.SetAuditEvent
.Flags
[i
];
291 return STATUS_SUCCESS
;
297 SepRmCreateLogonSession(
300 PSEP_LOGON_SESSION_REFERENCES CurrentSession
, NewSession
;
304 DPRINT("SepRmCreateLogonSession(%08lx:%08lx)\n",
305 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
307 /* Allocate a new session structure */
308 NewSession
= ExAllocatePoolWithTag(PagedPool
,
309 sizeof(SEP_LOGON_SESSION_REFERENCES
),
310 SEP_LOGON_SESSION_TAG
);
311 if (NewSession
== NULL
)
313 return STATUS_INSUFFICIENT_RESOURCES
;
317 NewSession
->LogonId
= *LogonLuid
;
318 NewSession
->ReferenceCount
= 0;
319 NewSession
->Flags
= 0;
320 NewSession
->pDeviceMap
= NULL
;
321 InitializeListHead(&NewSession
->TokenList
);
323 /* Acquire the database lock */
324 KeAcquireGuardedMutex(&SepRmDbLock
);
326 /* Loop all existing sessions */
327 for (CurrentSession
= SepLogonSessions
;
328 CurrentSession
!= NULL
;
329 CurrentSession
= CurrentSession
->Next
)
331 /* Check if the LUID matches the new one */
332 if (RtlEqualLuid(&CurrentSession
->LogonId
, LogonLuid
))
334 Status
= STATUS_LOGON_SESSION_EXISTS
;
339 /* Insert the new session */
340 NewSession
->Next
= SepLogonSessions
;
341 SepLogonSessions
= NewSession
;
343 Status
= STATUS_SUCCESS
;
346 /* Release the database lock */
347 KeReleaseGuardedMutex(&SepRmDbLock
);
349 if (!NT_SUCCESS(Status
))
351 ExFreePoolWithTag(NewSession
, SEP_LOGON_SESSION_TAG
);
359 SepRmDeleteLogonSession(
362 DPRINT("SepRmDeleteLogonSession(%08lx:%08lx)\n",
363 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
367 return STATUS_NOT_IMPLEMENTED
;
372 SepRmReferenceLogonSession(
375 PSEP_LOGON_SESSION_REFERENCES CurrentSession
;
379 DPRINT("SepRmReferenceLogonSession(%08lx:%08lx)\n",
380 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
382 /* Acquire the database lock */
383 KeAcquireGuardedMutex(&SepRmDbLock
);
385 /* Loop all existing sessions */
386 for (CurrentSession
= SepLogonSessions
;
387 CurrentSession
!= NULL
;
388 CurrentSession
= CurrentSession
->Next
)
390 /* Check if the LUID matches the new one */
391 if (RtlEqualLuid(&CurrentSession
->LogonId
, LogonLuid
))
393 /* Reference the session */
394 CurrentSession
->ReferenceCount
+= 1;
395 DPRINT("ReferenceCount: %lu\n", CurrentSession
->ReferenceCount
);
397 /* Release the database lock */
398 KeReleaseGuardedMutex(&SepRmDbLock
);
400 return STATUS_SUCCESS
;
404 /* Release the database lock */
405 KeReleaseGuardedMutex(&SepRmDbLock
);
407 return STATUS_NO_SUCH_LOGON_SESSION
;
412 SepRmDereferenceLogonSession(
415 PSEP_LOGON_SESSION_REFERENCES CurrentSession
;
417 DPRINT("SepRmDereferenceLogonSession(%08lx:%08lx)\n",
418 LogonLuid
->HighPart
, LogonLuid
->LowPart
);
420 /* Acquire the database lock */
421 KeAcquireGuardedMutex(&SepRmDbLock
);
423 /* Loop all existing sessions */
424 for (CurrentSession
= SepLogonSessions
;
425 CurrentSession
!= NULL
;
426 CurrentSession
= CurrentSession
->Next
)
428 /* Check if the LUID matches the new one */
429 if (RtlEqualLuid(&CurrentSession
->LogonId
, LogonLuid
))
431 /* Dereference the session */
432 CurrentSession
->ReferenceCount
-= 1;
433 DPRINT("ReferenceCount: %lu\n", CurrentSession
->ReferenceCount
);
435 /* Release the database lock */
436 KeReleaseGuardedMutex(&SepRmDbLock
);
438 return STATUS_SUCCESS
;
442 /* Release the database lock */
443 KeReleaseGuardedMutex(&SepRmDbLock
);
445 return STATUS_NO_SUCH_LOGON_SESSION
;
451 SepRmCommandServerThreadInit(VOID
)
453 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
454 SEP_RM_API_MESSAGE Message
;
455 UNICODE_STRING PortName
;
456 REMOTE_PORT_VIEW RemotePortView
;
458 LARGE_INTEGER SectionSize
;
459 HANDLE SectionHandle
;
464 SectionHandle
= NULL
;
470 /* Wait until LSASS is ready */
471 Status
= ZwWaitForSingleObject(SeLsaInitEvent
, FALSE
, NULL
);
472 if (!NT_SUCCESS(Status
))
474 DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status
);
478 /* We don't need this event anymore */
479 ObCloseHandle(SeLsaInitEvent
, KernelMode
);
481 /* Initialize the connection message */
482 Message
.Header
.u1
.s1
.TotalLength
= sizeof(Message
);
483 Message
.Header
.u1
.s1
.DataLength
= 0;
485 /* Only LSASS can connect, so handle the connection right now */
486 Status
= ZwListenPort(SeRmCommandPort
, &Message
.Header
);
487 if (!NT_SUCCESS(Status
))
489 DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status
);
493 /* Set the Port View structure length */
494 RemotePortView
.Length
= sizeof(RemotePortView
);
496 /* Accept the connection */
497 Status
= ZwAcceptConnectPort(&SepRmCommandMessagePort
,
503 if (!NT_SUCCESS(Status
))
505 DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status
);
509 /* Complete the connection */
510 Status
= ZwCompleteConnectPort(SepRmCommandMessagePort
);
511 if (!NT_SUCCESS(Status
))
513 DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status
);
517 /* Create a section for messages */
518 SectionSize
.QuadPart
= PAGE_SIZE
;
519 Status
= ZwCreateSection(&SectionHandle
,
526 if (!NT_SUCCESS(Status
))
528 DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status
);
532 /* Setup the PORT_VIEW structure */
533 PortView
.Length
= sizeof(PortView
);
534 PortView
.SectionHandle
= SectionHandle
;
535 PortView
.SectionOffset
= 0;
536 PortView
.ViewSize
= SectionSize
.LowPart
;
537 PortView
.ViewBase
= NULL
;
538 PortView
.ViewRemoteBase
= NULL
;
540 /* Setup security QOS */
541 SecurityQos
.Length
= sizeof(SecurityQos
);
542 SecurityQos
.ImpersonationLevel
= SecurityImpersonation
;
543 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
544 SecurityQos
.EffectiveOnly
= TRUE
;
546 /* Connect to LSASS */
547 RtlInitUnicodeString(&PortName
, L
"\\SeLsaCommandPort");
548 Status
= ZwConnectPort(&PortHandle
,
556 if (!NT_SUCCESS(Status
))
558 DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status
);
562 /* Remember section base and view offset */
563 SepCommandPortViewBase
= PortView
.ViewBase
;
564 SepCommandPortViewRemoteBase
= PortView
.ViewRemoteBase
;
565 SepCommandPortViewBaseOffset
= (ULONG_PTR
)SepCommandPortViewRemoteBase
-
566 (ULONG_PTR
)SepCommandPortViewBase
;
568 DPRINT("SepRmCommandServerThreadInit: done\n");
571 /* Check for failure */
572 if (!NT_SUCCESS(Status
))
574 if (PortHandle
!= NULL
)
576 ObCloseHandle(PortHandle
, KernelMode
);
582 /* Did we create a section? */
583 if (SectionHandle
!= NULL
)
585 ObCloseHandle(SectionHandle
, KernelMode
);
593 SepRmCommandServerThread(
596 SEP_RM_API_MESSAGE Message
;
597 PPORT_MESSAGE ReplyMessage
;
598 HANDLE DummyPortHandle
;
601 /* Initialize the server thread */
602 if (!SepRmCommandServerThreadInit())
604 DPRINT1("Security: Terminating Rm Command Server Thread\n");
614 /* Wait for a message */
615 Status
= ZwReplyWaitReceivePort(SepRmCommandMessagePort
,
619 if (!NT_SUCCESS(Status
))
621 DPRINT1("Failed to get message: 0x%lx", Status
);
626 /* Check if this is a connection request */
627 if (Message
.Header
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
629 /* Reject connection request */
630 ZwAcceptConnectPort(&DummyPortHandle
,
642 /* Check if the port died */
643 if ((Message
.Header
.u2
.s2
.Type
== LPC_PORT_CLOSED
) ||
644 (Message
.Header
.u2
.s2
.Type
== LPC_CLIENT_DIED
))
646 /* LSASS is dead, so let's quit as well */
650 /* Check if this is an actual request */
651 if (Message
.Header
.u2
.s2
.Type
!= LPC_REQUEST
)
653 DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n",
654 Message
.Header
.u2
.s2
.Type
);
656 /* Restart without replying */
661 ReplyMessage
= &Message
.Header
;
663 switch (Message
.ApiNumber
)
665 case RmAuditSetCommand
:
666 Status
= SepRmSetAuditEvent(&Message
);
669 case RmCreateLogonSession
:
670 Status
= SepRmCreateLogonSession(&Message
.u
.LogonLuid
);
673 case RmDeleteLogonSession
:
674 Status
= SepRmDeleteLogonSession(&Message
.u
.LogonLuid
);
678 DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n",
683 Message
.u
.ResultStatus
= Status
;
686 /* Close the port handles */
687 ObCloseHandle(SepRmCommandMessagePort
, KernelMode
);
688 ObCloseHandle(SeRmCommandPort
, KernelMode
);
692 /* PUBLIC FUNCTIONS ***********************************************************/
699 SeMarkLogonSessionForTerminationNotification(
703 return STATUS_NOT_IMPLEMENTED
;
712 SeRegisterLogonSessionTerminatedRoutine(
713 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
)
716 return STATUS_NOT_IMPLEMENTED
;
725 SeUnregisterLogonSessionTerminatedRoutine(
726 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
)
729 return STATUS_NOT_IMPLEMENTED
;