~ubuntu-branches/ubuntu/trusty/net-snmp/trusty

« back to all changes in this revision

Viewing changes to agent/mibgroup/snmpv3/usmUser.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * usmUser.c
 
3
 */
 
4
 
 
5
#include <net-snmp/net-snmp-config.h>
 
6
#include <stdlib.h>
 
7
 
 
8
#if HAVE_STRING_H
 
9
#include <string.h>
 
10
#else
 
11
#include <strings.h>
 
12
#endif
 
13
 
 
14
#if HAVE_WINSOCK_H
 
15
#include <winsock.h>
 
16
#endif
 
17
 
 
18
#include <net-snmp/net-snmp-includes.h>
 
19
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
20
 
 
21
#include "util_funcs.h"
 
22
#include "usmUser.h"
 
23
 
 
24
int usmStatusCheck(struct usmUser *uptr);
 
25
 
 
26
struct variable4 usmUser_variables[] = {
 
27
    {USMUSERSPINLOCK, ASN_INTEGER, RWRITE, var_usmUser, 1, {1}},
 
28
    {USMUSERSECURITYNAME, ASN_OCTET_STR, RONLY, var_usmUser, 3, {2, 1, 3}},
 
29
    {USMUSERCLONEFROM, ASN_OBJECT_ID, RWRITE, var_usmUser, 3, {2, 1, 4}},
 
30
    {USMUSERAUTHPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
 
31
     {2, 1, 5}},
 
32
    {USMUSERAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
 
33
     {2, 1, 6}},
 
34
    {USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
 
35
     {2, 1, 7}},
 
36
    {USMUSERPRIVPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
 
37
     {2, 1, 8}},
 
38
    {USMUSERPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
 
39
     {2, 1, 9}},
 
40
    {USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
 
41
     {2, 1, 10}},
 
42
    {USMUSERPUBLIC, ASN_OCTET_STR, RWRITE, var_usmUser, 3, {2, 1, 11}},
 
43
    {USMUSERSTORAGETYPE, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 12}},
 
44
    {USMUSERSTATUS, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 13}},
 
45
 
 
46
};
 
47
 
 
48
oid             usmUser_variables_oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 2 };
 
49
 
 
50
 
 
51
/*
 
52
 * needed for the write_ functions to find the start of the index 
 
53
 */
 
54
#define USM_MIB_LENGTH 12
 
55
 
 
56
static unsigned int usmUserSpinLock = 0;
 
57
 
 
58
void
 
59
init_usmUser(void)
 
60
{
 
61
    snmpd_register_config_handler("usmUser",
 
62
                                  usm_parse_config_usmUser, NULL, NULL);
 
63
    snmpd_register_config_handler("createUser",
 
64
                                  usm_parse_create_usmUser, NULL,
 
65
                                  "username (MD5|SHA) passphrase [DES [passphrase]]");
 
66
 
 
67
    /*
 
68
     * we need to be called back later 
 
69
     */
 
70
    snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
 
71
                           usm_store_users, NULL);
 
72
 
 
73
    REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4,
 
74
                 usmUser_variables_oid);
 
75
}
 
76
 
 
77
/*******************************************************************-o-******
 
78
 * usm_generate_OID
 
79
 *
 
80
 * Parameters:
 
81
 *      *prefix         (I) OID prefix to the usmUser table entry.
 
82
 *       prefixLen      (I)
 
83
 *      *uptr           (I) Pointer to a user in the user list.
 
84
 *      *length         (O) Length of generated index OID.
 
85
 *      
 
86
 * Returns:
 
87
 *      Pointer to the OID index for the user (uptr)  -OR-
 
88
 *      NULL on failure.
 
89
 *
 
90
 *
 
91
 * Generate the index OID for a given usmUser name.  'length' is set to
 
92
 * the length of the index OID.
 
93
 *
 
94
 * Index OID format is:
 
95
 *
 
96
 *    <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
 
97
 */
 
98
oid            *
 
99
usm_generate_OID(oid * prefix, size_t prefixLen, struct usmUser *uptr,
 
100
                 size_t * length)
 
101
{
 
102
    oid            *indexOid;
 
103
    int             i;
 
104
 
 
105
    *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
 
106
    indexOid = (oid *) malloc(*length * sizeof(oid));
 
107
    if (indexOid) {
 
108
        memmove(indexOid, prefix, prefixLen * sizeof(oid));
 
109
 
 
110
        indexOid[prefixLen] = uptr->engineIDLen;
 
111
        for (i = 0; i < (int) uptr->engineIDLen; i++)
 
112
            indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i];
 
113
 
 
114
        indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
 
115
        for (i = 0; i < (int) strlen(uptr->name); i++)
 
116
            indexOid[prefixLen + uptr->engineIDLen + 2 + i] =
 
117
                (oid) uptr->name[i];
 
118
    }
 
119
    return indexOid;
 
120
 
 
121
}                               /* end usm_generate_OID() */
 
122
 
 
123
/*
 
124
 * usm_parse_oid(): parses an index to the usmTable to break it down into
 
125
 * a engineID component and a name component.  The results are stored in:
 
126
 * 
 
127
 * **engineID:   a newly malloced string.
 
128
 * *engineIDLen: The length of the malloced engineID string above.
 
129
 * **name:       a newly malloced string.
 
130
 * *nameLen:     The length of the malloced name string above.
 
131
 * 
 
132
 * returns 1 if an error is encountered, or 0 if successful.
 
133
 */
 
134
int
 
135
usm_parse_oid(oid * oidIndex, size_t oidLen,
 
136
              unsigned char **engineID, size_t * engineIDLen,
 
137
              unsigned char **name, size_t * nameLen)
 
138
{
 
139
    int             nameL;
 
140
    int             engineIDL;
 
141
    int             i;
 
142
 
 
143
    /*
 
144
     * first check the validity of the oid 
 
145
     */
 
146
    if ((oidLen <= 0) || (!oidIndex)) {
 
147
        DEBUGMSGTL(("usmUser",
 
148
                    "parse_oid: null oid or zero length oid passed in\n"));
 
149
        return 1;
 
150
    }
 
151
    engineIDL = *oidIndex;      /* initial engineID length */
 
152
    if ((int) oidLen < engineIDL + 2) {
 
153
        DEBUGMSGTL(("usmUser",
 
154
                    "parse_oid: invalid oid length: less than the engineIDLen\n"));
 
155
        return 1;
 
156
    }
 
157
    nameL = oidIndex[engineIDL + 1];    /* the initial name length */
 
158
    if ((int) oidLen != engineIDL + nameL + 2) {
 
159
        DEBUGMSGTL(("usmUser",
 
160
                    "parse_oid: invalid oid length: length is not exact\n"));
 
161
        return 1;
 
162
    }
 
163
 
 
164
    /*
 
165
     * its valid, malloc the space and store the results 
 
166
     */
 
167
    if (engineID == NULL || name == NULL) {
 
168
        DEBUGMSGTL(("usmUser",
 
169
                    "parse_oid: null storage pointer passed in.\n"));
 
170
        return 1;
 
171
    }
 
172
 
 
173
    *engineID = (unsigned char *) malloc(engineIDL);
 
174
    if (*engineID == NULL) {
 
175
        DEBUGMSGTL(("usmUser",
 
176
                    "parse_oid: malloc of the engineID failed\n"));
 
177
        return 1;
 
178
    }
 
179
    *engineIDLen = engineIDL;
 
180
 
 
181
    *name = (unsigned char *) malloc(nameL + 1);
 
182
    if (*name == NULL) {
 
183
        DEBUGMSGTL(("usmUser", "parse_oid: malloc of the name failed\n"));
 
184
        free(*engineID);
 
185
        return 1;
 
186
    }
 
187
    *nameLen = nameL;
 
188
 
 
189
    for (i = 0; i < engineIDL; i++) {
 
190
        if (oidIndex[i + 1] > 255) {
 
191
            goto UPO_parse_error;
 
192
        }
 
193
        engineID[0][i] = (unsigned char) oidIndex[i + 1];
 
194
    }
 
195
 
 
196
    for (i = 0; i < nameL; i++) {
 
197
        if (oidIndex[i + 2 + engineIDL] > 255) {
 
198
          UPO_parse_error:
 
199
            free(*engineID);
 
200
            free(*name);
 
201
            return 1;
 
202
        }
 
203
        name[0][i] = (unsigned char) oidIndex[i + 2 + engineIDL];
 
204
    }
 
205
    name[0][nameL] = 0;
 
206
 
 
207
    return 0;
 
208
 
 
209
}                               /* end usm_parse_oid() */
 
