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.
887 lines
22 KiB
887 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1992-1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
snmpmgrs.c
|
|
|
|
Abstract:
|
|
|
|
Contains routines for manipulating manager structures.
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
10-Feb-1997 DonRyan
|
|
Rewrote to implement SNMPv2 support.
|
|
|
|
--*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Header files //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "globals.h"
|
|
#include "snmpmgrs.h"
|
|
#include "network.h"
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Public procedures //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
AllocMLE(
|
|
PMANAGER_LIST_ENTRY * ppMLE,
|
|
LPSTR pManager
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates manager structure and initializes.
|
|
|
|
Arguments:
|
|
|
|
pManager - pointer to manager string.
|
|
|
|
ppMLE - pointer to receive pointer to entry.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fOk = FALSE;
|
|
PMANAGER_LIST_ENTRY pMLE = NULL;
|
|
DWORD dwIpAddr;
|
|
LPSTR pszManager;
|
|
|
|
// attempt to allocate structure
|
|
pMLE = AgentMemAlloc(sizeof(MANAGER_LIST_ENTRY));
|
|
|
|
// validate
|
|
if (pMLE != NULL) {
|
|
|
|
// allocate memory for manager string
|
|
pMLE->pManager = AgentMemAlloc(strlen(pManager)+1);
|
|
|
|
// validate
|
|
if (pMLE->pManager != NULL) {
|
|
|
|
// transfer manager string
|
|
strcpy(pMLE->pManager, pManager);
|
|
|
|
// Attempt to resolve manager network address
|
|
// For IPX addresses, this call always succeeds
|
|
// When SnmpSvcAddrToSocket fails, this means we deal with a dynamic IP Address
|
|
// for which the gethostbyname() failed.
|
|
if (SnmpSvcAddrToSocket(pMLE->pManager, &pMLE->SockAddr)) {
|
|
|
|
// see if tcpip address
|
|
if (pMLE->SockAddr.sa_family == AF_INET) {
|
|
|
|
// save structure size for later use
|
|
pMLE->SockAddrLen = sizeof(struct sockaddr_in);
|
|
|
|
pszManager = pMLE->pManager;
|
|
|
|
// attempt to convert address directly
|
|
dwIpAddr = inet_addr(pMLE->pManager);
|
|
|
|
// assume address is dynamic if error occurs
|
|
pMLE->fDynamicName = (dwIpAddr == SOCKET_ERROR);
|
|
|
|
// note time manager addr updated
|
|
pMLE->dwLastUpdate = GetCurrentTime();
|
|
|
|
// success
|
|
fOk = TRUE;
|
|
|
|
} else if (pMLE->SockAddr.sa_family == AF_IPX) {
|
|
|
|
// save structure size for later use
|
|
pMLE->SockAddrLen = sizeof(struct sockaddr_ipx);
|
|
|
|
// no name lookup for ipx
|
|
pMLE->fDynamicName = FALSE;
|
|
|
|
// success
|
|
fOk = TRUE;
|
|
}
|
|
|
|
pMLE->dwAge = MGRADDR_ALIVE;
|
|
|
|
} else {
|
|
LPTSTR tcsManager;
|
|
|
|
#ifdef UNICODE
|
|
SnmpUtilUTF8ToUnicode(&tcsManager, pMLE->pManager, TRUE);
|
|
#else
|
|
tcsManager=pMLE->pManager;
|
|
#endif
|
|
// at this point the address can be only an IP address!
|
|
// so we know pMLE->SockAddrLen as the size of the struct sockaddr_in!
|
|
pMLE->SockAddrLen = sizeof(struct sockaddr_in);
|
|
|
|
// since SnmpSvcAddrToSocket failed, that means inet_addr() failed hence
|
|
// we deal with a dynamic IP address
|
|
pMLE->fDynamicName = TRUE;
|
|
|
|
// set 'age' to dying
|
|
pMLE->dwAge = snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number;
|
|
|
|
// if the registry parameter is -1 this stands for 'keep retrying forever'
|
|
// in this case set the dwAge to the default MGRADDR_DYING(16) and never decrement it
|
|
if (pMLE->dwAge == (DWORD)-1)
|
|
pMLE->dwAge = MGRADDR_DYING;
|
|
|
|
// report a warning to the system log
|
|
ReportSnmpEvent(
|
|
SNMP_EVENT_NAME_RESOLUTION_FAILURE,
|
|
1,
|
|
&tcsManager,
|
|
0);
|
|
|
|
#ifdef UNICODE
|
|
SnmpUtilMemFree(tcsManager);
|
|
#endif
|
|
|
|
// success
|
|
fOk = TRUE;
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
if (!fOk) {
|
|
|
|
// release
|
|
FreeMLE(pMLE);
|
|
|
|
// re-init
|
|
pMLE = NULL;
|
|
}
|
|
}
|
|
|
|
// transfer
|
|
*ppMLE = pMLE;
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FreeMLE(
|
|
PMANAGER_LIST_ENTRY pMLE
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases manager structure.
|
|
|
|
Arguments:
|
|
|
|
pMLE - pointer to manager list entry to be freed.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fOk = TRUE;
|
|
|
|
// validate pointer
|
|
if (pMLE != NULL) {
|
|
|
|
// release string
|
|
AgentMemFree(pMLE->pManager);
|
|
|
|
// release structure
|
|
AgentMemFree(pMLE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UpdateMLE(
|
|
PMANAGER_LIST_ENTRY pMLE
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates manager structure.
|
|
An address will be resolved only if it is not marked as being 'DEAD'. A 'DEAD' address failed to be resolved for
|
|
more than MGRADDR_DYING times. A 'DEAD' address will no longer be used as a trap destination, but it will still
|
|
be validating the incoming SNMP requests if it could be resolve at least once since the service started up.
|
|
|
|
Arguments:
|
|
|
|
pMLE - pointer to manager list entry to be updated.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fOk = TRUE;
|
|
DWORD dwElaspedTime;
|
|
struct sockaddr SockAddr;
|
|
|
|
SNMPDBG((SNMP_LOG_TRACE,
|
|
"SNMP: SVC: Update manager '%s' with age %d.\n",
|
|
pMLE->pManager,
|
|
pMLE->dwAge));
|
|
|
|
// don't try to resolve this address if it is already dead
|
|
if (pMLE->dwAge == MGRADDR_DEAD)
|
|
return FALSE;
|
|
|
|
// see if name dynamic
|
|
if (pMLE->fDynamicName) {
|
|
|
|
// determine elasped time since last update
|
|
dwElaspedTime = GetCurrentTime() - pMLE->dwLastUpdate;
|
|
|
|
// resolve the address only if it failed to be resolved on last update
|
|
// or its update time expired.
|
|
if (pMLE->dwAge != MGRADDR_ALIVE || dwElaspedTime > DEFAULT_NAME_TIMEOUT) {
|
|
|
|
// attempt to resolve manager network address
|
|
// for IPX addresses, this call always succeeds
|
|
fOk = SnmpSvcAddrToSocket(pMLE->pManager, &SockAddr);
|
|
|
|
// validate
|
|
if (fOk) {
|
|
|
|
// update entry with new address
|
|
memcpy(&pMLE->SockAddr, &SockAddr, sizeof(SockAddr));
|
|
|
|
// note time dynamic name resolved
|
|
pMLE->dwLastUpdate = GetCurrentTime();
|
|
|
|
// make sure manager age is 'ALIVE'
|
|
pMLE->dwAge = MGRADDR_ALIVE;
|
|
|
|
} else if (pMLE->dwAge == MGRADDR_ALIVE) {
|
|
|
|
// Previously 'ALIVE' address cannot be resolved anymore
|
|
// set its age to the one specified by 'NameResolutionRetries' parameter in
|
|
// order to give some more chances.
|
|
pMLE->dwAge = snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number;
|
|
|
|
// if the registry parameter is -1 this stands for 'keep retrying forever'
|
|
// in this case set the dwAge to the default MGRADDR_DYING(16) which will never be decremented
|
|
if (pMLE->dwAge == (DWORD)-1)
|
|
pMLE->dwAge = MGRADDR_DYING;
|
|
|
|
} else if (pMLE->dwAge != MGRADDR_DEAD) {
|
|
|
|
// the address could not be resolved before and it still cannot be resolved
|
|
// decrement its retry counter only if the 'NameResolutionRetries' parameter says so
|
|
if (snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number != -1)
|
|
pMLE->dwAge--;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindManagerByName(
|
|
PMANAGER_LIST_ENTRY * ppMLE,
|
|
PLIST_ENTRY pListHead,
|
|
LPSTR pManager
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locates manager in list.
|
|
|
|
Arguments:
|
|
|
|
ppMLE - pointer to receive pointer to entry.
|
|
|
|
pListHead - pointer to head of manager list.
|
|
|
|
pManager - pointer to manager to find.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY pLE;
|
|
PMANAGER_LIST_ENTRY pMLE;
|
|
|
|
// initialize
|
|
*ppMLE = NULL;
|
|
|
|
// obtain pointer to list head
|
|
pLE = pListHead->Flink;
|
|
|
|
// process all entries in list
|
|
while (pLE != pListHead) {
|
|
|
|
// retrieve pointer to community structure
|
|
pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
|
|
|
|
// compare community string with entry
|
|
if (!strcmp(pMLE->pManager, pManager)) {
|
|
|
|
// transfer
|
|
*ppMLE = pMLE;
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
|
|
// next entry
|
|
pLE = pLE->Flink;
|
|
}
|
|
|
|
// failure
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsManagerAddrLegal(
|
|
struct sockaddr_in * pAddr
|
|
)
|
|
{
|
|
DWORD dwHostMask;
|
|
DWORD dwAddress = ntohl(pAddr->sin_addr.S_un.S_addr);
|
|
|
|
// check address legality only for Ip addresses
|
|
if (pAddr->sin_family != AF_INET)
|
|
return TRUE;
|
|
|
|
// disallow multicast (or future use) source addresses
|
|
// local broadcast will be filtered out here as well
|
|
if ((dwAddress & 0xe0000000) == 0xe0000000)
|
|
return FALSE;
|
|
|
|
// get hostmask for class 'C' addresses
|
|
if ((dwAddress & 0xc0000000) == 0xc0000000)
|
|
dwHostMask = 0x000000ff;
|
|
|
|
// get hostmask for class 'B' addresses
|
|
else if ((dwAddress & 0x80000000) == 0x80000000)
|
|
dwHostMask = 0x0000ffff;
|
|
|
|
// get hostidmask for class 'A' addresses
|
|
else
|
|
dwHostMask = 0x00ffffff;
|
|
|
|
SNMPDBG((SNMP_LOG_TRACE,"SNMP: dwAddress=%08x, dwHostMask=%08x, port=%d\n",
|
|
dwAddress, dwHostMask, ntohs(pAddr->sin_port)));
|
|
|
|
return ((dwAddress & dwHostMask) != 0 // check against net address
|
|
&& ((dwAddress & dwHostMask) != (0x00ffffff & dwHostMask)) // check against broadcast address
|
|
// && ntohs(pAddr->sin_port) >= 1024 // check against reserved port
|
|
);
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindManagerByAddr(
|
|
PMANAGER_LIST_ENTRY * ppMLE,
|
|
struct sockaddr * pSockAddr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locates permitted manager in list.
|
|
|
|
Arguments:
|
|
|
|
ppMLE - pointer to receive pointer to entry.
|
|
|
|
pSockAddr - pointer to socket address to find.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY pLE;
|
|
PMANAGER_LIST_ENTRY pMLE;
|
|
DWORD dwSockAddrLen;
|
|
enum
|
|
{
|
|
SRCH_ALIVE,
|
|
SRCH_DYING,
|
|
SRCH_DONE
|
|
} state;
|
|
|
|
// initialize
|
|
*ppMLE = NULL;
|
|
|
|
// loop twice through the list of permitted managers
|
|
// in the first loop look only through 'ALIVE' managers
|
|
// in the second loop look through the 'DYING' or 'DEAD' managers.
|
|
// ... this logic minimizes the response time for regular SNMP requests,
|
|
// as far as there is a bigger chance to have the request comming from an 'ALIVE' manager.
|
|
// otherwise, gethostbyname() called in UpdateMLE() lasts about 1/2 sec!!!
|
|
for (state = SRCH_ALIVE, pLE = g_PermittedManagers.Flink;
|
|
state != SRCH_DONE;
|
|
pLE=pLE->Flink)
|
|
{
|
|
// retrieve pointer to manager structure
|
|
pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
|
|
|
|
// if we are in the first loop ..
|
|
if (state == SRCH_ALIVE)
|
|
{
|
|
// .. but reached its end ..
|
|
if (pLE == &g_PermittedManagers)
|
|
{
|
|
// .. go further with the second loop
|
|
state = SRCH_DYING;
|
|
continue;
|
|
}
|
|
|
|
// .. pass over the managers that are not 'ALIVE'
|
|
if (pMLE->dwAge != MGRADDR_ALIVE)
|
|
continue;
|
|
}
|
|
|
|
// if we are in the second loop ..
|
|
if (state == SRCH_DYING)
|
|
{
|
|
// .. but reached its end ..
|
|
if (pLE == &g_PermittedManagers)
|
|
{
|
|
// .. mark the end of scanning
|
|
state = SRCH_DONE;
|
|
continue;
|
|
}
|
|
|
|
// .. pass over the managers that are 'ALIVE'
|
|
if (pMLE->dwAge == MGRADDR_ALIVE || pMLE->dwAge == MGRADDR_DEAD)
|
|
continue;
|
|
}
|
|
|
|
// update name:
|
|
// 'DEAD' addresses will no longer be resolved,
|
|
// 'DYING' addresses will be given another chance to resolve until they become 'DEAD'
|
|
// 'ALIVE' addresses that fail to resolve will become 'DYING'
|
|
// next, all managers with a valid address will participate to validation (see below)
|
|
UpdateMLE(pMLE);
|
|
|
|
// compare address families
|
|
if (IsValidSockAddr(&pMLE->SockAddr) &&
|
|
pMLE->SockAddr.sa_family == pSockAddr->sa_family)
|
|
{
|
|
|
|
// determine address family
|
|
if (pMLE->SockAddr.sa_family == AF_INET)
|
|
{
|
|
|
|
struct sockaddr_in * pSockAddrIn1;
|
|
struct sockaddr_in * pSockAddrIn2;
|
|
|
|
// obtain pointer to protocol specific structure
|
|
pSockAddrIn1= (struct sockaddr_in *)pSockAddr;
|
|
pSockAddrIn2= (struct sockaddr_in *)&pMLE->SockAddr;
|
|
|
|
// acknowledge this manager only if its address matches
|
|
// a permitted manager with a valid (not NULL) IP address.
|
|
// This is tested regardless the 'dwAge' of the permitted manager.
|
|
if (!memcmp(&pSockAddrIn1->sin_addr,
|
|
&pSockAddrIn2->sin_addr,
|
|
sizeof(pSockAddrIn2->sin_addr)))
|
|
{
|
|
|
|
// transfer
|
|
*ppMLE = pMLE;
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
else if (pMLE->SockAddr.sa_family == AF_IPX)
|
|
{
|
|
|
|
struct sockaddr_ipx * pSockAddrIpx1;
|
|
struct sockaddr_ipx * pSockAddrIpx2;
|
|
|
|
// obtain pointer to protocol specific structure
|
|
pSockAddrIpx1= (struct sockaddr_ipx *)pSockAddr;
|
|
pSockAddrIpx2= (struct sockaddr_ipx *)&pMLE->SockAddr;
|
|
|
|
// acknowledge this manager only if its ipx address matches a
|
|
// permitted manager with a valid (nodenum != 0) IPX address.
|
|
// This is tested regardless the 'dwAge' of the permitted manager.
|
|
if (!memcmp(pSockAddrIpx1->sa_netnum,
|
|
pSockAddrIpx2->sa_netnum,
|
|
sizeof(pSockAddrIpx2->sa_netnum)) &&
|
|
!memcmp(pSockAddrIpx1->sa_nodenum,
|
|
pSockAddrIpx2->sa_nodenum,
|
|
sizeof(pSockAddrIpx2->sa_nodenum)))
|
|
{
|
|
|
|
// transfer
|
|
*ppMLE = pMLE;
|
|
|
|
// success
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// failure
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AddManager(
|
|
PLIST_ENTRY pListHead,
|
|
LPSTR pManager
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds manager structure to list.
|
|
|
|
Arguments:
|
|
|
|
pListHead - pointer to head of list.
|
|
|
|
pManager - pointer to manager to add.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fOk = FALSE;
|
|
PMANAGER_LIST_ENTRY pMLE = NULL;
|
|
|
|
// attempt to locate in list
|
|
if (FindManagerByName(&pMLE, pListHead, pManager)) {
|
|
|
|
SNMPDBG((
|
|
SNMP_LOG_TRACE,
|
|
"SNMP: SVC: updating manager %s.\n",
|
|
pManager
|
|
));
|
|
|
|
// success
|
|
fOk = TRUE;
|
|
|
|
} else {
|
|
|
|
// allocate manager structure
|
|
if (AllocMLE(&pMLE, pManager)) {
|
|
|
|
SNMPDBG((
|
|
SNMP_LOG_TRACE,
|
|
"SNMP: SVC: adding manager %s.\n",
|
|
pManager
|
|
));
|
|
|
|
// insert into managers list
|
|
InsertTailList(pListHead, &pMLE->Link);
|
|
|
|
// success
|
|
fOk = TRUE;
|
|
}
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LoadManagers(
|
|
HKEY hKey,
|
|
PLIST_ENTRY pListHead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructs list of permitted managers.
|
|
|
|
Arguments:
|
|
|
|
hKey - registry key containing manager values.
|
|
|
|
pListHead - pointer to head of list.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG lStatus;
|
|
DWORD dwIndex;
|
|
DWORD dwNameSize;
|
|
DWORD dwValueSize;
|
|
DWORD dwValueType;
|
|
CHAR szName[MAX_PATH];
|
|
CHAR szValue[MAX_PATH]; // buffer for holding the translation UNICODE->UTF8
|
|
BOOL fOk = FALSE;
|
|
|
|
// initialize
|
|
dwIndex = 0;
|
|
lStatus = ERROR_SUCCESS;
|
|
|
|
// loop until error or end of list
|
|
while (lStatus == ERROR_SUCCESS)
|
|
{
|
|
// initialize buffer sizes
|
|
dwNameSize = sizeof(szName)/sizeof(szName[0]); // size in TCHARs
|
|
dwValueSize = sizeof(szValue); // size in bytes
|
|
|
|
szValue[0] = '\0';
|
|
|
|
// read next value
|
|
lStatus = RegEnumValueA(
|
|
hKey,
|
|
dwIndex,
|
|
szName,
|
|
&dwNameSize,
|
|
NULL,
|
|
&dwValueType,
|
|
szValue,
|
|
&dwValueSize
|
|
);
|
|
|
|
// validate return code
|
|
if (lStatus == ERROR_SUCCESS)
|
|
{
|
|
szValue[dwValueSize]='\0';
|
|
|
|
if (AddManager(pListHead, szValue)) // add valid manager to manager list
|
|
dwIndex++; //next
|
|
else
|
|
lStatus = ERROR_NOT_ENOUGH_MEMORY; // reset status to reflect failure
|
|
}
|
|
else if (lStatus == ERROR_NO_MORE_ITEMS)
|
|
fOk = TRUE; // success
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnloadManagers(
|
|
PLIST_ENTRY pListHead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys list of permitted managers.
|
|
|
|
Arguments:
|
|
|
|
pListHead - pointer to head of list.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY pLE;
|
|
PMANAGER_LIST_ENTRY pMLE;
|
|
|
|
// process entries until empty
|
|
while (!IsListEmpty(pListHead)) {
|
|
|
|
// extract next entry
|
|
pLE = RemoveHeadList(pListHead);
|
|
|
|
// retrieve pointer to manager structure
|
|
pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
|
|
|
|
// release
|
|
FreeMLE(pMLE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LoadPermittedManagers(
|
|
BOOL bFirstCall
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructs list of permitted managers.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey;
|
|
LONG lStatus;
|
|
BOOL fPolicy;
|
|
LPTSTR pszKey;
|
|
BOOL fOk = FALSE;
|
|
|
|
SNMPDBG((
|
|
SNMP_LOG_TRACE,
|
|
"SNMP: SVC: loading permitted managers.\n"
|
|
));
|
|
|
|
#ifdef _POLICY
|
|
// we need to provide precedence to the parameters set through the policy
|
|
fPolicy = TRUE;
|
|
#else
|
|
fPolicy = FALSE;
|
|
#endif
|
|
|
|
do
|
|
{
|
|
// if the policy is to be enforced, check the policy registry location first
|
|
pszKey = fPolicy ? REG_POLICY_PERMITTED_MANAGERS : REG_KEY_PERMITTED_MANAGERS;
|
|
|
|
// open registry subkey
|
|
lStatus = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
pszKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
// if the call succeeded or we were not checking the policy, break the loop
|
|
if (lStatus == ERROR_SUCCESS || !fPolicy)
|
|
break;
|
|
|
|
// being at this point, this means we were checking for the policy parameters.
|
|
// If and only if the policy is not defined (registry key is missing) we
|
|
// reset the error, mark 'fPolicy already tried' and go back into the loop
|
|
if (lStatus == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
lStatus = ERROR_SUCCESS;
|
|
fPolicy = FALSE;
|
|
}
|
|
} while (lStatus == ERROR_SUCCESS);
|
|
|
|
// validate return code
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
|
|
// call routine to load managers into global list
|
|
LoadManagers(hKey, &g_PermittedManagers);
|
|
|
|
// close key
|
|
RegCloseKey(hKey);
|
|
|
|
// at this point consider success (errors localized at particular managers were logged already)
|
|
fOk = TRUE;
|
|
}
|
|
else
|
|
// it doesn't matter how the values are, the key has to exist,
|
|
// so mark as bFirstCall in order to log an event if this is not true.
|
|
bFirstCall = TRUE;
|
|
|
|
if (!fOk) {
|
|
|
|
SNMPDBG((
|
|
SNMP_LOG_ERROR,
|
|
"SNMP: SVC: error %d processing PermittedManagers subkey.\n",
|
|
lStatus
|
|
));
|
|
|
|
// report an error only if on first call (service initialization)
|
|
// otherwise, due to registry operations through regedit, the event log
|
|
// might be flooded with records
|
|
if (bFirstCall)
|
|
// report event
|
|
ReportSnmpEvent(
|
|
SNMP_EVENT_INVALID_REGISTRY_KEY,
|
|
1,
|
|
&pszKey,
|
|
lStatus
|
|
);
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnloadPermittedManagers(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys list of permitted managers.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
Returns true if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
// call common routine with global list
|
|
return UnloadManagers(&g_PermittedManagers);
|
|
}
|
|
|