added files
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / vacm.c
1 /*
2  * vacm.c
3  *
4  * SNMPv3 View-based Access Control Model
5  */
6
7 #include <net-snmp/net-snmp-config.h>
8
9 #if HAVE_STDLIB_H
10 #include <stdlib.h>
11 #endif
12 #if HAVE_STRING_H
13 #include <string.h>
14 #else
15 #include <strings.h>
16 #endif
17 #if HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #include <sys/types.h>
21 #include <stdio.h>
22 #if TIME_WITH_SYS_TIME
23 # ifdef WIN32
24 #  include <sys/timeb.h>
25 # else
26 #  include <sys/time.h>
27 # endif
28 # include <time.h>
29 #else
30 # if HAVE_SYS_TIME_H
31 #  include <sys/time.h>
32 # else
33 #  include <time.h>
34 # endif
35 #endif
36
37 #if HAVE_WINSOCK_H
38 #include <winsock.h>
39 #endif
40
41 #if HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44
45 #if HAVE_DMALLOC_H
46 #include <dmalloc.h>
47 #endif
48
49 #include <net-snmp/types.h>
50 #include <net-snmp/output_api.h>
51 #include <net-snmp/config_api.h>
52
53 #include <net-snmp/library/snmp_api.h>
54 #include <net-snmp/library/vacm.h>
55
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;
59
60 void
61 vacm_save(const char *token, const char *type)
62 {
63     struct vacm_viewEntry *vptr;
64     struct vacm_accessEntry *aptr;
65     struct vacm_groupEntry *gptr;
66
67     for (vptr = viewList; vptr != NULL; vptr = vptr->next) {
68         if (vptr->viewStorageType == ST_NONVOLATILE)
69             vacm_save_view(vptr, token, type);
70     }
71
72     for (aptr = accessList; aptr != NULL; aptr = aptr->next) {
73         if (aptr->storageType == ST_NONVOLATILE)
74             vacm_save_access(aptr, token, type);
75     }
76
77     for (gptr = groupList; gptr != NULL; gptr = gptr->next) {
78         if (gptr->storageType == ST_NONVOLATILE)
79             vacm_save_group(gptr, token, type);
80     }
81 }
82
83 /*
84  * vacm_save_view(): saves a view entry to the persistent cache 
85  */
86 void
87 vacm_save_view(struct vacm_viewEntry *view, const char *token,
88                const char *type)
89 {
90     char            line[4096];
91     char           *cptr;
92
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 */
98
99     cptr =
100         read_config_save_octet_string(cptr, (u_char *) view->viewName + 1,
101                                       view->viewName[0] + 1);
102     *cptr++ = ' ';
103     cptr =
104         read_config_save_objid(cptr, view->viewSubtree,
105                                view->viewSubtreeLen);
106     *cptr++ = ' ';
107     cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask,
108                                          view->viewMaskLen);
109
110     read_config_store(type, line);
111 }
112
113 void
114 vacm_parse_config_view(const char *token, char *line)
115 {
116     struct vacm_viewEntry view;
117     struct vacm_viewEntry *vptr;
118     char           *viewName = (char *) &view.viewName;
119     oid            *viewSubtree = (oid *) & view.viewSubtree;
120     u_char         *viewMask;
121     size_t          len;
122
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);
129     line =
130         read_config_read_octet_string(line, (u_char **) & viewName, &len);
131     view.viewSubtreeLen = MAX_OID_LEN;
132     line =
133         read_config_read_objid(line, (oid **) & viewSubtree,
134                                &view.viewSubtreeLen);
135
136     vptr =
137         vacm_createViewEntry(view.viewName, view.viewSubtree,
138                              view.viewSubtreeLen);
139     if (!vptr)
140         return;
141
142     vptr->viewStatus = view.viewStatus;
143     vptr->viewStorageType = view.viewStorageType;
144     vptr->viewType = view.viewType;
145     viewMask = (u_char *) vptr->viewMask;
146     line =
147         read_config_read_octet_string(line, (u_char **) & viewMask,
148                                       &vptr->viewMaskLen);
149 }
150
151 /*
152  * vacm_save_access(): saves an access entry to the persistent cache 
153  */
154 void
155 vacm_save_access(struct vacm_accessEntry *access_entry, const char *token,
156                  const char *type)
157 {
158     char            line[4096];
159     char           *cptr;
160
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 */
168     cptr =
169         read_config_save_octet_string(cptr,
170                                       (u_char *) access_entry->groupName + 1,
171                                       access_entry->groupName[0] + 1);
172     *cptr++ = ' ';
173     cptr =
174         read_config_save_octet_string(cptr,
175                                       (u_char *) access_entry->contextPrefix + 1,
176                                       access_entry->contextPrefix[0] + 1);
177
178     *cptr++ = ' ';
179     cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->readView,
180                                          strlen(access_entry->readView) + 1);
181     *cptr++ = ' ';
182     cptr =
183         read_config_save_octet_string(cptr, (u_char *) access_entry->writeView,
184                                       strlen(access_entry->writeView) + 1);
185     *cptr++ = ' ';
186     cptr =
187         read_config_save_octet_string(cptr, (u_char *) access_entry->notifyView,
188                                       strlen(access_entry->notifyView) + 1);
189
190     read_config_store(type, line);
191 }
192
193 void
194 vacm_parse_config_access(const char *token, char *line)
195 {
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;
201     size_t          len;
202
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);
213     line =
214         read_config_read_octet_string(line, (u_char **) & groupName, &len);
215     line =
216         read_config_read_octet_string(line, (u_char **) & contextPrefix,
217                                       &len);
218
219     aptr = vacm_createAccessEntry(access.groupName, access.contextPrefix,
220                                   access.securityModel,
221                                   access.securityLevel);
222     if (!aptr)
223         return;
224
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;
231     line =
232         read_config_read_octet_string(line, (u_char **) & readView, &len);
233     writeView = (char *) aptr->writeView;
234     line =
235         read_config_read_octet_string(line, (u_char **) & writeView, &len);
236     notifyView = (char *) aptr->notifyView;
237     line =
238         read_config_read_octet_string(line, (u_char **) & notifyView,
239                                       &len);
240 }
241
242 /*
243  * vacm_save_group(): saves a group entry to the persistent cache 
244  */
245 void
246 vacm_save_group(struct vacm_groupEntry *group_entry, const char *token,
247                 const char *type)
248 {
249     char            line[4096];
250     char           *cptr;
251
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 */
258
259     cptr =
260         read_config_save_octet_string(cptr,
261                                       (u_char *) group_entry->securityName + 1,
262                                       group_entry->securityName[0] + 1);
263     *cptr++ = ' ';
264     cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName,
265                                          strlen(group_entry->groupName) + 1);
266
267     read_config_store(type, line);
268 }
269
270 void
271 vacm_parse_config_group(const char *token, char *line)
272 {
273     struct vacm_groupEntry group;
274     struct vacm_groupEntry *gptr;
275     char           *securityName = (char *) &group.securityName;
276     char           *groupName;
277     size_t          len;
278
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);
285     line =
286         read_config_read_octet_string(line, (u_char **) & securityName,
287                                       &len);
288
289     gptr = vacm_createGroupEntry(group.securityModel, group.securityName);
290     if (!gptr)
291         return;
292
293     gptr->status = group.status;
294     gptr->storageType = group.storageType;
295     groupName = (char *) gptr->groupName;
296     line =
297         read_config_read_octet_string(line, (u_char **) & groupName, &len);
298 }
299
300 struct vacm_viewEntry *
301 vacm_getViewEntry(const char *viewName,
302                   oid * viewSubtree, size_t viewSubtreeLen, int mode)
303 {
304     struct vacm_viewEntry *vp, *vpret = NULL;
305     char            view[VACMSTRINGLEN];
306     int             found, glen;
307     int count=0;
308
309     glen = (int) strlen(viewName);
310     if (glen < 0 || glen >= VACM_MAX_STRING)
311         return NULL;
312     view[0] = glen;
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;
318             int             oidpos;
319             found = 1;
320
321             if (mode != VACM_MODE_IGNORE_MASK) {  /* check the mask */
322                 for (oidpos = 0;
323                      found && oidpos < (int) vp->viewSubtreeLen - 1;
324                      oidpos++) {
325                     if ((vp->viewMask[maskpos] & mask) != 0) {
326                         if (viewSubtree[oidpos] !=
327                             vp->viewSubtree[oidpos + 1])
328                             found = 0;
329                     }
330                     if (mask == 1) {
331                         mask = 0x80;
332                         maskpos++;
333                     } else
334                         mask >>= 1;
335                 }
336             }
337             if (found) {
338                 /*
339                  * match successful, keep this node if its longer than
340                  * the previous or (equal and lexicographically greater
341                  * than the previous). 
342                  */
343                 count++;
344                 if (mode == VACM_MODE_CHECK_SUBTREE) {
345                     vpret = vp;
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) >
353                                0)) {
354                     vpret = vp;
355                 }
356             }
357         }
358     }
359     DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none"));
360     if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) {
361         return NULL;
362     }
363     return vpret;
364 }
365
366 void
367 vacm_scanViewInit(void)
368 {
369     viewScanPtr = viewList;
370 }
371
372 struct vacm_viewEntry *
373 vacm_scanViewNext(void)
374 {
375     struct vacm_viewEntry *returnval = viewScanPtr;
376     if (viewScanPtr)
377         viewScanPtr = viewScanPtr->next;
378     return returnval;
379 }
380
381 struct vacm_viewEntry *
382 vacm_createViewEntry(const char *viewName,
383                      oid * viewSubtree, size_t viewSubtreeLen)
384 {
385     struct vacm_viewEntry *vp, *lp, *op = NULL;
386     int             cmp, cmp2, glen;
387
388     glen = (int) strlen(viewName);
389     if (glen < 0 || glen >= VACM_MAX_STRING)
390         return NULL;
391     vp = (struct vacm_viewEntry *) calloc(1,
392                                           sizeof(struct vacm_viewEntry));
393     if (vp == NULL)
394         return NULL;
395     vp->reserved =
396         (struct vacm_viewEntry *) calloc(1, sizeof(struct vacm_viewEntry));
397     if (vp->reserved == NULL) {
398         free(vp);
399         return NULL;
400     }
401
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;
407
408     lp = viewList;
409     while (lp) {
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)
414             break;
415         if (cmp > 0)
416             break;
417         op = lp;
418         lp = lp->next;
419     }
420     vp->next = lp;
421     if (op)
422         op->next = vp;
423     else
424         viewList = vp;
425     return vp;
426 }
427
428 void
429 vacm_destroyViewEntry(const char *viewName,
430                       oid * viewSubtree, size_t viewSubtreeLen)
431 {
432     struct vacm_viewEntry *vp, *lastvp = NULL;
433
434     if (viewList && !strcmp(viewList->viewName + 1, viewName)
435         && viewList->viewSubtreeLen == viewSubtreeLen
436         && !memcmp((char *) viewList->viewSubtree, (char *) viewSubtree,
437                    viewSubtreeLen * sizeof(oid))) {
438         vp = viewList;
439         viewList = viewList->next;
440     } else {
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)))
446                 break;
447             lastvp = vp;
448         }
449         if (!vp)
450             return;
451         lastvp->next = vp->next;
452     }
453     if (vp->reserved)
454         free(vp->reserved);
455     free(vp);
456     return;
457 }
458
459 void
460 vacm_destroyAllViewEntries(void)
461 {
462     struct vacm_viewEntry *vp;
463     while ((vp = viewList)) {
464         viewList = vp->next;
465         if (vp->reserved)
466             free(vp->reserved);
467         free(vp);
468     }
469 }
470
471 struct vacm_groupEntry *
472 vacm_getGroupEntry(int securityModel, const char *securityName)
473 {
474     struct vacm_groupEntry *vp;
475     char            secname[VACMSTRINGLEN];
476     int             glen;
477
478     glen = (int) strlen(securityName);
479
480     if (glen < 0 || glen >= VACM_MAX_STRING)
481         return NULL;
482     secname[0] = glen;
483     strcpy(secname + 1, securityName);
484
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))
489             return vp;
490     }
491     return NULL;
492 }
493
494 void
495 vacm_scanGroupInit(void)
496 {
497     groupScanPtr = groupList;
498 }
499
500 struct vacm_groupEntry *
501 vacm_scanGroupNext(void)
502 {
503     struct vacm_groupEntry *returnval = groupScanPtr;
504     if (groupScanPtr)
505         groupScanPtr = groupScanPtr->next;
506     return returnval;
507 }
508
509 struct vacm_groupEntry *
510 vacm_createGroupEntry(int securityModel, const char *securityName)
511 {
512     struct vacm_groupEntry *gp, *lg, *og;
513     int             cmp, glen;
514
515     glen = (int) strlen(securityName);
516     if (glen < 0 || glen >= VACM_MAX_STRING)
517         return NULL;
518     gp = (struct vacm_groupEntry *) calloc(1,
519                                            sizeof(struct vacm_groupEntry));
520     if (gp == NULL)
521         return NULL;
522     gp->reserved =
523         (struct vacm_groupEntry *) calloc(1,
524                                           sizeof(struct vacm_groupEntry));
525     if (gp->reserved == NULL) {
526         free(gp);
527         return NULL;
528     }
529
530     gp->securityModel = securityModel;
531     gp->securityName[0] = glen;
532     strcpy(gp->securityName + 1, securityName);
533
534     lg = groupList;
535     og = NULL;
536     while (lg) {
537         if (lg->securityModel > securityModel)
538             break;
539         if (lg->securityModel == securityModel &&
540             (cmp =
541              memcmp(lg->securityName, gp->securityName, glen + 1)) > 0)
542             break;
543         /*
544          * if (lg->securityModel == securityModel && cmp == 0) abort(); 
545          */
546         og = lg;
547         lg = lg->next;
548     }
549     gp->next = lg;
550     if (og == NULL)
551         groupList = gp;
552     else
553         og->next = gp;
554     return gp;
555 }
556
557 void
558 vacm_destroyGroupEntry(int securityModel, const char *securityName)
559 {
560     struct vacm_groupEntry *vp, *lastvp = NULL;
561
562     if (groupList && groupList->securityModel == securityModel
563         && !strcmp(groupList->securityName + 1, securityName)) {
564         vp = groupList;
565         groupList = groupList->next;
566     } else {
567         for (vp = groupList; vp; vp = vp->next) {
568             if (vp->securityModel == securityModel
569                 && !strcmp(vp->securityName + 1, securityName))
570                 break;
571             lastvp = vp;
572         }
573         if (!vp)
574             return;
575         lastvp->next = vp->next;
576     }
577     if (vp->reserved)
578         free(vp->reserved);
579     free(vp);
580     return;
581 }
582
583 void
584 vacm_destroyAllGroupEntries(void)
585 {
586     struct vacm_groupEntry *gp;
587     while ((gp = groupList)) {
588         groupList = gp->next;
589         if (gp->reserved)
590             free(gp->reserved);
591         free(gp);
592     }
593 }
594
595 struct vacm_accessEntry *
596 vacm_getAccessEntry(const char *groupName,
597                     const char *contextPrefix,
598                     int securityModel, int securityLevel)
599 {
600     struct vacm_accessEntry *vp;
601     char            group[VACMSTRINGLEN];
602     char            context[VACMSTRINGLEN];
603     int             glen, clen;
604
605     glen = (int) strlen(groupName);
606     if (glen < 0 || glen >= VACM_MAX_STRING)
607         return NULL;
608     clen = (int) strlen(contextPrefix);
609     if (clen < 0 || clen >= VACM_MAX_STRING)
610         return NULL;
611
612     group[0] = glen;
613     strcpy(group + 1, groupName);
614     context[0] = clen;
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)
621             &&
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))))
629             return vp;
630     }
631     return NULL;
632 }
633
634 void
635 vacm_scanAccessInit(void)
636 {
637     accessScanPtr = accessList;
638 }
639
640 struct vacm_accessEntry *
641 vacm_scanAccessNext(void)
642 {
643     struct vacm_accessEntry *returnval = accessScanPtr;
644     if (accessScanPtr)
645         accessScanPtr = accessScanPtr->next;
646     return returnval;
647 }
648
649 struct vacm_accessEntry *
650 vacm_createAccessEntry(const char *groupName,
651                        const char *contextPrefix,
652                        int securityModel, int securityLevel)
653 {
654     struct vacm_accessEntry *vp, *lp, *op = NULL;
655     int             cmp, glen, clen;
656
657     glen = (int) strlen(groupName);
658     if (glen < 0 || glen >= VACM_MAX_STRING)
659         return NULL;
660     clen = (int) strlen(contextPrefix);
661     if (clen < 0 || clen >= VACM_MAX_STRING)
662         return NULL;
663     vp = (struct vacm_accessEntry *) calloc(1,
664                                             sizeof(struct
665                                                    vacm_accessEntry));
666     if (vp == NULL)
667         return NULL;
668     vp->reserved =
669         (struct vacm_accessEntry *) calloc(1,
670                                            sizeof(struct
671                                                   vacm_accessEntry));
672     if (vp->reserved == NULL) {
673         free(vp);
674         return NULL;
675     }
676
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);
683
684     lp = accessList;
685     while (lp) {
686         cmp = memcmp(lp->groupName, vp->groupName, glen + 1);
687         if (cmp > 0)
688             break;
689         if (cmp < 0)
690             goto next;
691         cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1);
692         if (cmp > 0)
693             break;
694         if (cmp < 0)
695             goto next;
696         if (lp->securityModel > securityModel)
697             break;
698         if (lp->securityModel < securityModel)
699             goto next;
700         if (lp->securityLevel > securityLevel)
701             break;
702       next:
703         op = lp;
704         lp = lp->next;
705     }
706     vp->next = lp;
707     if (op == NULL)
708         accessList = vp;
709     else
710         op->next = vp;
711     return vp;
712 }
713
714 void
715 vacm_destroyAccessEntry(const char *groupName,
716                         const char *contextPrefix,
717                         int securityModel, int securityLevel)
718 {
719     struct vacm_accessEntry *vp, *lastvp = NULL;
720
721     if (accessList && accessList->securityModel == securityModel
722         && accessList->securityModel == securityModel
723         && !strcmp(accessList->groupName + 1, groupName)
724         && !strcmp(accessList->contextPrefix + 1, contextPrefix)) {
725         vp = accessList;
726         accessList = accessList->next;
727     } else {
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))
733                 break;
734             lastvp = vp;
735         }
736         if (!vp)
737             return;
738         lastvp->next = vp->next;
739     }
740     if (vp->reserved)
741         free(vp->reserved);
742     free(vp);
743     return;
744 }
745
746 void
747 vacm_destroyAllAccessEntries(void)
748 {
749     struct vacm_accessEntry *ap;
750     while ((ap = accessList)) {
751         accessList = ap->next;
752         if (ap->reserved)
753             free(ap->reserved);
754         free(ap);
755     }
756 }
757
758 int
759 store_vacm(int majorID, int minorID, void *serverarg, void *clientarg)
760 {
761     /*
762      * figure out our application name 
763      */
764     char           *appname = (char *) clientarg;
765     if (appname == NULL) {
766         appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
767                                         NETSNMP_DS_LIB_APPTYPE);
768     }
769
770     /*
771      * save the VACM MIB 
772      */
773     vacm_save("vacm", appname);
774     return SNMPERR_SUCCESS;
775 }
776
777 /*
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),
780  * else return 0 
781  */
782 int
783 vacm_is_configured(void)
784 {
785     if (viewList == NULL && accessList == NULL && groupList == NULL) {
786         return 0;
787     }
788     return 1;
789 }
790