//+---------------------------------------------------------------------------- // // Copyright (C) 1992, Microsoft Corporation. // // File: PKT.C // // Contents: This module implements the Partition Knowledge Table routines // for the Dfs driver. // // Functions: PktInitialize - // PktInitializeLocalPartition - // RemoveLastComponent - // PktCreateEntry - // PktCreateSubordinateEntry - // PktLookupEntryById - // PktEntryModifyPrefix - // PktLookupEntryByPrefix - // PktLookupEntryByUid - // PktLookupReferralEntry - // PktSetRelationInfo - // PktTrimSubordinates - // PktpAddEntry - // // History: 5 May 1992 PeterCo Created. // //----------------------------------------------------------------------------- #include "dfsprocs.h" #include #include #include #include "attach.h" #include "log.h" #include "know.h" #define Dbg (DEBUG_TRACE_PKT) // // Local procedure prototypes // NTSTATUS PktInitializeLocalPartition( IN PDFS_PKT Pkt, IN PUNICODE_STRING LocalVolumeName, IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo); NTSTATUS PktpAddEntry ( IN PDFS_PKT Pkt, IN PUNICODE_STRING Prefix, IN PRESP_GET_DFS_REFERRAL ReferralBuffer, IN ULONG CreateDisposition, OUT PDFS_PKT_ENTRY *ppPktEntry); VOID PktShuffleServiceList( PDFS_PKT_ENTRY_INFO pInfo); VOID PktShuffleGroup( PDFS_PKT_ENTRY_INFO pInfo, ULONG nStart, ULONG nEnd); #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, PktInitialize ) #pragma alloc_text( PAGE, PktUninitialize ) #pragma alloc_text( PAGE, PktInitializeLocalPartition ) #pragma alloc_text( PAGE, RemoveLastComponent ) #pragma alloc_text( PAGE, PktCreateEntry ) #pragma alloc_text( PAGE, PktCreateSubordinateEntry ) #pragma alloc_text( PAGE, PktLookupEntryById ) #pragma alloc_text( PAGE, PktEntryModifyPrefix ) #pragma alloc_text( PAGE, PktLookupEntryByPrefix ) #pragma alloc_text( PAGE, PktLookupEntryByUid ) #pragma alloc_text( PAGE, PktSetRelationInfo ) #pragma alloc_text( PAGE, PktTrimSubordinates ) #pragma alloc_text( PAGE, PktpAddEntry ) #endif // ALLOC_PRAGMA // // declare the global null guid // GUID _TheNullGuid; //+------------------------------------------------------------------------- // // Function: PktInitialize, public // // Synopsis: PktInitialize initializes the partition knowledge table. // // Arguments: [Pkt] - pointer to an uninitialized PKT // // Returns: NTSTATUS - STATUS_SUCCESS if no error. // // Notes: This routine is called only at driver init time. // //-------------------------------------------------------------------------- NTSTATUS PktInitialize( IN PDFS_PKT Pkt ) { DebugTrace(+1, Dbg, "PktInitialize: Entered\n", 0); // // initialize the NULL GUID. // RtlZeroMemory(&_TheNullGuid, sizeof(GUID)); // // Always zero the pkt first // RtlZeroMemory(Pkt, sizeof(DFS_PKT)); // // do basic initialization // Pkt->NodeTypeCode = DFS_NTC_PKT; Pkt->NodeByteSize = sizeof(DFS_PKT); ExInitializeResourceLite(&Pkt->Resource); InitializeListHead(&Pkt->EntryList); DfsInitializeUnicodePrefix(&Pkt->LocalVolTable); DfsInitializeUnicodePrefix(&Pkt->PrefixTable); DfsInitializeUnicodePrefix(&Pkt->ShortPrefixTable); RtlInitializeUnicodePrefix(&Pkt->DSMachineTable); // // We don't know anything about our domain yet, so we leave // it NULL. This will get initialized later to the right value! // Pkt->DomainPktEntry = NULL; DebugTrace(-1, Dbg, "PktInitialize: Exit -> VOID\n", 0 ); return STATUS_SUCCESS; } VOID PktUninitialize( IN PDFS_PKT Pkt) { DfsFreePrefixTable(&Pkt->LocalVolTable); DfsFreePrefixTable(&Pkt->PrefixTable); DfsFreePrefixTable(&Pkt->ShortPrefixTable); ExDeleteResourceLite(&Pkt->Resource); } //+------------------------------------------------------------------------- // // Function: PktInitializeLocalPartition, public // // Synopsis: PktInitializeLocalPartition initializes the Pkt entry // and its subordinates specified by the ConfigInfo structure // passed in. // // Arguments: [Pkt] - a pointer to an (exclusively) acquired Pkt. // [LocalVolumeName] - the name of the local volume. // [ConfigInfo] - the parameters specifying the local // entry and all its exit points. // // Returns: [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory conditions // // [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would // require the invalidation of a local entry or exit point. // // [STATUS_INVALID_PARAMETER] - the Id specified for the // new entry is invalid. // // Note: The ConfigInfo argument is stripped of all its Ids as a // by-product of this operation. // // The Pkt needs to be acquired exclusively before calling this. // //-------------------------------------------------------------------------- NTSTATUS PktInitializeLocalPartition( IN PDFS_PKT Pkt, IN PUNICODE_STRING LocalVolumeName, IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo ) { NTSTATUS status; PDFS_PKT_ENTRY entry; DFS_PKT_ENTRY_ID entryId; PDFS_SERVICE localService; PDFS_PKT_RELATION_INFO relationInfo; PDFS_LOCAL_VOL_ENTRY localVolEntry; UNICODE_STRING LocalVolumeRelativeName; DebugTrace(+1, Dbg, "PktInitializeLocalPartition: Entered\n", 0); ASSERT(ARGUMENT_PRESENT(Pkt) && ARGUMENT_PRESENT(LocalVolumeName) && ARGUMENT_PRESENT(ConfigInfo)); // // Now we attempt to create a local service // structure for this Entry...so allocate some memory. // localService = (PDFS_SERVICE) ExAllocatePoolWithTag(PagedPool, sizeof(DFS_SERVICE), ' sfD'); if (localService == NULL) { DebugTrace(0, Dbg, "PktInitializeLocalPartition: Cannot allocate local service!\n",0); DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n", ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) ); return STATUS_INSUFFICIENT_RESOURCES; } localVolEntry = (PDFS_LOCAL_VOL_ENTRY) ExAllocatePoolWithTag( PagedPool, sizeof(DFS_LOCAL_VOL_ENTRY), ' sfD'); if (localVolEntry == NULL) { DebugTrace(0, Dbg, "PktInitializeLocalPartition: Cannot allocate local vol entry!\n",0); DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n", ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) ); ExFreePool(localService); return STATUS_INSUFFICIENT_RESOURCES; } // // Construct the local service. We need to first compute the // break point between the volume device object name, and the // local entry point within the volume, which will become the // service's "address". // if (!(ConfigInfo->EntryType & PKT_ENTRY_TYPE_LEAFONLY)) { status = DfsGetAttachName( LocalVolumeName, &LocalVolumeRelativeName); } else { LocalVolumeRelativeName = *LocalVolumeName; status = STATUS_SUCCESS; } if (NT_SUCCESS(status)) { status = PktServiceConstruct( localService, ConfigInfo->ServiceType | DFS_SERVICE_TYPE_LOCAL, PROV_STRIP_PREFIX, DFS_SERVICE_STATUS_VERIFIED, PROV_ID_LOCAL_FS, NULL, &LocalVolumeRelativeName ); } if (!NT_SUCCESS(status)) { DebugTrace(0, Dbg, "PktInitializeLocalPartition: Cannot construct local service!\n",0); DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n", ULongToPtr( status ) ); ExFreePool(localService); ExFreePool(localVolEntry); return status; } // // Now we attempt to create/update the entry point entry. // // // Remember! the create strips the entry Id off! so we need to // duplicate the entry id info off the relation info structure // so that we can pass it into PktCreateEntry... // relationInfo = &ConfigInfo->RelationInfo; status = PktEntryIdConstruct(&entryId, &relationInfo->EntryId.Uid, &relationInfo->EntryId.Prefix, &relationInfo->EntryId.ShortPrefix); DebugTrace(0, Dbg, "PktEntryIdConstruct returned 0x%x\n", ULongToPtr( status )); if (NT_SUCCESS(status)) { status = PktCreateEntry( Pkt, ConfigInfo->EntryType | PKT_ENTRY_TYPE_LOCAL | PKT_ENTRY_TYPE_PERMANENT, &entryId, NULL, PKT_ENTRY_SUPERSEDE, &entry); DebugTrace(0, Dbg, "PktCreateEntry returned 0x%x\n", ULongToPtr( status )); } if (NT_SUCCESS(status)) { PDFS_PKT_ENTRY subEntry; PDFS_PKT_ENTRY_ID subId; PDFS_PKT_ENTRY_ID lastSubId; // // We trim the subordinates off the entry that are not // included in the relation info. // PktTrimSubordinates(Pkt, entry, relationInfo); // // Go through and create/update all the subordinates. // subId = relationInfo->SubordinateIdList; lastSubId = &subId[ relationInfo->SubordinateIdCount ]; for (subId = relationInfo->SubordinateIdList; subId < lastSubId; subId++) { PktCreateSubordinateEntry( Pkt, entry, PKT_ENTRY_TYPE_LOCAL_XPOINT | PKT_ENTRY_TYPE_PERMANENT, subId, NULL, PKT_ENTRY_SUPERSEDE, &subEntry); DebugTrace(0, Dbg, "PktCreateSubordinateEntry returned 0x%x\n", ULongToPtr( status )); } if (NT_SUCCESS(status)) { // // We set the local service of this entry... // status = PktEntrySetLocalService( Pkt, entry, localService, localVolEntry, LocalVolumeName, &ConfigInfo->Share); DebugTrace(0, Dbg, "PktEntrySetLocalService returned 0x%x\n", ULongToPtr( status )); } if (NT_SUCCESS(status) && !(entry->Type & PKT_ENTRY_TYPE_LEAFONLY)) { status = DfsAttachVolume( LocalVolumeName, &localService->pProvider); if (!NT_SUCCESS(status)) { PktEntryUnsetLocalService( Pkt, entry, LocalVolumeName ); ExFreePool(localVolEntry); } } if (!NT_SUCCESS(status)) { // // We take somewhat draconian measures here. We could // not complete the initialization so we basically // invalidate everything to do with this entry. // while ((subEntry = PktEntryFirstSubordinate(entry)) != NULL) { PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE); } PktEntryDestroy(entry, Pkt, (BOOLEAN)TRUE); // // We need to destroy this as well since it will not get destroyed // as part of above. // PktServiceDestroy(localService, (BOOLEAN)TRUE); DebugTrace(0, Dbg, "PktInitializeLocalPartition: Error creating subordinate!\n",0); } } else { // // we could not create the entry so we need to deallocate the // service we allocated. // PktEntryIdDestroy(&entryId, FALSE); PktServiceDestroy(localService, (BOOLEAN)TRUE); ExFreePool(localVolEntry); DebugTrace(0, Dbg, "PktInitializeLocalPartition: Cannot create entry!\n", 0); } if (NT_SUCCESS(status)) { if (localService->Type & DFS_SERVICE_TYPE_OFFLINE) { localService->ProviderId = localService->pProvider->eProviderId; status = DfspTakeVolumeOffline( Pkt, entry ); } } DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n", ULongToPtr( status ) ); return status; } //+------------------------------------------------------------------------- // // Function: RemoveLastComponent, public // // Synopsis: Removes the last component of the string passed. // // Arguments: [Prefix] -- The prefix whose last component is to be returned. // [newPrefix] -- The new Prefix with the last component removed. // // Returns: NTSTATUS - STATUS_SUCCESS if no error. // // Notes: On return, the newPrefix points to the same memory buffer // as Prefix. // //-------------------------------------------------------------------------- void RemoveLastComponent( PUNICODE_STRING Prefix, PUNICODE_STRING newPrefix ) { PWCHAR pwch; USHORT i=0; *newPrefix = *Prefix; pwch = newPrefix->Buffer; pwch += (Prefix->Length/sizeof(WCHAR)) - 1; while ((*pwch != UNICODE_PATH_SEP) && (pwch != newPrefix->Buffer)) { i += sizeof(WCHAR); pwch--; } newPrefix->Length = newPrefix->Length - i; } //+------------------------------------------------------------------------- // // Function: PktCreateEntry, public // // Synopsis: PktCreateEntry creates a new partition table entry or // updates an existing one. The PKT must be acquired // exclusively for this operation. // // Arguments: [Pkt] - pointer to an initialized (and exclusively acquired) PKT // [PktEntryType] - the type of entry to create/update. // [PktEntryId] - pointer to the Id of the entry to create // [PktEntryInfo] - pointer to the guts of the entry // [CreateDisposition] - specifies whether to overwrite if // an entry already exists, etc. // [ppPktEntry] - the new entry is placed here. // // Returns: [STATUS_SUCCESS] - if all is well. // // [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was // set to PKT_REPLACE_ENTRY and no entry of the specified // Id exists to replace. // // [DFS_STATUS_ENTRY_EXISTS] - a create disposition of // PKT_CREATE_ENTRY was specified and an entry of the // specified Id already exists. // // [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would // required the invalidation of a local entry or exit point. // // [STATUS_INVALID_PARAMETER] - the Id specified for the // new entry is invalid. // // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was // available to complete the operation. // // Notes: The PktEntryId and PktEntryInfo structures are MOVED (not // COPIED) to the new entry. The memory used for UNICODE_STRINGS // and DFS_SERVICE arrays is used by the new entry. The // associated fields in the PktEntryId and PktEntryInfo // structures passed as arguments are Zero'd to indicate that // the memory has been "deallocated" from these strutures and // reallocated to the newly created PktEntry. Note that this // routine does not deallocate the PktEntryId structure or // the PktEntryInfo structure itself. On successful return from // this function, the PktEntryId structure will be modified // to have a NULL Prefix entry, and the PktEntryInfo structure // will be modified to have zero services and a null ServiceList // entry. // //-------------------------------------------------------------------------- NTSTATUS PktCreateEntry( IN PDFS_PKT Pkt, IN ULONG PktEntryType, IN PDFS_PKT_ENTRY_ID PktEntryId, IN PDFS_PKT_ENTRY_INFO PktEntryInfo OPTIONAL, IN ULONG CreateDisposition, OUT PDFS_PKT_ENTRY *ppPktEntry ) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT_ENTRY pfxMatchEntry = NULL; PDFS_PKT_ENTRY uidMatchEntry = NULL; PDFS_PKT_ENTRY entryToUpdate = NULL; PDFS_PKT_ENTRY entryToInvalidate = NULL; PDFS_PKT_ENTRY SupEntry = NULL; UNICODE_STRING remainingPath = {0, 0, NULL}; UNICODE_STRING newRemainingPath; ASSERT(ARGUMENT_PRESENT(Pkt) && ARGUMENT_PRESENT(PktEntryId) && ARGUMENT_PRESENT(ppPktEntry)); DebugTrace(+1, Dbg, "PktCreateEntry: Entered\n", 0); // // We're pessimistic at first... // *ppPktEntry = NULL; // // See if there exists an entry with this prefix. The prefix // must match exactly (i.e. No remaining path). // pfxMatchEntry = PktLookupEntryByPrefix(Pkt, &PktEntryId->Prefix, &remainingPath); if ((remainingPath.Length > 0) || (PktEntryId->Prefix.Length == 0)) { SupEntry = pfxMatchEntry; pfxMatchEntry = NULL; } else { UNICODE_STRING newPrefix; RemoveLastComponent(&PktEntryId->Prefix, &newPrefix); SupEntry = PktLookupEntryByPrefix(Pkt, &newPrefix, &newRemainingPath); } // // Now search for an entry that has the same Uid. // uidMatchEntry = PktLookupEntryByUid(Pkt, &PktEntryId->Uid); // // Now we must determine if during this create, we are going to be // updating or invalidating any existing entries. If an existing // entry is found that has the same Uid as the one we are trying to // create, the entry becomes a target for "updating". If the Uid // passed in is NULL, then we check to see if an entry exists that // has a NULL Uid AND a Prefix that matches. If this is the case, // that entry becomes the target for "updating". // // To determine if there is an entry to invalidate, we look for an // entry with the same Prefix as the one we are trying to create, BUT, // which has a different Uid. If we detect such a situation, we // we make the entry with the same Prefix the target for invalidation // (we do not allow two entries with the same Prefix, and we assume // that the new entry takes precedence). // if (uidMatchEntry != NULL) { entryToUpdate = uidMatchEntry; if (pfxMatchEntry != uidMatchEntry) entryToInvalidate = pfxMatchEntry; } else if ((pfxMatchEntry != NULL) && NullGuid(&pfxMatchEntry->Id.Uid)) { entryToUpdate = pfxMatchEntry; } else { entryToInvalidate = pfxMatchEntry; } // // Now we check to make sure that our create disposition is // consistent with what we are about to do. // if ((CreateDisposition & PKT_ENTRY_CREATE) && entryToUpdate != NULL) { *ppPktEntry = entryToUpdate; status = DFS_STATUS_ENTRY_EXISTS; } else if ((CreateDisposition & PKT_ENTRY_REPLACE) && entryToUpdate==NULL) { status = DFS_STATUS_NO_SUCH_ENTRY; } // // if we have an error here we can get out now! // if (!NT_SUCCESS(status)) { DebugTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr( status ) ); return status; } // // At this point, we have two possible entries - entryToUpdate and // entryToInvalidate. We make an additional check to see if there is // a conflict with an 8.3 prefix. This logic works according to the // following table: // // entryToUpdate | entryToInvalidate | 8.3 match || Action // | | || // 0 | 0 | 0 || Create // | | || // 1 | 0 | 0 || Update // | | || // 0 | 1 | 0 || Invalidate/Create // | | || // 1 | 1 | 0 || Invalidate/Update // | | || // 0 | 0 | 1 || 8.3 name conflict // | | || // 1 | 0 | 1 || In entryToUpdate is // | | || the 8.3 match, ok // 0 | 1 | 1 || If entryToInvalidate // | | || is the 8.3 match, // 1 | 1 | 1 || then invalidate, // | | || else 8.3 name conflict // if (PktEntryId->ShortPrefix.Length != 0) { PDFS_PKT_ENTRY shortpfxMatch; shortpfxMatch = PktLookupEntryByShortPrefix( Pkt, &PktEntryId->ShortPrefix, &remainingPath); if (remainingPath.Length > 0) shortpfxMatch = NULL; if (shortpfxMatch != NULL) { if (entryToUpdate == NULL && entryToInvalidate == NULL) { status = STATUS_DUPLICATE_NAME; } else if (entryToUpdate != NULL && entryToInvalidate == NULL) { if (shortpfxMatch != entryToUpdate) { status = STATUS_DUPLICATE_NAME; } } else if (entryToInvalidate != NULL) { if (shortpfxMatch != entryToInvalidate) { status = STATUS_DUPLICATE_NAME; } } } } if (!NT_SUCCESS(status)) { DebugTrace(-1, Dbg, "PktCreateEntry: (Short name conflict) Exit -> %08lx\n", ULongToPtr( status )); return status; } // // At this point we must insure that we are not going to // be invalidating any local partition entries. // if ((entryToInvalidate != NULL) && (!(entryToInvalidate->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) ) && (entryToInvalidate->Type & (PKT_ENTRY_TYPE_LOCAL | PKT_ENTRY_TYPE_LOCAL_XPOINT | PKT_ENTRY_TYPE_PERMANENT))) { DebugTrace(-1, Dbg, "PktCreateEntry(1): Exit -> %08lx\n", ULongToPtr( DFS_STATUS_LOCAL_ENTRY ) ); return DFS_STATUS_LOCAL_ENTRY; } // // We go up the links till we reach a REFERRAL entry type. Actually // we may never go up since we always link to a REFERRAL entry. Anyway // no harm done! // while ((SupEntry != NULL) && !(SupEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC)) { SupEntry = SupEntry->ClosestDC; } // // If we had success then we need to see if we have to // invalidate an entry. // if (NT_SUCCESS(status) && entryToInvalidate != NULL) PktEntryDestroy(entryToInvalidate, Pkt, (BOOLEAN)TRUE); // // If we are not updating an entry we must construct a new one // from scratch. Otherwise we need to update. // if (entryToUpdate != NULL) { status = PktEntryReassemble(entryToUpdate, Pkt, PktEntryType, PktEntryId, PktEntryInfo); if (NT_SUCCESS(status)) { (*ppPktEntry) = entryToUpdate; PktEntryLinkChild(SupEntry, entryToUpdate); } } else { // // Now we are going to create a new entry. So we have to set // the ClosestDC Entry pointer while creating this entry. The // ClosestDC entry value is already in SupEntry. // PDFS_PKT_ENTRY newEntry; newEntry = (PDFS_PKT_ENTRY) ExAllocatePoolWithTag( PagedPool, sizeof(DFS_PKT_ENTRY), ' sfD'); if (newEntry == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { status = PktEntryAssemble(newEntry, Pkt, PktEntryType, PktEntryId, PktEntryInfo); if (!NT_SUCCESS(status)) { ExFreePool(newEntry); } else { (*ppPktEntry) = newEntry; PktEntryLinkChild(SupEntry, newEntry); } } } DebugTrace(-1, Dbg, "PktCreateEntry(2): Exit -> %08lx\n", ULongToPtr( status )); return status; } //+------------------------------------------------------------------------- // // Function: PktCreateSubordinateEntry, public // // Synopsis: PktCreateSubordinateEntry creates/updates an entry to be // subordinate to an existing entry. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Superior] - a pointer to the superior entry. // [SubordinateType] - the type of subordinate entry to // create/update. // [SubordinateId] - the Id of the entry to create/update // to be subordinate. // [SubordinateInfo] - the Info of the entry to create/update. // [CreateDisposition] - identifies whether or not to supersede, // create, or update. // [Subordinate] - the (potentially new) subordinate entry. // // Returns: [STATUS_SUCCESS] - if all is well. // [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was // set to PKT_REPLACE_ENTRY and the Subordinate entry does // not exist. // [DFS_STATUS_ENTRY_EXISTS] - a create disposition of // PKT_CREATE_ENTRY was specified and the subordinate entry // already exists. // [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry // would have required that a local entry or exit point // be invalidated. // [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT // has been discovered. // [STATUS_INVALID_PARAMETER] - the Id specified for the // subordinate is invalid. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was // available to complete the operation. // // // Notes: If the subordinate exists and is currently a subordinate // of some other entry (then the Superior specified), it is // first removed from the old superior before making it // a subordinate of the Superior specified. // // The SubordinateId and SubordinateInfo structures are MOVED (not // COPIED) to the new entry. The memory used for UNICODE_STRINGS // and DFS_SERVICE arrays is used by the new entry. The // associated fields in the SubordinateId and SubordinateInfo // structures passed as arguments are Zero'd to indicate that // the memory has been "deallocated" from these strutures and // reallocated to the newly created Subordinate. Note that this // routine does not deallocate the SubordinateId structure or // the SubordinateInfo structure itself. On successful return from // this function, the SubordinateId structure will be modified // to have a NULL Prefix entry, and the SubordinateInfo structure // will be modified to have zero services and a null ServiceList // entry. //-------------------------------------------------------------------------- NTSTATUS PktCreateSubordinateEntry( IN PDFS_PKT Pkt, IN PDFS_PKT_ENTRY Superior, IN ULONG SubordinateType, IN PDFS_PKT_ENTRY_ID SubordinateId, IN PDFS_PKT_ENTRY_INFO SubordinateInfo OPTIONAL, IN ULONG CreateDisposition, IN OUT PDFS_PKT_ENTRY *Subordinate ) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT_ENTRY subEntry; DebugTrace(+1, Dbg, "PktCreateSubordinateEntry: Entered\n", 0); ASSERT(ARGUMENT_PRESENT(Pkt)); ASSERT(ARGUMENT_PRESENT(Superior)); ASSERT(ARGUMENT_PRESENT(SubordinateId)); ASSERT(ARGUMENT_PRESENT(Subordinate)); // // Now we go ahead and create the new sub entry... // status = PktCreateEntry( Pkt, SubordinateType, SubordinateId, SubordinateInfo, CreateDisposition, &subEntry ); if (NT_SUCCESS(status)) { PktSetTypeInheritance(Superior, subEntry) // // Link the child to the parent...note that this removes the // child from any other parent. // PktEntryLinkSubordinate(Superior, subEntry); // // Don't forget to set the return value... // (*Subordinate) = subEntry; } DebugTrace(-1, Dbg, "PktCreateSubordinateEntry: Exit -> %08lx\n", ULongToPtr( status )); return status; } //+------------------------------------------------------------------------- // // Function: PktEntryModifyPrefix, public // // Synopsis: PktEntryModifyPrefix finds an entry that has a // specified prefix. The PKT must be acquired for // this operation. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Prefix] - the volume's new entry path // [Entry] - pointer to the PKT entry that needs to be modified. // // Returns: [DFS_STATUS_BAD_EXIT_POINT] -- If the new prefix could // not be inserted into the prefix table. // // [STATUS_INSUFFICIENT_RESOURCES] -- If room for the new // prefix could not be allocated. // // [STATUS_SUCCESS] -- If everything succeeds. // // Notes: If everything succeeds, the old Entry->Id.Prefix.Buffer is // freed up. If this function fails, then everything, including // the prefix table, is left intact. // //-------------------------------------------------------------------------- NTSTATUS PktEntryModifyPrefix( IN PDFS_PKT Pkt, IN PUNICODE_STRING Prefix, IN PDFS_PKT_ENTRY Entry) { NTSTATUS status; UNICODE_STRING oldPrefix = Entry->Id.Prefix; DebugTrace(+1, Dbg, "PktEntryModifyPrefix: Entered\n", 0); // // First, try to allocate space for the new prefix. The old one has // already been saved in oldPrefix // Entry->Id.Prefix.Buffer = ExAllocatePoolWithTag(PagedPool, Prefix->MaximumLength, ' sfD'); if (Entry->Id.Prefix.Buffer != NULL) { // // Next, get rid of the existing prefix from the PrefixTable. // DfsRemoveUnicodePrefix(&(Pkt->PrefixTable), &oldPrefix); // // Now we will plug in the actual prefix. // wcscpy(Entry->Id.Prefix.Buffer, Prefix->Buffer); Entry->Id.Prefix.Length = Prefix->Length; Entry->Id.Prefix.MaximumLength = Prefix->MaximumLength; if (DfsInsertUnicodePrefix(&Pkt->PrefixTable, &(Entry->Id.Prefix), &(Entry->PrefixTableEntry))) { ExFreePool(oldPrefix.Buffer); status = STATUS_SUCCESS; } else { ExFreePool( Entry->Id.Prefix.Buffer ); Entry->Id.Prefix = oldPrefix; DfsInsertUnicodePrefix(&Pkt->PrefixTable, &(Entry->Id.Prefix), &(Entry->PrefixTableEntry)); status = DFS_STATUS_BAD_EXIT_POINT; } } else { DebugTrace(0, Dbg, "PktEntryModifyPrefix: Unable to allocate %d bytes\n", Prefix->MaximumLength); Entry->Id.Prefix = oldPrefix; status = STATUS_INSUFFICIENT_RESOURCES; } DebugTrace(-1, Dbg, "PktEntryModifyPrefix: Exit -> %08lx\n", ULongToPtr( status )); return(status); } //+------------------------------------------------------------------------- // // Function: PktLookupEntryById, public // // Synopsis: PktLookupEntryById finds an entry that has a // specified Entry Id. The PKT must be acquired for // this operation. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Id] - the partitions Id to lookup. // // Returns: The PKT_ENTRY that has the exact same Id, or NULL, // if none exists. // // Notes: // //-------------------------------------------------------------------------- PDFS_PKT_ENTRY PktLookupEntryById( IN PDFS_PKT Pkt, IN PDFS_PKT_ENTRY_ID Id ) { PDFS_PKT_ENTRY ep; UNICODE_STRING remaining; DebugTrace(+1, Dbg, "PktLookupEntryById: Entered\n", 0); ASSERT(ARGUMENT_PRESENT(Pkt) && ARGUMENT_PRESENT(Id)); ep = PktLookupEntryByPrefix(Pkt, &Id->Prefix, &remaining); if (ep != NULL) { if (remaining.Length != 0 || !GuidEqual(&Id->Uid, &ep->Id.Uid)) ep = NULL; } DebugTrace(-1, Dbg, "PktLookupEntryById: Exit -> %08lx\n", ep ); return ep; } //+------------------------------------------------------------------------- // // Function: PktLookupEntryByPrefix, public // // Synopsis: PktLookupEntryByPrefix finds an entry that has a // specified prefix. The PKT must be acquired for // this operation. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Prefix] - the partitions prefix to lookup. // [Remaining] - any remaining path. Points within // the Prefix to where any trailing (nonmatched) // characters are. // // Returns: The PKT_ENTRY that has the exact same prefix, or NULL, // if none exists. // // Notes: // //-------------------------------------------------------------------------- PDFS_PKT_ENTRY PktLookupEntryByPrefix( IN PDFS_PKT Pkt, IN PUNICODE_STRING Prefix, OUT PUNICODE_STRING Remaining ) { PUNICODE_PREFIX_TABLE_ENTRY pfxEntry; PDFS_PKT_ENTRY pktEntry; UNICODE_STRING PrefixTail; UNICODE_STRING EntryTail; DebugTrace(+1, Dbg, "PktLookupEntryByPrefix: Entered\n", 0); // // If there really is a prefix to lookup, use the prefix table // to initially find an entry // if ((Prefix->Length != 0) && (pfxEntry = DfsFindUnicodePrefix(&Pkt->PrefixTable,Prefix,Remaining))) { USHORT pfxLength; // // reset a pointer to the corresponding entry // pktEntry = CONTAINING_RECORD(pfxEntry, DFS_PKT_ENTRY, PrefixTableEntry ); RemoveFirstComponent(Prefix,&PrefixTail); RemoveFirstComponent(&pktEntry->Id.Prefix,&EntryTail); pfxLength = EntryTail.Length; // // Now calculate the remaining path and return // the entry we found. Note that we bump the length // up by one char so that we skip any path separater. // if ((pfxLength < PrefixTail.Length) && (PrefixTail.Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP)) pfxLength += sizeof(WCHAR); if (pfxLength <= PrefixTail.Length) { Remaining->Length = (USHORT)(PrefixTail.Length - pfxLength); Remaining->Buffer = &PrefixTail.Buffer[pfxLength/sizeof(WCHAR)]; Remaining->MaximumLength = (USHORT)(PrefixTail.MaximumLength - pfxLength); DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: Remaining = %wZ\n", Remaining); } else { Remaining->Length = Remaining->MaximumLength = 0; Remaining->Buffer = NULL; DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: No Remaining\n", 0); } DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n", pktEntry); return pktEntry; } DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n", NULL); return NULL; } //+------------------------------------------------------------------------- // // Function: PktLookupEntryByShortPrefix, public // // Synopsis: PktLookupEntryByShortPrefix finds an entry that has a // specified short (8.3) prefix. The PKT must be acquired for // this operation. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Prefix] - the partitions prefix to lookup. // [Remaining] - any remaining path. Points within // the Prefix to where any trailing (nonmatched) // characters are. // // Returns: The PKT_ENTRY that has the exact same prefix, or NULL, // if none exists. // // Notes: // //-------------------------------------------------------------------------- PDFS_PKT_ENTRY PktLookupEntryByShortPrefix( IN PDFS_PKT Pkt, IN PUNICODE_STRING Prefix, OUT PUNICODE_STRING Remaining ) { PUNICODE_PREFIX_TABLE_ENTRY pfxEntry; PDFS_PKT_ENTRY pktEntry; DebugTrace(+1, Dbg, "PktLookupEntryByShortPrefix: Entered\n", 0); // // If there really is a prefix to lookup, use the prefix table // to initially find an entry // if ((Prefix->Length != 0) && (pfxEntry = DfsFindUnicodePrefix(&Pkt->ShortPrefixTable,Prefix,Remaining))) { USHORT pfxLength; // // reset a pointer to the corresponding entry // pktEntry = CONTAINING_RECORD(pfxEntry, DFS_PKT_ENTRY, PrefixTableEntry ); pfxLength = pktEntry->Id.ShortPrefix.Length; // // Now calculate the remaining path and return // the entry we found. Note that we bump the length // up by one char so that we skip any path separater. // if ((pfxLength < Prefix->Length) && (Prefix->Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP)) pfxLength += sizeof(WCHAR); if (pfxLength <= Prefix->Length) { Remaining->Length = (USHORT)(Prefix->Length - pfxLength); Remaining->Buffer = &Prefix->Buffer[pfxLength/sizeof(WCHAR)]; Remaining->MaximumLength = (USHORT)(Prefix->MaximumLength - pfxLength); DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: Remaining = %wZ\n", Remaining); } else { Remaining->Length = Remaining->MaximumLength = 0; Remaining->Buffer = NULL; DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: No Remaining\n", 0); } DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n", pktEntry); return pktEntry; } DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n", NULL); return NULL; } //+------------------------------------------------------------------------- // // Function: PktLookupEntryByUid, public // // Synopsis: PktLookupEntryByUid finds an entry that has a // specified Uid. The PKT must be acquired for this operation. // // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT // [Uid] - a pointer to the partitions Uid to lookup. // // Returns: A pointer to the PKT_ENTRY that has the exact same // Uid, or NULL, if none exists. // // Notes: The input Uid cannot be the Null GUID. // // On a DC where there may be *lots* of entries in the PKT, // we may want to consider using some other algorithm for // looking up by ID. // //-------------------------------------------------------------------------- PDFS_PKT_ENTRY PktLookupEntryByUid( IN PDFS_PKT Pkt, IN GUID *Uid ) { PDFS_PKT_ENTRY entry; DebugTrace(+1, Dbg, "PktLookupEntryByUid: Entered\n", 0); // // We don't lookup NULL Uids // if (NullGuid(Uid)) { DebugTrace(0, Dbg, "PktLookupEntryByUid: NULL Guid\n", NULL); entry = NULL; } else { entry = PktFirstEntry(Pkt); } while (entry != NULL) { if (GuidEqual(&entry->Id.Uid, Uid)) break; entry = PktNextEntry(Pkt, entry); } DebugTrace(-1, Dbg, "PktLookupEntryByUid: Exit -> %08lx\n", entry); return entry; } //+------------------------------------------------------------------------- // // Function: PktSetRelationInfo, public // // Synopsis: PktSetRelationInfo takes the information specified in a // relation info structure and sets the Pkt entries accordingly. // // Arguments: [Pkt] - a pointer to an exclusively acquired Pkt. // [RelationInfo] - a pointer to a relation info structure // specifying the relationship that is to be set. // // Returns: [STATUS_SUCCESS] - if all is well. // [DFS_STATUS_NO_SUCH_ENTRY] - the EntryId specified in the // Relation Info structure does not exist. // [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry // would have required that a local entry or exit point // be invalidated. // [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT // has been discovered. // [STATUS_INVALID_PARAMETER] - the Id specified for a // subordinate is invalid. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was // available to complete the operation. // // // Notes: If this operation fails, all subordinates of the entry // are cleared. // //-------------------------------------------------------------------------- NTSTATUS PktSetRelationInfo( IN PDFS_PKT Pkt, IN PDFS_PKT_RELATION_INFO RelationInfo ) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT_ENTRY entry; ULONG i; DebugTrace(+1, Dbg, "PktSetRelationalInfo: Entered\n", 0); ASSERT(ARGUMENT_PRESENT(Pkt)); ASSERT(ARGUMENT_PRESENT(RelationInfo)); // // We need to lookup the entry for which we are setting relation // information on. // if ((entry = PktLookupEntryById(Pkt, &RelationInfo->EntryId)) == NULL) { DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n", ULongToPtr( DFS_STATUS_NO_SUCH_ENTRY )); return DFS_STATUS_NO_SUCH_ENTRY; } // // Now we go and trim off any subordinates that aren't // currently identified in the Relation Info structure. // PktTrimSubordinates(Pkt, entry, RelationInfo); // // Go through the relation info structure creating subordinates // for (i = 0; i < RelationInfo->SubordinateIdCount; i++) { PDFS_PKT_ENTRY subEntry; status = PktCreateSubordinateEntry( Pkt, entry, 0L, &RelationInfo->SubordinateIdList[i], NULL, PKT_ENTRY_SUPERSEDE, &subEntry ); if (!NT_SUCCESS(status)) { // // If there was an error, we clear away all subordinates. // ...It's an all or nothing proposition... // PktEntryClearSubordinates(entry); break; } } DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n", ULongToPtr( status )); return status; } //+------------------------------------------------------------------------- // // Function: PktTrimSubordinates, public // // Synopsis: PktTrimSubordinates invalidates all subordinate entries // that are not specified in the relation info structure // supplied. // // Arguments: [Pkt] - a pointer to an exclusively acquired Pkt. // [PktEntry] - a pointer to an entry that is to have all its // subordinates unlinked. // [RelationInfo] - a pointer to a relation info structure // specifying the relationship that the Pkt is to // be trimmed to. // // Returns: VOID // // Notes: This operation does not insure that all the subordinates // exist, it only insures that no subordinates that are // NOT specified in the relation info structure exist. // //-------------------------------------------------------------------------- VOID PktTrimSubordinates( IN PDFS_PKT Pkt, IN PDFS_PKT_ENTRY Entry, IN PDFS_PKT_RELATION_INFO RInfo ) { PDFS_PKT_ENTRY subEntry; DebugTrace(+1, Dbg, "PktTrimSubordinates: Entered\n", 0); ASSERT(ARGUMENT_PRESENT(Entry)); ASSERT(ARGUMENT_PRESENT(RInfo)); ASSERT(PktEntryIdEqual(&Entry->Id, &RInfo->EntryId)); // // go through the list of subordinate entries // subEntry = PktEntryFirstSubordinate(Entry); while (subEntry != NULL) { PDFS_PKT_ENTRY_ID id; PDFS_PKT_ENTRY nextSubEntry; BOOLEAN onTheList; // // Search the list of subordinate ids to insure that this // subordinate is on it. // for (onTheList = FALSE, id = RInfo->SubordinateIdList; id < &RInfo->SubordinateIdList[RInfo->SubordinateIdCount]; id++) { if (PktEntryIdEqual(&subEntry->Id, id)) { onTheList = TRUE; break; } } // // If we didn't find the subordinate on the list, we destroy... // Note that we have to get the next subordinate prior to this // just in case the current one gets nuked! // nextSubEntry = PktEntryNextSubordinate(Entry, subEntry); if (!onTheList) PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE); // // go to the next subordinate entry... // subEntry = nextSubEntry; } DebugTrace(-1, Dbg, "PktTrimSubordinates: Exit -> VOID\n", 0); } //+---------------------------------------------------------------------------- // // Function: PktpPruneExtraVolume // // Synopsis: Sometimes a DC thinks this server has an extra volume, so // that volume's knowledge needs to be pruned from the pkt and // registry, and the volume's exit points need to be deleted // from the disk. This routine is a helper routine to do that. // // Arguments: [RelationInfo] -- The Relation Info for the local volume // that needs to be pruned. // // Returns: [STATUS_SUCCESS] -- Local volume and its exit pts were deleted // // [STATUS_UNSUCCESSFUL] -- Some errors were encountered in // deleting the local volume; for each error, a message // was logged. // // Notes: Assumes Pkt has been acquired exclusive // // History: 05-April-95 Milans created // //----------------------------------------------------------------------------- NTSTATUS PktpPruneExtraVolume( IN PDFS_PKT_RELATION_INFO RelationInfo) { NTSTATUS status, returnStatus; PDFS_PKT_ENTRY_ID peid; UNICODE_STRING puStr[2]; ULONG i; puStr[1].MaximumLength = sizeof(L"LocalMachine"); puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR); puStr[1].Buffer = L"LocalMachine"; // // First we delete all the exit Points. // returnStatus = STATUS_SUCCESS; peid = RelationInfo->SubordinateIdList; for (i = 0; i < RelationInfo->SubordinateIdCount; i++) { status = DfsInternalDeleteExitPoint(peid, PKT_ENTRY_TYPE_CAIRO); if (!NT_SUCCESS(status)) { DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: DeletingExitPt " "failed: %08lx\n", ULongToPtr( status )); puStr[0] = peid->Prefix; LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr); returnStatus = STATUS_UNSUCCESSFUL; } peid++; } status = DfsInternalDeleteLocalVolume(&RelationInfo->EntryId); if (!NT_SUCCESS(status)) { puStr[0] = RelationInfo->EntryId.Prefix; DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: Deleting " "Extra Local Volume failed: %08lx\n", ULongToPtr( status )); LogWriteMessage(EXTRA_VOLUME_NOT_DELETED, status, 2, puStr); returnStatus = STATUS_UNSUCCESSFUL; } return( status ); } //+---------------------------------------------------------------------------- // // Function: PktpFixupRelationInfo // // Synopsis: Sometimes a DC will discover that this server has the wrong // information about a local volume. This routine will fix up // the local knowledge to that of the DC. // // Arguments: // // Returns: [STATUS_SUCCESS] -- We managed to completely sync up with // the DC's relation info. // // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory. // // [STATUS_UNSUCCESSFUL] -- We were unable to fully sync up - // a message was logged for the errors encountered. // // Notes: Assumes Pkt has been acquired exclusive // // History: 05-April-95 Milans created // //----------------------------------------------------------------------------- NTSTATUS PktpFixupRelationInfo( IN PDFS_PKT_RELATION_INFO Local, IN PDFS_PKT_RELATION_INFO Remote) { NTSTATUS status, returnStatus; PUNICODE_STRING lpfx, rpfx; ULONG i, j=0; ULONG *pulExitPtUsed = NULL; UNICODE_STRING LocalMachStr; UNICODE_STRING puStr[3]; UNICODE_STRING unusedShortPrefix; LocalMachStr.MaximumLength = sizeof(L"LocalMachine"); LocalMachStr.Length = LocalMachStr.MaximumLength - sizeof(WCHAR); LocalMachStr.Buffer = L"LocalMachine"; returnStatus = status = STATUS_SUCCESS; // // The GUIDs of this volume have already been matched otherwise we // would not be here. So we don't even look at that. We still // need to match the prefixes. If the prefixes are different then we // need to fix that. // lpfx = &Local->EntryId.Prefix; rpfx = &Remote->EntryId.Prefix; if (RtlCompareUnicodeString(lpfx, rpfx, TRUE)) { // // The Prefixes are different we need to fix this now. // But first let us log this event. // DebugTrace(0, Dbg, "Fixed Prefix [%wZ]\n", rpfx); DebugTrace(0, Dbg, "To be [%wZ]\n", lpfx); puStr[0] = Local->EntryId.Prefix; puStr[1] = Remote->EntryId.Prefix; puStr[2] = LocalMachStr; LogWriteMessage(PREFIX_MISMATCH, status, 3, puStr); status = DfsInternalModifyPrefix(&Remote->EntryId); if (NT_SUCCESS(status)) { LogWriteMessage(PREFIX_MISMATCH_FIXED, status, 3, puStr); } else { DebugTrace(0, 1, "Dfs - PktRelationInfoValidate: " "Status from DfsModifyePrefix = %08lx\n", ULongToPtr( status )); LogWriteMessage(PREFIX_MISMATCH_NOT_FIXED, status, 3,puStr); } } if (Remote->SubordinateIdCount != 0) { ULONG size = sizeof(ULONG) * Remote->SubordinateIdCount; pulExitPtUsed = ExAllocatePoolWithTag( PagedPool, size, ' sfD' ); if (pulExitPtUsed == NULL) { return ( STATUS_INSUFFICIENT_RESOURCES ); } else { RtlZeroMemory( pulExitPtUsed, size ); } } // // We step through each exit point in the local knowledge and // make sure that is right. If not we attempt to delete the exit // point from this machine. So this takes care of EXTRA // ExitPoints at this machine. We will still need to deal with // ExitPoints which the DC knows of whereas the this machine does // not. So we keep track of all the remote exit points which have // been acounted for by the local Relational info and then we // take the rest and create those exit points at this machine. // This takes care of TOO FEW ExitPoints at this machine. // for (i = 0; i < Local->SubordinateIdCount; i++) { ULONG j; GUID *lguid, *rguid; rpfx = &Local->SubordinateIdList[i].Prefix; rguid = &Local->SubordinateIdList[i].Uid; status = DFS_STATUS_BAD_EXIT_POINT; for (j = 0; j < Remote->SubordinateIdCount; j++) { lpfx = &Remote->SubordinateIdList[j].Prefix; lguid = &Remote->SubordinateIdList[j].Uid; if (!RtlCompareUnicodeString(lpfx, rpfx, TRUE) && GuidEqual(lguid, rguid)) { status = STATUS_SUCCESS; ASSERT(pulExitPtUsed[j] == FALSE); pulExitPtUsed[j] = TRUE; break; } } if (!NT_SUCCESS(status)) { // // In this case we have an exit point which the DC does not // recognise. We need to delete this. // puStr[0] = Local->SubordinateIdList[i].Prefix; puStr[1] = LocalMachStr; LogWriteMessage(EXTRA_EXIT_POINT, status, 2, puStr); status = DfsInternalDeleteExitPoint(&Local->SubordinateIdList[i], PKT_ENTRY_TYPE_CAIRO); if (!NT_SUCCESS(status)) { // // We want to Log an event here actually. // DebugTrace(0, 1, "Dfs - PktpFixupRelationInfo: Failed to delete [%wZ]\n", &Local->SubordinateIdList[i].Prefix ); LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr); returnStatus = STATUS_UNSUCCESSFUL; } else { LogWriteMessage(EXTRA_EXIT_POINT_DELETED, status, 2, puStr); } } } // // Now that we are done with getting rid of extra exit points // we only need to deal with any exit point that we dont have // and create any such that might exist. // for (i = 0; i < Remote->SubordinateIdCount; i++) { if (pulExitPtUsed[i] == FALSE) { puStr[0] = Remote->SubordinateIdList[i].Prefix; puStr[1] = LocalMachStr; LogWriteMessage(MISSING_EXIT_POINT, status, 2, puStr); RtlInitUnicodeString(&unusedShortPrefix, NULL); status = DfsInternalCreateExitPoint( &Remote->SubordinateIdList[i], PKT_ENTRY_TYPE_CAIRO, FILE_OPEN_IF, &unusedShortPrefix); if (NT_SUCCESS(status) && unusedShortPrefix.Buffer != NULL) { ExFreePool(unusedShortPrefix.Buffer); } if (!NT_SUCCESS(status)) { // // We want to Log an event here actually. // DebugTrace(0, 1, "DFS - PktpFixupRelationInfo: " "Failed to Create ExitPt [%wZ]\n", &Remote->SubordinateIdList[i].Prefix); LogWriteMessage(MISSING_EXIT_POINT_NOT_CREATED, status, 2, puStr); returnStatus = STATUS_UNSUCCESSFUL; } else { LogWriteMessage(MISSING_EXIT_POINT_CREATED, status, 2, puStr); } } } // end for each subordinate in remote relation info if (pulExitPtUsed != NULL) { ExFreePool(pulExitPtUsed); } return( returnStatus ); } //+---------------------------------------------------------------------------- // // Function: PktShuffleServiceList // // Synopsis: Randomizes a service list for proper load balancing. This // routine assumes that the service list is ordered based on // site costs. For each equivalent cost group, this routine // shuffles the service list. // // Arguments: [pInfo] -- Pointer to PktEntryInfo whose service list needs to // be shuffled. // // Returns: Nothing, unless rand() fails! // //----------------------------------------------------------------------------- VOID PktShuffleServiceList( PDFS_PKT_ENTRY_INFO pInfo) { PktShuffleGroup(pInfo, 0, pInfo->ServiceCount); } //+---------------------------------------------------------------------------- // // Function: PktShuffleGroup // // Synopsis: Shuffles a cost equivalent group of services around for load // balancing. Uses the classic card shuffling algorithm - for // each card in the deck, exchange it with a random card in the // deck. // // Arguments: // // Returns: // //----------------------------------------------------------------------------- VOID PktShuffleGroup( PDFS_PKT_ENTRY_INFO pInfo, ULONG nStart, ULONG nEnd) { ULONG i; LARGE_INTEGER seed; ASSERT( nStart < pInfo->ServiceCount ); ASSERT( nEnd <= pInfo->ServiceCount ); KeQuerySystemTime( &seed ); for (i = nStart; i < nEnd; i++) { DFS_SERVICE TempService; ULONG j; ASSERT (nEnd - nStart != 0); j = (RtlRandom( &seed.LowPart ) % (nEnd - nStart)) + nStart; ASSERT( j >= nStart && j <= nEnd ); TempService = pInfo->ServiceList[i]; pInfo->ServiceList[i] = pInfo->ServiceList[j]; pInfo->ServiceList[j] = TempService; } } //+---------------------------------------------------------------------------- // // Function: DfsBuildConnectionRequest // // Synopsis: Builds the EA and file names necessary to setup an // authenticated connection to a server. // // Arguments: [pService] -- Pointer to DFS_SERVICE describing server // [pProvider] -- Pointer to PROVIDER_DEF describing the // provider to use to establish the connection. // [pShareName] -- Share name to open. // // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES // //----------------------------------------------------------------------------- NTSTATUS DfsBuildConnectionRequest( IN PDFS_SERVICE pService, IN PPROVIDER_DEF pProvider, OUT PUNICODE_STRING pShareName) { ASSERT(pService != NULL); ASSERT(pProvider != NULL); RtlInitUnicodeString(pShareName, NULL); pShareName->Length = 0; pShareName->MaximumLength = pProvider->DeviceName.Length + sizeof(UNICODE_PATH_SEP_STR) + pService->Name.Length + sizeof(ROOT_SHARE_NAME); pShareName->Buffer = ExAllocatePoolWithTag(PagedPool, pShareName->MaximumLength, ' sfD'); if (pShareName->Buffer == NULL) { DebugTrace(0, Dbg, "Unable to allocate pool for share name!\n", 0); pShareName->Length = pShareName->MaximumLength = 0; return( STATUS_INSUFFICIENT_RESOURCES ); } RtlAppendUnicodeStringToString( pShareName, &pProvider->DeviceName ); RtlAppendUnicodeToString( pShareName, UNICODE_PATH_SEP_STR ); RtlAppendUnicodeStringToString( pShareName, &pService->Name ); RtlAppendUnicodeToString( pShareName, ROOT_SHARE_NAME ); return( STATUS_SUCCESS ); } //+---------------------------------------------------------------------------- // // Function: DfsFreeConnectionRequest // // Synopsis: Frees up the stuff allocated on a successful call to // DfsBuildConnectionRequest // // Arguments: [pShareName] -- Unicode string holding share name. // // Returns: Nothing // //----------------------------------------------------------------------------- VOID DfsFreeConnectionRequest( IN OUT PUNICODE_STRING pShareName) { if (pShareName->Buffer != NULL) { ExFreePool ( pShareName->Buffer ); } } //+------------------------------------------------------------------------- // // Function: DfsCreateConnection -- Create a connection to a server // // Synopsis: DfsCreateConnection will attempt to create a connection // to some server's IPC$ share. // // Arguments: [pService] -- the Service entry, giving the server principal // name // [remoteHandle] -- This is where the handle is returned. // // Returns: NTSTATUS - the status of the operation // // Notes: The Pkt must be acquired shared before calling this! It will // be released and reacquired in this routine. // // History: 31 Mar 1993 SudK Created // //-------------------------------------------------------------------------- NTSTATUS DfsCreateConnection( IN PDFS_SERVICE pService, IN PPROVIDER_DEF pProvider, OUT PHANDLE remoteHandle ) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING ShareName; NTSTATUS Status; ASSERT(pService != NULL); ASSERT(pProvider != NULL); ASSERT(ExIsResourceAcquiredSharedLite( &DfsData.Pkt.Resource )); Status = DfsBuildConnectionRequest( pService, pProvider, &ShareName); if (!NT_SUCCESS(Status)) { return( Status ); } InitializeObjectAttributes( &ObjectAttributes, &ShareName, // File Name 0, // Attributes NULL, // Root Directory NULL // Security ); // // Create or open a tree connection // PktRelease( &DfsData.Pkt ); Status = ZwCreateFile( remoteHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); PktAcquireShared( &DfsData.Pkt, TRUE ); if ( NT_SUCCESS( Status ) ) { DebugTrace(0, Dbg, "Created Connection Successfully\n", 0); Status = IoStatusBlock.Status; } DfsFreeConnectionRequest( &ShareName ); return Status; } //+------------------------------------------------------------------------- // // Function: DfsCloseConnection -- Close a connection to a server // // Synopsis: DfsCloseConnection will attempt to Close a connection // to some server. // // Effects: The file object referring to the the connection will be // closed. // // Arguments: pService - the Service entry, giving the server connection // handle // // Returns: NTSTATUS - the status of the operation // // History: 28 May 1992 Alanw Created // //-------------------------------------------------------------------------- NTSTATUS DfsCloseConnection( IN PDFS_SERVICE pService ) { ASSERT( pService->ConnFile != NULL ); ObDereferenceObject(pService->ConnFile); pService->ConnFile = NULL; return STATUS_SUCCESS; } //+------------------------------------------------------------------------- // // Function: DfsConcatenateFilePath, public // // Synopsis: DfsConcatenateFilePath will concatenate two strings // representing file path names, assuring that they are // separated by a single '\' character. // // Arguments: [Dest] - a pointer to the destination string // [RemainingPath] - the final part of the path name // [Length] - the length (in bytes) of RemainingPath // // Returns: BOOLEAN - TRUE unless Dest is too small to // hold the result (assert). // //-------------------------------------------------------------------------- BOOLEAN DfsConcatenateFilePath ( IN PUNICODE_STRING Dest, IN PWSTR RemainingPath, IN USHORT Length ) { PWSTR OutBuf = (PWSTR)&(((PCHAR)Dest->Buffer)[Dest->Length]); if (Dest->Length > 0) { ASSERT(OutBuf[-1] != UNICODE_NULL); } if (Dest->Length > 0 && OutBuf[-1] != UNICODE_PATH_SEP) { *OutBuf++ = UNICODE_PATH_SEP; Dest->Length += sizeof (WCHAR); } if (Length > 0 && *RemainingPath == UNICODE_PATH_SEP) { RemainingPath++; Length -= sizeof (WCHAR); } ASSERT(Dest->MaximumLength >= (USHORT)(Dest->Length + Length)); if (Length > 0) { RtlMoveMemory(OutBuf, RemainingPath, Length); Dest->Length += Length; } return TRUE; }