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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [snmp/] [lib/] [current/] [src/] [snmpusm.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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