Coverage Report

Created: 2023-11-19 06:08

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