Coverage Report

Created: 2025-10-13 06:36

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