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.

1019 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. remote.c
  5. Abstract:
  6. DNS Resolver Service.
  7. Remote APIs to resolver service.
  8. Author:
  9. Glenn Curtis (glennc) Feb 1997
  10. Revision History:
  11. Jim Gilroy (jamesg) March 2000 cleanup
  12. --*/
  13. #include "local.h"
  14. //
  15. // Local Definitions
  16. //
  17. typedef struct _POPUP_MSG_PARMS
  18. {
  19. LPWSTR Message;
  20. LPWSTR Title;
  21. }
  22. POPUP_MSG_PARMS, *PPOPUP_MSG_PARMS;
  23. //
  24. // Private protos
  25. //
  26. DNS_STATUS
  27. RslvrQueryToDnsServer(
  28. OUT PDNS_RECORD * ppRecord,
  29. IN PWSTR pwsName,
  30. IN WORD wType,
  31. IN DWORD Flags,
  32. OUT PBOOL pfCacheNegativeResponse
  33. );
  34. BOOL
  35. IsKnownTimedOutAdapter(
  36. VOID
  37. );
  38. VOID
  39. SetKnownTimedOutAdapter(
  40. VOID
  41. );
  42. BOOL
  43. IsTimeToResetServerPriorities(
  44. VOID
  45. );
  46. DWORD
  47. PopupMessageThread(
  48. IN PPOPUP_MSG_PARMS );
  49. PDNS_RPC_CACHE_TABLE
  50. CreateCacheTableEntry(
  51. IN LPWSTR Name
  52. );
  53. VOID
  54. FreeCacheTableEntryList(
  55. IN PDNS_RPC_CACHE_TABLE pCacheTableList
  56. );
  57. BOOL
  58. IsEmptyDnsResponse(
  59. IN PDNS_RECORD
  60. );
  61. //
  62. // Operations
  63. //
  64. DNS_STATUS
  65. CRrReadCache(
  66. IN DNS_RPC_HANDLE Reserved,
  67. OUT PDNS_RPC_CACHE_TABLE * ppCacheTable
  68. )
  69. /*++
  70. Routine Description:
  71. Arguments:
  72. Return Value:
  73. --*/ // CRrReadCache
  74. {
  75. DNS_STATUS status = ERROR_SUCCESS;
  76. PDNS_RPC_CACHE_TABLE pprevRpcEntry = NULL;
  77. DWORD iter;
  78. DWORD countEntries = 0;
  79. #define MAX_RPC_CACHE_ENTRY_COUNT (300)
  80. UNREFERENCED_PARAMETER(Reserved);
  81. DNSDBG( RPC, ( "CRrReadCache\n" ));
  82. if ( !ppCacheTable )
  83. {
  84. return ERROR_INVALID_PARAMETER;
  85. }
  86. *ppCacheTable = NULL;
  87. DNSLOG_F1( "DNS Caching Resolver Service - CRrReadCache" );
  88. if ( ClientThreadNotAllowedAccess() )
  89. {
  90. DNSLOG_F1( "CRrReadCache - ERROR_ACCESS_DENIED" );
  91. return ERROR_ACCESS_DENIED;
  92. }
  93. LOCK_CACHE();
  94. DNSLOG_F2( " Current number of entries in cache : %d",
  95. g_EntryCount );
  96. DNSLOG_F2( " Current number of RR sets in cache : %d",
  97. g_RecordSetCount );
  98. //
  99. // Loop through all hash table slots looking for cache entries
  100. // to return.
  101. //
  102. for ( iter = 0; iter < g_HashTableSize; iter++ )
  103. {
  104. PCACHE_ENTRY pentry = g_HashTable[iter];
  105. DWORD iter2;
  106. while ( pentry &&
  107. countEntries < MAX_RPC_CACHE_ENTRY_COUNT )
  108. {
  109. PDNS_RPC_CACHE_TABLE prpcEntry;
  110. prpcEntry = CreateCacheTableEntry( pentry->pName );
  111. if ( ! prpcEntry )
  112. {
  113. // only failure is memory alloc
  114. FreeCacheTableEntryList( *ppCacheTable );
  115. *ppCacheTable = NULL;
  116. status = ERROR_NOT_ENOUGH_MEMORY;
  117. goto ErrorExit;
  118. }
  119. //
  120. // insert new entry at end of current list
  121. //
  122. if ( pprevRpcEntry )
  123. pprevRpcEntry->pNext = prpcEntry;
  124. else
  125. *ppCacheTable = prpcEntry;
  126. pprevRpcEntry = prpcEntry;
  127. countEntries++;
  128. //
  129. // fill in entry with current cached types
  130. //
  131. for ( iter2 = 0; iter2 < pentry->MaxCount; iter2++ )
  132. {
  133. PDNS_RECORD prr = pentry->Records[iter2];
  134. WORD type;
  135. if ( !prr )
  136. {
  137. continue;
  138. }
  139. // DCR -- goofy, just make sure the same and index (or limit?)
  140. type = prr->wType;
  141. if ( ! prpcEntry->Type1 )
  142. prpcEntry->Type1 = type;
  143. else if ( ! prpcEntry->Type2 )
  144. prpcEntry->Type2 = type;
  145. else
  146. prpcEntry->Type3 = type;
  147. }
  148. pentry = pentry->pNext;
  149. }
  150. if ( countEntries > MAX_RPC_CACHE_ENTRY_COUNT )
  151. {
  152. break;
  153. }
  154. }
  155. ErrorExit:
  156. UNLOCK_CACHE();
  157. DNSLOG_F3( " CRrReadCache - Returning status : 0x%.8X\n\t%s",
  158. status,
  159. Dns_StatusString( status ) );
  160. DNSLOG_F1( "" );
  161. return status;
  162. }
  163. DNS_STATUS
  164. CRrReadCacheEntry(
  165. IN DNS_RPC_HANDLE Reserved,
  166. IN LPWSTR pwsName,
  167. IN WORD wType,
  168. OUT PDNS_RECORD * ppRRSet
  169. )
  170. /*++
  171. Routine Description:
  172. Arguments:
  173. Return Value:
  174. --*/ // CRrReadCacheEntry
  175. {
  176. DNS_STATUS status;
  177. PCACHE_ENTRY pentry;
  178. PDNS_RECORD prr;
  179. UNREFERENCED_PARAMETER(Reserved);
  180. DNSLOG_F1( "DNS Caching Resolver Service - CRrReadCacheEntry" );
  181. DNSLOG_F1( " Arguments:" );
  182. DNSLOG_F2( " Name : %S", pwsName );
  183. DNSLOG_F2( " Type : %d", wType );
  184. DNSLOG_F1( "" );
  185. DNSDBG( RPC, (
  186. "\nCRrReadCacheEntry( %S, %d )\n",
  187. pwsName,
  188. wType ));
  189. if ( !ppRRSet )
  190. return ERROR_INVALID_PARAMETER;
  191. if ( ClientThreadNotAllowedAccess() )
  192. {
  193. DNSLOG_F1( "CRrReadCacheEntry - ERROR_ACCESS_DENIED" );
  194. return ERROR_ACCESS_DENIED;
  195. }
  196. //
  197. // find record in cache
  198. // - copy if not NAME_ERROR or EMPTY
  199. // - default to not-found error
  200. // (DOES_NOT_EXIST error)
  201. //
  202. *ppRRSet = NULL;
  203. status = DNS_ERROR_RECORD_DOES_NOT_EXIST;
  204. Cache_GetRecordsForRpc(
  205. ppRRSet,
  206. & status,
  207. pwsName,
  208. wType,
  209. 0 // no screening flags
  210. );
  211. DNSLOG_F3( " CRrReadCacheEntry - Returning status : 0x%.8X\n\t%s",
  212. status,
  213. Dns_StatusString( status ) );
  214. DNSLOG_F1( "" );
  215. DNSDBG( RPC, (
  216. "Leave CRrReadCacheEntry( %S, %d ) => %d\n\n",
  217. pwsName,
  218. wType,
  219. status ));
  220. return status;
  221. }
  222. DNS_STATUS
  223. CRrGetHashTableStats(
  224. IN DNS_RPC_HANDLE Reserved,
  225. OUT LPDWORD pdwCacheHashTableSize,
  226. OUT LPDWORD pdwCacheHashTableBucketSize,
  227. OUT LPDWORD pdwNumberOfCacheEntries,
  228. OUT LPDWORD pdwNumberOfRecords,
  229. OUT LPDWORD pdwNumberOfExpiredRecords,
  230. OUT PDNS_STATS_TABLE * ppStatsTable
  231. )
  232. /*++
  233. Routine Description:
  234. Arguments:
  235. Return Value:
  236. --*/
  237. {
  238. PDNS_STATS_TABLE pprevRow = NULL;
  239. PDWORD_LIST_ITEM pprevItem = NULL;
  240. DWORD rowIter;
  241. DWORD itemIter;
  242. DWORD countExpiredRecords = 0;
  243. DWORD status = ERROR_SUCCESS;
  244. UNREFERENCED_PARAMETER(Reserved);
  245. if ( !pdwCacheHashTableSize ||
  246. !pdwCacheHashTableBucketSize ||
  247. !pdwNumberOfCacheEntries ||
  248. !pdwNumberOfRecords ||
  249. !pdwNumberOfExpiredRecords ||
  250. !ppStatsTable )
  251. {
  252. return ERROR_INVALID_PARAMETER;
  253. }
  254. DNSLOG_F1( "CRrGetHashTableStats" );
  255. DNSDBG( RPC, ( "CRrGetHashTableStats\n" ));
  256. if ( ClientThreadNotAllowedAccess() )
  257. {
  258. DNSLOG_F1( "CRrGetHashTableStats - ERROR_ACCESS_DENIED" );
  259. return ERROR_ACCESS_DENIED;
  260. }
  261. LOCK_CACHE();
  262. *pdwCacheHashTableSize = g_HashTableSize;
  263. //*pdwCacheHashTableBucketSize = g_CacheHashTableBucketSize;
  264. *pdwCacheHashTableBucketSize = 0;
  265. *pdwNumberOfCacheEntries = g_EntryCount;
  266. *pdwNumberOfRecords = g_RecordSetCount;
  267. *pdwNumberOfExpiredRecords = 0;
  268. //
  269. // read entire hash table
  270. //
  271. for ( rowIter = 0;
  272. rowIter < g_HashTableSize;
  273. rowIter++ )
  274. {
  275. PCACHE_ENTRY pentry = g_HashTable[rowIter];
  276. PDNS_STATS_TABLE pnewRow;
  277. //
  278. // create table for each new row
  279. //
  280. pnewRow = RPC_HEAP_ALLOC( sizeof(DNS_STATS_TABLE) );
  281. if ( !pnewRow )
  282. {
  283. status = ERROR_NOT_ENOUGH_MEMORY;
  284. goto Done;
  285. }
  286. if ( rowIter == 0 )
  287. *ppStatsTable = pnewRow;
  288. else
  289. pprevRow->pNext = pnewRow;
  290. //
  291. // fill in row data (if any)
  292. //
  293. while ( pentry )
  294. {
  295. PDWORD_LIST_ITEM pnewItem;
  296. pnewItem = RPC_HEAP_ALLOC( sizeof( DWORD_LIST_ITEM ) );
  297. if ( !pnewItem )
  298. {
  299. status = ERROR_NOT_ENOUGH_MEMORY;
  300. goto Done;
  301. }
  302. for ( itemIter = 0;
  303. itemIter < pentry->MaxCount;
  304. itemIter++ )
  305. {
  306. PDNS_RECORD prr = pentry->Records[itemIter];
  307. if ( prr )
  308. {
  309. pnewItem->Value1++;
  310. if ( !Cache_IsRecordTtlValid( prr ) )
  311. {
  312. pnewItem->Value2++;
  313. countExpiredRecords++;
  314. }
  315. }
  316. }
  317. if ( !pnewRow->pListItem )
  318. pnewRow->pListItem = pnewItem;
  319. else
  320. pprevItem->pNext = pnewItem;
  321. pprevItem = pnewItem;
  322. pentry = pentry->pNext;
  323. }
  324. pprevRow = pnewRow;
  325. }
  326. Done:
  327. UNLOCK_CACHE();
  328. *pdwNumberOfExpiredRecords = countExpiredRecords;
  329. return status;
  330. }
  331. BOOL
  332. IsKnownNetFailure(
  333. VOID
  334. )
  335. /*++
  336. Routine Description:
  337. Determine if we are in known net failure window.
  338. Arguments:
  339. None
  340. Return Value:
  341. TRUE if in known net failure
  342. FALSE otherwise
  343. --*/
  344. {
  345. BOOL flag = FALSE;
  346. DNSDBG( TRACE, ( "IsKnownNetFailure()\n" ));
  347. LOCK_NET_FAILURE();
  348. if ( g_NetFailureStatus )
  349. {
  350. if ( g_NetFailureTime < Dns_GetCurrentTimeInSeconds() )
  351. {
  352. g_NetFailureTime = 0;
  353. g_NetFailureStatus = ERROR_SUCCESS;
  354. flag = FALSE;
  355. }
  356. else
  357. {
  358. SetLastError( g_NetFailureStatus );
  359. flag = TRUE;
  360. }
  361. }
  362. UNLOCK_NET_FAILURE();
  363. return flag;
  364. }
  365. VOID
  366. SetKnownNetFailure(
  367. IN DNS_STATUS Status
  368. )
  369. /*++
  370. Routine Description:
  371. Set cause of net failure.
  372. Arguments:
  373. Status -- status code for cause of net failure
  374. Return Value:
  375. None
  376. --*/
  377. {
  378. LPSTR DnsString = NULL;
  379. LPWSTR InsertStrings[3];
  380. WCHAR String1[25];
  381. WCHAR String2[256];
  382. WCHAR String3[25];
  383. DNSDBG( TRACE, ( "SetKnownNetFailure()\n" ));
  384. //
  385. // don't indicate failure during boot
  386. //
  387. if ( Dns_GetCurrentTimeInSeconds() < THREE_MINUTES_FROM_SYSTEM_BOOT )
  388. {
  389. return;
  390. }
  391. if ( !g_LocalAddrArray || g_NetFailureCacheTime == 0 )
  392. {
  393. //
  394. // We are in a no-net configuration, there is no need
  395. // to display the pop-up message. No point warning
  396. // of DNS configuration problems when the system is
  397. // off the net.
  398. // - or -
  399. // We are on a NT server, and therefore don't do poor network
  400. // performance caching.
  401. //
  402. return;
  403. }
  404. LOCK_NET_FAILURE();
  405. g_NetFailureTime = Dns_GetCurrentTimeInSeconds() + g_NetFailureCacheTime;
  406. g_NetFailureStatus = Status;
  407. wsprintfW( String1, L"0x%.8X", Status );
  408. DnsString = DnsStatusString( Status );
  409. if ( DnsString )
  410. {
  411. Dns_StringCopy( (PBYTE) String2,
  412. NULL,
  413. (PCHAR) DnsString,
  414. (WORD) strlen( DnsString ),
  415. DnsCharSetAnsi,
  416. DnsCharSetUnicode );
  417. //
  418. // No need to free this since the string is just a pointer
  419. // to a global table entry.
  420. //
  421. // FREE_HEAP( DnsString );
  422. }
  423. else
  424. {
  425. wsprintfW( String2, L"<?>" );
  426. }
  427. wsprintfW( String3, L"%d", g_NetFailureCacheTime );
  428. if ( g_MessagePopupStrikes < 3 )
  429. {
  430. g_MessagePopupStrikes++;
  431. }
  432. else
  433. {
  434. if ( Status != g_PreviousNetFailureStatus )
  435. {
  436. //
  437. // DCR_PERF: should remove logging from inside lock
  438. //
  439. InsertStrings[0] = String1;
  440. InsertStrings[1] = String2;
  441. InsertStrings[2] = String3;
  442. ResolverLogEvent(
  443. EVENT_DNS_CACHE_NETWORK_PERF_WARNING,
  444. EVENTLOG_WARNING_TYPE,
  445. 3,
  446. InsertStrings,
  447. Status );
  448. g_PreviousNetFailureStatus = Status;
  449. }
  450. g_MessagePopupStrikes = 0;
  451. }
  452. UNLOCK_NET_FAILURE();
  453. }
  454. BOOL
  455. IsKnownTimedOutAdapter(
  456. VOID
  457. )
  458. /*++
  459. Routine Description:
  460. Determine if timed out adapter exists.
  461. Arguments:
  462. None
  463. Return Value:
  464. TRUE if timed out adapter
  465. FALSE otherwise
  466. --*/
  467. {
  468. BOOL flag = FALSE;
  469. DNSDBG( TRACE, ( "IsKnownTimedOutAdapter()\n" ));
  470. //
  471. // DCR: don't really need lock for this?
  472. // - could check if lock taken?
  473. // but if beat it -- so what
  474. //
  475. LOCK_NET_FAILURE();
  476. if ( g_fTimedOutAdapter )
  477. {
  478. if ( g_TimedOutAdapterTime < Dns_GetCurrentTimeInSeconds() )
  479. {
  480. DNSLOG_F1( " Timed out adapter cache expired, resseting adapter!" );
  481. g_TimedOutAdapterTime = 0;
  482. g_fTimedOutAdapter = FALSE;
  483. flag = FALSE;
  484. }
  485. else
  486. {
  487. flag = TRUE;
  488. }
  489. }
  490. UNLOCK_NET_FAILURE();
  491. return flag;
  492. }
  493. VOID
  494. SetKnownTimedOutAdapter(
  495. VOID
  496. )
  497. {
  498. DNSDBG( TRACE, ( "SetKnownTimedOutAdapter()\n" ));
  499. if ( Dns_GetCurrentTimeInSeconds() < THREE_MINUTES_FROM_SYSTEM_BOOT )
  500. {
  501. return;
  502. }
  503. if ( !g_LocalAddrArray )
  504. {
  505. //
  506. // We are in a no-net configuration, there is no need
  507. // to display the pop-up message. No point warning
  508. // of DNS configuration problems when the system is
  509. // off the net.
  510. //
  511. return;
  512. }
  513. DNSLOG_F1( " Detected a timed out adapter, disabling it for a little while" );
  514. LOCK_NET_FAILURE();
  515. g_TimedOutAdapterTime = Dns_GetCurrentTimeInSeconds() +
  516. g_AdapterTimeoutLimit;
  517. g_fTimedOutAdapter = TRUE;
  518. UNLOCK_NET_FAILURE();
  519. }
  520. DWORD
  521. PopupMessageThread(
  522. IN OUT PPOPUP_MSG_PARMS MsgParms
  523. )
  524. /*++
  525. Routine Description:
  526. Popup a message box with error.
  527. Arguments:
  528. MsgParms -- popup message parameters
  529. Return Value:
  530. ERROR_SUCCESS
  531. --*/
  532. {
  533. MessageBoxW(
  534. NULL,
  535. MsgParms->Message,
  536. MsgParms->Title,
  537. MB_SERVICE_NOTIFICATION | MB_ICONWARNING | MB_OK );
  538. GENERAL_HEAP_FREE( MsgParms->Message );
  539. GENERAL_HEAP_FREE( MsgParms->Title );
  540. GENERAL_HEAP_FREE( MsgParms );
  541. return ERROR_SUCCESS;
  542. }
  543. BOOL
  544. ClientThreadNotAllowedAccess(
  545. VOID
  546. )
  547. {
  548. #if 0
  549. //
  550. // DCR: should probably access check only for flush cache or
  551. // delete entry
  552. //
  553. //
  554. // DCR: - This idea of adding a security check for
  555. // DNS RPC API is really debatable. The data
  556. // maintained by the DNS Caching Resolver is definately
  557. // not private. Since the cache mimicks the DNS protocol
  558. // as a non-handle based access to public information,
  559. // it would require an access check for every interface
  560. // and for every call. Doing this would required a context
  561. // switch into kernel mode to perform the check. This is
  562. // a lot of overhead just to protect an API that provides
  563. // access to widely available information. After all, the
  564. // cache is supposed to improve name resolution performance!
  565. //
  566. // Below is the start of some code to implement an access
  567. // check, though it sounds like I should call the Win32
  568. // security function AccessCheck() and create a DNS cache
  569. // SID to compare the desired access of the client thread
  570. // against. This is not finished and I don't intend to
  571. // try finish it.
  572. //
  573. GENERIC_MAPPING DNSAccessMapping = {
  574. STANDARD_RIGHTS_READ,
  575. STANDARD_RIGHTS_WRITE,
  576. STANDARD_RIGHTS_EXECUTE
  577. };
  578. HANDLE hThread = GetCurrentThread();
  579. DWORD dwGrantedAccess;
  580. BOOL Result;
  581. if ( RpcImpersonateClient(NULL) )
  582. return TRUE;
  583. hThread = GetCurrentThread();
  584. if ( !hThread )
  585. {
  586. RpcRevertToSelf();
  587. return TRUE;
  588. }
  589. if ( OpenThreadToken( hThread,
  590. TOKEN_QUERY,
  591. FALSE,
  592. &hToken ) )
  593. {
  594. if ( AccessCheck( pSD,
  595. hToken,
  596. STANDARD_RIGHTS_WRITE,
  597. &DNSAccessMapping,
  598. pPS,
  599. sizeof( *pPS ),
  600. &dwGrantedAccess,
  601. &Result );
  602. }
  603. CloseHandle( hThread );
  604. RpcRevertToSelf();
  605. if ( Result )
  606. return FALSE;
  607. else
  608. return TRUE;
  609. #endif
  610. return FALSE;
  611. }
  612. PDNS_RPC_CACHE_TABLE
  613. CreateCacheTableEntry(
  614. IN LPWSTR pwsName
  615. )
  616. {
  617. PDNS_RPC_CACHE_TABLE prpcEntry = NULL;
  618. if ( ! pwsName )
  619. return NULL;
  620. prpcEntry = (PDNS_RPC_CACHE_TABLE)
  621. RPC_HEAP_ALLOC_ZERO( sizeof(DNS_RPC_CACHE_TABLE) );
  622. if ( prpcEntry == NULL )
  623. return NULL;
  624. prpcEntry->Name = RPC_HEAP_ALLOC( sizeof(WCHAR) * (wcslen(pwsName) + 1) );
  625. if ( ! prpcEntry->Name )
  626. {
  627. RPC_HEAP_FREE( prpcEntry );
  628. return NULL;
  629. }
  630. wcscpy( prpcEntry->Name, pwsName );
  631. return prpcEntry;
  632. }
  633. VOID
  634. FreeCacheTableEntryList(
  635. IN PDNS_RPC_CACHE_TABLE pCacheTableList )
  636. {
  637. while ( pCacheTableList )
  638. {
  639. PDNS_RPC_CACHE_TABLE pNext = pCacheTableList->pNext;
  640. if ( pCacheTableList->Name )
  641. {
  642. RPC_HEAP_FREE( pCacheTableList->Name );
  643. pCacheTableList->Name = NULL;
  644. }
  645. RPC_HEAP_FREE( pCacheTableList );
  646. pCacheTableList = pNext;
  647. }
  648. }
  649. BOOL
  650. IsEmptyDnsResponse(
  651. IN PDNS_RECORD pRecord
  652. )
  653. {
  654. //
  655. // DCR_FIX: should be dnslib utility
  656. //
  657. // DCR_FIX: should distinguish referral and no-records
  658. //
  659. PDNS_RECORD pTempRecord = pRecord;
  660. BOOL fEmpty = TRUE;
  661. while ( pTempRecord )
  662. {
  663. if ( pTempRecord->Flags.S.Section == DNSREC_ANSWER )
  664. {
  665. fEmpty = FALSE;
  666. break;
  667. }
  668. pTempRecord = pTempRecord->pNext;
  669. }
  670. return fEmpty;
  671. }
  672. DNS_STATUS
  673. CRrUpdateTest(
  674. IN DNS_RPC_HANDLE Reserved,
  675. IN PWSTR pwsName,
  676. IN DWORD fOptions,
  677. IN IP_ADDRESS ServerIp
  678. )
  679. /*++
  680. Routine Description:
  681. Do update test for existing record.
  682. DCR: need UpdateTest() IPv6 capable
  683. Arguments:
  684. Return Value:
  685. ErrorCode from update attempt.
  686. --*/
  687. {
  688. DNS_STATUS status = ERROR_SUCCESS;
  689. DNS_RECORD record;
  690. DWORD flags = fOptions;
  691. PSTR pnameTemp = NULL;
  692. PDNS_NETINFO pnetInfo = NULL;
  693. IP_ARRAY serverIpArray;
  694. PIP_ARRAY pserverIpArray = NULL;
  695. DNSLOG_F1( "DNS Caching Resolver Service - CRrUpdateTest" );
  696. DNSDBG( RPC, ( "\nCRrUpdateTest()\n" ));
  697. //
  698. // Validate arguments
  699. //
  700. if ( !pwsName || !ServerIp )
  701. {
  702. return ERROR_INVALID_PARAMETER;
  703. }
  704. //
  705. // make UTF8 name and FAZ
  706. //
  707. // DCR: not clear why all this work isn't just done in update API
  708. //
  709. pnameTemp = Dns_NameCopyAllocate(
  710. (PCHAR) pwsName,
  711. 0,
  712. DnsCharSetUnicode,
  713. DnsCharSetUtf8 );
  714. if ( ! pnameTemp )
  715. {
  716. return ERROR_NOT_ENOUGH_MEMORY;
  717. }
  718. serverIpArray.AddrCount = 1;
  719. serverIpArray.AddrArray[0] = ServerIp;
  720. pserverIpArray = &serverIpArray;
  721. status = Dns_FindAuthoritativeZoneLib(
  722. (PDNS_NAME) pnameTemp,
  723. 0,
  724. pserverIpArray,
  725. &pnetInfo );
  726. if ( status != NO_ERROR )
  727. {
  728. goto Cleanup;
  729. }
  730. //
  731. // build update prereq "nothing exists" record
  732. //
  733. RtlZeroMemory( &record, sizeof(DNS_RECORD) );
  734. record.pName = (PDNS_NAME) pnameTemp;
  735. record.wType = DNS_TYPE_ANY;
  736. record.wDataLength = 0;
  737. record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  738. //
  739. // update
  740. //
  741. status = Dns_UpdateLib(
  742. &record,
  743. 0,
  744. pnetInfo,
  745. NULL,
  746. NULL );
  747. Cleanup:
  748. Dns_Free( pnameTemp );
  749. NetInfo_Free( pnetInfo );
  750. DNSDBG( RPC, (
  751. "Leave CRrUpdateTest() => %d\n\n",
  752. status ));
  753. return status;
  754. }
  755. //
  756. // End remote.c
  757. //