Coverage Report

Created: 2023-06-07 06:42

/src/net-snmp/snmplib/snmpusm.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
 * snmpusm.c
18
 *
19
 * Routines to manipulate a information about a "user" as
20
 * defined by the SNMP-USER-BASED-SM-MIB MIB.
21
 *
22
 * All functions usm_set_usmStateReference_*() return 0 on success, -1
23
 * otherwise.
24
 *
25
 * !! Tab stops set to 4 in some parts of this file. !!
26
 *    (Designated on a per function.)
27
 */
28
29
#include <net-snmp/net-snmp-config.h>
30
#include <net-snmp/net-snmp-features.h>
31
32
#include <sys/types.h>
33
#include <stdio.h>
34
#ifdef HAVE_STDLIB_H
35
#include <stdlib.h>
36
#endif
37
#ifdef TIME_WITH_SYS_TIME
38
# include <sys/time.h>
39
# include <time.h>
40
#else
41
# ifdef HAVE_SYS_TIME_H
42
#  include <sys/time.h>
43
# else
44
#  include <time.h>
45
# endif
46
#endif
47
#ifdef HAVE_STRING_H
48
#include <string.h>
49
#else
50
#include <strings.h>
51
#endif
52
#ifdef HAVE_NETINET_IN_H
53
#include <netinet/in.h>
54
#endif
55
56
#ifdef HAVE_UNISTD_H
57
#include <unistd.h>
58
#endif
59
60
#include <net-snmp/types.h>
61
#include <net-snmp/output_api.h>
62
#include <net-snmp/config_api.h>
63
#include <net-snmp/utilities.h>
64
65
#include <net-snmp/library/asn1.h>
66
#include <net-snmp/library/snmp_api.h>
67
#include <net-snmp/library/callback.h>
68
#include <net-snmp/library/tools.h>
69
#include <net-snmp/library/keytools.h>
70
#include <net-snmp/library/snmpv3.h>
71
#include <net-snmp/library/lcd_time.h>
72
#include <net-snmp/library/scapi.h>
73
#include <net-snmp/library/callback.h>
74
#include <net-snmp/library/snmp_secmod.h>
75
#include <net-snmp/library/snmpusm.h>
76
#include <net-snmp/library/transform_oids.h>
77
#include <net-snmp/library/snmp_enum.h>
78
79
#ifdef HAVE_OPENSSL_DH_H
80
#include <openssl/dh.h>
81
#endif
82
83
netsnmp_feature_child_of(usm_all, libnetsnmp);
84
netsnmp_feature_child_of(usm_support, usm_all);
85
86
netsnmp_feature_require(usm_support);
87
88
struct usmStateReference {
89
    int             refcnt;
90
    char           *usr_name;
91
    size_t          usr_name_length;
92
    u_char         *usr_engine_id;
93
    size_t          usr_engine_id_length;
94
    oid            *usr_auth_protocol;
95
    size_t          usr_auth_protocol_length;
96
    u_char         *usr_auth_key;
97
    size_t          usr_auth_key_length;
98
    oid            *usr_priv_protocol;
99
    size_t          usr_priv_protocol_length;
100
    u_char         *usr_priv_key;
101
    size_t          usr_priv_key_length;
102
    u_int           usr_sec_level;
103
};
104
105
const oid usmNoAuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
106
                                 NETSNMP_USMAUTH_NOAUTH };
107
#ifndef NETSNMP_DISABLE_MD5
108
const oid usmHMACMD5AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
109
                                      NETSNMP_USMAUTH_HMACMD5 };
110
#endif
111
const oid usmHMACSHA1AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
112
                                       NETSNMP_USMAUTH_HMACSHA1 };
113
114
#ifdef HAVE_EVP_SHA384
115
const oid usmHMAC384SHA512AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
116
                                            NETSNMP_USMAUTH_HMAC384SHA512 };
117
const oid usmHMAC256SHA384AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
118
                                            NETSNMP_USMAUTH_HMAC256SHA384 };
119
#endif /* HAVE_EVP_SHA384 */
120
121
#ifdef HAVE_EVP_SHA224
122
const oid usmHMAC192SHA256AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
123
                                            NETSNMP_USMAUTH_HMAC192SHA256 };
124
const oid usmHMAC128SHA224AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID,
125
                                            NETSNMP_USMAUTH_HMAC128SHA224 };
126
#endif /* HAVE_EVP_SHA384 */
127
128
const oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
129
130
#ifndef NETSNMP_DISABLE_DES
131
const oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
132
#endif
133
134
135
const oid usmAESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 };
136
/* backwards compat */
137
const oid *usmAES128PrivProtocol = usmAESPrivProtocol;
138
139
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
140
    /* OIDs from http://www.snmp.com/eso/esoConsortiumMIB.txt */
141
const oid usmAES192PrivProtocol[9] = { 1,3,6,1,4,1,14832,1,3 };
142
const oid usmAES256PrivProtocol[9] = { 1,3,6,1,4,1,14832,1,4 };
143
    /* OIDs from CISCO MIB */
144
const oid usmAES192CiscoPrivProtocol[11]  = { 1,3,6,1,4,1,9,12,6,1,1 };
145
const oid usmAES256CiscoPrivProtocol[11]  = { 1,3,6,1,4,1,9,12,6,1,2 };
146
/*
147
 * these OIDs are in pySNMP source as OIDs for AES+Reeder. We'll just
148
 * use OIDS from CISCO-SNMP-USM-OIDS-MIB
149
 *
150
const oid usmAES192Cisco2PrivProtocol[11]  = { 1,3,6,1,4,1,9,12,6,1,101 };
151
const oid usmAES256Cisco2PrivProtocol[11]  = { 1,3,6,1,4,1,9,12,6,1,102 };
152
 */
153
#endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */
154
155
typedef struct usm_alg_type_s {
156
    const char *label;
157
    int         value;
158
} usm_alg_type_t;
159
160
static const usm_alg_type_t usm_auth_type[] = {
161
    { "NOAUTH", NETSNMP_USMAUTH_NOAUTH },
162
    { "SHA", NETSNMP_USMAUTH_HMACSHA1 },
163
    { "SHA-1", NETSNMP_USMAUTH_HMACSHA1 },
164
    { "SHA1", NETSNMP_USMAUTH_HMACSHA1 },
165
#ifndef NETSNMP_DISABLE_MD5
166
    { "MD5", NETSNMP_USMAUTH_HMACMD5 },
167
#endif
168
#ifdef HAVE_EVP_SHA224
169
    { "SHA-224", NETSNMP_USMAUTH_HMAC128SHA224 },
170
    { "SHA224", NETSNMP_USMAUTH_HMAC128SHA224 },
171
    { "SHA-256", NETSNMP_USMAUTH_HMAC192SHA256 },
172
    { "SHA256", NETSNMP_USMAUTH_HMAC192SHA256 },
173
#endif
174
#ifdef HAVE_EVP_SHA384
175
    { "SHA-384", NETSNMP_USMAUTH_HMAC256SHA384 },
176
    { "SHA384", NETSNMP_USMAUTH_HMAC256SHA384 },
177
    { "SHA-512",  NETSNMP_USMAUTH_HMAC384SHA512 },
178
    { "SHA512",  NETSNMP_USMAUTH_HMAC384SHA512 },
179
#endif
180
    { NULL, -1 }
181
};
182
183
static const usm_alg_type_t usm_priv_type[] = {
184
    { "NOPRIV", USM_CREATE_USER_PRIV_NONE },
185
#ifndef NETSNMP_DISABLE_DES
186
    { "DES", USM_CREATE_USER_PRIV_DES },
187
#endif
188
#ifdef HAVE_AES
189
    { "AES", USM_CREATE_USER_PRIV_AES },
190
    { "AES-128", USM_CREATE_USER_PRIV_AES },
191
    { "AES128", USM_CREATE_USER_PRIV_AES },
192
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
193
    { "AES-192", USM_CREATE_USER_PRIV_AES192 },
194
    { "AES192", USM_CREATE_USER_PRIV_AES192 },
195
    { "AES-256", USM_CREATE_USER_PRIV_AES256 },
196
    { "AES256", USM_CREATE_USER_PRIV_AES256 },
197
    /** cisco / pysnmp variations */
198
    { "AES-192-C", USM_CREATE_USER_PRIV_AES192_CISCO },
199
    { "AES192C", USM_CREATE_USER_PRIV_AES192_CISCO },
200
    { "AES-256-C", USM_CREATE_USER_PRIV_AES256_CISCO },
201
    { "AES256C", USM_CREATE_USER_PRIV_AES256_CISCO },
202
#endif
203
#endif
204
    { NULL, -1 },
205
};
206
207
static u_int    dummy_etime, dummy_eboot;       /* For ISENGINEKNOWN(). */
208
209
/*
210
 * Set up default snmpv3 parameter value storage.
211
 */
212
#ifdef NETSNMP_SECMOD_USM
213
static const oid *defaultAuthType = NULL;
214
static size_t   defaultAuthTypeLen = 0;
215
static const oid *defaultPrivType = NULL;
216
static size_t   defaultPrivTypeLen = 0;
217
#endif /* NETSNMP_SECMOD_USM */
218
219
/*
220
 * Globals.
221
 */
222
static u_int    salt_integer;
223
#ifdef HAVE_AES
224
static u_int    salt_integer64_1, salt_integer64_2;
225
#endif
226
        /*
227
         * 1/2 of seed for the salt.   Cf. RFC2274, Sect 8.1.1.1.
228
         */
229
230
static struct usmUser *noNameUser = NULL;
231
/*
232
 * Local storage (LCD) of the default user list.
233
 */
234
static struct usmUser *userList = NULL;
235
236
/*
237
 * Set a given field of the secStateRef.
238
 *
239
 * Allocate <len> bytes for type <type> pointed to by ref-><field>.
240
 * Then copy in <item> and record its length in ref-><field_len>.
241
 *
242
 * Return 0 on success, -1 otherwise.
243
 */
244
0
#define MAKE_ENTRY(ref, type, item, len, field, field_len)      \
245
0
do {                                                            \
246
0
  if (ref == NULL)                                        \
247
0
    return -1;                                      \
248
0
  if (ref->field != NULL) {                               \
249
0
    SNMP_ZERO(ref->field, ref->field_len);          \
250
0
    SNMP_FREE(ref->field);                          \
251
0
  }                                                       \
252
0
  ref->field_len = 0;                                     \
253
0
        if (len == 0 || item == NULL)                           \
254
0
    return 0;                                       \
255
0
  ref->field = netsnmp_memdup(item, len * sizeof(type));  \
256
0
        if (ref->field == NULL)                                 \
257
0
    return -1;                                      \
258
0
                                                                \
259
0
  ref->field_len = len;                                   \
260
0
  return 0;                                               \
261
0
} while (0)
262
263
static int
264
usm_clone_usmStateReference(struct usmStateReference *from,
265
                            struct usmStateReference **to);
266
267
static int
268
free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
269
          void *clientarg)
270
0
{
271
0
    u_char engineID[SNMP_MAX_ENG_SIZE];
272
0
    size_t engineID_len = sizeof(engineID);
273
274
0
    DEBUGMSGTL(("snmpv3", "free enginetime callback called\n"));
275
276
0
    engineID_len = snmpv3_get_engineID(engineID, engineID_len);
277
0
    if (engineID_len > 0)
278
0
  free_enginetime(engineID, engineID_len);
279
0
    return 0;
280
0
}
281
282
static struct usmStateReference *
283
usm_malloc_usmStateReference(void)
284
0
{
285
0
    struct usmStateReference *retval;
286
287
0
    retval = calloc(1, sizeof(struct usmStateReference));
288
0
    if (retval)
289
0
        retval->refcnt = 1;
290
291
0
    return retval;
292
0
}                               /* end usm_malloc_usmStateReference() */
293
294
static int
295
usm_clone(netsnmp_pdu *pdu, netsnmp_pdu *new_pdu)
296
0
{
297
0
    struct usmStateReference *ref = pdu->securityStateRef;
298
0
    struct usmStateReference **new_ref =
299
0
        (struct usmStateReference **)&new_pdu->securityStateRef;
300
0
    int ret = 0;
301
302
0
    if (!ref)
303
0
        return ret;
304
305
0
    if (pdu->command == SNMP_MSG_TRAP2) {
306
0
        netsnmp_assert(pdu->securityModel == SNMP_DEFAULT_SECMODEL);
307
0
        ret = usm_clone_usmStateReference(ref, new_ref);
308
0
    } else {
309
0
        netsnmp_assert(ref == *new_ref);
310
0
        ref->refcnt++;
311
0
    }
312
313
0
    return ret;
314
0
}
315
316
static void
317
usm_free_usmStateReference(void *old)
318
0
{
319
0
    struct usmStateReference *ref = old;
320
321
0
    if (!ref)
322
0
        return;
323
324
0
    if (--ref->refcnt > 0)
325
0
        return;
326
327
0
    SNMP_FREE(ref->usr_name);
328
0
    SNMP_FREE(ref->usr_engine_id);
329
0
    SNMP_FREE(ref->usr_auth_protocol);
330
0
    SNMP_FREE(ref->usr_priv_protocol);
331
332
0
    if (ref->usr_auth_key_length && ref->usr_auth_key) {
333
0
        SNMP_ZERO(ref->usr_auth_key, ref->usr_auth_key_length);
334
0
        SNMP_FREE(ref->usr_auth_key);
335
0
    }
336
0
    if (ref->usr_priv_key_length && ref->usr_priv_key) {
337
0
        SNMP_ZERO(ref->usr_priv_key, ref->usr_priv_key_length);
338
0
        SNMP_FREE(ref->usr_priv_key);
339
0
    }
340
341
0
    SNMP_FREE(ref);
342
0
}                               /* end usm_free_usmStateReference() */
343
344
struct usmUser *
345
usm_get_userList(void)
346
0
{
347
0
    return userList;
348
0
}
349
350
static int
351
usm_set_usmStateReference_name(struct usmStateReference *ref,
352
                               char *name, size_t name_len)
353
0
{
354
0
    MAKE_ENTRY(ref, char, name, name_len, usr_name, usr_name_length);
355
0
}
356
357
static int
358
usm_set_usmStateReference_engine_id(struct usmStateReference *ref,
359
                                    u_char * engine_id,
360
                                    size_t engine_id_len)
361
0
{
362
0
    MAKE_ENTRY(ref, u_char, engine_id, engine_id_len,
363
0
               usr_engine_id, usr_engine_id_length);
364
0
}
365
366
static int
367
usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref,
368
                                        oid * auth_protocol,
369
                                        size_t auth_protocol_len)
370
0
{
371
0
    MAKE_ENTRY(ref, oid, auth_protocol, auth_protocol_len,
372
0
               usr_auth_protocol, usr_auth_protocol_length);
373
0
}
374
375
static int
376
usm_set_usmStateReference_auth_key(struct usmStateReference *ref,
377
                                   u_char * auth_key, size_t auth_key_len)
378
0
{
379
0
    MAKE_ENTRY(ref, u_char, auth_key, auth_key_len,
380
0
               usr_auth_key, usr_auth_key_length);
381
0
}
382
383
static int
384
usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref,
385
                                        oid * priv_protocol,
386
                                        size_t priv_protocol_len)
387
0
{
388
0
    MAKE_ENTRY(ref, oid, priv_protocol, priv_protocol_len,
389
0
               usr_priv_protocol, usr_priv_protocol_length);
390
0
}
391
392
static int
393
usm_set_usmStateReference_priv_key(struct usmStateReference *ref,
394
                                   u_char * priv_key, size_t priv_key_len)
395
0
{
396
0
    MAKE_ENTRY(ref, u_char, priv_key, priv_key_len,
397
0
               usr_priv_key, usr_priv_key_length);
398
0
}
399
400
static int
401
usm_set_usmStateReference_sec_level(struct usmStateReference *ref,
402
                                    int sec_level)
403
0
{
404
0
    if (ref == NULL)
405
0
        return -1;
406
0
    ref->usr_sec_level = sec_level;
407
0
    return 0;
408
0
}
409
410
static int
411
usm_clone_usmStateReference(struct usmStateReference *from,
412
                            struct usmStateReference **to)
413
0
{
414
0
    struct usmStateReference *cloned_usmStateRef;
415
416
0
    if (from == NULL || to == NULL)
417
0
        return -1;
418
419
0
    *to = usm_malloc_usmStateReference();
420
0
    cloned_usmStateRef = *to;
421
422
0
    if (usm_set_usmStateReference_name(cloned_usmStateRef, from->usr_name, from->usr_name_length) ||
423
0
        usm_set_usmStateReference_engine_id(cloned_usmStateRef, from->usr_engine_id, from->usr_engine_id_length) ||
424
0
        usm_set_usmStateReference_auth_protocol(cloned_usmStateRef, from->usr_auth_protocol, from->usr_auth_protocol_length) ||
425
0
        usm_set_usmStateReference_auth_key(cloned_usmStateRef, from->usr_auth_key, from->usr_auth_key_length) ||
426
0
        usm_set_usmStateReference_priv_protocol(cloned_usmStateRef, from->usr_priv_protocol, from->usr_priv_protocol_length) ||
427
0
        usm_set_usmStateReference_priv_key(cloned_usmStateRef, from->usr_priv_key, from->usr_priv_key_length) ||
428
0
        usm_set_usmStateReference_sec_level(cloned_usmStateRef, from->usr_sec_level))
429
0
    {
430
0
        usm_free_usmStateReference(*to);
431
0
        *to = NULL;
432
0
        return -1;
433
0
    }
434
435
0
    return 0;
436
437
0
}
438
439
#ifdef NETSNMP_ENABLE_TESTING_CODE
440
/*******************************************************************-o-******
441
 * emergency_print
442
 *
443
 * Parameters:
444
 *  *field
445
 *   length
446
 *      
447
 *  This is a print routine that is solely included so that it can be
448
 *  used in gdb.  Don't use it as a function, it will be pulled before
449
 *  a real release of the code.
450
 *
451
 *  tab stop 4
452
 *
453
 *  XXX fflush() only works on FreeBSD; core dumps on Sun OS's
454
 */
455
void
456
emergency_print(u_char * field, u_int length)
457
{
458
    int             iindex;
459
    int             start = 0;
460
    int             stop = 25;
461
462
    while (start < stop) {
463
        for (iindex = start; iindex < stop; iindex++)
464
            printf("%02X ", field[iindex]);
465
466
        printf("\n");
467
        start = stop;
468
        stop = stop + 25 < length ? stop + 25 : length;
469
    }
470
    fflush(0);
471
472
}                               /* end emergency_print() */
473
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
474
475
static struct usmUser *
476
usm_get_user_from_list(const u_char *engineID, size_t engineIDLen,
477
                       const char *name, size_t nameLen,
478
                       struct usmUser *puserList, int use_default)
