Coverage Report

Created: 2026-03-20 06:47

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