OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [snmp/] [lib/] [v2_0/] [src/] [snmpusm.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ./lib/current/src/snmpusm.c
4
//
5
//
6
//==========================================================================
7
//####ECOSGPLCOPYRIGHTBEGIN####
8
// -------------------------------------------
9
// This file is part of eCos, the Embedded Configurable Operating System.
10
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11
//
12
// eCos is free software; you can redistribute it and/or modify it under
13
// the terms of the GNU General Public License as published by the Free
14
// Software Foundation; either version 2 or (at your option) any later version.
15
//
16
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19
// for more details.
20
//
21
// You should have received a copy of the GNU General Public License along
22
// with eCos; if not, write to the Free Software Foundation, Inc.,
23
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24
//
25
// As a special exception, if other files instantiate templates or use macros
26
// or inline functions from this file, or you compile this file and link it
27
// with other works to produce a work based on this file, this file does not
28
// by itself cause the resulting work to be covered by the GNU General Public
29
// License. However the source code for this file must still be made available
30
// in accordance with section (3) of the GNU General Public License.
31
//
32
// This exception does not invalidate any other reasons why a work based on
33
// this file might be covered by the GNU General Public License.
34
//
35
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36
// at http://sources.redhat.com/ecos/ecos-license/
37
// -------------------------------------------
38
//####ECOSGPLCOPYRIGHTEND####
39
//####UCDSNMPCOPYRIGHTBEGIN####
40
//
41
// -------------------------------------------
42
//
43
// Portions of this software may have been derived from the UCD-SNMP
44
// project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45
// California at Davis, which was originally based on the Carnegie Mellon
46
// University SNMP implementation.  Portions of this software are therefore
47
// covered by the appropriate copyright disclaimers included herein.
48
//
49
// The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50
// -------------------------------------------
51
//
52
//####UCDSNMPCOPYRIGHTEND####
53
//==========================================================================
54
//#####DESCRIPTIONBEGIN####
55
//
56
// Author(s):    hmt
57
// Contributors: hmt
58
// Date:         2000-05-30
59
// Purpose:      Port of UCD-SNMP distribution to eCos.
60
// Description:  
61
//              
62
//
63
//####DESCRIPTIONEND####
64
//
65
//==========================================================================
66
/********************************************************************
67
       Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
 
69
                          Derivative Work -
70
Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
 
72
                         All Rights Reserved
73
 
74
Permission to use, copy, modify and distribute this software and its
75
documentation for any purpose and without fee is hereby granted,
76
provided that the above copyright notice appears in all copies and
77
that both that copyright notice and this permission notice appear in
78
supporting documentation, and that the name of CMU and The Regents of
79
the University of California not be used in advertising or publicity
80
pertaining to distribution of the software without specific written
81
permission.
82
 
83
CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84
WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85
WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86
THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88
FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91
*********************************************************************/
92
/*
93
 * snmpusm.c
94
 *
95
 * Routines to manipulate a information about a "user" as
96
 * defined by the SNMP-USER-BASED-SM-MIB MIB.
97
 *
98
 * All functions usm_set_usmStateReference_*() return 0 on success, -1
99
 * otherwise.
100
 *
101
 * !! Tab stops set to 4 in some parts of this file. !!
102
 *    (Designated on a per function.)
103
 */
104
 
105
#include <config.h>
106
 
107
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
108
#include <sys/types.h>
109
#if HAVE_WINSOCK_H
110
#include <winsock.h>
111
#endif
112
#include <stdio.h>
113
#ifdef HAVE_STDLIB_H
114
#include <stdlib.h>
115
#endif
116
#if TIME_WITH_SYS_TIME
117
# ifdef WIN32
118
#  include <sys/timeb.h>
119
# else
120
#  include <sys/time.h>
121
# endif
122
# include <time.h>
123
#else
124
# if HAVE_SYS_TIME_H
125
#  include <sys/time.h>
126
# else
127
#  include <time.h>
128
# endif
129
#endif
130
#if HAVE_STRING_H
131
#include <string.h>
132
#else
133
#include <strings.h>
134
#endif
135
#ifdef HAVE_NETINET_IN_H
136
#include <netinet/in.h>
137
#endif
138
 
139
#if HAVE_DMALLOC_H
140
#include <dmalloc.h>
141
#endif
142
 
143
#include "asn1.h"
144
#include "snmp_api.h"
145
#include "snmp_debug.h"
146
#include "callback.h"
147
#include "tools.h"
148
#include "keytools.h"
149
#include "snmp.h"
150
#include "read_config.h"
151
#include "snmpv3.h"
152
#include "snmp-tc.h"
153
#include "lcd_time.h"
154
#include "scapi.h"
155
#include "callback.h"
156
#include "default_store.h"
157
#include "snmpusm.h"
158
 
159
#include "transform_oids.h"
160
 
161
static u_int    dummy_etime, dummy_eboot;       /* For ISENGINEKNOWN(). */
162
 
163
/*
164
 * Globals.
165
 */
166
static u_int salt_integer;
167
        /* 1/2 of seed for the salt.   Cf. RFC2274, Sect 8.1.1.1.
168
         */
169
 
170
int reportErrorOnUnknownID = 0;
171
        /* Should be determined based on msg type.
172
         */
173
 
174
static struct usmUser *initialUser = NULL;
175
static struct usmUser *noNameUser = NULL;
176
 
177
/*
178
 * Prototypes
179
 */
180
int
181
usm_check_secLevel_vs_protocols(int level,
182
                                oid *authProtocol, u_int authProtocolLen,
183
                                oid *privProtocol, u_int privProtocolLen);
184
 
185
/*
186
 * Set a given field of the secStateRef.
187
 *
188
 * Allocate <len> bytes for type <type> pointed to by ref-><field>.
189
 * Then copy in <item> and record its length in ref-><field_len>.
190
 *
191
 * Return 0 on success, -1 otherwise.
192
 */
193
#define MAKE_ENTRY( type, item, len, field, field_len )                 \
194
{                                                                       \
195
        if (ref == NULL)                                                \
196
                return -1;                                              \
197
        if (ref->field != NULL) {                                       \
198
                SNMP_ZERO(ref->field, ref->field_len);                  \
199
                SNMP_FREE(ref->field);                                  \
200
        }                                                               \
201
        ref->field_len = 0;                                              \
202
        if (len == 0 || item == NULL) {                                  \
203
                return 0;                                                \
204
        }                                                               \
205
        if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
206
        {                                                               \
207
                return -1;                                              \
208
        }                                                               \
209
                                                                        \
210
        memcpy (ref->field, item, len * sizeof(type));                  \
211
        ref->field_len = len;                                           \
212
                                                                        \
213
        return 0;                                                        \
214
}
215
 
216
 
217
void
218
usm_set_reportErrorOnUnknownID (int value)
219
{
220
        reportErrorOnUnknownID = value;
221
}
222
 
223
 
224
struct usmStateReference *
225
usm_malloc_usmStateReference(void)
226
{
227
        struct usmStateReference *retval = (struct usmStateReference *)
228
                calloc(1,sizeof(struct usmStateReference));
229
 
230
        return retval;
231
}  /* end usm_malloc_usmStateReference() */
232
 
233
 
234
void
235
usm_free_usmStateReference (void *old)
236
{
237
        struct usmStateReference *old_ref = (struct usmStateReference *)old;
238
 
239
    if (old_ref) {
240
 
241
        SNMP_FREE(old_ref->usr_name);
242
        SNMP_FREE(old_ref->usr_engine_id);
243
        SNMP_FREE(old_ref->usr_auth_protocol);
244
        SNMP_FREE(old_ref->usr_priv_protocol);
245
 
246
        if (old_ref->usr_auth_key) {
247
                SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
248
                SNMP_FREE(old_ref->usr_auth_key);
249
        }
250
        if (old_ref->usr_priv_key) {
251
                SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
252
                SNMP_FREE(old_ref->usr_priv_key);
253
        }
254
 
255
        SNMP_ZERO(old_ref, sizeof(*old_ref));
256
        SNMP_FREE(old_ref);
257
 
258
   }
259
 
260
}  /* end usm_free_usmStateReference() */
261
 
262
 
263
 
264
int
265
usm_set_usmStateReference_name (
266
        struct usmStateReference *ref,
267
        char *name,
268
        size_t name_len)
269
{
270
        MAKE_ENTRY (char,name,name_len,usr_name,usr_name_length);
271
}
272
 
273
int
274
usm_set_usmStateReference_engine_id (
275
        struct usmStateReference *ref,
276
        u_char *engine_id,
277
        size_t engine_id_len)
278
{
279
        MAKE_ENTRY (u_char,engine_id,engine_id_len,
280
                usr_engine_id,usr_engine_id_length);
281
}
282
 
283
int
284
usm_set_usmStateReference_auth_protocol (
285
        struct usmStateReference *ref,
286
        oid *auth_protocol,
287
        size_t auth_protocol_len)
288
{
289
        MAKE_ENTRY (oid ,auth_protocol,auth_protocol_len,
290
                usr_auth_protocol,usr_auth_protocol_length);
291
}
292
 
293
int
294
usm_set_usmStateReference_auth_key (
295
        struct usmStateReference *ref,
296
        u_char *auth_key,
297
        size_t auth_key_len)
298
{
299
        MAKE_ENTRY (u_char,auth_key,auth_key_len,
300
                usr_auth_key,usr_auth_key_length);
301
}
302
 
303
int
304
usm_set_usmStateReference_priv_protocol (
305
        struct usmStateReference *ref,
306
        oid *priv_protocol,
307
        size_t priv_protocol_len)
308
{
309
        MAKE_ENTRY (oid,priv_protocol,priv_protocol_len,
310
                usr_priv_protocol,usr_priv_protocol_length);
311
}
312
 
313
int
314
usm_set_usmStateReference_priv_key (
315
        struct usmStateReference *ref,
316
        u_char *priv_key,
317
        size_t priv_key_len)
318
{
319
        MAKE_ENTRY (u_char,priv_key,priv_key_len,
320
                usr_priv_key,usr_priv_key_length);
321
}
322
 
323
int
324
usm_set_usmStateReference_sec_level (
325
        struct usmStateReference *ref,
326
        int sec_level)
327
{
328
        if (ref == NULL) return -1;
329
        ref->usr_sec_level = sec_level;
330
        return 0;
331
}
332
 
333
 
334
 
335
#ifdef SNMP_TESTING_CODE
336
/*******************************************************************-o-******
337
 * emergency_print
338
 *
339
 * Parameters:
340
 *      *field
341
 *       length
342
 *
343
 *      This is a print routine that is solely included so that it can be
344
 *      used in gdb.  Don't use it as a function, it will be pulled before
345
 *      a real release of the code.
346
 *
347
 *      tab stop 4
348
 *
349
 *      XXX fflush() only works on FreeBSD; core dumps on Sun OS's
350
 */
351
void
352
emergency_print (u_char *field, u_int length)
353
{
354
        int iindex;
355
        int start=0;
356
        int stop=25;
357
 
358
        while (start < stop)
359
        {
360
                for (iindex = start; iindex < stop; iindex++)
361
                        printf ("%02X ", field[iindex]);
362
 
363
                printf ("\n");
364
                start = stop;
365
                stop = stop+25<length?stop+25:length;
366
        }
367
        fflush (0);
368
 
369
}  /* end emergency_print() */
370
#endif /* SNMP_TESTING_CODE */
371
 
372
 
373
/*******************************************************************-o-******
374
 * asn_predict_int_length
375
 *
376
 * Parameters:
377
 *      type    (UNUSED)
378
 *      number
379
 *      len
380
 *
381
 * Returns:
382
 *      Number of bytes necessary to store the ASN.1 encoded value of 'number'.
383
 *
384
 *
385
 *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
386
 *      use to encode a particular integer value.
387
 *
388
 *      Returns the length of the integer -- NOT THE HEADER!
389
 *
390
 *      Do this the same way as asn_build_int()...
391
 */
392
int
393
asn_predict_int_length (int type, long number, size_t len)
394
{
395
        register u_long mask;
396
 
397
 
398
        if (len != sizeof (long)) return -1;
399
 
400
        mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
401
        /* mask is 0xFF800000 on a big-endian machine */
402
 
403
        while((((number & mask) == 0) || ((number & mask) == mask)) && len > 1)
404
        {
405
                len--;
406
                number <<= 8;
407
        }
408
 
409
        return len;
410
 
411
}  /* end asn_predict_length() */
412
 
413
 
414
 
415
 
416
/*******************************************************************-o-******
417
 * asn_predict_length
418
 *
419
 * Parameters:
420
 *       type
421
 *      *ptr
422
 *       u_char_len
423
 *
424
 * Returns:
425
 *      Length in bytes:        1 + <n> + <u_char_len>, where
426
 *
427
 *              1               For the ASN.1 type.
428
 *              <n>             # of bytes to store length of data.
429
 *              <u_char_len>    Length of data associated with ASN.1 type.
430
 *
431
 *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
432
 *      use to encode a particular integer value.  This is as broken as the
433
 *      currently used encoder.
434
 *
435
 * XXX  How is <n> chosen, exactly??
436
 */
437
int
438
asn_predict_length (int type, u_char *ptr, size_t u_char_len)
439
{
440
 
441
        if (type & ASN_SEQUENCE) return 1+3+u_char_len;
442
 
443
        if (type &  ASN_INTEGER)
444
        {
445
                u_long value;
446
                memcpy (&value, ptr, u_char_len);
447
                u_char_len = asn_predict_int_length (type, value, u_char_len);
448
        }
449
 
450
        if (u_char_len < 0x80)
451
                return 1+1+u_char_len;
452
        else if (u_char_len < 0xFF)
453
                return 1+2+u_char_len;
454
        else
455
                return 1+3+u_char_len;
456
 
457
}  /* end asn_predict_length() */
458
 
459
 
460
 
461
 
462
/*******************************************************************-o-******
463
 * usm_calc_offsets
464
 *
465
 * Parameters:
466
 *      (See list below...)
467
 *
468
 * Returns:
469
 *      0        On success,
470
 *      -1      Otherwise.
471
 *
472
 *
473
 *      This routine calculates the offsets into an outgoing message buffer
474
 *      for the necessary values.  The outgoing buffer will generically
475
 *      look like this:
476
 *
477
 *      SNMPv3 Message
478
 *      SEQ len[11]
479
 *              INT len version
480
 *      Header
481
 *              SEQ len
482
 *                      INT len MsgID
483
 *                      INT len msgMaxSize
484
 *                      OST len msgFlags (OST = OCTET STRING)
485
 *                      INT len msgSecurityModel
486
 *      MsgSecurityParameters
487
 *              [1] OST len[2]
488
 *                      SEQ len[3]
489
 *                              OST len msgAuthoritativeEngineID
490
 *                              INT len msgAuthoritativeEngineBoots
491
 *                              INT len msgAuthoritativeEngineTime
492
 *                              OST len msgUserName
493
 *                              OST len[4] [5] msgAuthenticationParameters
494
 *                              OST len[6] [7] msgPrivacyParameters
495
 *      MsgData
496
 *              [8] OST len[9] [10] encryptedPDU
497
 *              or
498
 *              [8,10] SEQUENCE len[9] scopedPDU
499
 *      [12]
500
 *
501
 *      The bracketed points will be needed to be identified ([x] is an index
502
 *      value, len[x] means a length value).  Here is a semantic guide to them:
503
 *
504
 *      [1] = globalDataLen (input)
505
 *      [2] = otstlen
506
 *      [3] = seq_len
507
 *      [4] = msgAuthParmLen (may be 0 or 12)
508
 *      [5] = authParamsOffset
509
 *      [6] = msgPrivParmLen (may be 0 or 8)
510
 *      [7] = privParamsOffset
511
 *      [8] = globalDataLen + msgSecParmLen
512
 *      [9] = datalen
513
 *      [10] = dataOffset
514
 *      [11] = theTotalLength - the length of the header itself
515
 *      [12] = theTotalLength
516
 */
517
int
518
usm_calc_offsets (
519
        size_t  globalDataLen,  /* SNMPv3Message + HeaderData */
520
        int     secLevel,
521
        size_t  secEngineIDLen,
522
        size_t  secNameLen,
523
        size_t  scopedPduLen,   /* An BER encoded sequence. */
524
        u_long  engineboots,    /* XXX (asn1.c works in long, not int.) */
525
        long    engine_time,    /* XXX (asn1.c works in long, not int.) */
526
 
527
        size_t *theTotalLength,  /* globalDataLen + msgSecurityP. + msgData */
528
        size_t *authParamsOffset,/* Distance to auth bytes.                 */
529
        size_t *privParamsOffset,/* Distance to priv bytes.                 */
530
        size_t *dataOffset,      /* Distance to scopedPdu SEQ  -or-  the
531
                                  *   crypted (data) portion of msgData.    */
532
 
533
        size_t *datalen,        /* Size of msgData OCTET STRING encoding.  */
534
        size_t *msgAuthParmLen, /* Size of msgAuthenticationParameters.    */
535
        size_t *msgPrivParmLen, /* Size of msgPrivacyParameters.           */
536
        size_t *otstlen,        /* Size of msgSecurityP. O.S. encoding.    */
537
        size_t *seq_len,        /* Size of msgSecurityP. SEQ data.         */
538
        size_t *msgSecParmLen)  /* Size of msgSecurityP. SEQ.              */
539
{
540
        int     engIDlen,       /* Sizes of OCTET STRING and SEQ encodings */
541
                engBtlen,       /*   for fields within                     */
542
                engTmlen,       /*   msgSecurityParameters portion of      */
543
                namelen,        /*   SNMPv3Message.                        */
544
                authlen,
545
                privlen;
546
 
547
        /*
548
         * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
549
         * If doing encryption,     msgPrivParmLen = 8  else msgPrivParmLen = 0.
550
         */
551
        *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
552
                || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?12:0;
553
 
554
        *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?8:0;
555
 
556
 
557
        /*
558
         * Calculate lengths.
559
         */
560
        if ( (engIDlen = asn_predict_length(ASN_OCTET_STR,
561
                                0, secEngineIDLen)) == -1 )
562
        {
563
                return -1;
564
        }
565
 
566
        if ( (engBtlen = asn_predict_length (ASN_INTEGER,
567
                                (u_char*)&engineboots,sizeof(long))) == -1 )
568
        {
569
                return -1;
570
        }
571
 
572
        if ( (engTmlen = asn_predict_length (ASN_INTEGER,
573
                                (u_char*)&engine_time,sizeof(long))) == -1 )
574
        {
575
                return -1;
576
        }
577
 
578
        if ( (namelen = asn_predict_length (ASN_OCTET_STR,0,secNameLen))==-1 )
579
        {
580
                return -1;
581
        }
582
 
583
        if ( (authlen = asn_predict_length (ASN_OCTET_STR,
584
                                0,*msgAuthParmLen)) == -1 )
585
        {
586
                return -1;
587
        }
588
 
589
        if ( (privlen = asn_predict_length (ASN_OCTET_STR,
590
                                0,*msgPrivParmLen)) == -1 )
591
        {
592
                return -1;
593
        }
594
 
595
        *seq_len = engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
596
 
597
        if ( (*otstlen = asn_predict_length (ASN_SEQUENCE,
598
                                0, *seq_len)) == -1 )
599
        {
600
                return -1;
601
        }
602
 
603
        if ( (*msgSecParmLen = asn_predict_length (ASN_OCTET_STR,
604
                                0,*otstlen)) == -1 )
605
        {
606
                return -1;
607
        }
608
 
609
        *authParamsOffset =     globalDataLen +
610
                + (*msgSecParmLen - *seq_len)
611
                + engIDlen + engBtlen + engTmlen + namelen
612
                + (authlen - *msgAuthParmLen);
613
 
614
        *privParamsOffset =     *authParamsOffset + *msgAuthParmLen
615
                + (privlen - *msgPrivParmLen);
616
 
617
 
618
        /*
619
         * Compute the size of the plaintext.  Round up to account for cipher
620
         * block size, if necessary.
621
         *
622
         * XXX  This is hardwired for 1DES... If scopedPduLen is already
623
         *      a multiple of 8, then *add* 8 more; otherwise, round up
624
         *      to the next multiple of 8.
625
         *
626
         * FIX  Calculation of encrypted portion of msgData and consequent
627
         *      setting and sanity checking of theTotalLength, et al. should
628
         *      occur *after* encryption has taken place.
629
         */
630
        if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
631
        {
632
                scopedPduLen = ( scopedPduLen % 8 )
633
                                        ? ROUNDUP8(scopedPduLen)
634
                                        : scopedPduLen + 8;
635
 
636
                if ((*datalen =
637
                        asn_predict_length (ASN_OCTET_STR,0,scopedPduLen))==-1)
638
                {
639
                        return -1;
640
                }
641
        }
642
        else
643
        {
644
                *datalen = scopedPduLen;
645
        }
646
 
647
        *dataOffset     = globalDataLen + *msgSecParmLen +
648
                                                (*datalen - scopedPduLen);
649
        *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
650
 
651
        return 0;
652
 
653
}  /* end usm_calc_offsets() */
654
 
655
 
656
 
657
 
658
 
659
/*******************************************************************-o-******
660
 * usm_set_salt
661
 *
662
 * Parameters:
663
 *      *iv               (O)   Buffer to contain IV.
664
 *      *iv_length        (O)   Length of iv.
665
 *      *priv_salt        (I)   Salt portion of private key.
666
 *       priv_salt_length (I)   Length of priv_salt.
667
 *      *msgSalt          (I/O) Pointer salt portion of outgoing msg buffer.
668
 *
669
 * Returns:
670
 *      0        On success,
671
 *      -1      Otherwise.
672
 *
673
 *      Determine the initialization vector for the DES-CBC encryption.
674
 *      (Cf. RFC 2274, 8.1.1.1.)
675
 *
676
 *      iv is defined as the concatenation of engineBoots and the
677
 *              salt integer.
678
 *      The salt integer is incremented.
679
 *      The resulting salt is copied into the msgSalt buffer.
680
 *      The result of the concatenation is then XORed with the salt
681
 *              portion of the private key (last 8 bytes).
682
 *      The IV result is returned individually for further use.
683
 */
684
int
685
usm_set_salt (  u_char          *iv,
686
                size_t          *iv_length,
687
                u_char          *priv_salt,
688
                size_t           priv_salt_length,
689
                u_char          *msgSalt)
690
{
691
        size_t propersize_salt     = BYTESIZE(USM_MAX_SALT_LENGTH);
692
        int net_boots;
693
        int net_salt_int;
694
                /* net_* should be encoded in network byte order.  XXX  Why?
695
                 */
696
        int iindex;
697
 
698
 
699
        /*
700
         * Sanity check.
701
         */
702
        if ( !iv || !iv_length || !priv_salt || !msgSalt
703
                || (*iv_length != propersize_salt)
704
                || (priv_salt_length < propersize_salt) )
705
        {
706
                return -1;
707
        }
708
 
709
 
710
        net_boots       = htonl(snmpv3_local_snmpEngineBoots());
711
        net_salt_int    = htonl(salt_integer);
712
 
713
        salt_integer += 1;
714
 
715
        memcpy(iv,                      &net_boots,     propersize_salt/2);
716
        memcpy(iv+(propersize_salt/2), &net_salt_int,   propersize_salt/2);
717
 
718
        memcpy(msgSalt, iv, propersize_salt);
719
 
720
 
721
        /*
722
         * Turn the salt into an IV: XOR <boots, salt_int> with salt
723
         * portion of priv_key.
724
         */
725
        for (iindex = 0; iindex < (int)propersize_salt; iindex++)
726
                iv[iindex] ^= priv_salt[iindex];
727
 
728
 
729
        return 0;
730
 
731
}  /* end usm_set_salt() */
732
 
733
 
734
 
735
 
736
/*******************************************************************-o-******
737
 * usm_generate_out_msg
738
 *
739
 * Parameters:
740
 *      (See list below...)
741
 *
742
 * Returns:
743
 *      SNMPERR_SUCCESS                 On success.
744
 *      SNMPERR_USM_AUTHENTICATIONFAILURE
745
 *      SNMPERR_USM_ENCRYPTIONERROR
746
 *      SNMPERR_USM_GENERICERROR
747
 *      SNMPERR_USM_UNKNOWNSECURITYNAME
748
 *      SNMPERR_USM_GENERICERROR
749
 *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
750
 *
751
 *
752
 * Generates an outgoing message.
753
 *
754
 * XXX  Beware of misnomers!
755
 */
756
int
757
usm_generate_out_msg (
758
     int      msgProcModel,     /* (UNUSED) */
759
 
760
     u_char  *globalData,       /* IN */
761
                /* Pointer to msg header data will point to the beginning
762
                 * of the entire packet buffer to be transmitted on wire,
763
                 * memory will be contiguous with secParams, typically
764
                 * this pointer will be passed back as beginning of
765
                 * wholeMsg below.  asn seq. length is updated w/ new length.
766
                 *
767
                 * While this points to a buffer that should be big enough
768
                 * for the whole message, only the first two parts
769
                 * of the message are completed, namely SNMPv3Message and
770
                 * HeaderData.  globalDataLen (next parameter) represents
771
                 * the length of these two completed parts.
772
                 */
773
 
774
     size_t   globalDataLen,    /* IN - Length of msg header data.      */
775
     int      maxMsgSize,       /* (UNUSED) */
776
     int      secModel,         /* (UNUSED) */
777
     u_char  *secEngineID,      /* IN - Pointer snmpEngineID.           */
778
     size_t   secEngineIDLen,   /* IN - SnmpEngineID length.            */
779
     char    *secName,          /* IN - Pointer to securityName.        */
780
     size_t   secNameLen,       /* IN - SecurityName length.            */
781
     int      secLevel,         /* IN - AuthNoPriv, authPriv etc.       */
782
 
783
     u_char  *scopedPdu,        /* IN */
784
                /* Pointer to scopedPdu will be encrypted by USM if needed
785
                 * and written to packet buffer immediately following
786
                 * securityParameters, entire msg will be authenticated by
787
                 * USM if needed.
788
                 */
789
 
790
     size_t   scopedPduLen,     /* IN - scopedPdu length. */
791
 
792
     void    *secStateRef,      /* IN */
793
                /* secStateRef, pointer to cached info provided only for
794
                 * Response, otherwise NULL.
795
                 */
796
 
797
     u_char  *secParams,        /* OUT */
798
                /* BER encoded securityParameters pointer to offset within
799
                 * packet buffer where secParams should be written, the
800
                 * entire BER encoded OCTET STRING (including header) is
801
                 * written here by USM secParams = globalData +
802
                 * globalDataLen.
803
                 */
804
 
805
     size_t  *secParamsLen,     /* IN/OUT - Len available, len returned. */
806
 
807
     u_char **wholeMsg,         /* OUT */
808
                /* Complete authenticated/encrypted message - typically
809
                 * the pointer to start of packet buffer provided in
810
                 * globalData is returned here, could also be a separate
811
                 * buffer.
812
                 */
813
 
814
     size_t *wholeMsgLen)          /* IN/OUT - Len available, len returned. */
815
{
816
        size_t otstlen;
817
        size_t seq_len;
818
        size_t msgAuthParmLen;
819
        size_t msgPrivParmLen;
820
        size_t msgSecParmLen;
821
        size_t authParamsOffset;
822
        size_t privParamsOffset;
823
        size_t datalen;
824
        size_t dataOffset;
825
        size_t theTotalLength;
826
 
827
        u_char         *ptr;
828
        size_t          ptr_len;
829
        size_t          remaining;
830
        size_t          offSet;
831
        u_int           boots_uint;
832
        u_int           time_uint;
833
        long            boots_long;
834
        long            time_long;
835
 
836
        /*
837
                Indirection because secStateRef values override parameters.
838
 
839
                None of these are to be free'd - they are either pointing to
840
                what's in the secStateRef or to something either in the
841
                actual prarmeter list or the user list.
842
        */
843
 
844
        char   *theName                 = NULL;
845
        u_int   theNameLength           = 0;
846
        u_char *theEngineID             = NULL;
847
        u_int   theEngineIDLength       = 0;
848
        u_char *theAuthKey              = NULL;
849
        u_int   theAuthKeyLength        = 0;
850
        oid    *theAuthProtocol         = NULL;
851
        u_int   theAuthProtocolLength   = 0;
852
        u_char *thePrivKey              = NULL;
853
        u_int   thePrivKeyLength        = 0;
854
        oid    *thePrivProtocol         = NULL;
855
        u_int   thePrivProtocolLength   = 0;
856
        int     theSecLevel             = 0;     /* No defined const for bad
857
                                                 * value (other then err).
858
                                                 */
859
 
860
 
861
        DEBUGMSGTL(("usm","USM processing has begun.\n"));
862
 
863
        if (secStateRef != NULL)
864
        {
865
                /* To hush the compiler for now.  XXX */
866
                struct usmStateReference *ref
867
                                = (struct usmStateReference *)secStateRef;
868
 
869
                theName                 = ref->usr_name;
870
                theNameLength           = ref->usr_name_length;
871
                theEngineID             = ref->usr_engine_id;
872
                theEngineIDLength       = ref->usr_engine_id_length;
873
 
874
                if (!theEngineIDLength) {
875
                  theEngineID           = secEngineID;
876
                  theEngineIDLength     = secEngineIDLen;
877
                }
878
 
879
                theAuthProtocol         = ref->usr_auth_protocol;
880
                theAuthProtocolLength   = ref->usr_auth_protocol_length;
881
                theAuthKey              = ref->usr_auth_key;
882
                theAuthKeyLength        = ref->usr_auth_key_length;
883
                thePrivProtocol         = ref->usr_priv_protocol;
884
                thePrivProtocolLength   = ref->usr_priv_protocol_length;
885
                thePrivKey              = ref->usr_priv_key;
886
                thePrivKeyLength        = ref->usr_priv_key_length;
887
                theSecLevel             = ref->usr_sec_level;
888
        }
889
 
890
        /*
891
         * Identify the user record.
892
         */
893
        else
894
        {
895
                struct usmUser *user;
896
 
897
                /* we do allow an unknown user name for
898
                   unauthenticated requests. */
899
                if ( (user =
900
                        usm_get_user(secEngineID, secEngineIDLen, secName))
901
                                == NULL &&
902
                                        secLevel != SNMP_SEC_LEVEL_NOAUTH)
903
                {
904
                        DEBUGMSGTL(("usm","Unknown User\n"));
905
                        usm_free_usmStateReference (secStateRef);
906
                        return SNMPERR_USM_UNKNOWNSECURITYNAME;
907
                }
908
 
909
                theName                 = secName;
910
                theNameLength           = secNameLen;
911
                theEngineID             = secEngineID;
912
                theSecLevel             = secLevel;
913
                theEngineIDLength       = secEngineIDLen;
914
                if (user) {
915
                  theAuthProtocol       = user->authProtocol;
916
                  theAuthProtocolLength = user->authProtocolLen;
917
                  theAuthKey            = user->authKey;
918
                  theAuthKeyLength      = user->authKeyLen;
919
                  thePrivProtocol       = user->privProtocol;
920
                  thePrivProtocolLength = user->privProtocolLen;
921
                  thePrivKey            = user->privKey;
922
                  thePrivKeyLength      = user->privKeyLen;
923
                } else {
924
                  /* unknown users can not do authentication (obviously) */
925
                  theAuthProtocol       = usmNoAuthProtocol;
926
                  theAuthProtocolLength = sizeof(usmNoAuthProtocol)/sizeof(oid);
927
                  theAuthKey            = NULL;
928
                  theAuthKeyLength      = 0;
929
                  thePrivProtocol       = usmNoPrivProtocol;
930
                  thePrivProtocolLength = sizeof(usmNoPrivProtocol)/sizeof(oid);
931
                  thePrivKey            = NULL;
932
                  thePrivKeyLength      = 0;
933
                }
934
        }  /* endif -- secStateRef==NULL */
935
 
936
 
937
        /*
938
                From here to the end of the function, avoid reference to
939
                secName, secEngineID, secLevel, and associated lengths.
940
        */
941
 
942
 
943
        /*
944
         * Check to see if the user can use the requested sec services.
945
         */
946
        if (usm_check_secLevel_vs_protocols(
947
                theSecLevel,
948
                theAuthProtocol, theAuthProtocolLength,
949
                theAuthProtocol, theAuthProtocolLength) == 1)
950
        {
951
                DEBUGMSGTL(("usm","Unsupported Security Level\n"));
952
                usm_free_usmStateReference (secStateRef);
953
                return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
954
        }
955
 
956
 
957
        /*
958
         * Retrieve the engine information.
959
         *
960
         * XXX  No error is declared in the EoP when sending messages to
961
         *      unknown engines, processing continues w/ boots/time == (0,0).
962
         */
963
        if (get_enginetime (theEngineID, theEngineIDLength,
964
                            &boots_uint, &time_uint, FALSE) == -1)
965
        {
966
                DEBUGMSGTL(("usm","%s\n", "Failed to find engine data."));
967
        }
968
 
969
        boots_long = boots_uint;
970
        time_long  = time_uint;
971
 
972
 
973
        /*
974
         * Set up the Offsets.
975
         */
976
        if (usm_calc_offsets (globalDataLen, theSecLevel, theEngineIDLength,
977
                theNameLength, scopedPduLen, boots_long, time_long,
978
                &theTotalLength, &authParamsOffset,
979
                &privParamsOffset, &dataOffset, &datalen,
980
                &msgAuthParmLen, &msgPrivParmLen,
981
                &otstlen, &seq_len, &msgSecParmLen) == -1)
982
        {
983
                DEBUGMSGTL(("usm","Failed calculating offsets.\n"));
984
                usm_free_usmStateReference (secStateRef);
985
                return SNMPERR_USM_GENERICERROR;
986
        }
987
 
988
        /*
989
                So, we have the offsets for the three parts that need to be
990
                determined, and an overall length.  Now we need to make
991
                sure all of this would fit in the outgoing buffer, and
992
                whether or not we need to make a new buffer, etc.
993
        */
994
 
995
 
996
        /*
997
         * Set wholeMsg as a pointer to globalData.  Sanity check for
998
         * the proper size.
999
         *
1000
         * Mark workspace in the message with bytes of all 1's to make it
1001
         * easier to find mistakes in raw message dumps.
1002
         */
1003
        ptr = *wholeMsg = globalData;
1004
        if (theTotalLength > *wholeMsgLen)
1005
        {
1006
                DEBUGMSGTL(("usm","Message won't fit in buffer.\n"));
1007
                usm_free_usmStateReference (secStateRef);
1008
                return SNMPERR_USM_GENERICERROR;
1009
        }
1010
 
1011
        ptr_len = *wholeMsgLen = theTotalLength;
1012
 
1013
#ifdef SNMP_TESTING_CODE
1014
        memset (&ptr[globalDataLen], 0xFF, theTotalLength-globalDataLen);
1015
#endif /* SNMP_TESTING_CODE */
1016
 
1017
 
1018
        /*
1019
         * Do the encryption.
1020
         */
1021
        if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1022
        {
1023
                size_t  encrypted_length = theTotalLength - dataOffset;
1024
                size_t  salt_length      = BYTESIZE(USM_MAX_SALT_LENGTH);
1025
                u_char  salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1026
 
1027
                /* XXX  Hardwired to seek into a 1DES private key!
1028
                 */
1029
                if ( usm_set_salt(      salt,           &salt_length,
1030
                                        thePrivKey+8,   thePrivKeyLength-8,
1031
                                        &ptr[privParamsOffset])
1032
                                                == -1 )
1033
                {
1034
                        DEBUGMSGTL(("usm","Can't set DES-CBC salt.\n"));
1035
                        usm_free_usmStateReference (secStateRef);
1036
                        return SNMPERR_USM_GENERICERROR;
1037
                }
1038
 
1039
                if ( sc_encrypt(
1040
                         thePrivProtocol,        thePrivProtocolLength,
1041
                         thePrivKey,             thePrivKeyLength,
1042
                         salt,                   salt_length,
1043
                         scopedPdu,              scopedPduLen,
1044
                        &ptr[dataOffset],       &encrypted_length)
1045
                                                        != SNMP_ERR_NOERROR )
1046
                {
1047
                        DEBUGMSGTL(("usm","DES-CBC error.\n"));
1048
                        usm_free_usmStateReference (secStateRef);
1049
                        return SNMPERR_USM_ENCRYPTIONERROR;
1050
                }
1051
 
1052
 
1053
#ifdef SNMP_TESTING_CODE
1054
                if ( debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1055
                        dump_chunk("usm/dump", "This data was encrypted:",
1056
                                        scopedPdu, scopedPduLen);
1057
                        dump_chunk("usm/dump", "salt + Encrypted form:",
1058
                                        salt, salt_length);
1059
                        dump_chunk("usm/dump", NULL,
1060
                                        &ptr[dataOffset], encrypted_length);
1061
                        dump_chunk("usm/dump", "*wholeMsg:",
1062
                                        *wholeMsg, theTotalLength);
1063
                }
1064
#endif
1065
 
1066
 
1067
                ptr     = *wholeMsg;
1068
                ptr_len = *wholeMsgLen = theTotalLength;
1069
 
1070
 
1071
                /*
1072
                 * XXX  Sanity check for salt length should be moved up
1073
                 *      under usm_calc_offsets() or tossed.
1074
                 */
1075
                if ( (encrypted_length != (theTotalLength - dataOffset))
1076
                                || (salt_length != msgPrivParmLen) )
1077
                {
1078
                        DEBUGMSGTL(("usm","DES-CBC length error.\n"));
1079
                        usm_free_usmStateReference (secStateRef);
1080
                        return SNMPERR_USM_ENCRYPTIONERROR;
1081
                }
1082
 
1083
                DEBUGMSGTL(("usm","Encryption successful.\n"));
1084
        }
1085
 
1086
        /*
1087
         * No encryption for you!
1088
         */
1089
        else
1090
        {
1091
                memcpy( &ptr[dataOffset], scopedPdu, scopedPduLen );
1092
        }
1093
 
1094
 
1095
 
1096
        /*
1097
         * Start filling in the other fields (in prep for authentication).
1098
         *
1099
         * offSet is an octet string header, which is different from all
1100
         * the other headers.
1101
         */
1102
        remaining = ptr_len - globalDataLen;
1103
 
1104
        offSet =  ptr_len - remaining;
1105
        asn_build_header (&ptr[offSet], &remaining,
1106
                (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR), otstlen);
1107
 
1108
        offSet = ptr_len - remaining;
1109
        asn_build_sequence (&ptr[offSet], &remaining,
1110
                (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
1111
 
1112
        offSet = ptr_len - remaining;
1113
        asn_build_string (&ptr[offSet], &remaining,
1114
                (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1115
                theEngineID, theEngineIDLength);
1116
 
1117
        offSet = ptr_len - remaining;
1118
        asn_build_int (&ptr[offSet], &remaining,
1119
                (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1120
                &boots_long, sizeof(long));
1121
 
1122
        offSet = ptr_len - remaining;
1123
        asn_build_int (&ptr[offSet], &remaining,
1124
                (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1125
                &time_long, sizeof(long));
1126
 
1127
        offSet = ptr_len - remaining;
1128
        asn_build_string (&ptr[offSet], &remaining,
1129
                (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1130
                (u_char *)theName, theNameLength);
1131
 
1132
 
1133
        /*
1134
                Note: if there is no authentication being done,
1135
                msgAuthParmLen is 0, and there is no effect (other than
1136
                inserting a zero-length header) of the following
1137
                statements.
1138
        */
1139
 
1140
        offSet = ptr_len - remaining;
1141
        asn_build_header(
1142
                        &ptr[offSet],
1143
                        &remaining,
1144
                        (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1145
                        msgAuthParmLen);
1146
 
1147
        if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1148
                || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1149
        {
1150
                offSet = ptr_len - remaining;
1151
                memset (&ptr[offSet],0,msgAuthParmLen);
1152
        }
1153
 
1154
        remaining -= msgAuthParmLen;
1155
 
1156
 
1157
        /*
1158
                Note: if there is no encryption being done, msgPrivParmLen
1159
                is 0, and there is no effect (other than inserting a
1160
                zero-length header) of the following statements.
1161
        */
1162
 
1163
        offSet = ptr_len - remaining;
1164
        asn_build_header(
1165
                &ptr[offSet],
1166
                &remaining,
1167
                (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1168
                msgPrivParmLen);
1169
 
1170
        remaining -= msgPrivParmLen;    /* Skipping the IV already there. */
1171
 
1172
 
1173
        /*
1174
         * For privacy, need to add the octet string header for it.
1175
         */
1176
        if (theSecLevel==SNMP_SEC_LEVEL_AUTHPRIV)
1177
        {
1178
                offSet = ptr_len - remaining;
1179
                asn_build_header(
1180
                        &ptr[offSet],
1181
                        &remaining,
1182
                        (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1183
                        theTotalLength - dataOffset );
1184
        }
1185
 
1186
 
1187
        /*
1188
         * Adjust overall length and store it as the first SEQ length
1189
         * of the SNMPv3Message.
1190
         *
1191
         * FIX  4 is a magic number!
1192
         */
1193
        remaining = theTotalLength;
1194
        asn_build_sequence (ptr, &remaining,
1195
                (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), theTotalLength-4);
1196
 
1197
 
1198
        /*
1199
         * Now, time to consider / do authentication.
1200
         */
1201
        if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1202
                || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1203
        {
1204
                size_t  temp_sig_len    = msgAuthParmLen;
1205
                u_char *temp_sig        = (u_char *) malloc (temp_sig_len);
1206
 
1207
                if (temp_sig == NULL)
1208
                {
1209
                        DEBUGMSGTL(("usm","Out of memory.\n"));
1210
                        usm_free_usmStateReference (secStateRef);
1211
                        return SNMPERR_USM_GENERICERROR;
1212
                }
1213
 
1214
                if ( sc_generate_keyed_hash (
1215
                        theAuthProtocol,         theAuthProtocolLength,
1216
                        theAuthKey,              theAuthKeyLength,
1217
                        ptr,                     ptr_len,
1218
                        temp_sig,               &temp_sig_len)
1219
                                                        != SNMP_ERR_NOERROR )
1220
                {
1221
                        /* FIX temp_sig_len defined?!
1222
                         */
1223
                        SNMP_ZERO(temp_sig, temp_sig_len);
1224
                        SNMP_FREE(temp_sig);
1225
                        DEBUGMSGTL(("usm","Signing failed.\n"));
1226
                        usm_free_usmStateReference (secStateRef);
1227
                        return SNMPERR_USM_AUTHENTICATIONFAILURE;
1228
                }
1229
 
1230
                if (temp_sig_len != msgAuthParmLen)
1231
                {
1232
                        SNMP_ZERO(temp_sig, temp_sig_len);
1233
                        SNMP_FREE(temp_sig);
1234
                        DEBUGMSGTL(("usm","Signing lengths failed.\n"));
1235
                        usm_free_usmStateReference (secStateRef);
1236
                        return SNMPERR_USM_AUTHENTICATIONFAILURE;
1237
                }
1238
 
1239
                memcpy (&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
1240
 
1241
                SNMP_ZERO(temp_sig, temp_sig_len);
1242
                SNMP_FREE(temp_sig);
1243
 
1244
        }  /* endif -- create keyed hash */
1245
 
1246
 
1247
        usm_free_usmStateReference (secStateRef);
1248
 
1249
        DEBUGMSGTL(("usm","USM processing completed.\n"));
1250
 
1251
        return SNMPERR_SUCCESS;
1252
 
1253
}  /* end usm_generate_out_msg() */
1254
 
1255
 
1256
 
1257
 
1258
/*******************************************************************-o-******
1259
 * usm_parse_security_parameters
1260
 *
1261
 * Parameters:
1262
 *      (See list below...)
1263
 *
1264
 * Returns:
1265
 *      0        On success,
1266
 *      -1      Otherwise.
1267
 *
1268
 *      tab stop 4
1269
 *
1270
 *      Extracts values from the security header and data portions of the
1271
 *      incoming buffer.
1272
 */
1273
int
1274
usm_parse_security_parameters (
1275
        u_char  *secParams,
1276
        size_t   remaining,
1277
        u_char  *secEngineID,
1278
        size_t  *secEngineIDLen,
1279
        u_int   *boots_uint,
1280
        u_int   *time_uint,
1281
        char    *secName,
1282
        size_t  *secNameLen,
1283
        u_char  *signature,
1284
        size_t  *signature_length,
1285
        u_char  *salt,
1286
        size_t  *salt_length,
1287
        u_char **data_ptr)
1288
{
1289
        u_char  *parse_ptr = secParams;
1290
        u_char  *value_ptr;
1291
        u_char  *next_ptr;
1292
        u_char   type_value;
1293
 
1294
        size_t   octet_string_length = remaining;
1295
        size_t   sequence_length;
1296
        size_t   remaining_bytes;
1297
 
1298
        long     boots_long;
1299
        long     time_long;
1300
 
1301
        u_int    origNameLen;
1302
 
1303
 
1304
        /*
1305
         * Eat the first octet header.
1306
         */
1307
        if ((value_ptr = asn_parse_sequence (parse_ptr, &octet_string_length,
1308
                &type_value,
1309
                (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1310
                "usm first octet")) == NULL)
1311
        {
1312
                /* RETURN parse error */ return -1;
1313
        }
1314
 
1315
 
1316
        /*
1317
         * Eat the sequence header.
1318
         */
1319
        parse_ptr       = value_ptr;
1320
        sequence_length = octet_string_length;
1321
 
1322
        if ((value_ptr = asn_parse_sequence (parse_ptr, &sequence_length,
1323
                &type_value,
1324
                (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1325
                "usm sequence")) == NULL)
1326
        {
1327
                /* RETURN parse error */ return -1;
1328
        }
1329
 
1330
 
1331
        /*
1332
         * Retrieve the engineID.
1333
         */
1334
        parse_ptr       = value_ptr;
1335
        remaining_bytes = sequence_length;
1336
 
1337
        DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineID\n");
1338
        if ( (next_ptr
1339
                = asn_parse_string (parse_ptr, &remaining_bytes, &type_value,
1340
                        secEngineID, secEngineIDLen)) == NULL )
1341
        {
1342
                DEBUGINDENTLESS();
1343
                /* RETURN parse error */ return -1;
1344
        }
1345
        DEBUGINDENTLESS();
1346
 
1347
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1348
        {
1349
                /* RETURN parse error */ return -1;
1350
        }
1351
 
1352
 
1353
        /*
1354
         * Retrieve the engine boots, notice switch in the way next_ptr and
1355
         * remaining_bytes are used (to accomodate the asn code).
1356
         */
1357
        DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineBoots\n");
1358
        if ((next_ptr = asn_parse_int (next_ptr, &remaining_bytes, &type_value,
1359
                &boots_long, sizeof(long))) == NULL)
1360
        {
1361
                DEBUGINDENTLESS();
1362
                /* RETURN parse error */ return -1;
1363
        }
1364
        DEBUGINDENTLESS();
1365
 
1366
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_INTEGER))
1367
        {
1368
                DEBUGINDENTLESS();
1369
                /* RETURN parse error */ return -1;
1370
        }
1371
 
1372
        *boots_uint = (u_int) boots_long;
1373
 
1374
 
1375
        /*
1376
         * Retrieve the time value.
1377
         */
1378
        DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineTime\n");
1379
        if ((next_ptr = asn_parse_int (next_ptr, &remaining_bytes, &type_value,
1380
                &time_long, sizeof(long))) == NULL)
1381
        {
1382
                /* RETURN parse error */ return -1;
1383
        }
1384
 
1385
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_INTEGER))
1386
        {
1387
                  DEBUGINDENTLESS();
1388
                  /* RETURN parse error */ return -1;
1389
        }
1390
 
1391
        *time_uint = (u_int) time_long;
1392
 
1393
 
1394
        /*
1395
         * Retrieve the secName.
1396
         */
1397
        origNameLen = *secNameLen;
1398
 
1399
        DEBUGDUMPHEADER("dump_recv", "Parsing msgUserName\n");
1400
        if ( (next_ptr
1401
                = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1402
                        (u_char *)secName, secNameLen)) == NULL )
1403
        {
1404
                DEBUGINDENTLESS();
1405
                /* RETURN parse error */ return -1;
1406
        }
1407
        DEBUGINDENTLESS();
1408
 
1409
        /* FIX -- doesn't this also indicate a buffer overrun?
1410
         */
1411
        if ((int)origNameLen < *secNameLen + 1)
1412
        {
1413
                /* RETURN parse error, but it's really a parameter error */
1414
                return -1;
1415
        }
1416
 
1417
        secName[*secNameLen] = '\0';
1418
 
1419
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1420
        {
1421
                /* RETURN parse error */ return -1;
1422
        }
1423
 
1424
 
1425
        /*
1426
         * Retrieve the signature and blank it if there.
1427
         */
1428
        DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthenticationParameters\n");
1429
        if ( (next_ptr
1430
                = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1431
                        signature, signature_length)) == NULL )
1432
        {
1433
                DEBUGINDENTLESS();
1434
                /* RETURN parse error */ return -1;
1435
        }
1436
        DEBUGINDENTLESS();
1437
 
1438
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1439
        {
1440
                /* RETURN parse error */ return -1;
1441
        }
1442
 
1443
        if (*signature_length != 0) /* Blanking for authentication step later */
1444
        {
1445
                memset (next_ptr-(u_long)*signature_length,
1446
                                                0, *signature_length);
1447
        }
1448
 
1449
 
1450
        /*
1451
         * Retrieve the salt.
1452
         *
1453
         * Note that the next ptr is where the data section starts.
1454
         */
1455
        DEBUGDUMPHEADER("dump_recv", "Parsing msgPrivacyParameters\n");
1456
        if ( (*data_ptr
1457
                = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1458
                        salt, salt_length)) == NULL )
1459
        {
1460
                DEBUGINDENTLESS();
1461
                /* RETURN parse error */ return -1;
1462
        }
1463
        DEBUGINDENTLESS();
1464
 
1465
        if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1466
        {
1467
                /* RETURN parse error */ return -1;
1468
        }
1469
 
1470
        return 0;
1471
 
1472
}  /* end usm_parse_security_parameters() */
1473
 
1474
 
1475
 
1476
 
1477
/*******************************************************************-o-******
1478
 * usm_check_and_update_timeliness
1479
 *
1480
 * Parameters:
1481
 *      *secEngineID
1482
 *       secEngineIDen
1483
 *       boots_uint
1484
 *       time_uint
1485
 *      *error
1486
 *
1487
 * Returns:
1488
 *      0        On success,
1489
 *      -1      Otherwise.
1490
 *
1491
 *
1492
 * Performs the incoming timeliness checking and setting.
1493
 */
1494
int
1495
usm_check_and_update_timeliness(
1496
        u_char *secEngineID,
1497
        size_t  secEngineIDLen,
1498
        u_int   boots_uint,
1499
        u_int   time_uint,
1500
        int    *error)
1501
{
1502
        u_char  myID[USM_MAX_ID_LENGTH];
1503
        int     myIDLength = snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
1504
        u_int   myBoots;
1505
        u_int   myTime;
1506
 
1507
 
1508
 
1509
        if ( (myIDLength > USM_MAX_ID_LENGTH) || (myIDLength < 0) )
1510
        {
1511
                /* We're probably already screwed...buffer overwrite.  XXX? */
1512
                DEBUGMSGTL(("usm","Buffer overflow.\n"));
1513
                *error = SNMPERR_USM_GENERICERROR;
1514
                return -1;
1515
        }
1516
 
1517
        myBoots = snmpv3_local_snmpEngineBoots();
1518
        myTime  = snmpv3_local_snmpEngineTime();
1519
 
1520
 
1521
        /*
1522
         * IF the time involved is local
1523
         *     Make sure  message is inside the time window
1524
         * ELSE
1525
         *      IF boots is higher or boots is the same and time is higher
1526
         *              remember this new data
1527
         *      ELSE
1528
         *              IF !(boots same and time within USM_TIME_WINDOW secs)
1529
         *                      Message is too old
1530
         *              ELSE
1531
         *                      Message is ok, but don't take time
1532
         *              ENDIF
1533
         *      ENDIF
1534
         * ENDIF
1535
         */
1536
 
1537
        /*
1538
         * This is a local reference.
1539
         */
1540
        if ( (int)secEngineIDLen == myIDLength
1541
                && memcmp (secEngineID, myID, myIDLength) == 0 )
1542
        {
1543
                u_int time_difference = myTime > time_uint ?
1544
                        myTime - time_uint : time_uint - myTime;
1545
 
1546
                if (boots_uint == ENGINEBOOT_MAX
1547
                        || boots_uint != myBoots
1548
                        || time_difference > USM_TIME_WINDOW)
1549
                {
1550
                        if ( snmp_increment_statistic(
1551
                                        STAT_USMSTATSNOTINTIMEWINDOWS) == 0 )
1552
                        {
1553
                                DEBUGMSGTL(("usm","%s\n",
1554
                                        "Failed to increment statistic."));
1555
                        }
1556
 
1557
                        DEBUGMSGTL(("usm","%s\n", "Not in local time window."));
1558
                        *error = SNMPERR_USM_NOTINTIMEWINDOW;
1559
                        return -1;
1560
                }
1561
 
1562
                *error = SNMPERR_SUCCESS;
1563
                return 0;
1564
        }
1565
 
1566
        /*
1567
         * This is a remote reference.
1568
         */
1569
        else
1570
        {
1571
                u_int   theirBoots,
1572
                        theirTime,
1573
                        theirLastTime;
1574
                u_int   time_difference;
1575
 
1576
                if ( get_enginetime_ex( secEngineID,    secEngineIDLen,
1577
                                        &theirBoots,    &theirTime,
1578
                                        &theirLastTime,
1579
                                        TRUE)
1580
                                                        != SNMPERR_SUCCESS)
1581
                {
1582
                        DEBUGMSGTL(("usm","%s\n",
1583
                                "Failed to get remote engine's times."));
1584
 
1585
                        *error = SNMPERR_USM_GENERICERROR;
1586
                        return -1;
1587
                }
1588
 
1589
                time_difference = theirTime > time_uint ?
1590
                        theirTime - time_uint : time_uint - theirTime;
1591
 
1592
 
1593
                /*
1594
                 * XXX  Contrary to the pseudocode:
1595
                 *      See if boots is invalid first.
1596
                 */
1597
                if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint)
1598
                {
1599
                        DEBUGMSGTL(("usm","%s\n", "Remote boot count invalid."));
1600
 
1601
                        *error = SNMPERR_USM_NOTINTIMEWINDOW;
1602
                        return -1;
1603
                }
1604
 
1605
 
1606
                /*
1607
                 * Boots is ok, see if the boots is the same but the time
1608
                 * is old.
1609
                 */
1610
                if (theirBoots == boots_uint && time_uint < theirLastTime)
1611
                {
1612
                        if(time_difference > USM_TIME_WINDOW)
1613
                        {
1614
                                DEBUGMSGTL(("usm","%s\n", "Message too old."));
1615
                                *error = SNMPERR_USM_NOTINTIMEWINDOW;
1616
                                return -1;
1617
                        }
1618
 
1619
                        else            /* Old, but acceptable */
1620
                        {
1621
                                *error = SNMPERR_SUCCESS;
1622
                                return 0;
1623
                        }
1624
                }
1625
 
1626
 
1627
                /*
1628
                        Message is ok, either boots has been advanced, or
1629
                        time is greater than before with the same boots.
1630
                */
1631
 
1632
                if ( set_enginetime(    secEngineID,    secEngineIDLen,
1633
                                        boots_uint,     time_uint,
1634
                                        TRUE)
1635
                                                        != SNMPERR_SUCCESS)
1636
                {
1637
                        DEBUGMSGTL(("usm","%s\n", "Failed updating remote boot/time."));
1638
                        *error = SNMPERR_USM_GENERICERROR;
1639
                        return -1;
1640
                }
1641
 
1642
                *error = SNMPERR_SUCCESS;
1643
                return 0;                /* Fresh message and time updated */
1644
 
1645
        }  /* endif -- local or remote time reference. */
1646
 
1647
 
1648
}  /* end usm_check_and_update_timeliness() */
1649
 
1650
 
1651
 
1652
 
1653
/*******************************************************************-o-******
1654
 * usm_process_in_msg
1655
 *
1656
 * Parameters:
1657
 *      (See list below...)
1658
 *
1659
 * Returns:
1660
 *      SNMPERR_SUCCESS                 On success.
1661
 *      SNMPERR_USM_AUTHENTICATIONFAILURE
1662
 *      SNMPERR_USM_DECRYPTIONERROR
1663
 *      SNMPERR_USM_GENERICERROR
1664
 *      SNMPERR_USM_PARSEERROR
1665
 *      SNMPERR_USM_UNKNOWNENGINEID
1666
 *      SNMPERR_USM_PARSEERROR
1667
 *      SNMPERR_USM_UNKNOWNSECURITYNAME
1668
 *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
1669
 *
1670
 *
1671
 * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
1672
 *
1673
 * FIX  Memory leaks if secStateRef is allocated and a return occurs
1674
 *      without cleaning up.  May contain secrets...
1675
 */
1676
int
1677
usm_process_in_msg (
1678
        int      msgProcModel,     /* (UNUSED) */
1679
        size_t   maxMsgSize,       /* IN     - Used to calc maxSizeResponse.  */
1680
 
1681
        u_char  *secParams,        /* IN     - BER encoded securityParameters.*/
1682
        int      secModel,         /* (UNUSED) */
1683
        int      secLevel,         /* IN     - AuthNoPriv, authPriv etc.      */
1684
 
1685
        u_char  *wholeMsg,         /* IN     - Original v3 message.           */
1686
        size_t   wholeMsgLen,      /* IN     - Msg length.                    */
1687
 
1688
        u_char  *secEngineID,      /* OUT    - Pointer snmpEngineID.          */
1689
        size_t  *secEngineIDLen,   /* IN/OUT - Len available, len returned.   */
1690
                                   /*   NOTE: Memory provided by caller.      */
1691
 
1692
        char *secName,             /* OUT    - Pointer to securityName.       */
1693
        size_t  *secNameLen,       /* IN/OUT - Len available, len returned.   */
1694
 
1695
        u_char **scopedPdu,        /* OUT    - Pointer to plaintext scopedPdu.*/
1696
        size_t  *scopedPduLen,     /* IN/OUT - Len available, len returned.   */
1697
 
1698
        size_t  *maxSizeResponse,  /* OUT    - Max size of Response PDU.      */
1699
        void   **secStateRf)       /* OUT    - Ref to security state.         */
1700
{
1701
        size_t   remaining = wholeMsgLen
1702
                                - (u_int)
1703
                                        ((u_long)*secParams-(u_long)*wholeMsg);
1704
        u_int   boots_uint;
1705
        u_int   time_uint;
1706
        u_char  signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
1707
        size_t  signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
1708
        u_char  salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1709
        size_t  salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1710
        u_char  iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
1711
        u_int   iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1712
        u_char *data_ptr;
1713
        u_char *value_ptr;
1714
        u_char  type_value;
1715
        u_char *end_of_overhead;
1716
        int     error;
1717
        int     i;
1718
        struct usmStateReference **secStateRef = (struct usmStateReference **)secStateRf;
1719
 
1720
        struct usmUser *user;
1721
 
1722
 
1723
        DEBUGMSGTL(("usm","USM processing begun...\n"));
1724
 
1725
 
1726
        if (secStateRef)                /* FIX -- huh?  destroy it? */
1727
        {
1728
                *secStateRef = usm_malloc_usmStateReference();
1729
                if (*secStateRef == NULL)
1730
                {
1731
                        DEBUGMSGTL(("usm", "Out of memory.\n"));
1732
                        return SNMPERR_USM_GENERICERROR;
1733
                }
1734
        }
1735
 
1736
 
1737
        /*
1738
         * Make sure the *secParms is an OCTET STRING.
1739
         * Extract the user name, engine ID, and security level.
1740
         */
1741
        if ( usm_parse_security_parameters (
1742
                 secParams,              remaining,
1743
                 secEngineID,            secEngineIDLen,
1744
                &boots_uint,            &time_uint,
1745
                 secName,                secNameLen,
1746
                 signature,             &signature_length,
1747
                 salt,                  &salt_length,
1748
                 &data_ptr)
1749
                        == -1 )
1750
        {
1751
                DEBUGMSGTL(("usm","Parsing failed.\n"));
1752
                if (snmp_increment_statistic (STAT_SNMPINASNPARSEERRS)==0)
1753
                {
1754
                        DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1755
                }
1756
                return SNMPERR_USM_PARSEERROR;
1757
        }
1758
 
1759
 
1760
        if (secStateRef)
1761
        {
1762
                /* Cache the name, engine ID, and security level,
1763
                 * per step 2 (section 3.2)
1764
                 */
1765
                if ( usm_set_usmStateReference_name (
1766
                                *secStateRef, secName, *secNameLen) == -1 )
1767
                {
1768
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache name."));
1769
                        return SNMPERR_USM_GENERICERROR;
1770
                }
1771
 
1772
                if ( usm_set_usmStateReference_engine_id (
1773
                        *secStateRef, secEngineID, *secEngineIDLen) == -1 )
1774
                {
1775
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache engine id."));
1776
                        return SNMPERR_USM_GENERICERROR;
1777
                }
1778
 
1779
                if ( usm_set_usmStateReference_sec_level (
1780
                                        *secStateRef, secLevel) == -1 )
1781
                {
1782
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache security level."));
1783
                        return SNMPERR_USM_GENERICERROR;
1784
                }
1785
        }
1786
 
1787
 
1788
        /*
1789
         * Locate the engine ID record.
1790
         * If it is unknown, then either create one or note this as an error.
1791
         */
1792
        if (reportErrorOnUnknownID)
1793
        {
1794
                if (ISENGINEKNOWN(secEngineID, *secEngineIDLen)==FALSE)
1795
                {
1796
                        DEBUGMSGTL(("usm","Unknown Engine ID.\n"));
1797
                        if (snmp_increment_statistic (
1798
                                        STAT_USMSTATSUNKNOWNENGINEIDS)==0)
1799
                        {
1800
                                DEBUGMSGTL(("usm","%s\n",
1801
                                        "Failed to increment statistic."));
1802
                        }
1803
                        return SNMPERR_USM_UNKNOWNENGINEID;
1804
                }
1805
        }
1806
        else
1807
        {
1808
                if ( ENSURE_ENGINE_RECORD(secEngineID,*secEngineIDLen)
1809
                                                        != SNMPERR_SUCCESS )
1810
                {
1811
                        DEBUGMSGTL(("usm","%s\n", "Couldn't ensure engine record."));
1812
                        return SNMPERR_USM_GENERICERROR;
1813
                }
1814
 
1815
        }
1816
 
1817
 
1818
        /*
1819
         * Locate the User record.
1820
         * If the user/engine ID is unknown, report this as an error.
1821
         */
1822
        if ( (user =
1823
                usm_get_user(secEngineID, *secEngineIDLen, secName))
1824
                        == NULL )
1825
        {
1826
                DEBUGMSGTL(("usm","Unknown User.\n"));
1827
                if (snmp_increment_statistic (STAT_USMSTATSUNKNOWNUSERNAMES)==0)
1828
                {
1829
                        DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1830
                }
1831
                return SNMPERR_USM_UNKNOWNSECURITYNAME;
1832
        }
1833
 
1834
 
1835
        /*
1836
         * Make sure the security level is appropriate.
1837
         */
1838
        if (usm_check_secLevel(secLevel, user) == 1)
1839
        {
1840
                DEBUGMSGTL(("usm","Unsupported Security Level.\n"));
1841
                if (snmp_increment_statistic
1842
                                        (STAT_USMSTATSUNSUPPORTEDSECLEVELS)==0)
1843
                {
1844
                        DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1845
                }
1846
                return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
1847
        }
1848
 
1849
 
1850
        /*
1851
         * Check the authentication credentials of the message.
1852
         */
1853
        if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1854
                || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1855
        {
1856
                if ( sc_check_keyed_hash (
1857
                        user->authProtocol,     user->authProtocolLen,
1858
                        user->authKey,          user->authKeyLen,
1859
                        wholeMsg,               wholeMsgLen,
1860
                        signature,              signature_length)
1861
                                                        != SNMP_ERR_NOERROR )
1862
                {
1863
                        DEBUGMSGTL(("usm","Verification failed.\n"));
1864
                        if (snmp_increment_statistic
1865
                                        (STAT_USMSTATSWRONGDIGESTS)==0)
1866
                        {
1867
                                DEBUGMSGTL(("usm","%s\n",
1868
                                    "Failed to increment statistic."));
1869
                        }
1870
                        return SNMPERR_USM_AUTHENTICATIONFAILURE;
1871
                }
1872
 
1873
                DEBUGMSGTL(("usm","Verification succeeded.\n"));
1874
        }
1875
 
1876
 
1877
        /*
1878
         * Steps 10-11  user is already set - relocated before timeliness
1879
         * check in case it fails - still save user data for response.
1880
         *
1881
         * Cache the keys and protocol oids, per step 11 (s3.2).
1882
         */
1883
        if (secStateRef)
1884
        {
1885
                if (usm_set_usmStateReference_auth_protocol (*secStateRef,
1886
                        user->authProtocol, user->authProtocolLen) ==-1)
1887
                {
1888
                        DEBUGMSGTL(("usm","%s\n",
1889
                                "Couldn't cache authentication protocol."));
1890
                        return SNMPERR_USM_GENERICERROR;
1891
                }
1892
 
1893
                if (usm_set_usmStateReference_auth_key (*secStateRef,
1894
                        user->authKey, user->authKeyLen) == -1)
1895
                {
1896
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache authentiation key."));
1897
                        return SNMPERR_USM_GENERICERROR;
1898
                }
1899
 
1900
                if (usm_set_usmStateReference_priv_protocol (*secStateRef,
1901
                        user->privProtocol, user->privProtocolLen) ==-1)
1902
                {
1903
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache privacy protocol."));
1904
                        return SNMPERR_USM_GENERICERROR;
1905
                }
1906
 
1907
                if (usm_set_usmStateReference_priv_key (*secStateRef,
1908
                        user->privKey, user->privKeyLen) == -1)
1909
                {
1910
                        DEBUGMSGTL(("usm","%s\n", "Couldn't cache privacy key."));
1911
                        return SNMPERR_USM_GENERICERROR;
1912
                }
1913
        }
1914
 
1915
 
1916
        /*
1917
         * Perform the timeliness/time manager functions.
1918
         */
1919
        if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1920
                        || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1921
        {
1922
                if ( usm_check_and_update_timeliness (
1923
                        secEngineID, *secEngineIDLen,
1924
                        boots_uint, time_uint, &error) == -1 )
1925
                {
1926
                        return error;
1927
                }
1928
        }
1929
 
1930
#ifdef                                                  LCD_TIME_SYNC_OPT       
1931
        /*
1932
         * Cache the unauthenticated time to use in case we don't have
1933
         * anything better - this guess will be no worse than (0,0)
1934
         * that we normally use.
1935
         */
1936
        else
1937
        {
1938
                set_enginetime(secEngineID, *secEngineIDLen,
1939
                                                boots_uint, time_uint, FALSE);
1940
        }
1941
#endif                                                  /* LCD_TIME_SYNC_OPT */
1942
 
1943
 
1944
        /*
1945
         * If needed, decrypt the scoped PDU.
1946
         */
1947
        if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1948
        {
1949
                remaining = wholeMsgLen - (data_ptr - wholeMsg);
1950
 
1951
                if ((value_ptr = asn_parse_sequence (data_ptr, &remaining,
1952
                        &type_value,
1953
                        (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1954
                        "encrypted sPDU")) == NULL)
1955
                {
1956
                        DEBUGMSGTL(("usm","%s\n",
1957
                                "Failed while parsing encrypted sPDU."));
1958
                        if (snmp_increment_statistic
1959
                                                (STAT_SNMPINASNPARSEERRS)==0)
1960
                        {
1961
                                DEBUGMSGTL(("usm","%s\n",
1962
                                        "Failed increment statistic."));
1963
                        }
1964
                        return SNMPERR_USM_PARSEERROR;
1965
                }
1966
 
1967
                end_of_overhead = value_ptr;
1968
 
1969
                /*
1970
                 * XOR the salt with the last (iv_length) bytes
1971
                 * of the priv_key to obtain the IV.
1972
                 */
1973
                for (i = 0; i < (int)iv_length; i++)
1974
                  iv[i] = salt[i] ^ user->privKey[iv_length + i];
1975
 
1976
                if (sc_decrypt (
1977
                         user->privProtocol,    user->privProtocolLen,
1978
                         user->privKey,         user->privKeyLen,
1979
                         iv,                    iv_length,
1980
                         value_ptr,             remaining,
1981
                        *scopedPdu,             scopedPduLen)
1982
                                                        != SNMP_ERR_NOERROR)
1983
                {
1984
                        DEBUGMSGTL(("usm","%s\n", "Failed decryption."));
1985
                        if (snmp_increment_statistic
1986
                                        (STAT_USMSTATSDECRYPTIONERRORS)==0)
1987
                        {
1988
                                DEBUGMSGTL(("usm","%s\n",
1989
                                        "Failed increment statistic."));
1990
                        }
1991
                        return SNMPERR_USM_DECRYPTIONERROR;
1992
                }
1993
 
1994
#ifdef SNMP_TESTING_CODE
1995
                if ( debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1996
                        dump_chunk("usm/dump", "Decrypted chunk:",
1997
                                                *scopedPdu, *scopedPduLen);
1998
                        dump_chunk("usm/dump", "IV + Encrypted form:",
1999
                                                salt, salt_length);
2000
                        dump_chunk("usm/dump", NULL,
2001
                                                value_ptr, remaining);
2002
                }
2003
#endif
2004
        }
2005
 
2006
        /*
2007
         * sPDU is plaintext.
2008
         */
2009
        else
2010
        {
2011
                *scopedPdu      = data_ptr;
2012
                *scopedPduLen   = wholeMsgLen - (data_ptr - wholeMsg);
2013
                end_of_overhead = data_ptr;
2014
 
2015
        }  /* endif -- PDU decryption */
2016
 
2017
 
2018
        /*
2019
         * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
2020
         *
2021
         * FIX  Correct?
2022
         */
2023
        *maxSizeResponse = maxMsgSize - (int)
2024
                                ((u_long)end_of_overhead - (u_long)wholeMsg);
2025
 
2026
 
2027
        DEBUGMSGTL(("usm","USM processing completed.\n"));
2028
 
2029
        return SNMPERR_SUCCESS;
2030
 
2031
}  /* end usm_process_in_msg() */
2032
 
2033
void
2034
init_usm(void) {
2035
  snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
2036
                         init_usm_post_config, NULL);
2037
}
2038
 
2039
/*
2040
 * initializations for the USM.
2041
 *
2042
 * Should be called after the configuration files have been read.
2043
 *
2044
 * Set "arbitrary" portion of salt to a random number.
2045
 */
2046
int
2047
init_usm_post_config(int majorid, int minorid, void *serverarg,
2048
                     void *clientarg) {
2049
  size_t        salt_integer_len = sizeof(salt_integer);
2050
 
2051
  initialUser = usm_create_initial_user("initial", usmHMACMD5AuthProtocol,
2052
                                        USM_LENGTH_OID_TRANSFORM,
2053
                                        usmDESPrivProtocol,
2054
                                        USM_LENGTH_OID_TRANSFORM);
2055
  SNMP_FREE(initialUser->engineID);
2056
  initialUser->engineIDLen = 0;
2057
 
2058
  if ( sc_random((u_char *) &salt_integer, &salt_integer_len) != SNMPERR_SUCCESS )
2059
  {
2060
        DEBUGMSGTL(("usm","sc_random() failed: using time() as salt.\n"));
2061
        salt_integer     = (u_int) time(NULL);
2062
        salt_integer_len = sizeof(salt_integer);
2063
  }
2064
 
2065
  noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
2066
                                        USM_LENGTH_OID_TRANSFORM,
2067
                                        usmDESPrivProtocol,
2068
                                        USM_LENGTH_OID_TRANSFORM);
2069
  SNMP_FREE(noNameUser->engineID);
2070
  noNameUser->engineIDLen = 0;
2071
 
2072
  return SNMPERR_SUCCESS;
2073
}  /* end init_usm_post_config() */
2074
 
2075
 
2076
/*
2077
 * Local storage (LCD) of the default user list.
2078
 */
2079
static struct usmUser *userList=NULL;
2080
 
2081
struct usmUser *
2082
usm_get_userList(void)
2083
{
2084
  return userList;
2085
}
2086
 
2087
 
2088
 
2089
/*******************************************************************-o-******
2090
 * usm_check_secLevel
2091
 *
2092
 * Parameters:
2093
 *       level
2094
 *      *user
2095
 *
2096
 * Returns:
2097
 *      0        On success,
2098
 *      -1      Otherwise.
2099
 *
2100
 * Checks that a given security level is valid for a given user.
2101
 */
2102
int
2103
usm_check_secLevel(int level, struct usmUser *user)
2104
{
2105
 
2106
  if ( level == SNMP_SEC_LEVEL_AUTHPRIV
2107
        && (snmp_oid_compare(user->privProtocol, user->privProtocolLen,
2108
                usmNoPrivProtocol, sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
2109
  {
2110
    return 1;
2111
  }
2112
  if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2113
        && (snmp_oid_compare(user->authProtocol, user->authProtocolLen,
2114
                usmNoAuthProtocol, sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
2115
  {
2116
    return 1;
2117
  }
2118
 
2119
  return 0;
2120
 
2121
}  /* end usm_check_secLevel() */
2122
 
2123
 
2124
 
2125
 
2126
/*******************************************************************-o-******
2127
 * usm_check_secLevel_vs_protocols
2128
 *
2129
 * Parameters:
2130
 *       level
2131
 *      *authProtocol
2132
 *       authProtocolLen
2133
 *      *privProtocol
2134
 *       privProtocolLen
2135
 *
2136
 * Returns:
2137
 *      0        On success,
2138
 *      -1      Otherwise.
2139
 *
2140
 * Same as above but with explicitly named transform types instead of taking
2141
 * from the usmUser structure.
2142
 */
2143
int
2144
usm_check_secLevel_vs_protocols(int level,
2145
        oid *authProtocol, u_int authProtocolLen,
2146
        oid *privProtocol, u_int privProtocolLen)
2147
{
2148
 
2149
  if ( level == SNMP_SEC_LEVEL_AUTHPRIV
2150
        && (snmp_oid_compare(privProtocol, privProtocolLen, usmNoPrivProtocol,
2151
                                sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
2152
  {
2153
    return 1;
2154
  }
2155
  if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2156
        && (snmp_oid_compare(authProtocol, authProtocolLen, usmNoAuthProtocol,
2157
                                sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
2158
  {
2159
    return 1;
2160
  }
2161
 
2162
  return 0;
2163
 
2164
}  /* end usm_check_secLevel_vs_protocols() */
2165
 
2166
 
2167
/* usm_update_engine_time(): Updates engine_time for all registered users.
2168
 * This function would be useful for systems that start up with default time
2169
 * settings and then update their timing reference using NTP at a later stage
2170
 */
2171
void usm_update_engine_time(void) {
2172
 
2173
  struct usmUser *ptr;
2174
  long            boots_long;
2175
  long            time_long;
2176
 
2177
  boots_long = snmpv3_local_snmpEngineBoots();
2178
  time_long  = snmpv3_local_snmpEngineTime();
2179
 
2180
  for (ptr = userList; ptr != NULL; ptr = ptr->next) {
2181
    set_enginetime( ptr->engineID, ptr->engineIDLen,
2182
                    boots_long, time_long, TRUE );
2183
  }
2184
}
2185
 
2186
 
2187
/* usm_get_user(): Returns a user from userList based on the engineID,
2188
   engineIDLen and name of the requested user. */
2189
 
2190
struct usmUser *
2191
usm_get_user(u_char *engineID, size_t engineIDLen, char *name)
2192
{
2193
  DEBUGMSGTL(("usm","getting user %s\n", name));
2194
  return usm_get_user_from_list(engineID, engineIDLen, name, userList, 1);
2195
}
2196
 
2197
struct usmUser *
2198
usm_get_user_from_list(u_char *engineID, size_t engineIDLen,
2199
                       char *name, struct usmUser *puserList, int use_default)
2200
{
2201
  struct usmUser *ptr;
2202
  char noName[] = "";
2203
  if (name == NULL)
2204
    name = noName;
2205
  for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
2206
    if (!strcmp(ptr->name, name) &&
2207
        ptr->engineIDLen == engineIDLen &&
2208
        ((ptr->engineID == NULL && engineID == NULL) ||
2209
         (ptr->engineID != NULL && engineID != NULL &&
2210
          memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
2211
      return ptr;
2212
  }
2213
  /* return "" user used to facilitate engineID discovery */
2214
  if (use_default && !strcmp(name, "")) return noNameUser;
2215
  /* this next line may be vestigial from when the draft used 'initial'
2216
     to discover engineID, also did not remove creation if 'inital' user
2217
     -gsm 2/6/99 */
2218
  if (use_default && !strcmp(name, "initial")) return initialUser;
2219
  return NULL;
2220
}
2221
 
2222
/* usm_add_user(): Add's a user to the userList, sorted by the
2223
   engineIDLength then the engineID then the name length then the name
2224
   to facilitate getNext calls on a usmUser table which is indexed by
2225
   these values.
2226
 
2227
   Note: userList must not be NULL (obviously), as thats a rather trivial
2228
   addition and is left to the API user.
2229
 
2230
   returns the head of the list (which could change due to this add).
2231
*/
2232
 
2233
struct usmUser *
2234
usm_add_user(struct usmUser *user)
2235
{
2236
  struct usmUser *uptr;
2237
  uptr = usm_add_user_to_list(user, userList);
2238
  if (uptr != NULL)
2239
    userList = uptr;
2240
  return uptr;
2241
}
2242
 
2243
struct usmUser *
2244
usm_add_user_to_list(struct usmUser *user,
2245
                                     struct usmUser *puserList)
2246
{
2247
  struct usmUser *nptr, *pptr;
2248
 
2249
  /* loop through puserList till we find the proper, sorted place to
2250
     insert the new user */
2251
  for (nptr = puserList, pptr = NULL; nptr != NULL;
2252
       pptr = nptr, nptr = nptr->next) {
2253
    if (nptr->engineIDLen > user->engineIDLen)
2254
      break;
2255
 
2256
    if (user->engineID == NULL && nptr->engineID != NULL)
2257
      break;
2258
 
2259
    if (nptr->engineIDLen == user->engineIDLen &&
2260
        (nptr->engineID != NULL && user->engineID != NULL &&
2261
         memcmp(nptr->engineID, user->engineID, user->engineIDLen) > 0))
2262
      break;
2263
 
2264
    if (!(nptr->engineID == NULL && user->engineID != NULL)) {
2265
      if (nptr->engineIDLen == user->engineIDLen &&
2266
          ((nptr->engineID == NULL && user->engineID == NULL) ||
2267
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2268
          strlen(nptr->name) > strlen(user->name))
2269
        break;
2270
 
2271
      if (nptr->engineIDLen == user->engineIDLen &&
2272
          ((nptr->engineID == NULL && user->engineID == NULL) ||
2273
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2274
          strlen(nptr->name) == strlen(user->name) &&
2275
          strcmp(nptr->name, user->name) > 0)
2276
        break;
2277
 
2278
      if (nptr->engineIDLen == user->engineIDLen &&
2279
          ((nptr->engineID == NULL && user->engineID == NULL) ||
2280
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2281
          strlen(nptr->name) == strlen(user->name) &&
2282
          strcmp(nptr->name, user->name) == 0)
2283
        /* the user is an exact match of a previous entry.  Bail */
2284
        return NULL;
2285
    }
2286
  }
2287
 
2288
  /* nptr should now point to the user that we need to add ourselves
2289
     in front of, and pptr should be our new 'prev'. */
2290
 
2291
  /* change our pointers */
2292
  user->prev = pptr;
2293
  user->next = nptr;
2294
 
2295
  /* change the next's prev pointer */
2296
  if (user->next)
2297
    user->next->prev = user;
2298
 
2299
  /* change the prev's next pointer */
2300
  if (user->prev)
2301
    user->prev->next = user;
2302
 
2303
  /* rewind to the head of the list and return it (since the new head
2304
     could be us, we need to notify the above routine who the head now is. */
2305
  for(pptr = user; pptr->prev != NULL; pptr = pptr->prev);
2306
  return pptr;
2307
}
2308
 
2309
/* usm_remove_user(): finds and removes a user from a list */
2310
struct usmUser *
2311
usm_remove_user(struct usmUser *user)
2312
{
2313
  return usm_remove_user_from_list(user, &userList);
2314
}
2315
 
2316
struct usmUser *
2317
usm_remove_user_from_list(struct usmUser *user,
2318
                                          struct usmUser **ppuserList)
2319
{
2320
  struct usmUser *nptr, *pptr;
2321
 
2322
  /* NULL pointers aren't allowed */
2323
  if (ppuserList == NULL)
2324
    return NULL;
2325
 
2326
  /* find the user in the list */
2327
  for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
2328
       pptr = nptr, nptr = nptr->next) {
2329
    if (nptr == user)
2330
      break;
2331
  }
2332
 
2333
  if (nptr) {
2334
    /* remove the user from the linked list */
2335
    if (pptr) {
2336
      pptr->next = nptr->next;
2337
    }
2338
    if (nptr->next) {
2339
      nptr->next->prev = pptr;
2340
    }
2341
  } else {
2342
    /* user didn't exit */
2343
    return NULL;
2344
  }
2345
  if (nptr == *ppuserList) /* we're the head of the list, need to change
2346
                            the head to the next user */
2347
    *ppuserList = nptr->next;
2348
  return *ppuserList;
2349
}  /* end usm_remove_user_from_list() */
2350
 
2351
 
2352
 
2353
 
2354
/* usm_free_user():  calls free() on all needed parts of struct usmUser and
2355
   the user himself.
2356
 
2357
   Note: This should *not* be called on an object in a list (IE,
2358
   remove it from the list first, and set next and prev to NULL), but
2359
   will try to reconnect the list pieces again if it is called this
2360
   way.  If called on the head of the list, the entire list will be
2361
   lost. */
2362
struct usmUser *
2363
usm_free_user(struct usmUser *user)
2364
{
2365
  if (user == NULL)
2366
    return NULL;
2367
 
2368
  SNMP_FREE(user->engineID);
2369
  SNMP_FREE(user->name);
2370
  SNMP_FREE(user->secName);
2371
  SNMP_FREE(user->cloneFrom);
2372
  SNMP_FREE(user->userPublicString);
2373
  SNMP_FREE(user->authProtocol);
2374
  SNMP_FREE(user->privProtocol);
2375
 
2376
  if (user->authKey != NULL) {
2377
    SNMP_ZERO(user->authKey, user->authKeyLen);
2378
    SNMP_FREE(user->authKey);
2379
  }
2380
 
2381
  if (user->privKey != NULL) {
2382
    SNMP_ZERO(user->privKey, user->privKeyLen);
2383
    SNMP_FREE(user->privKey);
2384
  }
2385
 
2386
 
2387
  /* FIX  Why not put this check *first?*
2388
   */
2389
  if (user->prev != NULL) { /* ack, this shouldn't happen */
2390
    user->prev->next = user->next;
2391
  }
2392
  if (user->next != NULL) {
2393
    user->next->prev = user->prev;
2394
    if (user->prev != NULL) /* ack this is really bad, because it means
2395
                              we'll loose the head of some structure tree */
2396
      DEBUGMSGTL(("usm","Severe: Asked to free the head of a usmUser tree somewhere."));
2397
  }
2398
 
2399
 
2400
  SNMP_ZERO(user, sizeof(*user));
2401
  SNMP_FREE(user);
2402
 
2403
  return NULL;  /* for convenience to returns from calling functions */
2404
 
2405
}  /* end usm_free_user() */
2406
 
2407
 
2408
 
2409
 
2410
/* take a given user and clone the security info into another */
2411
struct usmUser *
2412
usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
2413
{
2414
  /* copy the authProtocol oid row pointer */
2415
  SNMP_FREE(to->authProtocol);
2416
 
2417
  if ((to->authProtocol =
2418
       snmp_duplicate_objid(from->authProtocol,from->authProtocolLen)) != NULL)
2419
    to->authProtocolLen = from->authProtocolLen;
2420
  else
2421
    to->authProtocolLen = 0;
2422
 
2423
 
2424
  /* copy the authKey */
2425
  SNMP_FREE(to->authKey);
2426
 
2427
  if (from->authKeyLen > 0 &&
2428
      (to->authKey = (u_char *) malloc(from->authKeyLen))
2429
      != NULL) {
2430
    to->authKeyLen = from->authKeyLen;
2431
    memcpy(to->authKey, from->authKey, to->authKeyLen);
2432
  } else {
2433
    to->authKey = NULL;
2434
    to->authKeyLen = 0;
2435
  }
2436
 
2437
 
2438
  /* copy the privProtocol oid row pointer */
2439
  SNMP_FREE(to->privProtocol);
2440
 
2441
  if ((to->privProtocol =
2442
       snmp_duplicate_objid(from->privProtocol,from->privProtocolLen)) != NULL)
2443
    to->privProtocolLen = from->privProtocolLen;
2444
  else
2445
    to->privProtocolLen = 0;
2446
 
2447
  /* copy the privKey */
2448
  SNMP_FREE(to->privKey);
2449
 
2450
  if (from->privKeyLen > 0 &&
2451
      (to->privKey = (u_char *) malloc(from->privKeyLen))
2452
      != NULL) {
2453
    to->privKeyLen = from->privKeyLen;
2454
    memcpy(to->privKey, from->privKey, to->privKeyLen);
2455
  } else {
2456
    to->privKey = NULL;
2457
    to->privKeyLen = 0;
2458
  }
2459
  return to;
2460
}
2461
 
2462
/* usm_create_user(void):
2463
     create a default empty user, instantiating only the auth/priv
2464
     protocols to noAuth and noPriv OID pointers
2465
*/
2466
struct usmUser *
2467
usm_create_user(void)
2468
{
2469
  struct usmUser *newUser;
2470
 
2471
  /* create the new user */
2472
  newUser = (struct usmUser *) calloc(1,sizeof(struct usmUser));
2473
  if (newUser == NULL)
2474
    return NULL;
2475
 
2476
  /* fill the auth/priv protocols */
2477
  if ((newUser->authProtocol =
2478
       snmp_duplicate_objid(usmNoAuthProtocol,
2479
                            sizeof(usmNoAuthProtocol)/sizeof(oid))) == NULL)
2480
    return usm_free_user(newUser);
2481
  newUser->authProtocolLen = sizeof(usmNoAuthProtocol)/sizeof(oid);
2482
 
2483
  if ((newUser->privProtocol =
2484
       snmp_duplicate_objid(usmNoPrivProtocol,
2485
                            sizeof(usmNoPrivProtocol)/sizeof(oid))) == NULL)
2486
    return usm_free_user(newUser);
2487
  newUser->privProtocolLen = sizeof(usmNoPrivProtocol)/sizeof(oid);
2488
 
2489
  /* set the storage type to nonvolatile, and the status to ACTIVE */
2490
  newUser->userStorageType = ST_NONVOLATILE;
2491
  newUser->userStatus = RS_ACTIVE;
2492
  return newUser;
2493
 
2494
}  /* end usm_clone_user() */
2495
 
2496
 
2497
 
2498
 
2499
/* usm_create_initial_user(void):
2500
   creates an initial user, filled with the defaults defined in the
2501
   USM document.
2502
*/
2503
struct usmUser *
2504
usm_create_initial_user(const char *name, oid *authProtocol, size_t authProtocolLen,
2505
                        oid *privProtocol, size_t privProtocolLen)
2506
{
2507
  struct usmUser *newUser  = usm_create_user();
2508
  if (newUser == NULL)
2509
    return NULL;
2510
 
2511
  if ((newUser->name = strdup(name)) == NULL)
2512
    return usm_free_user(newUser);
2513
 
2514
  if ((newUser->secName = strdup(name)) == NULL)
2515
    return usm_free_user(newUser);
2516
 
2517
  if ((newUser->engineID = snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
2518
    return usm_free_user(newUser);
2519
 
2520
  if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid)*2)) == NULL)
2521
    return usm_free_user(newUser);
2522
  newUser->cloneFrom[0] = 0;
2523
  newUser->cloneFrom[1] = 0;
2524
  newUser->cloneFromLen = 2;
2525
 
2526
  SNMP_FREE(newUser->privProtocol);
2527
  if ((newUser->privProtocol = (oid *) malloc(privProtocolLen*sizeof(oid)))
2528
      == NULL)
2529
    return usm_free_user(newUser);
2530
  newUser->privProtocolLen = privProtocolLen;
2531
  memcpy(newUser->privProtocol, privProtocol, privProtocolLen*sizeof(oid));
2532
 
2533
  SNMP_FREE(newUser->authProtocol);
2534
  if ((newUser->authProtocol = (oid *) malloc(authProtocolLen*sizeof(oid)))
2535
      == NULL)
2536
    return usm_free_user(newUser);
2537
  newUser->authProtocolLen = authProtocolLen;
2538
  memcpy(newUser->authProtocol, authProtocol, authProtocolLen*sizeof(oid));
2539
 
2540
  newUser->userStatus = RS_ACTIVE;
2541
  newUser->userStorageType = ST_READONLY;
2542
 
2543
  return newUser;
2544
}
2545
 
2546
/* this is a callback that can store all known users based on a
2547
   previously registered application ID */
2548
int
2549
usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
2550
{
2551
  /* figure out our application name */
2552
  char *appname = (char *) clientarg;
2553
  if (appname == NULL)
2554
      appname = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE);
2555
 
2556
  /* save the user base */
2557
  usm_save_users("usmUser", appname);
2558
 
2559
  /* never fails */
2560
  return SNMPERR_SUCCESS;
2561
}
2562
 
2563
 
2564
/* usm_save_users(): saves a list of users to the persistent cache */
2565
void
2566
usm_save_users(const char *token, const char *type)
2567
{
2568
  usm_save_users_from_list(userList, token, type);
2569
}
2570
 
2571
void
2572
usm_save_users_from_list(struct usmUser *puserList, const char *token,
2573
                         const char *type)
2574
{
2575
  struct usmUser *uptr;
2576
  for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
2577
    if (uptr->userStorageType == ST_NONVOLATILE)
2578
      usm_save_user(uptr, token, type);
2579
  }
2580
}
2581
 
2582
/* usm_save_user(): saves a user to the persistent cache */
2583
void
2584
usm_save_user(struct usmUser *user, const char *token, const char *type)
2585
{
2586
  char line[4096];
2587
  char *cptr;
2588
 
2589
  memset(line, 0, sizeof(line));
2590
 
2591
  sprintf(line, "%s %d %d ", token, user->userStatus, user->userStorageType);
2592
  cptr = &line[strlen(line)]; /* the NULL */
2593
  cptr = read_config_save_octet_string(cptr, user->engineID, user->engineIDLen);
2594
  *cptr++ = ' ';
2595
  cptr = read_config_save_octet_string(cptr, (u_char *)user->name,
2596
                                       (user->name == NULL) ? 0 :
2597
                                       strlen(user->name)+1);
2598
  *cptr++ = ' ';
2599
  cptr = read_config_save_octet_string(cptr, (u_char *)user->secName,
2600
                                       (user->secName == NULL) ? 0 :
2601
                                       strlen(user->secName)+1);
2602
  *cptr++ = ' ';
2603
  cptr = read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
2604
  *cptr++ = ' ';
2605
  cptr = read_config_save_objid(cptr, user->authProtocol,
2606
                                user->authProtocolLen);
2607
  *cptr++ = ' ';
2608
  cptr = read_config_save_octet_string(cptr, user->authKey, user->authKeyLen);
2609
  *cptr++ = ' ';
2610
  cptr = read_config_save_objid(cptr, user->privProtocol,
2611
                                user->privProtocolLen);
2612
  *cptr++ = ' ';
2613
  cptr = read_config_save_octet_string(cptr, user->privKey, user->privKeyLen);
2614
  *cptr++ = ' ';
2615
  cptr = read_config_save_octet_string(cptr, user->userPublicString,
2616
                                       (user->userPublicString == NULL) ? 0 :
2617
                                       strlen((char *)user->userPublicString)+1);
2618
  read_config_store(type, line);
2619
}
2620
 
2621
/* usm_parse_user(): reads in a line containing a saved user profile
2622
   and returns a pointer to a newly created struct usmUser. */
2623
struct usmUser *
2624
usm_read_user(char *line)
2625
{
2626
  struct usmUser *user;
2627
  size_t len;
2628
 
2629
  user = usm_create_user();
2630
  if (user == NULL)
2631
    return NULL;
2632
 
2633
  user->userStatus = atoi(line);
2634
  line = skip_token(line);
2635
  user->userStorageType = atoi(line);
2636
  line = skip_token(line);
2637
  line = read_config_read_octet_string(line, &user->engineID,
2638
                                       &user->engineIDLen);
2639
 
2640
  /* set the lcd entry for this engineID to the minimum boots/time
2641
     values so that its a known engineid and won't return a report pdu.
2642
     This is mostly important when receiving v3 traps so that the usm
2643
     will at least continue processing them. */
2644
  set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
2645
 
2646
  line = read_config_read_octet_string(line, (u_char **)&user->name,
2647
                                       &len);
2648
  line = read_config_read_octet_string(line, (u_char **)&user->secName,
2649
                                       &len);
2650
  SNMP_FREE(user->cloneFrom);
2651
  user->cloneFromLen = 0;
2652
 
2653
  line = read_config_read_objid(line, &user->cloneFrom, &user->cloneFromLen);
2654
 
2655
  SNMP_FREE(user->authProtocol);
2656
  user->authProtocolLen = 0;
2657
 
2658
  line = read_config_read_objid(line, &user->authProtocol,
2659
                                &user->authProtocolLen);
2660
  line = read_config_read_octet_string(line, &user->authKey,
2661
                                       &user->authKeyLen);
2662
  SNMP_FREE(user->privProtocol);
2663
  user->privProtocolLen = 0;
2664
 
2665
  line = read_config_read_objid(line, &user->privProtocol,
2666
                                &user->privProtocolLen);
2667
  line = read_config_read_octet_string(line, &user->privKey,
2668
                                       &user->privKeyLen);
2669
  line = read_config_read_octet_string(line, &user->userPublicString,
2670
                                       &len);
2671
  return user;
2672
}
2673
 
2674
/* snmpd.conf parsing routines */
2675
void
2676
usm_parse_config_usmUser(const char *token, char *line)
2677
{
2678
  struct usmUser *uptr;
2679
 
2680
  uptr = usm_read_user(line);
2681
  usm_add_user(uptr);
2682
}
2683
 
2684
 
2685
 
2686
 
2687
/*******************************************************************-o-******
2688
 * usm_set_password
2689
 *
2690
 * Parameters:
2691
 *      *token
2692
 *      *line
2693
 *
2694
 *
2695
 * format: userSetAuthPass     secname engineIDLen engineID pass
2696
 *     or: userSetPrivPass     secname engineIDLen engineID pass
2697
 *     or: userSetAuthKey      secname engineIDLen engineID KuLen Ku
2698
 *     or: userSetPrivKey      secname engineIDLen engineID KuLen Ku
2699
 *     or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
2700
 *     or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul
2701
 *
2702
 * type is:     1=passphrase; 2=Ku; 3=Kul.
2703
 *
2704
 *
2705
 * ASSUMES  Passwords are null-terminated printable strings.
2706
 */
2707
void
2708
usm_set_password(const char *token, char *line)
2709
{
2710
  char           *cp;
2711
  char            nameBuf[SNMP_MAXBUF];
2712
  u_char         *engineID;
2713
  size_t          engineIDLen;
2714
  struct usmUser *user;
2715
 
2716
  cp = copy_word(line, nameBuf);
2717
  if (cp == NULL) {
2718
    config_perror("invalid name specifier");
2719
    return;
2720
  }
2721
 
2722
  DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
2723
  if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
2724
    /* match against all engineIDs we know about */
2725
    cp = skip_token(cp);
2726
    for(user = userList; user != NULL; user = user->next) {
2727
      if (strcmp(user->secName, nameBuf) == 0) {
2728
        usm_set_user_password(user, token, cp);
2729
      }
2730
    }
2731
  } else {
2732
    cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
2733
    if (cp == NULL) {
2734
      config_perror("invalid engineID specifier");
2735
      return;
2736
    }
2737
 
2738
    user = usm_get_user(engineID, engineIDLen, nameBuf);
2739
    if (user == NULL) {
2740
      config_perror("not a valid user/engineID pair");
2741
      return;
2742
    }
2743
    usm_set_user_password(user, token, cp);
2744
  }
2745
}
2746
 
2747
/* uses the rest of LINE to configure USER's password of type TOKEN */
2748
void
2749
usm_set_user_password(struct usmUser *user, const char *token, char *line)
2750
{
2751
  char   *cp = line;
2752
  u_char         *engineID = user->engineID;
2753
  size_t          engineIDLen = user->engineIDLen;
2754
 
2755
  u_char        **key;
2756
  size_t         *keyLen;
2757
  u_char          userKey[SNMP_MAXBUF_SMALL];
2758
  size_t          userKeyLen = SNMP_MAXBUF_SMALL;
2759
  int             type, ret;
2760
 
2761
  /*
2762
   * Retrieve the "old" key and set the key type.
2763
   */
2764
  if (strcmp(token, "userSetAuthPass") == 0) {
2765
    key = &user->authKey;
2766
    keyLen = &user->authKeyLen;
2767
    type = 0;
2768
  } else if (strcmp(token, "userSetPrivPass") == 0) {
2769
    key = &user->privKey;
2770
    keyLen = &user->privKeyLen;
2771
    type = 0;
2772
  } else if (strcmp(token, "userSetAuthKey") == 0) {
2773
    key = &user->authKey;
2774
    keyLen = &user->authKeyLen;
2775
    type = 1;
2776
  } else if (strcmp(token, "userSetPrivKey") == 0) {
2777
    key = &user->privKey;
2778
    keyLen = &user->privKeyLen;
2779
    type = 1;
2780
  } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
2781
    key = &user->authKey;
2782
    keyLen = &user->authKeyLen;
2783
    type = 2;
2784
  } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
2785
    key = &user->privKey;
2786
    keyLen = &user->privKeyLen;
2787
    type = 2;
2788
  } else {
2789
    /* no old key, or token was not recognized */
2790
    return;
2791
  }
2792
 
2793
  if (*key) {
2794
    /* (destroy and) free the old key */
2795
    memset(*key, 0, *keyLen);
2796
    free(*key);
2797
  }
2798
 
2799
  if (type == 0) {
2800
    /* convert the password into a key
2801
     */
2802
    ret = generate_Ku(  user->authProtocol, user->authProtocolLen,
2803
                        (u_char *)cp, strlen(cp),
2804
                        userKey, &userKeyLen );
2805
 
2806
    if (ret != SNMPERR_SUCCESS) {
2807
      config_perror("setting key failed (in sc_genKu())");
2808
      return;
2809
    }
2810
  } else if (type == 1) {
2811
    cp = read_config_read_octet_string(cp, (u_char **) &userKey, &userKeyLen);
2812
 
2813
    if (cp == NULL) {
2814
      config_perror("invalid user key");
2815
      return;
2816
    }
2817
  }
2818
 
2819
  if (type < 2) {
2820
    *key = (u_char *)malloc(SNMP_MAXBUF_SMALL);
2821
    *keyLen = SNMP_MAXBUF_SMALL;
2822
    ret = generate_kul( user->authProtocol, user->authProtocolLen,
2823
                        engineID, engineIDLen,
2824
                        userKey, userKeyLen,
2825
                        *key, keyLen );
2826
    if (ret != SNMPERR_SUCCESS) {
2827
      config_perror("setting key failed (in generate_kul())");
2828
      return;
2829
    }
2830
 
2831
    /* (destroy and) free the old key */
2832
    memset(userKey, 0, sizeof(userKey));
2833
 
2834
  } else {
2835
    /* the key is given, copy it in */
2836
    cp = read_config_read_octet_string(cp, key, keyLen);
2837
 
2838
    if (cp == NULL) {
2839
      config_perror("invalid localized user key");
2840
      return;
2841
    }
2842
  }
2843
}  /* end usm_set_password() */
2844
 
2845
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.