479
0
{
480
0
    struct usmUser *ptr;
481
482
0
    for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
483
0
        if (ptr->name && strlen(ptr->name) == nameLen &&
484
0
            memcmp(ptr->name, name, nameLen) == 0) {
485
0
          DEBUGMSGTL(("usm", "match on user %s\n", ptr->name));
486
0
          if (ptr->engineIDLen == engineIDLen &&
487
0
            ((ptr->engineID == NULL && engineID == NULL) ||
488
0
             (ptr->engineID != NULL && engineID != NULL &&
489
0
              memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
490
0
            return ptr;
491
0
          DEBUGMSGTL(("usm", "no match on engineID ("));
492
0
          if (engineID) {
493
0
              DEBUGMSGHEX(("usm", engineID, engineIDLen));
494
0
          } else {
495
0
              DEBUGMSGTL(("usm", "Empty EngineID"));
496
0
          }
497
0
          DEBUGMSG(("usm", ")\n"));
498
0
        }
499
0
    }
500
501
    /*
502
     * return "" user used to facilitate engineID discovery
503
     */
504
0
    if (use_default && !strcmp(name, ""))
505
0
        return noNameUser;
506
0
    return NULL;
507
0
}
508
509
struct usmUser *
510
usm_get_user2(const u_char *engineID, size_t engineIDLen, const void *name,
511
              size_t nameLen)
512
0
{
513
0
    DEBUGMSGTL(("usm", "getting user %.*s\n", (int)nameLen,
514
0
                (const char *)name));
515
0
    return usm_get_user_from_list(engineID, engineIDLen, name, nameLen,
516
0
                                  userList, 1);
517
0
}
518
519
/*
520
 * usm_get_user(): Returns a user from userList based on the engineID,
521
 * engineIDLen and name of the requested user.
522
 */
523
struct usmUser *
524
usm_get_user(const u_char *engineID, size_t engineIDLen, const char *name)
525
0
{
526
0
    return usm_get_user2(engineID, engineIDLen, name, strlen(name));
527
0
}
528
529
static struct usmUser *
530
usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
531
0
{
532
0
    struct usmUser *nptr, *pptr, *optr;
533
534
    /*
535
     * loop through puserList till we find the proper, sorted place to
536
     * insert the new user
537
     */
538
    /* XXX - how to handle a NULL user->name ?? */
539
    /* XXX - similarly for a NULL nptr->name ?? */
540
0
    for (nptr = puserList, pptr = NULL; nptr != NULL;
541
0
         pptr = nptr, nptr = nptr->next) {
542
0
        if (nptr->engineIDLen > user->engineIDLen)
543
0
            break;
544
545
0
        if (user->engineID == NULL && nptr->engineID != NULL)
546
0
            break;
547
548
0
        if (nptr->engineIDLen == user->engineIDLen &&
549
0
            (nptr->engineID != NULL && user->engineID != NULL &&
550
0
             memcmp(nptr->engineID, user->engineID,
551
0
                    user->engineIDLen) > 0))
552
0
            break;
553
554
0
        if (!(nptr->engineID == NULL && user->engineID != NULL)) {
555
0
            if (nptr->engineIDLen == user->engineIDLen &&
556
0
                ((nptr->engineID == NULL && user->engineID == NULL) ||
557
0
                 memcmp(nptr->engineID, user->engineID,
558
0
                        user->engineIDLen) == 0)
559
0
                && strlen(nptr->name) > strlen(user->name))
560
0
                break;
561
562
0
            if (nptr->engineIDLen == user->engineIDLen &&
563
0
                ((nptr->engineID == NULL && user->engineID == NULL) ||
564
0
                 memcmp(nptr->engineID, user->engineID,
565
0
                        user->engineIDLen) == 0)
566
0
                && strlen(nptr->name) == strlen(user->name)
567
0
                && strcmp(nptr->name, user->name) > 0)
568
0
                break;
569
570
0
            if (nptr->engineIDLen == user->engineIDLen &&
571
0
                ((nptr->engineID == NULL && user->engineID == NULL) ||
572
0
                 memcmp(nptr->engineID, user->engineID,
573
0
                        user->engineIDLen) == 0)
574
0
                && strlen(nptr->name) == strlen(user->name)
575
0
                && strcmp(nptr->name, user->name) == 0) {
576
                /*
577
                 * the user is an exact match of a previous entry.
578
                 * Credentials may be different, though, so remove
579
                 * the old entry (and add the new one)!
580
                 */
581
0
                if (pptr) { /* change prev's next pointer */
582
0
                  pptr->next = nptr->next;
583
0
                }
584
0
                if (nptr->next) { /* change next's prev pointer */
585
0
                  nptr->next->prev = pptr;
586
0
                }
587
0
                optr = nptr;
588
0
                nptr = optr->next; /* add new user at this position */
589
                /* free the old user */
590
0
                optr->next=NULL;
591
0
                optr->prev=NULL;
592
0
                usm_free_user(optr);
593
0
                break; /* new user will be added below */
594
0
            }
595
0
        }
596
0
    }
597
598
    /*
599
     * nptr should now point to the user that we need to add ourselves
600
     * in front of, and pptr should be our new 'prev'.
601
     */
602
603
    /*
604
     * change our pointers
605
     */
606
0
    user->prev = pptr;
607
0
    user->next = nptr;
608
609
    /*
610
     * change the next's prev pointer
611
     */
612
0
    if (user->next)
613
0
        user->next->prev = user;
614
615
    /*
616
     * change the prev's next pointer
617
     */
618
0
    if (user->prev)
619
0
        user->prev->next = user;
620
621
    /*
622
     * rewind to the head of the list and return it (since the new head
623
     * could be us, we need to notify the above routine who the head now is.
624
     */
625
0
    for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
626
0
    return pptr;
627
0
}
628
629
/*
630
 * usm_add_user(): Add's a user to the userList, sorted by the
631
 * engineIDLength then the engineID then the name length then the name
632
 * to facilitate getNext calls on a usmUser table which is indexed by
633
 * these values.
634
 *
635
 * returns the head of the list (which could change due to this add).
636
 */
637
638
struct usmUser *
639
usm_add_user(struct usmUser *user)
640
0
{
641
0
    struct usmUser *uptr;
642
0
    uptr = usm_add_user_to_list(user, userList);
643
0
    if (uptr != NULL)
644
0
        userList = uptr;
645
0
    return uptr;
646
0
}
647
648
/*
649
 * usm_remove_usmUser_from_list remove user from (optional) list
650
 *
651
 * if list is not specified, defaults to global userList.
652
 *
653
 * returns SNMPERR_SUCCESS or SNMPERR_USM_UNKNOWNSECURITYNAME
654
 */
655
static int
656
usm_remove_usmUser_from_list(struct usmUser *user, struct usmUser **ppuserList)
657
0
{
658
0
    struct usmUser *nptr, *pptr;
659
660
    /*
661
     * NULL pointers aren't allowed
662
     */
663
0
    if (ppuserList == NULL)
664
0
        ppuserList = &userList;
665
666
0
    if (*ppuserList == NULL)
667
0
        return SNMPERR_USM_UNKNOWNSECURITYNAME;
668
669
    /*
670
     * find the user in the list
671
     */
672
0
    for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
673
0
         pptr = nptr, nptr = nptr->next) {
674
0
        if (nptr == user)
675
0
            break;
676
0
    }
677
678
0
    if (nptr) {
679
        /*
680
         * remove the user from the linked list
681
         */
682
0
        if (pptr) {
683
0
            pptr->next = nptr->next;
684
0
        }
685
0
        if (nptr->next) {
686
0
            nptr->next->prev = pptr;
687
0
        }
688
0
    } else {
689
        /*
690
         * user didn't exist
691
         */
692
0
        return SNMPERR_USM_UNKNOWNSECURITYNAME;
693
0
    }
694
0
    if (nptr == *ppuserList)    /* we're the head of the list, need to change
695
                                 * * the head to the next user */
696
0
        *ppuserList = nptr->next;
697
0
    return SNMPERR_SUCCESS;
698
0
}                               /* end usm_remove_usmUser_from_list() */
699
700
/*
701
 * usm_remove_user_from_list
702
 *
703
 * removes user from list.
704
 *
705
 * returns new list head on success, or NULL on error.
706
 *
707
 * NOTE: if there was only one user in the list, list head will be NULL.
708
 *       So NULL can also mean success. Use the newer usm_remove_usmUser() for
709
 *       more specific return codes. This function is kept for backwards
710
 *       compatability with this ambiguous behaviour.
711
 */
712
static struct usmUser *
713
usm_remove_user_from_list(struct usmUser *user,
714
                          struct usmUser **ppuserList)
715
0
{
716
0
    int rc = usm_remove_usmUser_from_list(user, ppuserList);
717
0
    if (rc != SNMPERR_SUCCESS || NULL == ppuserList)
718
0
        return NULL;
719
720
0
    return *ppuserList;
721
0
}                               /* end usm_remove_user_from_list() */
722
723
/*
724
 * usm_remove_user(): finds and removes a user from a list
725
 */
726
struct usmUser *
727
usm_remove_user(struct usmUser *user)
728
0
{
729
0
    return usm_remove_user_from_list(user, &userList);
730
0
}
731
732
/*
733
 * usm_free_user():  calls free() on all needed parts of struct usmUser and
734
 * the user himself.
735
 *
736
 * Note: This should *not* be called on an object in a list (IE,
737
 * remove it from the list first, and set next and prev to NULL), but
738
 * will try to reconnect the list pieces again if it is called this
739
 * way.  If called on the head of the list, the entire list will be
740
 * lost.
741
 */
742
struct usmUser *
743
usm_free_user(struct usmUser *user)
744
0
{
745
0
    if (user == NULL)
746
0
        return NULL;
747
748
0
    SNMP_FREE(user->engineID);
749
0
    SNMP_FREE(user->name);
750
0
    SNMP_FREE(user->secName);
751
0
    SNMP_FREE(user->cloneFrom);
752
0
    SNMP_FREE(user->userPublicString);
753
0
    SNMP_FREE(user->authProtocol);
754
0
    SNMP_FREE(user->privProtocol);
755
756
0
    if (user->authKey != NULL) {
757
0
        SNMP_ZERO(user->authKey, user->authKeyLen);
758
0
        SNMP_FREE(user->authKey);
759
0
    }
760
761
0
    if (user->privKey != NULL) {
762
0
        SNMP_ZERO(user->privKey, user->privKeyLen);
763
0
        SNMP_FREE(user->privKey);
764
0
    }
765
766
0
    if (user->authKeyKu != NULL) {
767
0
        SNMP_ZERO(user->authKeyKu, user->authKeyKuLen);
768
0
        SNMP_FREE(user->authKeyKu);
769
0
    }
770
771
0
    if (user->privKeyKu != NULL) {
772
0
        SNMP_ZERO(user->privKeyKu, user->privKeyKuLen);
773
0
        SNMP_FREE(user->privKeyKu);
774
0
    }
775
776
0
#ifdef NETSNMP_USE_OPENSSL
777
0
    if (user->usmDHUserAuthKeyChange)
778
0
    {
779
0
        DH_free(user->usmDHUserAuthKeyChange);
780
0
        user->usmDHUserAuthKeyChange = NULL;
781
0
    }
782
783
0
    if (user->usmDHUserPrivKeyChange)
784
0
    {
785
0
        DH_free(user->usmDHUserPrivKeyChange);
786
0
        user->usmDHUserPrivKeyChange = NULL;
787
0
    }
788
0
#endif
789
790
    /*
791
     * FIX  Why not put this check *first?*
792
     */
793
0
    if (user->prev != NULL && user->prev != (struct usmUser *)-1) {   /* ack, this shouldn't happen */
794
0
        user->prev->next = user->next;
795
0
    }
796
0
    if (user->next != NULL && user->next != (struct usmUser *)-1) {
797
0
        user->next->prev = user->prev;
798
0
        if (user->prev != NULL) /* ack this is really bad, because it means
799
                                 * * we'll loose the head of some structure tree */
800
0
            DEBUGMSGTL(("usm",
801
0
                        "Severe: Asked to free the head of a usmUser tree somewhere."));
802
0
    }
803
804
805
0
    SNMP_ZERO(user, sizeof(*user));
806
0
    SNMP_FREE(user);
807
808
0
    return NULL;                /* for convenience to returns from calling functions */
809
810
0
}                               /* end usm_free_user() */
811
812
int usm_set_priv_key(struct usmUser *user, const char *fname,
813
                     u_char **old_key, size_t *old_key_len,
814
                     const u_char *new_key, u_int new_key_len)
815
0
{
816
0
    u_char buf[SNMP_MAXBUF_SMALL], buf2[SNMP_MAXBUF_SMALL];
817
0
    size_t buflen = sizeof(buf);
818
0
    int plen, res;
819
820
0
    plen = sc_get_proper_priv_length(user->privProtocol,
821
0
                                     user->privProtocolLen);
822
0
    DEBUGMSGTL(("usmUser", "plen %d\n", plen));
823
    /*
824
     * extend key as needed
825
     */
826
0
    DEBUGMSGTL(("9:usmUser", "%s: new_key_len %d\n", fname, new_key_len));
827
0
    if (new_key_len < 2 * plen) {
828
0
        struct usmUser dummy;
829
830
0
        memset(&dummy, 0x0, sizeof(dummy));
831
0
        dummy.engineID = user->engineID;
832
0
        dummy.engineIDLen = user->engineIDLen;
833
0
        dummy.authProtocol = user->authProtocol;
834
0
        dummy.authProtocolLen = user->authProtocolLen;
835
0
        dummy.privProtocol = user->privProtocol;
836
0
        dummy.privProtocolLen = user->privProtocolLen;
837
0
        memcpy(buf2, new_key, new_key_len);
838
0
        dummy.privKey = buf2;
839
0
        dummy.privKeyLen = new_key_len;
840
0
        res = usm_extend_user_kul(&dummy, sizeof(buf2));
841
0
        if (res != SNMP_ERR_NOERROR) {
842
0
            DEBUGMSGTL(("usmUser", "%s: extend kul failed\n", fname));
843
0
            return SNMP_ERR_GENERR;
844
0
        }
845
0
        DEBUGMSGTL(("9:usmUser", "%s: extend kul OK\n", fname));
846
0
        new_key = dummy.privKey;
847
0
        new_key_len = dummy.privKeyLen;
848
        /*
849
         * make sure no reallocation happened; buf2 must be large enoungh
850
         */
851
0
        netsnmp_assert(dummy.privKey == buf2);
852
0
    }
853
854
    /*
855
     * Change the key. 
856
     */
857
0
    DEBUGMSGTL(("usmUser", "%s: changing priv key for user %s\n",
858
0
                fname, user->secName));
859
860
0
    res = decode_keychange(user->authProtocol, user->authProtocolLen,
861
0
                           user->privKey, user->privKeyLen, new_key,
862
0
                           new_key_len, buf, &buflen);
863
0
    if (res != SNMPERR_SUCCESS) {
864
0
        DEBUGMSGTL(("usmUser", "%s failed\n", fname));
865
0
        return SNMP_ERR_GENERR;
866
0
    }
867
0
    DEBUGMSGTL(("usmUser", "%s succeeded\n", fname));
868
0
    *old_key = user->privKey;
869
0
    *old_key_len = user->privKeyLen;
870
0
    user->privKey = netsnmp_memdup(buf, buflen);
871
0
    if (user->privKey == NULL)
872
0
        return SNMP_ERR_RESOURCEUNAVAILABLE;
873
0
    user->privKeyLen = buflen;
874
0
    return SNMP_ERR_NOERROR;
875
0
}
876
877
/*******************************************************************-o-******
878
 * usm_generate_OID
879
 *
880
 * Parameters:
881
 *  *prefix   (I) OID prefix to the usmUser table entry.
882
 *   prefixLen  (I)
883
 *  *uptr   (I) Pointer to a user in the user list.
884
 *  *length   (O) Length of generated index OID.
885
 *      
886
 * Returns:
887
 *  Pointer to the OID index for the user (uptr)  -OR-
888
 *  NULL on failure.
889
 *
890
 *
891
 * Generate the index OID for a given usmUser name.  'length' is set to
892
 * the length of the index OID.
893
 *
894
 * Index OID format is:
895
 *
896
 *    <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
897
 */
898
oid            *
899
usm_generate_OID(const oid *prefix, size_t prefixLen,
900
                 const struct usmUser *uptr, size_t *length)
901
0
{
902
0
    oid            *indexOid;
903
0
    int             i;
904
905
0
    *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
906
0
    indexOid = malloc(*length * sizeof(oid));
907
0
    if (!indexOid)
908
0
        return indexOid;
909
910
0
    memmove(indexOid, prefix, prefixLen * sizeof(oid));
911
912
0
    indexOid[prefixLen] = uptr->engineIDLen;
913
0
    for (i = 0; i < uptr->engineIDLen; i++)
914
0
        indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i];
915
916
0
    indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
917
0
    for (i = 0; i < strlen(uptr->name); i++)
918
0
        indexOid[prefixLen + uptr->engineIDLen + 2 + i] = (oid) uptr->name[i];
919
920
0
    return indexOid;
921
0
}                               /* end usm_generate_OID() */
922
923
/*******************************************************************-o-******
924
 * asn_predict_int_length
925
 *
926
 * Parameters:
927
 *  type  (UNUSED)
928
 *  number
929
 *  len
930
 *      
931
 * Returns:
932
 *  Number of bytes necessary to store the ASN.1 encoded value of 'number'.
933
 *
934
 *
935
 *  This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
936
 *  use to encode a particular integer value.
937
 *
938
 *  Returns the length of the integer -- NOT THE HEADER!
939
 *
940
 *  Do this the same way as asn_build_int()...
941
 */
942
static int
943
asn_predict_int_length(int type, long number, size_t len)
944
0
{
945
0
    register u_long mask;
946
947
948
0
    if (len != sizeof(long))
949
0
        return -1;
950
951
0
    mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
952
    /*
953
     * mask is 0xFF800000 on a big-endian machine 
954
     */
955
956
0
    while ((((number & mask) == 0) || ((number & mask) == mask))
957
0
           && len > 1) {
958
0
        len--;
959
0
        number <<= 8;
960
0
    }
961
962
0
    return len;
963
964
0
}                               /* end asn_predict_length() */
965
966
/*******************************************************************-o-******
967
 * asn_predict_length
968
 *
969
 * Parameters:
970
 *   type
971
 *  *ptr
972
 *   u_char_len
973
 *      
974
 * Returns:
975
 *  Length in bytes:  1 + <n> + <u_char_len>, where
976
 *
977
 *    1   For the ASN.1 type.
978
 *    <n>   # of bytes to store length of data.
979
 *    <u_char_len>  Length of data associated with ASN.1 type.
980
 *
981
 *  This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
982
 *  use to encode a particular integer value.  This is as broken as the
983
 *  currently used encoder.
984
 *
985
 * XXX  How is <n> chosen, exactly??
986
 */
987
static int
988
asn_predict_length(int type, u_char * ptr, size_t u_char_len)
989
0
{
990
991
0
    if (type & ASN_SEQUENCE)
992
0
        return 1 + 3 + u_char_len;
993
994
0
    if (type & ASN_INTEGER) {
995
0
        u_long          value;
996
0
        memcpy(&value, ptr, u_char_len);
997
0
        u_char_len = asn_predict_int_length(type, value, u_char_len);
998
0
    }
999
1000
0
    if (u_char_len < 0x80)
1001
0
        return 1 + 1 + u_char_len;
1002
0
    else if (u_char_len < 0xFF)
1003
0
        return 1 + 2 + u_char_len;
1004
0
    else
1005
0
        return 1 + 3 + u_char_len;
1006
1007
0
}                               /* end asn_predict_length() */
1008
1009
/*******************************************************************-o-******
1010
 * usm_calc_offsets
1011
 *
1012
 * Parameters:
1013
 *  (See list below...)
1014
 *      
1015
 * Returns:
1016
 *  0 On success,
1017
 *  -1  Otherwise.
1018
 *
1019
 *
1020
 *  This routine calculates the offsets into an outgoing message buffer
1021
 *  for the necessary values.  The outgoing buffer will generically
1022
 *  look like this:
1023
 *
1024
 *  SNMPv3 Message
1025
 *  SEQ len[11]
1026
 *    INT len version
1027
 *  Header
1028
 *    SEQ len
1029
 *      INT len MsgID
1030
 *      INT len msgMaxSize
1031
 *      OST len msgFlags (OST = OCTET STRING)
1032
 *      INT len msgSecurityModel
1033
 *  MsgSecurityParameters
1034
 *    [1] OST len[2]
1035
 *      SEQ len[3]
1036
 *        OST len msgAuthoritativeEngineID
1037
 *        INT len msgAuthoritativeEngineBoots
1038
 *        INT len msgAuthoritativeEngineTime
1039
 *        OST len msgUserName
1040
 *        OST len[4] [5] msgAuthenticationParameters
1041
 *        OST len[6] [7] msgPrivacyParameters
1042
 *  MsgData
1043
 *    [8] OST len[9] [10] encryptedPDU
1044
 *    or
1045
 *    [8,10] SEQUENCE len[9] scopedPDU
1046
 *  [12]
1047
 *
1048
 *  The bracketed points will be needed to be identified ([x] is an index
1049
 *  value, len[x] means a length value).  Here is a semantic guide to them:
1050
 *
1051
 *  [1] = globalDataLen (input)
1052
 *  [2] = otstlen
1053
 *  [3] = seq_len
1054
 *  [4] = msgAuthParmLen (may be 0 or 12)
1055
 *  [5] = authParamsOffset
1056
 *  [6] = msgPrivParmLen (may be 0 or 8)
1057
 *  [7] = privParamsOffset
1058
 *  [8] = globalDataLen + msgSecParmLen
1059
 *  [9] = datalen
1060
 *  [10] = dataOffset
1061
 *  [11] = theTotalLength - the length of the header itself
1062
 *  [12] = theTotalLength
1063
 */
1064
static int
1065
usm_calc_offsets(size_t globalDataLen,  /* SNMPv3Message + HeaderData */
1066
                 int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen,   /* An BER encoded sequence. */
1067
                 u_long engineboots,    /* XXX (asn1.c works in long, not int.) */
1068
                 long engine_time,      /* XXX (asn1.c works in long, not int.) */
1069
                 size_t * theTotalLength,       /* globalDataLen + msgSecurityP. + msgData */
1070
                 size_t * authParamsOffset,     /* Distance to auth bytes.                 */
1071
                 size_t * privParamsOffset,     /* Distance to priv bytes.                 */
1072
                 size_t * dataOffset,   /* Distance to scopedPdu SEQ  -or-  the
1073
                                         *   crypted (data) portion of msgData.    */
1074
                 size_t * datalen,      /* Size of msgData OCTET STRING encoding.  */
1075
                 size_t * msgAuthParmLen,       /* Size of msgAuthenticationParameters.    */
1076
                 size_t * msgPrivParmLen,       /* Size of msgPrivacyParameters.           */
1077
                 size_t * otstlen,      /* Size of msgSecurityP. O.S. encoding.    */
1078
                 size_t * seq_len,      /* Size of msgSecurityP. SEQ data.         */
1079
                 size_t * msgSecParmLen)
1080
0
{                               /* Size of msgSecurityP. SEQ.              */
1081
0
    int             engIDlen,   /* Sizes of OCTET STRING and SEQ encodings */
1082
0
                    engBtlen,   /*   for fields within                     */
1083
0
                    engTmlen,   /*   msgSecurityParameters portion of      */
1084
0
                    namelen,    /*   SNMPv3Message.                        */
1085
0
                    authlen, privlen, ret;
1086
1087
    /*
1088
     * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
1089
     * If doing encryption,     msgPrivParmLen = 8  else msgPrivParmLen = 0.
1090
     */
1091
0
    *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1092
0
                       || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0;
1093
1094
0
    *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0;
1095
1096
1097
    /*
1098
     * Calculate lengths.
1099
     */
1100
0
    if ((engIDlen = asn_predict_length(ASN_OCTET_STR,
1101
0
                                       NULL, secEngineIDLen)) == -1) {
1102
0
        return -1;
1103
0
    }
1104
1105
0
    if ((engBtlen = asn_predict_length(ASN_INTEGER,
1106
0
                                       (u_char *) & engineboots,
1107
0
                                       sizeof(long))) == -1) {
1108
0
        return -1;
1109
0
    }
1110
1111
0
    if ((engTmlen = asn_predict_length(ASN_INTEGER,
1112
0
                                       (u_char *) & engine_time,
1113
0
                                       sizeof(long))) == -1) {
1114
0
        return -1;
1115
0
    }
1116
1117
0
    if ((namelen = asn_predict_length(ASN_OCTET_STR,
1118
0
                                      NULL, secNameLen)) == -1) {
1119
0
        return -1;
1120
0
    }
1121
1122
0
    if ((authlen = asn_predict_length(ASN_OCTET_STR,
1123
0
                                      NULL, *msgAuthParmLen)) == -1) {
1124
0
        return -1;
1125
0
    }
1126
1127
0
    if ((privlen = asn_predict_length(ASN_OCTET_STR,
1128
0
                                      NULL, *msgPrivParmLen)) == -1) {
1129
0
        return -1;
1130
0
    }
1131
1132
0
    *seq_len =
1133
0
        engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
1134
1135
0
    if ((ret = asn_predict_length(ASN_SEQUENCE,
1136
0
                                      NULL, *seq_len)) == -1) {
1137
0
        return -1;
1138
0
    }
1139
0
    *otstlen = (size_t)ret;
1140
1141
0
    if ((ret = asn_predict_length(ASN_OCTET_STR,
1142
0
                                      NULL, *otstlen)) == -1) {
1143
0
        return -1;
1144
0
    }
1145
0
    *msgSecParmLen = (size_t)ret;
1146
1147
0
    *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len)
1148
0
        + engIDlen + engBtlen + engTmlen + namelen
1149
0
        + (authlen - *msgAuthParmLen);
1150
1151
0
    *privParamsOffset = *authParamsOffset + *msgAuthParmLen
1152
0
        + (privlen - *msgPrivParmLen);
1153
1154
1155
    /*
1156
     * Compute the size of the plaintext.  Round up to account for cipher
1157
     * block size, if necessary.
1158
     *
1159
     * XXX  This is hardwired for 1DES... If scopedPduLen is already
1160
     *      a multiple of 8, then *add* 8 more; otherwise, round up
1161
     *      to the next multiple of 8.
1162
     *
1163
     * FIX  Calculation of encrypted portion of msgData and consequent
1164
     *      setting and sanity checking of theTotalLength, et al. should
1165
     *      occur *after* encryption has taken place.
1166
     */
1167
0
    if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1168
0
        scopedPduLen = ROUNDUP8(scopedPduLen);
1169
1170
0
        if ((ret = asn_predict_length(ASN_OCTET_STR, NULL, scopedPduLen)) == -1) {
1171
0
            return -1;
1172
0
        }
1173
0
        *datalen = (size_t)ret;
1174
0
    } else {
1175
0
        *datalen = scopedPduLen;
1176
0
    }
1177
1178
0
    *dataOffset = globalDataLen + *msgSecParmLen +
1179
0
        (*datalen - scopedPduLen);
1180
0
    *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
1181
1182
0
    return 0;
1183
1184
0
}                               /* end usm_calc_offsets() */
1185
1186
#ifndef NETSNMP_DISABLE_DES
1187
/*******************************************************************-o-******
1188
 * usm_set_salt
1189
 *
1190
 * Parameters:
1191
 *  *iv     (O)   Buffer to contain IV.
1192
 *  *iv_length    (O)   Length of iv.
1193
 *  *priv_salt    (I)   Salt portion of private key.
1194
 *   priv_salt_length (I)   Length of priv_salt.
1195
 *  *msgSalt    (I/O) Pointer salt portion of outgoing msg buffer.
1196
 *      
1197
 * Returns:
1198
 *  0 On success,
1199
 *  -1  Otherwise.
1200
 *
1201
 *  Determine the initialization vector for the DES-CBC encryption.
1202
 *  (Cf. RFC 2274, 8.1.1.1.)
1203
 *
1204
 *  iv is defined as the concatenation of engineBoots and the
1205
 *    salt integer.
1206
 *  The salt integer is incremented.
1207
 *  The resulting salt is copied into the msgSalt buffer.
1208
 *  The result of the concatenation is then XORed with the salt
1209
 *    portion of the private key (last 8 bytes).
1210
 *  The IV result is returned individually for further use.
1211
 */
1212
static int
1213
usm_set_salt(u_char * iv,
1214
             size_t * iv_length,
1215
             u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
1216
0
{
1217
0
    size_t          propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
1218
0
    int             net_boots;
1219
0
    int             net_salt_int;
1220
    /*
1221
     * net_* should be encoded in network byte order.  XXX  Why?
1222
     */
1223
0
    int             iindex;
1224
1225
1226
    /*
1227
     * Sanity check.
1228
     */
1229
0
    if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt)
1230
0
        || (priv_salt_length < propersize_salt)) {
1231
0
        return -1;
1232
0
    }
1233
1234
1235
0
    net_boots = htonl(snmpv3_local_snmpEngineBoots());
1236
0
    net_salt_int = htonl(salt_integer);
1237
1238
0
    salt_integer += 1;
1239
1240
0
    memcpy(iv, &net_boots, propersize_salt / 2);
1241
0
    memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2);
1242
1243
0
    if (msgSalt)
1244
0
        memcpy(msgSalt, iv, propersize_salt);
1245
1246
1247
    /*
1248
     * Turn the salt into an IV: XOR <boots, salt_int> with salt
1249
     * portion of priv_key.
1250
     */
1251
0
    for (iindex = 0; iindex < (int) propersize_salt; iindex++)
1252
0
        iv[iindex] ^= priv_salt[iindex];
1253
1254
1255
0
    return 0;
1256
1257
0
}                               /* end usm_set_salt() */
1258
#endif
1259
1260
#ifdef HAVE_AES
1261
/*******************************************************************-o-******
1262
 * usm_set_aes_iv
1263
 *
1264
 * Parameters:
1265
 *  *iv     (O)   Buffer to contain IV.
1266
 *  *iv_length    (O)   Length of iv.
1267
 *      net_boots         (I)   the network byte order of the authEng boots val
1268
 *      net_time         (I)   the network byte order of the authEng time val
1269
 *      *salt             (O)   A buffer for the outgoing salt (= 8 bytes of iv)
1270
 *      
1271
 * Returns:
1272
 *  0 On success,
1273
 *  -1  Otherwise.
1274
 *
1275
 *  Determine the initialization vector for AES encryption.
1276
 *  (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
1277
 *
1278
 *  iv is defined as the concatenation of engineBoots, engineTime
1279
    and a 64 bit salt-integer.
1280
 *  The 64 bit salt integer is incremented.
1281
 *  The resulting salt is copied into the salt buffer.
1282
 *  The IV result is returned individually for further use.
1283
 */
1284
static int
1285
usm_set_aes_iv(u_char * iv,
1286
               size_t * iv_length,
1287
               u_int net_boots,
1288
               u_int net_time,
1289
               u_char * salt)
1290
0
{
1291
    /*
1292
     * net_* should be encoded in network byte order.
1293
     */
1294
0
    int             net_salt_int1, net_salt_int2;
1295
0
#define PROPER_AES_IV_SIZE 64
1296
1297
    /*
1298
     * Sanity check.
1299
     */
1300
0
    if (!iv || !iv_length) {
1301
0
        return -1;
1302
0
    }
1303
1304
0
    net_salt_int1 = htonl(salt_integer64_1);
1305
0
    net_salt_int2 = htonl(salt_integer64_2);
1306
1307
0
    if ((salt_integer64_2 += 1) == 0)
1308
0
        salt_integer64_2 += 1;
1309
    
1310
    /* XXX: warning: hard coded proper lengths */
1311
0
    memcpy(iv, &net_boots, 4);
1312
0
    memcpy(iv+4, &net_time, 4);
1313
0
    memcpy(iv+8, &net_salt_int1, 4);
1314
0
    memcpy(iv+12, &net_salt_int2, 4);
1315
1316
0
    memcpy(salt, iv+8, 8); /* only copy the needed portion */
1317
0
    return 0;
1318
0
}                               /* end usm_set_aes_iv() */
1319
#endif /* HAVE_AES */
1320
1321
/*******************************************************************-o-******
1322
 * usm_check_secLevel_vs_protocols
1323
 *
1324
 * Parameters:
1325
 *   level
1326
 *  *authProtocol
1327
 *   authProtocolLen
1328
 *  *privProtocol
1329
 *   privProtocolLen
1330
 *
1331
 * Returns:
1332
 *  0 On success,
1333
 *  1 Otherwise.
1334
 *
1335
 * Same as above but with explicitly named transform types instead of taking
1336
 * from the usmUser structure.
1337
 */
