ReactOS 0.4.15-dev-5664-g3bf4ef6
dosdev.c File Reference
#include "basesrv.h"
#include <debug.h>
Include dependency graph for dosdev.c:

Go to the source code of this file.

Classes

struct  _BSM_REQUEST
 

Macros

#define NDEBUG
 

Typedefs

typedef struct _BSM_REQUEST BSM_REQUEST
 
typedef struct _BSM_REQUESTPBSM_REQUEST
 

Functions

 LONG (WINAPI *PBROADCASTSYSTEMMESSAGEEXW)(DWORD
 
VOID BaseInitDefineDosDevice (VOID)
 
VOID BaseCleanupDefineDosDevice (VOID)
 
NTSTATUS GetCallerLuid (PLUID CallerLuid)
 
NTSTATUS IsGlobalSymbolicLink (HANDLE LinkHandle, PBOOLEAN IsGlobal)
 
BOOLEAN CheckForGlobalDriveLetter (SHORT DriveLetter)
 
NTSTATUS SendWinStationBSM (DWORD Flags, LPDWORD Recipients, UINT Message, WPARAM wParam, LPARAM lParam)
 
NTSTATUS BroadcastDriveLetterChange (LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
 
ULONG NTAPI BaseSrvBSMThread (PVOID StartupContext)
 
NTSTATUS CreateBSMThread (VOID)
 
NTSTATUS AddBSMRequest (LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
 
 CSR_API (BaseSrvDefineDosDevice)
 

Variables

static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
 
RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec
 
PBSM_REQUEST BSM_Request_Queue = NULL
 
PBSM_REQUEST BSM_Request_Queue_End = NULL
 
ULONG BaseSrvpBSMThreadCount = 0
 
 LPDWORD
 
 UINT
 
 WPARAM
 
 LPARAM
 
 PBSMINFO = NULL
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 13 of file dosdev.c.

Typedef Documentation

◆ BSM_REQUEST

◆ PBSM_REQUEST

Function Documentation

◆ AddBSMRequest()

NTSTATUS AddBSMRequest ( LONG  DriveLetter,
BOOLEAN  RemoveDefinition,
PLUID  BroadcastLuid 
)

Definition at line 391 of file dosdev.c.

394{
395 LUID CallerLuid;
397 LUID SystemLuid = SYSTEM_LUID;
399
400 /* We need a broadcast LUID */
401 if (BroadcastLuid == NULL)
402 {
404 }
405
406 /*
407 * If LUID mappings are not enabled, this call makes no sense
408 * It should not happen though
409 */
411 {
413 }
414
415 /* Get our caller LUID (not the broadcaster!) */
416 Status = GetCallerLuid(&CallerLuid);
417 if (!NT_SUCCESS(Status))
418 {
419 return Status;
420 }
421
422 /* System cannot create LUID mapped drives - thus broadcast makes no sense */
423 if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
424 {
426 }
427
428 /* Allocate our request */
430 if (Request == NULL)
431 {
432 return STATUS_NO_MEMORY;
433 }
434
435 /* Initialize it */
436 Request->DriveLetter = DriveLetter;
437 Request->RemoveDefinition = RemoveDefinition;
438 RtlCopyLuid(&Request->BroadcastLuid, BroadcastLuid);
439 Request->Next = NULL;
440
441 /* And queue it */
443
444 /* At the end of the queue if not empty */
446 {
448 }
449 /* Otherwise, initialize the queue */
450 else
451 {
453 }
454
455 /* We're in FIFO mode */
457
458 /* If we don't have a messaging thread running, then start one */
459 if (BaseSrvpBSMThreadCount >= 1)
460 {
462 }
463 else
464 {
467 }
468
469 return Status;
470}
LONG NTSTATUS
Definition: precomp.h:26
HANDLE BaseSrvHeap
Definition: init.c:29
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
Status
Definition: gdiplustypes.h:25
NTSYSAPI void WINAPI RtlCopyLuid(PLUID, const LUID *)
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
BOOLEAN LUIDDeviceMapsEnabled
Definition: base.h:141
struct _BSM_REQUEST * Next
Definition: dosdev.c:18
NTSTATUS GetCallerLuid(PLUID CallerLuid)
Definition: dosdev.c:45
ULONG BaseSrvpBSMThreadCount
Definition: dosdev.c:29
PBSM_REQUEST BSM_Request_Queue
Definition: dosdev.c:28
RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec
Definition: dosdev.c:27
NTSTATUS CreateBSMThread(VOID)
Definition: dosdev.c:369
PBSM_REQUEST BSM_Request_Queue_End
Definition: dosdev.c:28
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
#define SYSTEM_LUID
Definition: setypes.h:700

Referenced by CSR_API().

◆ BaseCleanupDefineDosDevice()

VOID BaseCleanupDefineDosDevice ( VOID  )

Definition at line 39 of file dosdev.c.

40{
42}
NTSYSAPI NTSTATUS NTAPI RtlDeleteCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
Definition: dosdev.c:26

Referenced by DllMain().

◆ BaseInitDefineDosDevice()

VOID BaseInitDefineDosDevice ( VOID  )

Definition at line 34 of file dosdev.c.

35{
37}
NTSYSAPI NTSTATUS NTAPI RtlInitializeCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)

Referenced by CSR_SERVER_DLL_INIT().

◆ BaseSrvBSMThread()

ULONG NTAPI BaseSrvBSMThread ( PVOID  StartupContext)

Definition at line 314 of file dosdev.c.

315{
318 PBSM_REQUEST CurrentRequest;
319
320 /* We have a thread */
321 ExitStatus = 0;
324
325 while (TRUE)
326 {
327 /* If we flushed the queue, job done */
328 if (BSM_Request_Queue == NULL)
329 {
330 break;
331 }
332
333 /* Queue current request, and remove it from the queue */
334 CurrentRequest = BSM_Request_Queue;
336
337 /* If that was the last request, NULLify queue end */
338 if (BSM_Request_Queue == NULL)
339 {
341 }
342
344
345 /* Broadcast the message */
347 CurrentRequest->RemoveDefinition,
348 &CurrentRequest->BroadcastLuid);
349
350 /* Reflect the last entry status on stop */
351 CurrentRequest->Next = NULL;
353
354 RtlFreeHeap(BaseSrvHeap, 0, CurrentRequest);
356 }
357
358 /* Here, we've flushed the queue, quit the user thread */
361
362 NtCurrentTeb()->FreeStackOnTermination = TRUE;
364
365 return ExitStatus;
366}
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
#define TRUE
Definition: types.h:120
#define NtCurrentTeb
unsigned int ULONG
Definition: retypes.h:1
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:859
NTSTATUS NtTerminateThread(IN HANDLE ThreadHandle OPTIONAL, IN NTSTATUS ExitStatus)
Definition: kill.c:1279
LONG DriveLetter
Definition: dosdev.c:20
LONG RemoveDefinition
Definition: dosdev.c:21
LUID BroadcastLuid
Definition: dosdev.c:19
NTSTATUS BroadcastDriveLetterChange(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:226
#define NtCurrentThread()

Referenced by CreateBSMThread().

◆ BroadcastDriveLetterChange()

NTSTATUS BroadcastDriveLetterChange ( LONG  DriveLetter,
BOOLEAN  RemoveDefinition,
PLUID  BroadcastLuid 
)

Definition at line 226 of file dosdev.c.

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;
275 RtlCopyLuid(&Info.luid, BroadcastLuid);
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}
WPARAM wParam
Definition: combotst.c:138
#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
unsigned long DWORD
Definition: ntddk_ex.h:95
NTSTATUS NTAPI LdrGetProcedureAddress(IN PVOID BaseAddress, IN PANSI_STRING Name, IN ULONG Ordinal, OUT PVOID *ProcedureAddress)
Definition: ldrapi.c:823
NTSTATUS NTAPI LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, IN PULONG DllCharacteristics OPTIONAL, IN PUNICODE_STRING DllName, OUT PVOID *DllHandle)
Definition: ldrapi.c:805
UNICODE_STRING Volume
Definition: fltkernel.h:1172
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define L(x)
Definition: ntvdm.h:50
NTSTATUS SendWinStationBSM(DWORD Flags, LPDWORD Recipients, UINT Message, WPARAM wParam, LPARAM lParam)
Definition: dosdev.c:215
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
LONG_PTR LPARAM
Definition: windef.h:208
#define WM_DEVICECHANGE
Definition: winuser.h:1801
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

