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.
1845 lines
50 KiB
1845 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dynreg.c
|
|
|
|
Abstract:
|
|
|
|
Domain Name System (DNS) API
|
|
|
|
Dynamic registration implementation
|
|
|
|
Author:
|
|
|
|
Ram Viswanathan (ramv) March 27 1997
|
|
|
|
Revision History:
|
|
|
|
Jim Gilroy (jamesg) May 2001 proper cred handling
|
|
|
|
Jim Gilroy (jamesg) Dec 2001 init,shutdown,race protection
|
|
|
|
--*/
|
|
|
|
#include "local.h"
|
|
|
|
#define ENABLE_DEBUG_LOGGING 0
|
|
|
|
#include "logit.h"
|
|
|
|
|
|
// hQuitEvent
|
|
// hSem
|
|
// handles
|
|
// hConsumerThread
|
|
// fStopNotify
|
|
|
|
HANDLE g_DhcpSrvQuitEvent = NULL;
|
|
HANDLE g_DhcpSrvSem = NULL;
|
|
HANDLE g_DhcpSrvWaitHandles[2] = { NULL, NULL};
|
|
HANDLE g_hDhcpSrvRegThread = NULL;
|
|
BOOL g_fDhcpSrvStop = FALSE;
|
|
|
|
// g_pdnsQueue
|
|
// g_pDhcpSrvTimedOutQueue
|
|
// g_QueueCount
|
|
// g_MainQueueCount
|
|
|
|
PDYNDNSQUEUE g_pDhcpSrvQueue = NULL;
|
|
PDYNDNSQUEUE g_pDhcpSrvTimedOutQueue = NULL;
|
|
DWORD g_DhcpSrvRegQueueCount = 0;
|
|
DWORD g_DhcpSrvMainQueueCount = 0;
|
|
BOOL g_fDhcpSrvQueueCsCreated = FALSE;
|
|
|
|
#define MAX_QLEN 0xFFFF
|
|
#define MAX_RETRIES 0x3
|
|
|
|
//
|
|
// Max queue size
|
|
// - configurable in init
|
|
// - default 1K
|
|
// - max 64K
|
|
//
|
|
|
|
#define DHCPSRV_DEFAULT_MAX_QUEUE_SIZE 0x0400
|
|
#define DHCPSRV_MAX_QUEUE_SIZE 0xffff
|
|
|
|
DWORD g_DhcpSrvMaxQueueSize = DHCPSRV_DEFAULT_MAX_QUEUE_SIZE;
|
|
|
|
|
|
|
|
//
|
|
// protection for init\shutdown
|
|
//
|
|
|
|
BOOL g_fDhcpSrvCsCreated = FALSE;
|
|
CRITICAL_SECTION g_DhcpSrvCS;
|
|
|
|
#define DHCP_SRV_STATE_LOCK() LockDhcpSrvState()
|
|
#define DHCP_SRV_STATE_UNLOCK() LeaveCriticalSection( &g_DhcpSrvCS )
|
|
|
|
|
|
#define DNS_DHCP_SRV_STATE_UNINIT 0
|
|
#define DNS_DHCP_SRV_STATE_INIT_FAILED 1
|
|
#define DNS_DHCP_SRV_STATE_SHUTDOWN 2
|
|
#define DNS_DHCP_SRV_STATE_INITIALIZING 5
|
|
#define DNS_DHCP_SRV_STATE_SHUTTING_DOWN 6
|
|
#define DNS_DHCP_SRV_STATE_RUNNING 10
|
|
#define DNS_DHCP_SRV_STATE_QUEUING 11
|
|
|
|
DWORD g_DhcpSrvState = DNS_DHCP_SRV_STATE_UNINIT;
|
|
|
|
|
|
//
|
|
// Credentials for updates
|
|
//
|
|
|
|
PSEC_WINNT_AUTH_IDENTITY_W g_pIdentityCreds = NULL;
|
|
|
|
//CredHandle g_CredHandle;
|
|
|
|
HANDLE g_UpdateCredContext = NULL;
|
|
|
|
|
|
//
|
|
// Queue allocations in dnslib heap
|
|
//
|
|
|
|
#define QUEUE_ALLOC_HEAP(Size) Dns_Alloc(Size)
|
|
#define QUEUE_ALLOC_HEAP_ZERO(Size) Dns_AllocZero(Size)
|
|
#define QUEUE_FREE_HEAP(pMem) Dns_Free(pMem)
|
|
|
|
|
|
|
|
//
|
|
// local helper functions
|
|
//
|
|
|
|
BOOL
|
|
LockDhcpSrvState(
|
|
VOID
|
|
);
|
|
|
|
DNS_STATUS
|
|
DynDnsRegisterEntries(
|
|
VOID
|
|
);
|
|
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
DynDnsAddForward(
|
|
IN OUT REGISTER_HOST_ENTRY HostAddr,
|
|
IN LPWSTR pszName,
|
|
IN DWORD dwTTL,
|
|
IN PIP4_ARRAY DnsServerList
|
|
)
|
|
{
|
|
DNS_STATUS status = 0;
|
|
DNS_RECORD record;
|
|
|
|
DYNREG_F1( "Inside function DynDnsAddForward" );
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
|
|
record.pName = (PTCHAR) pszName;
|
|
record.wType = DNS_TYPE_A;
|
|
record.dwTtl = dwTTL;
|
|
record.wDataLength = sizeof(record.Data.A);
|
|
record.Data.A.IpAddress = HostAddr.Addr.ipAddr;
|
|
|
|
DYNREG_F1( "DynDnsAddForward - Calling DnsReplaceRecordSet_W for A record:" );
|
|
DYNREG_F2( " Name: %S", record.pName );
|
|
DYNREG_F2( " Address: 0x%x", record.Data.A.IpAddress );
|
|
|
|
status = DnsReplaceRecordSetW(
|
|
& record,
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList,
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsAddForward - DnsReplaceRecordSet returned status: 0%x", status );
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
DynDnsDeleteForwards(
|
|
IN PDNS_RECORD pDnsList,
|
|
IN IP4_ADDRESS ipAddr,
|
|
IN PIP4_ARRAY DnsServerList
|
|
)
|
|
{
|
|
DNS_STATUS status = 0;
|
|
PDNS_RECORD prr;
|
|
DNS_RECORD record;
|
|
|
|
DYNREG_F1( "Inside function DynDnsDeleteForwards" );
|
|
|
|
//
|
|
// the list pointed to by pDnsList is a set of PTR records.
|
|
//
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
|
|
prr = pDnsList;
|
|
|
|
for ( prr = pDnsList;
|
|
prr;
|
|
prr = prr->pNext )
|
|
{
|
|
if ( prr->wType != DNS_TYPE_PTR )
|
|
{
|
|
//
|
|
// should not happen
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// As far as the DHCP server is concerned, when timeout happens
|
|
// or when client releases an address, It can update the
|
|
// address lookup to clean up turds left over by say, a roaming
|
|
// laptop
|
|
//
|
|
|
|
record.pName = prr->Data.Ptr.pNameHost;
|
|
record.wType = DNS_TYPE_A;
|
|
record.wDataLength = sizeof(DNS_A_DATA);
|
|
record.Data.A.IpAddress = ipAddr ;
|
|
|
|
//
|
|
// make the appropriate call and return the first failed error
|
|
//
|
|
|
|
DYNREG_F1( "DynDnsDeleteForwards - Calling ModifyRecords(Remove) for A record:" );
|
|
DYNREG_F2( " Name: %S", record.pName );
|
|
DYNREG_F2( " Address: 0x%x", record.Data.A.IpAddress );
|
|
|
|
status = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
& record, // delete record
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList, // DNS servers
|
|
NULL // reserved
|
|
);
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// DCR_QUESTION: do we really want to stop on failure?
|
|
break;
|
|
}
|
|
DYNREG_F2( "DynDnsDeleteForwards - ModifyRecords(Remove) returned status: 0%x", status );
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
DynDnsAddEntry(
|
|
REGISTER_HOST_ENTRY HostAddr,
|
|
LPWSTR pszName,
|
|
DWORD dwRegisteredTTL,
|
|
BOOL fDoForward,
|
|
PDWORD pdwFwdErrCode,
|
|
PIP4_ARRAY DnsServerList
|
|
)
|
|
{
|
|
DNS_STATUS status = 0;
|
|
DWORD returnCode = 0;
|
|
DNS_RECORD record;
|
|
WCHAR reverseNameBuf[DNS_MAX_REVERSE_NAME_BUFFER_LENGTH];
|
|
DWORD cch;
|
|
|
|
DYNREG_F1( "Inside function DynDnsAddEntry" );
|
|
|
|
*pdwFwdErrCode = 0;
|
|
|
|
if ( !(HostAddr.dwOptions & REGISTER_HOST_PTR) )
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// create reverse lookup name for IP address
|
|
//
|
|
|
|
Dns_Ip4AddressToReverseName_W(
|
|
reverseNameBuf,
|
|
HostAddr.Addr.ipAddr );
|
|
|
|
|
|
if ( fDoForward )
|
|
{
|
|
DYNREG_F1( "DynDnsAddEntry - Calling DynDnsAddForward" );
|
|
|
|
//
|
|
// we simply make a best case effort to do the forward add
|
|
// if it fails, we simply ignore
|
|
//
|
|
|
|
returnCode = DynDnsAddForward(
|
|
HostAddr,
|
|
pszName,
|
|
dwRegisteredTTL,
|
|
DnsServerList );
|
|
|
|
DYNREG_F2( "DynDnsAddEntry - DynDnsAddForward returned: 0%x",
|
|
returnCode );
|
|
|
|
*pdwFwdErrCode = returnCode;
|
|
}
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
|
|
record.pName = (PDNS_NAME) reverseNameBuf;
|
|
record.dwTtl = dwRegisteredTTL;
|
|
record.wType = DNS_TYPE_PTR;
|
|
record.Data.Ptr.pNameHost = (PDNS_NAME)pszName;
|
|
record.wDataLength = sizeof(record.Data.Ptr.pNameHost);
|
|
|
|
DYNREG_F1( "DynDnsAddEntry - Calling DnsAddRecords_W for PTR record:" );
|
|
DYNREG_F2( " Name: %S", record.pName );
|
|
DYNREG_F2( " Ptr: %S", record.Data.Ptr.pNameHost );
|
|
|
|
status = DnsModifyRecordsInSet_W(
|
|
& record, // add record
|
|
NULL, // no delete records
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no context handle
|
|
(PIP4_ARRAY) DnsServerList, // DNS servers
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsAddEntry - DnsAddRecords_W returned status: 0%x", status );
|
|
|
|
Exit:
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
DynDnsDeleteEntry(
|
|
REGISTER_HOST_ENTRY HostAddr,
|
|
LPWSTR pszName,
|
|
BOOL fDoForward,
|
|
PDWORD pdwFwdErrCode,
|
|
PIP4_ARRAY DnsServerList
|
|
)
|
|
{
|
|
//
|
|
// Brief Synopsis of functionality:
|
|
// On DoForward try deleting the forward mapping. Ignore failure
|
|
// Then try deleting the PTR record. If that fails
|
|
// because server is down, try again, if it fails because the
|
|
// operation was refused, then dont retry
|
|
//
|
|
|
|
DWORD status = 0;
|
|
DWORD returnCode = 0;
|
|
DNS_RECORD recordPtr;
|
|
DNS_RECORD recordA;
|
|
WCHAR reverseNameBuf[DNS_MAX_REVERSE_NAME_BUFFER_LENGTH] ;
|
|
INT i;
|
|
INT cch;
|
|
PDNS_RECORD precord = NULL;
|
|
|
|
DYNREG_F1( "Inside function DynDnsDeleteEntry" );
|
|
|
|
*pdwFwdErrCode = 0;
|
|
|
|
//
|
|
// build reverse lookup name for IP
|
|
//
|
|
|
|
Dns_Ip4AddressToReverseName_W(
|
|
reverseNameBuf,
|
|
HostAddr.Addr.ipAddr);
|
|
|
|
|
|
if ( fDoForward )
|
|
{
|
|
if ( pszName && *pszName )
|
|
{
|
|
//
|
|
// we delete a specific forward. not all forwards as we do
|
|
// when we do a query
|
|
//
|
|
|
|
RtlZeroMemory( &recordA, sizeof(DNS_RECORD) );
|
|
|
|
recordA.pName = (PDNS_NAME) pszName;
|
|
recordA.wType = DNS_TYPE_A;
|
|
recordA.wDataLength = sizeof(DNS_A_DATA);
|
|
recordA.Data.A.IpAddress = HostAddr.Addr.ipAddr;
|
|
|
|
DYNREG_F1( "DynDnsDeleteEntry - Calling ModifyRecords(Remove) for A record:" );
|
|
DYNREG_F2( " Name: %S", recordA.pName );
|
|
DYNREG_F2( " Address: 0x%x", recordA.Data.A.IpAddress );
|
|
|
|
//
|
|
// make the appropriate call
|
|
//
|
|
|
|
returnCode = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
&recordA, // delete record
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList, // DNS servers
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - ModifyRecords(Remove) returned status: 0%x", returnCode );
|
|
|
|
*pdwFwdErrCode = returnCode;
|
|
}
|
|
else
|
|
{
|
|
DYNREG_F1( "DynDnsDeleteEntry - Name not specified, going to query for PTR" );
|
|
|
|
//
|
|
//name not specified
|
|
//
|
|
status = DnsQuery_W(
|
|
reverseNameBuf,
|
|
DNS_TYPE_PTR,
|
|
DNS_QUERY_BYPASS_CACHE,
|
|
DnsServerList,
|
|
&precord,
|
|
NULL );
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - DnsQuery_W returned status: 0%x", status );
|
|
|
|
switch ( status )
|
|
{
|
|
case DNS_ERROR_RCODE_NO_ERROR:
|
|
|
|
DYNREG_F1( "DynDnsDeleteEntry - Calling DynDnsDeleteForwards" );
|
|
|
|
returnCode = DynDnsDeleteForwards(
|
|
precord,
|
|
HostAddr.Addr.ipAddr,
|
|
DnsServerList );
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - DynDnsDeleteForwards returned status: 0%x", returnCode );
|
|
|
|
*pdwFwdErrCode = returnCode;
|
|
|
|
#if 0
|
|
switch ( returnCode )
|
|
{
|
|
case DNS_ERROR_RCODE_NO_ERROR:
|
|
//
|
|
// we succeeded, break out
|
|
//
|
|
break;
|
|
|
|
case DNS_ERROR_RCODE_REFUSED:
|
|
//
|
|
// nothing can be done
|
|
//
|
|
break;
|
|
|
|
case DNS_ERROR_RCODE_SERVER_FAILURE:
|
|
case ERROR_TIMEOUT:
|
|
//
|
|
// need to retry this again
|
|
//
|
|
// goto Exit; // if uncommented will force retry
|
|
break;
|
|
|
|
case DNS_ERROR_RCODE_NOT_IMPLEMENTED:
|
|
default:
|
|
//
|
|
// query itself failed. Nothing can be done
|
|
//
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// caller takes care of each situation in turn
|
|
// PTR record cannot be queried for and hence
|
|
// cant be deleted
|
|
//
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// delete PTR Record
|
|
//
|
|
|
|
if ( pszName && *pszName )
|
|
{
|
|
//
|
|
// name is known
|
|
//
|
|
|
|
RtlZeroMemory( &recordPtr, sizeof(DNS_RECORD) );
|
|
|
|
recordPtr.pName = (PDNS_NAME) reverseNameBuf;
|
|
recordPtr.wType = DNS_TYPE_PTR;
|
|
recordPtr.wDataLength = sizeof(DNS_PTR_DATA);
|
|
recordPtr.Data.Ptr.pNameHost = (PDNS_NAME) pszName;
|
|
|
|
DYNREG_F1( "DynDnsDeleteEntry - Calling ModifyRecords(Remove) for PTR record:" );
|
|
DYNREG_F2( " Name: %S", recordPtr.pName );
|
|
DYNREG_F2( " PTR : 0%x", recordPtr.Data.Ptr.pNameHost );
|
|
|
|
status = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
&recordPtr, // delete record
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList, // DNS servers
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - ModifyRecords(Remove) returned status: 0%x", status );
|
|
}
|
|
else
|
|
{
|
|
DYNREG_F1( "DynDnsDeleteEntry - Calling ModifyRecords(Remove) for PTR record:" );
|
|
|
|
if ( fDoForward && precord )
|
|
{
|
|
//
|
|
// remove record from the earlier query that you made
|
|
//
|
|
|
|
status = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
precord, // delete record from query
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList,
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - ModifyRecords(Remove) returned status: 0%x", status );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// name is NOT known
|
|
//
|
|
// remove ALL records of PTR type
|
|
// - zero datalength indicates type delete
|
|
//
|
|
|
|
RtlZeroMemory( &recordPtr, sizeof(DNS_RECORD) );
|
|
|
|
recordPtr.pName = (PDNS_NAME) reverseNameBuf;
|
|
recordPtr.wType = DNS_TYPE_PTR;
|
|
recordPtr.Data.Ptr.pNameHost = (PDNS_NAME) NULL;
|
|
|
|
DYNREG_F1( "DynDnsDeleteEntry - Calling ModifyRecords(Remove) for ANY PTR records:" );
|
|
DYNREG_F2( " Name: %S", recordPtr.pName );
|
|
DYNREG_F2( " PTR : 0%x", recordPtr.Data.Ptr.pNameHost );
|
|
|
|
status = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
&recordPtr, // delete record
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) DnsServerList,
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsDeleteEntry - ModifyRecords(Remove) returned status: 0%x", status );
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if ( precord )
|
|
{
|
|
// DCR: need to fix this in Win2K
|
|
//
|
|
//QUEUE_FREE_HEAP( precord );
|
|
|
|
DnsRecordListFree(
|
|
precord,
|
|
DnsFreeRecordListDeep );
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
DynDnsRegisterEntries(
|
|
VOID
|
|
)
|
|
|
|
/*
|
|
DynDnsRegisterEntries()
|
|
|
|
This is the thread that dequeues the appropriate parameters
|
|
from the main queue and starts acting upon it. This is where
|
|
the bulk of the work gets done. Note that this function
|
|
gets called in an endless loop
|
|
|
|
Briefly, this is what the function does.
|
|
|
|
a) Find PTR corresponding to the Host Addr passed in.
|
|
b) If this is the same as the Address name passed in, then leave as is,
|
|
Otherwise delete and add new PTR record.
|
|
c) Follow forward and delete if possible from the forward's
|
|
dns server.
|
|
d) If DoForward then do what the client would've done in an NT5.0 case,
|
|
i.e. Try to write a new forward lookup.
|
|
|
|
|
|
Arguments:
|
|
|
|
No arguments
|
|
|
|
Return Value:
|
|
|
|
is 0 if Success. and (DWORD)-1 if failure.
|
|
|
|
*/
|
|
|
|
{
|
|
/*
|
|
cases to be considered here.
|
|
|
|
DYNDNS_ADD_ENTRY:
|
|
First query for the lookup
|
|
For each of the PTR records that come back, you need to check
|
|
against the one you are asked to register. If there is a match,
|
|
exit with success. If not add this entry for the PTR
|
|
|
|
if downlevel, then we need to add this entry to forward A record
|
|
as well.
|
|
|
|
DYNDNS_DELETE_ENTRY
|
|
Delete the entry that corresponds to the pair that you have specified
|
|
here. If it does not exist then do nothing about it.
|
|
|
|
If downlevel here, then go to the A record correspond to this and
|
|
delete the forward entry as well.
|
|
|
|
*/
|
|
|
|
DWORD status, dwWaitResult;
|
|
PQELEMENT pQElement = NULL;
|
|
PWSTR pszName = NULL;
|
|
BOOL fDoForward;
|
|
PQELEMENT pBackDependency = NULL;
|
|
REGISTER_HOST_ENTRY HostAddr ;
|
|
DWORD dwOperation;
|
|
DWORD dwCurrTime;
|
|
DWORD dwTTL;
|
|
DWORD dwWaitTime = INFINITE;
|
|
DWORD dwFwdAddErrCode = 0;
|
|
DHCP_CALLBACK_FN pfnDhcpCallBack = NULL;
|
|
PVOID pvData = NULL;
|
|
|
|
DYNREG_F1( "Inside function DynDnsRegisterEntries" );
|
|
|
|
//
|
|
// call back function
|
|
//
|
|
|
|
//
|
|
// check to see if there is any item in the timed out queue
|
|
// that has the timer gone out and so you can start processing
|
|
// that element right away
|
|
//
|
|
|
|
dwCurrTime = Dns_GetCurrentTimeInSeconds();
|
|
|
|
if ( g_pDhcpSrvTimedOutQueue &&
|
|
g_pDhcpSrvTimedOutQueue->pHead &&
|
|
(dwCurrTime > g_pDhcpSrvTimedOutQueue->pHead->dwRetryTime) )
|
|
{
|
|
//
|
|
// dequeue an element from the timed out queue and process it
|
|
//
|
|
DYNREG_F1( "DynDnsRegisterEntries - Dequeue element from timed out list" );
|
|
|
|
pQElement = Dequeue( g_pDhcpSrvTimedOutQueue );
|
|
if ( !pQElement )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
pfnDhcpCallBack = pQElement->pfnDhcpCallBack;
|
|
pvData = pQElement->pvData;
|
|
|
|
//
|
|
// now determine if we have processed this element way too many
|
|
// times
|
|
//
|
|
|
|
if ( pQElement->dwRetryCount >= MAX_RETRIES )
|
|
{
|
|
DYNREG_F1( "DynDnsRegisterEntries - Element has failed too many times, calling DHCP callback function" );
|
|
if (pQElement->fDoForwardOnly)
|
|
{
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FWD_FAILED, pvData);
|
|
}
|
|
else
|
|
{
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FAILURE, pvData);
|
|
}
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
status = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwRetryTime = GetEarliestRetryTime (g_pDhcpSrvTimedOutQueue);
|
|
|
|
DYNREG_F1( "DynDnsRegisterEntries - No element in timed out queue." );
|
|
DYNREG_F1( " Going to wait for next element." );
|
|
|
|
dwWaitTime = dwRetryTime != (DWORD)-1 ?
|
|
(dwRetryTime > dwCurrTime? (dwRetryTime - dwCurrTime) *1000: 0)
|
|
: INFINITE;
|
|
|
|
dwWaitResult = WaitForMultipleObjects(
|
|
2,
|
|
g_DhcpSrvWaitHandles,
|
|
FALSE,
|
|
dwWaitTime );
|
|
|
|
switch ( dwWaitResult )
|
|
{
|
|
|
|
case WAIT_OBJECT_0:
|
|
//
|
|
// quit event, return and let caller take care
|
|
//
|
|
return(0);
|
|
|
|
case WAIT_OBJECT_0 + 1 :
|
|
|
|
//
|
|
// dequeue an element from the main queue and process
|
|
//
|
|
|
|
pQElement = Dequeue(g_pDhcpSrvQueue);
|
|
if ( !pQElement )
|
|
{
|
|
status = NO_ERROR; // Note: This actually does happen
|
|
// because when Ram adds a new
|
|
// entry, he may put it in the
|
|
// timed out queue instead of the
|
|
// g_pDhcpSrvQueue when there is a related
|
|
// item pending a retry time. Assert
|
|
// removed and error code changed to
|
|
// to success by GlennC - 3/6/98.
|
|
goto Exit;
|
|
}
|
|
|
|
EnterCriticalSection(&g_QueueCS);
|
|
g_DhcpSrvMainQueueCount--;
|
|
LeaveCriticalSection(&g_QueueCS);
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
//
|
|
// Let us exit the function this time around. We will catch the
|
|
// timed out element the next time around
|
|
//
|
|
return ERROR_SUCCESS;
|
|
|
|
default:
|
|
|
|
ASSERT( FALSE );
|
|
return dwWaitResult;
|
|
}
|
|
}
|
|
|
|
//
|
|
// safe to make a call since you are not dependent on anyone
|
|
//
|
|
|
|
DYNREG_F1( "DynDnsRegisterEntries - Got an element to process!" );
|
|
|
|
pszName = pQElement->pszName;
|
|
fDoForward = pQElement->fDoForward;
|
|
HostAddr = pQElement->HostAddr;
|
|
dwOperation = pQElement->dwOperation;
|
|
dwTTL = pQElement->dwTTL;
|
|
pfnDhcpCallBack = pQElement->pfnDhcpCallBack;
|
|
pvData = pQElement->pvData;
|
|
|
|
if ( dwOperation == DYNDNS_ADD_ENTRY )
|
|
{
|
|
//
|
|
// make the appropriate API call to add an entry
|
|
//
|
|
|
|
if (pQElement->fDoForwardOnly )
|
|
{
|
|
DYNREG_F1( "DynDnsRegisterEntries - Calling DynDnsAddForward" );
|
|
status = DynDnsAddForward ( HostAddr,
|
|
pszName,
|
|
dwTTL,
|
|
pQElement->DnsServerList );
|
|
DYNREG_F2( "DynDnsRegisterEntries - DynDnsAddForward returned status: 0%x", status );
|
|
}
|
|
else
|
|
{
|
|
DYNREG_F1( "DynDnsRegisterEntries - Calling DynDnsAddEntry" );
|
|
status = DynDnsAddEntry( HostAddr,
|
|
pszName,
|
|
dwTTL,
|
|
fDoForward,
|
|
&dwFwdAddErrCode,
|
|
pQElement->DnsServerList );
|
|
DYNREG_F2( "DynDnsRegisterEntries - DynDnsAddEntry returned status: 0%x", status );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// make the appropriate call to delete here
|
|
//
|
|
|
|
if ( pQElement->fDoForwardOnly )
|
|
{
|
|
DNS_RECORD record;
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
|
|
record.pName = (PTCHAR) pszName;
|
|
record.wType = DNS_TYPE_A;
|
|
record.wDataLength = sizeof(DNS_A_DATA);
|
|
record.Data.A.IpAddress = HostAddr.Addr.ipAddr ;
|
|
|
|
status = DNS_ERROR_RCODE_NO_ERROR;
|
|
|
|
DYNREG_F1( "DynDnsRegisterEntries - Calling ModifyRecords(Remove)" );
|
|
|
|
dwFwdAddErrCode = DnsModifyRecordsInSet_W(
|
|
NULL, // no add records
|
|
& record, // delete record
|
|
DNS_UPDATE_CACHE_SECURITY_CONTEXT,
|
|
NULL, // no security context
|
|
(PIP4_ARRAY) pQElement->DnsServerList,
|
|
NULL // reserved
|
|
);
|
|
|
|
DYNREG_F2( "DynDnsRegisterEntries - ModifyRecords(Remove) returned status: 0%x", dwFwdAddErrCode );
|
|
}
|
|
else
|
|
{
|
|
DYNREG_F1( "DynDnsRegisterEntries - Calling DynDnsDeleteEntry" );
|
|
status = DynDnsDeleteEntry( HostAddr,
|
|
pszName,
|
|
fDoForward,
|
|
&dwFwdAddErrCode,
|
|
pQElement->DnsServerList );
|
|
DYNREG_F2( "DynDnsRegisterEntries - DynDnsDeleteEntry returned status: 0%x", status );
|
|
}
|
|
}
|
|
|
|
if (status == DNS_ERROR_RCODE_NO_ERROR &&
|
|
dwFwdAddErrCode == DNS_ERROR_RCODE_NO_ERROR )
|
|
{
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack) (DNSDHCP_SUCCESS, pvData);
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
|
|
}
|
|
else if ( status == DNS_ERROR_RCODE_NO_ERROR &&
|
|
dwFwdAddErrCode != DNS_ERROR_RCODE_NO_ERROR )
|
|
{
|
|
//
|
|
// adding reverse succeeded but adding forward failed
|
|
//
|
|
|
|
dwCurrTime = Dns_GetCurrentTimeInSeconds();
|
|
|
|
pQElement->fDoForwardOnly = TRUE;
|
|
|
|
if ( pQElement->dwRetryCount >= MAX_RETRIES )
|
|
{
|
|
//
|
|
// clean up pQElement and stop retrying
|
|
//
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FWD_FAILED, pvData);
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
status = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// we may need to retry this guy later
|
|
//
|
|
|
|
switch ( dwFwdAddErrCode )
|
|
{
|
|
case DNS_ERROR_RCODE_SERVER_FAILURE:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_SERVER_FAILURE );
|
|
break;
|
|
|
|
case ERROR_TIMEOUT:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_TIMEOUT );
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// different kind of error on attempting to add forward.
|
|
// like connection refused etc.
|
|
// call the callback to indicate that you failed on
|
|
// forward only
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FWD_FAILED, pvData);
|
|
}
|
|
}
|
|
else if ( status != DNS_ERROR_RCODE_NO_ERROR &&
|
|
dwFwdAddErrCode == DNS_ERROR_RCODE_NO_ERROR )
|
|
{
|
|
//
|
|
// adding forward succeeded but adding reverse failed
|
|
//
|
|
|
|
dwCurrTime = Dns_GetCurrentTimeInSeconds();
|
|
|
|
pQElement->fDoForwardOnly = FALSE;
|
|
pQElement->fDoForward = FALSE;
|
|
|
|
if ( pQElement->dwRetryCount >= MAX_RETRIES )
|
|
{
|
|
//
|
|
// clean up pQElement and stop retrying
|
|
//
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FAILURE, pvData);
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
status = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// we may need to retry this guy later
|
|
//
|
|
|
|
switch ( status )
|
|
{
|
|
case DNS_ERROR_RCODE_SERVER_FAILURE:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_SERVER_FAILURE );
|
|
break;
|
|
|
|
case ERROR_TIMEOUT:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_TIMEOUT );
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// different kind of error on attempting to add forward.
|
|
// like connection refused etc.
|
|
// call the callback to indicate that you at least succeeded
|
|
// with the forward registration
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FAILURE, pvData);
|
|
}
|
|
}
|
|
else if (status == DNS_ERROR_RCODE_SERVER_FAILURE ||
|
|
status == DNS_ERROR_TRY_AGAIN_LATER ||
|
|
status == ERROR_TIMEOUT )
|
|
{
|
|
//
|
|
// we need to retry this guy later
|
|
//
|
|
dwCurrTime = Dns_GetCurrentTimeInSeconds();
|
|
|
|
switch (status)
|
|
{
|
|
case DNS_ERROR_RCODE_SERVER_FAILURE:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_SERVER_FAILURE );
|
|
break;
|
|
|
|
case ERROR_TIMEOUT:
|
|
|
|
status = AddToTimedOutQueue(
|
|
pQElement,
|
|
g_pDhcpSrvTimedOutQueue,
|
|
dwCurrTime + RETRY_TIME_TIMEOUT );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// a different kind of error, really nothing can be done
|
|
// free memory and get the hell out
|
|
// call the callback to say that registration failed
|
|
//
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
|
|
if ( pfnDhcpCallBack )
|
|
(*pfnDhcpCallBack)(DNSDHCP_FAILURE, pvData);
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
//
|
|
// Main registration thread
|
|
//
|
|
|
|
VOID
|
|
DynDnsConsumerThread(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD dwRetval;
|
|
|
|
DYNREG_F1( "Inside function DynDnsConsumerThread" );
|
|
|
|
while ( ! g_fDhcpSrvStop )
|
|
{
|
|
dwRetval = DynDnsRegisterEntries();
|
|
if ( !dwRetval )
|
|
{
|
|
//
|
|
// Ram note: get Munil/Ramesh to implement call back function
|
|
//
|
|
}
|
|
}
|
|
|
|
// exiting thread
|
|
//ExitThread(0); // This sets the handle in the waitforsingleobject for
|
|
}
|
|
|
|
|
|
//
|
|
// Init\Cleanup routines
|
|
//
|
|
|
|
|
|
BOOL
|
|
LockDhcpSrvState(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Lock the state to allow state change.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if locked the state for state change.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
BOOL retval = TRUE;
|
|
|
|
//
|
|
// protect init of DHCP server lock with general CS
|
|
//
|
|
|
|
if ( !g_fDhcpSrvCsCreated )
|
|
{
|
|
LOCK_GENERAL();
|
|
if ( !g_fDhcpSrvCsCreated )
|
|
{
|
|
retval = RtlInitializeCriticalSection( &g_DhcpSrvCS ) == NO_ERROR;
|
|
g_fDhcpSrvCsCreated = retval;
|
|
}
|
|
UNLOCK_GENERAL();
|
|
if ( !retval )
|
|
{
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
//
|
|
// grab DHCP server lock
|
|
//
|
|
|
|
EnterCriticalSection( &g_DhcpSrvCS );
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
VOID
|
|
DhcpSrv_Cleanup(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup CS created for DHCP server registration.
|
|
|
|
This is ONLY called from process detach. Should be safe.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( g_fDhcpSrvCsCreated )
|
|
{
|
|
DeleteCriticalSection( &g_DhcpSrvCS );
|
|
}
|
|
g_fDhcpSrvCsCreated = FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
DhcpSrv_PrivateCleanup(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Common cleanup between failed init and terminate.
|
|
|
|
Function exists just to kill off common code.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// common cleanup
|
|
// - queues
|
|
// - queue CS itself
|
|
// - semaphore
|
|
// - event
|
|
// - security credential info
|
|
//
|
|
|
|
if ( g_fDhcpSrvQueueCsCreated )
|
|
{
|
|
if ( g_pDhcpSrvQueue )
|
|
{
|
|
FreeQueue( g_pDhcpSrvQueue );
|
|
g_pDhcpSrvQueue = NULL;
|
|
}
|
|
|
|
if ( g_pDhcpSrvTimedOutQueue )
|
|
{
|
|
FreeQueue( g_pDhcpSrvTimedOutQueue );
|
|
g_pDhcpSrvTimedOutQueue = NULL;
|
|
}
|
|
g_DhcpSrvMainQueueCount = 0;
|
|
|
|
DeleteCriticalSection( &g_QueueCS );
|
|
g_fDhcpSrvQueueCsCreated = FALSE;
|
|
}
|
|
|
|
if ( g_DhcpSrvSem )
|
|
{
|
|
CloseHandle( g_DhcpSrvSem );
|
|
g_DhcpSrvSem = NULL;
|
|
}
|
|
|
|
if ( g_DhcpSrvQuitEvent )
|
|
{
|
|
CloseHandle( g_DhcpSrvQuitEvent );
|
|
g_DhcpSrvQuitEvent = NULL;
|
|
}
|
|
|
|
if ( g_pIdentityCreds )
|
|
{
|
|
Dns_FreeAuthIdentityCredentials( g_pIdentityCreds );
|
|
g_pIdentityCreds = NULL;
|
|
}
|
|
|
|
if ( g_UpdateCredContext )
|
|
{
|
|
DnsReleaseContextHandle( g_UpdateCredContext );
|
|
g_UpdateCredContext = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsDhcpSrvRegisterInit(
|
|
IN PDNS_CREDENTIALS pCredentials,
|
|
IN DWORD MaxQueueSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize DHCP server DNS registration.
|
|
|
|
Arguments:
|
|
|
|
pCredentials -- credentials to do registrations under (if any)
|
|
|
|
MaxQueueSize -- max size of registration queue
|
|
|
|
Return Value:
|
|
|
|
DNS or Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
INT i;
|
|
DWORD threadId;
|
|
DNS_STATUS status = NO_ERROR;
|
|
BOOL failed = TRUE;
|
|
|
|
//
|
|
// protection for init\shutdown
|
|
// - lock out possibility of race condition
|
|
// - skip init if already running
|
|
// - set state to indicate initializing (informational only)
|
|
//
|
|
|
|
if ( !DHCP_SRV_STATE_LOCK() )
|
|
{
|
|
ASSERT( FALSE );
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
if ( g_DhcpSrvState == DNS_DHCP_SRV_STATE_RUNNING )
|
|
{
|
|
status = NO_ERROR;
|
|
goto Unlock;
|
|
}
|
|
|
|
ASSERT( g_DhcpSrvState == DNS_DHCP_SRV_STATE_UNINIT ||
|
|
g_DhcpSrvState == DNS_DHCP_SRV_STATE_INIT_FAILED ||
|
|
g_DhcpSrvState == DNS_DHCP_SRV_STATE_SHUTDOWN );
|
|
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_INITIALIZING;
|
|
|
|
|
|
//
|
|
// init globals
|
|
// - also init debug logging
|
|
//
|
|
|
|
DYNREG_INIT();
|
|
|
|
DNS_ASSERT(!g_DhcpSrvQuitEvent && !g_DhcpSrvSem);
|
|
|
|
g_fDhcpSrvStop = FALSE;
|
|
|
|
g_DhcpSrvQuitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
if ( !g_DhcpSrvQuitEvent )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
g_DhcpSrvSem = CreateSemaphore( NULL, 0, MAX_QLEN, NULL );
|
|
if ( ! g_DhcpSrvSem )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
g_DhcpSrvWaitHandles[0] = g_DhcpSrvQuitEvent;
|
|
g_DhcpSrvWaitHandles[1] = g_DhcpSrvSem;
|
|
|
|
Dns_InitializeSecondsTimer();
|
|
|
|
//
|
|
// init queuing stuff
|
|
//
|
|
|
|
status = RtlInitializeCriticalSection( &g_QueueCS );
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
g_fDhcpSrvQueueCsCreated = TRUE;
|
|
|
|
status = InitializeQueues( &g_pDhcpSrvQueue, &g_pDhcpSrvTimedOutQueue );
|
|
if ( status != NO_ERROR )
|
|
{
|
|
g_pDhcpSrvQueue = NULL;
|
|
g_pDhcpSrvTimedOutQueue = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
g_DhcpSrvMainQueueCount = 0;
|
|
|
|
//
|
|
// have creds?
|
|
// - create global credentials
|
|
// - acquire a valid SSPI handle using these creds
|
|
//
|
|
// DCR: global cred handle not MT safe
|
|
// here we are in the DHCP server process and don't have
|
|
// any reason to use another update context; but if
|
|
// shared with some other service this breaks
|
|
//
|
|
// fix should be to have separate
|
|
// - creds
|
|
// - cred handle
|
|
// that is kept here (not cached) and pushed down
|
|
// on each update call
|
|
//
|
|
|
|
if ( pCredentials )
|
|
{
|
|
DNS_ASSERT( g_pIdentityCreds == NULL );
|
|
|
|
g_pIdentityCreds = Dns_AllocateCredentials(
|
|
pCredentials->pUserName,
|
|
pCredentials->pDomain,
|
|
pCredentials->pPassword );
|
|
if ( !g_pIdentityCreds )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// DCR: this won't work if creds will expire
|
|
// but it seems like they autorefresh
|
|
|
|
status = Dns_StartSecurity(
|
|
FALSE // not process attach
|
|
);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
status = ERROR_CANNOT_IMPERSONATE;
|
|
goto Exit;
|
|
}
|
|
|
|
status = Dns_RefreshSSpiCredentialsHandle(
|
|
FALSE, // client
|
|
(PCHAR) g_pIdentityCreds // creds
|
|
);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
status = ERROR_CANNOT_IMPERSONATE;
|
|
goto Exit;
|
|
}
|
|
#if 0
|
|
DNS_ASSERT( g_UpdateCredContext == NULL );
|
|
|
|
status = DnsAcquireContextHandle_W(
|
|
0, // flags
|
|
g_pIdentityCreds, // creds
|
|
& g_UpdateCredContext // set handle
|
|
);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// fire up registration thread
|
|
// - pass creds as start param
|
|
// - if thread start fails, free creds
|
|
//
|
|
|
|
g_hDhcpSrvRegThread = CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)DynDnsConsumerThread,
|
|
NULL,
|
|
0,
|
|
&threadId );
|
|
|
|
if ( g_hDhcpSrvRegThread == NULL )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// set queue size -- if given
|
|
// - but put cap to avoid runaway memory
|
|
//
|
|
|
|
if ( MaxQueueSize != 0 )
|
|
{
|
|
if ( MaxQueueSize > DHCPSRV_MAX_QUEUE_SIZE )
|
|
{
|
|
MaxQueueSize = DHCPSRV_MAX_QUEUE_SIZE;
|
|
}
|
|
g_DhcpSrvMaxQueueSize = MaxQueueSize;
|
|
}
|
|
|
|
failed = FALSE;
|
|
|
|
Exit:
|
|
|
|
//
|
|
// if failed, clean up globals
|
|
//
|
|
|
|
if ( failed )
|
|
{
|
|
// fix up return code
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
status = GetLastError();
|
|
if ( status == NO_ERROR )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
// global cleanup
|
|
// - shared between failure case here and term function
|
|
|
|
DhcpSrv_PrivateCleanup();
|
|
|
|
// indicate unitialized
|
|
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_INIT_FAILED;
|
|
}
|
|
else
|
|
{
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_RUNNING;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
Unlock:
|
|
|
|
// unlock -- allow queuing or reinit
|
|
|
|
DHCP_SRV_STATE_UNLOCK();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsDhcpSrvRegisterTerm(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialization routine each process should call exactly on exit after
|
|
using DnsDhcpSrvRegisterHostAddrs. This will signal to us that if our
|
|
thread is still trying to talk to a server, we'll stop trying.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
DNS or Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
DWORD waitResult;
|
|
|
|
DYNREG_F1( "Inside function DnsDhcpSrvRegisterTerm" );
|
|
|
|
|
|
//
|
|
// lock to eliminate race condition
|
|
// - verify that we're running
|
|
// - indicate in process of shutdown (purely informational)
|
|
//
|
|
|
|
if ( !DHCP_SRV_STATE_LOCK() )
|
|
{
|
|
ASSERT( FALSE );
|
|
return DNS_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
if ( g_DhcpSrvState != DNS_DHCP_SRV_STATE_RUNNING )
|
|
{
|
|
ASSERT( g_DhcpSrvState == DNS_DHCP_SRV_STATE_UNINIT ||
|
|
g_DhcpSrvState == DNS_DHCP_SRV_STATE_INIT_FAILED ||
|
|
g_DhcpSrvState == DNS_DHCP_SRV_STATE_SHUTDOWN );
|
|
goto Unlock;
|
|
}
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_SHUTTING_DOWN;
|
|
|
|
|
|
//
|
|
// signal consummer thread for shutdown
|
|
//
|
|
|
|
g_fDhcpSrvStop = TRUE;
|
|
SetEvent( g_DhcpSrvQuitEvent );
|
|
|
|
waitResult = WaitForSingleObject( g_hDhcpSrvRegThread, INFINITE );
|
|
|
|
switch( waitResult )
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
//
|
|
// client thread terminated
|
|
//
|
|
CloseHandle(g_hDhcpSrvRegThread);
|
|
g_hDhcpSrvRegThread = NULL;
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
if ( g_hDhcpSrvRegThread )
|
|
{
|
|
//
|
|
// Why hasn't this thread stopped?
|
|
//
|
|
DYNREG_F1( "DNSAPI: DHCP Server DNS registration thread won't stop!" );
|
|
DNS_ASSERT( FALSE );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DNS_ASSERT( FALSE );
|
|
}
|
|
|
|
//
|
|
// cleanup globals
|
|
// - queues
|
|
// - event
|
|
// - semaphore
|
|
// - update security cred info
|
|
//
|
|
|
|
DhcpSrv_PrivateCleanup();
|
|
|
|
//
|
|
// Blow away any cached security context handles
|
|
//
|
|
// DCR: security context dump is not multi-service safe
|
|
// should have this cleanup just the context's associated
|
|
// with DHCP server service;
|
|
// either need some key or use cred handle
|
|
//
|
|
|
|
Dns_TimeoutSecurityContextList( TRUE );
|
|
|
|
Unlock:
|
|
|
|
// unlock -- returning to uninitialized state
|
|
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_SHUTDOWN;
|
|
DHCP_SRV_STATE_UNLOCK();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
WINAPI
|
|
DnsDhcpSrvRegisterHostName(
|
|
IN REGISTER_HOST_ENTRY HostAddr,
|
|
IN PWSTR pwsName,
|
|
IN DWORD dwTTL,
|
|
IN DWORD dwFlags, // An entry you want to blow away
|
|
IN DHCP_CALLBACK_FN pfnDhcpCallBack,
|
|
IN PVOID pvData,
|
|
IN PIP4_ADDRESS pipDnsServerList,
|
|
IN DWORD dwDnsServerCount
|
|
)
|
|
/*++
|
|
|
|
DnsDhcpSrvRegisterHostName()
|
|
|
|
The main DHCP registration thread calls this function each time a
|
|
registration needs to be done.
|
|
|
|
Brief Synopsis of the working of this function
|
|
|
|
This function creates a queue object of the type given in queue.c
|
|
and enqueues the appropriate object after grabbing hold of the
|
|
critical section.
|
|
|
|
Arguments:
|
|
|
|
HostAddr --- The Host Addr you wish to register
|
|
pszName --- The Host Name to be associated with the address
|
|
dwTTL --- Time to Live.
|
|
dwOperation -- The following flags are valid
|
|
|
|
DYNDNS_DELETE_ENTRY -- Delete the entry being referred to.
|
|
DYNDNS_ADD_ENTRY -- Register the new entry.
|
|
DYNDNS_REG_FORWARD -- Register the forward as well
|
|
|
|
Return Value:
|
|
|
|
is 0 if Success. and (DWORD)-1 if failure.
|
|
|
|
--*/
|
|
{
|
|
PQELEMENT pQElement = NULL;
|
|
DWORD status = ERROR_SUCCESS;
|
|
BOOL fSem = FALSE;
|
|
BOOL fRegForward = dwFlags & DYNDNS_REG_FORWARD ? TRUE: FALSE ;
|
|
|
|
DYNREG_F1( "Inside function DnsDhcpSrvRegisterHostName_W" );
|
|
|
|
// RAMNOTE: parameter checking on queuing
|
|
|
|
if ( g_fDhcpSrvStop ||
|
|
! g_pDhcpSrvTimedOutQueue ||
|
|
! g_pDhcpSrvQueue )
|
|
{
|
|
DYNREG_F1( "g_fDhcpSrvStop || ! g_pDhcpSrvTimedOutQueue || ! g_pDhcpSrvQueue" );
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Returning ERROR_INVALID_PARAMETER" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( !(dwFlags & DYNDNS_DELETE_ENTRY) && ( !pwsName || !*pwsName ) )
|
|
{
|
|
DYNREG_F1( "!(dwFlags & DYNDNS_DELETE_ENTRY) && ( !pwsName || !*pwsName )" );
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Returning ERROR_INVALID_PARAMETER" );
|
|
//
|
|
// Null parameter for name can be specified only when operation
|
|
// is to do a delete
|
|
//
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( ! (dwFlags & DYNDNS_ADD_ENTRY || dwFlags & DYNDNS_DELETE_ENTRY ) )
|
|
{
|
|
DYNREG_F1( "! (dwFlags & DYNDNS_ADD_ENTRY || dwFlags & DYNDNS_DELETE_ENTRY )" );
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Returning ERROR_INVALID_PARAMETER" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( (dwFlags & DYNDNS_DELETE_ENTRY) && (dwFlags & DYNDNS_ADD_ENTRY) )
|
|
{
|
|
DYNREG_F1( "(dwFlags & DYNDNS_DELETE_ENTRY) && (dwFlags & DYNDNS_ADD_ENTRY)" );
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Returning ERROR_INVALID_PARAMETER" );
|
|
//
|
|
// you cant ask me to both add and delete an entry
|
|
//
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( ! (HostAddr.dwOptions & REGISTER_HOST_PTR) )
|
|
{
|
|
DYNREG_F1( "! (HostAddr.dwOptions & REGISTER_HOST_PTR)" );
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Returning ERROR_INVALID_PARAMETER" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( g_DhcpSrvMainQueueCount > g_DhcpSrvMaxQueueSize )
|
|
{
|
|
return DNS_ERROR_TRY_AGAIN_LATER;
|
|
}
|
|
|
|
//
|
|
// create a queue element
|
|
//
|
|
|
|
pQElement = (PQELEMENT) QUEUE_ALLOC_HEAP_ZERO(sizeof(QELEMENT) );
|
|
if ( !pQElement )
|
|
{
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Failed to create element!" );
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
& pQElement->HostAddr,
|
|
&HostAddr,
|
|
sizeof(REGISTER_HOST_ENTRY));
|
|
|
|
pQElement->pszName = NULL;
|
|
|
|
if ( pwsName )
|
|
{
|
|
pQElement->pszName = (LPWSTR) QUEUE_ALLOC_HEAP_ZERO(wcslen(pwsName)*2+ 2 );
|
|
if ( !pQElement->pszName )
|
|
{
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Failed to allocate name buffer!" );
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
wcscpy(pQElement->pszName, pwsName);
|
|
}
|
|
|
|
if ( dwDnsServerCount )
|
|
{
|
|
pQElement->DnsServerList = Dns_BuildIpArray(
|
|
dwDnsServerCount,
|
|
pipDnsServerList );
|
|
if ( !pQElement->DnsServerList )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pQElement->dwTTL = dwTTL;
|
|
pQElement->fDoForward = fRegForward;
|
|
|
|
//
|
|
// callback function
|
|
//
|
|
|
|
pQElement->pfnDhcpCallBack = pfnDhcpCallBack;
|
|
pQElement->pvData = pvData; // parameter to callback function
|
|
|
|
if (dwFlags & DYNDNS_ADD_ENTRY)
|
|
pQElement->dwOperation = DYNDNS_ADD_ENTRY;
|
|
else
|
|
pQElement->dwOperation = DYNDNS_DELETE_ENTRY;
|
|
|
|
//
|
|
// Set all the other fields to NULLs
|
|
//
|
|
|
|
pQElement->dwRetryTime = 0;
|
|
pQElement->pFLink = NULL;
|
|
pQElement->pBLink = NULL;
|
|
pQElement->fDoForwardOnly = FALSE;
|
|
|
|
//
|
|
// lock out terminate while queuing
|
|
// - and verify that properly initialized
|
|
//
|
|
|
|
if ( !DHCP_SRV_STATE_LOCK() )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
if ( g_DhcpSrvState != DNS_DHCP_SRV_STATE_RUNNING )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
ASSERT( FALSE );
|
|
DHCP_SRV_STATE_UNLOCK();
|
|
goto Exit;
|
|
}
|
|
|
|
// indicate queuing state
|
|
// - note this is entirely informational
|
|
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_QUEUING;
|
|
|
|
|
|
//
|
|
// put this element in the queue
|
|
//
|
|
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Put queue element in list" );
|
|
|
|
status = Enqueue( pQElement, g_pDhcpSrvQueue, g_pDhcpSrvTimedOutQueue);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
DYNREG_F1( "DnsDhcpSrvRegisterHostName_W - Failed to queue element in list!" );
|
|
}
|
|
|
|
//
|
|
// signal the semaphore the consumer may be waiting on
|
|
//
|
|
|
|
else
|
|
{
|
|
fSem = ReleaseSemaphore(
|
|
g_DhcpSrvSem,
|
|
1,
|
|
&g_DhcpSrvRegQueueCount );
|
|
if ( !fSem )
|
|
{
|
|
DNS_ASSERT( fSem ); // assert and say that something weird happened
|
|
}
|
|
}
|
|
|
|
// unlock -- returning to running state
|
|
|
|
g_DhcpSrvState = DNS_DHCP_SRV_STATE_RUNNING;
|
|
DHCP_SRV_STATE_UNLOCK();
|
|
|
|
Exit:
|
|
|
|
if ( status )
|
|
{
|
|
//
|
|
// something failed. Free all alloc'd memory
|
|
//
|
|
|
|
DhcpSrv_FreeQueueElement( pQElement );
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
//
|
|
// End dynreg.c
|
|
//
|
|
|