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