Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4228 lines
111 KiB

  1. /*++
  2. Copyright (c) 1987-1991 Microsoft Corporation
  3. Module Name:
  4. getdcnam.c
  5. Abstract:
  6. NetGetDCName API
  7. Author:
  8. Ported from Lan Man 2.0
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 09-Feb-1989 (PaulC)
  15. Created file, to hold NetGetDCName.
  16. 18-Apr-1989 (Ericpe)
  17. Implemented NetGetDCName.
  18. 30-May-1989 (DannyGl)
  19. Reduced DosReadMailslot timeout.
  20. 07-Jul-1989 (NealF)
  21. Use I_NetNameCanonicalize
  22. 27-Jul-1989 (WilliamW)
  23. Use WIN3 manifest for WIN3.0 compatibility
  24. 03-Jan-1990 (WilliamW)
  25. canonicalize domain and use I_NetCompareName
  26. 08-Jun-1991 (CliffV)
  27. Ported to NT
  28. 23-Jul-1991 JohnRo
  29. Implement downlevel NetGetDCName.
  30. --*/
  31. #include <nt.h>
  32. #include <ntrtl.h>
  33. #include <nturtl.h>
  34. #ifndef WIN32_CHICAGO
  35. #include <rpc.h>
  36. #include <ntrpcp.h> // needed by rpcasync.h
  37. #include <rpcasync.h> // I_RpcExceptionFilter
  38. #include <logon_c.h>// includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
  39. #else // WIN32_CHICAGO
  40. #include <windef.h>
  41. #include <lmcons.h>
  42. #endif // WIN32_CHICAGO
  43. #include <stdio.h>
  44. #include <winbase.h>
  45. #include <winsock2.h>
  46. #ifndef WIN32_CHICAGO
  47. #include <accessp.h>
  48. #include <align.h>
  49. #endif // WIN32_CHICAGO
  50. #include <debuglib.h> // IF_DEBUG()
  51. #include <dsgetdc.h> // DsGetDcName()
  52. #include <dsgetdcp.h> // DsGetDcNameWithAccount()
  53. #include <icanon.h> // NAMETYPE_* defines NetpIsRemote(), NIRFLAG_ equates.
  54. #include <lmapibuf.h>
  55. #include <lmerr.h>
  56. #ifndef WIN32_CHICAGO
  57. #include <lmremutl.h> // SUPPORTS_* defines
  58. #include <lmserver.h> // SV_TYPE_* defines
  59. #include <lmsvc.h> // SERVICE_* defines
  60. #include <lmwksta.h>
  61. #include <logonp.h> // NetpLogon routines
  62. #include <nlbind.h> // Netlogon RPC binding cache init routines
  63. #endif // WIN32_CHICAGO
  64. #include <netdebug.h> // NetpKdPrint
  65. #include <netlib.h> // NetpMemoryFree
  66. #ifndef WIN32_CHICAGO
  67. #include <netlibnt.h> // NetpApiStatusToNtStatus
  68. #include <netrpc.h>
  69. #include <rxdomain.h> // RxNetGetDCName().
  70. #include <string.h>
  71. #include <stdlib.h>
  72. #endif // WIN32_CHICAGO
  73. #include <tstring.h> // NetpCopyStrToWStr()
  74. #if DBG
  75. #define NETLOGONDBG 1
  76. #endif // DBG
  77. #include <nldebug.h> // NlPrint()
  78. #include <ntddbrow.h> // Needed by nlcommon.h
  79. #include <nlcommon.h> // Definitions shared with netlogon
  80. //
  81. // Only dynamically initialize winsock.
  82. //
  83. CRITICAL_SECTION GlobalDCNameCritSect;
  84. BOOLEAN DsGetDcWsaInitialized;
  85. #define LOCKDOMAINSEM() EnterCriticalSection( &GlobalDCNameCritSect )
  86. #define UNLOCKDOMAINSEM() LeaveCriticalSection( &GlobalDCNameCritSect )
  87. // end global dll data
  88. #ifdef WIN32_CHICAGO // from net\inc\logonp.h
  89. NET_API_STATUS
  90. NetpLogonWriteMailslot(
  91. IN LPWSTR MailslotName,
  92. IN LPVOID Buffer,
  93. IN DWORD BufferSize
  94. );
  95. NTSTATUS
  96. NetpApiStatusToNtStatus(
  97. NET_API_STATUS NetStatus
  98. );
  99. #endif // WIN32_CHICAGO
  100. NET_API_STATUS
  101. DCNameInitialize(
  102. VOID
  103. )
  104. /*++
  105. Routine Description:
  106. Perform per-process initialization.
  107. Arguments:
  108. None.
  109. Return Value:
  110. Status of the operation.
  111. --*/
  112. {
  113. NET_API_STATUS NetStatus = NO_ERROR;
  114. #ifndef NETTEST_UTILITY
  115. #ifndef WIN32_CHICAGO
  116. //
  117. // Initialize the RPC binding cache.
  118. //
  119. NetStatus = NlBindingAttachDll();
  120. if ( NetStatus != NO_ERROR ) {
  121. return NetStatus;
  122. }
  123. #endif // WIN32_CHICAGO
  124. #endif // NETTEST_UTILITY
  125. //
  126. // Initialize the DLL critsects.
  127. //
  128. try {
  129. InitializeCriticalSection( &GlobalDCNameCritSect );
  130. } except( EXCEPTION_EXECUTE_HANDLER ) {
  131. NlPrint((0,"NETAPI32.DLL: Cannot initialize GlobalDCNameCritSect\n"));
  132. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  133. }
  134. if ( NetStatus == NO_ERROR ) {
  135. //
  136. // Initialize globals
  137. //
  138. DsGetDcWsaInitialized = FALSE;
  139. //
  140. // Initialize the cache of discovered domains.
  141. //
  142. NetStatus = NetpDcInitializeCache();
  143. if ( NetStatus != NO_ERROR ) {
  144. NlPrint((0,"NETAPI32.DLL: Cannot NetpDcinitializeCache\n"));
  145. }
  146. }
  147. return NetStatus;
  148. }
  149. VOID
  150. DCNameClose(
  151. VOID
  152. )
  153. /*++
  154. Routine Description:
  155. Perform per-process cleanup.
  156. Arguments:
  157. None.
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. #ifndef NETTEST_UTILITY
  163. #ifndef WIN32_CHICAGO
  164. //
  165. // Shutdown the RPC binding cache.
  166. //
  167. NlBindingDetachDll();
  168. #endif // WIN32_CHICAGO
  169. #endif // NETTEST_UTILITY
  170. //
  171. // If we initialized winsock,
  172. // cleanup.
  173. //
  174. LOCKDOMAINSEM();
  175. if ( DsGetDcWsaInitialized ) {
  176. WSACleanup();
  177. DsGetDcWsaInitialized = FALSE;
  178. }
  179. UNLOCKDOMAINSEM();
  180. //
  181. // Delete the critsect that protects the DCName cache
  182. //
  183. DeleteCriticalSection( &GlobalDCNameCritSect );
  184. //
  185. // Free the cache of discovered DCs.
  186. //
  187. NetpDcUninitializeCache();
  188. }
  189. #if NETLOGONDBG
  190. #define MAX_PRINTF_LEN 1024 // Arbitrary.
  191. VOID
  192. NlPrintRoutine(
  193. IN DWORD DebugFlag,
  194. IN LPSTR Format,
  195. ...
  196. )
  197. /*++
  198. Routine Description:
  199. Local version of NlPrintRoutine for those instances where we're not
  200. compiled directly into the netlogon service.
  201. Arguments:
  202. Return Value:
  203. --*/
  204. {
  205. #ifdef NETTEST_UTILITY
  206. extern BOOL ReallyVerbose;
  207. #endif // NETTEST_UTILITY
  208. #ifndef NETTEST_UTILITY
  209. // NetlibpTrace |= NETLIB_DEBUG_LOGON; // ?? Force verbosity
  210. #ifndef WIN32_CHICAGO
  211. IF_DEBUG( LOGON ) {
  212. #endif // WIN32_CHICAGO
  213. #endif // NETTEST_UTILITY
  214. va_list arglist;
  215. char OutputBuffer[MAX_PRINTF_LEN];
  216. ULONG length = 0;
  217. static BeginningOfLine = TRUE;
  218. //
  219. // Handle the beginning of a new line.
  220. //
  221. //
  222. if ( BeginningOfLine ) {
  223. #ifdef NETTEST_UTILITY
  224. if ( ReallyVerbose ) {
  225. printf( " " );
  226. }
  227. #endif // NETTEST_UTILITY
  228. }
  229. va_start(arglist, Format);
  230. #ifndef WIN32_CHICAGO
  231. length = (ULONG) vsprintf(OutputBuffer, Format, arglist);
  232. #else // WIN32_CHICAGO
  233. length = (ULONG) vsprintf(OutputBuffer + length - 1, Format, arglist);
  234. #endif // WIN32_CHICAGO
  235. va_end(arglist);
  236. BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
  237. // Output buffer may contain percent signs (like "%SystemRoot%"), so
  238. // print it without parsing it.
  239. #ifndef WIN32_CHICAGO
  240. #ifdef NETTEST_UTILITY
  241. if ( ReallyVerbose ) {
  242. printf( "%s", (PCH) OutputBuffer);
  243. }
  244. #else NETTEST_UTILITY
  245. (void) DbgPrint( "%s", (PCH) OutputBuffer);
  246. #endif // NETTEST_UTILITY
  247. #else // WIN32_CHICAGO
  248. OutputDebugString( OutputBuffer);
  249. #endif // WIN32_CHICAGO
  250. #ifndef NETTEST_UTILITY
  251. #ifndef WIN32_CHICAGO
  252. }
  253. #endif // WIN32_CHICAGO
  254. #endif // NETTEST_UTILITY
  255. }
  256. #endif // DBG
  257. #ifndef WIN32_CHICAGO
  258. #if NETLOGONDBG
  259. //
  260. // Have my own version of RtlAssert so debug versions of netlogon really assert on
  261. // free builds.
  262. //
  263. VOID
  264. NlAssertFailed(
  265. IN PVOID FailedAssertion,
  266. IN PVOID FileName,
  267. IN ULONG LineNumber,
  268. IN PCHAR Message OPTIONAL
  269. )
  270. {
  271. #ifdef NETTEST_UTILITY
  272. NlPrint((0, "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
  273. Message ? Message : "",
  274. FailedAssertion,
  275. FileName,
  276. LineNumber
  277. ));
  278. #else NETTEST_UTILITY
  279. RtlAssert( FailedAssertion, FileName, LineNumber, Message );
  280. #endif NETTEST_UTILITY
  281. }
  282. #endif // DBG
  283. #endif //WIN32_CHICAGO
  284. #if NETLOGONDBG
  285. VOID
  286. NlpDumpBuffer(
  287. IN DWORD DebugFlag,
  288. PVOID Buffer,
  289. DWORD BufferSize
  290. )
  291. /*++
  292. Routine Description:
  293. Dumps the buffer content on to the debugger output.
  294. Arguments:
  295. DebugFlag: Debug flag to pass on to NlPrintRoutine
  296. Buffer: buffer pointer.
  297. BufferSize: size of the buffer.
  298. Return Value:
  299. none
  300. --*/
  301. {
  302. #define NUM_CHARS 16
  303. DWORD i, limit;
  304. CHAR TextBuffer[NUM_CHARS + 1];
  305. LPBYTE BufferPtr = Buffer;
  306. //
  307. // Hex dump of the bytes
  308. //
  309. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  310. for (i = 0; i < limit; i++) {
  311. if (i < BufferSize) {
  312. NlPrint((0,"%02x ", BufferPtr[i]));
  313. if (BufferPtr[i] < 31 ) {
  314. TextBuffer[i % NUM_CHARS] = '.';
  315. } else if (BufferPtr[i] == '\0') {
  316. TextBuffer[i % NUM_CHARS] = ' ';
  317. } else {
  318. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  319. }
  320. } else {
  321. NlPrint((0," "));
  322. TextBuffer[i % NUM_CHARS] = ' ';
  323. }
  324. if ((i + 1) % NUM_CHARS == 0) {
  325. TextBuffer[NUM_CHARS] = 0;
  326. NlPrint((0," %s\n", TextBuffer));
  327. }
  328. }
  329. UNREFERENCED_PARAMETER( DebugFlag );
  330. }
  331. #endif // DBG
  332. NTSTATUS
  333. NlBrowserSendDatagram(
  334. IN PVOID ContextDomainInfo,
  335. IN ULONG IpAddress,
  336. IN LPWSTR UnicodeDestinationName,
  337. IN DGRECEIVER_NAME_TYPE NameType,
  338. IN LPWSTR TransportName,
  339. IN LPSTR OemMailslotName,
  340. IN PVOID Buffer,
  341. IN ULONG BufferSize,
  342. IN OUT PBOOL FlushNameOnOneIpTransport OPTIONAL
  343. )
  344. /*++
  345. Routine Description:
  346. Send the specified mailslot message to the specified mailslot on the
  347. specified server on the specified transport..
  348. Arguments:
  349. DomainInfo - Hosted domain sending the datagram
  350. IpAddress - IpAddress of the machine to send the pind to.
  351. If zero, UnicodeDestinationName must be specified.
  352. If ALL_IP_TRANSPORTS, UnicodeDestination must be specified but the datagram
  353. will only be sent on IP transports.
  354. UnicodeDestinationName -- Name of the server to send to.
  355. NameType -- Type of name represented by UnicodeDestinationName.
  356. TransportName -- Name of the transport to send on.
  357. Use NULL to send on all transports.
  358. OemMailslotName -- Name of the mailslot to send to.
  359. Buffer -- Specifies a pointer to the mailslot message to send.
  360. BufferSize -- Size in bytes of the mailslot message
  361. FlushNameOnOneIpTransport -- Ignored in this implementation
  362. Return Value:
  363. Status of the operation.
  364. --*/
  365. {
  366. NTSTATUS Status;
  367. NET_API_STATUS NetStatus;
  368. WCHAR NetlogonMailslotName[MAX_PATH+1];
  369. //
  370. // Sanity check.
  371. //
  372. if ( ContextDomainInfo != NULL ||
  373. TransportName != NULL ) {
  374. NlPrint((NL_CRITICAL, "NETAPI32: NlBrowserSendDatagram internal error.\n" ));
  375. return STATUS_INTERNAL_ERROR;
  376. }
  377. //
  378. // Start building the destination mailslot name.
  379. //
  380. NetlogonMailslotName[0] = '\\';
  381. NetlogonMailslotName[1] = '\\';
  382. if ( UnicodeDestinationName != NULL ) {
  383. wcscpy(NetlogonMailslotName + 2, UnicodeDestinationName );
  384. } else {
  385. NlPrint((NL_CRITICAL, "NETAPI32: NlBrowserSendDatagram internal error 2.\n" ));
  386. return STATUS_INTERNAL_ERROR;
  387. }
  388. switch ( NameType ) {
  389. case PrimaryDomain: // Primary domain (signature 0), group
  390. break;
  391. case DomainName: // DC Domain name (domain name, signature 1c)
  392. wcscat( NetlogonMailslotName, L"*" );
  393. break;
  394. case PrimaryDomainBrowser: // PDC Browser name (domain name, signature 1b), unique
  395. wcscat( NetlogonMailslotName, L"**" );
  396. break;
  397. default:
  398. return STATUS_INVALID_PARAMETER;
  399. }
  400. NetpCopyStrToWStr( &NetlogonMailslotName[wcslen(NetlogonMailslotName)],
  401. OemMailslotName );
  402. NetStatus = NetpLogonWriteMailslot(
  403. NetlogonMailslotName,
  404. Buffer,
  405. BufferSize );
  406. #ifndef WIN32_CHICAGO
  407. NlPrint((NL_MAILSLOT,
  408. "Sent out '%s' message to %ws on all transports.\n",
  409. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)Buffer)->Opcode),
  410. NetlogonMailslotName));
  411. #endif // WIN32_CHICAGO
  412. #if NETLOGONDBG
  413. NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize );
  414. #endif // NETLOGONDBG
  415. if ( NetStatus != NERR_Success ) {
  416. Status = NetpApiStatusToNtStatus( NetStatus );
  417. NlPrint(( NL_CRITICAL,
  418. "NetpDcSendPing: cannot write netlogon mailslot: %ws 0x%lx %ld\n",
  419. UnicodeDestinationName,
  420. IpAddress,
  421. NetStatus));
  422. } else {
  423. Status = STATUS_SUCCESS;
  424. }
  425. NlPrint(( NL_MISC, "NlBrowserSendDatagram : returned 0x%lx\n", NetStatus));
  426. return Status;
  427. }
  428. NET_API_STATUS
  429. DsWsaInitialize(
  430. VOID
  431. )
  432. /*++
  433. Routine Description:
  434. Initialize winsock.
  435. Arguments:
  436. None.
  437. Return Value:
  438. Status of the operation.
  439. --*/
  440. {
  441. NET_API_STATUS NetStatus;
  442. WORD wVersionRequested;
  443. WSADATA wsaData;
  444. int err;
  445. LOCKDOMAINSEM();
  446. if ( !DsGetDcWsaInitialized ) {
  447. //
  448. // Initialize winsock.
  449. //
  450. wVersionRequested = MAKEWORD( 1, 1 );
  451. NetStatus = WSAStartup( wVersionRequested, &wsaData );
  452. if ( NetStatus != 0 ) {
  453. UNLOCKDOMAINSEM();
  454. NlPrint((NL_CRITICAL, "NETAPI32.DLL: Cannot initialize winsock %ld.\n", NetStatus ));
  455. return NetStatus;
  456. }
  457. if ( LOBYTE( wsaData.wVersion ) != 1 ||
  458. HIBYTE( wsaData.wVersion ) != 1 ) {
  459. WSACleanup();
  460. UNLOCKDOMAINSEM();
  461. NlPrint((NL_CRITICAL, "NETAPI32.DLL: Wrong winsock version %ld.\n", wsaData.wVersion ));
  462. return WSANOTINITIALISED;
  463. }
  464. DsGetDcWsaInitialized = TRUE;
  465. }
  466. UNLOCKDOMAINSEM();
  467. return NO_ERROR;
  468. }
  469. DWORD
  470. DsWsaGetDcName(
  471. IN LPCWSTR ComputerName OPTIONAL,
  472. IN LPCWSTR AccountName OPTIONAL,
  473. IN ULONG AllowableAccountControlBits,
  474. IN LPCWSTR DomainName OPTIONAL,
  475. IN GUID *DomainGuid OPTIONAL,
  476. IN LPCWSTR SiteName OPTIONAL,
  477. IN ULONG Flags,
  478. IN ULONG InternalFlags,
  479. IN DWORD Timeout,
  480. IN LPWSTR NetbiosPrimaryDomainName OPTIONAL,
  481. IN LPWSTR DnsPrimaryDomainName OPTIONAL,
  482. IN GUID *PrimaryDomainGuid OPTIONAL,
  483. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  484. )
  485. /*++
  486. Routine Description:
  487. Wrapper for DsIGetDcName that ensures WSA has been initialized.
  488. i
  489. Arguments:
  490. (See DsIGetDcName).
  491. Return Value:
  492. (See DsIGetDcName).
  493. --*/
  494. {
  495. NET_API_STATUS NetStatus;
  496. //
  497. // Pass the call through to DsIGetDcName
  498. //
  499. NetStatus = DsIGetDcName(
  500. ComputerName,
  501. AccountName,
  502. AllowableAccountControlBits,
  503. DomainName,
  504. NULL, // Tree name is not known
  505. DomainGuid,
  506. SiteName,
  507. Flags,
  508. InternalFlags,
  509. NULL, // No send datagram context
  510. Timeout,
  511. NetbiosPrimaryDomainName,
  512. DnsPrimaryDomainName,
  513. PrimaryDomainGuid,
  514. NULL,
  515. NULL,
  516. DomainControllerInfo );
  517. //
  518. // If Winsock has not yet been initialized,
  519. // initialize it.
  520. //
  521. if ( NetStatus == WSANOTINITIALISED ) {
  522. //
  523. // Initialize WSA.
  524. //
  525. NetStatus = DsWsaInitialize();
  526. if ( NetStatus != NO_ERROR ) {
  527. goto Cleanup;
  528. }
  529. //
  530. // Repeat the call.
  531. //
  532. NetStatus = DsIGetDcName(
  533. ComputerName,
  534. AccountName,
  535. AllowableAccountControlBits,
  536. DomainName,
  537. NULL, // Tree name is not known
  538. DomainGuid,
  539. SiteName,
  540. Flags,
  541. InternalFlags,
  542. NULL, // No send datagram context
  543. Timeout,
  544. NetbiosPrimaryDomainName,
  545. DnsPrimaryDomainName,
  546. PrimaryDomainGuid,
  547. NULL,
  548. NULL,
  549. DomainControllerInfo );
  550. }
  551. //
  552. // Free locally used resouces.
  553. //
  554. Cleanup:
  555. return NetStatus;
  556. }
  557. DWORD
  558. DsLocalGetDcName(
  559. IN LPCWSTR ComputerName OPTIONAL,
  560. IN LPCWSTR AccountName OPTIONAL,
  561. IN ULONG AllowableAccountControlBits,
  562. IN LPCWSTR DomainName OPTIONAL,
  563. IN GUID *DomainGuid OPTIONAL,
  564. IN LPCWSTR SiteName OPTIONAL,
  565. IN ULONG Flags,
  566. IN ULONG InternalFlags,
  567. IN DWORD Timeout,
  568. IN LPWSTR NetbiosPrimaryDomainName OPTIONAL,
  569. IN LPWSTR DnsPrimaryDomainName OPTIONAL,
  570. IN LPWSTR DnsPrimaryForestName OPTIONAL,
  571. IN GUID *PrimaryDomainGuid OPTIONAL,
  572. OUT PBOOLEAN Local,
  573. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  574. )
  575. /*++
  576. Routine Description:
  577. Wrapper for DsWsaGetDcName that ensures this is a local call.
  578. Arguments:
  579. (See DsIGetDcName).
  580. Local - Returns TRUE if the call is local and this routine performed
  581. the requested operation.
  582. Return Value:
  583. (See DsIGetDcName).
  584. --*/
  585. {
  586. NET_API_STATUS NetStatus;
  587. DWORD LocalOrRemote;
  588. //
  589. // If no computername was specified,
  590. // mark this as a local call.
  591. //
  592. *Local = TRUE;
  593. #ifndef WIN32_CHICAGO
  594. if ( ComputerName == NULL || ComputerName[0] == '\0' ) {
  595. LocalOrRemote = ISLOCAL;
  596. //
  597. // Check if the ComputerName specifies this machine.
  598. //
  599. } else {
  600. NetStatus = NetpIsRemote(
  601. (LPWSTR) ComputerName, // uncanon server name
  602. &LocalOrRemote,
  603. NULL,
  604. 0 );
  605. if (NetStatus != NERR_Success) {
  606. goto Cleanup;
  607. }
  608. }
  609. #else // WIN32_CHICAGO
  610. LocalOrRemote = ISLOCAL;
  611. #endif // WIN32_CHICAGO
  612. //
  613. // If the call is local,
  614. // just do it.
  615. //
  616. if ( LocalOrRemote == ISLOCAL ) {
  617. //
  618. // Initialize WSA.
  619. // (Ignore errors since WSA isn't always needed.)
  620. //
  621. (VOID) DsWsaInitialize();
  622. NetStatus = DsIGetDcName(
  623. NULL, // Don't use computer name. This has to be netbios name
  624. AccountName,
  625. AllowableAccountControlBits,
  626. DomainName,
  627. DnsPrimaryForestName,
  628. DomainGuid,
  629. SiteName,
  630. Flags,
  631. InternalFlags,
  632. NULL, // No send datagram context
  633. Timeout,
  634. NetbiosPrimaryDomainName,
  635. DnsPrimaryDomainName,
  636. PrimaryDomainGuid,
  637. NULL,
  638. NULL,
  639. DomainControllerInfo );
  640. } else {
  641. *Local = FALSE;
  642. NetStatus = NO_ERROR;
  643. }
  644. //
  645. // Cleanup all locally used resources
  646. //
  647. #ifndef WIN32_CHICAGO
  648. Cleanup:
  649. #endif // WIN32_CHICAGO
  650. return NetStatus;
  651. }
  652. DWORD
  653. WINAPI
  654. DsGetDcOpenW(
  655. IN LPCWSTR DnsName,
  656. IN ULONG OptionFlags,
  657. IN LPCWSTR SiteName OPTIONAL,
  658. IN GUID *DomainGuid OPTIONAL,
  659. IN LPCWSTR DnsForestName OPTIONAL,
  660. IN ULONG DcFlags,
  661. OUT PHANDLE RetGetDcContext
  662. )
  663. /*++
  664. Routine Description:
  665. Open a context for retrieval of the addresses of machines that have
  666. registered LDAP.TCP.<xxx> SRV records.
  667. Arguments:
  668. DnsName - Unicode DNS name of the LDAP server to lookup
  669. OptionFlags - Flags affecting the operation of the routine.
  670. DS_ONLY_DO_SITE_NAME - Non-site names should be ignored.
  671. DS_NOTIFY_AFTER_SITE_RECORDS - Return ERROR_FILEMARK_DETECTED
  672. after all site specific records have been processed.
  673. SiteName - Name of site the client is in.
  674. DomainGuid - Specifies the GUID of the domain specified by DnsName.
  675. This value is used to handle the case of domain renames. If this
  676. value is specified and DomainName has been renamed, DsGetDcName will
  677. attempt to locate a DC in the domain having this specified DomainGuid.
  678. DnsForestName - Specifies the name of the domain at the root of the tree
  679. containing DnsName. This value is used in conjunction with DomainGuid
  680. for finding DnsName if the domain has been renamed.
  681. DcFlags - Passes additional information to be used to process the request.
  682. DcFlags can be a combination values bitwise or'ed together.
  683. Any of the following flags are allowed and have the same meaning as
  684. for DsGetDcName:
  685. DS_PDC_REQUIRED
  686. DS_GC_SERVER_REQUIRED
  687. DS_WRITABLE_REQUIRED
  688. DS_FORCE_REDISCOVERY - Avoids DNS cache
  689. If no flags are specified, no special DC role is required.
  690. RetGetDcContext - Returns an opaque context.
  691. This context must be freed using DsGetDcClose.
  692. Return Value:
  693. Status of the operation.
  694. NO_ERROR: GetDcContext was returned successfully.
  695. --*/
  696. {
  697. NET_API_STATUS NetStatus = NO_ERROR;
  698. LPSTR DnsNameUtf8 = NULL;
  699. LPSTR DnsForestNameUtf8 = NULL;
  700. //
  701. // Validate the input
  702. //
  703. if ( DnsName == NULL || *DnsName == UNICODE_NULL ) {
  704. NetStatus = ERROR_INVALID_PARAMETER;
  705. goto Cleanup;
  706. }
  707. if ( RetGetDcContext == NULL ) {
  708. NetStatus = ERROR_INVALID_PARAMETER;
  709. goto Cleanup;
  710. }
  711. //
  712. // Convert DnsName and DnsForestName to UTF-8
  713. //
  714. DnsNameUtf8 = NetpAllocUtf8StrFromWStr( DnsName );
  715. if ( DnsNameUtf8 == NULL ) {
  716. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  717. goto Cleanup;
  718. }
  719. if ( DnsForestName != NULL ) {
  720. DnsForestNameUtf8 = NetpAllocUtf8StrFromWStr( DnsForestName );
  721. if ( DnsForestNameUtf8 == NULL ) {
  722. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  723. goto Cleanup;
  724. }
  725. }
  726. NetStatus = NetpDcGetDcOpen( DnsNameUtf8,
  727. OptionFlags,
  728. SiteName,
  729. DomainGuid,
  730. DnsForestNameUtf8,
  731. DcFlags,
  732. RetGetDcContext );
  733. Cleanup:
  734. if ( DnsNameUtf8 != NULL ) {
  735. NetpMemoryFree( DnsNameUtf8 );
  736. }
  737. if ( DnsForestNameUtf8 != NULL ) {
  738. NetpMemoryFree( DnsForestNameUtf8 );
  739. }
  740. return NetStatus;
  741. }
  742. DWORD
  743. WINAPI
  744. DsGetDcOpenA(
  745. IN LPCSTR DnsName,
  746. IN ULONG OptionFlags,
  747. IN LPCSTR SiteName OPTIONAL,
  748. IN GUID *DomainGuid OPTIONAL,
  749. IN LPCSTR DnsForestName OPTIONAL,
  750. IN ULONG DcFlags,
  751. OUT PHANDLE RetGetDcContext
  752. )
  753. /*++
  754. Routine Description:
  755. Open a context for retrieval of the addresses of machines that have
  756. registered LDAP.TCP.<xxx> SRV records.
  757. Arguments:
  758. DnsName - Unicode DNS name of the LDAP server to lookup
  759. OptionFlags - Flags affecting the operation of the routine.
  760. DS_ONLY_DO_SITE_NAME - Non-site names should be ignored.
  761. DS_NOTIFY_AFTER_SITE_RECORDS - Return ERROR_FILEMARK_DETECTED
  762. after all site specific records have been processed.
  763. SiteName - Name of site the client is in.
  764. DomainGuid - Specifies the GUID of the domain specified by DnsName.
  765. This value is used to handle the case of domain renames. If this
  766. value is specified and DomainName has been renamed, DsGetDcName will
  767. attempt to locate a DC in the domain having this specified DomainGuid.
  768. DnsForestName - Specifies the name of the domain at the root of the tree
  769. containing DnsName. This value is used in conjunction with DomainGuid
  770. for finding DnsName if the domain has been renamed.
  771. DcFlags - Passes additional information to be used to process the request.
  772. DcFlags can be a combination values bitwise or'ed together.
  773. Any of the following flags are allowed and have the same meaning as
  774. for DsGetDcName:
  775. DS_PDC_REQUIRED
  776. DS_GC_SERVER_REQUIRED
  777. DS_WRITABLE_REQUIRED
  778. DS_FORCE_REDISCOVERY - Avoids DNS cache
  779. If no flags are specified, no special DC role is required.
  780. RetGetDcContext - Returns an opaque context.
  781. This context must be freed using DsGetDcClose.
  782. Return Value:
  783. Status of the operation.
  784. NO_ERROR: GetDcContext was returned successfully.
  785. --*/
  786. {
  787. NET_API_STATUS NetStatus = NO_ERROR;
  788. LPWSTR DnsNameW = NULL;
  789. LPWSTR SiteNameW = NULL;
  790. LPWSTR DnsForestNameW = NULL;
  791. //
  792. // Convert DnsName and DnsForestName to UTF-8
  793. //
  794. if ( DnsName != NULL && *DnsName != '\0' ) {
  795. DnsNameW = NetpAllocWStrFromAStr( DnsName );
  796. if ( DnsNameW == NULL ) {
  797. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  798. goto Cleanup;
  799. }
  800. }
  801. if ( SiteName != NULL && *SiteName != '\0') {
  802. SiteNameW = NetpAllocWStrFromAStr( SiteName );
  803. if ( SiteNameW == NULL ) {
  804. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  805. goto Cleanup;
  806. }
  807. }
  808. if ( DnsForestName != NULL && *DnsForestName != '\0' ) {
  809. DnsForestNameW = NetpAllocWStrFromAStr( DnsForestName );
  810. if ( DnsForestNameW == NULL ) {
  811. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  812. goto Cleanup;
  813. }
  814. }
  815. NetStatus = DsGetDcOpenW( DnsNameW,
  816. OptionFlags,
  817. SiteNameW,
  818. DomainGuid,
  819. DnsForestNameW,
  820. DcFlags,
  821. RetGetDcContext );
  822. Cleanup:
  823. if ( DnsNameW != NULL ) {
  824. NetApiBufferFree( DnsNameW );
  825. }
  826. if ( SiteNameW != NULL ) {
  827. NetApiBufferFree( SiteNameW );
  828. }
  829. if ( DnsForestNameW != NULL ) {
  830. NetApiBufferFree( DnsForestNameW );
  831. }
  832. return NetStatus;
  833. }
  834. DWORD
  835. WINAPI
  836. DsGetDcNextW(
  837. IN HANDLE GetDcContextHandle,
  838. OUT PULONG SockAddressCount OPTIONAL,
  839. OUT LPSOCKET_ADDRESS *SockAddresses OPTIONAL,
  840. OUT LPWSTR *DnsHostName OPTIONAL
  841. )
  842. /*++
  843. Routine Description:
  844. Returns the next logical SRV record for the name opened by DsGetDcOpen.
  845. The returned record takes into account the weights and priorities specified
  846. in the SRV records.
  847. Arguments:
  848. GetDcContextHandle - An opaque context describing the SRV records.
  849. SockAddressCount - Returns the number of Addresses in SockAddresses.
  850. If NULL, addresses will not be looked up.
  851. SockAddresses - Returns an array SOCKET_ADDRESS structures for the server.
  852. All returned addresses will be of family AF_INET or AF_INET6.
  853. The returned sin_port field contains port from the SRV record.
  854. A Port of 0 indicate no port is available from DNS.
  855. This buffer should be freed using LocalFree().
  856. DnsHostName - Returns a pointer to the DnsHostName in the SRV record.
  857. A NULL is returned if no host name is known. Must be freed by
  858. calling NetApiBufferFree.
  859. Return Value:
  860. NO_ERROR: Addresses were returned
  861. ERROR_NO_MORE_ITEMS: No more addresses are available.
  862. ERROR_FILEMARK_DETECTED: Caller has specified the DS_NOTIFY_AFTER_SITE_RECORDS flag
  863. and DsGetDcNext has processed all of the site specific SRV records. The caller
  864. should take any action based on no site specific DCs being available, then
  865. should call DsGetDcNext to continue on to other DCs.
  866. Any other errors returned are those detected while trying to find the A
  867. records associated with the host of the SRV record. The caller can
  868. note the error (perhaps so the caller can return this status to
  869. his caller if no usefull server is found) then call DsGetDcNext
  870. again to get the next SRV record. The caller can inspect this error
  871. and return immediately if the caller deems the error serious.
  872. The following interesting errors might be returned:
  873. DNS_ERROR_RCODE_NAME_ERROR: No A records are available for this SRV record.
  874. ERROR_TIMEOUT: DNS server didn't respond in a reasonable time
  875. --*/
  876. {
  877. NET_API_STATUS NetStatus = NO_ERROR;
  878. LPSTR DnsHostNameUtf8 = NULL;
  879. LPWSTR LocalDnsHostName = NULL;
  880. ULONG LocalSockAddressCount = 0;
  881. LPSOCKET_ADDRESS LocalSockAddresses = NULL;
  882. //
  883. // Call the internal version
  884. //
  885. NetStatus = NetpDcGetDcNext( GetDcContextHandle,
  886. SockAddressCount != NULL ?
  887. &LocalSockAddressCount :
  888. NULL,
  889. SockAddresses != NULL ?
  890. &LocalSockAddresses :
  891. NULL,
  892. DnsHostName != NULL ?
  893. &DnsHostNameUtf8 :
  894. NULL );
  895. if ( NetStatus != NO_ERROR ) {
  896. goto Cleanup;
  897. }
  898. //
  899. // Convert the host name to Unicode, if needed
  900. //
  901. if ( DnsHostName != NULL ) {
  902. LocalDnsHostName = NetpAllocWStrFromUtf8Str( DnsHostNameUtf8 );
  903. if ( LocalDnsHostName == NULL ) {
  904. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  905. goto Cleanup;
  906. }
  907. }
  908. Cleanup:
  909. //
  910. // Return the data on success or clean up on error
  911. // (No need to free DnsHostNameUtf8 as it isn't allocated)
  912. //
  913. if ( NetStatus == NO_ERROR ) {
  914. if ( SockAddressCount != NULL ) {
  915. *SockAddressCount = LocalSockAddressCount;
  916. }
  917. if ( SockAddresses != NULL ) {
  918. *SockAddresses = LocalSockAddresses;
  919. }
  920. if ( DnsHostName != NULL ) {
  921. *DnsHostName = LocalDnsHostName;
  922. }
  923. } else {
  924. if ( LocalSockAddresses != NULL ) {
  925. LocalFree( LocalSockAddresses );
  926. }
  927. if ( LocalDnsHostName != NULL ) {
  928. NetApiBufferFree( LocalDnsHostName );
  929. }
  930. }
  931. return NetStatus;
  932. }
  933. DWORD
  934. WINAPI
  935. DsGetDcNextA(
  936. IN HANDLE GetDcContextHandle,
  937. OUT PULONG SockAddressCount OPTIONAL,
  938. OUT LPSOCKET_ADDRESS *SockAddresses OPTIONAL,
  939. OUT LPSTR *DnsHostName OPTIONAL
  940. )
  941. /*++
  942. Routine Description:
  943. Returns the next logical SRV record for the name opened by DsGetDcOpen.
  944. The returned record takes into account the weights and priorities specified
  945. in the SRV records.
  946. Arguments:
  947. GetDcContextHandle - An opaque context describing the SRV records.
  948. SockAddressCount - Returns the number of Addresses in SockAddresses.
  949. If NULL, addresses will not be looked up.
  950. SockAddresses - Returns an array SOCKET_ADDRESS structures for the server.
  951. All returned addresses will be of family AF_INET or AF_INET6.
  952. The returned sin_port field contains port from the SRV record.
  953. A Port of 0 indicate no port is available from DNS.
  954. This buffer should be freed using LocalFree().
  955. DnsHostName - Returns a pointer to the DnsHostName in the SRV record.
  956. A NULL is returned if no host name is known. Must be freed by
  957. calling NetApiBufferFree.
  958. Return Value:
  959. NO_ERROR: Addresses were returned
  960. ERROR_NO_MORE_ITEMS: No more addresses are available.
  961. ERROR_FILEMARK_DETECTED: Caller has specified the DS_NOTIFY_AFTER_SITE_RECORDS flag
  962. and DsGetDcNext has processed all of the site specific SRV records. The caller
  963. should take any action based on no site specific DCs being available, then
  964. should call DsGetDcNext to continue on to other DCs.
  965. Any other errors returned are those detected while trying to find the A
  966. records associated with the host of the SRV record. The caller can
  967. note the error (perhaps so the caller can return this status to
  968. his caller if no usefull server is found) then call DsGetDcNext
  969. again to get the next SRV record. The caller can inspect this error
  970. and return immediately if the caller deems the error serious.
  971. The following interesting errors might be returned:
  972. DNS_ERROR_RCODE_NAME_ERROR: No A records are available for this SRV record.
  973. ERROR_TIMEOUT: DNS server didn't respond in a reasonable time
  974. --*/
  975. {
  976. NET_API_STATUS NetStatus = NO_ERROR;
  977. LPWSTR DnsHostNameW = NULL;
  978. LPSTR LocalDnsHostName = NULL;
  979. ULONG LocalSockAddressCount = 0;
  980. LPSOCKET_ADDRESS LocalSockAddresses = NULL;
  981. //
  982. // Call the Unicode version
  983. //
  984. NetStatus = DsGetDcNextW( GetDcContextHandle,
  985. SockAddressCount != NULL ?
  986. &LocalSockAddressCount :
  987. NULL,
  988. SockAddresses != NULL ?
  989. &LocalSockAddresses :
  990. NULL,
  991. DnsHostName != NULL ?
  992. &DnsHostNameW :
  993. NULL );
  994. if ( NetStatus != NO_ERROR ) {
  995. goto Cleanup;
  996. }
  997. //
  998. // Convert the host name to Unicode, if needed
  999. //
  1000. if ( DnsHostName != NULL ) {
  1001. LocalDnsHostName = NetpAllocAStrFromWStr( DnsHostNameW );
  1002. if ( LocalDnsHostName == NULL ) {
  1003. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  1004. goto Cleanup;
  1005. }
  1006. }
  1007. Cleanup:
  1008. if ( DnsHostNameW != NULL ) {
  1009. NetApiBufferFree( DnsHostNameW );
  1010. }
  1011. //
  1012. // Return the data on success or clean up on error
  1013. //
  1014. if ( NetStatus == NO_ERROR ) {
  1015. if ( SockAddressCount != NULL ) {
  1016. *SockAddressCount = LocalSockAddressCount;
  1017. }
  1018. if ( SockAddresses != NULL ) {
  1019. *SockAddresses = LocalSockAddresses;
  1020. }
  1021. if ( DnsHostName != NULL ) {
  1022. *DnsHostName = LocalDnsHostName;
  1023. }
  1024. } else {
  1025. if ( LocalSockAddresses != NULL ) {
  1026. LocalFree( LocalSockAddresses );
  1027. }
  1028. if ( LocalDnsHostName != NULL ) {
  1029. NetApiBufferFree( LocalDnsHostName );
  1030. }
  1031. }
  1032. return NetStatus;
  1033. }
  1034. VOID
  1035. WINAPI
  1036. DsGetDcCloseW(
  1037. IN HANDLE GetDcContextHandle
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Free the context allocated by DsGetDcOpen
  1042. Arguments:
  1043. GetDcContextHandle - An opaque context describing the SRV records.
  1044. Return Value:
  1045. None
  1046. --*/
  1047. {
  1048. //
  1049. // Just call the internal version
  1050. //
  1051. NetpDcGetDcClose( GetDcContextHandle );
  1052. }
  1053. DWORD
  1054. WINAPI
  1055. DsGetDcNameA(
  1056. IN LPCSTR ComputerName OPTIONAL,
  1057. IN LPCSTR DomainName OPTIONAL,
  1058. IN GUID *DomainGuid OPTIONAL,
  1059. IN LPCSTR SiteName OPTIONAL,
  1060. IN ULONG Flags,
  1061. OUT PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Same as DsGetDcNameW except it takes and returns ASCII.
  1066. Arguments:
  1067. Same as DsGetDcNameW except it takes and returns ASCII.
  1068. Return Value:
  1069. Same as DsGetDcNameW except it takes and returns ASCII.
  1070. --*/
  1071. {
  1072. return DsGetDcNameWithAccountA( ComputerName,
  1073. NULL,
  1074. 0,
  1075. DomainName,
  1076. DomainGuid,
  1077. SiteName,
  1078. Flags,
  1079. DomainControllerInfo );
  1080. }
  1081. DWORD
  1082. WINAPI
  1083. DsGetDcNameWithAccountA(
  1084. IN LPCSTR ComputerName OPTIONAL,
  1085. IN LPCSTR AccountName OPTIONAL,
  1086. IN ULONG AllowableAccountControlBits,
  1087. IN LPCSTR DomainName OPTIONAL,
  1088. IN GUID *DomainGuid OPTIONAL,
  1089. IN LPCSTR SiteName OPTIONAL,
  1090. IN ULONG Flags,
  1091. OUT PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Same as DsGetDcNameW except it takes and returns ASCII.
  1096. Arguments:
  1097. Same as DsGetDcNameW except it takes and returns ASCII.
  1098. Return Value:
  1099. Same as DsGetDcNameW except it takes and returns ASCII.
  1100. --*/
  1101. {
  1102. DWORD WinStatus;
  1103. LPWSTR UnicodeComputerName = NULL;
  1104. LPWSTR UnicodeAccountName = NULL;
  1105. LPWSTR UnicodeDomainName = NULL;
  1106. LPWSTR UnicodeSiteName = NULL;
  1107. LPSTR AnsiDomainControllerName = NULL;
  1108. ULONG AnsiDomainControllerNameSize = 0;
  1109. LPSTR AnsiDomainControllerAddress = NULL;
  1110. ULONG AnsiDomainControllerAddressSize = 0;
  1111. LPSTR AnsiDomainName = NULL;
  1112. ULONG AnsiDomainNameSize = 0;
  1113. LPSTR AnsiForestName = NULL;
  1114. ULONG AnsiForestNameSize = 0;
  1115. LPSTR AnsiDcSiteName = NULL;
  1116. ULONG AnsiDcSiteNameSize = 0;
  1117. LPSTR AnsiClientSiteName = NULL;
  1118. ULONG AnsiClientSiteNameSize = 0;
  1119. CHAR szBuf[] = "";
  1120. LPBYTE Where;
  1121. PDOMAIN_CONTROLLER_INFOW DomainControllerInfoW = NULL;
  1122. //
  1123. // Convert input parameters to Unicode.
  1124. //
  1125. *DomainControllerInfo = NULL;
  1126. if ( ComputerName != NULL ) {
  1127. UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
  1128. if ( UnicodeComputerName == NULL ) {
  1129. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1130. goto Cleanup;
  1131. }
  1132. }
  1133. if ( AccountName != NULL ) {
  1134. UnicodeAccountName = NetpAllocWStrFromAStr( AccountName );
  1135. if ( UnicodeAccountName == NULL ) {
  1136. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1137. goto Cleanup;
  1138. }
  1139. }
  1140. if ( DomainName != NULL ) {
  1141. UnicodeDomainName = NetpAllocWStrFromAStr( DomainName );
  1142. if ( UnicodeDomainName == NULL ) {
  1143. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1144. goto Cleanup;
  1145. }
  1146. }
  1147. if ( SiteName != NULL ) {
  1148. UnicodeSiteName = NetpAllocWStrFromAStr( SiteName );
  1149. if ( UnicodeSiteName == NULL ) {
  1150. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1151. goto Cleanup;
  1152. }
  1153. }
  1154. //
  1155. // Call the Unicode version of the routine.
  1156. //
  1157. WinStatus = DsGetDcNameWithAccountW(
  1158. UnicodeComputerName,
  1159. UnicodeAccountName,
  1160. AllowableAccountControlBits,
  1161. UnicodeDomainName,
  1162. DomainGuid,
  1163. UnicodeSiteName,
  1164. Flags,
  1165. &DomainControllerInfoW );
  1166. if ( WinStatus != NO_ERROR ) {
  1167. goto Cleanup;
  1168. }
  1169. //
  1170. // Convert the output structure to Ansi character set.
  1171. //
  1172. if ( DomainControllerInfoW->DomainControllerName != NULL ) {
  1173. AnsiDomainControllerName = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainControllerName );
  1174. if ( AnsiDomainControllerName == NULL ) {
  1175. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1176. goto Cleanup;
  1177. }
  1178. AnsiDomainControllerNameSize = lstrlenA( AnsiDomainControllerName ) + 1;
  1179. }
  1180. if ( DomainControllerInfoW->DomainControllerAddress != NULL ) {
  1181. AnsiDomainControllerAddress = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainControllerAddress );
  1182. if ( AnsiDomainControllerAddress == NULL ) {
  1183. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1184. goto Cleanup;
  1185. }
  1186. AnsiDomainControllerAddressSize = lstrlenA( AnsiDomainControllerAddress ) + 1;
  1187. }
  1188. if ( DomainControllerInfoW->DomainName != NULL ) {
  1189. AnsiDomainName = NetpAllocAStrFromWStr( DomainControllerInfoW->DomainName );
  1190. if ( AnsiDomainName == NULL ) {
  1191. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1192. goto Cleanup;
  1193. }
  1194. AnsiDomainNameSize = lstrlenA( AnsiDomainName ) + 1;
  1195. }
  1196. if ( DomainControllerInfoW->DnsForestName != NULL ) {
  1197. AnsiForestName = NetpAllocAStrFromWStr( DomainControllerInfoW->DnsForestName );
  1198. if ( AnsiForestName == NULL ) {
  1199. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1200. goto Cleanup;
  1201. }
  1202. AnsiForestNameSize = lstrlenA( AnsiForestName ) + 1;
  1203. }
  1204. if ( DomainControllerInfoW->DcSiteName != NULL ) {
  1205. AnsiDcSiteName = NetpAllocAStrFromWStr( DomainControllerInfoW->DcSiteName );
  1206. if ( AnsiDcSiteName == NULL ) {
  1207. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1208. goto Cleanup;
  1209. }
  1210. AnsiDcSiteNameSize = lstrlenA( AnsiDcSiteName ) + 1;
  1211. }
  1212. if ( DomainControllerInfoW->ClientSiteName != NULL ) {
  1213. AnsiClientSiteName = NetpAllocAStrFromWStr( DomainControllerInfoW->ClientSiteName );
  1214. if ( AnsiClientSiteName == NULL ) {
  1215. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1216. goto Cleanup;
  1217. }
  1218. AnsiClientSiteNameSize = lstrlenA( AnsiClientSiteName ) + 1;
  1219. }
  1220. //
  1221. // Allocate the Ansi version of the structure.
  1222. //
  1223. WinStatus = NetApiBufferAllocate(
  1224. sizeof(DOMAIN_CONTROLLER_INFOA) +
  1225. AnsiDomainControllerNameSize +
  1226. AnsiDomainControllerAddressSize +
  1227. AnsiDomainNameSize +
  1228. AnsiForestNameSize +
  1229. AnsiDcSiteNameSize +
  1230. AnsiClientSiteNameSize,
  1231. DomainControllerInfo );
  1232. if ( WinStatus != NO_ERROR ) {
  1233. goto Cleanup;
  1234. }
  1235. Where = (LPBYTE)((*DomainControllerInfo) + 1);
  1236. //
  1237. // Copy information into the allocated buffer.
  1238. //
  1239. *(*DomainControllerInfo) = *(PDOMAIN_CONTROLLER_INFOA)DomainControllerInfoW;
  1240. if ( AnsiDomainControllerName != NULL ) {
  1241. (*DomainControllerInfo)->DomainControllerName = Where;
  1242. RtlCopyMemory( Where,
  1243. AnsiDomainControllerName,
  1244. AnsiDomainControllerNameSize );
  1245. Where += AnsiDomainControllerNameSize;
  1246. }
  1247. if ( AnsiDomainControllerAddress != NULL ) {
  1248. (*DomainControllerInfo)->DomainControllerAddress = Where;
  1249. RtlCopyMemory( Where,
  1250. AnsiDomainControllerAddress,
  1251. AnsiDomainControllerAddressSize );
  1252. Where += AnsiDomainControllerAddressSize;
  1253. }
  1254. if ( AnsiDomainName != NULL ) {
  1255. (*DomainControllerInfo)->DomainName = Where;
  1256. RtlCopyMemory( Where,
  1257. AnsiDomainName,
  1258. AnsiDomainNameSize );
  1259. Where += AnsiDomainNameSize;
  1260. }
  1261. if ( AnsiForestName != NULL ) {
  1262. (*DomainControllerInfo)->DnsForestName = Where;
  1263. RtlCopyMemory( Where,
  1264. AnsiForestName,
  1265. AnsiForestNameSize );
  1266. Where += AnsiForestNameSize;
  1267. }
  1268. if ( AnsiDcSiteName != NULL ) {
  1269. (*DomainControllerInfo)->DcSiteName = Where;
  1270. RtlCopyMemory( Where,
  1271. AnsiDcSiteName,
  1272. AnsiDcSiteNameSize );
  1273. Where += AnsiDcSiteNameSize;
  1274. }
  1275. if ( AnsiClientSiteName != NULL ) {
  1276. (*DomainControllerInfo)->ClientSiteName = Where;
  1277. RtlCopyMemory( Where,
  1278. AnsiClientSiteName,
  1279. AnsiClientSiteNameSize );
  1280. Where += AnsiClientSiteNameSize;
  1281. }
  1282. #ifdef WIN32_CHICAGO
  1283. NlPrint((NL_MISC, "DomainControllerName: \t\t\"%s\"\n", AnsiDomainControllerName ? AnsiDomainControllerName : szBuf));
  1284. NlPrint((NL_MISC, "DomainControllerAddress:\t\t\"%s\"\n", AnsiDomainControllerAddress ? AnsiDomainControllerAddress : szBuf ));
  1285. NlPrint((NL_MISC, "DomainControllerAddressType: \t%d\n", DomainControllerInfoW->DomainControllerAddressType ));
  1286. NlPrint((NL_MISC, "DomainGuid : \t\n"));
  1287. NlPrint((NL_MISC, "DomainName: \t\t\t\"%s\"\n", AnsiDomainName ? AnsiDomainName : szBuf));
  1288. NlPrint((NL_MISC, "DnsForestName: \t\t\t\"%s\"\n", AnsiForestName ? AnsiForestName : szBuf));
  1289. NlPrint((NL_MISC, "Flags: \t\t\t\t 0x%x\n", DomainControllerInfoW->Flags));
  1290. NlPrint((NL_MISC, "DcSiteName: \t\t\t\"%s\"\n", AnsiDcSiteName ? AnsiDcSiteName : szBuf));
  1291. NlPrint((NL_MISC, "ClientSiteName: \t\t\t\"%s\"\n", AnsiClientSiteName ? AnsiClientSiteName : szBuf));
  1292. #endif // WIN32_CHICAGO
  1293. WinStatus = NO_ERROR;
  1294. //
  1295. // Clean up locally used resources.
  1296. //
  1297. Cleanup:
  1298. if ( UnicodeComputerName != NULL ) {
  1299. NetApiBufferFree( UnicodeComputerName );
  1300. }
  1301. if ( UnicodeAccountName != NULL ) {
  1302. NetApiBufferFree( UnicodeAccountName );
  1303. }
  1304. if ( UnicodeDomainName != NULL ) {
  1305. NetApiBufferFree( UnicodeDomainName );
  1306. }
  1307. if ( UnicodeSiteName != NULL ) {
  1308. NetApiBufferFree( UnicodeSiteName );
  1309. }
  1310. if ( DomainControllerInfoW != NULL ) {
  1311. NetApiBufferFree( DomainControllerInfoW );
  1312. }
  1313. if ( AnsiDomainControllerName != NULL ) {
  1314. NetApiBufferFree( AnsiDomainControllerName );
  1315. }
  1316. if ( AnsiDomainControllerAddress != NULL ) {
  1317. NetApiBufferFree( AnsiDomainControllerAddress );
  1318. }
  1319. if ( AnsiDomainName != NULL ) {
  1320. NetApiBufferFree( AnsiDomainName );
  1321. }
  1322. if ( AnsiForestName != NULL ) {
  1323. NetApiBufferFree( AnsiForestName );
  1324. }
  1325. if ( AnsiDcSiteName != NULL ) {
  1326. NetApiBufferFree( AnsiDcSiteName );
  1327. }
  1328. if ( AnsiClientSiteName != NULL ) {
  1329. NetApiBufferFree( AnsiClientSiteName );
  1330. }
  1331. if ( WinStatus != NO_ERROR ) {
  1332. if ( *DomainControllerInfo != NULL ) {
  1333. NetApiBufferFree( *DomainControllerInfo );
  1334. *DomainControllerInfo = NULL;
  1335. }
  1336. }
  1337. return WinStatus;
  1338. }
  1339. #ifndef WIN32_CHICAGO
  1340. NTSTATUS
  1341. NlWaitForEvent(
  1342. LPWSTR EventName,
  1343. ULONG Timeout
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. Wait up to Timeout seconds for EventName to be triggered.
  1348. Arguments:
  1349. EventName - Name of event to wait on
  1350. Timeout - Timeout for event (in seconds).
  1351. Return Status:
  1352. STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  1353. STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  1354. --*/
  1355. {
  1356. NTSTATUS Status;
  1357. HANDLE EventHandle;
  1358. OBJECT_ATTRIBUTES EventAttributes;
  1359. UNICODE_STRING EventNameString;
  1360. LARGE_INTEGER LocalTimeout;
  1361. //
  1362. // Create an event for us to wait on.
  1363. //
  1364. RtlInitUnicodeString( &EventNameString, EventName);
  1365. InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
  1366. Status = NtCreateEvent(
  1367. &EventHandle,
  1368. SYNCHRONIZE,
  1369. &EventAttributes,
  1370. NotificationEvent,
  1371. (BOOLEAN) FALSE // The event is initially not signaled
  1372. );
  1373. if ( !NT_SUCCESS(Status)) {
  1374. //
  1375. // If the event already exists, the server beat us to creating it.
  1376. // Just open it.
  1377. //
  1378. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  1379. Status == STATUS_OBJECT_NAME_COLLISION ) {
  1380. Status = NtOpenEvent( &EventHandle,
  1381. SYNCHRONIZE,
  1382. &EventAttributes );
  1383. }
  1384. if ( !NT_SUCCESS(Status)) {
  1385. NlPrint((0,"[NETAPI32] OpenEvent failed %lx\n", Status ));
  1386. return Status;
  1387. }
  1388. }
  1389. //
  1390. // Wait for NETLOGON to initialize. Wait a maximum of Timeout seconds.
  1391. //
  1392. LocalTimeout.QuadPart = ((LONGLONG)(Timeout)) * (-10000000);
  1393. Status = NtWaitForSingleObject( EventHandle, (BOOLEAN)FALSE, &LocalTimeout);
  1394. (VOID) NtClose( EventHandle );
  1395. if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
  1396. if ( Status == STATUS_TIMEOUT ) {
  1397. Status = STATUS_NETLOGON_NOT_STARTED; // Map to an error condition
  1398. }
  1399. return Status;
  1400. }
  1401. return STATUS_SUCCESS;
  1402. }
  1403. NTSTATUS
  1404. NlWaitForNetlogon(
  1405. ULONG Timeout
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. Wait up to Timeout seconds for the netlogon service to start.
  1410. Arguments:
  1411. Timeout - Timeout for event (in seconds).
  1412. Return Status:
  1413. STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  1414. STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  1415. --*/
  1416. {
  1417. NTSTATUS Status;
  1418. NET_API_STATUS NetStatus;
  1419. SC_HANDLE ScManagerHandle = NULL;
  1420. SC_HANDLE ServiceHandle = NULL;
  1421. SERVICE_STATUS ServiceStatus;
  1422. LPQUERY_SERVICE_CONFIG ServiceConfig;
  1423. LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
  1424. QUERY_SERVICE_CONFIG DummyServiceConfig;
  1425. DWORD ServiceConfigSize;
  1426. //
  1427. // If the netlogon service is currently running,
  1428. // skip the rest of the tests.
  1429. //
  1430. Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 0 );
  1431. if ( NT_SUCCESS(Status) ) {
  1432. return Status;
  1433. }
  1434. //
  1435. // If we're in setup,
  1436. // don't bother waiting for netlogon to start.
  1437. //
  1438. if ( NlDoingSetup() ) {
  1439. return STATUS_NETLOGON_NOT_STARTED;
  1440. }
  1441. //
  1442. // Open a handle to the Netlogon Service.
  1443. //
  1444. ScManagerHandle = OpenSCManager(
  1445. NULL,
  1446. NULL,
  1447. SC_MANAGER_CONNECT );
  1448. if (ScManagerHandle == NULL) {
  1449. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenSCManager failed: "
  1450. "%lu\n", GetLastError()));
  1451. Status = STATUS_NETLOGON_NOT_STARTED;
  1452. goto Cleanup;
  1453. }
  1454. ServiceHandle = OpenService(
  1455. ScManagerHandle,
  1456. SERVICE_NETLOGON,
  1457. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  1458. if ( ServiceHandle == NULL ) {
  1459. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenService failed: "
  1460. "%lu\n", GetLastError()));
  1461. Status = STATUS_NETLOGON_NOT_STARTED;
  1462. goto Cleanup;
  1463. }
  1464. //
  1465. // If the Netlogon service isn't configured to be automatically started
  1466. // by the service controller, don't bother waiting for it to start.
  1467. //
  1468. // ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
  1469. // won't allow a null pointer, yet.
  1470. if ( QueryServiceConfig(
  1471. ServiceHandle,
  1472. &DummyServiceConfig,
  1473. sizeof(DummyServiceConfig),
  1474. &ServiceConfigSize )) {
  1475. ServiceConfig = &DummyServiceConfig;
  1476. } else {
  1477. NetStatus = GetLastError();
  1478. if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
  1479. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig failed: "
  1480. "%lu\n", NetStatus));
  1481. Status = STATUS_NETLOGON_NOT_STARTED;
  1482. goto Cleanup;
  1483. }
  1484. AllocServiceConfig = LocalAlloc( 0, ServiceConfigSize );
  1485. ServiceConfig = AllocServiceConfig;
  1486. if ( AllocServiceConfig == NULL ) {
  1487. Status = STATUS_NO_MEMORY;
  1488. goto Cleanup;
  1489. }
  1490. if ( !QueryServiceConfig(
  1491. ServiceHandle,
  1492. ServiceConfig,
  1493. ServiceConfigSize,
  1494. &ServiceConfigSize )) {
  1495. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig "
  1496. "failed again: %lu\n", GetLastError()));
  1497. Status = STATUS_NETLOGON_NOT_STARTED;
  1498. goto Cleanup;
  1499. }
  1500. }
  1501. if ( ServiceConfig->dwStartType != SERVICE_AUTO_START ) {
  1502. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: Netlogon start type invalid:"
  1503. "%lu\n", ServiceConfig->dwStartType ));
  1504. Status = STATUS_NETLOGON_NOT_STARTED;
  1505. goto Cleanup;
  1506. }
  1507. //
  1508. // Loop waiting for the netlogon service to start.
  1509. // (Convert Timeout to a number of 10 second iterations)
  1510. //
  1511. Timeout = (Timeout+9)/10;
  1512. for (;;) {
  1513. //
  1514. // Query the status of the Netlogon service.
  1515. //
  1516. if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
  1517. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceStatus failed: "
  1518. "%lu\n", GetLastError() ));
  1519. Status = STATUS_NETLOGON_NOT_STARTED;
  1520. goto Cleanup;
  1521. }
  1522. //
  1523. // Return or continue waiting depending on the state of
  1524. // the netlogon service.
  1525. //
  1526. switch( ServiceStatus.dwCurrentState) {
  1527. case SERVICE_RUNNING:
  1528. Status = STATUS_SUCCESS;
  1529. goto Cleanup;
  1530. case SERVICE_STOPPED:
  1531. //
  1532. // If Netlogon failed to start,
  1533. // error out now. The caller has waited long enough to start.
  1534. //
  1535. if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
  1536. #if NETLOGONDBG
  1537. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
  1538. "Netlogon service couldn't start: %lu %lx\n",
  1539. ServiceStatus.dwWin32ExitCode,
  1540. ServiceStatus.dwWin32ExitCode ));
  1541. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  1542. NlPrint((0, " Service specific error code: %lu %lx\n",
  1543. ServiceStatus.dwServiceSpecificExitCode,
  1544. ServiceStatus.dwServiceSpecificExitCode ));
  1545. }
  1546. #endif // DBG
  1547. Status = STATUS_NETLOGON_NOT_STARTED;
  1548. goto Cleanup;
  1549. }
  1550. //
  1551. // If Netlogon has never been started on this boot,
  1552. // continue waiting for it to start.
  1553. //
  1554. break;
  1555. //
  1556. // If Netlogon is trying to start up now,
  1557. // continue waiting for it to start.
  1558. //
  1559. case SERVICE_START_PENDING:
  1560. break;
  1561. //
  1562. // Any other state is bogus.
  1563. //
  1564. default:
  1565. NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
  1566. "Invalid service state: %lu\n",
  1567. ServiceStatus.dwCurrentState ));
  1568. Status = STATUS_NETLOGON_NOT_STARTED;
  1569. goto Cleanup;
  1570. }
  1571. //
  1572. // Wait ten seconds for the netlogon service to start.
  1573. // If it has successfully started, just return now.
  1574. //
  1575. Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 10 );
  1576. if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
  1577. goto Cleanup;
  1578. }
  1579. //
  1580. // If we've waited long enough for netlogon to start,
  1581. // time out now.
  1582. //
  1583. if ( (--Timeout) == 0 ) {
  1584. Status = STATUS_NETLOGON_NOT_STARTED;
  1585. goto Cleanup;
  1586. }
  1587. }
  1588. /* NOT REACHED */
  1589. Cleanup:
  1590. if ( ScManagerHandle != NULL ) {
  1591. (VOID) CloseServiceHandle(ScManagerHandle);
  1592. }
  1593. if ( ServiceHandle != NULL ) {
  1594. (VOID) CloseServiceHandle(ServiceHandle);
  1595. }
  1596. if ( AllocServiceConfig != NULL ) {
  1597. LocalFree( AllocServiceConfig );
  1598. }
  1599. return Status;
  1600. }
  1601. #endif // WIN32_CHICAGO
  1602. DWORD
  1603. WINAPI
  1604. #ifdef NETTEST_UTILITY
  1605. NettestDsGetDcNameW(
  1606. #else // NETTEST_UTILITY
  1607. DsGetDcNameW(
  1608. #endif // NETTEST_UTILITY
  1609. IN LPCWSTR ComputerName OPTIONAL,
  1610. IN LPCWSTR DomainName OPTIONAL,
  1611. IN GUID *DomainGuid OPTIONAL,
  1612. IN LPCWSTR SiteName OPTIONAL,
  1613. IN ULONG Flags,
  1614. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. The DsGetDcName API returns the name of a DC in a specified domain.
  1619. The domain may be trusted (directly or indirectly) by the caller or
  1620. may be untrusted. DC selection criteria are supplied to the API to
  1621. indicate preference for a DC with particular characteristics.
  1622. The DsGetDcName API is available in an ANSI and UNICODE versions.
  1623. This is the Unicode version.
  1624. The DsGetDcName API does not require any particular access to the
  1625. specified domain. DsGetDcName does not ensure the returned domain
  1626. controller is currently available by default. Rather, the caller
  1627. should attempt to use the returned domain controller. If the domain
  1628. controller is indeed not available, the caller should repeat the
  1629. DsGetDcName call specifying the DS_FORCE_REDISCOVERY flag.
  1630. The DsGetDcName API is remoted to the Netlogon service on the machine
  1631. specified by ComputerName.
  1632. Arguments:
  1633. ComputerName - Specifies the name of the server to remote this API to.
  1634. Typically, this parameter should be specified as NULL.
  1635. DomainName - The name of the domain to query. This name can either be a
  1636. DNS-style name (e.g., microsoft.com) or a flat-style name
  1637. (e.g., microsoft).
  1638. DomainGuid - Specifies the Domain GUID of the domain being queried.
  1639. This value is used to handle the case of domain renames. If this
  1640. value is specified and DomainName has been renamed, DsGetDcName will
  1641. attempt to locate a DC in the domain having this specified DomainGuid.
  1642. SiteName - Specifies the site name of the site the returned DC should be
  1643. "close" to. The parameter should typically be the site name of the
  1644. site the client is in. If not specified, the site name defaults to
  1645. the site of ComputerName.
  1646. Flags - Passes additional information to be used to process the request.
  1647. Flags can be a combination values bitwise or'ed together.
  1648. DomainControllerInfo - Returns a pointer to a DOMAIN_CONTROLLER_INFO
  1649. structure describing the domain controller selected. The returned
  1650. structure must be deallocated using NetApiBufferFree.
  1651. Return Value:
  1652. NO_ERROR - Operation completed successfully;
  1653. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  1654. operation.
  1655. ERROR_INVALID_DOMAINNAME - The format of the specified domain name is
  1656. invalid.
  1657. ERROR_NO_SUCH_DOMAIN: No DC is available for the specified domain or
  1658. the domain does not exist.
  1659. ERROR_NO_SUCH_USER: A DC responded that the specified user account
  1660. doesn't exist
  1661. ERROR_INVALID_FLAGS - The flags parameter has conflicting or superfluous
  1662. bits set.
  1663. ERROR_INTERNAL_ERROR: Unhandled situation detected.
  1664. Various Winsock errors.
  1665. --*/
  1666. {
  1667. NET_API_STATUS NetStatus;
  1668. return DsGetDcNameWithAccountW(
  1669. ComputerName,
  1670. NULL, // no AccountName,
  1671. 0, // no AllowableAccountControlBits,
  1672. DomainName,
  1673. DomainGuid,
  1674. SiteName,
  1675. Flags,
  1676. DomainControllerInfo );
  1677. }
  1678. DWORD
  1679. WINAPI
  1680. DsGetDcNameWithAccountW(
  1681. IN LPCWSTR ComputerName OPTIONAL,
  1682. IN LPCWSTR AccountName OPTIONAL,
  1683. IN ULONG AllowableAccountControlBits,
  1684. IN LPCWSTR DomainName OPTIONAL,
  1685. IN GUID *DomainGuid OPTIONAL,
  1686. IN LPCWSTR SiteName OPTIONAL,
  1687. IN ULONG Flags,
  1688. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  1689. )
  1690. /*++
  1691. Routine Description:
  1692. The DsGetDcName API returns the name of a DC in a specified domain.
  1693. The domain may be trusted (directly or indirectly) by the caller or
  1694. may be untrusted. DC selection criteria are supplied to the API to
  1695. indicate preference for a DC with particular characteristics.
  1696. The DsGetDcName API is available in an ANSI and UNICODE versions.
  1697. This is the Unicode version.
  1698. The DsGetDcName API does not require any particular access to the
  1699. specified domain. DsGetDcName does not ensure the returned domain
  1700. controller is currently available by default. Rather, the caller
  1701. should attempt to use the returned domain controller. If the domain
  1702. controller is indeed not available, the caller should repeat the
  1703. DsGetDcName call specifying the DS_FORCE_REDISCOVERY flag.
  1704. The DsGetDcName API is remoted to the Netlogon service on the machine
  1705. specified by ComputerName.
  1706. Arguments:
  1707. ComputerName - Specifies the name of the server to remote this API to.
  1708. Typically, this parameter should be specified as NULL.
  1709. AccountName - Account name to pass on the ping request.
  1710. If NULL, no account name will be sent.
  1711. AllowableAccountControlBits - Mask of allowable account types for AccountName.
  1712. Valid bits are those specified by UF_MACHINE_ACCOUNT_MASK.
  1713. Invalid bits are ignored. If more than one bit is specified, the
  1714. account can be of any of the specified types.
  1715. DomainName - The name of the domain to query. This name can either be a
  1716. DNS-style name (e.g., microsoft.com) or a flat-style name
  1717. (e.g., microsoft).
  1718. DomainGuid - Specifies the Domain GUID of the domain being queried.
  1719. This value is used to handle the case of domain renames. If this
  1720. value is specified and DomainName has been renamed, DsGetDcName will
  1721. attempt to locate a DC in the domain having this specified DomainGuid.
  1722. SiteName - Specifies the site name of the site the returned DC should be
  1723. "close" to. The parameter should typically be the site name of the
  1724. site the client is in. If not specified, the site name defaults to
  1725. the site of ComputerName.
  1726. Flags - Passes additional information to be used to process the request.
  1727. Flags can be a combination values bitwise or'ed together.
  1728. DomainControllerInfo - Returns a pointer to a DOMAIN_CONTROLLER_INFO
  1729. structure describing the domain controller selected. The returned
  1730. structure must be deallocated using NetApiBufferFree.
  1731. Return Value:
  1732. NO_ERROR - Operation completed successfully;
  1733. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  1734. operation.
  1735. ERROR_INVALID_DOMAINNAME - The format of the specified domain name is
  1736. invalid.
  1737. ERROR_NO_SUCH_DOMAIN: No DC is available for the specified domain or
  1738. the domain does not exist.
  1739. ERROR_NO_SUCH_USER: A DC responded that the specified user account
  1740. doesn't exist
  1741. ERROR_INVALID_FLAGS - The flags parameter has conflicting or superfluous
  1742. bits set.
  1743. ERROR_INTERNAL_ERROR: Unhandled situation detected.
  1744. Various Winsock errors.
  1745. --*/
  1746. {
  1747. NET_API_STATUS NetStatus;
  1748. GUID *PrimaryDomainGuid = NULL;
  1749. LPWSTR NetbiosPrimaryDomainName = NULL;
  1750. LPWSTR DnsPrimaryDomainName = NULL;
  1751. LPWSTR DnsPrimaryForestName = NULL;
  1752. BOOLEAN IsWorkgroupName;
  1753. BOOLEAN Local;
  1754. //
  1755. // Determine the PrimaryDomainName
  1756. //
  1757. #ifdef WIN32_CHICAGO
  1758. NetStatus = NetpGetDomainNameExEx( &NetbiosPrimaryDomainName,
  1759. &DnsPrimaryDomainName,
  1760. &IsWorkgroupName );
  1761. #else // WIN32_CHICAGO
  1762. NetStatus = NetpGetDomainNameExExEx( &NetbiosPrimaryDomainName,
  1763. &DnsPrimaryDomainName,
  1764. &DnsPrimaryForestName,
  1765. &PrimaryDomainGuid,
  1766. &IsWorkgroupName );
  1767. #endif // WIN32_CHICAGO
  1768. if ( NetStatus != NERR_Success ) {
  1769. NlPrint(( 0, "DsGetDcNameW: cannot call NetpGetDomainName: %ld\n",
  1770. NetStatus));
  1771. goto Cleanup;
  1772. }
  1773. #ifdef WIN32_CHICAGO
  1774. IsWorkgroupName = TRUE;
  1775. #endif // WIN32_CHICAGO
  1776. #ifdef NETTEST_UTILITY
  1777. IsWorkgroupName = TRUE;
  1778. #endif // NETTEST_UTILITY
  1779. //
  1780. // Sanity check the domain name since LSA doesn't and I'll AV below
  1781. //
  1782. if ( NetbiosPrimaryDomainName != NULL &&
  1783. wcslen( NetbiosPrimaryDomainName) > DNLEN ) {
  1784. NlPrint(( 0, "DsGetDcNameW: Workgroup name is too long: %ld\n",
  1785. wcslen( NetbiosPrimaryDomainName ) ));
  1786. NetStatus = ERROR_INVALID_DOMAINNAME;
  1787. goto Cleanup;
  1788. }
  1789. //
  1790. // If this machine is a member of a workgroup (not a domain),
  1791. // and the API isn't remoted,
  1792. // do the algorithm here.
  1793. // Netlogon isn't running on this machine.
  1794. //
  1795. if ( IsWorkgroupName ) {
  1796. DWORD Timeout = NL_DC_MAX_TIMEOUT; // 15 seconds
  1797. DWORD DialUpDelayInSeconds;
  1798. //
  1799. // Read the dial up delay from the registry. Add it to the
  1800. // maximum DC discovery timeout to account for dial up
  1801. // connections. If the value cannot be read, ignore it.
  1802. //
  1803. if ( NlReadDwordNetlogonRegValue("ExpectedDialupDelay",
  1804. &DialUpDelayInSeconds) ) {
  1805. NlPrint(( 0, "DsGetDcNameWithAccountW: Read dial up delay of %ld seconds\n",
  1806. DialUpDelayInSeconds ));
  1807. Timeout += DialUpDelayInSeconds * 1000;
  1808. }
  1809. NetStatus = DsLocalGetDcName(
  1810. ComputerName,
  1811. AccountName,
  1812. AllowableAccountControlBits,
  1813. DomainName,
  1814. DomainGuid,
  1815. SiteName,
  1816. Flags,
  1817. DS_PRIMARY_NAME_IS_WORKGROUP,
  1818. Timeout,
  1819. NetbiosPrimaryDomainName,
  1820. DnsPrimaryDomainName,
  1821. DnsPrimaryForestName,
  1822. PrimaryDomainGuid,
  1823. &Local,
  1824. DomainControllerInfo );
  1825. //
  1826. // If the call was performed locally,
  1827. // We're all done regardless of the status.
  1828. //
  1829. if ( Local ) {
  1830. goto Cleanup;
  1831. }
  1832. }
  1833. #ifndef NETTEST_UTILITY
  1834. #ifndef WIN32_CHICAGO
  1835. //
  1836. // Remote the API to the Netlogon service.
  1837. //
  1838. // Do the RPC call with an exception handler since RPC will raise an
  1839. // exception if anything fails. It is up to us to figure out what
  1840. // to do once the exception is raised.
  1841. //
  1842. RpcTryExcept {
  1843. //
  1844. // Call RPC version of the API.
  1845. //
  1846. *DomainControllerInfo = NULL; // Force RPC to allocate
  1847. NetStatus = DsrGetDcNameEx2(
  1848. (LPWSTR) ComputerName,
  1849. (LPWSTR) AccountName,
  1850. AllowableAccountControlBits,
  1851. (LPWSTR) DomainName,
  1852. DomainGuid,
  1853. (LPWSTR) SiteName,
  1854. Flags,
  1855. DomainControllerInfo );
  1856. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  1857. NetStatus = RpcExceptionCode();
  1858. } RpcEndExcept;
  1859. //
  1860. // If the netlogon service isn't running,
  1861. // and it's in the process of starting,
  1862. // wait for it to start.
  1863. //
  1864. if ( NetStatus == RPC_S_UNKNOWN_IF ) {
  1865. NTSTATUS TempStatus;
  1866. TempStatus = NlWaitForNetlogon( 90 );
  1867. if ( NT_SUCCESS(TempStatus) ) {
  1868. RpcTryExcept {
  1869. //
  1870. // Call RPC version of the API.
  1871. //
  1872. *DomainControllerInfo = NULL; // Force RPC to allocate
  1873. NetStatus = DsrGetDcNameEx2(
  1874. (LPWSTR) ComputerName,
  1875. (LPWSTR) AccountName,
  1876. AllowableAccountControlBits,
  1877. (LPWSTR) DomainName,
  1878. DomainGuid,
  1879. (LPWSTR) SiteName,
  1880. Flags,
  1881. DomainControllerInfo );
  1882. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  1883. NetStatus = RpcExceptionCode();
  1884. } RpcEndExcept;
  1885. }
  1886. }
  1887. //
  1888. // If Netlogon isn't running on the local machine,
  1889. // or Netlogon is the NT 4.0 version of netlogon (the upgrade case),
  1890. // try doing the call in-process.
  1891. //
  1892. if ( NetStatus == RPC_S_UNKNOWN_IF ||
  1893. NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
  1894. NET_API_STATUS TempStatus;
  1895. DWORD Timeout = NL_DC_MAX_TIMEOUT; // 15 seconds
  1896. DWORD DialUpDelayInSeconds;
  1897. //
  1898. // Read the dial up delay from the registry. Add it to the
  1899. // maximum DC discovery timeout to account for dial up
  1900. // connections. If the value cannot be read, ignore it.
  1901. //
  1902. if ( NlReadDwordNetlogonRegValue("ExpectedDialupDelay",
  1903. &DialUpDelayInSeconds) ) {
  1904. NlPrint(( 0, "DsGetDcNameWithAccountW: Read dial up delay of %ld seconds\n",
  1905. DialUpDelayInSeconds ));
  1906. Timeout += DialUpDelayInSeconds * 1000;
  1907. }
  1908. TempStatus = DsLocalGetDcName(
  1909. ComputerName,
  1910. AccountName,
  1911. AllowableAccountControlBits,
  1912. DomainName,
  1913. DomainGuid,
  1914. SiteName,
  1915. Flags,
  1916. IsWorkgroupName ?
  1917. DS_PRIMARY_NAME_IS_WORKGROUP : 0,
  1918. Timeout,
  1919. NetbiosPrimaryDomainName,
  1920. DnsPrimaryDomainName,
  1921. DnsPrimaryForestName,
  1922. PrimaryDomainGuid,
  1923. &Local,
  1924. DomainControllerInfo );
  1925. //
  1926. // If the call was performed locally,
  1927. // We're all done regardless of the status.
  1928. //
  1929. if ( Local ) {
  1930. NetStatus = TempStatus;
  1931. goto Cleanup;
  1932. }
  1933. }
  1934. #endif // WIN32_CHICAGO
  1935. #endif // NETTEST_UTILITY
  1936. IF_DEBUG( LOGON ) {
  1937. #ifndef WIN32_CHICAGO
  1938. NetpKdPrint(("DsrGetDcName rc = %lu 0x%lx\n",
  1939. NetStatus, NetStatus));
  1940. #else // WIN32_CHICAGO
  1941. NlPrint((0, "DsrGetDcName rc = %lu 0x%lx\n",
  1942. NetStatus, NetStatus));
  1943. #endif // WIN32_CHICAGO
  1944. }
  1945. Cleanup:
  1946. //
  1947. // Cleanup all locally used resources
  1948. //
  1949. if ( NetbiosPrimaryDomainName != NULL ) {
  1950. NetApiBufferFree( NetbiosPrimaryDomainName );
  1951. }
  1952. if ( DnsPrimaryDomainName != NULL ) {
  1953. NetApiBufferFree( DnsPrimaryDomainName );
  1954. }
  1955. if ( DnsPrimaryForestName != NULL ) {
  1956. NetApiBufferFree( DnsPrimaryForestName );
  1957. }
  1958. if ( PrimaryDomainGuid != NULL ) {
  1959. NetApiBufferFree( PrimaryDomainGuid );
  1960. }
  1961. #ifdef WIN32_CHICAGO
  1962. NlPrint((NL_MISC, "DsGetDcNameWithAccountW rc = %lu 0x%lx\n",
  1963. NetStatus, NetStatus));
  1964. #endif // WIN32_CHICAGO
  1965. return NetStatus;
  1966. }
  1967. #ifndef NETTEST_UTILITY
  1968. #ifndef WIN32_CHICAGO
  1969. NET_API_STATUS NET_API_FUNCTION
  1970. NetGetDCName (
  1971. IN LPCWSTR ServerName OPTIONAL,
  1972. IN LPCWSTR DomainName OPTIONAL,
  1973. OUT LPBYTE *Buffer
  1974. )
  1975. /*++
  1976. Routine Description:
  1977. Get the name of the primary domain controller for a domain.
  1978. Arguments:
  1979. ServerName - name of remote server (null for local)
  1980. DomainName - name of domain (null for primary)
  1981. Buffer - Returns a pointer to an allcated buffer containing the
  1982. servername of the PDC of the domain. The server name is prefixed
  1983. by \\. The buffer should be deallocated using NetApiBufferFree.
  1984. Return Value:
  1985. NERR_Success - Success. Buffer contains PDC name prefixed by \\.
  1986. NERR_DCNotFound No DC found for this domain.
  1987. ERROR_INVALID_NAME Badly formed domain name
  1988. --*/
  1989. {
  1990. NET_API_STATUS NetStatus = 0;
  1991. PDOMAIN_CONTROLLER_INFOW DomainControllerInfo = NULL;
  1992. //
  1993. // API SECURITY - Anyone can call anytime. No code required.
  1994. //
  1995. //
  1996. // Check if API is to be remoted, and handle downlevel case if so.
  1997. //
  1998. if ( (ServerName != NULL) && ( ServerName[0] != '\0') ) {
  1999. WCHAR UncCanonServerName[UNCLEN+1];
  2000. DWORD LocalOrRemote;
  2001. NetStatus = NetpIsRemote(
  2002. (LPWSTR) ServerName, // uncanon server name
  2003. & LocalOrRemote,
  2004. UncCanonServerName, // output: canon
  2005. NIRFLAG_MAPLOCAL // flags: map null to local name
  2006. );
  2007. if (NetStatus != NERR_Success) {
  2008. goto Cleanup;
  2009. }
  2010. if (LocalOrRemote == ISREMOTE) {
  2011. //
  2012. // Do the RPC call with an exception handler since RPC will raise an
  2013. // exception if anything fails. It is up to us to figure out what
  2014. // to do once the exception is raised.
  2015. //
  2016. NET_REMOTE_TRY_RPC
  2017. //
  2018. // Call RPC version of the API.
  2019. //
  2020. *Buffer = NULL;
  2021. NetStatus = NetrGetDCName(
  2022. (LPWSTR) ServerName,
  2023. (LPWSTR) DomainName,
  2024. (LPWSTR *)Buffer );
  2025. NET_REMOTE_RPC_FAILED(
  2026. "NetGetDCName",
  2027. UncCanonServerName,
  2028. NetStatus,
  2029. NET_REMOTE_FLAG_NORMAL,
  2030. SERVICE_NETLOGON )
  2031. //
  2032. // We should probaly check if it's really a downlevel machine
  2033. //
  2034. NetStatus = RxNetGetDCName(
  2035. UncCanonServerName,
  2036. (LPWSTR) DomainName,
  2037. (LPBYTE *) Buffer // may be allocated
  2038. );
  2039. NET_REMOTE_END
  2040. goto Cleanup;
  2041. }
  2042. //
  2043. // Must be explicit reference to local machine. Fall through and
  2044. // handle it.
  2045. //
  2046. }
  2047. //
  2048. // Simply call DsGetDcName to find the PDC.
  2049. //
  2050. // NT 3.x cached the response for the primary domain. The was Lanman
  2051. // legacy to avoid the expensive discovery. However, NT discovery is
  2052. // cheaper than the API calls Lanman used to verify the cached information.
  2053. //
  2054. //
  2055. NetStatus = DsGetDcNameW(
  2056. NULL, // Not remoted
  2057. DomainName,
  2058. NULL, // No Domain GUID
  2059. NULL, // No Site GUID
  2060. DS_FORCE_REDISCOVERY |
  2061. DS_PDC_REQUIRED |
  2062. DS_IS_FLAT_NAME |
  2063. DS_RETURN_FLAT_NAME,
  2064. &DomainControllerInfo );
  2065. //
  2066. // Map the status codes to be compatible.
  2067. //
  2068. if ( NetStatus != NO_ERROR ) {
  2069. if ( NlDcUseGenericStatus(NetStatus) ) {
  2070. NetStatus = NERR_DCNotFound;
  2071. }
  2072. goto Cleanup;
  2073. }
  2074. //
  2075. // Allocate a buffer to return to the caller and fill it in
  2076. //
  2077. NetStatus = NetapipBufferAllocate(
  2078. (wcslen(DomainControllerInfo->DomainControllerName) + 1) * sizeof(WCHAR),
  2079. (LPVOID *) Buffer );
  2080. if ( NetStatus != NO_ERROR ) {
  2081. IF_DEBUG( LOGON ) {
  2082. NetpKdPrint(( "NetGetDCName: cannot allocate response buffer.\n"));
  2083. }
  2084. goto Cleanup;
  2085. }
  2086. wcscpy((LPWSTR)*Buffer, DomainControllerInfo->DomainControllerName );
  2087. Cleanup:
  2088. //
  2089. // Cleanup all locally used resources
  2090. //
  2091. if ( DomainControllerInfo != NULL ) {
  2092. NetApiBufferFree( DomainControllerInfo );
  2093. }
  2094. return NetStatus;
  2095. }
  2096. NET_API_STATUS NET_API_FUNCTION
  2097. NetGetAnyDCName (
  2098. IN LPCWSTR ServerName OPTIONAL,
  2099. IN LPCWSTR DomainName OPTIONAL,
  2100. OUT LPBYTE *Buffer
  2101. )
  2102. /*++
  2103. Routine Description:
  2104. Get the name of the any domain controller for a domain that is directly trusted
  2105. by ServerName.
  2106. If ServerName is a standalone Windows NT Workstation or standalone Windows NT Server,
  2107. no DomainName is valid.
  2108. If ServerName is a Windows NT Workstation that is a member of a domain or a
  2109. Windows NT Server member server,
  2110. the DomainName must the the domain ServerName is a member of.
  2111. If ServerName is a Windows NT Server domain controller,
  2112. the DomainName must be one of the domains trusted by the
  2113. domain the server is a controller for.
  2114. The domain controller found is guaranteed to have been up at one point during
  2115. this API call.
  2116. Arguments:
  2117. ServerName - name of remote server (null for local)
  2118. DomainName - name of domain (null for primary domain)
  2119. Buffer - Returns a pointer to an allcated buffer containing the
  2120. servername of a DC of the domain. The server name is prefixed
  2121. by \\. The buffer should be deallocated using NetApiBufferFree.
  2122. Return Value:
  2123. ERROR_SUCCESS - Success. Buffer contains DC name prefixed by \\.
  2124. ERROR_NO_LOGON_SERVERS - No DC could be found
  2125. ERROR_NO_SUCH_DOMAIN - The specified domain is not a trusted domain.
  2126. ERROR_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
  2127. broken.
  2128. ERROR_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
  2129. broken or the password is broken.
  2130. ERROR_DOMAIN_TRUST_INCONSISTENT - The server that responded is not a proper
  2131. domain controller of the specified domain.
  2132. --*/
  2133. {
  2134. NET_API_STATUS NetStatus;
  2135. //
  2136. // Do the RPC call with an exception handler since RPC will raise an
  2137. // exception if anything fails. It is up to us to figure out what
  2138. // to do once the exception is raised.
  2139. //
  2140. RpcTryExcept {
  2141. *Buffer = NULL; // Force RPC to allocate
  2142. //
  2143. // Call RPC version of the API.
  2144. //
  2145. NetStatus = NetrGetAnyDCName(
  2146. (LPWSTR) ServerName,
  2147. (LPWSTR) DomainName,
  2148. (LPWSTR *) Buffer );
  2149. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2150. NetStatus = RpcExceptionCode();
  2151. } RpcEndExcept;
  2152. IF_DEBUG( LOGON ) {
  2153. NetpKdPrint(("NetGetAnyDCName rc = %lu 0x%lx\n",
  2154. NetStatus, NetStatus));
  2155. }
  2156. return NetStatus;
  2157. }
  2158. DWORD
  2159. WINAPI
  2160. DsValidateSubnetNameA(
  2161. IN LPCSTR SubnetName
  2162. )
  2163. /*++
  2164. Routine Description:
  2165. Routine to validate a subnet name of the form xxx.xxx.xxx.xxx/yy
  2166. Arguments:
  2167. SubnetName - Name of the subnet to validate.
  2168. Return Value:
  2169. NO_ERROR: Subnet name is valid
  2170. ERROR_INVALID_NAME: Subnet name is not valid
  2171. --*/
  2172. {
  2173. DWORD WinStatus;
  2174. LPWSTR UnicodeSubnetName = NULL;
  2175. //
  2176. // Convert to unicode.
  2177. //
  2178. if ( SubnetName == NULL ) {
  2179. return ERROR_INVALID_NAME;
  2180. }
  2181. UnicodeSubnetName = NetpAllocWStrFromAStr( SubnetName );
  2182. if ( UnicodeSubnetName == NULL ) {
  2183. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  2184. goto Cleanup;
  2185. }
  2186. //
  2187. // Validate the name
  2188. //
  2189. WinStatus = DsValidateSubnetNameW( UnicodeSubnetName );
  2190. //
  2191. // Clean up locally used resources.
  2192. //
  2193. Cleanup:
  2194. if ( UnicodeSubnetName != NULL ) {
  2195. NetApiBufferFree( UnicodeSubnetName );
  2196. }
  2197. return WinStatus;
  2198. }
  2199. DWORD
  2200. WINAPI
  2201. DsValidateSubnetNameW(
  2202. IN LPCWSTR SubnetName
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. Routine to validate a subnet name of the form xxx.xxx.xxx.xxx/yy
  2207. Arguments:
  2208. SubnetName - Name of the subnet to validate.
  2209. Return Value:
  2210. NO_ERROR: Subnet name is valid
  2211. ERROR_INVALID_NAME: Subnet name is not valid
  2212. --*/
  2213. {
  2214. DWORD WinStatus;
  2215. ULONG SubnetAddress;
  2216. ULONG SubnetMask;
  2217. BYTE SubnetBitCount;
  2218. //
  2219. // Caller the worker routine to do the real work
  2220. //
  2221. WinStatus = NlParseSubnetString( SubnetName,
  2222. &SubnetAddress,
  2223. &SubnetMask,
  2224. &SubnetBitCount );
  2225. //
  2226. // If Winsock has not yet been initialized,
  2227. // initialize it.
  2228. //
  2229. if ( WinStatus == WSANOTINITIALISED ) {
  2230. //
  2231. // Initialize WSA.
  2232. //
  2233. WinStatus = DsWsaInitialize();
  2234. if ( WinStatus != NO_ERROR ) {
  2235. goto Cleanup;
  2236. }
  2237. //
  2238. // Repeat the call.
  2239. //
  2240. WinStatus = NlParseSubnetString( SubnetName,
  2241. &SubnetAddress,
  2242. &SubnetMask,
  2243. &SubnetBitCount );
  2244. }
  2245. //
  2246. // Free locally used resouces.
  2247. //
  2248. Cleanup:
  2249. return WinStatus;
  2250. }
  2251. DWORD
  2252. WINAPI
  2253. DsGetSiteNameA(
  2254. IN LPCSTR ComputerName OPTIONAL,
  2255. OUT LPSTR *SiteName
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. Same as DsGetSiteNameW except it takes and returns ASCII.
  2260. Arguments:
  2261. Same as DsGetSiteNameW except it takes and returns ASCII.
  2262. Return Value:
  2263. Same as DsGetSiteNameW except it takes and returns ASCII.
  2264. --*/
  2265. {
  2266. DWORD WinStatus;
  2267. LPWSTR UnicodeComputerName = NULL;
  2268. LPWSTR UnicodeSiteName = NULL;
  2269. //
  2270. // Convert input parameters to Unicode.
  2271. //
  2272. *SiteName = NULL;
  2273. if ( ComputerName != NULL ) {
  2274. UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
  2275. if ( UnicodeComputerName == NULL ) {
  2276. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  2277. goto Cleanup;
  2278. }
  2279. }
  2280. //
  2281. // Call the Unicode version of the routine.
  2282. //
  2283. WinStatus = DsGetSiteNameW(
  2284. UnicodeComputerName,
  2285. &UnicodeSiteName );
  2286. if ( WinStatus != NO_ERROR ) {
  2287. goto Cleanup;
  2288. }
  2289. //
  2290. // Convert the output structure to ANSI character set.
  2291. //
  2292. *SiteName = NetpAllocAStrFromWStr( UnicodeSiteName );
  2293. if ( *SiteName == NULL ) {
  2294. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  2295. goto Cleanup;
  2296. }
  2297. WinStatus = NO_ERROR;
  2298. //
  2299. // Clean up locally used resources.
  2300. //
  2301. Cleanup:
  2302. if ( UnicodeComputerName != NULL ) {
  2303. NetApiBufferFree( UnicodeComputerName );
  2304. }
  2305. if ( UnicodeSiteName != NULL ) {
  2306. NetApiBufferFree( UnicodeSiteName );
  2307. }
  2308. return WinStatus;
  2309. }
  2310. DWORD
  2311. WINAPI
  2312. DsGetSiteNameW(
  2313. IN LPCWSTR ComputerName OPTIONAL,
  2314. OUT LPWSTR *SiteName
  2315. )
  2316. /*++
  2317. Routine Description:
  2318. The DsGetSiteName API returns the name site a computer is in.
  2319. For a DC, the SiteName is the site the DC is configured to be in.
  2320. For a member workstation or member server, this is the name of the site
  2321. the workstation is in as configured in the domain the machine is a member of.
  2322. A standalone workstation or standalone server will always return
  2323. ERROR_NO_SITENAME.
  2324. Arguments:
  2325. ComputerName - Specifies the name of the server to remote this API to.
  2326. Typically, this parameter should be specified as NULL.
  2327. SiteName - Returns the site name of the site this machine is in.
  2328. The returned buffer must be deallocated using NetApiBufferFree.
  2329. Return Value:
  2330. NO_ERROR - Operation completed successfully;
  2331. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2332. operation.
  2333. ERROR_NO_SITENAME - The machine is not in a site.
  2334. --*/
  2335. {
  2336. NET_API_STATUS NetStatus;
  2337. //
  2338. // Do the RPC call with an exception handler since RPC will raise an
  2339. // exception if anything fails. It is up to us to figure out what
  2340. // to do once the exception is raised.
  2341. //
  2342. RpcTryExcept {
  2343. *SiteName = NULL; // Force RPC to allocate
  2344. //
  2345. // Call RPC version of the API.
  2346. //
  2347. NetStatus = DsrGetSiteName(
  2348. (LPWSTR) ComputerName,
  2349. SiteName );
  2350. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2351. NetStatus = RpcExceptionCode();
  2352. } RpcEndExcept;
  2353. //
  2354. // If Netlogon isn't running on the local machine,
  2355. // or Netlogon is the NT 4.0 version of netlogon (the upgrade case),
  2356. // Simply indicate that there is no site.
  2357. //
  2358. if ( NetStatus == RPC_S_UNKNOWN_IF ||
  2359. NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
  2360. NetStatus = ERROR_NO_SITENAME;
  2361. }
  2362. IF_DEBUG( LOGON ) {
  2363. NetpKdPrint(("DsrGetSiteName rc = %lu 0x%lx\n",
  2364. NetStatus, NetStatus));
  2365. }
  2366. return NetStatus;
  2367. }
  2368. DWORD
  2369. WINAPI
  2370. DsAddressToSiteNamesA(
  2371. IN LPCSTR ComputerName OPTIONAL,
  2372. IN DWORD EntryCount,
  2373. IN PSOCKET_ADDRESS SocketAddresses,
  2374. OUT LPSTR **SiteNames
  2375. )
  2376. /*++
  2377. Routine Description:
  2378. The DsAddressToSiteNames API returns the site names that correspond to
  2379. the specified addresses.
  2380. Arguments:
  2381. ComputerName - Specifies the name of the domain controller to remote this API to.
  2382. EntryCount - Number of addresses to convert.
  2383. SocketAddresses - Specifies an EntryCount element array of addresses
  2384. to convert. Each address must be of type AF_INET.
  2385. SiteNames - Returns an array of pointers to site names. EntryCount entries
  2386. are returned. An entry will be returned as NULL if the corresponding
  2387. address does not map to any site or if the address is malformed.
  2388. The returned buffer must be deallocated using NetApiBufferFree.
  2389. Return Value:
  2390. NO_ERROR - Operation completed successfully;
  2391. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2392. operation.
  2393. --*/
  2394. {
  2395. NET_API_STATUS NetStatus;
  2396. PNL_SITE_NAME_ARRAY SiteNameArray;
  2397. LPWSTR UnicodeComputerName = NULL;
  2398. //
  2399. // Initialization
  2400. //
  2401. *SiteNames = NULL;
  2402. if ( EntryCount == 0 ) {
  2403. return ERROR_INVALID_PARAMETER;
  2404. }
  2405. //
  2406. // Convert input parameters to Unicode.
  2407. //
  2408. if ( ComputerName != NULL ) {
  2409. UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
  2410. if ( UnicodeComputerName == NULL ) {
  2411. return ERROR_NOT_ENOUGH_MEMORY;
  2412. }
  2413. }
  2414. //
  2415. // Do the RPC call with an exception handler since RPC will raise an
  2416. // exception if anything fails. It is up to us to figure out what
  2417. // to do once the exception is raised.
  2418. //
  2419. RpcTryExcept {
  2420. SiteNameArray = NULL; // Force RPC to allocate
  2421. //
  2422. // Call RPC version of the API.
  2423. //
  2424. NetStatus = DsrAddressToSiteNamesW(
  2425. UnicodeComputerName,
  2426. EntryCount,
  2427. (PNL_SOCKET_ADDRESS)SocketAddresses,
  2428. &SiteNameArray );
  2429. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2430. NetStatus = RpcExceptionCode();
  2431. } RpcEndExcept;
  2432. //
  2433. // Convert the site names to what the caller expects.
  2434. //
  2435. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  2436. //
  2437. // Sanity check
  2438. //
  2439. if ( EntryCount != SiteNameArray->EntryCount ) {
  2440. NetStatus = ERROR_INVALID_PARAMETER;
  2441. } else {
  2442. ULONG Size;
  2443. ULONG i;
  2444. //
  2445. // Allocate a buffer to return to the caller
  2446. //
  2447. Size = sizeof(LPSTR) * EntryCount;
  2448. for ( i=0; i<EntryCount; i++) {
  2449. Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  2450. }
  2451. *SiteNames = MIDL_user_allocate( Size );
  2452. if ( *SiteNames == NULL ) {
  2453. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2454. } else {
  2455. LPBYTE Where;
  2456. //
  2457. // Loop copying names to the caller.
  2458. //
  2459. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * EntryCount;
  2460. for ( i=0; i<EntryCount; i++) {
  2461. //
  2462. // If no name was returned,
  2463. // pass a NULL back to the caller.
  2464. //
  2465. if ( SiteNameArray->SiteNames[i].Length == 0 ) {
  2466. (*SiteNames)[i] = NULL;
  2467. //
  2468. // Copy the site name into the return buffer.
  2469. //
  2470. } else {
  2471. ANSI_STRING TempString;
  2472. NTSTATUS Status;
  2473. (*SiteNames)[i] = (LPSTR) Where;
  2474. TempString.Buffer = Where;
  2475. TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  2476. Status = RtlUnicodeStringToAnsiString(
  2477. &TempString,
  2478. &SiteNameArray->SiteNames[i],
  2479. FALSE );
  2480. if ( !NT_SUCCESS(Status) ) {
  2481. MIDL_user_free( *SiteNames );
  2482. *SiteNames = NULL;
  2483. NetStatus = NetpNtStatusToApiStatus( Status );
  2484. break;
  2485. }
  2486. Where += TempString.MaximumLength;
  2487. }
  2488. }
  2489. }
  2490. }
  2491. MIDL_user_free( SiteNameArray );
  2492. }
  2493. IF_DEBUG( LOGON ) {
  2494. NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
  2495. NetStatus, NetStatus));
  2496. }
  2497. if ( UnicodeComputerName != NULL ) {
  2498. NetApiBufferFree( UnicodeComputerName );
  2499. }
  2500. return NetStatus;
  2501. }
  2502. DWORD
  2503. WINAPI
  2504. DsAddressToSiteNamesW(
  2505. IN LPCWSTR ComputerName OPTIONAL,
  2506. IN DWORD EntryCount,
  2507. IN PSOCKET_ADDRESS SocketAddresses,
  2508. OUT LPWSTR **SiteNames
  2509. )
  2510. /*++
  2511. Routine Description:
  2512. The DsAddressToSiteNames API returns the site names that correspond to
  2513. the specified addresses.
  2514. Arguments:
  2515. ComputerName - Specifies the name of the domain controller to remote this API to.
  2516. EntryCount - Number of addresses to convert.
  2517. SocketAddresses - Specifies an EntryCount element array of addresses
  2518. to convert. Each address must be of type AF_INET.
  2519. SiteNames - Returns an array of pointers to site names. EntryCount entries
  2520. are returned. An entry will be returned as NULL if the corresponding
  2521. address does not map to any site or if the address is malformed.
  2522. The returned buffer must be deallocated using NetApiBufferFree.
  2523. Return Value:
  2524. NO_ERROR - Operation completed successfully;
  2525. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2526. operation.
  2527. --*/
  2528. {
  2529. NET_API_STATUS NetStatus;
  2530. PNL_SITE_NAME_ARRAY SiteNameArray;
  2531. //
  2532. // Initialization
  2533. //
  2534. *SiteNames = NULL;
  2535. if ( EntryCount == 0 ) {
  2536. return ERROR_INVALID_PARAMETER;
  2537. }
  2538. //
  2539. // Do the RPC call with an exception handler since RPC will raise an
  2540. // exception if anything fails. It is up to us to figure out what
  2541. // to do once the exception is raised.
  2542. //
  2543. RpcTryExcept {
  2544. SiteNameArray = NULL; // Force RPC to allocate
  2545. //
  2546. // Call RPC version of the API.
  2547. //
  2548. NetStatus = DsrAddressToSiteNamesW(
  2549. (LPWSTR) ComputerName,
  2550. EntryCount,
  2551. (PNL_SOCKET_ADDRESS)SocketAddresses,
  2552. &SiteNameArray );
  2553. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2554. NetStatus = RpcExceptionCode();
  2555. } RpcEndExcept;
  2556. //
  2557. // Convert the site names to what the caller expects.
  2558. //
  2559. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  2560. //
  2561. // Sanity check
  2562. //
  2563. if ( EntryCount != SiteNameArray->EntryCount ) {
  2564. NetStatus = ERROR_INVALID_PARAMETER;
  2565. } else {
  2566. ULONG Size;
  2567. ULONG i;
  2568. //
  2569. // Allocate a buffer to return to the caller
  2570. //
  2571. Size = sizeof(LPWSTR) * EntryCount;
  2572. for ( i=0; i<EntryCount; i++) {
  2573. Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
  2574. }
  2575. *SiteNames = MIDL_user_allocate( Size );
  2576. if ( *SiteNames == NULL ) {
  2577. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2578. } else {
  2579. LPBYTE Where;
  2580. //
  2581. // Loop copying names to the caller.
  2582. //
  2583. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * EntryCount;
  2584. for ( i=0; i<EntryCount; i++) {
  2585. //
  2586. // If no name was returned,
  2587. // pass a NULL back to the caller.
  2588. //
  2589. if ( SiteNameArray->SiteNames[i].Length == 0 ) {
  2590. (*SiteNames)[i] = NULL;
  2591. //
  2592. // Copy the site name into the return buffer.
  2593. //
  2594. } else {
  2595. (*SiteNames)[i] = (LPWSTR) Where;
  2596. RtlCopyMemory( Where,
  2597. SiteNameArray->SiteNames[i].Buffer,
  2598. SiteNameArray->SiteNames[i].Length );
  2599. Where += SiteNameArray->SiteNames[i].Length;
  2600. *(LPWSTR)Where = L'\0';
  2601. Where += sizeof(WCHAR);
  2602. }
  2603. }
  2604. }
  2605. }
  2606. MIDL_user_free( SiteNameArray );
  2607. }
  2608. IF_DEBUG( LOGON ) {
  2609. NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
  2610. NetStatus, NetStatus));
  2611. }
  2612. return NetStatus;
  2613. }
  2614. DWORD
  2615. WINAPI
  2616. DsAddressToSiteNamesExA(
  2617. IN LPCSTR ComputerName OPTIONAL,
  2618. IN DWORD EntryCount,
  2619. IN PSOCKET_ADDRESS SocketAddresses,
  2620. OUT LPSTR **SiteNames,
  2621. OUT LPSTR **SubnetNames
  2622. )
  2623. /*++
  2624. Routine Description:
  2625. The DsAddressToSiteNamesEx API returns the site names and subnet names
  2626. that correspond to the specified addresses.
  2627. Arguments:
  2628. ComputerName - Specifies the name of the domain controller to remote this API to.
  2629. EntryCount - Number of addresses to convert.
  2630. SocketAddresses - Specifies an EntryCount element array of addresses
  2631. to convert. Each address must be of type AF_INET.
  2632. SiteNames - Returns an array of pointers to site names. EntryCount entries
  2633. are returned. An entry will be returned as NULL if the corresponding
  2634. address does not map to any site or if the address is malformed.
  2635. The returned buffer must be deallocated using NetApiBufferFree.
  2636. SubnetNames - Returns an array of pointers to subnet names which were used
  2637. to perform the address to site name mappings. EntryCount entries
  2638. are returned. An entry will be returned as NULL if the corresponding address
  2639. to site mapping was not determined or if no subnet was used to perform the
  2640. corresponding address to site mapping which is the case when there is exactly
  2641. one site in the enterprise with no subnet objects mapped to it.
  2642. The returned buffer must be deallocated using NetApiBufferFree.
  2643. Return Value:
  2644. NO_ERROR - Operation completed successfully;
  2645. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2646. operation.
  2647. --*/
  2648. {
  2649. NET_API_STATUS NetStatus;
  2650. PNL_SITE_NAME_EX_ARRAY SiteNameArray;
  2651. LPWSTR UnicodeComputerName = NULL;
  2652. //
  2653. // Initialization
  2654. //
  2655. *SiteNames = NULL;
  2656. *SubnetNames = NULL;
  2657. if ( EntryCount == 0 ) {
  2658. return ERROR_INVALID_PARAMETER;
  2659. }
  2660. //
  2661. // Convert input parameters to Unicode.
  2662. //
  2663. if ( ComputerName != NULL ) {
  2664. UnicodeComputerName = NetpAllocWStrFromAStr( ComputerName );
  2665. if ( UnicodeComputerName == NULL ) {
  2666. return ERROR_NOT_ENOUGH_MEMORY;
  2667. }
  2668. }
  2669. //
  2670. // Do the RPC call with an exception handler since RPC will raise an
  2671. // exception if anything fails. It is up to us to figure out what
  2672. // to do once the exception is raised.
  2673. //
  2674. RpcTryExcept {
  2675. SiteNameArray = NULL; // Force RPC to allocate
  2676. //
  2677. // Call RPC version of the API.
  2678. //
  2679. NetStatus = DsrAddressToSiteNamesExW(
  2680. UnicodeComputerName,
  2681. EntryCount,
  2682. (PNL_SOCKET_ADDRESS)SocketAddresses,
  2683. &SiteNameArray );
  2684. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2685. NetStatus = RpcExceptionCode();
  2686. } RpcEndExcept;
  2687. //
  2688. // Convert the site names to what the caller expects.
  2689. //
  2690. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  2691. //
  2692. // Sanity check
  2693. //
  2694. if ( EntryCount != SiteNameArray->EntryCount ) {
  2695. NetStatus = ERROR_INVALID_PARAMETER;
  2696. } else {
  2697. ULONG Size;
  2698. ULONG i;
  2699. //
  2700. // Allocate a buffer to return to the caller
  2701. //
  2702. Size = sizeof(LPSTR) * EntryCount;
  2703. for ( i=0; i<EntryCount; i++) {
  2704. Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  2705. }
  2706. *SiteNames = MIDL_user_allocate( Size );
  2707. if ( *SiteNames == NULL ) {
  2708. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2709. } else {
  2710. Size = sizeof(LPSTR) * EntryCount;
  2711. for ( i=0; i<EntryCount; i++) {
  2712. Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SubnetNames[i] );
  2713. }
  2714. *SubnetNames = MIDL_user_allocate( Size );
  2715. if ( *SubnetNames == NULL ) {
  2716. MIDL_user_free( *SiteNames );
  2717. *SiteNames = NULL;
  2718. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2719. } else {
  2720. LPBYTE Where;
  2721. LPBYTE Where2;
  2722. //
  2723. // Loop copying names to the caller.
  2724. //
  2725. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * EntryCount;
  2726. Where2 = ((LPBYTE)(*SubnetNames)) + sizeof(LPSTR) * EntryCount;
  2727. for ( i=0; i<EntryCount; i++) {
  2728. //
  2729. // If no name was returned,
  2730. // pass a NULL back to the caller.
  2731. //
  2732. if ( SiteNameArray->SiteNames[i].Length == 0 ) {
  2733. (*SiteNames)[i] = NULL;
  2734. //
  2735. // Copy the site name into the return buffer.
  2736. //
  2737. } else {
  2738. ANSI_STRING TempString;
  2739. NTSTATUS Status;
  2740. (*SiteNames)[i] = (LPSTR) Where;
  2741. TempString.Buffer = Where;
  2742. TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  2743. Status = RtlUnicodeStringToAnsiString(
  2744. &TempString,
  2745. &SiteNameArray->SiteNames[i],
  2746. FALSE );
  2747. if ( !NT_SUCCESS(Status) ) {
  2748. MIDL_user_free( *SiteNames );
  2749. *SiteNames = NULL;
  2750. MIDL_user_free( *SubnetNames );
  2751. *SubnetNames = NULL;
  2752. NetStatus = NetpNtStatusToApiStatus( Status );
  2753. break;
  2754. }
  2755. Where += TempString.MaximumLength;
  2756. }
  2757. //
  2758. // If no name was returned,
  2759. // pass a NULL back to the caller.
  2760. //
  2761. if ( SiteNameArray->SubnetNames[i].Length == 0 ) {
  2762. (*SubnetNames)[i] = NULL;
  2763. //
  2764. // Copy the Subnet name into the return buffer.
  2765. //
  2766. } else {
  2767. ANSI_STRING TempString;
  2768. NTSTATUS Status;
  2769. (*SubnetNames)[i] = (LPSTR) Where2;
  2770. TempString.Buffer = Where2;
  2771. TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SubnetNames[i] );
  2772. Status = RtlUnicodeStringToAnsiString(
  2773. &TempString,
  2774. &SiteNameArray->SubnetNames[i],
  2775. FALSE );
  2776. if ( !NT_SUCCESS(Status) ) {
  2777. MIDL_user_free( *SubnetNames );
  2778. *SubnetNames = NULL;
  2779. MIDL_user_free( *SubnetNames );
  2780. *SubnetNames = NULL;
  2781. NetStatus = NetpNtStatusToApiStatus( Status );
  2782. break;
  2783. }
  2784. Where2 += TempString.MaximumLength;
  2785. }
  2786. }
  2787. }
  2788. }
  2789. }
  2790. MIDL_user_free( SiteNameArray );
  2791. }
  2792. IF_DEBUG( LOGON ) {
  2793. NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
  2794. NetStatus, NetStatus));
  2795. }
  2796. return NetStatus;
  2797. }
  2798. DWORD
  2799. WINAPI
  2800. DsAddressToSiteNamesExW(
  2801. IN LPCWSTR ComputerName OPTIONAL,
  2802. IN DWORD EntryCount,
  2803. IN PSOCKET_ADDRESS SocketAddresses,
  2804. OUT LPWSTR **SiteNames,
  2805. OUT LPWSTR **SubnetNames
  2806. )
  2807. /*++
  2808. Routine Description:
  2809. The DsAddressToSiteNames API returns the site names that correspond to
  2810. the specified addresses.
  2811. Arguments:
  2812. ComputerName - Specifies the name of the domain controller to remote this API to.
  2813. EntryCount - Number of addresses to convert.
  2814. SocketAddresses - Specifies an EntryCount element array of addresses
  2815. to convert. Each address must be of type AF_INET.
  2816. SiteNames - Returns an array of pointers to site names. EntryCount entries
  2817. are returned. An entry will be returned as NULL if the corresponding
  2818. address does not map to any site or if the address is malformed.
  2819. The returned buffer must be deallocated using NetApiBufferFree.
  2820. SubnetNames - Returns an array of pointers to subnet names which were used
  2821. to perform the address to site name mappings. EntryCount entries
  2822. are returned. An entry will be returned as NULL if the corresponding address
  2823. to site mapping was not determined or if no subnet was used to perform the
  2824. corresponding address to site mapping which is the case when there is exactly
  2825. one site in the enterprise with no subnet objects mapped to it.
  2826. The returned buffer must be deallocated using NetApiBufferFree.
  2827. Return Value:
  2828. NO_ERROR - Operation completed successfully;
  2829. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2830. operation.
  2831. --*/
  2832. {
  2833. NET_API_STATUS NetStatus;
  2834. PNL_SITE_NAME_EX_ARRAY SiteNameArray;
  2835. //
  2836. // Initialization
  2837. //
  2838. *SiteNames = NULL;
  2839. *SubnetNames = NULL;
  2840. if ( EntryCount == 0 ) {
  2841. return ERROR_INVALID_PARAMETER;
  2842. }
  2843. //
  2844. // Do the RPC call with an exception handler since RPC will raise an
  2845. // exception if anything fails. It is up to us to figure out what
  2846. // to do once the exception is raised.
  2847. //
  2848. RpcTryExcept {
  2849. SiteNameArray = NULL; // Force RPC to allocate
  2850. //
  2851. // Call RPC version of the API.
  2852. //
  2853. NetStatus = DsrAddressToSiteNamesExW(
  2854. (LPWSTR) ComputerName,
  2855. EntryCount,
  2856. (PNL_SOCKET_ADDRESS)SocketAddresses,
  2857. &SiteNameArray );
  2858. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  2859. NetStatus = RpcExceptionCode();
  2860. } RpcEndExcept;
  2861. //
  2862. // Convert the site names to what the caller expects.
  2863. //
  2864. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  2865. //
  2866. // Sanity check
  2867. //
  2868. if ( EntryCount != SiteNameArray->EntryCount ) {
  2869. NetStatus = ERROR_INVALID_PARAMETER;
  2870. } else {
  2871. ULONG Size;
  2872. ULONG i;
  2873. //
  2874. // Allocate a buffer to return to the caller
  2875. //
  2876. Size = sizeof(LPWSTR) * EntryCount;
  2877. for ( i=0; i<EntryCount; i++) {
  2878. Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
  2879. }
  2880. *SiteNames = MIDL_user_allocate( Size );
  2881. if ( *SiteNames == NULL ) {
  2882. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2883. } else {
  2884. //
  2885. // Allocate a buffer to return to the caller
  2886. //
  2887. Size = sizeof(LPWSTR) * EntryCount;
  2888. for ( i=0; i<EntryCount; i++) {
  2889. Size += SiteNameArray->SubnetNames[i].Length + sizeof(WCHAR);
  2890. }
  2891. *SubnetNames = MIDL_user_allocate( Size );
  2892. if ( *SubnetNames == NULL ) {
  2893. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2894. } else {
  2895. LPBYTE Where;
  2896. LPBYTE Where2;
  2897. //
  2898. // Loop copying names to the caller.
  2899. //
  2900. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * EntryCount;
  2901. Where2 = ((LPBYTE)(*SubnetNames)) + sizeof(LPWSTR) * EntryCount;
  2902. for ( i=0; i<EntryCount; i++) {
  2903. //
  2904. // If no name was returned,
  2905. // pass a NULL back to the caller.
  2906. //
  2907. if ( SiteNameArray->SiteNames[i].Length == 0 ) {
  2908. (*SiteNames)[i] = NULL;
  2909. //
  2910. // Copy the site name into the return buffer.
  2911. //
  2912. } else {
  2913. (*SiteNames)[i] = (LPWSTR) Where;
  2914. RtlCopyMemory( Where,
  2915. SiteNameArray->SiteNames[i].Buffer,
  2916. SiteNameArray->SiteNames[i].Length );
  2917. Where += SiteNameArray->SiteNames[i].Length;
  2918. *(LPWSTR)Where = L'\0';
  2919. Where += sizeof(WCHAR);
  2920. }
  2921. //
  2922. // If no name was returned,
  2923. // pass a NULL back to the caller.
  2924. //
  2925. if ( SiteNameArray->SubnetNames[i].Length == 0 ) {
  2926. (*SubnetNames)[i] = NULL;
  2927. //
  2928. // Copy the Subnet name into the return buffer.
  2929. //
  2930. } else {
  2931. (*SubnetNames)[i] = (LPWSTR) Where2;
  2932. RtlCopyMemory( Where2,
  2933. SiteNameArray->SubnetNames[i].Buffer,
  2934. SiteNameArray->SubnetNames[i].Length );
  2935. Where2 += SiteNameArray->SubnetNames[i].Length;
  2936. *(LPWSTR)Where2 = L'\0';
  2937. Where2 += sizeof(WCHAR);
  2938. }
  2939. }
  2940. }
  2941. }
  2942. }
  2943. MIDL_user_free( SiteNameArray );
  2944. }
  2945. IF_DEBUG( LOGON ) {
  2946. NetpKdPrint(("DsAddressToSiteNames rc = %lu 0x%lx\n",
  2947. NetStatus, NetStatus));
  2948. }
  2949. return NetStatus;
  2950. }
  2951. DWORD
  2952. WINAPI
  2953. DsGetDcSiteCoverageA(
  2954. IN LPCSTR ComputerName OPTIONAL,
  2955. OUT PULONG EntryCount,
  2956. OUT LPSTR **SiteNames
  2957. )
  2958. /*++
  2959. Routine Description:
  2960. This API returns the site names of all sites covered by a DC.
  2961. Arguments:
  2962. ComputerName - Specifies the name of the domain controller to remote this API to.
  2963. EntryCount - Returns the number of sites covered by DC.
  2964. SiteNames - Returns an array of pointers to site names.
  2965. The returned buffer must be deallocated using NetApiBufferFree.
  2966. Return Value:
  2967. NO_ERROR - Operation completed successfully;
  2968. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  2969. operation.
  2970. --*/
  2971. {
  2972. NET_API_STATUS NetStatus;
  2973. PNL_SITE_NAME_ARRAY SiteNameArray;
  2974. LPWSTR UnicodeComputerName = NULL;
  2975. //
  2976. // Initialization
  2977. //
  2978. *SiteNames = NULL;
  2979. //
  2980. // Convert input parameters to Unicode.
  2981. //
  2982. if ( ComputerName != NULL ) {
  2983. UnicodeComputerName = NetpAllocWStrFromAStr( (LPSTR)ComputerName );
  2984. if ( UnicodeComputerName == NULL ) {
  2985. return ERROR_NOT_ENOUGH_MEMORY;
  2986. }
  2987. }
  2988. //
  2989. // Do the RPC call with an exception handler since RPC will raise an
  2990. // exception if anything fails. It is up to us to figure out what
  2991. // to do once the exception is raised.
  2992. //
  2993. RpcTryExcept {
  2994. SiteNameArray = NULL; // Force RPC to allocate
  2995. //
  2996. // Call RPC version of the API.
  2997. //
  2998. NetStatus = DsrGetDcSiteCoverageW(
  2999. UnicodeComputerName,
  3000. &SiteNameArray );
  3001. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  3002. NetStatus = RpcExceptionCode();
  3003. } RpcEndExcept;
  3004. //
  3005. // Convert the site names to what the caller expects.
  3006. //
  3007. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  3008. ULONG Size;
  3009. ULONG i;
  3010. //
  3011. // Set the size of the array
  3012. //
  3013. *EntryCount = SiteNameArray->EntryCount;
  3014. //
  3015. // Allocate a buffer to return to the caller
  3016. //
  3017. Size = sizeof(LPSTR) * SiteNameArray->EntryCount;
  3018. for ( i=0; i<*EntryCount; i++ ) {
  3019. Size += RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  3020. }
  3021. *SiteNames = MIDL_user_allocate( Size );
  3022. if ( *SiteNames == NULL ) {
  3023. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  3024. } else {
  3025. LPBYTE Where;
  3026. //
  3027. // Loop copying names to the caller.
  3028. //
  3029. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPSTR) * SiteNameArray->EntryCount;
  3030. for ( i=0; i<*EntryCount; i++) {
  3031. //
  3032. // Copy the site name into the return buffer.
  3033. //
  3034. ANSI_STRING TempString;
  3035. NTSTATUS Status;
  3036. (*SiteNames)[i] = (LPSTR) Where;
  3037. TempString.Buffer = Where;
  3038. TempString.MaximumLength = (USHORT) RtlUnicodeStringToAnsiSize( &SiteNameArray->SiteNames[i] );
  3039. Status = RtlUnicodeStringToAnsiString(
  3040. &TempString,
  3041. &SiteNameArray->SiteNames[i],
  3042. FALSE );
  3043. if ( !NT_SUCCESS(Status) ) {
  3044. MIDL_user_free( *SiteNames );
  3045. *SiteNames = NULL;
  3046. NetStatus = NetpNtStatusToApiStatus( Status );
  3047. break;
  3048. }
  3049. Where += TempString.MaximumLength;
  3050. }
  3051. }
  3052. MIDL_user_free( SiteNameArray );
  3053. }
  3054. IF_DEBUG( LOGON ) {
  3055. NetpKdPrint(("DsGetDcSiteCoverage rc = %lu 0x%lx\n",
  3056. NetStatus, NetStatus));
  3057. }
  3058. if ( UnicodeComputerName != NULL ) {
  3059. NetApiBufferFree( UnicodeComputerName );
  3060. }
  3061. return NetStatus;
  3062. }
  3063. DWORD
  3064. WINAPI
  3065. DsGetDcSiteCoverageW(
  3066. IN LPCWSTR ComputerName OPTIONAL,
  3067. OUT PULONG EntryCount,
  3068. OUT LPWSTR **SiteNames
  3069. )
  3070. /*++
  3071. Routine Description:
  3072. This API returns the site names of all sites covered by a DC.
  3073. Arguments:
  3074. ComputerName - Specifies the name of the domain controller to remote this API to.
  3075. EntryCount - Returns the number of sites covered by DC.
  3076. SiteNames - Returns an array of pointers to site names.
  3077. The returned buffer must be deallocated using NetApiBufferFree.
  3078. Return Value:
  3079. NO_ERROR - Operation completed successfully;
  3080. ERROR_NOT_ENOUGH_MEMORY - There was not enough memory to complete the
  3081. operation.
  3082. --*/
  3083. {
  3084. NET_API_STATUS NetStatus;
  3085. PNL_SITE_NAME_ARRAY SiteNameArray;
  3086. //
  3087. // Initialization
  3088. //
  3089. *SiteNames = NULL;
  3090. //
  3091. // Do the RPC call with an exception handler since RPC will raise an
  3092. // exception if anything fails. It is up to us to figure out what
  3093. // to do once the exception is raised.
  3094. //
  3095. RpcTryExcept {
  3096. SiteNameArray = NULL; // Force RPC to allocate
  3097. //
  3098. // Call RPC version of the API.
  3099. //
  3100. NetStatus = DsrGetDcSiteCoverageW(
  3101. (LPWSTR) ComputerName,
  3102. &SiteNameArray );
  3103. } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
  3104. NetStatus = RpcExceptionCode();
  3105. } RpcEndExcept;
  3106. //
  3107. // Convert the site names to what the caller expects.
  3108. //
  3109. if ( NetStatus == NO_ERROR && SiteNameArray != NULL ) {
  3110. ULONG Size;
  3111. ULONG i;
  3112. //
  3113. // Set the size of the array
  3114. //
  3115. *EntryCount = SiteNameArray->EntryCount;
  3116. //
  3117. // Allocate a buffer to return to the caller
  3118. //
  3119. Size = sizeof(LPWSTR) * SiteNameArray->EntryCount;
  3120. for ( i=0; i<*EntryCount; i++) {
  3121. Size += SiteNameArray->SiteNames[i].Length + sizeof(WCHAR);
  3122. }
  3123. *SiteNames = MIDL_user_allocate( Size );
  3124. if ( *SiteNames == NULL ) {
  3125. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  3126. } else {
  3127. LPBYTE Where;
  3128. //
  3129. // Loop copying names to the caller.
  3130. //
  3131. Where = ((LPBYTE)(*SiteNames)) + sizeof(LPWSTR) * SiteNameArray->EntryCount;
  3132. for ( i=0; i<*EntryCount; i++) {
  3133. //
  3134. // Copy the site name into the return buffer.
  3135. //
  3136. (*SiteNames)[i] = (LPWSTR) Where;
  3137. RtlCopyMemory( Where,
  3138. SiteNameArray->SiteNames[i].Buffer,
  3139. SiteNameArray->SiteNames[i].Length );
  3140. Where += SiteNameArray->SiteNames[i].Length;
  3141. *(LPWSTR)Where = L'\0';
  3142. Where += sizeof(WCHAR);
  3143. }
  3144. }
  3145. MIDL_user_free( SiteNameArray );
  3146. }
  3147. IF_DEBUG( LOGON ) {
  3148. NetpKdPrint(("DsGetDcSiteCoverage rc = %lu 0x%lx\n",
  3149. NetStatus, NetStatus));
  3150. }
  3151. return NetStatus;
  3152. }
  3153. #endif // WIN32_CHICAGO
  3154. #endif // NETTEST_UTILITY