|
|
/*++
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
//
|