ReactOS 0.4.17-dev-1190-g4c812f4
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#if (NTDDI_VERSION < NTDDI_LONGHORN)
363 NtCurrentTeb()->FreeStackOnTermination = TRUE;
364#endif
366
367 return ExitStatus;
368}
369
372{
373 /* This can only be true for LUID mappings */
375 {
377 }
378
379 /* Create our user thread */
381 NULL,
382 FALSE,
383 0,
384 0,
385 0,
387 NULL,
388 NULL,
389 NULL);
390}
391
396{
397 LUID CallerLuid;
399 LUID SystemLuid = SYSTEM_LUID;
401
402 /* We need a broadcast LUID */
403 if (BroadcastLuid == NULL)
404 {
406 }
407
408 /*
409 * If LUID mappings are not enabled, this call makes no sense
410 * It should not happen though
411 */
413 {
415 }
416
417 /* Get our caller LUID (not the broadcaster!) */
418 Status = GetCallerLuid(&CallerLuid);
419 if (!NT_SUCCESS(Status))
420 {
421 return Status;
422 }
423
424 /* System cannot create LUID mapped drives - thus broadcast makes no sense */
425 if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
426 {
428 }
429
430 /* Allocate our request */
432 if (Request == NULL)
433 {
434 return STATUS_NO_MEMORY;
435 }
436
437 /* Initialize it */
438 Request->DriveLetter = DriveLetter;
439 Request->RemoveDefinition = RemoveDefinition;
440 RtlCopyLuid(&Request->BroadcastLuid, BroadcastLuid);
441 Request->Next = NULL;
442
443 /* And queue it */
445
446 /* At the end of the queue if not empty */
448 {
450 }
451 /* Otherwise, initialize the queue */
452 else
453 {
455 }
456
457 /* We're in FIFO mode */
459
460 /* If we don't have a messaging thread running, then start one */
461 if (BaseSrvpBSMThreadCount >= 1)
462 {
464 }
465 else
466 {
469 }
470
471 return Status;
472}
473
474/* PUBLIC SERVER APIS *********************************************************/
475
476CSR_API(BaseSrvDefineDosDevice)
477{
479 PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.DefineDosDeviceRequest;
481 HANDLE LinkHandle;
487 PSID SystemSid;
491 SHORT AbsLetter;
494 BOOLEAN HandleTarget;
495 BOOLEAN Broadcast = FALSE;
496 BOOLEAN IsGlobal = FALSE;
497 ULONG CchLengthLeft;
498 ULONG CchLength;
500 PWSTR TargetBuffer;
502 /* We store them on the stack, they are known in advance */
503 union {
505 UCHAR Buffer[20];
507 union {
508 ACL Dacl;
509 UCHAR Buffer[256];
510 } Dacl;
512 LUID CallerLuid;
513 WCHAR * CurrentPtr;
514 WCHAR CurrentChar;
515 PWSTR OrigPtr;
516 PWSTR InterPtr;
517 BOOLEAN RemoveFound;
518
519 if (!CsrValidateMessageBuffer(ApiMessage,
520 (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer,
521 DefineDosDeviceRequest->DeviceName.Length,
522 sizeof(BYTE)) ||
523 (DefineDosDeviceRequest->DeviceName.Length & 1) != 0 ||
524 !CsrValidateMessageBuffer(ApiMessage,
525 (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer,
526 DefineDosDeviceRequest->TargetPath.Length +
527 (DefineDosDeviceRequest->TargetPath.Length != 0
528 ? sizeof(UNICODE_NULL) : 0),
529 sizeof(BYTE)) ||
530 (DefineDosDeviceRequest->TargetPath.Length & 1) != 0)
531 {
533 }
534
535 DPRINT("BaseSrvDefineDosDevice entered, Flags:%d, DeviceName:%wZ (%d), TargetPath:%wZ (%d)\n",
536 DefineDosDeviceRequest->Flags,
537 &DefineDosDeviceRequest->DeviceName,
538 DefineDosDeviceRequest->DeviceName.Length,
539 &DefineDosDeviceRequest->TargetPath,
540 DefineDosDeviceRequest->TargetPath.Length);
541
542 /*
543 * Allocate a buffer big enough to contain:
544 * - device name
545 * - targets
546 */
548 if (lpBuffer == NULL)
549 {
550 return STATUS_NO_MEMORY;
551 }
552
553 /* Enter our critical section */
555 if (!NT_SUCCESS(Status))
556 {
557 DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
558 Status);
560 return Status;
561 }
562
563 LinkHandle = 0;
564 /* Does the caller wants to remove definition? */
565 RemoveDefinition = !!(DefineDosDeviceRequest->Flags & DDD_REMOVE_DEFINITION);
567 {
568 /* First of all, check if that's a drive letter device amongst LUID mappings */
569 if (BaseStaticServerData->LUIDDeviceMapsEnabled && !(DefineDosDeviceRequest->Flags & DDD_NO_BROADCAST_SYSTEM))
570 {
571 if (DefineDosDeviceRequest->DeviceName.Buffer != NULL &&
572 DefineDosDeviceRequest->DeviceName.Length == 2 * sizeof(WCHAR) &&
573 DefineDosDeviceRequest->DeviceName.Buffer[1] == L':')
574 {
575 Letter = DefineDosDeviceRequest->DeviceName.Buffer[0];
576
577 /* Handle both lower cases and upper cases */
578 AbsLetter = Letter - L'a';
579 if (AbsLetter < 26 && AbsLetter >= 0)
580 {
582 }
583
584 AbsLetter = Letter - L'A';
585 if (AbsLetter < 26)
586 {
587 /* That's a letter! */
588 DriveLetter = TRUE;
589 }
590 }
591 }
592
593 /* We can only broadcast drive letters in case of LUID mappings */
594 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE &&
595 !DriveLetter)
596 {
599 }
600
601 /* First usage of our buffer: create device name */
602 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\??\\%wZ", &DefineDosDeviceRequest->DeviceName);
603 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
604 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
606
607 /* And prepare to open it */
609 &DeviceName,
611 NULL,
612 NULL);
613
614 /* Assume it's OK and has a target to deal with */
615 HandleTarget = TRUE;
616
617 /* Move to the client context if the mapping was local */
619 {
622 }
623
624 /*
625 * While impersonating the caller, also get its LUID.
626 * This is mandatory in case we have a driver letter,
627 * Because we're in the case we've got LUID mapping
628 * enabled and broadcasting enabled. LUID will be required
629 * for the latter
630 */
631 if (DriveLetter)
632 {
633 Status = GetCallerLuid(&CallerLuid);
634 if (NT_SUCCESS(Status))
635 {
636 Broadcast = TRUE;
637 }
638 }
639
640 /* Now, open the device */
641 Status = NtOpenSymbolicLinkObject(&LinkHandle,
644
645 /* And get back to our context */
647
648 /* In case of LUID broadcast, do nothing but return to trigger broadcast */
649 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE)
650 {
651 /* Zero handle in case of a failure */
652 if (!NT_SUCCESS(Status))
653 {
654 LinkHandle = 0;
655 }
656
657 /* If removal was asked, and no object found: the remval was successful */
658 if (RemoveDefinition && Status == STATUS_OBJECT_NAME_NOT_FOUND)
659 {
661 }
662
663 /* We're done here, nothing more to do */
665 }
666
667 /* If device was not found */
669 {
670 /* No handle */
671 LinkHandle = 0;
672
673 /* If we were asked to remove... */
674 if (RemoveDefinition)
675 {
676 /*
677 * If caller asked to pop first entry, nothing specific,
678 * then, we can consider this as a success
679 */
680 if (DefineDosDeviceRequest->TargetPath.Length == 0)
681 {
683 }
684
685 /* We're done, nothing to change */
687 }
688
689 /* There's no target to handle */
690 HandleTarget = FALSE;
691
692 /*
693 * We'll consider, that's a success
694 * Failing to open the device doesn't prevent
695 * from creating it later on to create
696 * the linking.
697 */
699 }
700 else
701 {
702 /* Unexpected failure, forward to caller */
703 if (!NT_SUCCESS(Status))
704 {
706 }
707
708 /* If LUID mapping enabled */
710 {
711 /* Check if that's global link */
712 Status = IsGlobalSymbolicLink(LinkHandle, &IsGlobal);
713 if (!NT_SUCCESS(Status))
714 {
716 }
717
718 /* If so, change our device name namespace to GLOBAL?? for link creation */
719 if (IsGlobal)
720 {
721 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\GLOBAL??\\%wZ", &DefineDosDeviceRequest->DeviceName);
722 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
723 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
724
725 DeviceName.Length = CchLength * sizeof(WCHAR);
726 DeviceName.MaximumLength = CchLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
727 }
728 }
729 }
730
731 /* If caller provided a target */
732 if (DefineDosDeviceRequest->TargetPath.Length != 0)
733 {
734 /* Make sure it's null terminated */
735 DefineDosDeviceRequest->TargetPath.Buffer[DefineDosDeviceRequest->TargetPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
736
737 /* Compute its size */
738 TargetLength = wcslen(DefineDosDeviceRequest->TargetPath.Buffer);
739
740 /* And make sure it fits our buffer */
741 if (TargetLength + 1 >= CchLengthLeft)
742 {
745 }
746
747 /* Copy it to our internal buffer */
748 RtlMoveMemory(CurrentBuffer, DefineDosDeviceRequest->TargetPath.Buffer, TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
749 TargetBuffer = CurrentBuffer;
750
751 /* Update our buffer status */
752 CchLengthLeft -= (TargetLength + 1);
754 }
755 /* Otherwise, zero everything */
756 else
757 {
758 TargetBuffer = NULL;
759 TargetLength = 0;
760 }
761
762 /* If we opened the device, then, handle its current target */
763 if (HandleTarget)
764 {
765 /* Query it with our internal buffer */
766 LinkTarget.Length = 0;
767 LinkTarget.MaximumLength = CchLengthLeft * sizeof(WCHAR);
769
771 &LinkTarget,
772 &Length);
773 /* If we overflow, give up */
775 {
777 }
778 /* In case of a failure, bye bye */
779 if (!NT_SUCCESS(Status))
780 {
782 }
783
784 /*
785 * Properly null it for MULTI_SZ if needed
786 * Always update max length with
787 * the need size
788 * This is needed to hand relatively "small"
789 * strings to Ob and avoid killing ourselves
790 * on the next query
791 */
792 CchLength = Length / sizeof(WCHAR);
793 if (CchLength < 2 ||
794 CurrentBuffer[CchLength - 2] != UNICODE_NULL ||
795 CurrentBuffer[CchLength - 1] != UNICODE_NULL)
796 {
797 CurrentBuffer[CchLength] = UNICODE_NULL;
799 }
800 else
801 {
803 }
804 }
805 /* There's no target, and we're asked to remove, so null target */
806 else if (RemoveDefinition)
807 {
809 }
810 /* There's a target provided - new device, update buffer */
811 else
812 {
814 }
815
816 /*
817 * We no longer need old symlink, just drop it, we'll recreate it now
818 * with updated target.
819 * The benefit of it is that if caller asked us to drop last target, then
820 * the device is removed and not dangling
821 */
822 if (LinkHandle != 0)
823 {
824 Status = NtMakeTemporaryObject(LinkHandle);
825 NtClose(LinkHandle);
826 LinkHandle = 0;
827 }
828
829 /* At this point, we must have no failure */
830 if (!NT_SUCCESS(Status))
831 {
833 }
834
835 /*
836 * If we have to remove definition, let's start to browse our
837 * target to actually drop it.
838 */
839 if (RemoveDefinition)
840 {
841 /* We'll browse our multi sz string */
842 RemoveFound = FALSE;
843 CurrentPtr = LinkTarget.Buffer;
844 InterPtr = LinkTarget.Buffer;
845 while (*CurrentPtr != UNICODE_NULL)
846 {
847 CchLength = 0;
848 OrigPtr = CurrentPtr;
849 /* First, find next string */
850 while (TRUE)
851 {
852 CurrentChar = *CurrentPtr;
853 ++CurrentPtr;
854
855 if (CurrentChar == UNICODE_NULL)
856 {
857 break;
858 }
859
860 ++CchLength;
861 }
862
863 /* This check is a bit tricky, but dead useful:
864 * If on the previous loop, we found the caller provided target
865 * in our list, then, we'll move current entry over the found one
866 * So that, it gets deleted.
867 * Also, if we don't find caller entry in our entries, then move
868 * current entry in the string if a previous one got deleted
869 */
870 if (RemoveFound ||
871 ((!(DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
872 TargetLength != CchLength || _wcsicmp(OrigPtr, TargetBuffer) != 0) &&
873 ((DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
874 (TargetLength != 0 && _wcsnicmp(OrigPtr, TargetBuffer, TargetLength) != 0))))
875 {
876 if (InterPtr != OrigPtr)
877 {
878 RtlMoveMemory(InterPtr, OrigPtr, sizeof(WCHAR) * CchLength + sizeof(UNICODE_NULL));
879 }
880
881 InterPtr += (CchLength + 1);
882 }
883 else
884 {
885 /* Match case! Remember for next loop turn and to delete it */
886 RemoveFound = TRUE;
887 }
888 }
889
890 /*
891 * Drop last entry, as required (pop)
892 * If there was a match previously, everything
893 * is already moved, so we're just nulling
894 * the end of the string
895 * If there was no match, this is the pop
896 */
897 *InterPtr = UNICODE_NULL;
898 ++InterPtr;
899
900 /* Compute new target length */
902 /*
903 * If it's empty, quit
904 * Beware, here, we quit with STATUS_SUCCESS, and that's expected!
905 * In case we dropped last target entry, then, it's empty
906 * and there's no need to recreate the device we deleted previously
907 */
908 if (TargetLength == 0)
909 {
911 }
912
913 /* Update our target string */
916 }
917 /* If that's not a removal, just update the target to include new target */
918 else if (HandleTarget)
919 {
922 LinkTarget.MaximumLength += (TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
923 TargetLength *= sizeof(WCHAR);
924 }
925 /* No changes */
926 else
927 {
929 }
930
931 /* Make sure we don't create empty symlink */
932 if (TargetLength == 0)
933 {
935 }
936
937 /* Initialize our SIDs for symlink ACLs */
939 1,
948 &WorldSid);
949 if (!NT_SUCCESS(Status))
950 {
952 }
953
955 1,
964 &SystemSid);
965 if (!NT_SUCCESS(Status))
966 {
969 }
970
971 /* Initialize our SD (on stack) */
974
975 /* And our ACL (still on stack) */
977
978 /*
979 * For access mask, if we have no session ID, or if
980 * protection mode is disabled, make them wide open
981 */
982 if (SessionId == 0 ||
983 (ProtectionMode & 3) == 0)
984 {
986 }
987 else
988 {
990 }
991
992 /* Setup the ACL */
995
996 /* Drop SIDs */
998 RtlFreeSid(SystemSid);
999
1000 /* Link DACL to the SD */
1002
1003 /* And set it in the OA used for creation */
1004 ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
1005
1006 /*
1007 * If LUID and not global, we need to impersonate the caller
1008 * to make it local.
1009 */
1011 {
1012 if (!IsGlobal)
1013 {
1015 {
1018 }
1019 }
1020 }
1021 /* The object will be permanent */
1022 else
1023 {
1024 ObjectAttributes.Attributes |= OBJ_PERMANENT;
1025 }
1026
1027 /* (Re)Create the symbolic link/device */
1028 Status = NtCreateSymbolicLinkObject(&LinkHandle,
1031 &LinkTarget);
1032
1033 /* Revert to self if required */
1035 {
1037 }
1038
1039 /* In case of a success, make object permanent for LUID links */
1040 if (NT_SUCCESS(Status))
1041 {
1043 {
1044 Status = NtMakePermanentObject(LinkHandle);
1045 }
1046
1047 /* Close the link */
1048 NtClose(LinkHandle);
1049
1050 /*
1051 * Specific failure case here:
1052 * We were asked to remove something
1053 * but we didn't find the something
1054 * (we recreated the symlink hence the fail here!)
1055 * so fail with appropriate status
1056 */
1057 if (RemoveDefinition && !RemoveFound)
1058 {
1060 }
1061 }
1062
1063 /* We closed link, don't double close */
1064 LinkHandle = 0;
1065 }
1067 {
1068 /* If we need to close the link, do it now */
1069 if (LinkHandle != 0)
1070 {
1071 NtClose(LinkHandle);
1072 }
1073
1074 /* Free our internal buffer */
1076
1077 /* Broadcast drive letter creation */
1078 if (DriveLetter && Status == STATUS_SUCCESS && Broadcast)
1079 {
1080 LUID SystemLuid = SYSTEM_LUID;
1081
1082 /* If that's a global drive, broadcast as system */
1083 if (IsGlobal)
1084 {
1085 RtlCopyLuid(&CallerLuid, &SystemLuid);
1086 }
1087
1088 /* Broadcast the event */
1089 AddBSMRequest(AbsLetter, RemoveDefinition, &CallerLuid);
1090
1091 /*
1092 * If we removed drive, and the drive was shadowing a global one
1093 * broadcast the arrival of the global drive (as system - global)
1094 */
1095 if (RemoveDefinition && !RtlEqualLuid(&CallerLuid, &SystemLuid))
1096 {
1097 if (CheckForGlobalDriveLetter(AbsLetter))
1098 {
1099 AddBSMRequest(AbsLetter, FALSE, &CallerLuid);
1100 }
1101 }
1102 }
1103
1104 /* Done! */
1106 }
1107 _SEH2_END;
1108
1109 return Status;
1110}
1111
1112/* EOF */
static ACPI_BUFFER CurrentBuffer
WCHAR Letter
@ ObjectNameInformation
Definition: DriverTester.h:55
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG ReturnLength
static _Out_ PULONGLONG TargetLength
PRTL_UNICODE_STRING_BUFFER Path
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
EXTERN_C NTSTATUS WINAPI NtQueryObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG)
#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: ntoskrnl.c:15
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:616
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:634
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
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#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
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#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
#define SYMBOLIC_LINK_QUERY
Definition: volume.c:47
_ACRTIMP int __cdecl _snwprintf(wchar_t *, size_t, const wchar_t *,...)
Definition: wcs.c:1498
_ACRTIMP int __cdecl _wcsicmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:164
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2988
_ACRTIMP int __cdecl _wcsnicmp(const wchar_t *, const wchar_t *, size_t)
Definition: wcs.c:200
static SID_IDENTIFIER_AUTHORITY WorldAuthority
Definition: security.c:14
static const WCHAR Message[]
Definition: register.c:74
#define L(x)
Definition: resources.c:13
#define ULONG_PTR
Definition: config.h:101
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:24
unsigned int UINT
Definition: sysinfo.c:13
#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
LONG_PTR LPARAM
Definition: minwindef.h:175
UINT_PTR WPARAM
Definition: minwindef.h:174
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:115
static SID_IDENTIFIER_AUTHORITY SystemAuthority
Definition: msgina.c:38
_In_ ACCESS_MASK AccessMask
Definition: exfuncs.h:186
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:913
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:772
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL Dacl
Definition: rtlfuncs.h:1625
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)
_Out_ LPWSTR lpBuffer
Definition: netsh.h:68
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:177
#define SYMBOLIC_LINK_ALL_ACCESS
Definition: nt_native.h:1270
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
NTSTATUS NtTerminateThread(IN HANDLE ThreadHandle OPTIONAL, IN NTSTATUS ExitStatus)
Definition: kill.c:1315
#define LPDWORD
Definition: nt_native.h:46
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define NtCurrentProcess()
Definition: nt_native.h:1660
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3434
#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:2475
#define STATUS_NO_TOKEN
Definition: ntstatus.h:454
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:495
NTSTATUS NTAPI NtMakePermanentObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1520
NTSTATUS NTAPI NtMakeTemporaryObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1483
short WCHAR
Definition: pedump.c:58
short SHORT
Definition: pedump.c:59
long LONG
Definition: pedump.c:60
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define OBJ_PERMANENT
Definition: winternl.h:226
#define WM_DEVICECHANGE
Definition: winuser.h:1839
#define _SEH2_FINALLY
Definition: pseh2_64.h:153
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define _SEH2_LEAVE
Definition: pseh2_64.h:206
wcsncpy
#define UINT
Definition: utils.c:29
#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:1273
LUID AuthenticationId
Definition: setypes.h:1099
USHORT MaximumLength
Definition: env_spec_w32.h:370
ACPI_SIZE Length
Definition: actypes.h:1053
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:393
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:371
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 UCHAR
Definition: typedefs.h:53
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
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
#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:3281
#define DDD_NO_BROADCAST_SYSTEM
Definition: winbase.h:506
#define DDD_EXACT_MATCH_ON_REMOVE
Definition: winbase.h:505
#define DDD_LUID_BROADCAST_DRIVE
Definition: winbase.h:507
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:504
#define WINAPI
Definition: msvc.h:6
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAce(PACL, DWORD, DWORD, PSID)
#define NtCurrentThread()
Definition: winternl.h:5372
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
NTSYSAPI void WINAPI RtlCopyLuid(PLUID, const LUID *)
_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
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:304
#define SECURITY_WORLD_SID_AUTHORITY
Definition: setypes.h:527
#define TOKEN_QUERY
Definition: setypes.h:940
#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:987
#define SYSTEM_LUID
Definition: setypes.h:700
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
#define ACL_REVISION
Definition: setypes.h:39
unsigned char BYTE
Definition: xxhash.c:193
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292