//+------------------------------------------------------------------ // // Copyright (C) 1992, Microsoft Corporation // // File: Know.C // // Contents: This file has all the code that involves with knowledge // synchronisation on the DC. // // Synoposis: This code handles the fixing of knowledge inconsistencies. // All this code runs only on the DC in response to FSCTRLs from // a client etc. // // Functions: DfsModifyRemotePrefix - // DfsCreateRemoteExitPoint - // DfsDeleteRemoteExitPoint - // DfsTriggerKnowledgeVerification - // DfsFsctrlVerifyRemoteVolumeKnowledge - // DfsFsctrlVerifyLocalVolumeKnowledge - // DfsFsctrlGetKnowledgeSyncParameters - // DfsDispatchUserModeThread - // DfsFsctrlFixLocalVolumeKnowledge - // // History: 22-March-1993 SudK Created // 18-June-1992 SudK Added FixLocalVolumeKnowledge // //------------------------------------------------------------------- #include "dfsprocs.h" #include "fsctrl.h" #include "dnr.h" #include "know.h" #include "log.h" #include "smbtypes.h" #include "smbtrans.h" #define Dbg (DEBUG_TRACE_LOCALVOL) // // local function prototypes // #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, DfsTriggerKnowledgeVerification ) #pragma alloc_text( PAGE, DfsDispatchUserModeThread ) #endif // ALLOC_PRAGMA //+------------------------------------------------------------------ // // Function: DfsTriggerKnowledgeVerification // // Synopsis: This function calls the DC and informs it that a specific // service for a volume seems to have inconsistenct knowledge // with the DC. // // If the service in question is a local service, then it means // that there is an extra exit point on the disk. In that event // this routine merely deletes the extra exit point. // // Arguments: [DnrContext] -- The DnrContext has all that this func needs. // // Returns: The status from this not checked by anyone actually. // // History: 4-April-1993 SudK Created // // Notes: This method should be called from DNR only. It is // assumed that the caller has released any locks on the // PKT. There is a possibility of deadlock if the PKT lock // is held over this function, since the DC may call back // to us to correct knowledge errors. // //------------------------------------------------------------------- NTSTATUS DfsTriggerKnowledgeVerification( IN PDNR_CONTEXT DnrContext) { NTSTATUS status = STATUS_SUCCESS; NTSTATUS ReplStatus; IO_STATUS_BLOCK ioStatusBlock; ULONG size; PBYTE buffer = NULL; PDFS_REFERRAL_V1 ref; UNICODE_STRING prefix, address; PDFS_PKT_ENTRY pPktEntryDC; PDFS_SERVICE DCService; PPROVIDER_DEF DCProvider; REPL_SELECT_CONTEXT DCSelectContext; HANDLE remoteHandle; UNICODE_STRING puStr[2]; DfsDbgTrace(+1, Dbg, "DfsTriggerKnowledgeVerification: %wZ\n", &DnrContext->pPktEntry->Id.Prefix); DfsDbgTrace(0, Dbg, " ServiceName: [%wZ]\n", (DnrContext->pService->Type & DFS_SERVICE_TYPE_LOCAL) ? &DnrContext->pService->Address : &DnrContext->pService->Name); // // First, create a REQ_REPORT_DFS_INCONSISTENCY buffer for the rdr to // send to the DC. // if (DnrContext->pPktEntry->USN != DnrContext->USN) { DfsDbgTrace(0, Dbg,"Pkt Entry changed!\n", 0); DfsDbgTrace(0, Dbg, "Old USN: %d\n", DnrContext->USN); DfsDbgTrace(0, Dbg, "New USN: %d\n", DnrContext->pPktEntry->USN); status = STATUS_INVALID_HANDLE; } if (NT_SUCCESS(status)) { prefix = DnrContext->pPktEntry->Id.Prefix; address = DnrContext->pService->Address; size = prefix.Length + sizeof(WCHAR) + sizeof(DFS_REFERRAL_V1) + address.Length + sizeof(WCHAR); buffer = ExAllocatePool( PagedPool, size ); if (buffer != NULL) { RtlMoveMemory( buffer, prefix.Buffer, prefix.Length); ((PWCHAR)buffer)[prefix.Length/sizeof(WCHAR)] = UNICODE_NULL; ref = (PDFS_REFERRAL_V1) (buffer + prefix.Length + sizeof(WCHAR)); ref->VersionNumber = 1; ref->Size = sizeof(DFS_REFERRAL_V1) + address.Length + sizeof(WCHAR); ref->ServerType = 0; RtlMoveMemory( ref->ShareName, address.Buffer, address.Length ); ref->ShareName[ address.Length/sizeof(WCHAR) ] = UNICODE_NULL; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } // // Next, connect to the DC. // if (NT_SUCCESS(status)) { BOOLEAN pktLocked; // // We need to get a handle to the DC now. So that we can make an // FSCTRL to the DC. // PktAcquireShared( TRUE, &pktLocked ); ExAcquireResourceExclusive( &DfsData.Resource, TRUE ); pPktEntryDC = PktLookupReferralEntry( &DfsData.Pkt, DnrContext->pPktEntry); if (pPktEntryDC != NULL) { ReplStatus = ReplFindFirstProvider( pPktEntryDC, NULL, NULL, &DCService, &DCSelectContext); } if (pPktEntryDC == NULL || !NT_SUCCESS(ReplStatus)) { DfsDbgTrace(0, Dbg, "DfsTriggerKnowVerification. Failed to find DC\n", 0); status = STATUS_CANT_ACCESS_DOMAIN_INFO; } else { DCProvider = DCService->pProvider; } ExReleaseResource( &DfsData.Resource ); if (NT_SUCCESS(status)) { status = DfsCreateConnection( DCService, DCProvider, &remoteHandle); } PktRelease(); } // // Lastly, tell the DC to try and fix up the volume on the server. This // call may result in a call back to ourselves in the event that we // are missing knowledge about a local volume. // if (NT_SUCCESS(status)) { status = ZwFsControlFile( remoteHandle, NULL, NULL, NULL, &ioStatusBlock, FSCTL_DFS_VERIFY_REMOTE_VOLUME_KNOWLEDGE, buffer, size + sizeof(ULONG), NULL, 0 ); if (NT_SUCCESS(status)) status = ioStatusBlock.Status; ZwClose( remoteHandle ); } if (buffer != NULL) ExFreePool(buffer); DfsDbgTrace(-1, Dbg, "DfsTriggerKnowledgeVerification - exit %08lx\n", status); return(status); } //+------------------------------------------------------------------ // // Function: DfsDispatchUserModeThread // // Synopsis: This function is called on the DC when the driver discovers // a knowledge inconsistency and attempts to fix it. This // function wakes up a user level thread and tells it the // GUID and ServiceName of the volume to be fixed. This is done // by simply writing into a named pipe, which the user level // thread should be listening on. // // Arguments: [arg] -- The DFS_VOL_VERIFY struct has ID and SvcName which // need to be sent to the user mode server. // // Returns: // // History: 05-April-1993 SudK Created // // Notes: // //------------------------------------------------------------------- NTSTATUS DfsDispatchUserModeThread( IN PVOID InputBuffer, IN ULONG InputBufferLength) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN ProcessAttached = FALSE; HANDLE hPipe; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK Iosb; DfsDbgTrace(+1, Dbg, "DfsDispatchUserModeThread: Entered\n", 0); RtlInitUnicodeString(&UnicodeString, DFS_KERNEL_MESSAGE_PIPE); InitializeObjectAttributes( &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenFile(&hPipe, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &Iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); if ( !NT_SUCCESS(status) || !NT_SUCCESS(Iosb.Status) ) { DfsDbgTrace(0, Dbg, "Open of named pipe failed - %08lx\n", status); return(status); } status = ZwWriteFile( hPipe, NULL, NULL, NULL, &Iosb, &InputBufferLength, sizeof(InputBufferLength), NULL, NULL); if (NT_SUCCESS(status)) { status = Iosb.Status; } else { DfsDbgTrace(0, Dbg, "Write to named pipe failed -> %08lx\n", status); } if (NT_SUCCESS(status)) { status = ZwWriteFile( hPipe, NULL, NULL, NULL, &Iosb, InputBuffer, InputBufferLength, NULL, NULL); if (NT_SUCCESS(status)) { status = Iosb.Status; } else { DfsDbgTrace(0, Dbg, "Write to named pipe failed -> %08lx\n", status); } } if (NT_SUCCESS(status)) { // // Attempt to read back the status of the user-level operation // NTSTATUS OperationStatus ; status = ZwReadFile( hPipe, NULL, NULL, NULL, &Iosb, &OperationStatus, sizeof(OperationStatus), NULL, NULL); if (NT_SUCCESS(status)) { status = OperationStatus; } } ZwClose(hPipe); DfsDbgTrace(-1, Dbg, "DfsDispatchUserModeThread: Exited -> %08lx\n", status); return(status); }