Coverage Report

Created: 2026-08-28 09:48

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