ReactOS  0.4.15-dev-2354-g9e947e2
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 
16 typedef struct _BSM_REQUEST
17 {
18  struct _BSM_REQUEST * Next;
23 
24 /* GLOBALS ********************************************************************/
25 
30 LONG (WINAPI *PBROADCASTSYSTEMMESSAGEEXW)(DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO) = NULL;
31 
32 /* PRIVATE FUNCTIONS **********************************************************/
33 
35 {
37 }
38 
40 {
42 }
43 
45 GetCallerLuid(PLUID CallerLuid)
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;
63  FALSE, &TokenHandle);
64  /* If we fail, open process token */
65  if (Status == STATUS_NO_TOKEN)
66  {
69  &TokenHandle);
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),
79  &ReturnLength);
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;
111  _SEH2_TRY
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 */
123  PNameInfo = RtlAllocateHeap(BaseSrvHeap, 0, ReturnLength);
124  if (PNameInfo == NULL)
125  {
127  _SEH2_LEAVE;
128  }
129 
130  /* Query again handle information */
131  Status = NtQueryObject(LinkHandle,
133  PNameInfo,
134  ReturnLength,
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 
161 BOOLEAN
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 
195  CsrRevertToSelf();
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 
214 NTSTATUS
216  LPDWORD Recipients,
217  UINT Message,
218  WPARAM wParam,
219  LPARAM lParam)
220 {
222  return STATUS_NOT_IMPLEMENTED;
223 }
224 
225 NTSTATUS
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");
254  Status = LdrGetProcedureAddress(hUser32,
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 
312 ULONG
313 NTAPI
314 BaseSrvBSMThread(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;
352  ExitStatus = Status;
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 
368 NTSTATUS
370 {
371  /* This can only be true for LUID mappings */
373  {
374  return STATUS_ACCESS_DENIED;
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 
390 NTSTATUS
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  {
412  return STATUS_ACCESS_DENIED;
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  {
425  return STATUS_ACCESS_DENIED;
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 
474 CSR_API(BaseSrvDefineDosDevice)
475 {
477  PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.DefineDosDeviceRequest;
479  HANDLE LinkHandle;
482  ULONG Length;
485  PSID SystemSid;
486  PSID WorldSid;
487  PWSTR lpBuffer;
488  WCHAR Letter;
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  */
545  lpBuffer = RtlAllocateHeap(BaseSrvHeap, 0, 0x2000);
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);
564  _SEH2_TRY
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  {
596  _SEH2_LEAVE;
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  {
619  _SEH2_LEAVE;
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 */
644  CsrRevertToSelf();
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 */
662  _SEH2_LEAVE;
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 */
684  _SEH2_LEAVE;
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  {
703  _SEH2_LEAVE;
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  {
713  _SEH2_LEAVE;
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  {
742  _SEH2_LEAVE;
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 
768  Status = NtQuerySymbolicLinkObject(LinkHandle,
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  {
779  _SEH2_LEAVE;
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  {
830  _SEH2_LEAVE;
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  {
908  _SEH2_LEAVE;
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  {
932  _SEH2_LEAVE;
933  }
934 
935  /* Initialize our SIDs for symlink ACLs */
937  1,
946  &WorldSid);
947  if (!NT_SUCCESS(Status))
948  {
949  _SEH2_LEAVE;
950  }
951 
953  1,
962  &SystemSid);
963  if (!NT_SUCCESS(Status))
964  {
966  _SEH2_LEAVE;
967  }
968 
969  /* Initialize our SD (on stack) */
972 
973  /* And our ACL (still on stack) */
974  RtlCreateAcl(&Dacl.Dacl, sizeof(Dacl), ACL_REVISION);
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  {
1012  if (!CsrImpersonateClient(NULL))
1013  {
1015  _SEH2_LEAVE;
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 */
1032  if (BaseStaticServerData->LUIDDeviceMapsEnabled && !IsGlobal)
1033  {
1034  CsrRevertToSelf();
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 */
LUID AuthenticationId
Definition: setypes.h:1033
static ACPI_BUFFER CurrentBuffer
ULONG NTAPI BaseSrvBSMThread(PVOID StartupContext)
Definition: dosdev.c:314
LUID BroadcastLuid
Definition: dosdev.c:19
UNICODE_STRING TargetPath
Definition: basemsg.h:257
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
NTSTATUS BroadcastDriveLetterChange(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:226
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
LONG RemoveDefinition
Definition: dosdev.c:21
#define BSF_FORCEIFHUNG
Definition: dbt.h:54
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
NTSTATUS NTAPI LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, IN PULONG DllCharacteristics OPTIONAL, IN PUNICODE_STRING DllName, OUT PVOID *DllHandle)
Definition: ldrapi.c:805
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define TRUE
Definition: types.h:120
_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:182
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:521
uint16_t * PWSTR
Definition: typedefs.h:56
NTSYSAPI PVOID NTAPI RtlFreeSid(_In_ _Post_invalid_ PSID Sid)
ULONG SessionId
Definition: dllmain.c:28
LONG NTSTATUS
Definition: precomp.h:26
#define DDD_NO_BROADCAST_SYSTEM
Definition: winbase.h:523
static SID_IDENTIFIER_AUTHORITY WorldAuthority
Definition: security.c:14
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
BOOLEAN NTAPI CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, IN PVOID *Buffer, IN ULONG ElementCount, IN ULONG ElementSize)
Definition: api.c:1426
#define NtCurrentThread()
#define BSF_NOTIMEOUTIFNOTHUNG
Definition: dbt.h:57
_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)
BOOLEAN NTAPI CsrRevertToSelf(VOID)
Definition: procsup.c:1057
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
LPDWORD
Definition: dosdev.c:30
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
NTSTATUS AddBSMRequest(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:391
NTSTATUS NTAPI NtMakeTemporaryObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1385
UINT_PTR WPARAM
Definition: windef.h:207
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
NTSTATUS NTAPI NtOpenProcessToken(IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle)
Definition: security.c:350
UNICODE_STRING Name
Definition: nt_native.h:1270
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAce(PACL, DWORD, DWORD, PSID)
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
#define BSF_NOHANG
Definition: dbt.h:56
NTSYSAPI WCHAR NTAPI RtlUpcaseUnicodeChar(WCHAR Source)
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
struct _BSM_REQUEST * Next
Definition: dosdev.c:18
#define SYMBOLIC_LINK_ALL_ACCESS
Definition: nt_native.h:1267
#define DWORD
Definition: nt_native.h:44
WPARAM wParam
Definition: combotst.c:138
VOID BaseCleanupDefineDosDevice(VOID)
Definition: dosdev.c:39
NTSTATUS NTAPI NtMakePermanentObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1422
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
_SEH2_TRY
Definition: create.c:4226
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
uint32_t ULONG_PTR
Definition: typedefs.h:65
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:683
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
Definition: dosdev.c:26
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292
return STATUS_NOT_IMPLEMENTED
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3272
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
LONG DriveLetter
Definition: dosdev.c:20
#define FALSE
Definition: types.h:117
WPARAM
Definition: dosdev.c:30
#define UNICODE_NULL
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
long LONG
Definition: pedump.c:60
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
struct _BSM_REQUEST * PBSM_REQUEST
short SHORT
Definition: pedump.c:59
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:173
#define DBT_DEVICEREMOVECOMPLETE
Definition: dbt.h:16
UNICODE_STRING DeviceName
Definition: basemsg.h:256
struct _BASE_API_MESSAGE * PBASE_API_MESSAGE
NTSTATUS NTAPI LdrGetProcedureAddress(IN PVOID BaseAddress, IN PANSI_STRING Name, IN ULONG Ordinal, OUT PVOID *ProcedureAddress)
Definition: ldrapi.c:823
unsigned char BOOLEAN
BOOLEAN LUIDDeviceMapsEnabled
Definition: base.h:133
#define ACL_REVISION2
Definition: setypes.h:43
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
_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)
Definition: token.c:2226
LONG_PTR LPARAM
Definition: windef.h:208
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:715
Definition: bufpool.h:45
#define SECURITY_NT_AUTHORITY
Definition: setypes.h:526
#define NtCurrentProcess()
Definition: nt_native.h:1657
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
Status
Definition: gdiplustypes.h:24
NTSTATUS SendWinStationBSM(DWORD Flags, LPDWORD Recipients, UINT Message, WPARAM wParam, LPARAM lParam)
Definition: dosdev.c:215
NTSTATUS NtTerminateThread(IN HANDLE ThreadHandle OPTIONAL, IN NTSTATUS ExitStatus)
Definition: kill.c:1278
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define TOKEN_QUERY
Definition: setypes.h:874
__wchar_t WCHAR
Definition: xmlstorage.h:180
NTSYSAPI NTSTATUS NTAPI RtlInitializeCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define SECURITY_WORLD_SID_AUTHORITY
Definition: setypes.h:499
NTSTATUS NtQueryObject(IN HANDLE Handle, IN OBJECT_INFO_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength)
#define WINAPI
Definition: msvc.h:6
_In_ ACCESS_MASK AccessMask
Definition: exfuncs.h:186
unsigned long DWORD
Definition: ntddk_ex.h:95
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_NO_TOKEN
Definition: ntstatus.h:360
#define DBT_DEVTYP_VOLUME
Definition: dbt.h:21
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define READ_CONTROL
Definition: nt_native.h:58
CHAR Message[80]
Definition: alive.c:5
#define SECURITY_NULL_RID
Definition: setypes.h:512
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL Dacl
Definition: rtlfuncs.h:1552
unsigned char UCHAR
Definition: xmlstorage.h:181
ULONG ProtectionMode
Definition: init.c:34
char * PBOOLEAN
Definition: retypes.h:11
NTSTATUS IsGlobalSymbolicLink(HANDLE LinkHandle, PBOOLEAN IsGlobal)
Definition: dosdev.c:96
PBSM_REQUEST BSM_Request_Queue
Definition: dosdev.c:28
static const WCHAR L[]
Definition: oid.c:1250
LONG(WINAPI *PBROADCASTSYSTEMMESSAGEEXW)(DWORD
WCHAR Letter
PSID WorldSid
Definition: globals.c:15
#define OBJ_PERMANENT
Definition: winternl.h:226
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)
unsigned char BYTE
Definition: xxhash.c:193
#define SYSTEM_LUID
Definition: setypes.h:672
LPARAM
Definition: dosdev.c:30
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
CSR_API(BaseSrvDefineDosDevice)
Definition: dosdev.c:474
HANDLE BaseSrvHeap
Definition: init.c:29
struct _BSM_REQUEST BSM_REQUEST
_SEH2_END
Definition: create.c:4400
PRTL_UNICODE_STRING_BUFFER Path
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
PBSM_REQUEST BSM_Request_Queue_End
Definition: dosdev.c:28
#define DBT_DEVICEARRIVAL
Definition: dbt.h:12
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:859
_SEH2_FINALLY
Definition: create.c:4371
#define DDD_LUID_BROADCAST_DRIVE
Definition: winbase.h:524
NTSTATUS CreateBSMThread(VOID)
Definition: dosdev.c:369
#define SECURITY_RESTRICTED_CODE_RID
Definition: setypes.h:541
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
struct _DEV_BROADCAST_VOLUME DEV_BROADCAST_VOLUME
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define WM_DEVICECHANGE
Definition: winuser.h:1793
ULONG BaseSrvpBSMThreadCount
Definition: dosdev.c:29
#define DPRINT1
Definition: precomp.h:8
#define ACL_REVISION
Definition: setypes.h:39
NTSYSAPI void WINAPI RtlCopyLuid(PLUID, const LUID *)
NTSTATUS NTAPI NtOpenThreadToken(IN HANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN OpenAsSelf, OUT PHANDLE TokenHandle)
Definition: token.c:4245
#define BSM_ALLDESKTOPS
Definition: dbt.h:49
uint32_t * LPDWORD
Definition: typedefs.h:59
unsigned int ULONG
Definition: retypes.h:1
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
#define DBTF_NET
Definition: dbt.h:44
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNIMPLEMENTED
Definition: debug.h:115
PBSMINFO
Definition: dosdev.c:30
BOOLEAN NTAPI CsrImpersonateClient(IN PCSR_THREAD CsrThread)
Definition: procsup.c:932
#define ULONG_PTR
Definition: config.h:101
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_LEAVE
Definition: filesup.c:20
#define DPRINT
Definition: sndvol32.h:71
NTSYSAPI NTSTATUS NTAPI RtlDeleteCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
BOOLEAN CheckForGlobalDriveLetter(SHORT DriveLetter)
Definition: dosdev.c:162
RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec
Definition: dosdev.c:27
NTSTATUS GetCallerLuid(PLUID CallerLuid)
Definition: dosdev.c:45
LPARAM lParam
Definition: combotst.c:139
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define BSM_APPLICATIONS
Definition: dbt.h:48
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define DELETE
Definition: nt_native.h:57
#define DDD_EXACT_MATCH_ON_REMOVE
Definition: winbase.h:522
static SID_IDENTIFIER_AUTHORITY SystemAuthority
Definition: msgina.c:38
UINT
Definition: dosdev.c:30
VOID BaseInitDefineDosDevice(VOID)
Definition: dosdev.c:34