//+---------------------------------------------------------------------------- // // Copyright (C) 1992, Microsoft Corporation. // // File: UPkt.c // // Contents: This module contains user mode functions which support // operations on the DFS Partition Knowledge Table. // // Functions: PktOpen - // PktClose - // PktCreateEntry - // PktCreateSubordinateEntry - // PktFlushCache - // PktDestroyEntry - // PktModifyEntryGuid - // PktSetRelationInfo - // // History: // // [mikese] I replaced MemAlloc's by malloc's, but consider using // RtlAllocateHeap. // Also, most of the routines in the module have a remarkably similar // structure, and could probably be recoded using a common subroutine. // //----------------------------------------------------------------------------- #include #include #include "dfsmrshl.h" #include "nodetype.h" #include "libsup.h" #include "upkt.h" #include "dfsfsctl.h" #include "fsctrl.h" // needed for FSCTL_DFS_PKT_FLUSH_CACHE #define MAX_OUT_BUFFER_SIZE_RELINFO 0x1000 //+------------------------------------------------------------------------- // // Function: PktOpen, public // // Synopsis: Returns a handle to the Dfs PKT so operations can be made // to it. // // Arguments: // // Returns: [STATUS_SUCCESS] -- Successfully opened the pkt. // // [STATUS_FS_DRIVER_REQUIRED] -- Dfs driver not loaded // //-------------------------------------------------------------------------- NTSTATUS PktOpen( IN OUT PHANDLE PktHandle, IN ACCESS_MASK DesiredAccess, IN ULONG ShareAccess, IN PUNICODE_STRING DfsNtPathName OPTIONAL ) { NTSTATUS status; HANDLE dfsHandle; status = DfsOpen(&dfsHandle, DfsNtPathName); if(NT_SUCCESS(status)) { *PktHandle = dfsHandle; } else { status = STATUS_FS_DRIVER_REQUIRED; } return status; } //+------------------------------------------------------------------------- // // Function: PktClose, public // // Synopsis: // // Arguments: // // Returns: Nothing // //-------------------------------------------------------------------------- VOID PktClose( IN HANDLE PktHandle ) { NTSTATUS status = STATUS_SUCCESS; if(NT_SUCCESS(status)) NtClose(PktHandle); } //+------------------------------------------------------------------------- // // Function: PktCreateEntry, public // // Synopsis: // // Arguments: // // Returns: // //-------------------------------------------------------------------------- NTSTATUS PktCreateEntry( IN HANDLE PktHandle, IN ULONG EntryType, IN PDFS_PKT_ENTRY_ID EntryId, IN PDFS_PKT_ENTRY_INFO EntryInfo, IN ULONG CreateDisposition ) { NTSTATUS status; DFS_PKT_CREATE_ENTRY_ARG arg; MARSHAL_BUFFER marshalBuffer; ULONG size; arg.EntryType = EntryType; arg.EntryId = (*EntryId); arg.EntryInfo = (*EntryInfo); arg.CreateDisposition = CreateDisposition; size = 0L; status = DfsRtlSize(&MiPktCreateEntryArg, &arg, &size); if(NT_SUCCESS(status)) { PVOID buffer = malloc ( size ); if ( buffer == NULL ) return(STATUS_NO_MEMORY); MarshalBufferInitialize(&marshalBuffer, size, buffer); status = DfsRtlPut( &marshalBuffer, &MiPktCreateEntryArg, &arg ); if(NT_SUCCESS(status)) { status = DfsFsctl( PktHandle, FSCTL_DFS_PKT_CREATE_ENTRY, buffer, size, NULL, 0L ); } free(buffer); } return status; } //+------------------------------------------------------------------------- // // Function: PktCreateSubordinateEntry, public // // Synopsis: // // Arguments: // // Returns: // //-------------------------------------------------------------------------- NTSTATUS PktCreateSubordinateEntry( IN HANDLE PktHandle, IN PDFS_PKT_ENTRY_ID SuperiorId, IN ULONG SubordinateType, IN PDFS_PKT_ENTRY_ID SubordinateId, IN PDFS_PKT_ENTRY_INFO SubordinateInfo OPTIONAL, IN ULONG CreateDisposition ) { NTSTATUS status; DFS_PKT_CREATE_SUBORDINATE_ENTRY_ARG arg; MARSHAL_BUFFER marshalBuffer; ULONG size; arg.EntryId = (*SuperiorId); arg.SubEntryType = SubordinateType; arg.SubEntryId = (*SubordinateId); arg.SubEntryInfo = (*SubordinateInfo); arg.CreateDisposition = CreateDisposition; size = 0L; status = DfsRtlSize(&MiPktCreateSubordinateEntryArg, &arg, &size); if(NT_SUCCESS(status)) { PVOID buffer = malloc ( size ); if ( buffer == NULL ) return(STATUS_NO_MEMORY); MarshalBufferInitialize(&marshalBuffer, size, buffer); status = DfsRtlPut( &marshalBuffer, &MiPktCreateSubordinateEntryArg, &arg ); if(NT_SUCCESS(status)) { status = DfsFsctl( PktHandle, FSCTL_DFS_PKT_CREATE_SUBORDINATE_ENTRY, buffer, size, NULL, 0L ); } free(buffer); } return status; } //+------------------------------------------------------------------------- // // Function: PktDestroyEntry, public // // Synopsis: // // Arguments: // // Returns: // //-------------------------------------------------------------------------- NTSTATUS PktDestroyEntry( IN HANDLE PktHandle, IN DFS_PKT_ENTRY_ID victim ) { NTSTATUS status; MARSHAL_BUFFER marshalBuffer; ULONG size; size = 0L; status = DfsRtlSize(&MiPktEntryId, &victim, &size); if(NT_SUCCESS(status)) { PVOID buffer = malloc ( size ); if ( buffer == NULL ) return(STATUS_NO_MEMORY); MarshalBufferInitialize(&marshalBuffer, size, buffer); status = DfsRtlPut( &marshalBuffer, &MiPktEntryId, &victim ); if(NT_SUCCESS(status)) { status = DfsFsctl( PktHandle, FSCTL_DFS_PKT_DESTROY_ENTRY, buffer, size, NULL, 0L ); } free(buffer); } return status; } //+------------------------------------------------------------------------- // // Function: PktGetRelationInfo, public // // Synopsis: // // Arguments: // // Returns: // // Notes: The relationalInfo structure should be made available // by the caller but additional memory is allocated in here. // The caller should deallocate all that memory himself. // //-------------------------------------------------------------------------- NTSTATUS PktGetRelationInfo( IN HANDLE PktHandle, IN PDFS_PKT_ENTRY_ID EntryId, IN OUT PDFS_PKT_RELATION_INFO RelationInfo ) { NTSTATUS status; MARSHAL_BUFFER marshalBuffer; ULONG size; PVOID OutputBuffer; size = 0L; status = DfsRtlSize(&MiPktEntryId, EntryId, &size); if(NT_SUCCESS(status)) { PVOID buffer = malloc ( size ); if ( buffer == NULL ) return(STATUS_NO_MEMORY); MarshalBufferInitialize(&marshalBuffer, size, buffer); status = DfsRtlPut( &marshalBuffer, &MiPktEntryId, EntryId ); if(NT_SUCCESS(status)) { // Do we want to retry with larger sizes? OutputBuffer = malloc ( MAX_OUT_BUFFER_SIZE_RELINFO ); if ( OutputBuffer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; } else { status = DfsFsctl( PktHandle, FSCTL_DFS_PKT_GET_RELATION_INFO, buffer, size, OutputBuffer, MAX_OUT_BUFFER_SIZE_RELINFO); // // We can get rid of this right away. // if(NT_SUCCESS(status)) { MarshalBufferInitialize( &marshalBuffer, MAX_OUT_BUFFER_SIZE_RELINFO, OutputBuffer ); status = DfsRtlGet( &marshalBuffer, &MiPktRelationInfo, RelationInfo ); } free(OutputBuffer); } } free(buffer); } //Status from DfsRtlSize if (!NT_SUCCESS(status)) { RtlZeroMemory(RelationInfo, sizeof(DFS_PKT_RELATION_INFO)); } return status; } //+---------------------------------------------------------------------------- // // Function: PktValidateLocalVolumeInfo, public // // Synopsis: Asks the Dfs driver to validate its local volume info with // the one that is passed in. // // Arguments: [relationInfo] -- The DFS_PKT_RELATION_INFO to validate // against. // // Returns: [STATUS_SUCCESS] -- Successfully validated local volume info // // [STATUS_REGISTRY_RECOVERED] -- Successfully validated info, // but had to make changes to local info // // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- The driver has no record // of local volume described in relation info. // // [STATUS_UNSUCCESSFUL] -- Unable to fixup the local relation // info. An appropriate message was logged to the // local eventlog. // // [STATUS_DATA_ERROR] -- Passed in relationInfo is bogus. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition. // // [STATUS_FS_DRIVER_REQUIRED] -- Unable to open handle to the // Dfs driver // //----------------------------------------------------------------------------- NTSTATUS PktValidateLocalVolumeInfo( IN PDFS_PKT_RELATION_INFO relationInfo) { NTSTATUS status; HANDLE dfsHandle; MARSHAL_BUFFER marshalBuffer; PUCHAR pBuffer; ULONG cbBuffer; status = DfsOpen(&dfsHandle, NULL); if (NT_SUCCESS(status)) { cbBuffer = 0; status = DfsRtlSize( &MiPktRelationInfo, relationInfo, &cbBuffer ); if (NT_SUCCESS(status)) { pBuffer = malloc( cbBuffer ); if (pBuffer != NULL) { MarshalBufferInitialize(&marshalBuffer, cbBuffer, pBuffer); status = DfsRtlPut( &marshalBuffer, &MiPktRelationInfo, relationInfo); } else { status = STATUS_INSUFFICIENT_RESOURCES; } if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_VERIFY_LOCAL_VOLUME_KNOWLEDGE, pBuffer, cbBuffer, NULL, 0); } if (pBuffer != NULL) free(pBuffer); } NtClose( dfsHandle ); } return( status ); } //+---------------------------------------------------------------------------- // // Function: PktPruneLocalPartition // // Synopsis: Asks the Dfs Driver to get rid of a local volume that is // not supposed to be supported by this server. // // Arguments: [EntryId] -- The entry id of the volume to prune. // // Returns: [STATUS_SUCCESS] -- Successfully pruned the volume // // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- The driver has no record // of local volume described in relation info. // // [STATUS_UNSUCCESSFUL] -- Unable to fixup the local relation // info. An appropriate message was logged to the // local eventlog. // // [STATUS_DATA_ERROR] -- Passed in relationInfo is bogus. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition. // // [STATUS_FS_DRIVER_REQUIRED] -- Unable to open handle to the // Dfs driver // //----------------------------------------------------------------------------- NTSTATUS PktPruneLocalPartition( IN PDFS_PKT_ENTRY_ID EntryId) { NTSTATUS status; HANDLE dfsHandle; MARSHAL_BUFFER marshalBuffer; PUCHAR pBuffer; ULONG cbBuffer; status = DfsOpen(&dfsHandle, NULL); if (NT_SUCCESS(status)) { cbBuffer = 0; status = DfsRtlSize( &MiPktEntryId, EntryId, &cbBuffer ); if (NT_SUCCESS(status)) { pBuffer = malloc( cbBuffer ); if (pBuffer != NULL) { MarshalBufferInitialize(&marshalBuffer, cbBuffer, pBuffer); status = DfsRtlPut( &marshalBuffer, &MiPktEntryId, EntryId); } else { status = STATUS_INSUFFICIENT_RESOURCES; } if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_PRUNE_LOCAL_PARTITION, pBuffer, cbBuffer, NULL, 0); } if (pBuffer != NULL) free(pBuffer); } NtClose( dfsHandle ); } return( status ); } //+---------------------------------------------------------------------------- // // Function: PktIsChildnameLegal, public // // Synopsis: // // Arguments: // // Returns: // //----------------------------------------------------------------------------- NTSTATUS PktIsChildnameLegal( IN PWCHAR pwszParent, IN PWCHAR pwszChild, IN GUID *pidChild) { HANDLE dfsHandle; NTSTATUS Status; DFS_PKT_ENTRY_ID idParent, idChild; MARSHAL_BUFFER marshalBuffer; PUCHAR pBuffer; ULONG cbBuffer; RtlZeroMemory( &idParent, sizeof(DFS_PKT_ENTRY_ID) ); RtlZeroMemory( &idChild, sizeof(DFS_PKT_ENTRY_ID) ); RtlInitUnicodeString( &idParent.Prefix, pwszParent ); RtlInitUnicodeString( &idChild.Prefix, pwszChild ); idChild.Uid = *pidChild; cbBuffer = 0; Status = DfsOpen(&dfsHandle, NULL); if (NT_SUCCESS(Status)) { Status = DfsRtlSize( &MiPktEntryId, &idParent, &cbBuffer ); if (NT_SUCCESS(Status)) { Status = DfsRtlSize( &MiPktEntryId, &idChild, &cbBuffer ); } if (NT_SUCCESS(Status)) { pBuffer = malloc( cbBuffer ); if (pBuffer != NULL) { MarshalBufferInitialize( &marshalBuffer, cbBuffer, pBuffer ); Status = DfsRtlPut( &marshalBuffer, &MiPktEntryId, &idParent ); if (NT_SUCCESS(Status)) { Status = DfsRtlPut( &marshalBuffer, &MiPktEntryId, &idChild ); } if (NT_SUCCESS(Status)) { Status = DfsFsctl( dfsHandle, FSCTL_DFS_IS_CHILDNAME_LEGAL, pBuffer, cbBuffer, NULL, 0L); } free( pBuffer ); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } NtClose( dfsHandle ); } return( Status ); } //+---------------------------------------------------------------------------- // // Function: PktGetEntryType, public // // Synopsis: Given a prefix, this routine retrieves the entry type of the // PktEntry // // Arguments: [pwszPrefix] -- The prefix whose PktEntry's type is required // [pType] -- The type is returned here. // // Returns: // //----------------------------------------------------------------------------- NTSTATUS PktGetEntryType( IN PWSTR pwszPrefix, IN PULONG pType) { HANDLE dfsHandle; NTSTATUS Status; Status = DfsOpen(&dfsHandle, NULL); if (NT_SUCCESS(Status)) { Status = DfsFsctl( dfsHandle, FSCTL_DFS_GET_ENTRY_TYPE, pwszPrefix, wcslen(pwszPrefix) * sizeof(WCHAR), pType, sizeof(ULONG)); NtClose( dfsHandle ); } return( Status ); } //+---------------------------------------------------------------------------- // // Function: DfsSetServiceState // // Synopsis: Sets the state of a service on a volume. // // Arguments: [VolumeId] -- The volume on which to operate // [ServiceName] -- Name of service // [State] -- Either 0 or DFS_SERVICE_TYPE_OFFLINE // // Returns: [STATUS_SUCCESS] -- The specified replica was set // online/offline as speficied. // // [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not // found, or the specified replica is not a server for // the volume. // // [STATUS_DATA_ERROR] -- marshalling or unmarshalling error. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation. // // Status from opening handle to the Dfs driver. // //----------------------------------------------------------------------------- NTSTATUS DfsSetServiceState( IN PDFS_PKT_ENTRY_ID VolumeId, IN PWSTR ServiceName, IN ULONG State) { NTSTATUS status; HANDLE dfsHandle = NULL; DFS_DC_SET_SERVICE_STATE setSvcState; MARSHAL_BUFFER marshalBuffer; PUCHAR buffer = NULL; ULONG size; status = DfsOpen( &dfsHandle, NULL ); if (NT_SUCCESS(status)) { setSvcState.Id = *VolumeId; RtlInitUnicodeString( &setSvcState.ServiceName, ServiceName); setSvcState.State = State; size = 0; status = DfsRtlSize( &MiDCSetServiceState, &setSvcState, &size ); if (NT_SUCCESS(status)) { buffer = (PUCHAR) malloc( size ); if (buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { MarshalBufferInitialize( &marshalBuffer, size, buffer ); status = DfsRtlPut( & marshalBuffer, &MiDCSetServiceState, &setSvcState ); } if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_SET_SERVICE_STATE, buffer, size, NULL, 0); } NtClose( dfsHandle ); if (buffer != NULL) { free( buffer ); } } return( status ); } //+---------------------------------------------------------------------------- // // Function: DfsDCSetVolumeState // // Synopsis: Sets the state of a volume in the DCs. This will control // whether referrals will be given out to this volume or not. // // Arguments: [VolumeId] -- The volume on which to operate // [State] -- Either 0 or PKT_ENTRY_TYPE_OFFLINE // // Returns: [STATUS_SUCCESS] -- The specified replica was set // online/offline as speficied. // // [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not // found. // // [STATUS_DATA_ERROR] -- marshalling or unmarshalling error. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation. // // Status from opening handle to the Dfs driver. // //----------------------------------------------------------------------------- NTSTATUS DfsDCSetVolumeState( IN const PDFS_PKT_ENTRY_ID VolumeId, IN const ULONG State) { NTSTATUS status; HANDLE dfsHandle = NULL; DFS_SETSTATE_ARG setStateArg; MARSHAL_BUFFER marshalBuffer; PUCHAR buffer = NULL; ULONG size; status = DfsOpen( &dfsHandle, NULL ); if (NT_SUCCESS(status)) { setStateArg.Id = *VolumeId; setStateArg.Type = State; size = 0; status = DfsRtlSize( &MiSetStateArg, &setStateArg, &size ); if (NT_SUCCESS(status)) { buffer = (PUCHAR) malloc( size ); if (buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { MarshalBufferInitialize( &marshalBuffer, size, buffer ); status = DfsRtlPut( & marshalBuffer, &MiSetStateArg, &setStateArg ); } if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_DC_SET_VOLUME_STATE, buffer, size, NULL, 0); } NtClose( dfsHandle ); if (buffer != NULL) { free( buffer ); } } return( status ); } //+---------------------------------------------------------------------------- // // Function: DfsSetVolumeTimeout // // Synopsis: Sets the timeout of a volume in the DCs. // // Arguments: [VolumeId] -- The volume on which to operate // [Timeout] -- Timeout, in seconds // // Returns: [STATUS_SUCCESS] -- The specified timeout was set as specified. // // [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not // found. // // [STATUS_DATA_ERROR] -- marshalling or unmarshalling error. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation. // // Status from opening handle to the Dfs driver. // //----------------------------------------------------------------------------- NTSTATUS DfsSetVolumeTimeout( IN const PDFS_PKT_ENTRY_ID VolumeId, IN const ULONG Timeout) { NTSTATUS status; HANDLE dfsHandle = NULL; DFS_SET_VOLUME_TIMEOUT_ARG setVolTimeoutArg; MARSHAL_BUFFER marshalBuffer; PUCHAR buffer = NULL; ULONG size; status = DfsOpen( &dfsHandle, NULL ); if (NT_SUCCESS(status)) { setVolTimeoutArg.Id = *VolumeId; setVolTimeoutArg.Timeout = Timeout; size = 0; status = DfsRtlSize( &MiSetVolTimeoutArg, &setVolTimeoutArg, &size ); if (NT_SUCCESS(status)) { buffer = (PUCHAR) malloc( size ); if (buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } } if (NT_SUCCESS(status)) { MarshalBufferInitialize( &marshalBuffer, size, buffer ); status = DfsRtlPut( & marshalBuffer, &MiSetVolTimeoutArg, &setVolTimeoutArg ); } if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_SET_VOLUME_TIMEOUT, buffer, size, NULL, 0); } NtClose( dfsHandle ); if (buffer != NULL) { free( buffer ); } } return( status ); } //+---------------------------------------------------------------------------- // // Function: DfsCreateSiteEntry // // Synopsis: Loads a Site entry into the dfs site table // // Arguments: [pInfoArg] -- DFS_CREATE_SITE_INFO_ARG with info to update // // Returns: Status from opening handle to the Dfs driver. // //----------------------------------------------------------------------------- NTSTATUS DfsCreateSiteEntry( PCHAR arg, ULONG size) { NTSTATUS status; HANDLE dfsHandle = NULL; status = DfsOpen( &dfsHandle, NULL ); if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_CREATE_SITE_INFO, arg, size, NULL, 0); NtClose( dfsHandle ); } return( status ); } //+---------------------------------------------------------------------------- // // Function: DfsDeleteSiteEntry // // Synopsis: Loads a Site entry into the dfs site table // // Arguments: [pInfoArg] -- DFS_DELETE_SITE_INFO_ARG with info to update // // Returns: Status from opening handle to the Dfs driver. // //----------------------------------------------------------------------------- NTSTATUS DfsDeleteSiteEntry( PCHAR arg, ULONG size) { NTSTATUS status; HANDLE dfsHandle = NULL; status = DfsOpen( &dfsHandle, NULL ); if (NT_SUCCESS(status)) { status = DfsFsctl( dfsHandle, FSCTL_DFS_DELETE_SITE_INFO, arg, size, NULL, 0); NtClose( dfsHandle ); } return( status ); }