Something went wrong. Try again.
Reactos
Something went wrong. Try again.
80 kB · 2540 lines
C
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541/* * ReactOS kernel * Copyright (C) 2002 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *//* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: drivers/filesystems/mup/mup.c * PURPOSE: Multi UNC Provider * PROGRAMMER: Eric Kohl * Pierre Schweitzer (pierre@reactos.org) */
/* INCLUDES *****************************************************************/
#include "mup.h"
#define NDEBUG#include <debug.h>
ERESOURCE MupGlobalLock;ERESOURCE MupPrefixTableLock;ERESOURCE MupCcbListLock;ERESOURCE MupVcbLock;LIST_ENTRY MupProviderList;LIST_ENTRY MupPrefixList;LIST_ENTRY MupMasterQueryList;UNICODE_PREFIX_TABLE MupPrefixTable;LARGE_INTEGER MupKnownPrefixTimeout;ULONG MupProviderCount;BOOLEAN MupOrderInitialized;BOOLEAN MupEnableDfs;PDEVICE_OBJECT mupDeviceObject;NTSTATUS MupOrderedErrorList[] = { STATUS_UNSUCCESSFUL, STATUS_INVALID_PARAMETER, STATUS_REDIRECTOR_NOT_STARTED, STATUS_BAD_NETWORK_NAME, STATUS_BAD_NETWORK_PATH, 0 };
/* FUNCTIONS ****************************************************************/
CODE_SEG("INIT")VOIDMupInitializeData(VOID){ ExInitializeResourceLite(&MupGlobalLock); ExInitializeResourceLite(&MupPrefixTableLock); ExInitializeResourceLite(&MupCcbListLock); ExInitializeResourceLite(&MupVcbLock); MupProviderCount = 0; InitializeListHead(&MupProviderList); InitializeListHead(&MupPrefixList); InitializeListHead(&MupMasterQueryList); RtlInitializeUnicodePrefix(&MupPrefixTable); MupKnownPrefixTimeout.QuadPart = 9000000000LL; MupOrderInitialized = FALSE;}
VOIDMupUninitializeData(){ ExDeleteResourceLite(&MupGlobalLock); ExDeleteResourceLite(&MupPrefixTableLock); ExDeleteResourceLite(&MupCcbListLock); ExDeleteResourceLite(&MupVcbLock);}
CODE_SEG("INIT")VOIDMupInitializeVcb(PMUP_VCB Vcb){ RtlZeroMemory(Vcb, sizeof(MUP_VCB)); Vcb->NodeType = NODE_TYPE_VCB; Vcb->NodeStatus = NODE_STATUS_HEALTHY; Vcb->NodeReferences = 1; Vcb->NodeSize = sizeof(MUP_VCB);}
BOOLEANMuppIsDfsEnabled(VOID){ HANDLE Key; ULONG Length; NTSTATUS Status; UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; struct { KEY_VALUE_PARTIAL_INFORMATION KeyInfo; ULONG KeyValue; } KeyQueryOutput;
/* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */ KeyName.Buffer = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup"; KeyName.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL); KeyName.MaximumLength = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
/* Simply query registry to know whether we have to disable DFS. * Unless explicitly stated in registry, we will try to enable DFS. */ InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return TRUE; }
KeyName.Buffer = L"DisableDfs"; KeyName.Length = sizeof(L"DisableDfs") - sizeof(UNICODE_NULL); KeyName.MaximumLength = sizeof(L"DisableDfs");
Status = ZwQueryValueKey(Key, &KeyName, KeyValuePartialInformation, &KeyQueryOutput, sizeof(KeyQueryOutput), &Length); ZwClose(Key); if (!NT_SUCCESS(Status) || KeyQueryOutput.KeyInfo.Type != REG_DWORD) { return TRUE; }
return ((ULONG_PTR)KeyQueryOutput.KeyInfo.Data != 1);}
VOIDMupCalculateTimeout(PLARGE_INTEGER EntryTime){ LARGE_INTEGER CurrentTime;
/* Just get now + our allowed timeout */ KeQuerySystemTime(&CurrentTime); EntryTime->QuadPart = CurrentTime.QuadPart + MupKnownPrefixTimeout.QuadPart;}
PMUP_CCBMupCreateCcb(VOID){ PMUP_CCB Ccb;
Ccb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_CCB), TAG_MUP); if (Ccb == NULL) { return NULL; }
Ccb->NodeStatus = NODE_STATUS_HEALTHY; Ccb->NodeReferences = 1; Ccb->NodeType = NODE_TYPE_CCB; Ccb->NodeSize = sizeof(MUP_CCB);
return Ccb;}
PMUP_FCBMupCreateFcb(VOID){ PMUP_FCB Fcb;
Fcb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_FCB), TAG_MUP); if (Fcb == NULL) { return NULL; }
Fcb->NodeStatus = NODE_STATUS_HEALTHY; Fcb->NodeReferences = 1; Fcb->NodeType = NODE_TYPE_FCB; Fcb->NodeSize = sizeof(MUP_FCB); InitializeListHead(&Fcb->CcbList);
return Fcb;}
PMUP_MICMupAllocateMasterIoContext(VOID){ PMUP_MIC MasterIoContext;
MasterIoContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MIC), TAG_MUP); if (MasterIoContext == NULL) { return NULL; }
MasterIoContext->NodeStatus = NODE_STATUS_HEALTHY; MasterIoContext->NodeReferences = 1; MasterIoContext->NodeType = NODE_TYPE_MIC; MasterIoContext->NodeSize = sizeof(MUP_MIC);
return MasterIoContext;}
PMUP_UNCMupAllocateUncProvider(ULONG RedirectorDeviceNameLength){ PMUP_UNC UncProvider;
UncProvider = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_UNC) + RedirectorDeviceNameLength, TAG_MUP); if (UncProvider == NULL) { return NULL; }
UncProvider->NodeReferences = 0; UncProvider->NodeType = NODE_TYPE_UNC; UncProvider->NodeStatus = NODE_STATUS_HEALTHY; UncProvider->NodeSize = sizeof(MUP_UNC) + RedirectorDeviceNameLength; UncProvider->Registered = FALSE;
return UncProvider;}
PMUP_PFXMupAllocatePrefixEntry(ULONG PrefixLength){ PMUP_PFX Prefix; ULONG PrefixSize;
PrefixSize = sizeof(MUP_PFX) + PrefixLength; Prefix = ExAllocatePoolWithTag(PagedPool, PrefixSize, TAG_MUP); if (Prefix == NULL) { return NULL; }
RtlZeroMemory(Prefix, PrefixSize); Prefix->NodeType = NODE_TYPE_PFX; Prefix->NodeStatus = NODE_STATUS_HEALTHY; Prefix->NodeReferences = 1; Prefix->NodeSize = PrefixSize;
/* If we got a prefix, initialize the string */ if (PrefixLength != 0) { Prefix->AcceptedPrefix.Buffer = (PVOID)((ULONG_PTR)Prefix + sizeof(MUP_PFX)); Prefix->AcceptedPrefix.Length = PrefixLength; Prefix->AcceptedPrefix.MaximumLength = PrefixLength; } /* Otherwise, mark the fact that the allocation will be external */ else { Prefix->ExternalAlloc = TRUE; }
Prefix->KeepExtraRef = FALSE; /* Already init timeout to have one */ MupCalculateTimeout(&Prefix->ValidityTimeout);
return Prefix;}
PMUP_MQCMupAllocateMasterQueryContext(VOID){ PMUP_MQC MasterQueryContext;
MasterQueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MQC), TAG_MUP); if (MasterQueryContext == NULL) { return NULL; }
MasterQueryContext->NodeStatus = NODE_STATUS_HEALTHY; MasterQueryContext->NodeReferences = 1; MasterQueryContext->NodeType = NODE_TYPE_MQC; MasterQueryContext->NodeSize = sizeof(MUP_MQC); InitializeListHead(&MasterQueryContext->QueryPathList); InitializeListHead(&MasterQueryContext->MQCListEntry); ExInitializeResourceLite(&MasterQueryContext->QueryPathListLock);
return MasterQueryContext;}
ULONGMupDecodeFileObject(PFILE_OBJECT FileObject, PMUP_FCB * pFcb, PMUP_CCB * pCcb){ ULONG Type; PMUP_FCB Fcb;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); *pFcb = FileObject->FsContext; *pCcb = FileObject->FsContext2; Fcb = *pFcb;
if (Fcb == NULL) { ExReleaseResourceLite(&MupGlobalLock); return 0; }
Type = Fcb->NodeType; if ((Type != NODE_TYPE_VCB && Type != NODE_TYPE_FCB) || (Fcb->NodeStatus != NODE_STATUS_HEALTHY && Fcb->NodeStatus != NODE_STATUS_CLEANUP)) { *pFcb = 0; ExReleaseResourceLite(&MupGlobalLock); return 0; }
++Fcb->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
return Type;}
VOIDMupFreeNode(PVOID Node){ ExFreePoolWithTag(Node, TAG_MUP);}
VOIDMupDereferenceFcb(PMUP_FCB Fcb){ /* Just dereference and delete if no references left */ if (InterlockedDecrement(&Fcb->NodeReferences) == 0) { MupFreeNode(Fcb); }}
VOIDMupDereferenceCcb(PMUP_CCB Ccb){ /* Just dereference and delete (and clean) if no references left */ if (InterlockedDecrement(&Ccb->NodeReferences) == 0) { ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); RemoveEntryList(&Ccb->CcbListEntry); ExReleaseResourceLite(&MupCcbListLock); ObDereferenceObject(Ccb->FileObject); MupDereferenceFcb(Ccb->Fcb); MupFreeNode(Ccb); }}
VOIDMupDereferenceVcb(PMUP_VCB Vcb){ /* We cannot reach the point where no references are left */ if (InterlockedDecrement(&Vcb->NodeReferences) == 0) { KeBugCheckEx(FILE_SYSTEM, 3, 0, 0, 0); }}
NTSTATUSMupDereferenceMasterIoContext(PMUP_MIC MasterIoContext, PNTSTATUS NewStatus){ PIRP Irp; NTSTATUS Status; PIO_STACK_LOCATION Stack;
Status = STATUS_SUCCESS;
if (NewStatus != NULL) { /* Save last status, depending on whether it failed or not */ if (!NT_SUCCESS(*NewStatus)) { MasterIoContext->LastFailed = *NewStatus; } else { MasterIoContext->LastSuccess = STATUS_SUCCESS; } }
if (InterlockedDecrement(&MasterIoContext->NodeReferences) != 0) { return STATUS_PENDING; }
Irp = MasterIoContext->Irp; Stack = IoGetCurrentIrpStackLocation(Irp); if (Stack->MajorFunction == IRP_MJ_WRITE) { Irp->IoStatus.Information = Stack->Parameters.Write.Length; } else { Irp->IoStatus.Information = 0; }
/* In case we never had any success (init is a failure), get the last failed status */ if (!NT_SUCCESS(MasterIoContext->LastSuccess)) { Status = MasterIoContext->LastFailed; }
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); MupDereferenceFcb(MasterIoContext->Fcb); MupFreeNode(MasterIoContext);
return Status;}
VOIDMupDereferenceUncProvider(PMUP_UNC UncProvider){ InterlockedExchangeAdd(&UncProvider->NodeReferences, -1);}
VOIDMupDereferenceKnownPrefix(PMUP_PFX Prefix){ /* Just dereference and delete (and clean) if no references left */ if (InterlockedDecrement(&Prefix->NodeReferences) == 0) { if (Prefix->InTable) { RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry); RemoveEntryList(&Prefix->PrefixListEntry); }
if (Prefix->ExternalAlloc && Prefix->AcceptedPrefix.Buffer != NULL) { ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP); }
if (Prefix->UncProvider) { MupDereferenceUncProvider(Prefix->UncProvider); }
MupFreeNode(Prefix); }}
VOIDMupRemoveKnownPrefixEntry(PMUP_PFX Prefix){ RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry); RemoveEntryList(&Prefix->PrefixListEntry); Prefix->InTable = FALSE; MupDereferenceKnownPrefix(Prefix);}
VOIDMupInvalidatePrefixTable(VOID){ PMUP_PFX Prefix; PLIST_ENTRY Entry;
/* Browse the prefix table */ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); for (Entry = MupPrefixList.Flink; Entry != &MupPrefixList; Entry = Entry->Flink) { Prefix = CONTAINING_RECORD(Entry, MUP_PFX, PrefixListEntry);
/* And remove any entry in it */ if (Prefix->InTable) { MupRemoveKnownPrefixEntry(Prefix); } } ExReleaseResourceLite(&MupPrefixTableLock);}
VOIDMupCleanupVcb(PDEVICE_OBJECT DeviceObject, PIRP Irp, PMUP_VCB Vcb){ ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE);
/* Check we're not doing anything wrong first */ if (Vcb->NodeStatus != NODE_STATUS_HEALTHY || Vcb->NodeType != NODE_TYPE_VCB) { ExRaiseStatus(STATUS_INVALID_HANDLE); }
/* Remove share access */ IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp)->FileObject, &Vcb->ShareAccess);
ExReleaseResourceLite(&MupVcbLock);}
VOIDMupCleanupFcb(PDEVICE_OBJECT DeviceObject, PIRP Irp, PMUP_FCB Fcb){ PLIST_ENTRY Entry; PMUP_CCB Ccb;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); /* Check we're not doing anything wrong first */ if (Fcb->NodeStatus != NODE_STATUS_HEALTHY || Fcb->NodeType != NODE_TYPE_FCB) { ExRaiseStatus(STATUS_INVALID_HANDLE); } Fcb->NodeStatus = NODE_STATUS_CLEANUP; ExReleaseResourceLite(&MupGlobalLock);
/* Dereference any CCB associated with the FCB */ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); for (Entry = Fcb->CcbList.Flink; Entry != &Fcb->CcbList; Entry = Entry->Flink) { Ccb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry); ExReleaseResourceLite(&MupCcbListLock); MupDereferenceCcb(Ccb); ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); } ExReleaseResourceLite(&MupCcbListLock);}
NTSTATUSCommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PFORWARDED_IO_CONTEXT FwdCtxt){ NTSTATUS Status;
Status = Irp->IoStatus.Status;
/* Just free everything we had allocated */ if (Irp->MdlAddress != NULL) { MmUnlockPages(Irp->MdlAddress); IoFreeMdl(Irp->MdlAddress); }
if (Irp->Flags & IRP_DEALLOCATE_BUFFER) { ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_MUP); }
IoFreeIrp(Irp);
/* Dereference the master context * The upper IRP will be completed once all the lower IRPs are done * (and thus, references count reaches 0) */ MupDereferenceCcb(FwdCtxt->Ccb); MupDereferenceMasterIoContext(FwdCtxt->MasterIoContext, &Status); ExFreePoolWithTag(FwdCtxt, TAG_MUP);
return STATUS_MORE_PROCESSING_REQUIRED;}
VOIDNTAPIDeferredForwardedIoCompletionRoutine(PVOID Context){ PFORWARDED_IO_CONTEXT FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
CommonForwardedIoCompletionRoutine(FwdCtxt->DeviceObject, FwdCtxt->Irp, Context);}
NTSTATUSNTAPIForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context){ PFORWARDED_IO_CONTEXT FwdCtxt;
/* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */ if (KeGetCurrentIrql() < DISPATCH_LEVEL) { CommonForwardedIoCompletionRoutine(DeviceObject, Irp, Context); } else { FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
ExInitializeWorkItem(&FwdCtxt->WorkQueueItem, DeferredForwardedIoCompletionRoutine, Context); ExQueueWorkItem(&FwdCtxt->WorkQueueItem, CriticalWorkQueue); }
return STATUS_MORE_PROCESSING_REQUIRED;}
NTSTATUSBuildAndSubmitIrp(PIRP Irp, PMUP_CCB Ccb, PMUP_MIC MasterIoContext){ PMDL Mdl; PIRP LowerIrp; NTSTATUS Status; PIO_STACK_LOCATION Stack; PDEVICE_OBJECT DeviceObject; PFORWARDED_IO_CONTEXT FwdCtxt;
Status = STATUS_SUCCESS; LowerIrp = NULL; Mdl = NULL;
/* Allocate a context for the completion routine */ FwdCtxt = ExAllocatePoolWithTag(NonPagedPool, sizeof(FORWARDED_IO_CONTEXT), TAG_MUP); if (FwdCtxt == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
/* Init it */ FwdCtxt->DeviceObject = NULL; FwdCtxt->Irp = NULL;
/* Allocate the IRP */ DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject); LowerIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE); if (LowerIrp == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
/* Initialize it */ LowerIrp->Tail.Overlay.OriginalFileObject = Ccb->FileObject; LowerIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; LowerIrp->RequestorMode = KernelMode;
/* Copy the stack of the request we received to the IRP we'll pass below */ Stack = IoGetNextIrpStackLocation(LowerIrp); RtlMoveMemory(Stack, IoGetCurrentIrpStackLocation(Irp), sizeof(IO_STACK_LOCATION)); Stack->FileObject = Ccb->FileObject; /* Setup flags according to the FO */ if (Ccb->FileObject->Flags & FO_WRITE_THROUGH) { Stack->Flags = SL_WRITE_THROUGH; }
_SEH2_TRY { /* Does the device requires we do buffered IOs? */ if (DeviceObject->Flags & DO_BUFFERED_IO) { LowerIrp->AssociatedIrp.SystemBuffer = NULL;
if (Stack->Parameters.Write.Length == 0) { LowerIrp->Flags = IRP_BUFFERED_IO; } /* If we have data to pass */ else { /* If it's coming from usermode, probe first */ if (Irp->RequestorMode == UserMode) { ProbeForRead(Irp->UserBuffer, Stack->Parameters.Write.Length, sizeof(UCHAR)); }
/* Allocate the buffer */ LowerIrp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned, Stack->Parameters.Write.Length, TAG_MUP); if (LowerIrp->AssociatedIrp.SystemBuffer == NULL) { ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
/* And copy input (remember, we've to free!) */ RtlMoveMemory(LowerIrp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, Stack->Parameters.Write.Length); LowerIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; } } else { if (!(DeviceObject->Flags & DO_DIRECT_IO)) { LowerIrp->UserBuffer = Irp->UserBuffer; } else { /* For direct IOs, allocate an MDL and pass it */ if (Stack->Parameters.Write.Length != 0) { Mdl = IoAllocateMdl(Irp->UserBuffer, Stack->Parameters.Write.Length, FALSE, TRUE, LowerIrp); if (Mdl == NULL) { ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoReadAccess); } } }
/* Fix flags in the IRP */ if (Ccb->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { LowerIrp->Flags |= IRP_WRITE_OPERATION | IRP_NOCACHE; } else { LowerIrp->Flags |= IRP_WRITE_OPERATION; }
FwdCtxt->Ccb = Ccb; FwdCtxt->MasterIoContext = MasterIoContext;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); ++MasterIoContext->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
/* Set out completion routine */ IoSetCompletionRoutine(LowerIrp, ForwardedIoCompletionRoutine, FwdCtxt, TRUE, TRUE, TRUE); /* And call the device with our brand new IRP */ Status = IoCallDriver(Ccb->DeviceObject, LowerIrp); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
Cleanup: if (!NT_SUCCESS(Status)) { if (FwdCtxt != NULL) { ExFreePoolWithTag(FwdCtxt, TAG_MUP); }
if (LowerIrp != NULL) { if (LowerIrp->AssociatedIrp.SystemBuffer == NULL) { ExFreePoolWithTag(LowerIrp->AssociatedIrp.SystemBuffer, TAG_MUP); }
IoFreeIrp(LowerIrp); }
if (Mdl != NULL) { IoFreeMdl(Mdl); } }
return Status;}
NTSTATUSNTAPIMupForwardIoRequest(PDEVICE_OBJECT DeviceObject, PIRP Irp){ PMUP_FCB Fcb; PMUP_CCB Ccb; NTSTATUS Status; PLIST_ENTRY Entry; PMUP_CCB FcbListCcb; BOOLEAN CcbLockAcquired; PMUP_MIC MasterIoContext; PIO_STACK_LOCATION Stack;
/* If DFS is enabled, check if that's for DFS and is so relay */ if (MupEnableDfs && DeviceObject->DeviceType == FILE_DEVICE_DFS) { return DfsVolumePassThrough(DeviceObject, Irp); }
Stack = IoGetCurrentIrpStackLocation(Irp);
FsRtlEnterFileSystem();
/* Write request is only possible for a mailslot, we need a FCB */ MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); if (Fcb == NULL || Fcb->NodeType != NODE_TYPE_FCB) { FsRtlExitFileSystem(); Status = STATUS_INVALID_DEVICE_REQUEST; goto Complete; }
/* Allocate a context */ MasterIoContext = MupAllocateMasterIoContext(); if (MasterIoContext == NULL) { FsRtlExitFileSystem(); Status = STATUS_INSUFFICIENT_RESOURCES; goto Complete; }
/* Mark the IRP pending and init the context */ IoMarkIrpPending(Irp); MasterIoContext->Irp = Irp; /* Init with a failure to catch if we ever succeed */ MasterIoContext->LastSuccess = STATUS_UNSUCCESSFUL; /* Init with the worth failure possible */ MasterIoContext->LastFailed = STATUS_BAD_NETWORK_PATH; MasterIoContext->Fcb = Fcb;
_SEH2_TRY { ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); CcbLockAcquired = TRUE;
/* For all the CCB (ie, the mailslots) we have */ for (Entry = Fcb->CcbList.Flink; Entry != &Fcb->CcbList; Entry = Entry->Flink) { FcbListCcb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry); ExReleaseResourceLite(&MupCcbListLock); CcbLockAcquired = FALSE;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); ++FcbListCcb->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
/* Forward the write request */ BuildAndSubmitIrp(Irp, FcbListCcb, MasterIoContext); ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE); CcbLockAcquired = TRUE; }
ExReleaseResourceLite(&MupCcbListLock); CcbLockAcquired = FALSE; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { if (CcbLockAcquired) { ExReleaseResourceLite(&MupCcbListLock); } } _SEH2_END;
/* And done */ MupDereferenceMasterIoContext(MasterIoContext, NULL); FsRtlExitFileSystem();
return STATUS_PENDING;
Complete: /* Failure case */ Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); return Status;}
PMUP_UNCAddUnregisteredProvider(PCWSTR DeviceName, ULONG ProviderOrder){ PMUP_UNC UncProvider; ULONG StrLen, NameLen;
/* Just allocate the node */ NameLen = wcslen(DeviceName); StrLen = NameLen * sizeof(WCHAR); UncProvider = MupAllocateUncProvider(StrLen); if (UncProvider == NULL) { return NULL; }
/* And init it */ UncProvider->DeviceName.MaximumLength = StrLen; UncProvider->DeviceName.Length = StrLen; UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC)); UncProvider->ProviderOrder = ProviderOrder; RtlMoveMemory(UncProvider->DeviceName.Buffer, DeviceName, StrLen);
/* And add it to the global list * We're using tail here so that when called from registry init, * the providers with highest priority will be in the head of * the list */ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); InsertTailList(&MupProviderList, &UncProvider->ProviderListEntry); ExReleaseResourceLite(&MupGlobalLock);
return UncProvider;}
VOIDInitializeProvider(PCWSTR ProviderName, ULONG ProviderOrder){ NTSTATUS Status; HANDLE KeyHandle; UNICODE_STRING Key, Value; PKEY_VALUE_FULL_INFORMATION Info; OBJECT_ATTRIBUTES ObjectAttributes; ULONG NameLen, StrLen, ResultLength;
/* Get the information about the provider from registry */ NameLen = wcslen(ProviderName); StrLen = NameLen * sizeof(WCHAR) + sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L"\\NetworkProvider"); Key.Buffer = ExAllocatePoolWithTag(PagedPool, StrLen, TAG_MUP); if (Key.Buffer == NULL) { return; }
RtlMoveMemory(Key.Buffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\")); Key.MaximumLength = StrLen; Key.Length = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL); RtlAppendUnicodeToString(&Key, ProviderName); RtlAppendUnicodeToString(&Key, L"\\NetworkProvider");
InitializeObjectAttributes(&ObjectAttributes, &Key, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); ExFreePoolWithTag(Key.Buffer, TAG_MUP); if (!NT_SUCCESS(Status)) { return; }
RtlInitUnicodeString(&Value, L"DeviceName"); Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, NULL, 0, &ResultLength); if (Status == STATUS_BUFFER_TOO_SMALL) { Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP); if (Info == NULL) { ZwClose(KeyHandle); return; }
Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, Info, ResultLength, &ResultLength); } else { Info = NULL; }
ZwClose(KeyHandle);
/* And create the provider * It will remain unregistered until FsRTL receives a registration request and forwards * it to MUP */ if (NT_SUCCESS(Status)) { ASSERT(Info != NULL); AddUnregisteredProvider((PWSTR)((ULONG_PTR)Info + Info->DataOffset), ProviderOrder); }
if (Info != NULL) { ExFreePoolWithTag(Info, TAG_MUP); }}
VOIDMupGetProviderInformation(VOID){ BOOLEAN End; NTSTATUS Status; HANDLE KeyHandle; PWSTR Providers, Coma; PKEY_VALUE_FULL_INFORMATION Info; ULONG ResultLength, ProviderCount; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING NetworkProvider, ProviderOrder;
/* Open the registry to get the order of the providers */ RtlInitUnicodeString(&NetworkProvider, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order"); InitializeObjectAttributes(&ObjectAttributes, &NetworkProvider, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return; }
RtlInitUnicodeString(&ProviderOrder, L"ProviderOrder"); Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, NULL, 0, &ResultLength); if (Status == STATUS_BUFFER_TOO_SMALL) { Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL), TAG_MUP); if (Info == NULL) { ZwClose(KeyHandle); return; }
Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation, Info, ResultLength, &ResultLength); } else { Info = NULL; }
ZwClose(KeyHandle);
if (NT_SUCCESS(Status)) { ASSERT(Info != NULL);
Providers = (PWSTR)((ULONG_PTR)Info + Info->DataOffset); End = FALSE; ProviderCount = 0;
/* For all the providers we got (coma-separated list), just create a provider node with the right order * The order is just the order of the list * First has highest priority (0) and then, get lower and lower priority * The highest number is the lowest priority */ do { Coma = wcschr(Providers, L','); if (Coma != NULL) { *Coma = UNICODE_NULL; } else { End = TRUE; }
InitializeProvider(Providers, ProviderCount); ++ProviderCount;
Providers = Coma + 1; } while (!End); }
if (Info != NULL) { ExFreePoolWithTag(Info, TAG_MUP); }}
PMUP_UNCMupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName){ PLIST_ENTRY Entry; PMUP_UNC UncProvider;
/* Browse the list of all the providers nodes we have */ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) { UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
/* If one matches the device and is not registered, that's ours! */ if (!UncProvider->Registered && RtlEqualUnicodeString(RedirectorDeviceName, &UncProvider->DeviceName, TRUE)) { UncProvider->NodeStatus = NODE_STATUS_HEALTHY; break; } }
if (Entry == &MupProviderList) { UncProvider = NULL; } ExReleaseResourceLite(&MupGlobalLock);
return UncProvider;}
NTSTATUSRegisterUncProvider(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{ BOOLEAN New; PMUP_FCB Fcb; PMUP_CCB Ccb; NTSTATUS Status; PLIST_ENTRY Entry; PIO_STACK_LOCATION Stack; IO_STATUS_BLOCK IoStatusBlock; PMUP_UNC UncProvider, ListEntry; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING RedirectorDeviceName; OBJECT_HANDLE_INFORMATION HandleInfo; PMUP_PROVIDER_REGISTRATION_INFO RegInfo;
DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject, Irp); New = FALSE;
/* Check whether providers order was already initialized */ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); if (MupOrderInitialized) { ExReleaseResourceLite(&MupGlobalLock); } else { /* They weren't, so do it */ MupOrderInitialized = TRUE; ExReleaseResourceLite(&MupGlobalLock); MupGetProviderInformation(); }
Stack = IoGetCurrentIrpStackLocation(Irp);
/* This can only happen with a volume open */ if (MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb) != NODE_TYPE_VCB) { Irp->IoStatus.Status = STATUS_INVALID_HANDLE; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return STATUS_INVALID_HANDLE; }
/* Get the registration information */ RegInfo = (PMUP_PROVIDER_REGISTRATION_INFO)Irp->AssociatedIrp.SystemBuffer; _SEH2_TRY { RedirectorDeviceName.Length = RegInfo->RedirectorDeviceNameLength; RedirectorDeviceName.MaximumLength = RedirectorDeviceName.Length; RedirectorDeviceName.Buffer = (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset);
/* Have we got already a node for it? (Like from previous init) */ UncProvider = MupCheckForUnregisteredProvider(&RedirectorDeviceName); if (UncProvider == NULL) { /* If we don't, allocate a new one */ New = TRUE; UncProvider = MupAllocateUncProvider(RegInfo->RedirectorDeviceNameLength); if (UncProvider == NULL) { Status = STATUS_INVALID_USER_BUFFER; _SEH2_LEAVE; }
/* Set it up */ UncProvider->DeviceName.Length = RedirectorDeviceName.Length; UncProvider->DeviceName.MaximumLength = RedirectorDeviceName.MaximumLength; UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider + sizeof(MUP_UNC));
/* As it wasn't in registry for order, give the lowest priority possible */ UncProvider->ProviderOrder = MAXLONG; RtlMoveMemory(UncProvider->DeviceName.Buffer, (PWSTR)((ULONG_PTR)RegInfo + RegInfo->RedirectorDeviceNameOffset), RegInfo->RedirectorDeviceNameLength); }
/* Continue registration */ UncProvider->MailslotsSupported = RegInfo->MailslotsSupported; ++UncProvider->NodeReferences;
/* Open a handle to the device */ InitializeObjectAttributes(&ObjectAttributes, &UncProvider->DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&UncProvider->DeviceHandle, FILE_TRAVERSE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE); if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; }
/* And return the provider (as CCB) */ if (NT_SUCCESS(Status)) { Stack->FileObject->FsContext2 = UncProvider; Status = ObReferenceObjectByHandle(UncProvider->DeviceHandle, 0, NULL, KernelMode, (PVOID *)&UncProvider->FileObject, &HandleInfo); if (!NT_SUCCESS(Status)) { NtClose(UncProvider->DeviceHandle); } }
if (!NT_SUCCESS(Status)) { MupDereferenceUncProvider(UncProvider); } else { UncProvider->DeviceObject = IoGetRelatedDeviceObject(UncProvider->FileObject);
/* Now, insert the provider in our global list * They are sorted by order */ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); ++MupProviderCount; if (New) { for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) { ListEntry = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
if (UncProvider->ProviderOrder < ListEntry->ProviderOrder) { break; } }
InsertTailList(Entry, &UncProvider->ProviderListEntry); } UncProvider->Registered = TRUE; ExReleaseResourceLite(&MupGlobalLock); Status = STATUS_SUCCESS;
DPRINT1("UNC provider %wZ registered\n", &UncProvider->DeviceName); } } _SEH2_FINALLY { if (_SEH2_AbnormalTermination()) { Status = STATUS_INVALID_USER_BUFFER; }
MupDereferenceVcb((PMUP_VCB)Fcb);
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); } _SEH2_END;
return Status;}
NTSTATUSNTAPIMupFsControl(PDEVICE_OBJECT DeviceObject, PIRP Irp){ NTSTATUS Status; PIO_STACK_LOCATION Stack;
Stack = IoGetCurrentIrpStackLocation(Irp);
_SEH2_TRY { /* MUP only understands a single FSCTL code: registering UNC provider */ if (Stack->Parameters.FileSystemControl.FsControlCode == FSCTL_MUP_REGISTER_PROVIDER) { /* It obviously has to come from a driver/kernelmode thread */ if (Irp->RequestorMode == UserMode) { Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
_SEH2_LEAVE; }
Status = RegisterUncProvider(DeviceObject, Irp); } else { /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */ if (!MupEnableDfs) { Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
_SEH2_LEAVE; }
Status = DfsFsdFileSystemControl(DeviceObject, Irp); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
return Status;}
VOIDMupSetFileObject(PFILE_OBJECT FileObject, PMUP_FCB Fcb, PMUP_CCB Ccb){ FileObject->FsContext = Fcb; FileObject->FsContext2 = Ccb;}
NTSTATUSMupRerouteOpen(PFILE_OBJECT FileObject, PMUP_UNC UncProvider){ PWSTR FullPath; ULONG TotalLength;
DPRINT("Rerouting %wZ with %wZ\n", &FileObject->FileName, &UncProvider->DeviceName);
/* Get the full path name (device name first, and requested file name appended) */ TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length; if (TotalLength > MAXUSHORT) { return STATUS_NAME_TOO_LONG; }
/* Allocate a buffer big enough */ FullPath = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP); if (FullPath == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Create the full path */ RtlMoveMemory(FullPath, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length); RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath + UncProvider->DeviceName.Length), FileObject->FileName.Buffer, FileObject->FileName.Length);
/* And redo the path in the file object */ ExFreePoolWithTag(FileObject->FileName.Buffer, 0); FileObject->FileName.Buffer = FullPath; FileObject->FileName.MaximumLength = TotalLength; FileObject->FileName.Length = FileObject->FileName.MaximumLength;
/* Ob, please reparse to open the correct file at the right place, thanks! :-) */ return STATUS_REPARSE;}
NTSTATUSBroadcastOpen(PIRP Irp){ PMUP_FCB Fcb; HANDLE Handle; PLIST_ENTRY Entry; PMUP_CCB Ccb = NULL; PMUP_UNC UncProvider; UNICODE_STRING FullPath; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; NTSTATUS Status, LastFailed; ULONG TotalLength, LastOrder; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_HANDLE_INFORMATION HandleInfo; BOOLEAN Locked, Referenced, CcbInitialized;
Fcb = MupCreateFcb(); if (Fcb == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
Stack = IoGetCurrentIrpStackLocation(Irp); FileObject = Stack->FileObject; Locked = FALSE; Referenced = FALSE; CcbInitialized = FALSE; LastFailed = STATUS_NO_SUCH_FILE; LastOrder = (ULONG)-1;
_SEH2_TRY { ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); Locked = TRUE;
/* Associate our FCB with the FO */ MupSetFileObject(FileObject, Fcb, NULL); Fcb->FileObject = FileObject;
/* Now, broadcast the open to any UNC provider that supports mailslots */ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) { UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry); ++UncProvider->NodeReferences; Referenced = TRUE;
ExReleaseResourceLite(&MupGlobalLock); Locked = FALSE;
TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length; if (UncProvider->MailslotsSupported && TotalLength <= MAXUSHORT) { /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */ FullPath.Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP); if (FullPath.Buffer == NULL) { ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
FullPath.Length = TotalLength; FullPath.MaximumLength = TotalLength; RtlMoveMemory(FullPath.Buffer, UncProvider->DeviceName.Buffer, UncProvider->DeviceName.Length); RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath.Buffer + UncProvider->DeviceName.Length), FileObject->FileName.Buffer, FileObject->FileName.Length);
/* And just forward the creation request */ InitializeObjectAttributes(&ObjectAttributes, &FullPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); Status = IoCreateFile(&Handle, Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_SIMPLE_RIGHTS_MASK, &ObjectAttributes, &IoStatusBlock, NULL, Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS, Stack->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS, FILE_OPEN, Stack->Parameters.Create.Options & FILE_VALID_SET_FLAGS, NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING);
ExFreePoolWithTag(FullPath.Buffer, TAG_MUP);
/* If opening succeed */ if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status;
/* Create a CCB */ Ccb = MupCreateCcb(); if (Ccb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; }
/* And associated a FO to it */ if (NT_SUCCESS(Status)) { Status = ObReferenceObjectByHandle(Handle, 0, 0, 0, (PVOID *)&Ccb->FileObject, &HandleInfo); ZwClose(Handle); } }
/* If we failed, remember the last failed status of the higher priority provider */ if (!NT_SUCCESS(Status)) { if (UncProvider->ProviderOrder <= LastOrder) { LastOrder = UncProvider->ProviderOrder; LastFailed = Status; } } /* Otherwise, properly attach our CCB to the mailslot */ else { Ccb->DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject); Ccb->Fcb = Fcb;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); Locked = TRUE; ++Fcb->NodeReferences; ExReleaseResourceLite(&MupGlobalLock); Locked = FALSE; CcbInitialized = TRUE;
InsertTailList(&Fcb->CcbList, &Ccb->CcbListEntry); } }
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); Locked = TRUE; MupDereferenceUncProvider(UncProvider); Referenced = FALSE; }
ExReleaseResourceLite(&MupGlobalLock); Locked = FALSE; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* If we at least opened one mailslot, return success */ Status = (CcbInitialized ? STATUS_SUCCESS : LastFailed);
if (Referenced) { MupDereferenceUncProvider(UncProvider); }
if (Locked) { ExReleaseResourceLite(&MupGlobalLock); }
/* In case of failure, don't leak CCB */ if (!NT_SUCCESS(Status) && Ccb != NULL) { MupFreeNode(Ccb); }
return Status;}
PIRPMupBuildIoControlRequest(PFILE_OBJECT FileObject, PVOID Context, ULONG MajorFunction, ULONG IoctlCode, PVOID InputBuffer, ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize, PIO_COMPLETION_ROUTINE CompletionRoutine){ PIRP Irp; PIO_STACK_LOCATION Stack; PDEVICE_OBJECT DeviceObject;
if (InputBuffer == NULL) { return NULL; }
/* Get the device object */ DeviceObject = IoGetRelatedDeviceObject(FileObject); /* Allocate the IRP (with one more location for us */ Irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE); if (Irp == NULL) { return NULL; }
/* Skip our location */ IoSetNextIrpStackLocation(Irp); /* Setup the IRP */ Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); IoSetCompletionRoutine(Irp, CompletionRoutine, Context, TRUE, TRUE, TRUE);
/* Setup the stack */ Stack = IoGetNextIrpStackLocation(Irp); Stack->MajorFunction = MajorFunction; Stack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferSize; Stack->Parameters.DeviceIoControl.InputBufferLength = InputBufferSize; Stack->Parameters.DeviceIoControl.IoControlCode = IoctlCode; Stack->MinorFunction = 0; Stack->FileObject = FileObject; Stack->DeviceObject = DeviceObject;
switch (IO_METHOD_FROM_CTL_CODE(IoctlCode)) { case METHOD_BUFFERED: /* If it's buffered, just pass the buffers we got */ Irp->MdlAddress = NULL; Irp->AssociatedIrp.SystemBuffer = InputBuffer; Irp->UserBuffer = OutputBuffer; Irp->Flags = IRP_BUFFERED_IO;
if (OutputBuffer != NULL) { Irp->Flags |= IRP_INPUT_OPERATION; } break;
case METHOD_IN_DIRECT: case METHOD_OUT_DIRECT: /* Otherwise, allocate an MDL */ if (IoAllocateMdl(InputBuffer, InputBufferSize, FALSE, FALSE, Irp) == NULL) { IoFreeIrp(Irp); return NULL; }
Irp->AssociatedIrp.SystemBuffer = InputBuffer; Irp->Flags = IRP_BUFFERED_IO; MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoReadAccess); break;
case METHOD_NEITHER: /* Or pass the buffers */ Irp->UserBuffer = OutputBuffer; Irp->MdlAddress = NULL; Irp->AssociatedIrp.SystemBuffer = NULL; Stack->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; break; }
return Irp;}
VOIDMupFreeMasterQueryContext(PMUP_MQC MasterQueryContext){ ExDeleteResourceLite(&MasterQueryContext->QueryPathListLock); ExFreePoolWithTag(MasterQueryContext, TAG_MUP);}
NTSTATUSMupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext){ LONG References; NTSTATUS Status; BOOLEAN KeepExtraRef;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); --MasterQueryContext->NodeReferences; References = MasterQueryContext->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
if (References != 0) { DPRINT("Still having refs (%ld)\n", References); return STATUS_PENDING; }
/* We HAVE an IRP to complete. It cannot be NULL * Please, help preserving kittens, don't provide NULL IRPs. */ if (MasterQueryContext->Irp == NULL) { KeBugCheck(FILE_SYSTEM); }
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); RemoveEntryList(&MasterQueryContext->MQCListEntry); ExReleaseResourceLite(&MupGlobalLock);
ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); KeepExtraRef = MasterQueryContext->Prefix->KeepExtraRef; MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
/* We found a provider? */ if (MasterQueryContext->LatestProvider != NULL) { /* With a successful status? */ if (MasterQueryContext->LatestStatus == STATUS_SUCCESS) { /* Then, it's time to reroute, someone accepted to handle the file creation request! */ if (!KeepExtraRef) { MupDereferenceKnownPrefix(MasterQueryContext->Prefix); }
ExReleaseResourceLite(&MupPrefixTableLock); /* Reroute & complete :-) */ Status = MupRerouteOpen(MasterQueryContext->FileObject, MasterQueryContext->LatestProvider); goto Complete; } else { MupDereferenceUncProvider(MasterQueryContext->LatestProvider); } }
MupDereferenceKnownPrefix(MasterQueryContext->Prefix); ExReleaseResourceLite(&MupPrefixTableLock);
/* Return the highest failed status we had */ Status = MasterQueryContext->LatestStatus;
Complete: /* In finally, complete the IRP for real! */ MasterQueryContext->Irp->IoStatus.Status = Status; IoCompleteRequest(MasterQueryContext->Irp, IO_DISK_INCREMENT);
MasterQueryContext->Irp = NULL; MupFreeMasterQueryContext(MasterQueryContext);
return Status;}
NTSTATUSNTAPIQueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context){ PMUP_PFX Prefix; ULONG LatestPos, Pos; PWSTR AcceptedPrefix; PMUP_MQC MasterQueryContext; NTSTATUS Status, TableStatus; PQUERY_PATH_CONTEXT QueryContext; PQUERY_PATH_RESPONSE QueryResponse;
/* Get all the data from our query to the provider */ QueryContext = (PQUERY_PATH_CONTEXT)Context; QueryResponse = (PQUERY_PATH_RESPONSE)QueryContext->QueryPathRequest; MasterQueryContext = QueryContext->MasterQueryContext; Status = Irp->IoStatus.Status;
DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext->UncProvider->DeviceName, QueryResponse->LengthAccepted, Status);
ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE); RemoveEntryList(&QueryContext->QueryPathListEntry);
/* If the driver returned a success, and an acceptance length */ if (NT_SUCCESS(Status) && QueryResponse->LengthAccepted > 0) { Prefix = MasterQueryContext->Prefix;
/* Check if we already found a provider from a previous iteration */ if (MasterQueryContext->LatestProvider != NULL) { /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */ if (QueryContext->UncProvider->ProviderOrder >= MasterQueryContext->LatestProvider->ProviderOrder) { MupDereferenceUncProvider(QueryContext->UncProvider); goto Cleanup; }
/* Otherwise, if the prefix was in the prefix table, just drop it: * we have a provider which supersedes the accepted prefix, so leave * room for the new prefix/provider */ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); if (Prefix->InTable) { RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry); RemoveEntryList(&Prefix->PrefixListEntry); Prefix->InTable = FALSE; } ExReleaseResourceLite(&MupPrefixTableLock);
Prefix->KeepExtraRef = FALSE;
/* Release data associated with the current prefix, if any * We'll renew them with the new accepted prefix */ if (Prefix->AcceptedPrefix.Length != 0 && Prefix->AcceptedPrefix.Buffer != NULL) { ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP); Prefix->AcceptedPrefix.MaximumLength = 0; Prefix->AcceptedPrefix.Length = 0; Prefix->AcceptedPrefix.Buffer = NULL; Prefix->ExternalAlloc = FALSE; }
/* If there was also a provider, drop it, the new one * is different */ if (Prefix->UncProvider != NULL) { MupDereferenceUncProvider(Prefix->UncProvider); Prefix->UncProvider = NULL; } }
/* Now, set our information about the provider that accepted the prefix */ MasterQueryContext->LatestProvider = QueryContext->UncProvider; MasterQueryContext->LatestStatus = Status;
if (MasterQueryContext->FileObject->FsContext2 != (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT) { /* Allocate a buffer for the prefix */ AcceptedPrefix = ExAllocatePoolWithTag(PagedPool, QueryResponse->LengthAccepted, TAG_MUP); if (AcceptedPrefix == NULL) { Prefix->InTable = FALSE; } else { /* Set it up to the accepted length */ RtlMoveMemory(AcceptedPrefix, MasterQueryContext->FileObject->FileName.Buffer, QueryResponse->LengthAccepted); Prefix->UncProvider = MasterQueryContext->LatestProvider; Prefix->AcceptedPrefix.Buffer = AcceptedPrefix; Prefix->AcceptedPrefix.Length = QueryResponse->LengthAccepted; Prefix->AcceptedPrefix.MaximumLength = QueryResponse->LengthAccepted; Prefix->ExternalAlloc = TRUE;
/* Insert the accepted prefix in the table of known prefixes */ DPRINT("%wZ accepted %wZ\n", &Prefix->UncProvider->DeviceName, &Prefix->AcceptedPrefix); ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); if (RtlInsertUnicodePrefix(&MupPrefixTable, &Prefix->AcceptedPrefix, &Prefix->PrefixTableEntry)) { InsertHeadList(&MupPrefixList, &Prefix->PrefixListEntry); Prefix->InTable = TRUE; Prefix->KeepExtraRef = TRUE; } else { Prefix->InTable = FALSE; } ExReleaseResourceLite(&MupPrefixTableLock); } } } else { MupDereferenceUncProvider(QueryContext->UncProvider);
/* We failed and didn't find any provider over the latest iterations */ if (MasterQueryContext->LatestProvider == NULL) { /* If we had a success though (broken provider?) set our failed status */ if (NT_SUCCESS(MasterQueryContext->LatestStatus)) { MasterQueryContext->LatestStatus = Status; } else { TableStatus = MupOrderedErrorList[0]; LatestPos = 0;
/* Otherwise, time to compare statuses, between the latest failed * and the current failure. * We have an order table of failed status: the deeper you go in the * table, the more the error is critical. * Our goal is to return the most critical status that was returned by * any of the providers */
/* Look for latest status position */ while (TableStatus != 0 && TableStatus != MasterQueryContext->LatestStatus) { ++LatestPos; TableStatus = MupOrderedErrorList[LatestPos]; }
/* If at pos 0, the new status is likely more critical */ if (LatestPos == 0) { MasterQueryContext->LatestStatus = Status; } else { /* Otherwise, find position of the new status in the table */ Pos = 0; do { if (Status == MupOrderedErrorList[Pos]) { break; }
++Pos; } while (Pos < LatestPos);
/* If it has a higher position (more critical), return it */ if (Pos >= LatestPos) { MasterQueryContext->LatestStatus = Status; } } } } }
Cleanup: ExFreePoolWithTag(QueryResponse, TAG_MUP); ExFreePoolWithTag(QueryContext, TAG_MUP); IoFreeIrp(Irp);
ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock); MupDereferenceMasterQueryContext(MasterQueryContext);
return STATUS_MORE_PROCESSING_REQUIRED;}
NTSTATUSCreateRedirectedFile(PIRP Irp, PFILE_OBJECT FileObject, PIO_SECURITY_CONTEXT SecurityContext){ LONG Len; WCHAR Cur; PWSTR Name; PIRP QueryIrp; NTSTATUS Status; PMUP_PFX Prefix; PLIST_ENTRY Entry; PMUP_UNC UncProvider; PIO_STACK_LOCATION Stack; LARGE_INTEGER CurrentTime; PMUP_MQC MasterQueryContext; PQUERY_PATH_CONTEXT QueryContext; PQUERY_PATH_REQUEST QueryPathRequest; PUNICODE_PREFIX_TABLE_ENTRY TableEntry; BOOLEAN Locked, Referenced, BreakOnFirst;
/* We cannot open a file without a name */ if (FileObject->FileName.Length == 0) { Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST; }
DPRINT("Request for opening: %wZ\n", &FileObject->FileName);
Referenced = FALSE; BreakOnFirst = TRUE; Status = STATUS_BAD_NETWORK_PATH;
ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE); /* First, try to see if that's a prefix we already know */ TableEntry = RtlFindUnicodePrefix(&MupPrefixTable, &FileObject->FileName, 1); if (TableEntry != NULL) { Prefix = CONTAINING_RECORD(TableEntry, MUP_PFX, PrefixTableEntry);
DPRINT("Matching prefix found: %wZ\n", &Prefix->AcceptedPrefix);
/* If so, check whether the prefix is still valid */ KeQuerySystemTime(&CurrentTime); if (Prefix->ValidityTimeout.QuadPart < CurrentTime.QuadPart) { /* It is: so, update its validity period and reroute file opening */ MupCalculateTimeout(&Prefix->ValidityTimeout); Status = MupRerouteOpen(FileObject, Prefix->UncProvider); ExReleaseResourceLite(&MupPrefixTableLock);
if (Status == STATUS_REPARSE) { Irp->IoStatus.Information = FILE_SUPERSEDED; }
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return Status; }
/* When here, we found a matching prefix, but expired, remove it from the table * We'll redo a full search */ if (Prefix->InTable) { MupRemoveKnownPrefixEntry(Prefix); } } ExReleaseResourceLite(&MupPrefixTableLock);
Stack = IoGetCurrentIrpStackLocation(Irp); /* First of all, start looking for a mailslot */ if (FileObject->FileName.Buffer[0] == L'\\' && Stack->MajorFunction != IRP_MJ_CREATE) { Name = &FileObject->FileName.Buffer[1]; Len = FileObject->FileName.Length;
/* Skip the remote destination name */ do { Len -= sizeof(WCHAR); if (Len <= 0) { break; }
Cur = *Name; ++Name; } while (Cur != L'\\'); Len -= sizeof(WCHAR);
/* If we still have room for "Mailslot" to fit */ if (Len >= (sizeof(L"Mailslot") - sizeof(UNICODE_NULL))) { /* Get the len in terms of chars count */ Len /= sizeof(WCHAR); if (Len > ((sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR))) { Len = (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) / sizeof(WCHAR); }
/* It's indeed a mailslot opening! */ if (_wcsnicmp(Name, L"Mailslot", Len) == 0) { /* Broadcast open */ Status = BroadcastOpen(Irp); if (Status == STATUS_REPARSE) { Irp->IoStatus.Information = FILE_SUPERSEDED; }
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return Status; } } }
/* Ok, at that point, that's a regular MUP opening (if no DFS) */ if (!MupEnableDfs || FileObject->FsContext2 == (PVOID)DFS_DOWNLEVEL_OPEN_CONTEXT) { /* We won't complete immediately */ IoMarkIrpPending(Irp);
/* Allocate a new prefix for our search */ Prefix = MupAllocatePrefixEntry(0); if (Prefix == NULL) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return STATUS_PENDING; }
/* Allocate a context for our search */ MasterQueryContext = MupAllocateMasterQueryContext(); if (MasterQueryContext == NULL) { MupFreeNode(Prefix);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
return STATUS_PENDING; }
MasterQueryContext->Irp = Irp; MasterQueryContext->FileObject = FileObject; MasterQueryContext->LatestProvider = NULL; MasterQueryContext->Prefix = Prefix; MasterQueryContext->LatestStatus = STATUS_BAD_NETWORK_PATH; ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); InsertTailList(&MupMasterQueryList, &MasterQueryContext->MQCListEntry); ++Prefix->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
_SEH2_TRY { ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); Locked = TRUE;
/* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry = Entry->Flink) { UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
++UncProvider->NodeReferences; Referenced = TRUE;
ExReleaseResourceLite(&MupGlobalLock); Locked = FALSE;
/* We will obviously only query registered providers */ if (UncProvider->Registered) { /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */ QueryPathRequest = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), TAG_MUP); if (QueryPathRequest == NULL) { ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
/* Allocate a context for IRP completion routine * In case a prefix matches the path, the reroute will happen * in the completion routine, when we have return from the provider */ QueryContext = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_PATH_CONTEXT), TAG_MUP); if (QueryContext == NULL) { ExFreePoolWithTag(QueryPathRequest, TAG_MUP); ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
InitializeListHead(&QueryContext->QueryPathListEntry); QueryContext->MasterQueryContext = MasterQueryContext; QueryContext->QueryPathRequest = QueryPathRequest; QueryPathRequest->PathNameLength = FileObject->FileName.Length; QueryPathRequest->SecurityContext = SecurityContext; RtlMoveMemory(QueryPathRequest->FilePathName, FileObject->FileName.Buffer, FileObject->FileName.Length);
/* Build our IRP for the query */ QueryIrp = MupBuildIoControlRequest(UncProvider->FileObject, QueryContext, IRP_MJ_DEVICE_CONTROL, IOCTL_REDIR_QUERY_PATH, QueryPathRequest, FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), QueryPathRequest, sizeof(QUERY_PATH_RESPONSE), QueryPathCompletionRoutine); if (QueryIrp == NULL) { ExFreePoolWithTag(QueryContext, TAG_MUP); ExFreePoolWithTag(QueryPathRequest, TAG_MUP); ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
QueryIrp->RequestorMode = KernelMode; QueryContext->UncProvider = UncProvider; QueryContext->Irp = QueryIrp;
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); ++UncProvider->NodeReferences; ++MasterQueryContext->NodeReferences; ExReleaseResourceLite(&MupGlobalLock);
ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE); InsertTailList(&MasterQueryContext->QueryPathList, &QueryContext->QueryPathListEntry); ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock);
/* Query the provider !*/ DPRINT("Requesting UNC provider: %wZ\n", &UncProvider->DeviceName); DPRINT("Calling: %wZ\n", &UncProvider->DeviceObject->DriverObject->DriverName); Status = IoCallDriver(UncProvider->DeviceObject, QueryIrp); }
ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); Locked = TRUE;
/* We're done with that provider */ MupDereferenceUncProvider(UncProvider); Referenced = FALSE;
/* If query went fine on the first request, just break and leave */ if (BreakOnFirst && Status == STATUS_SUCCESS) { break; }
BreakOnFirst = FALSE; } } _SEH2_FINALLY { if (_SEH2_AbnormalTermination()) { MasterQueryContext->LatestStatus = STATUS_INSUFFICIENT_RESOURCES; }
if (Referenced) { MupDereferenceUncProvider(UncProvider); }
if (Locked) { ExReleaseResourceLite(&MupGlobalLock); }
MupDereferenceMasterQueryContext(MasterQueryContext);
Status = STATUS_PENDING; } _SEH2_END; } else { UNIMPLEMENTED; Status = STATUS_NOT_IMPLEMENTED; }
return Status;}
NTSTATUSOpenMupFileSystem(PMUP_VCB Vcb, PFILE_OBJECT FileObject, ACCESS_MASK DesiredAccess, USHORT ShareAccess){ NTSTATUS Status;
DPRINT1("Opening MUP\n");
ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE); _SEH2_TRY { /* Update share access, increase reference count, and associated VCB to the FO, that's it! */ Status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess, TRUE); if (NT_SUCCESS(Status)) { ++Vcb->NodeReferences; MupSetFileObject(FileObject, (PMUP_FCB)Vcb, NULL); Status = STATUS_SUCCESS; } } _SEH2_FINALLY { ExReleaseResourceLite(&MupVcbLock); } _SEH2_END;
return Status;}
NTSTATUSNTAPIMupCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp){ NTSTATUS Status; PIO_STACK_LOCATION Stack; PFILE_OBJECT FileObject, RelatedFileObject;
FsRtlEnterFileSystem();
_SEH2_TRY { /* If DFS is enabled, check if that's for DFS and is so relay */ if (MupEnableDfs && (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM)) { Status = DfsFsdCreate(DeviceObject, Irp); } else { Stack = IoGetCurrentIrpStackLocation(Irp); FileObject = Stack->FileObject; RelatedFileObject = FileObject->RelatedFileObject;
/* 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 */ if (FileObject->FileName.Length != 0 || (RelatedFileObject != NULL && ((PMUP_FCB)(RelatedFileObject->FsContext))->NodeType != NODE_TYPE_VCB)) { Status = CreateRedirectedFile(Irp, FileObject, Stack->Parameters.Create.SecurityContext); } /* Otherwise, it's just a volume open */ else { Status = OpenMupFileSystem(DeviceObject->DeviceExtension, FileObject, Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess);
Irp->IoStatus.Information = FILE_OPENED; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); } } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode();
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT); } _SEH2_END;
FsRtlExitFileSystem();
return Status;}
VOIDMupCloseUncProvider(PMUP_UNC UncProvider){ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
/* If the node was still valid, reregister the UNC provider */ if (UncProvider->NodeStatus == NODE_STATUS_HEALTHY) { UncProvider->NodeStatus = NODE_STATUS_CLEANUP; UncProvider->Registered = FALSE; ExReleaseResourceLite(&MupGlobalLock);
if (UncProvider->FileObject != NULL) { ZwClose(UncProvider->DeviceHandle); ObDereferenceObject(UncProvider->FileObject); } } else { ExReleaseResourceLite(&MupGlobalLock); }}
NTSTATUSNTAPIMupCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp){ ULONG Type; PMUP_FCB Fcb; PMUP_CCB Ccb; NTSTATUS Status; PIO_STACK_LOCATION Stack;
/* If DFS is enabled, check if that's for DFS and is so relay */ if (MupEnableDfs) { if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM) { return DfsFsdCleanup(DeviceObject, Irp); } }
FsRtlEnterFileSystem();
_SEH2_TRY { Stack = IoGetCurrentIrpStackLocation(Irp); Type = MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); switch (Type) { case NODE_TYPE_VCB: /* If we got a VCB, clean it up */ MupCleanupVcb(DeviceObject, Irp, (PMUP_VCB)Fcb);
Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
MupDereferenceVcb((PMUP_VCB)Fcb);
/* If Ccb is not null, then, it's a UNC provider node */ if (Ccb) { /* Close it, and dereference */ MupCloseUncProvider((PMUP_UNC)Ccb); MupDereferenceUncProvider((PMUP_UNC)Ccb); ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE); --MupProviderCount; ExReleaseResourceLite(&MupGlobalLock); }
Status = STATUS_SUCCESS; break;
case NODE_TYPE_FCB: /* If the node wasn't already cleaned, do it */ if (Fcb->NodeStatus == NODE_STATUS_HEALTHY) { MupCleanupFcb(DeviceObject, Irp, Fcb); Status = STATUS_SUCCESS; } else { Status = STATUS_INVALID_HANDLE; }
Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
MupDereferenceFcb(Fcb); break;
default: Status = STATUS_INVALID_HANDLE;
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
break; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
FsRtlExitFileSystem();
return Status;}
NTSTATUSMupCloseVcb(PDEVICE_OBJECT DeviceObject, PIRP Irp, PMUP_VCB Vcb, PFILE_OBJECT FileObject){ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
/* Remove FCB, UNC from FO */ MupSetFileObject(FileObject, NULL, NULL); MupDereferenceVcb(Vcb);
ExReleaseResourceLite(&MupGlobalLock);
return STATUS_SUCCESS;}
NTSTATUSMupCloseFcb(PDEVICE_OBJECT DeviceObject, PIRP Irp, PMUP_FCB Fcb, PFILE_OBJECT FileObject){ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
/* Remove FCB, CCB from FO */ MupSetFileObject(FileObject, NULL, NULL); MupDereferenceFcb(Fcb);
ExReleaseResourceLite(&MupGlobalLock);
return STATUS_SUCCESS;}
NTSTATUSNTAPIMupClose(PDEVICE_OBJECT DeviceObject, PIRP Irp){ PMUP_FCB Fcb; PMUP_CCB Ccb; NTSTATUS Status; PIO_STACK_LOCATION Stack;
/* If DFS is enabled, check if that's for DFS and is so relay */ if (MupEnableDfs) { if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM) { return DfsFsdClose(DeviceObject, Irp); } }
FsRtlEnterFileSystem();
_SEH2_TRY { /* Get our internal structures from FO */ Stack = IoGetCurrentIrpStackLocation(Irp); MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb); if (Fcb == NULL) { Status = STATUS_INVALID_HANDLE;
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
_SEH2_LEAVE; }
/* If we got the VCB, that's a volume close */ if (Fcb->NodeType == NODE_TYPE_VCB) { Status = MupCloseVcb(DeviceObject, Irp, (PMUP_VCB)Fcb, Stack->FileObject); } /* Otherwise close the FCB */ else if (Fcb->NodeType == NODE_TYPE_FCB) { MupDereferenceFcb(Fcb); Status = MupCloseFcb(DeviceObject, Irp, Fcb, Stack->FileObject); } else { Status = STATUS_INVALID_HANDLE;
Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_DISK_INCREMENT);
_SEH2_LEAVE; }
Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_DISK_INCREMENT); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
FsRtlExitFileSystem();
return Status;}
VOIDNTAPIMupUnload(PDRIVER_OBJECT DriverObject){ IoDeleteDevice(mupDeviceObject);
if (MupEnableDfs) { DfsUnload(DriverObject); }
MupUninitializeData();}
/* * FUNCTION: Called by the system to initialize the driver * ARGUMENTS: * DriverObject = object describing this driver * RegistryPath = path to our configuration entries * RETURNS: Success or failure */CODE_SEG("INIT")NTSTATUSNTAPIDriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath){ NTSTATUS Status; UNICODE_STRING MupString; PDEVICE_OBJECT DeviceObject;
/* Only initialize global state of the driver * Other inits will happen when required */ MupInitializeData();
/* Check if DFS is disabled */ MupEnableDfs = MuppIsDfsEnabled(); /* If it's not disabled but when cannot init, disable it */ if (MupEnableDfs && !NT_SUCCESS(DfsDriverEntry(DriverObject, RegistryPath))) { MupEnableDfs = FALSE; }
/* Create the MUP device */ RtlInitUnicodeString(&MupString, L"\\Device\\Mup"); Status = IoCreateDevice(DriverObject, sizeof(MUP_VCB), &MupString, FILE_DEVICE_MULTI_UNC_PROVIDER, 0, FALSE, &DeviceObject); if (!NT_SUCCESS(Status)) { if (MupEnableDfs) { DfsUnload(DriverObject); }
MupUninitializeData();
return Status; }
/* Set our MJ */ DriverObject->DriverUnload = MupUnload; DriverObject->MajorFunction[IRP_MJ_CREATE] = MupCreate; DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = MupCreate; DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = MupCreate; DriverObject->MajorFunction[IRP_MJ_WRITE] = MupForwardIoRequest; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = MupFsControl; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MupCleanup; DriverObject->MajorFunction[IRP_MJ_CLOSE] = MupClose;
/* And finish init */ mupDeviceObject = DeviceObject; MupInitializeVcb(DeviceObject->DeviceExtension);
return STATUS_SUCCESS;}