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.
3072 lines
72 KiB
3072 lines
72 KiB
/*++
|
|
|
|
Copyright (c) 1996-2002 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"
|
|
#include "dnssec.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_SECURITY_OFF | \
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT | \
|
|
DNS_UPDATE_SECURITY_ON | \
|
|
DNS_UPDATE_FORCE_SECURITY_NEGO | \
|
|
DNS_UPDATE_TRY_ALL_MASTER_SERVERS | \
|
|
DNS_UPDATE_REMOTE_SERVER | \
|
|
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
|
|
Dns_DoSecureUpdate(
|
|
IN PDNS_MSG_BUF pMsgSend,
|
|
OUT PDNS_MSG_BUF pMsgRecv,
|
|
IN OUT PHANDLE phContext,
|
|
IN DWORD dwFlag,
|
|
IN PDNS_NETINFO pNetworkInfo,
|
|
IN PADDR_ARRAY pServerList,
|
|
IN PWSTR pszNameServer,
|
|
IN PCHAR pCreds,
|
|
IN PCHAR pszContext
|
|
);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Update execution routines
|
|
//
|
|
|
|
VOID
|
|
Update_SaveResults(
|
|
IN OUT PUPDATE_BLOB pBlob,
|
|
IN DWORD Status,
|
|
IN DWORD Rcode,
|
|
IN PDNS_ADDR pServerAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save update results.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- update info blob
|
|
|
|
Status -- update status
|
|
|
|
Rcode -- returned RCODE
|
|
|
|
ServerIp -- server attempted update at
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_EXTRA_INFO pextra = (PDNS_EXTRA_INFO) pBlob->pExtraInfo;
|
|
|
|
//
|
|
// results - save to blob
|
|
//
|
|
|
|
pBlob->fSavedResults = TRUE;
|
|
|
|
Util_SetBasicResults(
|
|
& pBlob->Results,
|
|
Status,
|
|
Rcode,
|
|
pServerAddr );
|
|
|
|
//
|
|
// find and set extra info result blob (if any)
|
|
//
|
|
|
|
ExtraInfo_SetBasicResults(
|
|
pBlob->pExtraInfo,
|
|
& pBlob->Results );
|
|
|
|
//
|
|
// backward compat update results
|
|
//
|
|
|
|
if ( pServerAddr )
|
|
{
|
|
pextra = ExtraInfo_FindInList(
|
|
pBlob->pExtraInfo,
|
|
DNS_EXINFO_ID_RESULTS_V1 );
|
|
if ( pextra )
|
|
{
|
|
pextra->ResultsV1.Rcode = (WORD)Rcode;
|
|
pextra->ResultsV1.Status = Status;
|
|
|
|
if ( DnsAddr_IsIp4( pServerAddr ) )
|
|
{
|
|
pextra->ResultsV1.ServerIp4 = DnsAddr_GetIp4( pServerAddr );
|
|
}
|
|
else
|
|
{
|
|
DNS_ASSERT( DnsAddr_IsIp6( pServerAddr ) );
|
|
|
|
DnsAddr_WriteIp6(
|
|
& pextra->ResultsV1.ServerIp6,
|
|
pServerAddr );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Update_Send(
|
|
IN OUT PUPDATE_BLOB pBlob
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send DNS update.
|
|
|
|
This is the core update send routine that does
|
|
- packet build
|
|
- send
|
|
- secure fail over
|
|
- result data (if required)
|
|
|
|
This routine does NOT do FAZ or cache cleanup (see Update_FazSendFlush()).
|
|
|
|
Arguments:
|
|
|
|
pBlob -- update info blob
|
|
|
|
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;
|
|
PWSTR pzone;
|
|
PWSTR pserverName;
|
|
PCHAR pcreds = NULL;
|
|
BOOL fsecure = FALSE;
|
|
BOOL fswitchToTcp = FALSE;
|
|
DNS_HEADER header;
|
|
BYTE rcode = 0;
|
|
DNS_ADDR servAddr;
|
|
PDNS_ADDR pservAddr = NULL;
|
|
PADDR_ARRAY pserverArray = NULL;
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
PDNS_NETINFO pnetInfoLocal = NULL;
|
|
SEND_BLOB sendBlob;
|
|
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Update_Send( %p )\n",
|
|
pBlob ));
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_UpdateBlob( "Entering Update_Send", pBlob );
|
|
}
|
|
|
|
//
|
|
// build netinfo if missing
|
|
//
|
|
|
|
pnetInfo = pBlob->pNetInfo;
|
|
if ( !pnetInfo )
|
|
{
|
|
if ( pBlob->pServerList )
|
|
{
|
|
pnetInfoLocal = NetInfo_CreateForUpdate(
|
|
pBlob->pszZone,
|
|
pBlob->pszServerName,
|
|
pBlob->pServerList,
|
|
0 );
|
|
if ( !pnetInfoLocal )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
pnetInfo = pnetInfoLocal;
|
|
}
|
|
|
|
//
|
|
// get info from netinfo
|
|
// - must be update netinfo blob
|
|
//
|
|
|
|
if ( ! NetInfo_IsForUpdate(pnetInfo) )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pzone = NetInfo_UpdateZoneName( pnetInfo );
|
|
pserverArray = NetInfo_ConvertToAddrArray(
|
|
pnetInfo,
|
|
NULL, // all adapters
|
|
0 // no addr family
|
|
);
|
|
pserverName = NetInfo_UpdateServerName( pnetInfo );
|
|
|
|
if ( !pzone || !pserverArray )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// 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
|
|
(PDNS_NAME) pzone, // question zone\type SOA
|
|
DNS_TYPE_SOA,
|
|
pBlob->pRecords,
|
|
DNSQUERY_UNICODE_NAME, // 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;
|
|
}
|
|
|
|
//
|
|
// init send blob
|
|
//
|
|
// note: do NOT set server array here as update
|
|
// network info blob (from FAZ or built
|
|
// from passed in array ourselves) takes precedence
|
|
//
|
|
|
|
RtlZeroMemory( &sendBlob, sizeof(sendBlob) );
|
|
|
|
sendBlob.pSendMsg = pmsgSend;
|
|
sendBlob.pNetInfo = pnetInfo;
|
|
//sendBlob.pServerArray = pserverArray;
|
|
sendBlob.Flags = pBlob->Flags;
|
|
sendBlob.fSaveResponse = TRUE;
|
|
sendBlob.Results.pMessage = pmsgRecv;
|
|
sendBlob.pRecvMsgBuf = pmsgRecv;
|
|
|
|
//
|
|
// try non-secure first unless explicitly secure only
|
|
//
|
|
|
|
fsecure = (pBlob->Flags & DNS_UPDATE_SECURITY_ONLY);
|
|
|
|
if ( !fsecure )
|
|
{
|
|
status = Send_AndRecv( &sendBlob );
|
|
|
|
// QUESTION: is this adequate to preserve precon fail RCODEs
|
|
// does Send_AndRecv() always give success to valid response
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
rcode = pmsgRecv->MessageHead.ResponseCode;
|
|
status = Dns_MapRcodeToStatus( rcode );
|
|
}
|
|
|
|
if ( status != DNS_ERROR_RCODE_REFUSED ||
|
|
pBlob->Flags & 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 ( !pserverName )
|
|
{
|
|
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
|
|
//
|
|
// DCR_FIX0: Secure update needs to be non-IP4_ARRAY
|
|
//
|
|
|
|
pcreds = Dns_GetApiContextCredentials( pBlob->hCreds );
|
|
|
|
status = Dns_DoSecureUpdate(
|
|
pmsgSend,
|
|
pmsgRecv,
|
|
NULL,
|
|
pBlob->Flags,
|
|
pnetInfo,
|
|
pserverArray,
|
|
pserverName,
|
|
pcreds, // initialized in DnsAcquireContextHandle
|
|
NULL // default context name
|
|
);
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
rcode = pmsgRecv->MessageHead.ResponseCode;
|
|
status = Dns_MapRcodeToStatus( rcode );
|
|
}
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// result info
|
|
//
|
|
// DCR: note not perfect info on whether actually got to send
|
|
//
|
|
// DCR: could be a case with UDP where receive message is NOT
|
|
// the message we sent to
|
|
// would only occur if non-FAZ server array of multiple entries
|
|
// and timeout on first
|
|
//
|
|
// FIX6: serverIP and rcode should be handled in send code
|
|
//
|
|
|
|
if ( pmsgSend && pmsgRecv )
|
|
{
|
|
pservAddr = &servAddr;
|
|
DnsAddr_Copy( pservAddr, &pmsgSend->RemoteAddress );
|
|
|
|
rcode = pmsgRecv->MessageHead.ResponseCode;
|
|
#if 0
|
|
if ( (rcode || status==NO_ERROR) && !pmsgRecv->fTcp )
|
|
{
|
|
DnsAddr_Copy( pservAddr, &pmsgRecv->RemoteAddress );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// save results
|
|
|
|
Update_SaveResults(
|
|
pBlob,
|
|
status,
|
|
rcode,
|
|
pservAddr );
|
|
|
|
// return recv message buffer
|
|
|
|
if ( pBlob->fSaveRecvMsg )
|
|
{
|
|
pBlob->pMsgRecv = pmsgRecv;
|
|
}
|
|
else
|
|
{
|
|
FREE_HEAP( pmsgRecv );
|
|
pBlob->pMsgRecv = NULL;
|
|
}
|
|
FREE_HEAP( pmsgSend);
|
|
FREE_HEAP( pserverArray );
|
|
NetInfo_Free( pnetInfoLocal );
|
|
|
|
// winsock cleanup if we started
|
|
|
|
GUI_MODE_SETUP_WS_CLEANUP( g_InNTSetupMode );
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Leave Update_Send() => %d %s.\n\n",
|
|
status,
|
|
Dns_StatusString(status) ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Update_FazSendFlush(
|
|
IN OUT PUPDATE_BLOB pBlob
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send DNS update.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- update info blob
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error status on failure.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status;
|
|
PDNS_NETINFO plocalNetworkInfo = NULL;
|
|
PDNS_NETINFO pnetInfo = pBlob->pNetInfo;
|
|
|
|
DNSDBG( TRACE, ( "Update_FazSendFlush( %p )\n", pBlob ));
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_UpdateBlob( "Entering Update_FazSendFlush", pBlob );
|
|
}
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// need to build update adapter list from FAZ
|
|
// - only pass on BYPASS_CACHE flag
|
|
// - note FAZ will append DNS_QUERY_ALLOW_EMPTY_AUTH_RESP
|
|
// flag yet DnsQuery() will fail on that flag without
|
|
// BYPASS_CACHE also set
|
|
//
|
|
|
|
if ( ! NetInfo_IsForUpdate(pnetInfo) )
|
|
{
|
|
status = Faz_Private(
|
|
pBlob->pRecords->pName,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
NULL, // no specified servers
|
|
& plocalNetworkInfo );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
return( status );
|
|
}
|
|
pnetInfo = plocalNetworkInfo;
|
|
pBlob->pNetInfo = pnetInfo;
|
|
}
|
|
|
|
//
|
|
// call update send routine
|
|
//
|
|
|
|
status = Update_Send( pBlob );
|
|
|
|
//
|
|
// if updated name -- flush cache entry for name
|
|
//
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
DnsFlushResolverCacheEntry_W(
|
|
pBlob->pRecords->pName );
|
|
}
|
|
|
|
//
|
|
// 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?
|
|
//
|
|
// DCR: update flushes don't make sense
|
|
// 1) FAZ bypasses cache, so comment really isn't the problem
|
|
// 2) ought to flush name itself anytime we can
|
|
//
|
|
|
|
if ( status == DNS_ERROR_RECORD_TIMED_OUT )
|
|
{
|
|
PWSTR pzoneName;
|
|
|
|
if ( pnetInfo &&
|
|
(pzoneName = NetInfo_UpdateZoneName( pnetInfo )) )
|
|
{
|
|
DnsFlushResolverCacheEntry_W( pzoneName );
|
|
DnsFlushResolverCacheEntry_W( pBlob->pRecords->pName );
|
|
}
|
|
}
|
|
|
|
|
|
// cleanup local adapter list if used
|
|
|
|
if ( plocalNetworkInfo )
|
|
{
|
|
NetInfo_Free( plocalNetworkInfo );
|
|
if ( pBlob->pNetInfo == plocalNetworkInfo )
|
|
{
|
|
pBlob->pNetInfo = NULL;
|
|
}
|
|
}
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leave Update_FazSendFlush( %p ) => %d\n",
|
|
pBlob,
|
|
status ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Update_MultiMaster(
|
|
IN OUT PUPDATE_BLOB pBlob
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do multi-master update.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- update info blob
|
|
note: IP4 array ignored, must be converted to DNS_ADDR higher.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
PADDR_ARRAY pnsList = NULL;
|
|
PADDR_ARRAY pbadServerList = NULL;
|
|
PADDR_ARRAY plocalAddrs = NULL;
|
|
DNS_STATUS status = DNS_ERROR_NO_DNS_SERVERS;
|
|
DWORD iter;
|
|
PDNS_ADDR pfailedAddr;
|
|
BOOL fremoteUpdate = (pBlob->Flags & DNS_UPDATE_REMOTE_SERVER);
|
|
DWORD savedStatus;
|
|
BASIC_RESULTS savedRemoteResults;
|
|
BASIC_RESULTS savedLocalResults;
|
|
BOOL isLocal = FALSE;
|
|
BOOL fdoneLocal = FALSE;
|
|
BOOL fdoneRemote = FALSE;
|
|
BOOL fdoneRemoteSuccess = FALSE;
|
|
|
|
|
|
DNSDBG( UPDATE, (
|
|
"\nUpdate_MultiMaster( %p )\n", pBlob ));
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_UpdateBlob( "Entering Update_MultiMaster", pBlob );
|
|
}
|
|
|
|
DNS_ASSERT( !pBlob->fSaveRecvMsg );
|
|
pBlob->fSaveRecvMsg = FALSE;
|
|
|
|
//
|
|
// read NS list for zone
|
|
//
|
|
|
|
pnsList = GetNameServersListForDomain(
|
|
pBlob->pszZone,
|
|
pBlob->pServerList );
|
|
if ( !pnsList )
|
|
{
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// validate failed IP
|
|
//
|
|
|
|
pfailedAddr = &pBlob->FailedServer;
|
|
|
|
if ( DnsAddr_IsEmpty(pfailedAddr) )
|
|
{
|
|
pfailedAddr = NULL;
|
|
}
|
|
|
|
if ( pfailedAddr &&
|
|
pnsList->AddrCount == 1 &&
|
|
DAddr_IsEqual(
|
|
pfailedAddr,
|
|
& pnsList->AddrArray[0] ) )
|
|
{
|
|
status = ERROR_TIMEOUT;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// create bad server list
|
|
// - init with any previous failed DNS server
|
|
//
|
|
|
|
pbadServerList = DnsAddrArray_Create( pnsList->AddrCount + 1 );
|
|
if ( !pbadServerList )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Done;
|
|
}
|
|
if ( pfailedAddr )
|
|
{
|
|
DnsAddrArray_AddAddr(
|
|
pbadServerList,
|
|
pfailedAddr,
|
|
0, // no family screen
|
|
0 // no dup screen
|
|
);
|
|
}
|
|
|
|
//
|
|
// get local IP list
|
|
//
|
|
|
|
if ( fremoteUpdate )
|
|
{
|
|
plocalAddrs = NetInfo_GetLocalAddrArray(
|
|
pBlob->pNetInfo,
|
|
NULL, // no specific adapter
|
|
0, // no specific family
|
|
0, // no flags
|
|
FALSE // no force, should have recent copy
|
|
);
|
|
}
|
|
|
|
//
|
|
// init results
|
|
//
|
|
|
|
RtlZeroMemory( &savedRemoteResults, sizeof(savedRemoteResults) );
|
|
RtlZeroMemory( &savedLocalResults, sizeof(savedLocalResults) );
|
|
|
|
//
|
|
// 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++ )
|
|
{
|
|
PDNS_ADDR pservAddr = &pnsList->AddrArray[iter];
|
|
PDNS_ADDR pfazAddr;
|
|
ADDR_ARRAY ipArray;
|
|
|
|
//
|
|
// already attempted this server?
|
|
//
|
|
|
|
if ( AddrArray_ContainsAddr( pbadServerList, pservAddr ) )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster skip update to bad IP %s.\n",
|
|
DNSADDR_STRING(pservAddr) ));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// if require remote, screen out local server
|
|
//
|
|
// note: currently updating both local and one remote
|
|
// could do just remote
|
|
//
|
|
|
|
if ( fremoteUpdate )
|
|
{
|
|
isLocal = LocalIp_IsAddrLocal( pservAddr, plocalAddrs, NULL );
|
|
if ( isLocal )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster local IP %s -- IsDns %d.\n",
|
|
DNSADDR_STRING( pservAddr ),
|
|
g_IsDnsServer ));
|
|
|
|
if ( fdoneLocal )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster skip local IP %s after local.\n",
|
|
DNSADDR_STRING( pservAddr ) ));
|
|
continue;
|
|
}
|
|
}
|
|
else if ( fdoneRemoteSuccess )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster skip remote IP %s after success remote.\n",
|
|
DNSADDR_STRING( pservAddr ) ));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// FAZ to get primary "seen" by this NS
|
|
//
|
|
|
|
DnsAddrArray_InitSingleWithAddr(
|
|
& ipArray,
|
|
pservAddr );
|
|
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster FAZ to %s.\n",
|
|
DNSADDR_STRING( pservAddr ) ));
|
|
|
|
status = DoQuickFAZ(
|
|
&pnetInfo,
|
|
pBlob->pszZone,
|
|
&ipArray );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster skip IP %s on FAZ failure => %d.\n",
|
|
DNSADDR_STRING( pservAddr ),
|
|
status ));
|
|
continue;
|
|
}
|
|
|
|
DNS_ASSERT( pnetInfo->AdapterCount == 1 );
|
|
DNS_ASSERT( pnetInfo->AdapterArray[0].pDnsAddrs );
|
|
|
|
//
|
|
// check FAZ result IP
|
|
// - if different from server, use it
|
|
// - but verify not in bad\previous list
|
|
//
|
|
|
|
pfazAddr = &pnetInfo->AdapterArray[0].pDnsAddrs->AddrArray[0];
|
|
|
|
if ( !DnsAddr_IsEqual( pservAddr, pfazAddr, DNSADDR_MATCH_ADDR ) )
|
|
{
|
|
if ( DnsAddrArray_ContainsAddr(
|
|
pbadServerList,
|
|
pfazAddr,
|
|
DNSADDR_MATCH_ADDR ) )
|
|
{
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster skip FAZ result IP %s -- bad list.\n",
|
|
DNSADDR_STRING( pservAddr ) ));
|
|
NetInfo_Free( pnetInfo );
|
|
pnetInfo = NULL;
|
|
continue;
|
|
}
|
|
pservAddr = pfazAddr;
|
|
}
|
|
|
|
DNSDBG( UPDATE, (
|
|
"MultiMaster update to %s.\n",
|
|
DNSADDR_STRING( pservAddr ) ));
|
|
|
|
pBlob->pNetInfo = pnetInfo;
|
|
|
|
status = Update_FazSendFlush( pBlob );
|
|
|
|
pBlob->pNetInfo = NULL;
|
|
|
|
//
|
|
// save results
|
|
// - save local result (we assume there should only be one and
|
|
// if more than one result should be the same)
|
|
// - save best remote result; NO_ERROR tops, otherwise highest
|
|
// error is best
|
|
//
|
|
|
|
if ( isLocal )
|
|
{
|
|
fdoneLocal = TRUE;
|
|
RtlCopyMemory(
|
|
&savedLocalResults,
|
|
&pBlob->Results,
|
|
sizeof( savedLocalResults ) );
|
|
}
|
|
else
|
|
{
|
|
BOOL fsaveResults = FALSE;
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
fsaveResults = !fdoneRemoteSuccess;
|
|
fdoneRemoteSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fsaveResults = !fdoneRemoteSuccess &&
|
|
status > savedRemoteResults.Status;
|
|
}
|
|
if ( fsaveResults )
|
|
{
|
|
fdoneRemote = TRUE;
|
|
RtlCopyMemory(
|
|
&savedRemoteResults,
|
|
&pBlob->Results,
|
|
sizeof( savedRemoteResults ) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for continue
|
|
// - timeouts
|
|
// - all-master updates
|
|
// - require remote server update (but we save success IP
|
|
// and screen above)
|
|
//
|
|
// other cases stop once a single update completes
|
|
//
|
|
// DCR: continue multi-master-update until success?
|
|
// DCR: not supporting some servers update-on others off
|
|
// you can have case here where some servers are configured to
|
|
// accept update and some are not
|
|
|
|
if ( status == ERROR_TIMEOUT ||
|
|
status == DNS_RCODE_SERVER_FAILURE )
|
|
{
|
|
}
|
|
else if ( fremoteUpdate ||
|
|
( pBlob->Flags & DNS_UPDATE_TRY_ALL_MASTER_SERVERS ) )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
// continue -- screen off this IP
|
|
|
|
AddrArray_AddAddr(
|
|
pbadServerList,
|
|
pservAddr );
|
|
|
|
// cleanup FAZ netinfo
|
|
// - doing this last as FAZ IP is pointer into this struct
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
pnetInfo = NULL;
|
|
continue;
|
|
}
|
|
|
|
|
|
Done:
|
|
|
|
//
|
|
// set best results
|
|
//
|
|
|
|
{
|
|
PBASIC_RESULTS presults = NULL;
|
|
|
|
if ( fdoneRemote )
|
|
{
|
|
presults = &savedRemoteResults;
|
|
}
|
|
else if ( fdoneLocal )
|
|
{
|
|
presults = &savedLocalResults;
|
|
}
|
|
if ( presults )
|
|
{
|
|
Update_SaveResults(
|
|
pBlob,
|
|
presults->Status,
|
|
presults->Rcode,
|
|
&presults->ServerAddr );
|
|
|
|
status = presults->Status;
|
|
}
|
|
}
|
|
|
|
FREE_HEAP( pnsList );
|
|
FREE_HEAP( pbadServerList );
|
|
FREE_HEAP( plocalAddrs );
|
|
NetInfo_Free( pnetInfo );
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Update_Private(
|
|
IN OUT PUPDATE_BLOB pBlob
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main private update routine.
|
|
|
|
Do FAZ and determines
|
|
- multi-homing
|
|
- multi-master
|
|
before handing over to next level.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- update info blob
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PWSTR pzoneName;
|
|
PWSTR pname;
|
|
PADDR_ARRAY pserverList;
|
|
PADDR_ARRAY pserverListCopy = NULL;
|
|
PADDR_ARRAY poriginalServerList;
|
|
PIP4_ARRAY pserv4List;
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
DWORD flags = pBlob->Flags;
|
|
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Update_Private( blob=%p )\n",
|
|
pBlob ));
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_UpdateBlob( "Entering Update_Private", pBlob );
|
|
}
|
|
|
|
//
|
|
// get record name
|
|
//
|
|
|
|
if ( !pBlob->pRecords )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
pname = pBlob->pRecords->pName;
|
|
|
|
//
|
|
// unpack to locals
|
|
//
|
|
|
|
pserverList = pBlob->pServerList;
|
|
pserv4List = pBlob->pServ4List;
|
|
|
|
poriginalServerList = pserverList;
|
|
|
|
//
|
|
// caller has particular server list
|
|
// - convert IP4 list
|
|
//
|
|
|
|
pserverListCopy = Util_GetAddrArray(
|
|
NULL,
|
|
pserverList,
|
|
pserv4List,
|
|
pBlob->pExtraInfo );
|
|
|
|
//
|
|
// update with particular server list
|
|
//
|
|
|
|
if ( pserverListCopy )
|
|
{
|
|
//
|
|
// FAZ to create update network info
|
|
//
|
|
|
|
status = DoQuickFAZ(
|
|
&pnetInfo,
|
|
pname,
|
|
pserverListCopy );
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
DnsAddrArray_Free( pserverListCopy );
|
|
goto Done;
|
|
}
|
|
|
|
DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
|
|
pzoneName = NetInfo_UpdateZoneName( pnetInfo );
|
|
|
|
pBlob->pszZone = pzoneName;
|
|
pBlob->pNetInfo = pnetInfo;
|
|
|
|
//
|
|
// update scale
|
|
// - directly multimaster
|
|
// OR
|
|
// - single, but fail over to multi-master attempt if timeout
|
|
//
|
|
|
|
if ( flags & (DNS_UPDATE_TRY_ALL_MASTER_SERVERS | DNS_UPDATE_REMOTE_SERVER) )
|
|
{
|
|
pBlob->pServerList = pserverListCopy;
|
|
|
|
status = Update_MultiMaster( pBlob );
|
|
}
|
|
else
|
|
{
|
|
status = Update_FazSendFlush( pBlob );
|
|
|
|
if ( status == ERROR_TIMEOUT )
|
|
{
|
|
pBlob->pServerList = pserverListCopy;
|
|
status = Update_MultiMaster( pBlob );
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
DnsAddrArray_Free( pserverListCopy );
|
|
|
|
pBlob->pNetInfo = NULL;
|
|
pBlob->pServerList = poriginalServerList;
|
|
pBlob->pszZone = NULL;
|
|
DnsAddr_Clear( &pBlob->FailedServer );
|
|
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// server list unspecified
|
|
// - use FAZ to figure it out
|
|
//
|
|
|
|
else
|
|
{
|
|
PADDR_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,
|
|
pBlob->Flags
|
|
);
|
|
|
|
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;
|
|
}
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// do update on all distinct (disjoint) networks
|
|
//
|
|
|
|
for ( iter = 0;
|
|
iter < netCount;
|
|
iter++ )
|
|
{
|
|
PADDR_ARRAY pdnsArray = serverListArray[ iter ];
|
|
|
|
pnetInfo = networkInfoArray[ iter ];
|
|
if ( !pnetInfo )
|
|
{
|
|
ASSERT( FALSE );
|
|
FREE_HEAP( pdnsArray );
|
|
continue;
|
|
}
|
|
|
|
DNS_ASSERT( NetInfo_IsForUpdate(pnetInfo) );
|
|
pzoneName = NetInfo_UpdateZoneName( pnetInfo );
|
|
|
|
pBlob->pszZone = pzoneName;
|
|
pBlob->pNetInfo = pnetInfo;
|
|
|
|
//
|
|
// multimater update?
|
|
// - if flag set
|
|
// - or simple update (best net) times out
|
|
//
|
|
|
|
if ( flags & (DNS_UPDATE_TRY_ALL_MASTER_SERVERS | DNS_UPDATE_REMOTE_SERVER) )
|
|
{
|
|
pBlob->pServerList = pdnsArray;
|
|
|
|
status = Update_MultiMaster( pBlob );
|
|
}
|
|
else
|
|
{
|
|
status = Update_FazSendFlush( pBlob );
|
|
|
|
if ( status == ERROR_TIMEOUT )
|
|
{
|
|
pBlob->pServerList = pdnsArray;
|
|
status = Update_MultiMaster( pBlob );
|
|
}
|
|
}
|
|
|
|
// cleanup current network's info
|
|
// reset blob
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
FREE_HEAP( pdnsArray );
|
|
|
|
pBlob->pNetInfo = NULL;
|
|
pBlob->pServerList = NULL;
|
|
pBlob->pszZone = NULL;
|
|
DnsAddr_Clear( &pBlob->FailedServer );
|
|
|
|
if ( status == NO_ERROR ||
|
|
( pBlob->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 )
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
//
|
|
// force result blob setting for failure cases
|
|
//
|
|
|
|
if ( !pBlob->fSavedResults )
|
|
{
|
|
Update_SaveResults(
|
|
pBlob,
|
|
status,
|
|
0,
|
|
NULL );
|
|
}
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leaving Update_Private() => %d\n",
|
|
status ));
|
|
|
|
IF_DNSDBG( UPDATE )
|
|
{
|
|
DnsDbg_UpdateBlob( "Leaving Update_Private", pBlob );
|
|
}
|
|
|
|
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 (always in unicode)
|
|
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;
|
|
PWSTR 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 = 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_W( pname, prr->pName ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
prr = prr->pNext;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
PDNS_RECORD
|
|
buildUpdateRecordSet(
|
|
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: records sets always in unicode.
|
|
|
|
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, ( "buildUpdateRecordSet()\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
|
|
replaceRecordSetPrivate(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP4_ARRAY pServ4List, OPTIONAL
|
|
IN PVOID pExtraInfo,
|
|
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 - ptr to blob
|
|
|
|
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;
|
|
UPDATE_BLOB blob;
|
|
PDNS_ADDR_ARRAY pservArray = NULL;
|
|
|
|
|
|
DNSDBG( TRACE, (
|
|
"\n\nDnsReplaceRecordSet()\n"
|
|
"replaceRecordSetPrivate()\n"
|
|
"\tpReplaceSet = %p\n"
|
|
"\tOptions = %08x\n"
|
|
"\thCredentials = %p\n"
|
|
"\tpServ4List = %p\n"
|
|
"\tpExtra = %p\n"
|
|
"\tCharSet = %d\n",
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
pServ4List,
|
|
pExtraInfo,
|
|
CharSet
|
|
));
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// make local record set copy in unicode
|
|
//
|
|
|
|
if ( !pReplaceSet )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
preplaceCopy = Dns_RecordSetCopyEx(
|
|
pReplaceSet,
|
|
CharSet,
|
|
DnsCharSetUnicode );
|
|
if ( !preplaceCopy )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// 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 = preplaceCopy->pName;
|
|
rrDeleteType.wType = preplaceCopy->wType;
|
|
rrDeleteType.wDataLength = 0;
|
|
rrDeleteType.Flags.DW = DNSREC_UPDATE | DNSREC_DELETE | DNSREC_UNICODE;
|
|
|
|
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 = preplaceCopy->pName;
|
|
rrNoCname.wType = DNS_TYPE_CNAME;
|
|
rrNoCname.wDataLength = 0;
|
|
rrNoCname.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST | DNSREC_UNICODE;
|
|
rrNoCname.pNext = &rrDeleteType;
|
|
|
|
pupdateList = &rrNoCname;
|
|
}
|
|
|
|
//
|
|
// do the update
|
|
//
|
|
|
|
RtlZeroMemory( &blob, sizeof(blob) );
|
|
|
|
blob.pRecords = pupdateList;
|
|
blob.Flags = Options;
|
|
blob.pServ4List = pServ4List;
|
|
blob.pExtraInfo = pExtraInfo;
|
|
blob.hCreds = hCredentials;
|
|
|
|
status = Update_Private( &blob );
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// build addr array
|
|
//
|
|
|
|
pservArray = Util_GetAddrArray(
|
|
NULL, // no copy issue
|
|
NULL, // no addr array
|
|
pServ4List,
|
|
pExtraInfo );
|
|
|
|
// DCR: need to query update server list here to
|
|
// avoid intermediate caching
|
|
|
|
status = Query_Private(
|
|
preplaceCopy->pName,
|
|
DNS_TYPE_CNAME,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
pservArray,
|
|
& pqueryRR );
|
|
|
|
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 = Query_Private(
|
|
preplaceCopy->pName,
|
|
DNS_TYPE_ALL,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
pservArray,
|
|
& pqueryRR );
|
|
|
|
if ( status == ERROR_SUCCESS )
|
|
{
|
|
PDNS_RECORD prr = pqueryRR;
|
|
|
|
while ( prr )
|
|
{
|
|
if ( pReplaceSet->wType != prr->wType &&
|
|
Dns_NameCompare_W(
|
|
preplaceCopy->pName,
|
|
prr->pName ) )
|
|
{
|
|
status = DNS_ERROR_RCODE_YXRRSET;
|
|
break;
|
|
}
|
|
prr = prr->pNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
Dns_RecordListFree( pqueryRR );
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
Dns_RecordListFree( preplaceCopy );
|
|
DnsAddrArray_Free( pservArray );
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leave replaceRecordSetPrivate() = %d\n"
|
|
"Leave DnsReplaceRecordSet()\n\n\n",
|
|
status
|
|
));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetUTF8(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return replaceRecordSetPrivate(
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
aipServers,
|
|
pReserved,
|
|
DnsCharSetUtf8
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetW(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return replaceRecordSetPrivate(
|
|
pReplaceSet,
|
|
Options,
|
|
hCredentials,
|
|
aipServers,
|
|
pReserved,
|
|
DnsCharSetUnicode
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsReplaceRecordSetA(
|
|
IN PDNS_RECORD pReplaceSet,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return replaceRecordSetPrivate(
|
|
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 PADDR_ARRAY pServerList, OPTIONAL
|
|
IN PIP4_ARRAY pServ4List, 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 - ptr to blob
|
|
|
|
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;
|
|
UPDATE_BLOB blob;
|
|
|
|
DNSDBG( TRACE, (
|
|
"\n\nDns_ModifyRecordsInSet()\n"
|
|
"modifyRecordsInSetPrivate()\n"
|
|
"\tpAddSet = %p\n"
|
|
"\tpDeleteSet = %p\n"
|
|
"\tOptions = %08x\n"
|
|
"\thCredentials = %p\n"
|
|
"\tpServerList = %p\n"
|
|
"\tpServ4List = %p\n"
|
|
"\tCharSet = %d\n",
|
|
pAddRecords,
|
|
pDeleteRecords,
|
|
Options,
|
|
hCredentials,
|
|
pServerList,
|
|
pServ4List,
|
|
CharSet
|
|
));
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
//
|
|
// make local copy in unicode
|
|
//
|
|
|
|
if ( pAddRecords )
|
|
{
|
|
paddCopy = Dns_RecordSetCopyEx(
|
|
pAddRecords,
|
|
CharSet,
|
|
DnsCharSetUnicode );
|
|
}
|
|
if ( pDeleteRecords )
|
|
{
|
|
pdeleteCopy = Dns_RecordSetCopyEx(
|
|
pDeleteRecords,
|
|
CharSet,
|
|
DnsCharSetUnicode );
|
|
}
|
|
|
|
//
|
|
// 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_W( 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 = buildUpdateRecordSet(
|
|
NULL, // no precons
|
|
paddCopy,
|
|
pdeleteCopy );
|
|
|
|
//
|
|
// do the update
|
|
//
|
|
|
|
RtlZeroMemory( &blob, sizeof(blob) );
|
|
|
|
blob.pRecords = pupdateSet;
|
|
blob.Flags = Options;
|
|
blob.pServerList = pServerList;
|
|
blob.pServ4List = pServ4List;
|
|
blob.pExtraInfo = pReserved;
|
|
blob.hCreds = hCredentials;
|
|
|
|
status = Update_Private( &blob );
|
|
|
|
//
|
|
// cleanup local copy
|
|
//
|
|
|
|
Dns_RecordListFree( pupdateSet );
|
|
|
|
goto Exit;
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// cleanup copies on failure before combined list
|
|
//
|
|
|
|
Dns_RecordListFree( paddCopy );
|
|
Dns_RecordListFree( pdeleteCopy );
|
|
|
|
Exit:
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leave modifyRecordsInSetPrivate() => %d\n"
|
|
"Leave Dns_ModifyRecordsInSet()\n\n\n",
|
|
status ));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_W(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
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,
|
|
NULL, // no IP6 servers
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetUnicode
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_A(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
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,
|
|
NULL, // no IP6 servers
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetAnsi
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsModifyRecordsInSet_UTF8(
|
|
IN PDNS_RECORD pAddRecords,
|
|
IN PDNS_RECORD pDeleteRecords,
|
|
IN DWORD Options,
|
|
IN HANDLE hCredentials, OPTIONAL
|
|
IN PIP4_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 - ptr to blob
|
|
|
|
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,
|
|
NULL, // no IP6 servers
|
|
pServerList,
|
|
pReserved,
|
|
DnsCharSetUtf8
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Update test functions are called by system components
|
|
//
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_UTF8(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP4_ARRAY pServerList 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).
|
|
|
|
pServerList - 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, (
|
|
"\n\nDnsUpdateTest_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,
|
|
pServerList );
|
|
|
|
FREE_HEAP( pnameWide );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_A(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP4_ARRAY pServerList 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).
|
|
|
|
pServerList - 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, (
|
|
"\n\nDnsUpdateTest_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,
|
|
pServerList );
|
|
|
|
FREE_HEAP( pnameWide );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsUpdateTest_W(
|
|
IN HANDLE hCredentials OPTIONAL,
|
|
IN PCWSTR pszName,
|
|
IN DWORD Flags,
|
|
IN PIP4_ARRAY pServerList 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).
|
|
|
|
pServerList - 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;
|
|
UPDATE_BLOB blob;
|
|
|
|
DNSDBG( TRACE, (
|
|
"\n\nDnsUpdateTest_W( %S )\n",
|
|
pszName ));
|
|
|
|
//
|
|
// validation
|
|
//
|
|
|
|
if ( flags & DNS_UNACCEPTABLE_UPDATE_OPTIONS )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
if ( !pszName )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// read update config
|
|
//
|
|
|
|
Reg_RefreshUpdateConfig();
|
|
|
|
if ( UseSystemDefaultForSecurity( flags ) )
|
|
{
|
|
flags |= g_UpdateSecurityLevel;
|
|
}
|
|
if ( hCredentials )
|
|
{
|
|
flags |= DNS_UPDATE_CACHE_SECURITY_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// build record
|
|
// - NOEXIST prerequisite
|
|
//
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
record.pName = (PWSTR) pszName;
|
|
record.wType = DNS_TYPE_ANY;
|
|
record.wDataLength = 0;
|
|
record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST | DNSREC_UNICODE;
|
|
|
|
//
|
|
// do the prereq update
|
|
//
|
|
|
|
RtlZeroMemory( &blob, sizeof(blob) );
|
|
blob.pRecords = &record;
|
|
blob.Flags = flags;
|
|
blob.fUpdateTestMode = TRUE;
|
|
blob.pServ4List = pServerList;
|
|
blob.hCreds = hCredentials;
|
|
|
|
status = Update_Private( &blob );
|
|
|
|
Exit:
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leave DnsUpdateTest_W() = %d\n\n\n",
|
|
status ));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Old routines -- exported and used in dnsup.exe
|
|
//
|
|
// DCR: Work toward removing these old update functions.
|
|
//
|
|
|
|
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:
|
|
|
|
Interface for dnsup.exe.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
#if 0
|
|
DNS_STATUS status;
|
|
UPDATE_BLOB blob;
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Dns_UpdateLib()\n"
|
|
"\tflags = %08x\n"
|
|
"\tpRecord = %p\n"
|
|
"\t\towner = %S\n",
|
|
dwFlags,
|
|
pRecord,
|
|
pRecord ? pRecord->pName : NULL ));
|
|
|
|
//
|
|
// create blob
|
|
//
|
|
|
|
RtlZeroMemory( &blob, sizeof(blob) );
|
|
|
|
blob.pRecords = pRecord;
|
|
blob.Flags = dwFlags;
|
|
blob.pNetInfo = pNetworkInfo;
|
|
blob.hCreds = hCreds;
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
blob.fSaveRecvMsg = TRUE;
|
|
}
|
|
|
|
status = Update_FazSendFlush( &blob );
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
*ppMsgRecv = blob.pMsgRecv;
|
|
}
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Leave Dns_UpdateLib() => %d %s.\n\n",
|
|
status,
|
|
Dns_StatusString(status) ));
|
|
|
|
return( status );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
Dns_UpdateLibEx(
|
|
IN PDNS_RECORD pRecord,
|
|
IN DWORD dwFlags,
|
|
IN PWSTR pszZone,
|
|
IN PWSTR pszServerName,
|
|
IN PIP4_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.
|
|
|
|
--*/
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
#if 0
|
|
PDNS_NETINFO pnetInfo;
|
|
DNS_STATUS status = NO_ERROR;
|
|
|
|
DNSDBG( UPDATE, ( "Dns_UpdateLibEx()\n" ));
|
|
|
|
//
|
|
// convert params into UPDATE compatible adapter list
|
|
//
|
|
|
|
pnetInfo = NetInfo_CreateForUpdateIp4(
|
|
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 );
|
|
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Leave Dns_UpdateLibEx() => %d\n",
|
|
status ));
|
|
|
|
return status;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
#if 0
|
|
DNS_STATUS status;
|
|
PDNS_NETINFO plocalNetworkInfo = NULL;
|
|
UPDATE_BLOB blob;
|
|
|
|
DNSDBG( TRACE, ( "DnsUpdate()\n" ));
|
|
|
|
//
|
|
// create blob
|
|
//
|
|
|
|
RtlZeroMemory( &blob, sizeof(blob) );
|
|
|
|
blob.pRecords = pRecord;
|
|
blob.Flags = dwFlags;
|
|
blob.pNetInfo = pNetworkInfo;
|
|
blob.hCreds = hCreds;
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
blob.fSaveRecvMsg = TRUE;
|
|
}
|
|
|
|
status = Update_FazSendFlush( &blob );
|
|
|
|
if ( ppMsgRecv )
|
|
{
|
|
*ppMsgRecv = blob.pMsgRecv;
|
|
}
|
|
|
|
DNSDBG( UPDATE, (
|
|
"Leave DnsUpdate() => %d\n",
|
|
status ));
|
|
|
|
return status;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// End update.c
|
|
//
|
|
|
|
|