/* * vacm.c * * SNMPv3 View-based Access Control Model */ #include #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #else #include #endif #if HAVE_UNISTD_H #include #endif #include #include #if TIME_WITH_SYS_TIME # ifdef WIN32 # include # else # include # endif # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_WINSOCK_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_DMALLOC_H #include #endif #include "asn1.h" #include "snmp.h" #include "snmp_api.h" #include "vacm.h" #include "snmp_debug.h" #include "snmp-tc.h" #include "read_config.h" #include "default_store.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; void vacm_save(const char *token, const char *type) { struct vacm_viewEntry *vptr; struct vacm_accessEntry *aptr; struct vacm_groupEntry *gptr; 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) vacm_save_access(aptr, token, type); } 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)); sprintf(line, "%s%s %d %d %d ", token,"View", view->viewStatus, view->viewStorageType, view->viewType); cptr = &line[strlen(line)]; /* the NULL */ cptr = read_config_save_octet_string(cptr, (u_char *)view->viewName+1, view->viewName[0]+1); *cptr++ = ' '; cptr = read_config_save_objid(cptr, view->viewSubtree, view->viewSubtreeLen); *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, 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(line); view.viewStorageType=atoi(line); line=skip_token(line); view.viewType=atoi(line); line=skip_token(line); line = read_config_read_octet_string(line, (u_char **)&viewName,&len); view.viewSubtreeLen=MAX_OID_LEN; line = read_config_read_objid(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=(u_char *)vptr->viewMask; line = read_config_read_octet_string(line,(u_char **)&viewMask,&vptr->viewMaskLen); } /* vacm_save_access(): saves an access entry to the persistent cache */ void vacm_save_access(struct vacm_accessEntry *access, const char *token, const char *type) { char line[4096]; char *cptr; memset(line, 0, sizeof(line)); sprintf(line, "%s%s %d %d %d %d %d ", token,"Access", access->status, access->storageType, access->securityModel , access->securityLevel, access->contextMatch); cptr = &line[strlen(line)]; /* the NULL */ cptr = read_config_save_octet_string(cptr, (u_char *)access->groupName+1, access->groupName[0]+1); *cptr++ = ' '; cptr = read_config_save_octet_string(cptr, (u_char *)access->contextPrefix+1, access->contextPrefix[0]+1); *cptr++ = ' '; cptr = read_config_save_octet_string(cptr, (u_char *)access->readView, strlen(access->readView)+1); *cptr++ = ' '; cptr = read_config_save_octet_string(cptr, (u_char *)access->writeView, strlen(access->writeView)+1); *cptr++ = ' '; cptr = read_config_save_octet_string(cptr, (u_char *)access->notifyView, strlen(access->notifyView)+1); read_config_store(type, line); } void vacm_parse_config_access(const char *token, char *line) { struct vacm_accessEntry access; struct vacm_accessEntry *aptr; char *contextPrefix=(char *)&access.contextPrefix; char *groupName=(char *)&access.groupName; char *readView,*writeView,*notifyView; size_t len; access.status=atoi(line); line=skip_token(line); access.storageType=atoi(line); line=skip_token(line); access.securityModel=atoi(line); line=skip_token(line); access.securityLevel=atoi(line); line=skip_token(line); access.contextMatch=atoi(line); line=skip_token(line); line = read_config_read_octet_string(line, (u_char **)&groupName,&len); line = read_config_read_octet_string(line, (u_char **)&contextPrefix,&len); aptr=vacm_createAccessEntry(access.groupName,access.contextPrefix, access.securityModel,access.securityLevel); if(!aptr) return; aptr->status=access.status; aptr->storageType=access.storageType; aptr->securityModel=access.securityModel; aptr->securityLevel=access.securityLevel; aptr->contextMatch=access.contextMatch; readView=(char *)aptr->readView; line = read_config_read_octet_string(line,(u_char **)&readView,&len); writeView=(char *)aptr->writeView; line = read_config_read_octet_string(line,(u_char **)&writeView,&len); notifyView=(char *)aptr->notifyView; line = read_config_read_octet_string(line,(u_char **)¬ifyView,&len); } /* vacm_save_group(): saves a group entry to the persistent cache */ void vacm_save_group(struct vacm_groupEntry *group, const char *token, const char *type) { char line[4096]; char *cptr; memset(line, 0, sizeof(line)); sprintf(line, "%s%s %d %d %d ", token,"Group", group->status, group->storageType, group->securityModel); cptr = &line[strlen(line)]; /* the NULL */ cptr = read_config_save_octet_string(cptr, (u_char *)group->securityName+1, group->securityName[0]+1); *cptr++ = ' '; cptr = read_config_save_octet_string(cptr, (u_char *)group->groupName, strlen(group->groupName)+1); read_config_store(type, line); } void vacm_parse_config_group(const char *token, 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(line); group.storageType=atoi(line); line=skip_token(line); group.securityModel=atoi(line); line=skip_token(line); 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; line = read_config_read_octet_string(line, (u_char **)&groupName,&len); } struct vacm_viewEntry * vacm_getViewEntry(const char *viewName, oid *viewSubtree, size_t viewSubtreeLen) { struct vacm_viewEntry *vp, *vpret = NULL; char view[VACMSTRINGLEN]; int found, glen; glen = (int)strlen(viewName); if (glen < 0 || glen >= VACM_MAX_STRING) return NULL; view[0] = glen; strcpy(view+1, viewName); for(vp = viewList; vp; vp = vp->next){ if (!memcmp(view, vp->viewName,glen+1) && viewSubtreeLen >= vp->viewSubtreeLen) { int mask = 0x80, maskpos = 0; int oidpos; found = 1; for (oidpos = 0; found && oidpos < (int)vp->viewSubtreeLen-1; oidpos++) { if ((vp->viewMask[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). */ 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", (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,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 = viewList; 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 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+1, 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+1, 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[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; } 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) 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[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) && !memcmp(vp->contextPrefix, context, clen+1)) 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, 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; } 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+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) 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 = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); /* save the VACM MIB */ vacm_save("vacm",appname); return SNMPERR_SUCCESS; } /* returns 1 if vacm has *any* configuration entries in it (regardless of weather or not there is enough to make a decision based on it), else return 0 */ int vacm_is_configured(void) { if (viewList == NULL && accessList == NULL && groupList == NULL) return 0; return 1; }