4229 lines
111 KiB
C
4229 lines
111 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1987-1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
getdcnam.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
NetGetDCName API
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Ported from Lan Man 2.0
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User mode only.
|
|||
|
Contains NT-specific code.
|
|||
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
09-Feb-1989 (PaulC)
|
|||
|
Created file, to hold NetGetDCName.
|
|||
|
|
|||
|
18-Apr-1989 (Ericpe)
|
|||
|
Implemented NetGetDCName.
|
|||
|
|
|||
|
30-May-1989 (DannyGl)
|
|||
|
Reduced DosReadMailslot timeout.
|
|||
|
|
|||
|
07-Jul-1989 (NealF)
|
|||
|
Use I_NetNameCanonicalize
|
|||
|
|
|||
|
27-Jul-1989 (WilliamW)
|
|||
|
Use WIN3 manifest for WIN3.0 compatibility
|
|||
|
|
|||
|
03-Jan-1990 (WilliamW)
|
|||
|
canonicalize domain and use I_NetCompareName
|
|||
|
|
|||
|
08-Jun-1991 (CliffV)
|
|||
|
Ported to NT
|
|||
|
|
|||
|
23-Jul-1991 JohnRo
|
|||
|
Implement downlevel NetGetDCName.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
#include <rpc.h>
|
|||
|
#include <ntrpcp.h> // needed by rpcasync.h
|
|||
|
#include <rpcasync.h> // I_RpcExceptionFilter
|
|||
|
#include <logon_c.h>// includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
#include <windef.h>
|
|||
|
#include <lmcons.h>
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#include <stdio.h>
|
|||
|
|
|||
|
#include <winbase.h>
|
|||
|
#include <winsock2.h>
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
#include <accessp.h>
|
|||
|
#include <align.h>
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#include <debuglib.h> // IF_DEBUG()
|
|||
|
#include <dsgetdc.h> // DsGetDcName()
|
|||
|
#include <dsgetdcp.h> // DsGetDcNameWithAccount()
|
|||
|
#include <icanon.h> // NAMETYPE_* defines NetpIsRemote(), NIRFLAG_ equates.
|
|||
|
#include <lmapibuf.h>
|
|||
|
#include <lmerr.h>
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
#include <lmremutl.h> // SUPPORTS_* defines
|
|||
|
#include <lmserver.h> // SV_TYPE_* defines
|
|||
|
#include <lmsvc.h> // SERVICE_* defines
|
|||
|
#include <lmwksta.h>
|
|||
|
#include <logonp.h> // NetpLogon routines
|
|||
|
#include <nlbind.h> // Netlogon RPC binding cache init routines
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#include <netdebug.h> // NetpKdPrint
|
|||
|
#include <netlib.h> // NetpMemoryFree
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
#include <netlibnt.h> // NetpApiStatusToNtStatus
|
|||
|
#include <netrpc.h>
|
|||
|
#include <rxdomain.h> // RxNetGetDCName().
|
|||
|
#include <string.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#include <tstring.h> // NetpCopyStrToWStr()
|
|||
|
|
|||
|
#if DBG
|
|||
|
#define NETLOGONDBG 1
|
|||
|
#endif // DBG
|
|||
|
#include <nldebug.h> // NlPrint()
|
|||
|
#include <ntddbrow.h> // Needed by nlcommon.h
|
|||
|
#include <nlcommon.h> // Definitions shared with netlogon
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Only dynamically initialize winsock.
|
|||
|
//
|
|||
|
CRITICAL_SECTION GlobalDCNameCritSect;
|
|||
|
BOOLEAN DsGetDcWsaInitialized;
|
|||
|
|
|||
|
#define LOCKDOMAINSEM() EnterCriticalSection( &GlobalDCNameCritSect )
|
|||
|
#define UNLOCKDOMAINSEM() LeaveCriticalSection( &GlobalDCNameCritSect )
|
|||
|
|
|||
|
// end global dll data
|
|||
|
|
|||
|
#ifdef WIN32_CHICAGO // from net\inc\logonp.h
|
|||
|
NET_API_STATUS
|
|||
|
NetpLogonWriteMailslot(
|
|||
|
IN LPWSTR MailslotName,
|
|||
|
IN LPVOID Buffer,
|
|||
|
IN DWORD BufferSize
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
NetpApiStatusToNtStatus(
|
|||
|
NET_API_STATUS NetStatus
|
|||
|
);
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
DCNameInitialize(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Perform per-process initialization.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
//
|
|||
|
// Initialize the RPC binding cache.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NlBindingAttachDll();
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the DLL critsects.
|
|||
|
//
|
|||
|
|
|||
|
try {
|
|||
|
InitializeCriticalSection( &GlobalDCNameCritSect );
|
|||
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|||
|
NlPrint((0,"NETAPI32.DLL: Cannot initialize GlobalDCNameCritSect\n"));
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Initialize globals
|
|||
|
//
|
|||
|
|
|||
|
DsGetDcWsaInitialized = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the cache of discovered domains.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpDcInitializeCache();
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
NlPrint((0,"NETAPI32.DLL: Cannot NetpDcinitializeCache\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DCNameClose(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Perform per-process cleanup.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
//
|
|||
|
// Shutdown the RPC binding cache.
|
|||
|
//
|
|||
|
|
|||
|
NlBindingDetachDll();
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
//
|
|||
|
// If we initialized winsock,
|
|||
|
// cleanup.
|
|||
|
//
|
|||
|
|
|||
|
LOCKDOMAINSEM();
|
|||
|
if ( DsGetDcWsaInitialized ) {
|
|||
|
WSACleanup();
|
|||
|
DsGetDcWsaInitialized = FALSE;
|
|||
|
}
|
|||
|
UNLOCKDOMAINSEM();
|
|||
|
|
|||
|
//
|
|||
|
// Delete the critsect that protects the DCName cache
|
|||
|
//
|
|||
|
|
|||
|
DeleteCriticalSection( &GlobalDCNameCritSect );
|
|||
|
|
|||
|
//
|
|||
|
// Free the cache of discovered DCs.
|
|||
|
//
|
|||
|
|
|||
|
NetpDcUninitializeCache();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
#define MAX_PRINTF_LEN 1024 // Arbitrary.
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NlPrintRoutine(
|
|||
|
IN DWORD DebugFlag,
|
|||
|
IN LPSTR Format,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Local version of NlPrintRoutine for those instances where we're not
|
|||
|
compiled directly into the netlogon service.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
extern BOOL ReallyVerbose;
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
// NetlibpTrace |= NETLIB_DEBUG_LOGON; // ?? Force verbosity
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
va_list arglist;
|
|||
|
char OutputBuffer[MAX_PRINTF_LEN];
|
|||
|
ULONG length = 0;
|
|||
|
static BeginningOfLine = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Handle the beginning of a new line.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
if ( BeginningOfLine ) {
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
if ( ReallyVerbose ) {
|
|||
|
printf( " " );
|
|||
|
}
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
}
|
|||
|
|
|||
|
va_start(arglist, Format);
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
length = (ULONG) vsprintf(OutputBuffer, Format, arglist);
|
|||
|
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
length = (ULONG) vsprintf(OutputBuffer + length - 1, Format, arglist);
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
va_end(arglist);
|
|||
|
BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
|
|||
|
|
|||
|
// Output buffer may contain percent signs (like "%SystemRoot%"), so
|
|||
|
// print it without parsing it.
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
if ( ReallyVerbose ) {
|
|||
|
printf( "%s", (PCH) OutputBuffer);
|
|||
|
}
|
|||
|
#else NETTEST_UTILITY
|
|||
|
(void) DbgPrint( "%s", (PCH) OutputBuffer);
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
OutputDebugString( OutputBuffer);
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
}
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
//
|
|||
|
// Have my own version of RtlAssert so debug versions of netlogon really assert on
|
|||
|
// free builds.
|
|||
|
//
|
|||
|
VOID
|
|||
|
NlAssertFailed(
|
|||
|
IN PVOID FailedAssertion,
|
|||
|
IN PVOID FileName,
|
|||
|
IN ULONG LineNumber,
|
|||
|
IN PCHAR Message OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
NlPrint((0, "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
|
|||
|
Message ? Message : "",
|
|||
|
FailedAssertion,
|
|||
|
FileName,
|
|||
|
LineNumber
|
|||
|
));
|
|||
|
#else NETTEST_UTILITY
|
|||
|
RtlAssert( FailedAssertion, FileName, LineNumber, Message );
|
|||
|
#endif NETTEST_UTILITY
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
#endif //WIN32_CHICAGO
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
|
|||
|
VOID
|
|||
|
NlpDumpBuffer(
|
|||
|
IN DWORD DebugFlag,
|
|||
|
PVOID Buffer,
|
|||
|
DWORD BufferSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Dumps the buffer content on to the debugger output.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DebugFlag: Debug flag to pass on to NlPrintRoutine
|
|||
|
|
|||
|
Buffer: buffer pointer.
|
|||
|
|
|||
|
BufferSize: size of the buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#define NUM_CHARS 16
|
|||
|
|
|||
|
DWORD i, limit;
|
|||
|
CHAR TextBuffer[NUM_CHARS + 1];
|
|||
|
LPBYTE BufferPtr = Buffer;
|
|||
|
|
|||
|
//
|
|||
|
// Hex dump of the bytes
|
|||
|
//
|
|||
|
limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
|
|||
|
|
|||
|
for (i = 0; i < limit; i++) {
|
|||
|
|
|||
|
if (i < BufferSize) {
|
|||
|
|
|||
|
NlPrint((0,"%02x ", BufferPtr[i]));
|
|||
|
|
|||
|
if (BufferPtr[i] < 31 ) {
|
|||
|
TextBuffer[i % NUM_CHARS] = '.';
|
|||
|
} else if (BufferPtr[i] == '\0') {
|
|||
|
TextBuffer[i % NUM_CHARS] = ' ';
|
|||
|
} else {
|
|||
|
TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
NlPrint((0," "));
|
|||
|
TextBuffer[i % NUM_CHARS] = ' ';
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ((i + 1) % NUM_CHARS == 0) {
|
|||
|
TextBuffer[NUM_CHARS] = 0;
|
|||
|
NlPrint((0," %s\n", TextBuffer));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( DebugFlag );
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NlBrowserSendDatagram(
|
|||
|
IN PVOID ContextDomainInfo,
|
|||
|
IN ULONG IpAddress,
|
|||
|
IN LPWSTR UnicodeDestinationName,
|
|||
|
IN DGRECEIVER_NAME_TYPE NameType,
|
|||
|
IN LPWSTR TransportName,
|
|||
|
IN LPSTR OemMailslotName,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG BufferSize,
|
|||
|
IN OUT PBOOL FlushNameOnOneIpTransport OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Send the specified mailslot message to the specified mailslot on the
|
|||
|
specified server on the specified transport..
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DomainInfo - Hosted domain sending the datagram
|
|||
|
|
|||
|
IpAddress - IpAddress of the machine to send the pind to.
|
|||
|
If zero, UnicodeDestinationName must be specified.
|
|||
|
If ALL_IP_TRANSPORTS, UnicodeDestination must be specified but the datagram
|
|||
|
will only be sent on IP transports.
|
|||
|
|
|||
|
UnicodeDestinationName -- Name of the server to send to.
|
|||
|
|
|||
|
NameType -- Type of name represented by UnicodeDestinationName.
|
|||
|
|
|||
|
TransportName -- Name of the transport to send on.
|
|||
|
Use NULL to send on all transports.
|
|||
|
|
|||
|
OemMailslotName -- Name of the mailslot to send to.
|
|||
|
|
|||
|
Buffer -- Specifies a pointer to the mailslot message to send.
|
|||
|
|
|||
|
BufferSize -- Size in bytes of the mailslot message
|
|||
|
|
|||
|
FlushNameOnOneIpTransport -- Ignored in this implementation
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
WCHAR NetlogonMailslotName[MAX_PATH+1];
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check.
|
|||
|
//
|
|||
|
|
|||
|
if ( ContextDomainInfo != NULL ||
|
|||
|
TransportName != NULL ) {
|
|||
|
|
|||
|
NlPrint((NL_CRITICAL, "NETAPI32: NlBrowserSendDatagram internal error.\n" ));
|
|||
|
return STATUS_INTERNAL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Start building the destination mailslot name.
|
|||
|
//
|
|||
|
|
|||
|
NetlogonMailslotName[0] = '\\';
|
|||
|
NetlogonMailslotName[1] = '\\';
|
|||
|
|
|||
|
if ( UnicodeDestinationName != NULL ) {
|
|||
|
wcscpy(NetlogonMailslotName + 2, UnicodeDestinationName );
|
|||
|
} else {
|
|||
|
NlPrint((NL_CRITICAL, "NETAPI32: NlBrowserSendDatagram internal error 2.\n" ));
|
|||
|
return STATUS_INTERNAL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
switch ( NameType ) {
|
|||
|
case PrimaryDomain: // Primary domain (signature 0), group
|
|||
|
break;
|
|||
|
case DomainName: // DC Domain name (domain name, signature 1c)
|
|||
|
wcscat( NetlogonMailslotName, L"*" );
|
|||
|
break;
|
|||
|
case PrimaryDomainBrowser: // PDC Browser name (domain name, signature 1b), unique
|
|||
|
wcscat( NetlogonMailslotName, L"**" );
|
|||
|
break;
|
|||
|
default:
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
NetpCopyStrToWStr( &NetlogonMailslotName[wcslen(NetlogonMailslotName)],
|
|||
|
OemMailslotName );
|
|||
|
|
|||
|
NetStatus = NetpLogonWriteMailslot(
|
|||
|
NetlogonMailslotName,
|
|||
|
Buffer,
|
|||
|
BufferSize );
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
NlPrint((NL_MAILSLOT,
|
|||
|
"Sent out '%s' message to %ws on all transports.\n",
|
|||
|
NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)Buffer)->Opcode),
|
|||
|
NetlogonMailslotName));
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
#if NETLOGONDBG
|
|||
|
NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize );
|
|||
|
#endif // NETLOGONDBG
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
|
|||
|
Status = NetpApiStatusToNtStatus( NetStatus );
|
|||
|
|
|||
|
NlPrint(( NL_CRITICAL,
|
|||
|
"NetpDcSendPing: cannot write netlogon mailslot: %ws 0x%lx %ld\n",
|
|||
|
UnicodeDestinationName,
|
|||
|
IpAddress,
|
|||
|
NetStatus));
|
|||
|
|
|||
|
} else {
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NlPrint(( NL_MISC, "NlBrowserSendDatagram : returned 0x%lx\n", NetStatus));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
DsWsaInitialize(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize winsock.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
WORD wVersionRequested;
|
|||
|
WSADATA wsaData;
|
|||
|
int err;
|
|||
|
|
|||
|
LOCKDOMAINSEM();
|
|||
|
|
|||
|
if ( !DsGetDcWsaInitialized ) {
|
|||
|
//
|
|||
|
// Initialize winsock.
|
|||
|
//
|
|||
|
|
|||
|
wVersionRequested = MAKEWORD( 1, 1 );
|
|||
|
|
|||
|
NetStatus = WSAStartup( wVersionRequested, &wsaData );
|
|||
|
if ( NetStatus != 0 ) {
|
|||
|
UNLOCKDOMAINSEM();
|
|||
|
NlPrint((NL_CRITICAL, "NETAPI32.DLL: Cannot initialize winsock %ld.\n", NetStatus ));
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
if ( LOBYTE( wsaData.wVersion ) != 1 ||
|
|||
|
HIBYTE( wsaData.wVersion ) != 1 ) {
|
|||
|
WSACleanup();
|
|||
|
UNLOCKDOMAINSEM();
|
|||
|
NlPrint((NL_CRITICAL, "NETAPI32.DLL: Wrong winsock version %ld.\n", wsaData.wVersion ));
|
|||
|
return WSANOTINITIALISED;
|
|||
|
}
|
|||
|
|
|||
|
DsGetDcWsaInitialized = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
UNLOCKDOMAINSEM();
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
DsWsaGetDcName(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN LPCWSTR AccountName OPTIONAL,
|
|||
|
IN ULONG AllowableAccountControlBits,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
IN ULONG InternalFlags,
|
|||
|
IN DWORD Timeout,
|
|||
|
IN LPWSTR NetbiosPrimaryDomainName OPTIONAL,
|
|||
|
IN LPWSTR DnsPrimaryDomainName OPTIONAL,
|
|||
|
IN GUID *PrimaryDomainGuid OPTIONAL,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper for DsIGetDcName that ensures WSA has been initialized.
|
|||
|
i
|
|||
|
Arguments:
|
|||
|
|
|||
|
(See DsIGetDcName).
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
(See DsIGetDcName).
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pass the call through to DsIGetDcName
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsIGetDcName(
|
|||
|
ComputerName,
|
|||
|
AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
NULL, // Tree name is not known
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
InternalFlags,
|
|||
|
NULL, // No send datagram context
|
|||
|
Timeout,
|
|||
|
NetbiosPrimaryDomainName,
|
|||
|
DnsPrimaryDomainName,
|
|||
|
PrimaryDomainGuid,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
//
|
|||
|
// If Winsock has not yet been initialized,
|
|||
|
// initialize it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == WSANOTINITIALISED ) {
|
|||
|
|
|||
|
//
|
|||
|
// Initialize WSA.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsWsaInitialize();
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Repeat the call.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsIGetDcName(
|
|||
|
ComputerName,
|
|||
|
AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
NULL, // Tree name is not known
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
InternalFlags,
|
|||
|
NULL, // No send datagram context
|
|||
|
Timeout,
|
|||
|
NetbiosPrimaryDomainName,
|
|||
|
DnsPrimaryDomainName,
|
|||
|
PrimaryDomainGuid,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
DomainControllerInfo );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free locally used resouces.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
return NetStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
DsLocalGetDcName(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN LPCWSTR AccountName OPTIONAL,
|
|||
|
IN ULONG AllowableAccountControlBits,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
IN ULONG InternalFlags,
|
|||
|
IN DWORD Timeout,
|
|||
|
IN LPWSTR NetbiosPrimaryDomainName OPTIONAL,
|
|||
|
IN LPWSTR DnsPrimaryDomainName OPTIONAL,
|
|||
|
IN LPWSTR DnsPrimaryForestName OPTIONAL,
|
|||
|
IN GUID *PrimaryDomainGuid OPTIONAL,
|
|||
|
OUT PBOOLEAN Local,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper for DsWsaGetDcName that ensures this is a local call.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
(See DsIGetDcName).
|
|||
|
|
|||
|
Local - Returns TRUE if the call is local and this routine performed
|
|||
|
the requested operation.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
(See DsIGetDcName).
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
DWORD LocalOrRemote;
|
|||
|
|
|||
|
//
|
|||
|
// If no computername was specified,
|
|||
|
// mark this as a local call.
|
|||
|
//
|
|||
|
|
|||
|
*Local = TRUE;
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
if ( ComputerName == NULL || ComputerName[0] == '\0' ) {
|
|||
|
|
|||
|
LocalOrRemote = ISLOCAL;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the ComputerName specifies this machine.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
NetStatus = NetpIsRemote(
|
|||
|
(LPWSTR) ComputerName, // uncanon server name
|
|||
|
&LocalOrRemote,
|
|||
|
NULL,
|
|||
|
0 );
|
|||
|
|
|||
|
if (NetStatus != NERR_Success) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
LocalOrRemote = ISLOCAL;
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
//
|
|||
|
// If the call is local,
|
|||
|
// just do it.
|
|||
|
//
|
|||
|
|
|||
|
if ( LocalOrRemote == ISLOCAL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Initialize WSA.
|
|||
|
// (Ignore errors since WSA isn't always needed.)
|
|||
|
//
|
|||
|
|
|||
|
(VOID) DsWsaInitialize();
|
|||
|
|
|||
|
NetStatus = DsIGetDcName(
|
|||
|
NULL, // Don't use computer name. This has to be netbios name
|
|||
|
AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
DnsPrimaryForestName,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
InternalFlags,
|
|||
|
NULL, // No send datagram context
|
|||
|
Timeout,
|
|||
|
NetbiosPrimaryDomainName,
|
|||
|
DnsPrimaryDomainName,
|
|||
|
PrimaryDomainGuid,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
} else {
|
|||
|
*Local = FALSE;
|
|||
|
NetStatus = NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup all locally used resources
|
|||
|
//
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
Cleanup:
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcOpenW(
|
|||
|
IN LPCWSTR DnsName,
|
|||
|
IN ULONG OptionFlags,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR DnsForestName OPTIONAL,
|
|||
|
IN ULONG DcFlags,
|
|||
|
OUT PHANDLE RetGetDcContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Open a context for retrieval of the addresses of machines that have
|
|||
|
registered LDAP.TCP.<xxx> SRV records.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsName - Unicode DNS name of the LDAP server to lookup
|
|||
|
|
|||
|
OptionFlags - Flags affecting the operation of the routine.
|
|||
|
|
|||
|
DS_ONLY_DO_SITE_NAME - Non-site names should be ignored.
|
|||
|
|
|||
|
DS_NOTIFY_AFTER_SITE_RECORDS - Return ERROR_FILEMARK_DETECTED
|
|||
|
after all site specific records have been processed.
|
|||
|
|
|||
|
SiteName - Name of site the client is in.
|
|||
|
|
|||
|
DomainGuid - Specifies the GUID of the domain specified by DnsName.
|
|||
|
This value is used to handle the case of domain renames. If this
|
|||
|
value is specified and DomainName has been renamed, DsGetDcName will
|
|||
|
attempt to locate a DC in the domain having this specified DomainGuid.
|
|||
|
|
|||
|
DnsForestName - Specifies the name of the domain at the root of the tree
|
|||
|
containing DnsName. This value is used in conjunction with DomainGuid
|
|||
|
for finding DnsName if the domain has been renamed.
|
|||
|
|
|||
|
DcFlags - Passes additional information to be used to process the request.
|
|||
|
DcFlags can be a combination values bitwise or'ed together.
|
|||
|
|
|||
|
Any of the following flags are allowed and have the same meaning as
|
|||
|
for DsGetDcName:
|
|||
|
|
|||
|
DS_PDC_REQUIRED
|
|||
|
DS_GC_SERVER_REQUIRED
|
|||
|
DS_WRITABLE_REQUIRED
|
|||
|
DS_FORCE_REDISCOVERY - Avoids DNS cache
|
|||
|
|
|||
|
If no flags are specified, no special DC role is required.
|
|||
|
|
|||
|
RetGetDcContext - Returns an opaque context.
|
|||
|
This context must be freed using DsGetDcClose.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
NO_ERROR: GetDcContext was returned successfully.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
LPSTR DnsNameUtf8 = NULL;
|
|||
|
LPSTR DnsForestNameUtf8 = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Validate the input
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsName == NULL || *DnsName == UNICODE_NULL ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( RetGetDcContext == NULL ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert DnsName and DnsForestName to UTF-8
|
|||
|
//
|
|||
|
|
|||
|
DnsNameUtf8 = NetpAllocUtf8StrFromWStr( DnsName );
|
|||
|
if ( DnsNameUtf8 == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsForestName != NULL ) {
|
|||
|
DnsForestNameUtf8 = NetpAllocUtf8StrFromWStr( DnsForestName );
|
|||
|
if ( DnsForestNameUtf8 == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = NetpDcGetDcOpen( DnsNameUtf8,
|
|||
|
OptionFlags,
|
|||
|
SiteName,
|
|||
|
DomainGuid,
|
|||
|
DnsForestNameUtf8,
|
|||
|
DcFlags,
|
|||
|
RetGetDcContext );
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( DnsNameUtf8 != NULL ) {
|
|||
|
NetpMemoryFree( DnsNameUtf8 );
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsForestNameUtf8 != NULL ) {
|
|||
|
NetpMemoryFree( DnsForestNameUtf8 );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcOpenA(
|
|||
|
IN LPCSTR DnsName,
|
|||
|
IN ULONG OptionFlags,
|
|||
|
IN LPCSTR SiteName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCSTR DnsForestName OPTIONAL,
|
|||
|
IN ULONG DcFlags,
|
|||
|
OUT PHANDLE RetGetDcContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Open a context for retrieval of the addresses of machines that have
|
|||
|
registered LDAP.TCP.<xxx> SRV records.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsName - Unicode DNS name of the LDAP server to lookup
|
|||
|
|
|||
|
OptionFlags - Flags affecting the operation of the routine.
|
|||
|
|
|||
|
DS_ONLY_DO_SITE_NAME - Non-site names should be ignored.
|
|||
|
|
|||
|
DS_NOTIFY_AFTER_SITE_RECORDS - Return ERROR_FILEMARK_DETECTED
|
|||
|
after all site specific records have been processed.
|
|||
|
|
|||
|
SiteName - Name of site the client is in.
|
|||
|
|
|||
|
DomainGuid - Specifies the GUID of the domain specified by DnsName.
|
|||
|
This value is used to handle the case of domain renames. If this
|
|||
|
value is specified and DomainName has been renamed, DsGetDcName will
|
|||
|
attempt to locate a DC in the domain having this specified DomainGuid.
|
|||
|
|
|||
|
DnsForestName - Specifies the name of the domain at the root of the tree
|
|||
|
containing DnsName. This value is used in conjunction with DomainGuid
|
|||
|
for finding DnsName if the domain has been renamed.
|
|||
|
|
|||
|
DcFlags - Passes additional information to be used to process the request.
|
|||
|
DcFlags can be a combination values bitwise or'ed together.
|
|||
|
|
|||
|
Any of the following flags are allowed and have the same meaning as
|
|||
|
for DsGetDcName:
|
|||
|
|
|||
|
DS_PDC_REQUIRED
|
|||
|
DS_GC_SERVER_REQUIRED
|
|||
|
DS_WRITABLE_REQUIRED
|
|||
|
DS_FORCE_REDISCOVERY - Avoids DNS cache
|
|||
|
|
|||
|
If no flags are specified, no special DC role is required.
|
|||
|
|
|||
|
RetGetDcContext - Returns an opaque context.
|
|||
|
This context must be freed using DsGetDcClose.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
NO_ERROR: GetDcContext was returned successfully.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
LPWSTR DnsNameW = NULL;
|
|||
|
LPWSTR SiteNameW = NULL;
|
|||
|
LPWSTR DnsForestNameW = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Convert DnsName and DnsForestName to UTF-8
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsName != NULL && *DnsName != '\0' ) {
|
|||
|
DnsNameW = NetpAllocWStrFromAStr( DnsName );
|
|||
|
if ( DnsNameW == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( SiteName != NULL && *SiteName != '\0') {
|
|||
|
SiteNameW = NetpAllocWStrFromAStr( SiteName );
|
|||
|
if ( SiteNameW == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsForestName != NULL && *DnsForestName != '\0' ) {
|
|||
|
DnsForestNameW = NetpAllocWStrFromAStr( DnsForestName );
|
|||
|
if ( DnsForestNameW == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = DsGetDcOpenW( DnsNameW,
|
|||
|
OptionFlags,
|
|||
|
SiteNameW,
|
|||
|
DomainGuid,
|
|||
|
DnsForestNameW,
|
|||
|
DcFlags,
|
|||
|
RetGetDcContext );
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( DnsNameW != NULL ) {
|
|||
|
NetApiBufferFree( DnsNameW );
|
|||
|
}
|
|||
|
|
|||
|
if ( SiteNameW != NULL ) {
|
|||
|
NetApiBufferFree( SiteNameW );
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsForestNameW != NULL ) {
|
|||
|
NetApiBufferFree( DnsForestNameW );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcNextW(
|
|||
|
IN HANDLE GetDcContextHandle,
|
|||
|
OUT PULONG SockAddressCount OPTIONAL,
|
|||
|
OUT LPSOCKET_ADDRESS *SockAddresses OPTIONAL,
|
|||
|
OUT LPWSTR *DnsHostName OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the next logical SRV record for the name opened by DsGetDcOpen.
|
|||
|
The returned record takes into account the weights and priorities specified
|
|||
|
in the SRV records.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
GetDcContextHandle - An opaque context describing the SRV records.
|
|||
|
|
|||
|
SockAddressCount - Returns the number of Addresses in SockAddresses.
|
|||
|
If NULL, addresses will not be looked up.
|
|||
|
|
|||
|
SockAddresses - Returns an array SOCKET_ADDRESS structures for the server.
|
|||
|
All returned addresses will be of family AF_INET or AF_INET6.
|
|||
|
The returned sin_port field contains port from the SRV record.
|
|||
|
A Port of 0 indicate no port is available from DNS.
|
|||
|
This buffer should be freed using LocalFree().
|
|||
|
|
|||
|
DnsHostName - Returns a pointer to the DnsHostName in the SRV record.
|
|||
|
A NULL is returned if no host name is known. Must be freed by
|
|||
|
calling NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: Addresses were returned
|
|||
|
|
|||
|
ERROR_NO_MORE_ITEMS: No more addresses are available.
|
|||
|
|
|||
|
ERROR_FILEMARK_DETECTED: Caller has specified the DS_NOTIFY_AFTER_SITE_RECORDS flag
|
|||
|
and DsGetDcNext has processed all of the site specific SRV records. The caller
|
|||
|
should take any action based on no site specific DCs being available, then
|
|||
|
should call DsGetDcNext to continue on to other DCs.
|
|||
|
|
|||
|
Any other errors returned are those detected while trying to find the A
|
|||
|
records associated with the host of the SRV record. The caller can
|
|||
|
note the error (perhaps so the caller can return this status to
|
|||
|
his caller if no usefull server is found) then call DsGetDcNext
|
|||
|
again to get the next SRV record. The caller can inspect this error
|
|||
|
and return immediately if the caller deems the error serious.
|
|||
|
|
|||
|
The following interesting errors might be returned:
|
|||
|
|
|||
|
DNS_ERROR_RCODE_NAME_ERROR: No A records are available for this SRV record.
|
|||
|
|
|||
|
ERROR_TIMEOUT: DNS server didn't respond in a reasonable time
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
LPSTR DnsHostNameUtf8 = NULL;
|
|||
|
LPWSTR LocalDnsHostName = NULL;
|
|||
|
ULONG LocalSockAddressCount = 0;
|
|||
|
LPSOCKET_ADDRESS LocalSockAddresses = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Call the internal version
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpDcGetDcNext( GetDcContextHandle,
|
|||
|
SockAddressCount != NULL ?
|
|||
|
&LocalSockAddressCount :
|
|||
|
NULL,
|
|||
|
SockAddresses != NULL ?
|
|||
|
&LocalSockAddresses :
|
|||
|
NULL,
|
|||
|
DnsHostName != NULL ?
|
|||
|
&DnsHostNameUtf8 :
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the host name to Unicode, if needed
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsHostName != NULL ) {
|
|||
|
LocalDnsHostName = NetpAllocWStrFromUtf8Str( DnsHostNameUtf8 );
|
|||
|
if ( LocalDnsHostName == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
//
|
|||
|
// Return the data on success or clean up on error
|
|||
|
// (No need to free DnsHostNameUtf8 as it isn't allocated)
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
|
|||
|
if ( SockAddressCount != NULL ) {
|
|||
|
*SockAddressCount = LocalSockAddressCount;
|
|||
|
}
|
|||
|
if ( SockAddresses != NULL ) {
|
|||
|
*SockAddresses = LocalSockAddresses;
|
|||
|
}
|
|||
|
if ( DnsHostName != NULL ) {
|
|||
|
*DnsHostName = LocalDnsHostName;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if ( LocalSockAddresses != NULL ) {
|
|||
|
LocalFree( LocalSockAddresses );
|
|||
|
}
|
|||
|
if ( LocalDnsHostName != NULL ) {
|
|||
|
NetApiBufferFree( LocalDnsHostName );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcNextA(
|
|||
|
IN HANDLE GetDcContextHandle,
|
|||
|
OUT PULONG SockAddressCount OPTIONAL,
|
|||
|
OUT LPSOCKET_ADDRESS *SockAddresses OPTIONAL,
|
|||
|
OUT LPSTR *DnsHostName OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the next logical SRV record for the name opened by DsGetDcOpen.
|
|||
|
The returned record takes into account the weights and priorities specified
|
|||
|
in the SRV records.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
GetDcContextHandle - An opaque context describing the SRV records.
|
|||
|
|
|||
|
SockAddressCount - Returns the number of Addresses in SockAddresses.
|
|||
|
If NULL, addresses will not be looked up.
|
|||
|
|
|||
|
SockAddresses - Returns an array SOCKET_ADDRESS structures for the server.
|
|||
|
All returned addresses will be of family AF_INET or AF_INET6.
|
|||
|
The returned sin_port field contains port from the SRV record.
|
|||
|
A Port of 0 indicate no port is available from DNS.
|
|||
|
This buffer should be freed using LocalFree().
|
|||
|
|
|||
|
DnsHostName - Returns a pointer to the DnsHostName in the SRV record.
|
|||
|
A NULL is returned if no host name is known. Must be freed by
|
|||
|
calling NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: Addresses were returned
|
|||
|
|
|||
|
ERROR_NO_MORE_ITEMS: No more addresses are available.
|
|||
|
|
|||
|
ERROR_FILEMARK_DETECTED: Caller has specified the DS_NOTIFY_AFTER_SITE_RECORDS flag
|
|||
|
and DsGetDcNext has processed all of the site specific SRV records. The caller
|
|||
|
should take any action based on no site specific DCs being available, then
|
|||
|
should call DsGetDcNext to continue on to other DCs.
|
|||
|
|
|||
|
Any other errors returned are those detected while trying to find the A
|
|||
|
records associated with the host of the SRV record. The caller can
|
|||
|
note the error (perhaps so the caller can return this status to
|
|||
|
his caller if no usefull server is found) then call DsGetDcNext
|
|||
|
again to get the next SRV record. The caller can inspect this error
|
|||
|
and return immediately if the caller deems the error serious.
|
|||
|
|
|||
|
The following interesting errors might be returned:
|
|||
|
|
|||
|
DNS_ERROR_RCODE_NAME_ERROR: No A records are available for this SRV record.
|
|||
|
|
|||
|
ERROR_TIMEOUT: DNS server didn't respond in a reasonable time
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|||
|
LPWSTR DnsHostNameW = NULL;
|
|||
|
LPSTR LocalDnsHostName = NULL;
|
|||
|
ULONG LocalSockAddressCount = 0;
|
|||
|
LPSOCKET_ADDRESS LocalSockAddresses = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Call the Unicode version
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsGetDcNextW( GetDcContextHandle,
|
|||
|
SockAddressCount != NULL ?
|
|||
|
&LocalSockAddressCount :
|
|||
|
NULL,
|
|||
|
SockAddresses != NULL ?
|
|||
|
&LocalSockAddresses :
|
|||
|
NULL,
|
|||
|
DnsHostName != NULL ?
|
|||
|
&DnsHostNameW :
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the host name to Unicode, if needed
|
|||
|
//
|
|||
|
|
|||
|
if ( DnsHostName != NULL ) {
|
|||
|
LocalDnsHostName = NetpAllocAStrFromWStr( DnsHostNameW );
|
|||
|
if ( LocalDnsHostName == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( DnsHostNameW != NULL ) {
|
|||
|
NetApiBufferFree( DnsHostNameW );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return the data on success or clean up on error
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR ) {
|
|||
|
|
|||
|
if ( SockAddressCount != NULL ) {
|
|||
|
*SockAddressCount = LocalSockAddressCount;
|
|||
|
}
|
|||
|
if ( SockAddresses != NULL ) {
|
|||
|
*SockAddresses = LocalSockAddresses;
|
|||
|
}
|
|||
|
if ( DnsHostName != NULL ) {
|
|||
|
*DnsHostName = LocalDnsHostName;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if ( LocalSockAddresses != NULL ) {
|
|||
|
LocalFree( LocalSockAddresses );
|
|||
|
}
|
|||
|
if ( LocalDnsHostName != NULL ) {
|
|||
|
NetApiBufferFree( LocalDnsHostName );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
WINAPI
|
|||
|
DsGetDcCloseW(
|
|||
|
IN HANDLE GetDcContextHandle
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free the context allocated by DsGetDcOpen
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
GetDcContextHandle - An opaque context describing the SRV records.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Just call the internal version
|
|||
|
//
|
|||
|
NetpDcGetDcClose( GetDcContextHandle );
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcNameA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
IN LPCSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return DsGetDcNameWithAccountA( ComputerName,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
DomainName,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
DomainControllerInfo );
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcNameWithAccountA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
IN LPCSTR AccountName OPTIONAL,
|
|||
|
IN ULONG AllowableAccountControlBits,
|
|||
|
IN LPCSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Same as DsGetDcNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD WinStatus;
|
|||
|
LPWSTR UnicodeComputerName = NULL;
|
|||
|
LPWSTR UnicodeAccountName = NULL;
|
|||
|
LPWSTR UnicodeDomainName = NULL;
|
|||
|
LPWSTR UnicodeSiteName = NULL;
|
|||
|
|
|||
|
LPSTR AnsiDomainControllerName = NULL;
|
|||
|
ULONG AnsiDomainControllerNameSize = 0;
|
|||
|
LPSTR AnsiDomainControllerAddress = NULL;
|
|||
|
ULONG AnsiDomainControllerAddressSize = 0;
|
|||
|
LPSTR AnsiDomainName = NULL;
|
|||
|
ULONG AnsiDomainNameSize = 0;
|
|||
|
LPSTR AnsiForestName = NULL;
|
|||
|
ULONG AnsiForestNameSize = 0;
|
|||
|
LPSTR AnsiDcSiteName = NULL;
|
|||
|
ULONG AnsiDcSiteNameSize = 0;
|
|||
|
LPSTR AnsiClientSiteName = NULL;
|
|||
|
ULONG AnsiClientSiteNameSize = 0;
|
|||
|
CHAR szBuf[] = "";
|
|||
|
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
PDOMAIN_CONTROLLER_INFOW DomainControllerInfoW = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Convert input parameters to Unicode.
|
|||
|
//
|
|||
|
|
|||
|
*DomainControllerInfo = NULL;
|
|||
|
|
|||
|
if ( ComputerName != NULL ) {
|
|||
|
UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
|
|||
|
|
|||
|
if ( UnicodeComputerName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( AccountName != NULL ) {
|
|||
|
UnicodeAccountName = NetpAllocWStrFromAStr( AccountName );
|
|||
|
|
|||
|
if ( UnicodeAccountName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainName != NULL ) {
|
|||
|
UnicodeDomainName = NetpAllocWStrFromAStr( DomainName );
|
|||
|
|
|||
|
if ( UnicodeDomainName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( SiteName != NULL ) {
|
|||
|
UnicodeSiteName = NetpAllocWStrFromAStr( SiteName );
|
|||
|
|
|||
|
if ( UnicodeSiteName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call the Unicode version of the routine.
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = DsGetDcNameWithAccountW(
|
|||
|
UnicodeComputerName,
|
|||
|
UnicodeAccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
UnicodeDomainName,
|
|||
|
DomainGuid,
|
|||
|
UnicodeSiteName,
|
|||
|
Flags,
|
|||
|
&DomainControllerInfoW );
|
|||
|
|
|||
|
if ( WinStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the output structure to Ansi character set.
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainControllerInfoW->DomainControllerName != NULL ) {
|
|||
|
AnsiDomainControllerName = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainControllerName );
|
|||
|
|
|||
|
if ( AnsiDomainControllerName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiDomainControllerNameSize = lstrlenA( AnsiDomainControllerName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainControllerInfoW->DomainControllerAddress != NULL ) {
|
|||
|
AnsiDomainControllerAddress = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainControllerAddress );
|
|||
|
|
|||
|
if ( AnsiDomainControllerAddress == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiDomainControllerAddressSize = lstrlenA( AnsiDomainControllerAddress ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainControllerInfoW->DomainName != NULL ) {
|
|||
|
AnsiDomainName = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainName );
|
|||
|
|
|||
|
if ( AnsiDomainName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiDomainNameSize = lstrlenA( AnsiDomainName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainControllerInfoW->DnsForestName != NULL ) {
|
|||
|
AnsiForestName = NetpAllocAStrFromWStr( DomainControllerInfoW->DnsForestName );
|
|||
|
|
|||
|
if ( AnsiForestName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiForestNameSize = lstrlenA( AnsiForestName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainControllerInfoW->DcSiteName != NULL ) {
|
|||
|
AnsiDcSiteName = NetpAllocAStrFromWStr( DomainControllerInfoW->DcSiteName );
|
|||
|
|
|||
|
if ( AnsiDcSiteName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiDcSiteNameSize = lstrlenA( AnsiDcSiteName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainControllerInfoW->ClientSiteName != NULL ) {
|
|||
|
AnsiClientSiteName = NetpAllocAStrFromWStr( DomainControllerInfoW->ClientSiteName );
|
|||
|
|
|||
|
if ( AnsiClientSiteName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AnsiClientSiteNameSize = lstrlenA( AnsiClientSiteName ) + 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the Ansi version of the structure.
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = NetApiBufferAllocate(
|
|||
|
sizeof(DOMAIN_CONTROLLER_INFOA) +
|
|||
|
AnsiDomainControllerNameSize +
|
|||
|
AnsiDomainControllerAddressSize +
|
|||
|
AnsiDomainNameSize +
|
|||
|
AnsiForestNameSize +
|
|||
|
AnsiDcSiteNameSize +
|
|||
|
AnsiClientSiteNameSize,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
if ( WinStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
Where = (LPBYTE)((*DomainControllerInfo) + 1);
|
|||
|
|
|||
|
//
|
|||
|
// Copy information into the allocated buffer.
|
|||
|
//
|
|||
|
|
|||
|
*(*DomainControllerInfo) = *(PDOMAIN_CONTROLLER_INFOA)DomainControllerInfoW;
|
|||
|
|
|||
|
if ( AnsiDomainControllerName != NULL ) {
|
|||
|
(*DomainControllerInfo)->DomainControllerName = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiDomainControllerName,
|
|||
|
AnsiDomainControllerNameSize );
|
|||
|
Where += AnsiDomainControllerNameSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( AnsiDomainControllerAddress != NULL ) {
|
|||
|
(*DomainControllerInfo)->DomainControllerAddress = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiDomainControllerAddress,
|
|||
|
AnsiDomainControllerAddressSize );
|
|||
|
Where += AnsiDomainControllerAddressSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( AnsiDomainName != NULL ) {
|
|||
|
(*DomainControllerInfo)->DomainName = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiDomainName,
|
|||
|
AnsiDomainNameSize );
|
|||
|
Where += AnsiDomainNameSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( AnsiForestName != NULL ) {
|
|||
|
(*DomainControllerInfo)->DnsForestName = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiForestName,
|
|||
|
AnsiForestNameSize );
|
|||
|
Where += AnsiForestNameSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( AnsiDcSiteName != NULL ) {
|
|||
|
(*DomainControllerInfo)->DcSiteName = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiDcSiteName,
|
|||
|
AnsiDcSiteNameSize );
|
|||
|
Where += AnsiDcSiteNameSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( AnsiClientSiteName != NULL ) {
|
|||
|
(*DomainControllerInfo)->ClientSiteName = Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
AnsiClientSiteName,
|
|||
|
AnsiClientSiteNameSize );
|
|||
|
Where += AnsiClientSiteNameSize;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef WIN32_CHICAGO
|
|||
|
NlPrint((NL_MISC, "DomainControllerName: \t\t\"%s\"\n", AnsiDomainControllerName ? AnsiDomainControllerName : szBuf));
|
|||
|
NlPrint((NL_MISC, "DomainControllerAddress:\t\t\"%s\"\n", AnsiDomainControllerAddress ? AnsiDomainControllerAddress : szBuf ));
|
|||
|
NlPrint((NL_MISC, "DomainControllerAddressType: \t%d\n", DomainControllerInfoW->DomainControllerAddressType ));
|
|||
|
NlPrint((NL_MISC, "DomainGuid : \t\n"));
|
|||
|
NlPrint((NL_MISC, "DomainName: \t\t\t\"%s\"\n", AnsiDomainName ? AnsiDomainName : szBuf));
|
|||
|
NlPrint((NL_MISC, "DnsForestName: \t\t\t\"%s\"\n", AnsiForestName ? AnsiForestName : szBuf));
|
|||
|
NlPrint((NL_MISC, "Flags: \t\t\t\t 0x%x\n", DomainControllerInfoW->Flags));
|
|||
|
NlPrint((NL_MISC, "DcSiteName: \t\t\t\"%s\"\n", AnsiDcSiteName ? AnsiDcSiteName : szBuf));
|
|||
|
NlPrint((NL_MISC, "ClientSiteName: \t\t\t\"%s\"\n", AnsiClientSiteName ? AnsiClientSiteName : szBuf));
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
WinStatus = NO_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// Clean up locally used resources.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( UnicodeComputerName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeComputerName );
|
|||
|
}
|
|||
|
if ( UnicodeAccountName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeAccountName );
|
|||
|
}
|
|||
|
if ( UnicodeDomainName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeDomainName );
|
|||
|
}
|
|||
|
if ( UnicodeSiteName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeSiteName );
|
|||
|
}
|
|||
|
if ( DomainControllerInfoW != NULL ) {
|
|||
|
NetApiBufferFree( DomainControllerInfoW );
|
|||
|
}
|
|||
|
if ( AnsiDomainControllerName != NULL ) {
|
|||
|
NetApiBufferFree( AnsiDomainControllerName );
|
|||
|
}
|
|||
|
if ( AnsiDomainControllerAddress != NULL ) {
|
|||
|
NetApiBufferFree( AnsiDomainControllerAddress );
|
|||
|
}
|
|||
|
if ( AnsiDomainName != NULL ) {
|
|||
|
NetApiBufferFree( AnsiDomainName );
|
|||
|
}
|
|||
|
if ( AnsiForestName != NULL ) {
|
|||
|
NetApiBufferFree( AnsiForestName );
|
|||
|
}
|
|||
|
if ( AnsiDcSiteName != NULL ) {
|
|||
|
NetApiBufferFree( AnsiDcSiteName );
|
|||
|
}
|
|||
|
if ( AnsiClientSiteName != NULL ) {
|
|||
|
NetApiBufferFree( AnsiClientSiteName );
|
|||
|
}
|
|||
|
if ( WinStatus != NO_ERROR ) {
|
|||
|
if ( *DomainControllerInfo != NULL ) {
|
|||
|
NetApiBufferFree( *DomainControllerInfo );
|
|||
|
*DomainControllerInfo = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return WinStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NlWaitForEvent(
|
|||
|
LPWSTR EventName,
|
|||
|
ULONG Timeout
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wait up to Timeout seconds for EventName to be triggered.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
EventName - Name of event to wait on
|
|||
|
|
|||
|
Timeout - Timeout for event (in seconds).
|
|||
|
|
|||
|
Return Status:
|
|||
|
|
|||
|
STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
|
|||
|
STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
HANDLE EventHandle;
|
|||
|
OBJECT_ATTRIBUTES EventAttributes;
|
|||
|
UNICODE_STRING EventNameString;
|
|||
|
LARGE_INTEGER LocalTimeout;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Create an event for us to wait on.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &EventNameString, EventName);
|
|||
|
InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
|
|||
|
|
|||
|
Status = NtCreateEvent(
|
|||
|
&EventHandle,
|
|||
|
SYNCHRONIZE,
|
|||
|
&EventAttributes,
|
|||
|
NotificationEvent,
|
|||
|
(BOOLEAN) FALSE // The event is initially not signaled
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// If the event already exists, the server beat us to creating it.
|
|||
|
// Just open it.
|
|||
|
//
|
|||
|
|
|||
|
if( Status == STATUS_OBJECT_NAME_EXISTS ||
|
|||
|
Status == STATUS_OBJECT_NAME_COLLISION ) {
|
|||
|
|
|||
|
Status = NtOpenEvent( &EventHandle,
|
|||
|
SYNCHRONIZE,
|
|||
|
&EventAttributes );
|
|||
|
|
|||
|
}
|
|||
|
if ( !NT_SUCCESS(Status)) {
|
|||
|
NlPrint((0,"[NETAPI32] OpenEvent failed %lx\n", Status ));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Wait for NETLOGON to initialize. Wait a maximum of Timeout seconds.
|
|||
|
//
|
|||
|
|
|||
|
LocalTimeout.QuadPart = ((LONGLONG)(Timeout)) * (-10000000);
|
|||
|
Status = NtWaitForSingleObject( EventHandle, (BOOLEAN)FALSE, &LocalTimeout);
|
|||
|
(VOID) NtClose( EventHandle );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
|
|||
|
if ( Status == STATUS_TIMEOUT ) {
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED; // Map to an error condition
|
|||
|
}
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NlWaitForNetlogon(
|
|||
|
ULONG Timeout
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wait up to Timeout seconds for the netlogon service to start.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Timeout - Timeout for event (in seconds).
|
|||
|
|
|||
|
Return Status:
|
|||
|
|
|||
|
STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
|
|||
|
STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
SC_HANDLE ScManagerHandle = NULL;
|
|||
|
SC_HANDLE ServiceHandle = NULL;
|
|||
|
SERVICE_STATUS ServiceStatus;
|
|||
|
LPQUERY_SERVICE_CONFIG ServiceConfig;
|
|||
|
LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
|
|||
|
QUERY_SERVICE_CONFIG DummyServiceConfig;
|
|||
|
DWORD ServiceConfigSize;
|
|||
|
|
|||
|
//
|
|||
|
// If the netlogon service is currently running,
|
|||
|
// skip the rest of the tests.
|
|||
|
//
|
|||
|
|
|||
|
Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 0 );
|
|||
|
|
|||
|
if ( NT_SUCCESS(Status) ) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we're in setup,
|
|||
|
// don't bother waiting for netlogon to start.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlDoingSetup() ) {
|
|||
|
return STATUS_NETLOGON_NOT_STARTED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open a handle to the Netlogon Service.
|
|||
|
//
|
|||
|
|
|||
|
ScManagerHandle = OpenSCManager(
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
SC_MANAGER_CONNECT );
|
|||
|
|
|||
|
if (ScManagerHandle == NULL) {
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenSCManager failed: "
|
|||
|
"%lu\n", GetLastError()));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
ServiceHandle = OpenService(
|
|||
|
ScManagerHandle,
|
|||
|
SERVICE_NETLOGON,
|
|||
|
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
|
|||
|
|
|||
|
if ( ServiceHandle == NULL ) {
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenService failed: "
|
|||
|
"%lu\n", GetLastError()));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the Netlogon service isn't configured to be automatically started
|
|||
|
// by the service controller, don't bother waiting for it to start.
|
|||
|
//
|
|||
|
// ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
|
|||
|
// won't allow a null pointer, yet.
|
|||
|
|
|||
|
if ( QueryServiceConfig(
|
|||
|
ServiceHandle,
|
|||
|
&DummyServiceConfig,
|
|||
|
sizeof(DummyServiceConfig),
|
|||
|
&ServiceConfigSize )) {
|
|||
|
|
|||
|
ServiceConfig = &DummyServiceConfig;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
NetStatus = GetLastError();
|
|||
|
if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig failed: "
|
|||
|
"%lu\n", NetStatus));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
AllocServiceConfig = LocalAlloc( 0, ServiceConfigSize );
|
|||
|
ServiceConfig = AllocServiceConfig;
|
|||
|
|
|||
|
if ( AllocServiceConfig == NULL ) {
|
|||
|
Status = STATUS_NO_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ( !QueryServiceConfig(
|
|||
|
ServiceHandle,
|
|||
|
ServiceConfig,
|
|||
|
ServiceConfigSize,
|
|||
|
&ServiceConfigSize )) {
|
|||
|
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig "
|
|||
|
"failed again: %lu\n", GetLastError()));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( ServiceConfig->dwStartType != SERVICE_AUTO_START ) {
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: Netlogon start type invalid:"
|
|||
|
"%lu\n", ServiceConfig->dwStartType ));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop waiting for the netlogon service to start.
|
|||
|
// (Convert Timeout to a number of 10 second iterations)
|
|||
|
//
|
|||
|
|
|||
|
Timeout = (Timeout+9)/10;
|
|||
|
for (;;) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Query the status of the Netlogon service.
|
|||
|
//
|
|||
|
|
|||
|
if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
|
|||
|
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceStatus failed: "
|
|||
|
"%lu\n", GetLastError() ));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return or continue waiting depending on the state of
|
|||
|
// the netlogon service.
|
|||
|
//
|
|||
|
|
|||
|
switch( ServiceStatus.dwCurrentState) {
|
|||
|
case SERVICE_RUNNING:
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
case SERVICE_STOPPED:
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon failed to start,
|
|||
|
// error out now. The caller has waited long enough to start.
|
|||
|
//
|
|||
|
if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
|
|||
|
#if NETLOGONDBG
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
|
|||
|
"Netlogon service couldn't start: %lu %lx\n",
|
|||
|
ServiceStatus.dwWin32ExitCode,
|
|||
|
ServiceStatus.dwWin32ExitCode ));
|
|||
|
if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
|
|||
|
NlPrint((0, " Service specific error code: %lu %lx\n",
|
|||
|
ServiceStatus.dwServiceSpecificExitCode,
|
|||
|
ServiceStatus.dwServiceSpecificExitCode ));
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon has never been started on this boot,
|
|||
|
// continue waiting for it to start.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon is trying to start up now,
|
|||
|
// continue waiting for it to start.
|
|||
|
//
|
|||
|
case SERVICE_START_PENDING:
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Any other state is bogus.
|
|||
|
//
|
|||
|
default:
|
|||
|
NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
|
|||
|
"Invalid service state: %lu\n",
|
|||
|
ServiceStatus.dwCurrentState ));
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Wait ten seconds for the netlogon service to start.
|
|||
|
// If it has successfully started, just return now.
|
|||
|
//
|
|||
|
|
|||
|
Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 10 );
|
|||
|
|
|||
|
if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we've waited long enough for netlogon to start,
|
|||
|
// time out now.
|
|||
|
//
|
|||
|
|
|||
|
if ( (--Timeout) == 0 ) {
|
|||
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/* NOT REACHED */
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( ScManagerHandle != NULL ) {
|
|||
|
(VOID) CloseServiceHandle(ScManagerHandle);
|
|||
|
}
|
|||
|
if ( ServiceHandle != NULL ) {
|
|||
|
(VOID) CloseServiceHandle(ServiceHandle);
|
|||
|
}
|
|||
|
if ( AllocServiceConfig != NULL ) {
|
|||
|
LocalFree( AllocServiceConfig );
|
|||
|
}
|
|||
|
return Status;
|
|||
|
}
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
NettestDsGetDcNameW(
|
|||
|
#else // NETTEST_UTILITY
|
|||
|
DsGetDcNameW(
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsGetDcName API returns the name of a DC in a specified domain.
|
|||
|
The domain may be trusted (directly or indirectly) by the caller or
|
|||
|
may be untrusted. DC selection criteria are supplied to the API to
|
|||
|
indicate preference for a DC with particular characteristics.
|
|||
|
|
|||
|
The DsGetDcName API is available in an ANSI and UNICODE versions.
|
|||
|
This is the Unicode version.
|
|||
|
|
|||
|
The DsGetDcName API does not require any particular access to the
|
|||
|
specified domain. DsGetDcName does not ensure the returned domain
|
|||
|
controller is currently available by default. Rather, the caller
|
|||
|
should attempt to use the returned domain controller. If the domain
|
|||
|
controller is indeed not available, the caller should repeat the
|
|||
|
DsGetDcName call specifying the DS_FORCE_REDISCOVERY flag.
|
|||
|
|
|||
|
The DsGetDcName API is remoted to the Netlogon service on the machine
|
|||
|
specified by ComputerName.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the server to remote this API to.
|
|||
|
Typically, this parameter should be specified as NULL.
|
|||
|
|
|||
|
DomainName - The name of the domain to query. This name can either be a
|
|||
|
DNS-style name (e.g., microsoft.com) or a flat-style name
|
|||
|
(e.g., microsoft).
|
|||
|
|
|||
|
DomainGuid - Specifies the Domain GUID of the domain being queried.
|
|||
|
This value is used to handle the case of domain renames. If this
|
|||
|
value is specified and DomainName has been renamed, DsGetDcName will
|
|||
|
attempt to locate a DC in the domain having this specified DomainGuid.
|
|||
|
|
|||
|
SiteName - Specifies the site name of the site the returned DC should be
|
|||
|
"close" to. The parameter should typically be the site name of the
|
|||
|
site the client is in. If not specified, the site name defaults to
|
|||
|
the site of ComputerName.
|
|||
|
|
|||
|
Flags - Passes additional information to be used to process the request.
|
|||
|
Flags can be a combination values bitwise or'ed together.
|
|||
|
|
|||
|
DomainControllerInfo - Returns a pointer to a DOMAIN_CONTROLLER_INFO
|
|||
|
structure describing the domain controller selected. The returned
|
|||
|
structure must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
ERROR_INVALID_DOMAINNAME - The format of the specified domain name is
|
|||
|
invalid.
|
|||
|
|
|||
|
ERROR_NO_SUCH_DOMAIN: No DC is available for the specified domain or
|
|||
|
the domain does not exist.
|
|||
|
|
|||
|
ERROR_NO_SUCH_USER: A DC responded that the specified user account
|
|||
|
doesn't exist
|
|||
|
|
|||
|
ERROR_INVALID_FLAGS - The flags parameter has conflicting or superfluous
|
|||
|
bits set.
|
|||
|
|
|||
|
ERROR_INTERNAL_ERROR: Unhandled situation detected.
|
|||
|
|
|||
|
Various Winsock errors.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
return DsGetDcNameWithAccountW(
|
|||
|
ComputerName,
|
|||
|
NULL, // no AccountName,
|
|||
|
0, // no AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
DomainControllerInfo );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcNameWithAccountW(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN LPCWSTR AccountName OPTIONAL,
|
|||
|
IN ULONG AllowableAccountControlBits,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
IN GUID *DomainGuid OPTIONAL,
|
|||
|
IN LPCWSTR SiteName OPTIONAL,
|
|||
|
IN ULONG Flags,
|
|||
|
OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsGetDcName API returns the name of a DC in a specified domain.
|
|||
|
The domain may be trusted (directly or indirectly) by the caller or
|
|||
|
may be untrusted. DC selection criteria are supplied to the API to
|
|||
|
indicate preference for a DC with particular characteristics.
|
|||
|
|
|||
|
The DsGetDcName API is available in an ANSI and UNICODE versions.
|
|||
|
This is the Unicode version.
|
|||
|
|
|||
|
The DsGetDcName API does not require any particular access to the
|
|||
|
specified domain. DsGetDcName does not ensure the returned domain
|
|||
|
controller is currently available by default. Rather, the caller
|
|||
|
should attempt to use the returned domain controller. If the domain
|
|||
|
controller is indeed not available, the caller should repeat the
|
|||
|
DsGetDcName call specifying the DS_FORCE_REDISCOVERY flag.
|
|||
|
|
|||
|
The DsGetDcName API is remoted to the Netlogon service on the machine
|
|||
|
specified by ComputerName.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the server to remote this API to.
|
|||
|
Typically, this parameter should be specified as NULL.
|
|||
|
|
|||
|
AccountName - Account name to pass on the ping request.
|
|||
|
If NULL, no account name will be sent.
|
|||
|
|
|||
|
AllowableAccountControlBits - Mask of allowable account types for AccountName.
|
|||
|
Valid bits are those specified by UF_MACHINE_ACCOUNT_MASK.
|
|||
|
Invalid bits are ignored. If more than one bit is specified, the
|
|||
|
account can be of any of the specified types.
|
|||
|
|
|||
|
DomainName - The name of the domain to query. This name can either be a
|
|||
|
DNS-style name (e.g., microsoft.com) or a flat-style name
|
|||
|
(e.g., microsoft).
|
|||
|
|
|||
|
DomainGuid - Specifies the Domain GUID of the domain being queried.
|
|||
|
This value is used to handle the case of domain renames. If this
|
|||
|
value is specified and DomainName has been renamed, DsGetDcName will
|
|||
|
attempt to locate a DC in the domain having this specified DomainGuid.
|
|||
|
|
|||
|
SiteName - Specifies the site name of the site the returned DC should be
|
|||
|
"close" to. The parameter should typically be the site name of the
|
|||
|
site the client is in. If not specified, the site name defaults to
|
|||
|
the site of ComputerName.
|
|||
|
|
|||
|
Flags - Passes additional information to be used to process the request.
|
|||
|
Flags can be a combination values bitwise or'ed together.
|
|||
|
|
|||
|
DomainControllerInfo - Returns a pointer to a DOMAIN_CONTROLLER_INFO
|
|||
|
structure describing the domain controller selected. The returned
|
|||
|
structure must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
ERROR_INVALID_DOMAINNAME - The format of the specified domain name is
|
|||
|
invalid.
|
|||
|
|
|||
|
ERROR_NO_SUCH_DOMAIN: No DC is available for the specified domain or
|
|||
|
the domain does not exist.
|
|||
|
|
|||
|
ERROR_NO_SUCH_USER: A DC responded that the specified user account
|
|||
|
doesn't exist
|
|||
|
|
|||
|
ERROR_INVALID_FLAGS - The flags parameter has conflicting or superfluous
|
|||
|
bits set.
|
|||
|
|
|||
|
ERROR_INTERNAL_ERROR: Unhandled situation detected.
|
|||
|
|
|||
|
Various Winsock errors.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
GUID *PrimaryDomainGuid = NULL;
|
|||
|
LPWSTR NetbiosPrimaryDomainName = NULL;
|
|||
|
LPWSTR DnsPrimaryDomainName = NULL;
|
|||
|
LPWSTR DnsPrimaryForestName = NULL;
|
|||
|
BOOLEAN IsWorkgroupName;
|
|||
|
BOOLEAN Local;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Determine the PrimaryDomainName
|
|||
|
//
|
|||
|
|
|||
|
#ifdef WIN32_CHICAGO
|
|||
|
NetStatus = NetpGetDomainNameExEx( &NetbiosPrimaryDomainName,
|
|||
|
&DnsPrimaryDomainName,
|
|||
|
&IsWorkgroupName );
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
NetStatus = NetpGetDomainNameExExEx( &NetbiosPrimaryDomainName,
|
|||
|
&DnsPrimaryDomainName,
|
|||
|
&DnsPrimaryForestName,
|
|||
|
&PrimaryDomainGuid,
|
|||
|
&IsWorkgroupName );
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
NlPrint(( 0, "DsGetDcNameW: cannot call NetpGetDomainName: %ld\n",
|
|||
|
NetStatus));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
#ifdef WIN32_CHICAGO
|
|||
|
IsWorkgroupName = TRUE;
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#ifdef NETTEST_UTILITY
|
|||
|
IsWorkgroupName = TRUE;
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check the domain name since LSA doesn't and I'll AV below
|
|||
|
//
|
|||
|
|
|||
|
if ( NetbiosPrimaryDomainName != NULL &&
|
|||
|
wcslen( NetbiosPrimaryDomainName) > DNLEN ) {
|
|||
|
NlPrint(( 0, "DsGetDcNameW: Workgroup name is too long: %ld\n",
|
|||
|
wcslen( NetbiosPrimaryDomainName ) ));
|
|||
|
NetStatus = ERROR_INVALID_DOMAINNAME;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If this machine is a member of a workgroup (not a domain),
|
|||
|
// and the API isn't remoted,
|
|||
|
// do the algorithm here.
|
|||
|
// Netlogon isn't running on this machine.
|
|||
|
//
|
|||
|
|
|||
|
if ( IsWorkgroupName ) {
|
|||
|
DWORD Timeout = NL_DC_MAX_TIMEOUT; // 15 seconds
|
|||
|
DWORD DialUpDelayInSeconds;
|
|||
|
|
|||
|
//
|
|||
|
// Read the dial up delay from the registry. Add it to the
|
|||
|
// maximum DC discovery timeout to account for dial up
|
|||
|
// connections. If the value cannot be read, ignore it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlReadDwordNetlogonRegValue("ExpectedDialupDelay",
|
|||
|
&DialUpDelayInSeconds) ) {
|
|||
|
NlPrint(( 0, "DsGetDcNameWithAccountW: Read dial up delay of %ld seconds\n",
|
|||
|
DialUpDelayInSeconds ));
|
|||
|
Timeout += DialUpDelayInSeconds * 1000;
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = DsLocalGetDcName(
|
|||
|
ComputerName,
|
|||
|
AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
DS_PRIMARY_NAME_IS_WORKGROUP,
|
|||
|
Timeout,
|
|||
|
NetbiosPrimaryDomainName,
|
|||
|
DnsPrimaryDomainName,
|
|||
|
DnsPrimaryForestName,
|
|||
|
PrimaryDomainGuid,
|
|||
|
&Local,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
//
|
|||
|
// If the call was performed locally,
|
|||
|
// We're all done regardless of the status.
|
|||
|
//
|
|||
|
|
|||
|
if ( Local ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
//
|
|||
|
// Remote the API to the Netlogon service.
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
*DomainControllerInfo = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
NetStatus = DsrGetDcNameEx2(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
(LPWSTR) AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
(LPWSTR) DomainName,
|
|||
|
DomainGuid,
|
|||
|
(LPWSTR) SiteName,
|
|||
|
Flags,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// If the netlogon service isn't running,
|
|||
|
// and it's in the process of starting,
|
|||
|
// wait for it to start.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == RPC_S_UNKNOWN_IF ) {
|
|||
|
NTSTATUS TempStatus;
|
|||
|
|
|||
|
TempStatus = NlWaitForNetlogon( 90 );
|
|||
|
|
|||
|
|
|||
|
if ( NT_SUCCESS(TempStatus) ) {
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
*DomainControllerInfo = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
NetStatus = DsrGetDcNameEx2(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
(LPWSTR) AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
(LPWSTR) DomainName,
|
|||
|
DomainGuid,
|
|||
|
(LPWSTR) SiteName,
|
|||
|
Flags,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon isn't running on the local machine,
|
|||
|
// or Netlogon is the NT 4.0 version of netlogon (the upgrade case),
|
|||
|
// try doing the call in-process.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == RPC_S_UNKNOWN_IF ||
|
|||
|
NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
|
|||
|
NET_API_STATUS TempStatus;
|
|||
|
DWORD Timeout = NL_DC_MAX_TIMEOUT; // 15 seconds
|
|||
|
DWORD DialUpDelayInSeconds;
|
|||
|
|
|||
|
//
|
|||
|
// Read the dial up delay from the registry. Add it to the
|
|||
|
// maximum DC discovery timeout to account for dial up
|
|||
|
// connections. If the value cannot be read, ignore it.
|
|||
|
//
|
|||
|
|
|||
|
if ( NlReadDwordNetlogonRegValue("ExpectedDialupDelay",
|
|||
|
&DialUpDelayInSeconds) ) {
|
|||
|
NlPrint(( 0, "DsGetDcNameWithAccountW: Read dial up delay of %ld seconds\n",
|
|||
|
DialUpDelayInSeconds ));
|
|||
|
Timeout += DialUpDelayInSeconds * 1000;
|
|||
|
}
|
|||
|
|
|||
|
TempStatus = DsLocalGetDcName(
|
|||
|
ComputerName,
|
|||
|
AccountName,
|
|||
|
AllowableAccountControlBits,
|
|||
|
DomainName,
|
|||
|
DomainGuid,
|
|||
|
SiteName,
|
|||
|
Flags,
|
|||
|
IsWorkgroupName ?
|
|||
|
DS_PRIMARY_NAME_IS_WORKGROUP : 0,
|
|||
|
Timeout,
|
|||
|
NetbiosPrimaryDomainName,
|
|||
|
DnsPrimaryDomainName,
|
|||
|
DnsPrimaryForestName,
|
|||
|
PrimaryDomainGuid,
|
|||
|
&Local,
|
|||
|
DomainControllerInfo );
|
|||
|
|
|||
|
//
|
|||
|
// If the call was performed locally,
|
|||
|
// We're all done regardless of the status.
|
|||
|
//
|
|||
|
|
|||
|
if ( Local ) {
|
|||
|
NetStatus = TempStatus;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
NetpKdPrint(("DsrGetDcName rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
#else // WIN32_CHICAGO
|
|||
|
NlPrint((0, "DsrGetDcName rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup all locally used resources
|
|||
|
//
|
|||
|
|
|||
|
if ( NetbiosPrimaryDomainName != NULL ) {
|
|||
|
NetApiBufferFree( NetbiosPrimaryDomainName );
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsPrimaryDomainName != NULL ) {
|
|||
|
NetApiBufferFree( DnsPrimaryDomainName );
|
|||
|
}
|
|||
|
|
|||
|
if ( DnsPrimaryForestName != NULL ) {
|
|||
|
NetApiBufferFree( DnsPrimaryForestName );
|
|||
|
}
|
|||
|
|
|||
|
if ( PrimaryDomainGuid != NULL ) {
|
|||
|
NetApiBufferFree( PrimaryDomainGuid );
|
|||
|
}
|
|||
|
#ifdef WIN32_CHICAGO
|
|||
|
NlPrint((NL_MISC, "DsGetDcNameWithAccountW rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
#ifndef NETTEST_UTILITY
|
|||
|
#ifndef WIN32_CHICAGO
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetGetDCName (
|
|||
|
IN LPCWSTR ServerName OPTIONAL,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
OUT LPBYTE *Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get the name of the primary domain controller for a domain.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - name of remote server (null for local)
|
|||
|
|
|||
|
DomainName - name of domain (null for primary)
|
|||
|
|
|||
|
Buffer - Returns a pointer to an allcated buffer containing the
|
|||
|
servername of the PDC of the domain. The server name is prefixed
|
|||
|
by \\. The buffer should be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NERR_Success - Success. Buffer contains PDC name prefixed by \\.
|
|||
|
NERR_DCNotFound No DC found for this domain.
|
|||
|
ERROR_INVALID_NAME Badly formed domain name
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = 0;
|
|||
|
PDOMAIN_CONTROLLER_INFOW DomainControllerInfo = NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// API SECURITY - Anyone can call anytime. No code required.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Check if API is to be remoted, and handle downlevel case if so.
|
|||
|
//
|
|||
|
|
|||
|
if ( (ServerName != NULL) && ( ServerName[0] != '\0') ) {
|
|||
|
WCHAR UncCanonServerName[UNCLEN+1];
|
|||
|
DWORD LocalOrRemote;
|
|||
|
|
|||
|
NetStatus = NetpIsRemote(
|
|||
|
(LPWSTR) ServerName, // uncanon server name
|
|||
|
& LocalOrRemote,
|
|||
|
UncCanonServerName, // output: canon
|
|||
|
NIRFLAG_MAPLOCAL // flags: map null to local name
|
|||
|
);
|
|||
|
if (NetStatus != NERR_Success) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
if (LocalOrRemote == ISREMOTE) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
NET_REMOTE_TRY_RPC
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
*Buffer = NULL;
|
|||
|
|
|||
|
NetStatus = NetrGetDCName(
|
|||
|
(LPWSTR) ServerName,
|
|||
|
(LPWSTR) DomainName,
|
|||
|
(LPWSTR *)Buffer );
|
|||
|
|
|||
|
NET_REMOTE_RPC_FAILED(
|
|||
|
"NetGetDCName",
|
|||
|
UncCanonServerName,
|
|||
|
NetStatus,
|
|||
|
NET_REMOTE_FLAG_NORMAL,
|
|||
|
SERVICE_NETLOGON )
|
|||
|
|
|||
|
//
|
|||
|
// We should probaly check if it's really a downlevel machine
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = RxNetGetDCName(
|
|||
|
UncCanonServerName,
|
|||
|
(LPWSTR) DomainName,
|
|||
|
(LPBYTE *) Buffer // may be allocated
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NET_REMOTE_END
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Must be explicit reference to local machine. Fall through and
|
|||
|
// handle it.
|
|||
|
//
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Simply call DsGetDcName to find the PDC.
|
|||
|
//
|
|||
|
// NT 3.x cached the response for the primary domain. The was Lanman
|
|||
|
// legacy to avoid the expensive discovery. However, NT discovery is
|
|||
|
// cheaper than the API calls Lanman used to verify the cached information.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsGetDcNameW(
|
|||
|
NULL, // Not remoted
|
|||
|
DomainName,
|
|||
|
NULL, // No Domain GUID
|
|||
|
NULL, // No Site GUID
|
|||
|
DS_FORCE_REDISCOVERY |
|
|||
|
DS_PDC_REQUIRED |
|
|||
|
DS_IS_FLAT_NAME |
|
|||
|
DS_RETURN_FLAT_NAME,
|
|||
|
&DomainControllerInfo );
|
|||
|
|
|||
|
//
|
|||
|
// Map the status codes to be compatible.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
if ( NlDcUseGenericStatus(NetStatus) ) {
|
|||
|
NetStatus = NERR_DCNotFound;
|
|||
|
}
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller and fill it in
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetapipBufferAllocate(
|
|||
|
(wcslen(DomainControllerInfo->DomainControllerName) + 1) * sizeof(WCHAR),
|
|||
|
(LPVOID *) Buffer );
|
|||
|
|
|||
|
if ( NetStatus != NO_ERROR ) {
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(( "NetGetDCName: cannot allocate response buffer.\n"));
|
|||
|
}
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
wcscpy((LPWSTR)*Buffer, DomainControllerInfo->DomainControllerName );
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup all locally used resources
|
|||
|
//
|
|||
|
|
|||
|
if ( DomainControllerInfo != NULL ) {
|
|||
|
NetApiBufferFree( DomainControllerInfo );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetGetAnyDCName (
|
|||
|
IN LPCWSTR ServerName OPTIONAL,
|
|||
|
IN LPCWSTR DomainName OPTIONAL,
|
|||
|
OUT LPBYTE *Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get the name of the any domain controller for a domain that is directly trusted
|
|||
|
by ServerName.
|
|||
|
|
|||
|
|
|||
|
If ServerName is a standalone Windows NT Workstation or standalone Windows NT Server,
|
|||
|
no DomainName is valid.
|
|||
|
|
|||
|
If ServerName is a Windows NT Workstation that is a member of a domain or a
|
|||
|
Windows NT Server member server,
|
|||
|
the DomainName must the the domain ServerName is a member of.
|
|||
|
|
|||
|
If ServerName is a Windows NT Server domain controller,
|
|||
|
the DomainName must be one of the domains trusted by the
|
|||
|
domain the server is a controller for.
|
|||
|
|
|||
|
The domain controller found is guaranteed to have been up at one point during
|
|||
|
this API call.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - name of remote server (null for local)
|
|||
|
|
|||
|
DomainName - name of domain (null for primary domain)
|
|||
|
|
|||
|
Buffer - Returns a pointer to an allcated buffer containing the
|
|||
|
servername of a DC of the domain. The server name is prefixed
|
|||
|
by \\. The buffer should be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS - Success. Buffer contains DC name prefixed by \\.
|
|||
|
|
|||
|
ERROR_NO_LOGON_SERVERS - No DC could be found
|
|||
|
|
|||
|
ERROR_NO_SUCH_DOMAIN - The specified domain is not a trusted domain.
|
|||
|
|
|||
|
ERROR_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
|
|||
|
broken.
|
|||
|
|
|||
|
ERROR_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
|
|||
|
broken or the password is broken.
|
|||
|
|
|||
|
ERROR_DOMAIN_TRUST_INCONSISTENT - The server that responded is not a proper
|
|||
|
domain controller of the specified domain.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
*Buffer = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetrGetAnyDCName(
|
|||
|
(LPWSTR) ServerName,
|
|||
|
(LPWSTR) DomainName,
|
|||
|
(LPWSTR *) Buffer );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("NetGetAnyDCName rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsValidateSubnetNameA(
|
|||
|
IN LPCSTR SubnetName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Routine to validate a subnet name of the form xxx.xxx.xxx.xxx/yy
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SubnetName - Name of the subnet to validate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: Subnet name is valid
|
|||
|
|
|||
|
ERROR_INVALID_NAME: Subnet name is not valid
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD WinStatus;
|
|||
|
LPWSTR UnicodeSubnetName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Convert to unicode.
|
|||
|
//
|
|||
|
|
|||
|
if ( SubnetName == NULL ) {
|
|||
|
return ERROR_INVALID_NAME;
|
|||
|
}
|
|||
|
|
|||
|
UnicodeSubnetName = NetpAllocWStrFromAStr( SubnetName );
|
|||
|
|
|||
|
if ( UnicodeSubnetName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Validate the name
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = DsValidateSubnetNameW( UnicodeSubnetName );
|
|||
|
|
|||
|
//
|
|||
|
// Clean up locally used resources.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( UnicodeSubnetName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeSubnetName );
|
|||
|
}
|
|||
|
|
|||
|
return WinStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsValidateSubnetNameW(
|
|||
|
IN LPCWSTR SubnetName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Routine to validate a subnet name of the form xxx.xxx.xxx.xxx/yy
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SubnetName - Name of the subnet to validate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR: Subnet name is valid
|
|||
|
|
|||
|
ERROR_INVALID_NAME: Subnet name is not valid
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD WinStatus;
|
|||
|
ULONG SubnetAddress;
|
|||
|
ULONG SubnetMask;
|
|||
|
BYTE SubnetBitCount;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Caller the worker routine to do the real work
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = NlParseSubnetString( SubnetName,
|
|||
|
&SubnetAddress,
|
|||
|
&SubnetMask,
|
|||
|
&SubnetBitCount );
|
|||
|
|
|||
|
//
|
|||
|
// If Winsock has not yet been initialized,
|
|||
|
// initialize it.
|
|||
|
//
|
|||
|
|
|||
|
if ( WinStatus == WSANOTINITIALISED ) {
|
|||
|
|
|||
|
//
|
|||
|
// Initialize WSA.
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = DsWsaInitialize();
|
|||
|
|
|||
|
if ( WinStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Repeat the call.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
WinStatus = NlParseSubnetString( SubnetName,
|
|||
|
&SubnetAddress,
|
|||
|
&SubnetMask,
|
|||
|
&SubnetBitCount );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free locally used resouces.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
return WinStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetSiteNameA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
OUT LPSTR *SiteName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as DsGetSiteNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Same as DsGetSiteNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Same as DsGetSiteNameW except it takes and returns ASCII.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD WinStatus;
|
|||
|
LPWSTR UnicodeComputerName = NULL;
|
|||
|
LPWSTR UnicodeSiteName = NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert input parameters to Unicode.
|
|||
|
//
|
|||
|
|
|||
|
*SiteName = NULL;
|
|||
|
|
|||
|
if ( ComputerName != NULL ) {
|
|||
|
UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
|
|||
|
|
|||
|
if ( UnicodeComputerName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call the Unicode version of the routine.
|
|||
|
//
|
|||
|
|
|||
|
WinStatus = DsGetSiteNameW(
|
|||
|
UnicodeComputerName,
|
|||
|
&UnicodeSiteName );
|
|||
|
|
|||
|
if ( WinStatus != NO_ERROR ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the output structure to ANSI character set.
|
|||
|
//
|
|||
|
|
|||
|
*SiteName = NetpAllocAStrFromWStr( UnicodeSiteName );
|
|||
|
|
|||
|
if ( *SiteName == NULL ) {
|
|||
|
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
WinStatus = NO_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// Clean up locally used resources.
|
|||
|
//
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ( UnicodeComputerName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeComputerName );
|
|||
|
}
|
|||
|
if ( UnicodeSiteName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeSiteName );
|
|||
|
}
|
|||
|
|
|||
|
return WinStatus;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetSiteNameW(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
OUT LPWSTR *SiteName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsGetSiteName API returns the name site a computer is in.
|
|||
|
|
|||
|
For a DC, the SiteName is the site the DC is configured to be in.
|
|||
|
|
|||
|
For a member workstation or member server, this is the name of the site
|
|||
|
the workstation is in as configured in the domain the machine is a member of.
|
|||
|
|
|||
|
A standalone workstation or standalone server will always return
|
|||
|
ERROR_NO_SITENAME.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the server to remote this API to.
|
|||
|
Typically, this parameter should be specified as NULL.
|
|||
|
|
|||
|
SiteName - Returns the site name of the site this machine is in.
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
ERROR_NO_SITENAME - The machine is not in a site.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
*SiteName = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrGetSiteName(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
SiteName );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// If Netlogon isn't running on the local machine,
|
|||
|
// or Netlogon is the NT 4.0 version of netlogon (the upgrade case),
|
|||
|
// Simply indicate that there is no site.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == RPC_S_UNKNOWN_IF ||
|
|||
|
NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
|
|||
|
|
|||
|
NetStatus = ERROR_NO_SITENAME;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsrGetSiteName rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsAddressToSiteNamesA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
IN DWORD EntryCount,
|
|||
|
IN PSOCKET_ADDRESS SocketAddresses,
|
|||
|
OUT LPSTR **SiteNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsAddressToSiteNames API returns the site names that correspond to
|
|||
|
the specified addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Number of addresses to convert.
|
|||
|
|
|||
|
SocketAddresses - Specifies an EntryCount element array of addresses
|
|||
|
to convert. Each address must be of type AF_INET.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding
|
|||
|
address does not map to any site or if the address is malformed.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_ARRAY SiteNameArray;
|
|||
|
LPWSTR UnicodeComputerName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
*SiteNames = NULL;
|
|||
|
if ( EntryCount == 0 ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert input parameters to Unicode.
|
|||
|
//
|
|||
|
|
|||
|
if ( ComputerName != NULL ) {
|
|||
|
UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
|
|||
|
|
|||
|
if ( UnicodeComputerName == NULL ) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrAddressToSiteNamesW(
|
|||
|
UnicodeComputerName,
|
|||
|
EntryCount,
|
|||
|
(PNL_SOCKET_ADDRESS)SocketAddresses,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check
|
|||
|
//
|
|||
|
|
|||
|
if ( EntryCount != SiteNameArray->EntryCount ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SiteNames[i].Length == 0 ) {
|
|||
|
(*SiteNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
ANSI_STRING TempString;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPSTR) Where;
|
|||
|
TempString.Buffer = Where;
|
|||
|
TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
Status = RtlUnicodeStringToAnsiString(
|
|||
|
&TempString,
|
|||
|
&SiteNameArray->SiteNames[i],
|
|||
|
FALSE );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
MIDL_user_free( *SiteNames );
|
|||
|
*SiteNames = NULL;
|
|||
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Where += TempString.MaximumLength;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
if ( UnicodeComputerName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeComputerName );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsAddressToSiteNamesW(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN DWORD EntryCount,
|
|||
|
IN PSOCKET_ADDRESS SocketAddresses,
|
|||
|
OUT LPWSTR **SiteNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsAddressToSiteNames API returns the site names that correspond to
|
|||
|
the specified addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Number of addresses to convert.
|
|||
|
|
|||
|
SocketAddresses - Specifies an EntryCount element array of addresses
|
|||
|
to convert. Each address must be of type AF_INET.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding
|
|||
|
address does not map to any site or if the address is malformed.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_ARRAY SiteNameArray;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
*SiteNames = NULL;
|
|||
|
if ( EntryCount == 0 ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrAddressToSiteNamesW(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
EntryCount,
|
|||
|
(PNL_SOCKET_ADDRESS)SocketAddresses,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check
|
|||
|
//
|
|||
|
|
|||
|
if ( EntryCount != SiteNameArray->EntryCount ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPWSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SiteNames[i].Length == 0 ) {
|
|||
|
(*SiteNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPWSTR) Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
SiteNameArray->SiteNames[i].Buffer,
|
|||
|
SiteNameArray->SiteNames[i].Length );
|
|||
|
Where += SiteNameArray->SiteNames[i].Length;
|
|||
|
*(LPWSTR)Where = L'\0';
|
|||
|
Where += sizeof(WCHAR);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsAddressToSiteNamesExA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
IN DWORD EntryCount,
|
|||
|
IN PSOCKET_ADDRESS SocketAddresses,
|
|||
|
OUT LPSTR **SiteNames,
|
|||
|
OUT LPSTR **SubnetNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsAddressToSiteNamesEx API returns the site names and subnet names
|
|||
|
that correspond to the specified addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Number of addresses to convert.
|
|||
|
|
|||
|
SocketAddresses - Specifies an EntryCount element array of addresses
|
|||
|
to convert. Each address must be of type AF_INET.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding
|
|||
|
address does not map to any site or if the address is malformed.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
SubnetNames - Returns an array of pointers to subnet names which were used
|
|||
|
to perform the address to site name mappings. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding address
|
|||
|
to site mapping was not determined or if no subnet was used to perform the
|
|||
|
corresponding address to site mapping which is the case when there is exactly
|
|||
|
one site in the enterprise with no subnet objects mapped to it.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_EX_ARRAY SiteNameArray;
|
|||
|
LPWSTR UnicodeComputerName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
*SiteNames = NULL;
|
|||
|
*SubnetNames = NULL;
|
|||
|
if ( EntryCount == 0 ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert input parameters to Unicode.
|
|||
|
//
|
|||
|
|
|||
|
if ( ComputerName != NULL ) {
|
|||
|
UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
|
|||
|
|
|||
|
if ( UnicodeComputerName == NULL ) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrAddressToSiteNamesExW(
|
|||
|
UnicodeComputerName,
|
|||
|
EntryCount,
|
|||
|
(PNL_SOCKET_ADDRESS)SocketAddresses,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check
|
|||
|
//
|
|||
|
|
|||
|
if ( EntryCount != SiteNameArray->EntryCount ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
|
|||
|
Size = sizeof(LPSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SubnetNames[i] );
|
|||
|
}
|
|||
|
|
|||
|
*SubnetNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SubnetNames == NULL ) {
|
|||
|
MIDL_user_free( *SiteNames );
|
|||
|
*SiteNames = NULL;
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
LPBYTE Where;
|
|||
|
LPBYTE Where2;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * EntryCount;
|
|||
|
Where2 = ((LPBYTE)(*SubnetNames)) + sizeof(LPSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SiteNames[i].Length == 0 ) {
|
|||
|
(*SiteNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
ANSI_STRING TempString;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPSTR) Where;
|
|||
|
TempString.Buffer = Where;
|
|||
|
TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
Status = RtlUnicodeStringToAnsiString(
|
|||
|
&TempString,
|
|||
|
&SiteNameArray->SiteNames[i],
|
|||
|
FALSE );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
MIDL_user_free( *SiteNames );
|
|||
|
*SiteNames = NULL;
|
|||
|
MIDL_user_free( *SubnetNames );
|
|||
|
*SubnetNames = NULL;
|
|||
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Where += TempString.MaximumLength;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SubnetNames[i].Length == 0 ) {
|
|||
|
(*SubnetNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Subnet name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
ANSI_STRING TempString;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
(*SubnetNames)[i] = (LPSTR) Where2;
|
|||
|
TempString.Buffer = Where2;
|
|||
|
TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SubnetNames[i] );
|
|||
|
Status = RtlUnicodeStringToAnsiString(
|
|||
|
&TempString,
|
|||
|
&SiteNameArray->SubnetNames[i],
|
|||
|
FALSE );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
MIDL_user_free( *SubnetNames );
|
|||
|
*SubnetNames = NULL;
|
|||
|
MIDL_user_free( *SubnetNames );
|
|||
|
*SubnetNames = NULL;
|
|||
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Where2 += TempString.MaximumLength;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsAddressToSiteNamesExW(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
IN DWORD EntryCount,
|
|||
|
IN PSOCKET_ADDRESS SocketAddresses,
|
|||
|
OUT LPWSTR **SiteNames,
|
|||
|
OUT LPWSTR **SubnetNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The DsAddressToSiteNames API returns the site names that correspond to
|
|||
|
the specified addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Number of addresses to convert.
|
|||
|
|
|||
|
SocketAddresses - Specifies an EntryCount element array of addresses
|
|||
|
to convert. Each address must be of type AF_INET.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding
|
|||
|
address does not map to any site or if the address is malformed.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
SubnetNames - Returns an array of pointers to subnet names which were used
|
|||
|
to perform the address to site name mappings. EntryCount entries
|
|||
|
are returned. An entry will be returned as NULL if the corresponding address
|
|||
|
to site mapping was not determined or if no subnet was used to perform the
|
|||
|
corresponding address to site mapping which is the case when there is exactly
|
|||
|
one site in the enterprise with no subnet objects mapped to it.
|
|||
|
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_EX_ARRAY SiteNameArray;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
*SiteNames = NULL;
|
|||
|
*SubnetNames = NULL;
|
|||
|
if ( EntryCount == 0 ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrAddressToSiteNamesExW(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
EntryCount,
|
|||
|
(PNL_SOCKET_ADDRESS)SocketAddresses,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check
|
|||
|
//
|
|||
|
|
|||
|
if ( EntryCount != SiteNameArray->EntryCount ) {
|
|||
|
NetStatus = ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPWSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPWSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
Size += SiteNameArray->SubnetNames[i].Length + sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
*SubnetNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SubnetNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
LPBYTE Where;
|
|||
|
LPBYTE Where2;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * EntryCount;
|
|||
|
Where2 = ((LPBYTE)(*SubnetNames)) + sizeof(LPWSTR) * EntryCount;
|
|||
|
for ( i=0; i<EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SiteNames[i].Length == 0 ) {
|
|||
|
(*SiteNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPWSTR) Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
SiteNameArray->SiteNames[i].Buffer,
|
|||
|
SiteNameArray->SiteNames[i].Length );
|
|||
|
Where += SiteNameArray->SiteNames[i].Length;
|
|||
|
*(LPWSTR)Where = L'\0';
|
|||
|
Where += sizeof(WCHAR);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no name was returned,
|
|||
|
// pass a NULL back to the caller.
|
|||
|
//
|
|||
|
|
|||
|
if ( SiteNameArray->SubnetNames[i].Length == 0 ) {
|
|||
|
(*SubnetNames)[i] = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Subnet name into the return buffer.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
(*SubnetNames)[i] = (LPWSTR) Where2;
|
|||
|
RtlCopyMemory( Where2,
|
|||
|
SiteNameArray->SubnetNames[i].Buffer,
|
|||
|
SiteNameArray->SubnetNames[i].Length );
|
|||
|
Where2 += SiteNameArray->SubnetNames[i].Length;
|
|||
|
*(LPWSTR)Where2 = L'\0';
|
|||
|
Where2 += sizeof(WCHAR);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcSiteCoverageA(
|
|||
|
IN LPCSTR ComputerName OPTIONAL,
|
|||
|
OUT PULONG EntryCount,
|
|||
|
OUT LPSTR **SiteNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API returns the site names of all sites covered by a DC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Returns the number of sites covered by DC.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names.
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_ARRAY SiteNameArray;
|
|||
|
LPWSTR UnicodeComputerName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
*SiteNames = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Convert input parameters to Unicode.
|
|||
|
//
|
|||
|
|
|||
|
if ( ComputerName != NULL ) {
|
|||
|
UnicodeComputerName = NetpAllocWStrFromAStr( (LPSTR)ComputerName );
|
|||
|
|
|||
|
if ( UnicodeComputerName == NULL ) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrGetDcSiteCoverageW(
|
|||
|
UnicodeComputerName,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Set the size of the array
|
|||
|
//
|
|||
|
|
|||
|
*EntryCount = SiteNameArray->EntryCount;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPSTR) * SiteNameArray->EntryCount;
|
|||
|
for ( i=0; i<*EntryCount; i++ ) {
|
|||
|
Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * SiteNameArray->EntryCount;
|
|||
|
for ( i=0; i<*EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
ANSI_STRING TempString;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPSTR) Where;
|
|||
|
TempString.Buffer = Where;
|
|||
|
TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
|
|||
|
Status = RtlUnicodeStringToAnsiString(
|
|||
|
&TempString,
|
|||
|
&SiteNameArray->SiteNames[i],
|
|||
|
FALSE );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
MIDL_user_free( *SiteNames );
|
|||
|
*SiteNames = NULL;
|
|||
|
NetStatus = NetpNtStatusToApiStatus( Status );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Where += TempString.MaximumLength;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsGetDcSiteCoverage rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
if ( UnicodeComputerName != NULL ) {
|
|||
|
NetApiBufferFree( UnicodeComputerName );
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WINAPI
|
|||
|
DsGetDcSiteCoverageW(
|
|||
|
IN LPCWSTR ComputerName OPTIONAL,
|
|||
|
OUT PULONG EntryCount,
|
|||
|
OUT LPWSTR **SiteNames
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API returns the site names of all sites covered by a DC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ComputerName - Specifies the name of the domain controller to remote this API to.
|
|||
|
|
|||
|
EntryCount - Returns the number of sites covered by DC.
|
|||
|
|
|||
|
SiteNames - Returns an array of pointers to site names.
|
|||
|
The returned buffer must be deallocated using NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - Operation completed successfully;
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
PNL_SITE_NAME_ARRAY SiteNameArray;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
*SiteNames = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Do the RPC call with an exception handler since RPC will raise an
|
|||
|
// exception if anything fails. It is up to us to figure out what
|
|||
|
// to do once the exception is raised.
|
|||
|
//
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
|
|||
|
SiteNameArray = NULL; // Force RPC to allocate
|
|||
|
|
|||
|
//
|
|||
|
// Call RPC version of the API.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = DsrGetDcSiteCoverageW(
|
|||
|
(LPWSTR) ComputerName,
|
|||
|
&SiteNameArray );
|
|||
|
|
|||
|
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
|
|||
|
|
|||
|
NetStatus = RpcExceptionCode();
|
|||
|
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the site names to what the caller expects.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
|
|||
|
|
|||
|
ULONG Size;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Set the size of the array
|
|||
|
//
|
|||
|
|
|||
|
*EntryCount = SiteNameArray->EntryCount;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to return to the caller
|
|||
|
//
|
|||
|
|
|||
|
Size = sizeof(LPWSTR) * SiteNameArray->EntryCount;
|
|||
|
for ( i=0; i<*EntryCount; i++) {
|
|||
|
Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
*SiteNames = MIDL_user_allocate( Size );
|
|||
|
|
|||
|
if ( *SiteNames == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
|
|||
|
LPBYTE Where;
|
|||
|
|
|||
|
//
|
|||
|
// Loop copying names to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * SiteNameArray->EntryCount;
|
|||
|
for ( i=0; i<*EntryCount; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the site name into the return buffer.
|
|||
|
//
|
|||
|
|
|||
|
(*SiteNames)[i] = (LPWSTR) Where;
|
|||
|
RtlCopyMemory( Where,
|
|||
|
SiteNameArray->SiteNames[i].Buffer,
|
|||
|
SiteNameArray->SiteNames[i].Length );
|
|||
|
Where += SiteNameArray->SiteNames[i].Length;
|
|||
|
*(LPWSTR)Where = L'\0';
|
|||
|
Where += sizeof(WCHAR);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( SiteNameArray );
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG( LOGON ) {
|
|||
|
NetpKdPrint(("DsGetDcSiteCoverage rc = %lu 0x%lx\n",
|
|||
|
NetStatus, NetStatus));
|
|||
|
}
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|
|||
|
|
|||
|
#endif // WIN32_CHICAGO
|
|||
|
#endif // NETTEST_UTILITY
|