Referenced by BaseSrvBSMThread().

◆ CheckForGlobalDriveLetter()

BOOLEAN CheckForGlobalDriveLetter ( SHORT  DriveLetter)

Definition at line 162 of file dosdev.c.

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}
unsigned char BOOLEAN
PRTL_UNICODE_STRING_BUFFER Path
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
BOOLEAN NTAPI CsrImpersonateClient(IN PCSR_THREAD CsrThread)
Definition: procsup.c:932
BOOLEAN NTAPI CsrRevertToSelf(VOID)
Definition: procsup.c:1057
#define FALSE
Definition: types.h:117
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define UNICODE_NULL
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
NTSTATUS IsGlobalSymbolicLink(HANDLE LinkHandle, PBOOLEAN IsGlobal)
Definition: dosdev.c:96
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by CSR_API().

◆ CreateBSMThread()

NTSTATUS CreateBSMThread ( VOID  )

Definition at line 369 of file dosdev.c.

370{
371 /* This can only be true for LUID mappings */
373 {
375 }
376
377 /* Create our user thread */
379 NULL,
380 FALSE,
381 0,
382 0,
383 0,
385 NULL,
386 NULL,
387 NULL);
388}
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 NtCurrentProcess()
Definition: nt_native.h:1657
ULONG NTAPI BaseSrvBSMThread(PVOID StartupContext)
Definition: dosdev.c:314