210
 
 
211
/*******************************************************************-o-******
 
212
 * usm_parse_user
 
213
 *
 
214
 * Parameters:
 
215
 *      *name           Complete OID indexing a given usmUser entry.
 
216
 *       name_length
 
217
 *      
 
218
 * Returns:
 
219
 *      Pointer to a usmUser  -OR-
 
220
 *      NULL if name does not convert to a usmUser.
 
221
 * 
 
222
 * Convert an (full) OID and return a pointer to a matching user in the
 
223
 * user list if one exists.
 
224
 */
 
225
struct usmUser *
 
226
usm_parse_user(oid * name, size_t name_len)
 
227
{
 
228
    struct usmUser *uptr;
 
229
 
 
230
    char           *newName;
 
231
    u_char         *engineID;
 
232
    size_t          nameLen, engineIDLen;
 
233
 
 
234
    /*
 
235
     * get the name and engineID out of the incoming oid 
 
236
     */
 
237
    if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
238
                      &engineID, &engineIDLen, (u_char **) & newName,
 
239
                      &nameLen))
 
240
        return NULL;
 
241
 
 
242
    /*
 
243
     * Now see if a user exists with these index values 
 
244
     */
 
245
    uptr = usm_get_user(engineID, engineIDLen, newName);
 
246
    free(engineID);
 
247
    free(newName);
 
248
 
 
249
    return uptr;
 
250
 
 
251
}                               /* end usm_parse_user() */
 
252
 
 
253
/*******************************************************************-o-******
 
254
 * var_usmUser
 
255
 *
 
256
 * Parameters:
 
257
 *        *vp      (I)     Variable-binding associated with this action.
 
258
 *        *name    (I/O)   Input name requested, output name found.
 
259
 *        *length  (I/O)   Length of input and output oid's.
 
260
 *         exact   (I)     TRUE if an exact match was requested.
 
261
 *        *var_len (O)     Length of variable or 0 if function returned.
 
262
 *      (**write_method)   Hook to name a write method (UNUSED).
 
263
 *      
 
264
 * Returns:
 
265
 *      Pointer to (char *) containing related data of length 'length'
 
266
 *        (May be NULL.)
 
267
 *
 
268
 *
 
269
 * Call-back function passed to the agent in order to return information
 
270
 * for the USM MIB tree.
 
271
 *
 
272
 *
 
273
 * If this invocation is not for USMUSERSPINLOCK, lookup user name
 
274
 * in the usmUser list.
 
275
 *
 
276
 * If the name does not match any user and the request
 
277
 * is for an exact match, -or- if the usmUser list is empty, create a 
 
278
 * new list entry.
 
279
 *
 
280
 * Finally, service the given USMUSER* var-bind.  A NULL user generally
 
281
 * results in a NULL return value.
 
282
 */
 
283
u_char         *
 
284
var_usmUser(struct variable * vp,
 
285
            oid * name,
 
286
            size_t * length,
 
287
            int exact, size_t * var_len, WriteMethod ** write_method)
 
288
{
 
289
    struct usmUser *uptr = NULL, *nptr, *pptr;
 
290
    int             i, rtest, result;
 
291
    oid            *indexOid;
 
292
    size_t          len;
 
293
 
 
294
    /*
 
295
     * variables we may use later 
 
296
     */
 
297
    static long     long_ret;
 
298
    static u_char   string[1];
 
299
    static oid      objid[2];   /* for .0.0 */
 
300
 
 
301
    *write_method = 0;          /* assume it isnt writable for the time being */
 
302
    *var_len = sizeof(long_ret);        /* assume an integer and change later if not */
 
303
 
 
304
    if (vp->magic != USMUSERSPINLOCK) {
 
305
        oid             newname[MAX_OID_LEN];
 
306
        len = (*length < vp->namelen) ? *length : vp->namelen;
 
307
        rtest = snmp_oid_compare(name, len, vp->name, len);
 
308
        if (rtest > 0 ||
 
309
            /*
 
310
             * (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) || 
 
311
             */
 
312
            (exact == 1 && rtest != 0)) {
 
313
            if (var_len)
 
314
                *var_len = 0;
 
315
            return 0;
 
316
        }
 
317
        memset(newname, 0, sizeof(newname));
 
318
        if (((int) *length) <= (int) vp->namelen || rtest == -1) {
 
319
            /*
 
320
             * oid is not within our range yet 
 
321
             */
 
322
            /*
 
323
             * need to fail if not exact 
 
324
             */
 
325
            uptr = usm_get_userList();
 
326
 
 
327
        } else {
 
328
            for (nptr = usm_get_userList(), pptr = NULL, uptr = NULL;
 
329
                 nptr != NULL; pptr = nptr, nptr = nptr->next) {
 
330
                indexOid =
 
331
                    usm_generate_OID(vp->name, vp->namelen, nptr, &len);
 
332
                result = snmp_oid_compare(name, *length, indexOid, len);
 
333
                DEBUGMSGTL(("usmUser", "Checking user: %s - ",
 
334
                            nptr->name));
 
335
                for (i = 0; i < (int) nptr->engineIDLen; i++) {
 
336
                    DEBUGMSG(("usmUser", " %x", nptr->engineID[i]));
 
337
                }
 
338
                DEBUGMSG(("usmUser", " - %d \n  -> OID: ", result));
 
339
                DEBUGMSGOID(("usmUser", indexOid, len));
 
340
                DEBUGMSG(("usmUser", "\n"));
 
341
 
 
342
                free(indexOid);
 
343
 
 
344
                if (exact) {
 
345
                    if (result == 0) {
 
346
                        uptr = nptr;
 
347
                    }
 
348
                } else {
 
349
                    if (result == 0) {
 
350
                        /*
 
351
                         * found an exact match.  Need the next one for !exact 
 
352
                         */
 
353
                        uptr = nptr->next;
 
354
                    } else if (result == -1) {
 
355
                        uptr = nptr;
 
356
                        break;
 
357
                    }
 
358
                }
 
359
            }
 
360
        }                       /* endif -- name <= vp->name */
 
361
 
 
362
        /*
 
363
         * if uptr is NULL and exact we need to continue for creates 
 
364
         */
 
365
        if (uptr == NULL && !exact)
 
366
            return (NULL);
 
367
 
 
368
        if (uptr) {
 
369
            indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
 
370
            *length = len;
 
371
            memmove(name, indexOid, len * sizeof(oid));
 
372
            DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
 
373
            for (i = 0; i < (int) uptr->engineIDLen; i++) {
 
374
                DEBUGMSG(("usmUser", " %x", uptr->engineID[i]));
 
375
            }
 
376
            DEBUGMSG(("usmUser", "\n  -> OID: "));
 
377
            DEBUGMSGOID(("usmUser", indexOid, len));
 
378
            DEBUGMSG(("usmUser", "\n"));
 
379
 
 
380
            free(indexOid);
 
381
        }
 
382
    } else {
 
383
        if (header_generic(vp, name, length, exact, var_len, write_method))
 
384
            return 0;
 
385
    }                           /* endif -- vp->magic != USMUSERSPINLOCK */
 
386
 
 
387
    switch (vp->magic) {
 
388
    case USMUSERSPINLOCK:
 
389
        *write_method = write_usmUserSpinLock;
 
390
        long_ret = usmUserSpinLock;
 
391
        return (unsigned char *) &long_ret;
 
392
 
 
393
    case USMUSERSECURITYNAME:
 
394
        if (uptr) {
 
395
            *var_len = strlen(uptr->secName);
 
396
            return (unsigned char *) uptr->secName;
 
397
        }
 
398
        return NULL;
 
399
 
 
400
    case USMUSERCLONEFROM:
 
401
        *write_method = write_usmUserCloneFrom;
 
402
        if (uptr) {
 
403
            objid[0] = 0;       /* "When this object is read, the ZeroDotZero OID */
 
404
            objid[1] = 0;       /*  is returned." */
 
405
            *var_len = sizeof(oid) * 2;
 
406
            return (unsigned char *) objid;
 
407
        }
 
408
        return NULL;
 
409
 
 
410
    case USMUSERAUTHPROTOCOL:
 
411
        *write_method = write_usmUserAuthProtocol;
 
412
        if (uptr) {
 
413
            *var_len = uptr->authProtocolLen * sizeof(oid);
 
414
            return (u_char *) uptr->authProtocol;
 
415
        }
 
416
        return NULL;
 
417
 
 
418
    case USMUSERAUTHKEYCHANGE:
 
419
    case USMUSEROWNAUTHKEYCHANGE:
 
420
        /*
 
421
         * we treat these the same, and let the calling module
 
422
         * distinguish between them 
 
423
         */
 
424
        *write_method = write_usmUserAuthKeyChange;
 
425
        if (uptr) {
 
426
            *string = 0;        /* always return a NULL string */
 
427
            *var_len = 0;
 
428
            return string;
 
429
        }
 
430
        return NULL;
 
431
 
 
432
    case USMUSERPRIVPROTOCOL:
 
433
        *write_method = write_usmUserPrivProtocol;
 
434
        if (uptr) {
 
435
            *var_len = uptr->privProtocolLen * sizeof(oid);
 
436
            return (u_char *) uptr->privProtocol;
 
437
        }
 
438
        return NULL;
 
439
 
 
440
    case USMUSERPRIVKEYCHANGE:
 
441
    case USMUSEROWNPRIVKEYCHANGE:
 
442
        /*
 
443
         * we treat these the same, and let the calling module
 
444
         * distinguish between them 
 
445
         */
 
446
        *write_method = write_usmUserPrivKeyChange;
 
447
        if (uptr) {
 
448
            *string = 0;        /* always return a NULL string */
 
449
            *var_len = 0;
 
450
            return string;
 
451
        }
 
452
        return NULL;
 
453
 
 
454
    case USMUSERPUBLIC:
 
455
        *write_method = write_usmUserPublic;
 
456
        if (uptr) {
 
457
            if (uptr->userPublicString) {
 
458
                *var_len = strlen((char *) uptr->userPublicString);
 
459
                return uptr->userPublicString;
 
460
            }
 
461
            *string = 0;
 
462
            *var_len = 0;       /* return an empty string if the public
 
463
                                 * string hasn't been defined yet */
 
464
            return string;
 
465
        }
 
466
        return NULL;
 
467
 
 
468
    case USMUSERSTORAGETYPE:
 
469
        *write_method = write_usmUserStorageType;
 
470
        if (uptr) {
 
471
            long_ret = uptr->userStorageType;
 
472
            return (unsigned char *) &long_ret;
 
473
        }
 
474
        return NULL;
 
475
 
 
476
    case USMUSERSTATUS:
 
477
        *write_method = write_usmUserStatus;
 
478
        if (uptr) {
 
479
            long_ret = uptr->userStatus;
 
480
            return (unsigned char *) &long_ret;
 
481
        }
 
482
        return NULL;
 
483
 
 
484
    default:
 
485
        DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUser\n",
 
486
                    vp->magic));
 
