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