1338
static int
1339
usm_check_secLevel_vs_protocols(int level,
1340
                                const oid * authProtocol,
1341
                                u_int authProtocolLen,
1342
                                const oid * privProtocol,
1343
                                u_int privProtocolLen)
1344
0
{
1345
1346
0
    if (level == SNMP_SEC_LEVEL_AUTHPRIV
1347
0
        &&
1348
0
        (netsnmp_oid_equals
1349
0
         (privProtocol, privProtocolLen, usmNoPrivProtocol,
1350
0
          OID_LENGTH(usmNoPrivProtocol)) == 0)) {
1351
0
        DEBUGMSGTL(("usm", "Level: %d\n", level));
1352
0
        DEBUGMSGTL(("usm", "Auth Protocol: "));
1353
0
        DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
1354
0
        DEBUGMSG(("usm", ", Priv Protocol: "));
1355
0
        DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
1356
0
        DEBUGMSG(("usm", "\n"));
1357
0
        return 1;
1358
0
    }
1359
0
    if ((level == SNMP_SEC_LEVEL_AUTHPRIV
1360
0
         || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
1361
0
        &&
1362
0
        (netsnmp_oid_equals
1363
0
         (authProtocol, authProtocolLen, usmNoAuthProtocol,
1364
0
          OID_LENGTH(usmNoAuthProtocol)) == 0)) {
1365
0
        DEBUGMSGTL(("usm", "Level: %d\n", level));
1366
0
        DEBUGMSGTL(("usm", "Auth Protocol: "));
1367
0
        DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
1368
0
        DEBUGMSG(("usm", ", Priv Protocol: "));
1369
0
        DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
1370
0
        DEBUGMSG(("usm", "\n"));
1371
0
        return 1;
1372
0
    }
1373
1374
0
    return 0;
1375
1376
0
}                               /* end usm_check_secLevel_vs_protocols() */
1377
1378
/*******************************************************************-o-******
1379
 * usm_generate_out_msg
1380
 *
1381
 * Parameters:
1382
 *  (See list below...)
1383
 *      
1384
 * Returns:
1385
 *  SNMPERR_SUCCESS     On success.
1386
 *  SNMPERR_USM_AUTHENTICATIONFAILURE
1387
 *  SNMPERR_USM_ENCRYPTIONERROR
1388
 *  SNMPERR_USM_GENERICERROR
1389
 *  SNMPERR_USM_UNKNOWNSECURITYNAME
1390
 *  SNMPERR_USM_GENERICERROR
1391
 *  SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
1392
 *  
1393
 *
1394
 * Generates an outgoing message.
1395
 *
1396
 * XXX  Beware of misnomers!
1397
 */
1398
static int
1399
usm_generate_out_msg(int msgProcModel,  /* (UNUSED) */
1400
                     u_char * globalData,       /* IN */
1401
                     /*
1402
                      * Pointer to msg header data will point to the beginning
1403
                      * * of the entire packet buffer to be transmitted on wire,
1404
                      * * memory will be contiguous with secParams, typically
1405
                      * * this pointer will be passed back as beginning of
1406
                      * * wholeMsg below.  asn seq. length is updated w/ new length.
1407
                      * *
1408
                      * * While this points to a buffer that should be big enough
1409
                      * * for the whole message, only the first two parts
1410
                      * * of the message are completed, namely SNMPv3Message and
1411
                      * * HeaderData.  globalDataLen (next parameter) represents
1412
                      * * the length of these two completed parts.
1413
                      */
1414
                     size_t globalDataLen,      /* IN - Length of msg header data.      */
1415
                     int maxMsgSize,    /* (UNUSED) */
1416
                     int secModel,      /* (UNUSED) */
1417
                     const u_char *secEngineID, /* IN - Pointer snmpEngineID. */
1418
                     size_t secEngineIDLen,     /* IN - SnmpEngineID length.  */
1419
                     const char *secName,     /* IN - Pointer to securityName.*/
1420
                     size_t secNameLen, /* IN - SecurityName length.          */
1421
                     int secLevel,      /* IN - AuthNoPriv, authPriv etc.     */
1422
                     const u_char *scopedPdu, /* IN */
1423
                     /*
1424
                      * Pointer to scopedPdu will be encrypted by USM if needed
1425
                      * * and written to packet buffer immediately following
1426
                      * * securityParameters, entire msg will be authenticated by
1427
                      * * USM if needed.
1428
                      */
1429
                     size_t scopedPduLen,       /* IN - scopedPdu length. */
1430
                     const void *secStateRef, /* IN */
1431
                     /*
1432
                      * secStateRef, pointer to cached info provided only for
1433
                      * * Response, otherwise NULL.
1434
                      */
1435
                     u_char * secParams,        /* OUT */
1436
                     /*
1437
                      * BER encoded securityParameters pointer to offset within
1438
                      * * packet buffer where secParams should be written, the
1439
                      * * entire BER encoded OCTET STRING (including header) is
1440
                      * * written here by USM secParams = globalData +
1441
                      * * globalDataLen.
1442
                      */
1443
                     size_t * secParamsLen,     /* IN/OUT - Len available, len returned. */
1444
                     u_char ** wholeMsg,        /* OUT */
1445
                     /*
1446
                      * Complete authenticated/encrypted message - typically
1447
                      * * the pointer to start of packet buffer provided in
1448
                      * * globalData is returned here, could also be a separate
1449
                      * * buffer.
1450
                      */
1451
                     size_t * wholeMsgLen)
1452
0
{                               /* IN/OUT - Len available, len returned. */
1453
0
    size_t          otstlen;
1454
0
    size_t          seq_len;
1455
0
    size_t          msgAuthParmLen;
1456
0
    size_t          msgPrivParmLen;
1457
0
    size_t          msgSecParmLen;
1458
0
    size_t          authParamsOffset;
1459
0
    size_t          privParamsOffset;
1460
0
    size_t          datalen;
1461
0
    size_t          dataOffset;
1462
0
    size_t          theTotalLength;
1463
1464
0
    u_char         *ptr;
1465
0
    size_t          ptr_len;
1466
0
    size_t          remaining;
1467
0
    size_t          offSet;
1468
0
    u_int           boots_uint;
1469
0
    u_int           time_uint;
1470
0
    long            boots_long;
1471
0
    long            time_long;
1472
1473
    /*
1474
     * Indirection because secStateRef values override parameters.
1475
     * 
1476
     * None of these are to be free'd - they are either pointing to
1477
     * what's in the secStateRef or to something either in the
1478
     * actual prarmeter list or the user list.
1479
     */
1480
1481
0
    const char     *theName = NULL;
1482
0
    u_int           theNameLength = 0;
1483
0
    const u_char   *theEngineID = NULL;
1484
0
    u_int           theEngineIDLength = 0;
1485
0
    u_char         *theAuthKey = NULL;
1486
0
    u_int           theAuthKeyLength = 0;
1487
0
    const oid      *theAuthProtocol = NULL;
1488
0
    u_int           theAuthProtocolLength = 0;
1489
0
    u_char         *thePrivKey = NULL;
1490
0
    u_int           thePrivKeyLength = 0;
1491
0
    const oid      *thePrivProtocol = NULL;
1492
0
    u_int           thePrivProtocolLength = 0;
1493
0
    int             theSecLevel = 0;    /* No defined const for bad
1494
                                         * value (other then err).
1495
                                         */
1496
1497
0
    DEBUGMSGTL(("usm", "USM processing has begun.\n"));
1498
1499
0
    if (secStateRef != NULL) {
1500
        /*
1501
         * To hush the compiler for now.  XXX 
1502
         */
1503
0
        const struct usmStateReference *ref = secStateRef;
1504
1505
0
        theName = ref->usr_name;
1506
0
        theNameLength = ref->usr_name_length;
1507
0
        theEngineID = ref->usr_engine_id;
1508
0
        theEngineIDLength = ref->usr_engine_id_length;
1509
1510
0
        if (!theEngineIDLength) {
1511
0
            theEngineID = secEngineID;
1512
0
            theEngineIDLength = secEngineIDLen;
1513
0
        }
1514
1515
0
        theAuthProtocol = ref->usr_auth_protocol;
1516
0
        theAuthProtocolLength = ref->usr_auth_protocol_length;
1517
0
        theAuthKey = ref->usr_auth_key;
1518
0
        theAuthKeyLength = ref->usr_auth_key_length;
1519
0
        thePrivProtocol = ref->usr_priv_protocol;
1520
0
        thePrivProtocolLength = ref->usr_priv_protocol_length;
1521
0
        thePrivKey = ref->usr_priv_key;
1522
0
        thePrivKeyLength = ref->usr_priv_key_length;
1523
0
        theSecLevel = ref->usr_sec_level;
1524
0
    }
1525
1526
    /*
1527
     * Identify the user record.
1528
     */
1529
0
    else {
1530
0
        struct usmUser *user;
1531
1532
        /*
1533
         * we do allow an unknown user name for
1534
         * unauthenticated requests. 
1535
         */
1536
0
        user = usm_get_user2(secEngineID, secEngineIDLen, secName, secNameLen);
1537
0
        if (user == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
1538
0
            DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
1539
0
            return SNMPERR_USM_UNKNOWNSECURITYNAME;
1540
0
        }
1541
1542
0
        theName = secName;
1543
0
        theNameLength = secNameLen;
1544
0
        theEngineID = secEngineID;
1545
0
        theSecLevel = secLevel;
1546
0
        theEngineIDLength = secEngineIDLen;
1547
0
        if (user) {
1548
0
            theAuthProtocol = user->authProtocol;
1549
0
            theAuthProtocolLength = user->authProtocolLen;
1550
0
            theAuthKey = user->authKey;
1551
0
            theAuthKeyLength = user->authKeyLen;
1552
0
            thePrivProtocol = user->privProtocol;
1553
0
            thePrivProtocolLength = user->privProtocolLen;
1554
0
            thePrivKey = user->privKey;
1555
0
            thePrivKeyLength = user->privKeyLen;
1556
0
        } else {
1557
            /*
1558
             * unknown users can not do authentication (obviously) 
1559
             */
1560
0
            theAuthProtocol = usmNoAuthProtocol;
1561
0
            theAuthProtocolLength =
1562
0
                OID_LENGTH(usmNoAuthProtocol);
1563
0
            theAuthKey = NULL;
1564
0
            theAuthKeyLength = 0;
1565
0
            thePrivProtocol = usmNoPrivProtocol;
1566
0
            thePrivProtocolLength =
1567
0
                OID_LENGTH(usmNoPrivProtocol);
1568
0
            thePrivKey = NULL;
1569
0
            thePrivKeyLength = 0;
1570
0
        }
1571
0
    }                           /* endif -- secStateRef==NULL */
1572
1573
1574
    /*
1575
     * From here to the end of the function, avoid reference to
1576
     * secName, secEngineID, secLevel, and associated lengths.
1577
     */
1578
1579
1580
    /*
1581
     * Check to see if the user can use the requested sec services.
1582
     */
1583
0
    if (usm_check_secLevel_vs_protocols(theSecLevel,
1584
0
                                        theAuthProtocol,
1585
0
                                        theAuthProtocolLength,
1586
0
                                        thePrivProtocol,
1587
0
                                        thePrivProtocolLength) == 1) {
1588
0
        DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
1589
0
                    theSecLevel));
1590
0
        return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
1591
0
    }
1592
1593
1594
    /*
1595
     * Retrieve the engine information.
1596
     *
1597
     * XXX  No error is declared in the EoP when sending messages to
1598
     *      unknown engines, processing continues w/ boots/time == (0,0).
1599
     */
1600
0
    if (get_enginetime(theEngineID, theEngineIDLength,
1601
0
                       &boots_uint, &time_uint, FALSE) == -1) {
1602
0
        DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
1603
0
    }
1604
1605
0
    boots_long = boots_uint;
1606
0
    time_long = time_uint;
1607
1608
1609
    /*
1610
     * Set up the Offsets.
1611
     */
1612
0
    if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength,
1613
0
                         theNameLength, scopedPduLen, boots_long,
1614
0
                         time_long, &theTotalLength, &authParamsOffset,
1615
0
                         &privParamsOffset, &dataOffset, &datalen,
1616
0
                         &msgAuthParmLen, &msgPrivParmLen, &otstlen,
1617
0
                         &seq_len, &msgSecParmLen) == -1) {
1618
0
        DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
1619
0
        return SNMPERR_USM_GENERICERROR;
1620
0
    }
1621
1622
    /*
1623
     * So, we have the offsets for the three parts that need to be
1624
     * determined, and an overall length.  Now we need to make
1625
     * sure all of this would fit in the outgoing buffer, and
1626
     * whether or not we need to make a new buffer, etc.
1627
     */
1628
1629
1630
    /*
1631
     * Set wholeMsg as a pointer to globalData.  Sanity check for
1632
     * the proper size.
1633
     * 
1634
     * Mark workspace in the message with bytes of all 1's to make it
1635
     * easier to find mistakes in raw message dumps.
1636
     */
1637
0
    ptr = *wholeMsg = globalData;
1638
0
    if (theTotalLength > *wholeMsgLen) {
1639
0
        DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
1640
0
        return SNMPERR_USM_GENERICERROR;
1641
0
    }
1642
1643
0
    ptr_len = *wholeMsgLen = theTotalLength;
1644
1645
#ifdef NETSNMP_ENABLE_TESTING_CODE
1646
    memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);
1647
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
1648
1649
    /*
1650
     * Do the encryption.
1651
     */
1652
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1653
0
        size_t          encrypted_length = theTotalLength - dataOffset;
1654
0
        size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1655
0
        u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1656
0
        int             priv_type = sc_get_privtype(thePrivProtocol,
1657
0
                                                    thePrivProtocolLength);
1658
0
#ifdef HAVE_AES
1659
0
        if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) {
1660
0
            if (!thePrivKey ||
1661
0
                usm_set_aes_iv(salt, &salt_length,
1662
0
                               htonl(boots_uint), htonl(time_uint),
1663
0
                               &ptr[privParamsOffset]) == -1) {
1664
0
                DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
1665
0
                return SNMPERR_USM_GENERICERROR;
1666
0
            }
1667
0
        }
1668
0
#endif
1669
0
#ifndef NETSNMP_DISABLE_DES
1670
        /*
1671
         * XXX  Hardwired to seek into a 1DES private key!
1672
         */
1673
0
        if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) {
1674
0
            if (!thePrivKey ||
1675
0
                (usm_set_salt(salt, &salt_length,
1676
0
                              thePrivKey + 8, thePrivKeyLength - 8,
1677
0
                              &ptr[privParamsOffset])
1678
0
                 == -1)) {
1679
0
                DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
1680
0
                return SNMPERR_USM_GENERICERROR;
1681
0
            }
1682
0
        }
1683
0
#endif
1684
1685
0
        if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
1686
0
                       thePrivKey, thePrivKeyLength,
1687
0
                       salt, salt_length,
1688
0
                       scopedPdu, scopedPduLen,
1689
0
                       &ptr[dataOffset], &encrypted_length)
1690
0
            != SNMP_ERR_NOERROR) {
1691
0
            DEBUGMSGTL(("usm", "encryption error.\n"));
1692
0
            return SNMPERR_USM_ENCRYPTIONERROR;
1693
0
        }
1694
#ifdef NETSNMP_ENABLE_TESTING_CODE
1695
        if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1696
            dump_chunk("usm/dump", "This data was encrypted:",
1697
                       scopedPdu, scopedPduLen);
1698
            dump_chunk("usm/dump", "salt + Encrypted form:",
1699
                       salt, salt_length);
1700
            dump_chunk("usm/dump", NULL,
1701
                       &ptr[dataOffset], encrypted_length);
1702
            dump_chunk("usm/dump", "*wholeMsg:",
1703
                       *wholeMsg, theTotalLength);
1704
        }
1705
#endif
1706
1707
1708
0
        ptr = *wholeMsg;
1709
0
        ptr_len = *wholeMsgLen = theTotalLength;
1710
1711
1712
        /*
1713
         * XXX  Sanity check for salt length should be moved up
1714
         *      under usm_calc_offsets() or tossed.
1715
         */
1716
0
        if ((encrypted_length != (theTotalLength - dataOffset))
1717
0
            || (salt_length != msgPrivParmLen)) {
1718
0
            DEBUGMSGTL(("usm", "encryption length error.\n"));
1719
0
            return SNMPERR_USM_ENCRYPTIONERROR;
1720
0
        }
1721
1722
0
        DEBUGMSGTL(("usm", "Encryption successful.\n"));
1723
0
    }
1724
1725
    /*
1726
     * No encryption for you!
1727
     */
1728
0
    else {
1729
0
        memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen);
1730
0
    }
1731
1732
1733
1734
    /*
1735
     * Start filling in the other fields (in prep for authentication).
1736
     * 
1737
     * offSet is an octet string header, which is different from all
1738
     * the other headers.
1739
     */
1740
0
    remaining = ptr_len - globalDataLen;
1741
1742
0
    offSet = ptr_len - remaining;
1743
0
    asn_build_header(&ptr[offSet], &remaining,
1744
0
                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1745
0
                               ASN_OCTET_STR), otstlen);
1746
1747
0
    offSet = ptr_len - remaining;
1748
0
    asn_build_sequence(&ptr[offSet], &remaining,
1749
0
                       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
1750
1751
0
    offSet = ptr_len - remaining;
1752
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
1753
0
    asn_build_string(&ptr[offSet], &remaining,
1754
0
                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1755
0
                               ASN_OCTET_STR), theEngineID,
1756
0
                     theEngineIDLength);
1757
0
    DEBUGINDENTLESS();
1758
1759
0
    offSet = ptr_len - remaining;
1760
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
1761
0
    asn_build_int(&ptr[offSet], &remaining,
1762
0
                  (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1763
0
                  &boots_long, sizeof(long));
1764
0
    DEBUGINDENTLESS();
1765
1766
0
    offSet = ptr_len - remaining;
1767
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
1768
0
    asn_build_int(&ptr[offSet], &remaining,
1769
0
                  (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1770
0
                  &time_long, sizeof(long));
1771
0
    DEBUGINDENTLESS();
1772
1773
0
    offSet = ptr_len - remaining;
1774
0
    DEBUGDUMPHEADER("send", "msgUserName");
1775
0
    asn_build_string(&ptr[offSet], &remaining,
1776
0
                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1777
0
                               ASN_OCTET_STR), (const u_char *) theName,
1778
0
                     theNameLength);
1779
0
    DEBUGINDENTLESS();
1780
1781
1782
    /*
1783
     * Note: if there is no authentication being done,
1784
     * msgAuthParmLen is 0, and there is no effect (other than
1785
     * inserting a zero-length header) of the following
1786
     * statements.
1787
     */
1788
1789
0
    offSet = ptr_len - remaining;
1790
0
    asn_build_header(&ptr[offSet],
1791
0
                     &remaining,
1792
0
                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1793
0
                               ASN_OCTET_STR), msgAuthParmLen);
1794
1795
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1796
0
        || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1797
0
        offSet = ptr_len - remaining;
1798
0
        memset(&ptr[offSet], 0, msgAuthParmLen);
1799
0
    }
1800
1801
0
    remaining -= msgAuthParmLen;
1802
1803
1804
    /*
1805
     * Note: if there is no encryption being done, msgPrivParmLen
1806
     * is 0, and there is no effect (other than inserting a
1807
     * zero-length header) of the following statements.
1808
     */
1809
1810
0
    offSet = ptr_len - remaining;
1811
0
    asn_build_header(&ptr[offSet],
1812
0
                     &remaining,
1813
0
                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1814
0
                               ASN_OCTET_STR), msgPrivParmLen);
1815
1816
0
    remaining -= msgPrivParmLen;        /* Skipping the IV already there. */
1817
1818
1819
    /*
1820
     * For privacy, need to add the octet string header for it.
1821
     */
1822
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1823
0
        offSet = ptr_len - remaining;
1824
0
        asn_build_header(&ptr[offSet],
1825
0
                         &remaining,
1826
0
                         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1827
0
                                   ASN_OCTET_STR),
1828
0
                         theTotalLength - dataOffset);
1829
0
    }
1830
1831
1832
    /*
1833
     * Adjust overall length and store it as the first SEQ length
1834
     * of the SNMPv3Message.
1835
     *
1836
     * FIX  4 is a magic number!
1837
     */
1838
0
    remaining = theTotalLength;
1839
0
    asn_build_sequence(ptr, &remaining,
1840
0
                       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1841
0
                       theTotalLength - 4);
1842
1843
1844
    /*
1845
     * Now, time to consider / do authentication.
1846
     */
1847
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1848
0
        || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1849
0
        size_t          temp_sig_len = msgAuthParmLen;
1850
0
        u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
1851
1852
0
        if (temp_sig == NULL) {
1853
0
            DEBUGMSGTL(("usm", "Out of memory.\n"));
1854
0
            return SNMPERR_USM_GENERICERROR;
1855
0
        }
1856
1857
0
        if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
1858
0
                                   theAuthKey, theAuthKeyLength,
1859
0
                                   ptr, ptr_len, temp_sig, &temp_sig_len)
1860
0
            != SNMP_ERR_NOERROR) {
1861
            /*
1862
             * FIX temp_sig_len defined?!
1863
             */
1864
0
            SNMP_ZERO(temp_sig, temp_sig_len);
1865
0
            SNMP_FREE(temp_sig);
1866
0
            DEBUGMSGTL(("usm", "Signing failed.\n"));
1867
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
1868
0
        }
1869
1870
0
        if (temp_sig_len != msgAuthParmLen) {
1871
0
            SNMP_ZERO(temp_sig, temp_sig_len);
1872
0
            SNMP_FREE(temp_sig);
1873
0
            DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
1874
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
1875
0
        }
1876
1877
0
        memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
1878
1879
0
        SNMP_ZERO(temp_sig, temp_sig_len);
1880
0
        SNMP_FREE(temp_sig);
1881
1882
0
    }
1883
1884
    /*
1885
     * endif -- create keyed hash 
1886
     */
1887
1888
0
    DEBUGMSGTL(("usm", "USM processing completed.\n"));
1889
1890
0
    return SNMPERR_SUCCESS;
1891
1892
0
}                               /* end usm_generate_out_msg() */
1893
1894
static int
1895
usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
1896
0
{
1897
0
    if (!parms)
1898
0
        return SNMPERR_GENERR;
1899
1900
0
    return usm_generate_out_msg(parms->msgProcModel,
1901
0
                                parms->globalData, parms->globalDataLen,
1902
0
                                parms->maxMsgSize, parms->secModel,
1903
0
                                parms->secEngineID, parms->secEngineIDLen,
1904
0
                                parms->secName, parms->secNameLen,
1905
0
                                parms->secLevel,
1906
0
                                parms->scopedPdu, parms->scopedPduLen,
1907
0
                                parms->secStateRef,
1908
0
                                parms->secParams, parms->secParamsLen,
1909
0
                                parms->wholeMsg, parms->wholeMsgLen);
1910
0
}
1911
1912
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
1913
static int
1914
usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
1915
                      u_char * globalData,      /* IN */
1916
                      /*
1917
                       * points at the msgGlobalData, which is of length given by next 
1918
                       * parameter.  
1919
                       */
1920
                      size_t globalDataLen,     /* IN - Length of msg header data.      */
1921
                      int maxMsgSize,   /* (UNUSED) */
1922
                      int secModel,     /* (UNUSED) */
1923
                      const u_char *secEngineID, /* IN - Pointer snmpEngineID.*/
1924
                      size_t secEngineIDLen,     /* IN - SnmpEngineID length. */
1925
                      const char *secName,    /* IN - Pointer to securityName.*/
1926
                      size_t secNameLen,        /* IN - SecurityName length.  */
1927
                      int secLevel,         /* IN - AuthNoPriv, authPriv etc. */
1928
                      const u_char *scopedPdu,       /* IN */
1929
                      /*
1930
                       * Pointer to scopedPdu will be encrypted by USM if needed
1931
                       * * and written to packet buffer immediately following
1932
                       * * securityParameters, entire msg will be authenticated by
1933
                       * * USM if needed.
1934
                       */
1935
                      size_t scopedPduLen,      /* IN - scopedPdu length. */
1936
                      const void *secStateRef,  /* IN */
1937
                      /*
1938
                       * secStateRef, pointer to cached info provided only for
1939
                       * * Response, otherwise NULL.
1940
                       */
1941
                      u_char ** wholeMsg,       /*  IN/OUT  */
1942
                      /*
1943
                       * Points at the pointer to the packet buffer, which might get extended
1944
                       * if necessary via realloc().  
1945
                       */
