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 CODE_SEG("INIT") 57 VOID 58 MupInitializeData(VOID) 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 CODE_SEG("INIT") 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 explicitly 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_PTR)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 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject, 762 PIRP Irp) 763 { 764 PMUP_FCB Fcb; 765 PMUP_CCB Ccb; 766 NTSTATUS Status; 767 PLIST_ENTRY Entry; 768 PMUP_CCB FcbListCcb; 769 BOOLEAN CcbLockAcquired; 770 PMUP_MIC MasterIoContext; 771 PIO_STACK_LOCATION Stack; 772 773 /* If DFS is enabled, check if that's for DFS and is so relay */ 774 if (MupEnableDfs && DeviceObject->DeviceType == FILE_DEVICE_DFS) 775 { 776 return DfsVolumePassThrough(DeviceObject, Irp); 777 } 778 779 Stack = IoGetCurrentIrpStackLocation(Irp); 780 781 FsRtlEnterFileSystem(); 782 783 /* Write request is only possible for a mailslot, we need a FCB */ 784 MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); 785 if (Fcb == NULL || Fcb->NodeType != NODE_TYPE_FCB) 786 { 787 FsRtlExitFileSystem(); 788 Status = STATUS_INVALID_DEVICE_REQUEST; 789 goto Complete; 790 } 791 792 /* Allocate a context */ 793 MasterIoContext = MupAllocateMasterIoContext(); 794 if (MasterIoContext == NULL) 795 { 796 FsRtlExitFileSystem(); 797 Status = STATUS_INSUFFICIENT_RESOURCES; 798 goto Complete; 799 } 800 801 /* Mark the IRP pending and init the context */ 802 IoMarkIrpPending(Irp); 803 MasterIoContext->Irp = Irp; 804 /* Init with a failure to catch if we ever succeed */ 805 MasterIoContext->LastSuccess = STATUS_UNSUCCESSFUL; 806 /* Init with the worth failure possible */ 807 MasterIoContext->LastFailed = STATUS_BAD_NETWORK_PATH; 808 MasterIoContext->Fcb = Fcb; 809 810 _SEH2_TRY 811 { 812 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); 813 CcbLockAcquired = TRUE; 814 815 /* For all the CCB (ie, the mailslots) we have */ 816 for (Entry = Fcb->CcbList.Flink; 817 Entry != &Fcb->CcbList; 818 Entry = Entry->Flink) 819 { 820 FcbListCcb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry); 821 ExReleaseResourceLite(&MupCcbListLock); 822 CcbLockAcquired = FALSE; 823 824 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 825 ++FcbListCcb->NodeReferences; 826 ExReleaseResourceLite(&MupGlobalLock); 827 828 /* Forward the write request */ 829 BuildAndSubmitIrp(Irp, FcbListCcb, MasterIoContext); 830 ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); 831 CcbLockAcquired = TRUE; 832 } 833 834 ExReleaseResourceLite(&MupCcbListLock); 835 CcbLockAcquired = FALSE; 836 } 837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 838 { 839 if (CcbLockAcquired) 840 { 841 ExReleaseResourceLite(&MupCcbListLock); 842 } 843 } 844 _SEH2_END; 845 846 /* And done */ 847 MupDereferenceMasterIoContext(MasterIoContext, NULL); 848 FsRtlExitFileSystem(); 849 850 return STATUS_PENDING; 851 852 Complete: 853 /* Failure case */ 854 Irp->IoStatus.Status = Status; 855 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 856 return Status; 857 } 858 859 PMUP_UNC 860 AddUnregisteredProvider(PCWSTR DeviceName, 861 ULONG ProviderOrder) 862 { 863 PMUP_UNC UncProvider; 864 ULONG StrLen, NameLen; 865 866 /* Just allocate the node */ 867 NameLen = wcslen(DeviceName); 868 StrLen = NameLen * sizeof(WCHAR); 869 UncProvider = MupAllocateUncProvider(StrLen); 870 if (UncProvider == NULL) 871 { 872 return NULL; 873 } 874 875 /* And init it */ 876 UncProvider->DeviceName.MaximumLength = StrLen; 877 UncProvider->DeviceName.Length = StrLen; 878 UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC)); 879 UncProvider->ProviderOrder = ProviderOrder; 880 RtlMoveMemory(UncProvider->DeviceName.Buffer, DeviceName, StrLen); 881 882 /* And add it to the global list 883 * We're using tail here so that when called from registry init, 884 * the providers with highest priority will be in the head of 885 * the list 886 */ 887 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 888 InsertTailList(&MupProviderList, &UncProvider->ProviderListEntry); 889 ExReleaseResourceLite(&MupGlobalLock); 890 891 return UncProvider; 892 } 893 894 VOID 895 InitializeProvider(PCWSTR ProviderName, 896 ULONG ProviderOrder) 897 { 898 NTSTATUS Status; 899 HANDLE KeyHandle; 900 UNICODE_STRING Key, Value; 901 PKEY_VALUE_FULL_INFORMATION Info; 902 OBJECT_ATTRIBUTES ObjectAttributes; 903 ULONG NameLen, StrLen, ResultLength; 904 905 /* Get the information about the provider from registry */ 906 NameLen = wcslen(ProviderName); 907 StrLen = NameLen * sizeof(WCHAR) + sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L"\\NetworkProvider"); 908 Key.Buffer = ExAllocatePoolWithTag(PagedPool, StrLen, TAG_MUP); 909 if (Key.Buffer == NULL) 910 { 911 return; 912 } 913 914 RtlMoveMemory(Key.Buffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\")); 915 Key.MaximumLength = StrLen; 916 Key.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL); 917 RtlAppendUnicodeToString(&Key, ProviderName); 918 RtlAppendUnicodeToString(&Key, L"\\NetworkProvider"); 919 920 InitializeObjectAttributes(&ObjectAttributes, 921 &Key, 922 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 923 NULL, 924 NULL); 925 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 926 ExFreePoolWithTag(Key.Buffer, TAG_MUP); 927 if (!NT_SUCCESS(Status)) 928 { 929 return; 930 } 931 932 RtlInitUnicodeString(&Value, L"DeviceName"); 933 Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, NULL, 0, &ResultLength); 934 if (Status == STATUS_BUFFER_TOO_SMALL) 935 { 936 Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP); 937 if (Info == NULL) 938 { 939 ZwClose(KeyHandle); 940 return; 941 } 942 943 Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, Info, ResultLength, &ResultLength); 944 } 945 else 946 { 947 Info = NULL; 948 } 949 950 ZwClose(KeyHandle); 951 952 /* And create the provider 953 * It will remain unregistered until FsRTL receives a registration request and forwards 954 * it to MUP 955 */ 956 if (NT_SUCCESS(Status)) 957 { 958 ASSERT(Info != NULL); 959 AddUnregisteredProvider((PWSTR)((ULONG_PTR)Info + Info->DataOffset), ProviderOrder); 960 } 961 962 if (Info != NULL) 963 { 964 ExFreePoolWithTag(Info, TAG_MUP); 965 } 966 } 967 968 VOID 969 MupGetProviderInformation(VOID) 970 { 971 BOOLEAN End; 972 NTSTATUS Status; 973 HANDLE KeyHandle; 974 PWSTR Providers, Coma; 975 PKEY_VALUE_FULL_INFORMATION Info; 976 ULONG ResultLength, ProviderCount; 977 OBJECT_ATTRIBUTES ObjectAttributes; 978 UNICODE_STRING NetworkProvider, ProviderOrder; 979 980 /* Open the registry to get the order of the providers */ 981 RtlInitUnicodeString(&NetworkProvider, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order"); 982 InitializeObjectAttributes(&ObjectAttributes, 983 &NetworkProvider, 984 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 985 NULL, 986 NULL); 987 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 988 if (!NT_SUCCESS(Status)) 989 { 990 return; 991 } 992 993 RtlInitUnicodeString(&ProviderOrder, L"ProviderOrder"); 994 Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, NULL, 0, &ResultLength); 995 if (Status == STATUS_BUFFER_TOO_SMALL) 996 { 997 Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP); 998 if (Info == NULL) 999 { 1000 ZwClose(KeyHandle); 1001 return; 1002 } 1003 1004 Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, Info, ResultLength, &ResultLength); 1005 } 1006 else 1007 { 1008 Info = NULL; 1009 } 1010 1011 ZwClose(KeyHandle); 1012 1013 if (NT_SUCCESS(Status)) 1014 { 1015 ASSERT(Info != NULL); 1016 1017 Providers = (PWSTR)((ULONG_PTR)Info + Info->DataOffset); 1018 End = FALSE; 1019 ProviderCount = 0; 1020 1021 /* For all the providers we got (coma-separated list), just create a provider node with the right order 1022 * The order is just the order of the list 1023 * First has highest priority (0) and then, get lower and lower priority 1024 * The highest number is the lowest priority 1025 */ 1026 do 1027 { 1028 Coma = wcschr(Providers, L','); 1029 if (Coma != NULL) 1030 { 1031 *Coma = UNICODE_NULL; 1032 } 1033 else 1034 { 1035 End = TRUE; 1036 } 1037 1038 InitializeProvider(Providers, ProviderCount); 1039 ++ProviderCount; 1040 1041 Providers = Coma + 1; 1042 } while (!End); 1043 } 1044 1045 if (Info != NULL) 1046 { 1047 ExFreePoolWithTag(Info, TAG_MUP); 1048 } 1049 } 1050 1051 PMUP_UNC 1052 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName) 1053 { 1054 PLIST_ENTRY Entry; 1055 PMUP_UNC UncProvider; 1056 1057 /* Browse the list of all the providers nodes we have */ 1058 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1059 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) 1060 { 1061 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry); 1062 1063 /* If one matches the device and is not registered, that's ours! */ 1064 if (!UncProvider->Registered && RtlEqualUnicodeString(RedirectorDeviceName, &UncProvider->DeviceName, TRUE)) 1065 { 1066 UncProvider->NodeStatus = NODE_STATUS_HEALTHY; 1067 break; 1068 } 1069 } 1070 1071 if (Entry == &MupProviderList) 1072 { 1073 UncProvider = NULL; 1074 } 1075 ExReleaseResourceLite(&MupGlobalLock); 1076 1077 return UncProvider; 1078 } 1079 1080 NTSTATUS 1081 RegisterUncProvider(PDEVICE_OBJECT DeviceObject, 1082 PIRP Irp) 1083 1084 { 1085 BOOLEAN New; 1086 PMUP_FCB Fcb; 1087 PMUP_CCB Ccb; 1088 NTSTATUS Status; 1089 PLIST_ENTRY Entry; 1090 PIO_STACK_LOCATION Stack; 1091 IO_STATUS_BLOCK IoStatusBlock; 1092 PMUP_UNC UncProvider, ListEntry; 1093 OBJECT_ATTRIBUTES ObjectAttributes; 1094 UNICODE_STRING RedirectorDeviceName; 1095 OBJECT_HANDLE_INFORMATION HandleInfo; 1096 PMUP_PROVIDER_REGISTRATION_INFO RegInfo; 1097 1098 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject, Irp); 1099 New = FALSE; 1100 1101 /* Check whether providers order was already initialized */ 1102 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1103 if (MupOrderInitialized) 1104 { 1105 ExReleaseResourceLite(&MupGlobalLock); 1106 } 1107 else 1108 { 1109 /* They weren't, so do it */ 1110 MupOrderInitialized = TRUE; 1111 ExReleaseResourceLite(&MupGlobalLock); 1112 MupGetProviderInformation(); 1113 } 1114 1115 Stack = IoGetCurrentIrpStackLocation(Irp); 1116 1117 /* This can only happen with a volume open */ 1118 if (MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb) != NODE_TYPE_VCB) 1119 { 1120 Irp->IoStatus.Status = STATUS_INVALID_HANDLE; 1121 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1122 1123 return STATUS_INVALID_HANDLE; 1124 } 1125 1126 /* Get the registration information */ 1127 RegInfo = (PMUP_PROVIDER_REGISTRATION_INFO)Irp->AssociatedIrp.SystemBuffer; 1128 _SEH2_TRY 1129 { 1130 RedirectorDeviceName.Length = RegInfo->RedirectorDeviceNameLength; 1131 RedirectorDeviceName.MaximumLength = RedirectorDeviceName.Length; 1132 RedirectorDeviceName.Buffer = (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset); 1133 1134 /* Have we got already a node for it? (Like from previous init) */ 1135 UncProvider = MupCheckForUnregisteredProvider(&RedirectorDeviceName); 1136 if (UncProvider == NULL) 1137 { 1138 /* If we don't, allocate a new one */ 1139 New = TRUE; 1140 UncProvider = MupAllocateUncProvider(RegInfo->RedirectorDeviceNameLength); 1141 if (UncProvider == NULL) 1142 { 1143 Status = STATUS_INVALID_USER_BUFFER; 1144 _SEH2_LEAVE; 1145 } 1146 1147 /* Set it up */ 1148 UncProvider->DeviceName.Length = RedirectorDeviceName.Length; 1149 UncProvider->DeviceName.MaximumLength = RedirectorDeviceName.MaximumLength; 1150 UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC)); 1151 1152 /* As it wasn't in registry for order, give the lowest priority possible */ 1153 UncProvider->ProviderOrder = MAXLONG; 1154 RtlMoveMemory(UncProvider->DeviceName.Buffer, (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset), RegInfo->RedirectorDeviceNameLength); 1155 } 1156 1157 /* Continue registration */ 1158 UncProvider->MailslotsSupported = RegInfo->MailslotsSupported; 1159 ++UncProvider->NodeReferences; 1160 1161 /* Open a handle to the device */ 1162 InitializeObjectAttributes(&ObjectAttributes, 1163 &UncProvider->DeviceName, 1164 OBJ_CASE_INSENSITIVE, 1165 NULL, 1166 NULL); 1167 Status = NtOpenFile(&UncProvider->DeviceHandle, 1168 FILE_TRAVERSE, 1169 &ObjectAttributes, 1170 &IoStatusBlock, 1171 FILE_SHARE_READ | FILE_SHARE_WRITE, 1172 FILE_DIRECTORY_FILE); 1173 if (NT_SUCCESS(Status)) 1174 { 1175 Status = IoStatusBlock.Status; 1176 } 1177 1178 /* And return the provider (as CCB) */ 1179 if (NT_SUCCESS(Status)) 1180 { 1181 Stack->FileObject->FsContext2 = UncProvider; 1182 Status = ObReferenceObjectByHandle(UncProvider->DeviceHandle, 0, NULL, KernelMode, (PVOID *)&UncProvider->FileObject, &HandleInfo); 1183 if (!NT_SUCCESS(Status)) 1184 { 1185 NtClose(UncProvider->DeviceHandle); 1186 } 1187 } 1188 1189 if (!NT_SUCCESS(Status)) 1190 { 1191 MupDereferenceUncProvider(UncProvider); 1192 } 1193 else 1194 { 1195 UncProvider->DeviceObject = IoGetRelatedDeviceObject(UncProvider->FileObject); 1196 1197 /* Now, insert the provider in our global list 1198 * They are sorted by order 1199 */ 1200 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1201 ++MupProviderCount; 1202 if (New) 1203 { 1204 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) 1205 { 1206 ListEntry = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry); 1207 1208 if (UncProvider->ProviderOrder < ListEntry->ProviderOrder) 1209 { 1210 break; 1211 } 1212 } 1213 1214 InsertTailList(Entry, &UncProvider->ProviderListEntry); 1215 } 1216 UncProvider->Registered = TRUE; 1217 ExReleaseResourceLite(&MupGlobalLock); 1218 Status = STATUS_SUCCESS; 1219 1220 DPRINT1("UNC provider %wZ registered\n", &UncProvider->DeviceName); 1221 } 1222 } 1223 _SEH2_FINALLY 1224 { 1225 if (_SEH2_AbnormalTermination()) 1226 { 1227 Status = STATUS_INVALID_USER_BUFFER; 1228 } 1229 1230 MupDereferenceVcb((PMUP_VCB)Fcb); 1231 1232 Irp->IoStatus.Status = Status; 1233 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1234 } 1235 _SEH2_END; 1236 1237 return Status; 1238 } 1239 1240 NTSTATUS 1241 NTAPI 1242 MupFsControl(PDEVICE_OBJECT DeviceObject, 1243 PIRP Irp) 1244 { 1245 NTSTATUS Status; 1246 PIO_STACK_LOCATION Stack; 1247 1248 Stack = IoGetCurrentIrpStackLocation(Irp); 1249 1250 _SEH2_TRY 1251 { 1252 /* MUP only understands a single FSCTL code: registering UNC provider */ 1253 if (Stack->Parameters.FileSystemControl.FsControlCode == FSCTL_MUP_REGISTER_PROVIDER) 1254 { 1255 /* It obviously has to come from a driver/kernelmode thread */ 1256 if (Irp->RequestorMode == UserMode) 1257 { 1258 Status = STATUS_ACCESS_DENIED; 1259 1260 Irp->IoStatus.Status = Status; 1261 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1262 1263 _SEH2_LEAVE; 1264 } 1265 1266 Status = RegisterUncProvider(DeviceObject, Irp); 1267 } 1268 else 1269 { 1270 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */ 1271 if (!MupEnableDfs) 1272 { 1273 Status = STATUS_INVALID_PARAMETER; 1274 1275 Irp->IoStatus.Status = Status; 1276 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1277 1278 _SEH2_LEAVE; 1279 } 1280 1281 Status = DfsFsdFileSystemControl(DeviceObject, Irp); 1282 } 1283 } 1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1285 { 1286 Status = _SEH2_GetExceptionCode(); 1287 } 1288 _SEH2_END; 1289 1290 return Status; 1291 } 1292 1293 VOID 1294 MupSetFileObject(PFILE_OBJECT FileObject, 1295 PMUP_FCB Fcb, 1296 PMUP_CCB Ccb) 1297 { 1298 FileObject->FsContext = Fcb; 1299 FileObject->FsContext2 = Ccb; 1300 } 1301 1302 NTSTATUS 1303 MupRerouteOpen(PFILE_OBJECT FileObject, 1304 PMUP_UNC UncProvider) 1305 { 1306 PWSTR FullPath; 1307 ULONG TotalLength; 1308 1309 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject->FileName, &UncProvider->DeviceName); 1310 1311 /* Get the full path name (device name first, and requested file name appended) */ 1312 TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length; 1313 if (TotalLength > MAXUSHORT) 1314 { 1315 return STATUS_NAME_TOO_LONG; 1316 } 1317 1318 /* Allocate a buffer big enough */ 1319 FullPath = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP); 1320 if (FullPath == NULL) 1321 { 1322 return STATUS_INSUFFICIENT_RESOURCES; 1323 } 1324 1325 /* Create the full path */ 1326 RtlMoveMemory(FullPath, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length); 1327 RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath + UncProvider->DeviceName.Length), FileObject->FileName.Buffer, FileObject->FileName.Length); 1328 1329 /* And redo the path in the file object */ 1330 ExFreePoolWithTag(FileObject->FileName.Buffer, 0); 1331 FileObject->FileName.Buffer = FullPath; 1332 FileObject->FileName.MaximumLength = TotalLength; 1333 FileObject->FileName.Length = FileObject->FileName.MaximumLength; 1334 1335 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */ 1336 return STATUS_REPARSE; 1337 } 1338 1339 NTSTATUS 1340 BroadcastOpen(PIRP Irp) 1341 { 1342 PMUP_FCB Fcb; 1343 HANDLE Handle; 1344 PLIST_ENTRY Entry; 1345 PMUP_CCB Ccb = NULL; 1346 PMUP_UNC UncProvider; 1347 UNICODE_STRING FullPath; 1348 PFILE_OBJECT FileObject; 1349 PIO_STACK_LOCATION Stack; 1350 NTSTATUS Status, LastFailed; 1351 ULONG TotalLength, LastOrder; 1352 IO_STATUS_BLOCK IoStatusBlock; 1353 OBJECT_ATTRIBUTES ObjectAttributes; 1354 OBJECT_HANDLE_INFORMATION HandleInfo; 1355 BOOLEAN Locked, Referenced, CcbInitialized; 1356 1357 Fcb = MupCreateFcb(); 1358 if (Fcb == NULL) 1359 { 1360 return STATUS_INSUFFICIENT_RESOURCES; 1361 } 1362 1363 Stack = IoGetCurrentIrpStackLocation(Irp); 1364 FileObject = Stack->FileObject; 1365 Locked = FALSE; 1366 Referenced = FALSE; 1367 CcbInitialized = FALSE; 1368 LastFailed = STATUS_NO_SUCH_FILE; 1369 LastOrder = (ULONG)-1; 1370 1371 _SEH2_TRY 1372 { 1373 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1374 Locked = TRUE; 1375 1376 /* Associate our FCB with the FO */ 1377 MupSetFileObject(FileObject, Fcb, NULL); 1378 Fcb->FileObject = FileObject; 1379 1380 /* Now, broadcast the open to any UNC provider that supports mailslots */ 1381 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) 1382 { 1383 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry); 1384 ++UncProvider->NodeReferences; 1385 Referenced = TRUE; 1386 1387 ExReleaseResourceLite(&MupGlobalLock); 1388 Locked = FALSE; 1389 1390 TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length; 1391 if (UncProvider->MailslotsSupported && TotalLength <= MAXUSHORT) 1392 { 1393 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */ 1394 FullPath.Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP); 1395 if (FullPath.Buffer == NULL) 1396 { 1397 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 1398 } 1399 1400 FullPath.Length = TotalLength; 1401 FullPath.MaximumLength = TotalLength; 1402 RtlMoveMemory(FullPath.Buffer, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length); 1403 RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath.Buffer + UncProvider->DeviceName.Length), 1404 FileObject->FileName.Buffer, 1405 FileObject->FileName.Length); 1406 1407 /* And just forward the creation request */ 1408 InitializeObjectAttributes(&ObjectAttributes, 1409 &FullPath, 1410 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 1411 NULL, 1412 NULL); 1413 Status = IoCreateFile(&Handle, 1414 Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_SIMPLE_RIGHTS_MASK, 1415 &ObjectAttributes, 1416 &IoStatusBlock, 1417 NULL, 1418 Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS, 1419 Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS, 1420 FILE_OPEN, 1421 Stack->Parameters.Create.Options & FILE_VALID_SET_FLAGS, 1422 NULL, 1423 0, 1424 CreateFileTypeNone, 1425 NULL, 1426 IO_NO_PARAMETER_CHECKING); 1427 1428 ExFreePoolWithTag(FullPath.Buffer, TAG_MUP); 1429 1430 /* If opening succeed */ 1431 if (NT_SUCCESS(Status)) 1432 { 1433 Status = IoStatusBlock.Status; 1434 1435 /* Create a CCB */ 1436 Ccb = MupCreateCcb(); 1437 if (Ccb == NULL) 1438 { 1439 Status = STATUS_INSUFFICIENT_RESOURCES; 1440 } 1441 1442 /* And associated a FO to it */ 1443 if (NT_SUCCESS(Status)) 1444 { 1445 Status = ObReferenceObjectByHandle(Handle, 0, 0, 0, (PVOID *)&Ccb->FileObject, &HandleInfo); 1446 ZwClose(Handle); 1447 } 1448 } 1449 1450 /* If we failed, remember the last failed status of the higher priority provider */ 1451 if (!NT_SUCCESS(Status)) 1452 { 1453 if (UncProvider->ProviderOrder <= LastOrder) 1454 { 1455 LastOrder = UncProvider->ProviderOrder; 1456 LastFailed = Status; 1457 } 1458 } 1459 /* Otherwise, properly attach our CCB to the mailslot */ 1460 else 1461 { 1462 Ccb->DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject); 1463 Ccb->Fcb = Fcb; 1464 1465 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1466 Locked = TRUE; 1467 ++Fcb->NodeReferences; 1468 ExReleaseResourceLite(&MupGlobalLock); 1469 Locked = FALSE; 1470 CcbInitialized = TRUE; 1471 1472 InsertTailList(&Fcb->CcbList, &Ccb->CcbListEntry); 1473 } 1474 } 1475 1476 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1477 Locked = TRUE; 1478 MupDereferenceUncProvider(UncProvider); 1479 Referenced = FALSE; 1480 } 1481 1482 ExReleaseResourceLite(&MupGlobalLock); 1483 Locked = FALSE; 1484 } 1485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1486 { 1487 Status = _SEH2_GetExceptionCode(); 1488 } 1489 _SEH2_END; 1490 1491 /* If we at least opened one mailslot, return success */ 1492 Status = (CcbInitialized ? STATUS_SUCCESS : LastFailed); 1493 1494 if (Referenced) 1495 { 1496 MupDereferenceUncProvider(UncProvider); 1497 } 1498 1499 if (Locked) 1500 { 1501 ExReleaseResourceLite(&MupGlobalLock); 1502 } 1503 1504 /* In case of failure, don't leak CCB */ 1505 if (!NT_SUCCESS(Status) && Ccb != NULL) 1506 { 1507 MupFreeNode(Ccb); 1508 } 1509 1510 return Status; 1511 } 1512 1513 PIRP 1514 MupBuildIoControlRequest(PFILE_OBJECT FileObject, 1515 PVOID Context, 1516 ULONG MajorFunction, 1517 ULONG IoctlCode, 1518 PVOID InputBuffer, 1519 ULONG InputBufferSize, 1520 PVOID OutputBuffer, 1521 ULONG OutputBufferSize, 1522 PIO_COMPLETION_ROUTINE CompletionRoutine) 1523 { 1524 PIRP Irp; 1525 PIO_STACK_LOCATION Stack; 1526 PDEVICE_OBJECT DeviceObject; 1527 1528 if (InputBuffer == NULL) 1529 { 1530 return NULL; 1531 } 1532 1533 /* Get the device object */ 1534 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1535 /* Allocate the IRP (with one more location for us */ 1536 Irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE); 1537 if (Irp == NULL) 1538 { 1539 return NULL; 1540 } 1541 1542 /* Skip our location */ 1543 IoSetNextIrpStackLocation(Irp); 1544 /* Setup the IRP */ 1545 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1546 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1547 IoSetCompletionRoutine(Irp, CompletionRoutine, Context, TRUE, TRUE, TRUE); 1548 1549 /* Setup the stack */ 1550 Stack = IoGetNextIrpStackLocation(Irp); 1551 Stack->MajorFunction = MajorFunction; 1552 Stack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferSize; 1553 Stack->Parameters.DeviceIoControl.InputBufferLength = InputBufferSize; 1554 Stack->Parameters.DeviceIoControl.IoControlCode = IoctlCode; 1555 Stack->MinorFunction = 0; 1556 Stack->FileObject = FileObject; 1557 Stack->DeviceObject = DeviceObject; 1558 1559 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode)) 1560 { 1561 case METHOD_BUFFERED: 1562 /* If it's buffered, just pass the buffers we got */ 1563 Irp->MdlAddress = NULL; 1564 Irp->AssociatedIrp.SystemBuffer = InputBuffer; 1565 Irp->UserBuffer = OutputBuffer; 1566 Irp->Flags = IRP_BUFFERED_IO; 1567 1568 if (OutputBuffer != NULL) 1569 { 1570 Irp->Flags |= IRP_INPUT_OPERATION; 1571 } 1572 break; 1573 1574 case METHOD_IN_DIRECT: 1575 case METHOD_OUT_DIRECT: 1576 /* Otherwise, allocate an MDL */ 1577 if (IoAllocateMdl(InputBuffer, InputBufferSize, FALSE, FALSE, Irp) == NULL) 1578 { 1579 IoFreeIrp(Irp); 1580 return NULL; 1581 } 1582 1583 Irp->AssociatedIrp.SystemBuffer = InputBuffer; 1584 Irp->Flags = IRP_BUFFERED_IO; 1585 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoReadAccess); 1586 break; 1587 1588 case METHOD_NEITHER: 1589 /* Or pass the buffers */ 1590 Irp->UserBuffer = OutputBuffer; 1591 Irp->MdlAddress = NULL; 1592 Irp->AssociatedIrp.SystemBuffer = NULL; 1593 Stack->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; 1594 break; 1595 } 1596 1597 return Irp; 1598 } 1599 1600 VOID 1601 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext) 1602 { 1603 ExDeleteResourceLite(&MasterQueryContext->QueryPathListLock); 1604 ExFreePoolWithTag(MasterQueryContext, TAG_MUP); 1605 } 1606 1607 NTSTATUS 1608 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext) 1609 { 1610 LONG References; 1611 NTSTATUS Status; 1612 BOOLEAN KeepExtraRef; 1613 1614 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1615 --MasterQueryContext->NodeReferences; 1616 References = MasterQueryContext->NodeReferences; 1617 ExReleaseResourceLite(&MupGlobalLock); 1618 1619 if (References != 0) 1620 { 1621 DPRINT("Still having refs (%ld)\n", References); 1622 return STATUS_PENDING; 1623 } 1624 1625 /* We HAVE an IRP to complete. It cannot be NULL 1626 * Please, help preserving kittens, don't provide NULL IRPs. 1627 */ 1628 if (MasterQueryContext->Irp == NULL) 1629 { 1630 KeBugCheck(FILE_SYSTEM); 1631 } 1632 1633 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 1634 RemoveEntryList(&MasterQueryContext->MQCListEntry); 1635 ExReleaseResourceLite(&MupGlobalLock); 1636 1637 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); 1638 KeepExtraRef = MasterQueryContext->Prefix->KeepExtraRef; 1639 MupDereferenceKnownPrefix(MasterQueryContext->Prefix); 1640 1641 /* We found a provider? */ 1642 if (MasterQueryContext->LatestProvider != NULL) 1643 { 1644 /* With a successful status? */ 1645 if (MasterQueryContext->LatestStatus == STATUS_SUCCESS) 1646 { 1647 /* Then, it's time to reroute, someone accepted to handle the file creation request! */ 1648 if (!KeepExtraRef) 1649 { 1650 MupDereferenceKnownPrefix(MasterQueryContext->Prefix); 1651 } 1652 1653 ExReleaseResourceLite(&MupPrefixTableLock); 1654 /* Reroute & complete :-) */ 1655 Status = MupRerouteOpen(MasterQueryContext->FileObject, MasterQueryContext->LatestProvider); 1656 goto Complete; 1657 } 1658 else 1659 { 1660 MupDereferenceUncProvider(MasterQueryContext->LatestProvider); 1661 } 1662 } 1663 1664 MupDereferenceKnownPrefix(MasterQueryContext->Prefix); 1665 ExReleaseResourceLite(&MupPrefixTableLock); 1666 1667 /* Return the highest failed status we had */ 1668 Status = MasterQueryContext->LatestStatus; 1669 1670 Complete: 1671 /* In finally, complete the IRP for real! */ 1672 MasterQueryContext->Irp->IoStatus.Status = Status; 1673 IoCompleteRequest(MasterQueryContext->Irp, IO_DISK_INCREMENT); 1674 1675 MasterQueryContext->Irp = NULL; 1676 MupFreeMasterQueryContext(MasterQueryContext); 1677 1678 return Status; 1679 } 1680 1681 NTSTATUS 1682 NTAPI 1683 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject, 1684 PIRP Irp, 1685 PVOID Context) 1686 { 1687 PMUP_PFX Prefix; 1688 ULONG LatestPos, Pos; 1689 PWSTR AcceptedPrefix; 1690 PMUP_MQC MasterQueryContext; 1691 NTSTATUS Status, TableStatus; 1692 PQUERY_PATH_CONTEXT QueryContext; 1693 PQUERY_PATH_RESPONSE QueryResponse; 1694 1695 /* Get all the data from our query to the provider */ 1696 QueryContext = (PQUERY_PATH_CONTEXT)Context; 1697 QueryResponse = (PQUERY_PATH_RESPONSE)QueryContext->QueryPathRequest; 1698 MasterQueryContext = QueryContext->MasterQueryContext; 1699 Status = Irp->IoStatus.Status; 1700 1701 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext->UncProvider->DeviceName, QueryResponse->LengthAccepted, Status); 1702 1703 ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE); 1704 RemoveEntryList(&QueryContext->QueryPathListEntry); 1705 1706 /* If the driver returned a success, and an acceptance length */ 1707 if (NT_SUCCESS(Status) && QueryResponse->LengthAccepted > 0) 1708 { 1709 Prefix = MasterQueryContext->Prefix; 1710 1711 /* Check if we already found a provider from a previous iteration */ 1712 if (MasterQueryContext->LatestProvider != NULL) 1713 { 1714 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */ 1715 if (QueryContext->UncProvider->ProviderOrder >= MasterQueryContext->LatestProvider->ProviderOrder) 1716 { 1717 MupDereferenceUncProvider(QueryContext->UncProvider); 1718 goto Cleanup; 1719 } 1720 1721 /* Otherwise, if the prefix was in the prefix table, just drop it: 1722 * we have a provider which supersedes the accepted prefix, so leave 1723 * room for the new prefix/provider 1724 */ 1725 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); 1726 if (Prefix->InTable) 1727 { 1728 RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry); 1729 RemoveEntryList(&Prefix->PrefixListEntry); 1730 Prefix->InTable = FALSE; 1731 } 1732 ExReleaseResourceLite(&MupPrefixTableLock); 1733 1734 Prefix->KeepExtraRef = FALSE; 1735 1736 /* Release data associated with the current prefix, if any 1737 * We'll renew them with the new accepted prefix 1738 */ 1739 if (Prefix->AcceptedPrefix.Length != 0 && Prefix->AcceptedPrefix.Buffer != NULL) 1740 { 1741 ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP); 1742 Prefix->AcceptedPrefix.MaximumLength = 0; 1743 Prefix->AcceptedPrefix.Length = 0; 1744 Prefix->AcceptedPrefix.Buffer = NULL; 1745 Prefix->ExternalAlloc = FALSE; 1746 } 1747 1748 /* If there was also a provider, drop it, the new one 1749 * is different 1750 */ 1751 if (Prefix->UncProvider != NULL) 1752 { 1753 MupDereferenceUncProvider(Prefix->UncProvider); 1754 Prefix->UncProvider = NULL; 1755 } 1756 } 1757 1758 /* Now, set our information about the provider that accepted the prefix */ 1759 MasterQueryContext->LatestProvider = QueryContext->UncProvider; 1760 MasterQueryContext->LatestStatus = Status; 1761 1762 if (MasterQueryContext->FileObject->FsContext2 != (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT) 1763 { 1764 /* Allocate a buffer for the prefix */ 1765 AcceptedPrefix = ExAllocatePoolWithTag(PagedPool, QueryResponse->LengthAccepted, TAG_MUP); 1766 if (AcceptedPrefix == NULL) 1767 { 1768 Prefix->InTable = FALSE; 1769 } 1770 else 1771 { 1772 /* Set it up to the accepted length */ 1773 RtlMoveMemory(AcceptedPrefix, MasterQueryContext->FileObject->FileName.Buffer, QueryResponse->LengthAccepted); 1774 Prefix->UncProvider = MasterQueryContext->LatestProvider; 1775 Prefix->AcceptedPrefix.Buffer = AcceptedPrefix; 1776 Prefix->AcceptedPrefix.Length = QueryResponse->LengthAccepted; 1777 Prefix->AcceptedPrefix.MaximumLength = QueryResponse->LengthAccepted; 1778 Prefix->ExternalAlloc = TRUE; 1779 1780 /* Insert the accepted prefix in the table of known prefixes */ 1781 DPRINT1("%wZ accepted %wZ\n", &Prefix->UncProvider->DeviceName, &Prefix->AcceptedPrefix); 1782 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); 1783 if (RtlInsertUnicodePrefix(&MupPrefixTable, &Prefix->AcceptedPrefix, &Prefix->PrefixTableEntry)) 1784 { 1785 InsertHeadList(&MupPrefixList, &Prefix->PrefixListEntry); 1786 Prefix->InTable = TRUE; 1787 Prefix->KeepExtraRef = TRUE; 1788 } 1789 else 1790 { 1791 Prefix->InTable = FALSE; 1792 } 1793 ExReleaseResourceLite(&MupPrefixTableLock); 1794 } 1795 } 1796 } 1797 else 1798 { 1799 MupDereferenceUncProvider(QueryContext->UncProvider); 1800 1801 /* We failed and didn't find any provider over the latest iterations */ 1802 if (MasterQueryContext->LatestProvider == NULL) 1803 { 1804 /* If we had a success though (broken provider?) set our failed status */ 1805 if (NT_SUCCESS(MasterQueryContext->LatestStatus)) 1806 { 1807 MasterQueryContext->LatestStatus = Status; 1808 } 1809 else 1810 { 1811 TableStatus = MupOrderedErrorList[0]; 1812 LatestPos = 0; 1813 1814 /* Otherwise, time to compare statuses, between the latest failed 1815 * and the current failure. 1816 * We have an order table of failed status: the deeper you go in the 1817 * table, the more the error is critical. 1818 * Our goal is to return the most critical status that was returned by 1819 * any of the providers 1820 */ 1821 1822 /* Look for latest status position */ 1823 while (TableStatus != 0 && TableStatus != MasterQueryContext->LatestStatus) 1824 { 1825 ++LatestPos; 1826 TableStatus = MupOrderedErrorList[LatestPos]; 1827 } 1828 1829 /* If at pos 0, the new status is likely more critical */ 1830 if (LatestPos == 0) 1831 { 1832 MasterQueryContext->LatestStatus = Status; 1833 } 1834 else 1835 { 1836 /* Otherwise, find position of the new status in the table */ 1837 Pos = 0; 1838 do 1839 { 1840 if (Status == MupOrderedErrorList[Pos]) 1841 { 1842 break; 1843 } 1844 1845 ++Pos; 1846 } 1847 while (Pos < LatestPos); 1848 1849 /* If it has a higher position (more critical), return it */ 1850 if (Pos >= LatestPos) 1851 { 1852 MasterQueryContext->LatestStatus = Status; 1853 } 1854 } 1855 } 1856 } 1857 } 1858 1859 Cleanup: 1860 ExFreePoolWithTag(QueryResponse, TAG_MUP); 1861 ExFreePoolWithTag(QueryContext, TAG_MUP); 1862 IoFreeIrp(Irp); 1863 1864 ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock); 1865 MupDereferenceMasterQueryContext(MasterQueryContext); 1866 1867 return STATUS_MORE_PROCESSING_REQUIRED; 1868 } 1869 1870 NTSTATUS 1871 CreateRedirectedFile(PIRP Irp, 1872 PFILE_OBJECT FileObject, 1873 PIO_SECURITY_CONTEXT SecurityContext) 1874 { 1875 LONG Len; 1876 WCHAR Cur; 1877 PWSTR Name; 1878 PIRP QueryIrp; 1879 NTSTATUS Status; 1880 PMUP_PFX Prefix; 1881 PLIST_ENTRY Entry; 1882 PMUP_UNC UncProvider; 1883 PIO_STACK_LOCATION Stack; 1884 LARGE_INTEGER CurrentTime; 1885 PMUP_MQC MasterQueryContext; 1886 PQUERY_PATH_CONTEXT QueryContext; 1887 PQUERY_PATH_REQUEST QueryPathRequest; 1888 PUNICODE_PREFIX_TABLE_ENTRY TableEntry; 1889 BOOLEAN Locked, Referenced, BreakOnFirst; 1890 1891 /* We cannot open a file without a name */ 1892 if (FileObject->FileName.Length == 0) 1893 { 1894 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 1895 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1896 1897 return STATUS_INVALID_DEVICE_REQUEST; 1898 } 1899 1900 DPRINT1("Request for opening: %wZ\n", &FileObject->FileName); 1901 1902 Referenced = FALSE; 1903 BreakOnFirst = TRUE; 1904 Status = STATUS_BAD_NETWORK_PATH; 1905 1906 ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); 1907 /* First, try to see if that's a prefix we already know */ 1908 TableEntry = RtlFindUnicodePrefix(&MupPrefixTable, &FileObject->FileName, 1); 1909 if (TableEntry != NULL) 1910 { 1911 Prefix = CONTAINING_RECORD(TableEntry, MUP_PFX, PrefixTableEntry); 1912 1913 DPRINT("Matching prefix found: %wZ\n", &Prefix->AcceptedPrefix); 1914 1915 /* If so, check whether the prefix is still valid */ 1916 KeQuerySystemTime(&CurrentTime); 1917 if (Prefix->ValidityTimeout.QuadPart < CurrentTime.QuadPart) 1918 { 1919 /* It is: so, update its validity period and reroute file opening */ 1920 MupCalculateTimeout(&Prefix->ValidityTimeout); 1921 Status = MupRerouteOpen(FileObject, Prefix->UncProvider); 1922 ExReleaseResourceLite(&MupPrefixTableLock); 1923 1924 if (Status == STATUS_REPARSE) 1925 { 1926 Irp->IoStatus.Information = FILE_SUPERSEDED; 1927 } 1928 1929 Irp->IoStatus.Status = Status; 1930 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1931 1932 return Status; 1933 } 1934 1935 /* When here, we found a matching prefix, but expired, remove it from the table 1936 * We'll redo a full search 1937 */ 1938 if (Prefix->InTable) 1939 { 1940 MupRemoveKnownPrefixEntry(Prefix); 1941 } 1942 } 1943 ExReleaseResourceLite(&MupPrefixTableLock); 1944 1945 Stack = IoGetCurrentIrpStackLocation(Irp); 1946 /* First of all, start looking for a mailslot */ 1947 if (FileObject->FileName.Buffer[0] == L'\\' && Stack->MajorFunction != IRP_MJ_CREATE) 1948 { 1949 Name = &FileObject->FileName.Buffer[1]; 1950 Len = FileObject->FileName.Length; 1951 1952 /* Skip the remote destination name */ 1953 do 1954 { 1955 Len -= sizeof(WCHAR); 1956 if (Len <= 0) 1957 { 1958 break; 1959 } 1960 1961 Cur = *Name; 1962 ++Name; 1963 } while (Cur != L'\\'); 1964 Len -= sizeof(WCHAR); 1965 1966 /* If we still have room for "Mailslot" to fit */ 1967 if (Len >= (sizeof(L"Mailslot") - sizeof(UNICODE_NULL))) 1968 { 1969 /* Get the len in terms of chars count */ 1970 Len /= sizeof(WCHAR); 1971 if (Len > ((sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR))) 1972 { 1973 Len = (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR); 1974 } 1975 1976 /* It's indeed a mailslot opening! */ 1977 if (_wcsnicmp(Name, L"Mailslot", Len) == 0) 1978 { 1979 /* Broadcast open */ 1980 Status = BroadcastOpen(Irp); 1981 if (Status == STATUS_REPARSE) 1982 { 1983 Irp->IoStatus.Information = FILE_SUPERSEDED; 1984 } 1985 1986 Irp->IoStatus.Status = Status; 1987 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 1988 1989 return Status; 1990 } 1991 } 1992 } 1993 1994 /* Ok, at that point, that's a regular MUP opening (if no DFS) */ 1995 if (!MupEnableDfs || FileObject->FsContext2 == (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT) 1996 { 1997 /* We won't complete immediately */ 1998 IoMarkIrpPending(Irp); 1999 2000 /* Allocate a new prefix for our search */ 2001 Prefix = MupAllocatePrefixEntry(0); 2002 if (Prefix == NULL) 2003 { 2004 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 2005 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2006 2007 return STATUS_PENDING; 2008 } 2009 2010 /* Allocate a context for our search */ 2011 MasterQueryContext = MupAllocateMasterQueryContext(); 2012 if (MasterQueryContext == NULL) 2013 { 2014 MupFreeNode(Prefix); 2015 2016 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 2017 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2018 2019 return STATUS_PENDING; 2020 } 2021 2022 MasterQueryContext->Irp = Irp; 2023 MasterQueryContext->FileObject = FileObject; 2024 MasterQueryContext->LatestProvider = NULL; 2025 MasterQueryContext->Prefix = Prefix; 2026 MasterQueryContext->LatestStatus = STATUS_BAD_NETWORK_PATH; 2027 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2028 InsertTailList(&MupMasterQueryList, &MasterQueryContext->MQCListEntry); 2029 ++Prefix->NodeReferences; 2030 ExReleaseResourceLite(&MupGlobalLock); 2031 2032 _SEH2_TRY 2033 { 2034 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2035 Locked = TRUE; 2036 2037 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */ 2038 for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) 2039 { 2040 UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry); 2041 2042 ++UncProvider->NodeReferences; 2043 Referenced = TRUE; 2044 2045 ExReleaseResourceLite(&MupGlobalLock); 2046 Locked = FALSE; 2047 2048 /* We will obviously only query registered providers */ 2049 if (UncProvider->Registered) 2050 { 2051 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */ 2052 QueryPathRequest = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), TAG_MUP); 2053 if (QueryPathRequest == NULL) 2054 { 2055 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2056 } 2057 2058 /* Allocate a context for IRP completion routine 2059 * In case a prefix matches the path, the reroute will happen 2060 * in the completion routine, when we have return from the provider 2061 */ 2062 QueryContext = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_PATH_CONTEXT), TAG_MUP); 2063 if (QueryContext == NULL) 2064 { 2065 ExFreePoolWithTag(QueryPathRequest, TAG_MUP); 2066 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2067 } 2068 2069 InitializeListHead(&QueryContext->QueryPathListEntry); 2070 QueryContext->MasterQueryContext = MasterQueryContext; 2071 QueryContext->QueryPathRequest = QueryPathRequest; 2072 QueryPathRequest->PathNameLength = FileObject->FileName.Length; 2073 QueryPathRequest->SecurityContext = SecurityContext; 2074 RtlMoveMemory(QueryPathRequest->FilePathName, FileObject->FileName.Buffer, FileObject->FileName.Length); 2075 2076 /* Build our IRP for the query */ 2077 QueryIrp = MupBuildIoControlRequest(UncProvider->FileObject, 2078 QueryContext, 2079 IRP_MJ_DEVICE_CONTROL, 2080 IOCTL_REDIR_QUERY_PATH, 2081 QueryPathRequest, 2082 FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), 2083 QueryPathRequest, 2084 sizeof(QUERY_PATH_RESPONSE), 2085 QueryPathCompletionRoutine); 2086 if (QueryIrp == NULL) 2087 { 2088 ExFreePoolWithTag(QueryContext, TAG_MUP); 2089 ExFreePoolWithTag(QueryPathRequest, TAG_MUP); 2090 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2091 } 2092 2093 QueryIrp->RequestorMode = KernelMode; 2094 QueryContext->UncProvider = UncProvider; 2095 QueryContext->Irp = QueryIrp; 2096 2097 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2098 ++UncProvider->NodeReferences; 2099 ++MasterQueryContext->NodeReferences; 2100 ExReleaseResourceLite(&MupGlobalLock); 2101 2102 ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE); 2103 InsertTailList(&MasterQueryContext->QueryPathList, &QueryContext->QueryPathListEntry); 2104 ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock); 2105 2106 /* Query the provider !*/ 2107 DPRINT1("Requesting UNC provider: %wZ\n", &UncProvider->DeviceName); 2108 DPRINT("Calling: %wZ\n", &UncProvider->DeviceObject->DriverObject->DriverName); 2109 Status = IoCallDriver(UncProvider->DeviceObject, QueryIrp); 2110 } 2111 2112 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2113 Locked = TRUE; 2114 2115 /* We're done with that provider */ 2116 MupDereferenceUncProvider(UncProvider); 2117 Referenced = FALSE; 2118 2119 /* If query went fine on the first request, just break and leave */ 2120 if (BreakOnFirst && Status == STATUS_SUCCESS) 2121 { 2122 break; 2123 } 2124 2125 BreakOnFirst = FALSE; 2126 } 2127 } 2128 _SEH2_FINALLY 2129 { 2130 if (_SEH2_AbnormalTermination()) 2131 { 2132 MasterQueryContext->LatestStatus = STATUS_INSUFFICIENT_RESOURCES; 2133 } 2134 2135 if (Referenced) 2136 { 2137 MupDereferenceUncProvider(UncProvider); 2138 } 2139 2140 if (Locked) 2141 { 2142 ExReleaseResourceLite(&MupGlobalLock); 2143 } 2144 2145 MupDereferenceMasterQueryContext(MasterQueryContext); 2146 2147 Status = STATUS_PENDING; 2148 } 2149 _SEH2_END; 2150 } 2151 else 2152 { 2153 UNIMPLEMENTED; 2154 Status = STATUS_NOT_IMPLEMENTED; 2155 } 2156 2157 return Status; 2158 } 2159 2160 NTSTATUS 2161 OpenMupFileSystem(PMUP_VCB Vcb, 2162 PFILE_OBJECT FileObject, 2163 ACCESS_MASK DesiredAccess, 2164 USHORT ShareAccess) 2165 { 2166 NTSTATUS Status; 2167 2168 DPRINT1("Opening MUP\n"); 2169 2170 ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE); 2171 _SEH2_TRY 2172 { 2173 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */ 2174 Status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess, TRUE); 2175 if (NT_SUCCESS(Status)) 2176 { 2177 ++Vcb->NodeReferences; 2178 MupSetFileObject(FileObject, (PMUP_FCB)Vcb, NULL); 2179 Status = STATUS_SUCCESS; 2180 } 2181 } 2182 _SEH2_FINALLY 2183 { 2184 ExReleaseResourceLite(&MupVcbLock); 2185 } 2186 _SEH2_END; 2187 2188 return Status; 2189 } 2190 2191 NTSTATUS 2192 NTAPI 2193 MupCreate(PDEVICE_OBJECT DeviceObject, 2194 PIRP Irp) 2195 { 2196 NTSTATUS Status; 2197 PIO_STACK_LOCATION Stack; 2198 PFILE_OBJECT FileObject, RelatedFileObject; 2199 2200 FsRtlEnterFileSystem(); 2201 2202 _SEH2_TRY 2203 { 2204 /* If DFS is enabled, check if that's for DFS and is so relay */ 2205 if (MupEnableDfs && (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM)) 2206 { 2207 Status = DfsFsdCreate(DeviceObject, Irp); 2208 } 2209 else 2210 { 2211 Stack = IoGetCurrentIrpStackLocation(Irp); 2212 FileObject = Stack->FileObject; 2213 RelatedFileObject = FileObject->RelatedFileObject; 2214 2215 /* 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 */ 2216 if (FileObject->FileName.Length != 0 || (RelatedFileObject != NULL && ((PMUP_FCB)(RelatedFileObject->FsContext))->NodeType != NODE_TYPE_VCB)) 2217 { 2218 Status = CreateRedirectedFile(Irp, FileObject, Stack->Parameters.Create.SecurityContext); 2219 } 2220 /* Otherwise, it's just a volume open */ 2221 else 2222 { 2223 Status = OpenMupFileSystem(DeviceObject->DeviceExtension, 2224 FileObject, 2225 Stack->Parameters.Create.SecurityContext->DesiredAccess, 2226 Stack->Parameters.Create.ShareAccess); 2227 2228 Irp->IoStatus.Information = FILE_OPENED; 2229 Irp->IoStatus.Status = Status; 2230 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2231 } 2232 } 2233 } 2234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2235 { 2236 Status = _SEH2_GetExceptionCode(); 2237 2238 Irp->IoStatus.Status = Status; 2239 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2240 } 2241 _SEH2_END; 2242 2243 FsRtlExitFileSystem(); 2244 2245 return Status; 2246 } 2247 2248 VOID 2249 MupCloseUncProvider(PMUP_UNC UncProvider) 2250 { 2251 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2252 2253 /* If the node was still valid, reregister the UNC provider */ 2254 if (UncProvider->NodeStatus == NODE_STATUS_HEALTHY) 2255 { 2256 UncProvider->NodeStatus = NODE_STATUS_CLEANUP; 2257 UncProvider->Registered = FALSE; 2258 ExReleaseResourceLite(&MupGlobalLock); 2259 2260 if (UncProvider->FileObject != NULL) 2261 { 2262 ZwClose(UncProvider->DeviceHandle); 2263 ObDereferenceObject(UncProvider->FileObject); 2264 } 2265 } 2266 else 2267 { 2268 ExReleaseResourceLite(&MupGlobalLock); 2269 } 2270 } 2271 2272 NTSTATUS 2273 NTAPI 2274 MupCleanup(PDEVICE_OBJECT DeviceObject, 2275 PIRP Irp) 2276 { 2277 ULONG Type; 2278 PMUP_FCB Fcb; 2279 PMUP_CCB Ccb; 2280 NTSTATUS Status; 2281 PIO_STACK_LOCATION Stack; 2282 2283 /* If DFS is enabled, check if that's for DFS and is so relay */ 2284 if (MupEnableDfs) 2285 { 2286 if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM) 2287 { 2288 return DfsFsdCleanup(DeviceObject, Irp); 2289 } 2290 } 2291 2292 FsRtlEnterFileSystem(); 2293 2294 _SEH2_TRY 2295 { 2296 Stack = IoGetCurrentIrpStackLocation(Irp); 2297 Type = MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); 2298 switch (Type) 2299 { 2300 case NODE_TYPE_VCB: 2301 /* If we got a VCB, clean it up */ 2302 MupCleanupVcb(DeviceObject, Irp, (PMUP_VCB)Fcb); 2303 2304 Irp->IoStatus.Status = STATUS_SUCCESS; 2305 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2306 2307 MupDereferenceVcb((PMUP_VCB)Fcb); 2308 2309 /* If Ccb is not null, then, it's a UNC provider node */ 2310 if (Ccb) 2311 { 2312 /* Close it, and dereference */ 2313 MupCloseUncProvider((PMUP_UNC)Ccb); 2314 MupDereferenceUncProvider((PMUP_UNC)Ccb); 2315 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2316 --MupProviderCount; 2317 ExReleaseResourceLite(&MupGlobalLock); 2318 } 2319 2320 Status = STATUS_SUCCESS; 2321 break; 2322 2323 case NODE_TYPE_FCB: 2324 /* If the node wasn't already cleaned, do it */ 2325 if (Fcb->NodeStatus == NODE_STATUS_HEALTHY) 2326 { 2327 MupCleanupFcb(DeviceObject, Irp, Fcb); 2328 Status = STATUS_SUCCESS; 2329 } 2330 else 2331 { 2332 Status = STATUS_INVALID_HANDLE; 2333 } 2334 2335 Irp->IoStatus.Status = STATUS_SUCCESS; 2336 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2337 2338 MupDereferenceFcb(Fcb); 2339 break; 2340 2341 default: 2342 Status = STATUS_INVALID_HANDLE; 2343 2344 Irp->IoStatus.Status = Status; 2345 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2346 2347 break; 2348 } 2349 } 2350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2351 { 2352 Status = _SEH2_GetExceptionCode(); 2353 } 2354 _SEH2_END; 2355 2356 FsRtlExitFileSystem(); 2357 2358 return Status; 2359 } 2360 2361 NTSTATUS 2362 MupCloseVcb(PDEVICE_OBJECT DeviceObject, 2363 PIRP Irp, 2364 PMUP_VCB Vcb, 2365 PFILE_OBJECT FileObject) 2366 { 2367 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2368 2369 /* Remove FCB, UNC from FO */ 2370 MupSetFileObject(FileObject, NULL, NULL); 2371 MupDereferenceVcb(Vcb); 2372 2373 ExReleaseResourceLite(&MupGlobalLock); 2374 2375 return STATUS_SUCCESS; 2376 } 2377 2378 NTSTATUS 2379 MupCloseFcb(PDEVICE_OBJECT DeviceObject, 2380 PIRP Irp, 2381 PMUP_FCB Fcb, 2382 PFILE_OBJECT FileObject) 2383 { 2384 ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); 2385 2386 /* Remove FCB, CCB from FO */ 2387 MupSetFileObject(FileObject, NULL, NULL); 2388 MupDereferenceFcb(Fcb); 2389 2390 ExReleaseResourceLite(&MupGlobalLock); 2391 2392 return STATUS_SUCCESS; 2393 } 2394 2395 NTSTATUS 2396 NTAPI 2397 MupClose(PDEVICE_OBJECT DeviceObject, 2398 PIRP Irp) 2399 { 2400 PMUP_FCB Fcb; 2401 PMUP_CCB Ccb; 2402 NTSTATUS Status; 2403 PIO_STACK_LOCATION Stack; 2404 2405 /* If DFS is enabled, check if that's for DFS and is so relay */ 2406 if (MupEnableDfs) 2407 { 2408 if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM) 2409 { 2410 return DfsFsdClose(DeviceObject, Irp); 2411 } 2412 } 2413 2414 FsRtlEnterFileSystem(); 2415 2416 _SEH2_TRY 2417 { 2418 /* Get our internal structures from FO */ 2419 Stack = IoGetCurrentIrpStackLocation(Irp); 2420 MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); 2421 if (Fcb == NULL) 2422 { 2423 Status = STATUS_INVALID_HANDLE; 2424 2425 Irp->IoStatus.Status = Status; 2426 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2427 2428 _SEH2_LEAVE; 2429 } 2430 2431 /* If we got the VCB, that's a volume close */ 2432 if (Fcb->NodeType == NODE_TYPE_VCB) 2433 { 2434 Status = MupCloseVcb(DeviceObject, Irp, (PMUP_VCB)Fcb, Stack->FileObject); 2435 } 2436 /* Otherwise close the FCB */ 2437 else if (Fcb->NodeType == NODE_TYPE_FCB) 2438 { 2439 MupDereferenceFcb(Fcb); 2440 Status = MupCloseFcb(DeviceObject, Irp, Fcb, Stack->FileObject); 2441 } 2442 else 2443 { 2444 Status = STATUS_INVALID_HANDLE; 2445 2446 Irp->IoStatus.Status = Status; 2447 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2448 2449 _SEH2_LEAVE; 2450 } 2451 2452 Irp->IoStatus.Status = STATUS_SUCCESS; 2453 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2454 } 2455 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2456 { 2457 Status = _SEH2_GetExceptionCode(); 2458 } 2459 _SEH2_END; 2460 2461 FsRtlExitFileSystem(); 2462 2463 return Status; 2464 } 2465 2466 VOID 2467 NTAPI 2468 MupUnload(PDRIVER_OBJECT DriverObject) 2469 { 2470 IoDeleteDevice(mupDeviceObject); 2471 2472 if (MupEnableDfs) 2473 { 2474 DfsUnload(DriverObject); 2475 } 2476 2477 MupUninitializeData(); 2478 } 2479 2480 /* 2481 * FUNCTION: Called by the system to initialize the driver 2482 * ARGUMENTS: 2483 * DriverObject = object describing this driver 2484 * RegistryPath = path to our configuration entries 2485 * RETURNS: Success or failure 2486 */ 2487 CODE_SEG("INIT") 2488 NTSTATUS 2489 NTAPI 2490 DriverEntry(PDRIVER_OBJECT DriverObject, 2491 PUNICODE_STRING RegistryPath) 2492 { 2493 NTSTATUS Status; 2494 UNICODE_STRING MupString; 2495 PDEVICE_OBJECT DeviceObject; 2496 2497 /* Only initialize global state of the driver 2498 * Other inits will happen when required 2499 */ 2500 MupInitializeData(); 2501 2502 /* Check if DFS is disabled */ 2503 MupEnableDfs = MuppIsDfsEnabled(); 2504 /* If it's not disabled but when cannot init, disable it */ 2505 if (MupEnableDfs && !NT_SUCCESS(DfsDriverEntry(DriverObject, RegistryPath))) 2506 { 2507 MupEnableDfs = FALSE; 2508 } 2509 2510 /* Create the MUP device */ 2511 RtlInitUnicodeString(&MupString, L"\\Device\\Mup"); 2512 Status = IoCreateDevice(DriverObject, sizeof(MUP_VCB), &MupString, FILE_DEVICE_MULTI_UNC_PROVIDER, 0, FALSE, &DeviceObject); 2513 if (!NT_SUCCESS(Status)) 2514 { 2515 if (MupEnableDfs) 2516 { 2517 DfsUnload(DriverObject); 2518 } 2519 2520 MupUninitializeData(); 2521 2522 return Status; 2523 } 2524 2525 /* Set our MJ */ 2526 DriverObject->DriverUnload = MupUnload; 2527 DriverObject->MajorFunction[IRP_MJ_CREATE] = MupCreate; 2528 DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = MupCreate; 2529 DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = MupCreate; 2530 DriverObject->MajorFunction[IRP_MJ_WRITE] = MupForwardIoRequest; 2531 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = MupFsControl; 2532 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MupCleanup; 2533 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MupClose; 2534 2535 /* And finish init */ 2536 mupDeviceObject = DeviceObject; 2537 MupInitializeVcb(DeviceObject->DeviceExtension); 2538 2539 return STATUS_SUCCESS; 2540 } 2541