487
    }
 
488
    return 0;
 
489
 
 
490
}                               /* end var_usmUser() */
 
491
 
 
492
/*
 
493
 * write_usmUserSpinLock(): called when a set is performed on the
 
494
 * usmUserSpinLock object 
 
495
 */
 
496
int
 
497
write_usmUserSpinLock(int action,
 
498
                      u_char * var_val,
 
499
                      u_char var_val_type,
 
500
                      size_t var_val_len,
 
501
                      u_char * statP, oid * name, size_t name_len)
 
502
{
 
503
    /*
 
504
     * variables we may use later 
 
505
     */
 
506
    static long     long_ret;
 
507
 
 
508
    if (var_val_type != ASN_INTEGER) {
 
509
        DEBUGMSGTL(("usmUser",
 
510
                    "write to usmUserSpinLock not ASN_INTEGER\n"));
 
511
        return SNMP_ERR_WRONGTYPE;
 
512
    }
 
513
    if (var_val_len > sizeof(long_ret)) {
 
514
        DEBUGMSGTL(("usmUser", "write to usmUserSpinLock: bad length\n"));
 
515
        return SNMP_ERR_WRONGLENGTH;
 
516
    }
 
517
    long_ret = *((long *) var_val);
 
518
    if (long_ret != (long) usmUserSpinLock)
 
519
        return SNMP_ERR_INCONSISTENTVALUE;
 
520
    if (action == COMMIT) {
 
521
        if (usmUserSpinLock == 2147483647)
 
522
            usmUserSpinLock = 0;
 
523
        else
 
524
            usmUserSpinLock++;
 
525
    }
 
526
    return SNMP_ERR_NOERROR;
 
527
}                               /* end write_usmUserSpinLock() */
 
528
 
 
529
/*******************************************************************-o-******
 
530
 * write_usmUserCloneFrom
 
531
 *
 
532
 * Parameters:
 
533
 *       action
 
534
 *      *var_val
 
535
 *       var_val_type
 
536
 *       var_val_len
 
537
 *      *statP          (UNUSED)
 
538
 *      *name           OID of user to clone from.
 
539
 *       name_len
 
540
 *      
 
541
 * Returns:
 
542
 *      SNMP_ERR_NOERROR                On success  -OR-  If user exists
 
543
 *                                        and has already been cloned.
 
544
 *      SNMP_ERR_GENERR                 Local function call failures.
 
545
 *      SNMP_ERR_INCONSISTENTNAME       'name' does not exist in user list
 
546
 *                                        -OR-  user to clone from != RS_ACTIVE.
 
547
 *      SNMP_ERR_WRONGLENGTH            OID length > than local buffer size.
 
548
 *      SNMP_ERR_WRONGTYPE              ASN_OBJECT_ID is wrong.
 
549
 *
 
550
 *
 
551
 * XXX:  should handle action=UNDO's.
 
552
 */
 
553
int
 
554
write_usmUserCloneFrom(int action,
 
555
                       u_char * var_val,
 
556
                       u_char var_val_type,
 
557
                       size_t var_val_len,
 
558
                       u_char * statP, oid * name, size_t name_len)
 
559
{
 
560
    struct usmUser *uptr, *cloneFrom;
 
561
 
 
562
    if (action == RESERVE1) {
 
563
        if (var_val_type != ASN_OBJECT_ID) {
 
564
            DEBUGMSGTL(("usmUser",
 
565
                        "write to usmUserCloneFrom not ASN_OBJECT_ID\n"));
 
566
            return SNMP_ERR_WRONGTYPE;
 
567
        }
 
568
        if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
 
569
            var_val_len % sizeof(oid) != 0) {
 
570
            DEBUGMSGTL(("usmUser",
 
571
                        "write to usmUserCloneFrom: bad length\n"));
 
572
            return SNMP_ERR_WRONGLENGTH;
 
573
        }
 
574
    } else if (action == RESERVE2) {
 
575
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
576
            /*
 
577
             * We don't allow creations here.  
 
578
             */
 
579
            return SNMP_ERR_INCONSISTENTNAME;
 
580
        }
 
581
 
 
582
        /*
 
583
         * Has the user already been cloned?  If so, writes to this variable
 
584
         * are defined to have no effect and to produce no error.  
 
585
         */
 
586
        if (uptr->cloneFrom != NULL) {
 
587
            return SNMP_ERR_NOERROR;
 
588
        }
 
589
 
 
590
        cloneFrom =
 
591
            usm_parse_user((oid *) var_val, var_val_len / sizeof(oid));
 
592
        if (cloneFrom == NULL || cloneFrom->userStatus != SNMP_ROW_ACTIVE) {
 
593
            return SNMP_ERR_INCONSISTENTNAME;
 
594
        }
 
595
        uptr->cloneFrom = snmp_duplicate_objid((oid *) var_val,
 
596
                                               var_val_len / sizeof(oid));
 
597
        usm_cloneFrom_user(cloneFrom, uptr);
 
598
 
 
599
        if (usmStatusCheck(uptr) && uptr->userStatus == SNMP_ROW_NOTREADY) {
 
600
            uptr->userStatus = SNMP_ROW_NOTINSERVICE;
 
601
        }
 
602
    }
 
603
 
 
604
    return SNMP_ERR_NOERROR;
 
605
}
 
