1 /*
2  * SNMPv3 View-based Access Control Model
3  */
4 /* Portions of this file are subject to the following copyright(s).  See
5  * the Net-SNMP's COPYING file for more details and other copyrights
6  * that may apply:
7  */
8 /*
9  * Portions of this file are copyrighted by:
10  * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
11  * Use is subject to license terms specified in the COPYING file
12  * distributed with the Net-SNMP package.
13  *
14  * Portions of this file are copyrighted by:
15  * Copyright (c) 2016 VMware, Inc. All rights reserved.
16  * Use is subject to license terms specified in the COPYING file
17  * distributed with the Net-SNMP package.
18  */
19 
20 #include <net-snmp/net-snmp-config.h>
21 
22 #if HAVE_STDLIB_H
23 #include <stdlib.h>
24 #endif
25 #if HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #if HAVE_STRING_H
29 #include <string.h>
30 #else
31 #include <strings.h>
32 #endif
33 #if HAVE_MALLOC_H
34 #include <malloc.h>
35 #endif
36 #include <ctype.h>
37 #include <sys/types.h>
38 #if HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41 #if HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif
44 
45 #if HAVE_NETDB_H
46 #include <netdb.h>
47 #endif
48 
49 #include <net-snmp/net-snmp-includes.h>
50 #include <net-snmp/agent/net-snmp-agent-includes.h>
51 
52 #include <net-snmp/agent/agent_callbacks.h>
53 #include "vacm_conf.h"
54 
55 #include "snmpd.h"
56 
57 /**
58  * Registers the VACM token handlers for inserting rows into the vacm tables.
59  * These tokens will be recognised by both 'snmpd' and 'snmptrapd'.
60  */
61 void
init_vacm_config_tokens(void)62 init_vacm_config_tokens(void) {
63     snmpd_register_config_handler("group", vacm_parse_group,
64                                   vacm_free_group,
65                                   "name v1|v2c|usm|... security");
66     snmpd_register_config_handler("access", vacm_parse_access,
67                                   vacm_free_access,
68                                   "name context model level prefix read write notify");
69     snmpd_register_config_handler("setaccess", vacm_parse_setaccess,
70                                   vacm_free_access,
71                                   "name context model level prefix viewname viewval");
72     snmpd_register_config_handler("view", vacm_parse_view, vacm_free_view,
73                                   "name type subtree [mask]");
74     snmpd_register_const_config_handler("vacmView",
75                                         vacm_parse_config_view, NULL, NULL);
76     snmpd_register_const_config_handler("vacmGroup",
77                                         vacm_parse_config_group,
78                                         NULL, NULL);
79     snmpd_register_const_config_handler("vacmAccess",
80                                         vacm_parse_config_access,
81                                         NULL, NULL);
82     snmpd_register_const_config_handler("vacmAuthAccess",
83                                         vacm_parse_config_auth_access,
84                                         NULL, NULL);
85 
86     /* easy community auth handler */
87     snmpd_register_config_handler("authcommunity",
88                                   vacm_parse_authcommunity,
89                                   NULL, "authtype1,authtype2 community [default|hostname|network/bits [oid|-V view [context]]]");
90 
91     /* easy user auth handler */
92     snmpd_register_config_handler("authuser",
93                                   vacm_parse_authuser,
94                                   NULL, "authtype1,authtype2 [-s secmodel] user [noauth|auth|priv [oid|-V view [context]]]");
95     /* easy group auth handler */
96     snmpd_register_config_handler("authgroup",
97                                   vacm_parse_authuser,
98                                   NULL, "authtype1,authtype2 [-s secmodel] group [noauth|auth|priv [oid|-V view [context]]]");
99 
100     snmpd_register_config_handler("authaccess", vacm_parse_authaccess,
101                                   vacm_free_access,
102                                   "name authtype1,authtype2 [-s secmodel] group view [noauth|auth|priv [context|context*]]");
103 
104     /*
105      * Define standard views "_all_" and "_none_"
106      */
107     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
108                            SNMP_CALLBACK_PRE_READ_CONFIG,
109                            vacm_standard_views, NULL);
110     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
111                            SNMP_CALLBACK_POST_READ_CONFIG,
112                            vacm_warn_if_not_configured, NULL);
113 }
114 
115 /**
116  * Registers the easier-to-use VACM token handlers for quick access rules.
117  * These tokens will only be recognised by 'snmpd'.
118  */
119 void
init_vacm_snmpd_easy_tokens(void)120 init_vacm_snmpd_easy_tokens(void) {
121 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
122     snmpd_register_config_handler("rwcommunity", vacm_parse_rwcommunity, NULL,
123                                   "community [default|hostname|network/bits [oid|-V view [context]]]");
124     snmpd_register_config_handler("rocommunity", vacm_parse_rocommunity, NULL,
125                                   "community [default|hostname|network/bits [oid|-V view [context]]]");
126 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
127     snmpd_register_config_handler("rwcommunity6", vacm_parse_rwcommunity6, NULL,
128                                   "community [default|hostname|network/bits [oid|-V view [context]]]");
129     snmpd_register_config_handler("rocommunity6", vacm_parse_rocommunity6, NULL,
130                                   "community [default|hostname|network/bits [oid|-V view [context]]]");
131 #endif
132 #endif /* support for community based SNMP */
133     snmpd_register_config_handler("rwuser", vacm_parse_rwuser, NULL,
134                                   "user [noauth|auth|priv [oid|-V view [context]]]");
135     snmpd_register_config_handler("rouser", vacm_parse_rouser, NULL,
136                                   "user [noauth|auth|priv [oid|-V view [context]]]");
137 }
138 
139 void
init_vacm_conf(void)140 init_vacm_conf(void)
141 {
142     init_vacm_config_tokens();
143     init_vacm_snmpd_easy_tokens();
144     /*
145      * register ourselves to handle access control  ('snmpd' only)
146      */
147     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
148                            SNMPD_CALLBACK_ACM_CHECK, vacm_in_view_callback,
149                            NULL);
150     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
151                            SNMPD_CALLBACK_ACM_CHECK_INITIAL,
152                            vacm_in_view_callback, NULL);
153     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
154                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE,
155                            vacm_in_view_callback, NULL);
156 }
157 
158 
159 
160 void
vacm_parse_group(const char * token,char * param)161 vacm_parse_group(const char *token, char *param)
162 {
163     char            group[VACMSTRINGLEN], model[VACMSTRINGLEN], security[VACMSTRINGLEN];
164     int             imodel;
165     struct vacm_groupEntry *gp = NULL;
166     char           *st;
167 
168     st = copy_nword(param, group, sizeof(group)-1);
169     st = copy_nword(st, model, sizeof(model)-1);
170     st = copy_nword(st, security, sizeof(security)-1);
171 
172     if (group[0] == 0) {
173         config_perror("missing GROUP parameter");
174         return;
175     }
176     if (model[0] == 0) {
177         config_perror("missing MODEL parameter");
178         return;
179     }
180     if (security[0] == 0) {
181         config_perror("missing SECURITY parameter");
182         return;
183     }
184     if (strcasecmp(model, "v1") == 0)
185         imodel = SNMP_SEC_MODEL_SNMPv1;
186     else if (strcasecmp(model, "v2c") == 0)
187         imodel = SNMP_SEC_MODEL_SNMPv2c;
188     else if (strcasecmp(model, "any") == 0) {
189         config_perror
190             ("bad security model \"any\" should be: v1, v2c, usm or a registered security plugin name - installing anyway");
191         imodel = SNMP_SEC_MODEL_ANY;
192     } else {
193         if ((imodel = se_find_value_in_slist("snmp_secmods", model)) ==
194             SE_DNE) {
195             config_perror
196                 ("bad security model, should be: v1, v2c or usm or a registered security plugin name");
197             return;
198         }
199     }
200     if (strlen(security) + 1 > sizeof(gp->groupName)) {
201         config_perror("security name too long");
202         return;
203     }
204     gp = vacm_createGroupEntry(imodel, security);
205     if (!gp) {
206         config_perror("failed to create group entry");
207         return;
208     }
209     strlcpy(gp->groupName, group, sizeof(gp->groupName));
210     gp->storageType = SNMP_STORAGE_PERMANENT;
211     gp->status = SNMP_ROW_ACTIVE;
212     free(gp->reserved);
213     gp->reserved = NULL;
214 }
215 
216 void
vacm_free_group(void)217 vacm_free_group(void)
218 {
219     vacm_destroyAllGroupEntries();
220 }
221 
222 #define PARSE_CONT 0
223 #define PARSE_FAIL 1
224 
225 int
_vacm_parse_access_common(const char * token,char * param,char ** st,char ** name,char ** context,int * imodel,int * ilevel,int * iprefix)226 _vacm_parse_access_common(const char *token, char *param, char **st,
227                           char **name, char **context, int *imodel,
228                           int *ilevel, int *iprefix)
229 {
230     char *model, *level, *prefix;
231 
232     *name = strtok_r(param, " \t\n", st);
233     if (!*name) {
234         config_perror("missing NAME parameter");
235         return PARSE_FAIL;
236     }
237     *context = strtok_r(NULL, " \t\n", st);
238     if (!*context) {
239         config_perror("missing CONTEXT parameter");
240         return PARSE_FAIL;
241     }
242 
243     model = strtok_r(NULL, " \t\n", st);
244     if (!model) {
245         config_perror("missing MODEL parameter");
246         return PARSE_FAIL;
247     }
248     level = strtok_r(NULL, " \t\n", st);
249     if (!level) {
250         config_perror("missing LEVEL parameter");
251         return PARSE_FAIL;
252     }
253     prefix = strtok_r(NULL, " \t\n", st);
254     if (!prefix) {
255         config_perror("missing PREFIX parameter");
256         return PARSE_FAIL;
257     }
258 
259     if (strcmp(*context, "\"\"") == 0 || strcmp(*context, "\'\'") == 0)
260         **context = 0;
261     if (strcasecmp(model, "any") == 0)
262         *imodel = SNMP_SEC_MODEL_ANY;
263     else if (strcasecmp(model, "v1") == 0)
264         *imodel = SNMP_SEC_MODEL_SNMPv1;
265     else if (strcasecmp(model, "v2c") == 0)
266         *imodel = SNMP_SEC_MODEL_SNMPv2c;
267     else {
268         if ((*imodel = se_find_value_in_slist("snmp_secmods", model))
269             == SE_DNE) {
270             config_perror
271                 ("bad security model, should be: v1, v2c or usm or a registered security plugin name");
272             return PARSE_FAIL;
273         }
274     }
275 
276     if (strcasecmp(level, "noauth") == 0)
277         *ilevel = SNMP_SEC_LEVEL_NOAUTH;
278     else if (strcasecmp(level, "noauthnopriv") == 0)
279         *ilevel = SNMP_SEC_LEVEL_NOAUTH;
280     else if (strcasecmp(level, "auth") == 0)
281         *ilevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
282     else if (strcasecmp(level, "authnopriv") == 0)
283         *ilevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
284     else if (strcasecmp(level, "priv") == 0)
285         *ilevel = SNMP_SEC_LEVEL_AUTHPRIV;
286     else if (strcasecmp(level, "authpriv") == 0)
287         *ilevel = SNMP_SEC_LEVEL_AUTHPRIV;
288     else {
289         config_perror
290             ("bad security level (noauthnopriv, authnopriv, authpriv)");
291         return PARSE_FAIL;
292     }
293 
294     if (strcmp(prefix, "exact") == 0)
295         *iprefix = 1;
296     else if (strcmp(prefix, "prefix") == 0)
297         *iprefix = 2;
298     else if (strcmp(prefix, "0") == 0) {
299         config_perror
300             ("bad prefix match parameter \"0\", should be: exact or prefix - installing anyway");
301         *iprefix = 1;
302     } else {
303         config_perror
304             ("bad prefix match parameter, should be: exact or prefix");
305         return PARSE_FAIL;
306     }
307 
308     return PARSE_CONT;
309 }
310 
311 /* **************************************/
312 /* authorization parsing token handlers */
313 /* **************************************/
314 
315 int
vacm_parse_authtokens(const char * token,char ** confline)316 vacm_parse_authtokens(const char *token, char **confline)
317 {
318     char authspec[SNMP_MAXBUF_MEDIUM];
319     char *strtok_state;
320     char *type;
321     int viewtype, viewtypes = 0;
322 
323     *confline = copy_nword(*confline, authspec, sizeof(authspec));
324 
325     DEBUGMSGTL(("vacm_parse_authtokens","parsing %s",authspec));
326     if (!*confline) {
327         config_perror("Illegal configuration line: missing fields");
328         return -1;
329     }
330 
331     type = strtok_r(authspec, ",|:", &strtok_state);
332     while(type && *type != '\0') {
333         viewtype = se_find_value_in_slist(VACM_VIEW_ENUM_NAME, type);
334         if (viewtype < 0 || viewtype >= VACM_MAX_VIEWS) {
335             config_perror("Illegal view name");
336         } else {
337             viewtypes |= (1 << viewtype);
338         }
339         type = strtok_r(NULL, ",|:", &strtok_state);
340     }
341     DEBUGMSG(("vacm_parse_authtokens","  .. result = 0x%x\n",viewtypes));
342     return viewtypes;
343 }
344 
345 void
vacm_parse_authuser(const char * token,char * confline)346 vacm_parse_authuser(const char *token, char *confline)
347 {
348     int viewtypes = vacm_parse_authtokens(token, &confline);
349     if (viewtypes != -1)
350         vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_V3, viewtypes);
351 }
352 
353 void
vacm_parse_authcommunity(const char * token,char * confline)354 vacm_parse_authcommunity(const char *token, char *confline)
355 {
356     int viewtypes = vacm_parse_authtokens(token, &confline);
357     if (viewtypes != -1)
358         vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_COM, viewtypes);
359 }
360 
361 void
vacm_parse_authaccess(const char * token,char * confline)362 vacm_parse_authaccess(const char *token, char *confline)
363 {
364     char *group, *view, *tmp;
365     const char *context;
366     int  model = SNMP_SEC_MODEL_ANY;
367     int  level, prefix;
368     int  i;
369     char   *st;
370     struct vacm_accessEntry *ap;
371     int  viewtypes = vacm_parse_authtokens(token, &confline);
372 
373     if (viewtypes == -1)
374         return;
375 
376     group = strtok_r(confline, " \t\n", &st);
377     if (!group) {
378         config_perror("missing GROUP parameter");
379         return;
380     }
381     view = strtok_r(NULL, " \t\n", &st);
382     if (!view) {
383         config_perror("missing VIEW parameter");
384         return;
385     }
386 
387     /*
388      * Check for security model option
389      */
390     if ( strcasecmp(view, "-s") == 0 ) {
391         tmp = strtok_r(NULL, " \t\n", &st);
392         if (tmp) {
393             if (strcasecmp(tmp, "any") == 0)
394                 model = SNMP_SEC_MODEL_ANY;
395             else if (strcasecmp(tmp, "v1") == 0)
396                 model = SNMP_SEC_MODEL_SNMPv1;
397             else if (strcasecmp(tmp, "v2c") == 0)
398                 model = SNMP_SEC_MODEL_SNMPv2c;
399             else {
400                 model = se_find_value_in_slist("snmp_secmods", tmp);
401                 if (model == SE_DNE) {
402                     config_perror
403                         ("bad security model, should be: v1, v2c or usm or a registered security plugin name");
404                     return;
405                 }
406             }
407         } else {
408             config_perror("missing SECMODEL parameter");
409             return;
410         }
411         view = strtok_r(NULL, " \t\n", &st);
412         if (!view) {
413             config_perror("missing VIEW parameter");
414             return;
415         }
416     }
417     if (strlen(view) >= VACMSTRINGLEN ) {
418         config_perror("View value too long");
419         return;
420     }
421 
422     /*
423      * Now parse optional fields, or provide default values
424      */
425 
426     tmp = strtok_r(NULL, " \t\n", &st);
427     if (tmp) {
428         if (strcasecmp(tmp, "noauth") == 0)
429             level = SNMP_SEC_LEVEL_NOAUTH;
430         else if (strcasecmp(tmp, "noauthnopriv") == 0)
431             level = SNMP_SEC_LEVEL_NOAUTH;
432         else if (strcasecmp(tmp, "auth") == 0)
433             level = SNMP_SEC_LEVEL_AUTHNOPRIV;
434         else if (strcasecmp(tmp, "authnopriv") == 0)
435             level = SNMP_SEC_LEVEL_AUTHNOPRIV;
436         else if (strcasecmp(tmp, "priv") == 0)
437             level = SNMP_SEC_LEVEL_AUTHPRIV;
438         else if (strcasecmp(tmp, "authpriv") == 0)
439             level = SNMP_SEC_LEVEL_AUTHPRIV;
440         else {
441             config_perror
442                 ("bad security level (noauthnopriv, authnopriv, authpriv)");
443                 return;
444         }
445     } else {
446         /*  What about  SNMP_SEC_MODEL_ANY ?? */
447         if ( model == SNMP_SEC_MODEL_SNMPv1 ||
448              model == SNMP_SEC_MODEL_SNMPv2c )
449             level = SNMP_SEC_LEVEL_NOAUTH;
450         else
451             level = SNMP_SEC_LEVEL_AUTHNOPRIV;
452     }
453 
454 
455     context = tmp = strtok_r(NULL, " \t\n", &st);
456     if (tmp) {
457         tmp = (tmp + strlen(tmp)-1);
458         if (tmp && *tmp == '*') {
459             *tmp = '\0';
460             prefix = 2;
461         } else {
462             prefix = 1;
463         }
464     } else {
465         context = "";
466         prefix  = 1;   /* Or prefix(2) ?? */
467     }
468 
469     /*
470      * Now we can create the access entry
471      */
472     ap = vacm_getAccessEntry(group, context, model, level);
473     if (!ap) {
474         ap = vacm_createAccessEntry(group, context, model, level);
475         DEBUGMSGTL(("vacm:conf:authaccess",
476                     "no existing access found; creating a new one\n"));
477     } else {
478         DEBUGMSGTL(("vacm:conf:authaccess",
479                     "existing access found, using it\n"));
480     }
481     if (!ap) {
482         config_perror("failed to create access entry");
483         return;
484     }
485 
486     for (i = 0; i < VACM_MAX_VIEWS; i++) {
487         if (viewtypes & (1 << i)) {
488             strlcpy(ap->views[i], view, sizeof(ap->views[i]));
489         }
490     }
491     ap->contextMatch = prefix;
492     ap->storageType  = SNMP_STORAGE_PERMANENT;
493     ap->status       = SNMP_ROW_ACTIVE;
494     if (ap->reserved)
495         free(ap->reserved);
496     ap->reserved = NULL;
497 }
498 
499 void
vacm_parse_setaccess(const char * token,char * param)500 vacm_parse_setaccess(const char *token, char *param)
501 {
502     char *name, *context, *viewname, *viewval;
503     int  imodel, ilevel, iprefix;
504     int  viewnum;
505     char   *st;
506     struct vacm_accessEntry *ap;
507 
508     if (_vacm_parse_access_common(token, param, &st, &name,
509                                   &context, &imodel, &ilevel, &iprefix)
510         == PARSE_FAIL) {
511         return;
512     }
513 
514     viewname = strtok_r(NULL, " \t\n", &st);
515     if (!viewname) {
516         config_perror("missing viewname parameter");
517         return;
518     }
519     viewval = strtok_r(NULL, " \t\n", &st);
520     if (!viewval) {
521         config_perror("missing viewval parameter");
522         return;
523     }
524 
525     if (strlen(viewval) + 1 > sizeof(ap->views[VACM_VIEW_NOTIFY])) {
526         config_perror("View value too long");
527         return;
528     }
529 
530     viewnum = se_find_value_in_slist(VACM_VIEW_ENUM_NAME, viewname);
531     if (viewnum < 0 || viewnum >= VACM_MAX_VIEWS) {
532         config_perror("Illegal view name");
533         return;
534     }
535 
536     ap = vacm_getAccessEntry(name, context, imodel, ilevel);
537     if (!ap) {
538         ap = vacm_createAccessEntry(name, context, imodel, ilevel);
539         DEBUGMSGTL(("vacm:conf:setaccess",
540                     "no existing access found; creating a new one\n"));
541     } else {
542         DEBUGMSGTL(("vacm:conf:setaccess",
543                     "existing access found, using it\n"));
544     }
545     if (!ap) {
546         config_perror("failed to create access entry");
547         return;
548     }
549 
550     strlcpy(ap->views[viewnum], viewval, sizeof(ap->views[viewnum]));
551     ap->contextMatch = iprefix;
552     ap->storageType = SNMP_STORAGE_PERMANENT;
553     ap->status = SNMP_ROW_ACTIVE;
554     free(ap->reserved);
555     ap->reserved = NULL;
556 }
557 
558 void
vacm_parse_access(const char * token,char * param)559 vacm_parse_access(const char *token, char *param)
560 {
561     char           *name, *context, *readView, *writeView, *notify;
562     int             imodel, ilevel, iprefix;
563     struct vacm_accessEntry *ap;
564     char   *st;
565 
566 
567     if (_vacm_parse_access_common(token, param, &st, &name,
568                                   &context, &imodel, &ilevel, &iprefix)
569         == PARSE_FAIL) {
570         return;
571     }
572 
573     readView = strtok_r(NULL, " \t\n", &st);
574     if (!readView) {
575         config_perror("missing readView parameter");
576         return;
577     }
578     writeView = strtok_r(NULL, " \t\n", &st);
579     if (!writeView) {
580         config_perror("missing writeView parameter");
581         return;
582     }
583     notify = strtok_r(NULL, " \t\n", &st);
584     if (!notify) {
585         config_perror("missing notifyView parameter");
586         return;
587     }
588 
589     if (strlen(readView) + 1 > sizeof(ap->views[VACM_VIEW_READ])) {
590         config_perror("readView too long");
591         return;
592     }
593     if (strlen(writeView) + 1 > sizeof(ap->views[VACM_VIEW_WRITE])) {
594         config_perror("writeView too long");
595         return;
596     }
597     if (strlen(notify) + 1 > sizeof(ap->views[VACM_VIEW_NOTIFY])) {
598         config_perror("notifyView too long");
599         return;
600     }
601     ap = vacm_createAccessEntry(name, context, imodel, ilevel);
602     if (!ap) {
603         config_perror("failed to create access entry");
604         return;
605     }
606     strlcpy(ap->views[VACM_VIEW_READ], readView,
607             sizeof(ap->views[VACM_VIEW_READ]));
608     strlcpy(ap->views[VACM_VIEW_WRITE], writeView,
609             sizeof(ap->views[VACM_VIEW_WRITE]));
610     strlcpy(ap->views[VACM_VIEW_NOTIFY], notify,
611             sizeof(ap->views[VACM_VIEW_NOTIFY]));
612     ap->contextMatch = iprefix;
613     ap->storageType = SNMP_STORAGE_PERMANENT;
614     ap->status = SNMP_ROW_ACTIVE;
615     free(ap->reserved);
616     ap->reserved = NULL;
617 }
618 
619 void
vacm_free_access(void)620 vacm_free_access(void)
621 {
622     vacm_destroyAllAccessEntries();
623 }
624 
625 void
vacm_parse_view(const char * token,char * param)626 vacm_parse_view(const char *token, char *param)
627 {
628     char           *name, *type, *subtree, *mask;
629     int             inclexcl;
630     struct vacm_viewEntry *vp;
631     oid             suboid[MAX_OID_LEN];
632     size_t          suboid_len = 0;
633     size_t          mask_len = 0;
634     u_char          viewMask[VACMSTRINGLEN];
635     size_t          i;
636     char            *st;
637 
638     name = strtok_r(param, " \t\n", &st);
639     if (!name) {
640         config_perror("missing NAME parameter");
641         return;
642     }
643     type = strtok_r(NULL, " \n\t", &st);
644     if (!type) {
645         config_perror("missing TYPE parameter");
646         return;
647     }
648     subtree = strtok_r(NULL, " \t\n", &st);
649     if (!subtree) {
650         config_perror("missing SUBTREE parameter");
651         return;
652     }
653     mask = strtok_r(NULL, "\0", &st);
654 
655     if (strcmp(type, "included") == 0)
656         inclexcl = SNMP_VIEW_INCLUDED;
657     else if (strcmp(type, "excluded") == 0)
658         inclexcl = SNMP_VIEW_EXCLUDED;
659     else {
660         config_perror("TYPE must be included/excluded?");
661         return;
662     }
663     suboid_len = strlen(subtree)-1;
664     if (subtree[suboid_len] == '.')
665         subtree[suboid_len] = '\0';   /* stamp on a trailing . */
666     suboid_len = MAX_OID_LEN;
667     if (!snmp_parse_oid(subtree, suboid, &suboid_len)) {
668         config_perror("bad SUBTREE object id");
669         return;
670     }
671     if (mask) {
672         unsigned int val;
673         i = 0;
674         for (mask = strtok_r(mask, " .:", &st); mask; mask = strtok_r(NULL, " .:", &st)) {
675             if (i >= sizeof(viewMask)) {
676                 config_perror("MASK too long");
677                 return;
678             }
679             if (sscanf(mask, "%x", &val) == 0) {
680                 config_perror("invalid MASK");
681                 return;
682             }
683             viewMask[i] = val;
684             i++;
685         }
686         mask_len = i;
687     } else {
688         for (i = 0; i < sizeof(viewMask); i++)
689             viewMask[i] = 0xff;
690     }
691     vp = vacm_createViewEntry(name, suboid, suboid_len);
692     if (!vp) {
693         config_perror("failed to create view entry");
694         return;
695     }
696     memcpy(vp->viewMask, viewMask, sizeof(viewMask));
697     vp->viewMaskLen = mask_len;
698     vp->viewType = inclexcl;
699     vp->viewStorageType = SNMP_STORAGE_PERMANENT;
700     vp->viewStatus = SNMP_ROW_ACTIVE;
701     free(vp->reserved);
702     vp->reserved = NULL;
703 }
704 
705 void
vacm_free_view(void)706 vacm_free_view(void)
707 {
708     vacm_destroyAllViewEntries();
709 }
710 
711 void
vacm_gen_com2sec(int commcount,const char * community,const char * addressname,const char * publishtoken,void (* parser)(const char *,char *),char * secname,size_t secname_len,char * viewname,size_t viewname_len,int version,const char * context)712 vacm_gen_com2sec(int commcount, const char *community, const char *addressname,
713                  const char *publishtoken,
714                  void (*parser)(const char *, char *),
715                  char *secname, size_t secname_len,
716                  char *viewname, size_t viewname_len, int version,
717                  const char *context)
718 {
719     char            line[SPRINT_MAX_LEN];
720 
721     /*
722      * com2sec6|comsec [-Cn CONTEXT] anonymousSecNameNUM    ADDRESS  COMMUNITY
723      */
724     snprintf(secname, secname_len-1, "comm%d", commcount);
725     secname[secname_len-1] = '\0';
726     if (viewname) {
727         snprintf(viewname, viewname_len-1, "viewComm%d", commcount);
728         viewname[viewname_len-1] = '\0';
729     }
730     if ( context && *context )
731        snprintf(line, sizeof(line), "-Cn %s %s %s '%s'",
732              context, secname, addressname, community);
733     else
734        snprintf(line, sizeof(line), "%s %s '%s'",
735              secname, addressname, community);
736     line[ sizeof(line)-1 ] = 0;
737     DEBUGMSGTL((publishtoken, "passing: %s %s\n", publishtoken, line));
738     (*parser)(publishtoken, line);
739 
740     /*
741      * sec->group mapping
742      */
743     /*
744      * group   anonymousGroupNameNUM  any      anonymousSecNameNUM
745      */
746     if ( version & SNMP_SEC_MODEL_SNMPv1 ) {
747         snprintf(line, sizeof(line),
748              "grp%.28s v1 %s", secname, secname);
749         line[ sizeof(line)-1 ] = 0;
750         DEBUGMSGTL((publishtoken, "passing: %s %s\n", "group", line));
751         vacm_parse_group("group", line);
752     }
753 
754     if ( version & SNMP_SEC_MODEL_SNMPv2c ) {
755         snprintf(line, sizeof(line),
756              "grp%.28s v2c %s", secname, secname);
757         line[ sizeof(line)-1 ] = 0;
758         DEBUGMSGTL((publishtoken, "passing: %s %s\n", "group", line));
759         vacm_parse_group("group", line);
760     }
761 }
762 
763 void
vacm_parse_rwuser(const char * token,char * confline)764 vacm_parse_rwuser(const char *token, char *confline)
765 {
766     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_V3,
767                        VACM_VIEW_READ_BIT | VACM_VIEW_WRITE_BIT);
768 }
769 
770 void
vacm_parse_rouser(const char * token,char * confline)771 vacm_parse_rouser(const char *token, char *confline)
772 {
773     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_V3,
774                        VACM_VIEW_READ_BIT);
775 }
776 
777 void
vacm_parse_rocommunity(const char * token,char * confline)778 vacm_parse_rocommunity(const char *token, char *confline)
779 {
780     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_COMIPV4,
781                        VACM_VIEW_READ_BIT);
782 }
783 
784 void
vacm_parse_rwcommunity(const char * token,char * confline)785 vacm_parse_rwcommunity(const char *token, char *confline)
786 {
787     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_COMIPV4,
788                        VACM_VIEW_READ_BIT | VACM_VIEW_WRITE_BIT);
789 }
790 
791 void
vacm_parse_rocommunity6(const char * token,char * confline)792 vacm_parse_rocommunity6(const char *token, char *confline)
793 {
794     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_COMIPV6,
795                        VACM_VIEW_READ_BIT);
796 }
797 
798 void
vacm_parse_rwcommunity6(const char * token,char * confline)799 vacm_parse_rwcommunity6(const char *token, char *confline)
800 {
801     vacm_create_simple(token, confline, VACM_CREATE_SIMPLE_COMIPV6,
802                        VACM_VIEW_READ_BIT | VACM_VIEW_WRITE_BIT);
803 }
804 
805 
806 void
vacm_create_simple(const char * token,char * confline,int parsetype,int viewtypes)807 vacm_create_simple(const char *token, char *confline,
808                    int parsetype, int viewtypes)
809 {
810     char            line[SPRINT_MAX_LEN];
811     char            community[COMMUNITY_MAX_LEN];
812     char            theoid[SPRINT_MAX_LEN];
813     char            viewname[SPRINT_MAX_LEN];
814     char           *view_ptr = viewname;
815 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
816     char            addressname[SPRINT_MAX_LEN];
817     /* Conveniently, the community-based security
818        model values can also be used as bit flags */
819     int             commversion = SNMP_SEC_MODEL_SNMPv1 |
820                                   SNMP_SEC_MODEL_SNMPv2c;
821 #endif
822     const char     *rw = "none";
823     char            model[SPRINT_MAX_LEN];
824     char           *cp, *tmp;
825     char            secname[SPRINT_MAX_LEN];
826     char            grpname[SPRINT_MAX_LEN];
827     char            authlevel[SPRINT_MAX_LEN];
828     char            context[SPRINT_MAX_LEN];
829     int             ctxprefix = 1;  /* Default to matching all contexts */
830     static int      commcount = 0;
831 
832     /*
833      * init
834      */
835     strcpy(model, "any");
836     memset(context, 0, sizeof(context));
837     memset(secname, 0, sizeof(secname));
838     memset(grpname, 0, sizeof(grpname));
839 
840     /*
841      * community name or user name
842      */
843     cp = copy_nword(confline, community, sizeof(community));
844 
845     if (parsetype == VACM_CREATE_SIMPLE_V3) {
846         /*
847          * maybe security model type
848          */
849         if (strcmp(community, "-s") == 0) {
850             /*
851              * -s model ...
852              */
853             if (cp)
854                 cp = copy_nword(cp, model, sizeof(model));
855             if (!cp) {
856                 config_perror("illegal line");
857                 return;
858             }
859             if (cp)
860                 cp = copy_nword(cp, community, sizeof(community));
861         } else {
862             strcpy(model, "usm");
863         }
864         /*
865          * authentication level
866          */
867         if (cp && *cp)
868             cp = copy_nword(cp, authlevel, sizeof(authlevel));
869         else
870             strcpy(authlevel, "auth");
871         DEBUGMSGTL((token, "setting auth level: \"%s\"\n", authlevel));
872 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
873     } else {
874         if (strcmp(community, "-v") == 0) {
875             /*
876              * -v version ...
877              */
878             if (cp)
879                 cp = copy_nword(cp, model, sizeof(model));
880             if (!cp) {
881                 config_perror("illegal line");
882                 return;
883             }
884             if ( strcasecmp( model,  "1" ) == 0 )
885                 strcpy(model, "v1");
886             if ( strcasecmp( model, "v1" ) == 0 )
887                 commversion = SNMP_SEC_MODEL_SNMPv1;
888             if ( strcasecmp( model,  "2c" ) == 0 )
889                 strcpy(model, "v2c");
890             if ( strcasecmp( model, "v2c" ) == 0 )
891                 commversion = SNMP_SEC_MODEL_SNMPv2c;
892             if (cp)
893                 cp = copy_nword(cp, community, sizeof(community));
894         }
895         /*
896          * source address
897          */
898         if (cp && *cp) {
899             cp = copy_nword(cp, addressname, sizeof(addressname));
900         } else {
901             strcpy(addressname, "default");
902         }
903         /*
904          * authlevel has to be noauth
905          */
906         strcpy(authlevel, "noauth");
907 #endif /* support for community based SNMP */
908     }
909 
910     /*
911      * oid they can touch
912      */
913     if (cp && *cp) {
914         if (strncmp(cp, "-V ", 3) == 0) {
915              cp = skip_token(cp);
916              cp = copy_nword(cp, viewname, sizeof(viewname));
917              view_ptr = NULL;
918         } else {
919              cp = copy_nword(cp, theoid, sizeof(theoid));
920         }
921     } else {
922         strcpy(theoid, ".1");
923         strcpy(viewname, "_all_");
924         view_ptr = NULL;
925     }
926     /*
927      * optional, non-default context
928      */
929     if (cp && *cp) {
930         cp = copy_nword(cp, context, sizeof(context));
931         tmp = (context + strlen(context)-1);
932         if (tmp && *tmp == '*') {
933             *tmp = '\0';
934             ctxprefix = 1;
935         } else {
936             /*
937              * If no context field is given, then we default to matching
938              *   all contexts (for compatability with previous releases).
939              * But if a field context is specified (not ending with '*')
940              *   then this should be taken as an exact match.
941              * Specifying a context field of "" will match the default
942              *   context (and *only* the default context).
943              */
944             ctxprefix = 0;
945         }
946     }
947 
948     if (viewtypes & VACM_VIEW_WRITE_BIT)
949         rw = viewname;
950 
951     commcount++;
952 
953 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
954 #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
955     if (parsetype == VACM_CREATE_SIMPLE_COMIPV4 ||
956         parsetype == VACM_CREATE_SIMPLE_COM) {
957         vacm_gen_com2sec(commcount, community, addressname,
958                          "com2sec", &netsnmp_udp_parse_security,
959                          secname, sizeof(secname),
960                          view_ptr, sizeof(viewname), commversion, context);
961     }
962 #endif
963 
964 #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN
965     if (parsetype == VACM_CREATE_SIMPLE_COMUNIX ||
966         parsetype == VACM_CREATE_SIMPLE_COM) {
967         if ( *context )
968            snprintf(line, sizeof(line), "-Cn %s %s %s '%s'",
969              context, secname, addressname, community);
970         else
971             snprintf(line, sizeof(line), "%s %s '%s'",
972                  secname, addressname, community);
973         line[ sizeof(line)-1 ] = 0;
974         DEBUGMSGTL((token, "passing: %s %s\n", "com2secunix", line));
975         netsnmp_unix_parse_security("com2secunix", line);
976     }
977 #endif
978 
979 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
980     if (parsetype == VACM_CREATE_SIMPLE_COMIPV6 ||
981         parsetype == VACM_CREATE_SIMPLE_COM) {
982         vacm_gen_com2sec(commcount, community, addressname,
983                          "com2sec6", &netsnmp_udp6_parse_security,
984                          secname, sizeof(secname),
985                          view_ptr, sizeof(viewname), commversion, context);
986     }
987 #endif
988 #endif /* support for community based SNMP */
989 
990     if (parsetype == VACM_CREATE_SIMPLE_V3) {
991         /* support for SNMPv3 user names */
992         if (view_ptr) {
993             sprintf(viewname,"viewUSM%d",commcount);
994         }
995         if ( strcmp( token, "authgroup" ) == 0 ) {
996             strlcpy(grpname, community, sizeof(grpname));
997         } else {
998             strlcpy(secname, community, sizeof(secname));
999 
1000             /*
1001              * sec->group mapping
1002              */
1003             /*
1004              * group   anonymousGroupNameNUM  any      anonymousSecNameNUM
1005              */
1006             snprintf(grpname, sizeof(grpname), "grp%.28s", secname);
1007             for (tmp=grpname; *tmp; tmp++)
1008                 if (!isalnum((unsigned char)(*tmp)))
1009                     *tmp = '_';
1010             snprintf(line, sizeof(line),
1011                      "%s %s \"%s\"", grpname, model, secname);
1012             line[ sizeof(line)-1 ] = 0;
1013             DEBUGMSGTL((token, "passing: %s %s\n", "group", line));
1014             vacm_parse_group("group", line);
1015         }
1016     } else {
1017         snprintf(grpname, sizeof(grpname), "grp%.28s", secname);
1018         for (tmp=grpname; *tmp; tmp++)
1019             if (!isalnum((unsigned char)(*tmp)))
1020                 *tmp = '_';
1021     }
1022 
1023     /*
1024      * view definition
1025      */
1026     /*
1027      * view    anonymousViewNUM       included OID
1028      */
1029     if (view_ptr) {
1030         snprintf(line, sizeof(line), "%s included %s", viewname, theoid);
1031         line[ sizeof(line)-1 ] = 0;
1032         DEBUGMSGTL((token, "passing: %s %s\n", "view", line));
1033         vacm_parse_view("view", line);
1034     }
1035 
1036     /*
1037      * map everything together
1038      */
1039     if ((viewtypes == VACM_VIEW_READ_BIT) ||
1040         (viewtypes == (VACM_VIEW_READ_BIT | VACM_VIEW_WRITE_BIT))) {
1041         /* Use the simple line access command */
1042         /*
1043          * access  anonymousGroupNameNUM  "" MODEL AUTHTYPE prefix anonymousViewNUM [none/anonymousViewNUM] [none/anonymousViewNUM]
1044          */
1045         snprintf(line, sizeof(line),
1046                  "%s %s %s %s %s %s %s %s",
1047                  grpname, context[0] ? context : "\"\"",
1048                  model, authlevel,
1049                 (ctxprefix ? "prefix" : "exact"),
1050                  viewname, rw, rw);
1051         line[ sizeof(line)-1 ] = 0;
1052         DEBUGMSGTL((token, "passing: %s %s\n", "access", line));
1053         vacm_parse_access("access", line);
1054     } else {
1055         /* Use one setaccess line per access type */
1056         /*
1057          * setaccess  anonymousGroupNameNUM  "" MODEL AUTHTYPE prefix viewname viewval
1058          */
1059         int i;
1060         DEBUGMSGTL((token, " checking view levels for %x\n", viewtypes));
1061         for(i = 0; i <= VACM_MAX_VIEWS; i++) {
1062             if (viewtypes & (1 << i)) {
1063                 snprintf(line, sizeof(line),
1064                          "%s %s %s %s %s %s %s",
1065                          grpname, context[0] ? context : "\"\"",
1066                          model, authlevel,
1067                         (ctxprefix ? "prefix" : "exact"),
1068                          se_find_label_in_slist(VACM_VIEW_ENUM_NAME, i),
1069                          viewname);
1070                 line[ sizeof(line)-1 ] = 0;
1071                 DEBUGMSGTL((token, "passing: %s %s\n", "setaccess", line));
1072                 vacm_parse_setaccess("setaccess", line);
1073             }
1074         }
1075     }
1076 }
1077 
1078 int
vacm_standard_views(int majorID,int minorID,void * serverarg,void * clientarg)1079 vacm_standard_views(int majorID, int minorID, void *serverarg,
1080                             void *clientarg)
1081 {
1082     char            line[SPRINT_MAX_LEN];
1083 
1084     memset(line, 0, sizeof(line));
1085 
1086     snprintf(line, sizeof(line), "_all_ included .0");
1087     vacm_parse_view("view", line);
1088     snprintf(line, sizeof(line), "_all_ included .1");
1089     vacm_parse_view("view", line);
1090     snprintf(line, sizeof(line), "_all_ included .2");
1091     vacm_parse_view("view", line);
1092 
1093     snprintf(line, sizeof(line), "_none_ excluded .0");
1094     vacm_parse_view("view", line);
1095     snprintf(line, sizeof(line), "_none_ excluded .1");
1096     vacm_parse_view("view", line);
1097     snprintf(line, sizeof(line), "_none_ excluded .2");
1098     vacm_parse_view("view", line);
1099 
1100     return SNMP_ERR_NOERROR;
1101 }
1102 
1103 int
vacm_warn_if_not_configured(int majorID,int minorID,void * serverarg,void * clientarg)1104 vacm_warn_if_not_configured(int majorID, int minorID, void *serverarg,
1105                             void *clientarg)
1106 {
1107     const char * name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1108                                         NETSNMP_DS_LIB_APPTYPE);
1109     const int agent_mode =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1110                                                    NETSNMP_DS_AGENT_ROLE);
1111     if (NULL==name)
1112         name = "snmpd";
1113 
1114     if (!vacm_is_configured()) {
1115         /*
1116          *  An AgentX subagent relies on the master agent to apply suitable
1117          *    access control checks, so doesn't need local VACM configuration.
1118          *  The trap daemon has a separate check (see below).
1119          *
1120          *  Otherwise, an AgentX master or SNMP standalone agent requires some
1121          *    form of VACM configuration.  No config means that no incoming
1122          *    requests will be accepted, so warn the user accordingly.
1123          */
1124         if ((MASTER_AGENT == agent_mode) && (strcmp(name, "snmptrapd") != 0)) {
1125             snmp_log(LOG_WARNING,
1126                  "Warning: no access control information configured.\n"
1127                  "  (Config search path: %s)\n"
1128                  "  It's unlikely this agent can serve any useful purpose in this state.\n"
1129                  "  Run \"snmpconf -g basic_setup\" to help you "
1130                  "configure the %s.conf file for this agent.\n",
1131                  get_configuration_directory(), name);
1132         }
1133 
1134         /*
1135          *  The trap daemon implements VACM-style access control for incoming
1136          *    notifications, but offers a way of turning this off (for backwards
1137          *    compatability).  Check for this explicitly, and warn if necessary.
1138          *
1139          *  NB:  The NETSNMP_DS_APP_NO_AUTHORIZATION definition is a duplicate
1140          *       of an identical setting in "apps/snmptrapd_ds.h".
1141          *       These two need to be kept in synch.
1142          */
1143 #ifndef NETSNMP_DS_APP_NO_AUTHORIZATION
1144 #define NETSNMP_DS_APP_NO_AUTHORIZATION 17
1145 #endif
1146         if (!strcmp(name, "snmptrapd") &&
1147             !netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1148                                     NETSNMP_DS_APP_NO_AUTHORIZATION)) {
1149             snmp_log(LOG_WARNING,
1150                  "Warning: no access control information configured.\n"
1151                  "  (Config search path: %s)\n"
1152                  "This receiver will *NOT* accept any incoming notifications.\n",
1153                  get_configuration_directory());
1154         }
1155     }
1156     return SNMP_ERR_NOERROR;
1157 }
1158 
1159 int
vacm_in_view_callback(int majorID,int minorID,void * serverarg,void * clientarg)1160 vacm_in_view_callback(int majorID, int minorID, void *serverarg,
1161                       void *clientarg)
1162 {
1163     struct view_parameters *view_parms =
1164         (struct view_parameters *) serverarg;
1165     int             retval;
1166 
1167     if (view_parms == NULL)
1168         return 1;
1169     retval = vacm_in_view(view_parms->pdu, view_parms->name,
1170                           view_parms->namelen, view_parms->check_subtree);
1171     if (retval != 0)
1172         view_parms->errorcode = retval;
1173     return retval;
1174 }
1175 
1176 
1177 /**
1178  * vacm_in_view: decides if a given PDU can be acted upon
1179  *
1180  * Parameters:
1181  *	*pdu
1182  *	*name
1183  *	 namelen
1184  *       check_subtree
1185  *
1186  * Returns:
1187  * VACM_SUCCESS(0)	   On success.
1188  * VACM_NOSECNAME(1)	   Missing security name.
1189  * VACM_NOGROUP(2)	   Missing group
1190  * VACM_NOACCESS(3)	   Missing access
1191  * VACM_NOVIEW(4)	   Missing view
1192  * VACM_NOTINVIEW(5)	   Not in view
1193  * VACM_NOSUCHCONTEXT(6)   No Such Context
1194  * VACM_SUBTREE_UNKNOWN(7) When testing an entire subtree, UNKNOWN (ie, the entire
1195  *                         subtree has both allowed and disallowed portions)
1196  *
1197  * Debug output listed as follows:
1198  *	\<securityName\> \<groupName\> \<viewName\> \<viewType\>
1199  */
1200 int
vacm_in_view(netsnmp_pdu * pdu,oid * name,size_t namelen,int check_subtree)1201 vacm_in_view(netsnmp_pdu *pdu, oid * name, size_t namelen,
1202              int check_subtree)
1203 {
1204     int viewtype;
1205 
1206     switch (pdu->command) {
1207     case SNMP_MSG_GET:
1208     case SNMP_MSG_GETNEXT:
1209     case SNMP_MSG_GETBULK:
1210         viewtype = VACM_VIEW_READ;
1211         break;
1212 #ifndef NETSNMP_NO_WRITE_SUPPORT
1213     case SNMP_MSG_SET:
1214         viewtype = VACM_VIEW_WRITE;
1215         break;
1216 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
1217     case SNMP_MSG_TRAP:
1218     case SNMP_MSG_TRAP2:
1219     case SNMP_MSG_INFORM:
1220         viewtype = VACM_VIEW_NOTIFY;
1221         break;
1222     default:
1223         snmp_log(LOG_ERR, "bad msg type in vacm_in_view: %d\n",
1224                  pdu->command);
1225         viewtype = VACM_VIEW_READ;
1226     }
1227     return vacm_check_view(pdu, name, namelen, check_subtree, viewtype);
1228 }
1229 
1230 /**
1231  * vacm_check_view: decides if a given PDU can be taken based on a view type
1232  *
1233  * Parameters:
1234  *	*pdu
1235  *	*name
1236  *	 namelen
1237  *       check_subtree
1238  *       viewtype
1239  *
1240  * Returns:
1241  * VACM_SUCCESS(0)	   On success.
1242  * VACM_NOSECNAME(1)	   Missing security name.
1243  * VACM_NOGROUP(2)	   Missing group
1244  * VACM_NOACCESS(3)	   Missing access
1245  * VACM_NOVIEW(4)	   Missing view
1246  * VACM_NOTINVIEW(5)	   Not in view
1247  * VACM_NOSUCHCONTEXT(6)   No Such Context
1248  * VACM_SUBTREE_UNKNOWN(7) When testing an entire subtree, UNKNOWN (ie, the entire
1249  *                         subtree has both allowed and disallowed portions)
1250  *
1251  * Debug output listed as follows:
1252  *	\<securityName\> \<groupName\> \<viewName\> \<viewType\>
1253  */
1254 int
vacm_check_view(netsnmp_pdu * pdu,oid * name,size_t namelen,int check_subtree,int viewtype)1255 vacm_check_view(netsnmp_pdu *pdu, oid * name, size_t namelen,
1256                 int check_subtree, int viewtype)
1257 {
1258     return vacm_check_view_contents(pdu, name, namelen, check_subtree, viewtype,
1259                                     VACM_CHECK_VIEW_CONTENTS_NO_FLAGS);
1260 }
1261 
1262 int
vacm_check_view_contents(netsnmp_pdu * pdu,oid * name,size_t namelen,int check_subtree,int viewtype,int flags)1263 vacm_check_view_contents(netsnmp_pdu *pdu, oid * name, size_t namelen,
1264                          int check_subtree, int viewtype, int flags)
1265 {
1266     struct vacm_accessEntry *ap;
1267     struct vacm_groupEntry *gp;
1268     struct vacm_viewEntry *vp;
1269 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1270     char            vacm_default_context[1] = "";
1271     const char     *contextName = vacm_default_context;
1272     const char     *pdu_community;
1273 #endif
1274     const char     *sn = NULL;
1275     char           *vn;
1276 
1277     /*
1278      * len defined by the vacmContextName object
1279      */
1280 #define CONTEXTNAMEINDEXLEN 32
1281     char            contextNameIndex[CONTEXTNAMEINDEXLEN + 1];
1282 
1283 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1284 #if defined(NETSNMP_DISABLE_SNMPV1)
1285     if (pdu->version == SNMP_VERSION_2c)
1286 #else
1287 #if defined(NETSNMP_DISABLE_SNMPV2C)
1288     if (pdu->version == SNMP_VERSION_1)
1289 #else
1290     if (pdu->version == SNMP_VERSION_1 || pdu->version == SNMP_VERSION_2c)
1291 #endif
1292 #endif
1293     {
1294         pdu_community = (const char *) pdu->community;
1295         if (!pdu_community)
1296             pdu_community = "";
1297         if (snmp_get_do_debugging()) {
1298             char           *buf;
1299             if (pdu->community) {
1300                 buf = (char *) malloc(1 + pdu->community_len);
1301                 memcpy(buf, pdu->community, pdu->community_len);
1302                 buf[pdu->community_len] = '\0';
1303             } else {
1304                 DEBUGMSGTL(("mibII/vacm_vars", "NULL community"));
1305                 buf = strdup("NULL");
1306             }
1307 
1308             DEBUGMSGTL(("mibII/vacm_vars",
1309                         "vacm_in_view: ver=%ld, community=%s\n",
1310                         pdu->version, buf));
1311             free(buf);
1312         }
1313 
1314         /*
1315          * Okay, if this PDU was received from a UDP or a TCP transport then
1316          * ask the transport abstraction layer to map its source address and
1317          * community string to a security name for us.
1318          */
1319 
1320         if (0) {
1321 #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
1322         } else if (pdu->tDomain == netsnmpUDPDomain
1323 #ifdef NETSNMP_TRANSPORT_TCP_DOMAIN
1324             || pdu->tDomain == netsnmp_snmpTCPDomain
1325 #endif
1326             ) {
1327             if (!netsnmp_udp_getSecName(pdu->transport_data,
1328                                         pdu->transport_data_length,
1329                                         pdu_community,
1330                                         pdu->community_len, &sn,
1331                                         &contextName)) {
1332                 /*
1333                  * There are no com2sec entries.
1334                  */
1335                 sn = NULL;
1336             }
1337             /* force the community -> context name mapping here */
1338             SNMP_FREE(pdu->contextName);
1339             pdu->contextName = strdup(contextName);
1340             pdu->contextNameLen = strlen(contextName);
1341 #endif
1342 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1343         } else if (pdu->tDomain == netsnmp_UDPIPv6Domain
1344 #ifdef NETSNMP_TRANSPORT_TCPIPV6_DOMAIN
1345                    || pdu->tDomain == netsnmp_TCPIPv6Domain
1346 #endif
1347             ) {
1348             if (!netsnmp_udp6_getSecName(pdu->transport_data,
1349                                          pdu->transport_data_length,
1350                                          pdu_community,
1351                                          pdu->community_len, &sn,
1352                                          &contextName)) {
1353                 /*
1354                  * There are no com2sec entries.
1355                  */
1356                 sn = NULL;
1357             }
1358             /* force the community -> context name mapping here */
1359             SNMP_FREE(pdu->contextName);
1360             pdu->contextName = strdup(contextName);
1361             pdu->contextNameLen = strlen(contextName);
1362 #endif
1363 #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN
1364         } else if (pdu->tDomain == netsnmp_UnixDomain){
1365             if (!netsnmp_unix_getSecName(pdu->transport_data,
1366                                          pdu->transport_data_length,
1367                                          pdu_community,
1368                                          pdu->community_len, &sn,
1369                                          &contextName)) {
1370 					sn = NULL;
1371             }
1372             /* force the community -> context name mapping here */
1373             SNMP_FREE(pdu->contextName);
1374             pdu->contextName = strdup(contextName);
1375             pdu->contextNameLen = strlen(contextName);
1376 #endif
1377         } else {
1378             /*
1379              * Map other <community, transport-address> pairs to security names
1380              * here.  For now just let non-IPv4 transport always succeed.
1381              *
1382              * WHAAAATTTT.  No, we don't let non-IPv4 transports
1383              * succeed!  You must fix this to make it usable, sorry.
1384              * From a security standpoint this is insane. -- Wes
1385              */
1386             /** @todo alternate com2sec mappings for non v4 transports.
1387                 Should be implemented via registration */
1388             sn = NULL;
1389         }
1390 
1391     } else
1392 #endif /* !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) */
1393       if (find_sec_mod(pdu->securityModel)) {
1394         /*
1395          * any legal defined v3 security model
1396          */
1397         DEBUGMSG(("mibII/vacm_vars",
1398                   "vacm_in_view: ver=%ld, model=%d, secName=%s\n",
1399                   pdu->version, pdu->securityModel, pdu->securityName));
1400         sn = pdu->securityName;
1401     } else {
1402         sn = NULL;
1403     }
1404 
1405     if (sn == NULL) {
1406 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1407         snmp_increment_statistic(STAT_SNMPINBADCOMMUNITYNAMES);
1408 #endif
1409         DEBUGMSGTL(("mibII/vacm_vars",
1410                     "vacm_in_view: No security name found\n"));
1411         return VACM_NOSECNAME;
1412     }
1413 
1414     if (pdu->contextNameLen > CONTEXTNAMEINDEXLEN) {
1415         DEBUGMSGTL(("mibII/vacm_vars",
1416                     "vacm_in_view: bad ctxt length %d\n",
1417                     (int)pdu->contextNameLen));
1418         return VACM_NOSUCHCONTEXT;
1419     }
1420     /*
1421      * NULL termination of the pdu field is ugly here.  Do in PDU parsing?
1422      */
1423     if (pdu->contextName)
1424         memcpy(contextNameIndex, pdu->contextName, pdu->contextNameLen);
1425     else
1426         contextNameIndex[0] = '\0';
1427 
1428     contextNameIndex[pdu->contextNameLen] = '\0';
1429     if (!(flags & VACM_CHECK_VIEW_CONTENTS_DNE_CONTEXT_OK) &&
1430         !netsnmp_subtree_find_first(contextNameIndex)) {
1431         /*
1432          * rfc 3415 section 3.2, step 1
1433          * no such context here; return no such context error
1434          */
1435         DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: no such ctxt \"%s\"\n",
1436                     contextNameIndex));
1437         return VACM_NOSUCHCONTEXT;
1438     }
1439 
1440     DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: sn=%s", sn));
1441 
1442     gp = vacm_getGroupEntry(pdu->securityModel, sn);
1443     if (gp == NULL) {
1444         DEBUGMSG(("mibII/vacm_vars", "\n"));
1445         return VACM_NOGROUP;
1446     }
1447     DEBUGMSG(("mibII/vacm_vars", ", gn=%s", gp->groupName));
1448 
1449     ap = vacm_getAccessEntry(gp->groupName, contextNameIndex,
1450                              pdu->securityModel, pdu->securityLevel);
1451     if (ap == NULL) {
1452         DEBUGMSG(("mibII/vacm_vars", "\n"));
1453         return VACM_NOACCESS;
1454     }
1455 
1456     if (name == NULL) { /* only check the setup of the vacm for the request */
1457         DEBUGMSG(("mibII/vacm_vars", ", Done checking setup\n"));
1458         return VACM_SUCCESS;
1459     }
1460 
1461     if (viewtype < 0 || viewtype >= VACM_MAX_VIEWS) {
1462         DEBUGMSG(("mibII/vacm_vars", " illegal view type\n"));
1463         return VACM_NOACCESS;
1464     }
1465     vn = ap->views[viewtype];
1466     DEBUGMSG(("mibII/vacm_vars", ", vn=%s", vn));
1467 
1468     if (check_subtree) {
1469         DEBUGMSG(("mibII/vacm_vars", "\n"));
1470         return vacm_checkSubtree(vn, name, namelen);
1471     }
1472 
1473     vp = vacm_getViewEntry(vn, name, namelen, VACM_MODE_FIND);
1474 
1475     if (vp == NULL) {
1476         DEBUGMSG(("mibII/vacm_vars", "\n"));
1477         return VACM_NOVIEW;
1478     }
1479     DEBUGMSG(("mibII/vacm_vars", ", vt=%d\n", vp->viewType));
1480 
1481     if (vp->viewType == SNMP_VIEW_EXCLUDED) {
1482 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1483 #if defined(NETSNMP_DISABLE_SNMPV1)
1484         if (pdu->version == SNMP_VERSION_2c)
1485 #else
1486 #if defined(NETSNMP_DISABLE_SNMPV2C)
1487         if (pdu->version == SNMP_VERSION_1)
1488 #else
1489         if (pdu->version == SNMP_VERSION_1 || pdu->version == SNMP_VERSION_2c)
1490 #endif
1491 #endif
1492         {
1493             snmp_increment_statistic(STAT_SNMPINBADCOMMUNITYUSES);
1494         }
1495 #endif
1496         return VACM_NOTINVIEW;
1497     }
1498 
1499     return VACM_SUCCESS;
1500 
1501 }                               /* end vacm_in_view() */
1502 
1503 
1504