Coverage Report

Created: 2026-07-16 06:27

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