606
 
 
607
/*******************************************************************-o-******
 
608
 * write_usmUserAuthProtocol
 
609
 *
 
610
 * Parameters:
 
611
 *       action
 
612
 *      *var_val        OID of auth transform to set.
 
613
 *       var_val_type
 
614
 *       var_val_len
 
615
 *      *statP
 
616
 *      *name           OID of user upon which to perform set operation.
 
617
 *       name_len
 
618
 *      
 
619
 * Returns:
 
620
 *      SNMP_ERR_NOERROR                On success.
 
621
 *      SNMP_ERR_GENERR
 
622
 *      SNMP_ERR_INCONSISTENTVALUE
 
623
 *      SNMP_ERR_NOSUCHNAME
 
624
 *      SNMP_ERR_WRONGLENGTH
 
625
 *      SNMP_ERR_WRONGTYPE
 
626
 */
 
627
int
 
628
write_usmUserAuthProtocol(int action,
 
629
                          u_char * var_val,
 
630
                          u_char var_val_type,
 
631
                          size_t var_val_len,
 
632
                          u_char * statP, oid * name, size_t name_len)
 
633
{
 
634
    static oid     *optr;
 
635
    static size_t   olen;
 
636
    static int      resetOnFail;
 
637
    struct usmUser *uptr;
 
638
 
 
639
    if (action == RESERVE1) {
 
640
        resetOnFail = 0;
 
641
        if (var_val_type != ASN_OBJECT_ID) {
 
642
            DEBUGMSGTL(("usmUser",
 
643
                        "write to usmUserAuthProtocol not ASN_OBJECT_ID\n"));
 
644
            return SNMP_ERR_WRONGTYPE;
 
645
        }
 
646
        if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
 
647
            var_val_len % sizeof(oid) != 0) {
 
648
            DEBUGMSGTL(("usmUser",
 
649
                        "write to usmUserAuthProtocol: bad length\n"));
 
650
            return SNMP_ERR_WRONGLENGTH;
 
651
        }
 
652
    } else if (action == RESERVE2) {
 
653
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
654
            return SNMP_ERR_INCONSISTENTNAME;
 
655
        }
 
656
 
 
657
        if (uptr->userStatus == RS_ACTIVE
 
658
            || uptr->userStatus == RS_NOTREADY
 
659
            || uptr->userStatus == RS_NOTINSERVICE) {
 
660
            /*
 
661
             * The authProtocol is already set.  It is only legal to CHANGE it
 
662
             * to usmNoAuthProtocol...  
 
663
             */
 
664
            if (snmp_oid_compare
 
665
                ((oid *) var_val, var_val_len / sizeof(oid),
 
666
                 usmNoAuthProtocol,
 
667
                 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0) {
 
668
                /*
 
669
                 * ... and then only if the privProtocol is equal to
 
670
                 * usmNoPrivProtocol.  
 
671
                 */
 
672
                if (snmp_oid_compare
 
673
                    (uptr->privProtocol, uptr->privProtocolLen,
 
674
                     usmNoPrivProtocol,
 
675
                     sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
 
676
                    return SNMP_ERR_INCONSISTENTVALUE;
 
677
                }
 
678
                optr = uptr->authProtocol;
 
679
                olen = uptr->authProtocolLen;
 
680
                resetOnFail = 1;
 
681
                uptr->authProtocol = snmp_duplicate_objid((oid *) var_val,
 
682
                                                          var_val_len /
 
683
                                                          sizeof(oid));
 
684
                if (uptr->authProtocol == NULL) {
 
685
                    return SNMP_ERR_RESOURCEUNAVAILABLE;
 
686
                }
 
687
                uptr->authProtocolLen = var_val_len / sizeof(oid);
 
688
            } else
 
689
                if (snmp_oid_compare
 
690
                    ((oid *) var_val, var_val_len / sizeof(oid),
 
691
                     uptr->authProtocol, uptr->authProtocolLen) == 0) {
 
692
                /*
 
693
                 * But it's also okay to set it to the same thing as it
 
694
                 * currently is.  
 
695
                 */
 
696
                return SNMP_ERR_NOERROR;
 
697
            } else {
 
698
                return SNMP_ERR_INCONSISTENTVALUE;
 
699
            }
 
700
        } else {
 
701
            /*
 
702
             * This row is under creation.  It's okay to set
 
703
             * usmUserAuthProtocol to any valid authProtocol but it will be
 
704
             * overwritten when usmUserCloneFrom is set (so don't write it if
 
705
             * that has already been set).  
 
706
             */
 
707
 
 
708
            if (snmp_oid_compare
 
709
                ((oid *) var_val, var_val_len / sizeof(oid),
 
710
                 usmNoAuthProtocol,
 
711
                 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0
 
712
                || snmp_oid_compare((oid *) var_val,
 
713
                                    var_val_len / sizeof(oid),
 
714
                                    usmHMACMD5AuthProtocol,
 
715
                                    sizeof(usmHMACMD5AuthProtocol) /
 
716
                                    sizeof(oid)) == 0
 
717
                || snmp_oid_compare((oid *) var_val,
 
718
                                    var_val_len / sizeof(oid),
 
719
                                    usmHMACSHA1AuthProtocol,
 
720
                                    sizeof(usmHMACSHA1AuthProtocol) /
 
721
                                    sizeof(oid)) == 0) {
 
722
                if (uptr->cloneFrom != NULL) {
 
723
                    optr = uptr->authProtocol;
 
724
                    olen = uptr->authProtocolLen;
 
725
                    resetOnFail = 1;
 
726
                    uptr->authProtocol =
 
727
                        snmp_duplicate_objid((oid *) var_val,
 
728
                                             var_val_len / sizeof(oid));
 
729
                    if (uptr->authProtocol == NULL) {
 
730
                        return SNMP_ERR_RESOURCEUNAVAILABLE;
 
731
                    }
 
732
                    uptr->authProtocolLen = var_val_len / sizeof(oid);
 
733
                }
 
734
            } else {
 
735
                /*
 
736
                 * Unknown authentication protocol.  
 
737
                 */
 
738
                return SNMP_ERR_WRONGVALUE;
 
739
            }
 
740
        }
 
741
    } else if (action == COMMIT) {
 
742
        SNMP_FREE(optr);
 
743
        optr = NULL;
 
744
    } else if (action == FREE || action == UNDO) {
 
745
        if ((uptr = usm_parse_user(name, name_len)) != NULL) {
 
746
            if (resetOnFail) {
 
747
                SNMP_FREE(uptr->authProtocol);
 
748
                uptr->authProtocol = optr;
 
749
                uptr->authProtocolLen = olen;
 
750
            }
 
751
        }
 
752
    }
 
753
    return SNMP_ERR_NOERROR;
 
754
}                               /* end write_usmUserAuthProtocol() */
 
755
 
 
756
/*******************************************************************-o-******
 
757
 * write_usmUserAuthKeyChange
 
758
 *
 
759
 * Parameters:
 
760
 *       action         
 
761
 *      *var_val        Octet string representing new KeyChange value.
 
762
 *       var_val_type
 
763
 *       var_val_len
 
764
 *      *statP          (UNUSED)
 
765
 *      *name           OID of user upon which to perform set operation.
 
766
 *       name_len
 
767
 *      
 
768
 * Returns:
 
769
 *      SNMP_ERR_NOERR          Success.
 
770
 *      SNMP_ERR_WRONGTYPE      
 
771
 *      SNMP_ERR_WRONGLENGTH    
 
772
 *      SNMP_ERR_NOSUCHNAME     
 
773
 *      SNMP_ERR_GENERR
 
774
 *
 
775
 * Note: This function handles both the usmUserAuthKeyChange and
 
776
 *       usmUserOwnAuthKeyChange objects.  We are not passed the name
 
777
 *       of the user requseting the keychange, so we leave this to the
 
778
 *       calling module to verify when and if we should be called.  To
 
779
 *       change this would require a change in the mib module API to
 
780
 *       pass in the securityName requesting the change.
 
781
 *
 
782
 * XXX:  should handle action=UNDO's.
 
783
 */
 
784
int
 
785
write_usmUserAuthKeyChange(int action,
 
786
                           u_char * var_val,
 
787
                           u_char var_val_type,
 
788
                           size_t var_val_len,
 
789
                           u_char * statP, oid * name, size_t name_len)
 
790
{
 
791
    struct usmUser *uptr;
 
792
    unsigned char   buf[SNMP_MAXBUF_SMALL];
 
793
    size_t          buflen = SNMP_MAXBUF_SMALL;
 
794
    const char      fnAuthKey[] = "write_usmUserAuthKeyChange";
 
795
    const char      fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange";
 
796
    const char     *fname;
 
797
    static unsigned char *oldkey;
 
798
    static size_t   oldkeylen;
 
799
    static int      resetOnFail;
 
800
 
 
801
    if (name[USM_MIB_LENGTH - 1] == 6) {
 
802
        fname = fnAuthKey;
 
803
    } else {
 
804
        fname = fnOwnAuthKey;
 
805
    }
 
806
 
 
807
    if (action == RESERVE1) {
 
808
        resetOnFail = 0;
 
809
        if (var_val_type != ASN_OCTET_STR) {
 
810
            DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STR\n",
 
811
                        fname));
 
812
            return SNMP_ERR_WRONGTYPE;
 
813
        }
 
814
        if (var_val_len == 0) {
 
815
            return SNMP_ERR_WRONGLENGTH;
 
816
        }
 
817
    } else if (action == RESERVE2) {
 
818
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
819
            return SNMP_ERR_INCONSISTENTNAME;
 
820
        } else {
 
821
            if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
 
822
                                 usmHMACMD5AuthProtocol,
 
823
                                 sizeof(usmHMACMD5AuthProtocol) /
 
824
                                 sizeof(oid)) == 0) {
 
825
                if (var_val_len != 0 && var_val_len != 32) {
 
826
                    return SNMP_ERR_WRONGLENGTH;
 
827
                }
 
828
            } else
 