1946
                      size_t * wholeMsgLen,     /*  IN/OUT  */
1947
                      /*
1948
                       * Length of the entire packet buffer, **not** the length of the
1949
                       * packet.  
1950
                       */
1951
                      size_t * offset           /*  IN/OUT  */
1952
                      /*
1953
                       * Offset from the end of the packet buffer to the start of the packet,
1954
                       * also known as the packet length.  
1955
                       */
1956
    )
1957
0
{
1958
0
    size_t          msgAuthParmLen = 0;
1959
0
    u_int           boots_uint;
1960
0
    u_int           time_uint;
1961
0
    long            boots_long;
1962
0
    long            time_long;
1963
1964
    /*
1965
     * Indirection because secStateRef values override parameters.
1966
     * 
1967
     * None of these are to be free'd - they are either pointing to
1968
     * what's in the secStateRef or to something either in the
1969
     * actual parameter list or the user list.
1970
     */
1971
1972
0
    const char     *theName = NULL;
1973
0
    u_int           theNameLength = 0;
1974
0
    const u_char   *theEngineID = NULL;
1975
0
    u_int           theEngineIDLength = 0;
1976
0
    u_char         *theAuthKey = NULL;
1977
0
    u_int           theAuthKeyLength = 0;
1978
0
    const oid      *theAuthProtocol = NULL;
1979
0
    u_int           theAuthProtocolLength = 0;
1980
0
    u_char         *thePrivKey = NULL;
1981
0
    u_int           thePrivKeyLength = 0;
1982
0
    const oid      *thePrivProtocol = NULL;
1983
0
    u_int           thePrivProtocolLength = 0;
1984
0
    int             theSecLevel = 0;    /* No defined const for bad
1985
                                         * value (other then err). */
1986
0
    size_t          salt_length = 0, save_salt_length = 0;
1987
0
    u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1988
0
    u_char          authParams[USM_MAX_AUTHSIZE];
1989
0
    u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
1990
0
    size_t          sp_offset = 0, mac_offset = 0;
1991
0
    int             rc = 0;
1992
1993
0
    DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", (int)*offset));
1994
1995
0
    if (secStateRef != NULL) {
1996
        /*
1997
         * To hush the compiler for now.  XXX 
1998
         */
1999
0
        const struct usmStateReference *ref = secStateRef;
2000
2001
0
        theName = ref->usr_name;
2002
0
        theNameLength = ref->usr_name_length;
2003
0
        theEngineID = ref->usr_engine_id;
2004
0
        theEngineIDLength = ref->usr_engine_id_length;
2005
2006
0
        if (!theEngineIDLength) {
2007
0
            theEngineID = secEngineID;
2008
0
            theEngineIDLength = secEngineIDLen;
2009
0
        }
2010
2011
0
        theAuthProtocol = ref->usr_auth_protocol;
2012
0
        theAuthProtocolLength = ref->usr_auth_protocol_length;
2013
0
        theAuthKey = ref->usr_auth_key;
2014
0
        theAuthKeyLength = ref->usr_auth_key_length;
2015
0
        thePrivProtocol = ref->usr_priv_protocol;
2016
0
        thePrivProtocolLength = ref->usr_priv_protocol_length;
2017
0
        thePrivKey = ref->usr_priv_key;
2018
0
        thePrivKeyLength = ref->usr_priv_key_length;
2019
0
        theSecLevel = ref->usr_sec_level;
2020
0
    }
2021
2022
    /*
2023
     * * Identify the user record.
2024
     */
2025
0
    else {
2026
0
        struct usmUser *user;
2027
2028
        /*
2029
         * we do allow an unknown user name for
2030
         * unauthenticated requests. 
2031
         */
2032
0
        user = usm_get_user2(secEngineID, secEngineIDLen, secName, secNameLen);
2033
0
        if (user == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
2034
0
            DEBUGMSGTL(("usm", "Unknown User\n"));
2035
0
            return SNMPERR_USM_UNKNOWNSECURITYNAME;
2036
0
        }
2037
2038
0
        theName = secName;
2039
0
        theNameLength = secNameLen;
2040
0
        theEngineID = secEngineID;
2041
0
        theSecLevel = secLevel;
2042
0
        theEngineIDLength = secEngineIDLen;
2043
0
        if (user) {
2044
0
            theAuthProtocol = user->authProtocol;
2045
0
            theAuthProtocolLength = user->authProtocolLen;
2046
0
            theAuthKey = user->authKey;
2047
0
            theAuthKeyLength = user->authKeyLen;
2048
0
            thePrivProtocol = user->privProtocol;
2049
0
            thePrivProtocolLength = user->privProtocolLen;
2050
0
            thePrivKey = user->privKey;
2051
0
            thePrivKeyLength = user->privKeyLen;
2052
0
        } else {
2053
            /*
2054
             * unknown users can not do authentication (obviously) 
2055
             */
2056
0
            theAuthProtocol = usmNoAuthProtocol;
2057
0
            theAuthProtocolLength =
2058
0
                OID_LENGTH(usmNoAuthProtocol);
2059
0
            theAuthKey = NULL;
2060
0
            theAuthKeyLength = 0;
2061
0
            thePrivProtocol = usmNoPrivProtocol;
2062
0
            thePrivProtocolLength =
2063
0
                OID_LENGTH(usmNoPrivProtocol);
2064
0
            thePrivKey = NULL;
2065
0
            thePrivKeyLength = 0;
2066
0
        }
2067
0
    }                           /* endif -- secStateRef==NULL */
2068
2069
2070
    /*
2071
     * From here to the end of the function, avoid reference to
2072
     * secName, secEngineID, secLevel, and associated lengths.
2073
     */
2074
2075
2076
    /*
2077
     * Check to see if the user can use the requested sec services.
2078
     */
2079
0
    if (usm_check_secLevel_vs_protocols(theSecLevel,
2080
0
                                        theAuthProtocol,
2081
0
                                        theAuthProtocolLength,
2082
0
                                        thePrivProtocol,
2083
0
                                        thePrivProtocolLength) == 1) {
2084
0
        DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
2085
0
                    theSecLevel));
2086
2087
0
        return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
2088
0
    }
2089
2090
2091
    /*
2092
     * * Retrieve the engine information.
2093
     * *
2094
     * * XXX    No error is declared in the EoP when sending messages to
2095
     * *        unknown engines, processing continues w/ boots/time == (0,0).
2096
     */
2097
0
    if (get_enginetime(theEngineID, theEngineIDLength,
2098
0
                       &boots_uint, &time_uint, FALSE) == -1) {
2099
0
        DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
2100
0
    }
2101
2102
0
    boots_long = boots_uint;
2103
0
    time_long = time_uint;
2104
2105
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2106
        /*
2107
         * Initially assume that the ciphertext will end up the same size as
2108
         * the plaintext plus some padding.  Really sc_encrypt ought to be able
2109
         * to grow this for us, a la asn_realloc_rbuild_<type> functions, but
2110
         * this will do for now.  
2111
         */
2112
0
        u_char         *ciphertext = NULL;
2113
0
        size_t          ciphertextlen = scopedPduLen + 64;
2114
0
        int             priv_type = sc_get_privtype(thePrivProtocol,
2115
0
                                                    thePrivProtocolLength);
2116
2117
0
        if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) {
2118
0
            DEBUGMSGTL(("usm",
2119
0
                        "couldn't malloc %d bytes for encrypted PDU\n",
2120
0
                        (int)ciphertextlen));
2121
0
            return SNMPERR_MALLOC;
2122
0
        }
2123
2124
        /*
2125
         * XXX Hardwired to seek into a 1DES private key!  
2126
         */
2127
0
#ifdef HAVE_AES
2128
0
        if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) {
2129
0
            salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
2130
0
            save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
2131
0
            if (!thePrivKey ||
2132
0
                usm_set_aes_iv(salt, &salt_length,
2133
0
                               htonl(boots_uint), htonl(time_uint),
2134
0
                               iv) == -1) {
2135
0
                DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
2136
0
                SNMP_FREE(ciphertext);
2137
0
                return SNMPERR_USM_GENERICERROR;
2138
0
            }
2139
0
        } 
2140
0
#endif
2141
0
#ifndef NETSNMP_DISABLE_DES
2142
0
        if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) {
2143
0
            salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
2144
0
            save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
2145
0
            if (!thePrivKey || (usm_set_salt(salt, &salt_length,
2146
0
                                             thePrivKey + 8,
2147
0
                                             thePrivKeyLength - 8,
2148
0
                                             iv) == -1)) {
2149
0
                DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
2150
0
                SNMP_FREE(ciphertext);
2151
0
                return SNMPERR_USM_GENERICERROR;
2152
0
            }
2153
0
        }
2154
0
#endif
2155
#ifdef NETSNMP_ENABLE_TESTING_CODE
2156
        if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
2157
            dump_chunk("usm/dump", "This data was encrypted:",
2158
                       scopedPdu, scopedPduLen);
2159
        }
2160
#endif
2161
2162
0
        if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
2163
0
                       thePrivKey, thePrivKeyLength,
2164
0
                       salt, salt_length,
2165
0
                       scopedPdu, scopedPduLen,
2166
0
                       ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
2167
0
            DEBUGMSGTL(("usm", "encryption error.\n"));
2168
0
            SNMP_FREE(ciphertext);
2169
0
            return SNMPERR_USM_ENCRYPTIONERROR;
2170
0
        }
2171
2172
        /*
2173
         * Write the encrypted scopedPdu back into the packet buffer.  
2174
         */
2175
2176
0
        *offset = 0;
2177
0
        rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
2178
0
                                       (u_char) (ASN_UNIVERSAL |
2179
0
                                                 ASN_PRIMITIVE |
2180
0
                                                 ASN_OCTET_STR),
2181
0
                                       ciphertext, ciphertextlen);
2182
0
        if (rc == 0) {
2183
0
            DEBUGMSGTL(("usm", "Encryption failed.\n"));
2184
0
            SNMP_FREE(ciphertext);
2185
0
            return SNMPERR_USM_ENCRYPTIONERROR;
2186
0
        }
2187
2188
#ifdef NETSNMP_ENABLE_TESTING_CODE
2189
        if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
2190
            dump_chunk("usm/dump", "salt + Encrypted form: ", salt,
2191
                       salt_length);
2192
            dump_chunk("usm/dump", "wholeMsg:",
2193
                       (*wholeMsg + *wholeMsgLen - *offset), *offset);
2194
        }
2195
#endif
2196
2197
0
        DEBUGMSGTL(("usm", "Encryption successful.\n"));
2198
0
        SNMP_FREE(ciphertext);
2199
0
    } else {
2200
        /*
2201
         * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV  
2202
         */
2203
0
    }
2204
2205
    /*
2206
     * Start encoding the msgSecurityParameters.  
2207
     */
2208
2209
0
    sp_offset = *offset;
2210
2211
0
    DEBUGDUMPHEADER("send", "msgPrivacyParameters");
2212
    /*
2213
     * msgPrivacyParameters (warning: assumes DES salt).  
2214
     */
2215
0
    rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
2216
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2217
0
                                             | ASN_OCTET_STR),
2218
0
                                   iv,
2219
0
                                   save_salt_length);
2220
0
    DEBUGINDENTLESS();
2221
0
    if (rc == 0) {
2222
0
        DEBUGMSGTL(("usm", "building privParams failed.\n"));
2223
0
        return SNMPERR_TOO_LONG;
2224
0
    }
2225
2226
0
    DEBUGDUMPHEADER("send", "msgAuthenticationParameters");
2227
    /*
2228
     * msgAuthenticationParameters.
2229
     */
2230
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
2231
0
        || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2232
0
        memset(authParams, 0, sizeof(authParams));
2233
0
        msgAuthParmLen =
2234
0
            sc_get_auth_maclen(sc_get_authtype(theAuthProtocol,
2235
0
                                               theAuthProtocolLength));
2236
0
    }
2237
2238
0
    rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
2239
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2240
0
                                             | ASN_OCTET_STR), authParams,
2241
0
                                   msgAuthParmLen);
2242
0
    DEBUGINDENTLESS();
2243
0
    if (rc == 0) {
2244
0
        DEBUGMSGTL(("usm", "building authParams failed.\n"));
2245
0
        return SNMPERR_TOO_LONG;
2246
0
    }
2247
2248
    /*
2249
     * Remember where to put the actual HMAC we calculate later on.  An
2250
     * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1
2251
     * header of length 2, hence the fudge factor.  This works as long as
2252
     * auth lengths stay < 127.
2253
     */
2254
0
    mac_offset = *offset - 2;
2255
2256
    /*
2257
     * msgUserName.  
2258
     */
2259
0
    DEBUGDUMPHEADER("send", "msgUserName");
2260
0
    rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
2261
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2262
0
                                             | ASN_OCTET_STR),
2263
0
                                   (const u_char *) theName, theNameLength);
2264
0
    DEBUGINDENTLESS();
2265
0
    if (rc == 0) {
2266
0
        DEBUGMSGTL(("usm", "building authParams failed.\n"));
2267
0
        return SNMPERR_TOO_LONG;
2268
0
    }
2269
2270
    /*
2271
     * msgAuthoritativeEngineTime.  
2272
     */
2273
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
2274
0
    rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
2275
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2276
0
                                          ASN_INTEGER), &time_long,
2277
0
                                sizeof(long));
2278
0
    DEBUGINDENTLESS();
2279
0
    if (rc == 0) {
2280
0
        DEBUGMSGTL(("usm",
2281
0
                    "building msgAuthoritativeEngineTime failed.\n"));
2282
0
        return SNMPERR_TOO_LONG;
2283
0
    }
2284
2285
    /*
2286
     * msgAuthoritativeEngineBoots.  
2287
     */
2288
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
2289
0
    rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
2290
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2291
0
                                          ASN_INTEGER), &boots_long,
2292
0
                                sizeof(long));
2293
0
    DEBUGINDENTLESS();
2294
0
    if (rc == 0) {
2295
0
        DEBUGMSGTL(("usm",
2296
0
                    "building msgAuthoritativeEngineBoots failed.\n"));
2297
0
        return SNMPERR_TOO_LONG;
2298
0
    }
2299
2300
0
    DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
2301
0
    rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
2302
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2303
0
                                             | ASN_OCTET_STR), theEngineID,
2304
0
                                   theEngineIDLength);
2305
0
    DEBUGINDENTLESS();
2306
0
    if (rc == 0) {
2307
0
        DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
2308
0
        return SNMPERR_TOO_LONG;
2309
0
    }
2310
2311
    /*
2312
     * USM msgSecurityParameters sequence header  
2313
     */
2314
0
    rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
2315
0
                                     (u_char) (ASN_SEQUENCE |
2316
0
                                               ASN_CONSTRUCTOR),
2317
0
                                     *offset - sp_offset);
2318
0
    if (rc == 0) {
2319
0
        DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
2320
0
        return SNMPERR_TOO_LONG;
2321
0
    }
2322
2323
    /*
2324
     * msgSecurityParameters OCTET STRING wrapper.  
2325
     */
2326
0
    rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
2327
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2328
0
                                             | ASN_OCTET_STR),
2329
0
                                   *offset - sp_offset);
2330
2331
0
    if (rc == 0) {
2332
0
        DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
2333
0
        return SNMPERR_TOO_LONG;
2334
0
    }
2335
2336
    /*
2337
     * Copy in the msgGlobalData and msgVersion.  
2338
     */
2339
0
    while ((*wholeMsgLen - *offset) < globalDataLen) {
2340
0
        if (!asn_realloc(wholeMsg, wholeMsgLen)) {
2341
0
            DEBUGMSGTL(("usm", "building global data failed.\n"));
2342
0
            return SNMPERR_TOO_LONG;
2343
0
        }
2344
0
    }
2345
2346
0
    *offset += globalDataLen;
2347
0
    memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen);
2348
2349
    /*
2350
     * Total packet sequence.  
2351
     */
2352
0
    rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
2353
0
                                     (u_char) (ASN_SEQUENCE |
2354
0
                                               ASN_CONSTRUCTOR), *offset);
2355
0
    if (rc == 0) {
2356
0
        DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
2357
0
        return SNMPERR_TOO_LONG;
2358
0
    }
2359
2360
    /*
2361
     * Now consider / do authentication.  
2362
     */
2363
2364
0
    if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV ||
2365
0
        theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2366
0
        size_t          temp_sig_len = msgAuthParmLen;
2367
0
        u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
2368
0
        u_char         *proto_msg = *wholeMsg + *wholeMsgLen - *offset;
2369
0
        size_t          proto_msg_len = *offset;
2370
2371
2372
0
        if (temp_sig == NULL) {
2373
0
            DEBUGMSGTL(("usm", "Out of memory.\n"));
2374
0
            return SNMPERR_USM_GENERICERROR;
2375
0
        }
2376
2377
0
        if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
2378
0
                                   theAuthKey, theAuthKeyLength,
2379
0
                                   proto_msg, proto_msg_len,
2380
0
                                   temp_sig, &temp_sig_len)
2381
0
            != SNMP_ERR_NOERROR) {
2382
0
            SNMP_FREE(temp_sig);
2383
0
            DEBUGMSGTL(("usm", "Signing failed.\n"));
2384
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
2385
0
        }
2386
2387
0
        if (temp_sig_len != msgAuthParmLen) {
2388
0
            SNMP_FREE(temp_sig);
2389
0
            DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
2390
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
2391
0
        }
2392
2393
0
        memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig,
2394
0
               msgAuthParmLen);
2395
0
        SNMP_FREE(temp_sig);
2396
0
    }
2397
    /*
2398
     * endif -- create keyed hash 
2399
     */
2400
0
    DEBUGMSGTL(("usm", "USM processing completed.\n"));
2401
0
    return SNMPERR_SUCCESS;
2402
0
}                               /* end usm_rgenerate_out_msg() */
2403
2404
static int
2405
usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
2406
0
{
2407
0
    if (!parms)
2408
0
        return SNMPERR_GENERR;
2409
2410
0
    return usm_rgenerate_out_msg(parms->msgProcModel,
2411
0
                                 parms->globalData, parms->globalDataLen,
2412
0
                                 parms->maxMsgSize, parms->secModel,
2413
0
                                 parms->secEngineID, parms->secEngineIDLen,
2414
0
                                 parms->secName, parms->secNameLen,
2415
0
                                 parms->secLevel,
2416
0
                                 parms->scopedPdu, parms->scopedPduLen,
2417
0
                                 parms->secStateRef,
2418
0
                                 parms->wholeMsg, parms->wholeMsgLen,
2419
0
                                 parms->wholeMsgOffset);
2420
0
}
2421
#endif                          /* */
2422
2423
/*******************************************************************-o-******
2424
 * usm_parse_security_parameters
2425
 *
2426
 * Parameters:
2427
 *  (See list below...)
2428
 *      
2429
 * Returns:
2430
 *  0 On success,
2431
 *  -1  Otherwise.
2432
 *
2433
 *  tab stop 4
2434
 *
2435
 *  Extracts values from the security header and data portions of the
2436
 *  incoming buffer.
2437
 */
2438
static int
2439
usm_parse_security_parameters(u_char * secParams,
2440
                              size_t remaining,
2441
                              u_char * secEngineID,
2442
                              size_t * secEngineIDLen,
2443
                              u_int * boots_uint,
2444
                              u_int * time_uint,
2445
                              char *secName,
2446
                              size_t * secNameLen,
2447
                              u_char * signature,
2448
                              size_t * signature_length,
2449
                              u_char * salt,
2450
                              size_t * salt_length, u_char ** data_ptr)
2451
0
{
2452
0
    u_char         *parse_ptr = secParams;
2453
0
    u_char         *value_ptr;
2454
0
    u_char         *next_ptr;
2455
0
    u_char          type_value;
2456
2457
0
    size_t          octet_string_length = remaining;
2458
0
    size_t          sequence_length;
2459
0
    size_t          remaining_bytes;
2460
2461
0
    long            boots_long;
2462
0
    long            time_long;
2463
2464
0
    u_int           origNameLen;
2465
2466
2467
    /*
2468
     * Eat the first octet header.
2469
     */
2470
0
    if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length,
2471
0
                                        &type_value,
2472
0
                                        (ASN_UNIVERSAL | ASN_PRIMITIVE |
2473
0
                                         ASN_OCTET_STR),
2474
0
                                        "usm first octet")) == NULL) {
2475
        /*
2476
         * RETURN parse error 
2477
0
         */ return -1;
2478
0
    }
2479
2480
2481
    /*
2482
     * Eat the sequence header.
2483
     */
2484
0
    parse_ptr = value_ptr;
2485
0
    sequence_length = octet_string_length;
2486
2487
0
    if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length,
2488
0
                                        &type_value,
2489
0
                                        (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2490
0
                                        "usm sequence")) == NULL) {
2491
        /*
2492
         * RETURN parse error 
2493
0
         */ return -1;
2494
0
    }
2495
2496
2497
    /*
2498
     * Retrieve the engineID.
2499
     */
2500
0
    parse_ptr = value_ptr;
2501
0
    remaining_bytes = sequence_length;
2502
2503
0
    DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID");
2504
0
    if ((next_ptr
2505
0
         = asn_parse_string(parse_ptr, &remaining_bytes, &type_value,
2506
0
                            secEngineID, secEngineIDLen)) == NULL) {
2507
0
        DEBUGINDENTLESS();
2508
        /*
2509
         * RETURN parse error 
2510
0
         */ return -1;
2511
0
    }
2512
0
    DEBUGINDENTLESS();
2513
2514
0
    if (type_value !=
2515
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2516
        /*
2517
         * RETURN parse error 
2518
0
         */ return -1;
2519
0
    }
2520
2521
2522
    /*
2523
     * Retrieve the engine boots, notice switch in the way next_ptr and
2524
     * remaining_bytes are used (to accomodate the asn code).
2525
     */
2526
0
    DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots");
2527
0
    if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
2528
0
                                  &boots_long, sizeof(long))) == NULL) {
2529
0
        DEBUGINDENTLESS();
2530
        /*
2531
         * RETURN parse error 
2532
0
         */ return -1;
2533
0
    }
2534
0
    DEBUGINDENTLESS();
2535
2536
0
    if (type_value !=
2537
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
2538
0
        DEBUGINDENTLESS();
2539
        /*
2540
         * RETURN parse error 
2541
0
         */ return -1;
2542
0
    }
2543
2544
0
    *boots_uint = (u_int) boots_long;
2545
2546
2547
    /*
2548
     * Retrieve the time value.
2549
     */
2550
0
    DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime");
2551
0
    if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
2552
0
                                  &time_long, sizeof(long))) == NULL) {
2553
        /*
2554
         * RETURN parse error 
2555
0
         */ return -1;
2556
0
    }
2557
0
    DEBUGINDENTLESS();
2558
2559
0
    if (type_value !=
2560
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
2561
        /*
2562
         * RETURN parse error 
2563
0
         */ return -1;
2564
0
    }
2565
2566
0
    *time_uint = (u_int) time_long;
2567
2568
0
    if (*boots_uint > ENGINEBOOT_MAX || *time_uint > ENGINETIME_MAX) {
2569
0
        return -1;
2570
0
    }
2571
2572
    /*
2573
     * Retrieve the secName.
2574
     */
2575
0
    origNameLen = *secNameLen;
2576
2577
2578
0
    DEBUGDUMPHEADER("recv", "msgUserName");
2579
0
    if ((next_ptr
2580
0
         = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
2581
0
                            (u_char *) secName, secNameLen)) == NULL) {
2582
0
        DEBUGINDENTLESS();
2583
        /*
2584
         * RETURN parse error 
2585
0
         */ return -1;
2586
0
    }
2587
0
    DEBUGINDENTLESS();
2588
2589
    /*
2590
     * FIX -- doesn't this also indicate a buffer overrun?
2591
     */
2592
0
    if (origNameLen < *secNameLen + 1) {
2593
        /*
2594
         * RETURN parse error, but it's really a parameter error 
2595
         */
2596
0
        return -1;
2597
0
    }
2598
2599
0
    if (*secNameLen > 32) {
2600
        /*
2601
         * This is a USM-specific limitation over and above the above
2602
         * limitation (which will probably default to the length of an
2603
         * SnmpAdminString, i.e. 255).  See RFC 2574, sec. 2.4.  
2604
         */
2605
0
        return -1;
2606
0
    }
2607
2608
0
    secName[*secNameLen] = '\0';
2609
2610
0
    if (type_value !=
2611
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2612
        /*
2613
         * RETURN parse error 
2614
0
         */ return -1;
2615
0
    }
2616
2617
2618
    /*
2619
     * Retrieve the signature and blank it if there.
2620
     */
2621
0
    DEBUGDUMPHEADER("recv", "msgAuthenticationParameters");
2622
0
    if ((next_ptr
2623
0
         = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
2624
0
                            signature, signature_length)) == NULL) {
2625
0
        DEBUGINDENTLESS();
2626
        /*
2627
         * RETURN parse error 
2628
0
         */ return -1;
2629
0
    }
2630
0
    DEBUGINDENTLESS();
2631
2632
0
    if (type_value !=
2633
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2634
        /*
2635
         * RETURN parse error 
2636
0
         */ return -1;
2637
0
    }
2638
2639
0
    if (*signature_length != 0) {       /* Blanking for authentication step later */
2640
0
        memset(next_ptr - (u_long) * signature_length,
2641
0
               0, *signature_length);
2642
0
    }
