|
|
/*++
Copyright (c) 1992-1997 Microsoft Corporation
Module Name:
contexts.c
Abstract:
Contains routines for manipulating SNMP community structures.
Environment:
User Mode - Win32
Revision History:
10-Feb-1997 DonRyan Rewrote to implement SNMPv2 support.
--*/ ///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "contexts.h"
#include "snmpthrd.h"
#define DYN_REGISTRY_UPDATE 1
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL AddValidCommunity( LPWSTR pCommunity, DWORD dwAccess )
/*++
Routine Description:
Adds valid community to list.
Arguments:
pCommunity - pointer to community to add.
dwAccess - access rights for community.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE; PCOMMUNITY_LIST_ENTRY pCLE = NULL; AsnOctetString CommunityOctets; // initialize octet string info
CommunityOctets.length = wcslen(pCommunity) * sizeof(WCHAR); CommunityOctets.stream = (LPBYTE)pCommunity; CommunityOctets.dynamic = FALSE;
// attempt to locate in list
if (FindValidCommunity(&pCLE, &CommunityOctets)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: updating community %s.\n", StaticUnicodeToString((LPWSTR)pCommunity) ));
// update access rights
pCLE->dwAccess = dwAccess;
// success
fOk = TRUE;
} else {
// allocate community structure
if (AllocCLE(&pCLE, pCommunity)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: adding community %s.\n", CommunityOctetsToString(&(pCLE->Community), TRUE) ));
// insert into valid communities list
InsertTailList(&g_ValidCommunities, &pCLE->Link);
// update access rights
pCLE->dwAccess = dwAccess;
// success
fOk = TRUE; } }
return fOk; }
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL AllocCLE( PCOMMUNITY_LIST_ENTRY * ppCLE, LPWSTR pCommunity )
/*++
Routine Description:
Allocates community structure and initializes.
Arguments:
ppCLE - pointer to receive pointer to entry.
pCommunity - pointer to community string.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE; PCOMMUNITY_LIST_ENTRY pCLE = NULL;
// attempt to allocate structure
pCLE = AgentMemAlloc(sizeof(COMMUNITY_LIST_ENTRY));
// validate
if (pCLE != NULL) { // determine string length
DWORD nBytes = wcslen(pCommunity) * sizeof(WCHAR);
// allocate memory for string (include terminator)
pCLE->Community.stream = SnmpUtilMemAlloc(nBytes + sizeof(WCHAR));
// validate community string stream
if (pCLE->Community.stream != NULL) {
// set length of manager string
pCLE->Community.length = nBytes; // set memory allocation flag
pCLE->Community.dynamic = TRUE;
// transfer community string into octets
wcscpy((LPWSTR)(pCLE->Community.stream), pCommunity);
// success
fOk = TRUE;
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not copy community string %s.\n", StaticUnicodeToString(pCommunity) ));
// release
FreeCLE(pCLE);
// re-init
pCLE = NULL; }
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate context entry for %s.\n", StaticUnicodeToString(pCommunity) )); }
// transfer
*ppCLE = pCLE;
return fOk; }
BOOL FreeCLE( PCOMMUNITY_LIST_ENTRY pCLE )
/*++
Routine Description:
Releases community structure.
Arguments:
pCLE - pointer to community list entry to be freed.
Return Values:
Returns true if successful.
--*/
{ // validate pointer
if (pCLE != NULL) {
// release octet string contents
SnmpUtilOctetsFree(&pCLE->Community);
// release structure
AgentMemFree(pCLE); }
return TRUE; }
BOOL FindValidCommunity( PCOMMUNITY_LIST_ENTRY * ppCLE, AsnOctetString * pCommunity )
/*++
Routine Description:
Locates valid community in list.
Arguments:
ppCLE - pointer to receive pointer to entry.
pCommunity - pointer to community to find.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PCOMMUNITY_LIST_ENTRY pCLE;
// initialize
*ppCLE = NULL;
// obtain pointer to list head
pLE = g_ValidCommunities.Flink;
// process all entries in list
while (pLE != &g_ValidCommunities) {
// retrieve pointer to community structure
pCLE = CONTAINING_RECORD(pLE, COMMUNITY_LIST_ENTRY, Link);
// compare community string with entry
if (!SnmpUtilOctetsCmp(&pCLE->Community, pCommunity)) {
// transfer
*ppCLE = pCLE;
// success
return TRUE; }
// next entry
pLE = pLE->Flink; }
// failure
return FALSE; }
DWORD ParsePermissionMask( DWORD bitMask ) /*++
Routine Description:
Translates the permission mask from the bit-mask format (registry) into the internal constant value (constants from public\sdk\inc\snmp.h). The function works no longer if: - more than sizeof(DWORD)*8 permission values are defined - constant values (access policy) changes
Arguments:
bit-mask.
Return Values:
permission's constant value.
--*/ { DWORD dwPermission;
for(dwPermission = 0; (bitMask & ((DWORD)(-1)^1)) != 0; bitMask>>=1, dwPermission++);
return dwPermission; }
#ifdef DYN_REGISTRY_UPDATE
LONG UpdateRegistry( HKEY hKey, LPWSTR wszBogus, LPWSTR wszCommunity ) /*++
Routine Description:
Updates the registry configuration in order to be able to associate permission masks to each community: name type data old format: <whatever> REG_SZ community_name new format: community_name REG_DWORD permission_mask Arguments:
hKey - open handle to the key that contains the value szBogus - old format value name; useless data szCommunity - pointer to community name, as it was specified in the old format.
Return Values:
Returns ERROR_SUCCESS if successful.
--*/ { LONG lStatus; DWORD dwDataType;
// make sure the update was not tried (and breaked) before
lStatus = RegQueryValueExW( hKey, wszCommunity, 0, &dwDataType, NULL, NULL);
// if no previous (breaked) update, convert community to the new format
if (lStatus != ERROR_SUCCESS || dwDataType != REG_DWORD) { // permissions to be assigned to community
DWORD dwPermissionMask; // all communities that are converted to new format at this point,
// are converted to READ-ONLY permissions to tighten the security
dwPermissionMask = 1 << SNMP_ACCESS_READ_ONLY;
// set the new format value
lStatus = RegSetValueExW( hKey, wszCommunity, 0, REG_DWORD, (CONST BYTE *)&dwPermissionMask, sizeof(DWORD));
if (lStatus != ERROR_SUCCESS) return lStatus; }
// delete the old format value
lStatus = RegDeleteValueW( hKey, wszBogus);
return lStatus; } #endif
BOOL LoadValidCommunities( BOOL bFirstCall )
/*++
Routine Description:
Constructs list of valid communities.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{ HKEY hKey; LONG lStatus; DWORD dwIndex; WCHAR wszName[MAX_PATH]; // get the UNICODE encoding for szName
DWORD dwNameSize; DWORD dwDataType; WCHAR wszData[MAX_PATH]; // get the UNICODE encoding for szData
DWORD dwDataSize; BOOL fPolicy; LPTSTR pszKey; BOOL fOk = FALSE;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: loading valid communities.\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_VALID_COMMUNITIES : REG_KEY_VALID_COMMUNITIES;
// open registry subkey
lStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszKey, 0, #ifdef DYN_REGISTRY_UPDATE
bFirstCall ? KEY_READ | KEY_SET_VALUE : KEY_READ, #else
KEY_READ, #endif
&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) {
// initialize
dwIndex = 0;
// loop until error or end of list
for (dwIndex = 0; lStatus == ERROR_SUCCESS; dwIndex++)
{ // initialize buffer sizes
dwNameSize = sizeof(wszName) / sizeof(wszName[0]); // size in number of WCHARs, not the size in bytes
dwDataSize = sizeof(wszData); // size in number of bytes
// read next value
lStatus = RegEnumValueW( hKey, dwIndex, wszName, &dwNameSize, NULL, &dwDataType, (LPBYTE)wszData, &dwDataSize );
// validate return code
if (lStatus == ERROR_SUCCESS) {
// dynamically update values that are not of DWORD type
if (dwDataType != REG_DWORD) { #ifdef DYN_REGISTRY_UPDATE
if (dwDataType == REG_SZ) { // BUG# 638837, do not update ValidCommunities
// registry format in case we're working with policy
if (bFirstCall && !fPolicy) { if(UpdateRegistry(hKey, wszName, wszData) == ERROR_SUCCESS) { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: updated community registration\n" ));
// current value has been deleted, need to keep the index
dwIndex--; continue; } } else { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: old format community to be considered with read-only right"));
wcscpy(wszName, wszData); *(DWORD *)wszData = (1 << SNMP_ACCESS_READ_ONLY); } } else #endif
{ SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: wrong format in ValidCommunities[%d] registry entry\n", dwIndex )); continue; } }
// add valid community to list with related permissions
if (AddValidCommunity(wszName, ParsePermissionMask(*(DWORD *)wszData))) {
SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: rights set to %d for community '%s'\n", *(DWORD *)wszData, StaticUnicodeToString(wszName) ));
} else { // reset status to reflect failure
lStatus = ERROR_NOT_ENOUGH_MEMORY; } } else if (lStatus == ERROR_NO_MORE_ITEMS) { // success
fOk = TRUE; } } RegCloseKey(hKey); } 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 ValidCommunities subkey.\n", lStatus ));
// report an event only for the first call (initialization of the service).
// otherwise subsequent registry ops through regedit might flood the event log with
// unsignificant records
if (bFirstCall) // report event
ReportSnmpEvent( SNMP_EVENT_INVALID_REGISTRY_KEY, 1, &pszKey, lStatus ); } return fOk; }
BOOL UnloadValidCommunities( )
/*++
Routine Description:
Destroys list of valid communities.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PCOMMUNITY_LIST_ENTRY pCLE;
// process entries until list is empty
while (!IsListEmpty(&g_ValidCommunities)) {
// extract next entry from head of list
pLE = RemoveHeadList(&g_ValidCommunities);
// retrieve pointer to community structure
pCLE = CONTAINING_RECORD(pLE, COMMUNITY_LIST_ENTRY, Link); // release
FreeCLE(pCLE); }
return TRUE; }
|