ReactOS 0.4.16-dev-122-g325d74c
dosdev.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/dosdev.c
5 * PURPOSE: DOS Devices Management
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "basesrv.h"
12
13#define NDEBUG
14#include <debug.h>
15
16typedef struct _BSM_REQUEST
17{
23
24/* GLOBALS ********************************************************************/
25
30LONG (WINAPI *PBROADCASTSYSTEMMESSAGEEXW)(DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO) = NULL;
31
32/* PRIVATE FUNCTIONS **********************************************************/
33
35{
37}
38
40{
42}
43
46{
50 TOKEN_STATISTICS TokenInformation;
51
52 /* We need an output buffer */
53 if (CallerLuid == NULL)
54 {
56 }
57
58 /* Open thread token */
59 TokenHandle = 0;
60 ReturnLength = 0;
64 /* If we fail, open process token */
66 {
70 }
71
72 /* In case of a success get caller LUID and copy it back */
73 if (NT_SUCCESS(Status))
74 {
77 &TokenInformation,
78 sizeof(TokenInformation),
80 if (NT_SUCCESS(Status))
81 {
82 RtlCopyLuid(CallerLuid, &TokenInformation.AuthenticationId);
83 }
84 }
85
86 /* Close token handle */
87 if (TokenHandle != 0)
88 {
90 }
91
92 return Status;
93}
94
97 PBOOLEAN IsGlobal)
98{
101 UNICODE_STRING GlobalString;
102 OBJECT_NAME_INFORMATION NameInfo, *PNameInfo;
103
104 /* We need both parameters */
105 if (LinkHandle == 0 || IsGlobal == NULL)
106 {
108 }
109
110 PNameInfo = NULL;
112 {
113 /* Query handle information */
114 Status = NtQueryObject(LinkHandle,
116 &NameInfo,
117 0,
118 &ReturnLength);
119 /* Only failure we tolerate is length mismatch */
121 {
122 /* Allocate big enough buffer */
124 if (PNameInfo == NULL)
125 {
128 }
129
130 /* Query again handle information */
131 Status = NtQueryObject(LinkHandle,
133 PNameInfo,
135 &ReturnLength);
136
137 /*
138 * If it succeed, check we have Global??
139 * If so, return success
140 */
141 if (NT_SUCCESS(Status))
142 {
143 RtlInitUnicodeString(&GlobalString, L"\\GLOBAL??");
144 *IsGlobal = RtlPrefixUnicodeString(&GlobalString, &PNameInfo->Name, FALSE);
146 }
147 }
148 }
150 {
151 if (PNameInfo != NULL)
152 {
153 RtlFreeHeap(BaseSrvHeap, 0, PNameInfo);
154 }
155 }
156 _SEH2_END;
157
158 return Status;
159}
160
163{
164 WCHAR Path[8];
166 BOOLEAN IsGlobal;
167 UNICODE_STRING PathU;
168 HANDLE SymbolicLinkHandle;
170
171 /* Setup our drive path */
172 wcsncpy(Path, L"\\??\\X:", (sizeof(L"\\??\\X:") / sizeof(WCHAR)));
173 Path[4] = DriveLetter + L'A';
174 Path[6] = UNICODE_NULL;
175
176 /* Prepare everything to open the link */
177 RtlInitUnicodeString(&PathU, Path);
179 &PathU,
181 NULL,
182 NULL);
183
184 /* Impersonate the caller */
186 {
187 return FALSE;
188 }
189
190 /* Open our drive letter */
191 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle,
194
196
197 if (!NT_SUCCESS(Status))
198 {
199 return FALSE;
200 }
201
202 /* Check whether it's global */
203 Status = IsGlobalSymbolicLink(SymbolicLinkHandle, &IsGlobal);
204 NtClose(SymbolicLinkHandle);
205
206 if (!NT_SUCCESS(Status))
207 {
208 return FALSE;
209 }
210
211 return IsGlobal;
212}
213
216 LPDWORD Recipients,
220{
223}
224
229{
230 HANDLE hUser32;
232 UNICODE_STRING User32U;
233 ANSI_STRING ProcedureName;
234 DWORD Recipients, Flags, wParam;
235 LUID SystemLuid = SYSTEM_LUID;
236 BSMINFO Info;
238
239 /* We need a broadcast LUID */
240 if (BroadcastLuid == NULL)
241 {
243 }
244
245 /* Get the Csr procedure, and keep it forever */
246 if (PBROADCASTSYSTEMMESSAGEEXW == NULL)
247 {
248 hUser32 = NULL;
249 RtlInitUnicodeString(&User32U, L"user32");
250 Status = LdrGetDllHandle(NULL, NULL, &User32U, &hUser32);
251 if (hUser32 != NULL && NT_SUCCESS(Status))
252 {
253 RtlInitString(&ProcedureName, "CsrBroadcastSystemMessageExW");
255 &ProcedureName,
256 0,
257 (PVOID *)&PBROADCASTSYSTEMMESSAGEEXW);
258 if (!NT_SUCCESS(Status))
259 {
260 PBROADCASTSYSTEMMESSAGEEXW = NULL;
261 }
262 }
263
264 /* If we failed to get broadcast procedure, no more actions left */
265 if (PBROADCASTSYSTEMMESSAGEEXW == NULL)
266 {
267 return Status;
268 }
269 }
270
271 /* Initialize broadcast info */
272 Info.cbSize = sizeof(BSMINFO);
273 Info.hdesk = 0;
274 Info.hwnd = 0;
276
277 /* Initialize volume information */
278 Volume.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
279 Volume.dbcv_devicetype = DBT_DEVTYP_VOLUME;
280 Volume.dbcv_reserved = 0;
281 Volume.dbcv_unitmask = 1 << DriveLetter;
282 Volume.dbcv_flags = DBTF_NET;
283
284 /* Wide broadcast */
285 Recipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
287
288 /*
289 * If we don't broadcast as system, it's not a global drive
290 * notification, then mark it as LUID mapped drive
291 */
292 if (!RtlEqualLuid(&Info.luid, &SystemLuid))
293 {
294 Flags |= BSF_LUID;
295 }
296
297 /* Set event type */
299
300 /* And broadcast! */
301 Status = PBROADCASTSYSTEMMESSAGEEXW(Flags, &Recipients, WM_DEVICECHANGE, wParam, (LPARAM)&Volume, &Info);
302
303 /* If the drive is global, notify Winsta */
304 if (!(Flags & BSF_LUID))
305 {
307 }
308
309 return Status;
310}
311
312ULONG
313NTAPI
314BaseSrvBSMThread(PVOID StartupContext)
315{
318 PBSM_REQUEST CurrentRequest;
319
320 /* We have a thread */
321 ExitStatus = 0;
324
325 while (TRUE)
326 {
327 /* If we flushed the queue, job done */
328 if (BSM_Request_Queue == NULL)
329 {
330 break;
331 }
332
333 /* Queue current request, and remove it from the queue */
334 CurrentRequest = BSM_Request_Queue;
336
337 /* If that was the last request, NULLify queue end */
338 if (BSM_Request_Queue == NULL)
339 {
341 }
342
344
345 /* Broadcast the message */
347 CurrentRequest->RemoveDefinition,
348 &CurrentRequest->BroadcastLuid);
349
350 /* Reflect the last entry status on stop */
351 CurrentRequest->Next = NULL;
353
354 RtlFreeHeap(BaseSrvHeap, 0, CurrentRequest);
356 }
357
358 /* Here, we've flushed the queue, quit the user thread */
361
362 NtCurrentTeb()->FreeStackOnTermination = TRUE;
364
365 return ExitStatus;
366}
367
370{
371 /* This can only be true for LUID mappings */
373 {
375 }
376
377 /* Create our user thread */
379 NULL,
380 FALSE,
381 0,
382 0,
383 0,
385 NULL,
386 NULL,
387 NULL);
388}
389
394{
395 LUID CallerLuid;
397 LUID SystemLuid = SYSTEM_LUID;
399
400 /* We need a broadcast LUID */
401 if (BroadcastLuid == NULL)
402 {
404 }
405
406 /*
407 * If LUID mappings are not enabled, this call makes no sense
408 * It should not happen though
409 */
411 {
413 }
414
415 /* Get our caller LUID (not the broadcaster!) */
416 Status = GetCallerLuid(&CallerLuid);
417 if (!NT_SUCCESS(Status))
418 {
419 return Status;
420 }
421
422 /* System cannot create LUID mapped drives - thus broadcast makes no sense */
423 if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
424 {
426 }
427
428 /* Allocate our request */
430 if (Request == NULL)
431 {
432 return STATUS_NO_MEMORY;
433 }
434
435 /* Initialize it */
436 Request->DriveLetter = DriveLetter;
437 Request->RemoveDefinition = RemoveDefinition;
438 RtlCopyLuid(&Request->BroadcastLuid, BroadcastLuid);
439 Request->Next = NULL;
440
441 /* And queue it */
443
444 /* At the end of the queue if not empty */
446 {
448 }
449 /* Otherwise, initialize the queue */
450 else
451 {
453 }
454
455 /* We're in FIFO mode */
457
458 /* If we don't have a messaging thread running, then start one */
459 if (BaseSrvpBSMThreadCount >= 1)
460 {
462 }
463 else
464 {
467 }
468
469 return Status;
470}
471
472/* PUBLIC SERVER APIS *********************************************************/
473
474CSR_API(BaseSrvDefineDosDevice)
475{
477 PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.DefineDosDeviceRequest;
479 HANDLE LinkHandle;
485 PSID SystemSid;
489 SHORT AbsLetter;
492 BOOLEAN HandleTarget;
493 BOOLEAN Broadcast = FALSE;
494 BOOLEAN IsGlobal = FALSE;
495 ULONG CchLengthLeft;
496 ULONG CchLength;
497 ULONG TargetLength;
498 PWSTR TargetBuffer;
500 /* We store them on the stack, they are known in advance */
501 union {
503 UCHAR Buffer[20];
505 union {
506 ACL Dacl;
507 UCHAR Buffer[256];
508 } Dacl;
510 LUID CallerLuid;
511 WCHAR * CurrentPtr;
512 WCHAR CurrentChar;
513 PWSTR OrigPtr;
514 PWSTR InterPtr;
515 BOOLEAN RemoveFound;
516
517 if (!CsrValidateMessageBuffer(ApiMessage,
518 (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer,
519 DefineDosDeviceRequest->DeviceName.Length,
520 sizeof(BYTE)) ||
521 (DefineDosDeviceRequest->DeviceName.Length & 1) != 0 ||
522 !CsrValidateMessageBuffer(ApiMessage,
523 (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer,
524 DefineDosDeviceRequest->TargetPath.Length +
525 (DefineDosDeviceRequest->TargetPath.Length != 0
526 ? sizeof(UNICODE_NULL) : 0),
527 sizeof(BYTE)) ||
528 (DefineDosDeviceRequest->TargetPath.Length & 1) != 0)
529 {
531 }
532
533 DPRINT("BaseSrvDefineDosDevice entered, Flags:%d, DeviceName:%wZ (%d), TargetPath:%wZ (%d)\n",
534 DefineDosDeviceRequest->Flags,
535 &DefineDosDeviceRequest->DeviceName,
536 DefineDosDeviceRequest->DeviceName.Length,
537 &DefineDosDeviceRequest->TargetPath,
538 DefineDosDeviceRequest->TargetPath.Length);
539
540 /*
541 * Allocate a buffer big enough to contain:
542 * - device name
543 * - targets
544 */
546 if (lpBuffer == NULL)
547 {
548 return STATUS_NO_MEMORY;
549 }
550
551 /* Enter our critical section */
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
556 Status);
558 return Status;
559 }
560
561 LinkHandle = 0;
562 /* Does the caller wants to remove definition? */
563 RemoveDefinition = !!(DefineDosDeviceRequest->Flags & DDD_REMOVE_DEFINITION);
565 {
566 /* First of all, check if that's a drive letter device amongst LUID mappings */
567 if (BaseStaticServerData->LUIDDeviceMapsEnabled && !(DefineDosDeviceRequest->Flags & DDD_NO_BROADCAST_SYSTEM))
568 {
569 if (DefineDosDeviceRequest->DeviceName.Buffer != NULL &&
570 DefineDosDeviceRequest->DeviceName.Length == 2 * sizeof(WCHAR) &&
571 DefineDosDeviceRequest->DeviceName.Buffer[1] == L':')
572 {
573 Letter = DefineDosDeviceRequest->DeviceName.Buffer[0];
574
575 /* Handle both lower cases and upper cases */
576 AbsLetter = Letter - L'a';
577 if (AbsLetter < 26 && AbsLetter >= 0)
578 {
580 }
581
582 AbsLetter = Letter - L'A';
583 if (AbsLetter < 26)
584 {
585 /* That's a letter! */
586 DriveLetter = TRUE;
587 }
588 }
589 }
590
591 /* We can only broadcast drive letters in case of LUID mappings */
592 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE &&
593 !DriveLetter)
594 {
597 }
598
599 /* First usage of our buffer: create device name */
600 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\??\\%wZ", &DefineDosDeviceRequest->DeviceName);
601 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
602 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
604
605 /* And prepare to open it */
607 &DeviceName,
609 NULL,
610 NULL);
611
612 /* Assume it's OK and has a target to deal with */
613 HandleTarget = TRUE;
614
615 /* Move to the client context if the mapping was local */
617 {
620 }
621
622 /*
623 * While impersonating the caller, also get its LUID.
624 * This is mandatory in case we have a driver letter,
625 * Because we're in the case we've got LUID mapping
626 * enabled and broadcasting enabled. LUID will be required
627 * for the latter
628 */
629 if (DriveLetter)
630 {
631 Status = GetCallerLuid(&CallerLuid);
632 if (NT_SUCCESS(Status))
633 {
634 Broadcast = TRUE;
635 }
636 }
637
638 /* Now, open the device */
639 Status = NtOpenSymbolicLinkObject(&LinkHandle,
642
643 /* And get back to our context */
645
646 /* In case of LUID broadcast, do nothing but return to trigger broadcast */
647 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE)
648 {
649 /* Zero handle in case of a failure */
650 if (!NT_SUCCESS(Status))
651 {
652 LinkHandle = 0;
653 }
654
655 /* If removal was asked, and no object found: the remval was successful */
656 if (RemoveDefinition && Status == STATUS_OBJECT_NAME_NOT_FOUND)
657 {
659 }
660
661 /* We're done here, nothing more to do */
663 }
664
665 /* If device was not found */
667 {
668 /* No handle */
669 LinkHandle = 0;
670
671 /* If we were asked to remove... */
672 if (RemoveDefinition)
673 {
674 /*
675 * If caller asked to pop first entry, nothing specific,
676 * then, we can consider this as a success
677 */
678 if (DefineDosDeviceRequest->TargetPath.Length == 0)
679 {
681 }
682
683 /* We're done, nothing to change */
685 }
686
687 /* There's no target to handle */
688 HandleTarget = FALSE;
689
690 /*
691 * We'll consider, that's a success
692 * Failing to open the device doesn't prevent
693 * from creating it later on to create
694 * the linking.
695 */
697 }
698 else
699 {
700 /* Unexpected failure, forward to caller */
701 if (!NT_SUCCESS(Status))
702 {
704 }
705
706 /* If LUID mapping enabled */
708 {
709 /* Check if that's global link */
710 Status = IsGlobalSymbolicLink(LinkHandle, &IsGlobal);
711 if (!NT_SUCCESS(Status))
712 {
714 }
715
716 /* If so, change our device name namespace to GLOBAL?? for link creation */
717 if (IsGlobal)
718 {
719 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\GLOBAL??\\%wZ", &DefineDosDeviceRequest->DeviceName);
720 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
721 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
722
723 DeviceName.Length = CchLength * sizeof(WCHAR);
724 DeviceName.MaximumLength = CchLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
725 }
726 }
727 }
728
729 /* If caller provided a target */
730 if (DefineDosDeviceRequest->TargetPath.Length != 0)
731 {
732 /* Make sure it's null terminated */
733 DefineDosDeviceRequest->TargetPath.Buffer[DefineDosDeviceRequest->TargetPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
734
735 /* Compute its size */
736 TargetLength = wcslen(DefineDosDeviceRequest->TargetPath.Buffer);
737
738 /* And make sure it fits our buffer */
739 if (TargetLength + 1 >= CchLengthLeft)
740 {
743 }
744
745 /* Copy it to our internal buffer */
746 RtlMoveMemory(CurrentBuffer, DefineDosDeviceRequest->TargetPath.Buffer, TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
747 TargetBuffer = CurrentBuffer;
748
749 /* Update our buffer status */
750 CchLengthLeft -= (TargetLength + 1);
751 CurrentBuffer += (TargetLength + 1);
752 }
753 /* Otherwise, zero everything */
754 else
755 {
756 TargetBuffer = NULL;
757 TargetLength = 0;
758 }
759
760 /* If we opened the device, then, handle its current target */
761 if (HandleTarget)
762 {
763 /* Query it with our internal buffer */
764 LinkTarget.Length = 0;
765 LinkTarget.MaximumLength = CchLengthLeft * sizeof(WCHAR);
767
769 &LinkTarget,
770 &Length);
771 /* If we overflow, give up */
773 {
775 }
776 /* In case of a failure, bye bye */
777 if (!NT_SUCCESS(Status))
778 {
780 }
781
782 /*
783 * Properly null it for MULTI_SZ if needed
784 * Always update max length with
785 * the need size
786 * This is needed to hand relatively "small"
787 * strings to Ob and avoid killing ourselves
788 * on the next query
789 */
790 CchLength = Length / sizeof(WCHAR);
791 if (CchLength < 2 ||
792 CurrentBuffer[CchLength - 2] != UNICODE_NULL ||
793 CurrentBuffer[CchLength - 1] != UNICODE_NULL)
794 {
795 CurrentBuffer[CchLength] = UNICODE_NULL;
797 }
798 else
799 {
801 }
802 }
803 /* There's no target, and we're asked to remove, so null target */
804 else if (RemoveDefinition)
805 {
807 }
808 /* There's a target provided - new device, update buffer */
809 else
810 {
811 RtlInitUnicodeString(&LinkTarget, CurrentBuffer - TargetLength - 1);
812 }
813
814 /*
815 * We no longer need old symlink, just drop it, we'll recreate it now
816 * with updated target.
817 * The benefit of it is that if caller asked us to drop last target, then
818 * the device is removed and not dangling
819 */
820 if (LinkHandle != 0)
821 {
822 Status = NtMakeTemporaryObject(LinkHandle);
823 NtClose(LinkHandle);
824 LinkHandle = 0;
825 }
826
827 /* At this point, we must have no failure */
828 if (!NT_SUCCESS(Status))
829 {
831 }
832
833 /*
834 * If we have to remove definition, let's start to browse our
835 * target to actually drop it.
836 */
837 if (RemoveDefinition)
838 {
839 /* We'll browse our multi sz string */
840 RemoveFound = FALSE;
841 CurrentPtr = LinkTarget.Buffer;
842 InterPtr = LinkTarget.Buffer;
843 while (*CurrentPtr != UNICODE_NULL)
844 {
845 CchLength = 0;
846 OrigPtr = CurrentPtr;
847 /* First, find next string */
848 while (TRUE)
849 {
850 CurrentChar = *CurrentPtr;
851 ++CurrentPtr;
852
853 if (CurrentChar == UNICODE_NULL)
854 {
855 break;
856 }
857
858 ++CchLength;
859 }
860
861 /* This check is a bit tricky, but dead useful:
862 * If on the previous loop, we found the caller provided target
863 * in our list, then, we'll move current entry over the found one
864 * So that, it gets deleted.
865 * Also, if we don't find caller entry in our entries, then move
866 * current entry in the string if a previous one got deleted
867 */
868 if (RemoveFound ||
869 ((!(DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
870 TargetLength != CchLength || _wcsicmp(OrigPtr, TargetBuffer) != 0) &&
871 ((DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
872 (TargetLength != 0 && _wcsnicmp(OrigPtr, TargetBuffer, TargetLength) != 0))))
873 {
874 if (InterPtr != OrigPtr)
875 {
876 RtlMoveMemory(InterPtr, OrigPtr, sizeof(WCHAR) * CchLength + sizeof(UNICODE_NULL));
877 }
878
879 InterPtr += (CchLength + 1);
880 }
881 else
882 {
883 /* Match case! Remember for next loop turn and to delete it */
884 RemoveFound = TRUE;
885 }
886 }
887
888 /*
889 * Drop last entry, as required (pop)
890 * If there was a match previously, everything
891 * is already moved, so we're just nulling
892 * the end of the string
893 * If there was no match, this is the pop
894 */
895 *InterPtr = UNICODE_NULL;
896 ++InterPtr;
897
898 /* Compute new target length */
899 TargetLength = wcslen(LinkTarget.Buffer) * sizeof(WCHAR);
900 /*
901 * If it's empty, quit
902 * Beware, here, we quit with STATUS_SUCCESS, and that's expected!
903 * In case we dropped last target entry, then, it's empty
904 * and there's no need to recreate the device we deleted previously
905 */
906 if (TargetLength == 0)
907 {
909 }
910
911 /* Update our target string */
912 LinkTarget.Length = TargetLength;
914 }
915 /* If that's not a removal, just update the target to include new target */
916 else if (HandleTarget)
917 {
918 LinkTarget.Buffer = LinkTarget.Buffer - TargetLength - 1;
919 LinkTarget.Length = TargetLength * sizeof(WCHAR);
920 LinkTarget.MaximumLength += (TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
921 TargetLength *= sizeof(WCHAR);
922 }
923 /* No changes */
924 else
925 {
926 TargetLength = LinkTarget.Length;
927 }
928
929 /* Make sure we don't create empty symlink */
930 if (TargetLength == 0)
931 {
933 }
934
935 /* Initialize our SIDs for symlink ACLs */
937 1,
946 &WorldSid);
947 if (!NT_SUCCESS(Status))
948 {
950 }
951
953 1,
962 &SystemSid);
963 if (!NT_SUCCESS(Status))
964 {
967 }
968
969 /* Initialize our SD (on stack) */
972
973 /* And our ACL (still on stack) */
975
976 /*
977 * For access mask, if we have no session ID, or if
978 * protection mode is disabled, make them wide open
979 */
980 if (SessionId == 0 ||
981 (ProtectionMode & 3) == 0)
982 {
984 }
985 else
986 {
988 }
989
990 /* Setup the ACL */
993
994 /* Drop SIDs */
996 RtlFreeSid(SystemSid);
997
998 /* Link DACL to the SD */
1000
1001 /* And set it in the OA used for creation */
1002 ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
1003
1004 /*
1005 * If LUID and not global, we need to impersonate the caller
1006 * to make it local.
1007 */
1009 {
1010 if (!IsGlobal)
1011 {
1013 {
1016 }
1017 }
1018 }
1019 /* The object will be permanent */
1020 else
1021 {
1022 ObjectAttributes.Attributes |= OBJ_PERMANENT;
1023 }
1024
1025 /* (Re)Create the symbolic link/device */
1026 Status = NtCreateSymbolicLinkObject(&LinkHandle,
1029 &LinkTarget);
1030
1031 /* Revert to self if required */
1033 {
1035 }
1036
1037 /* In case of a success, make object permanent for LUID links */
1038 if (NT_SUCCESS(Status))
1039 {
1041 {
1042 Status = NtMakePermanentObject(LinkHandle);
1043 }
1044
1045 /* Close the link */
1046 NtClose(LinkHandle);
1047
1048 /*
1049 * Specific failure case here:
1050 * We were asked to remove something
1051 * but we didn't find the something
1052 * (we recreated the symlink hence the fail here!)
1053 * so fail with appropriate status
1054 */
1055 if (RemoveDefinition && !RemoveFound)
1056 {
1058 }
1059 }
1060
1061 /* We closed link, don't double close */
1062 LinkHandle = 0;
1063 }
1065 {
1066 /* If we need to close the link, do it now */
1067 if (LinkHandle != 0)
1068 {
1069 NtClose(LinkHandle);
1070 }
1071
1072 /* Free our internal buffer */
1074
1075 /* Broadcast drive letter creation */
1076 if (DriveLetter && Status == STATUS_SUCCESS && Broadcast)
1077 {
1078 LUID SystemLuid = SYSTEM_LUID;
1079
1080 /* If that's a global drive, broadcast as system */
1081 if (IsGlobal)
1082 {
1083 RtlCopyLuid(&CallerLuid, &SystemLuid);
1084 }
1085
1086 /* Broadcast the event */
1087 AddBSMRequest(AbsLetter, RemoveDefinition, &CallerLuid);
1088
1089 /*
1090 * If we removed drive, and the drive was shadowing a global one
1091 * broadcast the arrival of the global drive (as system - global)
1092 */
1093 if (RemoveDefinition && !RtlEqualLuid(&CallerLuid, &SystemLuid))
1094 {
1095 if (CheckForGlobalDriveLetter(AbsLetter))
1096 {
1097 AddBSMRequest(AbsLetter, FALSE, &CallerLuid);
1098 }
1099 }
1100 }
1101
1102 /* Done! */
1104 }
1105 _SEH2_END;
1106
1107 return Status;
1108}
1109
1110/* EOF */
static ACPI_BUFFER CurrentBuffer
WCHAR Letter
@ ObjectNameInformation
Definition: DriverTester.h:55
NTSTATUS NtQueryObject(IN HANDLE Handle, IN OBJECT_INFO_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength)
unsigned char BOOLEAN
PRTL_UNICODE_STRING_BUFFER Path
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PSID WorldSid
Definition: globals.c:15
struct _BASE_API_MESSAGE * PBASE_API_MESSAGE
ULONG ProtectionMode
Definition: init.c:34
HANDLE BaseSrvHeap
Definition: init.c:29
#define UNIMPLEMENTED
Definition: debug.h:118
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
Definition: bufpool.h:45
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
BOOLEAN NTAPI CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, IN PVOID *Buffer, IN ULONG ElementCount, IN ULONG ElementSize)
Definition: api.c:1430
BOOLEAN NTAPI CsrImpersonateClient(IN PCSR_THREAD CsrThread)
Definition: procsup.c:932
#define CSR_API(n)
Definition: csrsrv.h:176
BOOLEAN NTAPI CsrRevertToSelf(VOID)
Definition: procsup.c:1057
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:175
#define DBT_DEVTYP_VOLUME
Definition: dbt.h:21
#define BSF_NOTIMEOUTIFNOTHUNG
Definition: dbt.h:57
#define BSF_NOHANG
Definition: dbt.h:56
#define DBTF_NET
Definition: dbt.h:44
#define BSM_APPLICATIONS
Definition: dbt.h:48
#define BSF_FORCEIFHUNG
Definition: dbt.h:54
#define DBT_DEVICEARRIVAL
Definition: dbt.h:12
#define DBT_DEVICEREMOVECOMPLETE
Definition: dbt.h:16
struct _DEV_BROADCAST_VOLUME DEV_BROADCAST_VOLUME
#define BSM_ALLDESKTOPS
Definition: dbt.h:49
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
ULONG SessionId
Definition: dllmain.c:28
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
static SID_IDENTIFIER_AUTHORITY WorldAuthority
Definition: security.c:14
static const WCHAR Message[]
Definition: register.c:74
#define ULONG_PTR
Definition: config.h:101
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define _SEH2_LEAVE
Definition: filesup.c:20
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:25
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define OBJ_PERMANENT
Definition: winternl.h:226
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAce(PACL, DWORD, DWORD, PSID)
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
NTSYSAPI void WINAPI RtlCopyLuid(PLUID, const LUID *)
#define NtCurrentTeb
NTSTATUS NTAPI LdrGetDllHandle(_In_opt_ PWSTR DllPath, _In_opt_ PULONG DllCharacteristics, _In_ PUNICODE_STRING DllName, _Out_ PVOID *DllHandle)
Definition: ldrapi.c:770
NTSTATUS NTAPI LdrGetProcedureAddress(_In_ PVOID BaseAddress, _In_opt_ _When_(Ordinal==0, _Notnull_) PANSI_STRING Name, _In_opt_ _When_(Name==NULL, _In_range_(>, 0)) ULONG Ordinal, _Out_ PVOID *ProcedureAddress)
Definition: ldrapi.c:789
UNICODE_STRING Volume
Definition: fltkernel.h:1172
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
static SID_IDENTIFIER_AUTHORITY SystemAuthority
Definition: msgina.c:38
unsigned int UINT
Definition: ndis.h:50
_In_ ACCESS_MASK AccessMask
Definition: exfuncs.h:186
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:867
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:726
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL Dacl
Definition: rtlfuncs.h:1605
NTSYSAPI NTSTATUS NTAPI RtlDeleteCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI NTSTATUS NTAPI RtlCreateUserThread(_In_ PVOID ThreadContext, _Out_ HANDLE *OutThreadHandle, _Reserved_ PVOID Reserved1, _Reserved_ PVOID Reserved2, _Reserved_ PVOID Reserved3, _Reserved_ PVOID Reserved4, _Reserved_ PVOID Reserved5, _Reserved_ PVOID Reserved6, _Reserved_ PVOID Reserved7, _Reserved_ PVOID Reserved8)
NTSYSAPI NTSTATUS NTAPI RtlInitializeCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI PVOID NTAPI RtlFreeSid(_In_ _Post_invalid_ PSID Sid)
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:176
#define SYMBOLIC_LINK_ALL_ACCESS
Definition: nt_native.h:1267
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
ULONG ACCESS_MASK
Definition: nt_native.h:40
NTSTATUS NtTerminateThread(IN HANDLE ThreadHandle OPTIONAL, IN NTSTATUS ExitStatus)
Definition: kill.c:1279
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define LPDWORD
Definition: nt_native.h:46
#define NtCurrentProcess()
Definition: nt_native.h:1657
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define DELETE
Definition: nt_native.h:57
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
#define READ_CONTROL
Definition: nt_native.h:58
#define DWORD
Definition: nt_native.h:44
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSYSAPI NTSTATUS NTAPI RtlAllocateAndInitializeSid(IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, IN UCHAR SubAuthorityCount, IN ULONG SubAuthority0, IN ULONG SubAuthority1, IN ULONG SubAuthority2, IN ULONG SubAuthority3, IN ULONG SubAuthority4, IN ULONG SubAuthority5, IN ULONG SubAuthority6, IN ULONG SubAuthority7, OUT PSID *Sid)
Definition: sid.c:290
NTSTATUS NTAPI NtOpenProcessToken(IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle)
Definition: security.c:350
NTSTATUS NTAPI NtOpenThreadToken(_In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ BOOLEAN OpenAsSelf, _Out_ PHANDLE TokenHandle)
Opens a token that is tied to a thread handle.
Definition: token.c:2474
#define STATUS_NO_TOKEN
Definition: ntstatus.h:360
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI NtMakePermanentObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1510
NTSTATUS NTAPI NtMakeTemporaryObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1473
short SHORT
Definition: pedump.c:59
long LONG
Definition: pedump.c:60
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
#define DPRINT
Definition: sndvol32.h:73
UNICODE_STRING TargetPath
Definition: basemsg.h:257
UNICODE_STRING DeviceName
Definition: basemsg.h:256
BOOLEAN LUIDDeviceMapsEnabled
Definition: base.h:141
LONG DriveLetter
Definition: dosdev.c:20
LONG RemoveDefinition
Definition: dosdev.c:21
struct _BSM_REQUEST * Next
Definition: dosdev.c:18
LUID BroadcastLuid
Definition: dosdev.c:19
UNICODE_STRING Name
Definition: nt_native.h:1270
LUID AuthenticationId
Definition: setypes.h:1087
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOID BaseCleanupDefineDosDevice(VOID)
Definition: dosdev.c:39
NTSTATUS GetCallerLuid(PLUID CallerLuid)
Definition: dosdev.c:45
struct _BSM_REQUEST BSM_REQUEST
ULONG BaseSrvpBSMThreadCount
Definition: dosdev.c:29
static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
Definition: dosdev.c:26
VOID BaseInitDefineDosDevice(VOID)
Definition: dosdev.c:34
NTSTATUS AddBSMRequest(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:391
PBSM_REQUEST BSM_Request_Queue
Definition: dosdev.c:28
NTSTATUS SendWinStationBSM(DWORD Flags, LPDWORD Recipients, UINT Message, WPARAM wParam, LPARAM lParam)
Definition: dosdev.c:215
RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec
Definition: dosdev.c:27
PBSMINFO
Definition: dosdev.c:30
NTSTATUS CreateBSMThread(VOID)
Definition: dosdev.c:369
NTSTATUS BroadcastDriveLetterChange(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:226
ULONG NTAPI BaseSrvBSMThread(PVOID StartupContext)
Definition: dosdev.c:314
PBSM_REQUEST BSM_Request_Queue_End
Definition: dosdev.c:28
NTSTATUS IsGlobalSymbolicLink(HANDLE LinkHandle, PBOOLEAN IsGlobal)
Definition: dosdev.c:96
struct _BSM_REQUEST * PBSM_REQUEST
BOOLEAN CheckForGlobalDriveLetter(SHORT DriveLetter)
Definition: dosdev.c:162
_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtQueryInformationToken(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) PVOID TokenInformation, _In_ ULONG TokenInformationLength, _Out_ PULONG ReturnLength)
Queries a specific type of information in regard of an access token based upon the information class....
Definition: tokencls.c:473
uint16_t * PWSTR
Definition: typedefs.h:56
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint32_t * LPDWORD
Definition: typedefs.h:59
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define DDD_NO_BROADCAST_SYSTEM
Definition: winbase.h:526
#define DDD_EXACT_MATCH_ON_REMOVE
Definition: winbase.h:525
#define DDD_LUID_BROADCAST_DRIVE
Definition: winbase.h:527
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:524
LONG_PTR LPARAM
Definition: windef.h:208
UINT_PTR WPARAM
Definition: windef.h:207
#define WINAPI
Definition: msvc.h:6
#define WM_DEVICECHANGE
Definition: winuser.h:1814
_In_ USHORT _In_ ULONG _In_ PSOCKADDR _In_ PSOCKADDR _Reserved_ ULONG _In_opt_ PVOID _In_opt_ const WSK_CLIENT_CONNECTION_DISPATCH _In_opt_ PEPROCESS _In_opt_ PETHREAD _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor
Definition: wsk.h:191
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
#define SECURITY_WORLD_SID_AUTHORITY
Definition: setypes.h:527
#define TOKEN_QUERY
Definition: setypes.h:928
#define ACL_REVISION2
Definition: setypes.h:43
#define SECURITY_NULL_RID
Definition: setypes.h:540
#define SECURITY_RESTRICTED_CODE_RID
Definition: setypes.h:569
#define SECURITY_NT_AUTHORITY
Definition: setypes.h:554
@ TokenStatistics
Definition: setypes.h:975
#define SYSTEM_LUID
Definition: setypes.h:700
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
#define ACL_REVISION
Definition: setypes.h:39
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292
#define NtCurrentThread()