[TASKMGR] Process page: Allow using "Open File Location" functionality without runnin...
[reactos.git] / drivers / filesystems / mup / mup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/mup/mup.c
23 * PURPOSE: Multi UNC Provider
24 * PROGRAMMER: Eric Kohl
25 * Pierre Schweitzer (pierre@reactos.org)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "mup.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 ERESOURCE MupGlobalLock;
36 ERESOURCE MupPrefixTableLock;
37 ERESOURCE MupCcbListLock;
38 ERESOURCE MupVcbLock;
39 LIST_ENTRY MupProviderList;
40 LIST_ENTRY MupPrefixList;
41 LIST_ENTRY MupMasterQueryList;
42 UNICODE_PREFIX_TABLE MupPrefixTable;
43 LARGE_INTEGER MupKnownPrefixTimeout;
44 ULONG MupProviderCount;
45 BOOLEAN MupOrderInitialized;
46 BOOLEAN MupEnableDfs;
47 PDEVICE_OBJECT mupDeviceObject;
48 NTSTATUS MupOrderedErrorList[] = { STATUS_UNSUCCESSFUL,
49 STATUS_INVALID_PARAMETER,
50 STATUS_REDIRECTOR_NOT_STARTED,
51 STATUS_BAD_NETWORK_NAME,
52 STATUS_BAD_NETWORK_PATH, 0 };
53
54 /* FUNCTIONS ****************************************************************/
55
56 CODE_SEG("INIT")
57 VOID
58 MupInitializeData(VOID)
59 {
60 ExInitializeResourceLite(&MupGlobalLock);
61 ExInitializeResourceLite(&MupPrefixTableLock);
62 ExInitializeResourceLite(&MupCcbListLock);
63 ExInitializeResourceLite(&MupVcbLock);
64 MupProviderCount = 0;
65 InitializeListHead(&MupProviderList);
66 InitializeListHead(&MupPrefixList);
67 InitializeListHead(&MupMasterQueryList);
68 RtlInitializeUnicodePrefix(&MupPrefixTable);
69 MupKnownPrefixTimeout.QuadPart = 9000000000LL;
70 MupOrderInitialized = FALSE;
71 }
72
73 VOID
74 MupUninitializeData()
75 {
76 ExDeleteResourceLite(&MupGlobalLock);
77 ExDeleteResourceLite(&MupPrefixTableLock);
78 ExDeleteResourceLite(&MupCcbListLock);
79 ExDeleteResourceLite(&MupVcbLock);
80 }
81
82 CODE_SEG("INIT")
83 VOID
84 MupInitializeVcb(PMUP_VCB Vcb)
85 {
86 RtlZeroMemory(Vcb, sizeof(MUP_VCB));
87 Vcb->NodeType = NODE_TYPE_VCB;
88 Vcb->NodeStatus = NODE_STATUS_HEALTHY;
89 Vcb->NodeReferences = 1;
90 Vcb->NodeSize = sizeof(MUP_VCB);
91 }
92
93 BOOLEAN
94 MuppIsDfsEnabled(VOID)
95 {
96 HANDLE Key;
97 ULONG Length;
98 NTSTATUS Status;
99 UNICODE_STRING KeyName;
100 OBJECT_ATTRIBUTES ObjectAttributes;
101 struct
102 {
103 KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
104 ULONG KeyValue;
105 } KeyQueryOutput;
106
107 /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
108 KeyName.Buffer = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
109 KeyName.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL);
110 KeyName.MaximumLength = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
111
112 /* Simply query registry to know whether we have to disable DFS.
113 * Unless explicitly stated in registry, we will try to enable DFS.
114 */
115 InitializeObjectAttributes(&ObjectAttributes,
116 &KeyName,
117 OBJ_CASE_INSENSITIVE,
118 NULL,
119 NULL);
120
121 Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes);
122 if (!NT_SUCCESS(Status))
123 {
124 return TRUE;
125 }
126
127 KeyName.Buffer = L"DisableDfs";
128 KeyName.Length = sizeof(L"DisableDfs") - sizeof(UNICODE_NULL);
129 KeyName.MaximumLength = sizeof(L"DisableDfs");
130
131 Status = ZwQueryValueKey(Key, &KeyName, KeyValuePartialInformation, &KeyQueryOutput, sizeof(KeyQueryOutput), &Length);
132 ZwClose(Key);
133 if (!NT_SUCCESS(Status) || KeyQueryOutput.KeyInfo.Type != REG_DWORD)
134 {
135 return TRUE;
136 }
137
138 return ((ULONG_PTR)KeyQueryOutput.KeyInfo.Data != 1);
139 }
140
141 VOID
142 MupCalculateTimeout(PLARGE_INTEGER EntryTime)
143 {
144 LARGE_INTEGER CurrentTime;
145
146 /* Just get now + our allowed timeout */
147 KeQuerySystemTime(&CurrentTime);
148 EntryTime->QuadPart = CurrentTime.QuadPart + MupKnownPrefixTimeout.QuadPart;
149 }
150
151 PMUP_CCB
152 MupCreateCcb(VOID)
153 {
154 PMUP_CCB Ccb;
155
156 Ccb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_CCB), TAG_MUP);
157 if (Ccb == NULL)
158 {
159 return NULL;
160 }
161
162 Ccb->NodeStatus = NODE_STATUS_HEALTHY;
163 Ccb->NodeReferences = 1;
164 Ccb->NodeType = NODE_TYPE_CCB;
165 Ccb->NodeSize = sizeof(MUP_CCB);
166
167 return Ccb;
168 }
169
170 PMUP_FCB
171 MupCreateFcb(VOID)
172 {
173 PMUP_FCB Fcb;
174
175 Fcb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_FCB), TAG_MUP);
176 if (Fcb == NULL)
177 {
178 return NULL;
179 }
180
181 Fcb->NodeStatus = NODE_STATUS_HEALTHY;
182 Fcb->NodeReferences = 1;
183 Fcb->NodeType = NODE_TYPE_FCB;
184 Fcb->NodeSize = sizeof(MUP_FCB);
185 InitializeListHead(&Fcb->CcbList);
186
187 return Fcb;
188 }
189
190 PMUP_MIC
191 MupAllocateMasterIoContext(VOID)
192 {
193 PMUP_MIC MasterIoContext;
194
195 MasterIoContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MIC), TAG_MUP);
196 if (MasterIoContext == NULL)
197 {
198 return NULL;
199 }
200
201 MasterIoContext->NodeStatus = NODE_STATUS_HEALTHY;
202 MasterIoContext->NodeReferences = 1;
203 MasterIoContext->NodeType = NODE_TYPE_MIC;
204 MasterIoContext->NodeSize = sizeof(MUP_MIC);
205
206 return MasterIoContext;
207 }
208
209 PMUP_UNC
210 MupAllocateUncProvider(ULONG RedirectorDeviceNameLength)
211 {
212 PMUP_UNC UncProvider;
213
214 UncProvider = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_UNC) + RedirectorDeviceNameLength, TAG_MUP);
215 if (UncProvider == NULL)
216 {
217 return NULL;
218 }
219
220 UncProvider->NodeReferences = 0;
221 UncProvider->NodeType = NODE_TYPE_UNC;
222 UncProvider->NodeStatus = NODE_STATUS_HEALTHY;
223 UncProvider->NodeSize = sizeof(MUP_UNC) + RedirectorDeviceNameLength;
224 UncProvider->Registered = FALSE;
225
226 return UncProvider;
227 }
228
229 PMUP_PFX
230 MupAllocatePrefixEntry(ULONG PrefixLength)
231 {
232 PMUP_PFX Prefix;
233 ULONG PrefixSize;
234
235 PrefixSize = sizeof(MUP_PFX) + PrefixLength;
236 Prefix = ExAllocatePoolWithTag(PagedPool, PrefixSize, TAG_MUP);
237 if (Prefix == NULL)
238 {
239 return NULL;
240 }
241
242 RtlZeroMemory(Prefix, PrefixSize);
243 Prefix->NodeType = NODE_TYPE_PFX;
244 Prefix->NodeStatus = NODE_STATUS_HEALTHY;
245 Prefix->NodeReferences = 1;
246 Prefix->NodeSize = PrefixSize;
247
248 /* If we got a prefix, initialize the string */
249 if (PrefixLength != 0)
250 {
251 Prefix->AcceptedPrefix.Buffer = (PVOID)((ULONG_PTR)Prefix + sizeof(MUP_PFX));
252 Prefix->AcceptedPrefix.Length = PrefixLength;
253 Prefix->AcceptedPrefix.MaximumLength = PrefixLength;
254 }
255 /* Otherwise, mark the fact that the allocation will be external */
256 else
257 {
258 Prefix->ExternalAlloc = TRUE;
259 }
260
261 Prefix->KeepExtraRef = FALSE;
262 /* Already init timeout to have one */
263 MupCalculateTimeout(&Prefix->ValidityTimeout);
264
265 return Prefix;
266 }
267
268 PMUP_MQC
269 MupAllocateMasterQueryContext(VOID)
270 {
271 PMUP_MQC MasterQueryContext;
272
273 MasterQueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MQC), TAG_MUP);
274 if (MasterQueryContext == NULL)
275 {
276 return NULL;
277 }
278
279 MasterQueryContext->NodeStatus = NODE_STATUS_HEALTHY;
280 MasterQueryContext->NodeReferences = 1;
281 MasterQueryContext->NodeType = NODE_TYPE_MQC;
282 MasterQueryContext->NodeSize = sizeof(MUP_MQC);
283 InitializeListHead(&MasterQueryContext->QueryPathList);
284 InitializeListHead(&MasterQueryContext->MQCListEntry);
285 ExInitializeResourceLite(&MasterQueryContext->QueryPathListLock);
286
287 return MasterQueryContext;
288 }
289
290 ULONG
291 MupDecodeFileObject(PFILE_OBJECT FileObject, PMUP_FCB * pFcb, PMUP_CCB * pCcb)
292 {
293 ULONG Type;
294 PMUP_FCB Fcb;
295
296 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
297 *pFcb = FileObject->FsContext;
298 *pCcb = FileObject->FsContext2;
299 Fcb = *pFcb;
300
301 if (Fcb == NULL)
302 {
303 ExReleaseResourceLite(&MupGlobalLock);
304 return 0;
305 }
306
307 Type = Fcb->NodeType;
308 if ((Type != NODE_TYPE_VCB && Type != NODE_TYPE_FCB) || (Fcb->NodeStatus != NODE_STATUS_HEALTHY && Fcb->NodeStatus != NODE_STATUS_CLEANUP))
309 {
310 *pFcb = 0;
311 ExReleaseResourceLite(&MupGlobalLock);
312 return 0;
313 }
314
315 ++Fcb->NodeReferences;
316 ExReleaseResourceLite(&MupGlobalLock);
317
318 return Type;
319 }
320
321 VOID
322 MupFreeNode(PVOID Node)
323 {
324 ExFreePoolWithTag(Node, TAG_MUP);
325 }
326
327 VOID
328 MupDereferenceFcb(PMUP_FCB Fcb)
329 {
330 /* Just dereference and delete if no references left */
331 if (InterlockedDecrement(&Fcb->NodeReferences) == 0)
332 {
333 MupFreeNode(Fcb);
334 }
335 }
336
337 VOID
338 MupDereferenceCcb(PMUP_CCB Ccb)
339 {
340 /* Just dereference and delete (and clean) if no references left */
341 if (InterlockedDecrement(&Ccb->NodeReferences) == 0)
342 {
343 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
344 RemoveEntryList(&Ccb->CcbListEntry);
345 ExReleaseResourceLite(&MupCcbListLock);
346 ObDereferenceObject(Ccb->FileObject);
347 MupDereferenceFcb(Ccb->Fcb);
348 MupFreeNode(Ccb);
349 }
350 }
351
352 VOID
353 MupDereferenceVcb(PMUP_VCB Vcb)
354 {
355 /* We cannot reach the point where no references are left */
356 if (InterlockedDecrement(&Vcb->NodeReferences) == 0)
357 {
358 KeBugCheckEx(FILE_SYSTEM, 3, 0, 0, 0);
359 }
360 }
361
362 NTSTATUS
363 MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext,
364 PNTSTATUS NewStatus)
365 {
366 PIRP Irp;
367 NTSTATUS Status;
368 PIO_STACK_LOCATION Stack;
369
370 Status = STATUS_SUCCESS;
371
372 if (NewStatus != NULL)
373 {
374 /* Save last status, depending on whether it failed or not */
375 if (!NT_SUCCESS(*NewStatus))
376 {
377 MasterIoContext->LastFailed = *NewStatus;
378 }
379 else
380 {
381 MasterIoContext->LastSuccess = STATUS_SUCCESS;
382 }
383 }
384
385 if (InterlockedDecrement(&MasterIoContext->NodeReferences) != 0)
386 {
387 return STATUS_PENDING;
388 }
389
390 Irp = MasterIoContext->Irp;
391 Stack = IoGetCurrentIrpStackLocation(Irp);
392 if (Stack->MajorFunction == IRP_MJ_WRITE)
393 {
394 Irp->IoStatus.Information = Stack->Parameters.Write.Length;
395 }
396 else
397 {
398 Irp->IoStatus.Information = 0;
399 }
400
401 /* In case we never had any success (init is a failure), get the last failed status */
402 if (!NT_SUCCESS(MasterIoContext->LastSuccess))
403 {
404 Status = MasterIoContext->LastFailed;
405 }
406
407 Irp->IoStatus.Status = Status;
408 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
409 MupDereferenceFcb(MasterIoContext->Fcb);
410 MupFreeNode(MasterIoContext);
411
412 return Status;
413 }
414
415 VOID
416 MupDereferenceUncProvider(PMUP_UNC UncProvider)
417 {
418 InterlockedExchangeAdd(&UncProvider->NodeReferences, -1);
419 }
420
421 VOID
422 MupDereferenceKnownPrefix(PMUP_PFX Prefix)
423 {
424 /* Just dereference and delete (and clean) if no references left */
425 if (InterlockedDecrement(&Prefix->NodeReferences) == 0)
426 {
427 if (Prefix->InTable)
428 {
429 RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry);
430 RemoveEntryList(&Prefix->PrefixListEntry);
431 }
432
433 if (Prefix->ExternalAlloc && Prefix->AcceptedPrefix.Buffer != NULL)
434 {
435 ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP);
436 }
437
438 if (Prefix->UncProvider)
439 {
440 MupDereferenceUncProvider(Prefix->UncProvider);
441 }
442
443 MupFreeNode(Prefix);
444 }
445 }
446
447 VOID
448 MupRemoveKnownPrefixEntry(PMUP_PFX Prefix)
449 {
450 RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry);
451 RemoveEntryList(&Prefix->PrefixListEntry);
452 Prefix->InTable = FALSE;
453 MupDereferenceKnownPrefix(Prefix);
454 }
455
456 VOID
457 MupInvalidatePrefixTable(VOID)
458 {
459 PMUP_PFX Prefix;
460 PLIST_ENTRY Entry;
461
462 /* Browse the prefix table */
463 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
464 for (Entry = MupPrefixList.Flink;
465 Entry != &MupPrefixList;
466 Entry = Entry->Flink)
467 {
468 Prefix = CONTAINING_RECORD(Entry, MUP_PFX, PrefixListEntry);
469
470 /* And remove any entry in it */
471 if (Prefix->InTable)
472 {
473 MupRemoveKnownPrefixEntry(Prefix);
474 }
475 }
476 ExReleaseResourceLite(&MupPrefixTableLock);
477 }
478
479 VOID
480 MupCleanupVcb(PDEVICE_OBJECT DeviceObject,
481 PIRP Irp,
482 PMUP_VCB Vcb)
483 {
484 ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE);
485
486 /* Check we're not doing anything wrong first */
487 if (Vcb->NodeStatus != NODE_STATUS_HEALTHY || Vcb->NodeType != NODE_TYPE_VCB)
488 {
489 ExRaiseStatus(STATUS_INVALID_HANDLE);
490 }
491
492 /* Remove share access */
493 IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp)->FileObject, &Vcb->ShareAccess);
494
495 ExReleaseResourceLite(&MupVcbLock);
496 }
497
498 VOID
499 MupCleanupFcb(PDEVICE_OBJECT DeviceObject,
500 PIRP Irp,
501 PMUP_FCB Fcb)
502 {
503 PLIST_ENTRY Entry;
504 PMUP_CCB Ccb;
505
506 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
507 /* Check we're not doing anything wrong first */
508 if (Fcb->NodeStatus != NODE_STATUS_HEALTHY || Fcb->NodeType != NODE_TYPE_FCB)
509 {
510 ExRaiseStatus(STATUS_INVALID_HANDLE);
511 }
512 Fcb->NodeStatus = NODE_STATUS_CLEANUP;
513 ExReleaseResourceLite(&MupGlobalLock);
514
515 /* Dereference any CCB associated with the FCB */
516 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
517 for (Entry = Fcb->CcbList.Flink;
518 Entry != &Fcb->CcbList;
519 Entry = Entry->Flink)
520 {
521 Ccb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry);
522 ExReleaseResourceLite(&MupCcbListLock);
523 MupDereferenceCcb(Ccb);
524 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
525 }
526 ExReleaseResourceLite(&MupCcbListLock);
527 }
528
529 NTSTATUS
530 CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,
531 PIRP Irp,
532 PFORWARDED_IO_CONTEXT FwdCtxt)
533 {
534 NTSTATUS Status;
535
536 Status = Irp->IoStatus.Status;
537
538 /* Just free everything we had allocated */
539 if (Irp->MdlAddress != NULL)
540 {
541 MmUnlockPages(Irp->MdlAddress);
542 IoFreeMdl(Irp->MdlAddress);
543 }
544
545 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
546 {
547 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_MUP);
548 }
549
550 IoFreeIrp(Irp);
551
552 /* Dereference the master context
553 * The upper IRP will be completed once all the lower IRPs are done
554 * (and thus, references count reaches 0)
555 */
556 MupDereferenceCcb(FwdCtxt->Ccb);
557 MupDereferenceMasterIoContext(FwdCtxt->MasterIoContext, &Status);
558 ExFreePoolWithTag(FwdCtxt, TAG_MUP);
559
560 return STATUS_MORE_PROCESSING_REQUIRED;
561 }
562
563 VOID
564 NTAPI
565 DeferredForwardedIoCompletionRoutine(PVOID Context)
566 {
567 PFORWARDED_IO_CONTEXT FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
568
569 CommonForwardedIoCompletionRoutine(FwdCtxt->DeviceObject, FwdCtxt->Irp, Context);
570 }
571
572 NTSTATUS
573 NTAPI
574 ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,
575 PIRP Irp,
576 PVOID Context)
577 {
578 PFORWARDED_IO_CONTEXT FwdCtxt;
579
580 /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
581 if (KeGetCurrentIrql() < DISPATCH_LEVEL)
582 {
583 CommonForwardedIoCompletionRoutine(DeviceObject, Irp, Context);
584 }
585 else
586 {
587 FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
588
589 ExInitializeWorkItem(&FwdCtxt->WorkQueueItem, DeferredForwardedIoCompletionRoutine, Context);
590 ExQueueWorkItem(&FwdCtxt->WorkQueueItem, CriticalWorkQueue);
591 }
592
593 return STATUS_MORE_PROCESSING_REQUIRED;
594 }
595
596 NTSTATUS
597 BuildAndSubmitIrp(PIRP Irp,
598 PMUP_CCB Ccb,
599 PMUP_MIC MasterIoContext)
600 {
601 PMDL Mdl;
602 PIRP LowerIrp;
603 NTSTATUS Status;
604 PIO_STACK_LOCATION Stack;
605 PDEVICE_OBJECT DeviceObject;
606 PFORWARDED_IO_CONTEXT FwdCtxt;
607
608 Status = STATUS_SUCCESS;
609 LowerIrp = NULL;
610 Mdl = NULL;
611
612 /* Allocate a context for the completion routine */
613 FwdCtxt = ExAllocatePoolWithTag(NonPagedPool, sizeof(FORWARDED_IO_CONTEXT), TAG_MUP);
614 if (FwdCtxt == NULL)
615 {
616 Status = STATUS_INSUFFICIENT_RESOURCES;
617 goto Cleanup;
618 }
619
620 /* Init it */
621 FwdCtxt->DeviceObject = NULL;
622 FwdCtxt->Irp = NULL;
623
624 /* Allocate the IRP */
625 DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject);
626 LowerIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
627 if (LowerIrp == NULL)
628 {
629 Status = STATUS_INSUFFICIENT_RESOURCES;
630 goto Cleanup;
631 }
632
633 /* Initialize it */
634 LowerIrp->Tail.Overlay.OriginalFileObject = Ccb->FileObject;
635 LowerIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
636 LowerIrp->RequestorMode = KernelMode;
637
638 /* Copy the stack of the request we received to the IRP we'll pass below */
639 Stack = IoGetNextIrpStackLocation(LowerIrp);
640 RtlMoveMemory(Stack, IoGetCurrentIrpStackLocation(Irp), sizeof(IO_STACK_LOCATION));
641 Stack->FileObject = Ccb->FileObject;
642 /* Setup flags according to the FO */
643 if (Ccb->FileObject->Flags & FO_WRITE_THROUGH)
644 {
645 Stack->Flags = SL_WRITE_THROUGH;
646 }
647
648 _SEH2_TRY
649 {
650 /* Does the device requires we do buffered IOs? */
651 if (DeviceObject->Flags & DO_BUFFERED_IO)
652 {
653 LowerIrp->AssociatedIrp.SystemBuffer = NULL;
654
655 if (Stack->Parameters.Write.Length == 0)
656 {
657 LowerIrp->Flags = IRP_BUFFERED_IO;
658 }
659 /* If we have data to pass */
660 else
661 {
662 /* If it's coming from usermode, probe first */
663 if (Irp->RequestorMode == UserMode)
664 {
665 ProbeForRead(Irp->UserBuffer, Stack->Parameters.Write.Length, sizeof(UCHAR));
666 }
667
668 /* Allocate the buffer */
669 LowerIrp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned,
670 Stack->Parameters.Write.Length,
671 TAG_MUP);
672 if (LowerIrp->AssociatedIrp.SystemBuffer == NULL)
673 {
674 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
675 }
676
677 /* And copy input (remember, we've to free!) */
678 RtlMoveMemory(LowerIrp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, Stack->Parameters.Write.Length);
679 LowerIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
680 }
681 }
682 else
683 {
684 if (!(DeviceObject->Flags & DO_DIRECT_IO))
685 {
686 LowerIrp->UserBuffer = Irp->UserBuffer;
687 }
688 else
689 {
690 /* For direct IOs, allocate an MDL and pass it */
691 if (Stack->Parameters.Write.Length != 0)
692 {
693 Mdl = IoAllocateMdl(Irp->UserBuffer, Stack->Parameters.Write.Length, FALSE, TRUE, LowerIrp);
694 if (Mdl == NULL)
695 {
696 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
697 }
698
699 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoReadAccess);
700 }
701 }
702 }
703
704 /* Fix flags in the IRP */
705 if (Ccb->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
706 {
707 LowerIrp->Flags |= IRP_WRITE_OPERATION | IRP_NOCACHE;
708 }
709 else
710 {
711 LowerIrp->Flags |= IRP_WRITE_OPERATION;
712 }
713
714 FwdCtxt->Ccb = Ccb;
715 FwdCtxt->MasterIoContext = MasterIoContext;
716
717 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
718 ++MasterIoContext->NodeReferences;
719 ExReleaseResourceLite(&MupGlobalLock);
720
721 /* Set out completion routine */
722 IoSetCompletionRoutine(LowerIrp, ForwardedIoCompletionRoutine, FwdCtxt, TRUE, TRUE, TRUE);
723 /* And call the device with our brand new IRP */
724 Status = IoCallDriver(Ccb->DeviceObject, LowerIrp);
725 }
726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
727 {
728 Status = _SEH2_GetExceptionCode();
729 }
730 _SEH2_END;
731
732 Cleanup:
733 if (!NT_SUCCESS(Status))
734 {
735 if (FwdCtxt != NULL)
736 {
737 ExFreePoolWithTag(FwdCtxt, TAG_MUP);
738 }
739
740 if (LowerIrp != NULL)
741 {
742 if (LowerIrp->AssociatedIrp.SystemBuffer == NULL)
743 {
744 ExFreePoolWithTag(LowerIrp->AssociatedIrp.SystemBuffer, TAG_MUP);
745 }
746
747 IoFreeIrp(LowerIrp);
748 }
749
750 if (Mdl != NULL)
751 {
752 IoFreeMdl(Mdl);
753 }
754 }
755
756 return Status;
757 }
758
759 NTSTATUS
760 NTAPI
761 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject,
762 PIRP Irp)
763 {
764 PMUP_FCB Fcb;
765 PMUP_CCB Ccb;
766 NTSTATUS Status;
767 PLIST_ENTRY Entry;
768 PMUP_CCB FcbListCcb;
769 BOOLEAN CcbLockAcquired;
770 PMUP_MIC MasterIoContext;
771 PIO_STACK_LOCATION Stack;
772
773 /* If DFS is enabled, check if that's for DFS and is so relay */
774 if (MupEnableDfs && DeviceObject->DeviceType == FILE_DEVICE_DFS)
775 {
776 return DfsVolumePassThrough(DeviceObject, Irp);
777 }
778
779 Stack = IoGetCurrentIrpStackLocation(Irp);
780
781 FsRtlEnterFileSystem();
782
783 /* Write request is only possible for a mailslot, we need a FCB */
784 MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
785 if (Fcb == NULL || Fcb->NodeType != NODE_TYPE_FCB)
786 {
787 FsRtlExitFileSystem();
788 Status = STATUS_INVALID_DEVICE_REQUEST;
789 goto Complete;
790 }
791
792 /* Allocate a context */
793 MasterIoContext = MupAllocateMasterIoContext();
794 if (MasterIoContext == NULL)
795 {
796 FsRtlExitFileSystem();
797 Status = STATUS_INSUFFICIENT_RESOURCES;
798 goto Complete;
799 }
800
801 /* Mark the IRP pending and init the context */
802 IoMarkIrpPending(Irp);
803 MasterIoContext->Irp = Irp;
804 /* Init with a failure to catch if we ever succeed */
805 MasterIoContext->LastSuccess = STATUS_UNSUCCESSFUL;
806 /* Init with the worth failure possible */
807 MasterIoContext->LastFailed = STATUS_BAD_NETWORK_PATH;
808 MasterIoContext->Fcb = Fcb;
809
810 _SEH2_TRY
811 {
812 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
813 CcbLockAcquired = TRUE;
814
815 /* For all the CCB (ie, the mailslots) we have */
816 for (Entry = Fcb->CcbList.Flink;
817 Entry != &Fcb->CcbList;
818 Entry = Entry->Flink)
819 {
820 FcbListCcb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry);
821 ExReleaseResourceLite(&MupCcbListLock);
822 CcbLockAcquired = FALSE;
823
824 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
825 ++FcbListCcb->NodeReferences;
826 ExReleaseResourceLite(&MupGlobalLock);
827
828 /* Forward the write request */
829 BuildAndSubmitIrp(Irp, FcbListCcb, MasterIoContext);
830 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
831 CcbLockAcquired = TRUE;
832 }
833
834 ExReleaseResourceLite(&MupCcbListLock);
835 CcbLockAcquired = FALSE;
836 }
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
838 {
839 if (CcbLockAcquired)
840 {
841 ExReleaseResourceLite(&MupCcbListLock);
842 }
843 }
844 _SEH2_END;
845
846 /* And done */
847 MupDereferenceMasterIoContext(MasterIoContext, NULL);
848 FsRtlExitFileSystem();
849
850 return STATUS_PENDING;
851
852 Complete:
853 /* Failure case */
854 Irp->IoStatus.Status = Status;
855 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
856 return Status;
857 }
858
859 PMUP_UNC
860 AddUnregisteredProvider(PCWSTR DeviceName,
861 ULONG ProviderOrder)
862 {
863 PMUP_UNC UncProvider;
864 ULONG StrLen, NameLen;
865
866 /* Just allocate the node */
867 NameLen = wcslen(DeviceName);
868 StrLen = NameLen * sizeof(WCHAR);
869 UncProvider = MupAllocateUncProvider(StrLen);
870 if (UncProvider == NULL)
871 {
872 return NULL;
873 }
874
875 /* And init it */
876 UncProvider->DeviceName.MaximumLength = StrLen;
877 UncProvider->DeviceName.Length = StrLen;
878 UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC));
879 UncProvider->ProviderOrder = ProviderOrder;
880 RtlMoveMemory(UncProvider->DeviceName.Buffer, DeviceName, StrLen);
881
882 /* And add it to the global list
883 * We're using tail here so that when called from registry init,
884 * the providers with highest priority will be in the head of
885 * the list
886 */
887 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
888 InsertTailList(&MupProviderList, &UncProvider->ProviderListEntry);
889 ExReleaseResourceLite(&MupGlobalLock);
890
891 return UncProvider;
892 }
893
894 VOID
895 InitializeProvider(PCWSTR ProviderName,
896 ULONG ProviderOrder)
897 {
898 NTSTATUS Status;
899 HANDLE KeyHandle;
900 UNICODE_STRING Key, Value;
901 PKEY_VALUE_FULL_INFORMATION Info;
902 OBJECT_ATTRIBUTES ObjectAttributes;
903 ULONG NameLen, StrLen, ResultLength;
904
905 /* Get the information about the provider from registry */
906 NameLen = wcslen(ProviderName);
907 StrLen = NameLen * sizeof(WCHAR) + sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L"\\NetworkProvider");
908 Key.Buffer = ExAllocatePoolWithTag(PagedPool, StrLen, TAG_MUP);
909 if (Key.Buffer == NULL)
910 {
911 return;
912 }
913
914 RtlMoveMemory(Key.Buffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
915 Key.MaximumLength = StrLen;
916 Key.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL);
917 RtlAppendUnicodeToString(&Key, ProviderName);
918 RtlAppendUnicodeToString(&Key, L"\\NetworkProvider");
919
920 InitializeObjectAttributes(&ObjectAttributes,
921 &Key,
922 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
923 NULL,
924 NULL);
925 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
926 ExFreePoolWithTag(Key.Buffer, TAG_MUP);
927 if (!NT_SUCCESS(Status))
928 {
929 return;
930 }
931
932 RtlInitUnicodeString(&Value, L"DeviceName");
933 Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, NULL, 0, &ResultLength);
934 if (Status == STATUS_BUFFER_TOO_SMALL)
935 {
936 Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP);
937 if (Info == NULL)
938 {
939 ZwClose(KeyHandle);
940 return;
941 }
942
943 Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, Info, ResultLength, &ResultLength);
944 }
945 else
946 {
947 Info = NULL;
948 }
949
950 ZwClose(KeyHandle);
951
952 /* And create the provider
953 * It will remain unregistered until FsRTL receives a registration request and forwards
954 * it to MUP
955 */
956 if (NT_SUCCESS(Status))
957 {
958 ASSERT(Info != NULL);
959 AddUnregisteredProvider((PWSTR)((ULONG_PTR)Info + Info->DataOffset), ProviderOrder);
960 }
961
962 if (Info != NULL)
963 {
964 ExFreePoolWithTag(Info, TAG_MUP);
965 }
966 }
967
968 VOID
969 MupGetProviderInformation(VOID)
970 {
971 BOOLEAN End;
972 NTSTATUS Status;
973 HANDLE KeyHandle;
974 PWSTR Providers, Coma;
975 PKEY_VALUE_FULL_INFORMATION Info;
976 ULONG ResultLength, ProviderCount;
977 OBJECT_ATTRIBUTES ObjectAttributes;
978 UNICODE_STRING NetworkProvider, ProviderOrder;
979
980 /* Open the registry to get the order of the providers */
981 RtlInitUnicodeString(&NetworkProvider, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
982 InitializeObjectAttributes(&ObjectAttributes,
983 &NetworkProvider,
984 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
985 NULL,
986 NULL);
987 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
988 if (!NT_SUCCESS(Status))
989 {
990 return;
991 }
992
993 RtlInitUnicodeString(&ProviderOrder, L"ProviderOrder");
994 Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, NULL, 0, &ResultLength);
995 if (Status == STATUS_BUFFER_TOO_SMALL)
996 {
997 Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP);
998 if (Info == NULL)
999 {
1000 ZwClose(KeyHandle);
1001 return;
1002 }
1003
1004 Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, Info, ResultLength, &ResultLength);
1005 }
1006 else
1007 {
1008 Info = NULL;
1009 }
1010
1011 ZwClose(KeyHandle);
1012
1013 if (NT_SUCCESS(Status))
1014 {
1015 ASSERT(Info != NULL);
1016
1017 Providers = (PWSTR)((ULONG_PTR)Info + Info->DataOffset);
1018 End = FALSE;
1019 ProviderCount = 0;
1020
1021 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1022 * The order is just the order of the list
1023 * First has highest priority (0) and then, get lower and lower priority
1024 * The highest number is the lowest priority
1025 */
1026 do
1027 {
1028 Coma = wcschr(Providers, L',');
1029 if (Coma != NULL)
1030 {
1031 *Coma = UNICODE_NULL;
1032 }
1033 else
1034 {
1035 End = TRUE;
1036 }
1037
1038 InitializeProvider(Providers, ProviderCount);
1039 ++ProviderCount;
1040
1041 Providers = Coma + 1;
1042 } while (!End);
1043 }
1044
1045 if (Info != NULL)
1046 {
1047 ExFreePoolWithTag(Info, TAG_MUP);
1048 }
1049 }
1050
1051 PMUP_UNC
1052 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName)
1053 {
1054 PLIST_ENTRY Entry;
1055 PMUP_UNC UncProvider;
1056
1057 /* Browse the list of all the providers nodes we have */
1058 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1059 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink)
1060 {
1061 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
1062
1063 /* If one matches the device and is not registered, that's ours! */
1064 if (!UncProvider->Registered && RtlEqualUnicodeString(RedirectorDeviceName, &UncProvider->DeviceName, TRUE))
1065 {
1066 UncProvider->NodeStatus = NODE_STATUS_HEALTHY;
1067 break;
1068 }
1069 }
1070
1071 if (Entry == &MupProviderList)
1072 {
1073 UncProvider = NULL;
1074 }
1075 ExReleaseResourceLite(&MupGlobalLock);
1076
1077 return UncProvider;
1078 }
1079
1080 NTSTATUS
1081 RegisterUncProvider(PDEVICE_OBJECT DeviceObject,
1082 PIRP Irp)
1083
1084 {
1085 BOOLEAN New;
1086 PMUP_FCB Fcb;
1087 PMUP_CCB Ccb;
1088 NTSTATUS Status;
1089 PLIST_ENTRY Entry;
1090 PIO_STACK_LOCATION Stack;
1091 IO_STATUS_BLOCK IoStatusBlock;
1092 PMUP_UNC UncProvider, ListEntry;
1093 OBJECT_ATTRIBUTES ObjectAttributes;
1094 UNICODE_STRING RedirectorDeviceName;
1095 OBJECT_HANDLE_INFORMATION HandleInfo;
1096 PMUP_PROVIDER_REGISTRATION_INFO RegInfo;
1097
1098 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject, Irp);
1099 New = FALSE;
1100
1101 /* Check whether providers order was already initialized */
1102 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1103 if (MupOrderInitialized)
1104 {
1105 ExReleaseResourceLite(&MupGlobalLock);
1106 }
1107 else
1108 {
1109 /* They weren't, so do it */
1110 MupOrderInitialized = TRUE;
1111 ExReleaseResourceLite(&MupGlobalLock);
1112 MupGetProviderInformation();
1113 }
1114
1115 Stack = IoGetCurrentIrpStackLocation(Irp);
1116
1117 /* This can only happen with a volume open */
1118 if (MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb) != NODE_TYPE_VCB)
1119 {
1120 Irp->IoStatus.Status = STATUS_INVALID_HANDLE;
1121 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1122
1123 return STATUS_INVALID_HANDLE;
1124 }
1125
1126 /* Get the registration information */
1127 RegInfo = (PMUP_PROVIDER_REGISTRATION_INFO)Irp->AssociatedIrp.SystemBuffer;
1128 _SEH2_TRY
1129 {
1130 RedirectorDeviceName.Length = RegInfo->RedirectorDeviceNameLength;
1131 RedirectorDeviceName.MaximumLength = RedirectorDeviceName.Length;
1132 RedirectorDeviceName.Buffer = (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset);
1133
1134 /* Have we got already a node for it? (Like from previous init) */
1135 UncProvider = MupCheckForUnregisteredProvider(&RedirectorDeviceName);
1136 if (UncProvider == NULL)
1137 {
1138 /* If we don't, allocate a new one */
1139 New = TRUE;
1140 UncProvider = MupAllocateUncProvider(RegInfo->RedirectorDeviceNameLength);
1141 if (UncProvider == NULL)
1142 {
1143 Status = STATUS_INVALID_USER_BUFFER;
1144 _SEH2_LEAVE;
1145 }
1146
1147 /* Set it up */
1148 UncProvider->DeviceName.Length = RedirectorDeviceName.Length;
1149 UncProvider->DeviceName.MaximumLength = RedirectorDeviceName.MaximumLength;
1150 UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC));
1151
1152 /* As it wasn't in registry for order, give the lowest priority possible */
1153 UncProvider->ProviderOrder = MAXLONG;
1154 RtlMoveMemory(UncProvider->DeviceName.Buffer, (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset), RegInfo->RedirectorDeviceNameLength);
1155 }
1156
1157 /* Continue registration */
1158 UncProvider->MailslotsSupported = RegInfo->MailslotsSupported;
1159 ++UncProvider->NodeReferences;
1160
1161 /* Open a handle to the device */
1162 InitializeObjectAttributes(&ObjectAttributes,
1163 &UncProvider->DeviceName,
1164 OBJ_CASE_INSENSITIVE,
1165 NULL,
1166 NULL);
1167 Status = NtOpenFile(&UncProvider->DeviceHandle,
1168 FILE_TRAVERSE,
1169 &ObjectAttributes,
1170 &IoStatusBlock,
1171 FILE_SHARE_READ | FILE_SHARE_WRITE,
1172 FILE_DIRECTORY_FILE);
1173 if (NT_SUCCESS(Status))
1174 {
1175 Status = IoStatusBlock.Status;
1176 }
1177
1178 /* And return the provider (as CCB) */
1179 if (NT_SUCCESS(Status))
1180 {
1181 Stack->FileObject->FsContext2 = UncProvider;
1182 Status = ObReferenceObjectByHandle(UncProvider->DeviceHandle, 0, NULL, KernelMode, (PVOID *)&UncProvider->FileObject, &HandleInfo);
1183 if (!NT_SUCCESS(Status))
1184 {
1185 NtClose(UncProvider->DeviceHandle);
1186 }
1187 }
1188
1189 if (!NT_SUCCESS(Status))
1190 {
1191 MupDereferenceUncProvider(UncProvider);
1192 }
1193 else
1194 {
1195 UncProvider->DeviceObject = IoGetRelatedDeviceObject(UncProvider->FileObject);
1196
1197 /* Now, insert the provider in our global list
1198 * They are sorted by order
1199 */
1200 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1201 ++MupProviderCount;
1202 if (New)
1203 {
1204 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink)
1205 {
1206 ListEntry = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
1207
1208 if (UncProvider->ProviderOrder < ListEntry->ProviderOrder)
1209 {
1210 break;
1211 }
1212 }
1213
1214 InsertTailList(Entry, &UncProvider->ProviderListEntry);
1215 }
1216 UncProvider->Registered = TRUE;
1217 ExReleaseResourceLite(&MupGlobalLock);
1218 Status = STATUS_SUCCESS;
1219
1220 DPRINT1("UNC provider %wZ registered\n", &UncProvider->DeviceName);
1221 }
1222 }
1223 _SEH2_FINALLY
1224 {
1225 if (_SEH2_AbnormalTermination())
1226 {
1227 Status = STATUS_INVALID_USER_BUFFER;
1228 }
1229
1230 MupDereferenceVcb((PMUP_VCB)Fcb);
1231
1232 Irp->IoStatus.Status = Status;
1233 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1234 }
1235 _SEH2_END;
1236
1237 return Status;
1238 }
1239
1240 NTSTATUS
1241 NTAPI
1242 MupFsControl(PDEVICE_OBJECT DeviceObject,
1243 PIRP Irp)
1244 {
1245 NTSTATUS Status;
1246 PIO_STACK_LOCATION Stack;
1247
1248 Stack = IoGetCurrentIrpStackLocation(Irp);
1249
1250 _SEH2_TRY
1251 {
1252 /* MUP only understands a single FSCTL code: registering UNC provider */
1253 if (Stack->Parameters.FileSystemControl.FsControlCode == FSCTL_MUP_REGISTER_PROVIDER)
1254 {
1255 /* It obviously has to come from a driver/kernelmode thread */
1256 if (Irp->RequestorMode == UserMode)
1257 {
1258 Status = STATUS_ACCESS_DENIED;
1259
1260 Irp->IoStatus.Status = Status;
1261 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1262
1263 _SEH2_LEAVE;
1264 }
1265
1266 Status = RegisterUncProvider(DeviceObject, Irp);
1267 }
1268 else
1269 {
1270 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1271 if (!MupEnableDfs)
1272 {
1273 Status = STATUS_INVALID_PARAMETER;
1274
1275 Irp->IoStatus.Status = Status;
1276 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1277
1278 _SEH2_LEAVE;
1279 }
1280
1281 Status = DfsFsdFileSystemControl(DeviceObject, Irp);
1282 }
1283 }
1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1285 {
1286 Status = _SEH2_GetExceptionCode();
1287 }
1288 _SEH2_END;
1289
1290 return Status;
1291 }
1292
1293 VOID
1294 MupSetFileObject(PFILE_OBJECT FileObject,
1295 PMUP_FCB Fcb,
1296 PMUP_CCB Ccb)
1297 {
1298 FileObject->FsContext = Fcb;
1299 FileObject->FsContext2 = Ccb;
1300 }
1301
1302 NTSTATUS
1303 MupRerouteOpen(PFILE_OBJECT FileObject,
1304 PMUP_UNC UncProvider)
1305 {
1306 PWSTR FullPath;
1307 ULONG TotalLength;
1308
1309 DPRINT("Rerouting %wZ with %wZ\n", &FileObject->FileName, &UncProvider->DeviceName);
1310
1311 /* Get the full path name (device name first, and requested file name appended) */
1312 TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
1313 if (TotalLength > MAXUSHORT)
1314 {
1315 return STATUS_NAME_TOO_LONG;
1316 }
1317
1318 /* Allocate a buffer big enough */
1319 FullPath = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP);
1320 if (FullPath == NULL)
1321 {
1322 return STATUS_INSUFFICIENT_RESOURCES;
1323 }
1324
1325 /* Create the full path */
1326 RtlMoveMemory(FullPath, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length);
1327 RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath + UncProvider->DeviceName.Length), FileObject->FileName.Buffer, FileObject->FileName.Length);
1328
1329 /* And redo the path in the file object */
1330 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1331 FileObject->FileName.Buffer = FullPath;
1332 FileObject->FileName.MaximumLength = TotalLength;
1333 FileObject->FileName.Length = FileObject->FileName.MaximumLength;
1334
1335 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1336 return STATUS_REPARSE;
1337 }
1338
1339 NTSTATUS
1340 BroadcastOpen(PIRP Irp)
1341 {
1342 PMUP_FCB Fcb;
1343 HANDLE Handle;
1344 PLIST_ENTRY Entry;
1345 PMUP_CCB Ccb = NULL;
1346 PMUP_UNC UncProvider;
1347 UNICODE_STRING FullPath;
1348 PFILE_OBJECT FileObject;
1349 PIO_STACK_LOCATION Stack;
1350 NTSTATUS Status, LastFailed;
1351 ULONG TotalLength, LastOrder;
1352 IO_STATUS_BLOCK IoStatusBlock;
1353 OBJECT_ATTRIBUTES ObjectAttributes;
1354 OBJECT_HANDLE_INFORMATION HandleInfo;
1355 BOOLEAN Locked, Referenced, CcbInitialized;
1356
1357 Fcb = MupCreateFcb();
1358 if (Fcb == NULL)
1359 {
1360 return STATUS_INSUFFICIENT_RESOURCES;
1361 }
1362
1363 Stack = IoGetCurrentIrpStackLocation(Irp);
1364 FileObject = Stack->FileObject;
1365 Locked = FALSE;
1366 Referenced = FALSE;
1367 CcbInitialized = FALSE;
1368 LastFailed = STATUS_NO_SUCH_FILE;
1369 LastOrder = (ULONG)-1;
1370
1371 _SEH2_TRY
1372 {
1373 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1374 Locked = TRUE;
1375
1376 /* Associate our FCB with the FO */
1377 MupSetFileObject(FileObject, Fcb, NULL);
1378 Fcb->FileObject = FileObject;
1379
1380 /* Now, broadcast the open to any UNC provider that supports mailslots */
1381 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink)
1382 {
1383 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
1384 ++UncProvider->NodeReferences;
1385 Referenced = TRUE;
1386
1387 ExReleaseResourceLite(&MupGlobalLock);
1388 Locked = FALSE;
1389
1390 TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
1391 if (UncProvider->MailslotsSupported && TotalLength <= MAXUSHORT)
1392 {
1393 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1394 FullPath.Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP);
1395 if (FullPath.Buffer == NULL)
1396 {
1397 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
1398 }
1399
1400 FullPath.Length = TotalLength;
1401 FullPath.MaximumLength = TotalLength;
1402 RtlMoveMemory(FullPath.Buffer, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length);
1403 RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath.Buffer + UncProvider->DeviceName.Length),
1404 FileObject->FileName.Buffer,
1405 FileObject->FileName.Length);
1406
1407 /* And just forward the creation request */
1408 InitializeObjectAttributes(&ObjectAttributes,
1409 &FullPath,
1410 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1411 NULL,
1412 NULL);
1413 Status = IoCreateFile(&Handle,
1414 Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_SIMPLE_RIGHTS_MASK,
1415 &ObjectAttributes,
1416 &IoStatusBlock,
1417 NULL,
1418 Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
1419 Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
1420 FILE_OPEN,
1421 Stack->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
1422 NULL,
1423 0,
1424 CreateFileTypeNone,
1425 NULL,
1426 IO_NO_PARAMETER_CHECKING);
1427
1428 ExFreePoolWithTag(FullPath.Buffer, TAG_MUP);
1429
1430 /* If opening succeed */
1431 if (NT_SUCCESS(Status))
1432 {
1433 Status = IoStatusBlock.Status;
1434
1435 /* Create a CCB */
1436 Ccb = MupCreateCcb();
1437 if (Ccb == NULL)
1438 {
1439 Status = STATUS_INSUFFICIENT_RESOURCES;
1440 }
1441
1442 /* And associated a FO to it */
1443 if (NT_SUCCESS(Status))
1444 {
1445 Status = ObReferenceObjectByHandle(Handle, 0, 0, 0, (PVOID *)&Ccb->FileObject, &HandleInfo);
1446 ZwClose(Handle);
1447 }
1448 }
1449
1450 /* If we failed, remember the last failed status of the higher priority provider */
1451 if (!NT_SUCCESS(Status))
1452 {
1453 if (UncProvider->ProviderOrder <= LastOrder)
1454 {
1455 LastOrder = UncProvider->ProviderOrder;
1456 LastFailed = Status;
1457 }
1458 }
1459 /* Otherwise, properly attach our CCB to the mailslot */
1460 else
1461 {
1462 Ccb->DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject);
1463 Ccb->Fcb = Fcb;
1464
1465 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1466 Locked = TRUE;
1467 ++Fcb->NodeReferences;
1468 ExReleaseResourceLite(&MupGlobalLock);
1469 Locked = FALSE;
1470 CcbInitialized = TRUE;
1471
1472 InsertTailList(&Fcb->CcbList, &Ccb->CcbListEntry);
1473 }
1474 }
1475
1476 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1477 Locked = TRUE;
1478 MupDereferenceUncProvider(UncProvider);
1479 Referenced = FALSE;
1480 }
1481
1482 ExReleaseResourceLite(&MupGlobalLock);
1483 Locked = FALSE;
1484 }
1485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1486 {
1487 Status = _SEH2_GetExceptionCode();
1488 }
1489 _SEH2_END;
1490
1491 /* If we at least opened one mailslot, return success */
1492 Status = (CcbInitialized ? STATUS_SUCCESS : LastFailed);
1493
1494 if (Referenced)
1495 {
1496 MupDereferenceUncProvider(UncProvider);
1497 }
1498
1499 if (Locked)
1500 {
1501 ExReleaseResourceLite(&MupGlobalLock);
1502 }
1503
1504 /* In case of failure, don't leak CCB */
1505 if (!NT_SUCCESS(Status) && Ccb != NULL)
1506 {
1507 MupFreeNode(Ccb);
1508 }
1509
1510 return Status;
1511 }
1512
1513 PIRP
1514 MupBuildIoControlRequest(PFILE_OBJECT FileObject,
1515 PVOID Context,
1516 ULONG MajorFunction,
1517 ULONG IoctlCode,
1518 PVOID InputBuffer,
1519 ULONG InputBufferSize,
1520 PVOID OutputBuffer,
1521 ULONG OutputBufferSize,
1522 PIO_COMPLETION_ROUTINE CompletionRoutine)
1523 {
1524 PIRP Irp;
1525 PIO_STACK_LOCATION Stack;
1526 PDEVICE_OBJECT DeviceObject;
1527
1528 if (InputBuffer == NULL)
1529 {
1530 return NULL;
1531 }
1532
1533 /* Get the device object */
1534 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1535 /* Allocate the IRP (with one more location for us */
1536 Irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE);
1537 if (Irp == NULL)
1538 {
1539 return NULL;
1540 }
1541
1542 /* Skip our location */
1543 IoSetNextIrpStackLocation(Irp);
1544 /* Setup the IRP */
1545 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1546 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1547 IoSetCompletionRoutine(Irp, CompletionRoutine, Context, TRUE, TRUE, TRUE);
1548
1549 /* Setup the stack */
1550 Stack = IoGetNextIrpStackLocation(Irp);
1551 Stack->MajorFunction = MajorFunction;
1552 Stack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferSize;
1553 Stack->Parameters.DeviceIoControl.InputBufferLength = InputBufferSize;
1554 Stack->Parameters.DeviceIoControl.IoControlCode = IoctlCode;
1555 Stack->MinorFunction = 0;
1556 Stack->FileObject = FileObject;
1557 Stack->DeviceObject = DeviceObject;
1558
1559 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode))
1560 {
1561 case METHOD_BUFFERED:
1562 /* If it's buffered, just pass the buffers we got */
1563 Irp->MdlAddress = NULL;
1564 Irp->AssociatedIrp.SystemBuffer = InputBuffer;
1565 Irp->UserBuffer = OutputBuffer;
1566 Irp->Flags = IRP_BUFFERED_IO;
1567
1568 if (OutputBuffer != NULL)
1569 {
1570 Irp->Flags |= IRP_INPUT_OPERATION;
1571 }
1572 break;
1573
1574 case METHOD_IN_DIRECT:
1575 case METHOD_OUT_DIRECT:
1576 /* Otherwise, allocate an MDL */
1577 if (IoAllocateMdl(InputBuffer, InputBufferSize, FALSE, FALSE, Irp) == NULL)
1578 {
1579 IoFreeIrp(Irp);
1580 return NULL;
1581 }
1582
1583 Irp->AssociatedIrp.SystemBuffer = InputBuffer;
1584 Irp->Flags = IRP_BUFFERED_IO;
1585 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoReadAccess);
1586 break;
1587
1588 case METHOD_NEITHER:
1589 /* Or pass the buffers */
1590 Irp->UserBuffer = OutputBuffer;
1591 Irp->MdlAddress = NULL;
1592 Irp->AssociatedIrp.SystemBuffer = NULL;
1593 Stack->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
1594 break;
1595 }
1596
1597 return Irp;
1598 }
1599
1600 VOID
1601 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext)
1602 {
1603 ExDeleteResourceLite(&MasterQueryContext->QueryPathListLock);
1604 ExFreePoolWithTag(MasterQueryContext, TAG_MUP);
1605 }
1606
1607 NTSTATUS
1608 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext)
1609 {
1610 LONG References;
1611 NTSTATUS Status;
1612 BOOLEAN KeepExtraRef;
1613
1614 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1615 --MasterQueryContext->NodeReferences;
1616 References = MasterQueryContext->NodeReferences;
1617 ExReleaseResourceLite(&MupGlobalLock);
1618
1619 if (References != 0)
1620 {
1621 DPRINT("Still having refs (%ld)\n", References);
1622 return STATUS_PENDING;
1623 }
1624
1625 /* We HAVE an IRP to complete. It cannot be NULL
1626 * Please, help preserving kittens, don't provide NULL IRPs.
1627 */
1628 if (MasterQueryContext->Irp == NULL)
1629 {
1630 KeBugCheck(FILE_SYSTEM);
1631 }
1632
1633 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
1634 RemoveEntryList(&MasterQueryContext->MQCListEntry);
1635 ExReleaseResourceLite(&MupGlobalLock);
1636
1637 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
1638 KeepExtraRef = MasterQueryContext->Prefix->KeepExtraRef;
1639 MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
1640
1641 /* We found a provider? */
1642 if (MasterQueryContext->LatestProvider != NULL)
1643 {
1644 /* With a successful status? */
1645 if (MasterQueryContext->LatestStatus == STATUS_SUCCESS)
1646 {
1647 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1648 if (!KeepExtraRef)
1649 {
1650 MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
1651 }
1652
1653 ExReleaseResourceLite(&MupPrefixTableLock);
1654 /* Reroute & complete :-) */
1655 Status = MupRerouteOpen(MasterQueryContext->FileObject, MasterQueryContext->LatestProvider);
1656 goto Complete;
1657 }
1658 else
1659 {
1660 MupDereferenceUncProvider(MasterQueryContext->LatestProvider);
1661 }
1662 }
1663
1664 MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
1665 ExReleaseResourceLite(&MupPrefixTableLock);
1666
1667 /* Return the highest failed status we had */
1668 Status = MasterQueryContext->LatestStatus;
1669
1670 Complete:
1671 /* In finally, complete the IRP for real! */
1672 MasterQueryContext->Irp->IoStatus.Status = Status;
1673 IoCompleteRequest(MasterQueryContext->Irp, IO_DISK_INCREMENT);
1674
1675 MasterQueryContext->Irp = NULL;
1676 MupFreeMasterQueryContext(MasterQueryContext);
1677
1678 return Status;
1679 }
1680
1681 NTSTATUS
1682 NTAPI
1683 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject,
1684 PIRP Irp,
1685 PVOID Context)
1686 {
1687 PMUP_PFX Prefix;
1688 ULONG LatestPos, Pos;
1689 PWSTR AcceptedPrefix;
1690 PMUP_MQC MasterQueryContext;
1691 NTSTATUS Status, TableStatus;
1692 PQUERY_PATH_CONTEXT QueryContext;
1693 PQUERY_PATH_RESPONSE QueryResponse;
1694
1695 /* Get all the data from our query to the provider */
1696 QueryContext = (PQUERY_PATH_CONTEXT)Context;
1697 QueryResponse = (PQUERY_PATH_RESPONSE)QueryContext->QueryPathRequest;
1698 MasterQueryContext = QueryContext->MasterQueryContext;
1699 Status = Irp->IoStatus.Status;
1700
1701 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext->UncProvider->DeviceName, QueryResponse->LengthAccepted, Status);
1702
1703 ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE);
1704 RemoveEntryList(&QueryContext->QueryPathListEntry);
1705
1706 /* If the driver returned a success, and an acceptance length */
1707 if (NT_SUCCESS(Status) && QueryResponse->LengthAccepted > 0)
1708 {
1709 Prefix = MasterQueryContext->Prefix;
1710
1711 /* Check if we already found a provider from a previous iteration */
1712 if (MasterQueryContext->LatestProvider != NULL)
1713 {
1714 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1715 if (QueryContext->UncProvider->ProviderOrder >= MasterQueryContext->LatestProvider->ProviderOrder)
1716 {
1717 MupDereferenceUncProvider(QueryContext->UncProvider);
1718 goto Cleanup;
1719 }
1720
1721 /* Otherwise, if the prefix was in the prefix table, just drop it:
1722 * we have a provider which supersedes the accepted prefix, so leave
1723 * room for the new prefix/provider
1724 */
1725 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
1726 if (Prefix->InTable)
1727 {
1728 RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry);
1729 RemoveEntryList(&Prefix->PrefixListEntry);
1730 Prefix->InTable = FALSE;
1731 }
1732 ExReleaseResourceLite(&MupPrefixTableLock);
1733
1734 Prefix->KeepExtraRef = FALSE;
1735
1736 /* Release data associated with the current prefix, if any
1737 * We'll renew them with the new accepted prefix
1738 */
1739 if (Prefix->AcceptedPrefix.Length != 0 && Prefix->AcceptedPrefix.Buffer != NULL)
1740 {
1741 ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP);
1742 Prefix->AcceptedPrefix.MaximumLength = 0;
1743 Prefix->AcceptedPrefix.Length = 0;
1744 Prefix->AcceptedPrefix.Buffer = NULL;
1745 Prefix->ExternalAlloc = FALSE;
1746 }
1747
1748 /* If there was also a provider, drop it, the new one
1749 * is different
1750 */
1751 if (Prefix->UncProvider != NULL)
1752 {
1753 MupDereferenceUncProvider(Prefix->UncProvider);
1754 Prefix->UncProvider = NULL;
1755 }
1756 }
1757
1758 /* Now, set our information about the provider that accepted the prefix */
1759 MasterQueryContext->LatestProvider = QueryContext->UncProvider;
1760 MasterQueryContext->LatestStatus = Status;
1761
1762 if (MasterQueryContext->FileObject->FsContext2 != (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT)
1763 {
1764 /* Allocate a buffer for the prefix */
1765 AcceptedPrefix = ExAllocatePoolWithTag(PagedPool, QueryResponse->LengthAccepted, TAG_MUP);
1766 if (AcceptedPrefix == NULL)
1767 {
1768 Prefix->InTable = FALSE;
1769 }
1770 else
1771 {
1772 /* Set it up to the accepted length */
1773 RtlMoveMemory(AcceptedPrefix, MasterQueryContext->FileObject->FileName.Buffer, QueryResponse->LengthAccepted);
1774 Prefix->UncProvider = MasterQueryContext->LatestProvider;
1775 Prefix->AcceptedPrefix.Buffer = AcceptedPrefix;
1776 Prefix->AcceptedPrefix.Length = QueryResponse->LengthAccepted;
1777 Prefix->AcceptedPrefix.MaximumLength = QueryResponse->LengthAccepted;
1778 Prefix->ExternalAlloc = TRUE;
1779
1780 /* Insert the accepted prefix in the table of known prefixes */
1781 DPRINT("%wZ accepted %wZ\n", &Prefix->UncProvider->DeviceName, &Prefix->AcceptedPrefix);
1782 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
1783 if (RtlInsertUnicodePrefix(&MupPrefixTable, &Prefix->AcceptedPrefix, &Prefix->PrefixTableEntry))
1784 {
1785 InsertHeadList(&MupPrefixList, &Prefix->PrefixListEntry);
1786 Prefix->InTable = TRUE;
1787 Prefix->KeepExtraRef = TRUE;
1788 }
1789 else
1790 {
1791 Prefix->InTable = FALSE;
1792 }
1793 ExReleaseResourceLite(&MupPrefixTableLock);
1794 }
1795 }
1796 }
1797 else
1798 {
1799 MupDereferenceUncProvider(QueryContext->UncProvider);
1800
1801 /* We failed and didn't find any provider over the latest iterations */
1802 if (MasterQueryContext->LatestProvider == NULL)
1803 {
1804 /* If we had a success though (broken provider?) set our failed status */
1805 if (NT_SUCCESS(MasterQueryContext->LatestStatus))
1806 {
1807 MasterQueryContext->LatestStatus = Status;
1808 }
1809 else
1810 {
1811 TableStatus = MupOrderedErrorList[0];
1812 LatestPos = 0;
1813
1814 /* Otherwise, time to compare statuses, between the latest failed
1815 * and the current failure.
1816 * We have an order table of failed status: the deeper you go in the
1817 * table, the more the error is critical.
1818 * Our goal is to return the most critical status that was returned by
1819 * any of the providers
1820 */
1821
1822 /* Look for latest status position */
1823 while (TableStatus != 0 && TableStatus != MasterQueryContext->LatestStatus)
1824 {
1825 ++LatestPos;
1826 TableStatus = MupOrderedErrorList[LatestPos];
1827 }
1828
1829 /* If at pos 0, the new status is likely more critical */
1830 if (LatestPos == 0)
1831 {
1832 MasterQueryContext->LatestStatus = Status;
1833 }
1834 else
1835 {
1836 /* Otherwise, find position of the new status in the table */
1837 Pos = 0;
1838 do
1839 {
1840 if (Status == MupOrderedErrorList[Pos])
1841 {
1842 break;
1843 }
1844
1845 ++Pos;
1846 }
1847 while (Pos < LatestPos);
1848
1849 /* If it has a higher position (more critical), return it */
1850 if (Pos >= LatestPos)
1851 {
1852 MasterQueryContext->LatestStatus = Status;
1853 }
1854 }
1855 }
1856 }
1857 }
1858
1859 Cleanup:
1860 ExFreePoolWithTag(QueryResponse, TAG_MUP);
1861 ExFreePoolWithTag(QueryContext, TAG_MUP);
1862 IoFreeIrp(Irp);
1863
1864 ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock);
1865 MupDereferenceMasterQueryContext(MasterQueryContext);
1866
1867 return STATUS_MORE_PROCESSING_REQUIRED;
1868 }
1869
1870 NTSTATUS
1871 CreateRedirectedFile(PIRP Irp,
1872 PFILE_OBJECT FileObject,
1873 PIO_SECURITY_CONTEXT SecurityContext)
1874 {
1875 LONG Len;
1876 WCHAR Cur;
1877 PWSTR Name;
1878 PIRP QueryIrp;
1879 NTSTATUS Status;
1880 PMUP_PFX Prefix;
1881 PLIST_ENTRY Entry;
1882 PMUP_UNC UncProvider;
1883 PIO_STACK_LOCATION Stack;
1884 LARGE_INTEGER CurrentTime;
1885 PMUP_MQC MasterQueryContext;
1886 PQUERY_PATH_CONTEXT QueryContext;
1887 PQUERY_PATH_REQUEST QueryPathRequest;
1888 PUNICODE_PREFIX_TABLE_ENTRY TableEntry;
1889 BOOLEAN Locked, Referenced, BreakOnFirst;
1890
1891 /* We cannot open a file without a name */
1892 if (FileObject->FileName.Length == 0)
1893 {
1894 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1895 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1896
1897 return STATUS_INVALID_DEVICE_REQUEST;
1898 }
1899
1900 DPRINT("Request for opening: %wZ\n", &FileObject->FileName);
1901
1902 Referenced = FALSE;
1903 BreakOnFirst = TRUE;
1904 Status = STATUS_BAD_NETWORK_PATH;
1905
1906 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
1907 /* First, try to see if that's a prefix we already know */
1908 TableEntry = RtlFindUnicodePrefix(&MupPrefixTable, &FileObject->FileName, 1);
1909 if (TableEntry != NULL)
1910 {
1911 Prefix = CONTAINING_RECORD(TableEntry, MUP_PFX, PrefixTableEntry);
1912
1913 DPRINT("Matching prefix found: %wZ\n", &Prefix->AcceptedPrefix);
1914
1915 /* If so, check whether the prefix is still valid */
1916 KeQuerySystemTime(&CurrentTime);
1917 if (Prefix->ValidityTimeout.QuadPart < CurrentTime.QuadPart)
1918 {
1919 /* It is: so, update its validity period and reroute file opening */
1920 MupCalculateTimeout(&Prefix->ValidityTimeout);
1921 Status = MupRerouteOpen(FileObject, Prefix->UncProvider);
1922 ExReleaseResourceLite(&MupPrefixTableLock);
1923
1924 if (Status == STATUS_REPARSE)
1925 {
1926 Irp->IoStatus.Information = FILE_SUPERSEDED;
1927 }
1928
1929 Irp->IoStatus.Status = Status;
1930 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1931
1932 return Status;
1933 }
1934
1935 /* When here, we found a matching prefix, but expired, remove it from the table
1936 * We'll redo a full search
1937 */
1938 if (Prefix->InTable)
1939 {
1940 MupRemoveKnownPrefixEntry(Prefix);
1941 }
1942 }
1943 ExReleaseResourceLite(&MupPrefixTableLock);
1944
1945 Stack = IoGetCurrentIrpStackLocation(Irp);
1946 /* First of all, start looking for a mailslot */
1947 if (FileObject->FileName.Buffer[0] == L'\\' && Stack->MajorFunction != IRP_MJ_CREATE)
1948 {
1949 Name = &FileObject->FileName.Buffer[1];
1950 Len = FileObject->FileName.Length;
1951
1952 /* Skip the remote destination name */
1953 do
1954 {
1955 Len -= sizeof(WCHAR);
1956 if (Len <= 0)
1957 {
1958 break;
1959 }
1960
1961 Cur = *Name;
1962 ++Name;
1963 } while (Cur != L'\\');
1964 Len -= sizeof(WCHAR);
1965
1966 /* If we still have room for "Mailslot" to fit */
1967 if (Len >= (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)))
1968 {
1969 /* Get the len in terms of chars count */
1970 Len /= sizeof(WCHAR);
1971 if (Len > ((sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR)))
1972 {
1973 Len = (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
1974 }
1975
1976 /* It's indeed a mailslot opening! */
1977 if (_wcsnicmp(Name, L"Mailslot", Len) == 0)
1978 {
1979 /* Broadcast open */
1980 Status = BroadcastOpen(Irp);
1981 if (Status == STATUS_REPARSE)
1982 {
1983 Irp->IoStatus.Information = FILE_SUPERSEDED;
1984 }
1985
1986 Irp->IoStatus.Status = Status;
1987 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1988
1989 return Status;
1990 }
1991 }
1992 }
1993
1994 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
1995 if (!MupEnableDfs || FileObject->FsContext2 == (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT)
1996 {
1997 /* We won't complete immediately */
1998 IoMarkIrpPending(Irp);
1999
2000 /* Allocate a new prefix for our search */
2001 Prefix = MupAllocatePrefixEntry(0);
2002 if (Prefix == NULL)
2003 {
2004 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2005 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2006
2007 return STATUS_PENDING;
2008 }
2009
2010 /* Allocate a context for our search */
2011 MasterQueryContext = MupAllocateMasterQueryContext();
2012 if (MasterQueryContext == NULL)
2013 {
2014 MupFreeNode(Prefix);
2015
2016 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2017 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2018
2019 return STATUS_PENDING;
2020 }
2021
2022 MasterQueryContext->Irp = Irp;
2023 MasterQueryContext->FileObject = FileObject;
2024 MasterQueryContext->LatestProvider = NULL;
2025 MasterQueryContext->Prefix = Prefix;
2026 MasterQueryContext->LatestStatus = STATUS_BAD_NETWORK_PATH;
2027 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2028 InsertTailList(&MupMasterQueryList, &MasterQueryContext->MQCListEntry);
2029 ++Prefix->NodeReferences;
2030 ExReleaseResourceLite(&MupGlobalLock);
2031
2032 _SEH2_TRY
2033 {
2034 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2035 Locked = TRUE;
2036
2037 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2038 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink)
2039 {
2040 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
2041
2042 ++UncProvider->NodeReferences;
2043 Referenced = TRUE;
2044
2045 ExReleaseResourceLite(&MupGlobalLock);
2046 Locked = FALSE;
2047
2048 /* We will obviously only query registered providers */
2049 if (UncProvider->Registered)
2050 {
2051 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2052 QueryPathRequest = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), TAG_MUP);
2053 if (QueryPathRequest == NULL)
2054 {
2055 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2056 }
2057
2058 /* Allocate a context for IRP completion routine
2059 * In case a prefix matches the path, the reroute will happen
2060 * in the completion routine, when we have return from the provider
2061 */
2062 QueryContext = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_PATH_CONTEXT), TAG_MUP);
2063 if (QueryContext == NULL)
2064 {
2065 ExFreePoolWithTag(QueryPathRequest, TAG_MUP);
2066 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2067 }
2068
2069 InitializeListHead(&QueryContext->QueryPathListEntry);
2070 QueryContext->MasterQueryContext = MasterQueryContext;
2071 QueryContext->QueryPathRequest = QueryPathRequest;
2072 QueryPathRequest->PathNameLength = FileObject->FileName.Length;
2073 QueryPathRequest->SecurityContext = SecurityContext;
2074 RtlMoveMemory(QueryPathRequest->FilePathName, FileObject->FileName.Buffer, FileObject->FileName.Length);
2075
2076 /* Build our IRP for the query */
2077 QueryIrp = MupBuildIoControlRequest(UncProvider->FileObject,
2078 QueryContext,
2079 IRP_MJ_DEVICE_CONTROL,
2080 IOCTL_REDIR_QUERY_PATH,
2081 QueryPathRequest,
2082 FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST),
2083 QueryPathRequest,
2084 sizeof(QUERY_PATH_RESPONSE),
2085 QueryPathCompletionRoutine);
2086 if (QueryIrp == NULL)
2087 {
2088 ExFreePoolWithTag(QueryContext, TAG_MUP);
2089 ExFreePoolWithTag(QueryPathRequest, TAG_MUP);
2090 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2091 }
2092
2093 QueryIrp->RequestorMode = KernelMode;
2094 QueryContext->UncProvider = UncProvider;
2095 QueryContext->Irp = QueryIrp;
2096
2097 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2098 ++UncProvider->NodeReferences;
2099 ++MasterQueryContext->NodeReferences;
2100 ExReleaseResourceLite(&MupGlobalLock);
2101
2102 ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE);
2103 InsertTailList(&MasterQueryContext->QueryPathList, &QueryContext->QueryPathListEntry);
2104 ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock);
2105
2106 /* Query the provider !*/
2107 DPRINT("Requesting UNC provider: %wZ\n", &UncProvider->DeviceName);
2108 DPRINT("Calling: %wZ\n", &UncProvider->DeviceObject->DriverObject->DriverName);
2109 Status = IoCallDriver(UncProvider->DeviceObject, QueryIrp);
2110 }
2111
2112 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2113 Locked = TRUE;
2114
2115 /* We're done with that provider */
2116 MupDereferenceUncProvider(UncProvider);
2117 Referenced = FALSE;
2118
2119 /* If query went fine on the first request, just break and leave */
2120 if (BreakOnFirst && Status == STATUS_SUCCESS)
2121 {
2122 break;
2123 }
2124
2125 BreakOnFirst = FALSE;
2126 }
2127 }
2128 _SEH2_FINALLY
2129 {
2130 if (_SEH2_AbnormalTermination())
2131 {
2132 MasterQueryContext->LatestStatus = STATUS_INSUFFICIENT_RESOURCES;
2133 }
2134
2135 if (Referenced)
2136 {
2137 MupDereferenceUncProvider(UncProvider);
2138 }
2139
2140 if (Locked)
2141 {
2142 ExReleaseResourceLite(&MupGlobalLock);
2143 }
2144
2145 MupDereferenceMasterQueryContext(MasterQueryContext);
2146
2147 Status = STATUS_PENDING;
2148 }
2149 _SEH2_END;
2150 }
2151 else
2152 {
2153 UNIMPLEMENTED;
2154 Status = STATUS_NOT_IMPLEMENTED;
2155 }
2156
2157 return Status;
2158 }
2159
2160 NTSTATUS
2161 OpenMupFileSystem(PMUP_VCB Vcb,
2162 PFILE_OBJECT FileObject,
2163 ACCESS_MASK DesiredAccess,
2164 USHORT ShareAccess)
2165 {
2166 NTSTATUS Status;
2167
2168 DPRINT1("Opening MUP\n");
2169
2170 ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE);
2171 _SEH2_TRY
2172 {
2173 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2174 Status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess, TRUE);
2175 if (NT_SUCCESS(Status))
2176 {
2177 ++Vcb->NodeReferences;
2178 MupSetFileObject(FileObject, (PMUP_FCB)Vcb, NULL);
2179 Status = STATUS_SUCCESS;
2180 }
2181 }
2182 _SEH2_FINALLY
2183 {
2184 ExReleaseResourceLite(&MupVcbLock);
2185 }
2186 _SEH2_END;
2187
2188 return Status;
2189 }
2190
2191 NTSTATUS
2192 NTAPI
2193 MupCreate(PDEVICE_OBJECT DeviceObject,
2194 PIRP Irp)
2195 {
2196 NTSTATUS Status;
2197 PIO_STACK_LOCATION Stack;
2198 PFILE_OBJECT FileObject, RelatedFileObject;
2199
2200 FsRtlEnterFileSystem();
2201
2202 _SEH2_TRY
2203 {
2204 /* If DFS is enabled, check if that's for DFS and is so relay */
2205 if (MupEnableDfs && (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM))
2206 {
2207 Status = DfsFsdCreate(DeviceObject, Irp);
2208 }
2209 else
2210 {
2211 Stack = IoGetCurrentIrpStackLocation(Irp);
2212 FileObject = Stack->FileObject;
2213 RelatedFileObject = FileObject->RelatedFileObject;
2214
2215 /* If we have a file name or if the associated FCB of the related FO isn't the VCB, then, it's a regular opening */
2216 if (FileObject->FileName.Length != 0 || (RelatedFileObject != NULL && ((PMUP_FCB)(RelatedFileObject->FsContext))->NodeType != NODE_TYPE_VCB))
2217 {
2218 Status = CreateRedirectedFile(Irp, FileObject, Stack->Parameters.Create.SecurityContext);
2219 }
2220 /* Otherwise, it's just a volume open */
2221 else
2222 {
2223 Status = OpenMupFileSystem(DeviceObject->DeviceExtension,
2224 FileObject,
2225 Stack->Parameters.Create.SecurityContext->DesiredAccess,
2226 Stack->Parameters.Create.ShareAccess);
2227
2228 Irp->IoStatus.Information = FILE_OPENED;
2229 Irp->IoStatus.Status = Status;
2230 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2231 }
2232 }
2233 }
2234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2235 {
2236 Status = _SEH2_GetExceptionCode();
2237
2238 Irp->IoStatus.Status = Status;
2239 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2240 }
2241 _SEH2_END;
2242
2243 FsRtlExitFileSystem();
2244
2245 return Status;
2246 }
2247
2248 VOID
2249 MupCloseUncProvider(PMUP_UNC UncProvider)
2250 {
2251 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2252
2253 /* If the node was still valid, reregister the UNC provider */
2254 if (UncProvider->NodeStatus == NODE_STATUS_HEALTHY)
2255 {
2256 UncProvider->NodeStatus = NODE_STATUS_CLEANUP;
2257 UncProvider->Registered = FALSE;
2258 ExReleaseResourceLite(&MupGlobalLock);
2259
2260 if (UncProvider->FileObject != NULL)
2261 {
2262 ZwClose(UncProvider->DeviceHandle);
2263 ObDereferenceObject(UncProvider->FileObject);
2264 }
2265 }
2266 else
2267 {
2268 ExReleaseResourceLite(&MupGlobalLock);
2269 }
2270 }
2271
2272 NTSTATUS
2273 NTAPI
2274 MupCleanup(PDEVICE_OBJECT DeviceObject,
2275 PIRP Irp)
2276 {
2277 ULONG Type;
2278 PMUP_FCB Fcb;
2279 PMUP_CCB Ccb;
2280 NTSTATUS Status;
2281 PIO_STACK_LOCATION Stack;
2282
2283 /* If DFS is enabled, check if that's for DFS and is so relay */
2284 if (MupEnableDfs)
2285 {
2286 if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM)
2287 {
2288 return DfsFsdCleanup(DeviceObject, Irp);
2289 }
2290 }
2291
2292 FsRtlEnterFileSystem();
2293
2294 _SEH2_TRY
2295 {
2296 Stack = IoGetCurrentIrpStackLocation(Irp);
2297 Type = MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
2298 switch (Type)
2299 {
2300 case NODE_TYPE_VCB:
2301 /* If we got a VCB, clean it up */
2302 MupCleanupVcb(DeviceObject, Irp, (PMUP_VCB)Fcb);
2303
2304 Irp->IoStatus.Status = STATUS_SUCCESS;
2305 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2306
2307 MupDereferenceVcb((PMUP_VCB)Fcb);
2308
2309 /* If Ccb is not null, then, it's a UNC provider node */
2310 if (Ccb)
2311 {
2312 /* Close it, and dereference */
2313 MupCloseUncProvider((PMUP_UNC)Ccb);
2314 MupDereferenceUncProvider((PMUP_UNC)Ccb);
2315 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2316 --MupProviderCount;
2317 ExReleaseResourceLite(&MupGlobalLock);
2318 }
2319
2320 Status = STATUS_SUCCESS;
2321 break;
2322
2323 case NODE_TYPE_FCB:
2324 /* If the node wasn't already cleaned, do it */
2325 if (Fcb->NodeStatus == NODE_STATUS_HEALTHY)
2326 {
2327 MupCleanupFcb(DeviceObject, Irp, Fcb);
2328 Status = STATUS_SUCCESS;
2329 }
2330 else
2331 {
2332 Status = STATUS_INVALID_HANDLE;
2333 }
2334
2335 Irp->IoStatus.Status = STATUS_SUCCESS;
2336 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2337
2338 MupDereferenceFcb(Fcb);
2339 break;
2340
2341 default:
2342 Status = STATUS_INVALID_HANDLE;
2343
2344 Irp->IoStatus.Status = Status;
2345 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2346
2347 break;
2348 }
2349 }
2350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2351 {
2352 Status = _SEH2_GetExceptionCode();
2353 }
2354 _SEH2_END;
2355
2356 FsRtlExitFileSystem();
2357
2358 return Status;
2359 }
2360
2361 NTSTATUS
2362 MupCloseVcb(PDEVICE_OBJECT DeviceObject,
2363 PIRP Irp,
2364 PMUP_VCB Vcb,
2365 PFILE_OBJECT FileObject)
2366 {
2367 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2368
2369 /* Remove FCB, UNC from FO */
2370 MupSetFileObject(FileObject, NULL, NULL);
2371 MupDereferenceVcb(Vcb);
2372
2373 ExReleaseResourceLite(&MupGlobalLock);
2374
2375 return STATUS_SUCCESS;
2376 }
2377
2378 NTSTATUS
2379 MupCloseFcb(PDEVICE_OBJECT DeviceObject,
2380 PIRP Irp,
2381 PMUP_FCB Fcb,
2382 PFILE_OBJECT FileObject)
2383 {
2384 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
2385
2386 /* Remove FCB, CCB from FO */
2387 MupSetFileObject(FileObject, NULL, NULL);
2388 MupDereferenceFcb(Fcb);
2389
2390 ExReleaseResourceLite(&MupGlobalLock);
2391
2392 return STATUS_SUCCESS;
2393 }
2394
2395 NTSTATUS
2396 NTAPI
2397 MupClose(PDEVICE_OBJECT DeviceObject,
2398 PIRP Irp)
2399 {
2400 PMUP_FCB Fcb;
2401 PMUP_CCB Ccb;
2402 NTSTATUS Status;
2403 PIO_STACK_LOCATION Stack;
2404
2405 /* If DFS is enabled, check if that's for DFS and is so relay */
2406 if (MupEnableDfs)
2407 {
2408 if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM)
2409 {
2410 return DfsFsdClose(DeviceObject, Irp);
2411 }
2412 }
2413
2414 FsRtlEnterFileSystem();
2415
2416 _SEH2_TRY
2417 {
2418 /* Get our internal structures from FO */
2419 Stack = IoGetCurrentIrpStackLocation(Irp);
2420 MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
2421 if (Fcb == NULL)
2422 {
2423 Status = STATUS_INVALID_HANDLE;
2424
2425 Irp->IoStatus.Status = Status;
2426 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2427
2428 _SEH2_LEAVE;
2429 }
2430
2431 /* If we got the VCB, that's a volume close */
2432 if (Fcb->NodeType == NODE_TYPE_VCB)
2433 {
2434 Status = MupCloseVcb(DeviceObject, Irp, (PMUP_VCB)Fcb, Stack->FileObject);
2435 }
2436 /* Otherwise close the FCB */
2437 else if (Fcb->NodeType == NODE_TYPE_FCB)
2438 {
2439 MupDereferenceFcb(Fcb);
2440 Status = MupCloseFcb(DeviceObject, Irp, Fcb, Stack->FileObject);
2441 }
2442 else
2443 {
2444 Status = STATUS_INVALID_HANDLE;
2445
2446 Irp->IoStatus.Status = Status;
2447 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2448
2449 _SEH2_LEAVE;
2450 }
2451
2452 Irp->IoStatus.Status = STATUS_SUCCESS;
2453 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2454 }
2455 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2456 {
2457 Status = _SEH2_GetExceptionCode();
2458 }
2459 _SEH2_END;
2460
2461 FsRtlExitFileSystem();
2462
2463 return Status;
2464 }
2465
2466 VOID
2467 NTAPI
2468 MupUnload(PDRIVER_OBJECT DriverObject)
2469 {
2470 IoDeleteDevice(mupDeviceObject);
2471
2472 if (MupEnableDfs)
2473 {
2474 DfsUnload(DriverObject);
2475 }
2476
2477 MupUninitializeData();
2478 }
2479
2480 /*
2481 * FUNCTION: Called by the system to initialize the driver
2482 * ARGUMENTS:
2483 * DriverObject = object describing this driver
2484 * RegistryPath = path to our configuration entries
2485 * RETURNS: Success or failure
2486 */
2487 CODE_SEG("INIT")
2488 NTSTATUS
2489 NTAPI
2490 DriverEntry(PDRIVER_OBJECT DriverObject,
2491 PUNICODE_STRING RegistryPath)
2492 {
2493 NTSTATUS Status;
2494 UNICODE_STRING MupString;
2495 PDEVICE_OBJECT DeviceObject;
2496
2497 /* Only initialize global state of the driver
2498 * Other inits will happen when required
2499 */
2500 MupInitializeData();
2501
2502 /* Check if DFS is disabled */
2503 MupEnableDfs = MuppIsDfsEnabled();
2504 /* If it's not disabled but when cannot init, disable it */
2505 if (MupEnableDfs && !NT_SUCCESS(DfsDriverEntry(DriverObject, RegistryPath)))
2506 {
2507 MupEnableDfs = FALSE;
2508 }
2509
2510 /* Create the MUP device */
2511 RtlInitUnicodeString(&MupString, L"\\Device\\Mup");
2512 Status = IoCreateDevice(DriverObject, sizeof(MUP_VCB), &MupString, FILE_DEVICE_MULTI_UNC_PROVIDER, 0, FALSE, &DeviceObject);
2513 if (!NT_SUCCESS(Status))
2514 {
2515 if (MupEnableDfs)
2516 {
2517 DfsUnload(DriverObject);
2518 }
2519
2520 MupUninitializeData();
2521
2522 return Status;
2523 }
2524
2525 /* Set our MJ */
2526 DriverObject->DriverUnload = MupUnload;
2527 DriverObject->MajorFunction[IRP_MJ_CREATE] = MupCreate;
2528 DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = MupCreate;
2529 DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = MupCreate;
2530 DriverObject->MajorFunction[IRP_MJ_WRITE] = MupForwardIoRequest;
2531 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = MupFsControl;
2532 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MupCleanup;
2533 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MupClose;
2534
2535 /* And finish init */
2536 mupDeviceObject = DeviceObject;
2537 MupInitializeVcb(DeviceObject->DeviceExtension);
2538
2539 return STATUS_SUCCESS;
2540 }