Referenced by AddBSMRequest().

◆ CSR_API()

CSR_API ( BaseSrvDefineDosDevice  )

Definition at line 474 of file dosdev.c.

475{
477 PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.DefineDosDeviceRequest;
479 HANDLE LinkHandle;
485 PSID SystemSid;
489 SHORT AbsLetter;
490 BOOLEAN DriveLetter = FALSE;
491 BOOLEAN RemoveDefinition;
492 BOOLEAN HandleTarget;
493 BOOLEAN Broadcast = FALSE;
494 BOOLEAN IsGlobal = FALSE;
495 ULONG CchLengthLeft;
496 ULONG CchLength;
497 ULONG TargetLength;
498 PWSTR TargetBuffer;
500 /* We store them on the stack, they are known in advance */
501 union {
503 UCHAR Buffer[20];
505 union {
506 ACL Dacl;
507 UCHAR Buffer[256];
508 } Dacl;
510 LUID CallerLuid;
511 WCHAR * CurrentPtr;
512 WCHAR CurrentChar;
513 PWSTR OrigPtr;
514 PWSTR InterPtr;
515 BOOLEAN RemoveFound;
516
517 if (!CsrValidateMessageBuffer(ApiMessage,
518 (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer,
519 DefineDosDeviceRequest->DeviceName.Length,
520 sizeof(BYTE)) ||
521 (DefineDosDeviceRequest->DeviceName.Length & 1) != 0 ||
522 !CsrValidateMessageBuffer(ApiMessage,
523 (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer,
524 DefineDosDeviceRequest->TargetPath.Length +
525 (DefineDosDeviceRequest->TargetPath.Length != 0
526 ? sizeof(UNICODE_NULL) : 0),
527 sizeof(BYTE)) ||
528 (DefineDosDeviceRequest->TargetPath.Length & 1) != 0)
529 {
531 }
532
533 DPRINT("BaseSrvDefineDosDevice entered, Flags:%d, DeviceName:%wZ (%d), TargetPath:%wZ (%d)\n",
534 DefineDosDeviceRequest->Flags,
535 &DefineDosDeviceRequest->DeviceName,
536 DefineDosDeviceRequest->DeviceName.Length,
537 &DefineDosDeviceRequest->TargetPath,
538 DefineDosDeviceRequest->TargetPath.Length);
539
540 /*
541 * Allocate a buffer big enough to contain:
542 * - device name
543 * - targets
544 */
546 if (lpBuffer == NULL)
547 {
548 return STATUS_NO_MEMORY;
549 }
550
551 /* Enter our critical section */
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
556 Status);
558 return Status;
559 }
560
561 LinkHandle = 0;
562 /* Does the caller wants to remove definition? */
563 RemoveDefinition = !!(DefineDosDeviceRequest->Flags & DDD_REMOVE_DEFINITION);
565 {
566 /* First of all, check if that's a drive letter device amongst LUID mappings */
567 if (BaseStaticServerData->LUIDDeviceMapsEnabled && !(DefineDosDeviceRequest->Flags & DDD_NO_BROADCAST_SYSTEM))
568 {
569 if (DefineDosDeviceRequest->DeviceName.Buffer != NULL &&
570 DefineDosDeviceRequest->DeviceName.Length == 2 * sizeof(WCHAR) &&
571 DefineDosDeviceRequest->DeviceName.Buffer[1] == L':')
572 {
573 Letter = DefineDosDeviceRequest->DeviceName.Buffer[0];
574
575 /* Handle both lower cases and upper cases */
576 AbsLetter = Letter - L'a';
577 if (AbsLetter < 26 && AbsLetter >= 0)
578 {
580 }
581
582 AbsLetter = Letter - L'A';
583 if (AbsLetter < 26)
584 {
585 /* That's a letter! */
586 DriveLetter = TRUE;
587 }
588 }
589 }
590
591 /* We can only broadcast drive letters in case of LUID mappings */
592 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE &&
593 !DriveLetter)
594 {
597 }
598
599 /* First usage of our buffer: create device name */
600 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\??\\%wZ", &DefineDosDeviceRequest->DeviceName);
601 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
602 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
604
605 /* And prepare to open it */
607 &DeviceName,
609 NULL,
610 NULL);
611
612 /* Assume it's OK and has a target to deal with */
613 HandleTarget = TRUE;
614
615 /* Move to the client context if the mapping was local */
617 {
620 }
621
622 /*
623 * While impersonating the caller, also get its LUID.
624 * This is mandatory in case we have a driver letter,
625 * Because we're in the case we've got LUID mapping
626 * enabled and broadcasting enabled. LUID will be required
627 * for the latter
628 */
629 if (DriveLetter)
630 {
631 Status = GetCallerLuid(&CallerLuid);
632 if (NT_SUCCESS(Status))
633 {
634 Broadcast = TRUE;
635 }
636 }
637
638 /* Now, open the device */
639 Status = NtOpenSymbolicLinkObject(&LinkHandle,
642
643 /* And get back to our context */
645
646 /* In case of LUID broadcast, do nothing but return to trigger broadcast */
647 if (DefineDosDeviceRequest->Flags & DDD_LUID_BROADCAST_DRIVE)
648 {
649 /* Zero handle in case of a failure */
650 if (!NT_SUCCESS(Status))
651 {
652 LinkHandle = 0;
653 }
654
655 /* If removal was asked, and no object found: the remval was successful */
656 if (RemoveDefinition && Status == STATUS_OBJECT_NAME_NOT_FOUND)
657 {
659 }
660
661 /* We're done here, nothing more to do */
663 }
664
665 /* If device was not found */
667 {
668 /* No handle */
669 LinkHandle = 0;
670
671 /* If we were asked to remove... */
672 if (RemoveDefinition)
673 {
674 /*
675 * If caller asked to pop first entry, nothing specific,
676 * then, we can consider this as a success
677 */
678 if (DefineDosDeviceRequest->TargetPath.Length == 0)
679 {
681 }
682
683 /* We're done, nothing to change */
685 }
686
687 /* There's no target to handle */
688 HandleTarget = FALSE;
689
690 /*
691 * We'll consider, that's a success
692 * Failing to open the device doesn't prevent
693 * from creating it later on to create
694 * the linking.
695 */
697 }
698 else
699 {
700 /* Unexpected failure, forward to caller */
701 if (!NT_SUCCESS(Status))
702 {
704 }
705
706 /* If LUID mapping enabled */
708 {
709 /* Check if that's global link */
710 Status = IsGlobalSymbolicLink(LinkHandle, &IsGlobal);
711 if (!NT_SUCCESS(Status))
712 {
714 }
715
716 /* If so, change our device name namespace to GLOBAL?? for link creation */
717 if (IsGlobal)
718 {
719 CchLength = _snwprintf(lpBuffer, 0x1000, L"\\GLOBAL??\\%wZ", &DefineDosDeviceRequest->DeviceName);
720 CchLengthLeft = 0x1000 - 1 - CchLength; /* UNICODE_NULL */
721 CurrentBuffer = lpBuffer + CchLength + 1; /* UNICODE_NULL */
722
723 DeviceName.Length = CchLength * sizeof(WCHAR);
724 DeviceName.MaximumLength = CchLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
725 }
726 }
727 }
728
729 /* If caller provided a target */
730 if (DefineDosDeviceRequest->TargetPath.Length != 0)
731 {
732 /* Make sure it's null terminated */
733 DefineDosDeviceRequest->TargetPath.Buffer[DefineDosDeviceRequest->TargetPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
734
735 /* Compute its size */
736 TargetLength = wcslen(DefineDosDeviceRequest->TargetPath.Buffer);
737
738 /* And make sure it fits our buffer */
739 if (TargetLength + 1 >= CchLengthLeft)
740 {
743 }
744
745 /* Copy it to our internal buffer */
746 RtlMoveMemory(CurrentBuffer, DefineDosDeviceRequest->TargetPath.Buffer, TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
747 TargetBuffer = CurrentBuffer;
748
749 /* Update our buffer status */
750 CchLengthLeft -= (TargetLength + 1);
751 CurrentBuffer += (TargetLength + 1);
752 }
753 /* Otherwise, zero everything */
754 else
755 {
756 TargetBuffer = NULL;
757 TargetLength = 0;
758 }
759
760 /* If we opened the device, then, handle its current target */
761 if (HandleTarget)
762 {
763 /* Query it with our internal buffer */
764 LinkTarget.Length = 0;
765 LinkTarget.MaximumLength = CchLengthLeft * sizeof(WCHAR);
767
769 &LinkTarget,
770 &Length);
771 /* If we overflow, give up */
773 {
775 }
776 /* In case of a failure, bye bye */
777 if (!NT_SUCCESS(Status))
778 {
780 }
781
782 /*
783 * Properly null it for MULTI_SZ if needed
784 * Always update max length with
785 * the need size
786 * This is needed to hand relatively "small"
787 * strings to Ob and avoid killing ourselves
788 * on the next query
789 */
790 CchLength = Length / sizeof(WCHAR);
791 if (CchLength < 2 ||
792 CurrentBuffer[CchLength - 2] != UNICODE_NULL ||
793 CurrentBuffer[CchLength - 1] != UNICODE_NULL)
794 {
795 CurrentBuffer[CchLength] = UNICODE_NULL;
797 }
798 else
799 {
801 }
802 }
803 /* There's no target, and we're asked to remove, so null target */
804 else if (RemoveDefinition)
805 {
807 }
808 /* There's a target provided - new device, update buffer */
809 else
810 {
811 RtlInitUnicodeString(&LinkTarget, CurrentBuffer - TargetLength - 1);
812 }
813
814 /*
815 * We no longer need old symlink, just drop it, we'll recreate it now
816 * with updated target.
817 * The benefit of it is that if caller asked us to drop last target, then
818 * the device is removed and not dangling
819 */
820 if (LinkHandle != 0)
821 {
822 Status = NtMakeTemporaryObject(LinkHandle);
823 NtClose(LinkHandle);
824 LinkHandle = 0;
825 }
826
827 /* At this point, we must have no failure */
828 if (!NT_SUCCESS(Status))
829 {
831 }
832
833 /*
834 * If we have to remove definition, let's start to browse our
835 * target to actually drop it.
836 */
837 if (RemoveDefinition)
838 {
839 /* We'll browse our multi sz string */
840 RemoveFound = FALSE;
841 CurrentPtr = LinkTarget.Buffer;
842 InterPtr = LinkTarget.Buffer;
843 while (*CurrentPtr != UNICODE_NULL)
844 {
845 CchLength = 0;
846 OrigPtr = CurrentPtr;
847 /* First, find next string */
848 while (TRUE)
849 {
850 CurrentChar = *CurrentPtr;
851 ++CurrentPtr;
852
853 if (CurrentChar == UNICODE_NULL)
854 {
855 break;
856 }
857
858 ++CchLength;
859 }
860
861 /* This check is a bit tricky, but dead useful:
862 * If on the previous loop, we found the caller provided target
863 * in our list, then, we'll move current entry over the found one
864 * So that, it gets deleted.
865 * Also, if we don't find caller entry in our entries, then move
866 * current entry in the string if a previous one got deleted
867 */
868 if (RemoveFound ||
869 ((!(DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
870 TargetLength != CchLength || _wcsicmp(OrigPtr, TargetBuffer) != 0) &&
871 ((DefineDosDeviceRequest->Flags & DDD_EXACT_MATCH_ON_REMOVE) ||
872 (TargetLength != 0 && _wcsnicmp(OrigPtr, TargetBuffer, TargetLength) != 0))))
873 {
874 if (InterPtr != OrigPtr)
875 {
876 RtlMoveMemory(InterPtr, OrigPtr, sizeof(WCHAR) * CchLength + sizeof(UNICODE_NULL));
877 }
878
879 InterPtr += (CchLength + 1);
880 }
881 else
882 {
883 /* Match case! Remember for next loop turn and to delete it */
884 RemoveFound = TRUE;
885 }
886 }
887
888 /*
889 * Drop last entry, as required (pop)
890 * If there was a match previously, everything
891 * is already moved, so we're just nulling
892 * the end of the string
893 * If there was no match, this is the pop
894 */
895 *InterPtr = UNICODE_NULL;
896 ++InterPtr;
897
898 /* Compute new target length */
899 TargetLength = wcslen(LinkTarget.Buffer) * sizeof(WCHAR);
900 /*
901 * If it's empty, quit
902 * Beware, here, we quit with STATUS_SUCCESS, and that's expected!
903 * In case we dropped last target entry, then, it's empty
904 * and there's no need to recreate the device we deleted previously
905 */
906 if (TargetLength == 0)
907 {
909 }
910
911 /* Update our target string */
912 LinkTarget.Length = TargetLength;
914 }
915 /* If that's not a removal, just update the target to include new target */
916 else if (HandleTarget)
917 {
918 LinkTarget.Buffer = LinkTarget.Buffer - TargetLength - 1;
919 LinkTarget.Length = TargetLength * sizeof(WCHAR);
920 LinkTarget.MaximumLength += (TargetLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
921 TargetLength *= sizeof(WCHAR);
922 }
923 /* No changes */
924 else
925 {
926 TargetLength = LinkTarget.Length;
927 }
928
929 /* Make sure we don't create empty symlink */
930 if (TargetLength == 0)
931 {
933 }
934
935 /* Initialize our SIDs for symlink ACLs */
937 1,
946 &WorldSid);
947 if (!NT_SUCCESS(Status))
948 {
950 }
951
953 1,
962 &SystemSid);
963 if (!NT_SUCCESS(Status))
964 {
967 }
968
969 /* Initialize our SD (on stack) */
972
973 /* And our ACL (still on stack) */
975
976 /*
977 * For access mask, if we have no session ID, or if
978 * protection mode is disabled, make them wide open
979 */
980 if (SessionId == 0 ||
981 (ProtectionMode & 3) == 0)
982 {
984 }
985 else
986 {
988 }
989
990 /* Setup the ACL */
993
994 /* Drop SIDs */
996 RtlFreeSid(SystemSid);
997
998 /* Link DACL to the SD */
1000
1001 /* And set it in the OA used for creation */
1002 ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
1003
1004 /*
1005 * If LUID and not global, we need to impersonate the caller
1006 * to make it local.
1007 */
1009 {
1010 if (!IsGlobal)
1011 {
1013 {
1016 }
1017 }
1018 }
1019 /* The object will be permanent */
1020 else
1021 {
1022 ObjectAttributes.Attributes |= OBJ_PERMANENT;
1023 }
1024
1025 /* (Re)Create the symbolic link/device */
1026 Status = NtCreateSymbolicLinkObject(&LinkHandle,
1029 &LinkTarget);
1030
1031 /* Revert to self if required */
1033 {
1035 }
1036
1037 /* In case of a success, make object permanent for LUID links */
1038 if (NT_SUCCESS(Status))
1039 {
1041 {
1042 Status = NtMakePermanentObject(LinkHandle);
1043 }
1044
1045 /* Close the link */
1046 NtClose(LinkHandle);
1047
1048 /*
1049 * Specific failure case here:
1050 * We were asked to remove something
1051 * but we didn't find the something
1052 * (we recreated the symlink hence the fail here!)
1053 * so fail with appropriate status
1054 */
1055 if (RemoveDefinition && !RemoveFound)
1056 {
1058 }
1059 }
1060
1061 /* We closed link, don't double close */
1062 LinkHandle = 0;
1063 }
1065 {
1066 /* If we need to close the link, do it now */
1067 if (LinkHandle != 0)
1068 {
1069 NtClose(LinkHandle);
1070 }
1071
1072 /* Free our internal buffer */
1074
1075 /* Broadcast drive letter creation */
1076 if (DriveLetter && Status == STATUS_SUCCESS && Broadcast)
1077 {
1078 LUID SystemLuid = SYSTEM_LUID;
1079
1080 /* If that's a global drive, broadcast as system */
1081 if (IsGlobal)
1082 {
1083 RtlCopyLuid(&CallerLuid, &SystemLuid);
1084 }
1085
1086 /* Broadcast the event */
1087 AddBSMRequest(AbsLetter, RemoveDefinition, &CallerLuid);
1088
1089 /*
1090 * If we removed drive, and the drive was shadowing a global one
1091 * broadcast the arrival of the global drive (as system - global)
1092 */
1093 if (RemoveDefinition && !RtlEqualLuid(&CallerLuid, &SystemLuid))
1094 {
1095 if (CheckForGlobalDriveLetter(AbsLetter))
1096 {
1097 AddBSMRequest(AbsLetter, FALSE, &CallerLuid);
1098 }
1099 }
1100 }
1101
1102 /* Done! */
1104 }
1105 _SEH2_END;
1106
1107 return Status;
1108}
static ACPI_BUFFER CurrentBuffer
WCHAR Letter
#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
Definition: bufpool.h:45
BOOLEAN NTAPI CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, IN PVOID *Buffer, IN ULONG ElementCount, IN ULONG ElementSize)
Definition: api.c:1430
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:175
ULONG SessionId
Definition: dllmain.c:28
static SID_IDENTIFIER_AUTHORITY WorldAuthority
Definition: security.c:14
#define ULONG_PTR
Definition: config.h:101
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define _SEH2_LEAVE
Definition: filesup.c:20
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OBJ_PERMANENT
Definition: winternl.h:226
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAce(PACL, DWORD, DWORD, PSID)
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
static SID_IDENTIFIER_AUTHORITY SystemAuthority
Definition: msgina.c:38
_In_ ACCESS_MASK AccessMask
Definition: exfuncs.h:186
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL Dacl
Definition: rtlfuncs.h:1593
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
NTSYSAPI PVOID NTAPI RtlFreeSid(_In_ _Post_invalid_ PSID Sid)
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:176
#define SYMBOLIC_LINK_ALL_ACCESS
Definition: nt_native.h:1267
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define DELETE
Definition: nt_native.h:57
_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
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
NTSTATUS NTAPI NtMakePermanentObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1422
NTSTATUS NTAPI NtMakeTemporaryObject(IN HANDLE ObjectHandle)
Definition: oblife.c:1385
short SHORT
Definition: pedump.c:59
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
#define DPRINT
Definition: sndvol32.h:71
UNICODE_STRING TargetPath
Definition: basemsg.h:257
UNICODE_STRING DeviceName
Definition: basemsg.h:256
USHORT MaximumLength
Definition: env_spec_w32.h:370
NTSTATUS AddBSMRequest(LONG DriveLetter, BOOLEAN RemoveDefinition, PLUID BroadcastLuid)
Definition: dosdev.c:391
BOOLEAN CheckForGlobalDriveLetter(SHORT DriveLetter)
Definition: dosdev.c:162
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
#define DDD_NO_BROADCAST_SYSTEM
Definition: winbase.h:526
#define DDD_EXACT_MATCH_ON_REMOVE
Definition: winbase.h:525
#define DDD_LUID_BROADCAST_DRIVE
Definition: winbase.h:527
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:524
_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 SECURITY_WORLD_SID_AUTHORITY
Definition: setypes.h:527
#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
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
#define ACL_REVISION
Definition: setypes.h:39
unsigned char UCHAR
Definition: xmlstorage.h:181
unsigned char BYTE
Definition: xxhash.c:193
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292

