Source code of Windows XP (NT5)
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

/*++
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
//