Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3072 lines
72 KiB

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