829
                if (snmp_oid_compare
 
830
                    (uptr->authProtocol, uptr->authProtocolLen,
 
831
                     usmHMACSHA1AuthProtocol,
 
832
                     sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid)) == 0) {
 
833
                if (var_val_len != 0 && var_val_len != 40) {
 
834
                    return SNMP_ERR_WRONGLENGTH;
 
835
                }
 
836
            }
 
837
        }
 
838
    } else if (action == ACTION) {
 
839
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
840
            return SNMP_ERR_INCONSISTENTNAME;
 
841
        }
 
842
        if (uptr->cloneFrom == NULL) {
 
843
            return SNMP_ERR_INCONSISTENTNAME;
 
844
        }
 
845
        if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
 
846
                             usmNoAuthProtocol,
 
847
                             sizeof(usmNoAuthProtocol) / sizeof(oid)) ==
 
848
            0) {
 
849
            /*
 
850
             * "When the value of the corresponding usmUserAuthProtocol is
 
851
             * usmNoAuthProtocol, then a set is successful, but effectively
 
852
             * is a no-op."  
 
853
             */
 
854
            DEBUGMSGTL(("usmUser",
 
855
                        "%s: noAuthProtocol keyChange... success!\n",
 
856
                        fname));
 
857
            return SNMP_ERR_NOERROR;
 
858
        }
 
859
 
 
860
        /*
 
861
         * Change the key.  
 
862
         */
 
863
        DEBUGMSGTL(("usmUser", "%s: changing auth key for user %s\n",
 
864
                    fname, uptr->secName));
 
865
 
 
866
        if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
 
867
                             uptr->authKey, uptr->authKeyLen,
 
868
                             var_val, var_val_len,
 
869
                             buf, &buflen) != SNMPERR_SUCCESS) {
 
870
            DEBUGMSGTL(("usmUser", "%s: ... failed\n", fname));
 
871
            return SNMP_ERR_GENERR;
 
872
        }
 
873
        DEBUGMSGTL(("usmUser", "%s: ... succeeded\n", fname));
 
874
        resetOnFail = 1;
 
875
        oldkey = uptr->authKey;
 
876
        oldkeylen = uptr->authKeyLen;
 
877
        memdup(&uptr->authKey, buf, buflen);
 
878
        if (uptr->authKey == NULL) {
 
879
            return SNMP_ERR_RESOURCEUNAVAILABLE;
 
880
        }
 
881
        uptr->authKeyLen = buflen;
 
882
    } else if (action == COMMIT) {
 
883
        SNMP_FREE(oldkey);
 
884
        oldkey = NULL;
 
885
    } else if (action == UNDO) {
 
886
        if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
 
887
            SNMP_FREE(uptr->authKey);
 
888
            uptr->authKey = oldkey;
 
889
            uptr->authKeyLen = oldkeylen;
 
890
        }
 
891
    }
 
892
 
 
893
    return SNMP_ERR_NOERROR;
 
894
}                               /* end write_usmUserAuthKeyChange() */
 
895
 
 
896
int
 
897
write_usmUserPrivProtocol(int action,
 
898
                          u_char * var_val,
 
899
                          u_char var_val_type,
 
900
                          size_t var_val_len,
 
901
                          u_char * statP, oid * name, size_t name_len)
 
902
{
 
903
    static oid     *optr;
 
904
    static size_t   olen;
 
905
    static int      resetOnFail;
 
906
    struct usmUser *uptr;
 
907
 
 
908
    if (action == RESERVE1) {
 
909
        resetOnFail = 0;
 
910
        if (var_val_type != ASN_OBJECT_ID) {
 
911
            DEBUGMSGTL(("usmUser",
 
912
                        "write to usmUserPrivProtocol not ASN_OBJECT_ID\n"));
 
913
            return SNMP_ERR_WRONGTYPE;
 
914
        }
 
915
        if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
 
916
            var_val_len % sizeof(oid) != 0) {
 
917
            DEBUGMSGTL(("usmUser",
 
918
                        "write to usmUserPrivProtocol: bad length\n"));
 
919
            return SNMP_ERR_WRONGLENGTH;
 
920
        }
 
921
    } else if (action == RESERVE2) {
 
922
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
923
            return SNMP_ERR_INCONSISTENTNAME;
 
924
        }
 
925
 
 
926
        if (uptr->userStatus == RS_ACTIVE
 
927
            || uptr->userStatus == RS_NOTREADY
 
928
            || uptr->userStatus == RS_NOTINSERVICE) {
 
929
            /*
 
930
             * The privProtocol is already set.  It is only legal to CHANGE it
 
931
             * to usmNoPrivProtocol.  
 
932
             */
 
933
            if (snmp_oid_compare
 
934
                ((oid *) var_val, var_val_len / sizeof(oid),
 
935
                 usmNoPrivProtocol,
 
936
                 sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0) {
 
937
                resetOnFail = 1;
 
938
                optr = uptr->privProtocol;
 
939
                olen = uptr->privProtocolLen;
 
940
                uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
 
941
                                                          var_val_len /
 
942
                                                          sizeof(oid));
 
943
                if (uptr->privProtocol == NULL) {
 
944
                    return SNMP_ERR_RESOURCEUNAVAILABLE;
 
945
                }
 
946
                uptr->privProtocolLen = var_val_len / sizeof(oid);
 
947
            } else
 
948
                if (snmp_oid_compare
 
949
                    ((oid *) var_val, var_val_len / sizeof(oid),
 
950
                     uptr->privProtocol, uptr->privProtocolLen) == 0) {
 
951
                /*
 
952
                 * But it's also okay to set it to the same thing as it
 
953
                 * currently is.  
 
954
                 */
 
955
                return SNMP_ERR_NOERROR;
 
956
            } else {
 
957
                return SNMP_ERR_INCONSISTENTVALUE;
 
958
            }
 
959
        } else {
 
960
            /*
 
961
             * This row is under creation.  It's okay to set
 
962
             * usmUserPrivProtocol to any valid privProtocol with the proviso
 
963
             * that if usmUserAuthProtocol is set to usmNoAuthProtocol, it may
 
964
             * only be set to usmNoPrivProtocol.  The value will be overwritten
 
965
             * when usmUserCloneFrom is set (so don't write it if that has
 
966
             * already been set).  
 
967
             */
 
968
            if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
 
969
                                 usmNoAuthProtocol,
 
970
                                 sizeof(usmNoAuthProtocol) /
 
971
                                 sizeof(oid)) == 0) {
 
972
                if (snmp_oid_compare
 
973
                    ((oid *) var_val, var_val_len / sizeof(oid),
 
974
                     usmNoPrivProtocol,
 
975
                     sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
 
976
                    return SNMP_ERR_INCONSISTENTVALUE;
 
977
                }
 
978
            } else {
 
979
                if (snmp_oid_compare
 
980
                    ((oid *) var_val, var_val_len / sizeof(oid),
 
981
                     usmNoPrivProtocol,
 
982
                     sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
 
983
                    && snmp_oid_compare((oid *) var_val,
 
984
                                        var_val_len / sizeof(oid),
 
985
                                        usmDESPrivProtocol,
 
986
                                        sizeof(usmDESPrivProtocol) /
 
987
                                        sizeof(oid) != 0)) {
 
988
                    return SNMP_ERR_WRONGVALUE;
 
989
                }
 
990
            }
 
991
            resetOnFail = 1;
 
992
            optr = uptr->privProtocol;
 
993
            olen = uptr->privProtocolLen;
 
994
            uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
 
995
                                                      var_val_len /
 
996
                                                      sizeof(oid));
 
997
            if (uptr->privProtocol == NULL) {
 
998
                return SNMP_ERR_RESOURCEUNAVAILABLE;
 
999
            }
 
1000
            uptr->privProtocolLen = var_val_len / sizeof(oid);
 
1001
        }
 
