windows-nt/Source/XPSP1/NT/net/snmp/newagent/exe/contexts.c

681 lines
16 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 dwDataSize = MAX_PATH;
DWORD dwDataType;
// make sure the update was not tried (and breaked) before
dwDataSize = sizeof(DWORD);
lStatus = RegQueryValueExW(
hKey,
wszCommunity,
0,
&dwDataType,
NULL,
&dwDataSize);
// 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-CREATE permissions to ensure same functionality as
// the permisionless communities.
dwPermissionMask = 1 << SNMP_ACCESS_READ_CREATE;
// 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
CHAR szName[3*MAX_PATH]; // buffer for holding the translation UNICODE->UTF8
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)
{
if (bFirstCall)
{
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 full rights"));
wcscpy(wszName, wszData);
*(DWORD *)wszData = (1 << SNMP_ACCESS_READ_CREATE);
}
}
else
#endif
{
SNMPDBG((
SNMP_LOG_WARNING,
"SNMP: SVC: wrong format in ValidCommunities[%d] registry entry\n",
dwIndex
));
continue;
}
}
// convert the UNICODE representation to UTF8 representation
//dwNameSize = WideCharToMultiByte(
// CP_UTF8,
// 0,
// wszName,
// wcslen(wszName),
// szName,
// sizeof(szName),
// NULL,
// NULL);
// if error, just skip this community
//if (dwNameSize == 0)
//{
// SNMPDBG((
// SNMP_LOG_WARNING,
// "SNMP: SVC: community conversion to UTF8 failed with error %d.\n", GetLastError()));
// continue;
//}
// put the '\0' terminator to the string
//szName[dwNameSize] = '\0';
// add valid community to list with related permissions
//if (AddValidCommunity(szName, ParsePermissionMask(*(DWORD *)wszData)))
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;
}
}
}
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;
}