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