Coverage Report

Created: 2024-09-11 06:05

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