3073 lines
72 KiB
C
3073 lines
72 KiB
C
/*++
|
||
|
||
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
|
||
//
|
||
|
||
|