//+---------------------------------------------------------------------------- // // Copyright (C) 2000, Microsoft Corporation // // File: DfsAdsiApi.cxx // // Contents: Contains APIs to communicate with the DS // // Classes: none. // // History: March. 13 2001, Author: Rohanp // //----------------------------------------------------------------------------- #include "DfsAdsiAPi.hxx" #include "DfsError.hxx" #include "dfsgeneric.hxx" #include "dfsinit.hxx" #include "lm.h" #include "lmdfs.h" // // dfsdev: comment this properly. // LPWSTR RootDseString=L"LDAP://RootDSE"; // // dfscreatedn take a pathstring and fills it with the information // necessary for the path to be used as a Distinguished Name. // It starts the string with LDAP://, follows that with a DCName // if supplied, and then adds the array of CNNames passed in // one after the other , each one followed by a , // the final outcome is something like: // LDAP://ntdev-dc-01/CN=Dfs-Configuration, CN=System, Dc=Ntdev, etc // //dfsdev: this function should take a path len and return overflow // if we overrun the buffer!!! VOID DfsCreateDN( LPWSTR PathString, LPWSTR DCName, LPWSTR *CNNames ) { LPWSTR *InArray = CNNames; LPWSTR CNName; wcscpy(PathString, L"LDAP://"); // // if the dc name is specified, we want to go to a specific dc // add that in. // if ((DCName != NULL) && (wcslen(DCName) > 0)) { wcscat(PathString, DCName); wcscat(PathString, L"/"); } // // Now treat the CNNames as an array of LPWSTR and add each one of // the lpwstr to our path. // if (CNNames != NULL) { while ((CNName = *InArray++) != NULL) { wcscat(PathString, CNName); if (*InArray != NULL) { wcscat(PathString,L","); } } } return NOTHING; } DFSSTATUS DfsGenerateDfsAdNameContext( PUNICODE_STRING pString ) { IADs *pRootDseObject; HRESULT HResult; VARIANT VarDSRoot; DFSSTATUS Status; HResult = ADsGetObject( RootDseString, IID_IADs, (void **)&pRootDseObject ); if (SUCCEEDED(HResult)) { VariantInit( &VarDSRoot ); // Get the Directory Object on the root DSE, to get to the server configuration HResult = pRootDseObject->Get(L"defaultNamingContext",&VarDSRoot); if (SUCCEEDED(HResult)) { DfsCreateUnicodeStringFromString( pString, (LPWSTR)V_BSTR(&VarDSRoot) ); } VariantClear(&VarDSRoot); pRootDseObject->Release(); } Status = DfsGetErrorFromHr(HResult); return Status; } #if 0 HRESULT DfsGetADObject( LPWSTR DCName, REFIID Id, LPWSTR ObjectName, PVOID *ppObject ) { HRESULT HResult; LPOLESTR PathString; VARIANT VarDSRoot; LPWSTR CNNames[4]; LPWSTR DCNameToUse; UNICODE_STRING GotDCName; IADs *pRootDseObject; ULONG Index; PathString = new OLECHAR[MAX_PATH]; if (PathString == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } RtlInitUnicodeString( &GotDCName, NULL ); DCNameToUse = DCName; if (IsEmptyString(DCNameToUse)) { DfsGetBlobDCName( &GotDCName ); DCNameToUse = GotDCName.Buffer; } CNNames[0] = RootDseString; CNNames[1] = NULL; DfsCreateDN( PathString, DCNameToUse, CNNames ); // // contact the rootdse (local domain), and get the default // naming context. Use that to get to the dfs configuration // object. // HResult = ADsGetObject(PathString, IID_IADs, (void**)&pRootDseObject); if (SUCCEEDED(HResult)) { VariantInit( &VarDSRoot ); // Get the Directory Object on the root DSE, to get to the server configuration HResult = pRootDseObject->Get(L"defaultNamingContext",&VarDSRoot); if (SUCCEEDED(HResult)) { Index = 0; if (ObjectName != NULL) { CNNames[Index++] = ObjectName; } CNNames[Index++] = DFS_AD_CONFIG_DATA; CNNames[Index++] = (LPWSTR)V_BSTR(&VarDSRoot); CNNames[Index++] = NULL; DfsCreateDN( PathString, DCNameToUse, CNNames); VariantClear(&VarDSRoot); } pRootDseObject->Release(); } // // open dfs configuration container for enumeration. // if (SUCCEEDED(HResult)) { HResult = ADsGetObject(PathString, Id, ppObject ); } // // Since we initialized DCName with empty string, it is benign // to call this, even if we did not call GetBlobDCName above. // DfsReleaseBlobDCName( &GotDCName ); delete [] PathString; return HResult; } #endif HRESULT DfsGetADObject( LPWSTR DCName, REFIID Id, LPWSTR ObjectName, PVOID *ppObject ) { HRESULT HResult; LPOLESTR PathString; LPWSTR CNNames[4]; LPWSTR DCNameToUse; UNICODE_STRING GotDCName; ULONG Index; PathString = new OLECHAR[MAX_PATH]; if (PathString == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } RtlInitUnicodeString( &GotDCName, NULL ); DCNameToUse = DCName; if (IsEmptyString(DCNameToUse)) { DfsGetBlobDCName( &GotDCName ); DCNameToUse = GotDCName.Buffer; } Index = 0; if (ObjectName != NULL) { CNNames[Index++] = ObjectName; } CNNames[Index++] = DFS_AD_CONFIG_DATA; CNNames[Index++] = DfsGetDfsAdNameContextString(); CNNames[Index++] = NULL; DfsCreateDN( PathString, DCNameToUse, CNNames); // // open dfs configuration container for enumeration. // HResult = ADsOpenObject(PathString, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND | ADS_SERVER_BIND, Id, ppObject ); // // Since we initialized DCName with empty string, it is benign // to call this, even if we did not call GetBlobDCName above. // DfsReleaseBlobDCName( &GotDCName ); delete [] PathString; return HResult; } // // Given the root share name, get the root object. // DFSSTATUS DfsGetDfsRootADObject( LPWSTR DCName, LPWSTR RootName, IADs **ppRootObject ) { HRESULT HResult; LPWSTR RootCNName; DFSSTATUS Status = ERROR_SUCCESS; RootCNName = new WCHAR[MAX_PATH]; if (RootCNName == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } wcscpy(RootCNName, L"CN="); wcscat(RootCNName, RootName); HResult = DfsGetADObject( DCName, IID_IADs, RootCNName, (PVOID *)ppRootObject ); delete [] RootCNName; Status = DfsGetErrorFromHr(HResult); return Status; } DFSSTATUS PackRootName( LPWSTR Name, PDFS_INFO_200 pDfsInfo200, PULONG pBufferSize, PULONG pTotalSize ) { ULONG BufferLen = (wcslen(Name) + 1) * sizeof(WCHAR); ULONG NeedSize = sizeof(DFS_INFO_200) + BufferLen; DFSSTATUS Status = ERROR_SUCCESS; *pTotalSize += NeedSize; if (*pBufferSize >= NeedSize) { ULONG_PTR pStringBuffer; pStringBuffer = (ULONG_PTR)(pDfsInfo200) + *pBufferSize - BufferLen; wcscpy( (LPWSTR)pStringBuffer, &Name[3] ); pDfsInfo200->FtDfsName = (LPWSTR)pStringBuffer; *pBufferSize -= NeedSize; } else { Status = ERROR_BUFFER_OVERFLOW; *pBufferSize = 0; } return Status; } HRESULT DfsGetDfsConfigurationObject( LPWSTR DCName, IADsContainer **ppDfsConfiguration ) { HRESULT HResult; HResult = DfsGetADObject( DCName, IID_IADsContainer, NULL, (PVOID *)ppDfsConfiguration ); return HResult; } DFSSTATUS DfsDeleteDfsRootObject( LPWSTR DCName, LPWSTR RootName ) { BSTR ObjectName, ObjectClass; DFSSTATUS Status; HRESULT HResult; IADsContainer *pDfsConfiguration; IADs *pRootObject; Status = DfsGetDfsRootADObject( DCName, RootName, &pRootObject ); if (Status == ERROR_SUCCESS) { HResult = DfsGetDfsConfigurationObject( DCName, &pDfsConfiguration ); if (SUCCEEDED(HResult)) { HResult = pRootObject->get_Name(&ObjectName); if (SUCCEEDED(HResult)) { HResult = pRootObject->get_Class(&ObjectClass); if (SUCCEEDED(HResult)) { HResult = pDfsConfiguration->Delete( ObjectClass, ObjectName ); SysFreeString(ObjectClass); } SysFreeString(ObjectName); } pDfsConfiguration->Release(); } pRootObject->Release(); Status = DfsGetErrorFromHr(HResult); } return Status; } DFSSTATUS DfsEnumerateDfsADRoots( LPWSTR DCName, PULONG_PTR pBuffer, PULONG pBufferSize, PULONG pEntriesRead, PULONG pSizeRequired ) { HRESULT HResult; IADsContainer *pDfsConfiguration; IEnumVARIANT *pEnum; ULONG TotalSize = 0; ULONG TotalEntries = 0; PDFS_INFO_200 pDfsInfo200; ULONG BufferSize = *pBufferSize; DFSSTATUS Status; // // point the dfsinfo200 structure to the start of buffer passed in // we will use this as an array of info200 buffers. // pDfsInfo200 = (PDFS_INFO_200)*pBuffer; HResult = DfsGetDfsConfigurationObject( DCName, &pDfsConfiguration ); if (SUCCEEDED(HResult)) { HResult = ADsBuildEnumerator( pDfsConfiguration, &pEnum ); if (SUCCEEDED(HResult)) { VARIANT Variant; ULONG Fetched; BSTR BString; IADs *pRootObject; VariantInit(&Variant); while ((HResult = ADsEnumerateNext(pEnum, 1, &Variant, &Fetched)) == S_OK) { IDispatch *pDisp; pDisp = V_DISPATCH(&Variant); pDisp->QueryInterface(IID_IADs, (void **)&pRootObject); pDisp->Release(); pRootObject->get_Name(&BString); Status = PackRootName( BString, pDfsInfo200, &BufferSize, &TotalSize ); pRootObject->Release(); // DfsDev: investigate. this causes an av. // VariantClear(&Variant); if (Status == ERROR_SUCCESS) { TotalEntries++; pDfsInfo200++; } } if (HResult == S_FALSE) { HResult = S_OK; } ADsFreeEnumerator( pEnum ); } pDfsConfiguration->Release(); } Status = DfsGetErrorFromHr(HResult); if (Status == ERROR_SUCCESS) { *pSizeRequired = TotalSize; if (TotalSize > *pBufferSize) { Status = ERROR_BUFFER_OVERFLOW; } else { *pEntriesRead = TotalEntries; } } return Status; }