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.

4681 lines
107 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. update.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Update client routines.
  8. Author:
  9. Jim Gilroy (jamesg) October, 1996
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Security flag check
  15. //
  16. #define UseSystemDefaultForSecurity(flag) \
  17. ( ((flag) & DNS_UPDATE_SECURITY_CHOICE_MASK) \
  18. == DNS_UPDATE_SECURITY_USE_DEFAULT )
  19. //
  20. // Local update flag
  21. // - must make sure this is in UPDATE_RESERVED space
  22. //
  23. #define DNS_UPDATE_LOCAL_COPY (0x00010000)
  24. //
  25. // DCR_DELETE: this is stupid
  26. //
  27. #define DNS_UNACCEPTABLE_UPDATE_OPTIONS \
  28. (~ \
  29. ( DNS_UPDATE_SHARED | \
  30. DNS_UPDATE_SECURITY_OFF | \
  31. DNS_UPDATE_CACHE_SECURITY_CONTEXT | \
  32. DNS_UPDATE_SECURITY_ON | \
  33. DNS_UPDATE_FORCE_SECURITY_NEGO | \
  34. DNS_UPDATE_TRY_ALL_MASTER_SERVERS | \
  35. DNS_UPDATE_LOCAL_COPY | \
  36. DNS_UPDATE_SECURITY_ONLY ))
  37. //
  38. // Update Timeouts
  39. //
  40. // note, max is a little longer than might be expected as DNS server
  41. // may have to contact primary and wait for primary to do update (inc.
  42. // disk access) then response
  43. //
  44. #define INITIAL_UPDATE_TIMEOUT (4) // 4 seconds
  45. #define MAX_UPDATE_TIMEOUT (60) // 60 seconds
  46. //
  47. // Private prototypes
  48. //
  49. DNS_STATUS
  50. DoQuickUpdate(
  51. IN PDNS_RECORD pRecord,
  52. IN DWORD dwFlags,
  53. IN BOOL fUpdateTestMode,
  54. IN PIP_ARRAY pServerList OPTIONAL,
  55. IN HANDLE hCreds OPTIONAL
  56. );
  57. DNS_STATUS
  58. DoQuickUpdateEx(
  59. OUT PDNS_MSG_BUF * ppMsgRecv, OPTIONAL
  60. IN PDNS_RECORD pRecord,
  61. IN DWORD dwFlags,
  62. IN PDNS_NETINFO pNetworkInfo,
  63. IN HANDLE hCreds OPTIONAL
  64. );
  65. DNS_STATUS
  66. DoMultiMasterUpdate(
  67. IN PDNS_RECORD pRecord,
  68. IN DWORD dwFlags,
  69. IN HANDLE hCreds OPTIONAL,
  70. IN LPSTR pszDomain,
  71. IN IP_ADDRESS BadIp,
  72. IN PIP_ARRAY pServerList
  73. );
  74. VOID
  75. SetLastFailedUpdateInfo(
  76. IN PDNS_MSG_BUF pMsg,
  77. IN DNS_STATUS Status
  78. );
  79. PCHAR
  80. Dns_WriteNoDataUpdateRecordToMessage(
  81. IN PCHAR pch,
  82. IN PCHAR pchStop,
  83. IN WORD wClass,
  84. IN WORD wType
  85. )
  86. /*++
  87. Routine Description:
  88. No data RR cases:
  89. This includes prereqs and deletes except for specific record cases.
  90. Arguments:
  91. pch - ptr to next byte in packet buffer
  92. pchStop - end of packet buffer
  93. wClass - class
  94. wType - desired RR type
  95. Return Value:
  96. Ptr to next postion in buffer, if successful.
  97. NULL on error.
  98. --*/
  99. {
  100. PDNS_WIRE_RECORD pdnsRR;
  101. DNSDBG( WRITE, (
  102. "Writing update RR to packet buffer at %p.\n",
  103. pch ));
  104. //
  105. // out of space
  106. //
  107. pdnsRR = (PDNS_WIRE_RECORD) pch;
  108. pch += sizeof( DNS_WIRE_RECORD );
  109. if ( pch >= pchStop )
  110. {
  111. DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
  112. return( NULL );
  113. }
  114. //
  115. // set type and class
  116. //
  117. *(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
  118. *(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
  119. //
  120. // TTL and datalength zero for all no data cases
  121. // - prereqs except specific record delete
  122. // - deletes except specific record delete
  123. //
  124. *(UNALIGNED DWORD *) &pdnsRR->TimeToLive = 0;
  125. *(UNALIGNED WORD *) &pdnsRR->DataLength = 0;
  126. return( pch );
  127. }
  128. PCHAR
  129. Dns_WriteDataUpdateRecordToMessage(
  130. IN PCHAR pch,
  131. IN PCHAR pchStop,
  132. IN WORD wClass,
  133. IN WORD wType,
  134. IN DWORD dwTtl,
  135. IN WORD wDataLength
  136. )
  137. /*++
  138. Routine Description:
  139. No data RR cases:
  140. This includes prereqs and deletes except for specific record cases.
  141. Arguments:
  142. pch - ptr to next byte in packet buffer
  143. pchStop - end of packet buffer
  144. wClass - class
  145. wType - desired RR type
  146. dwTtl - time to live
  147. wDataLength - data length
  148. Return Value:
  149. Ptr to next postion in buffer, if successful.
  150. NULL on error.
  151. --*/
  152. {
  153. PDNS_WIRE_RECORD pdnsRR;
  154. DNSDBG( WRITE2, (
  155. "Writing RR to packet buffer at %p.\n",
  156. pch ));
  157. //
  158. // out of space
  159. //
  160. pdnsRR = (PDNS_WIRE_RECORD) pch;
  161. pch += sizeof( DNS_WIRE_RECORD );
  162. if ( pch + wDataLength >= pchStop )
  163. {
  164. DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
  165. return( NULL );
  166. }
  167. //
  168. // set type and class
  169. //
  170. *(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
  171. *(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
  172. //
  173. // TTL and datalength zero for all no data cases
  174. // - prereqs except specific record delete
  175. // - deletes except specific record delete
  176. //
  177. *(UNALIGNED DWORD *) &pdnsRR->TimeToLive = htonl( dwTtl );
  178. *(UNALIGNED WORD *) &pdnsRR->DataLength = htons( wDataLength );
  179. return( pch );
  180. }
  181. //
  182. // Host update routines
  183. //
  184. #if 0
  185. PDNS_MSG_BUF
  186. Dns_BuildHostUpdateMessage(
  187. IN OUT PDNS_MSG_BUF pMsg,
  188. IN LPSTR pszZone,
  189. IN LPSTR pszName,
  190. IN PIP_ARRAY aipAddresses,
  191. IN DWORD dwTtl
  192. )
  193. /*++
  194. Routine Description:
  195. Build server update message.
  196. Arguments:
  197. pMsg -- existing message buffer, to use; NULL to allocate new one
  198. pszZone -- zone name for update
  199. pszName -- full DNS hostname being updated
  200. aipAddresses -- IP addresses to be updated
  201. Return Value:
  202. ERROR_SUCCESS if successful.
  203. Error status on failure.
  204. --*/
  205. {
  206. PDNS_HEADER pdnsMsg;
  207. PCHAR pch;
  208. PCHAR pchstop;
  209. DWORD i;
  210. WORD nameOffset;
  211. IF_DNSDBG( UPDATE )
  212. {
  213. DNS_PRINT((
  214. "Enter Dns_BuildHostUpdateMessage()\n"
  215. "\tpMsg = %p\n"
  216. "\tpszZone = %s\n"
  217. "\tpszName = %s\n"
  218. "\tdwTtl = %d\n",
  219. pMsg,
  220. pszZone,
  221. pszName,
  222. dwTtl ));
  223. DnsDbg_IpArray(
  224. "\tHost IP array\n",
  225. "host",
  226. aipAddresses );
  227. }
  228. //
  229. // create message buffer
  230. //
  231. if ( !pMsg )
  232. {
  233. DNS_PRINT(( "Allocating new UPDATE message buffer.\n" ));
  234. pMsg = ALLOCATE_HEAP( DNS_UDP_ALLOC_LENGTH );
  235. if ( !pMsg )
  236. {
  237. return( NULL );
  238. }
  239. RtlZeroMemory(
  240. pMsg,
  241. DNS_UDP_ALLOC_LENGTH );
  242. pMsg->BufferLength = DNS_UDP_MAX_PACKET_LENGTH;
  243. pMsg->pBufferEnd = (PCHAR)&pMsg->MessageHead + pMsg->BufferLength;
  244. //
  245. // set default sockaddr info
  246. // - caller MUST choose remote IP address
  247. pMsg->RemoteAddress.sin_family = AF_INET;
  248. pMsg->RemoteAddress.sin_port = NET_ORDER_DNS_PORT;
  249. pMsg->RemoteAddressLength = sizeof( SOCKADDR_IN );
  250. // set header for update
  251. pMsg->MessageHead.Opcode = DNS_OPCODE_UPDATE;
  252. }
  253. //
  254. // existing message, just verify
  255. //
  256. ELSE_ASSERT( pMsg->MessageHead.Opcode == DNS_OPCODE_UPDATE );
  257. //
  258. // reset current pointer after header
  259. // - note: send length is set based on this ptr
  260. //
  261. pMsg->pCurrent = pMsg->MessageBody;
  262. //
  263. // build message
  264. //
  265. pch = pMsg->pCurrent;
  266. pchstop = pMsg->pBufferEnd;
  267. //
  268. // zone section
  269. //
  270. pMsg->MessageHead.QuestionCount = 1;
  271. pch = Dns_WriteDottedNameToPacket(
  272. pch,
  273. pchstop,
  274. pszZone,
  275. NULL,
  276. 0,
  277. FALSE );
  278. if ( !pch )
  279. {
  280. return( NULL );
  281. }
  282. *(UNALIGNED WORD *) pch = DNS_RTYPE_SOA;
  283. pch += sizeof(WORD);
  284. *(UNALIGNED WORD *) pch = DNS_RCLASS_INTERNET;
  285. pch += sizeof(WORD);
  286. //
  287. // prerequisites -- no records
  288. //
  289. pMsg->MessageHead.AnswerCount = 0;
  290. //
  291. // update
  292. // - delete A records at name
  293. // - add new A records
  294. //
  295. // save offset to host name for future writes
  296. nameOffset = (WORD)(pch - (PCHAR) &pMsg->MessageHead);
  297. pch = Dns_WriteDottedNameToPacket(
  298. pch,
  299. pchstop,
  300. pszName,
  301. pszZone,
  302. DNS_OFFSET_TO_QUESTION_NAME,
  303. FALSE );
  304. if ( !pch )
  305. {
  306. DNS_PRINT(( "ERROR writing dotted name to packet.\n" ));
  307. return( NULL );
  308. }
  309. pch = Dns_WriteNoDataUpdateRecordToMessage(
  310. pch,
  311. pchstop,
  312. DNS_CLASS_ALL, // delete all
  313. DNS_TYPE_A // A records
  314. );
  315. DNS_ASSERT( pch );
  316. //
  317. // add A record for each address in array
  318. // - use offset for name
  319. // - write IP
  320. for ( i=0; i<aipAddresses->AddrCount; i++ )
  321. {
  322. *(UNALIGNED WORD *) pch = htons( (WORD)(nameOffset|(WORD)0xC000) );
  323. pch += sizeof( WORD );
  324. pch = Dns_WriteDataUpdateRecordToMessage(
  325. pch,
  326. pchstop,
  327. DNS_CLASS_INTERNET,
  328. DNS_TYPE_A, // A records
  329. dwTtl,
  330. sizeof(IP_ADDRESS)
  331. );
  332. DNS_ASSERT( pch );
  333. *(UNALIGNED DWORD *) pch = aipAddresses->AddrArray[i];
  334. pch += sizeof(DWORD);
  335. }
  336. // total update sections RRs
  337. // one delete RR, plus one for each new IP
  338. pMsg->MessageHead.NameServerCount = (USHORT)(aipAddresses->AddrCount + 1);
  339. //
  340. // additional section - no records
  341. //
  342. pMsg->MessageHead.AdditionalCount = 0;
  343. //
  344. // reset current ptr -- need for send routine
  345. //
  346. pMsg->pCurrent = pch;
  347. IF_DNSDBG( SEND )
  348. {
  349. DnsDbg_Message(
  350. "UPDATE packet built",
  351. pMsg );
  352. }
  353. return( pMsg );
  354. }
  355. #endif
  356. PDNS_RECORD
  357. Dns_HostUpdateRRSet(
  358. IN LPSTR pszHostName,
  359. IN PIP_ARRAY AddrArray,
  360. IN DWORD dwTtl
  361. )
  362. /*++
  363. Routine Description:
  364. Create records for host update:
  365. -- whack of all A records
  366. -- add of all A records in new set
  367. Arguments:
  368. pszHostName -- host name, FULL FQDN
  369. AddrArray -- new IPs of host
  370. dwTtl -- TTL for records
  371. Return Value:
  372. Ptr to record list.
  373. NULL on error.
  374. --*/
  375. {
  376. DNS_RRSET rrset;
  377. PDNS_RECORD prr;
  378. DWORD i;
  379. //
  380. // create whack
  381. //
  382. prr = Dns_AllocateRecord( 0 );
  383. if ( ! prr )
  384. {
  385. return( NULL );
  386. }
  387. prr->pName = pszHostName;
  388. prr->wType = DNS_TYPE_A;
  389. prr->Flags.S.Section = DNSREC_UPDATE;
  390. prr->Flags.S.Delete = TRUE;
  391. //
  392. // create update record for each address
  393. //
  394. if ( !AddrArray )
  395. {
  396. return( prr );
  397. }
  398. DNS_RRSET_INIT( rrset );
  399. DNS_RRSET_ADD( rrset, prr );
  400. for ( i=0; i<AddrArray->AddrCount; i++ )
  401. {
  402. prr = Dns_AllocateRecord( sizeof(DNS_A_DATA) );
  403. if ( ! prr )
  404. {
  405. Dns_RecordListFree( rrset.pFirstRR );
  406. return( NULL );
  407. }
  408. prr->pName = pszHostName;
  409. prr->wType = DNS_TYPE_A;
  410. prr->Flags.S.Section = DNSREC_UPDATE;
  411. prr->dwTtl = dwTtl;
  412. prr->Data.A.IpAddress = AddrArray->AddrArray[i];
  413. DNS_RRSET_ADD( rrset, prr );
  414. }
  415. // return ptr to first record in list
  416. return( rrset.pFirstRR );
  417. }
  418. //
  419. // DCR: dead code, remove
  420. //
  421. DNS_STATUS
  422. Dns_UpdateHostAddrs(
  423. IN LPSTR pszName,
  424. IN PIP_ARRAY aipAddresses,
  425. IN PIP_ARRAY aipServers,
  426. IN DWORD dwTtl
  427. )
  428. /*++
  429. Routine Description:
  430. Updates client's A records registered with DNS server.
  431. Arguments:
  432. pszName -- name (FQDN) of client to update
  433. aipAddresses -- counted array of new client IP addrs
  434. aipServers -- counted array of DNS server IP addrs
  435. dwTtl -- TTL for new A records
  436. Return Value:
  437. ERROR_SUCCESS if successful.
  438. Error status on failure.
  439. --*/
  440. {
  441. PDNS_RECORD prr;
  442. DNS_STATUS status;
  443. IF_DNSDBG( UPDATE )
  444. {
  445. DNS_PRINT((
  446. "Enter Dns_UpdateHostAddrs()\n"
  447. "\tpszName = %s\n"
  448. "\tdwTtl = %d\n",
  449. pszName,
  450. dwTtl ));
  451. DnsDbg_IpArray(
  452. "\tHost IP array\n",
  453. "\tHost",
  454. aipAddresses );
  455. DnsDbg_IpArray(
  456. "\tNS IP array\n",
  457. "\tNS",
  458. aipServers );
  459. }
  460. //
  461. // never let anyone set a TTL longer than 1 hour
  462. //
  463. // DCR: define policy on what our clients should use for TTL
  464. // one hour is not bad
  465. // could key off type of address
  466. // RAS -- 15 minutes (as may be back up again quickly)
  467. // DHCP -- one hour (may move)
  468. // static -- one day (machines may be reconfigured)
  469. //
  470. if ( dwTtl > 3600 )
  471. {
  472. dwTtl = 3600;
  473. }
  474. //
  475. // build update RR set
  476. //
  477. prr = Dns_HostUpdateRRSet(
  478. pszName,
  479. aipAddresses,
  480. dwTtl );
  481. if ( ! prr )
  482. {
  483. status = GetLastError();
  484. DNS_ASSERT( status == DNS_ERROR_NO_MEMORY );
  485. return status;
  486. }
  487. //
  488. // do the update
  489. //
  490. status = Dns_UpdateLib(
  491. prr,
  492. 0, // no flags
  493. NULL, // no adapter list
  494. NULL, // use default credentials
  495. NULL // response not desired
  496. );
  497. Dns_RecordListFree( prr );
  498. DNSDBG( UPDATE, (
  499. "Leave Dns_UpdateHostAddrs() status=%d %s\n",
  500. status,
  501. Dns_StatusString(status) ));
  502. return( status );
  503. }
  504. DNS_STATUS
  505. Dns_UpdateLib(
  506. IN PDNS_RECORD pRecord,
  507. IN DWORD dwFlags,
  508. IN PDNS_NETINFO pNetworkInfo,
  509. IN HANDLE hCreds OPTIONAL,
  510. OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
  511. )
  512. /*++
  513. Routine Description:
  514. Send DNS update.
  515. Arguments:
  516. pRecord -- list of records to send in update
  517. dwFlags -- update flags; primarily security
  518. pNetworkInfo -- adapter list with necessary info for update
  519. - zone name
  520. - primary name server name
  521. - primary name server IP
  522. hCreds -- credentials handle returned from
  523. ppMsgRecv -- OPTIONAL addr to recv ptr to response message
  524. Return Value:
  525. ERROR_SUCCESS if successful.
  526. Error status on failure.
  527. --*/
  528. {
  529. PDNS_MSG_BUF pmsgSend = NULL;
  530. PDNS_MSG_BUF pmsgRecv = NULL;
  531. DNS_STATUS status = NO_ERROR;
  532. WORD length;
  533. PIP_ARRAY parrayServers = NULL;
  534. LPSTR pszzone;
  535. LPSTR pszserverName;
  536. BOOL fsecure = FALSE;
  537. BOOL fswitchToTcp = FALSE;
  538. DNS_HEADER header;
  539. PCHAR pCreds=NULL;
  540. DNSDBG( UPDATE, (
  541. "Dns_UpdateLib()\n"
  542. "\tflags = %08x\n"
  543. "\tpRecord = %p\n"
  544. "\t\towner = %s\n",
  545. dwFlags,
  546. pRecord,
  547. pRecord ? pRecord->pName : NULL ));
  548. //
  549. // if not a UPDATE compatibile adapter list -- no action
  550. //
  551. if ( ! NetInfo_IsForUpdate(pNetworkInfo) )
  552. {
  553. return( ERROR_INVALID_PARAMETER );
  554. }
  555. //
  556. // suck info from adapter list
  557. //
  558. pszzone = NetInfo_UpdateZoneName( pNetworkInfo );
  559. parrayServers = NetInfo_ConvertToIpArray( pNetworkInfo );
  560. pszserverName = NetInfo_UpdateServerName( pNetworkInfo );
  561. DNS_ASSERT( pszzone && parrayServers );
  562. //
  563. // build recv message buffer
  564. // - must be big enough for TCP
  565. //
  566. pmsgRecv = Dns_AllocateMsgBuf( DNS_TCP_DEFAULT_PACKET_LENGTH );
  567. if ( !pmsgRecv )
  568. {
  569. status = DNS_ERROR_NO_MEMORY;
  570. goto Cleanup;
  571. }
  572. //
  573. // build update packet
  574. // note currently this function allocates TCP sized buffer if records
  575. // given; if this changes need to alloc TCP buffer here
  576. //
  577. CLEAR_DNS_HEADER_FLAGS_AND_XID( &header );
  578. header.Opcode = DNS_OPCODE_UPDATE;
  579. pmsgSend = Dns_BuildPacket(
  580. &header, // copy header
  581. TRUE, // ... but not header counts
  582. pszzone, // question zone\type SOA
  583. DNS_TYPE_SOA,
  584. pRecord,
  585. 0, // no other flags
  586. TRUE // building an update packet
  587. );
  588. if ( !pmsgSend)
  589. {
  590. DNS_PRINT(( "ERROR: failed send buffer allocation.\n" ));
  591. status = DNS_ERROR_NO_MEMORY;
  592. goto Cleanup;
  593. }
  594. //
  595. // try non-secure first unless explicitly secure only
  596. //
  597. fsecure = (dwFlags & DNS_UPDATE_SECURITY_ONLY);
  598. if ( !fsecure )
  599. {
  600. status = Dns_SendAndRecv(
  601. pmsgSend,
  602. & pmsgRecv,
  603. NULL, // no response records
  604. dwFlags,
  605. parrayServers,
  606. pNetworkInfo );
  607. if ( status == ERROR_SUCCESS )
  608. {
  609. status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
  610. }
  611. if ( status != DNS_ERROR_RCODE_REFUSED ||
  612. dwFlags & DNS_UPDATE_SECURITY_OFF )
  613. {
  614. goto Cleanup;
  615. }
  616. DNSDBG( UPDATE, (
  617. "Failed unsecure update, switching to secure!\n"
  618. "\tcurrent time (ms) = %d\n",
  619. GetCurrentTime() ));
  620. fsecure = TRUE;
  621. }
  622. //
  623. // security
  624. // - must have server name
  625. // - must start package
  626. //
  627. if ( fsecure )
  628. {
  629. if ( !pszserverName )
  630. {
  631. status = ERROR_INVALID_PARAMETER;
  632. goto Cleanup;
  633. }
  634. status = Dns_StartSecurity( FALSE );
  635. if ( status != ERROR_SUCCESS )
  636. {
  637. goto Cleanup;
  638. }
  639. //
  640. // DCR: hCreds doesn't return security context
  641. // - idea of something beyond just standard security
  642. // credentials was we'd been able to return the context
  643. // handle
  644. //
  645. pCreds = Dns_GetApiContextCredentials(hCreds);
  646. status = Dns_DoSecureUpdate(
  647. pmsgSend,
  648. pmsgRecv,
  649. NULL,
  650. dwFlags,
  651. pNetworkInfo,
  652. parrayServers,
  653. pszserverName,
  654. pCreds, // initialized in DnsAcquireContextHandle
  655. NULL // default context name
  656. );
  657. if ( status == ERROR_SUCCESS )
  658. {
  659. status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
  660. }
  661. }
  662. Cleanup:
  663. // free server array sucked from adapter list
  664. if ( parrayServers )
  665. {
  666. FREE_HEAP( parrayServers );
  667. }
  668. // return recv message buffer
  669. if ( ppMsgRecv )
  670. {
  671. *ppMsgRecv = pmsgRecv;
  672. }
  673. else
  674. {
  675. FREE_HEAP( pmsgRecv );
  676. }
  677. FREE_HEAP( pmsgSend);
  678. DNSDBG( UPDATE, (
  679. "Dns_UpdateLib() completed, status = %d %s.\n\n",
  680. status,
  681. Dns_StatusString(status) ));
  682. return( status );
  683. }
  684. DNS_STATUS
  685. Dns_UpdateLibEx(
  686. IN PDNS_RECORD pRecord,
  687. IN DWORD dwFlags,
  688. IN PDNS_NAME pszZone,
  689. IN PDNS_NAME pszServerName,
  690. IN PIP_ARRAY aipServers,
  691. IN HANDLE hCreds OPTIONAL,
  692. OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
  693. )
  694. /*++
  695. Routine Description:
  696. Send DNS update.
  697. This routine builds an UPDATE compatible pNetworkInfo from the
  698. information given. Then calls Dns_Update().
  699. Arguments:
  700. pRecord -- list of records to send in update
  701. pszZone -- zone name for update
  702. pszServerName -- server name
  703. aipServers -- DNS servers to send update to
  704. hCreds -- Optional Credentials info
  705. ppMsgRecv -- addr for ptr to recv buffer, if desired
  706. Return Value:
  707. ERROR_SUCCESS if successful.
  708. Error status on failure.
  709. --*/
  710. {
  711. PDNS_NETINFO pnetInfo;
  712. DNS_STATUS status = NO_ERROR;
  713. DNSDBG( UPDATE, ( "Dns_UpdateLibEx()\n" ));
  714. //
  715. // convert params into UPDATE compatible adapter list
  716. //
  717. pnetInfo = NetInfo_CreateForUpdate(
  718. pszZone,
  719. pszServerName,
  720. aipServers,
  721. 0 );
  722. if ( !pnetInfo )
  723. {
  724. return( ERROR_INVALID_PARAMETER );
  725. }
  726. //
  727. // call real update function
  728. //
  729. status = Dns_UpdateLib(
  730. pRecord,
  731. dwFlags,
  732. pnetInfo,
  733. hCreds,
  734. ppMsgRecv );
  735. NetInfo_Free( pnetInfo );
  736. return status;
  737. }
  738. //
  739. // Update credentials
  740. //
  741. //
  742. // Credentials are an optional future parameter to allow the caller
  743. // to set the context handle to that of a given NT account. This
  744. // structure will most likely be the following as defined in rpcdce.h:
  745. //
  746. // #define SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
  747. //
  748. // typedef struct _SEC_WINNT_AUTH_IDENTITY_A {
  749. // unsigned char __RPC_FAR *User;
  750. // unsigned long UserLength;
  751. // unsigned char __RPC_FAR *Domain;
  752. // unsigned long DomainLength;
  753. // unsigned char __RPC_FAR *Password;
  754. // unsigned long PasswordLength;
  755. // unsigned long Flags;
  756. // } SEC_WINNT_AUTH_IDENTITY_A, *PSEC_WINNT_AUTH_IDENTITY_A;
  757. //
  758. // #define SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2
  759. //
  760. // typedef struct _SEC_WINNT_AUTH_IDENTITY_W {
  761. // unsigned short __RPC_FAR *User;
  762. // unsigned long UserLength;
  763. // unsigned short __RPC_FAR *Domain;
  764. // unsigned long DomainLength;
  765. // unsigned short __RPC_FAR *Password;
  766. // unsigned long PasswordLength;
  767. // unsigned long Flags;
  768. // } SEC_WINNT_AUTH_IDENTITY_W, *PSEC_WINNT_AUTH_IDENTITY_W;
  769. //
  770. DNS_STATUS
  771. WINAPI
  772. DnsAcquireContextHandle_W(
  773. IN DWORD CredentialFlags,
  774. IN PVOID Credentials OPTIONAL,
  775. OUT PHANDLE pContext
  776. )
  777. /*++
  778. Routine Description:
  779. Get credentials handle to security context for update.
  780. The handle can for the default process credentials (user account or
  781. system machine account) or for a specified set of credentials
  782. identified by Credentials.
  783. Arguments:
  784. CredentialFlags -- flags
  785. Credentials -- a PSEC_WINNT_AUTH_IDENTITY_W
  786. (explicit definition skipped to avoid requiring rpcdec.h)
  787. pContext -- addr to receive credentials handle
  788. Return Value:
  789. ERROR_SUCCESS if successful.
  790. ErrorCode on failure.
  791. --*/
  792. {
  793. if ( ! pContext )
  794. {
  795. return ERROR_INVALID_PARAMETER;
  796. }
  797. *pContext = Dns_CreateAPIContext(
  798. CredentialFlags,
  799. Credentials,
  800. TRUE // unicode
  801. );
  802. if ( ! *pContext )
  803. {
  804. return DNS_ERROR_NO_MEMORY;
  805. }
  806. else
  807. {
  808. return NO_ERROR;
  809. }
  810. }
  811. DNS_STATUS
  812. WINAPI
  813. DnsAcquireContextHandle_A(
  814. IN DWORD CredentialFlags,
  815. IN PVOID Credentials OPTIONAL,
  816. OUT PHANDLE pContext
  817. )
  818. /*++
  819. Routine Description:
  820. Get credentials handle to security context for update.
  821. The handle can for the default process credentials (user account or
  822. system machine account) or for a specified set of credentials
  823. identified by Credentials.
  824. Arguments:
  825. CredentialFlags -- flags
  826. Credentials -- a PSEC_WINNT_AUTH_IDENTITY_A
  827. (explicit definition skipped to avoid requiring rpcdec.h)
  828. pContext -- addr to receive credentials handle
  829. Return Value:
  830. ERROR_SUCCESS if successful.
  831. ErrorCode on failure.
  832. --*/
  833. {
  834. if ( ! pContext )
  835. {
  836. return ERROR_INVALID_PARAMETER;
  837. }
  838. *pContext = Dns_CreateAPIContext(
  839. CredentialFlags,
  840. Credentials,
  841. FALSE );
  842. if ( ! *pContext )
  843. {
  844. return DNS_ERROR_NO_MEMORY;
  845. }
  846. else
  847. {
  848. return NO_ERROR;
  849. }
  850. }
  851. VOID
  852. WINAPI
  853. DnsReleaseContextHandle(
  854. IN HANDLE ContextHandle
  855. )
  856. /*++
  857. Routine Description:
  858. Frees context handle created by DnsAcquireContextHandle_X() routines.
  859. Arguments:
  860. ContextHandle - Handle to be closed.
  861. Return Value:
  862. None.
  863. --*/
  864. {
  865. if ( ContextHandle )
  866. {
  867. //
  868. // free any cached security context handles
  869. //
  870. // DCR_FIX0: should delete all contexts associated with this
  871. // context (credentials handle) not all
  872. //
  873. // DCR: to be robust, user "ContextHandle" should be ref counted
  874. // it should be set one on create; when in use, incremented
  875. // then dec when done; then this Free could not collide with
  876. // another thread's use
  877. //
  878. //Dns_TimeoutSecurityContextListEx( TRUE, ContextHandle );
  879. Dns_TimeoutSecurityContextList( TRUE );
  880. Dns_FreeAPIContext( ContextHandle );
  881. }
  882. }
  883. //
  884. // Utilities
  885. //
  886. DWORD
  887. prepareUpdateRecordSet(
  888. IN OUT PDNS_RECORD pRRSet,
  889. IN BOOL fClearTtl,
  890. IN BOOL fSetFlags,
  891. IN WORD wFlags
  892. )
  893. /*++
  894. Routine Description:
  895. Validate and prepare record set for update.
  896. - record set is single RR set
  897. - sets record flags for update
  898. Arguments:
  899. pRRSet -- record set; MUST be in UTF8
  900. note: pRRSet is not touched (not OUT param)
  901. IF fClearTtl AND fSetFlags are both FALSE
  902. fClearTtl -- clear TTL in records; TRUE for delete set
  903. fSetFlags -- set section and delete flags
  904. wFlags -- flags field to set
  905. (should contain desired section and delete flags)
  906. Return Value:
  907. ERROR_SUCCESS if successful.
  908. ERROR_INVALID_PARAMETER if record set is not acceptable.
  909. --*/
  910. {
  911. PDNS_RECORD prr;
  912. PSTR pname;
  913. WORD type;
  914. DNSDBG( TRACE, ( "prepareUpdateRecordSet()\n" ));
  915. // validate
  916. if ( !pRRSet )
  917. {
  918. return ERROR_INVALID_PARAMETER;
  919. }
  920. type = pRRSet->wType;
  921. //
  922. // note: could do an "update-type" check here, but that just
  923. // A) burns unnecessary memory and cycles
  924. // B) makes it harder to test bogus records sent in updates
  925. // to the server
  926. //
  927. pname = (PSTR) pRRSet->pName;
  928. if ( !pname )
  929. {
  930. return ERROR_INVALID_PARAMETER;
  931. }
  932. //
  933. // check each RR in set
  934. // - validate RR is in set
  935. // - set RR flags
  936. //
  937. prr = pRRSet;
  938. while ( prr )
  939. {
  940. if ( fSetFlags )
  941. {
  942. prr->Flags.S.Section = 0;
  943. prr->Flags.S.Delete = 0;
  944. prr->Flags.DW |= wFlags;
  945. }
  946. if ( fClearTtl )
  947. {
  948. prr->dwTtl = 0;
  949. }
  950. // check current RR in set
  951. // - matches name and type
  952. if ( prr != pRRSet )
  953. {
  954. if ( prr->wType != type ||
  955. ! prr->pName ||
  956. ! Dns_NameCompare_UTF8( pname, prr->pName ) )
  957. {
  958. return ERROR_INVALID_PARAMETER;
  959. }
  960. }
  961. prr = prr->pNext;
  962. }
  963. return ERROR_SUCCESS;
  964. }
  965. PDNS_RECORD
  966. DnsBuildUpdateSet(
  967. IN OUT PDNS_RECORD pPrereqSet,
  968. IN OUT PDNS_RECORD pAddSet,
  969. IN OUT PDNS_RECORD pDeleteSet
  970. )
  971. /*++
  972. Routine Description:
  973. Build combined record list for update.
  974. Combines prereq, delete and add records.
  975. Note: record sets MUST be in UTF8.
  976. Arguments:
  977. pPrereqSet -- prerequisite records; note this does NOT
  978. include delete preqs (see note below)
  979. pAddSet -- records to add
  980. pDeleteSet -- records to delete
  981. Return Value:
  982. Ptr to combined record list for update.
  983. --*/
  984. {
  985. PDNS_RECORD plast = NULL;
  986. PDNS_RECORD pfirst = NULL;
  987. DNSDBG( TRACE, ( "DnsBuildUpdateSet()\n" ));
  988. //
  989. // append prereq set
  990. //
  991. // DCR: doesn't handle delete prereqs
  992. // this is fine because we roll our own, but if
  993. // later expand the function, then need them
  994. //
  995. // note, I could add flag==PREREQ datalength==0
  996. // test in prepareUpdateRecordSet() function, then
  997. // set Delete flag; however, we'd still have the
  998. // question of how to distinguish existence (class==ANY)
  999. // prereq from delete (class==NONE) prereq -- without
  1000. // directly exposing the record Delete flag
  1001. //
  1002. if ( pPrereqSet )
  1003. {
  1004. plast = pPrereqSet;
  1005. pfirst = pPrereqSet;
  1006. prepareUpdateRecordSet(
  1007. pPrereqSet,
  1008. FALSE, // no TTL clear
  1009. TRUE, // set flags
  1010. DNSREC_PREREQ // prereq section
  1011. );
  1012. while ( plast->pNext )
  1013. {
  1014. plast = plast->pNext;
  1015. }
  1016. }
  1017. //
  1018. // append delete records
  1019. // do before Add records so that delete\add of same record
  1020. // leaves it in place
  1021. //
  1022. if ( pDeleteSet )
  1023. {
  1024. if ( !plast )
  1025. {
  1026. plast = pDeleteSet;
  1027. pfirst = pDeleteSet;
  1028. }
  1029. else
  1030. {
  1031. plast->pNext = pDeleteSet;
  1032. }
  1033. prepareUpdateRecordSet(
  1034. pDeleteSet,
  1035. TRUE, // clear TTL
  1036. TRUE, // set flags
  1037. DNSREC_UPDATE | DNSREC_DELETE // update section, delete bit
  1038. );
  1039. while ( plast->pNext )
  1040. {
  1041. plast = plast->pNext;
  1042. }
  1043. }
  1044. //
  1045. // append add records
  1046. //
  1047. if ( pAddSet )
  1048. {
  1049. if ( !plast )
  1050. {
  1051. plast = pAddSet;
  1052. pfirst = pAddSet;
  1053. }
  1054. else
  1055. {
  1056. plast->pNext = pAddSet;
  1057. }
  1058. prepareUpdateRecordSet(
  1059. pAddSet,
  1060. FALSE, // no TTL change
  1061. TRUE, // set flags
  1062. DNSREC_UPDATE // update section
  1063. );
  1064. }
  1065. return pfirst;
  1066. }
  1067. BOOL
  1068. IsPtrUpdate(
  1069. IN PDNS_RECORD pRecordList
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. Check if update is PTR update.
  1074. Arguments:
  1075. pRecordList -- update record list
  1076. Return Value:
  1077. TRUE if PTR update.
  1078. FALSE otherwise.
  1079. --*/
  1080. {
  1081. PDNS_RECORD prr = pRecordList;
  1082. BOOL bptrUpdate = FALSE;
  1083. //
  1084. // find, then test first record in update section
  1085. //
  1086. while ( prr )
  1087. {
  1088. if ( prr->Flags.S.Section == DNSREC_UPDATE )
  1089. {
  1090. if ( prr->wType == DNS_TYPE_PTR )
  1091. {
  1092. bptrUpdate = TRUE;
  1093. }
  1094. break;
  1095. }
  1096. prr = prr->pNext;
  1097. }
  1098. return bptrUpdate;
  1099. }
  1100. //
  1101. // Replace functions
  1102. //
  1103. DNS_STATUS
  1104. WINAPI
  1105. replaceRecordsInSetPrivate(
  1106. IN PDNS_RECORD pReplaceSet,
  1107. IN DWORD Options,
  1108. IN HANDLE hCredentials, OPTIONAL
  1109. IN PIP_ARRAY pServerList, OPTIONAL
  1110. IN PVOID pReserved,
  1111. IN DNS_CHARSET CharSet
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Replace record set routine handling all character sets.
  1116. Arguments:
  1117. pReplaceSet - replacement record set
  1118. Options - update options
  1119. pServerList - list of DNS servers to go to; if not given, machines
  1120. default servers are queried to find correct servers to send update to
  1121. hCredentials - handle to credentials to be used for update; optional,
  1122. if not given security credentials of this process are used in update
  1123. pReserved - reserved; should be NULL
  1124. CharSet - character set of incoming records
  1125. Return Value:
  1126. ERROR_SUCCESS if update successful.
  1127. ErrorCode from server if server rejects update.
  1128. ERROR_INVALID_PARAMETER if bad param.
  1129. --*/
  1130. {
  1131. DNS_STATUS status;
  1132. PDNS_RECORD preplaceCopy = NULL;
  1133. PDNS_RECORD pupdateList = NULL;
  1134. BOOL btypeDelete;
  1135. DNS_RECORD rrNoCname;
  1136. DNS_RECORD rrDeleteType;
  1137. BOOL fcnameUpdate;
  1138. DNSDBG( TRACE, (
  1139. "replaceRecordsInSetPrivate()\n"
  1140. "\tpReplaceSet = %p\n"
  1141. "\tOptions = %08x\n"
  1142. "\thCredentials = %p\n"
  1143. "\tpServerList = %p\n"
  1144. "\tCharSet = %d\n",
  1145. pReplaceSet,
  1146. Options,
  1147. hCredentials,
  1148. pServerList,
  1149. CharSet
  1150. ));
  1151. //
  1152. // read update config
  1153. //
  1154. Reg_RefreshUpdateConfig();
  1155. //
  1156. // make local copy in UTF8
  1157. //
  1158. if ( !pReplaceSet )
  1159. {
  1160. return ERROR_INVALID_PARAMETER;
  1161. }
  1162. preplaceCopy = Dns_RecordSetCopyEx(
  1163. pReplaceSet,
  1164. CharSet,
  1165. DnsCharSetUtf8 );
  1166. if ( !preplaceCopy )
  1167. {
  1168. return ERROR_INVALID_PARAMETER;
  1169. }
  1170. //
  1171. // validate arguments
  1172. // - must have single RR set
  1173. // - mark them for update
  1174. //
  1175. status = prepareUpdateRecordSet(
  1176. preplaceCopy,
  1177. FALSE, // no TTL clear
  1178. TRUE, // set flags
  1179. DNSREC_UPDATE // flag as update
  1180. );
  1181. if ( status != ERROR_SUCCESS )
  1182. {
  1183. status = ERROR_INVALID_PARAMETER;
  1184. goto Cleanup;
  1185. }
  1186. //
  1187. // check if simple type delete
  1188. //
  1189. btypeDelete = ( preplaceCopy->wDataLength == 0 &&
  1190. preplaceCopy->pNext == NULL );
  1191. //
  1192. // set security for update
  1193. //
  1194. if ( UseSystemDefaultForSecurity( Options ) )
  1195. {
  1196. Options |= g_UpdateSecurityLevel;
  1197. }
  1198. if ( hCredentials )
  1199. {
  1200. Options |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
  1201. }
  1202. //
  1203. // type delete record
  1204. //
  1205. // if have replace records -- this goes in front
  1206. // if type delete -- then ONLY need this record
  1207. //
  1208. RtlZeroMemory( &rrDeleteType, sizeof(DNS_RECORD) );
  1209. rrDeleteType.pName = (PDNS_NAME) preplaceCopy->pName;
  1210. rrDeleteType.wType = preplaceCopy->wType;
  1211. rrDeleteType.wDataLength = 0;
  1212. rrDeleteType.Flags.DW = DNSREC_UPDATE | DNSREC_DELETE;
  1213. if ( btypeDelete )
  1214. {
  1215. rrDeleteType.pNext = NULL;
  1216. }
  1217. else
  1218. {
  1219. rrDeleteType.pNext = preplaceCopy;
  1220. }
  1221. pupdateList = &rrDeleteType;
  1222. //
  1223. // CNAME does not exist precondition record
  1224. // - for all updates EXCEPT CNAME
  1225. //
  1226. fcnameUpdate = ( preplaceCopy->wType == DNS_TYPE_CNAME );
  1227. if ( !fcnameUpdate )
  1228. {
  1229. RtlZeroMemory( &rrNoCname, sizeof(DNS_RECORD) );
  1230. rrNoCname.pName = (PDNS_NAME) preplaceCopy->pName;
  1231. rrNoCname.wType = DNS_TYPE_CNAME;
  1232. rrNoCname.wDataLength = 0;
  1233. rrNoCname.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  1234. rrNoCname.pNext = &rrDeleteType;
  1235. pupdateList = &rrNoCname;
  1236. }
  1237. //
  1238. // do the update
  1239. //
  1240. status = DoQuickUpdate(
  1241. pupdateList,
  1242. Options,
  1243. FALSE,
  1244. pServerList,
  1245. hCredentials);
  1246. if ( status == NO_ERROR )
  1247. {
  1248. DnsFlushResolverCacheEntry_UTF8( (LPSTR) preplaceCopy->pName );
  1249. }
  1250. //
  1251. // CNAME collision test
  1252. //
  1253. // if replacing CNAME may have gotten silent ignore
  1254. // - first check if successfully replaced CNAME
  1255. // - if still not sure, check that no other records
  1256. // at name -- if NON-CNAME found then treat silent ignore
  1257. // as YXRRSET error
  1258. //
  1259. if ( fcnameUpdate &&
  1260. ! btypeDelete &&
  1261. status == NO_ERROR )
  1262. {
  1263. PDNS_RECORD pqueryRR = NULL;
  1264. BOOL fsuccess = FALSE;
  1265. // DCR: need to query update server list here to
  1266. // avoid intermediate caching
  1267. status = DnsQuery_UTF8(
  1268. preplaceCopy->pName,
  1269. DNS_TYPE_CNAME,
  1270. DNS_QUERY_BYPASS_CACHE,
  1271. pServerList,
  1272. & pqueryRR,
  1273. NULL );
  1274. if ( status == NO_ERROR &&
  1275. Dns_RecordCompare(
  1276. preplaceCopy,
  1277. pqueryRR ) )
  1278. {
  1279. fsuccess = TRUE;
  1280. }
  1281. Dns_RecordListFree( pqueryRR );
  1282. if ( fsuccess )
  1283. {
  1284. goto Cleanup;
  1285. }
  1286. // query for any type at CNAME
  1287. // if found then assume we got a silent update
  1288. // success
  1289. status = DnsQuery_UTF8(
  1290. preplaceCopy->pName,
  1291. DNS_TYPE_ALL,
  1292. DNS_QUERY_BYPASS_CACHE,
  1293. pServerList,
  1294. & pqueryRR,
  1295. NULL );
  1296. if ( status == ERROR_SUCCESS )
  1297. {
  1298. PDNS_RECORD prr = pqueryRR;
  1299. while ( prr )
  1300. {
  1301. if ( pReplaceSet->wType != prr->wType &&
  1302. Dns_NameCompare_UTF8(
  1303. preplaceCopy->pName,
  1304. prr->pName ) )
  1305. {
  1306. status = DNS_ERROR_RCODE_YXRRSET;
  1307. break;
  1308. }
  1309. prr = prr->pNext;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. status = ERROR_SUCCESS;
  1315. }
  1316. Dns_RecordListFree( pqueryRR );
  1317. }
  1318. Cleanup:
  1319. Dns_RecordListFree( preplaceCopy );
  1320. return status;
  1321. }
  1322. DNS_STATUS
  1323. WINAPI
  1324. DnsReplaceRecordSetUTF8(
  1325. IN PDNS_RECORD pReplaceSet,
  1326. IN DWORD Options,
  1327. IN HANDLE hCredentials OPTIONAL,
  1328. IN PIP_ARRAY aipServers OPTIONAL,
  1329. IN PVOID pReserved
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. Dynamic update routine to replace record set on DNS server.
  1334. Arguments:
  1335. pReplaceSet - new record set for name and type
  1336. Options - update options
  1337. pServerList - list of DNS servers to go to; if not given, machines
  1338. default servers are queried to find correct servers to send update to
  1339. hCredentials - handle to credentials to be used for update; optional,
  1340. if not given securit5y credentials of this process are used in update
  1341. pReserved - reserved; should be NULL
  1342. Return Value:
  1343. None.
  1344. --*/
  1345. {
  1346. DNSDBG( TRACE, ( "DnsReplaceRecordSetUTF8()\n" ));
  1347. return replaceRecordsInSetPrivate(
  1348. pReplaceSet,
  1349. Options,
  1350. hCredentials,
  1351. aipServers,
  1352. pReserved,
  1353. DnsCharSetUtf8
  1354. );
  1355. }
  1356. DNS_STATUS
  1357. WINAPI
  1358. DnsReplaceRecordSetW(
  1359. IN PDNS_RECORD pReplaceSet,
  1360. IN DWORD Options,
  1361. IN HANDLE hCredentials OPTIONAL,
  1362. IN PIP_ARRAY aipServers OPTIONAL,
  1363. IN PVOID pReserved
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. Dynamic update routine to replace record set on DNS server.
  1368. Arguments:
  1369. pReplaceSet - new record set for name and type
  1370. Options - update options
  1371. pServerList - list of DNS servers to go to; if not given, machines
  1372. default servers are queried to find correct servers to send update to
  1373. hCredentials - handle to credentials to be used for update; optional,
  1374. if not given security credentials of this process are used in update
  1375. pReserved - reserved; should be NULL
  1376. Return Value:
  1377. None.
  1378. --*/
  1379. {
  1380. DNSDBG( TRACE, ( "DnsReplaceRecordSetW()\n" ));
  1381. return replaceRecordsInSetPrivate(
  1382. pReplaceSet,
  1383. Options,
  1384. hCredentials,
  1385. aipServers,
  1386. pReserved,
  1387. DnsCharSetUnicode
  1388. );
  1389. }
  1390. DNS_STATUS
  1391. WINAPI
  1392. DnsReplaceRecordSetA(
  1393. IN PDNS_RECORD pReplaceSet,
  1394. IN DWORD Options,
  1395. IN HANDLE hCredentials OPTIONAL,
  1396. IN PIP_ARRAY aipServers OPTIONAL,
  1397. IN PVOID pReserved
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. Dynamic update routine to replace record set on DNS server.
  1402. Arguments:
  1403. pReplaceSet - new record set for name and type
  1404. Options - update options
  1405. pServerList - list of DNS servers to go to; if not given, machines
  1406. default servers are queried to find correct servers to send update to
  1407. hCredentials - handle to credentials to be used for update; optional,
  1408. if not given security credentials of this process are used in update
  1409. pReserved - reserved; should be NULL
  1410. Return Value:
  1411. None.
  1412. --*/
  1413. {
  1414. DNSDBG( TRACE, ( "DnsReplaceRecordSetA()\n" ));
  1415. return replaceRecordsInSetPrivate(
  1416. pReplaceSet,
  1417. Options,
  1418. hCredentials,
  1419. aipServers,
  1420. pReserved,
  1421. DnsCharSetAnsi
  1422. );
  1423. }
  1424. //
  1425. // Modify functions
  1426. //
  1427. DNS_STATUS
  1428. WINAPI
  1429. modifyRecordsInSetPrivate(
  1430. IN PDNS_RECORD pAddRecords,
  1431. IN PDNS_RECORD pDeleteRecords,
  1432. IN DWORD Options,
  1433. IN HANDLE hCredentials, OPTIONAL
  1434. IN PIP_ARRAY pServerList, OPTIONAL
  1435. IN PVOID pReserved,
  1436. IN DNS_CHARSET CharSet
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Dynamic update routine to replace record set on DNS server.
  1441. Arguments:
  1442. pAddRecords - records to register on server
  1443. pDeleteRecords - records to remove from server
  1444. Options - update options
  1445. pServerList - list of DNS servers to go to; if not given, machines
  1446. default servers are queried to find correct servers to send update to
  1447. hCredentials - handle to credentials to be used for update; optional,
  1448. if not given security credentials of this process are used in update
  1449. pReserved - reserved; should be NULL
  1450. CharSet - character set of incoming records
  1451. Return Value:
  1452. ERROR_SUCCESS if update successful.
  1453. ErrorCode from server if server rejects update.
  1454. ERROR_INVALID_PARAMETER if bad param.
  1455. --*/
  1456. {
  1457. DNS_STATUS status;
  1458. PDNS_RECORD paddCopy = NULL;
  1459. PDNS_RECORD pdeleteCopy = NULL;
  1460. PDNS_RECORD pupdateSet = NULL;
  1461. DNSDBG( TRACE, (
  1462. "modifyRecordsInSetPrivate()\n"
  1463. "\tpAddSet = %p\n"
  1464. "\tpDeleteSet = %p\n"
  1465. "\tOptions = %08x\n"
  1466. "\thCredentials = %p\n"
  1467. "\tpServerList = %p\n"
  1468. "\tCharSet = %d\n",
  1469. pAddRecords,
  1470. pDeleteRecords,
  1471. Options,
  1472. hCredentials,
  1473. pServerList,
  1474. CharSet
  1475. ));
  1476. //
  1477. // read update config
  1478. //
  1479. Reg_RefreshUpdateConfig();
  1480. //
  1481. // make local copy in UTF8
  1482. //
  1483. if ( pAddRecords )
  1484. {
  1485. paddCopy = Dns_RecordSetCopyEx(
  1486. pAddRecords,
  1487. CharSet,
  1488. DnsCharSetUtf8 );
  1489. }
  1490. if ( pDeleteRecords )
  1491. {
  1492. pdeleteCopy = Dns_RecordSetCopyEx(
  1493. pDeleteRecords,
  1494. CharSet,
  1495. DnsCharSetUtf8 );
  1496. }
  1497. //
  1498. // validate arguments
  1499. // - add and delete must be for single RR set
  1500. // and must be for same RR set
  1501. //
  1502. if ( !paddCopy && !pdeleteCopy )
  1503. {
  1504. return ERROR_INVALID_PARAMETER;
  1505. }
  1506. if ( paddCopy )
  1507. {
  1508. status = prepareUpdateRecordSet(
  1509. paddCopy,
  1510. FALSE, // no TTL clear
  1511. FALSE, // no flag clear
  1512. 0 // no flags to set
  1513. );
  1514. if ( status != ERROR_SUCCESS )
  1515. {
  1516. status = ERROR_INVALID_PARAMETER;
  1517. goto Cleanup;
  1518. }
  1519. }
  1520. if ( pdeleteCopy )
  1521. {
  1522. status = prepareUpdateRecordSet(
  1523. pdeleteCopy,
  1524. FALSE, // no TTL clear
  1525. FALSE, // no flag clear
  1526. 0 // no flags to set
  1527. );
  1528. if ( status != ERROR_SUCCESS )
  1529. {
  1530. status = ERROR_INVALID_PARAMETER;
  1531. goto Cleanup;
  1532. }
  1533. }
  1534. if ( paddCopy &&
  1535. pdeleteCopy &&
  1536. ! Dns_NameCompare_UTF8( paddCopy->pName, pdeleteCopy->pName ) )
  1537. {
  1538. status = ERROR_INVALID_PARAMETER;
  1539. goto Cleanup;
  1540. }
  1541. //
  1542. // set security for update
  1543. //
  1544. if ( UseSystemDefaultForSecurity( Options ) )
  1545. {
  1546. Options |= g_UpdateSecurityLevel;
  1547. }
  1548. if ( hCredentials )
  1549. {
  1550. Options |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
  1551. }
  1552. //
  1553. // create update RRs
  1554. // - no prereqs
  1555. // - delete RRs set for delete
  1556. // - add RRs appended
  1557. //
  1558. pupdateSet = DnsBuildUpdateSet(
  1559. NULL, // no precons
  1560. paddCopy,
  1561. pdeleteCopy );
  1562. //
  1563. // do the update
  1564. //
  1565. status = DoQuickUpdate(
  1566. pupdateSet,
  1567. Options,
  1568. FALSE,
  1569. pServerList,
  1570. hCredentials );
  1571. //
  1572. // flush cache entry for update
  1573. //
  1574. if ( status == ERROR_SUCCESS )
  1575. {
  1576. DnsFlushResolverCacheEntry_UTF8( (LPSTR) pupdateSet->pName );
  1577. }
  1578. //
  1579. // cleanup local copy
  1580. //
  1581. Dns_RecordListFree( pupdateSet );
  1582. DNSDBG( TRACE, ( "Leave modifyRecordsInSetPrivate()\n" ));
  1583. return status;
  1584. Cleanup:
  1585. //
  1586. // cleanup copies on failure before combined list
  1587. //
  1588. Dns_RecordListFree( paddCopy );
  1589. Dns_RecordListFree( pdeleteCopy );
  1590. DNSDBG( TRACE, ( "Leave modifyRecordsInSetPrivate()\n" ));
  1591. return status;
  1592. }
  1593. DNS_STATUS
  1594. WINAPI
  1595. DnsModifyRecordsInSet_W(
  1596. IN PDNS_RECORD pAddRecords,
  1597. IN PDNS_RECORD pDeleteRecords,
  1598. IN DWORD Options,
  1599. IN HANDLE hCredentials, OPTIONAL
  1600. IN PIP_ARRAY pServerList, OPTIONAL
  1601. IN PVOID pReserved
  1602. )
  1603. /*++
  1604. Routine Description:
  1605. Dynamic update routine to modify record set on DNS server.
  1606. Arguments:
  1607. pAddRecords - records to register on server
  1608. pDeleteRecords - records to remove from server
  1609. Options - update options
  1610. pServerList - list of DNS servers to go to; if not given, machines
  1611. default servers are queried to find correct servers to send update to
  1612. hCredentials - handle to credentials to be used for update; optional,
  1613. if not given security credentials of this process are used in update
  1614. pReserved - reserved; should be NULL
  1615. Return Value:
  1616. ERROR_SUCCESS if update successful.
  1617. ErrorCode from server if server rejects update.
  1618. ERROR_INVALID_PARAMETER if bad param.
  1619. --*/
  1620. {
  1621. return modifyRecordsInSetPrivate(
  1622. pAddRecords,
  1623. pDeleteRecords,
  1624. Options,
  1625. hCredentials,
  1626. pServerList,
  1627. pReserved,
  1628. DnsCharSetUnicode
  1629. );
  1630. }
  1631. DNS_STATUS
  1632. WINAPI
  1633. DnsModifyRecordsInSet_A(
  1634. IN PDNS_RECORD pAddRecords,
  1635. IN PDNS_RECORD pDeleteRecords,
  1636. IN DWORD Options,
  1637. IN HANDLE hCredentials, OPTIONAL
  1638. IN PIP_ARRAY pServerList, OPTIONAL
  1639. IN PVOID pReserved
  1640. )
  1641. /*++
  1642. Routine Description:
  1643. Dynamic update routine to modify record set on DNS server.
  1644. Arguments:
  1645. pAddRecords - records to register on server
  1646. pDeleteRecords - records to remove from server
  1647. Options - update options
  1648. pServerList - list of DNS servers to go to; if not given, machines
  1649. default servers are queried to find correct servers to send update to
  1650. hCredentials - handle to credentials to be used for update; optional,
  1651. if not given security credentials of this process are used in update
  1652. pReserved - reserved; should be NULL
  1653. Return Value:
  1654. ERROR_SUCCESS if update successful.
  1655. ErrorCode from server if server rejects update.
  1656. ERROR_INVALID_PARAMETER if bad param.
  1657. --*/
  1658. {
  1659. return modifyRecordsInSetPrivate(
  1660. pAddRecords,
  1661. pDeleteRecords,
  1662. Options,
  1663. hCredentials,
  1664. pServerList,
  1665. pReserved,
  1666. DnsCharSetAnsi
  1667. );
  1668. }
  1669. DNS_STATUS
  1670. WINAPI
  1671. DnsModifyRecordsInSet_UTF8(
  1672. IN PDNS_RECORD pAddRecords,
  1673. IN PDNS_RECORD pDeleteRecords,
  1674. IN DWORD Options,
  1675. IN HANDLE hCredentials, OPTIONAL
  1676. IN PIP_ARRAY pServerList, OPTIONAL
  1677. IN PVOID pReserved
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. Dynamic update routine to modify record set on DNS server.
  1682. Arguments:
  1683. pAddRecords - records to register on server
  1684. pDeleteRecords - records to remove from server
  1685. Options - update options
  1686. pServerList - list of DNS servers to go to; if not given, machines
  1687. default servers are queried to find correct servers to send update to
  1688. hCredentials - handle to credentials to be used for update; optional,
  1689. if not given security credentials of this process are used in update
  1690. pReserved - reserved; should be NULL
  1691. Return Value:
  1692. ERROR_SUCCESS if update successful.
  1693. ErrorCode from server if server rejects update.
  1694. ERROR_INVALID_PARAMETER if bad param.
  1695. --*/
  1696. {
  1697. return modifyRecordsInSetPrivate(
  1698. pAddRecords,
  1699. pDeleteRecords,
  1700. Options,
  1701. hCredentials,
  1702. pServerList,
  1703. pReserved,
  1704. DnsCharSetUtf8
  1705. );
  1706. }
  1707. //
  1708. // Full scale update API
  1709. //
  1710. DNS_STATUS
  1711. DnsUpdate(
  1712. IN PDNS_RECORD pRecord,
  1713. IN DWORD dwFlags,
  1714. IN PDNS_NETINFO pNetworkInfo,
  1715. IN HANDLE hCreds, OPTIONAL
  1716. OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. Send DNS update.
  1721. Note if pNetworkInfo is not specified or not a valid UPDATE adapter list,
  1722. then a FindAuthoritativeZones (FAZ) query is done prior to the update.
  1723. Arguments:
  1724. pRecord -- list of records to send in update
  1725. dwFlags -- flags to update
  1726. pNetworkInfo -- DNS servers to send update to
  1727. ppMsgRecv -- addr for ptr to recv buffer, if desired
  1728. Return Value:
  1729. ERROR_SUCCESS if successful.
  1730. Error status on failure.
  1731. --*/
  1732. {
  1733. DNS_STATUS status;
  1734. PDNS_NETINFO plocalNetworkInfo = NULL;
  1735. DNSDBG( TRACE, ( "DnsUpdate()\n" ));
  1736. //
  1737. // read update config
  1738. //
  1739. Reg_RefreshUpdateConfig();
  1740. //
  1741. // need to build update adapter list from FAZ
  1742. // - only pass on BYPASS_CACHE flag
  1743. // - note DnsFindAuthoritativeZone() will append
  1744. // DNS_QUERY_ALLOW_EMPTY_AUTH_RESP flag yet
  1745. // DnsQuery_UTF8 will die on that flag without
  1746. // BYPASS_CACHE also set, so just set BYPASS_CACHE
  1747. // flag here;
  1748. // bogus, but that's how it is now
  1749. //
  1750. if ( ! NetInfo_IsForUpdate(pNetworkInfo) )
  1751. {
  1752. status = DnsFindAuthoritativeZone(
  1753. pRecord->pName,
  1754. //(dwFlags & DNS_QUERY_BYPASS_CACHE),
  1755. DNS_QUERY_BYPASS_CACHE,
  1756. NULL, // no specified servers
  1757. & plocalNetworkInfo );
  1758. if ( status != ERROR_SUCCESS )
  1759. {
  1760. return( status );
  1761. }
  1762. pNetworkInfo = plocalNetworkInfo;
  1763. }
  1764. //
  1765. // call the real update routine in dnslib
  1766. //
  1767. status = Dns_UpdateLib(
  1768. pRecord,
  1769. dwFlags,
  1770. pNetworkInfo,
  1771. hCreds,
  1772. ppMsgRecv );
  1773. // if there was an error sending the update, flush the resolver
  1774. // cache entry for the zone name to possibly pick up an alternate
  1775. // DNS server for the next retry attempt of a similar update.
  1776. //
  1777. // DCR_QUESTION: is this the correct error code?
  1778. // maybe ERROR_TIMED_OUT?
  1779. //
  1780. if ( status == DNS_ERROR_RECORD_TIMED_OUT )
  1781. {
  1782. PSTR pzoneName;
  1783. if ( pNetworkInfo &&
  1784. (pzoneName = NetInfo_UpdateZoneName( pNetworkInfo )) )
  1785. {
  1786. DnsFlushResolverCacheEntry_UTF8( pzoneName );
  1787. DnsFlushResolverCacheEntry_UTF8( pRecord->pName );
  1788. }
  1789. }
  1790. // cleanup local adapter list if used
  1791. if ( plocalNetworkInfo )
  1792. {
  1793. NetInfo_Free( plocalNetworkInfo );
  1794. }
  1795. return( status );
  1796. }
  1797. //
  1798. // Private update functions
  1799. //
  1800. // These calls are used only inside dnsapi.dll to do the client
  1801. // host updates. They are exposed in dnsapi.dll only for test
  1802. // purposes.
  1803. //
  1804. //
  1805. // DCR: eliminate nonsense "unique modify" routines -- they add no value
  1806. // moral -- don't let your PM talk to your developers
  1807. //
  1808. // DCR: get rid of old GlennC update routines
  1809. //
  1810. DNS_STATUS
  1811. DnsRegisterRRSet_Ex (
  1812. IN OUT PDNS_RECORD pRegisterSet,
  1813. IN DWORD fOptions,
  1814. IN PIP_ARRAY aipServers OPTIONAL,
  1815. IN HANDLE hCreds OPTIONAL
  1816. );
  1817. DNS_STATUS
  1818. DnsModifyRRSet_Ex (
  1819. IN PDNS_RECORD pCurrentSet,
  1820. IN PDNS_RECORD pNewSet,
  1821. IN DWORD fOptions,
  1822. IN PIP_ARRAY aipServers OPTIONAL,
  1823. IN HANDLE hCreds OPTIONAL
  1824. )
  1825. /*++
  1826. Routine Description:
  1827. Modify record set of known existing records.
  1828. Note: this is not my idea of "Modify". It is really "Register"
  1829. where you specify both what you think the existing set is and
  1830. what you want it to be.
  1831. Like most of these routines -- it's a big waste of time.
  1832. Arguments:
  1833. None.
  1834. Return Value:
  1835. None.
  1836. --*/
  1837. {
  1838. DNS_STATUS status = NO_ERROR;
  1839. PDNS_RECORD pCopyOfCurrentSet = NULL;
  1840. PDNS_RECORD pCopyOfNewSet = NULL;
  1841. PDNS_RECORD pAddSet = NULL;
  1842. PDNS_RECORD pDeleteSet = NULL;
  1843. PDNS_RECORD pUpdateSet = NULL;
  1844. PDNS_NETINFO pNetworkInfo = NULL;
  1845. DNSDBG( TRACE, ( "DnsModifyRRSet_Ex()\n" ));
  1846. IF_DNSDBG( UPDATE )
  1847. {
  1848. DnsDbg_RecordSet(
  1849. "DnsModifyRRSet_Ex() -- current set",
  1850. pCurrentSet );
  1851. DnsDbg_RecordSet(
  1852. "DnsModifyRRSet_Ex() -- new set",
  1853. pNewSet );
  1854. }
  1855. //
  1856. // Validate arguments ...
  1857. //
  1858. if ( ( fOptions != DNS_UPDATE_UNIQUE ) &&
  1859. ( fOptions & DNS_UNACCEPTABLE_UPDATE_OPTIONS ) )
  1860. {
  1861. return ERROR_INVALID_PARAMETER;
  1862. }
  1863. if ( prepareUpdateRecordSet( pCurrentSet,
  1864. FALSE,
  1865. FALSE,
  1866. 0 ) != NO_ERROR )
  1867. {
  1868. return ERROR_INVALID_PARAMETER;
  1869. }
  1870. if ( prepareUpdateRecordSet( pNewSet,
  1871. FALSE,
  1872. FALSE,
  1873. 0 ) != NO_ERROR )
  1874. {
  1875. return ERROR_INVALID_PARAMETER;
  1876. }
  1877. if ( !Dns_NameCompare_UTF8( pCurrentSet->pName, pNewSet->pName ) )
  1878. {
  1879. return ERROR_INVALID_PARAMETER;
  1880. }
  1881. //
  1882. // Make a copy of the RRSets, to preserve the original RRSets ...
  1883. //
  1884. pCopyOfCurrentSet = Dns_RecordSetCopyEx( pCurrentSet,
  1885. DnsCharSetUtf8,
  1886. DnsCharSetUtf8 );
  1887. if ( !pCopyOfCurrentSet )
  1888. {
  1889. status = DNS_ERROR_NO_MEMORY;
  1890. goto Exit;
  1891. }
  1892. pCopyOfNewSet = Dns_RecordSetCopyEx( pNewSet,
  1893. DnsCharSetUtf8,
  1894. DnsCharSetUtf8 );
  1895. if ( !pCopyOfNewSet )
  1896. {
  1897. status = DNS_ERROR_NO_MEMORY;
  1898. goto Exit;
  1899. }
  1900. //
  1901. // pAddSet = pCopyOfNewSet - pCopyOfCurrentSet
  1902. // pDeleteSet = pCopyOfCurrentSet - pCopyOfNewSet
  1903. //
  1904. //
  1905. // no change from previous registration?
  1906. // - touch DNS server to make sure it's in sync
  1907. //
  1908. if ( Dns_RecordSetCompare( pCopyOfNewSet,
  1909. pCopyOfCurrentSet,
  1910. &pAddSet,
  1911. &pDeleteSet ) )
  1912. {
  1913. status = DnsRegisterRRSet_Ex(
  1914. pCopyOfNewSet,
  1915. fOptions,
  1916. aipServers,
  1917. hCreds );
  1918. goto Exit;
  1919. }
  1920. //
  1921. // shared update - do simple modify
  1922. // - delete what was registered before, that don't want now
  1923. // - add everything in new set for robustness
  1924. //
  1925. if ( fOptions & DNS_UPDATE_SHARED )
  1926. {
  1927. //
  1928. // Update with the following:
  1929. // Prerequisites: Nothing
  1930. // Add: pCopyOfNewSet
  1931. // Delete: pDeleteSet
  1932. //
  1933. // Build the update request with Pre, Add, Del sets ...
  1934. //
  1935. pUpdateSet = DnsBuildUpdateSet( NULL,
  1936. pCopyOfNewSet,
  1937. pDeleteSet );
  1938. //
  1939. // Call update ...
  1940. //
  1941. status = DoQuickUpdate( pUpdateSet,
  1942. fOptions,
  1943. FALSE,
  1944. aipServers,
  1945. hCreds);
  1946. //
  1947. // Free memory used ...
  1948. //
  1949. Dns_RecordListFree( pUpdateSet );
  1950. pUpdateSet = NULL;
  1951. pCopyOfNewSet = NULL;
  1952. pDeleteSet = NULL;
  1953. goto Exit;
  1954. }
  1955. //
  1956. // Unique case
  1957. //
  1958. //
  1959. // Update with the following:
  1960. // Prerequisites: pCopyOfCurrentSet
  1961. // Add: pAddSet
  1962. // Delete: pDeleteSet
  1963. //
  1964. // Build the update request with Pre, Add, Del sets ...
  1965. //
  1966. pUpdateSet = DnsBuildUpdateSet( pCopyOfCurrentSet,
  1967. pAddSet,
  1968. pDeleteSet );
  1969. //
  1970. // Call update ...
  1971. //
  1972. status = DoQuickUpdate( pUpdateSet,
  1973. fOptions,
  1974. FALSE,
  1975. aipServers,
  1976. hCreds);
  1977. //
  1978. // Free memory used ...
  1979. //
  1980. Dns_RecordListFree( pUpdateSet );
  1981. pUpdateSet = NULL;
  1982. pCopyOfCurrentSet = NULL;
  1983. pAddSet = NULL;
  1984. pDeleteSet = NULL;
  1985. if ( status == DNS_ERROR_RCODE_YXRRSET ||
  1986. status == DNS_ERROR_RCODE_NXRRSET )
  1987. {
  1988. PDNS_RECORD pActualCurrentSet = NULL;
  1989. PDNS_RECORD pSharedSet = NULL;
  1990. PDNS_RECORD pNotUsedSet = NULL;
  1991. DNS_RECORD Record;
  1992. IP_ARRAY ipArray;
  1993. IP_ADDRESS serverIp = DnsGetLastServerUpdateIP();
  1994. if ( serverIp )
  1995. {
  1996. ipArray.AddrCount = 1;
  1997. ipArray.AddrArray[0] = serverIp;
  1998. }
  1999. pNetworkInfo = NetInfo_CreateFromIpArray(
  2000. aipServers,
  2001. serverIp,
  2002. FALSE, // no search info
  2003. NULL );
  2004. //
  2005. // Make another copy of the Current RRSet ...
  2006. //
  2007. pCopyOfCurrentSet = Dns_RecordSetCopyEx(
  2008. pCurrentSet,
  2009. DnsCharSetUtf8,
  2010. DnsCharSetUtf8 );
  2011. if ( !pCopyOfCurrentSet )
  2012. {
  2013. status = DNS_ERROR_NO_MEMORY;
  2014. goto Exit;
  2015. }
  2016. //
  2017. // Query server for pActualCurrentSet ...
  2018. //
  2019. status = QueryDirectEx(
  2020. NULL, // no response message
  2021. & pActualCurrentSet,
  2022. NULL, // no header
  2023. 0, // no header counts
  2024. (LPSTR) pCopyOfCurrentSet->pName,
  2025. pCopyOfCurrentSet->wType,
  2026. NULL, // no input records
  2027. DNS_QUERY_TREAT_AS_FQDN,
  2028. NULL, // no DNS server list
  2029. pNetworkInfo );
  2030. if ( IsEmptyDnsResponse( pActualCurrentSet ) )
  2031. {
  2032. Dns_RecordListFree( pActualCurrentSet );
  2033. pActualCurrentSet = NULL;
  2034. if ( status == NO_ERROR )
  2035. {
  2036. status = DNS_ERROR_RCODE_NAME_ERROR;
  2037. }
  2038. }
  2039. if ( status == DNS_ERROR_RCODE_NAME_ERROR ||
  2040. status == DNS_INFO_NO_RECORDS )
  2041. {
  2042. DNS_RECORD Record;
  2043. //
  2044. // Query failed to find any entry for given name and type.
  2045. // We now need to assume that the pCurrentSet is that there
  2046. // isn't anything registered.
  2047. //
  2048. RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
  2049. Record.pName = (PDNS_NAME) pCopyOfNewSet->pName;
  2050. Record.wType = pCopyOfNewSet->wType;
  2051. Record.wDataLength = 0; // Meaning all structures not present.
  2052. Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  2053. //
  2054. // Do an update with the following:
  2055. // Prerequisites: None - will be Record above.
  2056. // Add: pRegisterSet
  2057. // Delete: None
  2058. //
  2059. // Build the update request with Pre, Add, Del sets ...
  2060. //
  2061. pUpdateSet = DnsBuildUpdateSet( NULL,
  2062. pCopyOfNewSet,
  2063. NULL );
  2064. Record.pNext = pCopyOfNewSet;
  2065. status = DoQuickUpdate( &Record,
  2066. fOptions,
  2067. FALSE,
  2068. serverIp ? &ipArray : aipServers,
  2069. hCreds);
  2070. if ( status == DNS_ERROR_RCODE_YXRRSET ||
  2071. status == DNS_ERROR_RCODE_NXRRSET )
  2072. {
  2073. status = DNS_ERROR_TRY_AGAIN_LATER;
  2074. }
  2075. goto Exit;
  2076. }
  2077. if ( status )
  2078. {
  2079. goto Exit;
  2080. }
  2081. //
  2082. // Sometimes when DnsQuery is called, the returned record set
  2083. // contains additional records of different types than what
  2084. // was queried for. Need to strip off the additional records
  2085. // from the query results.
  2086. //
  2087. pNotUsedSet = DnsRecordSetDetach( pActualCurrentSet );
  2088. if ( pNotUsedSet )
  2089. {
  2090. Dns_RecordListFree( pNotUsedSet );
  2091. pNotUsedSet = NULL;
  2092. }
  2093. //
  2094. // pAddSet = pNewSet - pActualCurrentSet
  2095. // pDeleteSet = pActualCurrentSet - pNewSet
  2096. //
  2097. (void) Dns_RecordSetCompare( pCopyOfNewSet,
  2098. pActualCurrentSet,
  2099. &pAddSet,
  2100. &pDeleteSet );
  2101. //
  2102. // pSharedSet = pDeleteSet - pCopyOfCurrentSet
  2103. // pNotUsedSet = pCopyOfCurrentSet - pDeleteSet
  2104. //
  2105. (void) Dns_RecordSetCompare( pDeleteSet,
  2106. pCopyOfCurrentSet,
  2107. &pSharedSet,
  2108. &pNotUsedSet );
  2109. Dns_RecordListFree( pDeleteSet );
  2110. pDeleteSet = NULL;
  2111. Dns_RecordListFree( pCopyOfCurrentSet );
  2112. pCopyOfCurrentSet = NULL;
  2113. Dns_RecordListFree( pNotUsedSet );
  2114. pNotUsedSet = NULL;
  2115. Dns_RecordListFree( pActualCurrentSet );
  2116. pActualCurrentSet = NULL;
  2117. //
  2118. // unaccounted for records indicate other updater of name
  2119. //
  2120. // records we don't want (delete set) and did NOT previously
  2121. // register mean some other user is adding records
  2122. //
  2123. if ( pSharedSet )
  2124. {
  2125. Dns_RecordListFree( pSharedSet );
  2126. pSharedSet = NULL;
  2127. status = DNS_ERROR_NOT_UNIQUE;
  2128. goto Exit;
  2129. }
  2130. RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
  2131. Record.pName = (PDNS_NAME) pCopyOfNewSet->pName;
  2132. Record.wType = pCopyOfNewSet->wType;
  2133. Record.wDataLength = 0; // Meaning all data.
  2134. Record.Flags.DW = DNSREC_UPDATE | DNSREC_DELETE;
  2135. //
  2136. // Do an update with the following:
  2137. // Prerequisites: None
  2138. // Add: pCopyOfNewSet
  2139. // Delete: All
  2140. //
  2141. // Build the update request with Pre, Add, Del sets ...
  2142. //
  2143. pUpdateSet = DnsBuildUpdateSet( NULL,
  2144. pCopyOfNewSet,
  2145. NULL );
  2146. Record.pNext = pCopyOfNewSet;
  2147. status = DoQuickUpdate( &Record,
  2148. fOptions,
  2149. FALSE,
  2150. serverIp ? &ipArray : aipServers,
  2151. hCreds);
  2152. goto Exit;
  2153. }
  2154. Exit :
  2155. if ( pCopyOfCurrentSet )
  2156. {
  2157. Dns_RecordListFree( pCopyOfCurrentSet );
  2158. }
  2159. if ( pCopyOfNewSet )
  2160. {
  2161. Dns_RecordListFree( pCopyOfNewSet );
  2162. }
  2163. if ( pAddSet )
  2164. {
  2165. Dns_RecordListFree( pAddSet );
  2166. }
  2167. if ( pDeleteSet )
  2168. {
  2169. Dns_RecordListFree( pDeleteSet );
  2170. }
  2171. if ( pNetworkInfo )
  2172. {
  2173. NetInfo_Free( pNetworkInfo );
  2174. }
  2175. DNSDBG( TRACE, ( "Leave DnsModifyRRSet_Ex()\n" ));
  2176. return status;
  2177. }
  2178. DNS_STATUS
  2179. DnsRegisterRRSet_Ex(
  2180. IN OUT PDNS_RECORD pRegisterSet,
  2181. IN DWORD fOptions,
  2182. IN PIP_ARRAY aipServers OPTIONAL,
  2183. IN HANDLE hCreds OPTIONAL
  2184. )
  2185. /*++
  2186. Routine Description:
  2187. None.
  2188. Arguments:
  2189. None.
  2190. Return Value:
  2191. None.
  2192. --*/
  2193. {
  2194. DNS_STATUS status = NO_ERROR;
  2195. PDNS_RECORD pCurrentSet = NULL;
  2196. PDNS_RECORD pUpdateSet = NULL;
  2197. PDNS_NETINFO pNetworkInfo = NULL;
  2198. DNS_RECORD Record;
  2199. DNS_RECORD NoCName;
  2200. IP_ARRAY ipArray;
  2201. IP_ADDRESS serverIp = 0;
  2202. DNSDBG( TRACE, ( "DnsRegisterRRSet_Ex()\n" ));
  2203. IF_DNSDBG( UPDATE )
  2204. {
  2205. DnsDbg_RecordSet(
  2206. "DnsRegisterRRSet_Ex()",
  2207. pRegisterSet );
  2208. }
  2209. //
  2210. // Validate arguments ...
  2211. //
  2212. if ( ( fOptions != DNS_UPDATE_UNIQUE ) &&
  2213. ( fOptions & DNS_UNACCEPTABLE_UPDATE_OPTIONS ) )
  2214. {
  2215. return ERROR_INVALID_PARAMETER;
  2216. }
  2217. //
  2218. // Are all the RRSet structures of the same type and name?
  2219. // Mark them all as Updates (add) ...
  2220. //
  2221. if ( prepareUpdateRecordSet(
  2222. pRegisterSet,
  2223. FALSE,
  2224. TRUE,
  2225. DNSREC_UPDATE ) != NO_ERROR )
  2226. {
  2227. return ERROR_INVALID_PARAMETER;
  2228. }
  2229. //
  2230. // Prepare CName does not exist record
  2231. //
  2232. RtlZeroMemory( &NoCName, sizeof(DNS_RECORD) );
  2233. NoCName.pName = (PDNS_NAME) pRegisterSet->pName;
  2234. NoCName.wType = DNS_TYPE_CNAME;
  2235. NoCName.wDataLength = 0; // Meaning all structures not present.
  2236. NoCName.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  2237. //
  2238. // shared update
  2239. // - just throw our records out there (with CNAME no-exist)
  2240. //
  2241. // DCR: this case is just ModifyRecordsInSet
  2242. //
  2243. if ( fOptions & DNS_UPDATE_SHARED &&
  2244. pRegisterSet->wType != DNS_TYPE_CNAME )
  2245. {
  2246. NoCName.pNext = pRegisterSet;
  2247. status = DoQuickUpdate( &NoCName,
  2248. fOptions,
  2249. FALSE,
  2250. aipServers,
  2251. hCreds);
  2252. goto Exit;
  2253. }
  2254. //
  2255. // From here on down the code is handling the non-shared case ....
  2256. //
  2257. //
  2258. // Do an update with the following:
  2259. // Prerequisites: pRegisterSet
  2260. // Add: None
  2261. // Delete: None
  2262. //
  2263. // Build the update request with Pre, Add, Del sets ...
  2264. //
  2265. //
  2266. // DCR_PERF: prereq only update is wasteful
  2267. // we need to query AND we are trusting query
  2268. // -- supposed to find last update server -- so
  2269. // just do it
  2270. //
  2271. // - faz => find target DNS server
  2272. // - direct query for our set
  2273. // - compare
  2274. // - full match => done
  2275. // - unresolveable conflict => fail
  2276. // - ok mismatch => send replace
  2277. //
  2278. pUpdateSet = DnsBuildUpdateSet( pRegisterSet,
  2279. NULL,
  2280. NULL );
  2281. //
  2282. // Call update ...
  2283. //
  2284. if ( pUpdateSet->wType != DNS_TYPE_CNAME )
  2285. {
  2286. NoCName.pNext = pUpdateSet;
  2287. status = DoQuickUpdate( &NoCName,
  2288. fOptions,
  2289. FALSE,
  2290. aipServers,
  2291. hCreds);
  2292. }
  2293. else
  2294. {
  2295. status = DoQuickUpdate( pUpdateSet,
  2296. fOptions,
  2297. FALSE,
  2298. aipServers,
  2299. hCreds);
  2300. }
  2301. if ( status == NO_ERROR )
  2302. {
  2303. //
  2304. // We are done, no need to reregister since the server has
  2305. // what it should have.
  2306. //
  2307. goto Exit;
  2308. }
  2309. if ( status == DNS_ERROR_RCODE_YXRRSET ||
  2310. status == DNS_ERROR_RCODE_NXRRSET )
  2311. {
  2312. //
  2313. // For these errors, we just need to figure out what the server
  2314. // has and send the correct update info.
  2315. //
  2316. serverIp = DnsGetLastServerUpdateIP();
  2317. ipArray.AddrCount = 1;
  2318. ipArray.AddrArray[0] = serverIp;
  2319. status = NO_ERROR;
  2320. }
  2321. if ( status )
  2322. {
  2323. //
  2324. // For all other update errors, don't bother trying anything more.
  2325. //
  2326. goto Exit;
  2327. }
  2328. // get network info for
  2329. pNetworkInfo = NetInfo_CreateFromIpArray(
  2330. aipServers,
  2331. serverIp,
  2332. FALSE, // no search info
  2333. NULL );
  2334. //
  2335. // Let's see if the DNS server doesn't know about this set at all
  2336. // and just try to add it with the prerequisite that there is nothing
  2337. // there already for the given record name.
  2338. //
  2339. if ( pRegisterSet->wType == DNS_TYPE_CNAME )
  2340. {
  2341. //
  2342. // Handle CNAME type here as special case
  2343. //
  2344. RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
  2345. Record.pName = (PDNS_NAME) pRegisterSet->pName;
  2346. Record.wType = DNS_TYPE_ANY;
  2347. Record.wDataLength = 0; // Meaning all structures not present.
  2348. Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  2349. //
  2350. // Do an update with the following:
  2351. // Prerequisites: None - will be Record above.
  2352. // Add: pRegisterSet
  2353. // Delete: None
  2354. //
  2355. // Build the update request with Pre, Add, Del sets ...
  2356. //
  2357. pUpdateSet = DnsBuildUpdateSet( NULL,
  2358. pRegisterSet,
  2359. NULL );
  2360. Record.pNext = pRegisterSet;
  2361. status = DoQuickUpdate( &Record,
  2362. fOptions,
  2363. FALSE,
  2364. serverIp ? &ipArray : aipServers,
  2365. hCreds);
  2366. if ( status == DNS_ERROR_RCODE_YXRRSET ||
  2367. status == DNS_ERROR_RCODE_NXRRSET )
  2368. {
  2369. status = DNS_ERROR_TRY_AGAIN_LATER;
  2370. }
  2371. goto Exit;
  2372. }
  2373. else
  2374. {
  2375. RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
  2376. Record.pName = (PDNS_NAME) pRegisterSet->pName;
  2377. Record.wType = pRegisterSet->wType;
  2378. Record.wDataLength = 0; // Meaning all structures not present.
  2379. Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  2380. //
  2381. // Do an update with the following:
  2382. // Prerequisites: None - will be Record above and CNAME does not exist.
  2383. // Add: pRegisterSet
  2384. // Delete: All
  2385. //
  2386. // Build the update request with Pre, Add, Del sets ...
  2387. //
  2388. pUpdateSet = DnsBuildUpdateSet( NULL,
  2389. pRegisterSet,
  2390. NULL );
  2391. Record.pNext = pRegisterSet;
  2392. NoCName.pNext = &Record;
  2393. status = DoQuickUpdate( &NoCName,
  2394. fOptions,
  2395. FALSE,
  2396. serverIp ? &ipArray : aipServers,
  2397. hCreds);
  2398. }
  2399. if ( status == NO_ERROR )
  2400. {
  2401. //
  2402. // We are done, no need to reregister since the server has
  2403. // what it should have.
  2404. //
  2405. goto Exit;
  2406. }
  2407. if ( status == DNS_ERROR_RCODE_YXRRSET ||
  2408. status == DNS_ERROR_RCODE_NXRRSET )
  2409. {
  2410. //
  2411. // For these errors, we just need to figure out what the server
  2412. // has and send the correct update info.
  2413. //
  2414. status = NO_ERROR;
  2415. }
  2416. if ( status )
  2417. {
  2418. //
  2419. // For all other update errors, don't bother trying anything more.
  2420. //
  2421. goto Exit;
  2422. }
  2423. //
  2424. // Query server for pCurrentSet ...
  2425. //
  2426. status = QueryDirectEx(
  2427. NULL, // no response message
  2428. & pCurrentSet,
  2429. NULL, // no header
  2430. 0, // no header counts
  2431. (LPSTR) pRegisterSet->pName,
  2432. pRegisterSet->wType,
  2433. NULL, // no input records
  2434. DNS_QUERY_TREAT_AS_FQDN,
  2435. NULL, // no DNS server list
  2436. pNetworkInfo
  2437. );
  2438. if ( IsEmptyDnsResponse( pCurrentSet ) )
  2439. {
  2440. Dns_RecordListFree( pCurrentSet );
  2441. pCurrentSet = NULL;
  2442. }
  2443. if ( pCurrentSet )
  2444. {
  2445. PDNS_RECORD pOtherSet = NULL;
  2446. PDNS_RECORD pNotUsedSet = NULL;
  2447. //
  2448. // Sometimes when DnsQuery is called, the returned record set contains
  2449. // additional records of different types than what was queried for.
  2450. // Need to strip off the additional records from the query results.
  2451. //
  2452. pNotUsedSet = DnsRecordSetDetach( pCurrentSet );
  2453. if ( pNotUsedSet )
  2454. {
  2455. Dns_RecordListFree( pNotUsedSet );
  2456. pNotUsedSet = NULL;
  2457. }
  2458. //
  2459. // There are records on the server, make sure that these are ones
  2460. // that we know about, otherwise this call should return
  2461. // DNS_ERROR_NOT_UNIQUE.
  2462. //
  2463. if ( Dns_RecordSetCompare( pCurrentSet,
  2464. pRegisterSet,
  2465. &pOtherSet,
  2466. &pNotUsedSet ) )
  2467. {
  2468. //
  2469. // The two RRSets are the same. Weird! We just did a PreReq
  2470. // update looking for just this and it said the records weren't
  2471. // there, now when we query they are! This should never happen
  2472. // theoretically. Assert if otherwise . . .
  2473. //
  2474. DNS_ASSERT( FALSE );
  2475. status = NO_ERROR;
  2476. goto Exit;
  2477. }
  2478. if ( pNotUsedSet )
  2479. {
  2480. Dns_RecordListFree( pNotUsedSet );
  2481. pNotUsedSet = NULL;
  2482. }
  2483. //
  2484. // Test to see if any of the records up one the server are not the same
  2485. // as any in our registration set. If so return error . . .
  2486. //
  2487. if ( pOtherSet )
  2488. {
  2489. Dns_RecordListFree( pOtherSet );
  2490. pOtherSet = NULL;
  2491. status = DNS_ERROR_NOT_UNIQUE;
  2492. goto Exit;
  2493. }
  2494. //
  2495. // Call ModifyRecordSet with the Current and Register RR sets . . .
  2496. //
  2497. status = DnsModifyRRSet_Ex( pCurrentSet,
  2498. pRegisterSet,
  2499. fOptions,
  2500. serverIp ? &ipArray : aipServers,
  2501. hCreds );
  2502. }
  2503. else
  2504. {
  2505. //
  2506. // This is a confused DNS server! We've already tried a prerequisite
  2507. // update that there should be nothing, and add the registration
  2508. // RR set. No need to do it again, assume for now that the server
  2509. // is busy updating the particular RR set.
  2510. //
  2511. status = DNS_ERROR_TRY_AGAIN_LATER;
  2512. }
  2513. Exit :
  2514. if ( pCurrentSet )
  2515. {
  2516. Dns_RecordListFree( pCurrentSet );
  2517. }
  2518. if ( pNetworkInfo )
  2519. {
  2520. NetInfo_Free( pNetworkInfo );
  2521. }
  2522. DNSDBG( TRACE, ( "Leave DnsRegisterRRSet_Ex()\n" ));
  2523. return status;
  2524. }
  2525. //
  2526. // DCR_CLEANUP: ModifyRecordSet() functions?
  2527. // decide what to do with these
  2528. // if to be exposed -- then all three
  2529. // if only used by async reg, then just
  2530. // need UTF8 routine
  2531. //
  2532. DNS_STATUS
  2533. WINAPI
  2534. DnsModifyRecordSet_UTF8(
  2535. IN HANDLE hCredentials OPTIONAL,
  2536. IN PDNS_RECORD pCurrentSet,
  2537. IN PDNS_RECORD pNewSet,
  2538. IN DWORD fOptions,
  2539. IN PIP_ARRAY aipServers OPTIONAL )
  2540. /*++
  2541. Routine Description:
  2542. Dynamic DNS routine to update records. This function figures out the
  2543. records that need to be added and/or removed to modify an existing
  2544. record set in the DNS domain name space. This routine will not remove
  2545. any records that may have been added by another process for the given
  2546. record set name. In the case where "other" records are detected,
  2547. DNS_ERROR_NOT_UNIQUE will be returned.
  2548. Arguments:
  2549. hCredentials - handle to credentials to be used for update.
  2550. pCurrentSet - the set that the caller currently thinks is registered
  2551. in the DNS domain name space.
  2552. pNewSet - the set that should be registered in the DNS domain name
  2553. space. The current records will be modified to get to this
  2554. set.
  2555. fOptions - the Dynamic DNS update options that the caller may wish to
  2556. use (see dnsapi.h).
  2557. aipServers - a specific list of servers to goto to figure out the
  2558. authoritative DNS server(s) for the given record set
  2559. domain zone name.
  2560. Return Value:
  2561. None.
  2562. --*/
  2563. {
  2564. DNS_STATUS status = NO_ERROR;
  2565. PDNS_RECORD pCopyOfCurrentSet = NULL;
  2566. PDNS_RECORD pCopyOfNewSet = NULL;
  2567. DWORD dwFlags = fOptions;
  2568. DNSDBG( TRACE, ( "DnsModifyRecordSet_UTF8()\n" ));
  2569. //
  2570. // if just new set -- do an add
  2571. //
  2572. if ( pNewSet && !pCurrentSet )
  2573. {
  2574. return DnsAddRecordSet_UTF8( hCredentials,
  2575. pNewSet,
  2576. fOptions,
  2577. aipServers );
  2578. }
  2579. //
  2580. // if just current set -- do a delete
  2581. //
  2582. if ( !pNewSet && pCurrentSet )
  2583. {
  2584. return DnsModifyRecordsInSet_UTF8(
  2585. NULL, // no add records
  2586. pCurrentSet, // delete current set
  2587. fOptions,
  2588. hCredentials,
  2589. aipServers, // DNS servers
  2590. NULL // reserved
  2591. );
  2592. }
  2593. if ( !pNewSet && !pCurrentSet )
  2594. {
  2595. return ERROR_INVALID_PARAMETER;
  2596. }
  2597. if ( UseSystemDefaultForSecurity( dwFlags ) )
  2598. {
  2599. dwFlags |= g_UpdateSecurityLevel;
  2600. }
  2601. if ( hCredentials )
  2602. {
  2603. dwFlags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
  2604. }
  2605. //
  2606. // build record sets for update
  2607. //
  2608. // DCR_CLEANUP: unnecessary RR copy here
  2609. // DCR_FIX0: unnecessary RR copy here
  2610. // ModifyRRSet_Ex() does it's own copy
  2611. // and doesn't touch input records
  2612. //
  2613. pCopyOfCurrentSet = Dns_RecordSetCopyEx(
  2614. pCurrentSet,
  2615. DnsCharSetUtf8,
  2616. DnsCharSetUtf8 );
  2617. if ( !pCopyOfCurrentSet )
  2618. {
  2619. status = DNS_ERROR_NO_MEMORY;
  2620. goto Done;
  2621. }
  2622. pCopyOfNewSet = Dns_RecordSetCopyEx(
  2623. pNewSet,
  2624. DnsCharSetUtf8,
  2625. DnsCharSetUtf8 );
  2626. if ( !pCopyOfNewSet )
  2627. {
  2628. status = DNS_ERROR_NO_MEMORY;
  2629. goto Done;
  2630. }
  2631. status = DnsModifyRRSet_Ex(
  2632. pCopyOfCurrentSet,
  2633. pCopyOfNewSet,
  2634. dwFlags | DNS_UPDATE_UNIQUE,
  2635. aipServers,
  2636. hCredentials );
  2637. if ( status == NO_ERROR )
  2638. {
  2639. if ( pCopyOfCurrentSet )
  2640. {
  2641. DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfCurrentSet->pName );
  2642. }
  2643. else
  2644. {
  2645. DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfNewSet->pName );
  2646. }
  2647. }
  2648. Done:
  2649. Dns_RecordListFree( pCopyOfCurrentSet );
  2650. Dns_RecordListFree( pCopyOfNewSet );
  2651. DNSDBG( TRACE, ( "Leave DnsModifyRecordSet_UTF8()\n" ));
  2652. return status;
  2653. }
  2654. DNS_STATUS WINAPI
  2655. DnsModifyRecordSet_A (
  2656. IN HANDLE hCredentials OPTIONAL,
  2657. IN PDNS_RECORD pCurrentSet,
  2658. IN PDNS_RECORD pNewSet,
  2659. IN DWORD fOptions,
  2660. IN PIP_ARRAY aipServers OPTIONAL )
  2661. /*++
  2662. Routine Description:
  2663. ANSI version of ModifyRecordSet.
  2664. Note, there is NO use of this function it exists only for Elena's test
  2665. scripts. Once the test scripts are changed this function can be deleted.
  2666. Arguments:
  2667. same as above
  2668. Return Value:
  2669. None.
  2670. --*/
  2671. {
  2672. DNS_STATUS status;
  2673. PDNS_RECORD pcopyCurrent;
  2674. PDNS_RECORD pcopyNew;
  2675. DNSDBG( TRACE, ( "DnsModifyRecordSet_A()\n" ));
  2676. //
  2677. // copy record sets to UTF8
  2678. //
  2679. pcopyCurrent = Dns_RecordSetCopyEx(
  2680. pCurrentSet,
  2681. DnsCharSetAnsi,
  2682. DnsCharSetUtf8 );
  2683. pcopyNew = Dns_RecordSetCopyEx(
  2684. pNewSet,
  2685. DnsCharSetAnsi,
  2686. DnsCharSetUtf8 );
  2687. //
  2688. // modify in UTF8
  2689. //
  2690. status = DnsModifyRecordSet_UTF8(
  2691. hCredentials,
  2692. pcopyCurrent,
  2693. pcopyNew,
  2694. fOptions,
  2695. aipServers );
  2696. //
  2697. // cleanup local copies
  2698. //
  2699. Dns_RecordListFree( pcopyCurrent );
  2700. Dns_RecordListFree( pcopyNew );
  2701. return status;
  2702. }
  2703. DNS_STATUS
  2704. WINAPI
  2705. DnsModifyRecordSet_W(
  2706. IN HANDLE hCredentials OPTIONAL,
  2707. IN PDNS_RECORD pCurrentSet,
  2708. IN PDNS_RECORD pNewSet,
  2709. IN DWORD fOptions,
  2710. IN PIP_ARRAY aipServers OPTIONAL )
  2711. /*++
  2712. Routine Description:
  2713. Unicode version of ModifyRecordSet.
  2714. Note, there is NO use of this function it exists only for Elena's test
  2715. scripts. Once the test scripts are changed this function can be deleted.
  2716. Arguments:
  2717. same as above
  2718. Return Value:
  2719. None.
  2720. --*/
  2721. {
  2722. DNS_STATUS status;
  2723. PDNS_RECORD pcopyCurrent;
  2724. PDNS_RECORD pcopyNew;
  2725. DNSDBG( TRACE, ( "DnsModifyRecordSet_W()\n" ));
  2726. //
  2727. // copy record sets to UTF8
  2728. //
  2729. pcopyCurrent = Dns_RecordSetCopyEx(
  2730. pCurrentSet,
  2731. DnsCharSetUnicode,
  2732. DnsCharSetUtf8 );
  2733. pcopyNew = Dns_RecordSetCopyEx(
  2734. pNewSet,
  2735. DnsCharSetUnicode,
  2736. DnsCharSetUtf8 );
  2737. //
  2738. // modify in UTF8
  2739. //
  2740. status = DnsModifyRecordSet_UTF8(
  2741. hCredentials,
  2742. pcopyCurrent,
  2743. pcopyNew,
  2744. fOptions,
  2745. aipServers );
  2746. //
  2747. // cleanup local copies
  2748. //
  2749. Dns_RecordListFree( pcopyCurrent );
  2750. Dns_RecordListFree( pcopyNew );
  2751. return status;
  2752. }
  2753. //
  2754. // DCR_CLEANUP: DnsAddRecordSet() functions?
  2755. // decide what to do with these
  2756. // if to be exposed -- then all three
  2757. // if only used by async reg, then just
  2758. // need UTF8 routine
  2759. //
  2760. DNS_STATUS
  2761. WINAPI
  2762. DnsAddRecordSet_UTF8(
  2763. IN HANDLE hCredentials OPTIONAL,
  2764. IN OUT PDNS_RECORD pRegisterSet,
  2765. IN DWORD fOptions,
  2766. IN PIP_ARRAY aipServers OPTIONAL )
  2767. /*++
  2768. Routine Description:
  2769. Dynamic DNS routine to update records. This routine adds the
  2770. record set described by pRegisterSet to the DNS domain name
  2771. space. This routine fails with error DNS_ERROR_NOT_UNIQUE if
  2772. there are any pre-existing records in the DNS name space that are
  2773. not part of the set described by pRegisterSet.
  2774. Arguments:
  2775. hCredentials - handle to credentials to be used for update.
  2776. pRegisterSet - the set that should be registered in the DNS domain name
  2777. space.
  2778. fOptions - the Dynamic DNS update options that the caller may wish to
  2779. use (see dnsapi.h).
  2780. aipServers - a specific list of servers to goto to figure out the
  2781. authoritative DNS server(s) for the given record set
  2782. domain zone name.
  2783. Return Value:
  2784. None.
  2785. --*/
  2786. {
  2787. DNS_STATUS status = NO_ERROR;
  2788. PDNS_RECORD pCopyOfRegisterSet = NULL;
  2789. DWORD dwFlags = fOptions;
  2790. DNSDBG( TRACE, ( "DnsAddRecordSet_UTF8()\n" ));
  2791. IF_DNSDBG( UPDATE )
  2792. {
  2793. DnsDbg_RecordSet(
  2794. "DnsAddRecordSet_UTF8()",
  2795. pRegisterSet );
  2796. }
  2797. //
  2798. // Validate arguments ...
  2799. //
  2800. if ( !pRegisterSet )
  2801. {
  2802. return ERROR_INVALID_PARAMETER;
  2803. }
  2804. if ( UseSystemDefaultForSecurity( dwFlags ) )
  2805. {
  2806. dwFlags |= g_UpdateSecurityLevel;
  2807. }
  2808. if ( hCredentials )
  2809. {
  2810. dwFlags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
  2811. }
  2812. pCopyOfRegisterSet = Dns_RecordSetCopyEx( pRegisterSet,
  2813. DnsCharSetUtf8,
  2814. DnsCharSetUtf8 );
  2815. if ( !pCopyOfRegisterSet )
  2816. {
  2817. return DNS_ERROR_NO_MEMORY;
  2818. }
  2819. status = DnsRegisterRRSet_Ex( pCopyOfRegisterSet,
  2820. dwFlags | DNS_UPDATE_UNIQUE,
  2821. aipServers,
  2822. hCredentials);
  2823. if ( status == NO_ERROR )
  2824. {
  2825. DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfRegisterSet->pName );
  2826. }
  2827. Dns_RecordListFree( pCopyOfRegisterSet );
  2828. DNSDBG( TRACE, ( "Leave DnsAddRecordSet_UTF8()\n" ));
  2829. return status;
  2830. }
  2831. DNS_STATUS
  2832. WINAPI
  2833. DnsAddRecordSet_A(
  2834. IN HANDLE hCredentials OPTIONAL,
  2835. IN OUT PDNS_RECORD pRegisterSet,
  2836. IN DWORD fOptions,
  2837. IN PIP_ARRAY aipServers OPTIONAL
  2838. )
  2839. /*++
  2840. Routine Description:
  2841. ANSI version of AddRecordSet.
  2842. Note, there is NO use of this function it exists only for Elena's test
  2843. scripts. Once the test scripts are changed this function can be deleted.
  2844. Arguments:
  2845. same as above
  2846. Return Value:
  2847. None.
  2848. --*/
  2849. {
  2850. DNS_STATUS status;
  2851. PDNS_RECORD pcopySet;
  2852. DNSDBG( TRACE, ( "DnsAddRecordSet_A()\n" ));
  2853. //
  2854. // copy set to UTF8
  2855. //
  2856. pcopySet = Dns_RecordSetCopyEx(
  2857. pRegisterSet,
  2858. DnsCharSetAnsi,
  2859. DnsCharSetUtf8 );
  2860. //
  2861. // add set
  2862. //
  2863. status = DnsAddRecordSet_UTF8(
  2864. hCredentials,
  2865. pcopySet,
  2866. fOptions,
  2867. aipServers );
  2868. // cleanup local copy
  2869. Dns_RecordListFree( pcopySet );
  2870. return status;
  2871. }
  2872. DNS_STATUS
  2873. WINAPI
  2874. DnsAddRecordSet_W(
  2875. IN HANDLE hCredentials OPTIONAL,
  2876. IN OUT PDNS_RECORD pRegisterSet,
  2877. IN DWORD fOptions,
  2878. IN PIP_ARRAY aipServers OPTIONAL )
  2879. /*++
  2880. Routine Description:
  2881. ANSI version of AddRecordSet.
  2882. Note, there is NO use of this function it exists only for Elena's test
  2883. scripts. Once the test scripts are changed this function can be deleted.
  2884. Arguments:
  2885. same as above
  2886. Return Value:
  2887. None.
  2888. --*/
  2889. {
  2890. DNS_STATUS status;
  2891. PDNS_RECORD pcopySet;
  2892. DNSDBG( TRACE, ( "DnsAddRecordSet_W()\n" ));
  2893. //
  2894. // copy set to UTF8
  2895. //
  2896. pcopySet = Dns_RecordSetCopyEx(
  2897. pRegisterSet,
  2898. DnsCharSetUnicode,
  2899. DnsCharSetUtf8 );
  2900. //
  2901. // add set
  2902. //
  2903. status = DnsAddRecordSet_UTF8(
  2904. hCredentials,
  2905. pcopySet,
  2906. fOptions,
  2907. aipServers );
  2908. // cleanup local copy
  2909. Dns_RecordListFree( pcopySet );
  2910. return status;
  2911. }
  2912. //
  2913. // Update test functions are called by system components
  2914. //
  2915. DNS_STATUS
  2916. WINAPI
  2917. DnsUpdateTest_UTF8(
  2918. IN HANDLE hCredentials OPTIONAL,
  2919. IN PCSTR pszName,
  2920. IN DWORD Flags,
  2921. IN PIP_ARRAY pDnsServers OPTIONAL
  2922. )
  2923. /*++
  2924. Routine Description:
  2925. Dynamic DNS routine to test whether the caller can update the
  2926. records in the DNS domain name space for the given record name.
  2927. Arguments:
  2928. hCredentials - handle to credentials to be used for update.
  2929. pszName - the record set name that the caller wants to test.
  2930. Flags - the Dynamic DNS update options that the caller may wish to
  2931. use (see dnsapi.h).
  2932. pDnsServers - a specific list of servers to goto to figure out the
  2933. authoritative DNS server(s) for the given record set
  2934. domain zone name.
  2935. Return Value:
  2936. None.
  2937. --*/
  2938. {
  2939. PWSTR pnameWide = NULL;
  2940. DNS_STATUS status = NO_ERROR;
  2941. DNSDBG( TRACE, (
  2942. "DnsUpdateTest_UTF8( %s )\n",
  2943. pszName ));
  2944. if ( !pszName )
  2945. {
  2946. return ERROR_INVALID_PARAMETER;
  2947. }
  2948. pnameWide = Dns_NameCopyAllocate(
  2949. (PCHAR) pszName,
  2950. 0,
  2951. DnsCharSetUtf8,
  2952. DnsCharSetUnicode );
  2953. if ( !pnameWide )
  2954. {
  2955. return ERROR_INVALID_NAME;
  2956. }
  2957. status = DnsUpdateTest_W(
  2958. hCredentials,
  2959. (PCWSTR) pnameWide,
  2960. Flags,
  2961. pDnsServers );
  2962. FREE_HEAP( pnameWide );
  2963. return status;
  2964. }
  2965. DNS_STATUS
  2966. WINAPI
  2967. DnsUpdateTest_A(
  2968. IN HANDLE hCredentials OPTIONAL,
  2969. IN PCSTR pszName,
  2970. IN DWORD Flags,
  2971. IN PIP_ARRAY pDnsServers OPTIONAL
  2972. )
  2973. /*++
  2974. Routine Description:
  2975. Dynamic DNS routine to test whether the caller can update the
  2976. records in the DNS domain name space for the given record name.
  2977. Arguments:
  2978. hCredentials - handle to credentials to be used for update.
  2979. pszName - the record set name that the caller wants to test.
  2980. Flags - the Dynamic DNS update options that the caller may wish to
  2981. use (see dnsapi.h).
  2982. pDnsServers - a specific list of servers to goto to figure out the
  2983. authoritative DNS server(s) for the given record set
  2984. domain zone name.
  2985. Return Value:
  2986. None.
  2987. --*/
  2988. {
  2989. PWSTR pnameWide = NULL;
  2990. DNS_STATUS status = NO_ERROR;
  2991. DNSDBG( TRACE, (
  2992. "DnsUpdateTest_UTF8( %s )\n",
  2993. pszName ));
  2994. if ( !pszName )
  2995. {
  2996. return ERROR_INVALID_PARAMETER;
  2997. }
  2998. pnameWide = Dns_NameCopyAllocate(
  2999. (PCHAR) pszName,
  3000. 0,
  3001. DnsCharSetUtf8,
  3002. DnsCharSetUnicode );
  3003. if ( !pnameWide )
  3004. {
  3005. return ERROR_INVALID_NAME;
  3006. }
  3007. status = DnsUpdateTest_W(
  3008. hCredentials,
  3009. (PCWSTR) pnameWide,
  3010. Flags,
  3011. pDnsServers );
  3012. FREE_HEAP( pnameWide );
  3013. return status;
  3014. }
  3015. DNS_STATUS
  3016. WINAPI
  3017. DnsUpdateTest_W(
  3018. IN HANDLE hCredentials OPTIONAL,
  3019. IN PCWSTR pszName,
  3020. IN DWORD Flags,
  3021. IN PIP_ARRAY pDnsServers OPTIONAL
  3022. )
  3023. /*++
  3024. Routine Description:
  3025. Dynamic DNS routine to test whether the caller can update the
  3026. records in the DNS domain name space for the given record name.
  3027. Arguments:
  3028. hCredentials - handle to credentials to be used for update.
  3029. pszName - the record set name that the caller wants to test.
  3030. Flags - the Dynamic DNS update options that the caller may wish to
  3031. use (see dnsapi.h).
  3032. pDnsServers - a specific list of servers to goto to figure out the
  3033. authoritative DNS server(s) for the given record set
  3034. domain zone name.
  3035. Return Value:
  3036. None.
  3037. --*/
  3038. {
  3039. DNS_STATUS status = NO_ERROR;
  3040. DNS_RECORD record;
  3041. DWORD flags = Flags;
  3042. LPSTR pnameUtf8 = NULL;
  3043. DNSDBG( TRACE, (
  3044. "DnsUpdateTest_W( %S )\n",
  3045. pszName ));
  3046. //
  3047. // validation
  3048. //
  3049. if ( flags & DNS_UNACCEPTABLE_UPDATE_OPTIONS )
  3050. {
  3051. return ERROR_INVALID_PARAMETER;
  3052. }
  3053. if ( !pszName )
  3054. {
  3055. return ERROR_INVALID_PARAMETER;
  3056. }
  3057. //
  3058. // try resolver
  3059. //
  3060. if ( flags & DNS_UPDATE_TEST_USE_LOCAL_SYS_ACCT )
  3061. {
  3062. DWORD rpcStatus = NO_ERROR;
  3063. if ( !pDnsServers ||
  3064. pDnsServers->AddrCount != 1 )
  3065. {
  3066. return ERROR_INVALID_PARAMETER;
  3067. }
  3068. RpcTryExcept
  3069. {
  3070. status = CRrUpdateTest(
  3071. NULL,
  3072. (PWSTR) pszName,
  3073. 0,
  3074. pDnsServers->AddrArray[0] );
  3075. }
  3076. RpcExcept( DNS_RPC_EXCEPTION_FILTER )
  3077. {
  3078. rpcStatus = RpcExceptionCode();
  3079. }
  3080. RpcEndExcept
  3081. if ( rpcStatus == NO_ERROR )
  3082. {
  3083. return status;
  3084. }
  3085. return rpcStatus;
  3086. }
  3087. //
  3088. // direct update attempt
  3089. //
  3090. //
  3091. // read update config
  3092. //
  3093. Reg_RefreshUpdateConfig();
  3094. if ( UseSystemDefaultForSecurity( flags ) )
  3095. {
  3096. flags |= g_UpdateSecurityLevel;
  3097. }
  3098. if ( hCredentials )
  3099. {
  3100. flags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
  3101. }
  3102. //
  3103. // build record
  3104. // - NOEXIST prerequisite
  3105. //
  3106. pnameUtf8 = Dns_NameCopyAllocate(
  3107. (PCHAR) pszName,
  3108. 0,
  3109. DnsCharSetUnicode,
  3110. DnsCharSetUtf8 );
  3111. if ( ! pnameUtf8 )
  3112. {
  3113. return DNS_ERROR_NO_MEMORY;
  3114. }
  3115. RtlZeroMemory( &record, sizeof(DNS_RECORD) );
  3116. record.pName = (PDNS_NAME) pnameUtf8;
  3117. record.wType = DNS_TYPE_ANY;
  3118. record.wDataLength = 0;
  3119. record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
  3120. //
  3121. // do the prereq update
  3122. //
  3123. status = DoQuickUpdate(
  3124. &record,
  3125. flags,
  3126. TRUE,
  3127. pDnsServers,
  3128. hCredentials );
  3129. FREE_HEAP( pnameUtf8 );
  3130. return status;
  3131. }
  3132. //
  3133. // Update execution functions
  3134. //
  3135. DNS_STATUS
  3136. DoQuickUpdate(
  3137. IN PDNS_RECORD pRecord,
  3138. IN DWORD dwFlags,
  3139. IN BOOL fUpdateTestMode,
  3140. IN PIP_ARRAY pServerList OPTIONAL,
  3141. IN HANDLE hCreds OPTIONAL
  3142. )
  3143. /*++
  3144. Routine Description:
  3145. None.
  3146. Arguments:
  3147. None.
  3148. Return Value:
  3149. None.
  3150. --*/
  3151. {
  3152. DNS_STATUS status = NO_ERROR;
  3153. PSTR pzoneName;
  3154. PDNS_NAME pname = pRecord->pName;
  3155. PDNS_NETINFO pnetInfo = NULL;
  3156. DNSDBG( UPDATE, (
  3157. "DoQuickUpdate( rr=%p, flag=%08x )\n",
  3158. pRecord,
  3159. dwFlags ));
  3160. IF_DNSDBG( UPDATE )
  3161. {
  3162. DnsDbg_RecordSet(
  3163. "Entering DoQuickUpdate():",
  3164. pRecord );
  3165. }
  3166. //
  3167. // caller has particular server list
  3168. //
  3169. if ( pServerList )
  3170. {
  3171. IP_ADDRESS serverIp;
  3172. PIP_ARRAY pserverListCopy = Dns_CreateIpArrayCopy( pServerList );
  3173. if ( !pserverListCopy )
  3174. {
  3175. return DNS_ERROR_NO_MEMORY;
  3176. }
  3177. status = DoQuickFAZ(
  3178. &pnetInfo,
  3179. pname,
  3180. pserverListCopy );
  3181. if ( status != ERROR_SUCCESS )
  3182. {
  3183. FREE_HEAP( pserverListCopy );
  3184. pserverListCopy = NULL;
  3185. return status;
  3186. }
  3187. //
  3188. // FAZ should always produce update network info blob
  3189. //
  3190. DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
  3191. pzoneName = NetInfo_UpdateZoneName( pnetInfo );
  3192. if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
  3193. {
  3194. status = DoMultiMasterUpdate(
  3195. pRecord,
  3196. dwFlags,
  3197. hCreds,
  3198. pzoneName,
  3199. 0,
  3200. pserverListCopy );
  3201. }
  3202. else
  3203. {
  3204. status = DoQuickUpdateEx(
  3205. NULL,
  3206. pRecord,
  3207. dwFlags,
  3208. pnetInfo,
  3209. hCreds );
  3210. if ( status == ERROR_TIMEOUT )
  3211. {
  3212. serverIp = pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress;
  3213. #if DBG
  3214. if ( g_IsDnsServer &&
  3215. IsLocalIpAddress( serverIp ) )
  3216. {
  3217. DnsDbg_PrintfToDebugger(
  3218. "DNSAPI: Note that DDNS update to local server\n"
  3219. " with IP address 0x%.8x timed out,\n"
  3220. " now trying other DNS servers\n"
  3221. " authoritative for zone (%s)\n",
  3222. serverIp,
  3223. pzoneName );
  3224. }
  3225. #endif
  3226. status = DoMultiMasterUpdate(
  3227. pRecord,
  3228. dwFlags,
  3229. hCreds,
  3230. pzoneName,
  3231. serverIp,
  3232. pserverListCopy );
  3233. }
  3234. }
  3235. NetInfo_Free( pnetInfo );
  3236. FREE_HEAP( pserverListCopy );
  3237. pserverListCopy = NULL;
  3238. return status;
  3239. }
  3240. //
  3241. // server list unspecified
  3242. // - use FAZ to figure it out
  3243. //
  3244. else
  3245. {
  3246. PIP_ARRAY serverListArray[ UPDATE_ADAPTER_LIMIT ];
  3247. PDNS_NETINFO networkInfoArray[ UPDATE_ADAPTER_LIMIT ];
  3248. DWORD netCount = UPDATE_ADAPTER_LIMIT;
  3249. DWORD iter;
  3250. BOOL bsuccess = FALSE;
  3251. //
  3252. // build server list for update
  3253. // - collapse adapters on same network into single adapter
  3254. // - FAZ to find update servers
  3255. // - collapse results from same network into single target
  3256. //
  3257. netCount = GetDnsServerListsForUpdate(
  3258. serverListArray,
  3259. netCount,
  3260. dwFlags
  3261. );
  3262. status = CollapseDnsServerListsForUpdate(
  3263. serverListArray,
  3264. networkInfoArray,
  3265. & netCount,
  3266. pname );
  3267. DNS_ASSERT( netCount <= UPDATE_ADAPTER_LIMIT );
  3268. if ( netCount == 0 )
  3269. {
  3270. if ( status == ERROR_SUCCESS )
  3271. {
  3272. status = DNS_ERROR_NO_DNS_SERVERS;
  3273. }
  3274. return status;
  3275. }
  3276. //
  3277. // do update on all distinct (disjoint) networks
  3278. //
  3279. for ( iter = 0;
  3280. iter < netCount;
  3281. iter++ )
  3282. {
  3283. PIP_ARRAY pdnsArray = serverListArray[ iter ];
  3284. pnetInfo = networkInfoArray[ iter ];
  3285. if ( !pnetInfo )
  3286. {
  3287. ASSERT( FALSE );
  3288. FREE_HEAP( pdnsArray );
  3289. continue;
  3290. }
  3291. DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
  3292. pzoneName = NetInfo_UpdateZoneName( pnetInfo );
  3293. //
  3294. // multimater update?
  3295. // - if flag set
  3296. // - or simple update (best net) times out
  3297. //
  3298. if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
  3299. {
  3300. status = DoMultiMasterUpdate(
  3301. pRecord,
  3302. dwFlags,
  3303. hCreds,
  3304. pzoneName,
  3305. 0,
  3306. pdnsArray );
  3307. }
  3308. else
  3309. {
  3310. status = DoQuickUpdateEx(
  3311. NULL,
  3312. pRecord,
  3313. dwFlags,
  3314. pnetInfo,
  3315. hCreds );
  3316. if ( status == ERROR_TIMEOUT )
  3317. {
  3318. IP_ADDRESS serverIp;
  3319. serverIp = pnetInfo->AdapterArray[0]
  3320. ->ServerArray[0].IpAddress;
  3321. status = DoMultiMasterUpdate(
  3322. pRecord,
  3323. dwFlags,
  3324. hCreds,
  3325. pzoneName,
  3326. serverIp,
  3327. pdnsArray );
  3328. }
  3329. }
  3330. NetInfo_Free( pnetInfo );
  3331. FREE_HEAP( pdnsArray );
  3332. if ( status == NO_ERROR ||
  3333. ( fUpdateTestMode &&
  3334. ( status == DNS_ERROR_RCODE_YXDOMAIN ||
  3335. status == DNS_ERROR_RCODE_YXRRSET ||
  3336. status == DNS_ERROR_RCODE_NXRRSET ) ) )
  3337. {
  3338. bsuccess = TRUE;
  3339. }
  3340. }
  3341. //
  3342. // successful update on any network counts as success
  3343. //
  3344. // DCR_QUESTION: not sure why don't just NO_ERROR all bsuccess,
  3345. // only case would be this fUpdateTestMode thing above
  3346. // on single network
  3347. //
  3348. if ( bsuccess )
  3349. {
  3350. if ( netCount != 1 )
  3351. {
  3352. return NO_ERROR;
  3353. }
  3354. }
  3355. return status;
  3356. }
  3357. }
  3358. DNS_STATUS
  3359. DoQuickUpdateEx(
  3360. OUT PDNS_MSG_BUF * ppMsgRecv, OPTIONAL
  3361. IN PDNS_RECORD pRecord,
  3362. IN DWORD dwFlags,
  3363. IN PDNS_NETINFO pNetworkInfo,
  3364. IN HANDLE hCreds OPTIONAL
  3365. )
  3366. /*++
  3367. Routine Description:
  3368. None.
  3369. Arguments:
  3370. None.
  3371. Return Value:
  3372. None.
  3373. --*/
  3374. {
  3375. DNS_STATUS status = NO_ERROR;
  3376. PDNS_MSG_BUF pmsg = NULL;
  3377. DNSDBG( TRACE, ( "DoQuickUpdateEx()\n" ));
  3378. //
  3379. // do update
  3380. // - optionally specify update context through net adapter list
  3381. // otherwise DnsUpdateEx() will use FAZ
  3382. //
  3383. status = DnsUpdate(
  3384. pRecord,
  3385. dwFlags,
  3386. pNetworkInfo,
  3387. hCreds,
  3388. &pmsg
  3389. );
  3390. if ( pmsg )
  3391. {
  3392. //
  3393. // DCR: why LastDnsServerUpdated requires these errors?
  3394. //
  3395. if ( status == NO_ERROR ||
  3396. status == DNS_ERROR_RCODE_SERVER_FAILURE ||
  3397. status == DNS_ERROR_RCODE_NOT_IMPLEMENTED ||
  3398. status == DNS_ERROR_RCODE_REFUSED ||
  3399. status == DNS_ERROR_RCODE_YXRRSET ||
  3400. status == DNS_ERROR_RCODE_NXRRSET )
  3401. {
  3402. IP4_ADDRESS ip = MSG_REMOTE_IP4(pmsg);
  3403. DNSDBG( TRACE, ( "DNS Update sent to server 0x%x\n", ip ));
  3404. g_LastDNSServerUpdated = ip;
  3405. }
  3406. //
  3407. // build last update error blob here
  3408. //
  3409. if ( status != NO_ERROR )
  3410. {
  3411. SetLastFailedUpdateInfo(
  3412. pmsg,
  3413. status );
  3414. }
  3415. }
  3416. if ( ppMsgRecv )
  3417. {
  3418. *ppMsgRecv = pmsg;
  3419. }
  3420. else
  3421. {
  3422. if ( pmsg )
  3423. {
  3424. FREE_HEAP( pmsg );
  3425. }
  3426. }
  3427. GUI_MODE_SETUP_WS_CLEANUP( g_InNTSetupMode );
  3428. return status;
  3429. }
  3430. DNS_STATUS
  3431. DoMultiMasterUpdate(
  3432. IN PDNS_RECORD pRecord,
  3433. IN DWORD dwFlags,
  3434. IN HANDLE hCreds OPTIONAL,
  3435. IN LPSTR pszDomain,
  3436. IN IP_ADDRESS BadIp,
  3437. IN PIP_ARRAY pServerList
  3438. )
  3439. /*++
  3440. Routine Description:
  3441. Do update to multi-master DNS primary.
  3442. Arguments:
  3443. pRecord -- record list to update
  3444. Flags -- update options
  3445. hCreds -- update credentials
  3446. pszDomain -- domain (zone) name to update
  3447. BadIp -- IP of server that didn't response to previous update attempt
  3448. pServerList -- list of DNS servers
  3449. Return Value:
  3450. ERROR_SUCCESS if successful.
  3451. ErrorCode on failure.
  3452. --*/
  3453. {
  3454. PDNS_NETINFO pnetInfo = NULL;
  3455. PIP_ARRAY pnsList = NULL;
  3456. PIP_ARRAY pbadServerList = NULL;
  3457. DNS_STATUS status = DNS_ERROR_NO_DNS_SERVERS;
  3458. DWORD iter;
  3459. //
  3460. // Get the full NS server list for the domain name and x out BadIp
  3461. // if present.
  3462. //
  3463. pnsList = GetNameServersListForDomain( pszDomain, pServerList );
  3464. if ( !pnsList )
  3465. {
  3466. return status;
  3467. }
  3468. if ( pnsList->AddrCount == 1 &&
  3469. Dns_IsAddressInIpArray( pnsList, BadIp ) )
  3470. {
  3471. status = ERROR_TIMEOUT;
  3472. goto Done;
  3473. }
  3474. //
  3475. // Create and initialize bad servers list with BadIp
  3476. //
  3477. pbadServerList = Dns_CreateIpArray( pnsList->AddrCount + 1 );
  3478. if ( !pbadServerList )
  3479. {
  3480. status = DNS_ERROR_NO_MEMORY;
  3481. goto Done;
  3482. }
  3483. if ( BadIp )
  3484. {
  3485. Dns_AddIpToIpArray( pbadServerList, BadIp );
  3486. }
  3487. //
  3488. // attempt update against each multi-master DNS server
  3489. //
  3490. // identify multi-master servers as those which return their themselves
  3491. // as the authoritative server when do FAZ query
  3492. //
  3493. for ( iter = 0; iter < pnsList->AddrCount; iter++ )
  3494. {
  3495. IP_ARRAY ipArray;
  3496. IP_ADDRESS serverIp = pnsList->AddrArray[iter];
  3497. //
  3498. // If the current server that we are about to FAZ to is in
  3499. // the ignore list, skip it . . .
  3500. //
  3501. if ( Dns_IsAddressInIpArray( pbadServerList, serverIp ) )
  3502. {
  3503. continue;
  3504. }
  3505. ipArray.AddrCount = 1;
  3506. ipArray.AddrArray[0] = serverIp;
  3507. status = DoQuickFAZ(
  3508. &pnetInfo,
  3509. pszDomain,
  3510. &ipArray );
  3511. if ( status != ERROR_SUCCESS )
  3512. {
  3513. continue;
  3514. }
  3515. DNS_ASSERT( pnetInfo->AdapterCount == 1 );
  3516. DNS_ASSERT( pnetInfo->AdapterArray[0]->ServerCount != 0 );
  3517. if ( serverIp != pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress )
  3518. {
  3519. serverIp = pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress;
  3520. //
  3521. // If the current server that we are about to FAZ to is in
  3522. // the ignore list, skip it . . .
  3523. //
  3524. if ( Dns_IsAddressInIpArray( pbadServerList, serverIp ) )
  3525. {
  3526. NetInfo_Free( pnetInfo );
  3527. continue;
  3528. }
  3529. }
  3530. status = DoQuickUpdateEx(
  3531. NULL,
  3532. pRecord,
  3533. dwFlags,
  3534. pnetInfo,
  3535. hCreds
  3536. );
  3537. NetInfo_Free( pnetInfo );
  3538. if ( status == ERROR_TIMEOUT )
  3539. {
  3540. //
  3541. // Add serverIp to ignore list
  3542. //
  3543. Dns_AddIpToIpArray( pbadServerList, serverIp );
  3544. }
  3545. else
  3546. {
  3547. if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
  3548. {
  3549. Dns_AddIpToIpArray( pbadServerList, serverIp );
  3550. }
  3551. else
  3552. {
  3553. goto Done;
  3554. }
  3555. }
  3556. }
  3557. Done:
  3558. FREE_HEAP( pnsList );
  3559. FREE_HEAP( pbadServerList );
  3560. return status;
  3561. }
  3562. //
  3563. // DCR_DELETE: not sure of the point of GetLastServerUpdateIp()
  3564. //
  3565. IP_ADDRESS
  3566. DnsGetLastServerUpdateIP(
  3567. void )
  3568. /*++
  3569. Routine Description:
  3570. None.
  3571. Arguments:
  3572. None.
  3573. Return Value:
  3574. None.
  3575. --*/
  3576. {
  3577. return g_LastDNSServerUpdated;
  3578. }
  3579. //
  3580. // Last failed update info
  3581. //
  3582. DNS_FAILED_UPDATE_INFO g_FailedUpdateInfo = { 0, 0, 0, 0 };
  3583. VOID
  3584. DnsGetLastFailedUpdateInfo(
  3585. OUT PDNS_FAILED_UPDATE_INFO pInfo
  3586. )
  3587. /*++
  3588. Routine Description:
  3589. Retrieve failed update information.
  3590. Arguments:
  3591. pInfo -- ptr to receive failed info blob
  3592. Return Value:
  3593. None.
  3594. --*/
  3595. {
  3596. // fill in last info
  3597. RtlCopyMemory(
  3598. pInfo,
  3599. & g_FailedUpdateInfo,
  3600. sizeof(*pInfo) );
  3601. }
  3602. VOID
  3603. SetLastFailedUpdateInfo(
  3604. IN PDNS_MSG_BUF pMsg,
  3605. IN DNS_STATUS Status
  3606. )
  3607. /*++
  3608. Routine Description:
  3609. Set last failed update info.
  3610. Arguments:
  3611. pMsg -- message with update failure
  3612. Status -- status
  3613. Return Value:
  3614. None.
  3615. --*/
  3616. {
  3617. g_FailedUpdateInfo.Ip4Address = MSG_REMOTE_IP4(pMsg);
  3618. //g_FailedUpdateInfo.Ip6Address = MSG_REMOTE_IP6(pMsg);
  3619. g_FailedUpdateInfo.Status = Status;
  3620. g_FailedUpdateInfo.Rcode = pMsg->MessageHead.ResponseCode;
  3621. }
  3622. //
  3623. // DCR: include client secure update here
  3624. // to do so, will have to expose
  3625. // in dnslib some of the security utilities
  3626. // but then can REMOVE exports of a bunch
  3627. // of the send\recv\socket routines
  3628. //
  3629. //
  3630. // End of udpate.c
  3631. //