Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / snmpusm.c
1 #ifdef BRCM_SNMP_MIB_SUPPORT
2 /*
3  * snmpusm.c
4  *
5  * Routines to manipulate a information about a "user" as
6  * defined by the SNMP-USER-BASED-SM-MIB MIB.
7  *
8  * All functions usm_set_usmStateReference_*() return 0 on success, -1
9  * otherwise.
10  *
11  * !! Tab stops set to 4 in some parts of this file. !!
12  *    (Designated on a per function.)
13  */
14
15 #include <net-snmp/net-snmp-config.h>
16
17 #include <sys/types.h>
18 #if HAVE_WINSOCK_H
19 #include <winsock.h>
20 #endif
21 #include <stdio.h>
22 #ifdef HAVE_STDLIB_H
23 #include <stdlib.h>
24 #endif
25 #if TIME_WITH_SYS_TIME
26 # ifdef WIN32
27 #  include <sys/timeb.h>
28 # else
29 #  include <sys/time.h>
30 # endif
31 # include <time.h>
32 #else
33 # if HAVE_SYS_TIME_H
34 #  include <sys/time.h>
35 # else
36 #  include <time.h>
37 # endif
38 #endif
39 #if HAVE_STRING_H
40 #include <string.h>
41 #else
42 #include <strings.h>
43 #endif
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
46 #endif
47
48 #if HAVE_DMALLOC_H
49 #include <dmalloc.h>
50 #endif
51
52 #include <net-snmp/types.h>
53 #include <net-snmp/output_api.h>
54 #include <net-snmp/config_api.h>
55 #include <net-snmp/utilities.h>
56
57 #include <net-snmp/library/asn1.h>
58 #include <net-snmp/library/snmp_api.h>
59 #include <net-snmp/library/callback.h>
60 #include <net-snmp/library/keytools.h>
61 #include <net-snmp/library/snmpv3.h>
62 #include <net-snmp/library/lcd_time.h>
63 #include <net-snmp/library/scapi.h>
64 #include <net-snmp/library/callback.h>
65 #include <net-snmp/library/snmp_secmod.h>
66 #include <net-snmp/library/snmpusm.h>
67
68 oid             usmNoAuthProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 };
69 oid             usmHMACMD5AuthProtocol[10] =
70     { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 };
71 oid             usmHMACSHA1AuthProtocol[10] =
72     { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 };
73 oid             usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
74 oid             usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
75 oid             usmAES128PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,128 };
76 oid             usmAES192PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,192 };
77 oid             usmAES256PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,256 };
78
79 static u_int    dummy_etime, dummy_eboot;       /* For ISENGINEKNOWN(). */
80
81 /*
82  * Globals.
83  */
84 static u_int    salt_integer;
85 #ifdef HAVE_AES
86 static u_int    salt_integer64_1, salt_integer64_2;
87 #endif
88         /*
89          * 1/2 of seed for the salt.   Cf. RFC2274, Sect 8.1.1.1.
90          */
91
92 static struct usmUser *noNameUser = NULL;
93 /*
94  * Local storage (LCD) of the default user list.
95  */
96 static struct usmUser *userList = NULL;
97
98 /*
99  * Prototypes
100  */
101 int
102                 usm_check_secLevel_vs_protocols(int level,
103                                                 const oid * authProtocol,
104                                                 u_int authProtocolLen,
105                                                 const oid * privProtocol,
106                                                 u_int privProtocolLen);
107 int
108                 usm_calc_offsets(size_t globalDataLen,
109                                  int secLevel, size_t secEngineIDLen,
110                                  size_t secNameLen, size_t scopedPduLen,
111                                  u_long engineboots, long engine_time,
112                                  size_t * theTotalLength,
113                                  size_t * authParamsOffset,
114                                  size_t * privParamsOffset,
115                                  size_t * dataOffset, size_t * datalen,
116                                  size_t * msgAuthParmLen,
117                                  size_t * msgPrivParmLen, size_t * otstlen,
118                                  size_t * seq_len, size_t * msgSecParmLen);
119 /*
120  * Set a given field of the secStateRef.
121  *
122  * Allocate <len> bytes for type <type> pointed to by ref-><field>.
123  * Then copy in <item> and record its length in ref-><field_len>.
124  *
125  * Return 0 on success, -1 otherwise.
126  */
127 #define MAKE_ENTRY( type, item, len, field, field_len )                 \
128 {                                                                       \
129         if (ref == NULL)                                                \
130                 return -1;                                              \
131         if (ref->field != NULL) {                                       \
132                 SNMP_ZERO(ref->field, ref->field_len);                  \
133                 SNMP_FREE(ref->field);                                  \
134         }                                                               \
135         ref->field_len = 0;                                             \
136         if (len == 0 || item == NULL) {                                 \
137                 return 0;                                               \
138         }                                                               \
139         if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
140         {                                                               \
141                 return -1;                                              \
142         }                                                               \
143                                                                         \
144         memcpy (ref->field, item, len * sizeof(type));                  \
145         ref->field_len = len;                                           \
146                                                                         \
147         return 0;                                                       \
148 }
149
150
151 struct usmStateReference *
152 usm_malloc_usmStateReference(void)
153 {
154     struct usmStateReference *retval = (struct usmStateReference *)
155         calloc(1, sizeof(struct usmStateReference));
156
157     return retval;
158 }                               /* end usm_malloc_usmStateReference() */
159
160
161 void
162 usm_free_usmStateReference(void *old)
163 {
164     struct usmStateReference *old_ref = (struct usmStateReference *) old;
165
166     if (old_ref) {
167
168         SNMP_FREE(old_ref->usr_name);
169         SNMP_FREE(old_ref->usr_engine_id);
170         SNMP_FREE(old_ref->usr_auth_protocol);
171         SNMP_FREE(old_ref->usr_priv_protocol);
172
173         if (old_ref->usr_auth_key) {
174             SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
175             SNMP_FREE(old_ref->usr_auth_key);
176         }
177         if (old_ref->usr_priv_key) {
178             SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
179             SNMP_FREE(old_ref->usr_priv_key);
180         }
181
182         SNMP_ZERO(old_ref, sizeof(*old_ref));
183         SNMP_FREE(old_ref);
184
185     }
186
187 }                               /* end usm_free_usmStateReference() */
188
189 struct usmUser *
190 usm_get_userList(void)
191 {
192     return userList;
193 }
194
195 int
196 usm_set_usmStateReference_name(struct usmStateReference *ref,
197                                char *name, size_t name_len)
198 {
199     MAKE_ENTRY(char, name, name_len, usr_name, usr_name_length);
200 }
201
202 int
203 usm_set_usmStateReference_engine_id(struct usmStateReference *ref,
204                                     u_char * engine_id,
205                                     size_t engine_id_len)
206 {
207     MAKE_ENTRY(u_char, engine_id, engine_id_len,
208                usr_engine_id, usr_engine_id_length);
209 }
210
211 int
212 usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref,
213                                         oid * auth_protocol,
214                                         size_t auth_protocol_len)
215 {
216     MAKE_ENTRY(oid, auth_protocol, auth_protocol_len,
217                usr_auth_protocol, usr_auth_protocol_length);
218 }
219
220 int
221 usm_set_usmStateReference_auth_key(struct usmStateReference *ref,
222                                    u_char * auth_key, size_t auth_key_len)
223 {
224     MAKE_ENTRY(u_char, auth_key, auth_key_len,
225                usr_auth_key, usr_auth_key_length);
226 }
227
228 int
229 usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref,
230                                         oid * priv_protocol,
231                                         size_t priv_protocol_len)
232 {
233     MAKE_ENTRY(oid, priv_protocol, priv_protocol_len,
234                usr_priv_protocol, usr_priv_protocol_length);
235 }
236
237 int
238 usm_set_usmStateReference_priv_key(struct usmStateReference *ref,
239                                    u_char * priv_key, size_t priv_key_len)
240 {
241     MAKE_ENTRY(u_char, priv_key, priv_key_len,
242                usr_priv_key, usr_priv_key_length);
243 }
244
245 int
246 usm_set_usmStateReference_sec_level(struct usmStateReference *ref,
247                                     int sec_level)
248 {
249     if (ref == NULL)
250         return -1;
251     ref->usr_sec_level = sec_level;
252     return 0;
253 }
254
255
256
257 #ifdef SNMP_TESTING_CODE
258 /*******************************************************************-o-******
259  * emergency_print
260  *
261  * Parameters:
262  *      *field
263  *       length
264  *      
265  *      This is a print routine that is solely included so that it can be
266  *      used in gdb.  Don't use it as a function, it will be pulled before
267  *      a real release of the code.
268  *
269  *      tab stop 4
270  *
271  *      XXX fflush() only works on FreeBSD; core dumps on Sun OS's
272  */
273 void
274 emergency_print(u_char * field, u_int length)
275 {
276     int             iindex;
277     int             start = 0;
278     int             stop = 25;
279
280     while (start < stop) {
281         for (iindex = start; iindex < stop; iindex++)
282             printf("%02X ", field[iindex]);
283
284         printf("\n");
285         start = stop;
286         stop = stop + 25 < length ? stop + 25 : length;
287     }
288     fflush(0);
289
290 }                               /* end emergency_print() */
291 #endif                          /* SNMP_TESTING_CODE */
292
293
294 /*******************************************************************-o-******
295  * asn_predict_int_length
296  *
297  * Parameters:
298  *      type    (UNUSED)
299  *      number
300  *      len
301  *      
302  * Returns:
303  *      Number of bytes necessary to store the ASN.1 encoded value of 'number'.
304  *
305  *
306  *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
307  *      use to encode a particular integer value.
308  *
309  *      Returns the length of the integer -- NOT THE HEADER!
310  *
311  *      Do this the same way as asn_build_int()...
312  */
313 int
314 asn_predict_int_length(int type, long number, size_t len)
315 {
316     register u_long mask;
317
318
319     if (len != sizeof(long))
320         return -1;
321
322     mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
323     /*
324      * mask is 0xFF800000 on a big-endian machine 
325      */
326
327     while ((((number & mask) == 0) || ((number & mask) == mask))
328            && len > 1) {
329         len--;
330         number <<= 8;
331     }
332
333     return len;
334
335 }                               /* end asn_predict_length() */
336
337
338
339
340 /*******************************************************************-o-******
341  * asn_predict_length
342  *
343  * Parameters:
344  *       type
345  *      *ptr
346  *       u_char_len
347  *      
348  * Returns:
349  *      Length in bytes:        1 + <n> + <u_char_len>, where
350  *
351  *              1               For the ASN.1 type.
352  *              <n>             # of bytes to store length of data.
353  *              <u_char_len>    Length of data associated with ASN.1 type.
354  *
355  *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
356  *      use to encode a particular integer value.  This is as broken as the
357  *      currently used encoder.
358  *
359  * XXX  How is <n> chosen, exactly??
360  */
361 int
362 asn_predict_length(int type, u_char * ptr, size_t u_char_len)
363 {
364
365     if (type & ASN_SEQUENCE)
366         return 1 + 3 + u_char_len;
367
368     if (type & ASN_INTEGER) {
369         u_long          value;
370         memcpy(&value, ptr, u_char_len);
371         u_char_len = asn_predict_int_length(type, value, u_char_len);
372     }
373
374     if (u_char_len < 0x80)
375         return 1 + 1 + u_char_len;
376     else if (u_char_len < 0xFF)
377         return 1 + 2 + u_char_len;
378     else
379         return 1 + 3 + u_char_len;
380
381 }                               /* end asn_predict_length() */
382
383
384
385
386 /*******************************************************************-o-******
387  * usm_calc_offsets
388  *
389  * Parameters:
390  *      (See list below...)
391  *      
392  * Returns:
393  *      0       On success,
394  *      -1      Otherwise.
395  *
396  *
397  *      This routine calculates the offsets into an outgoing message buffer
398  *      for the necessary values.  The outgoing buffer will generically
399  *      look like this:
400  *
401  *      SNMPv3 Message
402  *      SEQ len[11]
403  *              INT len version
404  *      Header
405  *              SEQ len
406  *                      INT len MsgID
407  *                      INT len msgMaxSize
408  *                      OST len msgFlags (OST = OCTET STRING)
409  *                      INT len msgSecurityModel
410  *      MsgSecurityParameters
411  *              [1] OST len[2]
412  *                      SEQ len[3]
413  *                              OST len msgAuthoritativeEngineID
414  *                              INT len msgAuthoritativeEngineBoots
415  *                              INT len msgAuthoritativeEngineTime
416  *                              OST len msgUserName
417  *                              OST len[4] [5] msgAuthenticationParameters
418  *                              OST len[6] [7] msgPrivacyParameters
419  *      MsgData
420  *              [8] OST len[9] [10] encryptedPDU
421  *              or
422  *              [8,10] SEQUENCE len[9] scopedPDU
423  *      [12]
424  *
425  *      The bracketed points will be needed to be identified ([x] is an index
426  *      value, len[x] means a length value).  Here is a semantic guide to them:
427  *
428  *      [1] = globalDataLen (input)
429  *      [2] = otstlen
430  *      [3] = seq_len
431  *      [4] = msgAuthParmLen (may be 0 or 12)
432  *      [5] = authParamsOffset
433  *      [6] = msgPrivParmLen (may be 0 or 8)
434  *      [7] = privParamsOffset
435  *      [8] = globalDataLen + msgSecParmLen
436  *      [9] = datalen
437  *      [10] = dataOffset
438  *      [11] = theTotalLength - the length of the header itself
439  *      [12] = theTotalLength
440  */
441 int
442 usm_calc_offsets(size_t globalDataLen,  /* SNMPv3Message + HeaderData */
443                  int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen,   /* An BER encoded sequence. */
444                  u_long engineboots,    /* XXX (asn1.c works in long, not int.) */
445                  long engine_time,      /* XXX (asn1.c works in long, not int.) */
446                  size_t * theTotalLength,       /* globalDataLen + msgSecurityP. + msgData */
447                  size_t * authParamsOffset,     /* Distance to auth bytes.                 */
448                  size_t * privParamsOffset,     /* Distance to priv bytes.                 */
449                  size_t * dataOffset,   /* Distance to scopedPdu SEQ  -or-  the
450                                          *   crypted (data) portion of msgData.    */
451                  size_t * datalen,      /* Size of msgData OCTET STRING encoding.  */
452                  size_t * msgAuthParmLen,       /* Size of msgAuthenticationParameters.    */
453                  size_t * msgPrivParmLen,       /* Size of msgPrivacyParameters.           */
454                  size_t * otstlen,      /* Size of msgSecurityP. O.S. encoding.    */
455                  size_t * seq_len,      /* Size of msgSecurityP. SEQ data.         */
456                  size_t * msgSecParmLen)
457 {                               /* Size of msgSecurityP. SEQ.              */
458     int             engIDlen,   /* Sizes of OCTET STRING and SEQ encodings */
459                     engBtlen,   /*   for fields within                     */
460                     engTmlen,   /*   msgSecurityParameters portion of      */
461                     namelen,    /*   SNMPv3Message.                        */
462                     authlen, privlen;
463
464     /*
465      * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
466      * If doing encryption,     msgPrivParmLen = 8  else msgPrivParmLen = 0.
467      */
468     *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
469                        || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0;
470
471     *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0;
472
473
474     /*
475      * Calculate lengths.
476      */
477     if ((engIDlen = asn_predict_length(ASN_OCTET_STR,
478                                        0, secEngineIDLen)) == -1) {
479         return -1;
480     }
481
482     if ((engBtlen = asn_predict_length(ASN_INTEGER,
483                                        (u_char *) & engineboots,
484                                        sizeof(long))) == -1) {
485         return -1;
486     }
487
488     if ((engTmlen = asn_predict_length(ASN_INTEGER,
489                                        (u_char *) & engine_time,
490                                        sizeof(long))) == -1) {
491         return -1;
492     }
493
494     if ((namelen = asn_predict_length(ASN_OCTET_STR, 0, secNameLen)) == -1) {
495         return -1;
496     }
497
498     if ((authlen = asn_predict_length(ASN_OCTET_STR,
499                                       0, *msgAuthParmLen)) == -1) {
500         return -1;
501     }
502
503     if ((privlen = asn_predict_length(ASN_OCTET_STR,
504                                       0, *msgPrivParmLen)) == -1) {
505         return -1;
506     }
507
508     *seq_len =
509         engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
510
511     if ((*otstlen = asn_predict_length(ASN_SEQUENCE, 0, *seq_len)) == -1) {
512         return -1;
513     }
514
515     if ((*msgSecParmLen = asn_predict_length(ASN_OCTET_STR,
516                                              0, *otstlen)) == -1) {
517         return -1;
518     }
519
520     *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len)
521         + engIDlen + engBtlen + engTmlen + namelen
522         + (authlen - *msgAuthParmLen);
523
524     *privParamsOffset = *authParamsOffset + *msgAuthParmLen
525         + (privlen - *msgPrivParmLen);
526
527
528     /*
529      * Compute the size of the plaintext.  Round up to account for cipher
530      * block size, if necessary.
531      *
532      * XXX  This is hardwired for 1DES... If scopedPduLen is already
533      *      a multiple of 8, then *add* 8 more; otherwise, round up
534      *      to the next multiple of 8.
535      *
536      * FIX  Calculation of encrypted portion of msgData and consequent
537      *      setting and sanity checking of theTotalLength, et al. should
538      *      occur *after* encryption has taken place.
539      */
540     if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
541         scopedPduLen = ROUNDUP8(scopedPduLen);
542
543         if ((*datalen =
544              asn_predict_length(ASN_OCTET_STR, 0, scopedPduLen)) == -1) {
545             return -1;
546         }
547     } else {
548         *datalen = scopedPduLen;
549     }
550
551     *dataOffset = globalDataLen + *msgSecParmLen +
552         (*datalen - scopedPduLen);
553     *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
554
555     return 0;
556
557 }                               /* end usm_calc_offsets() */
558
559
560
561
562
563 /*******************************************************************-o-******
564  * usm_set_salt
565  *
566  * Parameters:
567  *      *iv               (O)   Buffer to contain IV.
568  *      *iv_length        (O)   Length of iv.
569  *      *priv_salt        (I)   Salt portion of private key.
570  *       priv_salt_length (I)   Length of priv_salt.
571  *      *msgSalt          (I/O) Pointer salt portion of outgoing msg buffer.
572  *      
573  * Returns:
574  *      0       On success,
575  *      -1      Otherwise.
576  *
577  *      Determine the initialization vector for the DES-CBC encryption.
578  *      (Cf. RFC 2274, 8.1.1.1.)
579  *
580  *      iv is defined as the concatenation of engineBoots and the
581  *              salt integer.
582  *      The salt integer is incremented.
583  *      The resulting salt is copied into the msgSalt buffer.
584  *      The result of the concatenation is then XORed with the salt
585  *              portion of the private key (last 8 bytes).
586  *      The IV result is returned individually for further use.
587  */
588 int
589 usm_set_salt(u_char * iv,
590              size_t * iv_length,
591              u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
592 {
593     size_t          propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
594     int             net_boots;
595     int             net_salt_int;
596     /*
597      * net_* should be encoded in network byte order.  XXX  Why?
598      */
599     int             iindex;
600
601
602     /*
603      * Sanity check.
604      */
605     if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt)
606         || (priv_salt_length < propersize_salt)) {
607         return -1;
608     }
609
610
611     net_boots = htonl(snmpv3_local_snmpEngineBoots());
612     net_salt_int = htonl(salt_integer);
613
614     salt_integer += 1;
615
616     memcpy(iv, &net_boots, propersize_salt / 2);
617     memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2);
618
619     if (msgSalt)
620         memcpy(msgSalt, iv, propersize_salt);
621
622
623     /*
624      * Turn the salt into an IV: XOR <boots, salt_int> with salt
625      * portion of priv_key.
626      */
627     for (iindex = 0; iindex < (int) propersize_salt; iindex++)
628         iv[iindex] ^= priv_salt[iindex];
629
630
631     return 0;
632
633 }                               /* end usm_set_salt() */
634
635 #ifdef HAVE_AES
636 /*******************************************************************-o-******
637  * usm_set_aes_iv
638  *
639  * Parameters:
640  *      *iv               (O)   Buffer to contain IV.
641  *      *iv_length        (O)   Length of iv.
642  *      net_boots         (I)   the network byte order of the authEng boots val
643  *      net_time         (I)   the network byte order of the authEng time val
644  *      *salt             (O)   A buffer for the outgoing salt (= 8 bytes of iv)
645  *      
646  * Returns:
647  *      0       On success,
648  *      -1      Otherwise.
649  *
650  *      Determine the initialization vector for AES encryption.
651  *      (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
652  *
653  *      iv is defined as the concatenation of engineBoots, engineTime
654         and a 64 bit salt-integer.
655  *      The 64 bit salt integer is incremented.
656  *      The resulting salt is copied into the salt buffer.
657  *      The IV result is returned individually for further use.
658  */
659 int
660 usm_set_aes_iv(u_char * iv,
661                size_t * iv_length,
662                u_int net_boots,
663                u_int net_time,
664                u_char * salt)
665 {
666     /*
667      * net_* should be encoded in network byte order.
668      */
669     int             net_salt_int1, net_salt_int2;
670 #define PROPER_AES_IV_SIZE 64
671
672     /*
673      * Sanity check.
674      */
675     if (!iv || !iv_length) {
676         return -1;
677     }
678
679     net_salt_int1 = htonl(salt_integer64_1);
680     net_salt_int2 = htonl(salt_integer64_2);
681
682     if ((salt_integer64_2 += 1) == 0)
683         salt_integer64_2 += 1;
684     
685     /* XXX: warning: hard coded proper lengths */
686     memcpy(iv, &net_boots, 4);
687     memcpy(iv+4, &net_time, 4);
688     memcpy(iv+8, &net_salt_int1, 4);
689     memcpy(iv+12, &net_salt_int2, 4);
690
691     memcpy(salt, iv+8, 8); /* only copy the needed portion */
692     return 0;
693 }                               /* end usm_set_salt() */
694 #endif /* HAVE_AES */
695
696 int
697 usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
698 {
699     if (!parms)
700         return SNMPERR_GENERR;
701
702     return usm_generate_out_msg(parms->msgProcModel,
703                                 parms->globalData, parms->globalDataLen,
704                                 parms->maxMsgSize, parms->secModel,
705                                 parms->secEngineID, parms->secEngineIDLen,
706                                 parms->secName, parms->secNameLen,
707                                 parms->secLevel,
708                                 parms->scopedPdu, parms->scopedPduLen,
709                                 parms->secStateRef,
710                                 parms->secParams, parms->secParamsLen,
711                                 parms->wholeMsg, parms->wholeMsgLen);
712 }
713
714 /*******************************************************************-o-******
715  * usm_generate_out_msg
716  *
717  * Parameters:
718  *      (See list below...)
719  *      
720  * Returns:
721  *      SNMPERR_SUCCESS                 On success.
722  *      SNMPERR_USM_AUTHENTICATIONFAILURE
723  *      SNMPERR_USM_ENCRYPTIONERROR
724  *      SNMPERR_USM_GENERICERROR
725  *      SNMPERR_USM_UNKNOWNSECURITYNAME
726  *      SNMPERR_USM_GENERICERROR
727  *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
728  *      
729  *
730  * Generates an outgoing message.
731  *
732  * XXX  Beware of misnomers!
733  */
734 int
735 usm_generate_out_msg(int msgProcModel,  /* (UNUSED) */
736                      u_char * globalData,       /* IN */
737                      /*
738                       * Pointer to msg header data will point to the beginning
739                       * * of the entire packet buffer to be transmitted on wire,
740                       * * memory will be contiguous with secParams, typically
741                       * * this pointer will be passed back as beginning of
742                       * * wholeMsg below.  asn seq. length is updated w/ new length.
743                       * *
744                       * * While this points to a buffer that should be big enough
745                       * * for the whole message, only the first two parts
746                       * * of the message are completed, namely SNMPv3Message and
747                       * * HeaderData.  globalDataLen (next parameter) represents
748                       * * the length of these two completed parts.
749                       */
750                      size_t globalDataLen,      /* IN - Length of msg header data.      */
751                      int maxMsgSize,    /* (UNUSED) */
752                      int secModel,      /* (UNUSED) */
753                      u_char * secEngineID,      /* IN - Pointer snmpEngineID.           */
754                      size_t secEngineIDLen,     /* IN - SnmpEngineID length.            */
755                      char *secName,     /* IN - Pointer to securityName.        */
756                      size_t secNameLen, /* IN - SecurityName length.            */
757                      int secLevel,      /* IN - AuthNoPriv, authPriv etc.       */
758                      u_char * scopedPdu,        /* IN */
759                      /*
760                       * Pointer to scopedPdu will be encrypted by USM if needed
761                       * * and written to packet buffer immediately following
762                       * * securityParameters, entire msg will be authenticated by
763                       * * USM if needed.
764                       */
765                      size_t scopedPduLen,       /* IN - scopedPdu length. */
766                      void *secStateRef, /* IN */
767                      /*
768                       * secStateRef, pointer to cached info provided only for
769                       * * Response, otherwise NULL.
770                       */
771                      u_char * secParams,        /* OUT */
772                      /*
773                       * BER encoded securityParameters pointer to offset within
774                       * * packet buffer where secParams should be written, the
775                       * * entire BER encoded OCTET STRING (including header) is
776                       * * written here by USM secParams = globalData +
777                       * * globalDataLen.
778                       */
779                      size_t * secParamsLen,     /* IN/OUT - Len available, len returned. */
780                      u_char ** wholeMsg,        /* OUT */
781                      /*
782                       * Complete authenticated/encrypted message - typically
783                       * * the pointer to start of packet buffer provided in
784                       * * globalData is returned here, could also be a separate
785                       * * buffer.
786                       */
787                      size_t * wholeMsgLen)
788 {                               /* IN/OUT - Len available, len returned. */
789     size_t          otstlen;
790     size_t          seq_len;
791     size_t          msgAuthParmLen;
792     size_t          msgPrivParmLen;
793     size_t          msgSecParmLen;
794     size_t          authParamsOffset;
795     size_t          privParamsOffset;
796     size_t          datalen;
797     size_t          dataOffset;
798     size_t          theTotalLength;
799
800     u_char         *ptr;
801     size_t          ptr_len;
802     size_t          remaining;
803     size_t          offSet;
804     u_int           boots_uint;
805     u_int           time_uint;
806     long            boots_long;
807     long            time_long;
808
809     /*
810      * Indirection because secStateRef values override parameters.
811      * 
812      * None of these are to be free'd - they are either pointing to
813      * what's in the secStateRef or to something either in the
814      * actual prarmeter list or the user list.
815      */
816
817     char           *theName = NULL;
818     u_int           theNameLength = 0;
819     u_char         *theEngineID = NULL;
820     u_int           theEngineIDLength = 0;
821     u_char         *theAuthKey = NULL;
822     u_int           theAuthKeyLength = 0;
823     const oid      *theAuthProtocol = NULL;
824     u_int           theAuthProtocolLength = 0;
825     u_char         *thePrivKey = NULL;
826     u_int           thePrivKeyLength = 0;
827     const oid      *thePrivProtocol = NULL;
828     u_int           thePrivProtocolLength = 0;
829     int             theSecLevel = 0;    /* No defined const for bad
830                                          * value (other then err).
831                                          */
832
833     DEBUGMSGTL(("usm", "USM processing has begun.\n"));
834
835     if (secStateRef != NULL) {
836         /*
837          * To hush the compiler for now.  XXX 
838          */
839         struct usmStateReference *ref
840             = (struct usmStateReference *) secStateRef;
841
842         theName = ref->usr_name;
843         theNameLength = ref->usr_name_length;
844         theEngineID = ref->usr_engine_id;
845         theEngineIDLength = ref->usr_engine_id_length;
846
847         if (!theEngineIDLength) {
848             theEngineID = secEngineID;
849             theEngineIDLength = secEngineIDLen;
850         }
851
852         theAuthProtocol = ref->usr_auth_protocol;
853         theAuthProtocolLength = ref->usr_auth_protocol_length;
854         theAuthKey = ref->usr_auth_key;
855         theAuthKeyLength = ref->usr_auth_key_length;
856         thePrivProtocol = ref->usr_priv_protocol;
857         thePrivProtocolLength = ref->usr_priv_protocol_length;
858         thePrivKey = ref->usr_priv_key;
859         thePrivKeyLength = ref->usr_priv_key_length;
860         theSecLevel = ref->usr_sec_level;
861     }
862
863     /*
864      * Identify the user record.
865      */
866     else {
867         struct usmUser *user;
868
869         /*
870          * we do allow an unknown user name for
871          * unauthenticated requests. 
872          */
873         if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
874             == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
875             DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
876             usm_free_usmStateReference(secStateRef);
877             return SNMPERR_USM_UNKNOWNSECURITYNAME;
878         }
879
880         theName = secName;
881         theNameLength = secNameLen;
882         theEngineID = secEngineID;
883         theSecLevel = secLevel;
884         theEngineIDLength = secEngineIDLen;
885         if (user) {
886             theAuthProtocol = user->authProtocol;
887             theAuthProtocolLength = user->authProtocolLen;
888             theAuthKey = user->authKey;
889             theAuthKeyLength = user->authKeyLen;
890             thePrivProtocol = user->privProtocol;
891             thePrivProtocolLength = user->privProtocolLen;
892             thePrivKey = user->privKey;
893             thePrivKeyLength = user->privKeyLen;
894         } else {
895             /*
896              * unknown users can not do authentication (obviously) 
897              */
898             theAuthProtocol = usmNoAuthProtocol;
899             theAuthProtocolLength =
900                 sizeof(usmNoAuthProtocol) / sizeof(oid);
901             theAuthKey = NULL;
902             theAuthKeyLength = 0;
903             thePrivProtocol = usmNoPrivProtocol;
904             thePrivProtocolLength =
905                 sizeof(usmNoPrivProtocol) / sizeof(oid);
906             thePrivKey = NULL;
907             thePrivKeyLength = 0;
908         }
909     }                           /* endif -- secStateRef==NULL */
910
911
912     /*
913      * From here to the end of the function, avoid reference to
914      * secName, secEngineID, secLevel, and associated lengths.
915      */
916
917
918     /*
919      * Check to see if the user can use the requested sec services.
920      */
921     if (usm_check_secLevel_vs_protocols(theSecLevel,
922                                         theAuthProtocol,
923                                         theAuthProtocolLength,
924                                         thePrivProtocol,
925                                         thePrivProtocolLength) == 1) {
926         DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
927                     theSecLevel));
928         usm_free_usmStateReference(secStateRef);
929         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
930     }
931
932
933     /*
934      * Retrieve the engine information.
935      *
936      * XXX  No error is declared in the EoP when sending messages to
937      *      unknown engines, processing continues w/ boots/time == (0,0).
938      */
939     if (get_enginetime(theEngineID, theEngineIDLength,
940                        &boots_uint, &time_uint, FALSE) == -1) {
941         DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
942     }
943
944     boots_long = boots_uint;
945     time_long = time_uint;
946
947
948     /*
949      * Set up the Offsets.
950      */
951     if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength,
952                          theNameLength, scopedPduLen, boots_long,
953                          time_long, &theTotalLength, &authParamsOffset,
954                          &privParamsOffset, &dataOffset, &datalen,
955                          &msgAuthParmLen, &msgPrivParmLen, &otstlen,
956                          &seq_len, &msgSecParmLen) == -1) {
957         DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
958         usm_free_usmStateReference(secStateRef);
959         return SNMPERR_USM_GENERICERROR;
960     }
961
962     /*
963      * So, we have the offsets for the three parts that need to be
964      * determined, and an overall length.  Now we need to make
965      * sure all of this would fit in the outgoing buffer, and
966      * whether or not we need to make a new buffer, etc.
967      */
968
969
970     /*
971      * Set wholeMsg as a pointer to globalData.  Sanity check for
972      * the proper size.
973      * 
974      * Mark workspace in the message with bytes of all 1's to make it
975      * easier to find mistakes in raw message dumps.
976      */
977     ptr = *wholeMsg = globalData;
978     if (theTotalLength > *wholeMsgLen) {
979         DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
980         usm_free_usmStateReference(secStateRef);
981         return SNMPERR_USM_GENERICERROR;
982     }
983
984     ptr_len = *wholeMsgLen = theTotalLength;
985
986 #ifdef SNMP_TESTING_CODE
987     memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);
988 #endif                          /* SNMP_TESTING_CODE */
989
990     /*
991      * Do the encryption.
992      */
993     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
994         size_t          encrypted_length = theTotalLength - dataOffset;
995         size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
996         u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
997
998         /*
999          * XXX  Hardwired to seek into a 1DES private key!
1000          */
1001 #ifdef HAVE_AES
1002         if (ISTRANSFORM(thePrivProtocol, AES128Priv) &&
1003             ISTRANSFORM(thePrivProtocol, AES192Priv) &&
1004             ISTRANSFORM(thePrivProtocol, AES256Priv)) {
1005             if (!thePrivKey ||
1006                 usm_set_aes_iv(salt, &salt_length,
1007                                htonl(boots_uint), htonl(time_uint),
1008                                &ptr[privParamsOffset]) == -1) {
1009                 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
1010                 usm_free_usmStateReference(secStateRef);
1011                 return SNMPERR_USM_GENERICERROR;
1012             }
1013         } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
1014 #endif
1015         if (!thePrivKey ||
1016             (usm_set_salt(salt, &salt_length,
1017                           thePrivKey + 8, thePrivKeyLength - 8,
1018                           &ptr[privParamsOffset])
1019              == -1)) {
1020             DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
1021             usm_free_usmStateReference(secStateRef);
1022             return SNMPERR_USM_GENERICERROR;
1023         }
1024 #ifdef HAVE_AES
1025         }
1026 #endif
1027
1028         if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
1029                        thePrivKey, thePrivKeyLength,
1030                        salt, salt_length,
1031                        scopedPdu, scopedPduLen,
1032                        &ptr[dataOffset], &encrypted_length)
1033             != SNMP_ERR_NOERROR) {
1034             DEBUGMSGTL(("usm", "DES-CBC error.\n"));
1035             usm_free_usmStateReference(secStateRef);
1036             return SNMPERR_USM_ENCRYPTIONERROR;
1037         }
1038 #ifdef SNMP_TESTING_CODE
1039         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1040             dump_chunk("usm/dump", "This data was encrypted:",
1041                        scopedPdu, scopedPduLen);
1042             dump_chunk("usm/dump", "salt + Encrypted form:",
1043                        salt, salt_length);
1044             dump_chunk("usm/dump", NULL,
1045                        &ptr[dataOffset], encrypted_length);
1046             dump_chunk("usm/dump", "*wholeMsg:",
1047                        *wholeMsg, theTotalLength);
1048         }
1049 #endif
1050
1051
1052         ptr = *wholeMsg;
1053         ptr_len = *wholeMsgLen = theTotalLength;
1054
1055
1056         /*
1057          * XXX  Sanity check for salt length should be moved up
1058          *      under usm_calc_offsets() or tossed.
1059          */
1060         if ((encrypted_length != (theTotalLength - dataOffset))
1061             || (salt_length != msgPrivParmLen)) {
1062             DEBUGMSGTL(("usm", "DES-CBC length error.\n"));
1063             usm_free_usmStateReference(secStateRef);
1064             return SNMPERR_USM_ENCRYPTIONERROR;
1065         }
1066
1067         DEBUGMSGTL(("usm", "Encryption successful.\n"));
1068     }
1069
1070     /*
1071      * No encryption for you!
1072      */
1073     else {
1074         memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen);
1075     }
1076
1077
1078
1079     /*
1080      * Start filling in the other fields (in prep for authentication).
1081      * 
1082      * offSet is an octet string header, which is different from all
1083      * the other headers.
1084      */
1085     remaining = ptr_len - globalDataLen;
1086
1087     offSet = ptr_len - remaining;
1088     asn_build_header(&ptr[offSet], &remaining,
1089                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1090                                ASN_OCTET_STR), otstlen);
1091
1092     offSet = ptr_len - remaining;
1093     asn_build_sequence(&ptr[offSet], &remaining,
1094                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
1095
1096     offSet = ptr_len - remaining;
1097     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
1098     asn_build_string(&ptr[offSet], &remaining,
1099                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1100                                ASN_OCTET_STR), theEngineID,
1101                      theEngineIDLength);
1102     DEBUGINDENTLESS();
1103
1104     offSet = ptr_len - remaining;
1105     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
1106     asn_build_int(&ptr[offSet], &remaining,
1107                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1108                   &boots_long, sizeof(long));
1109     DEBUGINDENTLESS();
1110
1111     offSet = ptr_len - remaining;
1112     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
1113     asn_build_int(&ptr[offSet], &remaining,
1114                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1115                   &time_long, sizeof(long));
1116     DEBUGINDENTLESS();
1117
1118     offSet = ptr_len - remaining;
1119     DEBUGDUMPHEADER("send", "msgUserName");
1120     asn_build_string(&ptr[offSet], &remaining,
1121                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1122                                ASN_OCTET_STR), (u_char *) theName,
1123                      theNameLength);
1124     DEBUGINDENTLESS();
1125
1126
1127     /*
1128      * Note: if there is no authentication being done,
1129      * msgAuthParmLen is 0, and there is no effect (other than
1130      * inserting a zero-length header) of the following
1131      * statements.
1132      */
1133
1134     offSet = ptr_len - remaining;
1135     asn_build_header(&ptr[offSet],
1136                      &remaining,
1137                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1138                                ASN_OCTET_STR), msgAuthParmLen);
1139
1140     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1141         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1142         offSet = ptr_len - remaining;
1143         memset(&ptr[offSet], 0, msgAuthParmLen);
1144     }
1145
1146     remaining -= msgAuthParmLen;
1147
1148
1149     /*
1150      * Note: if there is no encryption being done, msgPrivParmLen
1151      * is 0, and there is no effect (other than inserting a
1152      * zero-length header) of the following statements.
1153      */
1154
1155     offSet = ptr_len - remaining;
1156     asn_build_header(&ptr[offSet],
1157                      &remaining,
1158                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1159                                ASN_OCTET_STR), msgPrivParmLen);
1160
1161     remaining -= msgPrivParmLen;        /* Skipping the IV already there. */
1162
1163
1164     /*
1165      * For privacy, need to add the octet string header for it.
1166      */
1167     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1168         offSet = ptr_len - remaining;
1169         asn_build_header(&ptr[offSet],
1170                          &remaining,
1171                          (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1172                                    ASN_OCTET_STR),
1173                          theTotalLength - dataOffset);
1174     }
1175
1176
1177     /*
1178      * Adjust overall length and store it as the first SEQ length
1179      * of the SNMPv3Message.
1180      *
1181      * FIX  4 is a magic number!
1182      */
1183     remaining = theTotalLength;
1184     asn_build_sequence(ptr, &remaining,
1185                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1186                        theTotalLength - 4);
1187
1188
1189     /*
1190      * Now, time to consider / do authentication.
1191      */
1192     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1193         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1194         size_t          temp_sig_len = msgAuthParmLen;
1195         u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
1196
1197         if (temp_sig == NULL) {
1198             DEBUGMSGTL(("usm", "Out of memory.\n"));
1199             usm_free_usmStateReference(secStateRef);
1200             return SNMPERR_USM_GENERICERROR;
1201         }
1202
1203         if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
1204                                    theAuthKey, theAuthKeyLength,
1205                                    ptr, ptr_len, temp_sig, &temp_sig_len)
1206             != SNMP_ERR_NOERROR) {
1207             /*
1208              * FIX temp_sig_len defined?!
1209              */
1210             SNMP_ZERO(temp_sig, temp_sig_len);
1211             SNMP_FREE(temp_sig);
1212             DEBUGMSGTL(("usm", "Signing failed.\n"));
1213             usm_free_usmStateReference(secStateRef);
1214             return SNMPERR_USM_AUTHENTICATIONFAILURE;
1215         }
1216
1217         if (temp_sig_len != msgAuthParmLen) {
1218             SNMP_ZERO(temp_sig, temp_sig_len);
1219             SNMP_FREE(temp_sig);
1220             DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
1221             usm_free_usmStateReference(secStateRef);
1222             return SNMPERR_USM_AUTHENTICATIONFAILURE;
1223         }
1224
1225         memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
1226
1227         SNMP_ZERO(temp_sig, temp_sig_len);
1228         SNMP_FREE(temp_sig);
1229
1230     }
1231
1232     /*
1233      * endif -- create keyed hash 
1234      */
1235     usm_free_usmStateReference(secStateRef);
1236
1237     DEBUGMSGTL(("usm", "USM processing completed.\n"));
1238
1239     return SNMPERR_SUCCESS;
1240
1241 }                               /* end usm_generate_out_msg() */
1242
1243 #ifdef USE_REVERSE_ASNENCODING
1244 int
1245 usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
1246 {
1247     if (!parms)
1248         return SNMPERR_GENERR;
1249
1250     return usm_rgenerate_out_msg(parms->msgProcModel,
1251                                  parms->globalData, parms->globalDataLen,
1252                                  parms->maxMsgSize, parms->secModel,
1253                                  parms->secEngineID, parms->secEngineIDLen,
1254                                  parms->secName, parms->secNameLen,
1255                                  parms->secLevel,
1256                                  parms->scopedPdu, parms->scopedPduLen,
1257                                  parms->secStateRef,
1258                                  parms->wholeMsg, parms->wholeMsgLen,
1259                                  parms->wholeMsgOffset);
1260 }
1261
1262 int
1263 usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
1264                       u_char * globalData,      /* IN */
1265                       /*
1266                        * points at the msgGlobalData, which is of length given by next 
1267                        * parameter.  
1268                        */
1269                       size_t globalDataLen,     /* IN - Length of msg header data.      */
1270                       int maxMsgSize,   /* (UNUSED) */
1271                       int secModel,     /* (UNUSED) */
1272                       u_char * secEngineID,     /* IN - Pointer snmpEngineID.           */
1273                       size_t secEngineIDLen,    /* IN - SnmpEngineID length.            */
1274                       char *secName,    /* IN - Pointer to securityName.        */
1275                       size_t secNameLen,        /* IN - SecurityName length.            */
1276                       int secLevel,     /* IN - AuthNoPriv, authPriv etc.       */
1277                       u_char * scopedPdu,       /* IN */
1278                       /*
1279                        * Pointer to scopedPdu will be encrypted by USM if needed
1280                        * * and written to packet buffer immediately following
1281                        * * securityParameters, entire msg will be authenticated by
1282                        * * USM if needed.
1283                        */
1284                       size_t scopedPduLen,      /* IN - scopedPdu length. */
1285                       void *secStateRef,        /* IN */
1286                       /*
1287                        * secStateRef, pointer to cached info provided only for
1288                        * * Response, otherwise NULL.
1289                        */
1290                       u_char ** wholeMsg,       /*  IN/OUT  */
1291                       /*
1292                        * Points at the pointer to the packet buffer, which might get extended
1293                        * if necessary via realloc().  
1294                        */
1295                       size_t * wholeMsgLen,     /*  IN/OUT  */
1296                       /*
1297                        * Length of the entire packet buffer, **not** the length of the
1298                        * packet.  
1299                        */
1300                       size_t * offset   /*  IN/OUT  */
1301                       /*
1302                        * Offset from the end of the packet buffer to the start of the packet,
1303                        * also known as the packet length.  
1304                        */
1305     )
1306 {
1307     size_t          msgAuthParmLen = 0;
1308 #ifdef SNMP_TESTING_CODE
1309     size_t          theTotalLength;
1310 #endif
1311
1312     u_int           boots_uint;
1313     u_int           time_uint;
1314     long            boots_long;
1315     long            time_long;
1316
1317     /*
1318      * Indirection because secStateRef values override parameters.
1319      * 
1320      * None of these are to be free'd - they are either pointing to
1321      * what's in the secStateRef or to something either in the
1322      * actual prarmeter list or the user list.
1323      */
1324
1325     char           *theName = NULL;
1326     u_int           theNameLength = 0;
1327     u_char         *theEngineID = NULL;
1328     u_int           theEngineIDLength = 0;
1329     u_char         *theAuthKey = NULL;
1330     u_int           theAuthKeyLength = 0;
1331     const oid      *theAuthProtocol = NULL;
1332     u_int           theAuthProtocolLength = 0;
1333     u_char         *thePrivKey = NULL;
1334     u_int           thePrivKeyLength = 0;
1335     const oid      *thePrivProtocol = NULL;
1336     u_int           thePrivProtocolLength = 0;
1337     int             theSecLevel = 0;    /* No defined const for bad
1338                                          * value (other then err). */
1339     size_t          salt_length = 0, save_salt_length = 0, save_salt_offset = 0;
1340     u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1341     u_char          authParams[USM_MAX_AUTHSIZE];
1342     u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
1343     size_t          sp_offset = 0, mac_offset = 0;
1344     int             rc = 0;
1345
1346     DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", *offset));
1347
1348     if (secStateRef != NULL) {
1349         /*
1350          * To hush the compiler for now.  XXX 
1351          */
1352         struct usmStateReference *ref
1353             = (struct usmStateReference *) secStateRef;
1354
1355         theName = ref->usr_name;
1356         theNameLength = ref->usr_name_length;
1357         theEngineID = ref->usr_engine_id;
1358         theEngineIDLength = ref->usr_engine_id_length;
1359
1360         if (!theEngineIDLength) {
1361             theEngineID = secEngineID;
1362             theEngineIDLength = secEngineIDLen;
1363         }
1364
1365         theAuthProtocol = ref->usr_auth_protocol;
1366         theAuthProtocolLength = ref->usr_auth_protocol_length;
1367         theAuthKey = ref->usr_auth_key;
1368         theAuthKeyLength = ref->usr_auth_key_length;
1369         thePrivProtocol = ref->usr_priv_protocol;
1370         thePrivProtocolLength = ref->usr_priv_protocol_length;
1371         thePrivKey = ref->usr_priv_key;
1372         thePrivKeyLength = ref->usr_priv_key_length;
1373         theSecLevel = ref->usr_sec_level;
1374     }
1375
1376     /*
1377      * * Identify the user record.
1378      */
1379     else {
1380         struct usmUser *user;
1381
1382         /*
1383          * we do allow an unknown user name for
1384          * unauthenticated requests. 
1385          */
1386         if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
1387             == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
1388             DEBUGMSGTL(("usm", "Unknown User\n"));
1389             usm_free_usmStateReference(secStateRef);
1390             return SNMPERR_USM_UNKNOWNSECURITYNAME;
1391         }
1392
1393         theName = secName;
1394         theNameLength = secNameLen;
1395         theEngineID = secEngineID;
1396         theSecLevel = secLevel;
1397         theEngineIDLength = secEngineIDLen;
1398         if (user) {
1399             theAuthProtocol = user->authProtocol;
1400             theAuthProtocolLength = user->authProtocolLen;
1401             theAuthKey = user->authKey;
1402             theAuthKeyLength = user->authKeyLen;
1403             thePrivProtocol = user->privProtocol;
1404             thePrivProtocolLength = user->privProtocolLen;
1405             thePrivKey = user->privKey;
1406             thePrivKeyLength = user->privKeyLen;
1407         } else {
1408             /*
1409              * unknown users can not do authentication (obviously) 
1410              */
1411             theAuthProtocol = usmNoAuthProtocol;
1412             theAuthProtocolLength =
1413                 sizeof(usmNoAuthProtocol) / sizeof(oid);
1414             theAuthKey = NULL;
1415             theAuthKeyLength = 0;
1416             thePrivProtocol = usmNoPrivProtocol;
1417             thePrivProtocolLength =
1418                 sizeof(usmNoPrivProtocol) / sizeof(oid);
1419             thePrivKey = NULL;
1420             thePrivKeyLength = 0;
1421         }
1422     }                           /* endif -- secStateRef==NULL */
1423
1424
1425     /*
1426      * From here to the end of the function, avoid reference to
1427      * secName, secEngineID, secLevel, and associated lengths.
1428      */
1429
1430
1431     /*
1432      * Check to see if the user can use the requested sec services.
1433      */
1434     if (usm_check_secLevel_vs_protocols(theSecLevel,
1435                                         theAuthProtocol,
1436                                         theAuthProtocolLength,
1437                                         thePrivProtocol,
1438                                         thePrivProtocolLength) == 1) {
1439         DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
1440                     theSecLevel));
1441
1442         usm_free_usmStateReference(secStateRef);
1443         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
1444     }
1445
1446
1447     /*
1448      * * Retrieve the engine information.
1449      * *
1450      * * XXX    No error is declared in the EoP when sending messages to
1451      * *        unknown engines, processing continues w/ boots/time == (0,0).
1452      */
1453     if (get_enginetime(theEngineID, theEngineIDLength,
1454                        &boots_uint, &time_uint, FALSE) == -1) {
1455         DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
1456     }
1457
1458     boots_long = boots_uint;
1459     time_long = time_uint;
1460
1461     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1462         /*
1463          * Initially assume that the ciphertext will end up the same size as
1464          * the plaintext plus some padding.  Really sc_encrypt ought to be able
1465          * to grow this for us, a la asn_realloc_rbuild_<type> functions, but
1466          * this will do for now.  
1467          */
1468         u_char         *ciphertext = NULL;
1469         size_t          ciphertextlen = scopedPduLen + 64;
1470
1471         if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) {
1472             DEBUGMSGTL(("usm",
1473                         "couldn't malloc %d bytes for encrypted PDU\n",
1474                         ciphertextlen));
1475             usm_free_usmStateReference(secStateRef);
1476             return SNMPERR_MALLOC;
1477         }
1478
1479         /*
1480          * XXX Hardwired to seek into a 1DES private key!  
1481          */
1482 #ifdef HAVE_AES
1483         if (ISTRANSFORM(thePrivProtocol, AES128Priv) ||
1484             ISTRANSFORM(thePrivProtocol, AES192Priv) ||
1485             ISTRANSFORM(thePrivProtocol, AES256Priv)) {
1486             salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
1487             save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
1488             save_salt_offset = 0;
1489             if (!thePrivKey ||
1490                 usm_set_aes_iv(salt, &salt_length,
1491                                htonl(boots_uint), htonl(time_uint),
1492                                iv) == -1) {
1493                 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
1494                 usm_free_usmStateReference(secStateRef);
1495                 free(ciphertext);
1496                 return SNMPERR_USM_GENERICERROR;
1497             }
1498         } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
1499 #endif
1500             salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
1501             save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
1502             save_salt_offset = 0;
1503             if (!thePrivKey || (usm_set_salt(salt, &salt_length,
1504                                              thePrivKey + 8,
1505                                              thePrivKeyLength - 8,
1506                                              iv) == -1)) {
1507                 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
1508                 usm_free_usmStateReference(secStateRef);
1509                 free(ciphertext);
1510                 return SNMPERR_USM_GENERICERROR;
1511             }
1512 #ifdef HAVE_AES
1513         }
1514 #endif
1515 #ifdef SNMP_TESTING_CODE
1516         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1517             dump_chunk("usm/dump", "This data was encrypted:",
1518                        scopedPdu, scopedPduLen);
1519         }
1520 #endif
1521
1522         if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
1523                        thePrivKey, thePrivKeyLength,
1524                        salt, salt_length,
1525                        scopedPdu, scopedPduLen,
1526                        ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
1527             DEBUGMSGTL(("usm", "DES-CBC error.\n"));
1528             usm_free_usmStateReference(secStateRef);
1529             free(ciphertext);
1530             return SNMPERR_USM_ENCRYPTIONERROR;
1531         }
1532
1533         /*
1534          * Write the encrypted scopedPdu back into the packet buffer.  
1535          */
1536
1537 #ifdef SNMP_TESTING_CODE
1538         theTotalLength = *wholeMsgLen;
1539 #endif
1540         *offset = 0;
1541         rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1542                                        (u_char) (ASN_UNIVERSAL |
1543                                                  ASN_PRIMITIVE |
1544                                                  ASN_OCTET_STR),
1545                                        ciphertext, ciphertextlen);
1546 #ifdef SNMP_TESTING_CODE
1547         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1548             dump_chunk("usm/dump", "salt + Encrypted form: ", salt,
1549                        salt_length);
1550             dump_chunk("usm/dump", "wholeMsg:",
1551                        (*wholeMsg + *wholeMsgLen - *offset), *offset);
1552         }
1553 #endif
1554
1555         DEBUGMSGTL(("usm", "Encryption successful.\n"));
1556         free(ciphertext);
1557     } else {
1558         /*
1559          * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV  
1560          */
1561     }
1562
1563     /*
1564      * Start encoding the msgSecurityParameters.  
1565      */
1566
1567     sp_offset = *offset;
1568
1569     DEBUGDUMPHEADER("send", "msgPrivacyParameters");
1570     /*
1571      * msgPrivacyParameters (warning: assumes DES salt).  
1572      */
1573     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1574                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1575                                              | ASN_OCTET_STR),
1576                                    iv,
1577                                    save_salt_length);
1578     DEBUGINDENTLESS();
1579     if (rc == 0) {
1580         DEBUGMSGTL(("usm", "building privParams failed.\n"));
1581         usm_free_usmStateReference(secStateRef);
1582         return SNMPERR_TOO_LONG;
1583     }
1584
1585     DEBUGDUMPHEADER("send", "msgAuthenticationParameters");
1586     /*
1587      * msgAuthenticationParameters (warnings assumes 0x00 by 12).  
1588      */
1589     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1590         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1591         memset(authParams, 0, USM_MD5_AND_SHA_AUTH_LEN);
1592         msgAuthParmLen = USM_MD5_AND_SHA_AUTH_LEN;
1593     }
1594
1595     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1596                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1597                                              | ASN_OCTET_STR), authParams,
1598                                    msgAuthParmLen);
1599     DEBUGINDENTLESS();
1600     if (rc == 0) {
1601         DEBUGMSGTL(("usm", "building authParams failed.\n"));
1602         usm_free_usmStateReference(secStateRef);
1603         return SNMPERR_TOO_LONG;
1604     }
1605
1606     /*
1607      * Remember where to put the actual HMAC we calculate later on.  An
1608      * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1
1609      * header of length 2, hence the fudge factor.  
1610      */
1611
1612     mac_offset = *offset - 2;
1613
1614     /*
1615      * msgUserName.  
1616      */
1617     DEBUGDUMPHEADER("send", "msgUserName");
1618     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1619                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1620                                              | ASN_OCTET_STR),
1621                                    (u_char *) theName, theNameLength);
1622     DEBUGINDENTLESS();
1623     if (rc == 0) {
1624         DEBUGMSGTL(("usm", "building authParams failed.\n"));
1625         usm_free_usmStateReference(secStateRef);
1626         return SNMPERR_TOO_LONG;
1627     }
1628
1629     /*
1630      * msgAuthoritativeEngineTime.  
1631      */
1632     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
1633     rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
1634                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1635                                           ASN_INTEGER), &time_long,
1636                                 sizeof(long));
1637     DEBUGINDENTLESS();
1638     if (rc == 0) {
1639         DEBUGMSGTL(("usm",
1640                     "building msgAuthoritativeEngineTime failed.\n"));
1641         usm_free_usmStateReference(secStateRef);
1642         return SNMPERR_TOO_LONG;
1643     }
1644
1645     /*
1646      * msgAuthoritativeEngineBoots.  
1647      */
1648     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
1649     rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
1650                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1651                                           ASN_INTEGER), &boots_long,
1652                                 sizeof(long));
1653     DEBUGINDENTLESS();
1654     if (rc == 0) {
1655         DEBUGMSGTL(("usm",
1656                     "building msgAuthoritativeEngineBoots failed.\n"));
1657         usm_free_usmStateReference(secStateRef);
1658         return SNMPERR_TOO_LONG;
1659     }
1660
1661     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
1662     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1663                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1664                                              | ASN_OCTET_STR), theEngineID,
1665                                    theEngineIDLength);
1666     DEBUGINDENTLESS();
1667     if (rc == 0) {
1668         DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
1669         usm_free_usmStateReference(secStateRef);
1670         return SNMPERR_TOO_LONG;
1671     }
1672
1673     /*
1674      * USM msgSecurityParameters sequence header  
1675      */
1676     rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
1677                                      (u_char) (ASN_SEQUENCE |
1678                                                ASN_CONSTRUCTOR),
1679                                      *offset - sp_offset);
1680     if (rc == 0) {
1681         DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
1682         usm_free_usmStateReference(secStateRef);
1683         return SNMPERR_TOO_LONG;
1684     }
1685
1686     /*
1687      * msgSecurityParameters OCTET STRING wrapper.  
1688      */
1689     rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
1690                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1691                                              | ASN_OCTET_STR),
1692                                    *offset - sp_offset);
1693
1694     if (rc == 0) {
1695         DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
1696         usm_free_usmStateReference(secStateRef);
1697         return SNMPERR_TOO_LONG;
1698     }
1699
1700     /*
1701      * Copy in the msgGlobalData and msgVersion.  
1702      */
1703     while ((*wholeMsgLen - *offset) < globalDataLen) {
1704         if (!asn_realloc(wholeMsg, wholeMsgLen)) {
1705             DEBUGMSGTL(("usm", "building global data failed.\n"));
1706             usm_free_usmStateReference(secStateRef);
1707             return SNMPERR_TOO_LONG;
1708         }
1709     }
1710
1711     *offset += globalDataLen;
1712     memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen);
1713
1714     /*
1715      * Total packet sequence.  
1716      */
1717     rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
1718                                      (u_char) (ASN_SEQUENCE |
1719                                                ASN_CONSTRUCTOR), *offset);
1720     if (rc == 0) {
1721         DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
1722         usm_free_usmStateReference(secStateRef);
1723         return SNMPERR_TOO_LONG;
1724     }
1725
1726     /*
1727      * Now consider / do authentication.  
1728      */
1729
1730     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV ||
1731         theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1732         size_t          temp_sig_len = msgAuthParmLen;
1733         u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
1734         u_char         *proto_msg = *wholeMsg + *wholeMsgLen - *offset;
1735         size_t          proto_msg_len = *offset;
1736
1737
1738         if (temp_sig == NULL) {
1739             DEBUGMSGTL(("usm", "Out of memory.\n"));
1740             usm_free_usmStateReference(secStateRef);
1741             return SNMPERR_USM_GENERICERROR;
1742         }
1743
1744         if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
1745                                    theAuthKey, theAuthKeyLength,
1746                                    proto_msg, proto_msg_len,
1747                                    temp_sig, &temp_sig_len)
1748             != SNMP_ERR_NOERROR) {
1749             SNMP_FREE(temp_sig);
1750             DEBUGMSGTL(("usm", "Signing failed.\n"));
1751             usm_free_usmStateReference(secStateRef);
1752             return SNMPERR_USM_AUTHENTICATIONFAILURE;
1753         }
1754
1755         if (temp_sig_len != msgAuthParmLen) {
1756             SNMP_FREE(temp_sig);
1757             DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
1758             usm_free_usmStateReference(secStateRef);
1759             return SNMPERR_USM_AUTHENTICATIONFAILURE;
1760         }
1761
1762         memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig,
1763                msgAuthParmLen);
1764         SNMP_FREE(temp_sig);
1765     }
1766     /*
1767      * endif -- create keyed hash 
1768      */
1769     usm_free_usmStateReference(secStateRef);
1770     DEBUGMSGTL(("usm", "USM processing completed.\n"));
1771     return SNMPERR_SUCCESS;
1772 }                               /* end usm_rgenerate_out_msg() */
1773
1774 #endif                          /* */
1775
1776
1777
1778 /*******************************************************************-o-******
1779  * usm_parse_security_parameters
1780  *
1781  * Parameters:
1782  *      (See list below...)
1783  *      
1784  * Returns:
1785  *      0       On success,
1786  *      -1      Otherwise.
1787  *
1788  *      tab stop 4
1789  *
1790  *      Extracts values from the security header and data portions of the
1791  *      incoming buffer.
1792  */
1793 int
1794 usm_parse_security_parameters(u_char * secParams,
1795                               size_t remaining,
1796                               u_char * secEngineID,
1797                               size_t * secEngineIDLen,
1798                               u_int * boots_uint,
1799                               u_int * time_uint,
1800                               char *secName,
1801                               size_t * secNameLen,
1802                               u_char * signature,
1803                               size_t * signature_length,
1804                               u_char * salt,
1805                               size_t * salt_length, u_char ** data_ptr)
1806 {
1807     u_char         *parse_ptr = secParams;
1808     u_char         *value_ptr;
1809     u_char         *next_ptr;
1810     u_char          type_value;
1811
1812     size_t          octet_string_length = remaining;
1813     size_t          sequence_length;
1814     size_t          remaining_bytes;
1815
1816     long            boots_long;
1817     long            time_long;
1818
1819     u_int           origNameLen;
1820
1821
1822     /*
1823      * Eat the first octet header.
1824      */
1825     if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length,
1826                                         &type_value,
1827                                         (ASN_UNIVERSAL | ASN_PRIMITIVE |
1828                                          ASN_OCTET_STR),
1829                                         "usm first octet")) == NULL) {
1830         /*
1831          * RETURN parse error 
1832          */ return -1;
1833     }
1834
1835
1836     /*
1837      * Eat the sequence header.
1838      */
1839     parse_ptr = value_ptr;
1840     sequence_length = octet_string_length;
1841
1842     if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length,
1843                                         &type_value,
1844                                         (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1845                                         "usm sequence")) == NULL) {
1846         /*
1847          * RETURN parse error 
1848          */ return -1;
1849     }
1850
1851
1852     /*
1853      * Retrieve the engineID.
1854      */
1855     parse_ptr = value_ptr;
1856     remaining_bytes = sequence_length;
1857
1858     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID");
1859     if ((next_ptr
1860          = asn_parse_string(parse_ptr, &remaining_bytes, &type_value,
1861                             secEngineID, secEngineIDLen)) == NULL) {
1862         DEBUGINDENTLESS();
1863         /*
1864          * RETURN parse error 
1865          */ return -1;
1866     }
1867     DEBUGINDENTLESS();
1868
1869     if (type_value !=
1870         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1871         /*
1872          * RETURN parse error 
1873          */ return -1;
1874     }
1875
1876
1877     /*
1878      * Retrieve the engine boots, notice switch in the way next_ptr and
1879      * remaining_bytes are used (to accomodate the asn code).
1880      */
1881     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots");
1882     if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
1883                                   &boots_long, sizeof(long))) == NULL) {
1884         DEBUGINDENTLESS();
1885         /*
1886          * RETURN parse error 
1887          */ return -1;
1888     }
1889     DEBUGINDENTLESS();
1890
1891     if (type_value !=
1892         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
1893         DEBUGINDENTLESS();
1894         /*
1895          * RETURN parse error 
1896          */ return -1;
1897     }
1898
1899     *boots_uint = (u_int) boots_long;
1900
1901
1902     /*
1903      * Retrieve the time value.
1904      */
1905     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime");
1906     if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
1907                                   &time_long, sizeof(long))) == NULL) {
1908         /*
1909          * RETURN parse error 
1910          */ return -1;
1911     }
1912     DEBUGINDENTLESS();
1913
1914     if (type_value !=
1915         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
1916         /*
1917          * RETURN parse error 
1918          */ return -1;
1919     }
1920
1921     *time_uint = (u_int) time_long;
1922
1923
1924     /*
1925      * Retrieve the secName.
1926      */
1927     origNameLen = *secNameLen;
1928
1929
1930     DEBUGDUMPHEADER("recv", "msgUserName");
1931     if ((next_ptr
1932          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
1933                             (u_char *) secName, secNameLen)) == NULL) {
1934         DEBUGINDENTLESS();
1935         /*
1936          * RETURN parse error 
1937          */ return -1;
1938     }
1939     DEBUGINDENTLESS();
1940
1941     /*
1942      * FIX -- doesn't this also indicate a buffer overrun?
1943      */
1944     if ((int) origNameLen < *secNameLen + 1) {
1945         /*
1946          * RETURN parse error, but it's really a parameter error 
1947          */
1948         return -1;
1949     }
1950
1951     if (*secNameLen > 32) {
1952         /*
1953          * This is a USM-specific limitation over and above the above
1954          * limitation (which will probably default to the length of an
1955          * SnmpAdminString, i.e. 255).  See RFC 2574, sec. 2.4.  
1956          */
1957         return -1;
1958     }
1959
1960     secName[*secNameLen] = '\0';
1961
1962     if (type_value !=
1963         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1964         /*
1965          * RETURN parse error 
1966          */ return -1;
1967     }
1968
1969
1970     /*
1971      * Retrieve the signature and blank it if there.
1972      */
1973     DEBUGDUMPHEADER("recv", "msgAuthenticationParameters");
1974     if ((next_ptr
1975          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
1976                             signature, signature_length)) == NULL) {
1977         DEBUGINDENTLESS();
1978         /*
1979          * RETURN parse error 
1980          */ return -1;
1981     }
1982     DEBUGINDENTLESS();
1983
1984     if (type_value !=
1985         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1986         /*
1987          * RETURN parse error 
1988          */ return -1;
1989     }
1990
1991     if (*signature_length != 0) {       /* Blanking for authentication step later */
1992         memset(next_ptr - (u_long) * signature_length,
1993                0, *signature_length);
1994     }
1995
1996
1997     /*
1998      * Retrieve the salt.
1999      *
2000      * Note that the next ptr is where the data section starts.
2001      */
2002     DEBUGDUMPHEADER("recv", "msgPrivacyParameters");
2003     if ((*data_ptr
2004          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
2005                             salt, salt_length)) == NULL) {
2006         DEBUGINDENTLESS();
2007         /*
2008          * RETURN parse error 
2009          */ return -2;
2010     }
2011     DEBUGINDENTLESS();
2012
2013     if (type_value !=
2014         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2015         /*
2016          * RETURN parse error 
2017          */ return -2;
2018     }
2019
2020     return 0;
2021
2022 }                               /* end usm_parse_security_parameters() */
2023
2024
2025
2026
2027 /*******************************************************************-o-******
2028  * usm_check_and_update_timeliness
2029  *
2030  * Parameters:
2031  *      *secEngineID
2032  *       secEngineIDen
2033  *       boots_uint
2034  *       time_uint
2035  *      *error
2036  *      
2037  * Returns:
2038  *      0       On success,
2039  *      -1      Otherwise.
2040  *      
2041  *
2042  * Performs the incoming timeliness checking and setting.
2043  */
2044 int
2045 usm_check_and_update_timeliness(u_char * secEngineID,
2046                                 size_t secEngineIDLen,
2047                                 u_int boots_uint,
2048                                 u_int time_uint, int *error)
2049 {
2050     u_char          myID[USM_MAX_ID_LENGTH];
2051     u_long          myIDLength =
2052         snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
2053     u_int           myBoots;
2054     u_int           myTime;
2055
2056
2057
2058     if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) {
2059         /*
2060          * We're probably already screwed...buffer overwrite.  XXX? 
2061          */
2062         DEBUGMSGTL(("usm", "Buffer overflow.\n"));
2063         *error = SNMPERR_USM_GENERICERROR;
2064         return -1;
2065     }
2066
2067     myBoots = snmpv3_local_snmpEngineBoots();
2068     myTime = snmpv3_local_snmpEngineTime();
2069
2070
2071     /*
2072      * IF the time involved is local
2073      *     Make sure  message is inside the time window 
2074      * ELSE 
2075      *      IF boots is higher or boots is the same and time is higher
2076      *              remember this new data
2077      *      ELSE
2078      *              IF !(boots same and time within USM_TIME_WINDOW secs)
2079      *                      Message is too old 
2080      *              ELSE    
2081      *                      Message is ok, but don't take time
2082      *              ENDIF
2083      *      ENDIF
2084      * ENDIF
2085      */
2086
2087     /*
2088      * This is a local reference.
2089      */
2090     if ((int) secEngineIDLen == myIDLength
2091         && memcmp(secEngineID, myID, myIDLength) == 0) {
2092         u_int           time_difference = myTime > time_uint ?
2093             myTime - time_uint : time_uint - myTime;
2094
2095         if (boots_uint == ENGINEBOOT_MAX
2096             || boots_uint != myBoots
2097             || time_difference > USM_TIME_WINDOW) {
2098             if (snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS) ==
2099                 0) {
2100                 DEBUGMSGTL(("usm", "%s\n",
2101                             "Failed to increment statistic."));
2102             }
2103
2104             DEBUGMSGTL(("usm",
2105                         "boot_uint %u myBoots %u time_diff %u => not in time window\n",
2106                         boots_uint, myBoots, time_difference));
2107             *error = SNMPERR_USM_NOTINTIMEWINDOW;
2108             return -1;
2109         }
2110
2111         *error = SNMPERR_SUCCESS;
2112         return 0;
2113     }
2114
2115     /*
2116      * This is a remote reference.
2117      */
2118     else {
2119         u_int           theirBoots, theirTime, theirLastTime;
2120         u_int           time_difference;
2121
2122         if (get_enginetime_ex(secEngineID, secEngineIDLen,
2123                               &theirBoots, &theirTime,
2124                               &theirLastTime, TRUE)
2125             != SNMPERR_SUCCESS) {
2126             DEBUGMSGTL(("usm", "%s\n",
2127                         "Failed to get remote engine's times."));
2128
2129             *error = SNMPERR_USM_GENERICERROR;
2130             return -1;
2131         }
2132
2133         time_difference = theirTime > time_uint ?
2134             theirTime - time_uint : time_uint - theirTime;
2135
2136
2137         /*
2138          * XXX  Contrary to the pseudocode:
2139          *      See if boots is invalid first.
2140          */
2141         if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
2142             DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid."));
2143
2144             *error = SNMPERR_USM_NOTINTIMEWINDOW;
2145             return -1;
2146         }
2147
2148
2149         /*
2150          * Boots is ok, see if the boots is the same but the time
2151          * is old.
2152          */
2153         if (theirBoots == boots_uint && time_uint < theirLastTime) {
2154             if (time_difference > USM_TIME_WINDOW) {
2155                 DEBUGMSGTL(("usm", "%s\n", "Message too old."));
2156                 *error = SNMPERR_USM_NOTINTIMEWINDOW;
2157                 return -1;
2158             }
2159
2160             else {              /* Old, but acceptable */
2161
2162                 *error = SNMPERR_SUCCESS;
2163                 return 0;
2164             }
2165         }
2166
2167
2168         /*
2169          * Message is ok, either boots has been advanced, or
2170          * time is greater than before with the same boots.
2171          */
2172
2173         if (set_enginetime(secEngineID, secEngineIDLen,
2174                            boots_uint, time_uint, TRUE)
2175             != SNMPERR_SUCCESS) {
2176             DEBUGMSGTL(("usm", "%s\n",
2177                         "Failed updating remote boot/time."));
2178             *error = SNMPERR_USM_GENERICERROR;
2179             return -1;
2180         }
2181
2182         *error = SNMPERR_SUCCESS;
2183         return 0;               /* Fresh message and time updated */
2184
2185     }                           /* endif -- local or remote time reference. */
2186
2187
2188 }                               /* end usm_check_and_update_timeliness() */
2189
2190
2191
2192 int
2193 usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms)
2194 {
2195     if (!parms)
2196         return SNMPERR_GENERR;
2197
2198     return usm_process_in_msg(parms->msgProcModel,
2199                               parms->maxMsgSize,
2200                               parms->secParams,
2201                               parms->secModel,
2202                               parms->secLevel,
2203                               parms->wholeMsg,
2204                               parms->wholeMsgLen,
2205                               parms->secEngineID,
2206                               parms->secEngineIDLen,
2207                               parms->secName,
2208                               parms->secNameLen,
2209                               parms->scopedPdu,
2210                               parms->scopedPduLen,
2211                               parms->maxSizeResponse,
2212                               parms->secStateRef,
2213                               parms->sess, parms->msg_flags);
2214 }
2215
2216 /*******************************************************************-o-******
2217  * usm_process_in_msg
2218  *
2219  * Parameters:
2220  *      (See list below...)
2221  *      
2222  * Returns:
2223  *      SNMPERR_SUCCESS                 On success.
2224  *      SNMPERR_USM_AUTHENTICATIONFAILURE
2225  *      SNMPERR_USM_DECRYPTIONERROR
2226  *      SNMPERR_USM_GENERICERROR
2227  *      SNMPERR_USM_PARSEERROR
2228  *      SNMPERR_USM_UNKNOWNENGINEID
2229  *      SNMPERR_USM_PARSEERROR
2230  *      SNMPERR_USM_UNKNOWNSECURITYNAME
2231  *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
2232  *
2233  *
2234  * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
2235  *
2236  * FIX  Memory leaks if secStateRef is allocated and a return occurs
2237  *      without cleaning up.  May contain secrets...
2238  */
2239 int
2240 usm_process_in_msg(int msgProcModel,    /* (UNUSED) */
2241                    size_t maxMsgSize,   /* IN     - Used to calc maxSizeResponse.  */
2242                    u_char * secParams,  /* IN     - BER encoded securityParameters. */
2243                    int secModel,        /* (UNUSED) */
2244                    int secLevel,        /* IN     - AuthNoPriv, authPriv etc.      */
2245                    u_char * wholeMsg,   /* IN     - Original v3 message.           */
2246                    size_t wholeMsgLen,  /* IN     - Msg length.                    */
2247                    u_char * secEngineID,        /* OUT    - Pointer snmpEngineID.          */
2248                    size_t * secEngineIDLen,     /* IN/OUT - Len available, len returned.   */
2249                    /*
2250                     * NOTE: Memory provided by caller.      
2251                     */
2252                    char *secName,       /* OUT    - Pointer to securityName.       */
2253                    size_t * secNameLen, /* IN/OUT - Len available, len returned.   */
2254                    u_char ** scopedPdu, /* OUT    - Pointer to plaintext scopedPdu. */
2255                    size_t * scopedPduLen,       /* IN/OUT - Len available, len returned.   */
2256                    size_t * maxSizeResponse,    /* OUT    - Max size of Response PDU.      */
2257                    void **secStateRf,   /* OUT    - Ref to security state.         */
2258                    netsnmp_session * sess,      /* IN     - session which got the message  */
2259                    u_char msg_flags)
2260 {                               /* IN     - v3 Message flags.              */
2261     size_t          remaining = wholeMsgLen - (u_int)
2262         ((u_long) * secParams - (u_long) * wholeMsg);
2263     u_int           boots_uint;
2264     u_int           time_uint;
2265 #ifdef HAVE_AES
2266     u_int           net_boots, net_time;
2267 #endif
2268     u_char          signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
2269     size_t          signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
2270     u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
2271     size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2272     u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
2273     u_int           iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2274     u_char         *data_ptr;
2275     u_char         *value_ptr;
2276     u_char          type_value;
2277     u_char         *end_of_overhead;
2278     int             error;
2279     int             i, rc = 0;
2280     struct usmStateReference **secStateRef =
2281         (struct usmStateReference **) secStateRf;
2282
2283     struct usmUser *user;
2284
2285
2286     DEBUGMSGTL(("usm", "USM processing begun...\n"));
2287
2288
2289     if (secStateRef) {
2290         usm_free_usmStateReference(*secStateRef);
2291         *secStateRef = usm_malloc_usmStateReference();
2292         if (*secStateRef == NULL) {
2293             DEBUGMSGTL(("usm", "Out of memory.\n"));
2294             return SNMPERR_USM_GENERICERROR;
2295         }
2296     }
2297
2298
2299     /*
2300      * Make sure the *secParms is an OCTET STRING.
2301      * Extract the user name, engine ID, and security level.
2302      */
2303     if ((rc = usm_parse_security_parameters(secParams, remaining,
2304                                             secEngineID, secEngineIDLen,
2305                                             &boots_uint, &time_uint,
2306                                             secName, secNameLen,
2307                                             signature, &signature_length,
2308                                             salt, &salt_length,
2309                                             &data_ptr)) < 0) {
2310         DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc));
2311         if (rc == -2) {
2312             /*
2313              * This indicates a decryptionError.  
2314              */
2315             if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
2316                 0) {
2317                 DEBUGMSGTL(("usm", "%s\n",
2318                             "Failed to increment statistic."));
2319             }
2320             return SNMPERR_USM_DECRYPTIONERROR;
2321         }
2322         if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
2323             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2324         }
2325         return SNMPERR_USM_PARSEERROR;
2326     }
2327
2328
2329     if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) {
2330         /*
2331          * pull these out now so reports can use them 
2332          */
2333         *scopedPdu = data_ptr;
2334         *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
2335         end_of_overhead = data_ptr;
2336     }
2337
2338     if (secStateRef) {
2339         /*
2340          * Cache the name, engine ID, and security level,
2341          * * per step 2 (section 3.2)
2342          */
2343         if (usm_set_usmStateReference_name
2344             (*secStateRef, secName, *secNameLen) == -1) {
2345             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name."));
2346             return SNMPERR_USM_GENERICERROR;
2347         }
2348
2349         if (usm_set_usmStateReference_engine_id
2350             (*secStateRef, secEngineID, *secEngineIDLen) == -1) {
2351             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id."));
2352             return SNMPERR_USM_GENERICERROR;
2353         }
2354
2355         if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) ==
2356             -1) {
2357             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level."));
2358             return SNMPERR_USM_GENERICERROR;
2359         }
2360     }
2361
2362
2363     /*
2364      * Locate the engine ID record.
2365      * If it is unknown, then either create one or note this as an error.
2366      */
2367     if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE ||
2368                   (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH &&
2369                    (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) ||
2370         (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) {
2371         if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) {
2372             DEBUGMSGTL(("usm", "Unknown Engine ID.\n"));
2373             if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS) ==
2374                 0) {
2375                 DEBUGMSGTL(("usm", "%s\n",
2376                             "Failed to increment statistic."));
2377             }
2378             return SNMPERR_USM_UNKNOWNENGINEID;
2379         }
2380     } else {
2381         if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen)
2382             != SNMPERR_SUCCESS) {
2383             DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record."));
2384             return SNMPERR_USM_GENERICERROR;
2385         }
2386
2387     }
2388
2389
2390     /*
2391      * Locate the User record.
2392      * If the user/engine ID is unknown, report this as an error.
2393      */
2394     if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen,
2395                                        secName, userList,
2396                                        (sess->isAuthoritative ==
2397                                         SNMP_SESS_AUTHORITATIVE) ? 0 : 1))
2398         == NULL) {
2399         DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
2400         if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES) == 0) {
2401             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2402         }
2403         return SNMPERR_USM_UNKNOWNSECURITYNAME;
2404     }
2405
2406
2407     /*
2408      * Make sure the security level is appropriate.
2409      */
2410     if (usm_check_secLevel(secLevel, user) == 1) {
2411         DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n",
2412                     secLevel));
2413         if (snmp_increment_statistic
2414             (STAT_USMSTATSUNSUPPORTEDSECLEVELS) == 0) {
2415             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2416         }
2417         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
2418     }
2419
2420
2421     /*
2422      * Check the authentication credentials of the message.
2423      */
2424     if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
2425         || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2426         if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen,
2427                                 user->authKey, user->authKeyLen,
2428                                 wholeMsg, wholeMsgLen,
2429                                 signature, signature_length)
2430             != SNMP_ERR_NOERROR) {
2431             DEBUGMSGTL(("usm", "Verification failed.\n"));
2432             if (snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS) == 0) {
2433                 DEBUGMSGTL(("usm", "%s\n",
2434                             "Failed to increment statistic."));
2435             }
2436             return SNMPERR_USM_AUTHENTICATIONFAILURE;
2437         }
2438
2439         DEBUGMSGTL(("usm", "Verification succeeded.\n"));
2440     }
2441
2442
2443     /*
2444      * Steps 10-11  user is already set - relocated before timeliness 
2445      * check in case it fails - still save user data for response.
2446      *
2447      * Cache the keys and protocol oids, per step 11 (s3.2).
2448      */
2449     if (secStateRef) {
2450         if (usm_set_usmStateReference_auth_protocol(*secStateRef,
2451                                                     user->authProtocol,
2452                                                     user->
2453                                                     authProtocolLen) ==
2454             -1) {
2455             DEBUGMSGTL(("usm", "%s\n",
2456                         "Couldn't cache authentication protocol."));
2457             return SNMPERR_USM_GENERICERROR;
2458         }
2459
2460         if (usm_set_usmStateReference_auth_key(*secStateRef,
2461                                                user->authKey,
2462                                                user->authKeyLen) == -1) {
2463             DEBUGMSGTL(("usm", "%s\n",
2464                         "Couldn't cache authentiation key."));
2465             return SNMPERR_USM_GENERICERROR;
2466         }
2467
2468         if (usm_set_usmStateReference_priv_protocol(*secStateRef,
2469                                                     user->privProtocol,
2470                                                     user->
2471                                                     privProtocolLen) ==
2472             -1) {
2473             DEBUGMSGTL(("usm", "%s\n",
2474                         "Couldn't cache privacy protocol."));
2475             return SNMPERR_USM_GENERICERROR;
2476         }
2477
2478         if (usm_set_usmStateReference_priv_key(*secStateRef,
2479                                                user->privKey,
2480                                                user->privKeyLen) == -1) {
2481             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key."));
2482             return SNMPERR_USM_GENERICERROR;
2483         }
2484     }
2485
2486
2487     /*
2488      * Perform the timeliness/time manager functions.
2489      */
2490     if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
2491         || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2492         if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen,
2493                                             boots_uint, time_uint,
2494                                             &error) == -1) {
2495             return error;
2496         }
2497     }
2498 #ifdef                                                  LCD_TIME_SYNC_OPT
2499     /*
2500      * Cache the unauthenticated time to use in case we don't have
2501      * anything better - this guess will be no worse than (0,0)
2502      * that we normally use.
2503      */
2504     else {
2505         set_enginetime(secEngineID, *secEngineIDLen,
2506                        boots_uint, time_uint, FALSE);
2507     }
2508 #endif                          /* LCD_TIME_SYNC_OPT */
2509
2510
2511     /*
2512      * If needed, decrypt the scoped PDU.
2513      */
2514     if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2515         remaining = wholeMsgLen - (data_ptr - wholeMsg);
2516
2517         if ((value_ptr = asn_parse_sequence(data_ptr, &remaining,
2518                                             &type_value,
2519                                             (ASN_UNIVERSAL | ASN_PRIMITIVE
2520                                              | ASN_OCTET_STR),
2521                                             "encrypted sPDU")) == NULL) {
2522             DEBUGMSGTL(("usm", "%s\n",
2523                         "Failed while parsing encrypted sPDU."));
2524             if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
2525                 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2526             }
2527             usm_free_usmStateReference(*secStateRef);
2528             *secStateRef = NULL;
2529             return SNMPERR_USM_PARSEERROR;
2530         }
2531
2532         if (ISTRANSFORM(user->privProtocol, DESPriv)) {
2533             /*
2534              * From RFC2574:
2535              * 
2536              * "Before decryption, the encrypted data length is verified.
2537              * If the length of the OCTET STRING to be decrypted is not
2538              * an integral multiple of 8 octets, the decryption process
2539              * is halted and an appropriate exception noted."  
2540              */
2541
2542             if (remaining % 8 != 0) {
2543                 DEBUGMSGTL(("usm",
2544                             "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
2545                             remaining, remaining % 8));
2546                 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
2547                     0) {
2548                     DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2549                 }
2550                 usm_free_usmStateReference(*secStateRef);
2551                 *secStateRef = NULL;
2552                 return SNMPERR_USM_DECRYPTIONERROR;
2553             }
2554
2555             end_of_overhead = value_ptr;
2556
2557             /*
2558              * XOR the salt with the last (iv_length) bytes
2559              * of the priv_key to obtain the IV.
2560              */
2561             iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
2562             for (i = 0; i < (int) iv_length; i++)
2563                 iv[i] = salt[i] ^ user->privKey[iv_length + i];
2564         }
2565 #ifdef HAVE_AES
2566         else if (ISTRANSFORM(user->privProtocol, AES128Priv) ||
2567                  ISTRANSFORM(user->privProtocol, AES192Priv) ||
2568                  ISTRANSFORM(user->privProtocol, AES256Priv)) {
2569             iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
2570             net_boots = ntohl(boots_uint);
2571             net_time = ntohl(time_uint);
2572             memcpy(iv, &net_boots, 4);
2573             memcpy(iv+4, &net_time, 4);
2574             memcpy(iv+8, salt, salt_length);
2575         }
2576 #endif
2577         
2578         if (sc_decrypt(user->privProtocol, user->privProtocolLen,
2579                        user->privKey, user->privKeyLen,
2580                        iv, iv_length,
2581                        value_ptr, remaining, *scopedPdu, scopedPduLen)
2582             != SNMP_ERR_NOERROR) {
2583             DEBUGMSGTL(("usm", "%s\n", "Failed decryption."));
2584             if (snmp_increment_statistic
2585                 (STAT_USMSTATSDECRYPTIONERRORS) == 0) {
2586                 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2587             }
2588             return SNMPERR_USM_DECRYPTIONERROR;
2589         }
2590 #ifdef SNMP_TESTING_CODE
2591         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
2592             dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining);
2593             dump_chunk("usm/dump", "salt + Encrypted form:",
2594                        salt, salt_length);
2595             dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length);
2596             dump_chunk("usm/dump", "Decrypted chunk:",
2597                        *scopedPdu, *scopedPduLen);
2598         }
2599 #endif
2600     }
2601     /*
2602      * sPDU is plaintext.
2603      */
2604     else {
2605         *scopedPdu = data_ptr;
2606         *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
2607         end_of_overhead = data_ptr;
2608
2609     }                           /* endif -- PDU decryption */
2610
2611
2612     /*
2613      * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
2614      *
2615      * FIX  Correct? 
2616      */
2617     *maxSizeResponse = maxMsgSize - (int)
2618         ((u_long) end_of_overhead - (u_long) wholeMsg);
2619
2620
2621     DEBUGMSGTL(("usm", "USM processing completed.\n"));
2622
2623     return SNMPERR_SUCCESS;
2624
2625 }                               /* end usm_process_in_msg() */
2626
2627 void
2628 init_usm(void)
2629 {
2630     struct snmp_secmod_def *def;
2631
2632     DEBUGMSGTL(("init_usm", "unit_usm: %d %d\n", usmNoPrivProtocol[0],
2633                 usmNoPrivProtocol[1]));
2634
2635     sc_init();                  /* initalize scapi code */
2636
2637     /*
2638      * register ourselves as a security service 
2639      */
2640     def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
2641     /*
2642      * XXX: def->init_sess_secmod move stuff from snmp_api.c 
2643      */
2644     def->encode_reverse = usm_secmod_rgenerate_out_msg;
2645     def->encode_forward = usm_secmod_generate_out_msg;
2646     def->decode = usm_secmod_process_in_msg;
2647     def->pdu_free_state_ref = usm_free_usmStateReference;
2648     register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def);
2649
2650     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
2651                            SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
2652                            init_usm_post_config, NULL);
2653 }
2654
2655 /*
2656  * initializations for the USM.
2657  *
2658  * Should be called after the (engineid) configuration files have been read.
2659  *
2660  * Set "arbitrary" portion of salt to a random number.
2661  */
2662 int
2663 init_usm_post_config(int majorid, int minorid, void *serverarg,
2664                      void *clientarg)
2665 {
2666     size_t          salt_integer_len = sizeof(salt_integer);
2667
2668     if (sc_random((u_char *) & salt_integer, &salt_integer_len) !=
2669         SNMPERR_SUCCESS) {
2670         DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
2671         salt_integer = (u_int) time(NULL);
2672     }
2673
2674 #ifdef HAVE_AES
2675     salt_integer_len = sizeof (salt_integer64_1);
2676     if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
2677         SNMPERR_SUCCESS) {
2678         DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
2679         salt_integer64_1 = (u_int) time(NULL);
2680     }
2681     salt_integer_len = sizeof (salt_integer64_1);
2682     if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
2683         SNMPERR_SUCCESS) {
2684         DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
2685         salt_integer64_2 = (u_int) time(NULL);
2686     }
2687 #endif
2688     
2689     noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
2690                                          USM_LENGTH_OID_TRANSFORM,
2691                                          usmDESPrivProtocol,
2692                                          USM_LENGTH_OID_TRANSFORM);
2693
2694     SNMP_FREE(noNameUser->engineID);
2695     noNameUser->engineIDLen = 0;
2696
2697     return SNMPERR_SUCCESS;
2698 }                               /* end init_usm_post_config() */
2699
2700
2701 /*******************************************************************-o-******
2702  * usm_check_secLevel
2703  *
2704  * Parameters:
2705  *       level
2706  *      *user
2707  *      
2708  * Returns:
2709  *      0       On success,
2710  *      -1      Otherwise.
2711  *
2712  * Checks that a given security level is valid for a given user.
2713  */
2714 int
2715 usm_check_secLevel(int level, struct usmUser *user)
2716 {
2717
2718     DEBUGMSGTL(("comparex", "Comparing: %d %d ", usmNoPrivProtocol[0],
2719                 usmNoPrivProtocol[1]));
2720     DEBUGMSGOID(("comparex", usmNoPrivProtocol,
2721                  sizeof(usmNoPrivProtocol) / sizeof(oid)));
2722     DEBUGMSG(("comparex", "\n"));
2723     if (level == SNMP_SEC_LEVEL_AUTHPRIV
2724         && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen,
2725                              usmNoPrivProtocol,
2726                              sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
2727             0)) {
2728         DEBUGMSGTL(("usm", "Level: %d\n", level));
2729         DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2730         DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2731         DEBUGMSG(("usm", ", User Priv Protocol: "));
2732         DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2733         DEBUGMSG(("usm", "\n"));
2734         return 1;
2735     }
2736     if ((level == SNMP_SEC_LEVEL_AUTHPRIV
2737          || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2738         &&
2739         (netsnmp_oid_equals
2740          (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol,
2741           sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
2742         DEBUGMSGTL(("usm", "Level: %d\n", level));
2743         DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2744         DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2745         DEBUGMSG(("usm", ", User Priv Protocol: "));
2746         DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2747         DEBUGMSG(("usm", "\n"));
2748         return 1;
2749     }
2750
2751     return 0;
2752
2753 }                               /* end usm_check_secLevel() */
2754
2755
2756
2757
2758 /*******************************************************************-o-******
2759  * usm_check_secLevel_vs_protocols
2760  *
2761  * Parameters:
2762  *       level
2763  *      *authProtocol
2764  *       authProtocolLen
2765  *      *privProtocol
2766  *       privProtocolLen
2767  *      
2768  * Returns:
2769  *      0       On success,
2770  *      1       Otherwise.
2771  *
2772  * Same as above but with explicitly named transform types instead of taking
2773  * from the usmUser structure.
2774  */
2775 int
2776 usm_check_secLevel_vs_protocols(int level,
2777                                 const oid * authProtocol,
2778                                 u_int authProtocolLen,
2779                                 const oid * privProtocol,
2780                                 u_int privProtocolLen)
2781 {
2782
2783     if (level == SNMP_SEC_LEVEL_AUTHPRIV
2784         &&
2785         (netsnmp_oid_equals
2786          (privProtocol, privProtocolLen, usmNoPrivProtocol,
2787           sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0)) {
2788         DEBUGMSGTL(("usm", "Level: %d\n", level));
2789         DEBUGMSGTL(("usm", "Auth Protocol: "));
2790         DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
2791         DEBUGMSG(("usm", ", Priv Protocol: "));
2792         DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
2793         DEBUGMSG(("usm", "\n"));
2794         return 1;
2795     }
2796     if ((level == SNMP_SEC_LEVEL_AUTHPRIV
2797          || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2798         &&
2799         (netsnmp_oid_equals
2800          (authProtocol, authProtocolLen, usmNoAuthProtocol,
2801           sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
2802         DEBUGMSGTL(("usm", "Level: %d\n", level));
2803         DEBUGMSGTL(("usm", "Auth Protocol: "));
2804         DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
2805         DEBUGMSG(("usm", ", Priv Protocol: "));
2806         DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
2807         DEBUGMSG(("usm", "\n"));
2808         return 1;
2809     }
2810
2811     return 0;
2812
2813 }                               /* end usm_check_secLevel_vs_protocols() */
2814
2815
2816
2817
2818 /*
2819  * usm_get_user(): Returns a user from userList based on the engineID,
2820  * engineIDLen and name of the requested user. 
2821  */
2822
2823 struct usmUser *
2824 usm_get_user(u_char * engineID, size_t engineIDLen, char *name)
2825 {
2826     DEBUGMSGTL(("usm", "getting user %s\n", name));
2827     return usm_get_user_from_list(engineID, engineIDLen, name, userList,
2828                                   1);
2829 }
2830
2831 struct usmUser *
2832 usm_get_user_from_list(u_char * engineID, size_t engineIDLen,
2833                        char *name, struct usmUser *puserList,
2834                        int use_default)
2835 {
2836     struct usmUser *ptr;
2837     char            noName[] = "";
2838     if (name == NULL)
2839         name = noName;
2840     for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
2841         if (!strcmp(ptr->name, name) &&
2842             ptr->engineIDLen == engineIDLen &&
2843             ((ptr->engineID == NULL && engineID == NULL) ||
2844              (ptr->engineID != NULL && engineID != NULL &&
2845               memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
2846             return ptr;
2847     }
2848
2849     /*
2850      * return "" user used to facilitate engineID discovery 
2851      */
2852     if (use_default && !strcmp(name, ""))
2853         return noNameUser;
2854     return NULL;
2855 }
2856
2857 /*
2858  * usm_add_user(): Add's a user to the userList, sorted by the
2859  * engineIDLength then the engineID then the name length then the name
2860  * to facilitate getNext calls on a usmUser table which is indexed by
2861  * these values.
2862  * 
2863  * Note: userList must not be NULL (obviously), as thats a rather trivial
2864  * addition and is left to the API user.
2865  * 
2866  * returns the head of the list (which could change due to this add).
2867  */
2868
2869 struct usmUser *
2870 usm_add_user(struct usmUser *user)
2871 {
2872     struct usmUser *uptr;
2873     uptr = usm_add_user_to_list(user, userList);
2874     if (uptr != NULL)
2875         userList = uptr;
2876     return uptr;
2877 }
2878
2879 struct usmUser *
2880 usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
2881 {
2882     struct usmUser *nptr, *pptr;
2883
2884     /*
2885      * loop through puserList till we find the proper, sorted place to
2886      * insert the new user 
2887      */
2888     for (nptr = puserList, pptr = NULL; nptr != NULL;
2889          pptr = nptr, nptr = nptr->next) {
2890         if (nptr->engineIDLen > user->engineIDLen)
2891             break;
2892
2893         if (user->engineID == NULL && nptr->engineID != NULL)
2894             break;
2895
2896         if (nptr->engineIDLen == user->engineIDLen &&
2897             (nptr->engineID != NULL && user->engineID != NULL &&
2898              memcmp(nptr->engineID, user->engineID,
2899                     user->engineIDLen) > 0))
2900             break;
2901
2902         if (!(nptr->engineID == NULL && user->engineID != NULL)) {
2903             if (nptr->engineIDLen == user->engineIDLen &&
2904                 ((nptr->engineID == NULL && user->engineID == NULL) ||
2905                  memcmp(nptr->engineID, user->engineID,
2906                         user->engineIDLen) == 0)
2907                 && strlen(nptr->name) > strlen(user->name))
2908                 break;
2909
2910             if (nptr->engineIDLen == user->engineIDLen &&
2911                 ((nptr->engineID == NULL && user->engineID == NULL) ||
2912                  memcmp(nptr->engineID, user->engineID,
2913                         user->engineIDLen) == 0)
2914                 && strlen(nptr->name) == strlen(user->name)
2915                 && strcmp(nptr->name, user->name) > 0)
2916                 break;
2917
2918             if (nptr->engineIDLen == user->engineIDLen &&
2919                 ((nptr->engineID == NULL && user->engineID == NULL) ||
2920                  memcmp(nptr->engineID, user->engineID,
2921                         user->engineIDLen) == 0)
2922                 && strlen(nptr->name) == strlen(user->name)
2923                 && strcmp(nptr->name, user->name) == 0)
2924                 /*
2925                  * the user is an exact match of a previous entry.  Bail 
2926                  */
2927                 return NULL;
2928         }
2929     }
2930
2931     /*
2932      * nptr should now point to the user that we need to add ourselves
2933      * in front of, and pptr should be our new 'prev'. 
2934      */
2935
2936     /*
2937      * change our pointers 
2938      */
2939     user->prev = pptr;
2940     user->next = nptr;
2941
2942     /*
2943      * change the next's prev pointer 
2944      */
2945     if (user->next)
2946         user->next->prev = user;
2947
2948     /*
2949      * change the prev's next pointer 
2950      */
2951     if (user->prev)
2952         user->prev->next = user;
2953
2954     /*
2955      * rewind to the head of the list and return it (since the new head
2956      * could be us, we need to notify the above routine who the head now is. 
2957      */
2958     for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
2959     return pptr;
2960 }
2961
2962 /*
2963  * usm_remove_user(): finds and removes a user from a list 
2964  */
2965 struct usmUser *
2966 usm_remove_user(struct usmUser *user)
2967 {
2968     return usm_remove_user_from_list(user, &userList);
2969 }
2970
2971 struct usmUser *
2972 usm_remove_user_from_list(struct usmUser *user,
2973                           struct usmUser **ppuserList)
2974 {
2975     struct usmUser *nptr, *pptr;
2976
2977     /*
2978      * NULL pointers aren't allowed 
2979      */
2980     if (ppuserList == NULL)
2981         return NULL;
2982
2983     /*
2984      * find the user in the list 
2985      */
2986     for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
2987          pptr = nptr, nptr = nptr->next) {
2988         if (nptr == user)
2989             break;
2990     }
2991
2992     if (nptr) {
2993         /*
2994          * remove the user from the linked list 
2995          */
2996         if (pptr) {
2997             pptr->next = nptr->next;
2998         }
2999         if (nptr->next) {
3000             nptr->next->prev = pptr;
3001         }
3002     } else {
3003         /*
3004          * user didn't exit 
3005          */
3006         return NULL;
3007     }
3008     if (nptr == *ppuserList)    /* we're the head of the list, need to change
3009                                  * * the head to the next user */
3010         *ppuserList = nptr->next;
3011     return *ppuserList;
3012 }                               /* end usm_remove_user_from_list() */
3013
3014
3015
3016
3017 /*
3018  * usm_free_user():  calls free() on all needed parts of struct usmUser and
3019  * the user himself.
3020  * 
3021  * Note: This should *not* be called on an object in a list (IE,
3022  * remove it from the list first, and set next and prev to NULL), but
3023  * will try to reconnect the list pieces again if it is called this
3024  * way.  If called on the head of the list, the entire list will be
3025  * lost. 
3026  */
3027 struct usmUser *
3028 usm_free_user(struct usmUser *user)
3029 {
3030     if (user == NULL)
3031         return NULL;
3032
3033     SNMP_FREE(user->engineID);
3034     SNMP_FREE(user->name);
3035     SNMP_FREE(user->secName);
3036     SNMP_FREE(user->cloneFrom);
3037     SNMP_FREE(user->userPublicString);
3038     SNMP_FREE(user->authProtocol);
3039     SNMP_FREE(user->privProtocol);
3040
3041     if (user->authKey != NULL) {
3042         SNMP_ZERO(user->authKey, user->authKeyLen);
3043         SNMP_FREE(user->authKey);
3044     }
3045
3046     if (user->privKey != NULL) {
3047         SNMP_ZERO(user->privKey, user->privKeyLen);
3048         SNMP_FREE(user->privKey);
3049     }
3050
3051
3052     /*
3053      * FIX  Why not put this check *first?*
3054      */
3055     if (user->prev != NULL) {   /* ack, this shouldn't happen */
3056         user->prev->next = user->next;
3057     }
3058     if (user->next != NULL) {
3059         user->next->prev = user->prev;
3060         if (user->prev != NULL) /* ack this is really bad, because it means
3061                                  * * we'll loose the head of some structure tree */
3062             DEBUGMSGTL(("usm",
3063                         "Severe: Asked to free the head of a usmUser tree somewhere."));
3064     }
3065
3066
3067     SNMP_ZERO(user, sizeof(*user));
3068     SNMP_FREE(user);
3069
3070     return NULL;                /* for convenience to returns from calling functions */
3071
3072 }                               /* end usm_free_user() */
3073
3074
3075
3076
3077 /*
3078  * take a given user and clone the security info into another 
3079  */
3080 struct usmUser *
3081 usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
3082 {
3083     /*
3084      * copy the authProtocol oid row pointer 
3085      */
3086     SNMP_FREE(to->authProtocol);
3087
3088     if ((to->authProtocol =
3089          snmp_duplicate_objid(from->authProtocol,
3090                               from->authProtocolLen)) != NULL)
3091         to->authProtocolLen = from->authProtocolLen;
3092     else
3093         to->authProtocolLen = 0;
3094
3095
3096     /*
3097      * copy the authKey 
3098      */
3099     SNMP_FREE(to->authKey);
3100
3101     if (from->authKeyLen > 0 &&
3102         (to->authKey = (u_char *) malloc(from->authKeyLen))
3103         != NULL) {
3104         to->authKeyLen = from->authKeyLen;
3105         memcpy(to->authKey, from->authKey, to->authKeyLen);
3106     } else {
3107         to->authKey = NULL;
3108         to->authKeyLen = 0;
3109     }
3110
3111
3112     /*
3113      * copy the privProtocol oid row pointer 
3114      */
3115     SNMP_FREE(to->privProtocol);
3116
3117     if ((to->privProtocol =
3118          snmp_duplicate_objid(from->privProtocol,
3119                               from->privProtocolLen)) != NULL)
3120         to->privProtocolLen = from->privProtocolLen;
3121     else
3122         to->privProtocolLen = 0;
3123
3124     /*
3125      * copy the privKey 
3126      */
3127     SNMP_FREE(to->privKey);
3128
3129     if (from->privKeyLen > 0 &&
3130         (to->privKey = (u_char *) malloc(from->privKeyLen))
3131         != NULL) {
3132         to->privKeyLen = from->privKeyLen;
3133         memcpy(to->privKey, from->privKey, to->privKeyLen);
3134     } else {
3135         to->privKey = NULL;
3136         to->privKeyLen = 0;
3137     }
3138     return to;
3139 }
3140
3141 /*
3142  * usm_create_user(void):
3143  * create a default empty user, instantiating only the auth/priv
3144  * protocols to noAuth and noPriv OID pointers
3145  */
3146 struct usmUser *
3147 usm_create_user(void)
3148 {
3149     struct usmUser *newUser;
3150
3151     /*
3152      * create the new user 
3153      */
3154     newUser = (struct usmUser *) calloc(1, sizeof(struct usmUser));
3155     if (newUser == NULL)
3156         return NULL;
3157
3158     /*
3159      * fill the auth/priv protocols 
3160      */
3161     if ((newUser->authProtocol =
3162          snmp_duplicate_objid(usmNoAuthProtocol,
3163                               sizeof(usmNoAuthProtocol) / sizeof(oid))) ==
3164         NULL)
3165         return usm_free_user(newUser);
3166     newUser->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
3167
3168     if ((newUser->privProtocol =
3169          snmp_duplicate_objid(usmNoPrivProtocol,
3170                               sizeof(usmNoPrivProtocol) / sizeof(oid))) ==
3171         NULL)
3172         return usm_free_user(newUser);
3173     newUser->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
3174
3175     /*
3176      * set the storage type to nonvolatile, and the status to ACTIVE 
3177      */
3178     newUser->userStorageType = ST_NONVOLATILE;
3179     newUser->userStatus = RS_ACTIVE;
3180     return newUser;
3181
3182 }                               /* end usm_clone_user() */
3183
3184
3185
3186
3187 /*
3188  * usm_create_initial_user(void):
3189  * creates an initial user, filled with the defaults defined in the
3190  * USM document.
3191  */
3192 struct usmUser *
3193 usm_create_initial_user(const char *name,
3194                         const oid * authProtocol, size_t authProtocolLen,
3195                         const oid * privProtocol, size_t privProtocolLen)
3196 {
3197     struct usmUser *newUser = usm_create_user();
3198     if (newUser == NULL)
3199         return NULL;
3200
3201     if ((newUser->name = strdup(name)) == NULL)
3202         return usm_free_user(newUser);
3203
3204     if ((newUser->secName = strdup(name)) == NULL)
3205         return usm_free_user(newUser);
3206
3207     if ((newUser->engineID =
3208          snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
3209         return usm_free_user(newUser);
3210
3211     if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL)
3212         return usm_free_user(newUser);
3213     newUser->cloneFrom[0] = 0;
3214     newUser->cloneFrom[1] = 0;
3215     newUser->cloneFromLen = 2;
3216
3217     SNMP_FREE(newUser->privProtocol);
3218     if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol,
3219                                                       privProtocolLen)) ==
3220         NULL) {
3221         return usm_free_user(newUser);
3222     }
3223     newUser->privProtocolLen = privProtocolLen;
3224
3225     SNMP_FREE(newUser->authProtocol);
3226     if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol,
3227                                                       authProtocolLen)) ==
3228         NULL) {
3229         return usm_free_user(newUser);
3230     }
3231     newUser->authProtocolLen = authProtocolLen;
3232
3233     newUser->userStatus = RS_ACTIVE;
3234     newUser->userStorageType = ST_READONLY;
3235
3236     return newUser;
3237 }
3238
3239 /*
3240  * this is a callback that can store all known users based on a
3241  * previously registered application ID 
3242  */
3243 int
3244 usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
3245 {
3246     /*
3247      * figure out our application name 
3248      */
3249     char           *appname = (char *) clientarg;
3250     if (appname == NULL) {
3251         appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
3252                                         NETSNMP_DS_LIB_APPTYPE);
3253     }
3254
3255     /*
3256      * save the user base 
3257      */
3258     usm_save_users("usmUser", appname);
3259
3260     /*
3261      * never fails 
3262      */
3263     return SNMPERR_SUCCESS;
3264 }
3265
3266
3267 /*
3268  * usm_save_users(): saves a list of users to the persistent cache 
3269  */
3270 void
3271 usm_save_users(const char *token, const char *type)
3272 {
3273     usm_save_users_from_list(userList, token, type);
3274 }
3275
3276 void
3277 usm_save_users_from_list(struct usmUser *puserList, const char *token,
3278                          const char *type)
3279 {
3280     struct usmUser *uptr;
3281     for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
3282         if (uptr->userStorageType == ST_NONVOLATILE)
3283             usm_save_user(uptr, token, type);
3284     }
3285 }
3286
3287 /*
3288  * usm_save_user(): saves a user to the persistent cache 
3289  */
3290 void
3291 usm_save_user(struct usmUser *user, const char *token, const char *type)
3292 {
3293     char            line[4096];
3294     char           *cptr;
3295
3296     memset(line, 0, sizeof(line));
3297
3298     sprintf(line, "%s %d %d ", token, user->userStatus,
3299             user->userStorageType);
3300     cptr = &line[strlen(line)]; /* the NULL */
3301     cptr =
3302         read_config_save_octet_string(cptr, user->engineID,
3303                                       user->engineIDLen);
3304     *cptr++ = ' ';
3305     cptr = read_config_save_octet_string(cptr, (u_char *) user->name,
3306                                          (user->name == NULL) ? 0 :
3307                                          strlen(user->name) + 1);
3308     *cptr++ = ' ';
3309     cptr = read_config_save_octet_string(cptr, (u_char *) user->secName,
3310                                          (user->secName == NULL) ? 0 :
3311                                          strlen(user->secName) + 1);
3312     *cptr++ = ' ';
3313     cptr =
3314         read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
3315     *cptr++ = ' ';
3316     cptr = read_config_save_objid(cptr, user->authProtocol,
3317                                   user->authProtocolLen);
3318     *cptr++ = ' ';
3319     cptr =
3320         read_config_save_octet_string(cptr, user->authKey,
3321                                       user->authKeyLen);
3322     *cptr++ = ' ';
3323     cptr = read_config_save_objid(cptr, user->privProtocol,
3324                                   user->privProtocolLen);
3325     *cptr++ = ' ';
3326     cptr =
3327         read_config_save_octet_string(cptr, user->privKey,
3328                                       user->privKeyLen);
3329     *cptr++ = ' ';
3330     cptr = read_config_save_octet_string(cptr, user->userPublicString,
3331                                          (user->userPublicString ==
3332                                           NULL) ? 0 : strlen((char *)
3333                                                              user->
3334                                                              userPublicString)
3335                                          + 1);
3336     read_config_store(type, line);
3337 }
3338
3339 /*
3340  * usm_parse_user(): reads in a line containing a saved user profile
3341  * and returns a pointer to a newly created struct usmUser. 
3342  */
3343 struct usmUser *
3344 usm_read_user(char *line)
3345 {
3346     struct usmUser *user;
3347     size_t          len;
3348
3349     user = usm_create_user();
3350     if (user == NULL)
3351         return NULL;
3352
3353     user->userStatus = atoi(line);
3354     line = skip_token(line);
3355     user->userStorageType = atoi(line);
3356     line = skip_token(line);
3357     line = read_config_read_octet_string(line, &user->engineID,
3358                                          &user->engineIDLen);
3359
3360     /*
3361      * set the lcd entry for this engineID to the minimum boots/time
3362      * values so that its a known engineid and won't return a report pdu.
3363      * This is mostly important when receiving v3 traps so that the usm
3364      * will at least continue processing them. 
3365      */
3366     set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
3367
3368     line = read_config_read_octet_string(line, (u_char **) & user->name,
3369                                          &len);
3370     line = read_config_read_octet_string(line, (u_char **) & user->secName,
3371                                          &len);
3372     SNMP_FREE(user->cloneFrom);
3373     user->cloneFromLen = 0;
3374
3375     line =
3376         read_config_read_objid(line, &user->cloneFrom,
3377                                &user->cloneFromLen);
3378
3379     SNMP_FREE(user->authProtocol);
3380     user->authProtocolLen = 0;
3381
3382     line = read_config_read_objid(line, &user->authProtocol,
3383                                   &user->authProtocolLen);
3384     line = read_config_read_octet_string(line, &user->authKey,
3385                                          &user->authKeyLen);
3386     SNMP_FREE(user->privProtocol);
3387     user->privProtocolLen = 0;
3388
3389     line = read_config_read_objid(line, &user->privProtocol,
3390                                   &user->privProtocolLen);
3391     line = read_config_read_octet_string(line, &user->privKey,
3392                                          &user->privKeyLen);
3393     line = read_config_read_octet_string(line, &user->userPublicString,
3394                                          &len);
3395     return user;
3396 }
3397
3398 /*
3399  * snmpd.conf parsing routines 
3400  */
3401 void
3402 usm_parse_config_usmUser(const char *token, char *line)
3403 {
3404     struct usmUser *uptr;
3405
3406     uptr = usm_read_user(line);
3407     usm_add_user(uptr);
3408 }
3409
3410
3411
3412
3413 /*******************************************************************-o-******
3414  * usm_set_password
3415  *
3416  * Parameters:
3417  *      *token
3418  *      *line
3419  *      
3420  *
3421  * format: userSetAuthPass     secname engineIDLen engineID pass
3422  *     or: userSetPrivPass     secname engineIDLen engineID pass 
3423  *     or: userSetAuthKey      secname engineIDLen engineID KuLen Ku
3424  *     or: userSetPrivKey      secname engineIDLen engineID KuLen Ku 
3425  *     or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
3426  *     or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul 
3427  *
3428  * type is:     1=passphrase; 2=Ku; 3=Kul.
3429  *
3430  *
3431  * ASSUMES  Passwords are null-terminated printable strings.
3432  */
3433 void
3434 usm_set_password(const char *token, char *line)
3435 {
3436     char           *cp;
3437     char            nameBuf[SNMP_MAXBUF];
3438     u_char         *engineID;
3439     size_t          engineIDLen;
3440     struct usmUser *user;
3441
3442     cp = copy_nword(line, nameBuf, sizeof(nameBuf));
3443     if (cp == NULL) {
3444         config_perror("invalid name specifier");
3445         return;
3446     }
3447
3448     DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
3449     if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
3450         /*
3451          * match against all engineIDs we know about 
3452          */
3453         cp = skip_token(cp);
3454         for (user = userList; user != NULL; user = user->next) {
3455             if (strcmp(user->secName, nameBuf) == 0) {
3456                 usm_set_user_password(user, token, cp);
3457             }
3458         }
3459     } else {
3460         cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
3461         if (cp == NULL) {
3462             config_perror("invalid engineID specifier");
3463             return;
3464         }
3465
3466         user = usm_get_user(engineID, engineIDLen, nameBuf);
3467         if (user == NULL) {
3468             config_perror("not a valid user/engineID pair");
3469             return;
3470         }
3471         usm_set_user_password(user, token, cp);
3472     }
3473 }
3474
3475 /*
3476  * uses the rest of LINE to configure USER's password of type TOKEN 
3477  */
3478 void
3479 usm_set_user_password(struct usmUser *user, const char *token, char *line)
3480 {
3481     char           *cp = line;
3482     u_char         *engineID = user->engineID;
3483     size_t          engineIDLen = user->engineIDLen;
3484
3485     u_char        **key;
3486     size_t         *keyLen;
3487     u_char          userKey[SNMP_MAXBUF_SMALL];
3488     size_t          userKeyLen = SNMP_MAXBUF_SMALL;
3489     u_char         *userKeyP = userKey;
3490     int             type, ret;
3491
3492     /*
3493      * Retrieve the "old" key and set the key type.
3494      */
3495     if (strcmp(token, "userSetAuthPass") == 0) {
3496         key = &user->authKey;
3497         keyLen = &user->authKeyLen;
3498         type = 0;
3499     } else if (strcmp(token, "userSetPrivPass") == 0) {
3500         key = &user->privKey;
3501         keyLen = &user->privKeyLen;
3502         type = 0;
3503     } else if (strcmp(token, "userSetAuthKey") == 0) {
3504         key = &user->authKey;
3505         keyLen = &user->authKeyLen;
3506         type = 1;
3507     } else if (strcmp(token, "userSetPrivKey") == 0) {
3508         key = &user->privKey;
3509         keyLen = &user->privKeyLen;
3510         type = 1;
3511     } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
3512         key = &user->authKey;
3513         keyLen = &user->authKeyLen;
3514         type = 2;
3515     } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
3516         key = &user->privKey;
3517         keyLen = &user->privKeyLen;
3518         type = 2;
3519     } else {
3520         /*
3521          * no old key, or token was not recognized 
3522          */
3523         return;
3524     }
3525
3526     if (*key) {
3527         /*
3528          * (destroy and) free the old key 
3529          */
3530         memset(*key, 0, *keyLen);
3531         free(*key);
3532     }
3533
3534     if (type == 0) {
3535         /*
3536          * convert the password into a key 
3537          */
3538         ret = generate_Ku(user->authProtocol, user->authProtocolLen,
3539                           (u_char *) cp, strlen(cp), userKey, &userKeyLen);
3540
3541         if (ret != SNMPERR_SUCCESS) {
3542             config_perror("setting key failed (in sc_genKu())");
3543             return;
3544         }
3545     } else if (type == 1) {
3546         cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen);
3547
3548         if (cp == NULL) {
3549             config_perror("invalid user key");
3550             return;
3551         }
3552     }
3553
3554     if (type < 2) {
3555         *key = (u_char *) malloc(SNMP_MAXBUF_SMALL);
3556         *keyLen = SNMP_MAXBUF_SMALL;
3557         ret = generate_kul(user->authProtocol, user->authProtocolLen,
3558                            engineID, engineIDLen,
3559                            userKey, userKeyLen, *key, keyLen);
3560         if (ret != SNMPERR_SUCCESS) {
3561             config_perror("setting key failed (in generate_kul())");
3562             return;
3563         }
3564
3565         /*
3566          * (destroy and) free the old key 
3567          */
3568         memset(userKey, 0, sizeof(userKey));
3569
3570     } else {
3571         /*
3572          * the key is given, copy it in 
3573          */
3574         cp = read_config_read_octet_string(cp, key, keyLen);
3575
3576         if (cp == NULL) {
3577             config_perror("invalid localized user key");
3578             return;
3579         }
3580     }
3581 }                               /* end usm_set_password() */
3582
3583
3584 #endif /* BRCM_SNMP_MIB_SUPPORT (snmpv3) */