1 /* Portions of this file are subject to the following copyright(s).  See
2  * the Net-SNMP's COPYING file for more details and other copyrights
3  * that may apply:
4  */
5 /*
6  * Portions of this file are copyrighted by:
7  * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
8  * Use is subject to license terms specified in the COPYING file
9  * distributed with the Net-SNMP package.
10  *
11  * Portions of this file are copyrighted by:
12  * Copyright (c) 2016 VMware, Inc. All rights reserved.
13  * Use is subject to license terms specified in the COPYING file
14  * distributed with the Net-SNMP package.
15  */
16 
17 /*
18  * vacm.c
19  *
20  * SNMPv3 View-based Access Control Model
21  */
22 
23 #include <net-snmp/net-snmp-config.h>
24 
25 #if HAVE_STDLIB_H
26 #include <stdlib.h>
27 #endif
28 #if HAVE_STRING_H
29 #include <string.h>
30 #else
31 #include <strings.h>
32 #endif
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <sys/types.h>
37 #include <stdio.h>
38 #if TIME_WITH_SYS_TIME
39 # include <sys/time.h>
40 # include <time.h>
41 #else
42 # if HAVE_SYS_TIME_H
43 #  include <sys/time.h>
44 # else
45 #  include <time.h>
46 # endif
47 #endif
48 
49 #if HAVE_NETINET_IN_H
50 #include <netinet/in.h>
51 #endif
52 
53 #include <ctype.h>
54 
55 #include <net-snmp/types.h>
56 #include <net-snmp/output_api.h>
57 #include <net-snmp/config_api.h>
58 
59 #include <net-snmp/library/snmp_api.h>
60 #include <net-snmp/library/system.h> /* strlcpy() */
61 #include <net-snmp/library/tools.h>
62 #include <net-snmp/library/vacm.h>
63 
64 static struct vacm_viewEntry *viewList = NULL, *viewScanPtr = NULL;
65 static struct vacm_accessEntry *accessList = NULL, *accessScanPtr = NULL;
66 static struct vacm_groupEntry *groupList = NULL, *groupScanPtr = NULL;
67 
68 /*
69  * Macro to extend view masks with 1 bits when shorter than subtree lengths
70  * REF: vacmViewTreeFamilyMask [RFC3415], snmpNotifyFilterMask [RFC3413]
71  */
72 
73 #define VIEW_MASK(viewPtr, idx, mask) \
74     ((idx >= viewPtr->viewMaskLen) ? mask : (viewPtr->viewMask[idx] & mask))
75 
76 /**
77  * Initilizes the VACM code.
78  * Specifically:
79  *  - adds a set of enums mapping view numbers to human readable names
80  */
81 void
init_vacm(void)82 init_vacm(void)
83 {
84     /* views for access via get/set/send-notifications */
85     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("read"),
86                          VACM_VIEW_READ);
87     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("write"),
88                          VACM_VIEW_WRITE);
89     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("notify"),
90                          VACM_VIEW_NOTIFY);
91 
92     /* views for permissions when receiving notifications */
93     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("log"),
94                          VACM_VIEW_LOG);
95     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("execute"),
96                          VACM_VIEW_EXECUTE);
97     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("net"),
98                          VACM_VIEW_NET);
99 }
100 
101 void
vacm_save(const char * token,const char * type)102 vacm_save(const char *token, const char *type)
103 {
104     struct vacm_viewEntry *vptr;
105     struct vacm_accessEntry *aptr;
106     struct vacm_groupEntry *gptr;
107     int i;
108 
109     for (vptr = viewList; vptr != NULL; vptr = vptr->next) {
110         if (vptr->viewStorageType == ST_NONVOLATILE)
111             vacm_save_view(vptr, token, type);
112     }
113 
114     for (aptr = accessList; aptr != NULL; aptr = aptr->next) {
115         if (aptr->storageType == ST_NONVOLATILE) {
116             /* Store the standard views (if set) */
117             if ( aptr->views[VACM_VIEW_READ  ][0] ||
118                  aptr->views[VACM_VIEW_WRITE ][0] ||
119                  aptr->views[VACM_VIEW_NOTIFY][0] )
120                 vacm_save_access(aptr, token, type);
121             /* Store any other (valid) access views */
122             for ( i=VACM_VIEW_NOTIFY+1; i<VACM_MAX_VIEWS; i++ ) {
123                 if ( aptr->views[i][0] )
124                     vacm_save_auth_access(aptr, token, type, i);
125             }
126         }
127     }
128 
129     for (gptr = groupList; gptr != NULL; gptr = gptr->next) {
130         if (gptr->storageType == ST_NONVOLATILE)
131             vacm_save_group(gptr, token, type);
132     }
133 }
134 
135 /*
136  * vacm_save_view(): saves a view entry to the persistent cache
137  */
138 void
vacm_save_view(struct vacm_viewEntry * view,const char * token,const char * type)139 vacm_save_view(struct vacm_viewEntry *view, const char *token,
140                const char *type)
141 {
142     char            line[4096];
143     char           *cptr;
144 
145     memset(line, 0, sizeof(line));
146     snprintf(line, sizeof(line), "%s%s %d %d %d ", token, "View",
147             view->viewStatus, view->viewStorageType, view->viewType);
148     line[ sizeof(line)-1 ] = 0;
149     cptr = &line[strlen(line)]; /* the NULL */
150 
151     cptr =
152         read_config_save_octet_string(cptr, (u_char *) view->viewName + 1,
153                                       view->viewName[0]);
154     *cptr++ = ' ';
155     cptr =
156         read_config_save_objid(cptr, view->viewSubtree+1,
157                                      view->viewSubtreeLen-1);
158     *cptr++ = ' ';
159     cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask,
160                                          view->viewMaskLen);
161 
162     read_config_store(type, line);
163 }
164 
165 void
vacm_parse_config_view(const char * token,const char * line)166 vacm_parse_config_view(const char *token, const char *line)
167 {
168     struct vacm_viewEntry view;
169     struct vacm_viewEntry *vptr;
170     char           *viewName = (char *) &view.viewName;
171     oid            *viewSubtree = (oid *) & view.viewSubtree;
172     u_char         *viewMask;
173     size_t          len;
174 
175     view.viewStatus = atoi(line);
176     line = skip_token_const(line);
177     view.viewStorageType = atoi(line);
178     line = skip_token_const(line);
179     view.viewType = atoi(line);
180     line = skip_token_const(line);
181     len = sizeof(view.viewName);
182     line =
183         read_config_read_octet_string(line, (u_char **) & viewName, &len);
184     view.viewSubtreeLen = MAX_OID_LEN + 1;
185     line =
186         read_config_read_objid_const(line, (oid **) & viewSubtree,
187                                &view.viewSubtreeLen);
188 
189     vptr =
190         vacm_createViewEntry(view.viewName, view.viewSubtree,
191                              view.viewSubtreeLen);
192     if (!vptr) {
193         return;
194     }
195 
196     vptr->viewStatus = view.viewStatus;
197     vptr->viewStorageType = view.viewStorageType;
198     vptr->viewType = view.viewType;
199     viewMask = vptr->viewMask;
200     vptr->viewMaskLen = sizeof(vptr->viewMask);
201     line =
202         read_config_read_octet_string(line, &viewMask, &vptr->viewMaskLen);
203 }
204 
205 /*
206  * vacm_save_access(): saves an access entry to the persistent cache
207  */
208 void
vacm_save_access(struct vacm_accessEntry * access_entry,const char * token,const char * type)209 vacm_save_access(struct vacm_accessEntry *access_entry, const char *token,
210                  const char *type)
211 {
212     char            line[4096];
213     char           *cptr;
214 
215     memset(line, 0, sizeof(line));
216     snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
217             token, "Access", access_entry->status,
218             access_entry->storageType, access_entry->securityModel,
219             access_entry->securityLevel, access_entry->contextMatch);
220     line[ sizeof(line)-1 ] = 0;
221     cptr = &line[strlen(line)]; /* the NULL */
222     cptr =
223         read_config_save_octet_string(cptr,
224                                       (u_char *) access_entry->groupName + 1,
225                                       access_entry->groupName[0] + 1);
226     *cptr++ = ' ';
227     cptr =
228         read_config_save_octet_string(cptr,
229                                       (u_char *) access_entry->contextPrefix + 1,
230                                       access_entry->contextPrefix[0] + 1);
231 
232     *cptr++ = ' ';
233     cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_READ],
234                                          strlen(access_entry->views[VACM_VIEW_READ]) + 1);
235     *cptr++ = ' ';
236     cptr =
237         read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_WRITE],
238                                       strlen(access_entry->views[VACM_VIEW_WRITE]) + 1);
239     *cptr++ = ' ';
240     cptr =
241         read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_NOTIFY],
242                                       strlen(access_entry->views[VACM_VIEW_NOTIFY]) + 1);
243 
244     read_config_store(type, line);
245 }
246 
247 void
vacm_save_auth_access(struct vacm_accessEntry * access_entry,const char * token,const char * type,int authtype)248 vacm_save_auth_access(struct vacm_accessEntry *access_entry,
249                       const char *token, const char *type, int authtype)
250 {
251     char            line[4096];
252     char           *cptr;
253 
254     memset(line, 0, sizeof(line));
255     snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
256             token, "AuthAccess", access_entry->status,
257             access_entry->storageType, access_entry->securityModel,
258             access_entry->securityLevel, access_entry->contextMatch);
259     line[ sizeof(line)-1 ] = 0;
260     cptr = &line[strlen(line)]; /* the NULL */
261     cptr =
262         read_config_save_octet_string(cptr,
263                                       (u_char *) access_entry->groupName + 1,
264                                       access_entry->groupName[0] + 1);
265     *cptr++ = ' ';
266     cptr =
267         read_config_save_octet_string(cptr,
268                                       (u_char *) access_entry->contextPrefix + 1,
269                                       access_entry->contextPrefix[0] + 1);
270 
271     snprintf(cptr, sizeof(line)-(cptr-line), " %d ", authtype);
272     while ( *cptr )
273         cptr++;
274 
275     *cptr++ = ' ';
276     cptr = read_config_save_octet_string(cptr,
277                                (u_char *)access_entry->views[authtype],
278                                   strlen(access_entry->views[authtype]) + 1);
279 
280     read_config_store(type, line);
281 }
282 
283 char *
_vacm_parse_config_access_common(struct vacm_accessEntry ** aptr,const char * line)284 _vacm_parse_config_access_common(struct vacm_accessEntry **aptr,
285                                  const char *line)
286 {
287     struct vacm_accessEntry access;
288     char           *cPrefix = (char *) &access.contextPrefix;
289     char           *gName   = (char *) &access.groupName;
290     size_t          len;
291 
292     access.status = atoi(line);
293     line = skip_token_const(line);
294     access.storageType = atoi(line);
295     line = skip_token_const(line);
296     access.securityModel = atoi(line);
297     line = skip_token_const(line);
298     access.securityLevel = atoi(line);
299     line = skip_token_const(line);
300     access.contextMatch = atoi(line);
301     line = skip_token_const(line);
302     len  = sizeof(access.groupName);
303     line = read_config_read_octet_string(line, (u_char **) &gName,   &len);
304     len  = sizeof(access.contextPrefix);
305     line = read_config_read_octet_string(line, (u_char **) &cPrefix, &len);
306 
307     *aptr = vacm_getAccessEntry(access.groupName,
308                                   access.contextPrefix,
309                                   access.securityModel,
310                                   access.securityLevel);
311     if (!*aptr)
312         *aptr = vacm_createAccessEntry(access.groupName,
313                                   access.contextPrefix,
314                                   access.securityModel,
315                                   access.securityLevel);
316     if (!*aptr)
317         return NULL;
318 
319     (*aptr)->status = access.status;
320     (*aptr)->storageType   = access.storageType;
321     (*aptr)->securityModel = access.securityModel;
322     (*aptr)->securityLevel = access.securityLevel;
323     (*aptr)->contextMatch  = access.contextMatch;
324     return NETSNMP_REMOVE_CONST(char *, line);
325 }
326 
327 void
vacm_parse_config_access(const char * token,const char * line)328 vacm_parse_config_access(const char *token, const char *line)
329 {
330     struct vacm_accessEntry *aptr;
331     char           *readView, *writeView, *notifyView;
332     size_t          len;
333 
334     line = _vacm_parse_config_access_common(&aptr, line);
335     if (!line)
336         return;
337 
338     readView = (char *) aptr->views[VACM_VIEW_READ];
339     len = sizeof(aptr->views[VACM_VIEW_READ]);
340     line =
341         read_config_read_octet_string(line, (u_char **) & readView, &len);
342     writeView = (char *) aptr->views[VACM_VIEW_WRITE];
343     len = sizeof(aptr->views[VACM_VIEW_WRITE]);
344     line =
345         read_config_read_octet_string(line, (u_char **) & writeView, &len);
346     notifyView = (char *) aptr->views[VACM_VIEW_NOTIFY];
347     len = sizeof(aptr->views[VACM_VIEW_NOTIFY]);
348     line =
349         read_config_read_octet_string(line, (u_char **) & notifyView,
350                                       &len);
351 }
352 
353 void
vacm_parse_config_auth_access(const char * token,const char * line)354 vacm_parse_config_auth_access(const char *token, const char *line)
355 {
356     struct vacm_accessEntry *aptr;
357     int             authtype;
358     char           *view;
359     size_t          len;
360 
361     line = _vacm_parse_config_access_common(&aptr, line);
362     if (!line)
363         return;
364 
365     authtype = atoi(line);
366     line = skip_token_const(line);
367 
368     view = (char *) aptr->views[authtype];
369     len  = sizeof(aptr->views[authtype]);
370     line = read_config_read_octet_string(line, (u_char **) & view, &len);
371 }
372 
373 /*
374  * vacm_save_group(): saves a group entry to the persistent cache
375  */
376 void
vacm_save_group(struct vacm_groupEntry * group_entry,const char * token,const char * type)377 vacm_save_group(struct vacm_groupEntry *group_entry, const char *token,
378                 const char *type)
379 {
380     char            line[4096];
381     char           *cptr;
382 
383     memset(line, 0, sizeof(line));
384     snprintf(line, sizeof(line), "%s%s %d %d %d ",
385             token, "Group", group_entry->status,
386             group_entry->storageType, group_entry->securityModel);
387     line[ sizeof(line)-1 ] = 0;
388     cptr = &line[strlen(line)]; /* the NULL */
389 
390     cptr =
391         read_config_save_octet_string(cptr,
392                                       (u_char *) group_entry->securityName + 1,
393                                       group_entry->securityName[0] + 1);
394     *cptr++ = ' ';
395     cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName,
396                                          strlen(group_entry->groupName) + 1);
397 
398     read_config_store(type, line);
399 }
400 
401 void
vacm_parse_config_group(const char * token,const char * line)402 vacm_parse_config_group(const char *token, const char *line)
403 {
404     struct vacm_groupEntry group;
405     struct vacm_groupEntry *gptr;
406     char           *securityName = (char *) &group.securityName;
407     char           *groupName;
408     size_t          len;
409 
410     group.status = atoi(line);
411     line = skip_token_const(line);
412     group.storageType = atoi(line);
413     line = skip_token_const(line);
414     group.securityModel = atoi(line);
415     line = skip_token_const(line);
416     len = sizeof(group.securityName);
417     line =
418         read_config_read_octet_string(line, (u_char **) & securityName,
419                                       &len);
420 
421     gptr = vacm_createGroupEntry(group.securityModel, group.securityName);
422     if (!gptr)
423         return;
424 
425     gptr->status = group.status;
426     gptr->storageType = group.storageType;
427     groupName = (char *) gptr->groupName;
428     len = sizeof(group.groupName);
429     line =
430         read_config_read_octet_string(line, (u_char **) & groupName, &len);
431 }
432 
433 struct vacm_viewEntry *
netsnmp_view_get(struct vacm_viewEntry * head,const char * viewName,oid * viewSubtree,size_t viewSubtreeLen,int mode)434 netsnmp_view_get(struct vacm_viewEntry *head, const char *viewName,
435                   oid * viewSubtree, size_t viewSubtreeLen, int mode)
436 {
437     struct vacm_viewEntry *vp, *vpret = NULL;
438     char            view[VACMSTRINGLEN];
439     int             found, glen;
440     int count=0;
441 
442     glen = (int) strlen(viewName);
443     if (glen < 0 || glen > VACM_MAX_STRING)
444         return NULL;
445     view[0] = glen;
446     strlcpy(view + 1, viewName, sizeof(view) - 1);
447     for (vp = head; vp; vp = vp->next) {
448         if (!memcmp(view, vp->viewName, glen + 1)
449             && viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
450             int             mask = 0x80;
451             unsigned int    oidpos, maskpos = 0;
452             found = 1;
453 
454             for (oidpos = 0;
455                  found && oidpos < vp->viewSubtreeLen - 1;
456                  oidpos++) {
457                 if (mode==VACM_MODE_IGNORE_MASK || (VIEW_MASK(vp, maskpos, mask) != 0)) {
458                     if (viewSubtree[oidpos] !=
459                         vp->viewSubtree[oidpos + 1])
460                         found = 0;
461                 }
462                 if (mask == 1) {
463                     mask = 0x80;
464                     maskpos++;
465                 } else
466                     mask >>= 1;
467             }
468 
469             if (found) {
470                 /*
471                  * match successful, keep this node if its longer than
472                  * the previous or (equal and lexicographically greater
473                  * than the previous).
474                  */
475                 count++;
476                 if (mode == VACM_MODE_CHECK_SUBTREE) {
477                     vpret = vp;
478                 } else if (vpret == NULL
479                            || vp->viewSubtreeLen > vpret->viewSubtreeLen
480                            || (vp->viewSubtreeLen == vpret->viewSubtreeLen
481                                && snmp_oid_compare(vp->viewSubtree + 1,
482                                                    vp->viewSubtreeLen - 1,
483                                                    vpret->viewSubtree + 1,
484                                                    vpret->viewSubtreeLen - 1) >
485                                0)) {
486                     vpret = vp;
487                 }
488             }
489         }
490     }
491     DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none"));
492     if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) {
493         return NULL;
494     }
495     return vpret;
496 }
497 
498 /*******************************************************************o-o******
499  * netsnmp_view_exists
500  *
501  * Check to see if a view with the given name exists.
502  *
503  * Parameters:
504  *    viewName           - Name of view to check
505  *
506  * Returns 0 if the view does not exist. Otherwise, it returns the number
507  *         of OID rows for the given name.
508  */
509 int
netsnmp_view_exists(struct vacm_viewEntry * head,const char * viewName)510 netsnmp_view_exists(struct vacm_viewEntry *head, const char *viewName)
511 {
512     struct vacm_viewEntry *vp;
513     char                   view[VACMSTRINGLEN];
514     int                    len, count = 0;
515 
516     len = (int) strlen(viewName);
517     if (len < 0 || len > VACM_MAX_STRING)
518         return 0;
519     view[0] = len;
520     strcpy(view + 1, viewName);
521     DEBUGMSGTL(("9:vacm:view_exists", "checking %s\n", viewName));
522     for (vp = head; vp; vp = vp->next) {
523         if (memcmp(view, vp->viewName, len + 1) == 0)
524             ++count;
525     }
526 
527     return count;
528 }
529 
530 /*******************************************************************o-o******
531  * vacm_checkSubtree
532  *
533  * Check to see if everything within a subtree is in view, not in view,
534  * or possibly both.
535  *
536  * Parameters:
537  *   *viewName           - Name of view to check
538  *   *viewSubtree        - OID of subtree
539  *    viewSubtreeLen     - length of subtree OID
540  *
541  * Returns:
542  *   VACM_SUCCESS          The OID is included in the view.
543  *   VACM_NOTINVIEW        If no entry in the view list includes the
544  *                         provided OID, or the OID is explicitly excluded
545  *                         from the view.
546  *   VACM_SUBTREE_UNKNOWN  The entire subtree has both allowed and disallowed
547  *                         portions.
548  */
549 int
netsnmp_view_subtree_check(struct vacm_viewEntry * head,const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)550 netsnmp_view_subtree_check(struct vacm_viewEntry *head, const char *viewName,
551                            oid * viewSubtree, size_t viewSubtreeLen)
552 {
553     struct vacm_viewEntry *vp, *vpShorter = NULL, *vpLonger = NULL;
554     char            view[VACMSTRINGLEN];
555     int             found, glen;
556 
557     glen = (int) strlen(viewName);
558     if (glen < 0 || glen > VACM_MAX_STRING)
559         return VACM_NOTINVIEW;
560     view[0] = glen;
561     strlcpy(view + 1, viewName, sizeof(view) - 1);
562     DEBUGMSGTL(("9:vacm:checkSubtree", "view %s\n", viewName));
563     for (vp = head; vp; vp = vp->next) {
564         if (!memcmp(view, vp->viewName, glen + 1)) {
565             /*
566              * If the subtree defined in the view is shorter than or equal
567              * to the subtree we are comparing, then it might envelop the
568              * subtree we are comparing against.
569              */
570             if (viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
571                 int             mask = 0x80;
572                 unsigned int    oidpos, maskpos = 0;
573                 found = 1;
574 
575                 /*
576                  * check the mask
577                  */
578                 for (oidpos = 0;
579                      found && oidpos < vp->viewSubtreeLen - 1;
580                      oidpos++) {
581                     if (VIEW_MASK(vp, maskpos, mask) != 0) {
582                         if (viewSubtree[oidpos] !=
583                             vp->viewSubtree[oidpos + 1])
584                             found = 0;
585                     }
586                     if (mask == 1) {
587                         mask = 0x80;
588                         maskpos++;
589                     } else
590                         mask >>= 1;
591                 }
592 
593                 if (found) {
594                     /*
595                      * match successful, keep this node if it's longer than
596                      * the previous or (equal and lexicographically greater
597                      * than the previous).
598                      */
599                     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
600 
601                     if (vpShorter == NULL
602                         || vp->viewSubtreeLen > vpShorter->viewSubtreeLen
603                         || (vp->viewSubtreeLen == vpShorter->viewSubtreeLen
604                            && snmp_oid_compare(vp->viewSubtree + 1,
605                                                vp->viewSubtreeLen - 1,
606                                                vpShorter->viewSubtree + 1,
607                                                vpShorter->viewSubtreeLen - 1) >
608                                    0)) {
609                         vpShorter = vp;
610                     }
611                 }
612             }
613             /*
614              * If the subtree defined in the view is longer than the
615              * subtree we are comparing, then it might ambiguate our
616              * response.
617              */
618             else {
619                 int             mask = 0x80;
620                 unsigned int    oidpos, maskpos = 0;
621                 found = 1;
622 
623                 /*
624                  * check the mask up to the length of the provided subtree
625                  */
626                 for (oidpos = 0;
627                      found && oidpos < viewSubtreeLen;
628                      oidpos++) {
629                     if (VIEW_MASK(vp, maskpos, mask) != 0) {
630                         if (viewSubtree[oidpos] !=
631                             vp->viewSubtree[oidpos + 1])
632                             found = 0;
633                     }
634                     if (mask == 1) {
635                         mask = 0x80;
636                         maskpos++;
637                     } else
638                         mask >>= 1;
639                 }
640 
641                 if (found) {
642                     /*
643                      * match successful.  If we already found a match
644                      * with a different view type, then parts of the subtree
645                      * are included and others are excluded, so return UNKNOWN.
646                      */
647                     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
648                     if (vpLonger != NULL
649                         && (vpLonger->viewType != vp->viewType)) {
650                         DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
651                         return VACM_SUBTREE_UNKNOWN;
652                     }
653                     else if (vpLonger == NULL) {
654                         vpLonger = vp;
655                     }
656                 }
657             }
658         }
659     }
660     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched\n", viewName));
661 
662     /*
663      * If we found a matching view subtree with a longer OID than the provided
664      * OID, check to see if its type is consistent with any matching view
665      * subtree we may have found with a shorter OID than the provided OID.
666      *
667      * The view type of the longer OID is inconsistent with the shorter OID in
668      * either of these two cases:
669      *  1) No matching shorter OID was found and the view type of the longer
670      *     OID is INCLUDE.
671      *  2) A matching shorter ID was found and its view type doesn't match
672      *     the view type of the longer OID.
673      */
674     if (vpLonger != NULL) {
675         if ((!vpShorter && vpLonger->viewType != SNMP_VIEW_EXCLUDED)
676             || (vpShorter && vpLonger->viewType != vpShorter->viewType)) {
677             DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
678             return VACM_SUBTREE_UNKNOWN;
679         }
680     }
681 
682     if (vpShorter && vpShorter->viewType != SNMP_VIEW_EXCLUDED) {
683         DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "included"));
684         return VACM_SUCCESS;
685     }
686 
687     DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "excluded"));
688     return VACM_NOTINVIEW;
689 }
690 
691 void
vacm_scanViewInit(void)692 vacm_scanViewInit(void)
693 {
694     viewScanPtr = viewList;
695 }
696 
697 struct vacm_viewEntry *
vacm_scanViewNext(void)698 vacm_scanViewNext(void)
699 {
700     struct vacm_viewEntry *returnval = viewScanPtr;
701     if (viewScanPtr)
702         viewScanPtr = viewScanPtr->next;
703     return returnval;
704 }
705 
706 struct vacm_viewEntry *
netsnmp_view_create(struct vacm_viewEntry ** head,const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)707 netsnmp_view_create(struct vacm_viewEntry **head, const char *viewName,
708                      oid * viewSubtree, size_t viewSubtreeLen)
709 {
710     struct vacm_viewEntry *vp, *lp, *op = NULL;
711     int             cmp, cmp2, glen;
712 
713     glen = (int) strlen(viewName);
714     if (glen < 0 || glen > VACM_MAX_STRING || viewSubtreeLen > MAX_OID_LEN)
715         return NULL;
716     vp = (struct vacm_viewEntry *) calloc(1,
717                                           sizeof(struct vacm_viewEntry));
718     if (vp == NULL)
719         return NULL;
720     vp->reserved =
721         (struct vacm_viewEntry *) calloc(1, sizeof(struct vacm_viewEntry));
722     if (vp->reserved == NULL) {
723         free(vp);
724         return NULL;
725     }
726 
727     vp->viewName[0] = glen;
728     strlcpy(vp->viewName + 1, viewName, sizeof(vp->viewName) - 1);
729     vp->viewSubtree[0] = viewSubtreeLen;
730     memcpy(vp->viewSubtree + 1, viewSubtree, viewSubtreeLen * sizeof(oid));
731     vp->viewSubtreeLen = viewSubtreeLen + 1;
732 
733     lp = *head;
734     while (lp) {
735         cmp = memcmp(lp->viewName, vp->viewName, glen + 1);
736         cmp2 = snmp_oid_compare(lp->viewSubtree, lp->viewSubtreeLen,
737                                 vp->viewSubtree, vp->viewSubtreeLen);
738         if (cmp == 0 && cmp2 > 0)
739             break;
740         if (cmp > 0)
741             break;
742         op = lp;
743         lp = lp->next;
744     }
745     vp->next = lp;
746     if (op)
747         op->next = vp;
748     else
749         *head = vp;
750     return vp;
751 }
752 
753 void
netsnmp_view_destroy(struct vacm_viewEntry ** head,const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)754 netsnmp_view_destroy(struct vacm_viewEntry **head, const char *viewName,
755                       oid * viewSubtree, size_t viewSubtreeLen)
756 {
757     struct vacm_viewEntry *vp, *lastvp = NULL;
758 
759     if ((*head) && !strcmp((*head)->viewName + 1, viewName)
760         && (*head)->viewSubtreeLen == viewSubtreeLen
761         && !memcmp((char *) (*head)->viewSubtree, (char *) viewSubtree,
762                    viewSubtreeLen * sizeof(oid))) {
763         vp = (*head);
764         (*head) = (*head)->next;
765     } else {
766         for (vp = (*head); vp; vp = vp->next) {
767             if (!strcmp(vp->viewName + 1, viewName)
768                 && vp->viewSubtreeLen == viewSubtreeLen
769                 && !memcmp((char *) vp->viewSubtree, (char *) viewSubtree,
770                            viewSubtreeLen * sizeof(oid)))
771                 break;
772             lastvp = vp;
773         }
774         if (!vp || !lastvp)
775             return;
776         lastvp->next = vp->next;
777     }
778     if (vp->reserved)
779         free(vp->reserved);
780     free(vp);
781     return;
782 }
783 
784 void
netsnmp_view_clear(struct vacm_viewEntry ** head)785 netsnmp_view_clear(struct vacm_viewEntry **head)
786 {
787     struct vacm_viewEntry *vp;
788     while ((vp = (*head))) {
789         (*head) = vp->next;
790         if (vp->reserved)
791             free(vp->reserved);
792         free(vp);
793     }
794 }
795 
796 struct vacm_groupEntry *
vacm_getGroupEntry(int securityModel,const char * securityName)797 vacm_getGroupEntry(int securityModel, const char *securityName)
798 {
799     struct vacm_groupEntry *vp;
800     char            secname[VACMSTRINGLEN];
801     int             glen;
802 
803     glen = (int) strlen(securityName);
804     if (glen < 0 || glen > VACM_MAX_STRING)
805         return NULL;
806     secname[0] = glen;
807     strlcpy(secname + 1, securityName, sizeof(secname) - 1);
808 
809     for (vp = groupList; vp; vp = vp->next) {
810         if ((securityModel == vp->securityModel
811              || vp->securityModel == SNMP_SEC_MODEL_ANY)
812             && !memcmp(vp->securityName, secname, glen + 1))
813             return vp;
814     }
815     return NULL;
816 }
817 
818 void
vacm_scanGroupInit(void)819 vacm_scanGroupInit(void)
820 {
821     groupScanPtr = groupList;
822 }
823 
824 struct vacm_groupEntry *
vacm_scanGroupNext(void)825 vacm_scanGroupNext(void)
826 {
827     struct vacm_groupEntry *returnval = groupScanPtr;
828     if (groupScanPtr)
829         groupScanPtr = groupScanPtr->next;
830     return returnval;
831 }
832 
833 struct vacm_groupEntry *
vacm_createGroupEntry(int securityModel,const char * securityName)834 vacm_createGroupEntry(int securityModel, const char *securityName)
835 {
836     struct vacm_groupEntry *gp, *lg, *og;
837     int             cmp, glen;
838 
839     glen = (int) strlen(securityName);
840     if (glen < 0 || glen > VACM_MAX_STRING)
841         return NULL;
842     gp = (struct vacm_groupEntry *) calloc(1,
843                                            sizeof(struct vacm_groupEntry));
844     if (gp == NULL)
845         return NULL;
846     gp->reserved =
847         (struct vacm_groupEntry *) calloc(1,
848                                           sizeof(struct vacm_groupEntry));
849     if (gp->reserved == NULL) {
850         free(gp);
851         return NULL;
852     }
853 
854     gp->securityModel = securityModel;
855     gp->securityName[0] = glen;
856     strlcpy(gp->securityName + 1, securityName, sizeof(gp->securityName) - 1);
857 
858     lg = groupList;
859     og = NULL;
860     while (lg) {
861         if (lg->securityModel > securityModel)
862             break;
863         if (lg->securityModel == securityModel &&
864             (cmp =
865              memcmp(lg->securityName, gp->securityName, glen + 1)) > 0)
866             break;
867         /*
868          * if (lg->securityModel == securityModel && cmp == 0) abort();
869          */
870         og = lg;
871         lg = lg->next;
872     }
873     gp->next = lg;
874     if (og == NULL)
875         groupList = gp;
876     else
877         og->next = gp;
878     return gp;
879 }
880 
881 void
vacm_destroyGroupEntry(int securityModel,const char * securityName)882 vacm_destroyGroupEntry(int securityModel, const char *securityName)
883 {
884     struct vacm_groupEntry *vp, *lastvp = NULL;
885 
886     if (groupList && groupList->securityModel == securityModel
887         && !strcmp(groupList->securityName + 1, securityName)) {
888         vp = groupList;
889         groupList = groupList->next;
890     } else {
891         for (vp = groupList; vp; vp = vp->next) {
892             if (vp->securityModel == securityModel
893                 && !strcmp(vp->securityName + 1, securityName))
894                 break;
895             lastvp = vp;
896         }
897         if (!vp || !lastvp)
898             return;
899         lastvp->next = vp->next;
900     }
901     if (vp->reserved)
902         free(vp->reserved);
903     free(vp);
904     return;
905 }
906 
907 
908 void
vacm_destroyAllGroupEntries(void)909 vacm_destroyAllGroupEntries(void)
910 {
911     struct vacm_groupEntry *gp;
912     while ((gp = groupList)) {
913         groupList = gp->next;
914         if (gp->reserved)
915             free(gp->reserved);
916         free(gp);
917     }
918 }
919 
920 struct vacm_accessEntry *
_vacm_choose_best(struct vacm_accessEntry * current,struct vacm_accessEntry * candidate)921 _vacm_choose_best( struct vacm_accessEntry *current,
922                    struct vacm_accessEntry *candidate)
923 {
924     /*
925      * RFC 3415: vacmAccessTable:
926      *    2) if this set has [more than] one member, ...
927      *       it comes down to deciding how to weight the
928      *       preferences between ContextPrefixes,
929      *       SecurityModels, and SecurityLevels
930      */
931     if (( !current ) ||
932         /* a) if the subset of entries with securityModel
933          *    matching the securityModel in the message is
934          *    not empty, then discard the rest
935          */
936         (  current->securityModel == SNMP_SEC_MODEL_ANY &&
937          candidate->securityModel != SNMP_SEC_MODEL_ANY ) ||
938         /* b) if the subset of entries with vacmAccessContextPrefix
939          *    matching the contextName in the message is
940          *    not empty, then discard the rest
941          */
942         (  current->contextMatch  == CONTEXT_MATCH_PREFIX &&
943          candidate->contextMatch  == CONTEXT_MATCH_EXACT ) ||
944         /* c) discard all entries with ContextPrefixes shorter
945          *    than the longest one remaining in the set
946          */
947         (  current->contextMatch  == CONTEXT_MATCH_PREFIX &&
948            current->contextPrefix[0] < candidate->contextPrefix[0] ) ||
949         /* d) select the entry with the highest securityLevel
950          */
951         (  current->securityLevel < candidate->securityLevel )) {
952 
953         return candidate;
954     }
955 
956     return current;
957 }
958 
959 struct vacm_accessEntry *
vacm_getAccessEntry(const char * groupName,const char * contextPrefix,int securityModel,int securityLevel)960 vacm_getAccessEntry(const char *groupName,
961                     const char *contextPrefix,
962                     int securityModel, int securityLevel)
963 {
964     struct vacm_accessEntry *vp, *best=NULL;
965     char            group[VACMSTRINGLEN];
966     char            context[VACMSTRINGLEN];
967     int             glen, clen;
968 
969     glen = (int) strlen(groupName);
970     if (glen < 0 || glen > VACM_MAX_STRING)
971         return NULL;
972     clen = (int) strlen(contextPrefix);
973     if (clen < 0 || clen > VACM_MAX_STRING)
974         return NULL;
975 
976     group[0] = glen;
977     strlcpy(group + 1, groupName, sizeof(group) - 1);
978     context[0] = clen;
979     strlcpy(context + 1, contextPrefix, sizeof(context) - 1);
980     for (vp = accessList; vp; vp = vp->next) {
981         if ((securityModel == vp->securityModel
982              || vp->securityModel == SNMP_SEC_MODEL_ANY)
983             && securityLevel >= vp->securityLevel
984             && !memcmp(vp->groupName, group, glen + 1)
985             &&
986             ((vp->contextMatch == CONTEXT_MATCH_EXACT
987               && clen == vp->contextPrefix[0]
988               && (memcmp(vp->contextPrefix, context, clen + 1) == 0))
989              || (vp->contextMatch == CONTEXT_MATCH_PREFIX
990                  && clen >= vp->contextPrefix[0]
991                  && (memcmp(vp->contextPrefix + 1, context + 1,
992                             vp->contextPrefix[0]) == 0))))
993             best = _vacm_choose_best( best, vp );
994     }
995     return best;
996 }
997 
998 void
vacm_scanAccessInit(void)999 vacm_scanAccessInit(void)
1000 {
1001     accessScanPtr = accessList;
1002 }
1003 
1004 struct vacm_accessEntry *
vacm_scanAccessNext(void)1005 vacm_scanAccessNext(void)
1006 {
1007     struct vacm_accessEntry *returnval = accessScanPtr;
1008     if (accessScanPtr)
1009         accessScanPtr = accessScanPtr->next;
1010     return returnval;
1011 }
1012 
1013 struct vacm_accessEntry *
vacm_createAccessEntry(const char * groupName,const char * contextPrefix,int securityModel,int securityLevel)1014 vacm_createAccessEntry(const char *groupName,
1015                        const char *contextPrefix,
1016                        int securityModel, int securityLevel)
1017 {
1018     struct vacm_accessEntry *vp, *lp, *op = NULL;
1019     int             cmp, glen, clen;
1020 
1021     glen = (int) strlen(groupName);
1022     if (glen < 0 || glen > VACM_MAX_STRING)
1023         return NULL;
1024     clen = (int) strlen(contextPrefix);
1025     if (clen < 0 || clen > VACM_MAX_STRING)
1026         return NULL;
1027     vp = (struct vacm_accessEntry *) calloc(1,
1028                                             sizeof(struct
1029                                                    vacm_accessEntry));
1030     if (vp == NULL)
1031         return NULL;
1032     vp->reserved =
1033         (struct vacm_accessEntry *) calloc(1,
1034                                            sizeof(struct
1035                                                   vacm_accessEntry));
1036     if (vp->reserved == NULL) {
1037         free(vp);
1038         return NULL;
1039     }
1040 
1041     vp->securityModel = securityModel;
1042     vp->securityLevel = securityLevel;
1043     vp->groupName[0] = glen;
1044     strlcpy(vp->groupName + 1, groupName, sizeof(vp->groupName) - 1);
1045     vp->contextPrefix[0] = clen;
1046     strlcpy(vp->contextPrefix + 1, contextPrefix,
1047             sizeof(vp->contextPrefix) - 1);
1048 
1049     lp = accessList;
1050     while (lp) {
1051         cmp = memcmp(lp->groupName, vp->groupName, glen + 1);
1052         if (cmp > 0)
1053             break;
1054         if (cmp < 0)
1055             goto next;
1056         cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1);
1057         if (cmp > 0)
1058             break;
1059         if (cmp < 0)
1060             goto next;
1061         if (lp->securityModel > securityModel)
1062             break;
1063         if (lp->securityModel < securityModel)
1064             goto next;
1065         if (lp->securityLevel > securityLevel)
1066             break;
1067       next:
1068         op = lp;
1069         lp = lp->next;
1070     }
1071     vp->next = lp;
1072     if (op == NULL)
1073         accessList = vp;
1074     else
1075         op->next = vp;
1076     return vp;
1077 }
1078 
1079 void
vacm_destroyAccessEntry(const char * groupName,const char * contextPrefix,int securityModel,int securityLevel)1080 vacm_destroyAccessEntry(const char *groupName,
1081                         const char *contextPrefix,
1082                         int securityModel, int securityLevel)
1083 {
1084     struct vacm_accessEntry *vp, *lastvp = NULL;
1085 
1086     if (accessList && accessList->securityModel == securityModel
1087         && accessList->securityLevel == securityLevel
1088         && !strcmp(accessList->groupName + 1, groupName)
1089         && !strcmp(accessList->contextPrefix + 1, contextPrefix)) {
1090         vp = accessList;
1091         accessList = accessList->next;
1092     } else {
1093         for (vp = accessList; vp; vp = vp->next) {
1094             if (vp->securityModel == securityModel
1095                 && vp->securityLevel == securityLevel
1096                 && !strcmp(vp->groupName + 1, groupName)
1097                 && !strcmp(vp->contextPrefix + 1, contextPrefix))
1098                 break;
1099             lastvp = vp;
1100         }
1101         if (!vp || !lastvp)
1102             return;
1103         lastvp->next = vp->next;
1104     }
1105     if (vp->reserved)
1106         free(vp->reserved);
1107     free(vp);
1108     return;
1109 }
1110 
1111 void
vacm_destroyAllAccessEntries(void)1112 vacm_destroyAllAccessEntries(void)
1113 {
1114     struct vacm_accessEntry *ap;
1115     while ((ap = accessList)) {
1116         accessList = ap->next;
1117         if (ap->reserved)
1118             free(ap->reserved);
1119         free(ap);
1120     }
1121 }
1122 
1123 int
store_vacm(int majorID,int minorID,void * serverarg,void * clientarg)1124 store_vacm(int majorID, int minorID, void *serverarg, void *clientarg)
1125 {
1126     /*
1127      * figure out our application name
1128      */
1129     char           *appname = (char *) clientarg;
1130     if (appname == NULL) {
1131         appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1132 					NETSNMP_DS_LIB_APPTYPE);
1133     }
1134 
1135     /*
1136      * save the VACM MIB
1137      */
1138     vacm_save("vacm", appname);
1139     return SNMPERR_SUCCESS;
1140 }
1141 
1142 /*
1143  * returns 1 if vacm has *any* (non-built-in) configuration entries,
1144  * regardless of whether or not there is enough to make a decision,
1145  * else return 0
1146  */
1147 int
vacm_is_configured(void)1148 vacm_is_configured(void)
1149 {
1150     if (accessList == NULL && groupList == NULL) {
1151         return 0;
1152     }
1153     return 1;
1154 }
1155 
1156 /*
1157  * backwards compatability
1158  */
1159 struct vacm_viewEntry *
vacm_getViewEntry(const char * viewName,oid * viewSubtree,size_t viewSubtreeLen,int mode)1160 vacm_getViewEntry(const char *viewName,
1161                   oid * viewSubtree, size_t viewSubtreeLen, int mode)
1162 {
1163     return netsnmp_view_get( viewList, viewName, viewSubtree, viewSubtreeLen,
1164                              mode);
1165 }
1166 
1167 int
vacm_checkSubtree(const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)1168 vacm_checkSubtree(const char *viewName,
1169                   oid * viewSubtree, size_t viewSubtreeLen)
1170 {
1171     return netsnmp_view_subtree_check( viewList, viewName, viewSubtree,
1172                                        viewSubtreeLen);
1173 }
1174 
1175 struct vacm_viewEntry *
vacm_createViewEntry(const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)1176 vacm_createViewEntry(const char *viewName,
1177                      oid * viewSubtree, size_t viewSubtreeLen)
1178 {
1179     return netsnmp_view_create( &viewList, viewName, viewSubtree,
1180                                 viewSubtreeLen);
1181 }
1182 
1183 void
vacm_destroyViewEntry(const char * viewName,oid * viewSubtree,size_t viewSubtreeLen)1184 vacm_destroyViewEntry(const char *viewName,
1185                       oid * viewSubtree, size_t viewSubtreeLen)
1186 {
1187     netsnmp_view_destroy( &viewList, viewName, viewSubtree, viewSubtreeLen);
1188 }
1189 
1190 void
vacm_destroyAllViewEntries(void)1191 vacm_destroyAllViewEntries(void)
1192 {
1193     netsnmp_view_clear( &viewList );
1194 }
1195 
1196 /*
1197  * vacm simple api
1198  */
1199 
1200 int
netsnmp_vacm_simple_usm_add(const char * user,int rw,int authLevel,const char * view,oid * oidView,size_t oidViewLen,const char * context)1201 netsnmp_vacm_simple_usm_add(const char *user, int rw, int authLevel,
1202                             const char *view, oid *oidView, size_t oidViewLen,
1203                             const char *context)
1204 {
1205     struct vacm_viewEntry   *vacmEntry = NULL;
1206     struct vacm_groupEntry  *groupEntry = NULL;
1207     struct vacm_accessEntry *accessEntry = NULL;
1208     char                    *tmp, localContext[VACMSTRINGLEN];
1209     int                      exact = 1;  /* exact context match */
1210 
1211     if (NULL == user)
1212         return SNMPERR_GENERR;
1213 
1214     if (authLevel < SNMP_SEC_LEVEL_NOAUTH ||
1215         authLevel > SNMP_SEC_LEVEL_AUTHPRIV)
1216         return SNMPERR_GENERR;
1217 
1218     if (NULL != view) {
1219         /*
1220          * if we are given a view name, it is an error if
1221          *   - it exists and we have an oid
1222          *   - it doesn't exist and we don't have an oid
1223          */
1224         if (netsnmp_view_exists(viewList, view) != 0) {
1225             if (NULL != oidView || oidViewLen > 0) {
1226                 DEBUGMSGTL(("vacm:simple_usm", "can't modify existing view"));
1227                 return SNMPERR_GENERR;
1228             }
1229         } else {
1230             if (NULL == oidView || oidViewLen == 0) {
1231                 DEBUGMSGTL(("vacm:simple_usm", "can't create view w/out oid"));
1232                 return SNMPERR_GENERR;
1233             }
1234             /** try and create view for oid */
1235             vacmEntry = vacm_createViewEntry(view, oidView, oidViewLen);
1236             if (NULL == vacmEntry) {
1237                 DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
1238                 return SNMPERR_GENERR;
1239             }
1240             SNMP_FREE(vacmEntry->reserved);
1241         }
1242     } else if (0 == oidViewLen || NULL == oidView) {
1243         view = "_all_"; /* no oid either, just use _all_ */
1244     } else {
1245         DEBUGMSGTL(("vacm:simple_usm", "need view name for new views"));
1246         return SNMPERR_GENERR;
1247     }
1248 
1249     /*
1250      * group
1251      * grpv3user usm \"v3user\"\000prefix\000_all_\000_all_\000_all_\000\060"
1252      * vacm_createGroupEntry() also automatically inserts into group list.
1253      */
1254     groupEntry = vacm_createGroupEntry(SNMP_SEC_MODEL_USM, user);
1255     if (NULL == groupEntry) {
1256         DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
1257         goto bail;
1258     }
1259     snprintf(groupEntry->groupName, sizeof(groupEntry->groupName)-2,
1260              "grp%.28s", user);
1261     for (tmp=groupEntry->groupName; *tmp; tmp++)
1262         if (!isalnum((unsigned char)(*tmp)))
1263             *tmp = '_';
1264     groupEntry->storageType = SNMP_STORAGE_PERMANENT;
1265     groupEntry->status = SNMP_ROW_ACTIVE;
1266     SNMP_FREE(groupEntry->reserved);
1267 
1268     /*
1269      * access
1270      * grpv3user myctx usm noauth exact _all_ none none
1271      */
1272     if (NULL == context) {
1273         localContext[0] = 0;
1274         context = localContext;
1275     } else {
1276         /** check for wildcard in context */
1277         int contextLen = strlen(context);
1278         if ('*' == context[contextLen - 1]) {
1279             strlcpy(localContext, context, sizeof(localContext));
1280             localContext[contextLen - 1] = 0;
1281             context = localContext;
1282             exact = 2; /* not exact, have context prefix */
1283         }
1284     }
1285     accessEntry = vacm_createAccessEntry(groupEntry->groupName, context,
1286                                          SNMP_SEC_MODEL_USM, authLevel);
1287     if (NULL == accessEntry) {
1288         DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed"));
1289         goto bail;
1290     }
1291     strlcpy(accessEntry->views[VACM_VIEW_READ], view,
1292             sizeof(accessEntry->views[VACM_VIEW_READ]));
1293     if (0 == rw)
1294         view = "none";
1295     strlcpy(accessEntry->views[VACM_VIEW_WRITE], view,
1296             sizeof(accessEntry->views[VACM_VIEW_WRITE]));
1297     strlcpy(accessEntry->views[VACM_VIEW_NOTIFY], view,
1298             sizeof(accessEntry->views[VACM_VIEW_NOTIFY]));
1299 
1300     accessEntry->contextMatch = exact;
1301     accessEntry->storageType = SNMP_STORAGE_PERMANENT;
1302     accessEntry->status = SNMP_ROW_ACTIVE;
1303     SNMP_FREE(accessEntry->reserved);
1304 
1305     return SNMPERR_SUCCESS;
1306 
1307 bail:
1308     if (NULL != groupEntry)
1309         vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user);
1310 
1311     if (NULL != vacmEntry)
1312         vacm_destroyViewEntry(vacmEntry->viewName+1, vacmEntry->viewSubtree,
1313                               vacmEntry->viewSubtreeLen);
1314 
1315     return SNMPERR_GENERR;
1316 }
1317 
1318 int
netsnmp_vacm_simple_usm_del(const char * user,int authLevel,const char * view,oid * oidView,size_t oidViewLen,const char * context)1319 netsnmp_vacm_simple_usm_del(const char *user, int authLevel,
1320                             const char *view, oid *oidView, size_t oidViewLen,
1321                             const char *context)
1322 {
1323     char                     localContext[VACMSTRINGLEN];
1324     char                     group[VACMSTRINGLEN];
1325 
1326     /*
1327      * only delete simple views (one OID) for which we have an OID.
1328      * never delete '_all_'.
1329      */
1330     if ((NULL != view) && (NULL != oidView) && (oidViewLen > 0) &&
1331         (strcmp(view, "_all_") != 0) &&
1332         (netsnmp_view_exists(viewList, view) == 1)) {
1333         vacm_destroyViewEntry(view, oidView, oidViewLen);
1334     }
1335 
1336     vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user);
1337 
1338     snprintf(group, sizeof(group)-2, "grp%.28s", user);
1339     if (NULL == context) {
1340         localContext[0] = 0;
1341         context = localContext;
1342     } else {
1343         /** check for wildcard in context */
1344         int contextLen = strlen(context);
1345         if ('*' == context[contextLen - 1]) {
1346             strlcpy(localContext, context, sizeof(localContext));
1347             localContext[contextLen - 1] = 0;
1348             context = localContext;
1349         }
1350     }
1351 
1352     vacm_destroyAccessEntry(group, context, SNMP_SEC_MODEL_USM, authLevel);
1353 
1354     return SNMPERR_SUCCESS;
1355 }
1356