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