mirror of https://github.com/tongzx/nt5src
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
4681 lines
107 KiB
/*++
|
|
|
|
Copyright (c) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
update.c
|
|
|
|
Abstract:
|
|
|
|
Domain Name System (DNS) API
|
|
|
|
Update client routines.
|
|
|
|
Author:
|
|
|
|
Jim Gilroy (jamesg) October, 1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "local.h"
|
|
|
|
|
|
//
|
|
// Security flag check
|
|
//
|
|
|
|
#define UseSystemDefaultForSecurity(flag) \
|
|
( ((flag) & DNS_UPDATE_SECURITY_CHOICE_MASK) \
|
|
== DNS_UPDATE_SECURITY_USE_DEFAULT )
|
|
|
|
//
|
|
// Local update flag
|
|
// - must make sure this is in UPDATE_RESERVED space
|
|
//
|
|
|
|
#define DNS_UPDATE_LOCAL_COPY (0x00010000)
|
|
|
|
//
|
|
// DCR_DELETE: this is stupid
|
|
//
|
|
|
|
#define DNS_UNACCEPTABLE_UPDATE_OPTIONS \
|
|
(~ \
|
|
( DNS_UPDATE_SHARED | \
|
|
DNS_UPDATE_SECURITY_OFF | \
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT | \
|
|
DNS_UPDATE_SECURITY_ON | \
|
|
DNS_UPDATE_FORCE_SECURITY_NEGO | \
|
|
DNS_UPDATE_TRY_ALL_MASTER_SERVERS | \
|
|
DNS_UPDATE_LOCAL_COPY | \
|
|
DNS_UPDATE_SECURITY_ONLY ))
|
|
|
|
|
|
//
|
|
// Update Timeouts
|
|
//
|
|
// note, max is a little longer than might be expected as DNS server
|
|
// may have to contact primary and wait for primary to do update (inc.
|
|
// disk access) then response
|
|
//
|
|
|
|
#define INITIAL_UPDATE_TIMEOUT (4) // 4 seconds
|
|
#define MAX_UPDATE_TIMEOUT (60) // 60 seconds
|
|
|
|
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
DNS_STATUS
|
|
DoQuickUpdate(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN BOOL fUpdateTestMode,
|
|
IN PIP_ARRAY pServerList OPTIONAL,
|
|
IN HANDLE hCreds OPTIONAL
|
|
);
|
|
|
|
DNS_STATUS
|
|
DoQuickUpdateEx(
|
|
OUT PDNS_MSG_BUF * ppMsgRecv, OPTIONAL
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PDNS_NETINFO pNetworkInfo,
|
|
IN HANDLE hCreds OPTIONAL
|
|
);
|
|
|
|
DNS_STATUS
|
|
DoMultiMasterUpdate(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN HANDLE hCreds OPTIONAL,
|
|
IN LPSTR pszDomain,
|
|
IN IP_ADDRESS BadIp,
|
|
IN PIP_ARRAY pServerList
|
|
);
|
|
|
|
VOID
|
|
SetLastFailedUpdateInfo(
|
|
IN PDNS_MSG_BUF pMsg,
|
|
IN DNS_STATUS Status
|
|
);
|
|
|
|
|
|
|
|
|
|
PCHAR
|
|
Dns_WriteNoDataUpdateRecordToMessage(
|
|
IN PCHAR pch,
|
|
IN PCHAR pchStop,
|
|
IN WORD wClass,
|
|
IN WORD wType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
No data RR cases:
|
|
|
|
This includes prereqs and deletes except for specific record cases.
|
|
|
|
Arguments:
|
|
|
|
pch - ptr to next byte in packet buffer
|
|
|
|
pchStop - end of packet buffer
|
|
|
|
wClass - class
|
|
|
|
wType - desired RR type
|
|
|
|
Return Value:
|
|
|
|
Ptr to next postion in buffer, if successful.
|
|
NULL on error.
|
|
|
|
--*/
|
|
{
|
|
PDNS_WIRE_RECORD pdnsRR;
|
|
|
|
DNSDBG( WRITE, (
|
|
"Writing update RR to packet buffer at %p.\n",
|
|
pch ));
|
|
|
|
//
|
|
// out of space
|
|
//
|
|
|
|
pdnsRR = (PDNS_WIRE_RECORD) pch;
|
|
pch += sizeof( DNS_WIRE_RECORD );
|
|
if ( pch >= pchStop )
|
|
{
|
|
DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// set type and class
|
|
//
|
|
|
|
*(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
|
|
*(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
|
|
|
|
//
|
|
// TTL and datalength zero for all no data cases
|
|
// - prereqs except specific record delete
|
|
// - deletes except specific record delete
|
|
//
|
|
|
|
*(UNALIGNED DWORD *) &pdnsRR->TimeToLive = 0;
|
|
*(UNALIGNED WORD *) &pdnsRR->DataLength = 0;
|
|
|
|
return( pch );
|
|
}
|
|
|
|
|
|
|
|
PCHAR
|
|
Dns_WriteDataUpdateRecordToMessage(
|
|
IN PCHAR pch,
|
|
IN PCHAR pchStop,
|
|
IN WORD wClass,
|
|
IN WORD wType,
|
|
IN DWORD dwTtl,
|
|
IN WORD wDataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
No data RR cases:
|
|
|
|
This includes prereqs and deletes except for specific record cases.
|
|
|
|
Arguments:
|
|
|
|
pch - ptr to next byte in packet buffer
|
|
|
|
pchStop - end of packet buffer
|
|
|
|
wClass - class
|
|
|
|
wType - desired RR type
|
|
|
|
dwTtl - time to live
|
|
|
|
wDataLength - data length
|
|
|
|
Return Value:
|
|
|
|
Ptr to next postion in buffer, if successful.
|
|
NULL on error.
|
|
|
|
--*/
|
|
{
|
|
PDNS_WIRE_RECORD pdnsRR;
|
|
|
|
DNSDBG( WRITE2, (
|
|
"Writing RR to packet buffer at %p.\n",
|
|
pch ));
|
|
|
|
//
|
|
// out of space
|
|
//
|
|
|
|
pdnsRR = (PDNS_WIRE_RECORD) pch;
|
|
pch += sizeof( DNS_WIRE_RECORD );
|
|
if ( pch + wDataLength >= pchStop )
|
|
{
|
|
DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// set type and class
|
|
//
|
|
|
|
*(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
|
|
*(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
|
|
|
|
//
|
|
// TTL and datalength zero for all no data cases
|
|
// - prereqs except specific record delete
|
|
// - deletes except specific record delete
|
|
//
|
|
|
|
*(UNALIGNED DWORD *) &pdnsRR->TimeToLive = htonl( dwTtl );
|
|
*(UNALIGNED WORD *) &pdnsRR->DataLength = htons( wDataLength );
|
|
|
|
return( pch );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Host update routines
|
|
//
|
|
|
|
#if 0
|
|
PDNS_MSG_BUF
|
|
Dns_BuildHostUpdateMessage(
|
|
IN OUT PDNS_MSG_BUF pMsg,
|
|
IN LPSTR pszZone,
|
|
IN LPSTR pszName,
|
|
IN PIP_ARRAY aipAddresses,
|
|
IN DWORD dwTtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build server update message.
|
|
|
|
Arguments:
|
|
|
|
pMsg -- existing message buffer, to use; NULL to allocate new one
|
|
|
|
pszZone -- zone name for update
|
|
|
|
pszName -- full DNS hostname being updated
|
|
|
|
aipAddresses -- IP addresses to be updated
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_HEADER pdnsMsg;
|
|
PCHAR pch;
|
|
PCHAR pchstop;
|
|
DWORD i;
|
|
WORD nameOffset;
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DNS_PRINT((
|
|
"Enter Dns_BuildHostUpdateMessage()\n"
|
|
"\tpMsg = %p\n"
|
|
"\tpszZone = %s\n"
|
|
"\tpszName = %s\n"
|
|
"\tdwTtl = %d\n",
|
|
pMsg,
|
|
pszZone,
|
|
pszName,
|
|
dwTtl ));
|
|
DnsDbg_IpArray(
|
|
"\tHost IP array\n",
|
|
"host",
|
|
aipAddresses );
|
|
}
|
|
|
|
//
|
|
// create message buffer
|
|
//
|
|
|
|
if ( !pMsg )
|
|
{
|
|
DNS_PRINT(( "Allocating new UPDATE message buffer.\n" ));
|
|
|
|
pMsg = ALLOCATE_HEAP( DNS_UDP_ALLOC_LENGTH );
|
|
if ( !pMsg )
|
|
{
|
|
return( NULL );
|
|
}
|
|
RtlZeroMemory(
|
|
pMsg,
|
|
DNS_UDP_ALLOC_LENGTH );
|
|
|
|
pMsg->BufferLength = DNS_UDP_MAX_PACKET_LENGTH;
|
|
pMsg->pBufferEnd = (PCHAR)&pMsg->MessageHead + pMsg->BufferLength;
|
|
|
|
//
|
|
// set default sockaddr info
|
|
// - caller MUST choose remote IP address
|
|
|
|
pMsg->RemoteAddress.sin_family = AF_INET;
|
|
pMsg->RemoteAddress.sin_port = NET_ORDER_DNS_PORT;
|
|
pMsg->RemoteAddressLength = sizeof( SOCKADDR_IN );
|
|
|
|
// set header for update
|
|
|
|
pMsg->MessageHead.Opcode = DNS_OPCODE_UPDATE;
|
|
}
|
|
|
|
//
|
|
// existing message, just verify
|
|
//
|
|
|
|
ELSE_ASSERT( pMsg->MessageHead.Opcode == DNS_OPCODE_UPDATE );
|
|
|
|
//
|
|
// reset current pointer after header
|
|
// - note: send length is set based on this ptr
|
|
//
|
|
|
|
pMsg->pCurrent = pMsg->MessageBody;
|
|
|
|
|
|
//
|
|
// build message
|
|
//
|
|
|
|
pch = pMsg->pCurrent;
|
|
pchstop = pMsg->pBufferEnd;
|
|
|
|
//
|
|
// zone section
|
|
//
|
|
|
|
pMsg->MessageHead.QuestionCount = 1;
|
|
pch = Dns_WriteDottedNameToPacket(
|
|
pch,
|
|
pchstop,
|
|
pszZone,
|
|
NULL,
|
|
0,
|
|
FALSE );
|
|
if ( !pch )
|
|
{
|
|
return( NULL );
|
|
}
|
|
*(UNALIGNED WORD *) pch = DNS_RTYPE_SOA;
|
|
pch += sizeof(WORD);
|
|
*(UNALIGNED WORD *) pch = DNS_RCLASS_INTERNET;
|
|
pch += sizeof(WORD);
|
|
|
|
//
|
|
// prerequisites -- no records
|
|
//
|
|
|
|
pMsg->MessageHead.AnswerCount = 0;
|
|
|
|
//
|
|
// update
|
|
// - delete A records at name
|
|
// - add new A records
|
|
//
|
|
|
|
// save offset to host name for future writes
|
|
|
|
nameOffset = (WORD)(pch - (PCHAR) &pMsg->MessageHead);
|
|
|
|
pch = Dns_WriteDottedNameToPacket(
|
|
pch,
|
|
pchstop,
|
|
pszName,
|
|
pszZone,
|
|
DNS_OFFSET_TO_QUESTION_NAME,
|
|
FALSE );
|
|
if ( !pch )
|
|
{
|
|
DNS_PRINT(( "ERROR writing dotted name to packet.\n" ));
|
|
return( NULL );
|
|
}
|
|
pch = Dns_WriteNoDataUpdateRecordToMessage(
|
|
pch,
|
|
pchstop,
|
|
DNS_CLASS_ALL, // delete all
|
|
DNS_TYPE_A // A records
|
|
);
|
|
DNS_ASSERT( pch );
|
|
|
|
//
|
|
// add A record for each address in array
|
|
// - use offset for name
|
|
// - write IP
|
|
|
|
for ( i=0; i<aipAddresses->AddrCount; i++ )
|
|
{
|
|
*(UNALIGNED WORD *) pch = htons( (WORD)(nameOffset|(WORD)0xC000) );
|
|
pch += sizeof( WORD );
|
|
pch = Dns_WriteDataUpdateRecordToMessage(
|
|
pch,
|
|
pchstop,
|
|
DNS_CLASS_INTERNET,
|
|
DNS_TYPE_A, // A records
|
|
dwTtl,
|
|
sizeof(IP_ADDRESS)
|
|
);
|
|
DNS_ASSERT( pch );
|
|
*(UNALIGNED DWORD *) pch = aipAddresses->AddrArray[i];
|
|
pch += sizeof(DWORD);
|
|
}
|
|
|
|
// total update sections RRs
|
|
// one delete RR, plus one for each new IP
|
|
|
|
pMsg->MessageHead.NameServerCount = (USHORT)(aipAddresses->AddrCount + 1);
|
|
|
|
//
|
|
// additional section - no records
|
|
//
|
|
|
|
pMsg->MessageHead.AdditionalCount = 0;
|
|
|
|
//
|
|
// reset current ptr -- need for send routine
|
|
//
|
|
|
|
pMsg->pCurrent = pch;
|
|
|
|
IF_DNSDBG( SEND )
|
|
{
|
|
DnsDbg_Message(
|
|
"UPDATE packet built",
|
|
pMsg );
|
|
}
|
|
return( pMsg );
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
PDNS_RECORD
|
|
Dns_HostUpdateRRSet(
|
|
IN LPSTR pszHostName,
|
|
IN PIP_ARRAY AddrArray,
|
|
IN DWORD dwTtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create records for host update:
|
|
-- whack of all A records
|
|
-- add of all A records in new set
|
|
|
|
Arguments:
|
|
|
|
pszHostName -- host name, FULL FQDN
|
|
|
|
AddrArray -- new IPs of host
|
|
|
|
dwTtl -- TTL for records
|
|
|
|
Return Value:
|
|
|
|
Ptr to record list.
|
|
NULL on error.
|
|
|
|
--*/
|
|
{
|
|
DNS_RRSET rrset;
|
|
PDNS_RECORD prr;
|
|
DWORD i;
|
|
|
|
//
|
|
// create whack
|
|
//
|
|
|
|
prr = Dns_AllocateRecord( 0 );
|
|
if ( ! prr )
|
|
{
|
|
return( NULL );
|
|
}
|
|
prr->pName = pszHostName;
|
|
prr->wType = DNS_TYPE_A;
|
|
prr->Flags.S.Section = DNSREC_UPDATE;
|
|
prr->Flags.S.Delete = TRUE;
|
|
|
|
//
|
|
// create update record for each address
|
|
//
|
|
|
|
if ( !AddrArray )
|
|
{
|
|
return( prr );
|
|
}
|
|
DNS_RRSET_INIT( rrset );
|
|
DNS_RRSET_ADD( rrset, prr );
|
|
|
|
for ( i=0; i<AddrArray->AddrCount; i++ )
|
|
{
|
|
prr = Dns_AllocateRecord( sizeof(DNS_A_DATA) );
|
|
if ( ! prr )
|
|
{
|
|
Dns_RecordListFree( rrset.pFirstRR );
|
|
return( NULL );
|
|
}
|
|
prr->pName = pszHostName;
|
|
prr->wType = DNS_TYPE_A;
|
|
prr->Flags.S.Section = DNSREC_UPDATE;
|
|
prr->dwTtl = dwTtl;
|
|
prr->Data.A.IpAddress = AddrArray->AddrArray[i];
|
|
|
|
DNS_RRSET_ADD( rrset, prr );
|
|
}
|
|
|
|
// return ptr to first record in list
|
|
|
|
return( rrset.pFirstRR );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// DCR: dead code, remove
|
|
//
|
|
DNS_STATUS
|
|
Dns_UpdateHostAddrs(
|
|
IN LPSTR pszName,
|
|
IN PIP_ARRAY aipAddresses,
|
|
IN PIP_ARRAY aipServers,
|
|
IN DWORD dwTtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates client's A records registered with DNS server.
|
|
|
|
Arguments:
|
|
|
|
pszName -- name (FQDN) of client to update
|
|
|
|
aipAddresses -- counted array of new client IP addrs
|
|
|
|
aipServers -- counted array of DNS server IP addrs
|
|
|
|
dwTtl -- TTL for new A records
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_RECORD prr;
|
|
DNS_STATUS status;
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DNS_PRINT((
|
|
"Enter Dns_UpdateHostAddrs()\n"
|
|
"\tpszName = %s\n"
|
|
"\tdwTtl = %d\n",
|
|
pszName,
|
|
dwTtl ));
|
|
DnsDbg_IpArray(
|
|
"\tHost IP array\n",
|
|
"\tHost",
|
|
aipAddresses );
|
|
DnsDbg_IpArray(
|
|
"\tNS IP array\n",
|
|
"\tNS",
|
|
aipServers );
|
|
}
|
|
|
|
//
|
|
// never let anyone set a TTL longer than 1 hour
|
|
//
|
|
// DCR: define policy on what our clients should use for TTL
|
|
// one hour is not bad
|
|
// could key off type of address
|
|
// RAS -- 15 minutes (as may be back up again quickly)
|
|
// DHCP -- one hour (may move)
|
|
// static -- one day (machines may be reconfigured)
|
|
//
|
|
|
|
if ( dwTtl > 3600 )
|
|
{
|
|
dwTtl = 3600;
|
|
}
|
|
|
|
//
|
|
// build update RR set
|
|
//
|
|
|
|
prr = Dns_HostUpdateRRSet(
|
|
pszName,
|
|
aipAddresses,
|
|
dwTtl );
|
|
if ( ! prr )
|
|
{
|
|
status = GetLastError();
|
|
DNS_ASSERT( status == DNS_ERROR_NO_MEMORY );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// do the update
|
|
//
|
|
|
|
status = Dns_UpdateLib(
|
|
prr,
|
|
0, // no flags
|
|
NULL, // no adapter list
|
|
NULL, // use default credentials
|
|
NULL // response not desired
|
|
);
|
|
|
|
Dns_RecordListFree( prr );
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Leave Dns_UpdateHostAddrs() status=%d %s\n",
|
|
status,
|
|
Dns_StatusString(status) ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Dns_UpdateLib(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PDNS_NETINFO pNetworkInfo,
|
|
IN HANDLE hCreds OPTIONAL,
|
|
OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send DNS update.
|
|
|
|
Arguments:
|
|
|
|
pRecord -- list of records to send in update
|
|
|
|
dwFlags -- update flags; primarily security
|
|
|
|
pNetworkInfo -- adapter list with necessary info for update
|
|
- zone name
|
|
- primary name server name
|
|
- primary name server IP
|
|
|
|
hCreds -- credentials handle returned from
|
|
|
|
|
|
ppMsgRecv -- OPTIONAL addr to recv ptr to response message
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_MSG_BUF pmsgSend = NULL;
|
|
PDNS_MSG_BUF pmsgRecv = NULL;
|
|
DNS_STATUS status = NO_ERROR;
|
|
WORD length;
|
|
PIP_ARRAY parrayServers = NULL;
|
|
LPSTR pszzone;
|
|
LPSTR pszserverName;
|
|
BOOL fsecure = FALSE;
|
|
BOOL fswitchToTcp = FALSE;
|
|
DNS_HEADER header;
|
|
PCHAR pCreds=NULL;
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Dns_UpdateLib()\n"
|
|
"\tflags = %08x\n"
|
|
"\tpRecord = %p\n"
|
|
"\t\towner = %s\n",
|
|
dwFlags,
|
|
pRecord,
|
|
pRecord ? pRecord->pName : NULL ));
|
|
|
|
//
|
|
// if not a UPDATE compatibile adapter list -- no action
|
|
//
|
|
|
|
if ( ! NetInfo_IsForUpdate(pNetworkInfo) )
|
|
{
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// suck info from adapter list
|
|
//
|
|
|
|
pszzone = NetInfo_UpdateZoneName( pNetworkInfo );
|
|
|
|
parrayServers = NetInfo_ConvertToIpArray( pNetworkInfo );
|
|
|
|
pszserverName = NetInfo_UpdateServerName( pNetworkInfo );
|
|
|
|
DNS_ASSERT( pszzone && parrayServers );
|
|
|
|
//
|
|
// build recv message buffer
|
|
// - must be big enough for TCP
|
|
//
|
|
|
|
pmsgRecv = Dns_AllocateMsgBuf( DNS_TCP_DEFAULT_PACKET_LENGTH );
|
|
if ( !pmsgRecv )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// build update packet
|
|
// note currently this function allocates TCP sized buffer if records
|
|
// given; if this changes need to alloc TCP buffer here
|
|
//
|
|
|
|
CLEAR_DNS_HEADER_FLAGS_AND_XID( &header );
|
|
header.Opcode = DNS_OPCODE_UPDATE;
|
|
|
|
pmsgSend = Dns_BuildPacket(
|
|
&header, // copy header
|
|
TRUE, // ... but not header counts
|
|
pszzone, // question zone\type SOA
|
|
DNS_TYPE_SOA,
|
|
pRecord,
|
|
0, // no other flags
|
|
TRUE // building an update packet
|
|
);
|
|
if ( !pmsgSend)
|
|
{
|
|
DNS_PRINT(( "ERROR: failed send buffer allocation.\n" ));
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// try non-secure first unless explicitly secure only
|
|
//
|
|
|
|
fsecure = (dwFlags & DNS_UPDATE_SECURITY_ONLY);
|
|
|
|
if ( !fsecure )
|
|
{
|
|
status = Dns_SendAndRecv(
|
|
pmsgSend,
|
|
& pmsgRecv,
|
|
NULL, // no response records
|
|
dwFlags,
|
|
parrayServers,
|
|
pNetworkInfo );
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
|
|
}
|
|
|
|
if ( status != DNS_ERROR_RCODE_REFUSED ||
|
|
dwFlags & DNS_UPDATE_SECURITY_OFF )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Failed unsecure update, switching to secure!\n"
|
|
"\tcurrent time (ms) = %d\n",
|
|
GetCurrentTime() ));
|
|
fsecure = TRUE;
|
|
}
|
|
|
|
//
|
|
// security
|
|
// - must have server name
|
|
// - must start package
|
|
//
|
|
|
|
if ( fsecure )
|
|
{
|
|
if ( !pszserverName )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
status = Dns_StartSecurity( FALSE );
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// DCR: hCreds doesn't return security context
|
|
// - idea of something beyond just standard security
|
|
// credentials was we'd been able to return the context
|
|
// handle
|
|
//
|
|
|
|
pCreds = Dns_GetApiContextCredentials(hCreds);
|
|
|
|
status = Dns_DoSecureUpdate(
|
|
pmsgSend,
|
|
pmsgRecv,
|
|
NULL,
|
|
dwFlags,
|
|
pNetworkInfo,
|
|
parrayServers,
|
|
pszserverName,
|
|
pCreds, // initialized in DnsAcquireContextHandle
|
|
NULL // default context name
|
|
);
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
status = Dns_MapRcodeToStatus( pmsgRecv->MessageHead.ResponseCode );
|
|
}
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
// free server array sucked from adapter list
|
|
|
|
if ( parrayServers )
|
|
{
|
|
FREE_HEAP( parrayServers );
|
|
}
|
|
|
|
// return recv message buffer
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
*ppMsgRecv = pmsgRecv;
|
|
}
|
|
else
|
|
{
|
|
FREE_HEAP( pmsgRecv );
|
|
}
|
|
FREE_HEAP( pmsgSend);
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Dns_UpdateLib() completed, status = %d %s.\n\n",
|
|
status,
|
|
Dns_StatusString(status) ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Dns_UpdateLibEx(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PDNS_NAME pszZone,
|
|
IN PDNS_NAME pszServerName,
|
|
IN PIP_ARRAY aipServers,
|
|
IN HANDLE hCreds OPTIONAL,
|
|
OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send DNS update.
|
|
|
|
This routine builds an UPDATE compatible pNetworkInfo from the
|
|
information given. Then calls Dns_Update().
|
|
|
|
Arguments:
|
|
|
|
pRecord -- list of records to send in update
|
|
|
|
pszZone -- zone name for update
|
|
|
|
pszServerName -- server name
|
|
|
|
aipServers -- DNS servers to send update to
|
|
|
|
hCreds -- Optional Credentials info
|
|
|
|
ppMsgRecv -- addr for ptr to recv buffer, if desired
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_NETINFO pnetInfo;
|
|
DNS_STATUS status = NO_ERROR;
|
|
|
|
DNSDBG( UPDATE, ( "Dns_UpdateLibEx()\n" ));
|
|
|
|
//
|
|
// convert params into UPDATE compatible adapter list
|
|
//
|
|
|
|
pnetInfo = NetInfo_CreateForUpdate(
|
|
pszZone,
|
|
pszServerName,
|
|
aipServers,
|
|
0 );
|
|
|
|
if ( !pnetInfo )
|
|
{
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// call real update function
|
|
//
|
|
|
|
status = Dns_UpdateLib(
|
|
pRecord,
|
|
dwFlags,
|
|
pnetInfo,
|
|
hCreds,
|
|
ppMsgRecv );
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Update credentials
|
|
//
|
|
|
|
//
|
|
// Credentials are an optional future parameter to allow the caller
|
|
// to set the context handle to that of a given NT account. This
|
|
// structure will most likely be the following as defined in rpcdce.h:
|
|
//
|
|
// #define SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
|
|
//
|
|
// typedef struct _SEC_WINNT_AUTH_IDENTITY_A {
|
|
// unsigned char __RPC_FAR *User;
|
|
// unsigned long UserLength;
|
|
// unsigned char __RPC_FAR *Domain;
|
|
// unsigned long DomainLength;
|
|
// unsigned char __RPC_FAR *Password;
|
|
// unsigned long PasswordLength;
|
|
// unsigned long Flags;
|
|
// } SEC_WINNT_AUTH_IDENTITY_A, *PSEC_WINNT_AUTH_IDENTITY_A;
|
|
//
|
|
// #define SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2
|
|
//
|
|
// typedef struct _SEC_WINNT_AUTH_IDENTITY_W {
|
|
// unsigned short __RPC_FAR *User;
|
|
// unsigned long UserLength;
|
|
// unsigned short __RPC_FAR *Domain;
|
|
// unsigned long DomainLength;
|
|
// unsigned short __RPC_FAR *Password;
|
|
// unsigned long PasswordLength;
|
|
// unsigned long Flags;
|
|
// } SEC_WINNT_AUTH_IDENTITY_W, *PSEC_WINNT_AUTH_IDENTITY_W;
|
|
//
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsAcquireContextHandle_W(
|
|
IN DWORD CredentialFlags,
|
|
IN PVOID Credentials OPTIONAL,
|
|
OUT PHANDLE pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get credentials handle to security context for update.
|
|
|
|
The handle can for the default process credentials (user account or
|
|
system machine account) or for a specified set of credentials
|
|
identified by Credentials.
|
|
|
|
Arguments:
|
|
|
|
CredentialFlags -- flags
|
|
|
|
Credentials -- a PSEC_WINNT_AUTH_IDENTITY_W
|
|
(explicit definition skipped to avoid requiring rpcdec.h)
|
|
|
|
pContext -- addr to receive credentials handle
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
if ( ! pContext )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pContext = Dns_CreateAPIContext(
|
|
CredentialFlags,
|
|
Credentials,
|
|
TRUE // unicode
|
|
);
|
|
if ( ! *pContext )
|
|
{
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsAcquireContextHandle_A(
|
|
IN DWORD CredentialFlags,
|
|
IN PVOID Credentials OPTIONAL,
|
|
OUT PHANDLE pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get credentials handle to security context for update.
|
|
|
|
The handle can for the default process credentials (user account or
|
|
system machine account) or for a specified set of credentials
|
|
identified by Credentials.
|
|
|
|
Arguments:
|
|
|
|
CredentialFlags -- flags
|
|
|
|
Credentials -- a PSEC_WINNT_AUTH_IDENTITY_A
|
|
(explicit definition skipped to avoid requiring rpcdec.h)
|
|
|
|
pContext -- addr to receive credentials handle
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
if ( ! pContext )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pContext = Dns_CreateAPIContext(
|
|
CredentialFlags,
|
|
Credentials,
|
|
FALSE );
|
|
if ( ! *pContext )
|
|
{
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
DnsReleaseContextHandle(
|
|
IN HANDLE ContextHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees context handle created by DnsAcquireContextHandle_X() routines.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to be closed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if ( ContextHandle )
|
|
{
|
|
//
|
|
// free any cached security context handles
|
|
//
|
|
// DCR_FIX0: should delete all contexts associated with this
|
|
// context (credentials handle) not all
|
|
//
|
|
// DCR: to be robust, user "ContextHandle" should be ref counted
|
|
// it should be set one on create; when in use, incremented
|
|
// then dec when done; then this Free could not collide with
|
|
// another thread's use
|
|
//
|
|
|
|
//Dns_TimeoutSecurityContextListEx( TRUE, ContextHandle );
|
|
|
|
Dns_TimeoutSecurityContextList( TRUE );
|
|
|
|
Dns_FreeAPIContext( ContextHandle );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Utilities
|
|
//
|
|
|
|
DWORD
|
|
prepareUpdateRecordSet(
|
|
IN OUT PDNS_RECORD pRRSet,
|
|
IN BOOL fClearTtl,
|
|
IN BOOL fSetFlags,
|
|
IN WORD wFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate and prepare record set for update.
|
|
- record set is single RR set
|
|
- sets record flags for update
|
|
|
|
Arguments:
|
|
|
|
pRRSet -- record set; MUST be in UTF8
|
|
note: pRRSet is not touched (not OUT param)
|
|
IF fClearTtl AND fSetFlags are both FALSE
|
|
|
|
fClearTtl -- clear TTL in records; TRUE for delete set
|
|
|
|
fSetFlags -- set section and delete flags
|
|
|
|
wFlags -- flags field to set
|
|
(should contain desired section and delete flags)
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ERROR_INVALID_PARAMETER if record set is not acceptable.
|
|
|
|
--*/
|
|
{
|
|
PDNS_RECORD prr;
|
|
PSTR pname;
|
|
WORD type;
|
|
|
|
DNSDBG( TRACE, ( "prepareUpdateRecordSet()\n" ));
|
|
|
|
// validate
|
|
|
|
if ( !pRRSet )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
type = pRRSet->wType;
|
|
|
|
//
|
|
// note: could do an "update-type" check here, but that just
|
|
// A) burns unnecessary memory and cycles
|
|
// B) makes it harder to test bogus records sent in updates
|
|
// to the server
|
|
//
|
|
|
|
pname = (PSTR) pRRSet->pName;
|
|
if ( !pname )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// check each RR in set
|
|
// - validate RR is in set
|
|
// - set RR flags
|
|
//
|
|
|
|
prr = pRRSet;
|
|
|
|
while ( prr )
|
|
{
|
|
if ( fSetFlags )
|
|
{
|
|
prr->Flags.S.Section = 0;
|
|
prr->Flags.S.Delete = 0;
|
|
prr->Flags.DW |= wFlags;
|
|
}
|
|
if ( fClearTtl )
|
|
{
|
|
prr->dwTtl = 0;
|
|
}
|
|
|
|
// check current RR in set
|
|
// - matches name and type
|
|
|
|
if ( prr != pRRSet )
|
|
{
|
|
if ( prr->wType != type ||
|
|
! prr->pName ||
|
|
! Dns_NameCompare_UTF8( pname, prr->pName ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
prr = prr->pNext;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PDNS_RECORD
|
|
DnsBuildUpdateSet(
|
|
IN OUT PDNS_RECORD pPrereqSet,
|
|
IN OUT PDNS_RECORD pAddSet,
|
|
IN OUT PDNS_RECORD pDeleteSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build combined record list for update.
|
|
Combines prereq, delete and add records.
|
|
|
|
Note: record sets MUST be in UTF8.
|
|
|
|
Arguments:
|
|
|
|
pPrereqSet -- prerequisite records; note this does NOT
|
|
include delete preqs (see note below)
|
|
|
|
pAddSet -- records to add
|
|
|
|
pDeleteSet -- records to delete
|
|
|
|
Return Value:
|
|
|
|
Ptr to combined record list for update.
|
|
|
|
--*/
|
|
{
|
|
PDNS_RECORD plast = NULL;
|
|
PDNS_RECORD pfirst = NULL;
|
|
|
|
|
|
DNSDBG( TRACE, ( "DnsBuildUpdateSet()\n" ));
|
|
|
|
//
|
|
// append prereq set
|
|
//
|
|
// DCR: doesn't handle delete prereqs
|
|
// this is fine because we roll our own, but if
|
|
// later expand the function, then need them
|
|
//
|
|
// note, I could add flag==PREREQ datalength==0
|
|
// test in prepareUpdateRecordSet() function, then
|
|
// set Delete flag; however, we'd still have the
|
|
// question of how to distinguish existence (class==ANY)
|
|
// prereq from delete (class==NONE) prereq -- without
|
|
// directly exposing the record Delete flag
|
|
//
|
|
|
|
if ( pPrereqSet )
|
|
{
|
|
plast = pPrereqSet;
|
|
pfirst = pPrereqSet;
|
|
|
|
prepareUpdateRecordSet(
|
|
pPrereqSet,
|
|
FALSE, // no TTL clear
|
|
TRUE, // set flags
|
|
DNSREC_PREREQ // prereq section
|
|
);
|
|
|
|
while ( plast->pNext )
|
|
{
|
|
plast = plast->pNext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// append delete records
|
|
// do before Add records so that delete\add of same record
|
|
// leaves it in place
|
|
//
|
|
|
|
if ( pDeleteSet )
|
|
{
|
|
if ( !plast )
|
|
{
|
|
plast = pDeleteSet;
|
|
pfirst = pDeleteSet;
|
|
}
|
|
else
|
|
{
|
|
plast->pNext = pDeleteSet;
|
|
}
|
|
|
|
prepareUpdateRecordSet(
|
|
pDeleteSet,
|
|
TRUE, // clear TTL
|
|
TRUE, // set flags
|
|
DNSREC_UPDATE | DNSREC_DELETE // update section, delete bit
|
|
);
|
|
|
|
while ( plast->pNext )
|
|
{
|
|
plast = plast->pNext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// append add records
|
|
//
|
|
|
|
if ( pAddSet )
|
|
{
|
|
if ( !plast )
|
|
{
|
|
plast = pAddSet;
|
|
pfirst = pAddSet;
|
|
}
|
|
else
|
|
{
|
|
plast->pNext = pAddSet;
|
|
}
|
|
prepareUpdateRecordSet(
|
|
pAddSet,
|
|
FALSE, // no TTL change
|
|
TRUE, // set flags
|
|
DNSREC_UPDATE // update section
|
|
);
|
|
}
|
|
|
|
return pfirst;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsPtrUpdate(
|
|
IN PDNS_RECORD pRecordList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if update is PTR update.
|
|
|
|
Arguments:
|
|
|
|
pRecordList -- update record list
|
|
|
|
Return Value:
|
|
|
|
TRUE if PTR update.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PDNS_RECORD prr = pRecordList;
|
|
BOOL bptrUpdate = FALSE;
|
|
|
|
//
|
|
// find, then test first record in update section
|
|
//
|
|
|
|
while ( prr )
|
|
{
|
|
if ( prr->Flags.S.Section == DNSREC_UPDATE )
|
|
{
|
|
if ( prr->wType == DNS_TYPE_PTR )
|
|
{
|
|
bptrUpdate = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
prr = prr->pNext;
|
|
}
|
|
|
|
return bptrUpdate;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Replace functions
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
replaceRecordsInSetPrivate(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP_ARRAY pServerList, OPTIONAL
|
|
IN PVOID pReserved,
|
|
IN DNS_CHARSET CharSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Replace record set routine handling all character sets.
|
|
|
|
Arguments:
|
|
|
|
pReplaceSet - replacement record set
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
CharSet - character set of incoming records
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if update successful.
|
|
ErrorCode from server if server rejects update.
|
|
ERROR_INVALID_PARAMETER if bad param.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD preplaceCopy = NULL;
|
|
PDNS_RECORD pupdateList = NULL;
|
|
BOOL btypeDelete;
|
|
DNS_RECORD rrNoCname;
|
|
DNS_RECORD rrDeleteType;
|
|
BOOL fcnameUpdate;
|
|
|
|
DNSDBG( TRACE, (
|
|
"replaceRecordsInSetPrivate()\n"
|
|
"\tpReplaceSet = %p\n"
|
|
"\tOptions = %08x\n"
|
|
"\thCredentials = %p\n"
|
|
"\tpServerList = %p\n"
|
|
"\tCharSet = %d\n",
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
CharSet
|
|
));
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// make local copy in UTF8
|
|
//
|
|
|
|
if ( !pReplaceSet )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
preplaceCopy = Dns_RecordSetCopyEx(
|
|
pReplaceSet,
|
|
CharSet,
|
|
DnsCharSetUtf8 );
|
|
if ( !preplaceCopy )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// validate arguments
|
|
// - must have single RR set
|
|
// - mark them for update
|
|
//
|
|
|
|
status = prepareUpdateRecordSet(
|
|
preplaceCopy,
|
|
FALSE, // no TTL clear
|
|
TRUE, // set flags
|
|
DNSREC_UPDATE // flag as update
|
|
);
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// check if simple type delete
|
|
//
|
|
|
|
btypeDelete = ( preplaceCopy->wDataLength == 0 &&
|
|
preplaceCopy->pNext == NULL );
|
|
|
|
|
|
//
|
|
// set security for update
|
|
//
|
|
|
|
if ( UseSystemDefaultForSecurity( Options ) )
|
|
{
|
|
Options |= g_UpdateSecurityLevel;
|
|
}
|
|
if ( hCredentials )
|
|
{
|
|
Options |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// type delete record
|
|
//
|
|
// if have replace records -- this goes in front
|
|
// if type delete -- then ONLY need this record
|
|
//
|
|
|
|
RtlZeroMemory( &rrDeleteType, sizeof(DNS_RECORD) );
|
|
rrDeleteType.pName = (PDNS_NAME) preplaceCopy->pName;
|
|
rrDeleteType.wType = preplaceCopy->wType;
|
|
rrDeleteType.wDataLength = 0;
|
|
rrDeleteType.Flags.DW = DNSREC_UPDATE | DNSREC_DELETE;
|
|
|
|
if ( btypeDelete )
|
|
{
|
|
rrDeleteType.pNext = NULL;
|
|
}
|
|
else
|
|
{
|
|
rrDeleteType.pNext = preplaceCopy;
|
|
}
|
|
|
|
pupdateList = &rrDeleteType;
|
|
|
|
//
|
|
// CNAME does not exist precondition record
|
|
// - for all updates EXCEPT CNAME
|
|
//
|
|
|
|
fcnameUpdate = ( preplaceCopy->wType == DNS_TYPE_CNAME );
|
|
|
|
if ( !fcnameUpdate )
|
|
{
|
|
RtlZeroMemory( &rrNoCname, sizeof(DNS_RECORD) );
|
|
rrNoCname.pName = (PDNS_NAME) preplaceCopy->pName;
|
|
rrNoCname.wType = DNS_TYPE_CNAME;
|
|
rrNoCname.wDataLength = 0;
|
|
rrNoCname.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
rrNoCname.pNext = &rrDeleteType;
|
|
|
|
pupdateList = &rrNoCname;
|
|
}
|
|
|
|
//
|
|
// do the update
|
|
//
|
|
|
|
status = DoQuickUpdate(
|
|
pupdateList,
|
|
Options,
|
|
FALSE,
|
|
pServerList,
|
|
hCredentials);
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( (LPSTR) preplaceCopy->pName );
|
|
}
|
|
|
|
//
|
|
// CNAME collision test
|
|
//
|
|
// if replacing CNAME may have gotten silent ignore
|
|
// - first check if successfully replaced CNAME
|
|
// - if still not sure, check that no other records
|
|
// at name -- if NON-CNAME found then treat silent ignore
|
|
// as YXRRSET error
|
|
//
|
|
|
|
if ( fcnameUpdate &&
|
|
! btypeDelete &&
|
|
status == NO_ERROR )
|
|
{
|
|
PDNS_RECORD pqueryRR = NULL;
|
|
BOOL fsuccess = FALSE;
|
|
|
|
// DCR: need to query update server list here to
|
|
// avoid intermediate caching
|
|
|
|
status = DnsQuery_UTF8(
|
|
preplaceCopy->pName,
|
|
DNS_TYPE_CNAME,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
pServerList,
|
|
& pqueryRR,
|
|
NULL );
|
|
|
|
if ( status == NO_ERROR &&
|
|
Dns_RecordCompare(
|
|
preplaceCopy,
|
|
pqueryRR ) )
|
|
{
|
|
fsuccess = TRUE;
|
|
}
|
|
Dns_RecordListFree( pqueryRR );
|
|
|
|
if ( fsuccess )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// query for any type at CNAME
|
|
// if found then assume we got a silent update
|
|
// success
|
|
|
|
status = DnsQuery_UTF8(
|
|
preplaceCopy->pName,
|
|
DNS_TYPE_ALL,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
pServerList,
|
|
& pqueryRR,
|
|
NULL );
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
PDNS_RECORD prr = pqueryRR;
|
|
|
|
while ( prr )
|
|
{
|
|
if ( pReplaceSet->wType != prr->wType &&
|
|
Dns_NameCompare_UTF8(
|
|
preplaceCopy->pName,
|
|
prr->pName ) )
|
|
{
|
|
status = DNS_ERROR_RCODE_YXRRSET;
|
|
break;
|
|
}
|
|
prr = prr->pNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
Dns_RecordListFree( pqueryRR );
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
Dns_RecordListFree( preplaceCopy );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetUTF8(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to replace record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pReplaceSet - new record set for name and type
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given securit5y credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNSDBG( TRACE, ( "DnsReplaceRecordSetUTF8()\n" ));
|
|
|
|
return replaceRecordsInSetPrivate(
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
aipServers,
|
|
pReserved,
|
|
DnsCharSetUtf8
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetW(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to replace record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pReplaceSet - new record set for name and type
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNSDBG( TRACE, ( "DnsReplaceRecordSetW()\n" ));
|
|
|
|
return replaceRecordsInSetPrivate(
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
aipServers,
|
|
pReserved,
|
|
DnsCharSetUnicode
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetA(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to replace record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pReplaceSet - new record set for name and type
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNSDBG( TRACE, ( "DnsReplaceRecordSetA()\n" ));
|
|
|
|
return replaceRecordsInSetPrivate(
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
aipServers,
|
|
pReserved,
|
|
DnsCharSetAnsi
|
|
);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Modify functions
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
modifyRecordsInSetPrivate(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP_ARRAY pServerList, OPTIONAL
|
|
IN PVOID pReserved,
|
|
IN DNS_CHARSET CharSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to replace record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pAddRecords - records to register on server
|
|
|
|
pDeleteRecords - records to remove from server
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
CharSet - character set of incoming records
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if update successful.
|
|
ErrorCode from server if server rejects update.
|
|
ERROR_INVALID_PARAMETER if bad param.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD paddCopy = NULL;
|
|
PDNS_RECORD pdeleteCopy = NULL;
|
|
PDNS_RECORD pupdateSet = NULL;
|
|
|
|
DNSDBG( TRACE, (
|
|
"modifyRecordsInSetPrivate()\n"
|
|
"\tpAddSet = %p\n"
|
|
"\tpDeleteSet = %p\n"
|
|
"\tOptions = %08x\n"
|
|
"\thCredentials = %p\n"
|
|
"\tpServerList = %p\n"
|
|
"\tCharSet = %d\n",
|
|
pAddRecords,
|
|
pDeleteRecords,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
CharSet
|
|
));
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// make local copy in UTF8
|
|
//
|
|
|
|
if ( pAddRecords )
|
|
{
|
|
paddCopy = Dns_RecordSetCopyEx(
|
|
pAddRecords,
|
|
CharSet,
|
|
DnsCharSetUtf8 );
|
|
}
|
|
if ( pDeleteRecords )
|
|
{
|
|
pdeleteCopy = Dns_RecordSetCopyEx(
|
|
pDeleteRecords,
|
|
CharSet,
|
|
DnsCharSetUtf8 );
|
|
}
|
|
|
|
//
|
|
// validate arguments
|
|
// - add and delete must be for single RR set
|
|
// and must be for same RR set
|
|
//
|
|
|
|
if ( !paddCopy && !pdeleteCopy )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( paddCopy )
|
|
{
|
|
status = prepareUpdateRecordSet(
|
|
paddCopy,
|
|
FALSE, // no TTL clear
|
|
FALSE, // no flag clear
|
|
0 // no flags to set
|
|
);
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
if ( pdeleteCopy )
|
|
{
|
|
status = prepareUpdateRecordSet(
|
|
pdeleteCopy,
|
|
FALSE, // no TTL clear
|
|
FALSE, // no flag clear
|
|
0 // no flags to set
|
|
);
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ( paddCopy &&
|
|
pdeleteCopy &&
|
|
! Dns_NameCompare_UTF8( paddCopy->pName, pdeleteCopy->pName ) )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// set security for update
|
|
//
|
|
|
|
if ( UseSystemDefaultForSecurity( Options ) )
|
|
{
|
|
Options |= g_UpdateSecurityLevel;
|
|
}
|
|
if ( hCredentials )
|
|
{
|
|
Options |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// create update RRs
|
|
// - no prereqs
|
|
// - delete RRs set for delete
|
|
// - add RRs appended
|
|
//
|
|
|
|
pupdateSet = DnsBuildUpdateSet(
|
|
NULL, // no precons
|
|
paddCopy,
|
|
pdeleteCopy );
|
|
|
|
//
|
|
// do the update
|
|
//
|
|
|
|
status = DoQuickUpdate(
|
|
pupdateSet,
|
|
Options,
|
|
FALSE,
|
|
pServerList,
|
|
hCredentials );
|
|
|
|
//
|
|
// flush cache entry for update
|
|
//
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( (LPSTR) pupdateSet->pName );
|
|
}
|
|
|
|
//
|
|
// cleanup local copy
|
|
//
|
|
|
|
Dns_RecordListFree( pupdateSet );
|
|
|
|
DNSDBG( TRACE, ( "Leave modifyRecordsInSetPrivate()\n" ));
|
|
return status;
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// cleanup copies on failure before combined list
|
|
//
|
|
|
|
Dns_RecordListFree( paddCopy );
|
|
Dns_RecordListFree( pdeleteCopy );
|
|
|
|
DNSDBG( TRACE, ( "Leave modifyRecordsInSetPrivate()\n" ));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_W(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP_ARRAY pServerList, OPTIONAL
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to modify record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pAddRecords - records to register on server
|
|
|
|
pDeleteRecords - records to remove from server
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if update successful.
|
|
ErrorCode from server if server rejects update.
|
|
ERROR_INVALID_PARAMETER if bad param.
|
|
|
|
--*/
|
|
{
|
|
return modifyRecordsInSetPrivate(
|
|
pAddRecords,
|
|
pDeleteRecords,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetUnicode
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_A(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP_ARRAY pServerList, OPTIONAL
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to modify record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pAddRecords - records to register on server
|
|
|
|
pDeleteRecords - records to remove from server
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if update successful.
|
|
ErrorCode from server if server rejects update.
|
|
ERROR_INVALID_PARAMETER if bad param.
|
|
|
|
--*/
|
|
{
|
|
return modifyRecordsInSetPrivate(
|
|
pAddRecords,
|
|
pDeleteRecords,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetAnsi
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_UTF8(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP_ARRAY pServerList, OPTIONAL
|
|
IN PVOID pReserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic update routine to modify record set on DNS server.
|
|
|
|
Arguments:
|
|
|
|
pAddRecords - records to register on server
|
|
|
|
pDeleteRecords - records to remove from server
|
|
|
|
Options - update options
|
|
|
|
pServerList - list of DNS servers to go to; if not given, machines
|
|
default servers are queried to find correct servers to send update to
|
|
|
|
hCredentials - handle to credentials to be used for update; optional,
|
|
if not given security credentials of this process are used in update
|
|
|
|
pReserved - reserved; should be NULL
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if update successful.
|
|
ErrorCode from server if server rejects update.
|
|
ERROR_INVALID_PARAMETER if bad param.
|
|
|
|
--*/
|
|
{
|
|
return modifyRecordsInSetPrivate(
|
|
pAddRecords,
|
|
pDeleteRecords,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetUtf8
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Full scale update API
|
|
//
|
|
|
|
DNS_STATUS
|
|
DnsUpdate(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PDNS_NETINFO pNetworkInfo,
|
|
IN HANDLE hCreds, OPTIONAL
|
|
OUT PDNS_MSG_BUF * ppMsgRecv OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send DNS update.
|
|
|
|
Note if pNetworkInfo is not specified or not a valid UPDATE adapter list,
|
|
then a FindAuthoritativeZones (FAZ) query is done prior to the update.
|
|
|
|
Arguments:
|
|
|
|
pRecord -- list of records to send in update
|
|
|
|
dwFlags -- flags to update
|
|
|
|
pNetworkInfo -- DNS servers to send update to
|
|
|
|
ppMsgRecv -- addr for ptr to recv buffer, if desired
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_NETINFO plocalNetworkInfo = NULL;
|
|
|
|
DNSDBG( TRACE, ( "DnsUpdate()\n" ));
|
|
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// need to build update adapter list from FAZ
|
|
// - only pass on BYPASS_CACHE flag
|
|
// - note DnsFindAuthoritativeZone() will append
|
|
// DNS_QUERY_ALLOW_EMPTY_AUTH_RESP flag yet
|
|
// DnsQuery_UTF8 will die on that flag without
|
|
// BYPASS_CACHE also set, so just set BYPASS_CACHE
|
|
// flag here;
|
|
// bogus, but that's how it is now
|
|
//
|
|
|
|
if ( ! NetInfo_IsForUpdate(pNetworkInfo) )
|
|
{
|
|
status = DnsFindAuthoritativeZone(
|
|
pRecord->pName,
|
|
//(dwFlags & DNS_QUERY_BYPASS_CACHE),
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
NULL, // no specified servers
|
|
& plocalNetworkInfo );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
return( status );
|
|
}
|
|
pNetworkInfo = plocalNetworkInfo;
|
|
}
|
|
|
|
//
|
|
// call the real update routine in dnslib
|
|
//
|
|
|
|
status = Dns_UpdateLib(
|
|
pRecord,
|
|
dwFlags,
|
|
pNetworkInfo,
|
|
hCreds,
|
|
ppMsgRecv );
|
|
|
|
// if there was an error sending the update, flush the resolver
|
|
// cache entry for the zone name to possibly pick up an alternate
|
|
// DNS server for the next retry attempt of a similar update.
|
|
//
|
|
// DCR_QUESTION: is this the correct error code?
|
|
// maybe ERROR_TIMED_OUT?
|
|
//
|
|
|
|
if ( status == DNS_ERROR_RECORD_TIMED_OUT )
|
|
{
|
|
PSTR pzoneName;
|
|
|
|
if ( pNetworkInfo &&
|
|
(pzoneName = NetInfo_UpdateZoneName( pNetworkInfo )) )
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( pzoneName );
|
|
DnsFlushResolverCacheEntry_UTF8( pRecord->pName );
|
|
}
|
|
}
|
|
|
|
// cleanup local adapter list if used
|
|
|
|
if ( plocalNetworkInfo )
|
|
{
|
|
NetInfo_Free( plocalNetworkInfo );
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Private update functions
|
|
//
|
|
// These calls are used only inside dnsapi.dll to do the client
|
|
// host updates. They are exposed in dnsapi.dll only for test
|
|
// purposes.
|
|
//
|
|
//
|
|
// DCR: eliminate nonsense "unique modify" routines -- they add no value
|
|
// moral -- don't let your PM talk to your developers
|
|
//
|
|
// DCR: get rid of old GlennC update routines
|
|
//
|
|
|
|
DNS_STATUS
|
|
DnsRegisterRRSet_Ex (
|
|
IN OUT PDNS_RECORD pRegisterSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN HANDLE hCreds OPTIONAL
|
|
);
|
|
|
|
|
|
DNS_STATUS
|
|
DnsModifyRRSet_Ex (
|
|
IN PDNS_RECORD pCurrentSet,
|
|
IN PDNS_RECORD pNewSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN HANDLE hCreds OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Modify record set of known existing records.
|
|
|
|
Note: this is not my idea of "Modify". It is really "Register"
|
|
where you specify both what you think the existing set is and
|
|
what you want it to be.
|
|
|
|
Like most of these routines -- it's a big waste of time.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD pCopyOfCurrentSet = NULL;
|
|
PDNS_RECORD pCopyOfNewSet = NULL;
|
|
PDNS_RECORD pAddSet = NULL;
|
|
PDNS_RECORD pDeleteSet = NULL;
|
|
PDNS_RECORD pUpdateSet = NULL;
|
|
PDNS_NETINFO pNetworkInfo = NULL;
|
|
|
|
DNSDBG( TRACE, ( "DnsModifyRRSet_Ex()\n" ));
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_RecordSet(
|
|
"DnsModifyRRSet_Ex() -- current set",
|
|
pCurrentSet );
|
|
DnsDbg_RecordSet(
|
|
"DnsModifyRRSet_Ex() -- new set",
|
|
pNewSet );
|
|
}
|
|
|
|
//
|
|
// Validate arguments ...
|
|
//
|
|
if ( ( fOptions != DNS_UPDATE_UNIQUE ) &&
|
|
( fOptions & DNS_UNACCEPTABLE_UPDATE_OPTIONS ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( prepareUpdateRecordSet( pCurrentSet,
|
|
FALSE,
|
|
FALSE,
|
|
0 ) != NO_ERROR )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( prepareUpdateRecordSet( pNewSet,
|
|
FALSE,
|
|
FALSE,
|
|
0 ) != NO_ERROR )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( !Dns_NameCompare_UTF8( pCurrentSet->pName, pNewSet->pName ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the RRSets, to preserve the original RRSets ...
|
|
//
|
|
pCopyOfCurrentSet = Dns_RecordSetCopyEx( pCurrentSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
|
|
if ( !pCopyOfCurrentSet )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
pCopyOfNewSet = Dns_RecordSetCopyEx( pNewSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
if ( !pCopyOfNewSet )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// pAddSet = pCopyOfNewSet - pCopyOfCurrentSet
|
|
// pDeleteSet = pCopyOfCurrentSet - pCopyOfNewSet
|
|
//
|
|
|
|
//
|
|
// no change from previous registration?
|
|
// - touch DNS server to make sure it's in sync
|
|
//
|
|
|
|
if ( Dns_RecordSetCompare( pCopyOfNewSet,
|
|
pCopyOfCurrentSet,
|
|
&pAddSet,
|
|
&pDeleteSet ) )
|
|
{
|
|
status = DnsRegisterRRSet_Ex(
|
|
pCopyOfNewSet,
|
|
fOptions,
|
|
aipServers,
|
|
hCreds );
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// shared update - do simple modify
|
|
// - delete what was registered before, that don't want now
|
|
// - add everything in new set for robustness
|
|
//
|
|
|
|
if ( fOptions & DNS_UPDATE_SHARED )
|
|
{
|
|
//
|
|
// Update with the following:
|
|
// Prerequisites: Nothing
|
|
// Add: pCopyOfNewSet
|
|
// Delete: pDeleteSet
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( NULL,
|
|
pCopyOfNewSet,
|
|
pDeleteSet );
|
|
|
|
//
|
|
// Call update ...
|
|
//
|
|
status = DoQuickUpdate( pUpdateSet,
|
|
fOptions,
|
|
FALSE,
|
|
aipServers,
|
|
hCreds);
|
|
|
|
//
|
|
// Free memory used ...
|
|
//
|
|
Dns_RecordListFree( pUpdateSet );
|
|
pUpdateSet = NULL;
|
|
pCopyOfNewSet = NULL;
|
|
pDeleteSet = NULL;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Unique case
|
|
//
|
|
|
|
//
|
|
// Update with the following:
|
|
// Prerequisites: pCopyOfCurrentSet
|
|
// Add: pAddSet
|
|
// Delete: pDeleteSet
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( pCopyOfCurrentSet,
|
|
pAddSet,
|
|
pDeleteSet );
|
|
|
|
//
|
|
// Call update ...
|
|
//
|
|
status = DoQuickUpdate( pUpdateSet,
|
|
fOptions,
|
|
FALSE,
|
|
aipServers,
|
|
hCreds);
|
|
|
|
//
|
|
// Free memory used ...
|
|
//
|
|
Dns_RecordListFree( pUpdateSet );
|
|
pUpdateSet = NULL;
|
|
pCopyOfCurrentSet = NULL;
|
|
pAddSet = NULL;
|
|
pDeleteSet = NULL;
|
|
|
|
if ( status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
PDNS_RECORD pActualCurrentSet = NULL;
|
|
PDNS_RECORD pSharedSet = NULL;
|
|
PDNS_RECORD pNotUsedSet = NULL;
|
|
DNS_RECORD Record;
|
|
IP_ARRAY ipArray;
|
|
IP_ADDRESS serverIp = DnsGetLastServerUpdateIP();
|
|
|
|
if ( serverIp )
|
|
{
|
|
ipArray.AddrCount = 1;
|
|
ipArray.AddrArray[0] = serverIp;
|
|
}
|
|
|
|
pNetworkInfo = NetInfo_CreateFromIpArray(
|
|
aipServers,
|
|
serverIp,
|
|
FALSE, // no search info
|
|
NULL );
|
|
|
|
//
|
|
// Make another copy of the Current RRSet ...
|
|
//
|
|
pCopyOfCurrentSet = Dns_RecordSetCopyEx(
|
|
pCurrentSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
if ( !pCopyOfCurrentSet )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Query server for pActualCurrentSet ...
|
|
//
|
|
|
|
status = QueryDirectEx(
|
|
NULL, // no response message
|
|
& pActualCurrentSet,
|
|
NULL, // no header
|
|
0, // no header counts
|
|
(LPSTR) pCopyOfCurrentSet->pName,
|
|
pCopyOfCurrentSet->wType,
|
|
NULL, // no input records
|
|
DNS_QUERY_TREAT_AS_FQDN,
|
|
NULL, // no DNS server list
|
|
pNetworkInfo );
|
|
|
|
if ( IsEmptyDnsResponse( pActualCurrentSet ) )
|
|
{
|
|
Dns_RecordListFree( pActualCurrentSet );
|
|
pActualCurrentSet = NULL;
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
status = DNS_ERROR_RCODE_NAME_ERROR;
|
|
}
|
|
}
|
|
|
|
if ( status == DNS_ERROR_RCODE_NAME_ERROR ||
|
|
status == DNS_INFO_NO_RECORDS )
|
|
{
|
|
DNS_RECORD Record;
|
|
|
|
//
|
|
// Query failed to find any entry for given name and type.
|
|
// We now need to assume that the pCurrentSet is that there
|
|
// isn't anything registered.
|
|
//
|
|
RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
|
|
Record.pName = (PDNS_NAME) pCopyOfNewSet->pName;
|
|
Record.wType = pCopyOfNewSet->wType;
|
|
Record.wDataLength = 0; // Meaning all structures not present.
|
|
Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
//
|
|
// Do an update with the following:
|
|
// Prerequisites: None - will be Record above.
|
|
// Add: pRegisterSet
|
|
// Delete: None
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( NULL,
|
|
pCopyOfNewSet,
|
|
NULL );
|
|
|
|
Record.pNext = pCopyOfNewSet;
|
|
|
|
status = DoQuickUpdate( &Record,
|
|
fOptions,
|
|
FALSE,
|
|
serverIp ? &ipArray : aipServers,
|
|
hCreds);
|
|
|
|
if ( status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
status = DNS_ERROR_TRY_AGAIN_LATER;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( status )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Sometimes when DnsQuery is called, the returned record set
|
|
// contains additional records of different types than what
|
|
// was queried for. Need to strip off the additional records
|
|
// from the query results.
|
|
//
|
|
pNotUsedSet = DnsRecordSetDetach( pActualCurrentSet );
|
|
|
|
if ( pNotUsedSet )
|
|
{
|
|
Dns_RecordListFree( pNotUsedSet );
|
|
pNotUsedSet = NULL;
|
|
}
|
|
|
|
//
|
|
// pAddSet = pNewSet - pActualCurrentSet
|
|
// pDeleteSet = pActualCurrentSet - pNewSet
|
|
//
|
|
(void) Dns_RecordSetCompare( pCopyOfNewSet,
|
|
pActualCurrentSet,
|
|
&pAddSet,
|
|
&pDeleteSet );
|
|
|
|
|
|
//
|
|
// pSharedSet = pDeleteSet - pCopyOfCurrentSet
|
|
// pNotUsedSet = pCopyOfCurrentSet - pDeleteSet
|
|
//
|
|
(void) Dns_RecordSetCompare( pDeleteSet,
|
|
pCopyOfCurrentSet,
|
|
&pSharedSet,
|
|
&pNotUsedSet );
|
|
|
|
Dns_RecordListFree( pDeleteSet );
|
|
pDeleteSet = NULL;
|
|
Dns_RecordListFree( pCopyOfCurrentSet );
|
|
pCopyOfCurrentSet = NULL;
|
|
Dns_RecordListFree( pNotUsedSet );
|
|
pNotUsedSet = NULL;
|
|
Dns_RecordListFree( pActualCurrentSet );
|
|
pActualCurrentSet = NULL;
|
|
|
|
//
|
|
// unaccounted for records indicate other updater of name
|
|
//
|
|
// records we don't want (delete set) and did NOT previously
|
|
// register mean some other user is adding records
|
|
//
|
|
|
|
if ( pSharedSet )
|
|
{
|
|
Dns_RecordListFree( pSharedSet );
|
|
pSharedSet = NULL;
|
|
|
|
status = DNS_ERROR_NOT_UNIQUE;
|
|
goto Exit;
|
|
}
|
|
|
|
RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
|
|
Record.pName = (PDNS_NAME) pCopyOfNewSet->pName;
|
|
Record.wType = pCopyOfNewSet->wType;
|
|
Record.wDataLength = 0; // Meaning all data.
|
|
Record.Flags.DW = DNSREC_UPDATE | DNSREC_DELETE;
|
|
|
|
//
|
|
// Do an update with the following:
|
|
// Prerequisites: None
|
|
// Add: pCopyOfNewSet
|
|
// Delete: All
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( NULL,
|
|
pCopyOfNewSet,
|
|
NULL );
|
|
|
|
Record.pNext = pCopyOfNewSet;
|
|
|
|
status = DoQuickUpdate( &Record,
|
|
fOptions,
|
|
FALSE,
|
|
serverIp ? &ipArray : aipServers,
|
|
hCreds);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
Exit :
|
|
|
|
if ( pCopyOfCurrentSet )
|
|
{
|
|
Dns_RecordListFree( pCopyOfCurrentSet );
|
|
}
|
|
|
|
if ( pCopyOfNewSet )
|
|
{
|
|
Dns_RecordListFree( pCopyOfNewSet );
|
|
}
|
|
|
|
if ( pAddSet )
|
|
{
|
|
Dns_RecordListFree( pAddSet );
|
|
}
|
|
|
|
if ( pDeleteSet )
|
|
{
|
|
Dns_RecordListFree( pDeleteSet );
|
|
}
|
|
|
|
if ( pNetworkInfo )
|
|
{
|
|
NetInfo_Free( pNetworkInfo );
|
|
}
|
|
|
|
DNSDBG( TRACE, ( "Leave DnsModifyRRSet_Ex()\n" ));
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
DnsRegisterRRSet_Ex(
|
|
IN OUT PDNS_RECORD pRegisterSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL,
|
|
IN HANDLE hCreds OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
None.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD pCurrentSet = NULL;
|
|
PDNS_RECORD pUpdateSet = NULL;
|
|
PDNS_NETINFO pNetworkInfo = NULL;
|
|
DNS_RECORD Record;
|
|
DNS_RECORD NoCName;
|
|
IP_ARRAY ipArray;
|
|
IP_ADDRESS serverIp = 0;
|
|
|
|
DNSDBG( TRACE, ( "DnsRegisterRRSet_Ex()\n" ));
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_RecordSet(
|
|
"DnsRegisterRRSet_Ex()",
|
|
pRegisterSet );
|
|
}
|
|
|
|
//
|
|
// Validate arguments ...
|
|
//
|
|
if ( ( fOptions != DNS_UPDATE_UNIQUE ) &&
|
|
( fOptions & DNS_UNACCEPTABLE_UPDATE_OPTIONS ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Are all the RRSet structures of the same type and name?
|
|
// Mark them all as Updates (add) ...
|
|
//
|
|
if ( prepareUpdateRecordSet(
|
|
pRegisterSet,
|
|
FALSE,
|
|
TRUE,
|
|
DNSREC_UPDATE ) != NO_ERROR )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Prepare CName does not exist record
|
|
//
|
|
RtlZeroMemory( &NoCName, sizeof(DNS_RECORD) );
|
|
NoCName.pName = (PDNS_NAME) pRegisterSet->pName;
|
|
NoCName.wType = DNS_TYPE_CNAME;
|
|
NoCName.wDataLength = 0; // Meaning all structures not present.
|
|
NoCName.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
|
|
//
|
|
// shared update
|
|
// - just throw our records out there (with CNAME no-exist)
|
|
//
|
|
// DCR: this case is just ModifyRecordsInSet
|
|
//
|
|
|
|
if ( fOptions & DNS_UPDATE_SHARED &&
|
|
pRegisterSet->wType != DNS_TYPE_CNAME )
|
|
{
|
|
NoCName.pNext = pRegisterSet;
|
|
|
|
status = DoQuickUpdate( &NoCName,
|
|
fOptions,
|
|
FALSE,
|
|
aipServers,
|
|
hCreds);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// From here on down the code is handling the non-shared case ....
|
|
//
|
|
|
|
//
|
|
// Do an update with the following:
|
|
// Prerequisites: pRegisterSet
|
|
// Add: None
|
|
// Delete: None
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
|
|
//
|
|
// DCR_PERF: prereq only update is wasteful
|
|
// we need to query AND we are trusting query
|
|
// -- supposed to find last update server -- so
|
|
// just do it
|
|
//
|
|
// - faz => find target DNS server
|
|
// - direct query for our set
|
|
// - compare
|
|
// - full match => done
|
|
// - unresolveable conflict => fail
|
|
// - ok mismatch => send replace
|
|
//
|
|
|
|
pUpdateSet = DnsBuildUpdateSet( pRegisterSet,
|
|
NULL,
|
|
NULL );
|
|
|
|
//
|
|
// Call update ...
|
|
//
|
|
if ( pUpdateSet->wType != DNS_TYPE_CNAME )
|
|
{
|
|
NoCName.pNext = pUpdateSet;
|
|
|
|
status = DoQuickUpdate( &NoCName,
|
|
fOptions,
|
|
FALSE,
|
|
aipServers,
|
|
hCreds);
|
|
}
|
|
else
|
|
{
|
|
status = DoQuickUpdate( pUpdateSet,
|
|
fOptions,
|
|
FALSE,
|
|
aipServers,
|
|
hCreds);
|
|
}
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// We are done, no need to reregister since the server has
|
|
// what it should have.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
if ( status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
//
|
|
// For these errors, we just need to figure out what the server
|
|
// has and send the correct update info.
|
|
//
|
|
serverIp = DnsGetLastServerUpdateIP();
|
|
|
|
ipArray.AddrCount = 1;
|
|
ipArray.AddrArray[0] = serverIp;
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( status )
|
|
{
|
|
//
|
|
// For all other update errors, don't bother trying anything more.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
// get network info for
|
|
|
|
pNetworkInfo = NetInfo_CreateFromIpArray(
|
|
aipServers,
|
|
serverIp,
|
|
FALSE, // no search info
|
|
NULL );
|
|
|
|
//
|
|
// Let's see if the DNS server doesn't know about this set at all
|
|
// and just try to add it with the prerequisite that there is nothing
|
|
// there already for the given record name.
|
|
//
|
|
|
|
if ( pRegisterSet->wType == DNS_TYPE_CNAME )
|
|
{
|
|
//
|
|
// Handle CNAME type here as special case
|
|
//
|
|
|
|
RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
|
|
Record.pName = (PDNS_NAME) pRegisterSet->pName;
|
|
Record.wType = DNS_TYPE_ANY;
|
|
Record.wDataLength = 0; // Meaning all structures not present.
|
|
Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
//
|
|
// Do an update with the following:
|
|
// Prerequisites: None - will be Record above.
|
|
// Add: pRegisterSet
|
|
// Delete: None
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( NULL,
|
|
pRegisterSet,
|
|
NULL );
|
|
|
|
Record.pNext = pRegisterSet;
|
|
|
|
status = DoQuickUpdate( &Record,
|
|
fOptions,
|
|
FALSE,
|
|
serverIp ? &ipArray : aipServers,
|
|
hCreds);
|
|
|
|
if ( status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
status = DNS_ERROR_TRY_AGAIN_LATER;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
RtlZeroMemory( &Record, sizeof(DNS_RECORD) );
|
|
Record.pName = (PDNS_NAME) pRegisterSet->pName;
|
|
Record.wType = pRegisterSet->wType;
|
|
Record.wDataLength = 0; // Meaning all structures not present.
|
|
Record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
//
|
|
// Do an update with the following:
|
|
// Prerequisites: None - will be Record above and CNAME does not exist.
|
|
// Add: pRegisterSet
|
|
// Delete: All
|
|
//
|
|
// Build the update request with Pre, Add, Del sets ...
|
|
//
|
|
pUpdateSet = DnsBuildUpdateSet( NULL,
|
|
pRegisterSet,
|
|
NULL );
|
|
|
|
Record.pNext = pRegisterSet;
|
|
NoCName.pNext = &Record;
|
|
|
|
status = DoQuickUpdate( &NoCName,
|
|
fOptions,
|
|
FALSE,
|
|
serverIp ? &ipArray : aipServers,
|
|
hCreds);
|
|
}
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
//
|
|
// We are done, no need to reregister since the server has
|
|
// what it should have.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
if ( status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
//
|
|
// For these errors, we just need to figure out what the server
|
|
// has and send the correct update info.
|
|
//
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
if ( status )
|
|
{
|
|
//
|
|
// For all other update errors, don't bother trying anything more.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Query server for pCurrentSet ...
|
|
//
|
|
|
|
status = QueryDirectEx(
|
|
NULL, // no response message
|
|
& pCurrentSet,
|
|
NULL, // no header
|
|
0, // no header counts
|
|
(LPSTR) pRegisterSet->pName,
|
|
pRegisterSet->wType,
|
|
NULL, // no input records
|
|
DNS_QUERY_TREAT_AS_FQDN,
|
|
NULL, // no DNS server list
|
|
pNetworkInfo
|
|
);
|
|
|
|
if ( IsEmptyDnsResponse( pCurrentSet ) )
|
|
{
|
|
Dns_RecordListFree( pCurrentSet );
|
|
pCurrentSet = NULL;
|
|
}
|
|
|
|
if ( pCurrentSet )
|
|
{
|
|
PDNS_RECORD pOtherSet = NULL;
|
|
PDNS_RECORD pNotUsedSet = NULL;
|
|
|
|
//
|
|
// Sometimes when DnsQuery is called, the returned record set contains
|
|
// additional records of different types than what was queried for.
|
|
// Need to strip off the additional records from the query results.
|
|
//
|
|
pNotUsedSet = DnsRecordSetDetach( pCurrentSet );
|
|
|
|
if ( pNotUsedSet )
|
|
{
|
|
Dns_RecordListFree( pNotUsedSet );
|
|
pNotUsedSet = NULL;
|
|
}
|
|
|
|
//
|
|
// There are records on the server, make sure that these are ones
|
|
// that we know about, otherwise this call should return
|
|
// DNS_ERROR_NOT_UNIQUE.
|
|
//
|
|
|
|
if ( Dns_RecordSetCompare( pCurrentSet,
|
|
pRegisterSet,
|
|
&pOtherSet,
|
|
&pNotUsedSet ) )
|
|
{
|
|
//
|
|
// The two RRSets are the same. Weird! We just did a PreReq
|
|
// update looking for just this and it said the records weren't
|
|
// there, now when we query they are! This should never happen
|
|
// theoretically. Assert if otherwise . . .
|
|
//
|
|
DNS_ASSERT( FALSE );
|
|
|
|
status = NO_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
if ( pNotUsedSet )
|
|
{
|
|
Dns_RecordListFree( pNotUsedSet );
|
|
pNotUsedSet = NULL;
|
|
}
|
|
|
|
//
|
|
// Test to see if any of the records up one the server are not the same
|
|
// as any in our registration set. If so return error . . .
|
|
//
|
|
|
|
if ( pOtherSet )
|
|
{
|
|
Dns_RecordListFree( pOtherSet );
|
|
pOtherSet = NULL;
|
|
status = DNS_ERROR_NOT_UNIQUE;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Call ModifyRecordSet with the Current and Register RR sets . . .
|
|
//
|
|
|
|
status = DnsModifyRRSet_Ex( pCurrentSet,
|
|
pRegisterSet,
|
|
fOptions,
|
|
serverIp ? &ipArray : aipServers,
|
|
hCreds );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a confused DNS server! We've already tried a prerequisite
|
|
// update that there should be nothing, and add the registration
|
|
// RR set. No need to do it again, assume for now that the server
|
|
// is busy updating the particular RR set.
|
|
//
|
|
|
|
status = DNS_ERROR_TRY_AGAIN_LATER;
|
|
}
|
|
|
|
Exit :
|
|
|
|
if ( pCurrentSet )
|
|
{
|
|
Dns_RecordListFree( pCurrentSet );
|
|
}
|
|
|
|
if ( pNetworkInfo )
|
|
{
|
|
NetInfo_Free( pNetworkInfo );
|
|
}
|
|
|
|
DNSDBG( TRACE, ( "Leave DnsRegisterRRSet_Ex()\n" ));
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// DCR_CLEANUP: ModifyRecordSet() functions?
|
|
// decide what to do with these
|
|
// if to be exposed -- then all three
|
|
// if only used by async reg, then just
|
|
// need UTF8 routine
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordSet_UTF8(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PDNS_RECORD pCurrentSet,
|
|
IN PDNS_RECORD pNewSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic DNS routine to update records. This function figures out the
|
|
records that need to be added and/or removed to modify an existing
|
|
record set in the DNS domain name space. This routine will not remove
|
|
any records that may have been added by another process for the given
|
|
record set name. In the case where "other" records are detected,
|
|
DNS_ERROR_NOT_UNIQUE will be returned.
|
|
|
|
Arguments:
|
|
|
|
hCredentials - handle to credentials to be used for update.
|
|
|
|
pCurrentSet - the set that the caller currently thinks is registered
|
|
in the DNS domain name space.
|
|
|
|
pNewSet - the set that should be registered in the DNS domain name
|
|
space. The current records will be modified to get to this
|
|
set.
|
|
|
|
fOptions - the Dynamic DNS update options that the caller may wish to
|
|
use (see dnsapi.h).
|
|
|
|
aipServers - a specific list of servers to goto to figure out the
|
|
authoritative DNS server(s) for the given record set
|
|
domain zone name.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD pCopyOfCurrentSet = NULL;
|
|
PDNS_RECORD pCopyOfNewSet = NULL;
|
|
DWORD dwFlags = fOptions;
|
|
|
|
DNSDBG( TRACE, ( "DnsModifyRecordSet_UTF8()\n" ));
|
|
|
|
//
|
|
// if just new set -- do an add
|
|
//
|
|
|
|
if ( pNewSet && !pCurrentSet )
|
|
{
|
|
return DnsAddRecordSet_UTF8( hCredentials,
|
|
pNewSet,
|
|
fOptions,
|
|
aipServers );
|
|
}
|
|
|
|
//
|
|
// if just current set -- do a delete
|
|
//
|
|
|
|
if ( !pNewSet && pCurrentSet )
|
|
{
|
|
return DnsModifyRecordsInSet_UTF8(
|
|
NULL, // no add records
|
|
pCurrentSet, // delete current set
|
|
fOptions,
|
|
hCredentials,
|
|
aipServers, // DNS servers
|
|
NULL // reserved
|
|
);
|
|
}
|
|
|
|
if ( !pNewSet && !pCurrentSet )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( UseSystemDefaultForSecurity( dwFlags ) )
|
|
{
|
|
dwFlags |= g_UpdateSecurityLevel;
|
|
}
|
|
|
|
if ( hCredentials )
|
|
{
|
|
dwFlags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// build record sets for update
|
|
//
|
|
// DCR_CLEANUP: unnecessary RR copy here
|
|
// DCR_FIX0: unnecessary RR copy here
|
|
// ModifyRRSet_Ex() does it's own copy
|
|
// and doesn't touch input records
|
|
//
|
|
|
|
pCopyOfCurrentSet = Dns_RecordSetCopyEx(
|
|
pCurrentSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
if ( !pCopyOfCurrentSet )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
pCopyOfNewSet = Dns_RecordSetCopyEx(
|
|
pNewSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
if ( !pCopyOfNewSet )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
status = DnsModifyRRSet_Ex(
|
|
pCopyOfCurrentSet,
|
|
pCopyOfNewSet,
|
|
dwFlags | DNS_UPDATE_UNIQUE,
|
|
aipServers,
|
|
hCredentials );
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
if ( pCopyOfCurrentSet )
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfCurrentSet->pName );
|
|
}
|
|
else
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfNewSet->pName );
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
Dns_RecordListFree( pCopyOfCurrentSet );
|
|
Dns_RecordListFree( pCopyOfNewSet );
|
|
|
|
DNSDBG( TRACE, ( "Leave DnsModifyRecordSet_UTF8()\n" ));
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS WINAPI
|
|
DnsModifyRecordSet_A (
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PDNS_RECORD pCurrentSet,
|
|
IN PDNS_RECORD pNewSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI version of ModifyRecordSet.
|
|
|
|
Note, there is NO use of this function it exists only for Elena's test
|
|
scripts. Once the test scripts are changed this function can be deleted.
|
|
|
|
Arguments:
|
|
|
|
same as above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD pcopyCurrent;
|
|
PDNS_RECORD pcopyNew;
|
|
|
|
DNSDBG( TRACE, ( "DnsModifyRecordSet_A()\n" ));
|
|
|
|
//
|
|
// copy record sets to UTF8
|
|
//
|
|
|
|
pcopyCurrent = Dns_RecordSetCopyEx(
|
|
pCurrentSet,
|
|
DnsCharSetAnsi,
|
|
DnsCharSetUtf8 );
|
|
|
|
pcopyNew = Dns_RecordSetCopyEx(
|
|
pNewSet,
|
|
DnsCharSetAnsi,
|
|
DnsCharSetUtf8 );
|
|
|
|
//
|
|
// modify in UTF8
|
|
//
|
|
|
|
status = DnsModifyRecordSet_UTF8(
|
|
hCredentials,
|
|
pcopyCurrent,
|
|
pcopyNew,
|
|
fOptions,
|
|
aipServers );
|
|
|
|
//
|
|
// cleanup local copies
|
|
//
|
|
|
|
Dns_RecordListFree( pcopyCurrent );
|
|
Dns_RecordListFree( pcopyNew );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordSet_W(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PDNS_RECORD pCurrentSet,
|
|
IN PDNS_RECORD pNewSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unicode version of ModifyRecordSet.
|
|
|
|
Note, there is NO use of this function it exists only for Elena's test
|
|
scripts. Once the test scripts are changed this function can be deleted.
|
|
|
|
Arguments:
|
|
|
|
same as above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD pcopyCurrent;
|
|
PDNS_RECORD pcopyNew;
|
|
|
|
DNSDBG( TRACE, ( "DnsModifyRecordSet_W()\n" ));
|
|
|
|
//
|
|
// copy record sets to UTF8
|
|
//
|
|
|
|
pcopyCurrent = Dns_RecordSetCopyEx(
|
|
pCurrentSet,
|
|
DnsCharSetUnicode,
|
|
DnsCharSetUtf8 );
|
|
|
|
pcopyNew = Dns_RecordSetCopyEx(
|
|
pNewSet,
|
|
DnsCharSetUnicode,
|
|
DnsCharSetUtf8 );
|
|
|
|
//
|
|
// modify in UTF8
|
|
//
|
|
|
|
status = DnsModifyRecordSet_UTF8(
|
|
hCredentials,
|
|
pcopyCurrent,
|
|
pcopyNew,
|
|
fOptions,
|
|
aipServers );
|
|
|
|
//
|
|
// cleanup local copies
|
|
//
|
|
|
|
Dns_RecordListFree( pcopyCurrent );
|
|
Dns_RecordListFree( pcopyNew );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// DCR_CLEANUP: DnsAddRecordSet() functions?
|
|
// decide what to do with these
|
|
// if to be exposed -- then all three
|
|
// if only used by async reg, then just
|
|
// need UTF8 routine
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsAddRecordSet_UTF8(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN OUT PDNS_RECORD pRegisterSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic DNS routine to update records. This routine adds the
|
|
record set described by pRegisterSet to the DNS domain name
|
|
space. This routine fails with error DNS_ERROR_NOT_UNIQUE if
|
|
there are any pre-existing records in the DNS name space that are
|
|
not part of the set described by pRegisterSet.
|
|
|
|
Arguments:
|
|
|
|
hCredentials - handle to credentials to be used for update.
|
|
|
|
pRegisterSet - the set that should be registered in the DNS domain name
|
|
space.
|
|
|
|
fOptions - the Dynamic DNS update options that the caller may wish to
|
|
use (see dnsapi.h).
|
|
|
|
aipServers - a specific list of servers to goto to figure out the
|
|
authoritative DNS server(s) for the given record set
|
|
domain zone name.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD pCopyOfRegisterSet = NULL;
|
|
DWORD dwFlags = fOptions;
|
|
|
|
DNSDBG( TRACE, ( "DnsAddRecordSet_UTF8()\n" ));
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_RecordSet(
|
|
"DnsAddRecordSet_UTF8()",
|
|
pRegisterSet );
|
|
}
|
|
|
|
//
|
|
// Validate arguments ...
|
|
//
|
|
|
|
if ( !pRegisterSet )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( UseSystemDefaultForSecurity( dwFlags ) )
|
|
{
|
|
dwFlags |= g_UpdateSecurityLevel;
|
|
}
|
|
|
|
if ( hCredentials )
|
|
{
|
|
dwFlags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
pCopyOfRegisterSet = Dns_RecordSetCopyEx( pRegisterSet,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUtf8 );
|
|
if ( !pCopyOfRegisterSet )
|
|
{
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
status = DnsRegisterRRSet_Ex( pCopyOfRegisterSet,
|
|
dwFlags | DNS_UPDATE_UNIQUE,
|
|
aipServers,
|
|
hCredentials);
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
DnsFlushResolverCacheEntry_UTF8( (LPSTR) pCopyOfRegisterSet->pName );
|
|
}
|
|
|
|
Dns_RecordListFree( pCopyOfRegisterSet );
|
|
|
|
|
|
DNSDBG( TRACE, ( "Leave DnsAddRecordSet_UTF8()\n" ));
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsAddRecordSet_A(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN OUT PDNS_RECORD pRegisterSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI version of AddRecordSet.
|
|
|
|
Note, there is NO use of this function it exists only for Elena's test
|
|
scripts. Once the test scripts are changed this function can be deleted.
|
|
|
|
Arguments:
|
|
|
|
same as above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD pcopySet;
|
|
|
|
DNSDBG( TRACE, ( "DnsAddRecordSet_A()\n" ));
|
|
|
|
//
|
|
// copy set to UTF8
|
|
//
|
|
|
|
pcopySet = Dns_RecordSetCopyEx(
|
|
pRegisterSet,
|
|
DnsCharSetAnsi,
|
|
DnsCharSetUtf8 );
|
|
|
|
//
|
|
// add set
|
|
//
|
|
|
|
status = DnsAddRecordSet_UTF8(
|
|
hCredentials,
|
|
pcopySet,
|
|
fOptions,
|
|
aipServers );
|
|
|
|
// cleanup local copy
|
|
|
|
Dns_RecordListFree( pcopySet );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsAddRecordSet_W(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN OUT PDNS_RECORD pRegisterSet,
|
|
IN DWORD fOptions,
|
|
IN PIP_ARRAY aipServers OPTIONAL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI version of AddRecordSet.
|
|
|
|
Note, there is NO use of this function it exists only for Elena's test
|
|
scripts. Once the test scripts are changed this function can be deleted.
|
|
|
|
Arguments:
|
|
|
|
same as above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_RECORD pcopySet;
|
|
|
|
DNSDBG( TRACE, ( "DnsAddRecordSet_W()\n" ));
|
|
|
|
//
|
|
// copy set to UTF8
|
|
//
|
|
|
|
pcopySet = Dns_RecordSetCopyEx(
|
|
pRegisterSet,
|
|
DnsCharSetUnicode,
|
|
DnsCharSetUtf8 );
|
|
|
|
//
|
|
// add set
|
|
//
|
|
|
|
status = DnsAddRecordSet_UTF8(
|
|
hCredentials,
|
|
pcopySet,
|
|
fOptions,
|
|
aipServers );
|
|
|
|
// cleanup local copy
|
|
|
|
Dns_RecordListFree( pcopySet );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Update test functions are called by system components
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_UTF8(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP_ARRAY pDnsServers OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic DNS routine to test whether the caller can update the
|
|
records in the DNS domain name space for the given record name.
|
|
|
|
Arguments:
|
|
|
|
hCredentials - handle to credentials to be used for update.
|
|
|
|
pszName - the record set name that the caller wants to test.
|
|
|
|
Flags - the Dynamic DNS update options that the caller may wish to
|
|
use (see dnsapi.h).
|
|
|
|
pDnsServers - a specific list of servers to goto to figure out the
|
|
authoritative DNS server(s) for the given record set
|
|
domain zone name.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR pnameWide = NULL;
|
|
DNS_STATUS status = NO_ERROR;
|
|
|
|
DNSDBG( TRACE, (
|
|
"DnsUpdateTest_UTF8( %s )\n",
|
|
pszName ));
|
|
|
|
|
|
if ( !pszName )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pnameWide = Dns_NameCopyAllocate(
|
|
(PCHAR) pszName,
|
|
0,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUnicode );
|
|
if ( !pnameWide )
|
|
{
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
|
|
status = DnsUpdateTest_W(
|
|
hCredentials,
|
|
(PCWSTR) pnameWide,
|
|
Flags,
|
|
pDnsServers );
|
|
|
|
FREE_HEAP( pnameWide );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_A(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP_ARRAY pDnsServers OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic DNS routine to test whether the caller can update the
|
|
records in the DNS domain name space for the given record name.
|
|
|
|
Arguments:
|
|
|
|
hCredentials - handle to credentials to be used for update.
|
|
|
|
pszName - the record set name that the caller wants to test.
|
|
|
|
Flags - the Dynamic DNS update options that the caller may wish to
|
|
use (see dnsapi.h).
|
|
|
|
pDnsServers - a specific list of servers to goto to figure out the
|
|
authoritative DNS server(s) for the given record set
|
|
domain zone name.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR pnameWide = NULL;
|
|
DNS_STATUS status = NO_ERROR;
|
|
|
|
DNSDBG( TRACE, (
|
|
"DnsUpdateTest_UTF8( %s )\n",
|
|
pszName ));
|
|
|
|
|
|
if ( !pszName )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pnameWide = Dns_NameCopyAllocate(
|
|
(PCHAR) pszName,
|
|
0,
|
|
DnsCharSetUtf8,
|
|
DnsCharSetUnicode );
|
|
if ( !pnameWide )
|
|
{
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
|
|
status = DnsUpdateTest_W(
|
|
hCredentials,
|
|
(PCWSTR) pnameWide,
|
|
Flags,
|
|
pDnsServers );
|
|
|
|
FREE_HEAP( pnameWide );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_W(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCWSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP_ARRAY pDnsServers OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dynamic DNS routine to test whether the caller can update the
|
|
records in the DNS domain name space for the given record name.
|
|
|
|
Arguments:
|
|
|
|
hCredentials - handle to credentials to be used for update.
|
|
|
|
pszName - the record set name that the caller wants to test.
|
|
|
|
Flags - the Dynamic DNS update options that the caller may wish to
|
|
use (see dnsapi.h).
|
|
|
|
pDnsServers - a specific list of servers to goto to figure out the
|
|
authoritative DNS server(s) for the given record set
|
|
domain zone name.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
DNS_RECORD record;
|
|
DWORD flags = Flags;
|
|
LPSTR pnameUtf8 = NULL;
|
|
|
|
DNSDBG( TRACE, (
|
|
"DnsUpdateTest_W( %S )\n",
|
|
pszName ));
|
|
|
|
//
|
|
// validation
|
|
//
|
|
|
|
if ( flags & DNS_UNACCEPTABLE_UPDATE_OPTIONS )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if ( !pszName )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// try resolver
|
|
//
|
|
|
|
if ( flags & DNS_UPDATE_TEST_USE_LOCAL_SYS_ACCT )
|
|
{
|
|
DWORD rpcStatus = NO_ERROR;
|
|
|
|
if ( !pDnsServers ||
|
|
pDnsServers->AddrCount != 1 )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
RpcTryExcept
|
|
{
|
|
status = CRrUpdateTest(
|
|
NULL,
|
|
(PWSTR) pszName,
|
|
0,
|
|
pDnsServers->AddrArray[0] );
|
|
}
|
|
RpcExcept( DNS_RPC_EXCEPTION_FILTER )
|
|
{
|
|
rpcStatus = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
|
|
if ( rpcStatus == NO_ERROR )
|
|
{
|
|
return status;
|
|
}
|
|
return rpcStatus;
|
|
}
|
|
|
|
//
|
|
// direct update attempt
|
|
//
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
if ( UseSystemDefaultForSecurity( flags ) )
|
|
{
|
|
flags |= g_UpdateSecurityLevel;
|
|
}
|
|
if ( hCredentials )
|
|
{
|
|
flags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// build record
|
|
// - NOEXIST prerequisite
|
|
//
|
|
|
|
pnameUtf8 = Dns_NameCopyAllocate(
|
|
(PCHAR) pszName,
|
|
0,
|
|
DnsCharSetUnicode,
|
|
DnsCharSetUtf8 );
|
|
if ( ! pnameUtf8 )
|
|
{
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
record.pName = (PDNS_NAME) pnameUtf8;
|
|
record.wType = DNS_TYPE_ANY;
|
|
record.wDataLength = 0;
|
|
record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
//
|
|
// do the prereq update
|
|
//
|
|
|
|
status = DoQuickUpdate(
|
|
&record,
|
|
flags,
|
|
TRUE,
|
|
pDnsServers,
|
|
hCredentials );
|
|
|
|
FREE_HEAP( pnameUtf8 );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Update execution functions
|
|
//
|
|
|
|
DNS_STATUS
|
|
DoQuickUpdate(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN BOOL fUpdateTestMode,
|
|
IN PIP_ARRAY pServerList OPTIONAL,
|
|
IN HANDLE hCreds OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
None.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PSTR pzoneName;
|
|
PDNS_NAME pname = pRecord->pName;
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
|
|
DNSDBG( UPDATE, (
|
|
"DoQuickUpdate( rr=%p, flag=%08x )\n",
|
|
pRecord,
|
|
dwFlags ));
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_RecordSet(
|
|
"Entering DoQuickUpdate():",
|
|
pRecord );
|
|
}
|
|
|
|
//
|
|
// caller has particular server list
|
|
//
|
|
|
|
if ( pServerList )
|
|
{
|
|
IP_ADDRESS serverIp;
|
|
PIP_ARRAY pserverListCopy = Dns_CreateIpArrayCopy( pServerList );
|
|
|
|
if ( !pserverListCopy )
|
|
{
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
status = DoQuickFAZ(
|
|
&pnetInfo,
|
|
pname,
|
|
pserverListCopy );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
FREE_HEAP( pserverListCopy );
|
|
pserverListCopy = NULL;
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// FAZ should always produce update network info blob
|
|
//
|
|
|
|
DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
|
|
pzoneName = NetInfo_UpdateZoneName( pnetInfo );
|
|
|
|
if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
|
|
{
|
|
status = DoMultiMasterUpdate(
|
|
pRecord,
|
|
dwFlags,
|
|
hCreds,
|
|
pzoneName,
|
|
0,
|
|
pserverListCopy );
|
|
}
|
|
else
|
|
{
|
|
status = DoQuickUpdateEx(
|
|
NULL,
|
|
pRecord,
|
|
dwFlags,
|
|
pnetInfo,
|
|
hCreds );
|
|
|
|
if ( status == ERROR_TIMEOUT )
|
|
{
|
|
serverIp = pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress;
|
|
#if DBG
|
|
if ( g_IsDnsServer &&
|
|
IsLocalIpAddress( serverIp ) )
|
|
{
|
|
DnsDbg_PrintfToDebugger(
|
|
"DNSAPI: Note that DDNS update to local server\n"
|
|
" with IP address 0x%.8x timed out,\n"
|
|
" now trying other DNS servers\n"
|
|
" authoritative for zone (%s)\n",
|
|
serverIp,
|
|
pzoneName );
|
|
}
|
|
#endif
|
|
status = DoMultiMasterUpdate(
|
|
pRecord,
|
|
dwFlags,
|
|
hCreds,
|
|
pzoneName,
|
|
serverIp,
|
|
pserverListCopy );
|
|
}
|
|
}
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
|
|
FREE_HEAP( pserverListCopy );
|
|
pserverListCopy = NULL;
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// server list unspecified
|
|
// - use FAZ to figure it out
|
|
//
|
|
|
|
else
|
|
{
|
|
PIP_ARRAY serverListArray[ UPDATE_ADAPTER_LIMIT ];
|
|
PDNS_NETINFO networkInfoArray[ UPDATE_ADAPTER_LIMIT ];
|
|
DWORD netCount = UPDATE_ADAPTER_LIMIT;
|
|
DWORD iter;
|
|
BOOL bsuccess = FALSE;
|
|
|
|
//
|
|
// build server list for update
|
|
// - collapse adapters on same network into single adapter
|
|
// - FAZ to find update servers
|
|
// - collapse results from same network into single target
|
|
//
|
|
|
|
netCount = GetDnsServerListsForUpdate(
|
|
serverListArray,
|
|
netCount,
|
|
dwFlags
|
|
);
|
|
|
|
status = CollapseDnsServerListsForUpdate(
|
|
serverListArray,
|
|
networkInfoArray,
|
|
& netCount,
|
|
pname );
|
|
|
|
DNS_ASSERT( netCount <= UPDATE_ADAPTER_LIMIT );
|
|
|
|
if ( netCount == 0 )
|
|
{
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
status = DNS_ERROR_NO_DNS_SERVERS;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// do update on all distinct (disjoint) networks
|
|
//
|
|
|
|
for ( iter = 0;
|
|
iter < netCount;
|
|
iter++ )
|
|
{
|
|
PIP_ARRAY pdnsArray = serverListArray[ iter ];
|
|
|
|
pnetInfo = networkInfoArray[ iter ];
|
|
if ( !pnetInfo )
|
|
{
|
|
ASSERT( FALSE );
|
|
FREE_HEAP( pdnsArray );
|
|
continue;
|
|
}
|
|
|
|
DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
|
|
pzoneName = NetInfo_UpdateZoneName( pnetInfo );
|
|
|
|
//
|
|
// multimater update?
|
|
// - if flag set
|
|
// - or simple update (best net) times out
|
|
//
|
|
|
|
if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
|
|
{
|
|
status = DoMultiMasterUpdate(
|
|
pRecord,
|
|
dwFlags,
|
|
hCreds,
|
|
pzoneName,
|
|
0,
|
|
pdnsArray );
|
|
}
|
|
else
|
|
{
|
|
status = DoQuickUpdateEx(
|
|
NULL,
|
|
pRecord,
|
|
dwFlags,
|
|
pnetInfo,
|
|
hCreds );
|
|
|
|
if ( status == ERROR_TIMEOUT )
|
|
{
|
|
IP_ADDRESS serverIp;
|
|
|
|
serverIp = pnetInfo->AdapterArray[0]
|
|
->ServerArray[0].IpAddress;
|
|
|
|
status = DoMultiMasterUpdate(
|
|
pRecord,
|
|
dwFlags,
|
|
hCreds,
|
|
pzoneName,
|
|
serverIp,
|
|
pdnsArray );
|
|
}
|
|
}
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
FREE_HEAP( pdnsArray );
|
|
|
|
if ( status == NO_ERROR ||
|
|
( fUpdateTestMode &&
|
|
( status == DNS_ERROR_RCODE_YXDOMAIN ||
|
|
status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET ) ) )
|
|
{
|
|
bsuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// successful update on any network counts as success
|
|
//
|
|
// DCR_QUESTION: not sure why don't just NO_ERROR all bsuccess,
|
|
// only case would be this fUpdateTestMode thing above
|
|
// on single network
|
|
//
|
|
|
|
if ( bsuccess )
|
|
{
|
|
if ( netCount != 1 )
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
DoQuickUpdateEx(
|
|
OUT PDNS_MSG_BUF * ppMsgRecv, OPTIONAL
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PDNS_NETINFO pNetworkInfo,
|
|
IN HANDLE hCreds OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
None.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_MSG_BUF pmsg = NULL;
|
|
|
|
DNSDBG( TRACE, ( "DoQuickUpdateEx()\n" ));
|
|
|
|
//
|
|
// do update
|
|
// - optionally specify update context through net adapter list
|
|
// otherwise DnsUpdateEx() will use FAZ
|
|
//
|
|
|
|
status = DnsUpdate(
|
|
pRecord,
|
|
dwFlags,
|
|
pNetworkInfo,
|
|
hCreds,
|
|
&pmsg
|
|
);
|
|
|
|
if ( pmsg )
|
|
{
|
|
//
|
|
// DCR: why LastDnsServerUpdated requires these errors?
|
|
//
|
|
if ( status == NO_ERROR ||
|
|
status == DNS_ERROR_RCODE_SERVER_FAILURE ||
|
|
status == DNS_ERROR_RCODE_NOT_IMPLEMENTED ||
|
|
status == DNS_ERROR_RCODE_REFUSED ||
|
|
status == DNS_ERROR_RCODE_YXRRSET ||
|
|
status == DNS_ERROR_RCODE_NXRRSET )
|
|
{
|
|
IP4_ADDRESS ip = MSG_REMOTE_IP4(pmsg);
|
|
|
|
DNSDBG( TRACE, ( "DNS Update sent to server 0x%x\n", ip ));
|
|
g_LastDNSServerUpdated = ip;
|
|
}
|
|
|
|
//
|
|
// build last update error blob here
|
|
//
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
SetLastFailedUpdateInfo(
|
|
pmsg,
|
|
status );
|
|
}
|
|
}
|
|
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
*ppMsgRecv = pmsg;
|
|
}
|
|
else
|
|
{
|
|
if ( pmsg )
|
|
{
|
|
FREE_HEAP( pmsg );
|
|
}
|
|
}
|
|
|
|
GUI_MODE_SETUP_WS_CLEANUP( g_InNTSetupMode );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
DoMultiMasterUpdate(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN HANDLE hCreds OPTIONAL,
|
|
IN LPSTR pszDomain,
|
|
IN IP_ADDRESS BadIp,
|
|
IN PIP_ARRAY pServerList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do update to multi-master DNS primary.
|
|
|
|
Arguments:
|
|
|
|
pRecord -- record list to update
|
|
|
|
Flags -- update options
|
|
|
|
hCreds -- update credentials
|
|
|
|
pszDomain -- domain (zone) name to update
|
|
|
|
BadIp -- IP of server that didn't response to previous update attempt
|
|
|
|
pServerList -- list of DNS servers
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
PIP_ARRAY pnsList = NULL;
|
|
PIP_ARRAY pbadServerList = NULL;
|
|
DNS_STATUS status = DNS_ERROR_NO_DNS_SERVERS;
|
|
DWORD iter;
|
|
|
|
//
|
|
// Get the full NS server list for the domain name and x out BadIp
|
|
// if present.
|
|
//
|
|
|
|
pnsList = GetNameServersListForDomain( pszDomain, pServerList );
|
|
if ( !pnsList )
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if ( pnsList->AddrCount == 1 &&
|
|
Dns_IsAddressInIpArray( pnsList, BadIp ) )
|
|
{
|
|
status = ERROR_TIMEOUT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Create and initialize bad servers list with BadIp
|
|
//
|
|
|
|
pbadServerList = Dns_CreateIpArray( pnsList->AddrCount + 1 );
|
|
if ( !pbadServerList )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
if ( BadIp )
|
|
{
|
|
Dns_AddIpToIpArray( pbadServerList, BadIp );
|
|
}
|
|
|
|
//
|
|
// attempt update against each multi-master DNS server
|
|
//
|
|
// identify multi-master servers as those which return their themselves
|
|
// as the authoritative server when do FAZ query
|
|
//
|
|
|
|
for ( iter = 0; iter < pnsList->AddrCount; iter++ )
|
|
{
|
|
IP_ARRAY ipArray;
|
|
IP_ADDRESS serverIp = pnsList->AddrArray[iter];
|
|
|
|
//
|
|
// If the current server that we are about to FAZ to is in
|
|
// the ignore list, skip it . . .
|
|
//
|
|
if ( Dns_IsAddressInIpArray( pbadServerList, serverIp ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ipArray.AddrCount = 1;
|
|
ipArray.AddrArray[0] = serverIp;
|
|
|
|
status = DoQuickFAZ(
|
|
&pnetInfo,
|
|
pszDomain,
|
|
&ipArray );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
DNS_ASSERT( pnetInfo->AdapterCount == 1 );
|
|
DNS_ASSERT( pnetInfo->AdapterArray[0]->ServerCount != 0 );
|
|
|
|
if ( serverIp != pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress )
|
|
{
|
|
serverIp = pnetInfo->AdapterArray[0]->ServerArray[0].IpAddress;
|
|
|
|
//
|
|
// If the current server that we are about to FAZ to is in
|
|
// the ignore list, skip it . . .
|
|
//
|
|
if ( Dns_IsAddressInIpArray( pbadServerList, serverIp ) )
|
|
{
|
|
NetInfo_Free( pnetInfo );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
status = DoQuickUpdateEx(
|
|
NULL,
|
|
pRecord,
|
|
dwFlags,
|
|
pnetInfo,
|
|
hCreds
|
|
);
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
|
|
if ( status == ERROR_TIMEOUT )
|
|
{
|
|
//
|
|
// Add serverIp to ignore list
|
|
//
|
|
|
|
Dns_AddIpToIpArray( pbadServerList, serverIp );
|
|
}
|
|
else
|
|
{
|
|
if ( dwFlags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS )
|
|
{
|
|
Dns_AddIpToIpArray( pbadServerList, serverIp );
|
|
}
|
|
else
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Done:
|
|
|
|
FREE_HEAP( pnsList );
|
|
FREE_HEAP( pbadServerList );
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// DCR_DELETE: not sure of the point of GetLastServerUpdateIp()
|
|
//
|
|
|
|
IP_ADDRESS
|
|
DnsGetLastServerUpdateIP(
|
|
void )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
None.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return g_LastDNSServerUpdated;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Last failed update info
|
|
//
|
|
|
|
DNS_FAILED_UPDATE_INFO g_FailedUpdateInfo = { 0, 0, 0, 0 };
|
|
|
|
|
|
VOID
|
|
DnsGetLastFailedUpdateInfo(
|
|
OUT PDNS_FAILED_UPDATE_INFO pInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve failed update information.
|
|
|
|
Arguments:
|
|
|
|
pInfo -- ptr to receive failed info blob
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
// fill in last info
|
|
|
|
RtlCopyMemory(
|
|
pInfo,
|
|
& g_FailedUpdateInfo,
|
|
sizeof(*pInfo) );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetLastFailedUpdateInfo(
|
|
IN PDNS_MSG_BUF pMsg,
|
|
IN DNS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set last failed update info.
|
|
|
|
Arguments:
|
|
|
|
pMsg -- message with update failure
|
|
|
|
Status -- status
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
g_FailedUpdateInfo.Ip4Address = MSG_REMOTE_IP4(pMsg);
|
|
//g_FailedUpdateInfo.Ip6Address = MSG_REMOTE_IP6(pMsg);
|
|
g_FailedUpdateInfo.Status = Status;
|
|
g_FailedUpdateInfo.Rcode = pMsg->MessageHead.ResponseCode;
|
|
}
|
|
|
|
//
|
|
// DCR: include client secure update here
|
|
// to do so, will have to expose
|
|
// in dnslib some of the security utilities
|
|
// but then can REMOVE exports of a bunch
|
|
// of the send\recv\socket routines
|
|
//
|
|
|
|
//
|
|
// End of udpate.c
|
|
//
|