4 * SNMPv3 View-based Access Control Model
7 #include <net-snmp/net-snmp-config.h>
20 #include <sys/types.h>
22 #if TIME_WITH_SYS_TIME
24 # include <sys/timeb.h>
26 # include <sys/time.h>
31 # include <sys/time.h>
42 #include <netinet/in.h>
49 #include <net-snmp/types.h>
50 #include <net-snmp/output_api.h>
51 #include <net-snmp/config_api.h>
53 #include <net-snmp/library/snmp_api.h>
54 #include <net-snmp/library/vacm.h>
56 static struct vacm_viewEntry *viewList = NULL, *viewScanPtr = NULL;
57 static struct vacm_accessEntry *accessList = NULL, *accessScanPtr = NULL;
58 static struct vacm_groupEntry *groupList = NULL, *groupScanPtr = NULL;
61 vacm_save(const char *token, const char *type)
63 struct vacm_viewEntry *vptr;
64 struct vacm_accessEntry *aptr;
65 struct vacm_groupEntry *gptr;
67 for (vptr = viewList; vptr != NULL; vptr = vptr->next) {
68 if (vptr->viewStorageType == ST_NONVOLATILE)
69 vacm_save_view(vptr, token, type);
72 for (aptr = accessList; aptr != NULL; aptr = aptr->next) {
73 if (aptr->storageType == ST_NONVOLATILE)
74 vacm_save_access(aptr, token, type);
77 for (gptr = groupList; gptr != NULL; gptr = gptr->next) {
78 if (gptr->storageType == ST_NONVOLATILE)
79 vacm_save_group(gptr, token, type);
84 * vacm_save_view(): saves a view entry to the persistent cache
87 vacm_save_view(struct vacm_viewEntry *view, const char *token,
93 memset(line, 0, sizeof(line));
94 snprintf(line, sizeof(line), "%s%s %d %d %d ", token, "View",
95 view->viewStatus, view->viewStorageType, view->viewType);
96 line[ sizeof(line)-1 ] = 0;
97 cptr = &line[strlen(line)]; /* the NULL */
100 read_config_save_octet_string(cptr, (u_char *) view->viewName + 1,
101 view->viewName[0] + 1);
104 read_config_save_objid(cptr, view->viewSubtree,
105 view->viewSubtreeLen);
107 cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask,
110 read_config_store(type, line);
114 vacm_parse_config_view(const char *token, char *line)
116 struct vacm_viewEntry view;
117 struct vacm_viewEntry *vptr;
118 char *viewName = (char *) &view.viewName;
119 oid *viewSubtree = (oid *) & view.viewSubtree;
123 view.viewStatus = atoi(line);
124 line = skip_token(line);
125 view.viewStorageType = atoi(line);
126 line = skip_token(line);
127 view.viewType = atoi(line);
128 line = skip_token(line);
130 read_config_read_octet_string(line, (u_char **) & viewName, &len);
131 view.viewSubtreeLen = MAX_OID_LEN;
133 read_config_read_objid(line, (oid **) & viewSubtree,
134 &view.viewSubtreeLen);
137 vacm_createViewEntry(view.viewName, view.viewSubtree,
138 view.viewSubtreeLen);
142 vptr->viewStatus = view.viewStatus;
143 vptr->viewStorageType = view.viewStorageType;
144 vptr->viewType = view.viewType;
145 viewMask = (u_char *) vptr->viewMask;
147 read_config_read_octet_string(line, (u_char **) & viewMask,
152 * vacm_save_access(): saves an access entry to the persistent cache
155 vacm_save_access(struct vacm_accessEntry *access_entry, const char *token,
161 memset(line, 0, sizeof(line));
162 snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
163 token, "Access", access_entry->status,
164 access_entry->storageType, access_entry->securityModel,
165 access_entry->securityLevel, access_entry->contextMatch);
166 line[ sizeof(line)-1 ] = 0;
167 cptr = &line[strlen(line)]; /* the NULL */
169 read_config_save_octet_string(cptr,
170 (u_char *) access_entry->groupName + 1,
171 access_entry->groupName[0] + 1);
174 read_config_save_octet_string(cptr,
175 (u_char *) access_entry->contextPrefix + 1,
176 access_entry->contextPrefix[0] + 1);
179 cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->readView,
180 strlen(access_entry->readView) + 1);
183 read_config_save_octet_string(cptr, (u_char *) access_entry->writeView,
184 strlen(access_entry->writeView) + 1);
187 read_config_save_octet_string(cptr, (u_char *) access_entry->notifyView,
188 strlen(access_entry->notifyView) + 1);
190 read_config_store(type, line);
194 vacm_parse_config_access(const char *token, char *line)
196 struct vacm_accessEntry access;
197 struct vacm_accessEntry *aptr;
198 char *contextPrefix = (char *) &access.contextPrefix;
199 char *groupName = (char *) &access.groupName;
200 char *readView, *writeView, *notifyView;
203 access.status = atoi(line);
204 line = skip_token(line);
205 access.storageType = atoi(line);
206 line = skip_token(line);
207 access.securityModel = atoi(line);
208 line = skip_token(line);
209 access.securityLevel = atoi(line);
210 line = skip_token(line);
211 access.contextMatch = atoi(line);
212 line = skip_token(line);
214 read_config_read_octet_string(line, (u_char **) & groupName, &len);
216 read_config_read_octet_string(line, (u_char **) & contextPrefix,
219 aptr = vacm_createAccessEntry(access.groupName, access.contextPrefix,
220 access.securityModel,
221 access.securityLevel);
225 aptr->status = access.status;
226 aptr->storageType = access.storageType;
227 aptr->securityModel = access.securityModel;
228 aptr->securityLevel = access.securityLevel;
229 aptr->contextMatch = access.contextMatch;
230 readView = (char *) aptr->readView;
232 read_config_read_octet_string(line, (u_char **) & readView, &len);
233 writeView = (char *) aptr->writeView;
235 read_config_read_octet_string(line, (u_char **) & writeView, &len);
236 notifyView = (char *) aptr->notifyView;
238 read_config_read_octet_string(line, (u_char **) & notifyView,
243 * vacm_save_group(): saves a group entry to the persistent cache
246 vacm_save_group(struct vacm_groupEntry *group_entry, const char *token,
252 memset(line, 0, sizeof(line));
253 snprintf(line, sizeof(line), "%s%s %d %d %d ",
254 token, "Group", group_entry->status,
255 group_entry->storageType, group_entry->securityModel);
256 line[ sizeof(line)-1 ] = 0;
257 cptr = &line[strlen(line)]; /* the NULL */
260 read_config_save_octet_string(cptr,
261 (u_char *) group_entry->securityName + 1,
262 group_entry->securityName[0] + 1);
264 cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName,
265 strlen(group_entry->groupName) + 1);
267 read_config_store(type, line);
271 vacm_parse_config_group(const char *token, char *line)
273 struct vacm_groupEntry group;
274 struct vacm_groupEntry *gptr;
275 char *securityName = (char *) &group.securityName;
279 group.status = atoi(line);
280 line = skip_token(line);
281 group.storageType = atoi(line);
282 line = skip_token(line);
283 group.securityModel = atoi(line);
284 line = skip_token(line);
286 read_config_read_octet_string(line, (u_char **) & securityName,
289 gptr = vacm_createGroupEntry(group.securityModel, group.securityName);
293 gptr->status = group.status;
294 gptr->storageType = group.storageType;
295 groupName = (char *) gptr->groupName;
297 read_config_read_octet_string(line, (u_char **) & groupName, &len);
300 struct vacm_viewEntry *
301 vacm_getViewEntry(const char *viewName,
302 oid * viewSubtree, size_t viewSubtreeLen, int mode)
304 struct vacm_viewEntry *vp, *vpret = NULL;
305 char view[VACMSTRINGLEN];
309 glen = (int) strlen(viewName);
310 if (glen < 0 || glen >= VACM_MAX_STRING)
313 strcpy(view + 1, viewName);
314 for (vp = viewList; vp; vp = vp->next) {
315 if (!memcmp(view, vp->viewName, glen + 1)
316 && viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
317 int mask = 0x80, maskpos = 0;
321 if (mode != VACM_MODE_IGNORE_MASK) { /* check the mask */
323 found && oidpos < (int) vp->viewSubtreeLen - 1;
325 if ((vp->viewMask[maskpos] & mask) != 0) {
326 if (viewSubtree[oidpos] !=
327 vp->viewSubtree[oidpos + 1])
339 * match successful, keep this node if its longer than
340 * the previous or (equal and lexicographically greater
341 * than the previous).
344 if (mode == VACM_MODE_CHECK_SUBTREE) {
346 } else if (vpret == NULL
347 || vp->viewSubtreeLen > vpret->viewSubtreeLen
348 || (vp->viewSubtreeLen == vpret->viewSubtreeLen
349 && snmp_oid_compare(vp->viewSubtree + 1,
350 vp->viewSubtreeLen - 1,
351 vpret->viewSubtree + 1,
352 vpret->viewSubtreeLen - 1) >
359 DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none"));
360 if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) {
367 vacm_scanViewInit(void)
369 viewScanPtr = viewList;
372 struct vacm_viewEntry *
373 vacm_scanViewNext(void)
375 struct vacm_viewEntry *returnval = viewScanPtr;
377 viewScanPtr = viewScanPtr->next;
381 struct vacm_viewEntry *
382 vacm_createViewEntry(const char *viewName,
383 oid * viewSubtree, size_t viewSubtreeLen)
385 struct vacm_viewEntry *vp, *lp, *op = NULL;
388 glen = (int) strlen(viewName);
389 if (glen < 0 || glen >= VACM_MAX_STRING)
391 vp = (struct vacm_viewEntry *) calloc(1,
392 sizeof(struct vacm_viewEntry));
396 (struct vacm_viewEntry *) calloc(1, sizeof(struct vacm_viewEntry));
397 if (vp->reserved == NULL) {
402 vp->viewName[0] = glen;
403 strcpy(vp->viewName + 1, viewName);
404 vp->viewSubtree[0] = viewSubtreeLen;
405 memcpy(vp->viewSubtree + 1, viewSubtree, viewSubtreeLen * sizeof(oid));
406 vp->viewSubtreeLen = viewSubtreeLen + 1;
410 cmp = memcmp(lp->viewName, vp->viewName, glen + 1);
411 cmp2 = snmp_oid_compare(lp->viewSubtree, lp->viewSubtreeLen,
412 vp->viewSubtree, vp->viewSubtreeLen);
413 if (cmp == 0 && cmp2 > 0)
429 vacm_destroyViewEntry(const char *viewName,
430 oid * viewSubtree, size_t viewSubtreeLen)
432 struct vacm_viewEntry *vp, *lastvp = NULL;
434 if (viewList && !strcmp(viewList->viewName + 1, viewName)
435 && viewList->viewSubtreeLen == viewSubtreeLen
436 && !memcmp((char *) viewList->viewSubtree, (char *) viewSubtree,
437 viewSubtreeLen * sizeof(oid))) {
439 viewList = viewList->next;
441 for (vp = viewList; vp; vp = vp->next) {
442 if (!strcmp(vp->viewName + 1, viewName)
443 && vp->viewSubtreeLen == viewSubtreeLen
444 && !memcmp((char *) vp->viewSubtree, (char *) viewSubtree,
445 viewSubtreeLen * sizeof(oid)))
451 lastvp->next = vp->next;
460 vacm_destroyAllViewEntries(void)
462 struct vacm_viewEntry *vp;
463 while ((vp = viewList)) {
471 struct vacm_groupEntry *
472 vacm_getGroupEntry(int securityModel, const char *securityName)
474 struct vacm_groupEntry *vp;
475 char secname[VACMSTRINGLEN];
478 glen = (int) strlen(securityName);
480 if (glen < 0 || glen >= VACM_MAX_STRING)
483 strcpy(secname + 1, securityName);
485 for (vp = groupList; vp; vp = vp->next) {
486 if ((securityModel == vp->securityModel
487 || vp->securityModel == SNMP_SEC_MODEL_ANY)
488 && !memcmp(vp->securityName, secname, glen + 1))
495 vacm_scanGroupInit(void)
497 groupScanPtr = groupList;
500 struct vacm_groupEntry *
501 vacm_scanGroupNext(void)
503 struct vacm_groupEntry *returnval = groupScanPtr;
505 groupScanPtr = groupScanPtr->next;
509 struct vacm_groupEntry *
510 vacm_createGroupEntry(int securityModel, const char *securityName)
512 struct vacm_groupEntry *gp, *lg, *og;
515 glen = (int) strlen(securityName);
516 if (glen < 0 || glen >= VACM_MAX_STRING)
518 gp = (struct vacm_groupEntry *) calloc(1,
519 sizeof(struct vacm_groupEntry));
523 (struct vacm_groupEntry *) calloc(1,
524 sizeof(struct vacm_groupEntry));
525 if (gp->reserved == NULL) {
530 gp->securityModel = securityModel;
531 gp->securityName[0] = glen;
532 strcpy(gp->securityName + 1, securityName);
537 if (lg->securityModel > securityModel)
539 if (lg->securityModel == securityModel &&
541 memcmp(lg->securityName, gp->securityName, glen + 1)) > 0)
544 * if (lg->securityModel == securityModel && cmp == 0) abort();
558 vacm_destroyGroupEntry(int securityModel, const char *securityName)
560 struct vacm_groupEntry *vp, *lastvp = NULL;
562 if (groupList && groupList->securityModel == securityModel
563 && !strcmp(groupList->securityName + 1, securityName)) {
565 groupList = groupList->next;
567 for (vp = groupList; vp; vp = vp->next) {
568 if (vp->securityModel == securityModel
569 && !strcmp(vp->securityName + 1, securityName))
575 lastvp->next = vp->next;
584 vacm_destroyAllGroupEntries(void)
586 struct vacm_groupEntry *gp;
587 while ((gp = groupList)) {
588 groupList = gp->next;
595 struct vacm_accessEntry *
596 vacm_getAccessEntry(const char *groupName,
597 const char *contextPrefix,
598 int securityModel, int securityLevel)
600 struct vacm_accessEntry *vp;
601 char group[VACMSTRINGLEN];
602 char context[VACMSTRINGLEN];
605 glen = (int) strlen(groupName);
606 if (glen < 0 || glen >= VACM_MAX_STRING)
608 clen = (int) strlen(contextPrefix);
609 if (clen < 0 || clen >= VACM_MAX_STRING)
613 strcpy(group + 1, groupName);
615 strcpy(context + 1, contextPrefix);
616 for (vp = accessList; vp; vp = vp->next) {
617 if ((securityModel == vp->securityModel
618 || vp->securityModel == SNMP_SEC_MODEL_ANY)
619 && securityLevel >= vp->securityLevel
620 && !memcmp(vp->groupName, group, glen + 1)
622 ((vp->contextMatch == CONTEXT_MATCH_EXACT
623 && clen == vp->contextPrefix[0]
624 && (memcmp(vp->contextPrefix, context, clen + 1) == 0))
625 || (vp->contextMatch == CONTEXT_MATCH_PREFIX
626 && clen >= vp->contextPrefix[0]
627 && (memcmp(vp->contextPrefix + 1, context + 1,
628 vp->contextPrefix[0]) == 0))))
635 vacm_scanAccessInit(void)
637 accessScanPtr = accessList;
640 struct vacm_accessEntry *
641 vacm_scanAccessNext(void)
643 struct vacm_accessEntry *returnval = accessScanPtr;
645 accessScanPtr = accessScanPtr->next;
649 struct vacm_accessEntry *
650 vacm_createAccessEntry(const char *groupName,
651 const char *contextPrefix,
652 int securityModel, int securityLevel)
654 struct vacm_accessEntry *vp, *lp, *op = NULL;
657 glen = (int) strlen(groupName);
658 if (glen < 0 || glen >= VACM_MAX_STRING)
660 clen = (int) strlen(contextPrefix);
661 if (clen < 0 || clen >= VACM_MAX_STRING)
663 vp = (struct vacm_accessEntry *) calloc(1,
669 (struct vacm_accessEntry *) calloc(1,
672 if (vp->reserved == NULL) {
677 vp->securityModel = securityModel;
678 vp->securityLevel = securityLevel;
679 vp->groupName[0] = glen;
680 strcpy(vp->groupName + 1, groupName);
681 vp->contextPrefix[0] = clen;
682 strcpy(vp->contextPrefix + 1, contextPrefix);
686 cmp = memcmp(lp->groupName, vp->groupName, glen + 1);
691 cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1);
696 if (lp->securityModel > securityModel)
698 if (lp->securityModel < securityModel)
700 if (lp->securityLevel > securityLevel)
715 vacm_destroyAccessEntry(const char *groupName,
716 const char *contextPrefix,
717 int securityModel, int securityLevel)
719 struct vacm_accessEntry *vp, *lastvp = NULL;
721 if (accessList && accessList->securityModel == securityModel
722 && accessList->securityModel == securityModel
723 && !strcmp(accessList->groupName + 1, groupName)
724 && !strcmp(accessList->contextPrefix + 1, contextPrefix)) {
726 accessList = accessList->next;
728 for (vp = accessList; vp; vp = vp->next) {
729 if (vp->securityModel == securityModel
730 && vp->securityLevel == securityLevel
731 && !strcmp(vp->groupName + 1, groupName)
732 && !strcmp(vp->contextPrefix + 1, contextPrefix))
738 lastvp->next = vp->next;
747 vacm_destroyAllAccessEntries(void)
749 struct vacm_accessEntry *ap;
750 while ((ap = accessList)) {
751 accessList = ap->next;
759 store_vacm(int majorID, int minorID, void *serverarg, void *clientarg)
762 * figure out our application name
764 char *appname = (char *) clientarg;
765 if (appname == NULL) {
766 appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
767 NETSNMP_DS_LIB_APPTYPE);
773 vacm_save("vacm", appname);
774 return SNMPERR_SUCCESS;
778 * returns 1 if vacm has *any* configuration entries in it (regardless
779 * of weather or not there is enough to make a decision based on it),
783 vacm_is_configured(void)
785 if (viewList == NULL && accessList == NULL && groupList == NULL) {