1002
    } else if (action == COMMIT) {
 
1003
        SNMP_FREE(optr);
 
1004
        optr = NULL;
 
1005
    } else if (action == FREE || action == UNDO) {
 
1006
        if ((uptr = usm_parse_user(name, name_len)) != NULL) {
 
1007
            if (resetOnFail) {
 
1008
                SNMP_FREE(uptr->privProtocol);
 
1009
                uptr->privProtocol = optr;
 
1010
                uptr->privProtocolLen = olen;
 
1011
            }
 
1012
        }
 
1013
    }
 
1014
 
 
1015
    return SNMP_ERR_NOERROR;
 
1016
}                               /* end write_usmUserPrivProtocol() */
 
1017
 
 
1018
/*
 
1019
 * Note: This function handles both the usmUserPrivKeyChange and
 
1020
 *       usmUserOwnPrivKeyChange objects.  We are not passed the name
 
1021
 *       of the user requseting the keychange, so we leave this to the
 
1022
 *       calling module to verify when and if we should be called.  To
 
1023
 *       change this would require a change in the mib module API to
 
1024
 *       pass in the securityName requesting the change.
 
1025
 *
 
1026
 */
 
1027
int
 
1028
write_usmUserPrivKeyChange(int action,
 
1029
                           u_char * var_val,
 
1030
                           u_char var_val_type,
 
1031
                           size_t var_val_len,
 
1032
                           u_char * statP, oid * name, size_t name_len)
 
1033
{
 
1034
    struct usmUser *uptr;
 
1035
    unsigned char   buf[SNMP_MAXBUF_SMALL];
 
1036
    size_t          buflen = SNMP_MAXBUF_SMALL;
 
1037
    const char      fnPrivKey[] = "write_usmUserPrivKeyChange";
 
1038
    const char      fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange";
 
1039
    const char     *fname;
 
1040
    static unsigned char *oldkey;
 
1041
    static size_t   oldkeylen;
 
1042
    static int      resetOnFail;
 
1043
 
 
1044
    if (name[USM_MIB_LENGTH - 1] == 9) {
 
1045
        fname = fnPrivKey;
 
1046
    } else {
 
1047
        fname = fnOwnPrivKey;
 
1048
    }
 
1049
 
 
1050
    if (action == RESERVE1) {
 
1051
        resetOnFail = 0;
 
1052
        if (var_val_type != ASN_OCTET_STR) {
 
1053
            DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STR\n",
 
1054
                        fname));
 
1055
            return SNMP_ERR_WRONGTYPE;
 
1056
        }
 
1057
        if (var_val_len == 0) {
 
1058
            return SNMP_ERR_WRONGLENGTH;
 
1059
        }
 
1060
    } else if (action == RESERVE2) {
 
1061
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
1062
            return SNMP_ERR_INCONSISTENTNAME;
 
1063
        } else {
 
1064
            if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
 
1065
                                 usmDESPrivProtocol,
 
1066
                                 sizeof(usmDESPrivProtocol) /
 
1067
                                 sizeof(oid)) == 0) {
 
1068
                if (var_val_len != 0 && var_val_len != 32) {
 
1069
                    return SNMP_ERR_WRONGLENGTH;
 
1070
                }
 
1071
            }
 
1072
        }
 
1073
    } else if (action == ACTION) {
 
1074
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
1075
            return SNMP_ERR_INCONSISTENTNAME;
 
1076
        }
 
1077
        if (uptr->cloneFrom == NULL) {
 
1078
            return SNMP_ERR_INCONSISTENTNAME;
 
1079
        }
 
1080
        if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
 
1081
                             usmNoPrivProtocol,
 
1082
                             sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
 
1083
            0) {
 
1084
            /*
 
1085
             * "When the value of the corresponding usmUserPrivProtocol is
 
1086
             * usmNoPrivProtocol, then a set is successful, but effectively
 
1087
             * is a no-op."  
 
1088
             */
 
1089
            DEBUGMSGTL(("usmUser",
 
1090
                        "%s: noPrivProtocol keyChange... success!\n",
 
1091
                        fname));
 
1092
            return SNMP_ERR_NOERROR;
 
1093
        }
 
1094
 
 
1095
        /*
 
1096
         * Change the key. 
 
1097
         */
 
1098
        DEBUGMSGTL(("usmUser", "%s: changing priv key for user %s\n",
 
1099
                    fname, uptr->secName));
 
1100
 
 
1101
        if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
 
1102
                             uptr->privKey, uptr->privKeyLen,
 
1103
                             var_val, var_val_len,
 
1104
                             buf, &buflen) != SNMPERR_SUCCESS) {
 
1105
            DEBUGMSGTL(("usmUser", "%s: ... failed\n", fname));
 
1106
            return SNMP_ERR_GENERR;
 
1107
        }
 
1108
        DEBUGMSGTL(("usmUser", "%s: ... succeeded\n", fname));
 
1109
        resetOnFail = 1;
 
1110
        oldkey = uptr->privKey;
 
1111
        oldkeylen = uptr->privKeyLen;
 
1112
        memdup(&uptr->privKey, buf, buflen);
 
1113
        if (uptr->privKey == NULL) {
 
1114
            return SNMP_ERR_RESOURCEUNAVAILABLE;
 
1115
        }
 
1116
        uptr->privKeyLen = buflen;
 
1117
    } else if (action == COMMIT) {
 
1118
        SNMP_FREE(oldkey);
 
1119
        oldkey = NULL;
 
1120
    } else if (action == UNDO) {
 
1121
        if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
 
1122
            SNMP_FREE(uptr->privKey);
 
1123
            uptr->privKey = oldkey;
 
1124
            uptr->privKeyLen = oldkeylen;
 
1125
        }
 
1126
    }
 
1127
 
 
1128
    return SNMP_ERR_NOERROR;
 
1129
}                               /* end write_usmUserPrivKeyChange() */
 
1130
 
 
1131
int
 
1132
write_usmUserPublic(int action,
 
1133
                    u_char * var_val,
 
1134
                    u_char var_val_type,
 
1135
                    size_t var_val_len,
 
1136
                    u_char * statP, oid * name, size_t name_len)
 
1137
{
 
1138
    struct usmUser *uptr = NULL;
 
1139
 
 
1140
    if (var_val_type != ASN_OCTET_STR) {
 
1141
        DEBUGMSGTL(("usmUser",
 
1142
                    "write to usmUserPublic not ASN_OCTET_STR\n"));
 
1143
        return SNMP_ERR_WRONGTYPE;
 
1144
    }
 
1145
    if (var_val_len < 0 || var_val_len > 32) {
 
1146
        DEBUGMSGTL(("usmUser", "write to usmUserPublic: bad length\n"));
 
1147
        return SNMP_ERR_WRONGLENGTH;
 
1148
    }
 
1149
    if (action == COMMIT) {
 
1150
        /*
 
1151
         * don't allow creations here 
 
1152
         */
 
1153
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
1154
            return SNMP_ERR_NOSUCHNAME;
 
1155
        }
 
1156
        if (uptr->userPublicString)
 
1157
            free(uptr->userPublicString);
 
1158
        uptr->userPublicString = (u_char *) malloc(var_val_len + 1);
 
1159
        if (uptr->userPublicString == NULL) {
 
1160
            return SNMP_ERR_GENERR;
 
1161
        }
 
1162
        memcpy(uptr->userPublicString, var_val, var_val_len);
 
1163
        uptr->userPublicString[var_val_len] = 0;
 
1164
        DEBUGMSG(("usmUser", "setting public string: %d - %s\n",
 
1165
                  var_val_len, uptr->userPublicString));
 
1166
    }
 
1167
    return SNMP_ERR_NOERROR;
 
