ReactOS  0.4.14-dev-323-g6fe6a88
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 0
518  /* FIXME: Check why it fails.... */
519  if (!CsrValidateMessageBuffer(ApiMessage,
520  (PVOID*)&DefineDosDeviceRequest->DeviceName,
521  DefineDosDeviceRequest->DeviceName.Length,
522  1) ||
523  (DefineDosDeviceRequest->DeviceName.Length & 1) != 0 ||
524  !CsrValidateMessageBuffer(ApiMessage,
525  (PVOID*)&DefineDosDeviceRequest->TargetPath,
526  (DefineDosDeviceRequest->TargetPath.Length != 0 ? sizeof(UNICODE_NULL) : 0) + DefineDosDeviceRequest->TargetPath.Length,
527  1) ||
528  (DefineDosDeviceRequest->TargetPath.Length & 1) != 0)
529  {
531  }
532 #endif
533 
534  DPRINT("BaseSrvDefineDosDevice entered, Flags:%d, DeviceName:%wZ (%d), TargetPath:%wZ (%d)\n",
535  DefineDosDeviceRequest->Flags,
536  &DefineDosDeviceRequest->DeviceName,
537  DefineDosDeviceRequest->DeviceName.Length,
538  &DefineDosDeviceRequest->TargetPath,
539  DefineDosDeviceRequest->TargetPath.Length);
540 
541  /*
542  * Allocate a buffer big enough to contain:
543  * - device name
544  * - targets
545  */
546  lpBuffer = RtlAllocateHeap(BaseSrvHeap, 0, 0x2000);
547  if (lpBuffer == NULL)
548  {
549  return STATUS_NO_MEMORY;
550  }
551 
552  /* Enter our critical section */
554  if (!NT_SUCCESS(Status))
555  {
556  DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
557  Status);
559  return Status;
560  }
561 
562  LinkHandle = 0;
563  /* Does the caller wants to remove definition? */
564  RemoveDefinition = !!(DefineDosDeviceRequest->Flags & DDD_REMOVE_DEFINITION);
565  _SEH2_TRY
566  {
567  /* First of all, check if that's a drive letter device amongst LUID mappings */
568  if (BaseStaticServerData->LUIDDeviceMapsEnabled && !(DefineDosDeviceRequest->Flags & DDD_NO_BROADCAST_SYSTEM))
569  {
570  if (DefineDosDeviceRequest->DeviceName.Buffer != NULL &&
571  DefineDosDeviceRequest->DeviceName.Length == 2 * sizeof(WCHAR) &&
572  DefineDosDeviceRequest->DeviceName.Buffer[1] == L':')
573  {
574  Letter = DefineDosDeviceRequest->DeviceName.Buffer[0];
575 
576  /* Handle both lower cases and upper cases */
577  AbsLetter = Letter - L'a';
578  if (AbsLetter < 26 && AbsLetter >= 0)
579  {
581  }
582 
583  AbsLetter = Letter - L'A';
584  if (AbsLetter < 26)
585  {
586  /* That's a letter! */
587  DriveLetter = TRUE;
588  }
589  }
590  }
591 
592  /* We can only broadcast drive letters in case of LUID mappings */
593  if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE &&
594  !DriveLetter)
595  {
597  _SEH2_LEAVE;
598  }
599 
600  /* First usage of our buffer: create device name */
601  CchLength = _snwprintf(lpBuffer, 0x1000, L"\\??\\%wZ", &DefineDosDeviceRequest->DeviceName);
602  CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
603  CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
605 
606  /* And prepare to open it */
608  &DeviceName,
610  NULL,
611  NULL);
612 
613  /* Assume it's OK and has a target to deal with */
614  HandleTarget = TRUE;
615 
616  /* Move to the client context if the mapping was local */
618  {
620  _SEH2_LEAVE;
621  }
622 
623  /*
624  * While impersonating the caller, also get its LUID.
625  * This is mandatory in case we have a driver letter,
626  * Because we're in the case we've got LUID mapping
627  * enabled and broadcasting enabled. LUID will be required
628  * for the latter
629  */
630  if (DriveLetter)
631  {
632  Status = GetCallerLuid(&CallerLuid);
633  if (NT_SUCCESS(Status))
634  {
635  Broadcast = TRUE;
636  }
637  }
638 
639  /* Now, open the device */
640  Status = NtOpenSymbolicLinkObject(&LinkHandle,
643 
644  /* And get back to our context */
645  CsrRevertToSelf();
646 
647  /* In case of LUID broadcast, do nothing but return to trigger broadcast */
648  if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE)
649  {
650  /* Zero handle in case of a failure */
651  if (!NT_SUCCESS(Status))
652  {
653  LinkHandle = 0;
654  }
655 
656  /* If removal was asked, and no object found: the remval was successful */
657  if (RemoveDefinition && Status == STATUS_OBJECT_NAME_NOT_FOUND)
658  {
660  }
661 
662  /* We're done here, nothing more to do */
663  _SEH2_LEAVE;
664  }
665 
666  /* If device was not found */
668  {
669  /* No handle */
670  LinkHandle = 0;
671 
672  /* If we were asked to remove... */
673  if (RemoveDefinition)
674  {
675  /*
676  * If caller asked to pop first entry, nothing specific,
677  * then, we can consider this as a success
678  */
679  if (DefineDosDeviceRequest->TargetPath.Length == 0)
680  {
682  }
683 
684  /* We're done, nothing to change */
685  _SEH2_LEAVE;
686  }
687 
688  /* There's no target to handle */
689  HandleTarget = FALSE;
690 
691  /*
692  * We'll consider, that's a success
693  * Failing to open the device doesn't prevent
694  * from creating it later on to create
695  * the linking.
696  */
698  }
699  else
700  {
701  /* Unexpected failure, forward to caller */
702  if (!NT_SUCCESS(Status))
703  {
704  _SEH2_LEAVE;
705  }
706 
707  /* If LUID mapping enabled */
709  {
710  /* Check if that's global link */
711  Status = IsGlobalSymbolicLink(LinkHandle, &IsGlobal);
712  if (!NT_SUCCESS(Status))
713  {
714  _SEH2_LEAVE;
715  }
716 
717  /* If so, change our device name namespace to GLOBAL?? for link creation */
718  if (IsGlobal)
719  {
720  CchLength = _snwprintf(lpBuffer, 0x1000, L"\\GLOBAL??\\%wZ", &DefineDosDeviceRequest->DeviceName);
721  CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
722  CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
723 
724  DeviceName.Length = CchLength * sizeof(WCHAR);
725  DeviceName.MaximumLength = CchLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
726  }
727  }
728  }
729 
730  /* If caller provided a target */
731  if (DefineDosDeviceRequest->TargetPath.Length != 0)
732  {
733  /* Make sure it's null terminated */
734  DefineDosDeviceRequest->TargetPath.Buffer[DefineDosDeviceRequest->TargetPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
735 
736  /* Compute its size */
737  TargetLength = wcslen(DefineDosDeviceRequest->TargetPath.Buffer);
738 
739  /* And make sure it fits our buffer */
740  if (TargetLength + 1 >= CchLengthLeft)
741  {
743  _SEH2_LEAVE;
744  }
745 
746  /* Copy it to our internal buffer */
747  RtlMoveMemory(CurrentBuffer, DefineDosDeviceRequest->TargetPath.Buffer, TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
748  TargetBuffer = CurrentBuffer;
749 
750  /* Update our buffer status */
751  CchLengthLeft -= (TargetLength + 1);
752  CurrentBuffer += (TargetLength + 1);
753  }
754  /* Otherwise, zero everything */
755  else
756  {
757  TargetBuffer = NULL;
758  TargetLength = 0;
759  }
760 
761  /* If we opened the device, then, handle its current target */
762  if (HandleTarget)
763  {
764  /* Query it with our internal buffer */
765  LinkTarget.Length = 0;
766  LinkTarget.MaximumLength = CchLengthLeft * sizeof(WCHAR);
768 
769  Status = NtQuerySymbolicLinkObject(LinkHandle,
770  &LinkTarget,
771  &Length);
772  /* If we overflow, give up */
774  {
776  }
777  /* In case of a failure, bye bye */
778  if (!NT_SUCCESS(Status))
779  {
780  _SEH2_LEAVE;
781  }
782 
783  /*
784  * Properly null it for MULTI_SZ if needed
785  * Always update max length with
786  * the need size
787  * This is needed to hand relatively "small"
788  * strings to Ob and avoid killing ourselves
789  * on the next query
790  */
791  CchLength = Length / sizeof(WCHAR);
792  if (CchLength < 2 ||
793  CurrentBuffer[CchLength - 2] != UNICODE_NULL ||
794  CurrentBuffer[CchLength - 1] != UNICODE_NULL)
795  {
796  CurrentBuffer[CchLength] = UNICODE_NULL;
798  }
799  else
800  {
802  }
803  }
804  /* There's no target, and we're asked to remove, so null target */
805  else if (RemoveDefinition)
806  {
808  }
809  /* There's a target provided - new device, update buffer */
810  else
811  {
812  RtlInitUnicodeString(&LinkTarget, CurrentBuffer - TargetLength - 1);
813  }
814 
815  /*
816  * We no longer need old symlink, just drop it, we'll recreate it now
817  * with updated target.
818  * The benefit of it is that if caller asked us to drop last target, then
819  * the device is removed and not dangling
820  */
821  if (LinkHandle != 0)
822  {
823  Status = NtMakeTemporaryObject(LinkHandle);
824  NtClose(LinkHandle);
825  LinkHandle = 0;
826  }
827 
828  /* At this point, we must have no failure */
829  if (!NT_SUCCESS(Status))
830  {
831  _SEH2_LEAVE;
832  }
833 
834  /*
835  * If we have to remove definition, let's start to browse our
836  * target to actually drop it.
837  */
838  if (RemoveDefinition)
839  {
840  /* We'll browse our multi sz string */
841  RemoveFound = FALSE;
842  CurrentPtr = LinkTarget.Buffer;
843  InterPtr = LinkTarget.Buffer;
844  while (*CurrentPtr != UNICODE_NULL)
845  {
846  CchLength = 0;
847  OrigPtr = CurrentPtr;
848  /* First, find next string */
849  while (TRUE)
850  {
851  CurrentChar = *CurrentPtr;
852  ++CurrentPtr;
853 
854  if (CurrentChar == UNICODE_NULL)
855  {
856  break;
857  }
858 
859  ++CchLength;
860  }
861 
862  /* This check is a bit tricky, but dead useful:
863  * If on the previous loop, we found the caller provided target
864  * in our list, then, we'll move current entry over the found one
865  * So that, it gets deleted.
866  * Also, if we don't find caller entry in our entries, then move
867  * current entry in the string if a previous one got deleted
868  */
869  if (RemoveFound ||
870  ((!(DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
871  TargetLength != CchLength || _wcsicmp(OrigPtr, TargetBuffer) != 0) &&
872  ((DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
873  (TargetLength != 0 && _wcsnicmp(OrigPtr, TargetBuffer, TargetLength) != 0))))
874  {
875  if (InterPtr != OrigPtr)
876  {
877  RtlMoveMemory(InterPtr, OrigPtr, sizeof(WCHAR) * CchLength + sizeof(UNICODE_NULL));
878  }
879 
880  InterPtr += (CchLength + 1);
881  }
882  else
883  {
884  /* Match case! Remember for next loop turn and to delete it */
885  RemoveFound = TRUE;
886  }
887  }
888 
889  /*
890  * Drop last entry, as required (pop)
891  * If there was a match previously, everything
892  * is already moved, so we're just nulling
893  * the end of the string
894  * If there was no match, this is the pop
895  */
896  *InterPtr = UNICODE_NULL;
897  ++InterPtr;
898 
899  /* Compute new target length */
900  TargetLength = wcslen(LinkTarget.Buffer) * sizeof(WCHAR);
901  /*
902  * If it's empty, quit
903  * Beware, here, we quit with STATUS_SUCCESS, and that's expected!
904  * In case we dropped last target entry, then, it's empty
905  * and there's no need to recreate the device we deleted previously
906  */
907  if (TargetLength == 0)
908  {
909  _SEH2_LEAVE;
910  }
911 
912  /* Update our target string */
913  LinkTarget.Length = TargetLength;
915  }
916  /* If that's not a removal, just update the target to include new target */
917  else if (HandleTarget)
918  {
919  LinkTarget.Buffer = LinkTarget.Buffer - TargetLength - 1;
920  LinkTarget.Length = TargetLength * sizeof(WCHAR);
921  LinkTarget.MaximumLength += (TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
922  TargetLength *= sizeof(WCHAR);
923  }
924  /* No changes */
925  else
926  {
927  TargetLength = LinkTarget.Length;
928  }
929 
930  /* Make sure we don't create empty symlink */
931  if (TargetLength == 0)
932  {
933  _SEH2_LEAVE;
934  }
935 
936  /* Initialize our SIDs for symlink ACLs */
938  1,
947  &WorldSid);
948  if (!NT_SUCCESS(Status))
949  {
950  _SEH2_LEAVE;
951  }
952 
954  1,
963  &SystemSid);
964  if (!NT_SUCCESS(Status))
965  {
967  _SEH2_LEAVE;
968  }
969 
970  /* Initialize our SD (on stack) */
973 
974  /* And our ACL (still on stack) */
975  RtlCreateAcl(&Dacl.Dacl, sizeof(Dacl), ACL_REVISION);
976 
977  /*
978  * For access mask, if we have no session ID, or if
979  * protection mode is disabled, make them wide open
980  */
981  if (SessionId == 0 ||
982  (ProtectionMode & 3) == 0)
983  {
985  }
986  else
987  {
989  }
990 
991  /* Setup the ACL */
994 
995  /* Drop SIDs */
997  RtlFreeSid(SystemSid);
998 
999  /* Link DACL to the SD */
1001 
1002  /* And set it in the OA used for creation */
1003  ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
1004 
1005  /*
1006  * If LUID and not global, we need to impersonate the caller
1007  * to make it local.
1008  */
1010  {
1011  if (!IsGlobal)
1012  {
1013  if (!CsrImpersonateClient(NULL))
1014  {
1016  _SEH2_LEAVE;
1017  }
1018  }
1019  }
1020  /* The object will be permanent */
1021  else
1022  {
1023  ObjectAttributes.Attributes |= OBJ_PERMANENT;
1024  }
1025 
1026  /* (Re)Create the symbolic link/device */
1027  Status = NtCreateSymbolicLinkObject(&LinkHandle,
1030  &LinkTarget);
1031 
1032  /* Revert to self if required */
1033  if (BaseStaticServerData->LUIDDeviceMapsEnabled && !IsGlobal)
1034  {
1035  CsrRevertToSelf();
1036  }
1037 
1038  /* In case of a success, make object permanent for LUID links */
1039  if (NT_SUCCESS(Status))
1040  {
1042  {
1043  Status = NtMakePermanentObject(LinkHandle);
1044  }
1045 
1046  /* Close the link */
1047  NtClose(LinkHandle);
1048 
1049  /*
1050  * Specific failure case here:
1051  * We were asked to remove something
1052  * but we didn't find the something
1053  * (we recreated the symlink hence the fail here!)
1054  * so fail with appropriate status
1055  */
1056  if (RemoveDefinition && !RemoveFound)
1057  {
1059  }
1060  }
1061 
1062  /* We closed link, don't double close */
1063  LinkHandle = 0;
1064  }
1066  {
1067  /* If we need to close the link, do it now */
1068  if (LinkHandle != 0)
1069  {
1070  NtClose(LinkHandle);
1071  }
1072 
1073  /* Free our internal buffer */
1075 
1076  /* Broadcast drive letter creation */
1077  if (DriveLetter && Status == STATUS_SUCCESS && Broadcast)
1078  {
1079  LUID SystemLuid = SYSTEM_LUID;
1080 
1081  /* If that's a global drive, broadcast as system */
1082  if (IsGlobal)
1083  {
1084  RtlCopyLuid(&CallerLuid, &SystemLuid);
1085  }
1086 
1087  /* Broadcast the event */
1088  AddBSMRequest(AbsLetter, RemoveDefinition, &CallerLuid);
1089 
1090  /*
1091  * If we removed drive, and the drive was shadowing a global one
1092  * broadcast the arrival of the global drive (as system - global)
1093  */
1094  if (RemoveDefinition && !RtlEqualLuid(&CallerLuid, &SystemLuid))
1095  {
1096  if (CheckForGlobalDriveLetter(AbsLetter))
1097  {
1098  AddBSMRequest(AbsLetter, FALSE, &CallerLuid);
1099  }
1100  }
1101  }
1102 
1103  /* Done! */
1105  }
1106  _SEH2_END;
1107 
1108  return Status;
1109 }
1110 
1111 /* EOF */
LUID AuthenticationId
Definition: setypes.h:1033
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 TRUE
Definition: types.h:120
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:387
NTSTATUS NTAPI LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, IN PULONG DllCharacteristics OPTIONAL, IN PUNICODE_STRING DllName, OUT PVOID *DllHandle)
Definition: ldrapi.c:805
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
USHORT MaximumLength
Definition: env_spec_w32.h:370
_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:505
uint16_t * PWSTR
Definition: typedefs.h:54
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:507
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:1315
#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:1048
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
LPDWORD
Definition: dosdev.c:30
#define OBJ_PERMANENT
Definition: winternl.h:226
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
WCHAR DeviceName[]
Definition: adapter.cpp:21
#define BSF_NOHANG
Definition: dbt.h:56
NTSYSAPI void WINAPI RtlCopyLuid(PLUID, const LUID *)
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
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAce(PACL, DWORD, DWORD, PSID)
WPARAM wParam
Definition: combotst.c:138
VOID BaseCleanupDefineDosDevice(VOID)
Definition: dosdev.c:39
struct TraceInfo Info
NTSTATUS NTAPI NtMakePermanentObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1422
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
_SEH2_TRY
Definition: create.c:4250
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
uint32_t ULONG_PTR
Definition: typedefs.h:63
_In_ NDIS_HANDLE _In_ PNDIS_REQUEST Request
Definition: ndis.h:5173
#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
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
LONG DriveLetter
Definition: dosdev.c:20
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,...)
smooth NULL
Definition: ftsmooth.c:416
_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:1839
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
LONG_PTR LPARAM
Definition: windef.h:208
void DPRINT(...)
Definition: polytest.cpp:61
_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
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
#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:8
_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
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define STATUS_NO_TOKEN
Definition: ntstatus.h:346
#define DBT_DEVTYP_VOLUME
Definition: dbt.h:21
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#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:1553
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
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)
#define SYSTEM_LUID
Definition: setypes.h:672
LPARAM
Definition: dosdev.c:30
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
Status
Definition: gdiplustypes.h:24
CSR_API(BaseSrvDefineDosDevice)
Definition: dosdev.c:474
HANDLE BaseSrvHeap
Definition: init.c:29
struct _BSM_REQUEST BSM_REQUEST
_SEH2_END
Definition: create.c:4424
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:246
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:859
static PVOID CurrentBuffer
_SEH2_FINALLY
Definition: create.c:4395
#define DDD_LUID_BROADCAST_DRIVE
Definition: winbase.h:508
NTSTATUS CreateBSMThread(VOID)
Definition: dosdev.c:369
#define SECURITY_RESTRICTED_CODE_RID
Definition: setypes.h:541
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
struct _DEV_BROADCAST_VOLUME DEV_BROADCAST_VOLUME
#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
NTSTATUS NTAPI NtOpenThreadToken(IN HANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN OpenAsSelf, OUT PHANDLE TokenHandle)
Definition: token.c:3858
#define BSM_ALLDESKTOPS
Definition: dbt.h:49
uint32_t * LPDWORD
Definition: typedefs.h:57
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:114
PBSMINFO
Definition: dosdev.c:30
BOOLEAN NTAPI CsrImpersonateClient(IN PCSR_THREAD CsrThread)
Definition: procsup.c:925
#define ULONG_PTR
Definition: config.h:101
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define _SEH2_LEAVE
Definition: filesup.c:20
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
return STATUS_SUCCESS
Definition: btrfs.c:2938
NTSTATUS GetCallerLuid(PLUID CallerLuid)
Definition: dosdev.c:45
LPARAM lParam
Definition: combotst.c:139
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
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:506
static SID_IDENTIFIER_AUTHORITY SystemAuthority
Definition: msgina.c:38
UINT
Definition: dosdev.c:30
VOID BaseInitDefineDosDevice(VOID)
Definition: dosdev.c:34