| /* |
| * vacm.c |
| * |
| * SNMPv3 View-based Access Control Model |
| */ |
| |
| #include <config.h> |
| |
| #if STDC_HEADERS |
| #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 |
| # ifdef WIN32 |
| # include <sys/timeb.h> |
| # else |
| # include <sys/time.h> |
| # endif |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| |
| #if HAVE_WINSOCK_H |
| #include <winsock.h> |
| #endif |
| |
| #if HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| |
| #include "asn1.h" |
| #include "snmp.h" |
| #include "snmp_api.h" |
| #include "vacm.h" |
| #include "snmp_debug.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; |
| |
| struct vacm_viewEntry * |
| vacm_getViewEntry(const char *viewName, |
| oid *viewSubtree, |
| size_t viewSubtreeLen) |
| { |
| struct vacm_viewEntry *vp, *vpret = NULL; |
| char view[32]; |
| int found; |
| |
| view[0] = strlen(viewName); |
| strcpy(view+1, viewName); |
| for(vp = viewList; vp; vp = vp->next){ |
| if (!strcmp(view, vp->viewName) |
| && viewSubtreeLen >= vp->viewSubtreeLen) { |
| int mask = 0x80, maskpos = 0; |
| int oidpos; |
| found = 1; |
| for (oidpos = 0; found && oidpos < (int)vp->viewSubtreeLen; oidpos++) { |
| if ((vp->viewMask[maskpos] & mask) != 0) { |
| if (viewSubtree[oidpos] != vp->viewSubtree[oidpos]) |
| 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). */ |
| if (vpret == NULL || vp->viewSubtreeLen > vpret->viewSubtreeLen || |
| (vp->viewSubtreeLen == vpret->viewSubtreeLen && |
| snmp_oid_compare(vp->viewSubtree, vp->viewSubtreeLen, |
| vpret->viewSubtree, |
| vpret->viewSubtreeLen) > 0)) |
| vpret = vp; |
| } |
| } |
| } |
| DEBUGMSGTL(("vacm:getView", ", %s", (vpret)?"found":"none")); |
| return vpret; |
| } |
| |
| 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 * |
| vacm_createViewEntry(const char *viewName, |
| oid *viewSubtree, |
| size_t viewSubtreeLen) |
| { |
| struct vacm_viewEntry *vp, *lp, *op = NULL; |
| int cmp; |
| |
| vp = (struct vacm_viewEntry *)malloc(sizeof(struct vacm_viewEntry)); |
| memset(vp, 0, sizeof(struct vacm_viewEntry)); |
| |
| vp->viewName[0] = strlen(viewName); |
| strcpy(vp->viewName+1, viewName); |
| memcpy(vp->viewSubtree, viewSubtree, viewSubtreeLen * sizeof(oid)); |
| vp->viewSubtreeLen = viewSubtreeLen; |
| vp->reserved = (struct vacm_viewEntry *)malloc(sizeof(struct vacm_viewEntry)); |
| memset(vp->reserved, 0, sizeof(struct vacm_viewEntry)); |
| |
| lp = viewList; |
| while (lp) { |
| cmp = strcmp(lp->viewName, vp->viewName); |
| if (cmp > 0) break; |
| if (cmp < 0) goto next; |
| |
| next: |
| op = lp; |
| lp = lp->next; |
| } |
| vp->next = lp; |
| if (op) op->next = vp; |
| else viewList = vp; |
| return vp; |
| } |
| |
| void |
| vacm_destroyViewEntry(const char *viewName, |
| oid *viewSubtree, |
| size_t viewSubtreeLen) |
| { |
| struct vacm_viewEntry *vp, *lastvp = NULL; |
| |
| if (viewList && !strcmp(viewList->viewName, viewName) |
| && viewList->viewSubtreeLen == viewSubtreeLen |
| && !memcmp((char *)viewList->viewSubtree, (char *)viewSubtree, |
| viewSubtreeLen * sizeof(oid))){ |
| vp = viewList; |
| viewList = viewList->next; |
| } else { |
| for (vp = viewList; vp; vp = vp->next){ |
| if (!strcmp(vp->viewName, viewName) |
| && vp->viewSubtreeLen == viewSubtreeLen |
| && !memcmp((char *)vp->viewSubtree, (char *)viewSubtree, |
| viewSubtreeLen * sizeof(oid))) |
| break; |
| lastvp = vp; |
| } |
| if (!vp) |
| return; |
| lastvp->next = vp->next; |
| } |
| if (vp->reserved) |
| free(vp->reserved); |
| free(vp); |
| return; |
| } |
| |
| void vacm_destroyAllViewEntries (void) |
| { |
| struct vacm_viewEntry *vp; |
| while ((vp = viewList)) { |
| viewList = 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[32]; |
| |
| secname[0] = strlen(securityName); |
| strcpy(secname+1, securityName); |
| |
| for (vp = groupList; vp; vp = vp->next) { |
| if ((securityModel == vp->securityModel || vp->securityModel == SNMP_SEC_MODEL_ANY) |
| && !strcmp(vp->securityName, secname)) |
| 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; |
| |
| gp = (struct vacm_groupEntry *)malloc(sizeof(struct vacm_groupEntry)); |
| memset(gp, 0, sizeof(struct vacm_groupEntry)); |
| |
| gp->securityModel = securityModel; |
| gp->securityName[0] = strlen(securityName); |
| strcpy(gp->securityName+1, securityName); |
| gp->reserved = (struct vacm_groupEntry *)malloc(sizeof(struct vacm_groupEntry)); |
| memset(gp->reserved, 0, sizeof(struct vacm_groupEntry)); |
| |
| lg = groupList; |
| og = NULL; |
| while (lg) { |
| if (lg->securityModel > securityModel) break; |
| if (lg->securityModel == securityModel && |
| (cmp = strcmp(lg->securityName, gp->securityName)) > 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, securityName)) { |
| vp = groupList; |
| groupList = groupList->next; |
| } else { |
| for (vp = groupList; vp; vp = vp->next){ |
| if (vp->securityModel == securityModel |
| && !strcmp(vp->securityName, securityName)) |
| break; |
| lastvp = vp; |
| } |
| if (!vp) |
| 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_getAccessEntry(const char *groupName, |
| const char *contextPrefix, |
| int securityModel, |
| int securityLevel) |
| { |
| struct vacm_accessEntry *vp; |
| char group[32]; |
| char context[32]; |
| |
| group[0] = strlen(groupName); |
| strcpy(group+1, groupName); |
| context[0] = strlen(contextPrefix); |
| strcpy(context+1, contextPrefix); |
| for(vp = accessList; vp; vp = vp->next){ |
| if ((securityModel == vp->securityModel || vp->securityModel == SNMP_SEC_MODEL_ANY) |
| && securityLevel >= vp->securityLevel |
| && !strcmp(vp->groupName, group) |
| && !strcmp(vp->contextPrefix, context)) |
| return vp; |
| } |
| return NULL; |
| } |
| |
| 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; |
| |
| vp = (struct vacm_accessEntry *)malloc(sizeof(struct vacm_accessEntry)); |
| memset(vp, 0, sizeof(struct vacm_accessEntry)); |
| |
| vp->securityModel = securityModel; |
| vp->securityLevel = securityLevel; |
| vp->groupName[0] = strlen(groupName); |
| strcpy(vp->groupName+1, groupName); |
| vp->contextPrefix[0] = strlen(contextPrefix); |
| strcpy(vp->contextPrefix+1, contextPrefix); |
| vp->reserved = (struct vacm_accessEntry *)malloc(sizeof(struct vacm_accessEntry)); |
| memset(vp->reserved, 0, sizeof(struct vacm_accessEntry)); |
| |
| lp = accessList; |
| while (lp) { |
| cmp = strcmp(lp->groupName, vp->groupName); |
| if (cmp > 0) break; |
| if (cmp < 0) goto next; |
| cmp = strcmp(lp->contextPrefix, vp->contextPrefix); |
| 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->securityModel == securityModel |
| && !strcmp(accessList->groupName, groupName) |
| && !strcmp(accessList->contextPrefix, contextPrefix)) { |
| vp = accessList; |
| accessList = accessList->next; |
| } else { |
| for (vp = accessList; vp; vp = vp->next){ |
| if (vp->securityModel == securityModel |
| && vp->securityLevel == securityLevel |
| && !strcmp(vp->groupName, groupName) |
| && !strcmp(vp->contextPrefix, contextPrefix)) |
| break; |
| lastvp = vp; |
| } |
| if (!vp) |
| 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); |
| } |
| } |