Leaked source code of windows server 2003
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.

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