2643
2644
2645
    /*
2646
     * Retrieve the salt.
2647
     *
2648
     * Note that the next ptr is where the data section starts.
2649
     */
2650
0
    DEBUGDUMPHEADER("recv", "msgPrivacyParameters");
2651
0
    if ((*data_ptr
2652
0
         = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
2653
0
                            salt, salt_length)) == NULL) {
2654
0
        DEBUGINDENTLESS();
2655
        /*
2656
         * RETURN parse error 
2657
0
         */ return -2;
2658
0
    }
2659
0
    DEBUGINDENTLESS();
2660
2661
0
    if (type_value !=
2662
0
        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2663
        /*
2664
         * RETURN parse error 
2665
0
         */ return -2;
2666
0
    }
2667
2668
0
    return 0;
2669
2670
0
}                               /* end usm_parse_security_parameters() */
2671
2672
2673
2674
2675
/*******************************************************************-o-******
2676
 * usm_check_and_update_timeliness
2677
 *
2678
 * Parameters:
2679
 *  *secEngineID
2680
 *   secEngineIDen
2681
 *   boots_uint
2682
 *   time_uint
2683
 *  *error
2684
 *      
2685
 * Returns:
2686
 *  0 On success,
2687
 *  -1  Otherwise.
2688
 *  
2689
 *
2690
 * Performs the incoming timeliness checking and setting.
2691
 */
2692
static int
2693
usm_check_and_update_timeliness(u_char * secEngineID,
2694
                                size_t secEngineIDLen,
2695
                                u_int boots_uint,
2696
                                u_int time_uint, int *error)
2697
0
{
2698
0
    u_char          myID[USM_MAX_ID_LENGTH];
2699
0
    u_long          myIDLength =
2700
0
        snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
2701
0
    u_int           myBoots;
2702
0
    u_int           myTime;
2703
2704
2705
2706
0
    if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) {
2707
        /*
2708
         * We're probably already screwed...buffer overwrite.  XXX? 
2709
         */
2710
0
        DEBUGMSGTL(("usm", "Buffer overflow.\n"));
2711
0
        *error = SNMPERR_USM_GENERICERROR;
2712
0
        return -1;
2713
0
    }
2714
2715
0
    myBoots = snmpv3_local_snmpEngineBoots();
2716
0
    myTime = snmpv3_local_snmpEngineTime();
2717
2718
2719
    /*
2720
     * IF the time involved is local
2721
     *     Make sure  message is inside the time window 
2722
     * ELSE 
2723
     *      IF boots is higher or boots is the same and time is higher
2724
     *              remember this new data
2725
     *      ELSE
2726
     *              IF !(boots same and time within USM_TIME_WINDOW secs)
2727
     *                      Message is too old 
2728
     *              ELSE    
2729
     *                      Message is ok, but don't take time
2730
     *              ENDIF
2731
     *      ENDIF
2732
     * ENDIF
2733
     */
2734
2735
    /*
2736
     * This is a local reference.
2737
     */
2738
0
    if (secEngineIDLen == myIDLength
2739
0
        && memcmp(secEngineID, myID, myIDLength) == 0) {
2740
0
        u_int           time_difference = myTime > time_uint ?
2741
0
            myTime - time_uint : time_uint - myTime;
2742
2743
0
        if (boots_uint == ENGINEBOOT_MAX
2744
0
            || boots_uint != myBoots
2745
0
            || time_difference > USM_TIME_WINDOW) {
2746
0
            snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS);
2747
2748
0
            DEBUGMSGTL(("usm",
2749
0
                        "boot_uint %u myBoots %u time_diff %u => not in time window\n",
2750
0
                        boots_uint, myBoots, time_difference));
2751
0
            *error = SNMPERR_USM_NOTINTIMEWINDOW;
2752
0
            return -1;
2753
0
        }
2754
2755
0
        *error = SNMPERR_SUCCESS;
2756
0
        return 0;
2757
0
    }
2758
2759
    /*
2760
     * This is a remote reference.
2761
     */
2762
0
    else {
2763
0
        u_int           theirBoots, theirTime, theirLastTime;
2764
0
        u_int           time_difference;
2765
2766
0
        if (get_enginetime_ex(secEngineID, secEngineIDLen,
2767
0
                              &theirBoots, &theirTime,
2768
0
                              &theirLastTime, TRUE)
2769
0
            != SNMPERR_SUCCESS) {
2770
0
            DEBUGMSGTL(("usm", "%s\n",
2771
0
                        "Failed to get remote engine's times."));
2772
2773
0
            *error = SNMPERR_USM_GENERICERROR;
2774
0
            return -1;
2775
0
        }
2776
2777
0
        time_difference = theirTime > time_uint ?
2778
0
            theirTime - time_uint : time_uint - theirTime;
2779
2780
2781
        /*
2782
         * XXX  Contrary to the pseudocode:
2783
         *      See if boots is invalid first.
2784
         */
2785
0
        if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
2786
0
            DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid."));
2787
2788
0
            *error = SNMPERR_USM_NOTINTIMEWINDOW;
2789
0
            return -1;
2790
0
        }
2791
2792
2793
        /*
2794
         * Boots is ok, see if the boots is the same but the time
2795
         * is old.
2796
         */
2797
0
        if (theirBoots == boots_uint && time_uint < theirLastTime) {
2798
0
            if (time_difference > USM_TIME_WINDOW) {
2799
0
                DEBUGMSGTL(("usm", "%s\n", "Message too old."));
2800
0
                *error = SNMPERR_USM_NOTINTIMEWINDOW;
2801
0
                return -1;
2802
0
            }
2803
2804
0
            else {              /* Old, but acceptable */
2805
2806
0
                *error = SNMPERR_SUCCESS;
2807
0
                return 0;
2808
0
            }
2809
0
        }
2810
2811
2812
        /*
2813
         * Message is ok, either boots has been advanced, or
2814
         * time is greater than before with the same boots.
2815
         */
2816
2817
0
        if (set_enginetime(secEngineID, secEngineIDLen,
2818
0
                           boots_uint, time_uint, TRUE)
2819
0
            != SNMPERR_SUCCESS) {
2820
0
            DEBUGMSGTL(("usm", "%s\n",
2821
0
                        "Failed updating remote boot/time."));
2822
0
            *error = SNMPERR_USM_GENERICERROR;
2823
0
            return -1;
2824
0
        }
2825
2826
0
        *error = SNMPERR_SUCCESS;
2827
0
        return 0;               /* Fresh message and time updated */
2828
2829
0
    }                           /* endif -- local or remote time reference. */
2830
2831
2832
0
}                               /* end usm_check_and_update_timeliness() */
2833
2834
/*******************************************************************-o-******
2835
 * usm_check_secLevel
2836
 *
2837
 * Parameters:
2838
 *   level
2839
 *  *user
2840
 *      
2841
 * Returns:
2842
 *  0 On success,
2843
 *  -1  Otherwise.
2844
 *
2845
 * Checks that a given security level is valid for a given user.
2846
 */
2847
static int
2848
usm_check_secLevel(int level, struct usmUser *user)
2849
0
{
2850
2851
0
    if (user->userStatus != RS_ACTIVE)
2852
0
        return -1;
2853
2854
0
    DEBUGMSGTL(("comparex", "Comparing: %" NETSNMP_PRIo "u %" NETSNMP_PRIo "u ",
2855
0
                usmNoPrivProtocol[0], usmNoPrivProtocol[1]));
2856
0
    DEBUGMSGOID(("comparex", usmNoPrivProtocol,
2857
0
                 OID_LENGTH(usmNoPrivProtocol)));
2858
0
    DEBUGMSG(("comparex", "\n"));
2859
0
    if (level == SNMP_SEC_LEVEL_AUTHPRIV
2860
0
        && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen,
2861
0
                             usmNoPrivProtocol,
2862
0
                             OID_LENGTH(usmNoPrivProtocol)) ==
2863
0
            0)) {
2864
0
        DEBUGMSGTL(("usm", "Level: %d\n", level));
2865
0
        DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2866
0
        DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2867
0
        DEBUGMSG(("usm", ", User Priv Protocol: "));
2868
0
        DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2869
0
        DEBUGMSG(("usm", "\n"));
2870
0
        return 1;
2871
0
    }
2872
0
    if ((level == SNMP_SEC_LEVEL_AUTHPRIV
2873
0
         || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2874
0
        &&
2875
0
        (netsnmp_oid_equals
2876
0
         (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol,
2877
0
          OID_LENGTH(usmNoAuthProtocol)) == 0)) {
2878
0
        DEBUGMSGTL(("usm", "Level: %d\n", level));
2879
0
        DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2880
0
        DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2881
0
        DEBUGMSG(("usm", ", User Priv Protocol: "));
2882
0
        DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2883
0
        DEBUGMSG(("usm", "\n"));
2884
0
        return 1;
2885
0
    }
2886
2887
0
    return 0;
2888
0
}                               /* end usm_check_secLevel() */
2889
2890
/*******************************************************************-o-******
2891
 * usm_process_in_msg
2892
 *
2893
 * Parameters:
2894
 *  (See list below...)
2895
 *      
2896
 * Returns:
2897
 *  SNMPERR_SUCCESS     On success.
2898
 *  SNMPERR_USM_AUTHENTICATIONFAILURE
2899
 *  SNMPERR_USM_DECRYPTIONERROR
2900
 *  SNMPERR_USM_GENERICERROR
2901
 *  SNMPERR_USM_PARSEERROR
2902
 *  SNMPERR_USM_UNKNOWNENGINEID
2903
 *  SNMPERR_USM_PARSEERROR
2904
 *  SNMPERR_USM_UNKNOWNSECURITYNAME
2905
 *  SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
2906
 *
2907
 *
2908
 * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
2909
 */
2910
static int
2911
usm_process_in_msg(int msgProcModel,    /* (UNUSED) */
2912
                   size_t maxMsgSize,   /* IN     - Used to calc maxSizeResponse.  */
2913
                   u_char * secParams,  /* IN     - BER encoded securityParameters. */
2914
                   int secModel,        /* (UNUSED) */
2915
                   int secLevel,        /* IN     - AuthNoPriv, authPriv etc.      */
2916
                   u_char * wholeMsg,   /* IN     - Original v3 message.           */
2917
                   size_t wholeMsgLen,  /* IN     - Msg length.                    */
2918
                   u_char * secEngineID,        /* OUT    - Pointer snmpEngineID.          */
2919
                   size_t * secEngineIDLen,     /* IN/OUT - Len available, len returned.   */
2920
                   /*
2921
                    * NOTE: Memory provided by caller.      
2922
                    */
2923
                   char *secName,       /* OUT    - Pointer to securityName.       */
2924
                   size_t * secNameLen, /* IN/OUT - Len available, len returned.   */
2925
                   u_char ** scopedPdu, /* OUT    - Pointer to plaintext scopedPdu. */
2926
                   size_t * scopedPduLen,       /* IN/OUT - Len available, len returned.   */
2927
                   size_t * maxSizeResponse,    /* OUT    - Max size of Response PDU.      */
2928
                   void **secStateRf,   /* OUT    - Ref to security state.         */
2929
                   netsnmp_session * sess,      /* IN     - session which got the message  */
2930
                   u_char msg_flags)
2931
0
{                               /* IN     - v3 Message flags.              */
2932
0
    size_t          remaining = wholeMsgLen - (u_int)
2933
0
        ((u_long) * secParams - (u_long) * wholeMsg);
2934
0
    u_int           boots_uint;
2935
0
    u_int           time_uint;
2936
0
#ifdef HAVE_AES
2937
0
    u_int           net_boots, net_time;
2938
0
#endif
2939
0
#ifndef NETSNMP_DISABLE_DES
2940
0
    int             i;
2941
0
#endif
2942
0
    u_char          signature[USM_MAX_AUTHSIZE];
2943
0
    size_t          signature_length = USM_MAX_AUTHSIZE;
2944
0
    u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
2945
0
    size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2946
0
    u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
2947
0
    u_int           iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2948
0
    u_char         *data_ptr;
2949
0
    u_char         *value_ptr;
2950
0
    u_char          type_value;
2951
0
    u_char         *end_of_overhead = NULL;
2952
0
    int             error;
2953
0
    int             rc = 0;
2954
0
    struct usmStateReference **secStateRef =
2955
0
        (struct usmStateReference **) secStateRf;
2956
2957
0
    struct usmUser *user;
2958
2959
2960
0
    DEBUGMSGTL(("usm", "USM processing begun...\n"));
2961
2962
0
    netsnmp_assert(secStateRef);
2963
2964
0
    usm_free_usmStateReference(*secStateRef);
2965
0
    *secStateRef = usm_malloc_usmStateReference();
2966
0
    if (*secStateRef == NULL) {
2967
0
        DEBUGMSGTL(("usm", "Out of memory.\n"));
2968
0
        return SNMPERR_USM_GENERICERROR;
2969
0
    }
2970
2971
    /*
2972
     * Make sure the *secParms is an OCTET STRING.
2973
     * Extract the user name, engine ID, and security level.
2974
     */
2975
0
    if ((rc = usm_parse_security_parameters(secParams, remaining,
2976
0
                                            secEngineID, secEngineIDLen,
2977
0
                                            &boots_uint, &time_uint,
2978
0
                                            secName, secNameLen,
2979
0
                                            signature, &signature_length,
2980
0
                                            salt, &salt_length,
2981
0
                                            &data_ptr)) < 0) {
2982
0
        DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc));
2983
0
        if (rc == -2) {
2984
            /*
2985
             * This indicates a decryptionError.  
2986
             */
2987
0
            snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS);
2988
0
            error = SNMPERR_USM_DECRYPTIONERROR;
2989
0
        } else {
2990
0
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
2991
0
            error = SNMPERR_USM_PARSEERROR;
2992
0
        }
2993
0
        goto err;
2994
0
    }
2995
2996
    /*
2997
     * RFC 2574 section 8.3.2
2998
     * 1)  If the privParameters field is not an 8-octet OCTET STRING,
2999
     * then an error indication (decryptionError) is returned to the
3000
     * calling module.
3001
     */
3002
0
    if ((secLevel == SNMP_SEC_LEVEL_AUTHPRIV) && (salt_length != 8)) {
3003
0
        snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS);
3004
0
        error = SNMPERR_USM_DECRYPTIONERROR;
3005
0
        goto err;
3006
0
    }
3007
3008
0
    if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) {
3009
        /*
3010
         * pull these out now so reports can use them 
3011
         */
3012
0
        *scopedPdu = data_ptr;
3013
0
        *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
3014
0
        end_of_overhead = data_ptr;
3015
0
    }
3016
3017
    /*
3018
     * Cache the name, engine ID, and security level,
3019
     * * per step 2 (section 3.2)
3020
     */
3021
0
    if (usm_set_usmStateReference_name
3022
0
        (*secStateRef, secName, *secNameLen) == -1) {
3023
0
        DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name."));
3024
0
        error = SNMPERR_USM_GENERICERROR;
3025
0
        goto err;
3026
0
    }
3027
3028
0
    if (usm_set_usmStateReference_engine_id
3029
0
        (*secStateRef, secEngineID, *secEngineIDLen) == -1) {
3030
0
        DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id."));
3031
0
        error = SNMPERR_USM_GENERICERROR;
3032
0
        goto err;
3033
0
    }
3034
3035
0
    if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) ==
3036
0
        -1) {
3037
0
        DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level."));
3038
0
        error = SNMPERR_USM_GENERICERROR;
3039
0
        goto err;
3040
0
    }
3041
3042
    /*
3043
     * Locate the engine ID record.
3044
     * If it is unknown, then either create one or note this as an error.
3045
     */
3046
0
    if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE ||
3047
0
                  (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH &&
3048
0
                   (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) ||
3049
0
        (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) {
3050
0
        if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) {
3051
0
            DEBUGMSGTL(("usm", "Unknown Engine ID.\n"));
3052
0
            snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS);
3053
0
            error = SNMPERR_USM_UNKNOWNENGINEID;
3054
0
            goto err;
3055
0
        }
3056
0
    } else {
3057
0
        if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen)
3058
0
            != SNMPERR_SUCCESS) {
3059
0
            DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record."));
3060
0
            error = SNMPERR_USM_GENERICERROR;
3061
0
            goto err;
3062
0
        }
3063
3064
0
    }
3065
3066
3067
    /*
3068
     * Locate the User record.
3069
     * If the user/engine ID is unknown, report this as an error.
3070
     */
3071
0
    if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen,
3072
0
                                       secName, *secNameLen, userList,
3073
0
                                       (((sess && sess->isAuthoritative ==
3074
0
                                          SNMP_SESS_AUTHORITATIVE) ||
3075
0
                                         (!sess)) ? 0 : 1)))
3076
0
        == NULL) {
3077
0
        DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
3078
0
        snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES);
3079
0
        error = SNMPERR_USM_UNKNOWNSECURITYNAME;
3080
0
        goto err;
3081
0
    }
3082
3083
    /* ensure the user is active */
3084
0
    if (user->userStatus != RS_ACTIVE) {
3085
0
        DEBUGMSGTL(("usm", "Attempt to use an inactive user.\n"));
3086
0
        error = SNMPERR_USM_UNKNOWNSECURITYNAME;
3087
0
        goto err;
3088
0
    }
3089
3090
    /*
3091
     * Make sure the security level is appropriate.
3092
     */
3093
3094
0
    rc = usm_check_secLevel(secLevel, user);
3095
0
    if (1 == rc) {
3096
0
        DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n",
3097
0
                    secLevel));
3098
0
        snmp_increment_statistic(STAT_USMSTATSUNSUPPORTEDSECLEVELS);
3099
0
        error = SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
3100
0
        goto err;
3101
0
    } else if (rc != 0) {
3102
0
        DEBUGMSGTL(("usm", "Unknown issue.\n"));
3103
0
        error = SNMPERR_USM_GENERICERROR;
3104
0
        goto err;
3105
0
    }
3106
3107
    /*
3108
     * Check the authentication credentials of the message.
3109
     */
3110
0
    if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
3111
0
        || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
3112
0
        if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen,
3113
0
                                user->authKey, user->authKeyLen,
3114
0
                                wholeMsg, wholeMsgLen,
3115
0
                                signature, signature_length)
3116
0
            != SNMP_ERR_NOERROR) {
3117
0
            DEBUGMSGTL(("usm", "Verification failed.\n"));
3118
0
            snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS);
3119
0
      snmp_log(LOG_WARNING, "Authentication failed for %s\n",
3120
0
        user->name);
3121
0
            error = SNMPERR_USM_AUTHENTICATIONFAILURE;
3122
0
            goto err;
3123
0
        }
3124
3125
0
        DEBUGMSGTL(("usm", "Verification succeeded.\n"));
3126
0
    }
3127
3128
3129
    /*
3130
     * Steps 10-11  user is already set - relocated before timeliness 
3131
     * check in case it fails - still save user data for response.
3132
     *
3133
     * Cache the keys and protocol oids, per step 11 (s3.2).
3134
     */
3135
0
    if (usm_set_usmStateReference_auth_protocol(*secStateRef,
3136
0
                                                user->authProtocol,
3137
0
                                                user->
3138
0
                                                authProtocolLen) == -1) {
3139
0
        DEBUGMSGTL(("usm", "%s\n",
3140
0
                    "Couldn't cache authentication protocol."));
3141
0
        error = SNMPERR_USM_GENERICERROR;
3142
0
        goto err;
3143
0
    }
3144
3145
0
    if (usm_set_usmStateReference_auth_key(*secStateRef,
3146
0
                                           user->authKey,
3147
0
                                           user->authKeyLen) == -1) {
3148
0
        DEBUGMSGTL(("usm", "%s\n",
3149
0
                    "Couldn't cache authentication key."));
3150
0
        error = SNMPERR_USM_GENERICERROR;
3151
0
        goto err;
3152
0
    }
3153
3154
0
    if (usm_set_usmStateReference_priv_protocol(*secStateRef,
3155
0
                                                user->privProtocol,
3156
0
                                                user->
3157
0
                                                privProtocolLen) == -1) {
3158
0
        DEBUGMSGTL(("usm", "%s\n",
3159
0
                    "Couldn't cache privacy protocol."));
3160
0
        error = SNMPERR_USM_GENERICERROR;
3161
0
        goto err;
3162
0
    }
3163
3164
0
    if (usm_set_usmStateReference_priv_key(*secStateRef,
3165
0
                                           user->privKey,
3166
0
                                           user->privKeyLen) == -1) {
3167
0
        DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key."));
3168
0
        error = SNMPERR_USM_GENERICERROR;
3169
0
        goto err;
3170
0
    }
3171
3172
3173
    /*
3174
     * Perform the timeliness/time manager functions.
3175
     */
3176
0
    if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
3177
0
        || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
3178
0
        if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen,
3179
0
                                            boots_uint, time_uint,
3180
0
                                            &error) == -1) {
3181
0
            goto err;
3182
0
        }
3183
0
    }
3184
0
#ifdef              LCD_TIME_SYNC_OPT
3185
    /*
3186
     * Cache the unauthenticated time to use in case we don't have
3187
     * anything better - this guess will be no worse than (0,0)
3188
     * that we normally use.
3189
     */
3190
0
    else {
3191
0
        set_enginetime(secEngineID, *secEngineIDLen,
3192
0
                       boots_uint, time_uint, FALSE);
3193
0
    }
3194
0
#endif                          /* LCD_TIME_SYNC_OPT */
3195
3196
3197
    /*
3198
     * If needed, decrypt the scoped PDU.
3199
     */
3200
0
    if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
3201
0
        int priv_type = sc_get_privtype(user->privProtocol,
3202
0
                                        user->privProtocolLen);
3203
0
        remaining = wholeMsgLen - (data_ptr - wholeMsg);
3204
3205
0
        if ((value_ptr = asn_parse_sequence(data_ptr, &remaining,
3206
0
                                            &type_value,
3207
0
                                            (ASN_UNIVERSAL | ASN_PRIMITIVE
3208
0
                                             | ASN_OCTET_STR),
3209
0
                                            "encrypted sPDU")) == NULL) {
3210
0
            DEBUGMSGTL(("usm", "%s\n",
3211
0
                        "Failed while parsing encrypted sPDU."));
3212
0
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3213
0
            usm_free_usmStateReference(*secStateRef);
3214
0
            *secStateRef = NULL;
3215
0
            error = SNMPERR_USM_PARSEERROR;
3216
0
            goto err;
3217
0
        }
3218
3219
0
#ifndef NETSNMP_DISABLE_DES
3220
0
        if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) {
3221
            /*
3222
             * From RFC2574:
3223
             * 
3224
             * "Before decryption, the encrypted data length is verified.
3225
             * If the length of the OCTET STRING to be decrypted is not
3226
             * an integral multiple of 8 octets, the decryption process
3227
             * is halted and an appropriate exception noted."  
3228
             */
3229
3230
0
            if (remaining % 8 != 0) {
3231
0
                DEBUGMSGTL(("usm",
3232
0
                            "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %lu)\n",
3233
0
                            (unsigned long)remaining, (unsigned long)remaining % 8));
3234
0
                snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS);
3235
0
                usm_free_usmStateReference(*secStateRef);
3236
0
                *secStateRef = NULL;
3237
0
                error = SNMPERR_USM_DECRYPTIONERROR;
3238
0
                goto err;
3239
0
            }
3240
3241
0
            end_of_overhead = value_ptr;
3242
3243
0
            if ( !user->privKey ) {
3244
0
                DEBUGMSGTL(("usm", "No privacy pass phrase for %s\n", user->secName));
3245
0
                snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS);
3246
0
                usm_free_usmStateReference(*secStateRef);
3247
0
                *secStateRef = NULL;
3248
0
                error = SNMPERR_USM_DECRYPTIONERROR;
3249
0
                goto err;
3250
0
            }
3251
3252
            /*
3253
             * XOR the salt with the last (iv_length) bytes
3254
             * of the priv_key to obtain the IV.
3255
             */
3256
0
            iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
3257
0
            for (i = 0; i < (int) iv_length; i++)
3258
0
                iv[i] = salt[i] ^ user->privKey[iv_length + i];
3259
0
        }
3260
0
#endif
3261
0
#ifdef HAVE_AES
3262
0
        if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) {
3263
0
            iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
3264
0
            net_boots = ntohl(boots_uint);
3265
0
            net_time = ntohl(time_uint);
3266
0
            memcpy(iv, &net_boots, 4);
3267
0
            memcpy(iv+4, &net_time, 4);
3268
0
            memcpy(iv+8, salt, salt_length);
3269
0
        }
3270
0
#endif
3271
3272
#ifdef NETSNMP_ENABLE_TESTING_CODE
3273
        if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
3274
            dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining);
3275
            dump_chunk("usm/dump", "salt + Encrypted form:",
3276
                       salt, salt_length);
3277
            dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length);
3278
        }
3279
#endif
3280
0
        if (sc_decrypt(user->privProtocol, user->privProtocolLen,
3281
0
                       user->privKey, user->privKeyLen,
3282
0
                       iv, iv_length,
3283
0
                       value_ptr, remaining, *scopedPdu, scopedPduLen)
3284
0
            != SNMP_ERR_NOERROR) {
3285
0
            DEBUGMSGTL(("usm", "%s\n", "Failed decryption."));
3286
0
            snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS);
3287
0
            error = SNMPERR_USM_DECRYPTIONERROR;
3288
0
            goto err;
3289
0
        }
