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