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