3290
#ifdef NETSNMP_ENABLE_TESTING_CODE
3291
        if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
3292
            dump_chunk("usm/dump", "Decrypted chunk:",
3293
                       *scopedPdu, *scopedPduLen);
3294
        }
3295
#endif
3296
0
    }
3297
    /*
3298
     * sPDU is plaintext.
3299
     */
3300
0
    else {
3301
0
        *scopedPdu = data_ptr;
3302
0
        *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
3303
0
        end_of_overhead = data_ptr;
3304
3305
0
    }                           /* endif -- PDU decryption */
3306
3307
3308
    /*
3309
     * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
3310
     *
3311
     * FIX  Correct? 
3312
     */
3313
0
    *maxSizeResponse = maxMsgSize - (end_of_overhead - wholeMsg);
3314
3315
3316
0
    DEBUGMSGTL(("usm", "USM processing completed.\n"));
3317
3318
0
    return SNMPERR_SUCCESS;
3319
3320
0
err:
3321
0
    usm_free_usmStateReference(*secStateRef);
3322
0
    *secStateRef = NULL;
3323
0
    netsnmp_assert(error != SNMPERR_SUCCESS);
3324
0
    return error;
3325
0
}                               /* end usm_process_in_msg() */
3326
3327
static int
3328
usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms)
3329
0
{
3330
0
    if (!parms)
3331
0
        return SNMPERR_GENERR;
3332
3333
0
    return usm_process_in_msg(parms->msgProcModel,
3334
0
                              parms->maxMsgSize,
3335
0
                              parms->secParams,
3336
0
                              parms->secModel,
3337
0
                              parms->secLevel,
3338
0
                              parms->wholeMsg,
3339
0
                              parms->wholeMsgLen,
3340
0
                              parms->secEngineID,
3341
0
                              parms->secEngineIDLen,
3342
0
                              parms->secName,
3343
0
                              parms->secNameLen,
3344
0
                              parms->scopedPdu,
3345
0
                              parms->scopedPduLen,
3346
0
                              parms->maxSizeResponse,
3347
0
                              parms->secStateRef,
3348
0
                              parms->sess, parms->msg_flags);
3349
0
}
3350
3351
static void
3352
usm_handle_report(struct session_list *slp,
3353
                  netsnmp_transport *transport, netsnmp_session *session,
3354
                  int result, netsnmp_pdu *pdu)
3355
0
{
3356
    /*
3357
     * handle reportable errors 
3358
     */
3359
3360
    /* this will get in our way */
3361
0
    usm_free_usmStateReference(pdu->securityStateRef);
3362
0
    pdu->securityStateRef = NULL;
3363
3364
0
    switch (result) {
3365
0
    case SNMPERR_USM_AUTHENTICATIONFAILURE:
3366
0
    {
3367
0
        int res = session->s_snmp_errno;
3368
0
        session->s_snmp_errno = result;
3369
0
        if (session->callback) {
3370
0
            session->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
3371
0
                              session, pdu->reqid, pdu,
3372
0
                              session->callback_magic);
3373
0
        }
3374
0
        session->s_snmp_errno = res;
3375
0
    }  
3376
0
    NETSNMP_FALLTHROUGH;
3377
0
    case SNMPERR_USM_UNKNOWNENGINEID:
3378
0
    case SNMPERR_USM_UNKNOWNSECURITYNAME:
3379
0
    case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
3380
0
    case SNMPERR_USM_NOTINTIMEWINDOW:
3381
0
    case SNMPERR_USM_DECRYPTIONERROR:
3382
3383
0
        if (SNMP_CMD_CONFIRMED(pdu->command) ||
3384
0
            (pdu->command == 0
3385
0
             && (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT))) {
3386
0
            netsnmp_pdu    *pdu2;
3387
0
            int             flags = pdu->flags;
3388
3389
0
            pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
3390
0
            pdu2 = snmp_clone_pdu(pdu);
3391
0
            pdu->flags = pdu2->flags = flags;
3392
0
            snmpv3_make_report(pdu2, result);
3393
0
            if (0 == snmp_sess_send(slp, pdu2)) {
3394
0
                snmp_free_pdu(pdu2);
3395
                /*
3396
                 * TODO: indicate error 
3397
                 */
3398
0
            }
3399
0
        }
3400
0
        break;
3401
0
    }       
3402
0
}
3403
3404
/** utility function to call netsnmp_extend_kul for a usmUser */
3405
int
3406
usm_extend_user_kul(struct usmUser *user, u_int privKeyBufSize)
3407
0
{
3408
0
    const netsnmp_priv_alg_info *pai;
3409
3410
0
    DEBUGMSGTL(("usm", "extending key\n"));
3411
3412
0
    if (NULL == user) {
3413
0
        DEBUGMSGTL(("usm", "null user!\n"));
3414
0
        return SNMPERR_GENERR;
3415
0
    }
3416
3417
0
    pai = sc_get_priv_alg_byoid(user->privProtocol, user->privProtocolLen);
3418
0
    if (NULL == pai) {
3419
0
        DEBUGMSGTL(("usm", "privProtocol lookup failed!\n"));
3420
0
        return SNMPERR_GENERR;
3421
0
    }
3422
3423
0
    return netsnmp_extend_kul(pai->proper_length, user->authProtocol,
3424
0
                              user->authProtocolLen, pai->type, user->engineID,
3425
0
                              user->engineIDLen, &user->privKey,
3426
0
                              &user->privKeyLen, privKeyBufSize);
3427
0
}
3428
3429
/* sets up initial default session parameters */
3430
static int
3431
usm_session_init(netsnmp_session *in_session, netsnmp_session *session)
3432
0
{
3433
0
    char *cp;
3434
0
    size_t i;
3435
    
3436
0
    if (in_session->securityAuthProtoLen > 0) {
3437
0
        session->securityAuthProto =
3438
0
            snmp_duplicate_objid(in_session->securityAuthProto,
3439
0
                                 in_session->securityAuthProtoLen);
3440
0
        if (session->securityAuthProto == NULL) {
3441
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
3442
0
            return SNMPERR_MALLOC;
3443
0
        }
3444
0
    } else if (get_default_authtype(&i) != NULL) {
3445
0
        session->securityAuthProto =
3446
0
            snmp_duplicate_objid(get_default_authtype(NULL), i);
3447
0
        session->securityAuthProtoLen = i;
3448
0
    }
3449
3450
0
    if (in_session->securityPrivProtoLen > 0) {
3451
0
        session->securityPrivProto =
3452
0
            snmp_duplicate_objid(in_session->securityPrivProto,
3453
0
                                 in_session->securityPrivProtoLen);
3454
0
        if (session->securityPrivProto == NULL) {
3455
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
3456
0
            return SNMPERR_MALLOC;
3457
0
        }
3458
0
    } else if (get_default_privtype(&i) != NULL) {
3459
0
        session->securityPrivProto =
3460
0
            snmp_duplicate_objid(get_default_privtype(NULL), i);
3461
0
        session->securityPrivProtoLen = i;
3462
0
    }
3463
3464
0
    if ((in_session->securityAuthKeyLen <= 0) &&
3465
0
        ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3466
0
             NETSNMP_DS_LIB_AUTHMASTERKEY)))) {
3467
0
        size_t buflen = sizeof(session->securityAuthKey);
3468
0
        u_char *tmpp = session->securityAuthKey;
3469
0
        session->securityAuthKeyLen = 0;
3470
        /* it will be a hex string */
3471
0
        if (!snmp_hex_to_binary(&tmpp, &buflen,
3472
0
                                &session->securityAuthKeyLen, 0, cp)) {
3473
0
            snmp_set_detail("error parsing authentication master key");
3474
0
            return SNMP_ERR_GENERR;
3475
0
        }
3476
0
    } else if ((in_session->securityAuthKeyLen <= 0) &&
3477
0
               ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3478
0
                                            NETSNMP_DS_LIB_AUTHPASSPHRASE)) ||
3479
0
                (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3480
0
                                            NETSNMP_DS_LIB_PASSPHRASE)))) {
3481
0
        session->securityAuthKeyLen = USM_AUTH_KU_LEN;
3482
0
        if (generate_Ku(session->securityAuthProto,
3483
0
                        session->securityAuthProtoLen,
3484
0
                        (u_char *) cp, strlen(cp),
3485
0
                        session->securityAuthKey,
3486
0
                        &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
3487
0
            snmp_set_detail
3488
0
                ("Error generating a key (Ku) from the supplied authentication pass phrase.");
3489
0
            return SNMP_ERR_GENERR;
3490
0
        }
3491
0
    }
3492
3493
    
3494
0
    if ((in_session->securityPrivKeyLen <= 0) &&
3495
0
        ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3496
0
             NETSNMP_DS_LIB_PRIVMASTERKEY)))) {
3497
0
        size_t buflen = sizeof(session->securityPrivKey);
3498
0
        u_char *tmpp = session->securityPrivKey;
3499
0
        session->securityPrivKeyLen = 0;
3500
        /* it will be a hex string */
3501
0
        if (!snmp_hex_to_binary(&tmpp, &buflen,
3502
0
                                &session->securityPrivKeyLen, 0, cp)) {
3503
0
            snmp_set_detail("error parsing encryption master key");
3504
0
            return SNMP_ERR_GENERR;
3505
0
        }
3506
0
    } else if ((in_session->securityPrivKeyLen <= 0) &&
3507
0
               ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3508
0
                                            NETSNMP_DS_LIB_PRIVPASSPHRASE)) ||
3509
0
                (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3510
0
                                            NETSNMP_DS_LIB_PASSPHRASE)))) {
3511
0
        session->securityPrivKeyLen = USM_PRIV_KU_LEN;
3512
0
        if (generate_Ku(session->securityAuthProto,
3513
0
                        session->securityAuthProtoLen,
3514
0
                        (u_char *) cp, strlen(cp),
3515
0
                        session->securityPrivKey,
3516
0
                        &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
3517
0
            snmp_set_detail
3518
0
                ("Error generating a key (Ku) from the supplied privacy pass phrase.");
3519
0
            return SNMP_ERR_GENERR;
3520
0
        }
3521
0
    }
3522
3523
0
    return SNMPERR_SUCCESS;
3524
0
}
3525
3526
static int usm_build_user(struct usmUser **result,
3527
                          const netsnmp_session *session)
3528
0
{
3529
0
    struct usmUser *user;
3530
3531
0
    DEBUGMSGTL(("usm", "Building user %s...\n", session->securityName));
3532
    /*
3533
     * user doesn't exist so we create and add it
3534
     */
3535
0
    user = calloc(1, sizeof(struct usmUser));
3536
0
    if (user == NULL)
3537
0
        goto err;
3538
3539
    /*
3540
     * copy in the securityName
3541
     */
3542
0
    if (session->securityName) {
3543
0
        user->name = strdup(session->securityName);
3544
0
        user->secName = strdup(session->securityName);
3545
0
        if (user->name == NULL || user->secName == NULL)
3546
0
            goto err;
3547
0
    }
3548
3549
    /*
3550
     * copy in the engineID
3551
     */
3552
0
    user->engineID = netsnmp_memdup(session->securityEngineID,
3553
0
                                    session->securityEngineIDLen);
3554
0
    if (session->securityEngineID && !user->engineID)
3555
0
        goto err;
3556
0
    user->engineIDLen = session->securityEngineIDLen;
3557
0
    *result = user;
3558
0
    return SNMPERR_SUCCESS;
3559
3560
0
err:
3561
0
    usm_free_user(user);
3562
0
    return SNMPERR_GENERR;
3563
0
}
3564
3565
/*
3566
 * usm_create_user_from_session(netsnmp_session *session):
3567
 * 
3568
 * creates a user in the usm table from the information in a session.
3569
 * If the user already exists, it is updated with the current
3570
 * information from the session
3571
 * 
3572
 * Parameters:
3573
 * session -- IN: pointer to the session to use when creating the user.
3574
 * 
3575
 * Returns:
3576
 * SNMPERR_SUCCESS
3577
 * SNMPERR_GENERR 
3578
 */
3579
int
3580
usm_create_user_from_session(netsnmp_session * session)
3581
0
{
3582
0
    struct usmUser *user;
3583
0
    int             user_just_created = 0;
3584
0
    char *cp;
3585
3586
    /*
3587
     * - don't create-another/copy-into user for this session by default
3588
     * - bail now (no error) if we don't have an engineID
3589
     */
3590
0
    if (SNMP_FLAGS_USER_CREATED == (session->flags & SNMP_FLAGS_USER_CREATED) ||
3591
0
        session->securityModel != SNMP_SEC_MODEL_USM ||
3592
0
        session->version != SNMP_VERSION_3 ||
3593
0
        session->securityNameLen == 0 ||
3594
0
        session->securityEngineIDLen == 0)
3595
0
        return SNMPERR_SUCCESS;
3596
3597
0
    DEBUGMSGTL(("usm", "no flag defined...  continuing\n"));
3598
0
    session->flags |= SNMP_FLAGS_USER_CREATED;
3599
3600
    /*
3601
     * now that we have the engineID, create an entry in the USM list
3602
     * for this user using the information in the session 
3603
     */
3604
0
    user = usm_get_user_from_list(session->securityEngineID,
3605
0
                                  session->securityEngineIDLen,
3606
0
                                  session->securityName,
3607
0
                                  session->securityNameLen,
3608
0
                                  usm_get_userList(), 0);
3609
0
    if (NULL != user) {
3610
0
        DEBUGMSGTL(("usm", "user exists x=%p\n", user));
3611
0
    } else {
3612
0
        if (usm_build_user(&user, session) != SNMPERR_SUCCESS)
3613
0
            return SNMPERR_GENERR;
3614
0
        user_just_created = 1;
3615
0
    }
3616
3617
    /*
3618
     * copy the auth protocol 
3619
     */
3620
0
    if (user->authProtocol == NULL && session->securityAuthProto != NULL) {
3621
0
        SNMP_FREE(user->authProtocol);
3622
0
        user->authProtocol =
3623
0
            snmp_duplicate_objid(session->securityAuthProto,
3624
0
                                 session->securityAuthProtoLen);
3625
0
        if (user->authProtocol == NULL) {
3626
0
            usm_free_user(user);
3627
0
            return SNMPERR_GENERR;
3628
0
        }
3629
0
        user->authProtocolLen = session->securityAuthProtoLen;
3630
0
    }
3631
3632
    /*
3633
     * copy the priv protocol 
3634
     */
3635
0
    if (user->privProtocol == NULL && session->securityPrivProto != NULL) {
3636
0
        SNMP_FREE(user->privProtocol);
3637
0
        user->privProtocol =
3638
0
            snmp_duplicate_objid(session->securityPrivProto,
3639
0
                                 session->securityPrivProtoLen);
3640
0
        if (user->privProtocol == NULL) {
3641
0
            usm_free_user(user);
3642
0
            return SNMPERR_GENERR;
3643
0
        }
3644
0
        user->privProtocolLen = session->securityPrivProtoLen;
3645
0
    }
3646
3647
    /*
3648
     * copy in the authentication Key.  If not localized, localize it 
3649
     */
3650
0
    if (user->authKey == NULL) {
3651
0
        if (session->securityAuthLocalKey != NULL
3652
0
            && session->securityAuthLocalKeyLen != 0) {
3653
            /* already localized key passed in.  use it */
3654
0
            SNMP_FREE(user->authKey);
3655
0
            user->authKey = netsnmp_memdup(session->securityAuthLocalKey,
3656
0
                                           session->securityAuthLocalKeyLen);
3657
0
            if (!user->authKey) {
3658
0
                usm_free_user(user);
3659
0
                return SNMPERR_GENERR;
3660
0
            }
3661
0
            user->authKeyLen = session->securityAuthLocalKeyLen;
3662
0
        } else if (session->securityAuthKeyLen != 0) {
3663
0
            SNMP_FREE(user->authKey);
3664
0
            user->authKey = calloc(1, USM_LENGTH_KU_HASHBLOCK);
3665
0
            user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
3666
0
            if ((user->authKey == NULL) ||
3667
0
                generate_kul(user->authProtocol, user->authProtocolLen,
3668
0
                             user->engineID, user->engineIDLen,
3669
0
                             session->securityAuthKey,
3670
0
                             session->securityAuthKeyLen, user->authKey,
3671
0
                             &user->authKeyLen) != SNMPERR_SUCCESS) {
3672
0
                usm_free_user(user);
3673
0
                return SNMPERR_GENERR;
3674
0
            }
3675
0
        } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3676
0
                                               NETSNMP_DS_LIB_AUTHLOCALIZEDKEY))) {
3677
0
            size_t buflen = USM_AUTH_KU_LEN;
3678
0
            SNMP_FREE(user->authKey);
3679
0
            user->authKey = (u_char *)malloc(buflen); /* max length needed */
3680
0
            user->authKeyLen = 0;
3681
            /* it will be a hex string */
3682
0
            if ((NULL == user->authKey) ||
3683
0
                !snmp_hex_to_binary(&user->authKey, &buflen, &user->authKeyLen,
3684
0
                                    0, cp)) {
3685
0
                usm_free_user(user);
3686
0
                return SNMPERR_GENERR;
3687
0
            }
3688
0
        }
3689
0
    }
3690
3691
    /*
3692
     * copy in the privacy Key.  If not localized, localize it 
3693
     */
3694
0
    if (user->privKey == NULL) {
3695
        /** save buffer size in case we need to extend key */
3696
0
        int keyBufSize = USM_PRIV_KU_LEN;
3697
3698
0
        DEBUGMSGTL(("usm", "copying privKey\n"));
3699
0
        if (session->securityPrivLocalKey != NULL
3700
0
            && session->securityPrivLocalKeyLen != 0) {
3701
            /* already localized key passed in.  use it */
3702
0
            SNMP_FREE(user->privKey);
3703
0
            user->privKey = netsnmp_memdup(session->securityPrivLocalKey,
3704
0
                                           session->securityPrivLocalKeyLen);
3705
0
            if (!user->privKey) {
3706
0
                usm_free_user(user);
3707
0
                return SNMPERR_GENERR;
3708
0
            }
3709
0
            keyBufSize = user->privKeyLen = session->securityPrivLocalKeyLen;
3710
0
        } else if (session->securityPrivKeyLen != 0) {
3711
0
            SNMP_FREE(user->privKey);
3712
0
            user->privKey = calloc(1, keyBufSize);
3713
0
            user->privKeyLen = keyBufSize;
3714
0
            if ((user->privKey == NULL) ||
3715
0
                generate_kul(user->authProtocol, user->authProtocolLen,
3716
0
                             user->engineID, user->engineIDLen,
3717
0
                             session->securityPrivKey,
3718
0
                             session->securityPrivKeyLen, user->privKey,
3719
0
                             &user->privKeyLen) != SNMPERR_SUCCESS) {
3720
0
                usm_free_user(user);
3721
0
                return SNMPERR_GENERR;
3722
0
            }
3723
0
        } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3724
0
                                               NETSNMP_DS_LIB_PRIVLOCALIZEDKEY))) {
3725
0
            size_t buflen = keyBufSize;
3726
0
            user->privKey = (u_char *)malloc(buflen); /* max length needed */
3727
0
            user->privKeyLen = 0;
3728
            /* it will be a hex string */
3729
0
            if ((NULL == user->privKey) ||
3730
0
                !snmp_hex_to_binary(&user->privKey, &buflen, &user->privKeyLen,
3731
0
                                    0, cp)) {
3732
0
                usm_free_user(user);
3733
0
                return SNMPERR_GENERR;
3734
0
            }
3735
0
        }
3736
0
        if (usm_extend_user_kul(user, keyBufSize) != SNMPERR_SUCCESS) {
3737
0
            usm_free_user(user);
3738
0
            return SNMPERR_GENERR;
3739
0
        }
3740
0
    }
3741
3742
0
    if (user_just_created) {
3743
        /*
3744
         * add the user into the database 
3745
         */
3746
0
        user->userStatus = RS_ACTIVE;
3747
0
        user->userStorageType = ST_READONLY;
3748
0
        usm_add_user(user);
3749
0
    }
3750
0
    DEBUGMSGTL(("9:usm", "user created\n"));
3751
3752
0
    return SNMPERR_SUCCESS;
3753
3754
3755
0
}
3756
3757
/* A wrapper around the hook */
3758
static int
3759
usm_create_user_from_session_hook(struct session_list *slp,
3760
                                  netsnmp_session *session)