1168
}                               /* end write_usmUserPublic() */
 
1169
 
 
1170
int
 
1171
write_usmUserStorageType(int action,
 
1172
                         u_char * var_val,
 
1173
                         u_char var_val_type,
 
1174
                         size_t var_val_len,
 
1175
                         u_char * statP, oid * name, size_t name_len)
 
1176
{
 
1177
    long            long_ret = *((long *) var_val);
 
1178
    static long     oldValue;
 
1179
    struct usmUser *uptr;
 
1180
    static int      resetOnFail;
 
1181
 
 
1182
    if (action == RESERVE1) {
 
1183
        resetOnFail = 0;
 
1184
        if (var_val_type != ASN_INTEGER) {
 
1185
            DEBUGMSGTL(("usmUser",
 
1186
                        "write to usmUserStorageType not ASN_INTEGER\n"));
 
1187
            return SNMP_ERR_WRONGTYPE;
 
1188
        }
 
1189
        if (var_val_len != sizeof(long)) {
 
1190
            DEBUGMSGTL(("usmUser",
 
1191
                        "write to usmUserStorageType: bad length\n"));
 
1192
            return SNMP_ERR_WRONGLENGTH;
 
1193
        }
 
1194
        if (long_ret < 1 || long_ret > 5) {
 
1195
            return SNMP_ERR_WRONGVALUE;
 
1196
        }
 
1197
    } else if (action == RESERVE2) {
 
1198
        if ((uptr = usm_parse_user(name, name_len)) == NULL) {
 
1199
            return SNMP_ERR_INCONSISTENTNAME;
 
1200
        }
 
1201
        if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
 
1202
            (uptr->userStorageType == ST_VOLATILE ||
 
1203
             uptr->userStorageType == ST_NONVOLATILE)) {
 
1204
            oldValue = uptr->userStorageType;
 
1205
            uptr->userStorageType = long_ret;
 
1206
            resetOnFail = 1;
 
1207
        } else {
 
1208
            /*
 
1209
             * From RFC2574:
 
1210
             * 
 
1211
             * "Note that any user who employs authentication or privacy must
 
1212
             * allow its secret(s) to be updated and thus cannot be 'readOnly'.
 
1213
             * 
 
1214
             * If an initial set operation tries to set the value to 'readOnly'
 
1215
             * for a user who employs authentication or privacy, then an
 
1216
             * 'inconsistentValue' error must be returned.  Note that if the
 
1217
             * value has been previously set (implicit or explicit) to any
 
1218
             * value, then the rules as defined in the StorageType Textual
 
1219
             * Convention apply.  
 
1220
             */
 
1221
            DEBUGMSGTL(("usmUser",
 
1222
                        "long_ret %d uptr->st %d uptr->status %d\n",
 
1223
                        long_ret, uptr->userStorageType,
 
1224
                        uptr->userStatus));
 
1225
 
 
1226
            if (long_ret == ST_READONLY &&
 
1227
                uptr->userStorageType != ST_READONLY &&
 
1228
                (uptr->userStatus == RS_ACTIVE ||
 
1229
                 uptr->userStatus == RS_NOTINSERVICE)) {
 
1230
                return SNMP_ERR_WRONGVALUE;
 
1231
            } else if (long_ret == ST_READONLY &&
 
1232
                       (snmp_oid_compare
 
1233
                        (uptr->privProtocol, uptr->privProtocolLen,
 
1234
                         usmNoPrivProtocol,
 
1235
                         sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
 
1236
                        || snmp_oid_compare(uptr->authProtocol,
 
1237
                                            uptr->authProtocolLen,
 
1238
                                            usmNoAuthProtocol,
 
1239
                                            sizeof(usmNoAuthProtocol) /
 
1240
                                            sizeof(oid)) != 0)) {
 
1241
                return SNMP_ERR_INCONSISTENTVALUE;
 
1242
            } else {
 
1243
                return SNMP_ERR_WRONGVALUE;
 
1244
            }
 
1245
        }
 
1246
    } else if (action == UNDO || action == FREE) {
 
1247
        if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
 
1248
            uptr->userStorageType = oldValue;
 
1249
        }
 
1250
    }
 
1251
    return SNMP_ERR_NOERROR;
 
1252
}                               /* end write_usmUserStorageType() */
 
1253
 
 
1254
/*
 
1255
 * Return 1 if enough objects have been set up to transition rowStatus to
 
1256
 * notInService(2) or active(1).  
 
1257
 */
 
1258
 
 
1259
int
 
1260
usmStatusCheck(struct usmUser *uptr)
 
1261
{
 
1262
    if (uptr == NULL) {
 
1263
        return 0;
 
1264
    } else {
 
1265
        if (uptr->cloneFrom == NULL) {
 
1266
            return 0;
 
1267
        }
 
1268
    }
 
1269
    return 1;
 
1270
}
 
1271
 
 
1272
/*******************************************************************-o-******
 
1273
 * write_usmUserStatus
 
1274
 *
 
1275
 * Parameters:
 
1276
 *       action
 
1277
 *      *var_val
 
1278
 *       var_val_type
 
1279
 *       var_val_len
 
1280
 *      *statP
 
1281
 *      *name
 
1282
 *       name_len
 
1283
 *      
 
1284
 * Returns:
 
1285
 *      SNMP_ERR_NOERROR                On success.
 
1286
 *      SNMP_ERR_GENERR 
 
1287
 *      SNMP_ERR_INCONSISTENTNAME
 
1288
 *      SNMP_ERR_INCONSISTENTVALUE
 
1289
 *      SNMP_ERR_WRONGLENGTH
 
1290
 *      SNMP_ERR_WRONGTYPE
 
1291
 */
 
1292
int
 
1293
write_usmUserStatus(int action,
 
1294
                    u_char * var_val,
 
1295
                    u_char var_val_type,
 
1296
                    size_t var_val_len,
 
1297
                    u_char * statP, oid * name, size_t name_len)
 
1298
{
 
1299
    /*
 
1300
     * variables we may use later 
 
1301
     */
 
1302
    static long     long_ret;
 
1303
    unsigned char  *engineID;
 
1304
    size_t          engineIDLen;
 
1305
    char           *newName;
 
1306
    size_t          nameLen;
 
1307
    struct usmUser *uptr = NULL;
 
1308
 
 
1309
    if (action == RESERVE1) {
 
1310
        if (var_val_type != ASN_INTEGER) {
 
1311
            DEBUGMSGTL(("usmUser",
 
1312
                        "write to usmUserStatus not ASN_INTEGER\n"));
 
1313
            return SNMP_ERR_WRONGTYPE;
 
1314
        }
 
1315
        if (var_val_len != sizeof(long_ret)) {
 
1316
            DEBUGMSGTL(("usmUser",
 
1317
                        "write to usmUserStatus: bad length\n"));
 
1318
            return SNMP_ERR_WRONGLENGTH;
 
1319
        }
 
1320
        long_ret = *((long *) var_val);
 
1321
        if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6) {
 
1322
            return SNMP_ERR_WRONGVALUE;
 
1323
        }
 
1324
 
 
1325
        /*
 
1326
         * See if we can parse the oid for engineID/name first.  
 
1327
         */
 
1328
        if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
1329
                          &engineID, &engineIDLen, (u_char **) & newName,
 
1330
                          &nameLen)) {
 
1331
            return SNMP_ERR_INCONSISTENTNAME;
 
1332
        }
 
1333
 
 
1334
        if (engineIDLen < 5 || engineIDLen > 32 || nameLen < 1
 
1335
            || nameLen > 32) {
 
1336
            SNMP_FREE(engineID);
 
1337
            SNMP_FREE(newName);
 
1338
            return SNMP_ERR_NOCREATION;
 
1339
        }
 
1340
 
 
1341
        /*
 
1342
         * Now see if a user already exists with these index values. 
 
1343
         */
 
1344
        uptr = usm_get_user(engineID, engineIDLen, newName);
 
1345
 
 
1346
        if (uptr != NULL) {
 
1347
            if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
 
1348
                SNMP_FREE(engineID);
 
1349
                SNMP_FREE(newName);
 
1350
                long_ret = RS_NOTREADY;
 
1351
                return SNMP_ERR_INCONSISTENTVALUE;
 
1352
            }
 
1353
            SNMP_FREE(engineID);
 
1354
            SNMP_FREE(newName);
 
