507 lines
10 KiB
C
507 lines
10 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
notesrv.c
|
||
|
||
Abstract:
|
||
|
||
DNS Resolver Service
|
||
|
||
Notifications to other services.
|
||
|
||
Author:
|
||
|
||
Glenn Curtis (glennc) Feb 1998
|
||
|
||
Revision History:
|
||
|
||
Jim Gilroy (jamesg) March 2000 cleanup
|
||
Jim Gilroy (jamesg) Nov 2000 created this module
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
#include <svcs.h>
|
||
|
||
|
||
//
|
||
// DCR: eliminate this module
|
||
// entirely unclear why we should be notifying remote
|
||
// services of PnP -- weird idea
|
||
// only actual DNS events should be in our charter
|
||
//
|
||
|
||
//
|
||
// Notification list entry
|
||
//
|
||
|
||
typedef struct _SERVICE_NOTIFICATION_
|
||
{
|
||
struct _SERVICE_NOTIFICATION_ * pNext;
|
||
PWSTR pszServiceName;
|
||
DWORD dwControl;
|
||
}
|
||
SERVICE_NOTIFICATION, * PSERVICE_NOTIFICATION;
|
||
|
||
|
||
//
|
||
// Service notification list
|
||
// Services we should notify if DNS config changes.
|
||
//
|
||
|
||
PSERVICE_NOTIFICATION g_ServiceNotificationList = NULL;
|
||
|
||
//
|
||
// Locking on service control list
|
||
// - overload net failure
|
||
//
|
||
|
||
#define LOCK_SERVICE_LIST() LOCK_NET_FAILURE()
|
||
#define UNLOCK_SERVICE_LIST() UNLOCK_NET_FAILURE()
|
||
|
||
|
||
|
||
|
||
//
|
||
// Routines
|
||
//
|
||
|
||
DWORD
|
||
SendServiceControlCode(
|
||
IN LPWSTR pszServiceName,
|
||
IN DWORD dwControl
|
||
)
|
||
{
|
||
DWORD status = NO_ERROR;
|
||
SC_HANDLE scManagerHandle = NULL;
|
||
SC_HANDLE scServiceHandle = NULL;
|
||
SERVICE_STATUS serviceStatus;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"SendServiceControlCode( %S, %d )\n",
|
||
pszServiceName,
|
||
dwControl ));
|
||
|
||
//
|
||
// DCR_FIX: identical to routine in dnsapi.dll
|
||
// so either expose OR dnslib it
|
||
//
|
||
//
|
||
// DCR_FIX0: service notification probably not working
|
||
// i don't believe this is working because no longer
|
||
// local system, probably can't open with this access
|
||
//
|
||
|
||
scManagerHandle = OpenSCManagerW( NULL,
|
||
NULL,
|
||
SC_MANAGER_ALL_ACCESS );
|
||
|
||
if ( !scManagerHandle )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"OpenSCManagerW( %S ) -- FAILED! %d\n",
|
||
pszServiceName,
|
||
GetLastError() ));
|
||
return GetLastError();
|
||
}
|
||
|
||
scServiceHandle = OpenServiceW( scManagerHandle,
|
||
pszServiceName,
|
||
SERVICE_ALL_ACCESS );
|
||
if ( !scServiceHandle )
|
||
{
|
||
CloseServiceHandle( scManagerHandle );
|
||
return GetLastError();
|
||
}
|
||
|
||
if ( !ControlService( scServiceHandle,
|
||
dwControl,
|
||
&serviceStatus ) )
|
||
{
|
||
status = GetLastError();
|
||
}
|
||
|
||
CloseServiceHandle( scServiceHandle );
|
||
CloseServiceHandle( scManagerHandle );
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ServiceNotificationCallback(
|
||
IN PVOID pContext
|
||
)
|
||
{
|
||
PSERVICE_NOTIFICATION pserviceNot;
|
||
|
||
UNREFERENCED_PARAMETER( pContext );
|
||
|
||
DNSLOG_F1( " Inside callback function ServiceNotificationCallback" );
|
||
|
||
//
|
||
// Send PnP to any registered services
|
||
//
|
||
|
||
LOCK_SERVICE_LIST();
|
||
|
||
for ( pserviceNot = g_ServiceNotificationList;
|
||
pserviceNot != NULL;
|
||
pserviceNot = pserviceNot->pNext
|
||
)
|
||
{
|
||
DNSLOG_F3( " Sending PnP notification to %S with control %d",
|
||
pserviceNot->pszServiceName,
|
||
pserviceNot->dwControl );
|
||
|
||
SendServiceControlCode(
|
||
pserviceNot->pszServiceName,
|
||
pserviceNot->dwControl );
|
||
}
|
||
UNLOCK_SERVICE_LIST();
|
||
|
||
//
|
||
// always indicate PnP to DNS server
|
||
//
|
||
|
||
DNSLOG_F2(
|
||
" Sending PnP notification to DNS server with control %d",
|
||
SERVICE_CONTROL_PARAMCHANGE );
|
||
|
||
SendServiceControlCode(
|
||
L"dns",
|
||
SERVICE_CONTROL_PARAMCHANGE );
|
||
|
||
DNSLOG_F1( " Leaving callback function ServiceNotificationCallback" );
|
||
DNSLOG_F1( "" );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
SendServiceNotifications(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Send service notifications.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( ANY, ( "SendServiceNotifications()\n" ));
|
||
|
||
DNSLOG_F1( "Notify any other services of the PnP event" );
|
||
|
||
//
|
||
// DCR: cheesy hack to notify DNS server of paramchange
|
||
//
|
||
|
||
if ( g_IsDnsServer )
|
||
{
|
||
SendServiceControlCode(
|
||
L"Dns",
|
||
SERVICE_CONTROL_PARAMCHANGE );
|
||
}
|
||
|
||
//
|
||
// notify other services by queuing callback
|
||
// - callback function then notifies services
|
||
//
|
||
|
||
RtlQueueWorkItem(
|
||
ServiceNotificationCallback, // callback
|
||
NULL, // context data
|
||
WT_EXECUTEONLYONCE ); // flags
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
CleanupServiceNotification(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup service notification list.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PSERVICE_NOTIFICATION pnext;
|
||
PSERVICE_NOTIFICATION pfree;
|
||
|
||
LOCK_SERVICE_LIST();
|
||
|
||
pnext = g_ServiceNotificationList;
|
||
while ( pnext )
|
||
{
|
||
PSERVICE_NOTIFICATION pfree = pnext;
|
||
|
||
pnext = pnext->pNext;
|
||
GENERAL_HEAP_FREE( pfree );
|
||
}
|
||
g_ServiceNotificationList = NULL;
|
||
|
||
UNLOCK_SERVICE_LIST();
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Remote API for registration\deregistraion
|
||
//
|
||
|
||
BOOL
|
||
CRrRegisterParamChange(
|
||
IN DNS_RPC_HANDLE Reserved,
|
||
IN LPWSTR pszServiceName,
|
||
IN DWORD dwControl
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
pszServiceName -- name of service to register
|
||
|
||
dwControl -- control to send
|
||
|
||
Return Value:
|
||
|
||
TRUE if success
|
||
FALSE on error
|
||
|
||
--*/
|
||
{
|
||
PSERVICE_NOTIFICATION pprevService = NULL;
|
||
PSERVICE_NOTIFICATION pservice;
|
||
DWORD countService = 0;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
DNSLOG_F1( "DNS Caching Resolver Service - CRrRegisterParamChange" );
|
||
DNSLOG_F2( "Going to try register service notification entry for %S",
|
||
pszServiceName );
|
||
DNSLOG_F2( "Control: %d", dwControl );
|
||
|
||
DNSDBG( RPC, (
|
||
"CRrRegisterParamChange( %S, control=%d )\n",
|
||
pszServiceName,
|
||
dwControl ));
|
||
|
||
//
|
||
// access check
|
||
// refuse setting check on resolver service itself
|
||
//
|
||
|
||
if ( ClientThreadNotAllowedAccess() )
|
||
{
|
||
DNSLOG_F1( "CRrRegisterParamChange - ERROR_ACCESS_DENIED" );
|
||
return FALSE;
|
||
}
|
||
|
||
if ( !pszServiceName ||
|
||
! wcsicmp_ThatWorks( DNS_RESOLVER_SERVICE, pszServiceName ) )
|
||
{
|
||
DNSLOG_F1( "CRrRegisterParamChange - ERROR_INVALID_PARAMETER" );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// search service list for service
|
||
// - if service exists, bail
|
||
// - if too many services, bail
|
||
//
|
||
|
||
LOCK_SERVICE_LIST();
|
||
|
||
pservice = g_ServiceNotificationList;
|
||
|
||
while ( pservice )
|
||
{
|
||
if ( ! wcsicmp_ThatWorks(
|
||
pservice->pszServiceName,
|
||
pszServiceName ) )
|
||
{
|
||
pservice->dwControl = dwControl;
|
||
UNLOCK_SERVICE_LIST();
|
||
|
||
DNSLOG_F2(
|
||
"Service already registered, resetting control %d\n"
|
||
"Returning SUCCESS",
|
||
dwControl );
|
||
return TRUE;
|
||
}
|
||
|
||
pprevService = pservice;
|
||
pservice = pservice->pNext;
|
||
countService++;
|
||
}
|
||
|
||
if ( countService > MAX_DNS_NOTIFICATION_LIST_SIZE )
|
||
{
|
||
UNLOCK_SERVICE_LIST();
|
||
|
||
DNSLOG_F2(
|
||
"Registered service %S, returning error.\n"
|
||
"\tThere are too many services alreadyin the notification list!",
|
||
pszServiceName );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// service not found -- add it
|
||
// - alloc single blob
|
||
// - name of service will follow structure
|
||
//
|
||
// DCR: if always doing single blob, why have pointer? duh
|
||
//
|
||
|
||
pservice = GENERAL_HEAP_ALLOC(
|
||
sizeof(SERVICE_NOTIFICATION)
|
||
+ ((wcslen(pszServiceName) + 1) * sizeof(WCHAR)) );
|
||
if ( !pservice )
|
||
{
|
||
UNLOCK_SERVICE_LIST();
|
||
DNSLOG_F1( "Could not allocate memory to register service," );
|
||
DNSLOG_F1( "returning FAILURE" );
|
||
return FALSE;
|
||
}
|
||
|
||
pservice->pNext = NULL;
|
||
pservice->dwControl = dwControl;
|
||
pservice->pszServiceName = (LPWSTR) ( (LPBYTE) pservice +
|
||
sizeof(SERVICE_NOTIFICATION) );
|
||
wcscpy(
|
||
pservice->pszServiceName,
|
||
pszServiceName );
|
||
|
||
|
||
if ( pprevService )
|
||
{
|
||
pprevService->pNext = pservice;
|
||
}
|
||
else
|
||
{
|
||
g_ServiceNotificationList = pservice;
|
||
}
|
||
|
||
UNLOCK_SERVICE_LIST();
|
||
DNSLOG_F2(
|
||
"Registered service %S, returning SUCCESS",
|
||
pszServiceName );
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
CRrDeregisterParamChange(
|
||
IN DNS_RPC_HANDLE Reserved,
|
||
IN LPWSTR pszServiceName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PSERVICE_NOTIFICATION pprevService = NULL;
|
||
PSERVICE_NOTIFICATION pservice;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
|
||
DNSLOG_F1( "DNS Caching Resolver Service - CRrDeregisterParamChange" );
|
||
DNSLOG_F2( "Going to try remove service notification entry for %S",
|
||
pszServiceName );
|
||
|
||
DNSDBG( RPC, (
|
||
"CRrDeregisterParamChange( %S )\n",
|
||
pszServiceName ));
|
||
|
||
if ( ClientThreadNotAllowedAccess() )
|
||
{
|
||
DNSLOG_F1( "CRrDeregisterParamChange - ERROR_ACCESS_DENIED" );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// search service list for desired service
|
||
// - delete entry if found
|
||
//
|
||
|
||
LOCK_SERVICE_LIST();
|
||
|
||
pservice = g_ServiceNotificationList;
|
||
|
||
while ( pservice )
|
||
{
|
||
if ( ! wcsicmp_ThatWorks(
|
||
pservice->pszServiceName,
|
||
pszServiceName ) )
|
||
{
|
||
// service found, cut from list
|
||
|
||
if ( pprevService )
|
||
{
|
||
pprevService->pNext = pservice->pNext;
|
||
}
|
||
else
|
||
{
|
||
g_ServiceNotificationList = pservice->pNext;
|
||
}
|
||
UNLOCK_SERVICE_LIST();
|
||
|
||
GENERAL_HEAP_FREE( pservice );
|
||
DNSLOG_F1( "Found entry, returning SUCCESS" );
|
||
return TRUE;
|
||
}
|
||
|
||
pprevService = pservice;
|
||
pservice = pservice->pNext;
|
||
}
|
||
|
||
UNLOCK_SERVICE_LIST();
|
||
DNSLOG_F1( "Did not find entry, returning FAILURE" );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// End notesrv.c
|
||
//
|