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

945 lines
23 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1997, Microsoft Corporation
  4. //
  5. // File: dfslpc.c
  6. //
  7. // Contents: Code implement lpc server for dfs.sys
  8. //
  9. // Classes:
  10. //
  11. // Functions:
  12. //
  13. // History: 18 Dec 97 Jharper created (from XACT stuff)
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <dfsfsctl.h>
  20. #include <windows.h>
  21. #include <stdlib.h>
  22. #include <lm.h>
  23. #include <winsock2.h>
  24. #include <dsgetdc.h>
  25. #include <dfssrv.h>
  26. #include <dsrole.h>
  27. #include "dfsipc.h"
  28. extern WCHAR DomainName[MAX_PATH];
  29. extern DSROLE_MACHINE_ROLE DfsMachineRole;
  30. //
  31. // Event logging and debugging globals
  32. //
  33. extern ULONG DfsSvcVerbose;
  34. extern ULONG DfsEventLog;
  35. //
  36. // Number of worker threads.
  37. //
  38. LONG DfsThreads = 0;
  39. //
  40. // Event signalled when the last worker thread terminates.
  41. //
  42. HANDLE DfsAllThreadsTerminatedEvent = NULL;
  43. //
  44. // Boolean indicating whether server is active or terminating.
  45. //
  46. BOOL DfsTerminating = FALSE;
  47. //
  48. // Handle for the LPC port used for communication between the dfs driver
  49. // and server
  50. //
  51. HANDLE DfsConnectionPortHandle = NULL;
  52. HANDLE DfsCommunicationPortHandle = NULL;
  53. //
  54. // Handle for communicating with the dfs driver
  55. //
  56. HANDLE serverHandle = NULL;
  57. //
  58. // This is the number of threads blocked waiting for an LPC request.
  59. // When it drops to zero, all threads are active and another thread is
  60. // created.
  61. //
  62. LONG DfsWaitingApiThreads = 0;
  63. VOID
  64. DfsProcessApisWrapper (
  65. DWORD ThreadNum
  66. );
  67. VOID
  68. DfsProcessApis (
  69. DWORD ThreadNum
  70. );
  71. VOID
  72. DfsLoadIpCache(
  73. PDFS_IPADDRESS pIpAddress,
  74. LPWSTR SiteName
  75. );
  76. NTSTATUS
  77. AddrToSite(
  78. PDFS_IPADDRESS IpAddress,
  79. LPWSTR **pppSiteName
  80. );
  81. //
  82. // Flags used in DsGetDcName()
  83. //
  84. DWORD dwFlags[] = {
  85. DS_DIRECTORY_SERVICE_REQUIRED |
  86. DS_IP_REQUIRED,
  87. DS_DIRECTORY_SERVICE_REQUIRED |
  88. DS_IP_REQUIRED |
  89. DS_FORCE_REDISCOVERY
  90. };
  91. DWORD
  92. DfsStartDfssrv (
  93. VOID)
  94. {
  95. NTSTATUS status;
  96. DWORD error;
  97. DWORD i;
  98. HANDLE threadHandle;
  99. DWORD threadId;
  100. HANDLE eventHandle;
  101. UNICODE_STRING unicodeName;
  102. IO_STATUS_BLOCK ioStatusBlock;
  103. OBJECT_ATTRIBUTES objectAttributes;
  104. PORT_MESSAGE connectionRequest;
  105. BOOL waitForEvent;
  106. PCHAR bp;
  107. ULONG size;
  108. PUNICODE_STRING pustr;
  109. UNICODE_STRING DfsDriverName;
  110. #if DBG
  111. if (DfsSvcVerbose)
  112. DbgPrint("DfsStartDfssrv()\n", 0);
  113. #endif
  114. // Sleep(60*1000);
  115. // lpc_debug_trace("DfsStartDfssrv done sleeping...\n", 0);
  116. //
  117. // Set up variables so that we'll know how to shut down in case of
  118. // an error.
  119. //
  120. serverHandle = NULL;
  121. eventHandle = NULL;
  122. DfsAllThreadsTerminatedEvent = NULL;
  123. waitForEvent = FALSE;
  124. //
  125. // Create a event that will be set by the last thread to exit.
  126. //
  127. status = NtCreateEvent(
  128. &DfsAllThreadsTerminatedEvent,
  129. EVENT_ALL_ACCESS,
  130. NULL,
  131. NotificationEvent,
  132. FALSE
  133. );
  134. if ( !NT_SUCCESS(status) ) {
  135. DfsAllThreadsTerminatedEvent = NULL;
  136. goto exit;
  137. }
  138. #if DBG
  139. if (DfsSvcVerbose)
  140. DbgPrint("created event\n", 0);
  141. #endif
  142. //
  143. // Open the server device. Note that we need this handle because
  144. // the handle used by the main server service is synchronous. We
  145. // need to to do the DFS_CONNECT FSCTL asynchronously.
  146. //
  147. RtlInitUnicodeString( &unicodeName, DFS_SERVER_NAME );
  148. InitializeObjectAttributes(
  149. &objectAttributes,
  150. &unicodeName,
  151. OBJ_CASE_INSENSITIVE,
  152. NULL,
  153. NULL
  154. );
  155. status = NtOpenFile(
  156. &serverHandle,
  157. FILE_READ_DATA | FILE_WRITE_DATA, // DesiredAccess
  158. &objectAttributes,
  159. &ioStatusBlock,
  160. 0L, // ShareAccess
  161. 0L // OpenOptions
  162. );
  163. if ( NT_SUCCESS(status) ) {
  164. status = ioStatusBlock.Status;
  165. }
  166. if ( !NT_SUCCESS(status) ) {
  167. goto exit;
  168. }
  169. #if DBG
  170. if (DfsSvcVerbose)
  171. DbgPrint("opened device\n", 0);
  172. #endif
  173. //
  174. // Create the LPC port.
  175. //
  176. // Right now this only tries a single port name. If, for some
  177. // bizarre reason, somebody already has a port by this name,
  178. // then this will fail. It might make sense to try different
  179. // names if this fails.
  180. //
  181. RtlInitUnicodeString( &unicodeName, DFS_PORT_NAME_W );
  182. InitializeObjectAttributes(
  183. &objectAttributes,
  184. &unicodeName,
  185. 0,
  186. NULL,
  187. NULL
  188. );
  189. status = NtCreatePort(
  190. &DfsConnectionPortHandle,
  191. &objectAttributes,
  192. 0,
  193. DFS_PORT_MAX_MESSAGE_LENGTH,
  194. DFS_PORT_MAX_MESSAGE_LENGTH * 32
  195. );
  196. #if DBG
  197. if (DfsSvcVerbose)
  198. DbgPrint("NtCreatePort status=0x%x\n", status);
  199. #endif
  200. if ( ! NT_SUCCESS(status) ) {
  201. DfsConnectionPortHandle = NULL;
  202. goto exit;
  203. }
  204. //
  205. // Set up an event so that we'll know when IO completes, then send
  206. // the FSCTL to the server indicating that it should now connect to
  207. // us. We'll set up the port while the IO is outstanding, then wait
  208. // on the event when the port setup is complete.
  209. //
  210. status = NtCreateEvent(
  211. &eventHandle,
  212. EVENT_ALL_ACCESS,
  213. NULL, // ObjectAttributes
  214. NotificationEvent,
  215. FALSE
  216. );
  217. #if DBG
  218. if (DfsSvcVerbose)
  219. DbgPrint("NtCreateEvent status=0x%x\n", status);
  220. #endif
  221. if ( !NT_SUCCESS(status) ) {
  222. goto exit;
  223. }
  224. size = sizeof(UNICODE_STRING) + unicodeName.Length + sizeof(WCHAR);
  225. pustr = (UNICODE_STRING *)(bp = malloc(size));
  226. if (pustr == NULL) {
  227. status = STATUS_INSUFFICIENT_RESOURCES;
  228. goto exit;
  229. }
  230. RtlZeroMemory(bp, size);
  231. pustr->Length = unicodeName.Length;
  232. pustr->MaximumLength = unicodeName.Length + sizeof(WCHAR);
  233. pustr->Buffer = (WCHAR *)(bp + sizeof(UNICODE_STRING));
  234. RtlCopyMemory(pustr->Buffer, unicodeName.Buffer, unicodeName.Length);
  235. pustr->Buffer = (WCHAR *)sizeof(UNICODE_STRING);
  236. #if DBG
  237. if (DfsSvcVerbose)
  238. DbgPrint("Calling NtFsControlFile(FSCTL_SRV_DFSSRV_CONNECT)\n", status);
  239. #endif
  240. status = NtFsControlFile(
  241. serverHandle,
  242. eventHandle,
  243. NULL, // ApcRoutine
  244. NULL, // ApcContext
  245. &ioStatusBlock,
  246. FSCTL_SRV_DFSSRV_CONNECT,
  247. bp,
  248. size,
  249. NULL, // OutputBuffer
  250. 0L // OutputBufferLength
  251. );
  252. #if DBG
  253. if (DfsSvcVerbose)
  254. DbgPrint("NtFsControlFile status=0x%x\n", status);
  255. #endif
  256. free(pustr);
  257. if ( !NT_SUCCESS(status) ) {
  258. goto exit;
  259. }
  260. waitForEvent = TRUE;
  261. //
  262. // Start listening for the server's connection to the port. Note
  263. // that it is OK if the server happens to call NtConnectPort
  264. // first--it will simply block until this call to NtListenPort
  265. // occurs.
  266. //
  267. connectionRequest.u1.s1.TotalLength = sizeof(connectionRequest);
  268. connectionRequest.u1.s1.DataLength = (CSHORT)0;
  269. status = NtListenPort(
  270. DfsConnectionPortHandle,
  271. &connectionRequest
  272. );
  273. #if DBG
  274. if (DfsSvcVerbose)
  275. DbgPrint("NtListenPort status=0x%x\n", status);
  276. #endif
  277. if ( !NT_SUCCESS(status) ) {
  278. goto exit;
  279. }
  280. //
  281. // The server has initiated the connection. Accept the connection.
  282. //
  283. status = NtAcceptConnectPort(
  284. &DfsCommunicationPortHandle,
  285. NULL, // PortContext
  286. &connectionRequest,
  287. TRUE, // AcceptConnection
  288. NULL, // ServerView
  289. NULL // ClientView
  290. );
  291. #if DBG
  292. if (DfsSvcVerbose)
  293. DbgPrint("NtAcceptConnectPort status=0x%x\n", status);
  294. #endif
  295. if ( !NT_SUCCESS(status) ) {
  296. DfsCommunicationPortHandle = NULL;
  297. goto exit;
  298. }
  299. //
  300. // Complete the connection to the port, thereby releasing the server
  301. // thread waiting in NtConnectPort.
  302. //
  303. status = NtCompleteConnectPort( DfsCommunicationPortHandle );
  304. #if DBG
  305. if (DfsSvcVerbose)
  306. DbgPrint("NtCompleteConnectPort status=0x%x\n", status);
  307. #endif
  308. if ( !NT_SUCCESS(status) ) {
  309. goto exit;
  310. }
  311. status = STATUS_SUCCESS;
  312. exit:
  313. //
  314. // Wait for the IO to complete, then close the event handle.
  315. //
  316. if ( waitForEvent ) {
  317. NTSTATUS waitStatus;
  318. waitStatus = NtWaitForSingleObject( eventHandle, FALSE, NULL );
  319. #if DBG
  320. if (DfsSvcVerbose)
  321. DbgPrint("NtWaitForSingleObject status=0x%x\n", waitStatus);
  322. #endif
  323. if ( !NT_SUCCESS(waitStatus) ) {
  324. //
  325. // If another error has already occurred, don't report this
  326. // one.
  327. //
  328. if ( NT_SUCCESS(status) ) {
  329. status = waitStatus;
  330. }
  331. }
  332. //
  333. // Check the status in the IO status block. If it is bad, then
  334. // there was some problem on the server side of the port setup.
  335. //
  336. if ( !NT_SUCCESS(ioStatusBlock.Status) ) {
  337. //
  338. // If another error has already occurred, don't report this
  339. // one.
  340. //
  341. if ( NT_SUCCESS(status) ) {
  342. status = ioStatusBlock.Status;
  343. }
  344. }
  345. }
  346. if (eventHandle != NULL) {
  347. CloseHandle( eventHandle );
  348. }
  349. //
  350. // If the above failed, return to caller now.
  351. //
  352. if ( !NT_SUCCESS(status) ) {
  353. #if DBG
  354. if (DfsSvcVerbose)
  355. DbgPrint("DfsStartDfsSrv exit 0x%x\n", status);
  356. #endif
  357. return RtlNtStatusToDosError( status );
  358. }
  359. //
  360. // Start one API processing thread. It will spawn others if needed
  361. //
  362. DfsThreads = 1;
  363. DfsProcessApisWrapper(DfsThreads);
  364. //
  365. // Initialization succeeded.
  366. //
  367. return NO_ERROR;
  368. }
  369. VOID
  370. DfsProcessApisWrapper (
  371. DWORD ThreadNum)
  372. {
  373. DFSSRV_REQUEST_MESSAGE requestMessage;
  374. //
  375. // Increase the priority of this thread to just above foreground
  376. //
  377. SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
  378. //
  379. // Do the APIs
  380. //
  381. DfsProcessApis( ThreadNum );
  382. //
  383. // Decrement the count of threads. If the count goes to
  384. // zero, set the All Threads Terminated event.
  385. //
  386. if (InterlockedDecrement(&DfsThreads ) == 0 ) {
  387. SetEvent( DfsAllThreadsTerminatedEvent );
  388. } else if (DfsTerminating ) {
  389. //
  390. // There are still threads left, and we are trying to terminate. Queue
  391. // another message to the queue so the next thread will get it and
  392. // notice that we're trying to quit.
  393. //
  394. RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
  395. requestMessage.PortMessage.u1.s1.DataLength =
  396. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  397. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  398. requestMessage.MessageType = DFSSRV_MESSAGE_WAKEUP;
  399. NtRequestPort(
  400. DfsConnectionPortHandle,
  401. (PPORT_MESSAGE)&requestMessage
  402. );
  403. }
  404. ExitThread( NO_ERROR );
  405. }
  406. /*
  407. * This routine is called to stop the transaction processor once the
  408. * server driver has terminated.
  409. */
  410. VOID
  411. DfsStopDfssrv (
  412. VOID)
  413. {
  414. NTSTATUS status;
  415. static DFSSRV_REQUEST_MESSAGE requestMessage;
  416. LONG i;
  417. //
  418. // Stop all the worker threads, and release resources
  419. //
  420. if ( DfsConnectionPortHandle != NULL ) {
  421. //
  422. // Indicate that server is terminating.
  423. //
  424. DfsTerminating = TRUE;
  425. //
  426. // Queue a message to kill off the worker thereads
  427. //
  428. RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
  429. requestMessage.PortMessage.u1.s1.DataLength =
  430. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  431. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  432. requestMessage.MessageType = DFSSRV_MESSAGE_WAKEUP;
  433. status = NtRequestPort(
  434. DfsConnectionPortHandle,
  435. (PPORT_MESSAGE)&requestMessage
  436. );
  437. //
  438. // The above will cause all worker threads to wake up then die.
  439. //
  440. if ( DfsThreads != 0 ) {
  441. BOOL ok;
  442. ok = WaitForSingleObject( DfsAllThreadsTerminatedEvent, (DWORD)-1 );
  443. }
  444. CloseHandle( DfsConnectionPortHandle );
  445. }
  446. if( DfsCommunicationPortHandle != NULL ) {
  447. CloseHandle( DfsCommunicationPortHandle );
  448. DfsCommunicationPortHandle = NULL;
  449. }
  450. //
  451. // Close the termination event.
  452. //
  453. if ( DfsAllThreadsTerminatedEvent != NULL ) {
  454. CloseHandle( DfsAllThreadsTerminatedEvent );
  455. DfsAllThreadsTerminatedEvent = NULL;
  456. }
  457. //
  458. // Close handle to driver
  459. //
  460. if ( serverHandle != NULL ) {
  461. CloseHandle( serverHandle );
  462. }
  463. return;
  464. }
  465. NTSTATUS ReplyFailedStatus;
  466. #define MAX_RETRY_REPLY 10
  467. VOID
  468. DfsProcessApis (
  469. DWORD ThreadNum)
  470. {
  471. NTSTATUS status;
  472. DFSSRV_REQUEST_MESSAGE request;
  473. DFSSRV_REPLY_MESSAGE reply;
  474. BOOL sendReply = FALSE;
  475. WORD apiNumber;
  476. LPWSTR *SiteNames;
  477. ULONG RetryReplyCount = 0;
  478. RtlZeroMemory(&request, sizeof(DFSSRV_REQUEST_MESSAGE));
  479. //
  480. // Loop dispatching API requests.
  481. //
  482. while ( DfsTerminating == FALSE ) {
  483. //
  484. // We're waiting to handle another API...
  485. //
  486. InterlockedIncrement( &DfsWaitingApiThreads );
  487. //
  488. // Send the reply to the last message and wait for the next
  489. // message. The first time through the loop, there will be
  490. // no last message -- reply will be NULL.
  491. //
  492. status = NtReplyWaitReceivePort(
  493. DfsCommunicationPortHandle,
  494. NULL, // PortContext
  495. sendReply ? (PPORT_MESSAGE)&reply : NULL,
  496. (PPORT_MESSAGE)&request
  497. );
  498. if ( status == STATUS_INVALID_PORT_HANDLE
  499. || status == STATUS_PORT_DISCONNECTED
  500. || status == STATUS_INVALID_HANDLE
  501. || DfsTerminating
  502. || request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED ) {
  503. //
  504. // The port is no longer valid, or DFSSRV is terminating.
  505. //
  506. InterlockedDecrement( &DfsWaitingApiThreads );
  507. return;
  508. } else if (request.PortMessage.u2.s2.Type == LPC_CONNECTION_REQUEST) {
  509. sendReply = FALSE;
  510. continue;
  511. } else if ( !NT_SUCCESS(status) ) {
  512. //
  513. // Attempt to handle error returns from reply wait receive.
  514. //
  515. if ((status == STATUS_UNSUCCESSFUL) ||
  516. (status == STATUS_USER_APC)) {
  517. sendReply = FALSE;
  518. } else if ((status == STATUS_INVALID_PARAMETER) ||
  519. (status == STATUS_PORT_MESSAGE_TOO_LONG) ||
  520. (status == STATUS_REPLY_MESSAGE_MISMATCH)) {
  521. sendReply = FALSE;
  522. } else if (RetryReplyCount++ > MAX_RETRY_REPLY) {
  523. sendReply = FALSE;
  524. ReplyFailedStatus = status;
  525. }
  526. continue;
  527. }
  528. RetryReplyCount = 0;
  529. sendReply = TRUE;
  530. //
  531. // Set up the response message to be sent on the next call to
  532. // NtReplyWaitReceivePort.
  533. //
  534. reply.PortMessage.u1.s1.DataLength =
  535. sizeof(reply) - sizeof(PORT_MESSAGE);
  536. reply.PortMessage.u1.s1.TotalLength = sizeof(reply);
  537. reply.PortMessage.u2.ZeroInit = 0;
  538. reply.PortMessage.ClientId = request.PortMessage.ClientId;
  539. reply.PortMessage.MessageId = request.PortMessage.MessageId;
  540. if( InterlockedDecrement( &DfsWaitingApiThreads ) == 0 ) {
  541. HANDLE threadHandle;
  542. DWORD threadId;
  543. //
  544. // Are there other threads ready to handle new requests? If not, then
  545. // we should spawn a new thread.
  546. //
  547. InterlockedIncrement( &DfsThreads );
  548. threadHandle = CreateThread(
  549. NULL,
  550. 0,
  551. (LPTHREAD_START_ROUTINE)DfsProcessApisWrapper,
  552. (LPVOID)ULongToPtr( DfsThreads ),
  553. 0,
  554. &threadId
  555. );
  556. if ( threadHandle != 0 ) {
  557. CloseHandle( threadHandle );
  558. } else {
  559. InterlockedDecrement( &DfsThreads );
  560. }
  561. }
  562. switch ( request.MessageType ) {
  563. case DFSSRV_MESSAGE_GET_SITE_NAME:
  564. {
  565. ULONG IpAddress = *((ULONG *) &request.Message.GetSiteName.IpAddress.IpData);
  566. #if DBG
  567. if (DfsSvcVerbose)
  568. DbgPrint("Asking for SiteName for %d.%d.%d.%d\n",
  569. IpAddress & 0xff,
  570. (IpAddress >> 8) & 0xff,
  571. (IpAddress >> 16) & 0xff,
  572. (IpAddress >> 24) & 0xff);
  573. #endif
  574. SiteNames = NULL;
  575. #define _Dfs_LocalAddress 0x0100007f
  576. if ((request.Message.GetSiteName.IpAddress.IpLen == 4) &&
  577. (IpAddress == _Dfs_LocalAddress)) {
  578. LPWSTR SiteName;
  579. status = DsGetSiteName( NULL,
  580. &SiteName );
  581. if (status == NO_ERROR) {
  582. DfsLoadIpCache(&request.Message.GetSiteName.IpAddress, SiteName);
  583. NetApiBufferFree(SiteName);
  584. }
  585. }
  586. else {
  587. status = AddrToSite(
  588. &request.Message.GetSiteName.IpAddress,
  589. &SiteNames);
  590. if (status == NO_ERROR) {
  591. if (SiteNames != NULL && SiteNames[0] != NULL) {
  592. DfsLoadIpCache(&request.Message.GetSiteName.IpAddress, SiteNames[0]);
  593. }
  594. if (SiteNames != NULL) {
  595. NetApiBufferFree(SiteNames);
  596. }
  597. }
  598. }
  599. reply.Message.Result.Status = status;
  600. break;
  601. }
  602. case DFSSRV_MESSAGE_GET_DOMAIN_REFERRAL:
  603. {
  604. LPWSTR FtName = request.Message.GetFtDfs.FtName;
  605. #if DBG
  606. if (DfsSvcVerbose)
  607. DbgPrint("Asking for DOMAIN REFERRAL for %ws\n", FtName);
  608. #endif
  609. status = DfsDomainReferral(
  610. DomainName,
  611. FtName);
  612. reply.Message.Result.Status = status;
  613. break;
  614. }
  615. case DFSSRV_MESSAGE_GET_SPC_ENTRY:
  616. {
  617. LPWSTR SpcName = request.Message.GetSpcName.SpcName;
  618. ULONG Flags = request.Message.GetSpcName.Flags;
  619. #if DBG
  620. if (DfsSvcVerbose)
  621. DbgPrint("Asking for SPC EXPANSION for %ws\n", SpcName);
  622. #endif
  623. status = DfsGetTrustedDomainDCs(
  624. SpcName,
  625. Flags);
  626. reply.Message.Result.Status = status;
  627. break;
  628. }
  629. default:
  630. /* NOTHING */;
  631. }
  632. }
  633. }
  634. VOID
  635. DfsLoadIpCache(
  636. PDFS_IPADDRESS pIpAddress,
  637. LPWSTR SiteName)
  638. {
  639. NTSTATUS NtStatus;
  640. IO_STATUS_BLOCK IoStatusBlock;
  641. PDFS_CREATE_IP_INFO_ARG pInfoArg;
  642. ULONG size;
  643. size = sizeof(DFS_CREATE_IP_INFO_ARG) + wcslen(SiteName) * sizeof(WCHAR);
  644. pInfoArg = malloc(size);
  645. if (pInfoArg != NULL) {
  646. RtlZeroMemory(pInfoArg, size);
  647. pInfoArg->SiteName.Buffer = (LPWSTR)&pInfoArg[1];
  648. pInfoArg->SiteName.Length = wcslen(SiteName) * sizeof(WCHAR);
  649. pInfoArg->SiteName.MaximumLength = pInfoArg->SiteName.Length;
  650. RtlCopyMemory(pInfoArg->SiteName.Buffer,SiteName,pInfoArg->SiteName.Length);
  651. pInfoArg->SiteName.Buffer = (LPWSTR)sizeof(DFS_CREATE_IP_INFO_ARG);
  652. pInfoArg->IpAddress = *pIpAddress;
  653. NtStatus = NtFsControlFile(
  654. serverHandle,
  655. NULL, // Event,
  656. NULL, // ApcRoutine,
  657. NULL, // ApcContext,
  658. &IoStatusBlock,
  659. FSCTL_DFS_CREATE_IP_INFO,
  660. pInfoArg,
  661. size,
  662. NULL,
  663. 0
  664. );
  665. free(pInfoArg);
  666. }
  667. }
  668. NTSTATUS
  669. AddrToSite(
  670. PDFS_IPADDRESS IpAddress,
  671. LPWSTR **pppSiteName)
  672. {
  673. DWORD dwErr;
  674. PSOCKET_ADDRESS pSockAddr;
  675. SOCKET_ADDRESS SockAddr;
  676. PSOCKADDR_IN pSockAddrIn;
  677. SOCKADDR_IN SockAddrIn;
  678. WCHAR **SiteNames;
  679. DWORD cRetry;
  680. PDOMAIN_CONTROLLER_INFO pDCInfo;
  681. pSockAddr = &SockAddr;
  682. pSockAddr->iSockaddrLength = sizeof(SOCKADDR_IN);
  683. pSockAddr->lpSockaddr = (LPSOCKADDR)&SockAddrIn;
  684. pSockAddrIn = &SockAddrIn;
  685. pSockAddrIn->sin_family = IpAddress->IpFamily;
  686. pSockAddrIn->sin_port = 0;
  687. RtlCopyMemory(
  688. &pSockAddrIn->sin_addr,
  689. IpAddress->IpData,
  690. (IpAddress->IpLen & 0xff));
  691. if (DfsMachineRole == DsRole_RoleBackupDomainController
  692. ||
  693. DfsMachineRole == DsRole_RolePrimaryDomainController) {
  694. dwErr = DsAddressToSiteNames(
  695. NULL,
  696. 1,
  697. pSockAddr,
  698. pppSiteName);
  699. goto exit;
  700. }
  701. //
  702. // Call DsGetDcName() with ever-increasing urgency, until either
  703. // we get a good DC or we just give up.
  704. //
  705. for (cRetry = 0; cRetry < (sizeof(dwFlags) / sizeof(dwFlags[1])); cRetry++) {
  706. dwErr = DsGetDcName(
  707. NULL, // Computer to remote to
  708. NULL, // Domain - use local domain
  709. NULL, // Domain Guid
  710. NULL, // Site Guid
  711. dwFlags[cRetry], // Flags
  712. &pDCInfo);
  713. if (dwErr == ERROR_SUCCESS) {
  714. dwErr = DsAddressToSiteNames(
  715. pDCInfo->DomainControllerAddress,
  716. 1,
  717. pSockAddr,
  718. pppSiteName);
  719. NetApiBufferFree( pDCInfo );
  720. if (dwErr == ERROR_SUCCESS) {
  721. goto exit;
  722. }
  723. }
  724. }
  725. exit:
  726. return dwErr;
  727. }