3761
0
{
3762
0
    DEBUGMSGTL(("usm", "potentially bootstrapping the USM table from session data\n"));
3763
0
    return usm_create_user_from_session(session);
3764
0
}
3765
3766
static int
3767
usm_build_probe_pdu(netsnmp_pdu **pdu)
3768
0
{
3769
0
    struct usmUser *user;
3770
3771
    /*
3772
     * create the pdu 
3773
     */
3774
0
    if (!pdu)
3775
0
        return -1;
3776
0
    *pdu = snmp_pdu_create(SNMP_MSG_GET);
3777
0
    if (!(*pdu))
3778
0
        return -1;
3779
0
    (*pdu)->version = SNMP_VERSION_3;
3780
0
    (*pdu)->securityName = strdup("");
3781
0
    (*pdu)->securityNameLen = strlen((*pdu)->securityName);
3782
0
    (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
3783
0
    (*pdu)->securityModel = SNMP_SEC_MODEL_USM;
3784
3785
    /*
3786
     * create the empty user 
3787
     */
3788
0
    user = usm_get_user2(NULL, 0, (*pdu)->securityName,
3789
0
                         (*pdu)->securityNameLen);
3790
0
    if (user == NULL) {
3791
0
        user = calloc(1, sizeof(struct usmUser));
3792
0
        if (user == NULL) {
3793
0
            snmp_free_pdu(*pdu);
3794
0
            *pdu = (netsnmp_pdu *) NULL;
3795
0
            return -1;
3796
0
        }
3797
0
        user->name = strdup((*pdu)->securityName);
3798
0
        user->secName = strdup((*pdu)->securityName);
3799
0
        user->authProtocolLen = OID_LENGTH(usmNoAuthProtocol);
3800
0
        user->authProtocol =
3801
0
            snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
3802
0
        user->privProtocolLen = OID_LENGTH(usmNoPrivProtocol);
3803
0
        user->privProtocol =
3804
0
            snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
3805
0
        usm_add_user(user);
3806
0
    }
3807
0
    return 0;
3808
0
}
3809
3810
static int usm_discover_engineid(struct session_list *slp,
3811
                                 netsnmp_session *session)
3812
0
{
3813
0
    netsnmp_pdu    *pdu = NULL, *response = NULL;
3814
0
    int status, i;
3815
3816
0
    if (usm_build_probe_pdu(&pdu) != 0) {
3817
0
        DEBUGMSGTL(("snmp_api", "unable to create probe PDU\n"));
3818
0
        return SNMP_ERR_GENERR;
3819
0
    }
3820
0
    DEBUGMSGTL(("snmp_api", "probing for engineID...\n"));
3821
0
    session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
3822
0
    status = snmp_sess_synch_response(slp, pdu, &response);
3823
3824
0
    if ((response == NULL) && (status == STAT_SUCCESS)) {
3825
0
        status = STAT_ERROR;
3826
0
    }
3827
3828
0
    switch (status) {
3829
0
    case STAT_SUCCESS:
3830
0
        session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
3831
0
        DEBUGMSGTL(("snmp_sess_open",
3832
0
                    "error: expected Report as response to probe: %s (%ld)\n",
3833
0
                    snmp_errstring(response->errstat),
3834
0
                    response->errstat));
3835
0
        break;
3836
0
    case STAT_ERROR:   /* this is what we expected -> Report == STAT_ERROR */
3837
0
        session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
3838
0
        break;
3839
0
    case STAT_TIMEOUT:
3840
0
        session->s_snmp_errno = SNMPERR_TIMEOUT;
3841
0
        break;
3842
0
    default:
3843
0
        DEBUGMSGTL(("snmp_sess_open",
3844
0
                    "unable to connect with remote engine: %s (%d)\n",
3845
0
                    snmp_api_errstring(session->s_snmp_errno),
3846
0
                    session->s_snmp_errno));
3847
0
        break;
3848
0
    }
3849
3850
0
    if (slp->session->securityEngineIDLen == 0) {
3851
0
        DEBUGMSGTL(("snmp_api",
3852
0
                    "unable to determine remote engine ID\n"));
3853
        /* clear the flag so that probe occurs on next inform */
3854
0
        session->flags &= ~SNMP_FLAGS_DONT_PROBE;
3855
0
        return SNMP_ERR_GENERR;
3856
0
    }
3857
3858
0
    session->s_snmp_errno = SNMPERR_SUCCESS;
3859
0
    if (snmp_get_do_debugging()) {
3860
0
        DEBUGMSGTL(("snmp_sess_open",
3861
0
                    "  probe found engineID:  "));
3862
0
        for (i = 0; i < slp->session->securityEngineIDLen; i++)
3863
0
            DEBUGMSG(("snmp_sess_open", "%02x",
3864
0
                      slp->session->securityEngineID[i]));
3865
0
        DEBUGMSG(("snmp_sess_open", "\n"));
3866
0
    }
3867
3868
    /*
3869
     * if boot/time supplied set it for this engineID 
3870
     */
3871
0
    if (session->engineBoots || session->engineTime) {
3872
0
        set_enginetime(session->securityEngineID,
3873
0
                       session->securityEngineIDLen,
3874
0
                       session->engineBoots, session->engineTime,
3875
0
                       TRUE);
3876
0
    }
3877
0
    return SNMPERR_SUCCESS;
3878
0
}
3879
3880
static int
3881
usm_lookup_alg_type(const char *str, const usm_alg_type_t *types)
3882
0
{
3883
0
    int i, l;
3884
0
    l = strlen(str);
3885
0
    for (i = 0; types[i].label; ++i) {
3886
0
        if (0 == strncasecmp(types[i].label, str, l))
3887
0
            return types[i].value;
3888
0
    }
3889
3890
0
    return -1;
3891
0
}
3892
3893
static const char *
3894
usm_lookup_alg_str(int value, const usm_alg_type_t *types)
3895
0
{
3896
0
    int i;
3897
0
    for (i = 0; types[i].label; ++i)
3898
0
        if (value == types[i].value)
3899
0
            return types[i].label;
3900
3901
0
    return NULL;
3902
0
}
3903
3904
int
3905
usm_lookup_auth_type(const char *str)
3906
0
{
3907
0
    return usm_lookup_alg_type(str, usm_auth_type );
3908
0
}
3909
3910
int
3911
usm_lookup_priv_type(const char *str)
3912
0
{
3913
0
    return usm_lookup_alg_type(str, usm_priv_type );
3914
0
}
3915
3916
const char *
3917
usm_lookup_auth_str(int value)
3918
0
{
3919
0
    return usm_lookup_alg_str(value, usm_auth_type );
3920
0
}
3921
3922
const char *
3923
usm_lookup_priv_str(int value)
3924
0
{
3925
0
    return usm_lookup_alg_str(value, usm_priv_type );
3926
0
}
3927
3928
static void
3929
clear_user_list(void)
3930
0
{
3931
0
    struct usmUser *tmp = userList, *next = NULL;
3932
3933
0
    while (tmp != NULL) {
3934
0
  next = tmp->next;
3935
0
  usm_free_user(tmp);
3936
0
  tmp = next;
3937
0
    }
3938
0
    userList = NULL;
3939
3940
0
}
3941
3942
#ifndef NETSNMP_NO_WRITE_SUPPORT
3943
/*
3944
 * take a given user and clone the security info into another 
3945
 */
3946
struct usmUser *
3947
usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
3948
0
{
3949
0
    to->flags = from->flags;
3950
3951
    /*
3952
     * copy the authProtocol oid row pointer 
3953
     */
3954
0
    SNMP_FREE(to->authProtocol);
3955
3956
0
    if ((to->authProtocol =
3957
0
         snmp_duplicate_objid(from->authProtocol,
3958
0
                              from->authProtocolLen)) != NULL)
3959
0
        to->authProtocolLen = from->authProtocolLen;
3960
0
    else
3961
0
        to->authProtocolLen = 0;
3962
3963
3964
    /*
3965
     * copy the authKey 
3966
     */
3967
0
    SNMP_FREE(to->authKey);
3968
3969
0
    if (from->authKeyLen > 0 &&
3970
0
        (to->authKey = (u_char *) malloc(from->authKeyLen))
3971
0
        != NULL) {
3972
0
        to->authKeyLen = from->authKeyLen;
3973
0
        memcpy(to->authKey, from->authKey, to->authKeyLen);
3974
0
    } else {
3975
0
        to->authKey = NULL;
3976
0
        to->authKeyLen = 0;
3977
0
    }
3978
3979
    /*
3980
     * copy the authKeyKu
3981
     */
3982
0
    SNMP_FREE(to->authKeyKu);
3983
3984
0
    if (from->authKeyKuLen > 0 &&
3985
0
        (to->authKeyKu = (u_char *) malloc(from->authKeyKuLen)) != NULL) {
3986
0
        to->authKeyKuLen = from->authKeyKuLen;
3987
0
        memcpy(to->authKeyKu, from->authKeyKu, to->authKeyKuLen);
3988
0
    } else {
3989
0
        to->authKeyKu = NULL;
3990
0
        to->authKeyKuLen = 0;
3991
0
    }
3992
3993
3994
    /*
3995
     * copy the privProtocol oid row pointer 
3996
     */
3997
0
    SNMP_FREE(to->privProtocol);
3998
3999
0
    if ((to->privProtocol =
4000
0
         snmp_duplicate_objid(from->privProtocol,
4001
0
                              from->privProtocolLen)) != NULL)
4002
0
        to->privProtocolLen = from->privProtocolLen;
4003
0
    else
4004
0
        to->privProtocolLen = 0;
4005
4006
    /*
4007
     * copy the privKey 
4008
     */
4009
0
    SNMP_FREE(to->privKey);
4010
4011
0
    if (from->privKeyLen > 0 &&
4012
0
        (to->privKey = (u_char *) malloc(from->privKeyLen))
4013
0
        != NULL) {
4014
0
        to->privKeyLen = from->privKeyLen;
4015
0
        memcpy(to->privKey, from->privKey, to->privKeyLen);
4016
0
    } else {
4017
0
        to->privKey = NULL;
4018
0
        to->privKeyLen = 0;
4019
0
    }
4020
4021
    /*
4022
     * copy the privKeyKu
4023
     */
4024
0
    SNMP_FREE(to->privKeyKu);
4025
0
    if (from->privKeyKuLen > 0 &&
4026
0
        (to->privKeyKu = (u_char *) malloc(from->privKeyKuLen)) != NULL) {
4027
0
        to->privKeyKuLen = from->privKeyKuLen;
4028
0
        memcpy(to->privKeyKu, from->privKeyKu, to->privKeyKuLen);
4029
0
    } else {
4030
0
        to->privKeyKu = NULL;
4031
0
        to->privKeyKuLen = 0;
4032
0
    }
4033
0
    return to;
4034
0
}
4035
#endif /* NETSNMP_NO_WRITE_SUPPORT */
4036
4037
/*
4038
 * usm_create_user(void):
4039
 * create a default empty user, instantiating only the auth/priv
4040
 * protocols to noAuth and noPriv OID pointers
4041
 */
4042
struct usmUser *
4043
usm_create_user(void)
4044
0
{
4045
0
    struct usmUser *newUser;
4046
4047
    /*
4048
     * create the new user 
4049
     */
4050
0
    newUser = calloc(1, sizeof(struct usmUser));
4051
0
    if (newUser == NULL)
4052
0
        return NULL;
4053
4054
    /*
4055
     * fill the auth/priv protocols 
4056
     */
4057
0
    if ((newUser->authProtocol =
4058
0
         snmp_duplicate_objid(usmNoAuthProtocol,
4059
0
                              OID_LENGTH(usmNoAuthProtocol))) ==
4060
0
        NULL)
4061
0
        return usm_free_user(newUser);
4062
0
    newUser->authProtocolLen = OID_LENGTH(usmNoAuthProtocol);
4063
4064
0
    if ((newUser->privProtocol =
4065
0
         snmp_duplicate_objid(usmNoPrivProtocol,
4066
0
                              OID_LENGTH(usmNoPrivProtocol))) ==
4067
0
        NULL)
4068
0
        return usm_free_user(newUser);
4069
0
    newUser->privProtocolLen = OID_LENGTH(usmNoPrivProtocol);
4070
4071
    /*
4072
     * set the storage type to nonvolatile, and the status to ACTIVE 
4073
     */
4074
0
    newUser->userStorageType = ST_NONVOLATILE;
4075
0
    newUser->userStatus = RS_ACTIVE;
4076
0
    return newUser;
4077
4078
0
}                               /* end usm_clone_user() */
4079
4080
/*
4081
 * usm_create_initial_user(void):
4082
 * creates an initial user, filled with the defaults defined in the
4083
 * USM document.
4084
 */
4085
static struct usmUser *
4086
usm_create_initial_user(const char *name,
4087
                        const oid * authProtocol, size_t authProtocolLen,
4088
                        const oid * privProtocol, size_t privProtocolLen)
4089
0
{
4090
0
    struct usmUser *newUser = usm_create_user();
4091
0
    if (newUser == NULL)
4092
0
        return NULL;
4093
4094
0
    if ((newUser->name = strdup(name)) == NULL)
4095
0
        return usm_free_user(newUser);
4096
4097
0
    if ((newUser->secName = strdup(name)) == NULL)
4098
0
        return usm_free_user(newUser);
4099
4100
0
    if ((newUser->engineID =
4101
0
         snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
4102
0
        return usm_free_user(newUser);
4103
4104
0
    if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL)
4105
0
        return usm_free_user(newUser);
4106
0
    newUser->cloneFrom[0] = 0;
4107
0
    newUser->cloneFrom[1] = 0;
4108
0
    newUser->cloneFromLen = 2;
4109
4110
0
    SNMP_FREE(newUser->privProtocol);
4111
0
    if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol,
4112
0
                                                      privProtocolLen)) ==
4113
0
        NULL) {
4114
0
        return usm_free_user(newUser);
4115
0
    }
4116
0
    newUser->privProtocolLen = privProtocolLen;
4117
4118
0
    SNMP_FREE(newUser->authProtocol);
4119
0
    if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol,
4120
0
                                                      authProtocolLen)) ==
4121
0
        NULL) {
4122
0
        return usm_free_user(newUser);
4123
0
    }
4124
0
    newUser->authProtocolLen = authProtocolLen;
4125
4126
0
    newUser->userStatus = RS_ACTIVE;
4127
0
    newUser->userStorageType = ST_READONLY;
4128
4129
0
    return newUser;
4130
0
}
4131
4132
/*
4133
 * usm_save_user(): saves a user to the persistent cache 
4134
 */
4135
static void
4136
usm_save_user(struct usmUser *user, const char *token, const char *type)
4137
0
{
4138
0
    char            line[4096];
4139
0
    char           *cptr;
4140
4141
0
    memset(line, 0, sizeof(line));
4142
4143
0
    sprintf(line, "%s %d %d ", token, user->userStatus,
4144
0
            user->userStorageType);
4145
0
    cptr = &line[strlen(line)]; /* the NULL */
4146
0
    cptr =
4147
0
        read_config_save_octet_string(cptr, user->engineID,
4148
0
                                      user->engineIDLen);
4149
0
    *cptr++ = ' ';
4150
0
    cptr = read_config_save_octet_string(cptr, (u_char *) user->name,
4151
0
                                         (user->name == NULL) ? 0 :
4152
0
                                         strlen(user->name));
4153
0
    *cptr++ = ' ';
4154
0
    cptr = read_config_save_octet_string(cptr, (u_char *) user->secName,
4155
0
                                         (user->secName == NULL) ? 0 :
4156
0
                                         strlen(user->secName));
4157
0
    *cptr++ = ' ';
4158
0
    cptr =
4159
0
        read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
4160
0
    *cptr++ = ' ';
4161
0
    cptr = read_config_save_objid(cptr, user->authProtocol,
4162
0
                                  user->authProtocolLen);
4163
0
    *cptr++ = ' ';
4164
0
    cptr =
4165
0
        read_config_save_octet_string(cptr, user->authKey,
4166
0
                                      user->authKeyLen);
4167
0
    *cptr++ = ' ';
4168
0
    cptr = read_config_save_objid(cptr, user->privProtocol,
4169
0
                                  user->privProtocolLen);
4170
0
    *cptr++ = ' ';
4171
0
    cptr =
4172
0
        read_config_save_octet_string(cptr, user->privKey,
4173
0
                                      user->privKeyLen);
4174
0
    *cptr++ = ' ';
4175
0
    cptr = read_config_save_octet_string(cptr, user->userPublicString,
4176
0
                                         user->userPublicStringLen);
4177
4178
0
    read_config_store(type, line);
4179
0
}
4180
4181
static void
4182
usm_save_users_from_list(struct usmUser *puserList, const char *token,
4183
                         const char *type)
4184
0
{
4185
0
    struct usmUser *uptr;
4186
0
    for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
4187
0
        if (uptr->userStorageType == ST_NONVOLATILE)
4188
0
            usm_save_user(uptr, token, type);
4189
0
    }
4190
0
}
4191
4192
/*
4193
 * usm_save_users(): saves a list of users to the persistent cache 
4194
 */
4195
static void
4196
usm_save_users(const char *token, const char *type)
4197
0
{
4198
0
    usm_save_users_from_list(userList, token, type);
4199
0
}
4200
4201
/*
4202
 * this is a callback that can store all known users based on a
4203
 * previously registered application ID 
4204
 */
4205
static int
4206
usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
4207
0
{
4208
    /*
4209
     * figure out our application name 
4210
     */
4211
0
    char           *appname = (char *) clientarg;
4212
0
    if (appname == NULL) {
4213
0
        appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
4214
0
          NETSNMP_DS_LIB_APPTYPE);
4215
0
    }
4216
4217
    /*
4218
     * save the user base 
4219
     */
4220
0
    usm_save_users("usmUser", appname);
4221
4222
    /*
4223
     * never fails 
4224
     */
4225
0
    return SNMPERR_SUCCESS;
4226
0
}
4227
4228
/*
4229
 * usm_parse_user(): reads in a line containing a saved user profile
4230
 * and returns a pointer to a newly created struct usmUser. 
4231
 */
4232
static struct usmUser *
4233
usm_read_user(const char *line)
4234
0
{
4235
0
    struct usmUser *user;
4236
0
    size_t          len, proper_length, privtype;
4237
4238
0
    user = usm_create_user();
4239
0
    if (user == NULL)
4240
0
        return NULL;
4241
4242
0
    user->userStatus = atoi(line);
4243
0
    line = skip_token_const(line);
4244
0
    user->userStorageType = atoi(line);
4245
0
    line = skip_token_const(line);
4246
0
    line = read_config_read_octet_string_const(line, &user->engineID,
4247
0
                                               &user->engineIDLen);
4248
4249
    /*
4250
     * set the lcd entry for this engineID to the minimum boots/time
4251
     * values so that its a known engineid and won't return a report pdu.
4252
     * This is mostly important when receiving v3 traps so that the usm
4253
     * will at least continue processing them. 
4254
     */
4255
0
    set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
4256
4257
0
    line = read_config_read_octet_string(line, (u_char **) & user->name,
4258
0
                                         &len);
4259
0
    line = read_config_read_octet_string(line, (u_char **) & user->secName,
4260
0
                                         &len);
4261
0
    SNMP_FREE(user->cloneFrom);
4262
0
    user->cloneFromLen = 0;
4263
4264
0
    line = read_config_read_objid_const(line, &user->cloneFrom,
4265
0
                                        &user->cloneFromLen);
4266
4267
0
    SNMP_FREE(user->authProtocol);
4268
0
    user->authProtocolLen = 0;
4269
4270
0
    line = read_config_read_objid_const(line, &user->authProtocol,
4271
0
                                        &user->authProtocolLen);
4272
0
    line = read_config_read_octet_string_const(line, &user->authKey,
4273
0
                                               &user->authKeyLen);
4274
0
    SNMP_FREE(user->privProtocol);
4275
0
    user->privProtocolLen = 0;
4276
4277
0
    line = read_config_read_objid_const(line, &user->privProtocol,
4278
0
                                        &user->privProtocolLen);
4279
0
    line = read_config_read_octet_string(line, &user->privKey,
4280
0
                                         &user->privKeyLen);
4281
4282
0
    privtype = sc_get_privtype(user->privProtocol, user->privProtocolLen);
4283
0
    proper_length = sc_get_proper_priv_length_bytype(privtype);
4284
0
    if (USM_CREATE_USER_PRIV_DES == privtype)
4285
0
        proper_length *= 2; /* ?? we store salt with key */
4286
    /* For backwards compatibility */
4287
0
    if (user->privKeyLen > proper_length) {
4288
0
        user->privKeyLen = proper_length;
4289
0
    }
4290
4291
0
    line = read_config_read_octet_string(line, &user->userPublicString,
4292
0
                                         &user->userPublicStringLen);
4293
0
    return user;
4294
0
}
4295
4296
/*
4297
 * snmpd.conf parsing routines 
4298
 */
4299
void
4300
usm_parse_config_usmUser(const char *token, char *line)
4301
0
{
4302
0
    struct usmUser *uptr;
4303
4304
0
    uptr = usm_read_user(line);
4305
0
    if ( uptr)
4306
0
        usm_add_user(uptr);
4307
0
}
4308
4309
/*******************************************************************-o-******
4310
 * usm_set_password
4311
 *
4312
 * Parameters:
4313
 *  *token
4314
 *  *line
4315
 *      
4316
 *
4317
 * format: userSetAuthPass     secname engineIDLen engineID pass
4318
 *     or: userSetPrivPass     secname engineIDLen engineID pass 
4319
 *     or: userSetAuthKey      secname engineIDLen engineID KuLen Ku
4320
 *     or: userSetPrivKey      secname engineIDLen engineID KuLen Ku 
4321
 *     or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
4322
 *     or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul 
4323
 *
4324
 * type is: 1=passphrase; 2=Ku; 3=Kul.
4325
 *
4326
 *
4327
 * ASSUMES  Passwords are null-terminated printable strings.
4328
 */
4329
static void
4330
usm_set_password(const char *token, char *line)
4331
0
{
4332
0
    char           *cp;
4333
0
    char            nameBuf[SNMP_MAXBUF];
4334
0
    u_char         *engineID = NULL;
4335
0
    size_t          engineIDLen = 0;
4336
0
    struct usmUser *user;
4337
4338
0
    cp = copy_nword(line, nameBuf, sizeof(nameBuf));
4339
0
    if (cp == NULL) {
4340
0
        config_perror("invalid name specifier");
4341
0
        return;
4342
0
    }
4343
4344
0
    DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
4345
0
    if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
4346
        /*
4347
         * match against all engineIDs we know about 
4348
         */
4349
0
        cp = skip_token(cp);
4350
0
        for (user = userList; user != NULL; user = user->next) {
4351
0
            if (user->secName && strcmp(user->secName, nameBuf) == 0) {
4352
0
                usm_set_user_password(user, token, cp);
4353
0
            }
4354
0
        }
4355
0
    } else {
4356
0
        cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
4357
0
        if (cp == NULL) {
4358
0
            config_perror("invalid engineID specifier");
4359
0
            SNMP_FREE(engineID);
4360
0
            return;
4361
0
        }
4362
4363
0
        user = usm_get_user(engineID, engineIDLen, nameBuf);
4364
0
        if (user == NULL) {
4365
0
            config_perror("not a valid user/engineID pair");
4366
0
            SNMP_FREE(engineID);
4367
0
            return;
4368
0
        }
4369
0
        usm_set_user_password(user, token, cp);
4370
0
        SNMP_FREE(engineID);
4371
0
    }
4372
0
}
4373
4374
/*
4375
 * uses the rest of LINE to configure USER's password of type TOKEN 
4376
 */
4377
void
4378
usm_set_user_password(struct usmUser *user, const char *token, char *line)
4379
0
{
4380
0
    char           *cp = line;
4381
0
    u_char         *engineID = user->engineID;
4382
0
    size_t          engineIDLen = user->engineIDLen;
4383
4384
0
    u_char        **key;
4385
0
    size_t         *keyLen;
4386
0
    u_char          userKey[SNMP_MAXBUF_SMALL];
4387
0
    size_t          userKeyLen = SNMP_MAXBUF_SMALL;
4388
0
    u_char         *userKeyP = userKey;
4389
0
    int             type, ret;
4390
4391
    /*
4392
     * Retrieve the "old" key and set the key type.
4393
     */
4394
0
    if (!token) {
4395
0
        return;
4396
0
    } else if (strcmp(token, "userSetAuthPass") == 0) {
4397
0
        key = &user->authKey;
4398
0
        keyLen = &user->authKeyLen;
4399
0
        type = 0;
4400
0
    } else if (strcmp(token, "userSetPrivPass") == 0) {
4401
0
        key = &user->privKey;
4402
0
        keyLen = &user->privKeyLen;
4403
0
        type = 0;
4404
0
    } else if (strcmp(token, "userSetAuthKey") == 0) {
4405
0
        key = &user->authKey;
4406
0
        keyLen = &user->authKeyLen;
4407
0
        type = 1;
4408
0
    } else if (strcmp(token, "userSetPrivKey") == 0) {
4409
0
        key = &user->privKey;
4410
0
        keyLen = &user->privKeyLen;
4411
0
        type = 1;
4412
0
    } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
4413
0
        key = &user->authKey;
4414
0
        keyLen = &user->authKeyLen;
4415
0
        type = 2;
4416
0
    } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
4417
0
        key = &user->privKey;
4418
0
        keyLen = &user->privKeyLen;
4419
0
        type = 2;
4420
0
    } else {
4421
        /*
4422
         * no old key, or token was not recognized 
4423
         */
4424
0
        return;
4425
0
    }
4426
4427
0
    if (*key) {
4428
        /*
4429
         * (destroy and) free the old key 
4430
         */
4431
0
        memset(*key, 0, *keyLen);
4432
0
        SNMP_FREE(*key);
4433
0
    }
4434
4435
0
    if (type == 0) {
4436
        /*
4437
         * convert the password into a key 
4438
         */
4439
0
        if (cp == NULL) {
4440
0
            config_perror("missing user password");
4441
0
            return;
4442
0
        }
4443
0
        ret = generate_Ku(user->authProtocol, user->authProtocolLen,
4444
0
                          (u_char *) cp, strlen(cp), userKey, &userKeyLen);
4445
4446
0
        if (ret != SNMPERR_SUCCESS) {
4447
0
            config_perror("setting key failed (in sc_genKu())");
4448
0
            return;
4449
0
        }
4450
        /* save master key */
4451
0
        if (user->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4452
0
            if (userKey == user->privKey) {
4453
0
                user->privKeyKu = netsnmp_memdup(userKey, userKeyLen);
4454
0
                user->privKeyKuLen = userKeyLen;
4455
0
            } else if (userKey == user->authKey) {
4456
0
                user->authKeyKu = netsnmp_memdup(userKey, userKeyLen);
4457
0
                user->authKeyKuLen = userKeyLen;
4458
0
            }
4459
0
        }
4460
0
    } else if (type == 1) {
4461
0
        cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen);
4462
4463
0
        if (cp == NULL) {
4464
0
            config_perror("invalid user key");
4465
0
            return;
4466
0
        }
4467
0
    }
4468
4469
0
    if (type < 2) {
4470
0
        *key = (u_char *) malloc(SNMP_MAXBUF_SMALL);
4471
0
        *keyLen = SNMP_MAXBUF_SMALL;
4472
0
        ret = generate_kul(user->authProtocol, user->authProtocolLen,
4473
0
                           engineID, engineIDLen,
4474
0
                           userKey, userKeyLen, *key, keyLen);
4475
0
        if (ret != SNMPERR_SUCCESS) {
4476
0
            config_perror("setting key failed (in generate_kul())");
4477
0
            return;
4478
0
        }
4479
4480
        /*
4481
         * (destroy and) free the old key 
4482
         */
4483
0
        memset(userKey, 0, sizeof(userKey));
4484
4485
0
    } else {
4486
        /*
4487
         * the key is given, copy it in 
4488
         */
4489
0
        cp = read_config_read_octet_string(cp, key, keyLen);
4490
4491
0
        if (cp == NULL) {
4492
0
            config_perror("invalid localized user key");
4493
0
            return;
4494
0
        }
4495
0
    }
4496
4497
0
    if (key == &user->privKey) {
4498
0
        ret = usm_extend_user_kul(user, *keyLen);
4499
0
        if (SNMPERR_SUCCESS != ret) {
4500
0
            config_perror("error extending localized user key");
4501
0
            return;
4502
0
        }
4503
0
    }
4504
0
}                               /* end usm_set_password() */
4505
4506
/*
4507
 * create a usm user from a string.
4508
 *
4509
 * The format for the string is described in the createUser
4510
 * secion of the snmpd.conf man page.
4511
 *
4512
 * On success, a pointer to the created usmUser struct is returned.
4513
 * On error, a NULL pointer is returned. In this case, if a pointer to a
4514
 *    char pointer is provided in errorMsg, an error string is returned.
4515
 *    This error string points to a static message, and should not be
4516
 *    freed.
4517
 */
