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