◆ GetCallerLuid()

NTSTATUS GetCallerLuid ( PLUID  CallerLuid)

Definition at line 45 of file dosdev.c.

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}
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:718
#define READ_CONTROL
Definition: nt_native.h:58
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:2281
#define STATUS_NO_TOKEN
Definition: ntstatus.h:360
LUID AuthenticationId
Definition: setypes.h:1083
_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
#define TOKEN_QUERY
Definition: setypes.h:924
@ TokenStatistics
Definition: setypes.h:971

Referenced by AddBSMRequest(), and CSR_API().

◆ IsGlobalSymbolicLink()

NTSTATUS IsGlobalSymbolicLink ( HANDLE  LinkHandle,
PBOOLEAN  IsGlobal 
)

Definition at line 96 of file dosdev.c.

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}
@ ObjectNameInformation
Definition: DriverTester.h:55
NTSTATUS NtQueryObject(IN HANDLE Handle, IN OBJECT_INFO_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength)
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
UNICODE_STRING Name
Definition: nt_native.h:1270
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133

Referenced by CheckForGlobalDriveLetter(), and CSR_API().

◆ LONG()

LONG ( WINAPI PBROADCASTSYSTEMMESSAGEEXW)

◆ SendWinStationBSM()

NTSTATUS SendWinStationBSM ( DWORD  Flags,
LPDWORD  Recipients,
UINT  Message,
WPARAM  wParam,
LPARAM  lParam 
)

