[NTOSKRNL] Implement SeGetLogonIdDeviceMap
[reactos.git] / ntoskrnl / se / srm.c
1 /*
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
6 *
7 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
8 * Pierre Schweitzer (pierre@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 extern LUID SeSystemAuthenticationId;
18 extern LUID SeAnonymousAuthenticationId;
19
20 /* PRIVATE DEFINITIONS ********************************************************/
21
22 #define SEP_LOGON_SESSION_TAG 'sLeS'
23
24 typedef struct _SEP_LOGON_SESSION_REFERENCES
25 {
26 struct _SEP_LOGON_SESSION_REFERENCES *Next;
27 LUID LogonId;
28 ULONG ReferenceCount;
29 ULONG Flags;
30 PDEVICE_MAP pDeviceMap;
31 LIST_ENTRY TokenList;
32 } SEP_LOGON_SESSION_REFERENCES, *PSEP_LOGON_SESSION_REFERENCES;
33
34 VOID
35 NTAPI
36 SepRmCommandServerThread(
37 PVOID StartContext);
38
39 static
40 NTSTATUS
41 SepRmCreateLogonSession(
42 PLUID LogonLuid);
43
44
45 /* GLOBALS ********************************************************************/
46
47 HANDLE SeRmCommandPort;
48 HANDLE SeLsaInitEvent;
49
50 PVOID SepCommandPortViewBase;
51 PVOID SepCommandPortViewRemoteBase;
52 ULONG_PTR SepCommandPortViewBaseOffset;
53
54 static HANDLE SepRmCommandMessagePort;
55
56 BOOLEAN SepAdtAuditingEnabled;
57 ULONG SepAdtMinListLength = 0x2000;
58 ULONG SepAdtMaxListLength = 0x3000;
59
60 #define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1)
61 UCHAR SeAuditingState[POLICY_AUDIT_EVENT_TYPE_COUNT];
62
63 KGUARDED_MUTEX SepRmDbLock;
64 PSEP_LOGON_SESSION_REFERENCES SepLogonSessions;
65
66
67 /* PRIVATE FUNCTIONS **********************************************************/
68
69 NTSTATUS
70 NTAPI
71 SepRegQueryHelper(
72 PCWSTR KeyName,
73 PCWSTR ValueName,
74 ULONG ValueType,
75 ULONG DataLength,
76 PVOID ValueData)
77 {
78 UNICODE_STRING ValueNameString;
79 UNICODE_STRING KeyNameString;
80 ULONG ResultLength;
81 OBJECT_ATTRIBUTES ObjectAttributes;
82 HANDLE KeyHandle = NULL;
83 struct
84 {
85 KEY_VALUE_PARTIAL_INFORMATION Partial;
86 UCHAR Buffer[64];
87 } KeyValueInformation;
88 NTSTATUS Status, CloseStatus;
89 PAGED_CODE();
90
91 RtlInitUnicodeString(&KeyNameString, KeyName);
92 InitializeObjectAttributes(&ObjectAttributes,
93 &KeyNameString,
94 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
95 NULL,
96 NULL);
97
98 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
99 if (!NT_SUCCESS(Status))
100 {
101 return Status;
102 }
103
104 RtlInitUnicodeString(&ValueNameString, ValueName);
105 Status = ZwQueryValueKey(KeyHandle,
106 &ValueNameString,
107 KeyValuePartialInformation,
108 &KeyValueInformation.Partial,
109 sizeof(KeyValueInformation),
110 &ResultLength);
111 if (!NT_SUCCESS(Status))
112 {
113 goto Cleanup;
114 }
115
116 if ((KeyValueInformation.Partial.Type != ValueType) ||
117 (KeyValueInformation.Partial.DataLength != DataLength))
118 {
119 Status = STATUS_OBJECT_TYPE_MISMATCH;
120 goto Cleanup;
121 }
122
123
124 if (ValueType == REG_BINARY)
125 {
126 RtlCopyMemory(ValueData, KeyValueInformation.Partial.Data, DataLength);
127 }
128 else if (ValueType == REG_DWORD)
129 {
130 *(PULONG)ValueData = *(PULONG)KeyValueInformation.Partial.Data;
131 }
132 else
133 {
134 Status = STATUS_INVALID_PARAMETER;
135 }
136
137 Cleanup:
138 CloseStatus = ZwClose(KeyHandle);
139 ASSERT(NT_SUCCESS( CloseStatus ));
140
141 return Status;
142 }
143
144
145 BOOLEAN
146 NTAPI
147 SeRmInitPhase0(VOID)
148 {
149 NTSTATUS Status;
150
151 /* Initialize the database lock */
152 KeInitializeGuardedMutex(&SepRmDbLock);
153
154 /* Create the system logon session */
155 Status = SepRmCreateLogonSession(&SeSystemAuthenticationId);
156 if (!NT_VERIFY(NT_SUCCESS(Status)))
157 {
158 return FALSE;
159 }
160
161 /* Create the anonymous logon session */
162 Status = SepRmCreateLogonSession(&SeAnonymousAuthenticationId);
163 if (!NT_VERIFY(NT_SUCCESS(Status)))
164 {
165 return FALSE;
166 }
167
168 return TRUE;
169 }
170
171
172 BOOLEAN
173 NTAPI
174 SeRmInitPhase1(VOID)
175 {
176 UNICODE_STRING Name;
177 OBJECT_ATTRIBUTES ObjectAttributes;
178 HANDLE ThreadHandle;
179 NTSTATUS Status;
180
181 /* Create the SeRm command port */
182 RtlInitUnicodeString(&Name, L"\\SeRmCommandPort");
183 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL);
184 Status = ZwCreatePort(&SeRmCommandPort,
185 &ObjectAttributes,
186 sizeof(ULONG),
187 PORT_MAXIMUM_MESSAGE_LENGTH,
188 2 * PAGE_SIZE);
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status);
192 return FALSE;
193 }
194
195 /* Create SeLsaInitEvent */
196 RtlInitUnicodeString(&Name, L"\\SeLsaInitEvent");
197 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL);
198 Status = ZwCreateEvent(&SeLsaInitEvent,
199 GENERIC_WRITE,
200 &ObjectAttributes,
201 NotificationEvent,
202 FALSE);
203 if (!NT_VERIFY((NT_SUCCESS(Status))))
204 {
205 DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status);
206 return FALSE;
207 }
208
209 /* Create the SeRm server thread */
210 Status = PsCreateSystemThread(&ThreadHandle,
211 THREAD_ALL_ACCESS,
212 NULL,
213 NULL,
214 NULL,
215 SepRmCommandServerThread,
216 NULL);
217 if (!NT_SUCCESS(Status))
218 {
219 DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status);
220 return FALSE;
221 }
222
223 ObCloseHandle(ThreadHandle, KernelMode);
224
225 return TRUE;
226 }
227
228 static
229 VOID
230 SepAdtInitializeBounds(VOID)
231 {
232 struct
233 {
234 ULONG MaxLength;
235 ULONG MinLength;
236 } ListBounds;
237 NTSTATUS Status;
238 PAGED_CODE();
239
240 Status = SepRegQueryHelper(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa",
241 L"Bounds",
242 REG_BINARY,
243 sizeof(ListBounds),
244 &ListBounds);
245 if (!NT_SUCCESS(Status))
246 {
247 /* No registry values, so keep hardcoded defaults */
248 return;
249 }
250
251 /* Check if the bounds are valid */
252 if ((ListBounds.MaxLength < ListBounds.MinLength) ||
253 (ListBounds.MinLength < 16) ||
254 (ListBounds.MaxLength - ListBounds.MinLength < 16))
255 {
256 DPRINT1("ListBounds are invalid: %u, %u\n",
257 ListBounds.MinLength, ListBounds.MaxLength);
258 return;
259 }
260
261 /* Set the new bounds globally */
262 SepAdtMinListLength = ListBounds.MinLength;
263 SepAdtMaxListLength = ListBounds.MaxLength;
264 }
265
266
267 static
268 NTSTATUS
269 SepRmSetAuditEvent(
270 PSEP_RM_API_MESSAGE Message)
271 {
272 ULONG i;
273 PAGED_CODE();
274
275 /* First re-initialize the bounds from the registry */
276 SepAdtInitializeBounds();
277
278 /* Make sure we have the right message and clear */
279 ASSERT(Message->ApiNumber == RmAuditSetCommand);
280 Message->ApiNumber = 0;
281
282 /* Store the enable flag in the global variable */
283 SepAdtAuditingEnabled = Message->u.SetAuditEvent.Enabled;
284
285 /* Loop all audit event types */
286 for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++)
287 {
288 /* Save the provided flags in the global array */
289 SeAuditingState[i] = (UCHAR)Message->u.SetAuditEvent.Flags[i];
290 }
291
292 return STATUS_SUCCESS;
293 }
294
295
296 static
297 NTSTATUS
298 SepRmCreateLogonSession(
299 PLUID LogonLuid)
300 {
301 PSEP_LOGON_SESSION_REFERENCES CurrentSession, NewSession;
302 NTSTATUS Status;
303 PAGED_CODE();
304
305 DPRINT("SepRmCreateLogonSession(%08lx:%08lx)\n",
306 LogonLuid->HighPart, LogonLuid->LowPart);
307
308 /* Allocate a new session structure */
309 NewSession = ExAllocatePoolWithTag(PagedPool,
310 sizeof(SEP_LOGON_SESSION_REFERENCES),
311 SEP_LOGON_SESSION_TAG);
312 if (NewSession == NULL)
313 {
314 return STATUS_INSUFFICIENT_RESOURCES;
315 }
316
317 /* Initialize it */
318 NewSession->LogonId = *LogonLuid;
319 NewSession->ReferenceCount = 0;
320 NewSession->Flags = 0;
321 NewSession->pDeviceMap = NULL;
322 InitializeListHead(&NewSession->TokenList);
323
324 /* Acquire the database lock */
325 KeAcquireGuardedMutex(&SepRmDbLock);
326
327 /* Loop all existing sessions */
328 for (CurrentSession = SepLogonSessions;
329 CurrentSession != NULL;
330 CurrentSession = CurrentSession->Next)
331 {
332 /* Check if the LUID matches the new one */
333 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid))
334 {
335 Status = STATUS_LOGON_SESSION_EXISTS;
336 goto Leave;
337 }
338 }
339
340 /* Insert the new session */
341 NewSession->Next = SepLogonSessions;
342 SepLogonSessions = NewSession;
343
344 Status = STATUS_SUCCESS;
345
346 Leave:
347 /* Release the database lock */
348 KeReleaseGuardedMutex(&SepRmDbLock);
349
350 if (!NT_SUCCESS(Status))
351 {
352 ExFreePoolWithTag(NewSession, SEP_LOGON_SESSION_TAG);
353 }
354
355 return Status;
356 }
357
358 static
359 NTSTATUS
360 SepRmDeleteLogonSession(
361 PLUID LogonLuid)
362 {
363 DPRINT("SepRmDeleteLogonSession(%08lx:%08lx)\n",
364 LogonLuid->HighPart, LogonLuid->LowPart);
365
366 UNIMPLEMENTED;
367 NT_ASSERT(FALSE);
368 return STATUS_NOT_IMPLEMENTED;
369 }
370
371
372 NTSTATUS
373 SepRmReferenceLogonSession(
374 PLUID LogonLuid)
375 {
376 PSEP_LOGON_SESSION_REFERENCES CurrentSession;
377
378 PAGED_CODE();
379
380 DPRINT("SepRmReferenceLogonSession(%08lx:%08lx)\n",
381 LogonLuid->HighPart, LogonLuid->LowPart);
382
383 /* Acquire the database lock */
384 KeAcquireGuardedMutex(&SepRmDbLock);
385
386 /* Loop all existing sessions */
387 for (CurrentSession = SepLogonSessions;
388 CurrentSession != NULL;
389 CurrentSession = CurrentSession->Next)
390 {
391 /* Check if the LUID matches the new one */
392 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid))
393 {
394 /* Reference the session */
395 CurrentSession->ReferenceCount += 1;
396 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount);
397
398 /* Release the database lock */
399 KeReleaseGuardedMutex(&SepRmDbLock);
400
401 return STATUS_SUCCESS;
402 }
403 }
404
405 /* Release the database lock */
406 KeReleaseGuardedMutex(&SepRmDbLock);
407
408 return STATUS_NO_SUCH_LOGON_SESSION;
409 }
410
411
412 NTSTATUS
413 SepRmDereferenceLogonSession(
414 PLUID LogonLuid)
415 {
416 PSEP_LOGON_SESSION_REFERENCES CurrentSession;
417
418 DPRINT("SepRmDereferenceLogonSession(%08lx:%08lx)\n",
419 LogonLuid->HighPart, LogonLuid->LowPart);
420
421 /* Acquire the database lock */
422 KeAcquireGuardedMutex(&SepRmDbLock);
423
424 /* Loop all existing sessions */
425 for (CurrentSession = SepLogonSessions;
426 CurrentSession != NULL;
427 CurrentSession = CurrentSession->Next)
428 {
429 /* Check if the LUID matches the new one */
430 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid))
431 {
432 /* Dereference the session */
433 CurrentSession->ReferenceCount -= 1;
434 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount);
435
436 /* Release the database lock */
437 KeReleaseGuardedMutex(&SepRmDbLock);
438
439 return STATUS_SUCCESS;
440 }
441 }
442
443 /* Release the database lock */
444 KeReleaseGuardedMutex(&SepRmDbLock);
445
446 return STATUS_NO_SUCH_LOGON_SESSION;
447 }
448
449
450 BOOLEAN
451 NTAPI
452 SepRmCommandServerThreadInit(VOID)
453 {
454 SECURITY_QUALITY_OF_SERVICE SecurityQos;
455 SEP_RM_API_MESSAGE Message;
456 UNICODE_STRING PortName;
457 REMOTE_PORT_VIEW RemotePortView;
458 PORT_VIEW PortView;
459 LARGE_INTEGER SectionSize;
460 HANDLE SectionHandle;
461 HANDLE PortHandle;
462 NTSTATUS Status;
463 BOOLEAN Result;
464
465 SectionHandle = NULL;
466 PortHandle = NULL;
467
468 /* Assume success */
469 Result = TRUE;
470
471 /* Wait until LSASS is ready */
472 Status = ZwWaitForSingleObject(SeLsaInitEvent, FALSE, NULL);
473 if (!NT_SUCCESS(Status))
474 {
475 DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status);
476 goto Cleanup;
477 }
478
479 /* We don't need this event anymore */
480 ObCloseHandle(SeLsaInitEvent, KernelMode);
481
482 /* Initialize the connection message */
483 Message.Header.u1.s1.TotalLength = sizeof(Message);
484 Message.Header.u1.s1.DataLength = 0;
485
486 /* Only LSASS can connect, so handle the connection right now */
487 Status = ZwListenPort(SeRmCommandPort, &Message.Header);
488 if (!NT_SUCCESS(Status))
489 {
490 DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status);
491 goto Cleanup;
492 }
493
494 /* Set the Port View structure length */
495 RemotePortView.Length = sizeof(RemotePortView);
496
497 /* Accept the connection */
498 Status = ZwAcceptConnectPort(&SepRmCommandMessagePort,
499 NULL,
500 &Message.Header,
501 TRUE,
502 NULL,
503 &RemotePortView);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status);
507 goto Cleanup;
508 }
509
510 /* Complete the connection */
511 Status = ZwCompleteConnectPort(SepRmCommandMessagePort);
512 if (!NT_SUCCESS(Status))
513 {
514 DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status);
515 goto Cleanup;
516 }
517
518 /* Create a section for messages */
519 SectionSize.QuadPart = PAGE_SIZE;
520 Status = ZwCreateSection(&SectionHandle,
521 SECTION_ALL_ACCESS,
522 NULL,
523 &SectionSize,
524 PAGE_READWRITE,
525 SEC_COMMIT,
526 NULL);
527 if (!NT_SUCCESS(Status))
528 {
529 DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status);
530 goto Cleanup;
531 }
532
533 /* Setup the PORT_VIEW structure */
534 PortView.Length = sizeof(PortView);
535 PortView.SectionHandle = SectionHandle;
536 PortView.SectionOffset = 0;
537 PortView.ViewSize = SectionSize.LowPart;
538 PortView.ViewBase = NULL;
539 PortView.ViewRemoteBase = NULL;
540
541 /* Setup security QOS */
542 SecurityQos.Length = sizeof(SecurityQos);
543 SecurityQos.ImpersonationLevel = SecurityImpersonation;
544 SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
545 SecurityQos.EffectiveOnly = TRUE;
546
547 /* Connect to LSASS */
548 RtlInitUnicodeString(&PortName, L"\\SeLsaCommandPort");
549 Status = ZwConnectPort(&PortHandle,
550 &PortName,
551 &SecurityQos,
552 &PortView,
553 NULL,
554 0,
555 0,
556 0);
557 if (!NT_SUCCESS(Status))
558 {
559 DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status);
560 goto Cleanup;
561 }
562
563 /* Remember section base and view offset */
564 SepCommandPortViewBase = PortView.ViewBase;
565 SepCommandPortViewRemoteBase = PortView.ViewRemoteBase;
566 SepCommandPortViewBaseOffset = (ULONG_PTR)SepCommandPortViewRemoteBase -
567 (ULONG_PTR)SepCommandPortViewBase;
568
569 DPRINT("SepRmCommandServerThreadInit: done\n");
570
571 Cleanup:
572 /* Check for failure */
573 if (!NT_SUCCESS(Status))
574 {
575 if (PortHandle != NULL)
576 {
577 ObCloseHandle(PortHandle, KernelMode);
578 }
579
580 Result = FALSE;
581 }
582
583 /* Did we create a section? */
584 if (SectionHandle != NULL)
585 {
586 ObCloseHandle(SectionHandle, KernelMode);
587 }
588
589 return Result;
590 }
591
592 VOID
593 NTAPI
594 SepRmCommandServerThread(
595 PVOID StartContext)
596 {
597 SEP_RM_API_MESSAGE Message;
598 PPORT_MESSAGE ReplyMessage;
599 HANDLE DummyPortHandle;
600 NTSTATUS Status;
601
602 /* Initialize the server thread */
603 if (!SepRmCommandServerThreadInit())
604 {
605 DPRINT1("Security: Terminating Rm Command Server Thread\n");
606 return;
607 }
608
609 /* No reply yet */
610 ReplyMessage = NULL;
611
612 /* Start looping */
613 while (TRUE)
614 {
615 /* Wait for a message */
616 Status = ZwReplyWaitReceivePort(SepRmCommandMessagePort,
617 NULL,
618 ReplyMessage,
619 &Message.Header);
620 if (!NT_SUCCESS(Status))
621 {
622 DPRINT1("Failed to get message: 0x%lx", Status);
623 ReplyMessage = NULL;
624 continue;
625 }
626
627 /* Check if this is a connection request */
628 if (Message.Header.u2.s2.Type == LPC_CONNECTION_REQUEST)
629 {
630 /* Reject connection request */
631 ZwAcceptConnectPort(&DummyPortHandle,
632 NULL,
633 &Message.Header,
634 FALSE,
635 NULL,
636 NULL);
637
638 /* Start over */
639 ReplyMessage = NULL;
640 continue;
641 }
642
643 /* Check if the port died */
644 if ((Message.Header.u2.s2.Type == LPC_PORT_CLOSED) ||
645 (Message.Header.u2.s2.Type == LPC_CLIENT_DIED))
646 {
647 /* LSASS is dead, so let's quit as well */
648 break;
649 }
650
651 /* Check if this is an actual request */
652 if (Message.Header.u2.s2.Type != LPC_REQUEST)
653 {
654 DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n",
655 Message.Header.u2.s2.Type);
656
657 /* Restart without replying */
658 ReplyMessage = NULL;
659 continue;
660 }
661
662 ReplyMessage = &Message.Header;
663
664 switch (Message.ApiNumber)
665 {
666 case RmAuditSetCommand:
667 Status = SepRmSetAuditEvent(&Message);
668 break;
669
670 case RmCreateLogonSession:
671 Status = SepRmCreateLogonSession(&Message.u.LogonLuid);
672 break;
673
674 case RmDeleteLogonSession:
675 Status = SepRmDeleteLogonSession(&Message.u.LogonLuid);
676 break;
677
678 default:
679 DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n",
680 Message.ApiNumber);
681 ReplyMessage = NULL;
682 }
683
684 Message.u.ResultStatus = Status;
685 }
686
687 /* Close the port handles */
688 ObCloseHandle(SepRmCommandMessagePort, KernelMode);
689 ObCloseHandle(SeRmCommandPort, KernelMode);
690 }
691
692
693 /* PUBLIC FUNCTIONS ***********************************************************/
694
695 /*
696 * @unimplemented
697 */
698 NTSTATUS
699 NTAPI
700 SeGetLogonIdDeviceMap(
701 IN PLUID LogonId,
702 OUT PDEVICE_MAP * DeviceMap
703 )
704 {
705 NTSTATUS Status;
706 WCHAR Buffer[63];
707 PDEVICE_MAP LocalMap;
708 HANDLE DirectoryHandle, LinkHandle;
709 OBJECT_ATTRIBUTES ObjectAttributes;
710 PSEP_LOGON_SESSION_REFERENCES CurrentSession;
711 UNICODE_STRING DirectoryName, LinkName, TargetName;
712
713 PAGED_CODE();
714
715 if (LogonId == NULL ||
716 DeviceMap == NULL)
717 {
718 return STATUS_INVALID_PARAMETER;
719 }
720
721 /* Acquire the database lock */
722 KeAcquireGuardedMutex(&SepRmDbLock);
723
724 /* Loop all existing sessions */
725 for (CurrentSession = SepLogonSessions;
726 CurrentSession != NULL;
727 CurrentSession = CurrentSession->Next)
728 {
729 /* Check if the LUID matches the provided one */
730 if (RtlEqualLuid(&CurrentSession->LogonId, LogonId))
731 {
732 break;
733 }
734 }
735
736 /* No session found, fail */
737 if (CurrentSession == NULL)
738 {
739 /* Release the database lock */
740 KeReleaseGuardedMutex(&SepRmDbLock);
741
742 return STATUS_NO_SUCH_LOGON_SESSION;
743 }
744
745 /* The found session has a device map, return it! */
746 if (CurrentSession->pDeviceMap != NULL)
747 {
748 *DeviceMap = CurrentSession->pDeviceMap;
749
750 /* Release the database lock */
751 KeReleaseGuardedMutex(&SepRmDbLock);
752
753 return STATUS_SUCCESS;
754 }
755
756 /* At that point, we'll setup a new device map for the session */
757 LocalMap = NULL;
758
759 /* Reference the session so that it doesn't go away */
760 CurrentSession->ReferenceCount += 1;
761
762 /* Release the database lock */
763 KeReleaseGuardedMutex(&SepRmDbLock);
764
765 /* Create our object directory given the LUID */
766 _snwprintf(Buffer,
767 sizeof(Buffer) / sizeof(WCHAR),
768 L"\\Sessions\\0\\DosDevices\\%08x-%08x",
769 LogonId->HighPart,
770 LogonId->LowPart);
771 RtlInitUnicodeString(&DirectoryName, Buffer);
772
773 InitializeObjectAttributes(&ObjectAttributes,
774 &DirectoryName,
775 OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
776 NULL,
777 NULL);
778 Status = ZwCreateDirectoryObject(&DirectoryHandle,
779 DIRECTORY_ALL_ACCESS,
780 &ObjectAttributes);
781 if (NT_SUCCESS(Status))
782 {
783 /* Create the associated device map */
784 Status = ObSetDirectoryDeviceMap(&LocalMap, DirectoryHandle);
785 if (NT_SUCCESS(Status))
786 {
787 /* Make Global point to \Global?? in the directory */
788 RtlInitUnicodeString(&LinkName, L"Global");
789 RtlInitUnicodeString(&TargetName, L"\\Global??");
790
791 InitializeObjectAttributes(&ObjectAttributes,
792 &LinkName,
793 OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
794 DirectoryHandle,
795 NULL);
796 Status = ZwCreateSymbolicLinkObject(&LinkHandle,
797 SYMBOLIC_LINK_ALL_ACCESS,
798 &ObjectAttributes,
799 &TargetName);
800 if (!NT_SUCCESS(Status))
801 {
802 ObfDereferenceDeviceMap(LocalMap);
803 }
804 else
805 {
806 ZwClose(LinkHandle);
807 }
808 }
809
810 ZwClose(DirectoryHandle);
811 }
812
813 /* Acquire the database lock */
814 KeAcquireGuardedMutex(&SepRmDbLock);
815
816 /* If we succeed... */
817 if (NT_SUCCESS(Status))
818 {
819 /* The session now has a device map? We raced with someone else */
820 if (CurrentSession->pDeviceMap != NULL)
821 {
822 /* Give up on our new device map */
823 ObfDereferenceDeviceMap(LocalMap);
824 }
825 /* Otherwise use our newly allocated device map */
826 else
827 {
828 CurrentSession->pDeviceMap = LocalMap;
829 }
830
831 /* Return the device map */
832 *DeviceMap = CurrentSession->pDeviceMap;
833 }
834 /* Zero output */
835 else
836 {
837 *DeviceMap = NULL;
838 }
839
840 /* Release the database lock */
841 KeReleaseGuardedMutex(&SepRmDbLock);
842
843 /* We're done with the session */
844 SepRmDereferenceLogonSession(&CurrentSession->LogonId);
845
846 return Status;
847 }
848
849 /*
850 * @unimplemented
851 */
852 NTSTATUS
853 NTAPI
854 SeMarkLogonSessionForTerminationNotification(
855 IN PLUID LogonId)
856 {
857 UNIMPLEMENTED;
858 return STATUS_NOT_IMPLEMENTED;
859 }
860
861
862 /*
863 * @unimplemented
864 */
865 NTSTATUS
866 NTAPI
867 SeRegisterLogonSessionTerminatedRoutine(
868 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine)
869 {
870 UNIMPLEMENTED;
871 return STATUS_NOT_IMPLEMENTED;
872 }
873
874
875 /*
876 * @unimplemented
877 */
878 NTSTATUS
879 NTAPI
880 SeUnregisterLogonSessionTerminatedRoutine(
881 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine)
882 {
883 UNIMPLEMENTED;
884 return STATUS_NOT_IMPLEMENTED;
885 }