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