4518
static struct usmUser *
4519
usm_create_usmUser_from_string(char *line, const char **errorMsg)
4520
0
{
4521
0
    char           *cp;
4522
0
    const char     *dummy;
4523
0
    char            buf[SNMP_MAXBUF_MEDIUM];
4524
0
    struct usmUser *newuser;
4525
0
    u_char          userKey[SNMP_MAXBUF_SMALL], *tmpp;
4526
0
    size_t          userKeyLen = SNMP_MAXBUF_SMALL;
4527
0
    size_t          privKeySize;
4528
0
    size_t          ret;
4529
0
    int             ret2, properLen, properPrivKeyLen;
4530
0
    const oid      *def_auth_prot, *def_priv_prot;
4531
0
    size_t          def_auth_prot_len, def_priv_prot_len;
4532
0
    const netsnmp_priv_alg_info *pai;
4533
4534
0
    def_auth_prot = get_default_authtype(&def_auth_prot_len);
4535
0
    def_priv_prot = get_default_privtype(&def_priv_prot_len);
4536
4537
0
    if (NULL == line)
4538
0
        return NULL;
4539
4540
#ifdef NETSNMP_ENABLE_TESTING_CODE
4541
    DEBUGMSGTL(("usmUser", "new user %s\n", line)); /* logs passphrases */
4542
#endif
4543
4544
0
    if (NULL == errorMsg)
4545
0
        errorMsg = &dummy;
4546
0
    *errorMsg = NULL; /* no errors yet */
4547
4548
0
    newuser = usm_create_user();
4549
0
    if (newuser == NULL) {
4550
0
        *errorMsg = "malloc failure creating new user";
4551
0
        goto fail;
4552
0
    }
4553
4554
    /*
4555
     * READ: Security Name 
4556
     */
4557
0
    cp = copy_nword(line, buf, sizeof(buf));
4558
4559
    /*
4560
     * check for (undocumented) 'keep master key' flag. so far, this is
4561
     * just used for users for informs (who need non-localized keys).
4562
     */
4563
0
    if (strcmp(buf, "-M") == 0) {
4564
0
        newuser->flags |= USMUSER_FLAG_KEEP_MASTER_KEY;
4565
0
        cp = copy_nword(cp, buf, sizeof(buf));
4566
0
    }
4567
4568
    /*
4569
     * might be a -e ENGINEID argument 
4570
     */
4571
0
    if (strcmp(buf, "-e") == 0) {
4572
0
        size_t          ebuf_len = 32, eout_len = 0;
4573
0
        u_char         *ebuf = (u_char *) malloc(ebuf_len);
4574
4575
0
        if (ebuf == NULL) {
4576
0
            *errorMsg = "malloc failure processing -e flag";
4577
0
            goto fail;
4578
0
        }
4579
4580
        /*
4581
         * Get the specified engineid from the line.  
4582
         */
4583
0
        cp = copy_nword(cp, buf, sizeof(buf));
4584
0
        if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
4585
0
            *errorMsg = "invalid EngineID argument to -e";
4586
0
            SNMP_FREE(ebuf);
4587
0
            goto fail;
4588
0
        }
4589
4590
0
        newuser->engineID = ebuf;
4591
0
        newuser->engineIDLen = eout_len;
4592
0
        cp = copy_nword(cp, buf, sizeof(buf));
4593
0
    } else {
4594
0
        newuser->engineID = snmpv3_generate_engineID(&ret);
4595
0
        if (ret == 0) {
4596
0
            goto fail;
4597
0
        }
4598
0
        newuser->engineIDLen = ret;
4599
0
    }
4600
4601
0
    newuser->secName = strdup(buf);
4602
0
    newuser->name = strdup(buf);
4603
4604
0
    if (!cp) {
4605
#ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV
4606
        /** no passwords ok iff defaults are noauth/nopriv */
4607
        if (snmp_oid_compare(usmNoAuthProtocol, OID_LENGTH(usmNoAuthProtocol),
4608
                             def_auth_prot, def_auth_prot_len) != 0) {
4609
            *errorMsg = "no authentication pass phrase";
4610
            goto fail;
4611
        }
4612
        if (snmp_oid_compare(usmNoPrivProtocol, OID_LENGTH(usmNoPrivProtocol),
4613
                             def_priv_prot, def_priv_prot_len) != 0) {
4614
            *errorMsg = "no privacy pass phrase";
4615
            goto fail;
4616
        }
4617
#endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */
4618
0
        goto add;               /* no authentication or privacy type */
4619
0
    }
4620
4621
    /*
4622
     * READ: Authentication Type 
4623
     */
4624
0
    newuser->authProtocol[0] = 0;
4625
0
    cp = copy_nword(cp, buf, sizeof(buf));
4626
0
    if ((strncmp(cp, "default", 7) == 0) && (NULL != def_auth_prot)) {
4627
0
        SNMP_FREE(newuser->authProtocol);
4628
0
        newuser->authProtocol = snmp_duplicate_objid(def_auth_prot,
4629
0
                                                     def_auth_prot_len);
4630
0
        if (newuser->authProtocol == NULL) {
4631
0
            *errorMsg = "malloc failed";
4632
0
            goto fail;
4633
0
        }
4634
0
        newuser->authProtocolLen = def_auth_prot_len;
4635
0
    } else {
4636
0
        const oid *auth_prot;
4637
0
        int auth_type = usm_lookup_auth_type(buf);
4638
0
        if (auth_type < 0) {
4639
0
            *errorMsg = "unknown authProtocol";
4640
0
            goto fail;
4641
0
        }
4642
0
        auth_prot = sc_get_auth_oid(auth_type, &newuser->authProtocolLen);
4643
0
        if (auth_prot) {
4644
0
            SNMP_FREE(newuser->authProtocol);
4645
0
            newuser->authProtocol =
4646
0
                snmp_duplicate_objid(auth_prot, newuser->authProtocolLen);
4647
0
        }
4648
0
        if (newuser->authProtocol == NULL) {
4649
0
            *errorMsg = "malloc failed";
4650
0
            goto fail;
4651
0
        }
4652
0
    }
4653
0
    if (0 == newuser->authProtocol[0]) {
4654
0
        *errorMsg = "Unknown authentication protocol";
4655
0
        goto fail;
4656
0
    }
4657
#ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV
4658
    if (snmp_oid_compare(newuser->authProtocol, newuser->authProtocolLen,
4659
                         def_auth_prot, def_auth_prot_len) != 0) {
4660
        *errorMsg = "auth protocol does not match system policy";
4661
        goto fail;
4662
    }
4663
#endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */
4664
4665
    /*
4666
     * READ: Authentication Pass Phrase or key
4667
     */
4668
0
    cp = copy_nword(cp, buf, sizeof(buf));
4669
0
    if (strcmp(buf,"-m") == 0) {
4670
        /* a master key is specified */
4671
0
        cp = copy_nword(cp, buf, sizeof(buf));
4672
0
        ret = sizeof(userKey);
4673
0
        tmpp = userKey;
4674
0
        userKeyLen = 0;
4675
0
        if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
4676
0
            *errorMsg = "invalid key value argument to -m";
4677
0
            goto fail;
4678
0
        }
4679
        /* save master key */
4680
0
        if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4681
0
            newuser->authKeyKu = netsnmp_memdup(userKey, userKeyLen);
4682
0
            newuser->authKeyKuLen = userKeyLen;
4683
0
        }
4684
0
    } else if (strcmp(buf,"-l") != 0) {
4685
        /* a password is specified */
4686
0
        userKeyLen = sizeof(userKey);
4687
0
        ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
4688
0
                          (u_char *) buf, strlen(buf), userKey, &userKeyLen);
4689
0
        if (ret2 != SNMPERR_SUCCESS) {
4690
0
            *errorMsg = "could not generate the authentication key from the supplied pass phrase.";
4691
0
            goto fail;
4692
0
        }
4693
        /* save master key */
4694
0
        if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4695
0
            newuser->authKeyKu = netsnmp_memdup(userKey, userKeyLen);
4696
0
            newuser->authKeyKuLen = userKeyLen;
4697
0
        }
4698
0
    }        
4699
        
4700
    /*
4701
     * And turn it into a localized key 
4702
     */
4703
0
    properLen = sc_get_proper_auth_length_bytype(
4704
0
        sc_get_authtype(newuser->authProtocol, newuser->authProtocolLen));
4705
0
    if (properLen <= 0) {
4706
0
        *errorMsg = "Could not get proper authentication protocol key length";
4707
0
        goto fail;
4708
0
    }
4709
0
    newuser->authKey = (u_char *) malloc(properLen);
4710
0
    newuser->authKeyLen = properLen;
4711
4712
0
    if (strcmp(buf,"-l") == 0) {
4713
        /* a local key is directly specified */
4714
0
        cp = copy_nword(cp, buf, sizeof(buf));
4715
0
        ret = newuser->authKeyLen;
4716
0
        newuser->authKeyLen = 0;
4717
0
        if (!snmp_hex_to_binary(&newuser->authKey, &ret,
4718
0
                                &newuser->authKeyLen, 0, buf)) {
4719
0
            *errorMsg = "invalid key value argument to -l";
4720
0
            goto fail;
4721
0
        }
4722
0
        if (properLen != newuser->authKeyLen) {
4723
0
            *errorMsg = "improper key length to -l";
4724
0
            goto fail;
4725
0
        }
4726
0
    } else {
4727
0
        ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
4728
0
                           newuser->engineID, newuser->engineIDLen,
4729
0
                           userKey, userKeyLen,
4730
0
                           newuser->authKey, &newuser->authKeyLen);
4731
0
        if (ret2 != SNMPERR_SUCCESS) {
4732
0
            *errorMsg = "could not generate localized authentication key (Kul) from the master key (Ku).";
4733
0
            goto fail;
4734
0
        }
4735
0
    }
4736
4737
0
    if (!cp) {
4738
0
#ifndef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV
4739
0
        goto add;               /* no privacy type (which is legal) */
4740
#else
4741
        if (snmp_oid_compare(usmNoPrivProtocol, OID_LENGTH(usmNoPrivProtocol),
4742
                             def_priv_prot, def_priv_prot_len) == 0)
4743
            goto add;
4744
        else {
4745
            *errorMsg = "priv protocol does not match system policy";
4746
            goto fail;
4747
        }
4748
#endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */
4749
0
    }
4750
4751
    /*
4752
     * READ: Privacy Type 
4753
     */
4754
0
    newuser->privProtocol[0] = 0;
4755
0
    cp = copy_nword(cp, buf, sizeof(buf));
4756
0
    if ((strncmp(buf, "default", 7) == 0) && (NULL != def_priv_prot)) {
4757
0
        SNMP_FREE(newuser->privProtocol);
4758
0
        newuser->privProtocol =
4759
0
            snmp_duplicate_objid(def_priv_prot, def_priv_prot_len);
4760
0
        if (newuser->privProtocol == NULL) {
4761
0
            *errorMsg = "malloc failed";
4762
0
            goto fail;
4763
0
        }
4764
0
        newuser->privProtocolLen = def_priv_prot_len;
4765
0
        pai = sc_get_priv_alg_byoid(newuser->privProtocol,
4766
0
                                    newuser->privProtocolLen);
4767
0
    } else {
4768
0
        int priv_type = usm_lookup_priv_type(buf);
4769
0
        if (priv_type < 0) {
4770
0
            *errorMsg = "unknown privProtocol";
4771
0
            DEBUGMSGTL(("usmUser", "%s %s\n", *errorMsg, buf));
4772
0
            goto fail;
4773
0
        }
4774
0
        DEBUGMSGTL(("9:usmUser", "privProtocol %s\n", buf));
4775
0
        pai = sc_get_priv_alg_bytype(priv_type);
4776
0
        if (pai) {
4777
0
            SNMP_FREE(newuser->privProtocol);
4778
0
            newuser->privProtocolLen = pai->oid_len;
4779
0
            newuser->privProtocol =
4780
0
                snmp_duplicate_objid(pai->alg_oid, newuser->privProtocolLen);
4781
0
            DEBUGMSGTL(("9:usmUser", "pai %s\n", pai->name));
4782
0
            if (newuser->privProtocol == NULL) {
4783
0
                *errorMsg = "malloc failed";
4784
0
                goto fail;
4785
0
            }
4786
0
        }
4787
0
    }
4788
0
    if (NULL == pai) {
4789
0
        *errorMsg = "priv protocol lookup failed";
4790
0
        goto fail;
4791
0
    }
4792
4793
0
    if (0 == newuser->privProtocol[0] && NULL == *errorMsg)
4794
0
        *errorMsg = "Unknown privacy protocol";
4795
0
    if (NULL != *errorMsg)
4796
0
        goto fail;
4797
#ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV
4798
    if (snmp_oid_compare(newuser->privProtocol, newuser->privProtocolLen,
4799
                         def_priv_prot, def_priv_prot_len) != 0) {
4800
        *errorMsg = "priv protocol does not match system policy";
4801
        goto fail;
4802
    }
4803
#endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */
4804
4805
0
    properPrivKeyLen = pai->proper_length;
4806
0
    if (USM_CREATE_USER_PRIV_DES == pai->type)
4807
0
        properPrivKeyLen *= 2; /* ?? we store salt with key */
4808
4809
    /*
4810
     * READ: Encryption Pass Phrase or key
4811
     */
4812
0
    if (!cp) {
4813
        /*
4814
         * assume the same as the authentication key 
4815
         */
4816
0
        newuser->privKey = netsnmp_memdup(newuser->authKey,
4817
0
                                          newuser->authKeyLen);
4818
0
        privKeySize = newuser->privKeyLen = newuser->authKeyLen;
4819
0
        if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4820
0
            newuser->privKeyKu = netsnmp_memdup(newuser->authKeyKu,
4821
0
                                                newuser->authKeyKuLen);
4822
0
            newuser->privKeyKuLen = newuser->authKeyKuLen;
4823
0
        }
4824
0
    } else {
4825
0
        cp = copy_nword(cp, buf, sizeof(buf));
4826
        
4827
0
        if (strcmp(buf,"-m") == 0) {
4828
            /* a master key is specified */
4829
0
            cp = copy_nword(cp, buf, sizeof(buf));
4830
0
            ret = sizeof(userKey);
4831
0
            tmpp = userKey;
4832
0
            userKeyLen = 0;
4833
0
            if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
4834
0
                *errorMsg = "invalid key value argument to -m";
4835
0
                goto fail;
4836
0
            }
4837
            /* save master key */
4838
0
            if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4839
0
                newuser->privKeyKu = netsnmp_memdup(userKey, userKeyLen);
4840
0
                newuser->privKeyKuLen = userKeyLen;
4841
0
            }
4842
0
        } else if (strcmp(buf,"-l") != 0) {
4843
            /* a password is specified */
4844
0
            userKeyLen = sizeof(userKey);
4845
0
            ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
4846
0
                              (u_char*)buf, strlen(buf), userKey, &userKeyLen);
4847
0
            if (ret2 != SNMPERR_SUCCESS) {
4848
0
                *errorMsg = "could not generate the privacy key from the supplied pass phrase.";
4849
0
                goto fail;
4850
0
            }
4851
            /* save master key */
4852
0
            if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) {
4853
0
                newuser->privKeyKu = netsnmp_memdup(userKey, userKeyLen);
4854
0
                newuser->privKeyKuLen = userKeyLen;
4855
0
            }
4856
0
        }
4857
4858
        /*
4859
         * And turn it into a localized key
4860
         * Allocate enough space for greater of auth mac and privKey len.
4861
         */
4862
0
        privKeySize = SNMP_MAX(properPrivKeyLen, properLen);
4863
0
        newuser->privKey = (u_char *) malloc(privKeySize);
4864
0
        newuser->privKeyLen = privKeySize;
4865
4866
0
        if (strcmp(buf,"-l") == 0) {
4867
            /* a local key is directly specified */
4868
0
            cp = copy_nword(cp, buf, sizeof(buf));
4869
0
            ret = newuser->privKeyLen;
4870
0
            newuser->privKeyLen = 0;
4871
0
            if (!snmp_hex_to_binary(&newuser->privKey, &ret,
4872
0
                                    &newuser->privKeyLen, 0, buf)) {
4873
0
                *errorMsg = "invalid key value argument to -l";
4874
0
                goto fail;
4875
0
            }
4876
0
        } else {
4877
0
            ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
4878
0
                               newuser->engineID, newuser->engineIDLen,
4879
0
                               userKey, userKeyLen,
4880
0
                               newuser->privKey, &newuser->privKeyLen);
4881
0
            if (ret2 != SNMPERR_SUCCESS) {
4882
0
                *errorMsg = "could not generate localized privacy key (Kul) from the master key (Ku).";
4883
0
                goto fail;
4884
0
            }
4885
0
        }
4886
4887
0
        if (newuser->privKeyLen < properPrivKeyLen) {
4888
0
            ret = usm_extend_user_kul(newuser, properPrivKeyLen);
4889
0
            if (ret != SNMPERR_SUCCESS) {
4890
0
                *errorMsg = "could not extend localized privacy key to required length.";
4891
0
                goto fail;
4892
0
            }
4893
0
        }
4894
0
    }
4895
4896
0
    if ((newuser->privKeyLen >= properPrivKeyLen) || (properPrivKeyLen == 0)){
4897
0
        DEBUGMSGTL(("9:usmUser", "truncating privKeyLen from %" NETSNMP_PRIz "d to %d\n",
4898
0
                    newuser->privKeyLen, properPrivKeyLen));
4899
0
        newuser->privKeyLen = properPrivKeyLen;
4900
0
    }
4901
0
    else {
4902
0
        DEBUGMSGTL(("usmUser",
4903
0
                    "privKey length %" NETSNMP_PRIz "d < %d required by privProtocol\n",
4904
0
                    newuser->privKeyLen, properPrivKeyLen));
4905
0
      *errorMsg = "privKey length is less than required by privProtocol";
4906
0
      goto fail;
4907
0
    }
4908
4909
0
  add:
4910
0
    usm_add_user(newuser);
4911
0
    DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
4912
0
    DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
4913
0
    DEBUGMSG(("usmUser", "\n"));
4914
4915
0
    return newuser;
4916
4917
0
  fail:
4918
0
    usm_free_user(newuser);
4919
0
    return NULL;
4920
0
}
4921
4922
void
4923
usm_parse_create_usmUser(const char *token, char *line)
4924
0
{
4925
0
    const char *error = NULL;
4926
0
    usm_create_usmUser_from_string(line, &error);
4927
0
    if (error)
4928
0
        config_perror(error);
4929
0
}
4930
4931
static void
4932
snmpv3_authtype_conf(const char *word, char *cptr)
4933
0
{
4934
0
    int auth_type = usm_lookup_auth_type(cptr);
4935
0
    if (auth_type < 0)
4936
0
        config_perror("Unknown authentication type");
4937
0
    defaultAuthType = sc_get_auth_oid(auth_type, &defaultAuthTypeLen);
4938
0
    DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr));
4939
0
}
4940
4941
const oid      *
4942
get_default_authtype(size_t * len)
4943
0
{
4944
0
    if (defaultAuthType == NULL) {
4945
0
        defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
4946
0
        defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
4947
0
    }
4948
0
    if (len)
4949
0
        *len = defaultAuthTypeLen;
4950
0
    return defaultAuthType;
4951
0
}
4952
4953
static void
4954
snmpv3_privtype_conf(const char *word, char *cptr)
4955
0
{
4956
0
    int priv_type = usm_lookup_priv_type(cptr);
4957
0
    if (priv_type < 0)
4958
0
        config_perror("Unknown privacy type");
4959
0
    defaultPrivType = sc_get_priv_oid(priv_type, &defaultPrivTypeLen);
4960
0
    DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr));
4961
0
}
4962
4963
const oid      *
4964
get_default_privtype(size_t * len)
4965
0
{
4966
0
    if (defaultPrivType == NULL) {
4967
0
        defaultPrivType = SNMP_DEFAULT_PRIV_PROTO;
4968
0
        defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
4969
0
    }
4970
0
    if (len)
4971
0
        *len = defaultPrivTypeLen;
4972
0
    return defaultPrivType;
4973
0
}
4974
4975
void
4976
init_usm_conf(const char *app)
4977
0
{
4978
0
    register_config_handler(app, "usmUser",
4979
0
                                  usm_parse_config_usmUser, NULL, NULL);
4980
0
    register_config_handler(app, "createUser",
4981
0
                                  usm_parse_create_usmUser, NULL,
4982
0
                                  "username [-e ENGINEID] (MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224|default) authpassphrase [(DES|AES|default) [privpassphrase]]");
4983
4984
    /*
4985
     * we need to be called back later
4986
     */
4987
0
    snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
4988
0
                           usm_store_users, NULL);
4989
0
}
4990
4991
/*
4992
 * initializations for the USM.
4993
 *
4994
 * Should be called after the (engineid) configuration files have been read.
4995
 *
4996
 * Set "arbitrary" portion of salt to a random number.
4997
 */
4998
static int
4999
init_usm_post_config(int majorid, int minorid, void *serverarg,
5000
                     void *clientarg)
5001
0
{
5002
0
    size_t          salt_integer_len = sizeof(salt_integer);
5003
5004
0
    if (sc_random((u_char *) & salt_integer, &salt_integer_len) !=
5005
0
        SNMPERR_SUCCESS) {
5006
0
        DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
5007
0
        salt_integer = (u_int) time(NULL);
5008
0
    }
5009
5010
0
#ifdef HAVE_AES
5011
0
    salt_integer_len = sizeof (salt_integer64_1);
5012
0
    if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
5013
0
        SNMPERR_SUCCESS) {
5014
0
        DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
5015
0
        salt_integer64_1 = (u_int) time(NULL);
5016
0
    }
5017
0
    salt_integer_len = sizeof (salt_integer64_1);
5018
0
    if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
5019
0
        SNMPERR_SUCCESS) {
5020
0
        DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
5021
0
        salt_integer64_2 = (u_int) time(NULL);
5022
0
    }
5023
0
#endif
5024
5025
0
#ifndef NETSNMP_DISABLE_MD5
5026
0
    noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
5027
0
                                         OID_LENGTH(usmHMACMD5AuthProtocol),
5028
0
                                         SNMP_DEFAULT_PRIV_PROTO,
5029
0
                                         SNMP_DEFAULT_PRIV_PROTOLEN);
5030
#else
5031
    noNameUser = usm_create_initial_user("", usmHMACSHA1AuthProtocol,
5032
                                         OID_LENGTH(usmHMACSHA1AuthProtocol),
5033
                                         SNMP_DEFAULT_PRIV_PROTO,
5034
                                         SNMP_DEFAULT_PRIV_PROTOLEN);
5035
#endif
5036
5037
0
    if ( noNameUser ) {
5038
0
        SNMP_FREE(noNameUser->engineID);
5039
0
        noNameUser->engineIDLen = 0;
5040
0
    }
5041
5042
0
    return SNMPERR_SUCCESS;
5043
0
}                               /* end init_usm_post_config() */
5044
5045
static int
5046
deinit_usm_post_config(int majorid, int minorid, void *serverarg,
5047
           void *clientarg)
5048
0
{
5049
0
    if (usm_free_user(noNameUser) != NULL) {
5050
0
  DEBUGMSGTL(("deinit_usm_post_config", "could not free initial user\n"));
5051
0
  return SNMPERR_GENERR;
5052
0
    }
5053
0
    noNameUser = NULL;
5054
5055
0
    DEBUGMSGTL(("deinit_usm_post_config", "initial user removed\n"));
5056
0
    return SNMPERR_SUCCESS;
5057
0
}                               /* end deinit_usm_post_config() */
5058
5059
void
5060
init_usm(void)
5061
0
{
5062
0
    struct snmp_secmod_def *def;
5063
0
    char *type;
5064
5065
0
    DEBUGMSGTL(("init_usm", "unit_usm: %" NETSNMP_PRIo "u %" NETSNMP_PRIo "u\n",
5066
0
                usmNoPrivProtocol[0], usmNoPrivProtocol[1]));
5067
5068
0
    sc_init();                  /* initalize scapi code */
5069
5070
    /*
5071
     * register ourselves as a security service
5072
     */
5073
0
    def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
5074
0
    if (def == NULL)
5075
0
        return;
5076
    /*
5077
     * XXX: def->init_sess_secmod move stuff from snmp_api.c
5078
     */
5079
0
    def->encode_reverse = usm_secmod_rgenerate_out_msg;
5080
0
    def->encode_forward = usm_secmod_generate_out_msg;
5081
0
    def->decode = usm_secmod_process_in_msg;
5082
0
    def->pdu_clone = usm_clone;
5083
0
    def->pdu_free_state_ref = usm_free_usmStateReference;
5084
0
    def->session_setup = usm_session_init;
5085
0
    def->handle_report = usm_handle_report;
5086
0
    def->probe_engineid = usm_discover_engineid;
5087
0
    def->post_probe_engineid = usm_create_user_from_session_hook;
5088
0
    if (register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def) != SNMPERR_SUCCESS) {
5089
0
        SNMP_FREE(def);
5090
0
        snmp_log(LOG_ERR, "could not register usm sec mod\n");
5091
0
        return;
5092
0
    }
5093
5094
0
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
5095
0
                           SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
5096
0
                           init_usm_post_config, NULL);
5097
5098
0
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
5099
0
                           SNMP_CALLBACK_SHUTDOWN,
5100
0
                           deinit_usm_post_config, NULL);
5101
5102
0
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
5103
0
                           SNMP_CALLBACK_SHUTDOWN,
5104
0
                           free_engineID, NULL);
5105
5106
0
    register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
5107
0
                            NULL, "MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224");
5108
0
    register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
5109
0
                            NULL,
5110
0
                            "DES"
5111
0
#ifdef HAVE_AES
5112
0
                            "|AES|AES-128"
5113
0
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
5114
0
                            "|AES-192|AES-256"
5115
0
#endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */
5116
#else
5117
                            " (AES support not available)"
5118
#endif
5119
0
                           );
5120
5121
    /*
5122
     * Free stuff at shutdown time
5123
     */
5124
0
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
5125
0
                           SNMP_CALLBACK_SHUTDOWN,
5126
0
                           free_enginetime_on_shutdown, NULL);
5127
5128
5129
0
    type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE);
5130
5131
0
    register_config_handler(type, "userSetAuthPass", usm_set_password,
5132
0
                            NULL, NULL);
5133
0
    register_config_handler(type, "userSetPrivPass", usm_set_password,
5134
0
                            NULL, NULL);
5135
0
    register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
5136
0
                            NULL);
5137
0
    register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
5138
0
                            NULL);
5139
0
    register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
5140
0
                            NULL, NULL);
5141
0
    register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
5142
0
                            NULL, NULL);
5143
0
}
5144
5145
void
5146
shutdown_usm(void)
5147
0
{
5148
0
    free_etimelist();
5149
0
    clear_user_list();
5150
0
}