871 lines
22 KiB
C
871 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ds.c
|
||
|
||
Abstract:
|
||
|
||
This file contains all the routines used in interfacing with the DS. We go
|
||
to the DS go make sure we are not a Rogue server, and also to retrieve all
|
||
configuration information.
|
||
|
||
Author:
|
||
|
||
Shirish Koti (koti) 26-May-1997
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// System Includes
|
||
//
|
||
#define INC_OLE2
|
||
|
||
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
#include "activeds.h"
|
||
#include "adsi.h"
|
||
|
||
|
||
|
||
#if DBG
|
||
#define DBGPRINT printf
|
||
#else
|
||
#define DBGPRINT
|
||
#endif
|
||
|
||
#include <netlib.h>
|
||
#include <lmapibuf.h>
|
||
#include <dsgetdc.h>
|
||
#include <dnsapi.h>
|
||
|
||
#include "adsi.h"
|
||
|
||
#include <dsauth.h>
|
||
#include <dhcpapi.h>
|
||
#include <dhcpds.h>
|
||
|
||
DWORD
|
||
ValidateService(
|
||
LPWSTR lpwDomain, // domain name
|
||
LPWSTR lpwUserName, // usually NULL
|
||
LPWSTR lpwPassword, // usually NULL
|
||
DWORD dwAuthFlags, // ??
|
||
LPWSTR lpwObjectPath, // where our things are stored (e.g. DHCP)
|
||
LPWSTR lpwSrchFilter, // objects we're looking for (objectClass==DHCP)
|
||
LPWSTR *ppwAttrName, // name of the attribute we're looking for
|
||
LPWSTR lpwAttrVal // value of the attribute we're looking for
|
||
);
|
||
|
||
|
||
LPWSTR lpwGlbNamingContextString = DHCPDS_NAMING_CONTEXT;
|
||
|
||
|
||
|
||
DWORD
|
||
DhcpDSGetDomainAndRoot(
|
||
LPWSTR * ppwDomainName,
|
||
LPWSTR * ppwRootName,
|
||
BOOLEAN * fIsStandAlone
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function gets the DS Domain and the root of the enterprise that this
|
||
machine is a member of.
|
||
|
||
NOTE: Memory is allocated to hold strings pointed to by *ppwDomainName and
|
||
*ppwRootName, and the caller must free that memory.
|
||
One of ppwDomainName or ppwRootName can be NULL, to indicate the caller
|
||
doesn't want that info. (e.g. only root is needed, not domain)
|
||
|
||
Arguments:
|
||
|
||
ppwDomainName - pointer to a string that will hold domain name
|
||
ppwRootName - pointer to a string that will hold the root of enterprise
|
||
fIsStandAlone - pointer to a boolean: TRUE if this server is Standalone
|
||
|
||
Return Value:
|
||
|
||
Result of the operation
|
||
--*/
|
||
{
|
||
DWORD dwError;
|
||
LPTSTR NetbiosDomNamePtr=NULL;
|
||
LPTSTR pDomain=NULL;
|
||
LPWSTR lpwRetDomainName=NULL;
|
||
LPWSTR lpwRetRootName=NULL;
|
||
BOOLEAN IsWorkgroup=TRUE;
|
||
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
|
||
|
||
|
||
|
||
// initialize, in case we bail out
|
||
if (ppwDomainName)
|
||
{
|
||
*ppwDomainName = NULL;
|
||
}
|
||
|
||
if (ppwRootName)
|
||
{
|
||
*ppwRootName = NULL;
|
||
}
|
||
|
||
*fIsStandAlone = FALSE;
|
||
|
||
|
||
//
|
||
// first, find out which domain we are a member of.
|
||
//
|
||
dwError = NetpGetDomainNameExEx(
|
||
&NetbiosDomNamePtr,
|
||
&pDomain,
|
||
&IsWorkgroup);
|
||
|
||
//
|
||
// if NetpGetDomainNameExEx failed, we shouldn't proceed
|
||
//
|
||
if (dwError != NO_ERROR)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: NetpGetDomainNameExEx failed (%ld)\n",dwError);
|
||
return(dwError);
|
||
}
|
||
|
||
// we don't care about this domain name: free the buffer
|
||
if (NetbiosDomNamePtr)
|
||
{
|
||
NetApiBufferFree(NetbiosDomNamePtr);
|
||
}
|
||
|
||
// if this is a standalone server, we're done here
|
||
if (IsWorkgroup)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: server is part of a workgroup\n");
|
||
|
||
*fIsStandAlone = TRUE;
|
||
|
||
if (pDomain)
|
||
{
|
||
NetApiBufferFree(pDomain);
|
||
}
|
||
|
||
return(NO_ERROR);
|
||
}
|
||
|
||
// if pDomain is NULL, it means that the DNS domain isn't configured.
|
||
// For the purpose of rogue-detection, we will assume it to be a workgroup
|
||
// though in the strictest sense that's not true.
|
||
if (pDomain == NULL)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: pDomain is NULL: assuming part of workgroup\n");
|
||
|
||
*fIsStandAlone = TRUE;
|
||
|
||
return(NO_ERROR);
|
||
}
|
||
|
||
|
||
//
|
||
// if the caller wants DomainName, allocate space, and copy it in
|
||
//
|
||
if (ppwDomainName)
|
||
{
|
||
lpwRetDomainName = (LPWSTR)LocalAlloc(
|
||
LPTR,
|
||
(wcslen(pDomain)+1)*sizeof(WCHAR) );
|
||
|
||
if (lpwRetDomainName == NULL)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: malloc 1 failed (%ld)\n",
|
||
(wcslen(pDomain)+1)*sizeof(WCHAR));
|
||
|
||
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto DhcpGetDSDomain_ErrExit;
|
||
}
|
||
|
||
// copy the name in
|
||
wcscpy(lpwRetDomainName, pDomain);
|
||
|
||
*ppwDomainName = lpwRetDomainName;
|
||
}
|
||
|
||
|
||
//
|
||
// See if the caller wants DS Root as well
|
||
// get the info about this domain controller (the only thing we want
|
||
// from all the good info in pDCInfo is the DS root name (DnsForestName field)
|
||
//
|
||
|
||
if (ppwRootName)
|
||
{
|
||
dwError = DsGetDcName(
|
||
NULL, // server name
|
||
pDomain, // domain name
|
||
NULL, // domain guid
|
||
NULL, // site name
|
||
DS_IS_DNS_NAME,
|
||
&pDCInfo);
|
||
|
||
if (dwError != NO_ERROR)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: DsGetDcName failed %ld\n",dwError);
|
||
|
||
goto DhcpGetDSDomain_ErrExit;
|
||
}
|
||
|
||
|
||
//
|
||
// RootName: allocate space, and copy the root name in
|
||
//
|
||
|
||
lpwRetRootName = (LPWSTR)LocalAlloc(
|
||
LPTR,
|
||
(wcslen(pDCInfo->DnsForestName)+1)*sizeof(WCHAR) );
|
||
|
||
if (lpwRetRootName == NULL)
|
||
{
|
||
DBGPRINT("DhcpGetDSDomain: malloc 2 failed (%ld)\n",
|
||
(wcslen(pDCInfo->DnsForestName)+1)*sizeof(WCHAR));
|
||
|
||
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto DhcpGetDSDomain_ErrExit;
|
||
}
|
||
|
||
// copy the name in
|
||
wcscpy(lpwRetRootName, pDCInfo->DnsForestName);
|
||
|
||
*ppwRootName = lpwRetRootName;
|
||
|
||
NetApiBufferFree(pDCInfo);
|
||
}
|
||
|
||
NetApiBufferFree(pDomain);
|
||
|
||
return(NO_ERROR);
|
||
|
||
|
||
DhcpGetDSDomain_ErrExit:
|
||
|
||
DBGPRINT("DhcpGetDSDomain: executing error path, dwError = %ld\n",dwError);
|
||
|
||
//
|
||
// free the things that were given to us (or we took!)
|
||
//
|
||
if (pDomain)
|
||
{
|
||
NetApiBufferFree(pDomain);
|
||
}
|
||
|
||
if (pDCInfo)
|
||
{
|
||
NetApiBufferFree(pDCInfo);
|
||
}
|
||
|
||
if (lpwRetDomainName)
|
||
{
|
||
LocalFree(lpwRetDomainName);
|
||
}
|
||
|
||
if (lpwRetRootName)
|
||
{
|
||
LocalFree(lpwRetRootName);
|
||
}
|
||
|
||
if (ppwDomainName)
|
||
{
|
||
*ppwDomainName = NULL;
|
||
}
|
||
|
||
if (ppwRootName)
|
||
{
|
||
*ppwRootName = NULL;
|
||
}
|
||
|
||
return(dwError);
|
||
}
|
||
|
||
//BeginExport(function)
|
||
//DOC DhcpDSValidateServer validates the server in the DS by looking for the server
|
||
//DOC object and checking to see if the given IpAddress is present in the DS.
|
||
//DOC This calls the other helper routine in DhcpDs.dll to do the real work.
|
||
//DOC Returns one of
|
||
//DOC DHCPDSERR_DS_OPERATION_FAILED
|
||
//DOC DHCPDSERR_ENTRY_NOT_FOUND
|
||
//DOC DHCPDSERR_ENTRY_FOUND
|
||
//DOC DHCPDSERR_SERVER_IS_STANDALONE
|
||
DWORD
|
||
DhcpDSValidateServer( // validate in DS
|
||
IN LPWSTR lpwDomain, // OPTIONAL NULL ==> Default domain
|
||
IN DWORD *lpIpAddress, // one of the IpAddresses that must exist in DS
|
||
IN ULONG dwIpAddressCount, // # of ip addresses supplied..
|
||
IN LPWSTR lpwUserName, // OPTIONAL NULL ==> m/c account
|
||
IN LPWSTR lpwPassword, // OPTIONAL password to use
|
||
IN DWORD dwAuthFlags // MUST BE ZERO?
|
||
) //EndExport(function)
|
||
{
|
||
DWORD Error;
|
||
BOOL Found;
|
||
BOOL IsStandAlone;
|
||
|
||
IsStandAlone = FALSE;
|
||
Found = FALSE;
|
||
Error = DhcpDsValidateService // check to validate for dhcp
|
||
(
|
||
lpwDomain,
|
||
lpIpAddress,
|
||
dwIpAddressCount,
|
||
lpwUserName,
|
||
lpwPassword,
|
||
dwAuthFlags,
|
||
&Found,
|
||
&IsStandAlone
|
||
);
|
||
|
||
if( ERROR_SUCCESS != Error )
|
||
return DHCPDSERR_DS_OPERATION_FAILED;
|
||
|
||
if( IsStandAlone ) return DHCPDSERR_SERVER_IS_STANDALONE;
|
||
|
||
return Found? DHCPDSERR_ENTRY_FOUND : DHCPDSERR_ENTRY_NOT_FOUND;
|
||
}
|
||
|
||
DWORD
|
||
DhcpDSMapDomainToCNPath(
|
||
LPWSTR lpwDomain,
|
||
LPWSTR lpwUserName,
|
||
LPWSTR lpwPassword,
|
||
DWORD dwAuthFlags,
|
||
LPWSTR *ppwCNPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retrieves the full path to the Configuration Container, given
|
||
the name of the domain. If the domain name is not specified, server's domain
|
||
name is assumed.
|
||
|
||
NOTE: memory is allocated for ppwCNPath on successful return. Caller must
|
||
free this memory.
|
||
|
||
Arguments:
|
||
|
||
lpwDomain - domain name in which to validate the service. Can be NULL to
|
||
indicate the server's domain
|
||
lpwUserName - account name to use during DS lookup. Usually, NULL (default)
|
||
lpwPassword - password for the above user
|
||
dwAuthFlags - flags to use
|
||
ppwCNPath - pointer to string containing the path, on return.
|
||
|
||
Return Value:
|
||
|
||
Result of the operation
|
||
--*/
|
||
{
|
||
HRESULT hr=S_OK;
|
||
LPWSTR pCanonName;
|
||
LPWSTR lpwLocalDomain=NULL;
|
||
LPWSTR lpwDomainToContact=NULL;
|
||
LPWSTR lpwDCName;
|
||
HANDLE handle = NULL;
|
||
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
|
||
DWORD dwCanonNameLen;
|
||
PADS_ATTR_INFO pAttributeEntries=NULL;
|
||
DWORD dwNumAttributesReturned=0;
|
||
BOOLEAN fIsStandAlone;
|
||
BOOLEAN fCNStringFound;
|
||
DWORD dwRetCode;
|
||
DWORD index;
|
||
|
||
|
||
*ppwCNPath = NULL;
|
||
|
||
lpwDomainToContact = lpwDomain;
|
||
|
||
//
|
||
// if domain name is not supplied, find local domain first
|
||
//
|
||
if (!lpwDomain)
|
||
{
|
||
dwRetCode = DhcpDSGetDomainAndRoot(
|
||
&lpwLocalDomain,
|
||
NULL,
|
||
&fIsStandAlone);
|
||
|
||
if (dwRetCode != NO_ERROR)
|
||
{
|
||
DBGPRINT("DhcpDSMap..CNPath: GetLocalDom.. failed (0x%x)\n",dwRetCode);
|
||
return(dwRetCode);
|
||
}
|
||
|
||
//
|
||
// are we a standalone server? if so, return error since there is no
|
||
// local domain (and the caller didn't specify a domain)
|
||
//
|
||
if (fIsStandAlone)
|
||
{
|
||
DBGPRINT("DhcpDSMap..CNPath: standalone has no domain!\n");
|
||
return(DHCPDSERR_SERVER_IS_STANDALONE);
|
||
}
|
||
|
||
lpwDomainToContact = lpwLocalDomain;
|
||
}
|
||
|
||
//
|
||
// first, find a DC for this domain
|
||
//
|
||
dwRetCode = DsGetDcName(
|
||
NULL, // server name
|
||
lpwDomainToContact, // domain name
|
||
NULL, // domain guid
|
||
NULL, // site name
|
||
DS_IS_DNS_NAME, // what flag(s) to use?
|
||
&pDCInfo);
|
||
|
||
// if we first obtained local domain, free it here
|
||
if (lpwLocalDomain != NULL)
|
||
{
|
||
LocalFree((PCHAR)lpwLocalDomain);
|
||
}
|
||
|
||
if (dwRetCode != NO_ERROR)
|
||
{
|
||
DBGPRINT("MapDomainToCNPath: DsGetDcName failed %ld\n",dwRetCode);
|
||
|
||
return(dwRetCode);
|
||
}
|
||
|
||
|
||
lpwDCName = pDCInfo->DomainControllerName;
|
||
|
||
// skip the two leading '\'
|
||
lpwDCName += 2;
|
||
|
||
// also, skip the trailing '.'
|
||
lpwDCName[wcslen(lpwDCName)-1] = 0;
|
||
|
||
dwCanonNameLen = sizeof(DHCPDS_ROOTDSE_PRE) +
|
||
(wcslen(lpwDCName)+1)*sizeof(WCHAR) +
|
||
sizeof(DHCPDS_ROOTDSE_POST) +
|
||
sizeof(WCHAR);
|
||
|
||
pCanonName = (LPWSTR)LocalAlloc(LPTR, dwCanonNameLen);
|
||
|
||
if (pCanonName == NULL)
|
||
{
|
||
DBGPRINT("DhcpDSMapDomainToCNPath: malloc 1 failed (%ld)\n",dwCanonNameLen);
|
||
|
||
NetApiBufferFree(pDCInfo);
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
// copy the LDAP:// string
|
||
wcscpy(pCanonName, DHCPDS_ROOTDSE_PRE);
|
||
|
||
|
||
// append the server name
|
||
wcscat(pCanonName, lpwDCName);
|
||
|
||
// then append the RootDSE part
|
||
wcscat(pCanonName, DHCPDS_ROOTDSE_POST);
|
||
|
||
// don't need this nomore: free it now
|
||
NetApiBufferFree(pDCInfo);
|
||
|
||
// now, open the RootDSE "object"
|
||
hr = ADSIOpenDSObject(
|
||
pCanonName,
|
||
lpwUserName,
|
||
lpwPassword,
|
||
dwAuthFlags,
|
||
&handle
|
||
);
|
||
|
||
// free this first: don't need this nomore
|
||
LocalFree((PCHAR)pCanonName);
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
DBGPRINT("ADSIOpenDSObject (RootDSE) failed with 0x%x\n",hr);
|
||
return(DHCPDSERR_DS_OPERATION_FAILED);
|
||
}
|
||
|
||
|
||
// now, get all the attributes on this object
|
||
hr = ADSIGetObjectAttributes(
|
||
handle,
|
||
&lpwGlbNamingContextString,
|
||
1,
|
||
&pAttributeEntries,
|
||
&dwNumAttributesReturned);
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
DBGPRINT("ADSIGetObjectAttributes (RootDSE) failed with 0x%x\n",hr);
|
||
|
||
dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
|
||
goto DhcpDSMapDomainToCNPath_Exit;
|
||
}
|
||
|
||
|
||
fCNStringFound = FALSE;
|
||
|
||
//
|
||
// now, of all the values returned, find the one that we are
|
||
// interested in (the one starts with CN=Configuration,)
|
||
//
|
||
for (index=0; index<pAttributeEntries->dwNumValues; index++)
|
||
{
|
||
if (pAttributeEntries->pADsValues[index].dwType != ADSTYPE_CASE_IGNORE_STRING)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (wcsncmp(pAttributeEntries->pADsValues[index].CaseIgnoreString,
|
||
DHCPDS_CN_STRING,
|
||
wcslen(DHCPDS_CN_STRING)) == 0)
|
||
{
|
||
fCNStringFound = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!fCNStringFound)
|
||
{
|
||
DBGPRINT("MapDomainToCNPath: %d values returned, but not ours\n",
|
||
pAttributeEntries->dwNumValues);
|
||
|
||
dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
|
||
goto DhcpDSMapDomainToCNPath_Exit;
|
||
}
|
||
|
||
dwCanonNameLen = (wcslen(pAttributeEntries->pADsValues[index].CaseIgnoreString) +
|
||
1) * sizeof(WCHAR);
|
||
|
||
(*ppwCNPath) = (LPWSTR)LocalAlloc(LPTR, dwCanonNameLen);
|
||
|
||
if ((*ppwCNPath) == NULL)
|
||
{
|
||
DBGPRINT("MapDomainToCNPath: malloc 2 failed (%ld)\n",dwCanonNameLen);
|
||
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto DhcpDSMapDomainToCNPath_Exit;
|
||
}
|
||
|
||
// now, copy the-path-to-Configuration string
|
||
wcscpy((*ppwCNPath),pAttributeEntries->pADsValues[index].CaseIgnoreString);
|
||
|
||
dwRetCode = 0;
|
||
|
||
DhcpDSMapDomainToCNPath_Exit:
|
||
|
||
// free pAttributeEntries
|
||
if (pAttributeEntries)
|
||
{
|
||
FreeADsMem(pAttributeEntries);
|
||
}
|
||
|
||
ADSICloseDSObject( handle );
|
||
|
||
return(dwRetCode);
|
||
}
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
ValidateService(
|
||
LPWSTR lpwDomain,
|
||
LPWSTR lpwUserName,
|
||
LPWSTR lpwPassword,
|
||
DWORD dwAuthFlags,
|
||
LPWSTR lpwObjectPath,
|
||
LPWSTR lpwSrchFilter,
|
||
LPWSTR *ppwAttrName,
|
||
LPWSTR lpwAttrVal
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function determines if the given attribute (ipaddress in case of
|
||
DHCP) is present in the list of authorized entities (DHCP Servers) on the DS
|
||
enterprise.
|
||
|
||
Arguments:
|
||
|
||
lpwDomain - domain name in which to validate the service. Can be NULL to
|
||
indicate the server's domain
|
||
lpwUserName - account name to use during DS lookup. Usually, NULL (default)
|
||
lpwPassword - password for the above user
|
||
dwAuthFlags - flags to use
|
||
lpwObjectPath - path to where the "entities" are stored
|
||
lpwSrchFilter - the filter to use to get our "entities" (e.g.(objectClass==DHCPClass)
|
||
ppwAttrName - name of the attribute we're looking for (e.g. IpAddress)
|
||
lpwAttrVal - value of the attribute (e.g. the server's ipaddress to validate)
|
||
|
||
Return Value:
|
||
|
||
Result of the operation
|
||
--*/
|
||
{
|
||
|
||
HRESULT hr=S_OK;
|
||
HANDLE handle = NULL;
|
||
ADS_SEARCH_HANDLE hSearchHandle=NULL;
|
||
ADS_SEARCH_COLUMN Column;
|
||
DWORD dwRetCode;
|
||
DWORD i;
|
||
LPWSTR lpwCNPath=NULL;
|
||
LPWSTR lpwFullDSPath=NULL;
|
||
DWORD dwLen;
|
||
BOOLEAN fObjectFound=FALSE;
|
||
|
||
|
||
|
||
dwRetCode = DHCPDSERR_ENTRY_NOT_FOUND;
|
||
|
||
//
|
||
// first, we need to get the full ads path to our container within the
|
||
// configuration container, from the domain name
|
||
//
|
||
dwRetCode = DhcpDSMapDomainToCNPath(
|
||
lpwDomain,
|
||
lpwUserName,
|
||
lpwPassword,
|
||
dwAuthFlags,
|
||
&lpwCNPath);
|
||
|
||
if (dwRetCode != 0)
|
||
{
|
||
DBGPRINT("ValidateService: MapDomainToCNPath failed with 0x%x\n",dwRetCode);
|
||
goto ValidateService_Exit;
|
||
}
|
||
|
||
dwLen = (wcslen(lpwObjectPath)+1)*sizeof(WCHAR) +
|
||
(wcslen(lpwCNPath)+1)*sizeof(WCHAR);
|
||
|
||
lpwFullDSPath = (LPWSTR)LocalAlloc(LPTR, dwLen);
|
||
|
||
if (lpwFullDSPath == NULL)
|
||
{
|
||
DBGPRINT("ValidateService: malloc failed (%ld)\n",dwLen);
|
||
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ValidateService_Exit;
|
||
}
|
||
|
||
// copy the lpwObjectPath (e.g. LDAP://CN=DHCP) string
|
||
wcscpy(lpwFullDSPath, lpwObjectPath);
|
||
|
||
// now, concatenate the path to the configuration container
|
||
wcscat(lpwFullDSPath, lpwCNPath);
|
||
|
||
hr = ADSIOpenDSObject(
|
||
lpwFullDSPath,
|
||
lpwUserName,
|
||
lpwPassword,
|
||
dwAuthFlags,
|
||
&handle
|
||
);
|
||
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
DBGPRINT("ValidateService: ADSIOpenDSObject failed with 0x%x\n",hr);
|
||
dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
|
||
goto ValidateService_Exit;
|
||
}
|
||
|
||
|
||
hr = ADSIExecuteSearch(
|
||
handle,
|
||
lpwSrchFilter,
|
||
ppwAttrName,
|
||
-1, // ok to always pass this?
|
||
&hSearchHandle
|
||
);
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
DBGPRINT("ADSIExecuteSearch failed with 0x%x\n",hr);
|
||
dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
|
||
goto ValidateService_Exit;
|
||
}
|
||
|
||
|
||
hr = ADSIGetNextRow(
|
||
handle,
|
||
hSearchHandle
|
||
);
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
DBGPRINT("ADSIGetNextRow failed with 0x%x\n",hr);
|
||
dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
|
||
goto ValidateService_Exit;
|
||
}
|
||
|
||
while (hr != S_ADS_NOMORE_ROWS && !fObjectFound)
|
||
{
|
||
//
|
||
// get the values for the attribute requested (e.g. ipaddress)
|
||
//
|
||
hr = ADSIGetColumn(
|
||
handle,
|
||
hSearchHandle,
|
||
ppwAttrName[0], // for now, only first one is needed
|
||
&Column
|
||
);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
//
|
||
// if the attribute is multivalued, compare all the values to see
|
||
// if we find the one we want
|
||
//
|
||
for (i=0; i < Column.dwNumValues; i++)
|
||
{
|
||
if (_wcsnicmp(
|
||
Column.pADsValues[i].CaseIgnoreString,
|
||
lpwAttrVal,
|
||
wcslen(lpwAttrVal)) == 0)
|
||
{
|
||
fObjectFound = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// free the column
|
||
ADSIFreeColumn(
|
||
handle,
|
||
&Column);
|
||
}
|
||
|
||
//
|
||
// it's strange if this attribute is not defined for this object since
|
||
// it's one of our objects. But, nevertheless, just skip it
|
||
//
|
||
else
|
||
{
|
||
DBGPRINT("ADSIGetColumn failed with hr = 0x%x\n",hr);
|
||
}
|
||
|
||
// move to the next object
|
||
hr = ADSIGetNextRow(
|
||
handle,
|
||
hSearchHandle
|
||
);
|
||
}
|
||
|
||
|
||
dwRetCode = (fObjectFound)? DHCPDSERR_ENTRY_FOUND : DHCPDSERR_ENTRY_NOT_FOUND;
|
||
|
||
ValidateService_Exit:
|
||
|
||
if (hSearchHandle)
|
||
{
|
||
ADSICloseSearchHandle(
|
||
handle,
|
||
hSearchHandle);
|
||
}
|
||
|
||
if (handle)
|
||
{
|
||
ADSICloseDSObject( handle );
|
||
}
|
||
|
||
if (lpwCNPath)
|
||
{
|
||
LocalFree((PCHAR)lpwCNPath);
|
||
}
|
||
|
||
if (lpwFullDSPath)
|
||
{
|
||
LocalFree((PCHAR)lpwFullDSPath);
|
||
}
|
||
|
||
return(dwRetCode) ;
|
||
}
|
||
|
||
|
||
DWORD
|
||
DhcpDSSameEnterprise(
|
||
LPWSTR lpwDomainName,
|
||
LPWSTR lpwRootName,
|
||
BOOLEAN *fIsSameEnterprise
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks if the given domain is part of the given DS Tree (in other
|
||
words, we want to find out if this domain belongs to another enterprise)
|
||
|
||
Arguments:
|
||
|
||
lpwDomainName - name of the domain in question
|
||
lpwRootName - root of the DS Tree to test against
|
||
fIsSameEnterprise - on return, TRUE or FALSE
|
||
|
||
Return Value:
|
||
|
||
result of the operation
|
||
|
||
--*/
|
||
{
|
||
|
||
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
|
||
DWORD dwRetCode;
|
||
|
||
|
||
//
|
||
// until we can definitely verify that the root of the given domain is
|
||
// the same as the one that is supplied, we return FALSE.
|
||
//
|
||
(*fIsSameEnterprise) = FALSE;
|
||
|
||
if (!lpwRootName)
|
||
{
|
||
DBGPRINT("DhcpDSSameEnterprise: C'mon, don't pass me a NULL!\n");
|
||
return(0);
|
||
}
|
||
|
||
dwRetCode = DsGetDcName(
|
||
NULL, // server name
|
||
lpwDomainName, // domain name
|
||
NULL, // domain guid
|
||
NULL, // site name
|
||
DS_IS_DNS_NAME, // what flag(s) to use?
|
||
&pDCInfo);
|
||
|
||
if (dwRetCode != NO_ERROR)
|
||
{
|
||
DBGPRINT("DhcpDSSameEnterprise: DsGetDcName failed (%ld)\n",dwRetCode);
|
||
|
||
return(dwRetCode);
|
||
}
|
||
|
||
// moment of truth: are the two roots the same?
|
||
(*fIsSameEnterprise) = (DnsCompareName(lpwRootName, pDCInfo->DnsForestName) != 0);
|
||
|
||
NetApiBufferFree(pDCInfo);
|
||
|
||
return(0);
|
||
|
||
}
|