|
|
/*++
Copyright (c) 1991-1996 Microsoft Corporation
Module Name:
dfsstub.c
Abstract:
These are the server service API RPC client stubs for DFS operations
Environment:
User Mode - Win32
--*/
//
// INCLUDES
//
#include <nt.h> // DbgPrint prototype
#include <ntrtl.h> // DbgPrint
#include <rpc.h> // DataTypes and runtime APIs
#include <srvsvc.h> // generated by the MIDL complier
#include <lmcons.h> // NET_API_STATUS
#include <debuglib.h> // (needed by netrpc.h)
#include <lmsvc.h> // (needed by netrpc.h)
#include <netdebug.h> // (needed by netrpc.h)
#include <lmerr.h> // NetError codes
#include <netrpc.h> // NET_REMOTE_ macros.
#include <nturtl.h>
#include <winbase.h>
#include <dfspriv.h>
#include <Winsock2.h>
#include <Dsgetdc.h>
#include <malloc.h>
#include <stdio.h>
#include <Lm.h>
NET_API_STATUS NET_API_FUNCTION I_NetDfsGetVersion( IN LPWSTR servername, OUT LPDWORD Version) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsGetVersion( servername, Version );
NET_REMOTE_RPC_FAILED( "I_NetDfsGetVersion", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return(apiStatus);
}
NET_API_STATUS NET_API_FUNCTION I_NetDfsCreateLocalPartition ( IN LPWSTR servername, IN LPWSTR ShareName, IN LPGUID EntryUid, IN LPWSTR EntryPrefix, IN LPWSTR ShortName, IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo, IN BOOL Force ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsCreateLocalPartition ( servername, ShareName, EntryUid, EntryPrefix, ShortName, RelationInfo, Force );
NET_REMOTE_RPC_FAILED( "NetDfsCreateLocalPartition", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return(apiStatus);
}
NET_API_STATUS NET_API_FUNCTION I_NetDfsDeleteLocalPartition ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsDeleteLocalPartition ( servername, Uid, Prefix );
NET_REMOTE_RPC_FAILED( "NetDfsDeleteLocalPartition", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsSetLocalVolumeState ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix, IN ULONG State ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsSetLocalVolumeState ( servername, Uid, Prefix, State );
NET_REMOTE_RPC_FAILED( "NetDfsSetLocalVolumeState", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsSetServerInfo ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsSetServerInfo ( servername, Uid, Prefix );
NET_REMOTE_RPC_FAILED( "NetDfsSetServerInfo", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsCreateExitPoint ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix, IN ULONG Type, IN ULONG ShortPrefixSize, OUT LPWSTR ShortPrefix ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsCreateExitPoint ( servername, Uid, Prefix, Type, ShortPrefixSize, ShortPrefix );
NET_REMOTE_RPC_FAILED( "NetDfsCreateExitPoint", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsDeleteExitPoint ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix, IN ULONG Type ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsDeleteExitPoint ( servername, Uid, Prefix, Type );
NET_REMOTE_RPC_FAILED( "NetDfsDeleteExitPoint", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsModifyPrefix ( IN LPWSTR servername OPTIONAL, IN LPGUID Uid, IN LPWSTR Prefix ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsModifyPrefix ( servername, Uid, Prefix );
NET_REMOTE_RPC_FAILED( "NetDfsModifyPrefix", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsFixLocalVolume ( IN LPWSTR servername OPTIONAL, IN LPWSTR VolumeName, IN ULONG EntryType, IN ULONG ServiceType, IN LPWSTR StgId, IN LPGUID EntryUid, // unique id for this partition
IN LPWSTR EntryPrefix, // path prefix for this partition
IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo, IN ULONG CreateDisposition ) { NET_API_STATUS apiStatus;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsFixLocalVolume ( servername, VolumeName, EntryType, ServiceType, StgId, EntryUid, EntryPrefix, RelationInfo, CreateDisposition );
NET_REMOTE_RPC_FAILED( "NetDfsFixLocalVolume", servername, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
apiStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END;
return apiStatus; }
NET_API_STATUS NET_API_FUNCTION I_NetDfsManagerReportSiteInfo ( IN LPWSTR ServerName, OUT LPDFS_SITELIST_INFO *ppSiteInfo ) { struct sockaddr_in Destination; struct hostent * pHostEnt; SOCKET_ADDRESS SocketAddress; NET_API_STATUS apiStatus; LPWSTR *SiteName = NULL; char* ServerNameA = NULL;
NET_REMOTE_TRY_RPC
apiStatus = NetrDfsManagerReportSiteInfo ( ServerName, ppSiteInfo );
NET_REMOTE_RPC_FAILED( "NetDfsMangerReportSiteInfo", ServerName, apiStatus, NET_REMOTE_FLAG_NORMAL, SERVICE_SERVER)
NET_REMOTE_END;
if(apiStatus != ERROR_SUCCESS) { WORD wVersionRequested; WSADATA wsaData; DWORD dwErr = ERROR_SUCCESS; int err; PDOMAIN_CONTROLLER_INFO pDCInfo;
wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* We could not find a usable */ /* WinSock DLL. */ return apiStatus; }
// we couldn't get the site name
ServerNameA = malloc(wcslen(ServerName) + 1);
if(ServerNameA == NULL) { apiStatus = ERROR_NOT_ENOUGH_MEMORY; } else { // need to convert from WCHAR* to char*
sprintf(ServerNameA, "%ws", ServerName);
if ((pHostEnt = gethostbyname(ServerNameA)) != NULL) { memcpy(&(Destination.sin_addr), pHostEnt->h_addr, pHostEnt->h_length); Destination.sin_family = pHostEnt->h_addrtype;
if(pHostEnt->h_addrtype != AF_INET) { apiStatus = ERROR_NOT_SUPPORTED; } else { SocketAddress.lpSockaddr = (struct sockaddr *)&Destination; SocketAddress.iSockaddrLength = sizeof(Destination); Destination.sin_port = 0; dwErr = DsGetDcName( NULL, // Computer to remote to
NULL, // Domain - use local domain
NULL, // Domain Guid
NULL, // Site Guid
0, // Flags
&pDCInfo);
if(dwErr == ERROR_SUCCESS) { apiStatus = DsAddressToSiteNames(pDCInfo->DomainControllerAddress, 1, &SocketAddress, &SiteName );
NetApiBufferFree( pDCInfo ); } else { apiStatus = ERROR_NOT_SUPPORTED; }
if(apiStatus == NO_ERROR) { if((SiteName == NULL) || (*SiteName == NULL)) { // If DsAddressToSiteNames can't map to a site name,
// it returns success but sets the buffer to NULL.
apiStatus = ERROR_NO_SITENAME; } else { // we got the site name
apiStatus = NetApiBufferAllocate( sizeof(DFS_SITELIST_INFO) + ((wcslen(*SiteName) + 1) * sizeof(WCHAR)), ppSiteInfo );
if(apiStatus == ERROR_SUCCESS) { (*ppSiteInfo)->cSites = 1; (*ppSiteInfo)->Site[0].SiteName = (LPWSTR)((ULONG_PTR)(*ppSiteInfo) + sizeof(DFS_SITELIST_INFO)); wcscpy((*ppSiteInfo)->Site[0].SiteName, *SiteName); } } } } } else { apiStatus = WSAGetLastError(); apiStatus = ERROR_NOT_SUPPORTED; } free(ServerNameA);
}
WSACleanup(); }
return apiStatus; }
#include <dsgetdc.h>
#include <winldap.h>
#include <lmapibuf.h>
//
// This is the container which holds the DFS configuration data
//
static const WCHAR DfsConfigContainer[] = L"CN=Dfs-Configuration,CN=System";
typedef struct { int cPieces; PCHAR rpPieces[1]; } DNS_NAME, *PDNS_NAME;
static DWORD BreakDnsName( IN CHAR *pName, OUT PDNS_NAME *ppDnsName )
/*++
Routine Description:
Breaks a DNS name in dotted string format (eg: dbsd.microsoft.com) into its constituent parts.
Arguments:
pName - pointer to string representing dotted DNS name to break.
ppDnsName - pointer to pointer to DNS_NAME struct which should be deallocated by NetApiBufferFree(). --*/
{ int cPieces; CHAR *p; DWORD cBytes; CHAR *buffer; int i; LPSTR seps = ".";
if ( (NULL == pName) || ('\0' == *pName) || ('.' == *pName) ) { return(ERROR_INVALID_PARAMETER); }
// Count number of pieces so we can figure out how much to allocate.
cPieces = 1; p = pName;
for ( p = pName; '\0' != *p; p++ ) { if ( '.' == *p ) { cPieces++; } }
// Calculate bytes to allocate. Allocate memory which will hold (in order)
// the DNS_NAME struct, the DNS_NAME.rpPieces pointer array, and finally
// a scratch buffer where we can strtok the input name.
cBytes = sizeof(DNS_NAME); cBytes += cPieces * sizeof(PCHAR); cBytes += strlen(pName) + 1;
NetApiBufferAllocate( cBytes, (PVOID *)ppDnsName );
if ( *ppDnsName == NULL ) { return(ERROR_NOT_ENOUGH_MEMORY); }
// Fill in the buffer and call strtok as often as required to chop it
// into pieces filling the DNS_NAME as we go.
buffer = (CHAR *) &((*ppDnsName)->rpPieces[cPieces]); strcpy(buffer, pName);
(*ppDnsName)->cPieces = cPieces; (*ppDnsName)->rpPieces[0] = strtok(buffer, seps);
for ( i = 1; i < cPieces; i++ ) { (*ppDnsName)->rpPieces[i] = strtok(NULL, seps); }
return(NO_ERROR); }
static DWORD FindContext( IN CHAR *pName, IN int cDnValues, IN CHAR **rpDnValues, OUT int *pMatchingValueIndex )
/*++
Routine Description:
Determines the best match of a DNS name (eg: dbsd.microsoft.com) to a set of RFC 1779 DNs (eg: ou=dbsd, ou=microsoft, c=us). We assume that the array of DNs represent NT5 DS naming contexts (i.e. domains) which is true with the exception of the Configuration naming context. For example, let's say a DC hosted three naming contexts:
1 - ou=dbsd, ou=microsoft, c=us 2 - ou=nt, ou=dbsd, ou=microsoft, c=us 3 - ou=configuration, ou=microsoft, c=us
Then dbsd.microsoft.com would match the 1st DN in the list. This is not foolproof in the case of a deviant namespace which has a domain structure like:
ou=dbsd, ou=microsoft, ou=com, ou=dbsd, ou=microsoft, c=us
But anyone with a namespace like that is going to have other problems anyway.
Arguments:
pName - pointer to DNS name to match.
cDnValues - count of values in rpDnValues.
rpDnValues - array of pointers to DNs to match against.
pMatchingValueIndex - pointer to int which will identify the best matching DN in rpDnValues on successful return.
Return Value:
NO_ERROR - success ERROR_NOT_ENOUGH_MEMORY - allocation error ERROR_INVALID_PARAMETER - invalid parameter ERROR_INVALID_DOMAINNAME - bad DNS or DN domain name
--*/ { DWORD dwErr; int i, j; CHAR **rpDn = NULL; int currentMatchLength; int bestMatchLength; int bestMatchIndex; PDNS_NAME pDomainDnsName = NULL;
dwErr = BreakDnsName(pName, &pDomainDnsName);
if ( NO_ERROR != dwErr ) { return(dwErr); }
// Iterate over the DN values and see which one has the longest match.
bestMatchIndex = 0; bestMatchLength = -1;
for ( i = 0; i < cDnValues; i++ ) { rpDn = ldap_explode_dn(rpDnValues[i], 1); // 1 ==> notypes
if ( NULL == rpDn ) { dwErr = ERROR_INVALID_DOMAINNAME; goto Cleanup; }
currentMatchLength = 0;
// Try to match each piece of the domain name to each piece of the
// DN. Fortunately, RFC 1779 DNs are ordered least to most significant
// just as DNS domain names are. rpDn[] is "terminated" with a NULL.
for ( j = 0; (j < pDomainDnsName->cPieces) && (NULL != rpDn[j]); j++ ) { if ( 0 == _stricmp(pDomainDnsName->rpPieces[j], rpDn[j]) ) { currentMatchLength++; } }
if ( (0 != currentMatchLength) && (currentMatchLength > bestMatchLength) ) { bestMatchLength = currentMatchLength; bestMatchIndex = i; }
ldap_value_free(rpDn); }
*pMatchingValueIndex = bestMatchIndex; dwErr = NO_ERROR;
Cleanup:
if ( pDomainDnsName != NULL ) { NetApiBufferFree( pDomainDnsName ); }
return(dwErr); }
/*
* This API returns a vector of \\server\share combinations which form the * root of a Fault Tolerant DFS. This null-terminated vector should be * freed by the caller with NetApiBufferFree(). * * If pLDAP is supplied, we asssume that this is the handle to the DS server * holding the configuration data. Else, we use wszDomainName to locate the * proper DS server. * * wszDfsName is the name of the fault tolerant DFS for which individual servers * are to be discovered. * */ NET_API_STATUS NET_API_FUNCTION I_NetDfsGetFtServers( IN PVOID LdapInputArg OPTIONAL, IN LPWSTR wszDomainName OPTIONAL, IN LPWSTR wszDfsName OPTIONAL, OUT LPWSTR **List ) { PLDAP pLDAP = (PLDAP)LdapInputArg; BOOLEAN bUnbindNeeded = FALSE; DWORD dwErr; NTSTATUS status; PWCHAR attrs[2]; LDAPMessage *pMsg = NULL; LDAPMessage *pEntry = NULL; WCHAR *pAttr = NULL; WCHAR **rpValues = NULL; WCHAR **allValues = NULL; WCHAR ***rpValuesToFree = NULL; INT cValues = 0; INT i; WCHAR *dfsDn = NULL; DWORD len; USHORT cChar; PWCHAR *resultVector; ULONG cBytes;
if (List == NULL) { return ERROR_INVALID_PARAMETER; }
*List = NULL;
if (!ARGUMENT_PRESENT(pLDAP)) {
DOMAIN_CONTROLLER_INFO *pInfo = NULL; ULONG dsAdditionalFlags = 0; ULONG retry;
for (retry = 0; pLDAP == NULL && retry < 2; retry++) {
//
// Find a DC for the given domain.
//
dwErr = DsGetDcName( NULL, // computer name
wszDomainName, // DNS domain name
NULL, // domain guid
NULL, // site guid
DS_DIRECTORY_SERVICE_REQUIRED | DS_IP_REQUIRED | dsAdditionalFlags, &pInfo);
if (dwErr != NO_ERROR) { return dwErr; }
//
// DomainControllerAddress is prefixed with "\\" so
// aditionally ensure there's some useful data there.
//
if (DS_INET_ADDRESS != pInfo->DomainControllerAddressType || (cChar = (USHORT)wcslen(pInfo->DomainControllerAddress)) < 3) {
NetApiBufferFree(pInfo); return ERROR_NO_SUCH_DOMAIN; }
//
// Try to connect to the DS server on the DC
//
pLDAP = ldap_openW(&pInfo->DomainControllerAddress[2], 0);
if (pLDAP == NULL) { //
// Couldn't connect. Let's force rediscovery and see if we
// can connect to a DC which is working!
//
NetApiBufferFree(pInfo); dsAdditionalFlags |= DS_FORCE_REDISCOVERY;
} else {
dwErr = ldap_bind_s(pLDAP, NULL, NULL, LDAP_AUTH_SSPI);
}
NetApiBufferFree(pInfo);
}
if (pLDAP == NULL || dwErr != LDAP_SUCCESS) { return ERROR_PATH_NOT_FOUND; }
bUnbindNeeded = TRUE;
}
//
// Read the namingContexts operational attribute.
//
pLDAP->ld_sizelimit = 0; // no search limit
pLDAP->ld_timelimit = 0; // no time limit
pLDAP->ld_deref = LDAP_DEREF_NEVER;
attrs[0] = L"defaultnamingContext"; attrs[1] = NULL;
if ((dwErr = ldap_search_sW( pLDAP, L"", // search base
LDAP_SCOPE_BASE, L"(objectClass=*)", // filter
attrs, 0, // attrs and values
&pMsg)) != LDAP_SUCCESS) {
goto Cleanup;
}
//
// Make sure we got back something reasonable
//
if (ldap_count_entries(pLDAP, pMsg) != 1 || (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL || (rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0])) == NULL || (cValues = ldap_count_valuesW(rpValues)) == 0 ) {
dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
if (ARGUMENT_PRESENT(wszDfsName)) {
//
// Looks good. Allocate enough memory to hold the DN of the
// DFS configuration data for the fault tolerant DFS in question
//
len = (DWORD)(3 * sizeof(WCHAR) + (wcslen(wszDfsName) + 1) * sizeof(WCHAR) + (wcslen(DfsConfigContainer) + 1) * sizeof(WCHAR) + (wcslen(rpValues[0]) + 1) * sizeof(WCHAR));
dwErr = NetApiBufferAllocate(len, (PVOID *)&dfsDn);
if (dfsDn == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
//
// Construct the DN
//
RtlZeroMemory(dfsDn, len); wcscpy(dfsDn, L"CN="); wcscat(dfsDn, wszDfsName); wcscat(dfsDn, L","); wcscat(dfsDn, DfsConfigContainer); wcscat(dfsDn, L","); wcscat(dfsDn, rpValues[0]);
//
// Now see if we can get at the 'remoteServerName' property of this object.
// This property holds the names of the servers hosting this DFS
//
pLDAP->ld_sizelimit = 0; pLDAP->ld_timelimit= 0; pLDAP->ld_deref = LDAP_DEREF_NEVER;
ldap_msgfree(pMsg); pMsg = NULL;
ldap_value_freeW(rpValues); rpValues = NULL;
attrs[0] = L"remoteServerName"; attrs[1] = NULL;
dwErr = ldap_search_sW( pLDAP, dfsDn, LDAP_SCOPE_BASE, L"(objectClass=*)", attrs, 0, &pMsg);
//
// Make sure the result is reasonable
//
if (ldap_count_entries(pLDAP, pMsg) == 0 || (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL || (rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0])) == NULL || rpValues[0][0] == L'\0' ) {
dwErr = ERROR_PATH_NOT_FOUND; goto Cleanup; }
//
// The result is reasonable, just point allValues to rpValues
//
allValues = rpValues;
} else {
//
// The caller is trying to retrieve the names of all the FT DFSs in the domain
//
// Allocate enough memory to hold the DN of the
// DFS configuration container
//
len = (wcslen(DfsConfigContainer) + 1) * sizeof(WCHAR) + (wcslen(rpValues[0]) + 1) * sizeof(WCHAR);
dwErr = NetApiBufferAllocate(len, (PVOID *)&dfsDn);
if (dfsDn == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
//
// Construct the DN
//
RtlZeroMemory(dfsDn, len); wcscpy(dfsDn, DfsConfigContainer); wcscat(dfsDn, L","); wcscat(dfsDn, rpValues[0]);
//
// Now see if we can enumerate the objects below this one. The names
// of these objects will be the different FT dfs's available
//
pLDAP->ld_sizelimit = 0; pLDAP->ld_timelimit= 0; pLDAP->ld_deref = LDAP_DEREF_NEVER;
ldap_msgfree(pMsg); pMsg = NULL;
ldap_value_freeW(rpValues); rpValues = NULL;
attrs[0] = L"CN"; attrs[1] = NULL;
dwErr = ldap_search_sW( pLDAP, dfsDn, LDAP_SCOPE_ONELEVEL, L"(objectClass=fTDfs)", attrs, 0, &pMsg);
//
// Make sure the result is reasonable
//
if ( ((cValues = ldap_count_entries(pLDAP, pMsg)) == 0) || (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL ) { dwErr = ERROR_PATH_NOT_FOUND; goto Cleanup; }
//
// The search for all FTDfs's returns multiple entries, each with
// one value for the object's CN. Coalesce these into a single array.
//
dwErr = NetApiBufferAllocate(2 * (cValues + 1) * sizeof(PWSTR), (PVOID *)&allValues);
if (dwErr != ERROR_SUCCESS) { goto Cleanup; }
rpValuesToFree = (WCHAR ***) &allValues[cValues + 1];
for (i = 0; (i < cValues) && (dwErr == ERROR_SUCCESS); i++) {
rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0]); rpValuesToFree[i] = rpValues; //
// Sanity check
//
if (ldap_count_valuesW(rpValues) == 0 || rpValues[0][0] == L'\0') { dwErr = ERROR_PATH_NOT_FOUND; } else { allValues[i] = rpValues[0]; pEntry = ldap_next_entry(pLDAP, pEntry); }
}
if (dwErr == ERROR_SUCCESS) { allValues[i] = NULL; rpValuesToFree[i] = NULL; } else { goto Cleanup; }
}
if (dwErr != LDAP_SUCCESS) { dwErr = ERROR_PATH_NOT_FOUND; goto Cleanup; }
//
// Now we need to allocate the memory to hold this vector and return the results.
//
// First see how much space we need
//
for (len = cValues = 0; allValues[cValues]; cValues++) { len += sizeof(LPWSTR) + (wcslen(allValues[cValues]) + 1) * sizeof(WCHAR); } len += sizeof(LPWSTR); // for the final NULL pointer
dwErr = NetApiBufferAllocate(len, (PVOID *)&resultVector);
if (dwErr == NO_ERROR) {
LPWSTR pstr = (LPWSTR)((PCHAR)resultVector + (cValues + 1) * sizeof(LPWSTR)); ULONG slen;
RtlZeroMemory(resultVector, len);
len -= (cValues+1) * sizeof(LPWSTR);
for (cValues = 0; allValues[cValues] && len >= sizeof(WCHAR); cValues++) {
resultVector[cValues] = pstr; wcscpy(pstr, allValues[cValues]); slen = wcslen(allValues[cValues]); pstr += slen + 1; len -= (slen + 1) * sizeof(WCHAR);
}
}
if (dwErr == NO_ERROR) { *List = resultVector; }
Cleanup:
if (ARGUMENT_PRESENT(wszDfsName)) { if (rpValues != NULL) { ldap_value_freeW(rpValues); } } else { if (rpValuesToFree != NULL) { for (i = 0; rpValuesToFree[i] != NULL; i++) { ldap_value_freeW(rpValuesToFree[i]); } } if (allValues != NULL) { NetApiBufferFree(allValues); } }
if (pMsg != NULL) { ldap_msgfree(pMsg); }
if (dfsDn != NULL) { NetApiBufferFree(dfsDn); }
if (pLDAP != NULL && bUnbindNeeded == TRUE) { ldap_unbind(pLDAP); }
return dwErr; }
|