mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5862 lines
136 KiB
5862 lines
136 KiB
/*++
|
|
|
|
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
|
|
//
|
|
|