summaryrefslogtreecommitdiff
path: root/snmplib/vacm.c
diff options
context:
space:
mode:
authorHideki Yamane <henrich@debian.org>2014-03-30 19:38:48 +0900
committerHideki Yamane <henrich@debian.org>2014-03-30 19:38:48 +0900
commit7769a9595c3da9a35f31b42451b1f6c3ed4004fa (patch)
tree009bf8fd68af6bb1129e07dd8c1ed205010d81f8 /snmplib/vacm.c
parent2e7891b0311204e0ecd5dc4a4334df01f3a6a1b4 (diff)
downloadpkg-net-snmp-7769a9595c3da9a35f31b42451b1f6c3ed4004fa.tar.gz
Imported Upstream version 5.7.2~dfsg
Diffstat (limited to 'snmplib/vacm.c')
-rw-r--r--snmplib/vacm.c1163
1 files changed, 1163 insertions, 0 deletions
diff --git a/snmplib/vacm.c b/snmplib/vacm.c
new file mode 100644
index 0000000..c639785
--- /dev/null
+++ b/snmplib/vacm.c
@@ -0,0 +1,1163 @@
+/* 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.
+ */
+
+/*
+ * 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 <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/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;
+ 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;
+ strcpy(view + 1, viewName);
+ 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******
+ * 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;
+ strcpy(view + 1, viewName);
+ 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)
+ 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;
+ strcpy(vp->viewName + 1, viewName);
+ 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;
+ strcpy(secname + 1, securityName);
+
+ 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;
+ strcpy(gp->securityName + 1, securityName);
+
+ 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;
+}
+
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+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;
+}
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+
+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;
+ strcpy(group + 1, groupName);
+ context[0] = clen;
+ strcpy(context + 1, contextPrefix);
+ 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;
+ strcpy(vp->groupName + 1, groupName);
+ vp->contextPrefix[0] = clen;
+ strcpy(vp->contextPrefix + 1, contextPrefix);
+
+ 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;
+}
+
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+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;
+}
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+
+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);
+}
+
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+void
+vacm_destroyViewEntry(const char *viewName,
+ oid * viewSubtree, size_t viewSubtreeLen)
+{
+ netsnmp_view_destroy( &viewList, viewName, viewSubtree, viewSubtreeLen);
+}
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+
+void
+vacm_destroyAllViewEntries(void)
+{
+ netsnmp_view_clear( &viewList );
+}
+