1360 lines
43 KiB
C
1360 lines
43 KiB
C
/* Portions of this file are subject to the following copyright(s). See
|
|
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
* that may apply:
|
|
*/
|
|
/*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright (c) 2016 VMware, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*/
|
|
|
|
/*
|
|
* vacm.c
|
|
*
|
|
* SNMPv3 View-based Access Control Model
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#if HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#if TIME_WITH_SYS_TIME
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#else
|
|
# if HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# else
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
|
|
#if HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
#if HAVE_DMALLOC_H
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <net-snmp/types.h>
|
|
#include <net-snmp/output_api.h>
|
|
#include <net-snmp/config_api.h>
|
|
|
|
#include <net-snmp/library/snmp_api.h>
|
|
#include <net-snmp/library/system.h> /* strlcpy() */
|
|
#include <net-snmp/library/tools.h>
|
|
#include <net-snmp/library/vacm.h>
|
|
|
|
static struct vacm_viewEntry *viewList = NULL, *viewScanPtr = NULL;
|
|
static struct vacm_accessEntry *accessList = NULL, *accessScanPtr = NULL;
|
|
static struct vacm_groupEntry *groupList = NULL, *groupScanPtr = NULL;
|
|
|
|
/*
|
|
* Macro to extend view masks with 1 bits when shorter than subtree lengths
|
|
* REF: vacmViewTreeFamilyMask [RFC3415], snmpNotifyFilterMask [RFC3413]
|
|
*/
|
|
|
|
#define VIEW_MASK(viewPtr, idx, mask) \
|
|
((idx >= viewPtr->viewMaskLen) ? mask : (viewPtr->viewMask[idx] & mask))
|
|
|
|
/**
|
|
* Initilizes the VACM code.
|
|
* Specifically:
|
|
* - adds a set of enums mapping view numbers to human readable names
|
|
*/
|
|
void
|
|
init_vacm(void)
|
|
{
|
|
/* views for access via get/set/send-notifications */
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("read"),
|
|
VACM_VIEW_READ);
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("write"),
|
|
VACM_VIEW_WRITE);
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("notify"),
|
|
VACM_VIEW_NOTIFY);
|
|
|
|
/* views for permissions when receiving notifications */
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("log"),
|
|
VACM_VIEW_LOG);
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("execute"),
|
|
VACM_VIEW_EXECUTE);
|
|
se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("net"),
|
|
VACM_VIEW_NET);
|
|
}
|
|
|
|
void
|
|
vacm_save(const char *token, const char *type)
|
|
{
|
|
struct vacm_viewEntry *vptr;
|
|
struct vacm_accessEntry *aptr;
|
|
struct vacm_groupEntry *gptr;
|
|
int i;
|
|
|
|
for (vptr = viewList; vptr != NULL; vptr = vptr->next) {
|
|
if (vptr->viewStorageType == ST_NONVOLATILE)
|
|
vacm_save_view(vptr, token, type);
|
|
}
|
|
|
|
for (aptr = accessList; aptr != NULL; aptr = aptr->next) {
|
|
if (aptr->storageType == ST_NONVOLATILE) {
|
|
/* Store the standard views (if set) */
|
|
if ( aptr->views[VACM_VIEW_READ ][0] ||
|
|
aptr->views[VACM_VIEW_WRITE ][0] ||
|
|
aptr->views[VACM_VIEW_NOTIFY][0] )
|
|
vacm_save_access(aptr, token, type);
|
|
/* Store any other (valid) access views */
|
|
for ( i=VACM_VIEW_NOTIFY+1; i<VACM_MAX_VIEWS; i++ ) {
|
|
if ( aptr->views[i][0] )
|
|
vacm_save_auth_access(aptr, token, type, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (gptr = groupList; gptr != NULL; gptr = gptr->next) {
|
|
if (gptr->storageType == ST_NONVOLATILE)
|
|
vacm_save_group(gptr, token, type);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vacm_save_view(): saves a view entry to the persistent cache
|
|
*/
|
|
void
|
|
vacm_save_view(struct vacm_viewEntry *view, const char *token,
|
|
const char *type)
|
|
{
|
|
char line[4096];
|
|
char *cptr;
|
|
|
|
memset(line, 0, sizeof(line));
|
|
snprintf(line, sizeof(line), "%s%s %d %d %d ", token, "View",
|
|
view->viewStatus, view->viewStorageType, view->viewType);
|
|
line[ sizeof(line)-1 ] = 0;
|
|
cptr = &line[strlen(line)]; /* the NULL */
|
|
|
|
cptr =
|
|
read_config_save_octet_string(cptr, (u_char *) view->viewName + 1,
|
|
view->viewName[0]);
|
|
*cptr++ = ' ';
|
|
cptr =
|
|
read_config_save_objid(cptr, view->viewSubtree+1,
|
|
view->viewSubtreeLen-1);
|
|
*cptr++ = ' ';
|
|
cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask,
|
|
view->viewMaskLen);
|
|
|
|
read_config_store(type, line);
|
|
}
|
|
|
|
void
|
|
vacm_parse_config_view(const char *token, const char *line)
|
|
{
|
|
struct vacm_viewEntry view;
|
|
struct vacm_viewEntry *vptr;
|
|
char *viewName = (char *) &view.viewName;
|
|
oid *viewSubtree = (oid *) & view.viewSubtree;
|
|
u_char *viewMask;
|
|
size_t len;
|
|
|
|
view.viewStatus = atoi(line);
|
|
line = skip_token_const(line);
|
|
view.viewStorageType = atoi(line);
|
|
line = skip_token_const(line);
|
|
view.viewType = atoi(line);
|
|
line = skip_token_const(line);
|
|
len = sizeof(view.viewName);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & viewName, &len);
|
|
view.viewSubtreeLen = MAX_OID_LEN + 1;
|
|
line =
|
|
read_config_read_objid_const(line, (oid **) & viewSubtree,
|
|
&view.viewSubtreeLen);
|
|
|
|
vptr =
|
|
vacm_createViewEntry(view.viewName, view.viewSubtree,
|
|
view.viewSubtreeLen);
|
|
if (!vptr) {
|
|
return;
|
|
}
|
|
|
|
vptr->viewStatus = view.viewStatus;
|
|
vptr->viewStorageType = view.viewStorageType;
|
|
vptr->viewType = view.viewType;
|
|
viewMask = vptr->viewMask;
|
|
vptr->viewMaskLen = sizeof(vptr->viewMask);
|
|
line =
|
|
read_config_read_octet_string(line, &viewMask, &vptr->viewMaskLen);
|
|
}
|
|
|
|
/*
|
|
* vacm_save_access(): saves an access entry to the persistent cache
|
|
*/
|
|
void
|
|
vacm_save_access(struct vacm_accessEntry *access_entry, const char *token,
|
|
const char *type)
|
|
{
|
|
char line[4096];
|
|
char *cptr;
|
|
|
|
memset(line, 0, sizeof(line));
|
|
snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
|
|
token, "Access", access_entry->status,
|
|
access_entry->storageType, access_entry->securityModel,
|
|
access_entry->securityLevel, access_entry->contextMatch);
|
|
line[ sizeof(line)-1 ] = 0;
|
|
cptr = &line[strlen(line)]; /* the NULL */
|
|
cptr =
|
|
read_config_save_octet_string(cptr,
|
|
(u_char *) access_entry->groupName + 1,
|
|
access_entry->groupName[0] + 1);
|
|
*cptr++ = ' ';
|
|
cptr =
|
|
read_config_save_octet_string(cptr,
|
|
(u_char *) access_entry->contextPrefix + 1,
|
|
access_entry->contextPrefix[0] + 1);
|
|
|
|
*cptr++ = ' ';
|
|
cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_READ],
|
|
strlen(access_entry->views[VACM_VIEW_READ]) + 1);
|
|
*cptr++ = ' ';
|
|
cptr =
|
|
read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_WRITE],
|
|
strlen(access_entry->views[VACM_VIEW_WRITE]) + 1);
|
|
*cptr++ = ' ';
|
|
cptr =
|
|
read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_NOTIFY],
|
|
strlen(access_entry->views[VACM_VIEW_NOTIFY]) + 1);
|
|
|
|
read_config_store(type, line);
|
|
}
|
|
|
|
void
|
|
vacm_save_auth_access(struct vacm_accessEntry *access_entry,
|
|
const char *token, const char *type, int authtype)
|
|
{
|
|
char line[4096];
|
|
char *cptr;
|
|
|
|
memset(line, 0, sizeof(line));
|
|
snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
|
|
token, "AuthAccess", access_entry->status,
|
|
access_entry->storageType, access_entry->securityModel,
|
|
access_entry->securityLevel, access_entry->contextMatch);
|
|
line[ sizeof(line)-1 ] = 0;
|
|
cptr = &line[strlen(line)]; /* the NULL */
|
|
cptr =
|
|
read_config_save_octet_string(cptr,
|
|
(u_char *) access_entry->groupName + 1,
|
|
access_entry->groupName[0] + 1);
|
|
*cptr++ = ' ';
|
|
cptr =
|
|
read_config_save_octet_string(cptr,
|
|
(u_char *) access_entry->contextPrefix + 1,
|
|
access_entry->contextPrefix[0] + 1);
|
|
|
|
snprintf(cptr, sizeof(line)-(cptr-line), " %d ", authtype);
|
|
while ( *cptr )
|
|
cptr++;
|
|
|
|
*cptr++ = ' ';
|
|
cptr = read_config_save_octet_string(cptr,
|
|
(u_char *)access_entry->views[authtype],
|
|
strlen(access_entry->views[authtype]) + 1);
|
|
|
|
read_config_store(type, line);
|
|
}
|
|
|
|
char *
|
|
_vacm_parse_config_access_common(struct vacm_accessEntry **aptr,
|
|
const char *line)
|
|
{
|
|
struct vacm_accessEntry access;
|
|
char *cPrefix = (char *) &access.contextPrefix;
|
|
char *gName = (char *) &access.groupName;
|
|
size_t len;
|
|
|
|
access.status = atoi(line);
|
|
line = skip_token_const(line);
|
|
access.storageType = atoi(line);
|
|
line = skip_token_const(line);
|
|
access.securityModel = atoi(line);
|
|
line = skip_token_const(line);
|
|
access.securityLevel = atoi(line);
|
|
line = skip_token_const(line);
|
|
access.contextMatch = atoi(line);
|
|
line = skip_token_const(line);
|
|
len = sizeof(access.groupName);
|
|
line = read_config_read_octet_string(line, (u_char **) &gName, &len);
|
|
len = sizeof(access.contextPrefix);
|
|
line = read_config_read_octet_string(line, (u_char **) &cPrefix, &len);
|
|
|
|
*aptr = vacm_getAccessEntry(access.groupName,
|
|
access.contextPrefix,
|
|
access.securityModel,
|
|
access.securityLevel);
|
|
if (!*aptr)
|
|
*aptr = vacm_createAccessEntry(access.groupName,
|
|
access.contextPrefix,
|
|
access.securityModel,
|
|
access.securityLevel);
|
|
if (!*aptr)
|
|
return NULL;
|
|
|
|
(*aptr)->status = access.status;
|
|
(*aptr)->storageType = access.storageType;
|
|
(*aptr)->securityModel = access.securityModel;
|
|
(*aptr)->securityLevel = access.securityLevel;
|
|
(*aptr)->contextMatch = access.contextMatch;
|
|
return NETSNMP_REMOVE_CONST(char *, line);
|
|
}
|
|
|
|
void
|
|
vacm_parse_config_access(const char *token, const char *line)
|
|
{
|
|
struct vacm_accessEntry *aptr;
|
|
char *readView, *writeView, *notifyView;
|
|
size_t len;
|
|
|
|
line = _vacm_parse_config_access_common(&aptr, line);
|
|
if (!line)
|
|
return;
|
|
|
|
readView = (char *) aptr->views[VACM_VIEW_READ];
|
|
len = sizeof(aptr->views[VACM_VIEW_READ]);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & readView, &len);
|
|
writeView = (char *) aptr->views[VACM_VIEW_WRITE];
|
|
len = sizeof(aptr->views[VACM_VIEW_WRITE]);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & writeView, &len);
|
|
notifyView = (char *) aptr->views[VACM_VIEW_NOTIFY];
|
|
len = sizeof(aptr->views[VACM_VIEW_NOTIFY]);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & notifyView,
|
|
&len);
|
|
}
|
|
|
|
void
|
|
vacm_parse_config_auth_access(const char *token, const char *line)
|
|
{
|
|
struct vacm_accessEntry *aptr;
|
|
int authtype;
|
|
char *view;
|
|
size_t len;
|
|
|
|
line = _vacm_parse_config_access_common(&aptr, line);
|
|
if (!line)
|
|
return;
|
|
|
|
authtype = atoi(line);
|
|
line = skip_token_const(line);
|
|
|
|
view = (char *) aptr->views[authtype];
|
|
len = sizeof(aptr->views[authtype]);
|
|
line = read_config_read_octet_string(line, (u_char **) & view, &len);
|
|
}
|
|
|
|
/*
|
|
* vacm_save_group(): saves a group entry to the persistent cache
|
|
*/
|
|
void
|
|
vacm_save_group(struct vacm_groupEntry *group_entry, const char *token,
|
|
const char *type)
|
|
{
|
|
char line[4096];
|
|
char *cptr;
|
|
|
|
memset(line, 0, sizeof(line));
|
|
snprintf(line, sizeof(line), "%s%s %d %d %d ",
|
|
token, "Group", group_entry->status,
|
|
group_entry->storageType, group_entry->securityModel);
|
|
line[ sizeof(line)-1 ] = 0;
|
|
cptr = &line[strlen(line)]; /* the NULL */
|
|
|
|
cptr =
|
|
read_config_save_octet_string(cptr,
|
|
(u_char *) group_entry->securityName + 1,
|
|
group_entry->securityName[0] + 1);
|
|
*cptr++ = ' ';
|
|
cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName,
|
|
strlen(group_entry->groupName) + 1);
|
|
|
|
read_config_store(type, line);
|
|
}
|
|
|
|
void
|
|
vacm_parse_config_group(const char *token, const char *line)
|
|
{
|
|
struct vacm_groupEntry group;
|
|
struct vacm_groupEntry *gptr;
|
|
char *securityName = (char *) &group.securityName;
|
|
char *groupName;
|
|
size_t len;
|
|
|
|
group.status = atoi(line);
|
|
line = skip_token_const(line);
|
|
group.storageType = atoi(line);
|
|
line = skip_token_const(line);
|
|
group.securityModel = atoi(line);
|
|
line = skip_token_const(line);
|
|
len = sizeof(group.securityName);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & securityName,
|
|
&len);
|
|
|
|
gptr = vacm_createGroupEntry(group.securityModel, group.securityName);
|
|
if (!gptr)
|
|
return;
|
|
|
|
gptr->status = group.status;
|
|
gptr->storageType = group.storageType;
|
|
groupName = (char *) gptr->groupName;
|
|
len = sizeof(group.groupName);
|
|
line =
|
|
read_config_read_octet_string(line, (u_char **) & groupName, &len);
|
|
}
|
|
|
|
struct vacm_viewEntry *
|
|
netsnmp_view_get(struct vacm_viewEntry *head, const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen, int mode)
|
|
{
|
|
struct vacm_viewEntry *vp, *vpret = NULL;
|
|
char view[VACMSTRINGLEN];
|
|
int found, glen;
|
|
int count=0;
|
|
|
|
glen = (int) strlen(viewName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return NULL;
|
|
view[0] = glen;
|
|
strlcpy(view + 1, viewName, sizeof(view) - 1);
|
|
for (vp = head; vp; vp = vp->next) {
|
|
if (!memcmp(view, vp->viewName, glen + 1)
|
|
&& viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
|
|
int mask = 0x80;
|
|
unsigned int oidpos, maskpos = 0;
|
|
found = 1;
|
|
|
|
for (oidpos = 0;
|
|
found && oidpos < vp->viewSubtreeLen - 1;
|
|
oidpos++) {
|
|
if (mode==VACM_MODE_IGNORE_MASK || (VIEW_MASK(vp, maskpos, mask) != 0)) {
|
|
if (viewSubtree[oidpos] !=
|
|
vp->viewSubtree[oidpos + 1])
|
|
found = 0;
|
|
}
|
|
if (mask == 1) {
|
|
mask = 0x80;
|
|
maskpos++;
|
|
} else
|
|
mask >>= 1;
|
|
}
|
|
|
|
if (found) {
|
|
/*
|
|
* match successful, keep this node if its longer than
|
|
* the previous or (equal and lexicographically greater
|
|
* than the previous).
|
|
*/
|
|
count++;
|
|
if (mode == VACM_MODE_CHECK_SUBTREE) {
|
|
vpret = vp;
|
|
} else if (vpret == NULL
|
|
|| vp->viewSubtreeLen > vpret->viewSubtreeLen
|
|
|| (vp->viewSubtreeLen == vpret->viewSubtreeLen
|
|
&& snmp_oid_compare(vp->viewSubtree + 1,
|
|
vp->viewSubtreeLen - 1,
|
|
vpret->viewSubtree + 1,
|
|
vpret->viewSubtreeLen - 1) >
|
|
0)) {
|
|
vpret = vp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none"));
|
|
if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) {
|
|
return NULL;
|
|
}
|
|
return vpret;
|
|
}
|
|
|
|
/*******************************************************************o-o******
|
|
* netsnmp_view_exists
|
|
*
|
|
* Check to see if a view with the given name exists.
|
|
*
|
|
* Parameters:
|
|
* viewName - Name of view to check
|
|
*
|
|
* Returns 0 if the view does not exist. Otherwise, it returns the number
|
|
* of OID rows for the given name.
|
|
*/
|
|
int
|
|
netsnmp_view_exists(struct vacm_viewEntry *head, const char *viewName)
|
|
{
|
|
struct vacm_viewEntry *vp;
|
|
char view[VACMSTRINGLEN];
|
|
int len, count = 0;
|
|
|
|
len = (int) strlen(viewName);
|
|
if (len < 0 || len > VACM_MAX_STRING)
|
|
return 0;
|
|
view[0] = len;
|
|
strcpy(view + 1, viewName);
|
|
DEBUGMSGTL(("9:vacm:view_exists", "checking %s\n", viewName));
|
|
for (vp = head; vp; vp = vp->next) {
|
|
if (memcmp(view, vp->viewName, len + 1) == 0)
|
|
++count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*******************************************************************o-o******
|
|
* vacm_checkSubtree
|
|
*
|
|
* Check to see if everything within a subtree is in view, not in view,
|
|
* or possibly both.
|
|
*
|
|
* Parameters:
|
|
* *viewName - Name of view to check
|
|
* *viewSubtree - OID of subtree
|
|
* viewSubtreeLen - length of subtree OID
|
|
*
|
|
* Returns:
|
|
* VACM_SUCCESS The OID is included in the view.
|
|
* VACM_NOTINVIEW If no entry in the view list includes the
|
|
* provided OID, or the OID is explicitly excluded
|
|
* from the view.
|
|
* VACM_SUBTREE_UNKNOWN The entire subtree has both allowed and disallowed
|
|
* portions.
|
|
*/
|
|
int
|
|
netsnmp_view_subtree_check(struct vacm_viewEntry *head, const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
struct vacm_viewEntry *vp, *vpShorter = NULL, *vpLonger = NULL;
|
|
char view[VACMSTRINGLEN];
|
|
int found, glen;
|
|
|
|
glen = (int) strlen(viewName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return VACM_NOTINVIEW;
|
|
view[0] = glen;
|
|
strlcpy(view + 1, viewName, sizeof(view) - 1);
|
|
DEBUGMSGTL(("9:vacm:checkSubtree", "view %s\n", viewName));
|
|
for (vp = head; vp; vp = vp->next) {
|
|
if (!memcmp(view, vp->viewName, glen + 1)) {
|
|
/*
|
|
* If the subtree defined in the view is shorter than or equal
|
|
* to the subtree we are comparing, then it might envelop the
|
|
* subtree we are comparing against.
|
|
*/
|
|
if (viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
|
|
int mask = 0x80;
|
|
unsigned int oidpos, maskpos = 0;
|
|
found = 1;
|
|
|
|
/*
|
|
* check the mask
|
|
*/
|
|
for (oidpos = 0;
|
|
found && oidpos < vp->viewSubtreeLen - 1;
|
|
oidpos++) {
|
|
if (VIEW_MASK(vp, maskpos, mask) != 0) {
|
|
if (viewSubtree[oidpos] !=
|
|
vp->viewSubtree[oidpos + 1])
|
|
found = 0;
|
|
}
|
|
if (mask == 1) {
|
|
mask = 0x80;
|
|
maskpos++;
|
|
} else
|
|
mask >>= 1;
|
|
}
|
|
|
|
if (found) {
|
|
/*
|
|
* match successful, keep this node if it's longer than
|
|
* the previous or (equal and lexicographically greater
|
|
* than the previous).
|
|
*/
|
|
DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
|
|
|
|
if (vpShorter == NULL
|
|
|| vp->viewSubtreeLen > vpShorter->viewSubtreeLen
|
|
|| (vp->viewSubtreeLen == vpShorter->viewSubtreeLen
|
|
&& snmp_oid_compare(vp->viewSubtree + 1,
|
|
vp->viewSubtreeLen - 1,
|
|
vpShorter->viewSubtree + 1,
|
|
vpShorter->viewSubtreeLen - 1) >
|
|
0)) {
|
|
vpShorter = vp;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* If the subtree defined in the view is longer than the
|
|
* subtree we are comparing, then it might ambiguate our
|
|
* response.
|
|
*/
|
|
else {
|
|
int mask = 0x80;
|
|
unsigned int oidpos, maskpos = 0;
|
|
found = 1;
|
|
|
|
/*
|
|
* check the mask up to the length of the provided subtree
|
|
*/
|
|
for (oidpos = 0;
|
|
found && oidpos < viewSubtreeLen;
|
|
oidpos++) {
|
|
if (VIEW_MASK(vp, maskpos, mask) != 0) {
|
|
if (viewSubtree[oidpos] !=
|
|
vp->viewSubtree[oidpos + 1])
|
|
found = 0;
|
|
}
|
|
if (mask == 1) {
|
|
mask = 0x80;
|
|
maskpos++;
|
|
} else
|
|
mask >>= 1;
|
|
}
|
|
|
|
if (found) {
|
|
/*
|
|
* match successful. If we already found a match
|
|
* with a different view type, then parts of the subtree
|
|
* are included and others are excluded, so return UNKNOWN.
|
|
*/
|
|
DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
|
|
if (vpLonger != NULL
|
|
&& (vpLonger->viewType != vp->viewType)) {
|
|
DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
|
|
return VACM_SUBTREE_UNKNOWN;
|
|
}
|
|
else if (vpLonger == NULL) {
|
|
vpLonger = vp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched\n", viewName));
|
|
|
|
/*
|
|
* If we found a matching view subtree with a longer OID than the provided
|
|
* OID, check to see if its type is consistent with any matching view
|
|
* subtree we may have found with a shorter OID than the provided OID.
|
|
*
|
|
* The view type of the longer OID is inconsistent with the shorter OID in
|
|
* either of these two cases:
|
|
* 1) No matching shorter OID was found and the view type of the longer
|
|
* OID is INCLUDE.
|
|
* 2) A matching shorter ID was found and its view type doesn't match
|
|
* the view type of the longer OID.
|
|
*/
|
|
if (vpLonger != NULL) {
|
|
if ((!vpShorter && vpLonger->viewType != SNMP_VIEW_EXCLUDED)
|
|
|| (vpShorter && vpLonger->viewType != vpShorter->viewType)) {
|
|
DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
|
|
return VACM_SUBTREE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
if (vpShorter && vpShorter->viewType != SNMP_VIEW_EXCLUDED) {
|
|
DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "included"));
|
|
return VACM_SUCCESS;
|
|
}
|
|
|
|
DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "excluded"));
|
|
return VACM_NOTINVIEW;
|
|
}
|
|
|
|
void
|
|
vacm_scanViewInit(void)
|
|
{
|
|
viewScanPtr = viewList;
|
|
}
|
|
|
|
struct vacm_viewEntry *
|
|
vacm_scanViewNext(void)
|
|
{
|
|
struct vacm_viewEntry *returnval = viewScanPtr;
|
|
if (viewScanPtr)
|
|
viewScanPtr = viewScanPtr->next;
|
|
return returnval;
|
|
}
|
|
|
|
struct vacm_viewEntry *
|
|
netsnmp_view_create(struct vacm_viewEntry **head, const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
struct vacm_viewEntry *vp, *lp, *op = NULL;
|
|
int cmp, cmp2, glen;
|
|
|
|
glen = (int) strlen(viewName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING || viewSubtreeLen > MAX_OID_LEN)
|
|
return NULL;
|
|
vp = (struct vacm_viewEntry *) calloc(1,
|
|
sizeof(struct vacm_viewEntry));
|
|
if (vp == NULL)
|
|
return NULL;
|
|
vp->reserved =
|
|
(struct vacm_viewEntry *) calloc(1, sizeof(struct vacm_viewEntry));
|
|
if (vp->reserved == NULL) {
|
|
free(vp);
|
|
return NULL;
|
|
}
|
|
|
|
vp->viewName[0] = glen;
|
|
strlcpy(vp->viewName + 1, viewName, sizeof(vp->viewName) - 1);
|
|
vp->viewSubtree[0] = viewSubtreeLen;
|
|
memcpy(vp->viewSubtree + 1, viewSubtree, viewSubtreeLen * sizeof(oid));
|
|
vp->viewSubtreeLen = viewSubtreeLen + 1;
|
|
|
|
lp = *head;
|
|
while (lp) {
|
|
cmp = memcmp(lp->viewName, vp->viewName, glen + 1);
|
|
cmp2 = snmp_oid_compare(lp->viewSubtree, lp->viewSubtreeLen,
|
|
vp->viewSubtree, vp->viewSubtreeLen);
|
|
if (cmp == 0 && cmp2 > 0)
|
|
break;
|
|
if (cmp > 0)
|
|
break;
|
|
op = lp;
|
|
lp = lp->next;
|
|
}
|
|
vp->next = lp;
|
|
if (op)
|
|
op->next = vp;
|
|
else
|
|
*head = vp;
|
|
return vp;
|
|
}
|
|
|
|
void
|
|
netsnmp_view_destroy(struct vacm_viewEntry **head, const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
struct vacm_viewEntry *vp, *lastvp = NULL;
|
|
|
|
if ((*head) && !strcmp((*head)->viewName + 1, viewName)
|
|
&& (*head)->viewSubtreeLen == viewSubtreeLen
|
|
&& !memcmp((char *) (*head)->viewSubtree, (char *) viewSubtree,
|
|
viewSubtreeLen * sizeof(oid))) {
|
|
vp = (*head);
|
|
(*head) = (*head)->next;
|
|
} else {
|
|
for (vp = (*head); vp; vp = vp->next) {
|
|
if (!strcmp(vp->viewName + 1, viewName)
|
|
&& vp->viewSubtreeLen == viewSubtreeLen
|
|
&& !memcmp((char *) vp->viewSubtree, (char *) viewSubtree,
|
|
viewSubtreeLen * sizeof(oid)))
|
|
break;
|
|
lastvp = vp;
|
|
}
|
|
if (!vp || !lastvp)
|
|
return;
|
|
lastvp->next = vp->next;
|
|
}
|
|
if (vp->reserved)
|
|
free(vp->reserved);
|
|
free(vp);
|
|
return;
|
|
}
|
|
|
|
void
|
|
netsnmp_view_clear(struct vacm_viewEntry **head)
|
|
{
|
|
struct vacm_viewEntry *vp;
|
|
while ((vp = (*head))) {
|
|
(*head) = vp->next;
|
|
if (vp->reserved)
|
|
free(vp->reserved);
|
|
free(vp);
|
|
}
|
|
}
|
|
|
|
struct vacm_groupEntry *
|
|
vacm_getGroupEntry(int securityModel, const char *securityName)
|
|
{
|
|
struct vacm_groupEntry *vp;
|
|
char secname[VACMSTRINGLEN];
|
|
int glen;
|
|
|
|
glen = (int) strlen(securityName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return NULL;
|
|
secname[0] = glen;
|
|
strlcpy(secname + 1, securityName, sizeof(secname) - 1);
|
|
|
|
for (vp = groupList; vp; vp = vp->next) {
|
|
if ((securityModel == vp->securityModel
|
|
|| vp->securityModel == SNMP_SEC_MODEL_ANY)
|
|
&& !memcmp(vp->securityName, secname, glen + 1))
|
|
return vp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
vacm_scanGroupInit(void)
|
|
{
|
|
groupScanPtr = groupList;
|
|
}
|
|
|
|
struct vacm_groupEntry *
|
|
vacm_scanGroupNext(void)
|
|
{
|
|
struct vacm_groupEntry *returnval = groupScanPtr;
|
|
if (groupScanPtr)
|
|
groupScanPtr = groupScanPtr->next;
|
|
return returnval;
|
|
}
|
|
|
|
struct vacm_groupEntry *
|
|
vacm_createGroupEntry(int securityModel, const char *securityName)
|
|
{
|
|
struct vacm_groupEntry *gp, *lg, *og;
|
|
int cmp, glen;
|
|
|
|
glen = (int) strlen(securityName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return NULL;
|
|
gp = (struct vacm_groupEntry *) calloc(1,
|
|
sizeof(struct vacm_groupEntry));
|
|
if (gp == NULL)
|
|
return NULL;
|
|
gp->reserved =
|
|
(struct vacm_groupEntry *) calloc(1,
|
|
sizeof(struct vacm_groupEntry));
|
|
if (gp->reserved == NULL) {
|
|
free(gp);
|
|
return NULL;
|
|
}
|
|
|
|
gp->securityModel = securityModel;
|
|
gp->securityName[0] = glen;
|
|
strlcpy(gp->securityName + 1, securityName, sizeof(gp->securityName) - 1);
|
|
|
|
lg = groupList;
|
|
og = NULL;
|
|
while (lg) {
|
|
if (lg->securityModel > securityModel)
|
|
break;
|
|
if (lg->securityModel == securityModel &&
|
|
(cmp =
|
|
memcmp(lg->securityName, gp->securityName, glen + 1)) > 0)
|
|
break;
|
|
/*
|
|
* if (lg->securityModel == securityModel && cmp == 0) abort();
|
|
*/
|
|
og = lg;
|
|
lg = lg->next;
|
|
}
|
|
gp->next = lg;
|
|
if (og == NULL)
|
|
groupList = gp;
|
|
else
|
|
og->next = gp;
|
|
return gp;
|
|
}
|
|
|
|
void
|
|
vacm_destroyGroupEntry(int securityModel, const char *securityName)
|
|
{
|
|
struct vacm_groupEntry *vp, *lastvp = NULL;
|
|
|
|
if (groupList && groupList->securityModel == securityModel
|
|
&& !strcmp(groupList->securityName + 1, securityName)) {
|
|
vp = groupList;
|
|
groupList = groupList->next;
|
|
} else {
|
|
for (vp = groupList; vp; vp = vp->next) {
|
|
if (vp->securityModel == securityModel
|
|
&& !strcmp(vp->securityName + 1, securityName))
|
|
break;
|
|
lastvp = vp;
|
|
}
|
|
if (!vp || !lastvp)
|
|
return;
|
|
lastvp->next = vp->next;
|
|
}
|
|
if (vp->reserved)
|
|
free(vp->reserved);
|
|
free(vp);
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
vacm_destroyAllGroupEntries(void)
|
|
{
|
|
struct vacm_groupEntry *gp;
|
|
while ((gp = groupList)) {
|
|
groupList = gp->next;
|
|
if (gp->reserved)
|
|
free(gp->reserved);
|
|
free(gp);
|
|
}
|
|
}
|
|
|
|
struct vacm_accessEntry *
|
|
_vacm_choose_best( struct vacm_accessEntry *current,
|
|
struct vacm_accessEntry *candidate)
|
|
{
|
|
/*
|
|
* RFC 3415: vacmAccessTable:
|
|
* 2) if this set has [more than] one member, ...
|
|
* it comes down to deciding how to weight the
|
|
* preferences between ContextPrefixes,
|
|
* SecurityModels, and SecurityLevels
|
|
*/
|
|
if (( !current ) ||
|
|
/* a) if the subset of entries with securityModel
|
|
* matching the securityModel in the message is
|
|
* not empty, then discard the rest
|
|
*/
|
|
( current->securityModel == SNMP_SEC_MODEL_ANY &&
|
|
candidate->securityModel != SNMP_SEC_MODEL_ANY ) ||
|
|
/* b) if the subset of entries with vacmAccessContextPrefix
|
|
* matching the contextName in the message is
|
|
* not empty, then discard the rest
|
|
*/
|
|
( current->contextMatch == CONTEXT_MATCH_PREFIX &&
|
|
candidate->contextMatch == CONTEXT_MATCH_EXACT ) ||
|
|
/* c) discard all entries with ContextPrefixes shorter
|
|
* than the longest one remaining in the set
|
|
*/
|
|
( current->contextMatch == CONTEXT_MATCH_PREFIX &&
|
|
current->contextPrefix[0] < candidate->contextPrefix[0] ) ||
|
|
/* d) select the entry with the highest securityLevel
|
|
*/
|
|
( current->securityLevel < candidate->securityLevel )) {
|
|
|
|
return candidate;
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
struct vacm_accessEntry *
|
|
vacm_getAccessEntry(const char *groupName,
|
|
const char *contextPrefix,
|
|
int securityModel, int securityLevel)
|
|
{
|
|
struct vacm_accessEntry *vp, *best=NULL;
|
|
char group[VACMSTRINGLEN];
|
|
char context[VACMSTRINGLEN];
|
|
int glen, clen;
|
|
|
|
glen = (int) strlen(groupName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return NULL;
|
|
clen = (int) strlen(contextPrefix);
|
|
if (clen < 0 || clen > VACM_MAX_STRING)
|
|
return NULL;
|
|
|
|
group[0] = glen;
|
|
strlcpy(group + 1, groupName, sizeof(group) - 1);
|
|
context[0] = clen;
|
|
strlcpy(context + 1, contextPrefix, sizeof(context) - 1);
|
|
for (vp = accessList; vp; vp = vp->next) {
|
|
if ((securityModel == vp->securityModel
|
|
|| vp->securityModel == SNMP_SEC_MODEL_ANY)
|
|
&& securityLevel >= vp->securityLevel
|
|
&& !memcmp(vp->groupName, group, glen + 1)
|
|
&&
|
|
((vp->contextMatch == CONTEXT_MATCH_EXACT
|
|
&& clen == vp->contextPrefix[0]
|
|
&& (memcmp(vp->contextPrefix, context, clen + 1) == 0))
|
|
|| (vp->contextMatch == CONTEXT_MATCH_PREFIX
|
|
&& clen >= vp->contextPrefix[0]
|
|
&& (memcmp(vp->contextPrefix + 1, context + 1,
|
|
vp->contextPrefix[0]) == 0))))
|
|
best = _vacm_choose_best( best, vp );
|
|
}
|
|
return best;
|
|
}
|
|
|
|
void
|
|
vacm_scanAccessInit(void)
|
|
{
|
|
accessScanPtr = accessList;
|
|
}
|
|
|
|
struct vacm_accessEntry *
|
|
vacm_scanAccessNext(void)
|
|
{
|
|
struct vacm_accessEntry *returnval = accessScanPtr;
|
|
if (accessScanPtr)
|
|
accessScanPtr = accessScanPtr->next;
|
|
return returnval;
|
|
}
|
|
|
|
struct vacm_accessEntry *
|
|
vacm_createAccessEntry(const char *groupName,
|
|
const char *contextPrefix,
|
|
int securityModel, int securityLevel)
|
|
{
|
|
struct vacm_accessEntry *vp, *lp, *op = NULL;
|
|
int cmp, glen, clen;
|
|
|
|
glen = (int) strlen(groupName);
|
|
if (glen < 0 || glen > VACM_MAX_STRING)
|
|
return NULL;
|
|
clen = (int) strlen(contextPrefix);
|
|
if (clen < 0 || clen > VACM_MAX_STRING)
|
|
return NULL;
|
|
vp = (struct vacm_accessEntry *) calloc(1,
|
|
sizeof(struct
|
|
vacm_accessEntry));
|
|
if (vp == NULL)
|
|
return NULL;
|
|
vp->reserved =
|
|
(struct vacm_accessEntry *) calloc(1,
|
|
sizeof(struct
|
|
vacm_accessEntry));
|
|
if (vp->reserved == NULL) {
|
|
free(vp);
|
|
return NULL;
|
|
}
|
|
|
|
vp->securityModel = securityModel;
|
|
vp->securityLevel = securityLevel;
|
|
vp->groupName[0] = glen;
|
|
strlcpy(vp->groupName + 1, groupName, sizeof(vp->groupName) - 1);
|
|
vp->contextPrefix[0] = clen;
|
|
strlcpy(vp->contextPrefix + 1, contextPrefix,
|
|
sizeof(vp->contextPrefix) - 1);
|
|
|
|
lp = accessList;
|
|
while (lp) {
|
|
cmp = memcmp(lp->groupName, vp->groupName, glen + 1);
|
|
if (cmp > 0)
|
|
break;
|
|
if (cmp < 0)
|
|
goto next;
|
|
cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1);
|
|
if (cmp > 0)
|
|
break;
|
|
if (cmp < 0)
|
|
goto next;
|
|
if (lp->securityModel > securityModel)
|
|
break;
|
|
if (lp->securityModel < securityModel)
|
|
goto next;
|
|
if (lp->securityLevel > securityLevel)
|
|
break;
|
|
next:
|
|
op = lp;
|
|
lp = lp->next;
|
|
}
|
|
vp->next = lp;
|
|
if (op == NULL)
|
|
accessList = vp;
|
|
else
|
|
op->next = vp;
|
|
return vp;
|
|
}
|
|
|
|
void
|
|
vacm_destroyAccessEntry(const char *groupName,
|
|
const char *contextPrefix,
|
|
int securityModel, int securityLevel)
|
|
{
|
|
struct vacm_accessEntry *vp, *lastvp = NULL;
|
|
|
|
if (accessList && accessList->securityModel == securityModel
|
|
&& accessList->securityLevel == securityLevel
|
|
&& !strcmp(accessList->groupName + 1, groupName)
|
|
&& !strcmp(accessList->contextPrefix + 1, contextPrefix)) {
|
|
vp = accessList;
|
|
accessList = accessList->next;
|
|
} else {
|
|
for (vp = accessList; vp; vp = vp->next) {
|
|
if (vp->securityModel == securityModel
|
|
&& vp->securityLevel == securityLevel
|
|
&& !strcmp(vp->groupName + 1, groupName)
|
|
&& !strcmp(vp->contextPrefix + 1, contextPrefix))
|
|
break;
|
|
lastvp = vp;
|
|
}
|
|
if (!vp || !lastvp)
|
|
return;
|
|
lastvp->next = vp->next;
|
|
}
|
|
if (vp->reserved)
|
|
free(vp->reserved);
|
|
free(vp);
|
|
return;
|
|
}
|
|
|
|
void
|
|
vacm_destroyAllAccessEntries(void)
|
|
{
|
|
struct vacm_accessEntry *ap;
|
|
while ((ap = accessList)) {
|
|
accessList = ap->next;
|
|
if (ap->reserved)
|
|
free(ap->reserved);
|
|
free(ap);
|
|
}
|
|
}
|
|
|
|
int
|
|
store_vacm(int majorID, int minorID, void *serverarg, void *clientarg)
|
|
{
|
|
/*
|
|
* figure out our application name
|
|
*/
|
|
char *appname = (char *) clientarg;
|
|
if (appname == NULL) {
|
|
appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_APPTYPE);
|
|
}
|
|
|
|
/*
|
|
* save the VACM MIB
|
|
*/
|
|
vacm_save("vacm", appname);
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* returns 1 if vacm has *any* (non-built-in) configuration entries,
|
|
* regardless of whether or not there is enough to make a decision,
|
|
* else return 0
|
|
*/
|
|
int
|
|
vacm_is_configured(void)
|
|
{
|
|
if (accessList == NULL && groupList == NULL) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* backwards compatability
|
|
*/
|
|
struct vacm_viewEntry *
|
|
vacm_getViewEntry(const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen, int mode)
|
|
{
|
|
return netsnmp_view_get( viewList, viewName, viewSubtree, viewSubtreeLen,
|
|
mode);
|
|
}
|
|
|
|
int
|
|
vacm_checkSubtree(const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
return netsnmp_view_subtree_check( viewList, viewName, viewSubtree,
|
|
viewSubtreeLen);
|
|
}
|
|
|
|
struct vacm_viewEntry *
|
|
vacm_createViewEntry(const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
return netsnmp_view_create( &viewList, viewName, viewSubtree,
|
|
viewSubtreeLen);
|
|
}
|
|
|
|
void
|
|
vacm_destroyViewEntry(const char *viewName,
|
|
oid * viewSubtree, size_t viewSubtreeLen)
|
|
{
|
|
netsnmp_view_destroy( &viewList, viewName, viewSubtree, viewSubtreeLen);
|
|
}
|
|
|
|
void
|
|
vacm_destroyAllViewEntries(void)
|
|
{
|
|
netsnmp_view_clear( &viewList );
|
|
}
|
|
|
|
/*
|
|
* vacm simple api
|
|
*/
|
|
|
|
int
|
|
netsnmp_vacm_simple_usm_add(const char *user, int rw, int authLevel,
|
|
const char *view, oid *oidView, size_t oidViewLen,
|
|
const char *context)
|
|
{
|
|
struct vacm_viewEntry *vacmEntry = NULL;
|
|
struct vacm_groupEntry *groupEntry = NULL;
|
|
struct vacm_accessEntry *accessEntry = NULL;
|
|
char *tmp, localContext[VACMSTRINGLEN];
|
|
int exact = 1; /* exact context match */
|
|
|
|
if (NULL == user)
|
|
return SNMPERR_GENERR;
|
|
|
|
if (authLevel < SNMP_SEC_LEVEL_NOAUTH ||
|
|
authLevel > SNMP_SEC_LEVEL_AUTHPRIV)
|
|
return SNMPERR_GENERR;
|
|
|
|
if (NULL != view) {
|
|
/*
|
|
* if we are given a view name, it is an error if
|
|
* - it exists and we have an oid
|
|
* - it doesn't exist and we don't have an oid
|
|
*/
|
|
if (netsnmp_view_exists(viewList, view) != 0) {
|
|
if (NULL != oidView || oidViewLen > 0) {
|
|
DEBUGMSGTL(("vacm:simple_usm", "can't modify existing view"));
|
|
return SNMPERR_GENERR;
|
|
}
|
|
} else {
|
|
if (NULL == oidView || oidViewLen == 0) {
|
|
DEBUGMSGTL(("vacm:simple_usm", "can't create view w/out oid"));
|
|
return SNMPERR_GENERR;
|
|
}
|
|
/** try and create view for oid */
|
|
vacmEntry = vacm_createViewEntry(view, oidView, oidViewLen);
|
|
if (NULL == vacmEntry) {
|
|
DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
|
|
return SNMPERR_GENERR;
|
|
}
|
|
SNMP_FREE(vacmEntry->reserved);
|
|
}
|
|
} else if (0 == oidViewLen || NULL == oidView) {
|
|
view = "_all_"; /* no oid either, just use _all_ */
|
|
} else {
|
|
DEBUGMSGTL(("vacm:simple_usm", "need view name for new views"));
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/*
|
|
* group
|
|
* grpv3user usm \"v3user\"\000prefix\000_all_\000_all_\000_all_\000\060"
|
|
* vacm_createGroupEntry() also automatically inserts into group list.
|
|
*/
|
|
groupEntry = vacm_createGroupEntry(SNMP_SEC_MODEL_USM, user);
|
|
if (NULL == groupEntry) {
|
|
DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
|
|
goto bail;
|
|
}
|
|
snprintf(groupEntry->groupName, sizeof(groupEntry->groupName)-2,
|
|
"grp%.28s", user);
|
|
for (tmp=groupEntry->groupName; *tmp; tmp++)
|
|
if (!isalnum((unsigned char)(*tmp)))
|
|
*tmp = '_';
|
|
groupEntry->storageType = SNMP_STORAGE_PERMANENT;
|
|
groupEntry->status = SNMP_ROW_ACTIVE;
|
|
SNMP_FREE(groupEntry->reserved);
|
|
|
|
/*
|
|
* access
|
|
* grpv3user myctx usm noauth exact _all_ none none
|
|
*/
|
|
if (NULL == context) {
|
|
localContext[0] = 0;
|
|
context = localContext;
|
|
} else {
|
|
/** check for wildcard in context */
|
|
int contextLen = strlen(context);
|
|
if ('*' == context[contextLen - 1]) {
|
|
strlcpy(localContext, context, sizeof(localContext));
|
|
localContext[contextLen - 1] = 0;
|
|
context = localContext;
|
|
exact = 2; /* not exact, have context prefix */
|
|
}
|
|
}
|
|
accessEntry = vacm_createAccessEntry(groupEntry->groupName, context,
|
|
SNMP_SEC_MODEL_USM, authLevel);
|
|
if (NULL == accessEntry) {
|
|
DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
|
|
goto bail;
|
|
}
|
|
strlcpy(accessEntry->views[VACM_VIEW_READ], view,
|
|
sizeof(accessEntry->views[VACM_VIEW_READ]));
|
|
if (0 == rw)
|
|
view = "none";
|
|
strlcpy(accessEntry->views[VACM_VIEW_WRITE], view,
|
|
sizeof(accessEntry->views[VACM_VIEW_WRITE]));
|
|
strlcpy(accessEntry->views[VACM_VIEW_NOTIFY], view,
|
|
sizeof(accessEntry->views[VACM_VIEW_NOTIFY]));
|
|
|
|
accessEntry->contextMatch = exact;
|
|
accessEntry->storageType = SNMP_STORAGE_PERMANENT;
|
|
accessEntry->status = SNMP_ROW_ACTIVE;
|
|
SNMP_FREE(accessEntry->reserved);
|
|
|
|
return SNMPERR_SUCCESS;
|
|
|
|
bail:
|
|
if (NULL != groupEntry)
|
|
vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user);
|
|
|
|
if (NULL != vacmEntry)
|
|
vacm_destroyViewEntry(vacmEntry->viewName+1, vacmEntry->viewSubtree,
|
|
vacmEntry->viewSubtreeLen);
|
|
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
int
|
|
netsnmp_vacm_simple_usm_del(const char *user, int authLevel,
|
|
const char *view, oid *oidView, size_t oidViewLen,
|
|
const char *context)
|
|
{
|
|
char localContext[VACMSTRINGLEN];
|
|
char group[VACMSTRINGLEN];
|
|
|
|
/*
|
|
* only delete simple views (one OID) for which we have an OID.
|
|
* never delete '_all_'.
|
|
*/
|
|
if ((NULL != view) && (NULL != oidView) && (oidViewLen > 0) &&
|
|
(strcmp(view, "_all_") != 0) &&
|
|
(netsnmp_view_exists(viewList, view) == 1)) {
|
|
vacm_destroyViewEntry(view, oidView, oidViewLen);
|
|
}
|
|
|
|
vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user);
|
|
|
|
snprintf(group, sizeof(group)-2, "grp%.28s", user);
|
|
if (NULL == context) {
|
|
localContext[0] = 0;
|
|
context = localContext;
|
|
} else {
|
|
/** check for wildcard in context */
|
|
int contextLen = strlen(context);
|
|
if ('*' == context[contextLen - 1]) {
|
|
strlcpy(localContext, context, sizeof(localContext));
|
|
localContext[contextLen - 1] = 0;
|
|
context = localContext;
|
|
}
|
|
}
|
|
|
|
vacm_destroyAccessEntry(group, context, SNMP_SEC_MODEL_USM, authLevel);
|
|
|
|
return SNMPERR_SUCCESS;
|
|
}
|