5863 lines
136 KiB
C
5863 lines
136 KiB
C
/*++
|
||
|
||
Copyright (c) 1996-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
winrnr.c
|
||
|
||
Abstract:
|
||
|
||
Rnr provider for ActiveDirectory.
|
||
|
||
Work items:
|
||
|
||
1) Need to support the NTDS Global catalog on LUP_DEEP from Root searches.
|
||
2) Need to add bind handle caching.
|
||
|
||
Author:
|
||
|
||
GlennC 23-Jul-1996
|
||
|
||
Revision History:
|
||
|
||
GlennC Added support for LUP_CONTAINERS in NSP2LookupServiceXXX
|
||
functions.
|
||
|
||
jamesg Jan 2001 cleanup, bug fixes, proper alignment
|
||
jamesg May 2001 rewrite
|
||
- 64-bit completely broken because 32-bit
|
||
structures used as bervals
|
||
- leaks
|
||
- duplicate code
|
||
- simplify flat buffer building macros
|
||
- allow for sockaddrs other than IP4
|
||
|
||
--*/
|
||
|
||
|
||
#include <stdio.h>
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <rpc.h>
|
||
#include <rpcdce.h>
|
||
#include <winsock2.h>
|
||
#include <ws2spi.h>
|
||
#include <wsipx.h>
|
||
#include <svcguid.h>
|
||
#include <rnraddrs.h>
|
||
#include <align.h>
|
||
#include <winldap.h>
|
||
|
||
#include <windns.h> // alignment macro
|
||
#include <dnslib.h> // flat buffer stuff, memory allocation
|
||
|
||
|
||
//
|
||
// RnR context
|
||
//
|
||
// Context we keep during a given RnR lookup session.
|
||
//
|
||
|
||
typedef struct
|
||
{
|
||
PLDAP pLdapServer;
|
||
PLDAP pLdapGlobalCatalog;
|
||
PWSTR DomainDN;
|
||
PWSTR WinsockServicesDN;
|
||
}
|
||
RNR_CONNECTION, *PRNR_CONNECTION;
|
||
|
||
typedef struct
|
||
{
|
||
DWORD Count;
|
||
DWORD CurrentIndex;
|
||
PWSTR Strings[0];
|
||
}
|
||
DN_ARRAY, *PDN_ARRAY;
|
||
|
||
typedef struct
|
||
{
|
||
DWORD Signature;
|
||
DWORD ControlFlags;
|
||
DWORD CurrentDN;
|
||
DWORD NumberOfProtocols;
|
||
PWSTR pwsServiceName;
|
||
PRNR_CONNECTION pRnrConnection;
|
||
PDN_ARRAY pDnArray;
|
||
PWSTR pwsContext;
|
||
PAFPROTOCOLS pafpProtocols;
|
||
PWSAVERSION pVersion;
|
||
WSAVERSION WsaVersion;
|
||
GUID ServiceClassGuid;
|
||
GUID ProviderGuid;
|
||
}
|
||
RNR_LOOKUP, *PRNR_LOOKUP;
|
||
|
||
|
||
//
|
||
// WSANSCLASSINFO stored in berval
|
||
//
|
||
// ClassInfo blobs read and written to directory with
|
||
// pointers replaced by offsets.
|
||
//
|
||
// Note: need to explicitly make this structure, because
|
||
// the WSANSCLASSINFO struct is different sizes for
|
||
// 32/64bit; this structure will match the 32-bit
|
||
// WSANSCLASSINFO which have already been written to
|
||
// the directory in Win2K deployments
|
||
//
|
||
|
||
typedef struct _ClassInfoAsBerval
|
||
{
|
||
DWORD NameOffset;
|
||
DWORD dwNameSpace;
|
||
DWORD dwValueType;
|
||
DWORD dwValueSize;
|
||
DWORD ValueOffset;
|
||
}
|
||
CLASSINFO_BERVAL, *PCLASSINFO_BERVAL;
|
||
|
||
//
|
||
// CSADDR stored in berval
|
||
//
|
||
// CSADDRs read and written to directory with
|
||
// pointers replaced by offsets.
|
||
//
|
||
// Note: as with WSANSCLASSINFO above CSADDR can not
|
||
// be used directly in both 32 and 64 bit. Make a structure
|
||
// that explicitly uses offsets and matches the already
|
||
// deployed 32-bit form.
|
||
//
|
||
|
||
typedef struct _CsaddrAsBerval
|
||
{
|
||
DWORD LocalZero;
|
||
LONG LocalLength;
|
||
DWORD RemoteZero;
|
||
LONG RemoteLength;
|
||
LONG iSocketType;
|
||
LONG iProtocol;
|
||
}
|
||
CSADDR_BERVAL, *PCSADDR_BERVAL;
|
||
|
||
|
||
//
|
||
// RnR defines
|
||
//
|
||
|
||
#define RNR_SIGNATURE 0x7364736e // "nsds"
|
||
#define RNR_SIGNATURE_FREE 0x65657266 // "free"
|
||
|
||
#define LDAP_GLOBAL_CATALOG 3268
|
||
|
||
//
|
||
// Standard out-of-mem rcode
|
||
//
|
||
|
||
#define ERROR_NO_MEMORY WSA_NOT_ENOUGH_MEMORY
|
||
|
||
//
|
||
// Defs to straight pointer
|
||
//
|
||
|
||
typedef LPGUID PGUID;
|
||
|
||
typedef LPWSASERVICECLASSINFOW PWSASERVICECLASSINFOW;
|
||
|
||
typedef DWORD RNR_STATUS;
|
||
|
||
#define GuidEqual(x,y) RtlEqualMemory( x, y, sizeof(GUID) )
|
||
|
||
//
|
||
// Debug printing
|
||
//
|
||
|
||
#ifdef DBG
|
||
//#define WINRNR_PRINT( foo ) KdPrint( foo )
|
||
#define WINRNR_PRINT( foo ) DNS_PRINT( foo )
|
||
#else
|
||
#define WINRNR_PRINT( foo )
|
||
#endif
|
||
|
||
#ifdef DBG
|
||
#define DnsDbg_DnArray(h,p) Print_DnArray( DnsPR, NULL, (h), (p) )
|
||
#define DnsDbg_RnrConnection(h,p) Print_RnrConnection( DnsPR, NULL, (h), (p) )
|
||
#define DnsDbg_RnrLookup(h,p) Print_RnrLookup( DnsPR, NULL, (h), (p) )
|
||
#else
|
||
#define DnsDbg_DnArray(h,p)
|
||
#define DnsDbg_RnrConnection(h,p)
|
||
#define DnsDbg_RnrLookup(h,p)
|
||
#endif
|
||
|
||
//
|
||
// LDAP search stuff
|
||
// - DN pieces
|
||
// - attributes
|
||
// - filters
|
||
//
|
||
|
||
WCHAR g_NtdsContainer[] = L"Container";
|
||
WCHAR g_CommonName[] = L"CN";
|
||
WCHAR g_DisplayName[] = L"displayName";
|
||
WCHAR g_Comment[] = L"description";
|
||
WCHAR g_DefaultDn[] = L"defaultNamingContext";
|
||
WCHAR g_ObjectClass[] = L"objectClass";
|
||
WCHAR g_ObjectName[] = L"name";
|
||
WCHAR g_ServiceClass[] = L"serviceClass";
|
||
WCHAR g_ServiceClassId[] = L"serviceClassID";
|
||
WCHAR g_ServiceClassInfo[] = L"serviceClassInfo";
|
||
WCHAR g_ServiceInstance[] = L"serviceInstance";
|
||
WCHAR g_ServiceVersion[] = L"serviceInstanceVersion";
|
||
WCHAR g_WinsockAddresses[] = L"winsockAddresses";
|
||
WCHAR g_WinsockServicesDn[] = L"CN=WinsockServices,CN=System,";
|
||
|
||
WCHAR g_FilterObjectClass_ServiceClass[] = L"(objectClass=serviceClass)";
|
||
WCHAR g_FilterObjectClass_ServiceInstance[] = L"(objectClass=serviceInstance)";
|
||
WCHAR g_FilterObjectClass_Container[] = L"(objectClass=Container)";
|
||
WCHAR g_FilterObjectClass_Star[] = L"(objectClass=*)";
|
||
|
||
WCHAR g_FilterCnEquals[] = L"CN=";
|
||
WCHAR g_FilterParenCnEquals[] = L"(CN=";
|
||
WCHAR g_FilterParenServiceClassIdEquals[] = L"(serviceClassId=";
|
||
WCHAR g_FilterParenServiceVersionEquals[] = L"(serviceVersion=";
|
||
|
||
//
|
||
// Access with #defines
|
||
//
|
||
|
||
#define NTDS_CONTAINER g_NtdsContainer
|
||
#define COMMON_NAME g_CommonName
|
||
#define DEFAULT_DOMAIN_DN g_DefaultDn
|
||
#define OBJECT_CLASS g_ObjectClass
|
||
#define OBJECT_COMMENT g_Comment
|
||
#define OBJECT_NAME g_ObjectName
|
||
#define SERVICE_CLASS g_ServiceClass
|
||
#define SERVICE_CLASS_ID g_ServiceClassId
|
||
#define SERVICE_CLASS_INFO g_ServiceClassInfo
|
||
#define SERVICE_CLASS_NAME g_DisplayName
|
||
#define SERVICE_COMMENT g_Comment
|
||
#define SERVICE_INSTANCE g_ServiceInstance
|
||
#define SERVICE_INSTANCE_NAME g_DisplayName
|
||
#define SERVICE_VERSION g_ServiceVersion
|
||
#define WINSOCK_ADDRESSES g_WinsockAddresses
|
||
#define WINSOCK_SERVICES g_WinsockServicesDn
|
||
|
||
// Filters
|
||
|
||
#define FILTER_OBJECT_CLASS_SERVICE_CLASS g_FilterObjectClass_ServiceClass
|
||
#define FILTER_OBJECT_CLASS_SERVICE_INSTANCE g_FilterObjectClass_ServiceInstance
|
||
#define FILTER_OBJECT_CLASS_NTDS_CONTAINER g_FilterObjectClass_Container
|
||
#define FILTER_OBJECT_CLASS_STAR g_FilterObjectClass_Star
|
||
|
||
#define FILTER_CN_EQUALS g_FilterCnEquals
|
||
#define FILTER_PAREN_CN_EQUALS g_FilterParenCnEquals
|
||
#define FILTER_PAREN_SERVICE_CLASS_ID_EQUALS g_FilterParenServiceClassIdEquals
|
||
#define FILTER_PAREN_SERVICE_VERSION_EQUALS g_FilterParenServiceVersionEquals
|
||
|
||
|
||
//
|
||
// GUID generated by uuidgen.exe for provider identifer,
|
||
// (3b2637ee-e580-11cf-a555-00c04fd8d4ac)
|
||
//
|
||
|
||
GUID g_NtdsProviderGuid =
|
||
{
|
||
0x3b2637ee,
|
||
0xe580,
|
||
0x11cf,
|
||
{0xa5, 0x55, 0x00, 0xc0, 0x4f, 0xd8, 0xd4, 0xac}
|
||
};
|
||
|
||
WCHAR g_NtdsProviderName[] = L"NTDS";
|
||
WCHAR g_NtdsProviderPath[] = L"%SystemRoot%\\System32\\winrnr.dll";
|
||
|
||
PWSTR g_pHostName = NULL;
|
||
PWSTR g_pFullName = NULL;
|
||
|
||
DWORD g_TlsIndex;
|
||
|
||
GUID HostAddrByInetStringGuid = SVCID_INET_HOSTADDRBYINETSTRING;
|
||
GUID ServiceByNameGuid = SVCID_INET_SERVICEBYNAME;
|
||
GUID HostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME;
|
||
GUID HostNameGuid = SVCID_HOSTNAME;
|
||
|
||
|
||
//
|
||
// Heap
|
||
//
|
||
|
||
#define ALLOC_HEAP_ZERO( size ) Dns_AllocZero( size )
|
||
#define ALLOC_HEAP( size ) Dns_Alloc( size )
|
||
#define FREE_HEAP( p ) Dns_Free( p )
|
||
|
||
|
||
|
||
#ifdef DBG
|
||
//
|
||
// Debug print utils
|
||
//
|
||
|
||
VOID
|
||
Print_DnArray(
|
||
IN PRINT_ROUTINE PrintRoutine,
|
||
IN PPRINT_CONTEXT PrintContext,
|
||
IN PSTR pszHeader,
|
||
IN PDN_ARRAY pDnArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Print DN array
|
||
|
||
Arguments:
|
||
|
||
pDnArray -- DN array to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DWORD iter;
|
||
|
||
if ( !pszHeader )
|
||
{
|
||
pszHeader = "DN Array:";
|
||
}
|
||
if ( !pDnArray )
|
||
{
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s NULL DN Array!\n",
|
||
pszHeader );
|
||
return;
|
||
}
|
||
|
||
DnsPrint_Lock();
|
||
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s\n"
|
||
"\tPtr = %p\n"
|
||
"\tCount = %d\n"
|
||
"\tStrings:\n",
|
||
pszHeader,
|
||
pDnArray,
|
||
pDnArray->Count );
|
||
|
||
for ( iter = 0; iter < pDnArray->Count; iter++ )
|
||
{
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"\t\tDN[%d] %S\n",
|
||
iter,
|
||
pDnArray->Strings[iter] );
|
||
}
|
||
DnsPrint_Unlock();
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
Print_RnrConnection(
|
||
IN PRINT_ROUTINE PrintRoutine,
|
||
IN PPRINT_CONTEXT PrintContext,
|
||
IN PSTR pszHeader,
|
||
IN PRNR_CONNECTION pRnrCon
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Print RnR connection info.
|
||
|
||
Arguments:
|
||
|
||
pRnrCon -- Rnr connection blob
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
if ( !pszHeader )
|
||
{
|
||
pszHeader = "RnR Connection:";
|
||
}
|
||
if ( !pRnrCon )
|
||
{
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s NULL RnR Connection!\n",
|
||
pszHeader );
|
||
return;
|
||
}
|
||
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s\n"
|
||
"\tPtr = %p\n"
|
||
"\tpLdap = %p\n"
|
||
"\tpLdap GC = %p\n"
|
||
"\tDomain DN = %S\n"
|
||
"\tWsockServicesDN = %S\n",
|
||
pszHeader,
|
||
pRnrCon,
|
||
pRnrCon->pLdapServer,
|
||
pRnrCon->pLdapGlobalCatalog,
|
||
pRnrCon->DomainDN,
|
||
pRnrCon->WinsockServicesDN
|
||
);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
Print_RnrLookup(
|
||
IN PRINT_ROUTINE PrintRoutine,
|
||
IN PPRINT_CONTEXT PrintContext,
|
||
IN PSTR pszHeader,
|
||
IN PRNR_LOOKUP pRnr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Print RnR lookup blob.
|
||
|
||
Arguments:
|
||
|
||
pRnr -- Rnr lookup blob
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
CHAR serviceGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
|
||
CHAR providerGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
|
||
|
||
|
||
if ( !pszHeader )
|
||
{
|
||
pszHeader = "RnR Lookup:";
|
||
}
|
||
if ( !pRnr )
|
||
{
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s NULL RnR Lookup!\n",
|
||
pszHeader );
|
||
return;
|
||
}
|
||
|
||
// convert GUIDs to strings
|
||
|
||
DnsStringPrint_Guid(
|
||
serviceGuidBuffer,
|
||
&pRnr->ServiceClassGuid
|
||
);
|
||
DnsStringPrint_Guid(
|
||
providerGuidBuffer,
|
||
&pRnr->ProviderGuid
|
||
);
|
||
|
||
DnsPrint_Lock();
|
||
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"%s\n"
|
||
"\tPtr = %p\n"
|
||
"\tSig = %08x\n"
|
||
"\tCntrl Flags = %08x\n"
|
||
"\tService Name = %S\n"
|
||
"\tpConnection = %p\n"
|
||
"\tpDnArray = %p\n"
|
||
"\tDN Index = %d\n"
|
||
"\tClass GUID = %s\n"
|
||
"\tProvider GUID = %s\n"
|
||
"\tpContext = %S\n"
|
||
"\tVersion = %p %08x %d\n"
|
||
"\tpProtocols = %p\n"
|
||
"\tNum Protocols = %d\n",
|
||
pszHeader,
|
||
pRnr,
|
||
pRnr->Signature,
|
||
pRnr->ControlFlags,
|
||
pRnr->pwsServiceName,
|
||
pRnr->pRnrConnection,
|
||
pRnr->pDnArray,
|
||
pRnr->CurrentDN,
|
||
serviceGuidBuffer,
|
||
providerGuidBuffer,
|
||
pRnr->pwsContext,
|
||
pRnr->pVersion,
|
||
pRnr->WsaVersion.dwVersion,
|
||
pRnr->WsaVersion.ecHow,
|
||
pRnr->pafpProtocols,
|
||
pRnr->NumberOfProtocols
|
||
);
|
||
|
||
if ( pRnr->pRnrConnection )
|
||
{
|
||
Print_RnrConnection(
|
||
PrintRoutine,
|
||
PrintContext,
|
||
NULL,
|
||
pRnr->pRnrConnection );
|
||
}
|
||
|
||
if ( pRnr->pDnArray )
|
||
{
|
||
Print_DnArray(
|
||
PrintRoutine,
|
||
PrintContext,
|
||
NULL,
|
||
pRnr->pDnArray );
|
||
}
|
||
|
||
if ( pRnr->pafpProtocols )
|
||
{
|
||
DnsPrint_AfProtocolsArray(
|
||
PrintRoutine,
|
||
PrintContext,
|
||
"\tProtocol array:",
|
||
pRnr->pafpProtocols,
|
||
pRnr->NumberOfProtocols );
|
||
}
|
||
PrintRoutine(
|
||
PrintContext,
|
||
"\n" );
|
||
|
||
DnsPrint_Unlock();
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
//
|
||
// Basic utils
|
||
//
|
||
|
||
PDN_ARRAY
|
||
AllocDnArray(
|
||
IN DWORD Count
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create DN array
|
||
|
||
Arguments:
|
||
|
||
Count -- string count to handle
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDN_ARRAY parray;
|
||
|
||
//
|
||
// free strings in array
|
||
//
|
||
|
||
parray = (PDN_ARRAY) ALLOC_HEAP_ZERO(
|
||
sizeof(*parray) +
|
||
Count*sizeof(PSTR) );
|
||
if ( parray )
|
||
{
|
||
parray->Count = Count;
|
||
}
|
||
return parray;
|
||
}
|
||
|
||
|
||
VOID
|
||
FreeDnArray(
|
||
IN OUT PDN_ARRAY pDnArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free DN array
|
||
|
||
Arguments:
|
||
|
||
pDnArray -- DN array to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DWORD iter;
|
||
|
||
if ( !pDnArray )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// free strings in array
|
||
//
|
||
|
||
for ( iter = 0; iter < pDnArray->Count; iter++ )
|
||
{
|
||
PWSTR pstr = pDnArray->Strings[iter];
|
||
if ( pstr )
|
||
{
|
||
FREE_HEAP( pstr );
|
||
}
|
||
}
|
||
FREE_HEAP( pDnArray );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
BuildDnArrayFromResults(
|
||
IN OUT PLDAP pLdap,
|
||
IN PLDAPMessage pLdapResults,
|
||
OUT PDWORD pdwCount, OPTIONAL
|
||
OUT PDN_ARRAY * ppDnArray OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build DN array from LDAP results
|
||
|
||
Arguments:
|
||
|
||
pLdap -- LDAP connection
|
||
|
||
pLdapResults -- LDAP results from search
|
||
|
||
pdwCount -- addr to receive count if getting count
|
||
|
||
ppDnArray -- addr to receive ptr to DN array
|
||
if not given, no DN array built
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on memory allocation failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
DWORD count;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
LDAPMessage * pnext;
|
||
DWORD iter;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"BuildDnArrayFromResults()\n"
|
||
"\tpLdap = %p\n"
|
||
"\tpResults = %p\n"
|
||
"\tpCount OUT = %p\n"
|
||
"\tpDnArray OUT = %p\n",
|
||
pLdap,
|
||
pLdapResults,
|
||
pdwCount,
|
||
ppDnArray ));
|
||
|
||
//
|
||
// count search hits
|
||
//
|
||
|
||
count = ldap_count_entries(
|
||
pLdap,
|
||
pLdapResults );
|
||
|
||
if ( count == 0 || !ppDnArray )
|
||
{
|
||
status = NO_ERROR;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// build DN array from ldap results
|
||
// - note that allocated strings are IN dnarray
|
||
//
|
||
|
||
pdnArray = AllocDnArray( count );
|
||
if ( !pdnArray )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
|
||
for ( pnext = ldap_first_entry( pLdap, pLdapResults ), iter=0;
|
||
pnext != NULL;
|
||
pnext = ldap_next_entry( pLdap, pnext ), iter++ )
|
||
{
|
||
PWSTR pnextDn = ldap_get_dn( pLdap, pnext );
|
||
PWSTR pdn;
|
||
|
||
pdn = Dns_CreateStringCopy_W( pnextDn );
|
||
|
||
ldap_memfree( pnextDn );
|
||
|
||
if ( !pdn )
|
||
{
|
||
FREE_HEAP( pdnArray );
|
||
pdnArray = NULL;
|
||
status = ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
if ( iter >= count )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
break;
|
||
}
|
||
pdnArray->Strings[iter] = pdn;
|
||
}
|
||
|
||
status = NO_ERROR;
|
||
|
||
Done:
|
||
|
||
|
||
if ( ppDnArray )
|
||
{
|
||
*ppDnArray = pdnArray;
|
||
}
|
||
if ( pdwCount )
|
||
{
|
||
*pdwCount = count;
|
||
}
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Lock();
|
||
DNS_PRINT((
|
||
"Leave BuildDnArrayFromResults() => %d\n"
|
||
"\tcount = %d\n",
|
||
status,
|
||
count ));
|
||
DnsDbg_DnArray(
|
||
NULL,
|
||
pdnArray );
|
||
DnsDbg_Unlock();
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
PWSTR
|
||
CreateFilterElement(
|
||
IN PBYTE pBlob,
|
||
IN DWORD BlobLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create filter element for flat blob.
|
||
|
||
Arguments:
|
||
|
||
pBlob -- ptr to blob
|
||
|
||
BlobLength -- length
|
||
|
||
Return Value:
|
||
|
||
Ptr to allocated filter element.
|
||
NULL on error.
|
||
|
||
--*/
|
||
{
|
||
PWSTR pfilter;
|
||
DWORD size;
|
||
|
||
DNSDBG( TRACE, (
|
||
"CreateFilterElement( %p, %d )\n",
|
||
pBlob,
|
||
BlobLength ));
|
||
|
||
//
|
||
// get size of filter string
|
||
//
|
||
// DCR: hard to believe the size should go *WCHAR
|
||
// seems like that would be taken care of
|
||
//
|
||
|
||
size = ldap_escape_filter_element(
|
||
pBlob,
|
||
BlobLength,
|
||
NULL, // no buffer
|
||
0 );
|
||
|
||
size *= sizeof(WCHAR);
|
||
|
||
pfilter = ALLOC_HEAP_ZERO( size );
|
||
if ( !pfilter )
|
||
{
|
||
SetLastError( ERROR_NO_MEMORY );
|
||
return NULL;
|
||
}
|
||
|
||
ldap_escape_filter_element(
|
||
pBlob,
|
||
BlobLength,
|
||
pfilter,
|
||
size );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave CreateFilterElement() => %S\n",
|
||
pfilter ));
|
||
|
||
return pfilter;
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
SetError(
|
||
IN RNR_STATUS dwError
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wraps SetLastError() and SOCKET_ERROR return.
|
||
|
||
Arguments:
|
||
|
||
dwError -- error code
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if dwError==NO_ERROR
|
||
SOCKET_ERROR on any other error.
|
||
|
||
--*/
|
||
{
|
||
if ( dwError )
|
||
{
|
||
SetLastError( dwError );
|
||
return( (DWORD) SOCKET_ERROR );
|
||
}
|
||
else
|
||
{
|
||
return( NO_ERROR );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
IsNameADn(
|
||
IN PWSTR szName,
|
||
OUT PWSTR * ppwsRdn,
|
||
OUT PWSTR * ppwsContext
|
||
)
|
||
{
|
||
#define NTDS_MAX_DN_LEN 1024
|
||
DWORD status = NO_ERROR;
|
||
WCHAR szNameBuf[ NTDS_MAX_DN_LEN ];
|
||
PWSTR szTemp;
|
||
PWSTR szComma = NULL;
|
||
DWORD i;
|
||
BOOL fQuoted = FALSE;
|
||
|
||
DNSDBG( TRACE, (
|
||
"IsNameADn( %S )\n",
|
||
szName ));
|
||
|
||
wcsncpy( szNameBuf, szName, NTDS_MAX_DN_LEN );
|
||
szNameBuf[ NTDS_MAX_DN_LEN-1 ] = 0;
|
||
|
||
szTemp = szNameBuf;
|
||
|
||
for ( i = 0; i < wcslen( szName ); i++ )
|
||
{
|
||
if ( szTemp[i] == L',' )
|
||
{
|
||
if ( !fQuoted )
|
||
{
|
||
szComma = &szTemp[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( szTemp[i] == L'\"' )
|
||
{
|
||
#if 0
|
||
// this one is a classic ... saving for posterity
|
||
|
||
if ( fQuoted )
|
||
fQuoted = FALSE;
|
||
else
|
||
fQuoted = TRUE;
|
||
#endif
|
||
fQuoted = !fQuoted;
|
||
}
|
||
}
|
||
|
||
if ( i >= wcslen( szName ) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
szComma[0] = 0;
|
||
szComma++;
|
||
|
||
if ( szComma[0] == L' ' )
|
||
szComma++;
|
||
|
||
if ( wcslen( szComma ) == 0 )
|
||
return FALSE;
|
||
|
||
*ppwsContext = (LPWSTR) ALLOC_HEAP_ZERO( ( wcslen( szComma ) + 1 ) *
|
||
sizeof( WCHAR ) );
|
||
|
||
if ( *ppwsContext == NULL )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
wcscpy( *ppwsContext, szComma );
|
||
|
||
*ppwsRdn = (LPWSTR) ALLOC_HEAP_ZERO( ( wcslen( szNameBuf ) + 1 ) *
|
||
sizeof( WCHAR ) );
|
||
|
||
if ( *ppwsRdn == NULL )
|
||
{
|
||
(void) FREE_HEAP( *ppwsContext );
|
||
*ppwsContext = NULL;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
if ( szNameBuf[0] == L'C' || szNameBuf[0] == L'c' &&
|
||
szNameBuf[1] == L'N' || szNameBuf[1] == L'n' &&
|
||
szNameBuf[2] == L'=' )
|
||
{
|
||
wcscpy( *ppwsRdn, szNameBuf + 3 );
|
||
}
|
||
else
|
||
{
|
||
wcscpy( *ppwsRdn, szNameBuf );
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Recursion locking
|
||
//
|
||
// Idea here is to keep LDAP calls from recursing back
|
||
// into these functions through ConnectToDefaultDirectory
|
||
// Simply set TLS pointer to one when do LDAP search and
|
||
// test in ConnectToDefaultDirectory(), quiting if already
|
||
// set.
|
||
//
|
||
|
||
BOOL
|
||
GetRecurseLock(
|
||
IN PSTR pszFunctionName
|
||
)
|
||
{
|
||
if ( TlsSetValue( g_TlsIndex, (LPVOID) 1 ) == FALSE )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!%s - TlsSetValue( %d, 1 ) failed!\n"
|
||
"\terror code: 0%x\n",
|
||
pszFunctionName,
|
||
g_TlsIndex,
|
||
GetLastError() ));
|
||
|
||
return( FALSE );
|
||
}
|
||
return( TRUE );
|
||
}
|
||
|
||
BOOL
|
||
ReleaseRecurseLock(
|
||
IN PSTR pszFunctionName
|
||
)
|
||
{
|
||
if ( TlsSetValue( g_TlsIndex, NULL ) == FALSE )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!%s - TlsSetValue( %d, NULL ) failed!\n"
|
||
"\terror code: 0%x\n",
|
||
pszFunctionName,
|
||
g_TlsIndex,
|
||
GetLastError() ));
|
||
|
||
return( FALSE );
|
||
}
|
||
return( TRUE );
|
||
}
|
||
|
||
BOOL
|
||
IsRecurseLocked(
|
||
VOID
|
||
)
|
||
{
|
||
return TlsGetValue( g_TlsIndex ) ? TRUE : FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
DoLdapSearch(
|
||
IN PSTR pszFunction,
|
||
IN BOOL fLocked,
|
||
IN PLDAP pLdap,
|
||
IN PWSTR pwsDN,
|
||
IN DWORD Flag,
|
||
IN PWSTR pwsFilter,
|
||
IN PWSTR * Attributes,
|
||
OUT PLDAPMessage * ppResults
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Do ldap search.
|
||
|
||
Wrapper function to do ldap search with recurse locking
|
||
and debug print.
|
||
|
||
Arguments:
|
||
|
||
pszFunction -- function calling in
|
||
|
||
fLocked -- already recurse locked
|
||
|
||
LDAP search params:
|
||
|
||
pLdap -- LDAP connection
|
||
|
||
pwsDN -- DN to search at
|
||
|
||
Flag -- search flag
|
||
|
||
pwsFilter -- filter
|
||
|
||
Attributes -- attribute array
|
||
|
||
ppResults -- addr to recv ptr to result message
|
||
caller must free
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
WSAEFAULT if buffer too small.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status;
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Lock();
|
||
DNSDBG( TRACE, (
|
||
"DoLdapSearch()\n"
|
||
"\tFunction = %s\n"
|
||
"\tLocked = %d\n"
|
||
"\tLDAP search params:\n"
|
||
"\tpLdap = %p\n"
|
||
"\tDN = %S\n"
|
||
"\tFlags = %08x\n"
|
||
"\tpFilter = %S\n"
|
||
"\tppResults = %p\n",
|
||
pszFunction,
|
||
fLocked,
|
||
pLdap,
|
||
pwsDN,
|
||
Flag,
|
||
pwsFilter,
|
||
ppResults ));
|
||
|
||
DnsDbg_StringArray(
|
||
" Search Attributes:",
|
||
(PSTR *) Attributes,
|
||
0, // count unknown, array NULL terminated
|
||
TRUE // in unicode
|
||
);
|
||
DnsDbg_Unlock();
|
||
}
|
||
|
||
//
|
||
// search
|
||
//
|
||
|
||
if ( !fLocked &&
|
||
!GetRecurseLock( pszFunction ) )
|
||
{
|
||
status = ERROR_LOCK_FAILED;
|
||
goto Exit;
|
||
}
|
||
|
||
status = ldap_search_s(
|
||
pLdap,
|
||
pwsDN,
|
||
Flag,
|
||
pwsFilter,
|
||
Attributes,
|
||
0,
|
||
ppResults );
|
||
|
||
if ( !fLocked &&
|
||
!ReleaseRecurseLock( pszFunction ) )
|
||
{
|
||
status = ERROR_LOCK_FAILED;
|
||
goto Exit;
|
||
}
|
||
|
||
if ( status != NO_ERROR && !*ppResults )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!%s -- ldap_search_s() failed 0%x\n",
|
||
pszFunction,
|
||
status ));
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: ldap_search_s() Failed! => %d\n"
|
||
"\tIn function %s\n"
|
||
"\tDN %S\n"
|
||
"\tFlag %08x\n"
|
||
"\tFilter %S\n",
|
||
status,
|
||
pszFunction,
|
||
pwsDN,
|
||
Flag,
|
||
pwsFilter ));
|
||
}
|
||
|
||
Exit:
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave DoLdapSearch() => %d\n",
|
||
status ));
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
DisconnectFromLDAPDirectory(
|
||
IN OUT PRNR_CONNECTION * ppRnrConnection
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Disconnect and cleanup RnR connection to directory.
|
||
|
||
Arguments:
|
||
|
||
pCsAddr -- ptr to CSADDR buffer to write
|
||
|
||
pBerval -- ptr to berval
|
||
|
||
NumberOfProtocols -- number of protocols in protocol array
|
||
|
||
pafpProtocols -- protocol array
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"DisconnectFromLDAPDirectory( %p (%p) )\n",
|
||
ppRnrConnection,
|
||
(ppRnrConnection) ? *ppRnrConnection : NULL ));
|
||
|
||
if ( ppRnrConnection )
|
||
{
|
||
PRNR_CONNECTION prnr = *ppRnrConnection;
|
||
|
||
if ( prnr )
|
||
{
|
||
ldap_unbind( prnr->pLdapServer );
|
||
ldap_unbind( prnr->pLdapGlobalCatalog );
|
||
FREE_HEAP( prnr->WinsockServicesDN );
|
||
FREE_HEAP( prnr->DomainDN );
|
||
FREE_HEAP( prnr );
|
||
*ppRnrConnection = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
ConnectToDefaultLDAPDirectory(
|
||
IN BOOL fNeedGlobalCatalog,
|
||
OUT PRNR_CONNECTION * ppRnrConnection
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Connect to directory.
|
||
|
||
Arguments:
|
||
|
||
fNeedGlobalCatalog -- TRUE if need to connect to GC
|
||
|
||
ppRnrConnection -- addr to recv connection blob
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_CONNECTION prnr = NULL;
|
||
PLDAP pldap = NULL;
|
||
PWSTR pstr;
|
||
DWORD count = 0;
|
||
BOOL frecurseLocked = FALSE;
|
||
LDAPMessage * results = NULL;
|
||
LDAPMessage * object;
|
||
PWSTR * ppvalue = NULL;
|
||
PWSTR stringArray[4];
|
||
PWSTR attrs[3] = { COMMON_NAME,
|
||
DEFAULT_DOMAIN_DN,
|
||
NULL };
|
||
|
||
DNSDBG( TRACE, (
|
||
"ConnectToDefaultLDAPDirectory()\n"
|
||
"\tNeed global catalog = %d\n"
|
||
"\tPtr to get Rnr conn = %p\n",
|
||
fNeedGlobalCatalog,
|
||
ppRnrConnection ));
|
||
|
||
//
|
||
// allocate blob of connection info
|
||
//
|
||
|
||
if ( ppRnrConnection == NULL )
|
||
{
|
||
return( WSA_INVALID_PARAMETER );
|
||
}
|
||
|
||
prnr = (PRNR_CONNECTION) ALLOC_HEAP_ZERO( sizeof(RNR_CONNECTION) );
|
||
*ppRnrConnection = prnr;
|
||
if ( !prnr )
|
||
{
|
||
return( WSA_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
//
|
||
// being called recursively -- bail
|
||
//
|
||
|
||
if ( IsRecurseLocked() )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
if ( !GetRecurseLock( "ConnectToDefaultLDAPDirectory" ) )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
frecurseLocked = TRUE;
|
||
|
||
//
|
||
// We need to keep the TLS value non-zero not just on the open but also
|
||
// across the bind and any other ldap calls for that matter. This is
|
||
// because the LDAP bind may do a reverse name lookup, in which case
|
||
// we'd come looping through here.
|
||
//
|
||
|
||
pldap = ldap_open( NULL, LDAP_PORT );
|
||
prnr->pLdapServer = pldap;
|
||
|
||
if ( fNeedGlobalCatalog )
|
||
{
|
||
prnr->pLdapGlobalCatalog = ldap_open( NULL, LDAP_GLOBAL_CATALOG );
|
||
}
|
||
if ( !pldap )
|
||
{
|
||
DNSDBG( TRACE, ( "Failed ldap_open() of default directory!\n" ));
|
||
status = WSAEHOSTUNREACH;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// If fNeedGlobalCatalog was TRUE and ldap_open failed against the
|
||
// GC server, don't bother about returning with error. We can still
|
||
// use the pldap handle.
|
||
//
|
||
// End of comment.
|
||
//
|
||
|
||
status = ldap_bind_s(
|
||
pldap,
|
||
NULL,
|
||
NULL,
|
||
LDAP_AUTH_SSPI );
|
||
if ( status )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Failed ldap_bind_s() => %d\n",
|
||
status ));
|
||
status = WSAENOTCONN;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// for the server that we are connected to, get the DN of the Domain
|
||
//
|
||
// need some general error code -- not WSAEFAULT
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"ConnectToDefaultDirectory",
|
||
TRUE, // already locked
|
||
pldap,
|
||
NULL,
|
||
LDAP_SCOPE_BASE,
|
||
FILTER_OBJECT_CLASS_STAR,
|
||
attrs,
|
||
&results );
|
||
|
||
frecurseLocked = FALSE;
|
||
if ( !ReleaseRecurseLock( "ConnectToDefaultLDAPDirectory" ) )
|
||
{
|
||
status = ERROR_LOCK_FAILED;
|
||
goto Exit;
|
||
}
|
||
if ( status && !results )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// count results
|
||
// - searched with flag LDAP_OBJECT_BASE should have one object
|
||
//
|
||
count = ldap_count_entries(
|
||
pldap,
|
||
results );
|
||
if ( count == 0 )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"No entries found in base search()\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
DNS_ASSERT( count == 1 );
|
||
|
||
//
|
||
// get object from results
|
||
//
|
||
|
||
object = ldap_first_entry(
|
||
pldap,
|
||
results );
|
||
if ( !object )
|
||
{
|
||
DNSDBG( TRACE, ( "Failed ldap_first_entry()\n" ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// read the defaultDomainDN base attribute
|
||
//
|
||
|
||
ppvalue = ldap_get_values(
|
||
pldap,
|
||
object,
|
||
DEFAULT_DOMAIN_DN );
|
||
if ( !ppvalue )
|
||
{
|
||
DNSDBG( TRACE, ( "Failed ldap_get_values()\n" ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// create DNs
|
||
// - winsock services \ default domain
|
||
// - domain
|
||
//
|
||
|
||
stringArray[0] = WINSOCK_SERVICES;
|
||
stringArray[1] = ppvalue[0];
|
||
stringArray[2] = NULL;
|
||
|
||
pstr = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pstr )
|
||
{
|
||
status = WSA_NOT_ENOUGH_MEMORY;
|
||
goto Exit;
|
||
}
|
||
prnr->WinsockServicesDN = pstr;
|
||
|
||
|
||
pstr = Dns_CreateStringCopy_W( ppvalue[0] );
|
||
if ( !pstr )
|
||
{
|
||
status = WSA_NOT_ENOUGH_MEMORY;
|
||
goto Exit;
|
||
}
|
||
prnr->DomainDN = pstr;
|
||
|
||
status = NO_ERROR;
|
||
|
||
|
||
Exit:
|
||
|
||
if ( frecurseLocked )
|
||
{
|
||
ReleaseRecurseLock( "ConnectToDefaultLDAPDirectory" );
|
||
}
|
||
|
||
ldap_value_free( ppvalue );
|
||
ldap_msgfree( results );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DisconnectFromLDAPDirectory( ppRnrConnection );
|
||
DNS_ASSERT( *ppRnrConnection == NULL );
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leaving ConnectToDefaultLDAPDirectory() => %d\n",
|
||
status ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
if ( status == NO_ERROR )
|
||
{
|
||
DnsDbg_RnrConnection(
|
||
"New RnR connection:",
|
||
*ppRnrConnection );
|
||
}
|
||
}
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
FreeRnrLookup(
|
||
IN OUT PRNR_LOOKUP pRnr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free RnR lookup blob.
|
||
|
||
Arguments:
|
||
|
||
pRnr -- ptr to Rnr lookup blob
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"FreeRnrLookup( %p )\n",
|
||
pRnr ));
|
||
|
||
if ( !pRnr )
|
||
{
|
||
return;
|
||
}
|
||
|
||
// disconnect from directory
|
||
|
||
if ( pRnr->pRnrConnection )
|
||
{
|
||
DisconnectFromLDAPDirectory( &pRnr->pRnrConnection );
|
||
}
|
||
|
||
// free subfields
|
||
|
||
FreeDnArray( pRnr->pDnArray );
|
||
Dns_Free( pRnr->pwsServiceName );
|
||
Dns_Free( pRnr->pwsContext );
|
||
Dns_Free( pRnr->pafpProtocols );
|
||
|
||
// specifically invalidate sig to help catch
|
||
// multiple frees
|
||
|
||
pRnr->Signature = RNR_SIGNATURE_FREE;
|
||
|
||
FREE_HEAP( pRnr );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// CSADDR read\write routines
|
||
//
|
||
|
||
RNR_STATUS
|
||
ModifyAddressInServiceInstance(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsDn,
|
||
IN PCSADDR_INFO pCsAddr,
|
||
IN BOOL fAdd
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Modify address (CSADDR) in service instance.
|
||
|
||
Arguments:
|
||
|
||
pRnrConnection -- RnR connection
|
||
|
||
pwsDn -- DN to make mod at
|
||
|
||
pCsAddr -- CSADDR for mode
|
||
|
||
fAdd -- TRUE for add, FALSE for delete
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
LDAPMod * modPtrArray[2];
|
||
LDAPMod mod;
|
||
PLDAP_BERVAL modBValues[2];
|
||
LDAP_BERVAL berval;
|
||
|
||
DWORD lenBerval;
|
||
DWORD lenLocal;
|
||
DWORD lenRemote;
|
||
DWORD offset;
|
||
DWORD op;
|
||
PCSADDR_BERVAL pcsaddrBerval;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"ModifyAddressInServiceInstance()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tpwsDN = %S\n"
|
||
"\tpCsAddr = %p\n"
|
||
"\tfAdd = %d\n",
|
||
pRnrConnection,
|
||
pwsDn,
|
||
pCsAddr,
|
||
fAdd ));
|
||
|
||
//
|
||
// allocate CSADDR_BERVAL
|
||
// - can not use CSADDR as contains pointers and will break in 64bit
|
||
// - CSADDR_BERVAL maps to 32-bit CSADDR size
|
||
//
|
||
|
||
lenLocal = pCsAddr->LocalAddr.iSockaddrLength;
|
||
lenRemote = pCsAddr->RemoteAddr.iSockaddrLength;
|
||
lenBerval = sizeof(CSADDR_BERVAL) + lenLocal + lenRemote;
|
||
|
||
pcsaddrBerval = (PCSADDR_BERVAL) ALLOC_HEAP_ZERO( lenBerval );
|
||
if ( !pcsaddrBerval )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// fill in CSADDR berval with CSADDR fields -- zero pointers
|
||
//
|
||
|
||
pcsaddrBerval->LocalZero = 0;
|
||
pcsaddrBerval->LocalLength = lenLocal;
|
||
pcsaddrBerval->RemoteZero = 0;
|
||
pcsaddrBerval->RemoteLength = lenRemote;
|
||
pcsaddrBerval->iSocketType = pCsAddr->iSocketType;
|
||
pcsaddrBerval->iProtocol = pCsAddr->iProtocol;
|
||
|
||
//
|
||
// copy sockaddrs
|
||
// - store offsets of sockaddrs from berval start
|
||
// (this allows any sockaddr
|
||
//
|
||
|
||
if ( lenLocal )
|
||
{
|
||
offset = sizeof(CSADDR_BERVAL);
|
||
|
||
RtlCopyMemory(
|
||
(PBYTE)pcsaddrBerval + offset,
|
||
pCsAddr->LocalAddr.lpSockaddr,
|
||
lenLocal );
|
||
}
|
||
if ( lenRemote )
|
||
{
|
||
offset = sizeof(CSADDR_BERVAL) + lenLocal;
|
||
|
||
RtlCopyMemory(
|
||
(PBYTE)pcsaddrBerval + offset,
|
||
pCsAddr->RemoteAddr.lpSockaddr,
|
||
lenRemote );
|
||
}
|
||
|
||
//
|
||
// WINSOCK_ADDRESSES attribute
|
||
// - CSADDR berval
|
||
//
|
||
|
||
if ( fAdd )
|
||
{
|
||
op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||
}
|
||
else
|
||
{
|
||
op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
|
||
}
|
||
|
||
mod.mod_op = op;
|
||
mod.mod_type = WINSOCK_ADDRESSES;
|
||
mod.mod_bvalues = modBValues;
|
||
modBValues[0] = & berval;
|
||
modBValues[1] = NULL;
|
||
berval.bv_len = lenBerval;
|
||
berval.bv_val = (PBYTE) pcsaddrBerval;
|
||
|
||
modPtrArray[0] = &mod;
|
||
modPtrArray[1] = NULL;
|
||
|
||
//
|
||
// do modify
|
||
//
|
||
|
||
if ( !GetRecurseLock( "ModifyAddressInServiceInstance" ) )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Done;
|
||
}
|
||
status = ldap_modify_s(
|
||
pRnrConnection->pLdapServer,
|
||
pwsDn,
|
||
modPtrArray );
|
||
|
||
if ( !ReleaseRecurseLock( "ModifyAddressInServiceInstance" ) )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// modify failed?
|
||
// - add treats already-exists as success
|
||
// - deleter treats doesn't-exist as success
|
||
//
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
if ( fAdd && status == LDAP_ATTRIBUTE_OR_VALUE_EXISTS )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"AlreadyExists error on add modify for %S\n"
|
||
"\ttreating as success\n",
|
||
pwsDn ));
|
||
status = NO_ERROR;
|
||
}
|
||
else if ( !fAdd && status == LDAP_NO_SUCH_ATTRIBUTE )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"NoSuchAttribute error on remove modify for %S\n"
|
||
"\ttreating as success\n",
|
||
pwsDn ));
|
||
status = NO_ERROR;
|
||
}
|
||
else
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ModifyAddressInServiceInstance -\n"
|
||
"ldap_modify_s() failed with error code: 0%x\n",
|
||
status ));
|
||
DNSDBG( TRACE, (
|
||
"ERROR: %d on CSADDR ldap_modify_s() for %S\n"
|
||
"\tfAdd = %d\n",
|
||
status,
|
||
pwsDn,
|
||
fAdd ));
|
||
status = WSAEFAULT;
|
||
}
|
||
}
|
||
|
||
|
||
Done:
|
||
|
||
FREE_HEAP( pcsaddrBerval );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave ModifyAddressInServiceInstance() => %d\n",
|
||
status ));
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
ExtractCsaddrFromBerval(
|
||
OUT PCSADDR_INFO pCsAddr,
|
||
IN PLDAP_BERVAL pBerval,
|
||
IN DWORD NumberOfProtocols,
|
||
IN PAFPROTOCOLS pafpProtocols
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Extract CSADDR from berval, and validate it matches
|
||
desired protocol.
|
||
|
||
Arguments:
|
||
|
||
pCsAddr -- ptr to CSADDR buffer to write
|
||
|
||
pBerval -- ptr to berval
|
||
|
||
NumberOfProtocols -- number of protocols in protocol array
|
||
|
||
pafpProtocols -- protocol array
|
||
|
||
Return Value:
|
||
|
||
TRUE if valid CSADDR of desired protocol.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
PCSADDR_BERVAL pcsaBval;
|
||
PCHAR pend;
|
||
DWORD iter;
|
||
BOOL retval = FALSE;
|
||
INT lenLocal;
|
||
INT lenRemote;
|
||
PSOCKADDR psaLocal;
|
||
PSOCKADDR psaRemote;
|
||
|
||
DNSDBG( TRACE, (
|
||
"ExtractCsaddrFromBerval()\n"
|
||
"\tpCsaddr OUT = %p\n"
|
||
"\tpBerval = %p\n"
|
||
"\tProto array = %p\n",
|
||
pCsAddr,
|
||
pBerval,
|
||
pafpProtocols ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_AfProtocolsArray(
|
||
"\tProtocol array:",
|
||
pafpProtocols,
|
||
NumberOfProtocols );
|
||
}
|
||
|
||
//
|
||
// unpack
|
||
// - verify csaddr has both sockaddrs within berval
|
||
// - unpack into real CSADDR, note we set the pointers
|
||
// but do NOT copy the sockaddrs
|
||
//
|
||
// note: we can't directly use the CSADDR_BERVAL because it is
|
||
// not a CSADDR in 64-bit
|
||
//
|
||
// note: perhaps should get the family fields out for test below
|
||
// with UNALIGNED copy; but as long as future sockaddrs are
|
||
// fixed, then their size will always be WORD aligned; since
|
||
// we unpack as vanilla SOCKADDR which only assumes WORD
|
||
// alignment we're ok; just need to make sure don't write
|
||
// odd byte count
|
||
//
|
||
|
||
pcsaBval = (PCSADDR_BERVAL) pBerval->bv_val;
|
||
pend = (PBYTE)pcsaBval + pBerval->bv_len;
|
||
|
||
// unpack local sockaddr info
|
||
|
||
psaLocal = NULL;
|
||
lenLocal = pcsaBval->LocalLength;
|
||
|
||
if ( lenLocal )
|
||
{
|
||
psaLocal = (PSOCKADDR) (pcsaBval + 1);
|
||
if ( lenLocal < 0 ||
|
||
(PBYTE)psaLocal + (DWORD)lenLocal > pend )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
// unpack remote sockaddr info
|
||
|
||
psaRemote = NULL;
|
||
lenRemote = pcsaBval->RemoteLength;
|
||
|
||
if ( lenRemote )
|
||
{
|
||
psaRemote = (PSOCKADDR) ((PBYTE)(pcsaBval + 1) + lenLocal);
|
||
if ( lenRemote < 0 ||
|
||
(PBYTE)psaRemote + (DWORD)lenRemote > pend )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
// fill in CSADDR fields
|
||
|
||
pCsAddr->LocalAddr.lpSockaddr = psaLocal;
|
||
pCsAddr->LocalAddr.iSockaddrLength = lenLocal;
|
||
pCsAddr->RemoteAddr.lpSockaddr = psaRemote;
|
||
pCsAddr->RemoteAddr.iSockaddrLength = lenRemote;
|
||
pCsAddr->iSocketType = pcsaBval->iSocketType;
|
||
pCsAddr->iProtocol = pcsaBval->iProtocol;
|
||
|
||
//
|
||
// if given protocols, sockaddr must match
|
||
//
|
||
|
||
retval = TRUE;
|
||
|
||
if ( pafpProtocols )
|
||
{
|
||
retval = FALSE;
|
||
|
||
for ( iter = 0; iter < NumberOfProtocols; iter++ )
|
||
{
|
||
INT proto = pafpProtocols[iter].iProtocol;
|
||
INT family = pafpProtocols[iter].iAddressFamily;
|
||
|
||
if ( proto == PF_UNSPEC ||
|
||
proto == pCsAddr->iProtocol )
|
||
{
|
||
if ( family == AF_UNSPEC ||
|
||
family == psaLocal->sa_family ||
|
||
family == psaRemote->sa_family )
|
||
{
|
||
retval = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Exit:
|
||
|
||
DNSDBG( TRACE, ( "Leave ExtractCsaddrFromBerval() => found = %d\n", retval ));
|
||
return retval;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Add routines
|
||
//
|
||
|
||
RNR_STATUS
|
||
AddServiceClass(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PGUID pServiceClassId,
|
||
IN PWSTR pwsClassName,
|
||
OUT PDN_ARRAY * ppDnArray OPTIONAL
|
||
)
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PWSTR pwsDn;
|
||
PWSTR stringArray[6];
|
||
PDN_ARRAY pdnArray = NULL;
|
||
|
||
// mod data
|
||
// - need up to four mods
|
||
// - three string
|
||
// - one berval
|
||
|
||
PLDAPMod modPtrArray[5];
|
||
LDAPMod modArray[4];
|
||
PWSTR modValues1[2];
|
||
PWSTR modValues2[2];
|
||
PWSTR modValues3[2];
|
||
PLDAP_BERVAL modBvalues1[2];
|
||
LDAP_BERVAL berval1;
|
||
PLDAPMod pmod;
|
||
DWORD index;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"AddServiceClass()\n"
|
||
"\tpRnr = %p\n"
|
||
"\tpClassGuid = %p\n"
|
||
"\tClassName = %S\n",
|
||
pRnrConnection,
|
||
pServiceClassId,
|
||
pwsClassName
|
||
));
|
||
|
||
//
|
||
// build DN for the ServiceClass object to be created
|
||
//
|
||
|
||
index = 0;
|
||
stringArray[index++] = FILTER_CN_EQUALS;
|
||
stringArray[index++] = pwsClassName;
|
||
stringArray[index++] = L",";
|
||
stringArray[index++] = pRnrConnection->WinsockServicesDN;
|
||
stringArray[index++] = NULL;
|
||
|
||
pwsDn = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pwsDn )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// build attributes for new service class
|
||
// - CN
|
||
// - ServiceClassName
|
||
// - ObjectClass
|
||
// - ServiceClassId (GUID)
|
||
//
|
||
|
||
pmod = modArray;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = COMMON_NAME;
|
||
pmod->mod_values = modValues1;
|
||
modValues1[0] = pwsClassName;
|
||
modValues1[1] = NULL;
|
||
modPtrArray[0] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = SERVICE_CLASS_NAME;
|
||
pmod->mod_values = modValues2;
|
||
modValues2[0] = pwsClassName;
|
||
modValues2[1] = NULL;
|
||
modPtrArray[1] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = OBJECT_CLASS;
|
||
pmod->mod_values = modValues3;
|
||
modValues3[0] = SERVICE_CLASS;
|
||
modValues3[1] = NULL;
|
||
modPtrArray[2] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||
pmod->mod_type = SERVICE_CLASS_ID;
|
||
pmod->mod_bvalues = modBvalues1;
|
||
modBvalues1[0] = & berval1;
|
||
modBvalues1[1] = NULL;
|
||
berval1.bv_len = sizeof(GUID);
|
||
berval1.bv_val = (LPBYTE) pServiceClassId;
|
||
modPtrArray[3] = pmod++;
|
||
|
||
modPtrArray[4] = NULL;
|
||
|
||
|
||
//
|
||
// add the service class
|
||
//
|
||
|
||
if ( !GetRecurseLock("AddServiceClass") )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
status = ldap_add_s(
|
||
pRnrConnection->pLdapServer,
|
||
pwsDn,
|
||
modPtrArray );
|
||
|
||
if ( !ReleaseRecurseLock("AddServiceClass") )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
if ( status != NO_ERROR )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!AddServiceClass -\n"
|
||
"ldap_add_s() failed with error code: 0%x\n", status ));
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// create DN array for added service class
|
||
//
|
||
// DCR: do we need DN or just service
|
||
//
|
||
|
||
if ( ppDnArray )
|
||
{
|
||
pdnArray = AllocDnArray( 1 );
|
||
if ( !pdnArray )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
pdnArray->Strings[0] = pwsDn;
|
||
*ppDnArray = pdnArray;
|
||
pwsDn = NULL;
|
||
}
|
||
|
||
Exit:
|
||
|
||
FREE_HEAP( pwsDn );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leaving AddServiceClass() => %d\n",
|
||
status ));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
AddClassInfoToServiceClass(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsServiceClassDN,
|
||
IN PWSANSCLASSINFO pNSClassInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add class info to a service class object.
|
||
|
||
This is helper routine for AddServiceInstance().
|
||
|
||
Arguments:
|
||
|
||
pRnrConnection -- Rnr blob
|
||
|
||
pwsServiceClassDN -- DN for service class being added
|
||
|
||
pNSClassInfo -- class info to add
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
LDAPMod * modPtrArray[2];
|
||
LDAPMod mod;
|
||
PLDAP_BERVAL modBValues[2];
|
||
LDAP_BERVAL berval;
|
||
DWORD blobSize;
|
||
DWORD nameLen;
|
||
PCLASSINFO_BERVAL pblob;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"AddClassInfoToServiceClass()\n"
|
||
"\tpRnr = %p\n"
|
||
"\tServiceClassDN = %S\n"
|
||
"\tpClassInfo = %p\n",
|
||
pRnrConnection,
|
||
pwsServiceClassDN,
|
||
pNSClassInfo ));
|
||
|
||
//
|
||
// build ClassInfo as berval
|
||
//
|
||
// - not directly using WSANSCLASSINFO as it contains
|
||
// pointers making length vary 32\64-bit
|
||
// - to handle this, offsets to name and value fields are
|
||
// encoded in DWORD fields where ptrs would be in WSANSCLASSINFO
|
||
//
|
||
// - name immediately follows CLASSINFO
|
||
// - value follows name (rounded to DWORD)
|
||
//
|
||
|
||
nameLen = (wcslen( pNSClassInfo->lpszName ) + 1) * sizeof(WCHAR);
|
||
nameLen = ROUND_UP_COUNT( nameLen, ALIGN_DWORD );
|
||
|
||
blobSize = sizeof(CLASSINFO_BERVAL)
|
||
+ nameLen
|
||
+ pNSClassInfo->dwValueSize;
|
||
|
||
pblob = (PCLASSINFO_BERVAL) ALLOC_HEAP_ZERO( blobSize );
|
||
if ( !pblob )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
pblob->dwNameSpace = pNSClassInfo->dwNameSpace;
|
||
pblob->dwValueType = pNSClassInfo->dwValueType;
|
||
pblob->dwValueSize = pNSClassInfo->dwValueSize;
|
||
pblob->NameOffset = sizeof(CLASSINFO_BERVAL);
|
||
pblob->ValueOffset = sizeof(CLASSINFO_BERVAL) + nameLen;
|
||
|
||
wcscpy(
|
||
(PWSTR) ((PBYTE)pblob + pblob->NameOffset),
|
||
(PWSTR) pNSClassInfo->lpszName );
|
||
|
||
RtlCopyMemory(
|
||
(PBYTE)pblob + pblob->ValueOffset,
|
||
pNSClassInfo->lpValue,
|
||
pNSClassInfo->dwValueSize );
|
||
|
||
//
|
||
// ldap mod to add service class info
|
||
//
|
||
|
||
mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||
mod.mod_type = SERVICE_CLASS_INFO;
|
||
mod.mod_bvalues = modBValues;
|
||
modBValues[0] = & berval;
|
||
modBValues[1] = NULL;
|
||
berval.bv_len = blobSize;
|
||
berval.bv_val = (PCHAR) pblob;
|
||
|
||
modPtrArray[0] = &mod;
|
||
modPtrArray[1] = NULL;
|
||
|
||
//
|
||
// add the class info to the service class
|
||
//
|
||
|
||
if ( !GetRecurseLock("AddClassInfoToServiceClass") )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
status = ldap_modify_s(
|
||
pRnrConnection->pLdapServer,
|
||
pwsServiceClassDN,
|
||
modPtrArray );
|
||
|
||
if ( !ReleaseRecurseLock("AddClassInfoToServiceClass") )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// modify failed?
|
||
// - treat already exits as success
|
||
//
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
if ( status == LDAP_ATTRIBUTE_OR_VALUE_EXISTS )
|
||
{
|
||
status = NO_ERROR;
|
||
goto Exit;
|
||
}
|
||
WINRNR_PRINT((
|
||
"WINRNR!AddClassInfoToServiceClass -\n"
|
||
"ldap_modify_s() failed with error code: 0%x\n",
|
||
status ));
|
||
status = WSAEFAULT;
|
||
}
|
||
|
||
Exit:
|
||
|
||
FREE_HEAP( pblob );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave AddClassInfoToServiceClass() => %d\n",
|
||
status ));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
AddServiceInstance(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsServiceName,
|
||
IN PGUID pServiceClassId,
|
||
IN PWSAVERSION pVersion, OPTIONAL
|
||
IN PWSTR pwsComment, OPTIONAL
|
||
OUT PDN_ARRAY * ppDnArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add a service to the directory.
|
||
|
||
Arguments:
|
||
|
||
pRnrConnection -- Rnr blob
|
||
|
||
pwsServiceName -- name of service being added
|
||
|
||
pServiceClassId -- class GUID
|
||
|
||
pVersion -- version data
|
||
|
||
pwsComment -- comment data
|
||
|
||
//
|
||
// DCR: should we just pass back name?
|
||
//
|
||
|
||
ppDnArray -- addr to receive DN array
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
|
||
// mod data
|
||
// - need up to six mods
|
||
// - four string
|
||
// - two berval
|
||
|
||
LDAPMod * modPtrArray[7];
|
||
LDAPMod modArray[6];
|
||
PWSTR modValues1[2];
|
||
PWSTR modValues2[2];
|
||
PWSTR modValues3[2];
|
||
PWSTR modValues4[2];
|
||
PLDAP_BERVAL modBvalues1[2];
|
||
PLDAP_BERVAL modBvalues2[2];
|
||
LDAP_BERVAL berval1;
|
||
LDAP_BERVAL berval2;
|
||
|
||
PLDAPMod pmod;
|
||
DWORD modIndex;
|
||
BOOL fuseDN;
|
||
PWSTR pwsRdn = NULL;
|
||
PWSTR psearchContextAllocated = NULL;
|
||
PWSTR pcontextDN = NULL;
|
||
DWORD contextLen;
|
||
PWSTR pnameService = NULL;
|
||
PWSTR pwsDN = NULL;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
PWSTR stringArray[6];
|
||
DWORD index;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"AddServiceInstance()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tServiceName = %S\n"
|
||
"\tClass GUID = %p\n"
|
||
"\tpVersion = %p\n"
|
||
"\tComment = %S\n"
|
||
"\tppArray OUT = %p\n",
|
||
pRnrConnection,
|
||
pwsServiceName,
|
||
pServiceClassId,
|
||
pVersion,
|
||
pwsComment,
|
||
ppDnArray ));
|
||
|
||
//
|
||
// determine service instance name
|
||
//
|
||
|
||
fuseDN = IsNameADn(
|
||
pwsServiceName,
|
||
& pwsRdn,
|
||
& psearchContextAllocated
|
||
);
|
||
if ( fuseDN )
|
||
{
|
||
pnameService = pwsRdn;
|
||
}
|
||
else
|
||
{
|
||
pnameService = pwsServiceName;
|
||
}
|
||
|
||
//
|
||
// build up an object DN for the ServiceClass object to be created.
|
||
// - if no context found from passed in name, append
|
||
// WinsockServices container
|
||
|
||
pcontextDN = psearchContextAllocated;
|
||
if ( !pcontextDN )
|
||
{
|
||
pcontextDN = pRnrConnection->WinsockServicesDN;
|
||
}
|
||
|
||
index = 0;
|
||
stringArray[index++] = FILTER_CN_EQUALS;
|
||
stringArray[index++] = pnameService;
|
||
stringArray[index++] = L",";
|
||
stringArray[index++] = pcontextDN;
|
||
stringArray[index++] = NULL;
|
||
|
||
pwsDN = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pwsDN )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// fill out attribute list to define new ServiceClass object
|
||
// - need to have CN, ObjectClass, and ServiceClassId
|
||
//
|
||
|
||
pmod = modArray;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = COMMON_NAME;
|
||
pmod->mod_values = modValues1;
|
||
modValues1[0] = pnameService;
|
||
modValues1[1] = NULL;
|
||
modPtrArray[0] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = SERVICE_INSTANCE_NAME;
|
||
pmod->mod_values = modValues2;
|
||
modValues2[0] = pnameService;
|
||
modValues2[1] = NULL;
|
||
modPtrArray[1] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = OBJECT_CLASS;
|
||
pmod->mod_values = modValues3;
|
||
modValues3[0] = SERVICE_INSTANCE;
|
||
modValues3[1] = NULL;
|
||
modPtrArray[2] = pmod++;
|
||
|
||
pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||
pmod->mod_type = SERVICE_CLASS_ID;
|
||
pmod->mod_bvalues = modBvalues1;
|
||
modBvalues1[0] = & berval1;
|
||
modBvalues1[1] = NULL;
|
||
berval1.bv_len = sizeof(GUID);
|
||
berval1.bv_val = (LPBYTE) pServiceClassId;
|
||
modPtrArray[3] = pmod++;
|
||
|
||
//
|
||
// write optional attributes
|
||
//
|
||
|
||
modIndex = 4;
|
||
|
||
if ( pVersion )
|
||
{
|
||
pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
|
||
pmod->mod_type = SERVICE_VERSION;
|
||
pmod->mod_bvalues = modBvalues2;
|
||
modBvalues2[0] = & berval2;
|
||
modBvalues2[1] = NULL;
|
||
berval2.bv_len = sizeof(WSAVERSION);
|
||
berval2.bv_val = (PBYTE) pVersion;
|
||
|
||
modPtrArray[ modIndex++ ] = pmod++;
|
||
}
|
||
|
||
if ( pwsComment )
|
||
{
|
||
pmod->mod_op = LDAP_MOD_ADD;
|
||
pmod->mod_type = SERVICE_COMMENT;
|
||
pmod->mod_values = modValues4;
|
||
modValues4[0] = pwsComment;
|
||
modValues4[1] = NULL;
|
||
|
||
modPtrArray[ modIndex++ ] = pmod++;
|
||
}
|
||
|
||
modPtrArray[ modIndex ] = NULL;
|
||
|
||
//
|
||
// Set thread table to (1) to prevent possible recursion in ldap_ call.
|
||
//
|
||
|
||
if ( !GetRecurseLock( "AddServiceInstance" ) )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
status = ldap_add_s(
|
||
pRnrConnection->pLdapServer,
|
||
pwsDN,
|
||
modPtrArray );
|
||
|
||
if ( status == LDAP_ALREADY_EXISTS )
|
||
{
|
||
status = ldap_modify_s(
|
||
pRnrConnection->pLdapServer,
|
||
pwsDN,
|
||
modPtrArray );
|
||
}
|
||
|
||
if ( !ReleaseRecurseLock( "AddServiceInstance" ) )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"AddServiceInstance - ldap_modify\\add failed %d (%0x)\n",
|
||
status, status ));
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
// create out DN array -- if requested
|
||
|
||
pdnArray = AllocDnArray( 1 );
|
||
if ( !pdnArray )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
pdnArray->Strings[0] = pwsDN;
|
||
|
||
|
||
Exit:
|
||
|
||
*ppDnArray = pdnArray;
|
||
|
||
FREE_HEAP( pwsRdn );
|
||
FREE_HEAP( psearchContextAllocated );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
FREE_HEAP( pwsDN );
|
||
DNS_ASSERT( pdnArray == NULL );
|
||
}
|
||
|
||
DNSDBG( TRACE, ( "Leave AddServiceInstance()\n" ));
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
GetAddressCountFromServiceInstance(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsDN,
|
||
OUT PDWORD pdwAddressCount
|
||
)
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap = pRnrConnection->pLdapServer;
|
||
LDAPMessage * results = NULL;
|
||
DWORD count;
|
||
DWORD countAddrs = 0;
|
||
LDAPMessage * object;
|
||
PLDAP_BERVAL * ppbval = NULL;
|
||
PWSTR attrs[3] = { SERVICE_CLASS_NAME,
|
||
WINSOCK_ADDRESSES,
|
||
NULL };
|
||
|
||
DNSDBG( TRACE, (
|
||
"GetAddressCountFromServiceInstance()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tDN = %S\n",
|
||
pRnrConnection,
|
||
pwsDN ));
|
||
|
||
//
|
||
// search
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"GetAddressCountFromServiceInstance",
|
||
FALSE,
|
||
pldap,
|
||
pwsDN,
|
||
LDAP_SCOPE_BASE,
|
||
FILTER_OBJECT_CLASS_SERVICE_INSTANCE,
|
||
attrs,
|
||
&results );
|
||
|
||
if ( status && !results )
|
||
{
|
||
// ldap_search_s was not successful, return known error code.
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// search completed successfully -- count results
|
||
//
|
||
|
||
count = ldap_count_entries( pldap, results );
|
||
if ( count == 0 )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!GetAddressCountFromServiceInstance -\n"
|
||
"ldap_count_entries() failed\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// We performed a search with flag LDAP_OBJECT_BASE, we should have
|
||
// only 1 entry returned for count.
|
||
//
|
||
// ASSERT( count == 1 );
|
||
|
||
//
|
||
// Parse the results.
|
||
//
|
||
|
||
object = ldap_first_entry( pldap, results );
|
||
if ( !object )
|
||
{
|
||
WINRNR_PRINT(( "WINRNR!GetAddressCountFromServiceInstance -\n" ));
|
||
WINRNR_PRINT(( "ldap_first_entry() failed\n" ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// Read the WinsockAddresses (if any) and get the count value.
|
||
// Remember these are BER values (Octet strings).
|
||
//
|
||
|
||
ppbval = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
WINSOCK_ADDRESSES );
|
||
if ( !ppbval )
|
||
{
|
||
// Attribute not present, return address count of zero.
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: GetAddressCountFromServiceInstance()\n"
|
||
"\tldap_get_values_len() failed\n" ));
|
||
status = NO_ERROR;
|
||
goto Exit;
|
||
}
|
||
|
||
countAddrs = ldap_count_values_len( ppbval );
|
||
ldap_value_free_len( ppbval );
|
||
status = NO_ERROR;
|
||
|
||
Exit:
|
||
|
||
ldap_msgfree( results );
|
||
|
||
// count out param
|
||
|
||
*pdwAddressCount = countAddrs;
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
FindServiceClass(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsServiceClassName, OPTIONAL
|
||
IN PGUID pServiceClassId,
|
||
OUT PDWORD pdwDnArrayCount, OPTIONAL
|
||
OUT PDN_ARRAY * ppDnArray OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find service class in directory.
|
||
|
||
Arguments:
|
||
|
||
pRnrConnection -- RnR connection
|
||
|
||
pwsServiceClassName -- service class name
|
||
|
||
pServiceClassId -- class GUID
|
||
|
||
pdwArrayCount -- addr to receive count
|
||
|
||
ppDnArray -- addr to recv DN array
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap = pRnrConnection->pLdapServer;
|
||
PWSTR pclassFilter = NULL;
|
||
PWSTR pfinalStr;
|
||
PWSTR pfilter = NULL;
|
||
LDAPMessage * presults = NULL;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
DWORD count;
|
||
LDAPMessage * pnext;
|
||
DWORD iter = 0;
|
||
DWORD index;
|
||
PWSTR stringArray[12];
|
||
PWSTR searchAttributes[2] = { COMMON_NAME, NULL };
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"FindServiceClass()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tClass Name = %S\n",
|
||
pRnrConnection,
|
||
pwsServiceClassName
|
||
));
|
||
|
||
//
|
||
// convert the GUID to a string for the search filter
|
||
//
|
||
|
||
pclassFilter = CreateFilterElement(
|
||
(PCHAR) pServiceClassId,
|
||
sizeof(GUID) );
|
||
if ( !pclassFilter )
|
||
{
|
||
return( ERROR_NO_MEMORY );
|
||
}
|
||
|
||
//
|
||
// build search filter
|
||
// class == ServiceClass
|
||
// AND
|
||
// CN == ServiceClassName
|
||
// OR
|
||
// serviceClass == ServiceClassGuid
|
||
//
|
||
// (&(OBJECT_CLASS=SERVICE_CLASS)
|
||
// (|(CN=xxxx)
|
||
// (SERVICE_CLASS_ID=yyyy)))
|
||
//
|
||
|
||
index = 0;
|
||
stringArray[index++] = L"(&";
|
||
stringArray[index++] = FILTER_OBJECT_CLASS_SERVICE_CLASS;
|
||
|
||
pfinalStr = L"))";
|
||
|
||
if ( pwsServiceClassName )
|
||
{
|
||
stringArray[index++] = L"(|(";
|
||
stringArray[index++] = FILTER_CN_EQUALS;
|
||
stringArray[index++] = pwsServiceClassName;
|
||
stringArray[index++] = L")";
|
||
|
||
pfinalStr = L")))";
|
||
}
|
||
stringArray[index++] = FILTER_PAREN_SERVICE_CLASS_ID_EQUALS;
|
||
stringArray[index++] = pclassFilter;
|
||
stringArray[index++] = pfinalStr;
|
||
stringArray[index] = NULL;
|
||
|
||
pfilter = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pfilter )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// search the default Winsock Services container
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"FindServiceClass",
|
||
FALSE,
|
||
pldap,
|
||
pRnrConnection->WinsockServicesDN,
|
||
LDAP_SCOPE_ONELEVEL,
|
||
pfilter,
|
||
searchAttributes,
|
||
&presults );
|
||
|
||
//
|
||
// if search unsuccessful, bail
|
||
//
|
||
|
||
if ( status != NO_ERROR && !presults )
|
||
{
|
||
//status = WSAEFAULT; // DCR: wrong error code
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// build DN array from results
|
||
//
|
||
|
||
status = BuildDnArrayFromResults(
|
||
pldap,
|
||
presults,
|
||
pdwDnArrayCount,
|
||
ppDnArray );
|
||
|
||
Exit:
|
||
|
||
ldap_msgfree( presults );
|
||
FREE_HEAP( pclassFilter );
|
||
FREE_HEAP( pfilter );
|
||
|
||
// set results OUT param
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
if ( ppDnArray )
|
||
{
|
||
*ppDnArray = NULL;
|
||
}
|
||
if ( pdwDnArrayCount )
|
||
{
|
||
*pdwDnArrayCount = 0;
|
||
}
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave FindServiceClass() => %d\n"
|
||
"\tcount = %d\n"
|
||
"\tpdnArray = %p\n"
|
||
"\tfirst DN = %S\n",
|
||
status,
|
||
pdwDnArrayCount ? *pdwDnArrayCount : 0,
|
||
(ppDnArray && *ppDnArray)
|
||
? *ppDnArray
|
||
: NULL,
|
||
(ppDnArray && *ppDnArray)
|
||
? (*ppDnArray)->Strings[0]
|
||
: NULL
|
||
));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
FindServiceInstance(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsServiceName OPTIONAL,
|
||
IN PGUID pServiceClassId OPTIONAL,
|
||
IN PWSAVERSION pVersion OPTIONAL,
|
||
IN PWSTR pwsContext OPTIONAL,
|
||
IN BOOL fPerformDeepSearch,
|
||
OUT PDWORD pdwDnArrayCount,
|
||
OUT PDN_ARRAY * ppDnArray OPTIONAL
|
||
)
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap = pRnrConnection->pLdapServer;
|
||
PWSTR pnameService;
|
||
PWSTR pwsRdn = NULL;
|
||
PWSTR psearchContextAllocated = NULL;
|
||
PWSTR pserviceContext;
|
||
PWSTR pclassFilter = NULL;
|
||
PWSTR pversionFilter = NULL;
|
||
PWSTR pfilter = NULL;
|
||
LDAPMessage * presults = NULL;
|
||
BOOL fuseDN;
|
||
DWORD index;
|
||
PWSTR psearchContext = NULL;
|
||
PWSTR stringArray[15];
|
||
PWSTR searchAttributes[2] = { COMMON_NAME, NULL };
|
||
|
||
DNSDBG( TRACE, (
|
||
"FindServiceInstance()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tServiceName = %S\n"
|
||
"\tpClassGUID = %p\n"
|
||
"\tpVersion = %p\n"
|
||
"\tpwsContext = %S\n"
|
||
"\tpCount OUT = %p\n"
|
||
"\tpDnArray OUT = %p\n",
|
||
pRnrConnection,
|
||
pwsServiceName,
|
||
pServiceClassId,
|
||
pVersion,
|
||
pwsContext,
|
||
pdwDnArrayCount,
|
||
ppDnArray
|
||
));
|
||
|
||
//
|
||
// get service name
|
||
// - if given name
|
||
// - get DN or is DN
|
||
// - else
|
||
// - search for any service "*"
|
||
//
|
||
|
||
pnameService = L"*";
|
||
|
||
if ( pwsServiceName )
|
||
{
|
||
// note, this can allocate pwsRdn and psearchContext
|
||
|
||
fuseDN = IsNameADn(
|
||
pwsServiceName,
|
||
& pwsRdn,
|
||
& psearchContextAllocated );
|
||
if ( fuseDN )
|
||
{
|
||
pnameService = pwsRdn;
|
||
}
|
||
else
|
||
{
|
||
pnameService = pwsServiceName;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if service class specified make filter
|
||
//
|
||
|
||
if ( pServiceClassId )
|
||
{
|
||
pclassFilter = CreateFilterElement(
|
||
(PCHAR) pServiceClassId,
|
||
sizeof(GUID) );
|
||
if ( !pclassFilter )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// version specified -- make filter
|
||
//
|
||
|
||
if ( pVersion )
|
||
{
|
||
pversionFilter = CreateFilterElement(
|
||
(PCHAR) pVersion,
|
||
sizeof(WSAVERSION) );
|
||
if ( !pversionFilter )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// context
|
||
// - use context found above or
|
||
// - passed in context or
|
||
// - WinsockServices DN
|
||
//
|
||
|
||
if ( psearchContextAllocated )
|
||
{
|
||
pserviceContext = psearchContextAllocated;
|
||
}
|
||
else if ( pwsContext )
|
||
{
|
||
pserviceContext = pwsContext;
|
||
}
|
||
else
|
||
{
|
||
pserviceContext = pRnrConnection->WinsockServicesDN;
|
||
}
|
||
|
||
//
|
||
// build filter
|
||
// - objects of class ServiceClass
|
||
// - with common name equal to pServiceInstanceName
|
||
//
|
||
// (&(objectClass=serviceInstance)
|
||
// (CN=pnameService)
|
||
// (serviceClassId=pclassFilter)
|
||
// (serviceVersion=pversionFilter))
|
||
//
|
||
|
||
index = 0;
|
||
stringArray[index++] = L"(&";
|
||
stringArray[index++] = FILTER_OBJECT_CLASS_SERVICE_INSTANCE;
|
||
stringArray[index++] = FILTER_PAREN_CN_EQUALS;
|
||
stringArray[index++] = pnameService;
|
||
stringArray[index++] = L")";
|
||
|
||
if ( pServiceClassId )
|
||
{
|
||
stringArray[index++] = FILTER_PAREN_SERVICE_CLASS_ID_EQUALS;
|
||
stringArray[index++] = pclassFilter;
|
||
stringArray[index++] = L")";
|
||
}
|
||
if ( pVersion )
|
||
{
|
||
stringArray[index++] = FILTER_PAREN_SERVICE_VERSION_EQUALS;
|
||
stringArray[index++] = pversionFilter;
|
||
stringArray[index++] = L")";
|
||
}
|
||
stringArray[index++] = L")";
|
||
stringArray[index] = NULL;
|
||
|
||
pfilter = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pfilter )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// search
|
||
// - in pserviceContext defined above
|
||
//
|
||
// DCR: - We may want to perform all of these searches against the
|
||
// Global Catalog server.
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"FindServiceInstance",
|
||
FALSE,
|
||
pldap,
|
||
pserviceContext,
|
||
fPerformDeepSearch
|
||
? LDAP_SCOPE_SUBTREE
|
||
: LDAP_SCOPE_ONELEVEL,
|
||
pfilter,
|
||
searchAttributes,
|
||
&presults );
|
||
|
||
if ( status && !presults )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// build DN array from results
|
||
//
|
||
|
||
status = BuildDnArrayFromResults(
|
||
pldap,
|
||
presults,
|
||
pdwDnArrayCount,
|
||
ppDnArray );
|
||
|
||
Exit:
|
||
|
||
ldap_msgfree( presults );
|
||
FREE_HEAP( pwsRdn );
|
||
FREE_HEAP( psearchContextAllocated );
|
||
FREE_HEAP( pclassFilter );
|
||
FREE_HEAP( pversionFilter );
|
||
FREE_HEAP( pfilter );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
if ( pdwDnArrayCount )
|
||
{
|
||
*pdwDnArrayCount = 0;
|
||
}
|
||
if ( ppDnArray )
|
||
{
|
||
*ppDnArray = NULL;
|
||
}
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave FindServiceInstance() => %d\n"
|
||
"\tpDnArray OUT = %p\n"
|
||
"\tfirst DN = %S\n",
|
||
status,
|
||
(ppDnArray && *ppDnArray)
|
||
? *ppDnArray
|
||
: NULL,
|
||
(ppDnArray && *ppDnArray)
|
||
? (*ppDnArray)->Strings[0]
|
||
: NULL
|
||
));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
FindSubordinateContainers(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsServiceName OPTIONAL,
|
||
IN PWSTR pwsContext OPTIONAL,
|
||
IN BOOL fPerformDeepSearch,
|
||
OUT PDN_ARRAY * ppDnArray OPTIONAL
|
||
)
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap = pRnrConnection->pLdapServer;
|
||
PWSTR pnameService;
|
||
PWSTR pwsRdn = NULL;
|
||
PWSTR psearchContextAllocated = NULL;
|
||
PWSTR psearchContext;
|
||
PWSTR pfilter = NULL;
|
||
DWORD index;
|
||
BOOL fuseDN;
|
||
PWSTR stringArray[8];
|
||
LDAPMessage * presults = NULL;
|
||
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"FindSubordinateContainers()\n"
|
||
"\tpRnrCon = %p\n"
|
||
"\tServiceName = %S\n"
|
||
"\tpwsContext = %S\n"
|
||
"\tfDeepSearch = %d\n"
|
||
"\tpDnArray OUT = %p\n",
|
||
pRnrConnection,
|
||
pwsServiceName,
|
||
pwsContext,
|
||
fPerformDeepSearch,
|
||
ppDnArray
|
||
));
|
||
|
||
//
|
||
// get service name
|
||
// - if given name
|
||
// - get DN or is DN
|
||
// - else
|
||
// - search for any service "*"
|
||
//
|
||
|
||
pnameService = L"*";
|
||
|
||
if ( pwsServiceName )
|
||
{
|
||
// note, this can allocate pwsRdn and psearchContext
|
||
|
||
fuseDN = IsNameADn(
|
||
pwsServiceName,
|
||
& pwsRdn,
|
||
& psearchContextAllocated );
|
||
if ( fuseDN )
|
||
{
|
||
pnameService = pwsRdn;
|
||
}
|
||
else
|
||
{
|
||
pnameService = pwsServiceName;
|
||
}
|
||
}
|
||
|
||
//
|
||
// build filter
|
||
// - objects of class NTDS container
|
||
// - with common name equal to pServiceInstanceName
|
||
//
|
||
// (&(OBJECT_CLASS=NTDS_CONTAINER)
|
||
// (COMMON_NAME=ServiceName))
|
||
//
|
||
|
||
index = 0;
|
||
stringArray[index++] = L"(&";
|
||
stringArray[index++] = FILTER_OBJECT_CLASS_NTDS_CONTAINER;
|
||
stringArray[index++] = FILTER_PAREN_CN_EQUALS;
|
||
stringArray[index++] = pnameService;
|
||
stringArray[index++] = L"))";
|
||
stringArray[index] = NULL;
|
||
|
||
pfilter = Dns_CreateConcatenatedString_W( stringArray );
|
||
if ( !pfilter )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// search context
|
||
// - use allocated from passed in DN or
|
||
// - passed in context
|
||
// - special context to indicated DomainDN or
|
||
// - winsock services DN
|
||
//
|
||
|
||
if ( psearchContextAllocated )
|
||
{
|
||
psearchContext = psearchContextAllocated;
|
||
}
|
||
else if ( pwsContext )
|
||
{
|
||
if ( wcscmp( pwsContext, L"\\" ) == 0 )
|
||
{
|
||
psearchContext = pRnrConnection->DomainDN;
|
||
}
|
||
else
|
||
{
|
||
psearchContext = pwsContext;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
psearchContext = pRnrConnection->WinsockServicesDN;
|
||
}
|
||
|
||
//
|
||
// search
|
||
// - in pserviceContext defined above
|
||
//
|
||
// DCR: - We may want to perform all of these searches against the
|
||
// Global Catalog server.
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"FindSubordinateContainer",
|
||
FALSE, // no locked
|
||
pldap,
|
||
psearchContext,
|
||
fPerformDeepSearch
|
||
? LDAP_SCOPE_SUBTREE
|
||
: LDAP_SCOPE_ONELEVEL,
|
||
pfilter,
|
||
NULL, // no attribute selection
|
||
&presults );
|
||
|
||
if ( status && !presults )
|
||
{
|
||
status = WSAEFAULT;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// build DN array from results
|
||
//
|
||
|
||
status = BuildDnArrayFromResults(
|
||
pldap,
|
||
presults,
|
||
NULL,
|
||
ppDnArray );
|
||
|
||
Exit:
|
||
|
||
ldap_msgfree( presults );
|
||
FREE_HEAP( pfilter );
|
||
FREE_HEAP( pwsRdn );
|
||
FREE_HEAP( psearchContextAllocated );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave FindSubordinateContainer() => %d\n"
|
||
"\tpDnArray OUT = %p\n",
|
||
"\tfirst DN = %S\n",
|
||
status,
|
||
(ppDnArray && *ppDnArray)
|
||
? *ppDnArray
|
||
: NULL,
|
||
(ppDnArray && *ppDnArray)
|
||
? (*ppDnArray)->Strings[0]
|
||
: NULL
|
||
));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Read routines
|
||
//
|
||
// These routines read directory data and write into
|
||
// RnR buffer. They are the working functions for
|
||
// RnR "Get" routines.
|
||
//
|
||
|
||
RNR_STATUS
|
||
ReadServiceClass(
|
||
IN PRNR_CONNECTION pRnrConnection,
|
||
IN PWSTR pwsDN,
|
||
IN OUT PDWORD pdwBufSize,
|
||
IN OUT PWSASERVICECLASSINFOW pServiceClassInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return service class info to caller.
|
||
|
||
Helper routine for NTDS_GetServiceClassInfo().
|
||
Read service class info for given DN and return
|
||
service class info buffer to caller.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
WSAEFAULT if buffer too small.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap = pRnrConnection->pLdapServer;
|
||
LDAPMessage * presults = NULL;
|
||
DWORD count;
|
||
DWORD iter;
|
||
LDAPMessage * object;
|
||
PWSTR * ppvalue = NULL;
|
||
PLDAP_BERVAL * ppberVal = NULL;
|
||
FLATBUF flatbuf;
|
||
PWSANSCLASSINFOW pbufClassInfoArray;
|
||
PBYTE pbuf;
|
||
PWSTR pbufString;
|
||
PWSTR attrs[4] = {
|
||
SERVICE_CLASS_INFO,
|
||
SERVICE_CLASS_ID,
|
||
SERVICE_CLASS_NAME,
|
||
NULL };
|
||
|
||
DNSDBG( TRACE, (
|
||
"ReadServiceClass()\n"
|
||
"\tprnr = %p\n"
|
||
"\tDN = %S\n"
|
||
"\tbuf size = %p (%d)\n"
|
||
"\tbuffer = %p\n",
|
||
pRnrConnection,
|
||
pwsDN,
|
||
pdwBufSize,
|
||
pdwBufSize ? *pdwBufSize : 0,
|
||
pServiceClassInfo ));
|
||
|
||
//
|
||
// create flat buffer for building response
|
||
// - starts immediately after service class info struct itself
|
||
//
|
||
|
||
ASSERT( pServiceClassInfo != NULL );
|
||
|
||
RtlZeroMemory(
|
||
(PBYTE) pServiceClassInfo,
|
||
*pdwBufSize );
|
||
|
||
FlatBuf_Init(
|
||
& flatbuf,
|
||
(LPBYTE) pServiceClassInfo + sizeof(WSASERVICECLASSINFOW),
|
||
(INT) *pdwBufSize - sizeof(WSASERVICECLASSINFOW)
|
||
);
|
||
|
||
//
|
||
// search
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"ReadServiceClass",
|
||
FALSE, // no locked
|
||
pldap,
|
||
pwsDN,
|
||
LDAP_SCOPE_BASE,
|
||
FILTER_OBJECT_CLASS_SERVICE_CLASS,
|
||
attrs,
|
||
&presults );
|
||
|
||
if ( status && !presults )
|
||
{
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// search completed
|
||
// - should have found just one service class
|
||
//
|
||
|
||
count = ldap_count_entries( pldap, presults );
|
||
if ( count == 0 )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadServiceClass -\n"
|
||
"ldap_count_entries() failed\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
DNS_ASSERT( count == 1 );
|
||
|
||
object = ldap_first_entry(
|
||
pldap,
|
||
presults );
|
||
if ( !object )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadServiceClass -\n"
|
||
"ldap_first_entry() failed\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// read the ServiceClassInfo(s) from bervals
|
||
// and write them to buffer
|
||
//
|
||
|
||
ppberVal = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
SERVICE_CLASS_INFO );
|
||
count = 0;
|
||
if ( ppberVal )
|
||
{
|
||
count = ldap_count_values_len( ppberVal );
|
||
}
|
||
pServiceClassInfo->dwCount = count;
|
||
|
||
// reserve space for class info array
|
||
|
||
pbufClassInfoArray = (PWSANSCLASSINFOW)
|
||
FlatBuf_Reserve(
|
||
& flatbuf,
|
||
count * sizeof(WSANSCLASSINFOW),
|
||
ALIGN_LPVOID
|
||
);
|
||
|
||
pServiceClassInfo->lpClassInfos = pbufClassInfoArray;
|
||
|
||
//
|
||
// copy each WSANSCLASSINFO we find
|
||
// - note that do not stop loop even if out of space
|
||
// continue for sizing purposes
|
||
//
|
||
|
||
for ( iter = 0; iter < count; iter++ )
|
||
{
|
||
PCLASSINFO_BERVAL pclassInfo;
|
||
PWSTR pname;
|
||
PBYTE pvalue;
|
||
PBYTE pdataEnd;
|
||
|
||
// recover WSANSCLASSINFO as structure
|
||
//
|
||
// WSANSCLASSINFO structures are stored as octect string in
|
||
// directory with offsets from structure start for pointer
|
||
// fields
|
||
//
|
||
// note: that the "pointer fields" are offsets in the
|
||
// structure and hence are NOT the size of pointers in 64-bit
|
||
// so we can NOT simply recover the structure and fixup
|
||
//
|
||
|
||
pclassInfo = (PCLASSINFO_BERVAL) ppberVal[iter]->bv_val;
|
||
pdataEnd = (PBYTE)pclassInfo + ppberVal[iter]->bv_len;
|
||
|
||
pvalue = ((PBYTE) pclassInfo + pclassInfo->ValueOffset);
|
||
pname = (PWSTR) ((PBYTE) pclassInfo + pclassInfo->NameOffset);
|
||
|
||
//
|
||
// validity check recovered data
|
||
// - name aligned
|
||
// - value within berval
|
||
// - name within berval
|
||
//
|
||
// DCR: explicit string validity\length check
|
||
//
|
||
|
||
if ( !POINTER_IS_ALIGNED( pname, ALIGN_WCHAR ) ||
|
||
pvalue < (PBYTE) (pclassInfo+1) ||
|
||
(pvalue + pclassInfo->dwValueSize) > pdataEnd ||
|
||
pname < (PWSTR) (pclassInfo+1) ||
|
||
pname >= (PWSTR) pdataEnd )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// copy NSCLASSINFO to buffer
|
||
// - flat copy of DWORD types and sizes
|
||
// - copy name string
|
||
// - copy value
|
||
|
||
pbufString = (PWSTR) FlatBuf_WriteString_W(
|
||
& flatbuf,
|
||
pname );
|
||
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
pvalue,
|
||
pclassInfo->dwValueSize,
|
||
0 // no alignment required
|
||
);
|
||
|
||
// write only if had space for NSCLASSINFO array above
|
||
|
||
if ( pbufClassInfoArray )
|
||
{
|
||
PWSANSCLASSINFO pbufClassInfo = &pbufClassInfoArray[iter];
|
||
|
||
pbufClassInfo->dwNameSpace = pclassInfo->dwNameSpace;
|
||
pbufClassInfo->dwValueType = pclassInfo->dwValueType;
|
||
pbufClassInfo->dwValueSize = pclassInfo->dwValueSize;
|
||
pbufClassInfo->lpszName = pbufString;
|
||
pbufClassInfo->lpValue = pbuf;
|
||
}
|
||
}
|
||
|
||
ldap_value_free_len( ppberVal );
|
||
ppberVal = NULL;
|
||
|
||
|
||
//
|
||
// Read the ServiceClassId and write it into buffer.
|
||
// Remember this is a BER value (Octet string).
|
||
//
|
||
|
||
ppberVal = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
SERVICE_CLASS_ID );
|
||
if ( !ppberVal || !ppberVal[0] )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadServiceClass -\n"
|
||
"ldap_get_values_len() failed\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
if ( ppberVal[0]->bv_len != sizeof(GUID) )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadServiceClass - corrupted DS data!\n"
|
||
"\tservice class id berval %p with invalid length %d\n",
|
||
ppberVal[0],
|
||
ppberVal[0]->bv_len ));
|
||
DNS_ASSERT( ppberVal[0]->bv_len == sizeof(GUID) );
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
// ASSERT( ldap_count_values_len( ppberVal ) == 1 );
|
||
|
||
// write the service class id GUID to buffer
|
||
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
ppberVal[0]->bv_val,
|
||
sizeof(GUID),
|
||
ALIGN_DWORD );
|
||
|
||
pServiceClassInfo->lpServiceClassId = (PGUID) pbuf;
|
||
|
||
ldap_value_free_len( ppberVal );
|
||
ppberVal = NULL;
|
||
|
||
//
|
||
// Read the ServiceClassName and write it into buffer.
|
||
//
|
||
|
||
ppvalue = ldap_get_values(
|
||
pldap,
|
||
object,
|
||
SERVICE_CLASS_NAME );
|
||
if ( !ppvalue )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadServiceClass -\n"
|
||
"ldap_get_values() failed\n" ));
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
// copy service class name
|
||
|
||
pbufString = (PWSTR) FlatBuf_WriteString_W(
|
||
& flatbuf,
|
||
ppvalue[0] );
|
||
|
||
pServiceClassInfo->lpszServiceClassName = pbufString;
|
||
|
||
ldap_value_free( ppvalue );
|
||
|
||
//
|
||
// check for inadequate space
|
||
// - set actual buffer size used
|
||
//
|
||
// DCR_QUESTION: do we fix up space all the time?
|
||
// or only when fail
|
||
//
|
||
|
||
status = NO_ERROR;
|
||
//*pdwBufSize -= flatbuf.BytesLeft;
|
||
|
||
if ( flatbuf.BytesLeft < 0 )
|
||
{
|
||
*pdwBufSize -= flatbuf.BytesLeft;
|
||
status = WSAEFAULT;
|
||
}
|
||
|
||
Done:
|
||
|
||
ldap_value_free_len( ppberVal );
|
||
ldap_msgfree( presults );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave ReadServiceClass() = %d\n",
|
||
status ));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
ReadQuerySet(
|
||
IN PRNR_LOOKUP pRnr,
|
||
IN PWSTR pwsDN,
|
||
IN OUT PDWORD pdwBufSize,
|
||
IN OUT PWSAQUERYSETW pqsResults
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read query set info.
|
||
|
||
Does LDAP search and fills in query set with desired results.
|
||
|
||
This collapses previous ReadServiceInstance() and
|
||
ReadSubordinateContainer() functions which had huge signatures
|
||
and basically had the same code except for the LDAP attributes.
|
||
|
||
The old functions had signature like this:
|
||
if ( prnr->ControlFlags & LUP_CONTAINERS )
|
||
{
|
||
status = ReadSubordinateContainer(
|
||
prnr->pRnrConnection,
|
||
preadDn,
|
||
prnr->ControlFlags,
|
||
prnr->ProviderGuid,
|
||
pdwBufSize,
|
||
pqsResults );
|
||
}
|
||
else
|
||
{
|
||
status = ReadServiceInstance(
|
||
prnr->pRnrConnection,
|
||
preadDn,
|
||
prnr->ControlFlags,
|
||
prnr->ProviderGuid,
|
||
prnr->ServiceClassGuid,
|
||
prnr->NumberOfProtocols,
|
||
prnr->pafpProtocols,
|
||
pdwBufSize,
|
||
pqsResults );
|
||
}
|
||
|
||
Arguments:
|
||
|
||
pRnrConnection -- RnR LDAP connection info
|
||
|
||
pwsDN -- DN to read at
|
||
|
||
pdwBufSize -- addr of result buffer length;
|
||
on return receives required buffer length
|
||
|
||
pqsResults -- query set result buffer
|
||
on return receives results of query
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
WSAEFAULT if buffer too small.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PLDAP pldap;
|
||
DWORD controlFlags;
|
||
BOOL fserviceInstance;
|
||
BOOL freturnedData = FALSE;
|
||
LDAPMessage * presults = NULL;
|
||
DWORD count = 0;
|
||
FLATBUF flatbuf;
|
||
LDAPMessage * object;
|
||
PWSTR * ppvalue = NULL;
|
||
PLDAP_BERVAL * ppberVal = NULL;
|
||
PCSADDR_INFO ptempCsaddrArray = NULL;
|
||
PBYTE pbuf;
|
||
PSTR pbufString;
|
||
PWSTR pcontext;
|
||
WSAQUERYSETW dummyResults;
|
||
INT bufSize;
|
||
PWSTR pfilter;
|
||
PWSTR pname;
|
||
PWSTR pcomment;
|
||
PWSTR attributes[6];
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"ReadQuerySet()\n"
|
||
"\tpRnr = %p\n"
|
||
"\tDN = %S\n"
|
||
"\tbuf size = %p (%d)\n"
|
||
"\tbuffer = %p\n",
|
||
pRnr,
|
||
pwsDN,
|
||
pdwBufSize,
|
||
pdwBufSize ? *pdwBufSize : 0,
|
||
pqsResults ));
|
||
|
||
//
|
||
// grab a few common params
|
||
//
|
||
|
||
if ( !pRnr->pRnrConnection )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
pldap = pRnr->pRnrConnection->pLdapServer;
|
||
controlFlags = pRnr->ControlFlags;
|
||
|
||
//
|
||
// setup ReadServiceInstance\ReadSubordinateContainer diffs
|
||
// - search attributes
|
||
// - search filter
|
||
// - attribute for name
|
||
// - attribute for comment
|
||
//
|
||
// DCR: could select attributes based on LUP_X flags
|
||
// but doubt there's much perf impact here
|
||
//
|
||
|
||
fserviceInstance = !(controlFlags & LUP_CONTAINERS);
|
||
|
||
if ( fserviceInstance )
|
||
{
|
||
attributes[0] = SERVICE_INSTANCE_NAME;
|
||
attributes[1] = SERVICE_CLASS_ID;
|
||
attributes[2] = SERVICE_VERSION;
|
||
attributes[3] = SERVICE_COMMENT;
|
||
attributes[4] = WINSOCK_ADDRESSES;
|
||
attributes[5] = NULL;
|
||
|
||
pfilter = FILTER_OBJECT_CLASS_SERVICE_INSTANCE;
|
||
pname = SERVICE_INSTANCE_NAME;
|
||
pcomment = SERVICE_COMMENT;
|
||
}
|
||
else // read container
|
||
{
|
||
attributes[0] = OBJECT_CLASS;
|
||
attributes[1] = OBJECT_COMMENT;
|
||
attributes[2] = OBJECT_NAME;
|
||
attributes[3] = NULL;
|
||
|
||
pfilter = FILTER_OBJECT_CLASS_NTDS_CONTAINER;
|
||
pname = OBJECT_NAME;
|
||
pcomment = OBJECT_COMMENT;
|
||
}
|
||
|
||
//
|
||
// init the buffer and flatbuf builder
|
||
//
|
||
// if given buffer that's even less than QUERYSET size
|
||
// use a dummy buffer to avoid useless tests while we
|
||
// build\size
|
||
//
|
||
|
||
bufSize = *pdwBufSize - sizeof(WSAQUERYSET);
|
||
if ( bufSize < 0 )
|
||
{
|
||
pqsResults = &dummyResults;
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
(PBYTE) pqsResults,
|
||
sizeof(WSAQUERYSETW) );
|
||
|
||
FlatBuf_Init(
|
||
& flatbuf,
|
||
(PBYTE) pqsResults + sizeof(WSAQUERYSETW),
|
||
bufSize
|
||
);
|
||
|
||
//
|
||
// search
|
||
//
|
||
|
||
status = DoLdapSearch(
|
||
"ReadQuerySet",
|
||
FALSE, // no locked
|
||
pldap,
|
||
pwsDN,
|
||
LDAP_SCOPE_BASE,
|
||
pfilter,
|
||
attributes,
|
||
& presults );
|
||
|
||
if ( status && !presults )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadQuerySet -\n"
|
||
"ldap_search_s() failed with error code: 0%x\n",
|
||
status ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// search completed -- check for valid presults
|
||
// - should have one object matching search criteria
|
||
|
||
count = ldap_count_entries( pldap, presults );
|
||
if ( count == 0 )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadQuerySet -\n"
|
||
"ldap_count_entries() failed\n" ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
object = ldap_first_entry( pldap, presults );
|
||
if ( !object )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!ReadQuerySet -\n"
|
||
"ldap_first_entry() failed\n" ));
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// for ReadServiceInstance -- read the sockaddrs and write to buffer
|
||
// - these are BER values
|
||
//
|
||
|
||
if ( fserviceInstance &&
|
||
controlFlags & LUP_RETURN_ADDR )
|
||
{
|
||
DWORD countBerval;
|
||
DWORD iter;
|
||
DWORD countCsaddr = 0;
|
||
PCSADDR_INFO pcsaddr;
|
||
|
||
ppberVal = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
WINSOCK_ADDRESSES );
|
||
if ( !ppberVal )
|
||
{
|
||
goto WriteName;
|
||
}
|
||
countBerval = ldap_count_values_len( ppberVal );
|
||
|
||
//
|
||
// extract each acceptable CSADDR to result buffer
|
||
//
|
||
// note: CSADDRs are written in packed array, so must write
|
||
// them all before writing their corresponding sockaddrs;
|
||
// and since we don't know whether result buffer is
|
||
// sufficient, must allocate temp array to handle unpacking
|
||
//
|
||
|
||
ptempCsaddrArray = (PCSADDR_INFO) ALLOC_HEAP(
|
||
countBerval * sizeof(CSADDR_INFO) );
|
||
if ( !ptempCsaddrArray )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// build temp CSADDR_INFO array
|
||
// - unpack from CSADDR_BERVAL format
|
||
// - verify acceptable protocol and family
|
||
|
||
pcsaddr = ptempCsaddrArray;
|
||
|
||
for ( iter = 0; iter < countBerval; iter++ )
|
||
{
|
||
if ( ! ExtractCsaddrFromBerval(
|
||
pcsaddr,
|
||
ppberVal[iter],
|
||
pRnr->NumberOfProtocols,
|
||
pRnr->pafpProtocols ) )
|
||
{
|
||
continue;
|
||
}
|
||
countCsaddr++;
|
||
pcsaddr++;
|
||
}
|
||
|
||
//
|
||
// protocol restrictions eliminated all address data?
|
||
// - return error code to skip this entry so caller
|
||
// can call down again
|
||
//
|
||
// DCR_QUESTION: why is this different than search failing?
|
||
|
||
if ( countCsaddr == 0 &&
|
||
pRnr->pafpProtocols &&
|
||
pRnr->NumberOfProtocols )
|
||
{
|
||
status = WSANO_ADDRESS;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// reserve space for CSADDR array
|
||
//
|
||
|
||
pbuf = FlatBuf_Reserve(
|
||
& flatbuf,
|
||
countCsaddr * sizeof(CSADDR_INFO),
|
||
ALIGN_LPVOID
|
||
);
|
||
|
||
pqsResults->lpcsaBuffer = (PCSADDR_INFO) pbuf;
|
||
pqsResults->dwNumberOfCsAddrs = countCsaddr;
|
||
|
||
//
|
||
// write sockaddrs for CSADDRs to result buffer
|
||
//
|
||
// note: that CSADDRs have been written to the result buffer
|
||
// with their sockaddr pointers pointing to the original
|
||
// sockaddrs IN the BERVAL; when we copy the sockaddr data
|
||
// we also need to reset the CSADDR sockaddr pointer
|
||
//
|
||
|
||
pcsaddr = ptempCsaddrArray;
|
||
|
||
for ( iter = 0; iter < countCsaddr; iter++ )
|
||
{
|
||
// write local sockaddr
|
||
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
(PBYTE) pcsaddr->LocalAddr.lpSockaddr,
|
||
pcsaddr->LocalAddr.iSockaddrLength,
|
||
ALIGN_DWORD );
|
||
|
||
pcsaddr->LocalAddr.lpSockaddr = (PSOCKADDR) pbuf;
|
||
|
||
// write remote sockaddr
|
||
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
(PBYTE) pcsaddr->LocalAddr.lpSockaddr,
|
||
pcsaddr->LocalAddr.iSockaddrLength,
|
||
ALIGN_DWORD );
|
||
|
||
pcsaddr->LocalAddr.lpSockaddr = (PSOCKADDR) pbuf;
|
||
pcsaddr++;
|
||
}
|
||
|
||
//
|
||
// copy temp CSADDR array to result buffer
|
||
// - space was reserved and aligned above
|
||
//
|
||
|
||
pbuf = (PBYTE) pqsResults->lpcsaBuffer;
|
||
if ( pbuf )
|
||
{
|
||
RtlCopyMemory(
|
||
pbuf,
|
||
ptempCsaddrArray,
|
||
countCsaddr * sizeof(CSADDR_INFO) );
|
||
}
|
||
freturnedData = TRUE;
|
||
}
|
||
|
||
WriteName:
|
||
|
||
//
|
||
// read the name and write it into buffer.
|
||
//
|
||
|
||
if ( controlFlags & LUP_RETURN_NAME )
|
||
{
|
||
ppvalue = ldap_get_values(
|
||
pldap,
|
||
object,
|
||
pname );
|
||
if ( ppvalue )
|
||
{
|
||
pbufString = FlatBuf_WriteString_W(
|
||
& flatbuf,
|
||
ppvalue[0] );
|
||
pqsResults->lpszServiceInstanceName = (PWSTR) pbufString;
|
||
freturnedData = TRUE;
|
||
ldap_value_free( ppvalue );
|
||
}
|
||
}
|
||
|
||
//
|
||
// for service instance
|
||
// - get serviceClassId
|
||
// - get serviceVersion
|
||
//
|
||
|
||
if ( fserviceInstance )
|
||
{
|
||
//
|
||
// read ServiceClassId (GUID) and write it to buffer
|
||
//
|
||
// DCR_QUESTION: originally we copied ServiceClassId passed in
|
||
// rather than one we read?
|
||
//
|
||
|
||
if ( controlFlags & LUP_RETURN_TYPE )
|
||
{
|
||
ppberVal = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
SERVICE_CLASS_ID );
|
||
if ( ppberVal )
|
||
{
|
||
if ( ppberVal[0]->bv_len == sizeof(GUID) )
|
||
{
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
ppberVal[0]->bv_val,
|
||
sizeof(GUID),
|
||
ALIGN_DWORD
|
||
);
|
||
pqsResults->lpServiceClassId = (PGUID) pbuf;
|
||
freturnedData = TRUE;
|
||
}
|
||
ldap_value_free_len( ppberVal );
|
||
}
|
||
}
|
||
|
||
//
|
||
// read ServiceVersion and write it to buffer
|
||
//
|
||
|
||
if ( controlFlags & LUP_RETURN_VERSION )
|
||
{
|
||
ppberVal = ldap_get_values_len(
|
||
pldap,
|
||
object,
|
||
SERVICE_VERSION );
|
||
|
||
if ( ppberVal )
|
||
{
|
||
if ( ppberVal[0]->bv_len == sizeof(WSAVERSION) )
|
||
{
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
ppberVal[0]->bv_val,
|
||
sizeof(WSAVERSION),
|
||
ALIGN_DWORD
|
||
);
|
||
pqsResults->lpVersion = (LPWSAVERSION) pbuf;
|
||
freturnedData = TRUE;
|
||
}
|
||
ldap_value_free_len( ppberVal );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// read comment and copy to buffer
|
||
//
|
||
|
||
if ( controlFlags & LUP_RETURN_COMMENT )
|
||
{
|
||
ppvalue = ldap_get_values(
|
||
pldap,
|
||
object,
|
||
pcomment );
|
||
if ( ppvalue )
|
||
{
|
||
pbufString = FlatBuf_WriteString_W(
|
||
& flatbuf,
|
||
ppvalue[0]
|
||
);
|
||
pqsResults->lpszComment = (PWSTR) pbufString;
|
||
freturnedData = TRUE;
|
||
ldap_value_free( ppvalue );
|
||
}
|
||
}
|
||
|
||
//
|
||
// if no search results written -- done
|
||
//
|
||
|
||
if ( !freturnedData )
|
||
{
|
||
status = WSANO_DATA;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// fill in other queryset fields
|
||
//
|
||
|
||
pqsResults->dwSize = sizeof( WSAQUERYSETW );
|
||
pqsResults->dwNameSpace = NS_NTDS;
|
||
|
||
//
|
||
// add the provider GUID
|
||
//
|
||
|
||
pbuf = FlatBuf_CopyMemory(
|
||
& flatbuf,
|
||
& pRnr->ProviderGuid,
|
||
sizeof(GUID),
|
||
ALIGN_DWORD
|
||
);
|
||
pqsResults->lpNSProviderId = (PGUID) pbuf;
|
||
|
||
//
|
||
// add the context string
|
||
//
|
||
|
||
pcontext = wcschr( pwsDN, L',' );
|
||
pcontext++;
|
||
|
||
pbufString = FlatBuf_WriteString_W(
|
||
& flatbuf,
|
||
pcontext );
|
||
|
||
pqsResults->lpszContext = (PWSTR) pbufString;
|
||
|
||
//
|
||
// check for inadequate space
|
||
// - set actual buffer size used
|
||
//
|
||
// DCR_QUESTION: do we fix up space all the time?
|
||
// or only when fail
|
||
//
|
||
|
||
status = NO_ERROR;
|
||
//*pdwBufSize -= flatbuf.BytesLeft;
|
||
|
||
if ( flatbuf.BytesLeft < 0 )
|
||
{
|
||
*pdwBufSize -= flatbuf.BytesLeft;
|
||
status = WSAEFAULT;
|
||
}
|
||
|
||
Exit:
|
||
|
||
ldap_msgfree( presults );
|
||
FREE_HEAP( ptempCsaddrArray );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave ReadQuerySet() => %d\n"
|
||
"\tpRnr = %p\n"
|
||
"\tpQuerySet = %p\n"
|
||
"\tbufLength = %d\n",
|
||
status,
|
||
pRnr,
|
||
pqsResults,
|
||
pdwBufSize ? *pdwBufSize : 0
|
||
));
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// NSP definition
|
||
//
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_Cleanup(
|
||
IN PGUID pProviderId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup NTDS provider.
|
||
|
||
This is called by WSACleanup() if NSPStartup was called.
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "NTDS_Cleanup( %p )\n", pProviderId ));
|
||
|
||
// free any global memory allocated
|
||
|
||
DnsApiFree( g_pHostName );
|
||
DnsApiFree( g_pFullName );
|
||
|
||
g_pHostName = NULL;
|
||
g_pFullName = NULL;
|
||
|
||
//
|
||
// DCR: note potentially leaking RnR lookup handles
|
||
// we are not keeping list of lookup handles,
|
||
// so can not clean them up, if callers expect WSACleanup() to
|
||
// handle it -- they'll leak
|
||
//
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_InstallServiceClass(
|
||
IN PGUID pProviderId,
|
||
IN PWSASERVICECLASSINFOW pServiceClassInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Install service class in directory.
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
pServiceClassInfo -- service class info blob
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_CONNECTION prnrCon = NULL;
|
||
DWORD iter;
|
||
DWORD count = 0;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
BOOL fisNTDS = FALSE;
|
||
PGUID pclassGuid;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_InstallServiceClass()\n"
|
||
"\tpGuid = %p\n"
|
||
"\tpServiceClass = %p\n",
|
||
pProviderId,
|
||
pServiceClassInfo ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Guid(
|
||
"InstallServiceClass Provider GUID:",
|
||
pProviderId );
|
||
}
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_WsaServiceClassInfo(
|
||
"InstallServiceClass() ServiceClassInfo:",
|
||
pServiceClassInfo,
|
||
TRUE // unicode
|
||
);
|
||
}
|
||
|
||
//
|
||
// validate service class
|
||
//
|
||
|
||
if ( ! pServiceClassInfo ||
|
||
! pServiceClassInfo->lpServiceClassId ||
|
||
! pServiceClassInfo->lpszServiceClassName ||
|
||
( pServiceClassInfo->dwCount &&
|
||
!pServiceClassInfo->lpClassInfos ) )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// don't install the DNS services -- they already exist
|
||
//
|
||
|
||
pclassGuid = pServiceClassInfo->lpServiceClassId;
|
||
|
||
if ( GuidEqual( pclassGuid, &HostAddrByInetStringGuid ) ||
|
||
GuidEqual( pclassGuid, &ServiceByNameGuid ) ||
|
||
GuidEqual( pclassGuid, &HostAddrByNameGuid ) ||
|
||
GuidEqual( pclassGuid, &HostNameGuid ) ||
|
||
IS_SVCID_DNS( pclassGuid ) )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
|
||
for ( iter = 0; iter < pServiceClassInfo->dwCount; iter++ )
|
||
{
|
||
if ( pServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_NTDS ||
|
||
pServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_ALL )
|
||
{
|
||
fisNTDS = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if ( !fisNTDS )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// connect to directory
|
||
//
|
||
|
||
status = ConnectToDefaultLDAPDirectory( FALSE, &prnrCon );
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// check if service class already installed in directory
|
||
//
|
||
|
||
status = FindServiceClass(
|
||
prnrCon,
|
||
pServiceClassInfo->lpszServiceClassName,
|
||
pclassGuid,
|
||
NULL, // don't need count
|
||
&pdnArray );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// service class not found -- add it
|
||
//
|
||
|
||
if ( !pdnArray )
|
||
{
|
||
status = AddServiceClass(
|
||
prnrCon,
|
||
pclassGuid,
|
||
pServiceClassInfo->lpszServiceClassName,
|
||
&pdnArray );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// loop through the WSANSCLASSINFO's for the given pServiceClassInfo
|
||
// - add/modify the ones with our dwNameSpace to the NSClassInfo
|
||
// property of the ServiceClass object.
|
||
//
|
||
// DCR: continue on error here and just save failing status?
|
||
//
|
||
|
||
for ( iter = 0; iter < pServiceClassInfo->dwCount; iter++ )
|
||
{
|
||
PWSANSCLASSINFO pclassInfo = &pServiceClassInfo->lpClassInfos[iter];
|
||
|
||
if ( pclassInfo->dwNameSpace == NS_NTDS ||
|
||
pclassInfo->dwNameSpace == NS_ALL )
|
||
{
|
||
status = AddClassInfoToServiceClass(
|
||
prnrCon,
|
||
pdnArray->Strings[0],
|
||
pclassInfo );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
Exit:
|
||
|
||
FreeDnArray( pdnArray );
|
||
|
||
DisconnectFromLDAPDirectory( &prnrCon );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave InstallServiceClass() => %d\n",
|
||
status ));
|
||
|
||
return( SetError( status ) );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_RemoveServiceClass(
|
||
IN PGUID pProviderId,
|
||
IN PGUID pServiceClassId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Remove service class from directory.
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
pServiceClassInfo -- service class info blob
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_CONNECTION prnrCon = NULL;
|
||
DWORD serviceCount = 0;
|
||
DWORD iter;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_RemoveServiceClass()\n"
|
||
"\tpProviderGuid = %p\n"
|
||
"\tpClassGuid = %p\n",
|
||
pProviderId,
|
||
pServiceClassId ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Guid(
|
||
"RemoveServiceClass Provider GUID:",
|
||
pProviderId );
|
||
}
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Guid(
|
||
"RemoveServiceClass GUID:",
|
||
pServiceClassId );
|
||
}
|
||
|
||
//
|
||
// validation
|
||
//
|
||
|
||
if ( !pServiceClassId )
|
||
{
|
||
return( SetError( WSA_INVALID_PARAMETER ) );
|
||
}
|
||
|
||
//
|
||
// connect to directory
|
||
//
|
||
|
||
status = ConnectToDefaultLDAPDirectory(
|
||
FALSE,
|
||
&prnrCon );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// find service class in directory
|
||
//
|
||
|
||
status = FindServiceClass(
|
||
prnrCon,
|
||
NULL,
|
||
pServiceClassId,
|
||
NULL, // don't need count
|
||
& pdnArray );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( !pdnArray )
|
||
{
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// should have found only one ServiceClass in the container,
|
||
// CN=WinsockServices, ... , with a ServiceClassId of pServiceClassId.
|
||
//
|
||
|
||
ASSERT( pdnArray->Count == 1 );
|
||
|
||
//
|
||
// found service class
|
||
// - check for service instances objects for the the class
|
||
// if found, we can't remove the class until instances
|
||
// are removed
|
||
//
|
||
|
||
status = FindServiceInstance(
|
||
prnrCon,
|
||
NULL, // no instance names
|
||
pServiceClassId, // find class by GUID
|
||
NULL, // no version
|
||
prnrCon->DomainDN, // context
|
||
TRUE, // search entire subtree
|
||
&serviceCount, // retrieve count
|
||
NULL // don't need DNs just count
|
||
);
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( serviceCount > 0 )
|
||
{
|
||
// still have service instances that reference the class
|
||
// so can't remove class
|
||
|
||
status = WSAETOOMANYREFS;
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// remove the service class
|
||
// - first string in pdnArray contains DN of the ServiceClass
|
||
//
|
||
|
||
status = ldap_delete_s(
|
||
prnrCon->pLdapServer,
|
||
pdnArray->Strings[0] );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!NTDS_RemoveServiceClass - ldap_delete_s()\n"
|
||
"failed with error code: 0%x\n",
|
||
status ));
|
||
status = WSAEACCES;
|
||
goto Exit;
|
||
}
|
||
|
||
|
||
Exit:
|
||
|
||
FreeDnArray( pdnArray );
|
||
|
||
DisconnectFromLDAPDirectory( &prnrCon );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave RemoveServiceClass() => %d\n",
|
||
status ));
|
||
|
||
return( SetError( status ) );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_GetServiceClassInfo(
|
||
IN PGUID pProviderId,
|
||
IN OUT PDWORD pdwBufSize,
|
||
IN OUT PWSASERVICECLASSINFOW pServiceClassInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read service class info
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
pdwBufSize -- addr with and to recv buffer size
|
||
input: buffer size
|
||
output: bytes required or written
|
||
|
||
pServiceClassInfo -- service class info buffer
|
||
input: valid service class GUID (lpServiceClassId)
|
||
output: filled in with service class info; subfield data follows
|
||
WSASERVICECLASSINFO struct
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_CONNECTION prnrCon = NULL;
|
||
DWORD count = 0;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_GetServiceClassInfo()\n"
|
||
"\tpProviderGuid = %p\n"
|
||
"\tpdwBufSize = %p (%d)\n"
|
||
"\tpClassInfo = %p\n",
|
||
pProviderId,
|
||
pdwBufSize,
|
||
pdwBufSize ? *pdwBufSize : 0,
|
||
pServiceClassInfo ));
|
||
|
||
//
|
||
// validate
|
||
//
|
||
|
||
if ( !pServiceClassInfo || !pdwBufSize )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_WsaServiceClassInfo(
|
||
"GetServiceClassInfo ServiceClassInfo:",
|
||
pServiceClassInfo,
|
||
TRUE // unicode
|
||
);
|
||
}
|
||
|
||
//
|
||
// connect
|
||
//
|
||
|
||
status = ConnectToDefaultLDAPDirectory(
|
||
FALSE,
|
||
&prnrCon );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// find service class
|
||
//
|
||
|
||
status = FindServiceClass(
|
||
prnrCon,
|
||
NULL,
|
||
pServiceClassInfo->lpServiceClassId,
|
||
NULL, // don't need count
|
||
&pdnArray );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( !pdnArray )
|
||
{
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
|
||
// should be only one ServiceClass in the container,
|
||
// OU=WinsockServices, ... , with a ServiceClassId of pServiceClassId.
|
||
|
||
ASSERT( pdnArray->Count == 1 );
|
||
|
||
//
|
||
// read attributes of the ServiceClass into buffer
|
||
//
|
||
|
||
status = ReadServiceClass(
|
||
prnrCon,
|
||
pdnArray->Strings[0],
|
||
pdwBufSize,
|
||
pServiceClassInfo );
|
||
|
||
|
||
|
||
Exit:
|
||
|
||
FreeDnArray( pdnArray );
|
||
|
||
DisconnectFromLDAPDirectory( &prnrCon );
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DNS_PRINT((
|
||
"Leave GetServiceClassInfo() = %d\n"
|
||
"\tbuf size = %d\n",
|
||
status,
|
||
pdwBufSize ? *pdwBufSize : 0 ));
|
||
|
||
if ( status == NO_ERROR )
|
||
{
|
||
DnsDbg_WsaServiceClassInfo(
|
||
"Leaving GetServiceClassInfo:",
|
||
pServiceClassInfo,
|
||
TRUE // unicode
|
||
);
|
||
}
|
||
}
|
||
|
||
return( SetError( status ) );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_SetService(
|
||
IN PGUID pProviderId,
|
||
IN PWSASERVICECLASSINFOW pServiceClassInfo,
|
||
IN PWSAQUERYSETW pqsReqInfo,
|
||
IN WSAESETSERVICEOP essOperation,
|
||
IN DWORD dwControlFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read service class info
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
pdwBufSize -- addr with and to recv buffer size
|
||
input: buffer size
|
||
output: bytes required or written
|
||
|
||
pServiceClassInfo -- service class info buffer
|
||
input: valid service class GUID (lpServiceClassId)
|
||
output: filled in with service class info; subfield data follows
|
||
WSASERVICECLASSINFO struct
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_CONNECTION prnrCon = NULL;
|
||
DWORD count = 0;
|
||
DWORD iter;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_SetService()\n"
|
||
"\tpProviderGuid = %p\n"
|
||
"\tpServiceClassInfo = %p\n"
|
||
"\tpQuerySet = %p\n"
|
||
"\tOperation = %d\n"
|
||
"\tControlFlags = %08x\n",
|
||
pProviderId,
|
||
pServiceClassInfo,
|
||
pqsReqInfo,
|
||
essOperation,
|
||
dwControlFlags ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Lock();
|
||
DnsDbg_Guid(
|
||
"SetService() Provider GUID:",
|
||
pProviderId );
|
||
|
||
DnsDbg_WsaServiceClassInfo(
|
||
"SetService ServiceClassInfo:",
|
||
pServiceClassInfo,
|
||
TRUE // unicode
|
||
);
|
||
|
||
DnsDbg_WsaQuerySet(
|
||
"SetService QuerySet:",
|
||
pqsReqInfo,
|
||
TRUE // unicode
|
||
);
|
||
DnsDbg_Unlock();
|
||
}
|
||
|
||
//
|
||
// param validation
|
||
//
|
||
|
||
if ( !pqsReqInfo )
|
||
{
|
||
return( SetError( WSA_INVALID_PARAMETER ) );
|
||
}
|
||
if ( pqsReqInfo->dwSize != sizeof( WSAQUERYSET ) )
|
||
{
|
||
return( SetError( WSAVERNOTSUPPORTED ) );
|
||
}
|
||
|
||
//
|
||
// connect
|
||
//
|
||
|
||
status = ConnectToDefaultLDAPDirectory(
|
||
FALSE,
|
||
&prnrCon );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// Figure out what operation and with what control flags are to be
|
||
// performed.
|
||
//
|
||
|
||
switch( essOperation )
|
||
{
|
||
case RNRSERVICE_REGISTER:
|
||
|
||
//
|
||
// check if service already registered
|
||
//
|
||
|
||
status = FindServiceInstance(
|
||
prnrCon,
|
||
pqsReqInfo->lpszServiceInstanceName,
|
||
pqsReqInfo->lpServiceClassId,
|
||
pqsReqInfo->lpVersion,
|
||
NULL, // no context
|
||
FALSE, // one level search
|
||
NULL, // don't need count
|
||
&pdnArray // get instance DNs
|
||
);
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// service instances doesn't exist => need to add
|
||
// - verify service class (matching GUID) exists
|
||
// - create instance of class
|
||
//
|
||
|
||
if ( !pdnArray )
|
||
{
|
||
PDN_ARRAY pserviceArray = NULL;
|
||
|
||
status = FindServiceClass(
|
||
prnrCon,
|
||
NULL, // no class name, using GUID
|
||
pqsReqInfo->lpServiceClassId,
|
||
& count,
|
||
NULL // class DN not required
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( count == 0 )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
DNS_ASSERT( count == 1 );
|
||
|
||
status = AddServiceInstance(
|
||
prnrCon,
|
||
pqsReqInfo->lpszServiceInstanceName,
|
||
pqsReqInfo->lpServiceClassId,
|
||
pqsReqInfo->lpVersion,
|
||
pqsReqInfo->lpszComment,
|
||
& pdnArray
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// add CSADDR_INFO
|
||
// to an Octet string, then try add it.
|
||
//
|
||
|
||
for ( iter = 0; iter < pqsReqInfo->dwNumberOfCsAddrs; iter++ )
|
||
{
|
||
status = ModifyAddressInServiceInstance(
|
||
prnrCon,
|
||
pdnArray->Strings[0],
|
||
& pqsReqInfo->lpcsaBuffer[iter],
|
||
TRUE // add address
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case RNRSERVICE_DEREGISTER:
|
||
case RNRSERVICE_DELETE:
|
||
|
||
status = FindServiceInstance(
|
||
prnrCon,
|
||
pqsReqInfo->lpszServiceInstanceName,
|
||
pqsReqInfo->lpServiceClassId,
|
||
pqsReqInfo->lpVersion,
|
||
NULL, // no context
|
||
FALSE, // one level search
|
||
NULL, // don't need count
|
||
& pdnArray // get DN array
|
||
);
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( !pdnArray )
|
||
{
|
||
// no service instance of given name found
|
||
status = WSATYPE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
DNS_ASSERT( pdnArray->Count == 1 );
|
||
|
||
//
|
||
// delete each CSADDR_INFO in pqsReqInfo from service instance
|
||
//
|
||
|
||
for ( iter = 0; iter < pqsReqInfo->dwNumberOfCsAddrs; iter++ )
|
||
{
|
||
status = ModifyAddressInServiceInstance(
|
||
prnrCon,
|
||
pdnArray->Strings[0],
|
||
& pqsReqInfo->lpcsaBuffer[iter],
|
||
FALSE // remove address
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// delete service?
|
||
// - RNRSERVICE_DELETE operation
|
||
// - no addresses on ServiceInstance object
|
||
// => then delete the serviceInstance
|
||
//
|
||
// DCR_QUESTION: RNRSERVICE_DELETE doesn't whack service
|
||
// regardless of existing CSADDRs?
|
||
//
|
||
|
||
if ( essOperation == RNRSERVICE_DELETE )
|
||
{
|
||
status = GetAddressCountFromServiceInstance(
|
||
prnrCon,
|
||
pdnArray->Strings[0],
|
||
& count );
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
if ( count == 0 )
|
||
{
|
||
status = ldap_delete_s(
|
||
prnrCon->pLdapServer,
|
||
pdnArray->Strings[0] );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
WINRNR_PRINT((
|
||
"WINRNR!NTDS_SetService - ldap_delete_s()\n"
|
||
"failed with error code: 0%x\n",
|
||
status ));
|
||
status = WSAEACCES;
|
||
goto Exit;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
default :
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Exit;
|
||
}
|
||
|
||
|
||
Exit:
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave NTDS_SetService() => %d\n",
|
||
status ));
|
||
|
||
FreeDnArray( pdnArray );
|
||
|
||
DisconnectFromLDAPDirectory( &prnrCon );
|
||
|
||
return( SetError(status) );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_LookupServiceBegin(
|
||
IN PGUID pProviderId,
|
||
IN PWSAQUERYSETW pqsRestrictions,
|
||
IN PWSASERVICECLASSINFOW pServiceClassInfo,
|
||
IN DWORD dwControlFlags,
|
||
OUT PHANDLE phLookup
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Start an NTDS service query.
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
pqsRestrictions -- restrictions on query
|
||
|
||
pServiceClassInfo -- service class info blob
|
||
|
||
dwControlFlags -- query control flags
|
||
|
||
phLookup -- addr to recv RnR lookup handle
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_LOOKUP prnr = NULL;
|
||
DWORD iter;
|
||
PWSTR pstring;
|
||
PBYTE pmem;
|
||
PGUID pclassGuid;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_LookupServiceBegin()\n"
|
||
"\tpProviderGuid = %p\n"
|
||
"\tpqsRestrictions = %p\n"
|
||
"\tpServiceClassInfo = %p\n"
|
||
"\tControlFlags = %08x\n",
|
||
pProviderId,
|
||
pqsRestrictions,
|
||
pServiceClassInfo,
|
||
dwControlFlags ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Lock();
|
||
DnsDbg_Guid(
|
||
"LookupServiceBegin Provider GUID:",
|
||
pProviderId
|
||
);
|
||
DnsDbg_WsaQuerySet(
|
||
"LookupServiceBegin QuerySet:",
|
||
pqsRestrictions,
|
||
TRUE // unicode
|
||
);
|
||
DnsDbg_WsaServiceClassInfo(
|
||
"LookupServiceBegin ServiceClassInfo:",
|
||
pServiceClassInfo,
|
||
TRUE // unicode
|
||
);
|
||
DnsDbg_Unlock();
|
||
}
|
||
|
||
//
|
||
// parameter validation
|
||
//
|
||
|
||
if ( !pqsRestrictions ||
|
||
!pProviderId ||
|
||
!pqsRestrictions->lpServiceClassId )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Failed;
|
||
}
|
||
|
||
if ( pqsRestrictions->dwNameSpace != NS_ALL &&
|
||
pqsRestrictions->dwNameSpace != NS_NTDS )
|
||
{
|
||
status = WSAEINVAL;
|
||
goto Failed;
|
||
}
|
||
|
||
//
|
||
// if known DNS lookup -- you're in the wrong provider
|
||
//
|
||
|
||
pclassGuid = pqsRestrictions->lpServiceClassId;
|
||
|
||
if ( GuidEqual( pclassGuid, &HostAddrByInetStringGuid ) ||
|
||
GuidEqual( pclassGuid, &ServiceByNameGuid ) ||
|
||
GuidEqual( pclassGuid, &HostAddrByNameGuid ) ||
|
||
GuidEqual( pclassGuid, &HostNameGuid ) ||
|
||
IS_SVCID_DNS( pclassGuid ) )
|
||
{
|
||
status = WSASERVICE_NOT_FOUND;
|
||
goto Failed;
|
||
}
|
||
|
||
if ( !( dwControlFlags & LUP_CONTAINERS ) &&
|
||
pqsRestrictions->lpszServiceInstanceName == NULL )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Failed;
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"VALID LookupServiceBegin ...\n" ));
|
||
|
||
//
|
||
// If were not enumerating containers, we need to test to see if name
|
||
// is TCPs (DNS).
|
||
//
|
||
|
||
if ( !( dwControlFlags & LUP_CONTAINERS ) )
|
||
{
|
||
//
|
||
// Need to test the ppwsServiceName to see if it is the same
|
||
// as that of the local machine name. If it is, then we return with
|
||
// an error since we don't know how to handle this scenario.
|
||
//
|
||
// DCR: fix local name compare
|
||
// DCR: this doesn't work on local name as service instance!!!!
|
||
//
|
||
|
||
if ( !g_pHostName )
|
||
{
|
||
g_pHostName = DnsQueryConfigAlloc(
|
||
DnsConfigHostName_W,
|
||
NULL );
|
||
}
|
||
if ( DnsNameCompare_W(
|
||
pqsRestrictions->lpszServiceInstanceName,
|
||
g_pHostName ) )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Failed;
|
||
}
|
||
|
||
//
|
||
// Need to test the ppwsServiceName to see if it is the same
|
||
// as that of the local machine's DNS name. If it is, then we return with
|
||
// an error since we don't know how to handle this scenario.
|
||
//
|
||
|
||
if ( !g_pFullName )
|
||
{
|
||
g_pFullName = DnsQueryConfigAlloc(
|
||
DnsConfigFullHostName_W,
|
||
NULL );
|
||
}
|
||
if ( DnsNameCompare_W(
|
||
pqsRestrictions->lpszServiceInstanceName,
|
||
g_pFullName ) )
|
||
{
|
||
status = WSA_INVALID_PARAMETER;
|
||
goto Failed;
|
||
}
|
||
}
|
||
|
||
if ( pqsRestrictions->dwSize != sizeof( WSAQUERYSET ) )
|
||
{
|
||
status = WSAVERNOTSUPPORTED;
|
||
goto Failed;
|
||
}
|
||
|
||
if ( pqsRestrictions->lpNSProviderId &&
|
||
!GuidEqual( pqsRestrictions->lpNSProviderId, pProviderId ) )
|
||
{
|
||
status = WSAEINVALIDPROVIDER;
|
||
goto Failed;
|
||
}
|
||
|
||
//
|
||
// create RnR lookup context
|
||
//
|
||
|
||
prnr = (PRNR_LOOKUP) ALLOC_HEAP_ZERO( sizeof(RNR_LOOKUP) );
|
||
if ( !prnr )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
|
||
prnr->Signature = RNR_SIGNATURE;
|
||
prnr->ControlFlags = dwControlFlags;
|
||
|
||
//
|
||
// copy subfields
|
||
// - service class GUID and version have buffers in RnR blob
|
||
// - instance name, context, proto array we alloc
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
&prnr->ProviderGuid,
|
||
pProviderId,
|
||
sizeof(GUID) );
|
||
|
||
if ( pqsRestrictions->lpServiceClassId )
|
||
{
|
||
RtlCopyMemory(
|
||
&prnr->ServiceClassGuid,
|
||
pqsRestrictions->lpServiceClassId,
|
||
sizeof(GUID) );
|
||
}
|
||
|
||
if ( pqsRestrictions->lpVersion )
|
||
{
|
||
RtlCopyMemory(
|
||
&prnr->WsaVersion,
|
||
pqsRestrictions->lpVersion,
|
||
sizeof(WSAVERSION) );
|
||
prnr->pVersion = &prnr->WsaVersion;
|
||
}
|
||
|
||
if ( pqsRestrictions->lpszServiceInstanceName )
|
||
{
|
||
pstring = Dns_CreateStringCopy_W(
|
||
pqsRestrictions->lpszServiceInstanceName );
|
||
if ( !pstring )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
prnr->pwsServiceName = pstring;
|
||
}
|
||
|
||
if ( pqsRestrictions->lpszContext )
|
||
{
|
||
pstring = Dns_CreateStringCopy_W(
|
||
pqsRestrictions->lpszContext );
|
||
if ( !pstring )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
prnr->pwsContext = pstring;
|
||
}
|
||
|
||
if ( pqsRestrictions->dwNumberOfProtocols > 0 )
|
||
{
|
||
pmem = Dns_AllocMemCopy(
|
||
pqsRestrictions->lpafpProtocols,
|
||
pqsRestrictions->dwNumberOfProtocols * sizeof(AFPROTOCOLS) );
|
||
if ( !pmem )
|
||
{
|
||
status = ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
prnr->pafpProtocols = (LPAFPROTOCOLS) pmem;
|
||
prnr->NumberOfProtocols = pqsRestrictions->dwNumberOfProtocols;
|
||
}
|
||
|
||
*phLookup = (HANDLE) prnr;
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave NTDS_LookupServiceBegin() => Success\n"
|
||
"\tpRnr = %p\n",
|
||
prnr ));
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_RnrLookup( "RnR Lookup Handle:", prnr );
|
||
}
|
||
return NO_ERROR;
|
||
|
||
|
||
Failed:
|
||
|
||
FreeRnrLookup( prnr );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave NTDS_LookupServiceBegin() => %d\n",
|
||
status ));
|
||
|
||
return SetError(status);
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_LookupServiceNext(
|
||
IN HANDLE hLookup,
|
||
IN DWORD dwControlFlags,
|
||
IN OUT PDWORD pdwBufferLength,
|
||
OUT PWSAQUERYSETW pqsResults
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Execute NTDS name space service query.
|
||
|
||
Queries for next instance result of query.
|
||
|
||
Arguments:
|
||
|
||
hLookup -- RnR lookup handle from NTDS_LookupServiceBegin
|
||
|
||
dwControlFlags -- control flags on query
|
||
|
||
pdwBufSize -- addr with and to recv buffer size
|
||
input: buffer size
|
||
output: bytes required or written
|
||
|
||
pqsResults -- query set buffer
|
||
input: ignored
|
||
output: filled in with query set results; subfield data follows
|
||
WSASQUERYSET struct
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
WSA_E_NO_MORE -- if no more results for query
|
||
WSASERVICE_NOT_FOUND -- if no results found for query
|
||
|
||
--*/
|
||
{
|
||
RNR_STATUS status = NO_ERROR;
|
||
PRNR_LOOKUP prnr = (PRNR_LOOKUP) hLookup;
|
||
PDN_ARRAY pdnArray = NULL;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_LookupServiceNext()\n"
|
||
"\tpRnr = %p\n"
|
||
"\tControlFlags = %08x\n"
|
||
"\tpdwBufLength = %p (len=%d)\n"
|
||
"\tpResultBuffer = %p\n",
|
||
hLookup,
|
||
dwControlFlags,
|
||
pdwBufferLength,
|
||
pdwBufferLength ? *pdwBufferLength : 0,
|
||
pqsResults ));
|
||
|
||
|
||
//
|
||
// validate RnR handle
|
||
//
|
||
|
||
if ( !prnr ||
|
||
prnr->Signature != RNR_SIGNATURE )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"ERROR: Invalid RnR lookup handle!\n"
|
||
"\thandle = %p\n"
|
||
"\tsig = %p\n",
|
||
prnr,
|
||
prnr ? prnr->Signature : 0 ));
|
||
|
||
DNS_ASSERT( !prnr || prnr->Signature != RNR_SIGNATURE_FREE );
|
||
status = WSA_INVALID_HANDLE;
|
||
goto Exit;
|
||
}
|
||
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_RnrLookup(
|
||
"LookupServiceNext RnR Handle:",
|
||
prnr );
|
||
}
|
||
|
||
//
|
||
// if no connection -- first LookupServiceNext
|
||
// - connect to directory
|
||
// - do search for desired objects
|
||
//
|
||
|
||
if ( !prnr->pRnrConnection )
|
||
{
|
||
status = ConnectToDefaultLDAPDirectory(
|
||
TRUE,
|
||
&prnr->pRnrConnection );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
//
|
||
// LUP_CONTAINERS
|
||
// - search for subordinate container objects to
|
||
// prnr->ServiceInstanceName
|
||
//
|
||
|
||
if ( prnr->ControlFlags & LUP_CONTAINERS )
|
||
{
|
||
status = FindSubordinateContainers(
|
||
prnr->pRnrConnection,
|
||
prnr->pwsServiceName,
|
||
( (prnr->ControlFlags & LUP_DEEP) &&
|
||
!prnr->pwsContext )
|
||
? prnr->pRnrConnection->DomainDN
|
||
: prnr->pwsContext,
|
||
( prnr->ControlFlags & LUP_DEEP )
|
||
? TRUE
|
||
: FALSE,
|
||
& pdnArray );
|
||
}
|
||
|
||
//
|
||
// not LUP_CONTAINERS -- find service instance
|
||
//
|
||
|
||
else
|
||
{
|
||
status = FindServiceInstance(
|
||
prnr->pRnrConnection,
|
||
prnr->pwsServiceName,
|
||
&prnr->ServiceClassGuid,
|
||
prnr->pVersion,
|
||
( (prnr->ControlFlags & LUP_DEEP) &&
|
||
!prnr->pwsContext )
|
||
? prnr->pRnrConnection->DomainDN
|
||
: prnr->pwsContext,
|
||
(prnr->ControlFlags & LUP_DEEP)
|
||
? TRUE
|
||
: FALSE,
|
||
NULL, // don't need count
|
||
&pdnArray );
|
||
}
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
// if couldn't find container or service instance -- bail
|
||
|
||
if ( !pdnArray )
|
||
{
|
||
status = WSASERVICE_NOT_FOUND;
|
||
goto Exit;
|
||
}
|
||
|
||
// save DN array to lookup blob
|
||
// - need on next LookupServiceNext call
|
||
|
||
prnr->pDnArray = pdnArray;
|
||
}
|
||
|
||
//
|
||
// have DN array
|
||
// - from search above
|
||
// - or previous LookupServiceNext() call
|
||
//
|
||
|
||
pdnArray = prnr->pDnArray;
|
||
if ( !pdnArray )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
status = WSA_E_NO_MORE;
|
||
goto Exit;
|
||
}
|
||
|
||
if ( dwControlFlags & LUP_FLUSHPREVIOUS )
|
||
{
|
||
prnr->CurrentDN++;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_LookupServiceNext() -- flushing previous\n"
|
||
"\tDN index now %d\n",
|
||
prnr->CurrentDN ));
|
||
}
|
||
|
||
//
|
||
// loop until successfully read info from DN
|
||
//
|
||
|
||
while ( 1 )
|
||
{
|
||
PWSTR preadDn;
|
||
|
||
if ( pdnArray->Count <= prnr->CurrentDN )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"NTDS_LookupServiceNext() -- used all the DNs\n"
|
||
"\tDN index now %d\n",
|
||
prnr->CurrentDN ));
|
||
status = WSA_E_NO_MORE;
|
||
goto Exit;
|
||
}
|
||
preadDn = pdnArray->Strings[ prnr->CurrentDN ];
|
||
|
||
//
|
||
// read properties and write to query set
|
||
//
|
||
// LUP_CONTAINERS
|
||
// - from container
|
||
// not LUP_CONTAINERS
|
||
// - service instance
|
||
//
|
||
|
||
status = ReadQuerySet(
|
||
prnr,
|
||
preadDn,
|
||
pdwBufferLength,
|
||
pqsResults );
|
||
|
||
// if successful, return
|
||
|
||
if ( status == NO_ERROR )
|
||
{
|
||
prnr->CurrentDN++;
|
||
goto Exit;
|
||
}
|
||
|
||
// if out of addresses, continue
|
||
|
||
if ( status == WSANO_ADDRESS )
|
||
{
|
||
prnr->CurrentDN++;
|
||
status = NO_ERROR;
|
||
continue;
|
||
}
|
||
break; // other errors are terminal
|
||
}
|
||
|
||
Exit:
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave NTDS_LookupServiceNext() => %d\n"
|
||
"\tpRnr = %p\n"
|
||
"\t DN Array = %p\n"
|
||
"\t DN Index = %d\n"
|
||
"\tbufLength = %d\n",
|
||
status,
|
||
hLookup,
|
||
prnr->pDnArray,
|
||
prnr->CurrentDN,
|
||
pdwBufferLength ? *pdwBufferLength : 0
|
||
));
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
SetLastError( status );
|
||
status = SOCKET_ERROR;
|
||
}
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NTDS_LookupServiceEnd(
|
||
IN HANDLE hLookup
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
End\cleanup query on RnR handle.
|
||
|
||
Arguments:
|
||
|
||
hLookup -- RnR query handle from NTDS_LookupServiceBegin
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
SOCKET_ERROR on failure. GetLastError() contains status.
|
||
|
||
--*/
|
||
{
|
||
PRNR_LOOKUP prnr = (PRNR_LOOKUP) hLookup;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NTDS_LookupServiceEnd( %p )\n",
|
||
hLookup ));
|
||
|
||
//
|
||
// validate lookup handle
|
||
// - close LDAP connection
|
||
// - free lookup blob
|
||
//
|
||
|
||
if ( !prnr ||
|
||
prnr->Signature != RNR_SIGNATURE )
|
||
{
|
||
DNS_ASSERT( prnr && prnr->Signature == RNR_SIGNATURE_FREE );
|
||
return SetError( WSA_INVALID_HANDLE );
|
||
}
|
||
|
||
DisconnectFromLDAPDirectory( & prnr->pRnrConnection );
|
||
|
||
FreeRnrLookup( prnr );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// NSP defintion
|
||
//
|
||
|
||
NSP_ROUTINE nsrVector =
|
||
{
|
||
FIELD_OFFSET( NSP_ROUTINE, NSPIoctl ),
|
||
1, // major version
|
||
1, // minor version
|
||
NTDS_Cleanup,
|
||
NTDS_LookupServiceBegin,
|
||
NTDS_LookupServiceNext,
|
||
NTDS_LookupServiceEnd,
|
||
NTDS_SetService,
|
||
NTDS_InstallServiceClass,
|
||
NTDS_RemoveServiceClass,
|
||
NTDS_GetServiceClassInfo
|
||
};
|
||
|
||
|
||
INT
|
||
WINAPI
|
||
NSPStartup(
|
||
IN PGUID pProviderId,
|
||
OUT LPNSP_ROUTINE psnpRoutines
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main NTDS provider entry point.
|
||
|
||
This exposes the NTDS provider to the world.
|
||
|
||
Arguments:
|
||
|
||
pProviderId -- provider GUID
|
||
|
||
psnpRoutines -- address to receive the NTDS provider definition
|
||
(the NSP table);
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"NSPStartup( %p %p )\n",
|
||
pProviderId,
|
||
psnpRoutines ));
|
||
IF_DNSDBG( TRACE )
|
||
{
|
||
DnsDbg_Guid(
|
||
"NSPStartup() Provider GUID:",
|
||
pProviderId );
|
||
}
|
||
|
||
//
|
||
// copy NTDS RnR NSP table to caller
|
||
//
|
||
|
||
RtlCopyMemory( psnpRoutines, &nsrVector, sizeof(nsrVector) );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// DLL exports
|
||
//
|
||
// Other exports beyond NSPStartup
|
||
//
|
||
|
||
RNR_STATUS
|
||
WINAPI
|
||
InstallNTDSProvider(
|
||
IN PWSTR szProviderName OPTIONAL,
|
||
IN PWSTR szProviderPath OPTIONAL,
|
||
IN PGUID pProviderId OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
IN PWSTR szProviderName OPTIONAL, // NULL defaults to name "NTDS"
|
||
IN PWSTR szProviderPath OPTIONAL, // NULL defaults to path
|
||
// "%SystemRoot%\System32\winrnr.dll"
|
||
IN PGUID pProviderId OPTIONAL ); // NULL defaults to GUID
|
||
// 3b2637ee-e580-11cf-a555-00c04fd8d4ac
|
||
--*/
|
||
{
|
||
WORD wVersionRequested;
|
||
WSADATA wsaData;
|
||
INT err;
|
||
|
||
wVersionRequested = MAKEWORD( 1, 1 );
|
||
|
||
err = WSAStartup( wVersionRequested, &wsaData );
|
||
if ( err != 0 )
|
||
{
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
//
|
||
// Confirm that the WinSock DLL supports 1.1.
|
||
// Note that if the DLL supports versions greater
|
||
// than 2.0 in addition to 1.1, it will still return
|
||
// 2.0 in wVersion since that is the version we
|
||
// requested.
|
||
//
|
||
if ( LOBYTE( wsaData.wVersion ) != 1 ||
|
||
HIBYTE( wsaData.wVersion ) != 1 )
|
||
{
|
||
err = ERROR_FILE_NOT_FOUND;
|
||
goto Done;
|
||
}
|
||
|
||
err = WSCInstallNameSpace(
|
||
szProviderName ? szProviderName : g_NtdsProviderName,
|
||
szProviderPath ? szProviderPath : g_NtdsProviderPath,
|
||
NS_NTDS,
|
||
0,
|
||
pProviderId ? pProviderId : &g_NtdsProviderGuid );
|
||
|
||
if ( err != ERROR_SUCCESS )
|
||
{
|
||
WSCUnInstallNameSpace( pProviderId ? pProviderId : &g_NtdsProviderGuid );
|
||
|
||
err = WSCInstallNameSpace(
|
||
szProviderName ? szProviderName : g_NtdsProviderName,
|
||
szProviderPath ? szProviderPath : g_NtdsProviderPath,
|
||
NS_NTDS,
|
||
0,
|
||
pProviderId ? pProviderId : &g_NtdsProviderGuid );
|
||
if ( err )
|
||
{
|
||
err = ERROR_BAD_ENVIRONMENT;
|
||
}
|
||
}
|
||
|
||
Done:
|
||
|
||
WSACleanup();
|
||
return( (DWORD)err );
|
||
}
|
||
|
||
|
||
|
||
RNR_STATUS
|
||
WINAPI
|
||
RemoveNTDSProvider(
|
||
IN PGUID pProviderId OPTIONAL
|
||
)
|
||
{
|
||
WORD wVersionRequested;
|
||
WSADATA wsaData;
|
||
INT err;
|
||
|
||
wVersionRequested = MAKEWORD( 1, 1 );
|
||
|
||
err = WSAStartup( wVersionRequested, &wsaData );
|
||
if ( err != 0 )
|
||
{
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
//
|
||
// Confirm that the WinSock DLL supports 1.1.
|
||
// Note that if the DLL supports versions greater
|
||
// than 2.0 in addition to 1.1, it will still return
|
||
// 2.0 in wVersion since that is the version we
|
||
// requested.
|
||
//
|
||
|
||
if ( LOBYTE( wsaData.wVersion ) != 1 ||
|
||
HIBYTE( wsaData.wVersion ) != 1 )
|
||
{
|
||
WSACleanup();
|
||
return( ERROR_FILE_NOT_FOUND );
|
||
}
|
||
|
||
WSCUnInstallNameSpace( pProviderId ? pProviderId : &g_NtdsProviderGuid );
|
||
|
||
WSACleanup();
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// DLL init\cleanup
|
||
//
|
||
|
||
BOOL
|
||
InitializeDll(
|
||
IN HINSTANCE hInstance,
|
||
IN DWORD dwReason,
|
||
IN PVOID pReserved
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dll init.
|
||
|
||
Arguments:
|
||
|
||
hdll -- instance handle
|
||
|
||
dwReason -- reason
|
||
|
||
pReserved -- reserved
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful.
|
||
FALSE on error.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// process attach
|
||
// - ignore thread attach\detach
|
||
//
|
||
|
||
if ( dwReason == DLL_PROCESS_ATTACH )
|
||
{
|
||
if ( ! DisableThreadLibraryCalls( hInstance ) )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// create recurse lock through TLS
|
||
// - start open
|
||
//
|
||
|
||
g_TlsIndex = TlsAlloc();
|
||
if ( g_TlsIndex == 0xFFFFFFFF )
|
||
{
|
||
// Could not allocate a thread table index.
|
||
WINRNR_PRINT(( "WINRNR!InitializeDll - TlsAlloc() failed\n" ));
|
||
return( FALSE );
|
||
}
|
||
if ( !ReleaseRecurseLock( "InitializeDll" ) )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
|
||
#if DBG
|
||
//
|
||
// init debug logging
|
||
// - do for any process beyond simple attach
|
||
//
|
||
// start logging with log filename generated to be
|
||
// unique for this process
|
||
//
|
||
// do NOT put drive specification in the file path
|
||
// do NOT set the debug flag -- the flag is read from
|
||
// the winrnr.flag file
|
||
//
|
||
|
||
{
|
||
CHAR szlogFileName[ 30 ];
|
||
|
||
sprintf(
|
||
szlogFileName,
|
||
"winrnr.%d.log",
|
||
GetCurrentProcessId() );
|
||
|
||
Dns_StartDebug(
|
||
0,
|
||
"winrnr.flag",
|
||
NULL,
|
||
szlogFileName,
|
||
0 );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// process detach
|
||
// - cleanup IF pReserved==NULL which indicates detach due
|
||
// to FreeLibrary
|
||
// - if process is exiting do nothing
|
||
//
|
||
|
||
else if ( dwReason == DLL_PROCESS_DETACH
|
||
&&
|
||
pReserved == NULL )
|
||
{
|
||
if ( g_TlsIndex != 0xFFFFFFFF )
|
||
{
|
||
if ( TlsFree( g_TlsIndex ) == FALSE )
|
||
{
|
||
// Could not free thread table index.
|
||
WINRNR_PRINT((
|
||
"WINRNR!InitializeDll - TlsFree( Index )\n"
|
||
"failed with error code: 0%x\n",
|
||
GetLastError() ));
|
||
return( FALSE );
|
||
}
|
||
g_TlsIndex = 0xFFFFFFFF;
|
||
}
|
||
}
|
||
|
||
return( TRUE );
|
||
}
|
||
|
||
//
|
||
// End winrnr.c
|
||
//
|
||
|