1355
        } else {
 
1356
            if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
 
1357
                SNMP_FREE(engineID);
 
1358
                SNMP_FREE(newName);
 
1359
                return SNMP_ERR_INCONSISTENTVALUE;
 
1360
            }
 
1361
            if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
 
1362
                if ((uptr = usm_create_user()) == NULL) {
 
1363
                    SNMP_FREE(engineID);
 
1364
                    SNMP_FREE(newName);
 
1365
                    return SNMP_ERR_RESOURCEUNAVAILABLE;
 
1366
                }
 
1367
                uptr->engineID = engineID;
 
1368
                uptr->name = newName;
 
1369
                uptr->secName = strdup(uptr->name);
 
1370
                if (uptr->secName == NULL) {
 
1371
                    usm_free_user(uptr);
 
1372
                    return SNMP_ERR_RESOURCEUNAVAILABLE;
 
1373
                }
 
1374
                uptr->engineIDLen = engineIDLen;
 
1375
 
 
1376
                /*
 
1377
                 * Set status to createAndGo or createAndWait so we can tell
 
1378
                 * that this row is under creation.  
 
1379
                 */
 
1380
 
 
1381
                uptr->userStatus = long_ret;
 
1382
 
 
1383
                /*
 
1384
                 * Add to the list of users (we will take it off again
 
1385
                 * later if something goes wrong).  
 
1386
                 */
 
1387
 
 
1388
                usm_add_user(uptr);
 
1389
            } else {
 
1390
                SNMP_FREE(engineID);
 
1391
                SNMP_FREE(newName);
 
1392
            }
 
1393
        }
 
1394
    } else if (action == ACTION) {
 
1395
        usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
1396
                      &engineID, &engineIDLen, (u_char **) & newName,
 
1397
                      &nameLen);
 
1398
        uptr = usm_get_user(engineID, engineIDLen, newName);
 
1399
        SNMP_FREE(engineID);
 
1400
        SNMP_FREE(newName);
 
1401
 
 
1402
        if (uptr != NULL) {
 
1403
            if (long_ret == RS_CREATEANDGO || long_ret == RS_ACTIVE) {
 
1404
                if (usmStatusCheck(uptr)) {
 
1405
                    uptr->userStatus = RS_ACTIVE;
 
1406
                } else {
 
1407
                    SNMP_FREE(engineID);
 
1408
                    SNMP_FREE(newName);
 
1409
                    return SNMP_ERR_INCONSISTENTVALUE;
 
1410
                }
 
1411
            } else if (long_ret == RS_CREATEANDWAIT) {
 
1412
                if (usmStatusCheck(uptr)) {
 
1413
                    uptr->userStatus = RS_NOTINSERVICE;
 
1414
                } else {
 
1415
                    uptr->userStatus = RS_NOTREADY;
 
1416
                }
 
1417
            } else if (long_ret == RS_NOTINSERVICE) {
 
1418
                if (uptr->userStatus == RS_ACTIVE ||
 
1419
                    uptr->userStatus == RS_NOTINSERVICE) {
 
1420
                    uptr->userStatus = RS_NOTINSERVICE;
 
1421
                } else {
 
1422
                    return SNMP_ERR_INCONSISTENTVALUE;
 
1423
                }
 
1424
            }
 
1425
        }
 
1426
    } else if (action == COMMIT) {
 
1427
        usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
1428
                      &engineID, &engineIDLen, (u_char **) & newName,
 
1429
                      &nameLen);
 
1430
        uptr = usm_get_user(engineID, engineIDLen, newName);
 
1431
        SNMP_FREE(engineID);
 
1432
        SNMP_FREE(newName);
 
1433
 
 
1434
        if (uptr != NULL) {
 
1435
            if (long_ret == RS_DESTROY) {
 
1436
                usm_remove_user(uptr);
 
1437
                usm_free_user(uptr);
 
1438
            }
 
1439
        }
 
1440
    } else if (action == UNDO || action == FREE) {
 
1441
        usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
1442
                      &engineID, &engineIDLen, (u_char **) & newName,
 
1443
                      &nameLen);
 
1444
        uptr = usm_get_user(engineID, engineIDLen, newName);
 
1445
        SNMP_FREE(engineID);
 
1446
        SNMP_FREE(newName);
 
1447
 
 
1448
        if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
 
1449
            usm_remove_user(uptr);
 
1450
            usm_free_user(uptr);
 
1451
        }
 
1452
    }
 
1453
 
 
1454
    return SNMP_ERR_NOERROR;
 
1455
}
 
1456
 
 
1457
#if 0
 
1458
 
 
1459
    /*
 
1460
     * see if we can parse the oid for engineID/name first 
 
1461
     */
 
1462
if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
 
1463
                  &engineID, &engineIDLen, (u_char **) & newName,
 
1464
                  &nameLen))
 
1465
    return SNMP_ERR_INCONSISTENTNAME;
 
1466
 
 
1467
    /*
 
1468
     * Now see if a user already exists with these index values 
 
1469
     */
 
1470
uptr = usm_get_user(engineID, engineIDLen, newName);
 
1471
 
 
1472
 
 
1473
if (uptr) {                     /* If so, we set the appropriate value... */
 
1474
    free(engineID);
 
1475
    free(newName);
 
1476
    if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
 
1477
        return SNMP_ERR_INCONSISTENTVALUE;
 
1478
    }
 
1479
    if (long_ret == RS_DESTROY) {
 
1480
        usm_remove_user(uptr);
 
1481
        usm_free_user(uptr);
 
1482
    } else {
 
1483
        uptr->userStatus = long_ret;
 
1484
    }
 
1485
 
 
1486
} else {                        /* ...else we create a new user */
 
1487
    /*
 
1488
     * check for a valid status column set 
 
1489
     */
 
1490
    if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
 
1491
        free(engineID);
 
1492
        free(newName);
 
1493
        return SNMP_ERR_INCONSISTENTVALUE;
 
1494
    }
 
1495
    if (long_ret == RS_DESTROY) {
 
1496
        /*
 
1497
         * destroying a non-existent row is actually legal 
 
1498
         */
 
1499
        free(engineID);
 
1500
        free(newName);
 
1501
        return SNMP_ERR_NOERROR;
 
1502
    }
 
1503
 
 
1504
    /*
 
1505
     * generate a new user 
 
1506
     */
 
1507
    if ((uptr = usm_create_user()) == NULL) {
 
1508
        free(engineID);
 
1509
        free(newName);
 
1510
        return SNMP_ERR_GENERR;
 
1511
    }
 
1512
 
 
1513
    /*
 
1514
     * copy in the engineID 
 
1515
     */
 
1516
    uptr->engineID = (unsigned char *) malloc(engineIDLen);
 
1517
    if (uptr->engineID == NULL) {
 
1518
        free(engineID);
 
1519
        free(newName);
 
1520
        usm_free_user(uptr);
 
1521
        return SNMP_ERR_GENERR;
 
1522
    }
 
1523
    uptr->engineIDLen = engineIDLen;
 
1524
    memcpy(uptr->engineID, engineID, engineIDLen);
 
1525
    free(engineID);
 
1526
 
 
1527
    /*
 
1528
     * copy in the name and secname 
 
1529
     */
 
1530
    if ((uptr->name = strdup(newName)) == NULL) {
 
1531
        free(newName);
 
1532
        usm_free_user(uptr);
 
1533
        return SNMP_ERR_GENERR;
 
1534
    }
 
1535
    free(newName);
 
1536
    if ((uptr->secName = strdup(uptr->name)) == NULL) {
 
1537
        usm_free_user(uptr);
 
1538
        return SNMP_ERR_GENERR;
 
1539
    }
 
1540
 
 
1541
    /*
 
1542
     * set the status of the row based on the request 
 
1543
     */
 
1544
    if (long_ret == RS_CREATEANDGO)
 
1545
        uptr->userStatus = RS_ACTIVE;
 
1546
    else if (long_ret == RS_CREATEANDWAIT)
 
1547
        uptr->userStatus = RS_NOTINSERVICE;
 
1548
 
 
1549
    /*
 
1550
     * finally, add it to our list of users 
 
1551
     */
 
1552
    usm_add_user(uptr);
 
1553
 
 
1554
}                               /* endif -- uptr */
 
1555
}                               /* endif -- action==COMMIT */
 
1556
 
 
1557
return SNMP_ERR_NOERROR;
 
1558
 
 
1559
}                               /* end write_usmUserStatus() */
 
1560
#endif