Definition at line 215 of file dosdev.c.

220{
223}
#define UNIMPLEMENTED
Definition: debug.h:115
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239

Referenced by BroadcastDriveLetterChange().

Variable Documentation

◆ BaseDefineDosDeviceCritSec

RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
static

Definition at line 26 of file dosdev.c.

Referenced by BaseCleanupDefineDosDevice(), BaseInitDefineDosDevice(), and CSR_API().

◆ BaseSrvDDDBSMCritSec

RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec

Definition at line 27 of file dosdev.c.

Referenced by AddBSMRequest(), BaseInitializeStaticServerData(), and BaseSrvBSMThread().

◆ BaseSrvpBSMThreadCount

ULONG BaseSrvpBSMThreadCount = 0

Definition at line 29 of file dosdev.c.

Referenced by AddBSMRequest(), and BaseSrvBSMThread().

◆ BSM_Request_Queue

PBSM_REQUEST BSM_Request_Queue = NULL

Definition at line 28 of file dosdev.c.

Referenced by AddBSMRequest(), and BaseSrvBSMThread().

◆ BSM_Request_Queue_End

PBSM_REQUEST BSM_Request_Queue_End = NULL

Definition at line 28 of file dosdev.c.

Referenced by AddBSMRequest(), and BaseSrvBSMThread().

◆ LPARAM

Definition at line 30 of file dosdev.c.

◆ LPDWORD

Definition at line 30 of file dosdev.c.

◆ PBSMINFO

PBSMINFO = NULL

Definition at line 30 of file dosdev.c.

◆ UINT

Definition at line 30 of file dosdev.c.

◆ WPARAM

Definition at line 30 of file dosdev.c.