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