net-snmp  5.4.1
snmpusm.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /*
00006  * Portions of this file are copyrighted by:
00007  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00008  * Use is subject to license terms specified in the COPYING file
00009  * distributed with the Net-SNMP package.
00010  */
00011 /*
00012  * snmpusm.c
00013  *
00014  * Routines to manipulate a information about a "user" as
00015  * defined by the SNMP-USER-BASED-SM-MIB MIB.
00016  *
00017  * All functions usm_set_usmStateReference_*() return 0 on success, -1
00018  * otherwise.
00019  *
00020  * !! Tab stops set to 4 in some parts of this file. !!
00021  *    (Designated on a per function.)
00022  */
00023 
00024 #include <net-snmp/net-snmp-config.h>
00025 
00026 #include <sys/types.h>
00027 #if HAVE_WINSOCK_H
00028 #include <winsock.h>
00029 #endif
00030 #include <stdio.h>
00031 #ifdef HAVE_STDLIB_H
00032 #include <stdlib.h>
00033 #endif
00034 #if TIME_WITH_SYS_TIME
00035 # ifdef WIN32
00036 #  include <sys/timeb.h>
00037 # else
00038 #  include <sys/time.h>
00039 # endif
00040 # include <time.h>
00041 #else
00042 # if HAVE_SYS_TIME_H
00043 #  include <sys/time.h>
00044 # else
00045 #  include <time.h>
00046 # endif
00047 #endif
00048 #if HAVE_STRING_H
00049 #include <string.h>
00050 #else
00051 #include <strings.h>
00052 #endif
00053 #ifdef HAVE_NETINET_IN_H
00054 #include <netinet/in.h>
00055 #endif
00056 
00057 #if HAVE_DMALLOC_H
00058 #include <dmalloc.h>
00059 #endif
00060 
00061 #include <net-snmp/types.h>
00062 #include <net-snmp/output_api.h>
00063 #include <net-snmp/config_api.h>
00064 #include <net-snmp/utilities.h>
00065 
00066 #include <net-snmp/library/asn1.h>
00067 #include <net-snmp/library/snmp_api.h>
00068 #include <net-snmp/library/callback.h>
00069 #include <net-snmp/library/tools.h>
00070 #include <net-snmp/library/keytools.h>
00071 #include <net-snmp/library/snmpv3.h>
00072 #include <net-snmp/library/lcd_time.h>
00073 #include <net-snmp/library/scapi.h>
00074 #include <net-snmp/library/callback.h>
00075 #include <net-snmp/library/snmp_secmod.h>
00076 #include <net-snmp/library/snmpusm.h>
00077 
00078 oid             usmNoAuthProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 };
00079 #ifndef NETSNMP_DISABLE_MD5
00080 oid             usmHMACMD5AuthProtocol[10] =
00081     { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 };
00082 #endif
00083 oid             usmHMACSHA1AuthProtocol[10] =
00084     { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 };
00085 oid             usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
00086 #ifndef NETSNMP_DISABLE_DES
00087 oid             usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
00088 #endif
00089 oid             usmAESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 };
00090 /* backwards compat */
00091 oid             *usmAES128PrivProtocol = usmAESPrivProtocol;
00092 
00093 static u_int    dummy_etime, dummy_eboot;       /* For ISENGINEKNOWN(). */
00094 
00095 /*
00096  * Globals.
00097  */
00098 static u_int    salt_integer;
00099 #ifdef HAVE_AES
00100 static u_int    salt_integer64_1, salt_integer64_2;
00101 #endif
00102         /*
00103          * 1/2 of seed for the salt.   Cf. RFC2274, Sect 8.1.1.1.
00104          */
00105 
00106 static struct usmUser *noNameUser = NULL;
00107 /*
00108  * Local storage (LCD) of the default user list.
00109  */
00110 static struct usmUser *userList = NULL;
00111 
00112 /*
00113  * Prototypes
00114  */
00115 int
00116                 usm_check_secLevel_vs_protocols(int level,
00117                                                 const oid * authProtocol,
00118                                                 u_int authProtocolLen,
00119                                                 const oid * privProtocol,
00120                                                 u_int privProtocolLen);
00121 int
00122                 usm_calc_offsets(size_t globalDataLen,
00123                                  int secLevel, size_t secEngineIDLen,
00124                                  size_t secNameLen, size_t scopedPduLen,
00125                                  u_long engineboots, long engine_time,
00126                                  size_t * theTotalLength,
00127                                  size_t * authParamsOffset,
00128                                  size_t * privParamsOffset,
00129                                  size_t * dataOffset, size_t * datalen,
00130                                  size_t * msgAuthParmLen,
00131                                  size_t * msgPrivParmLen, size_t * otstlen,
00132                                  size_t * seq_len, size_t * msgSecParmLen);
00133 /*
00134  * Set a given field of the secStateRef.
00135  *
00136  * Allocate <len> bytes for type <type> pointed to by ref-><field>.
00137  * Then copy in <item> and record its length in ref-><field_len>.
00138  *
00139  * Return 0 on success, -1 otherwise.
00140  */
00141 #define MAKE_ENTRY( type, item, len, field, field_len )                 \
00142 {                                                                       \
00143         if (ref == NULL)                                                \
00144                 return -1;                                              \
00145         if (ref->field != NULL) {                                       \
00146                 SNMP_ZERO(ref->field, ref->field_len);                  \
00147                 SNMP_FREE(ref->field);                                  \
00148         }                                                               \
00149         ref->field_len = 0;                                             \
00150         if (len == 0 || item == NULL) {                                 \
00151                 return 0;                                               \
00152         }                                                               \
00153         if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
00154         {                                                               \
00155                 return -1;                                              \
00156         }                                                               \
00157                                                                         \
00158         memcpy (ref->field, item, len * sizeof(type));                  \
00159         ref->field_len = len;                                           \
00160                                                                         \
00161         return 0;                                                       \
00162 }
00163 
00164 
00165 struct usmStateReference *
00166 usm_malloc_usmStateReference(void)
00167 {
00168     struct usmStateReference *retval = (struct usmStateReference *)
00169         calloc(1, sizeof(struct usmStateReference));
00170 
00171     return retval;
00172 }                               /* end usm_malloc_usmStateReference() */
00173 
00174 
00175 void
00176 usm_free_usmStateReference(void *old)
00177 {
00178     struct usmStateReference *old_ref = (struct usmStateReference *) old;
00179 
00180     if (old_ref) {
00181 
00182         SNMP_FREE(old_ref->usr_name);
00183         SNMP_FREE(old_ref->usr_engine_id);
00184         SNMP_FREE(old_ref->usr_auth_protocol);
00185         SNMP_FREE(old_ref->usr_priv_protocol);
00186 
00187         if (old_ref->usr_auth_key) {
00188             SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
00189             SNMP_FREE(old_ref->usr_auth_key);
00190         }
00191         if (old_ref->usr_priv_key) {
00192             SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
00193             SNMP_FREE(old_ref->usr_priv_key);
00194         }
00195 
00196         SNMP_ZERO(old_ref, sizeof(*old_ref));
00197         SNMP_FREE(old_ref);
00198 
00199     }
00200 
00201 }                               /* end usm_free_usmStateReference() */
00202 
00203 struct usmUser *
00204 usm_get_userList(void)
00205 {
00206     return userList;
00207 }
00208 
00209 int
00210 usm_set_usmStateReference_name(struct usmStateReference *ref,
00211                                char *name, size_t name_len)
00212 {
00213     MAKE_ENTRY(char, name, name_len, usr_name, usr_name_length);
00214 }
00215 
00216 int
00217 usm_set_usmStateReference_engine_id(struct usmStateReference *ref,
00218                                     u_char * engine_id,
00219                                     size_t engine_id_len)
00220 {
00221     MAKE_ENTRY(u_char, engine_id, engine_id_len,
00222                usr_engine_id, usr_engine_id_length);
00223 }
00224 
00225 int
00226 usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref,
00227                                         oid * auth_protocol,
00228                                         size_t auth_protocol_len)
00229 {
00230     MAKE_ENTRY(oid, auth_protocol, auth_protocol_len,
00231                usr_auth_protocol, usr_auth_protocol_length);
00232 }
00233 
00234 int
00235 usm_set_usmStateReference_auth_key(struct usmStateReference *ref,
00236                                    u_char * auth_key, size_t auth_key_len)
00237 {
00238     MAKE_ENTRY(u_char, auth_key, auth_key_len,
00239                usr_auth_key, usr_auth_key_length);
00240 }
00241 
00242 int
00243 usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref,
00244                                         oid * priv_protocol,
00245                                         size_t priv_protocol_len)
00246 {
00247     MAKE_ENTRY(oid, priv_protocol, priv_protocol_len,
00248                usr_priv_protocol, usr_priv_protocol_length);
00249 }
00250 
00251 int
00252 usm_set_usmStateReference_priv_key(struct usmStateReference *ref,
00253                                    u_char * priv_key, size_t priv_key_len)
00254 {
00255     MAKE_ENTRY(u_char, priv_key, priv_key_len,
00256                usr_priv_key, usr_priv_key_length);
00257 }
00258 
00259 int
00260 usm_set_usmStateReference_sec_level(struct usmStateReference *ref,
00261                                     int sec_level)
00262 {
00263     if (ref == NULL)
00264         return -1;
00265     ref->usr_sec_level = sec_level;
00266     return 0;
00267 }
00268 
00269 
00270 
00271 #ifdef NETSNMP_ENABLE_TESTING_CODE
00272 /*******************************************************************-o-******
00273  * emergency_print
00274  *
00275  * Parameters:
00276  *      *field
00277  *       length
00278  *      
00279  *      This is a print routine that is solely included so that it can be
00280  *      used in gdb.  Don't use it as a function, it will be pulled before
00281  *      a real release of the code.
00282  *
00283  *      tab stop 4
00284  *
00285  *      XXX fflush() only works on FreeBSD; core dumps on Sun OS's
00286  */
00287 void
00288 emergency_print(u_char * field, u_int length)
00289 {
00290     int             iindex;
00291     int             start = 0;
00292     int             stop = 25;
00293 
00294     while (start < stop) {
00295         for (iindex = start; iindex < stop; iindex++)
00296             printf("%02X ", field[iindex]);
00297 
00298         printf("\n");
00299         start = stop;
00300         stop = stop + 25 < length ? stop + 25 : length;
00301     }
00302     fflush(0);
00303 
00304 }                               /* end emergency_print() */
00305 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00306 
00307 
00308 /*******************************************************************-o-******
00309  * asn_predict_int_length
00310  *
00311  * Parameters:
00312  *      type    (UNUSED)
00313  *      number
00314  *      len
00315  *      
00316  * Returns:
00317  *      Number of bytes necessary to store the ASN.1 encoded value of 'number'.
00318  *
00319  *
00320  *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
00321  *      use to encode a particular integer value.
00322  *
00323  *      Returns the length of the integer -- NOT THE HEADER!
00324  *
00325  *      Do this the same way as asn_build_int()...
00326  */
00327 int
00328 asn_predict_int_length(int type, long number, size_t len)
00329 {
00330     register u_long mask;
00331 
00332 
00333     if (len != sizeof(long))
00334         return -1;
00335 
00336     mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
00337     /*
00338      * mask is 0xFF800000 on a big-endian machine 
00339      */
00340 
00341     while ((((number & mask) == 0) || ((number & mask) == mask))
00342            && len > 1) {
00343         len--;
00344         number <<= 8;
00345     }
00346 
00347     return len;
00348 
00349 }                               /* end asn_predict_length() */
00350 
00351 
00352 
00353 
00354 /*******************************************************************-o-******
00355  * asn_predict_length
00356  *
00357  * Parameters:
00358  *       type
00359  *      *ptr
00360  *       u_char_len
00361  *      
00362  * Returns:
00363  *      Length in bytes:        1 + <n> + <u_char_len>, where
00364  *
00365  *              1               For the ASN.1 type.
00366  *              <n>             # of bytes to store length of data.
00367  *              <u_char_len>    Length of data associated with ASN.1 type.
00368  *
00369  *      This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
00370  *      use to encode a particular integer value.  This is as broken as the
00371  *      currently used encoder.
00372  *
00373  * XXX  How is <n> chosen, exactly??
00374  */
00375 int
00376 asn_predict_length(int type, u_char * ptr, size_t u_char_len)
00377 {
00378 
00379     if (type & ASN_SEQUENCE)
00380         return 1 + 3 + u_char_len;
00381 
00382     if (type & ASN_INTEGER) {
00383         u_long          value;
00384         memcpy(&value, ptr, u_char_len);
00385         u_char_len = asn_predict_int_length(type, value, u_char_len);
00386     }
00387 
00388     if (u_char_len < 0x80)
00389         return 1 + 1 + u_char_len;
00390     else if (u_char_len < 0xFF)
00391         return 1 + 2 + u_char_len;
00392     else
00393         return 1 + 3 + u_char_len;
00394 
00395 }                               /* end asn_predict_length() */
00396 
00397 
00398 
00399 
00400 /*******************************************************************-o-******
00401  * usm_calc_offsets
00402  *
00403  * Parameters:
00404  *      (See list below...)
00405  *      
00406  * Returns:
00407  *      0       On success,
00408  *      -1      Otherwise.
00409  *
00410  *
00411  *      This routine calculates the offsets into an outgoing message buffer
00412  *      for the necessary values.  The outgoing buffer will generically
00413  *      look like this:
00414  *
00415  *      SNMPv3 Message
00416  *      SEQ len[11]
00417  *              INT len version
00418  *      Header
00419  *              SEQ len
00420  *                      INT len MsgID
00421  *                      INT len msgMaxSize
00422  *                      OST len msgFlags (OST = OCTET STRING)
00423  *                      INT len msgSecurityModel
00424  *      MsgSecurityParameters
00425  *              [1] OST len[2]
00426  *                      SEQ len[3]
00427  *                              OST len msgAuthoritativeEngineID
00428  *                              INT len msgAuthoritativeEngineBoots
00429  *                              INT len msgAuthoritativeEngineTime
00430  *                              OST len msgUserName
00431  *                              OST len[4] [5] msgAuthenticationParameters
00432  *                              OST len[6] [7] msgPrivacyParameters
00433  *      MsgData
00434  *              [8] OST len[9] [10] encryptedPDU
00435  *              or
00436  *              [8,10] SEQUENCE len[9] scopedPDU
00437  *      [12]
00438  *
00439  *      The bracketed points will be needed to be identified ([x] is an index
00440  *      value, len[x] means a length value).  Here is a semantic guide to them:
00441  *
00442  *      [1] = globalDataLen (input)
00443  *      [2] = otstlen
00444  *      [3] = seq_len
00445  *      [4] = msgAuthParmLen (may be 0 or 12)
00446  *      [5] = authParamsOffset
00447  *      [6] = msgPrivParmLen (may be 0 or 8)
00448  *      [7] = privParamsOffset
00449  *      [8] = globalDataLen + msgSecParmLen
00450  *      [9] = datalen
00451  *      [10] = dataOffset
00452  *      [11] = theTotalLength - the length of the header itself
00453  *      [12] = theTotalLength
00454  */
00455 int
00456 usm_calc_offsets(size_t globalDataLen,  /* SNMPv3Message + HeaderData */
00457                  int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen,   /* An BER encoded sequence. */
00458                  u_long engineboots,    /* XXX (asn1.c works in long, not int.) */
00459                  long engine_time,      /* XXX (asn1.c works in long, not int.) */
00460                  size_t * theTotalLength,       /* globalDataLen + msgSecurityP. + msgData */
00461                  size_t * authParamsOffset,     /* Distance to auth bytes.                 */
00462                  size_t * privParamsOffset,     /* Distance to priv bytes.                 */
00463                  size_t * dataOffset,   /* Distance to scopedPdu SEQ  -or-  the
00464                                          *   crypted (data) portion of msgData.    */
00465                  size_t * datalen,      /* Size of msgData OCTET STRING encoding.  */
00466                  size_t * msgAuthParmLen,       /* Size of msgAuthenticationParameters.    */
00467                  size_t * msgPrivParmLen,       /* Size of msgPrivacyParameters.           */
00468                  size_t * otstlen,      /* Size of msgSecurityP. O.S. encoding.    */
00469                  size_t * seq_len,      /* Size of msgSecurityP. SEQ data.         */
00470                  size_t * msgSecParmLen)
00471 {                               /* Size of msgSecurityP. SEQ.              */
00472     int             engIDlen,   /* Sizes of OCTET STRING and SEQ encodings */
00473                     engBtlen,   /*   for fields within                     */
00474                     engTmlen,   /*   msgSecurityParameters portion of      */
00475                     namelen,    /*   SNMPv3Message.                        */
00476                     authlen, privlen;
00477 
00478     /*
00479      * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
00480      * If doing encryption,     msgPrivParmLen = 8  else msgPrivParmLen = 0.
00481      */
00482     *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
00483                        || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0;
00484 
00485     *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0;
00486 
00487 
00488     /*
00489      * Calculate lengths.
00490      */
00491     if ((engIDlen = asn_predict_length(ASN_OCTET_STR,
00492                                        0, secEngineIDLen)) == -1) {
00493         return -1;
00494     }
00495 
00496     if ((engBtlen = asn_predict_length(ASN_INTEGER,
00497                                        (u_char *) & engineboots,
00498                                        sizeof(long))) == -1) {
00499         return -1;
00500     }
00501 
00502     if ((engTmlen = asn_predict_length(ASN_INTEGER,
00503                                        (u_char *) & engine_time,
00504                                        sizeof(long))) == -1) {
00505         return -1;
00506     }
00507 
00508     if ((namelen = asn_predict_length(ASN_OCTET_STR, 0, secNameLen)) == -1) {
00509         return -1;
00510     }
00511 
00512     if ((authlen = asn_predict_length(ASN_OCTET_STR,
00513                                       0, *msgAuthParmLen)) == -1) {
00514         return -1;
00515     }
00516 
00517     if ((privlen = asn_predict_length(ASN_OCTET_STR,
00518                                       0, *msgPrivParmLen)) == -1) {
00519         return -1;
00520     }
00521 
00522     *seq_len =
00523         engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
00524 
00525     if ((*otstlen = asn_predict_length(ASN_SEQUENCE, 0, *seq_len)) == -1) {
00526         return -1;
00527     }
00528 
00529     if ((*msgSecParmLen = asn_predict_length(ASN_OCTET_STR,
00530                                              0, *otstlen)) == -1) {
00531         return -1;
00532     }
00533 
00534     *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len)
00535         + engIDlen + engBtlen + engTmlen + namelen
00536         + (authlen - *msgAuthParmLen);
00537 
00538     *privParamsOffset = *authParamsOffset + *msgAuthParmLen
00539         + (privlen - *msgPrivParmLen);
00540 
00541 
00542     /*
00543      * Compute the size of the plaintext.  Round up to account for cipher
00544      * block size, if necessary.
00545      *
00546      * XXX  This is hardwired for 1DES... If scopedPduLen is already
00547      *      a multiple of 8, then *add* 8 more; otherwise, round up
00548      *      to the next multiple of 8.
00549      *
00550      * FIX  Calculation of encrypted portion of msgData and consequent
00551      *      setting and sanity checking of theTotalLength, et al. should
00552      *      occur *after* encryption has taken place.
00553      */
00554     if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
00555         scopedPduLen = ROUNDUP8(scopedPduLen);
00556 
00557         if ((*datalen =
00558              asn_predict_length(ASN_OCTET_STR, 0, scopedPduLen)) == -1) {
00559             return -1;
00560         }
00561     } else {
00562         *datalen = scopedPduLen;
00563     }
00564 
00565     *dataOffset = globalDataLen + *msgSecParmLen +
00566         (*datalen - scopedPduLen);
00567     *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
00568 
00569     return 0;
00570 
00571 }                               /* end usm_calc_offsets() */
00572 
00573 
00574 
00575 
00576 
00577 #ifndef NETSNMP_DISABLE_DES
00578 /*******************************************************************-o-******
00579  * usm_set_salt
00580  *
00581  * Parameters:
00582  *      *iv               (O)   Buffer to contain IV.
00583  *      *iv_length        (O)   Length of iv.
00584  *      *priv_salt        (I)   Salt portion of private key.
00585  *       priv_salt_length (I)   Length of priv_salt.
00586  *      *msgSalt          (I/O) Pointer salt portion of outgoing msg buffer.
00587  *      
00588  * Returns:
00589  *      0       On success,
00590  *      -1      Otherwise.
00591  *
00592  *      Determine the initialization vector for the DES-CBC encryption.
00593  *      (Cf. RFC 2274, 8.1.1.1.)
00594  *
00595  *      iv is defined as the concatenation of engineBoots and the
00596  *              salt integer.
00597  *      The salt integer is incremented.
00598  *      The resulting salt is copied into the msgSalt buffer.
00599  *      The result of the concatenation is then XORed with the salt
00600  *              portion of the private key (last 8 bytes).
00601  *      The IV result is returned individually for further use.
00602  */
00603 int
00604 usm_set_salt(u_char * iv,
00605              size_t * iv_length,
00606              u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
00607 {
00608     size_t          propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
00609     int             net_boots;
00610     int             net_salt_int;
00611     /*
00612      * net_* should be encoded in network byte order.  XXX  Why?
00613      */
00614     int             iindex;
00615 
00616 
00617     /*
00618      * Sanity check.
00619      */
00620     if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt)
00621         || (priv_salt_length < propersize_salt)) {
00622         return -1;
00623     }
00624 
00625 
00626     net_boots = htonl(snmpv3_local_snmpEngineBoots());
00627     net_salt_int = htonl(salt_integer);
00628 
00629     salt_integer += 1;
00630 
00631     memcpy(iv, &net_boots, propersize_salt / 2);
00632     memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2);
00633 
00634     if (msgSalt)
00635         memcpy(msgSalt, iv, propersize_salt);
00636 
00637 
00638     /*
00639      * Turn the salt into an IV: XOR <boots, salt_int> with salt
00640      * portion of priv_key.
00641      */
00642     for (iindex = 0; iindex < (int) propersize_salt; iindex++)
00643         iv[iindex] ^= priv_salt[iindex];
00644 
00645 
00646     return 0;
00647 
00648 }                               /* end usm_set_salt() */
00649 #endif
00650 
00651 #ifdef HAVE_AES
00652 /*******************************************************************-o-******
00653  * usm_set_aes_iv
00654  *
00655  * Parameters:
00656  *      *iv               (O)   Buffer to contain IV.
00657  *      *iv_length        (O)   Length of iv.
00658  *      net_boots         (I)   the network byte order of the authEng boots val
00659  *      net_time         (I)   the network byte order of the authEng time val
00660  *      *salt             (O)   A buffer for the outgoing salt (= 8 bytes of iv)
00661  *      
00662  * Returns:
00663  *      0       On success,
00664  *      -1      Otherwise.
00665  *
00666  *      Determine the initialization vector for AES encryption.
00667  *      (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
00668  *
00669  *      iv is defined as the concatenation of engineBoots, engineTime
00670         and a 64 bit salt-integer.
00671  *      The 64 bit salt integer is incremented.
00672  *      The resulting salt is copied into the salt buffer.
00673  *      The IV result is returned individually for further use.
00674  */
00675 int
00676 usm_set_aes_iv(u_char * iv,
00677                size_t * iv_length,
00678                u_int net_boots,
00679                u_int net_time,
00680                u_char * salt)
00681 {
00682     /*
00683      * net_* should be encoded in network byte order.
00684      */
00685     int             net_salt_int1, net_salt_int2;
00686 #define PROPER_AES_IV_SIZE 64
00687 
00688     /*
00689      * Sanity check.
00690      */
00691     if (!iv || !iv_length) {
00692         return -1;
00693     }
00694 
00695     net_salt_int1 = htonl(salt_integer64_1);
00696     net_salt_int2 = htonl(salt_integer64_2);
00697 
00698     if ((salt_integer64_2 += 1) == 0)
00699         salt_integer64_2 += 1;
00700     
00701     /* XXX: warning: hard coded proper lengths */
00702     memcpy(iv, &net_boots, 4);
00703     memcpy(iv+4, &net_time, 4);
00704     memcpy(iv+8, &net_salt_int1, 4);
00705     memcpy(iv+12, &net_salt_int2, 4);
00706 
00707     memcpy(salt, iv+8, 8); /* only copy the needed portion */
00708     return 0;
00709 }                               /* end usm_set_salt() */
00710 #endif /* HAVE_AES */
00711 
00712 int
00713 usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
00714 {
00715     if (!parms)
00716         return SNMPERR_GENERR;
00717 
00718     return usm_generate_out_msg(parms->msgProcModel,
00719                                 parms->globalData, parms->globalDataLen,
00720                                 parms->maxMsgSize, parms->secModel,
00721                                 parms->secEngineID, parms->secEngineIDLen,
00722                                 parms->secName, parms->secNameLen,
00723                                 parms->secLevel,
00724                                 parms->scopedPdu, parms->scopedPduLen,
00725                                 parms->secStateRef,
00726                                 parms->secParams, parms->secParamsLen,
00727                                 parms->wholeMsg, parms->wholeMsgLen);
00728 }
00729 
00730 /*******************************************************************-o-******
00731  * usm_generate_out_msg
00732  *
00733  * Parameters:
00734  *      (See list below...)
00735  *      
00736  * Returns:
00737  *      SNMPERR_SUCCESS                 On success.
00738  *      SNMPERR_USM_AUTHENTICATIONFAILURE
00739  *      SNMPERR_USM_ENCRYPTIONERROR
00740  *      SNMPERR_USM_GENERICERROR
00741  *      SNMPERR_USM_UNKNOWNSECURITYNAME
00742  *      SNMPERR_USM_GENERICERROR
00743  *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
00744  *      
00745  *
00746  * Generates an outgoing message.
00747  *
00748  * XXX  Beware of misnomers!
00749  */
00750 int
00751 usm_generate_out_msg(int msgProcModel,  /* (UNUSED) */
00752                      u_char * globalData,       /* IN */
00753                      /*
00754                       * Pointer to msg header data will point to the beginning
00755                       * * of the entire packet buffer to be transmitted on wire,
00756                       * * memory will be contiguous with secParams, typically
00757                       * * this pointer will be passed back as beginning of
00758                       * * wholeMsg below.  asn seq. length is updated w/ new length.
00759                       * *
00760                       * * While this points to a buffer that should be big enough
00761                       * * for the whole message, only the first two parts
00762                       * * of the message are completed, namely SNMPv3Message and
00763                       * * HeaderData.  globalDataLen (next parameter) represents
00764                       * * the length of these two completed parts.
00765                       */
00766                      size_t globalDataLen,      /* IN - Length of msg header data.      */
00767                      int maxMsgSize,    /* (UNUSED) */
00768                      int secModel,      /* (UNUSED) */
00769                      u_char * secEngineID,      /* IN - Pointer snmpEngineID.           */
00770                      size_t secEngineIDLen,     /* IN - SnmpEngineID length.            */
00771                      char *secName,     /* IN - Pointer to securityName.        */
00772                      size_t secNameLen, /* IN - SecurityName length.            */
00773                      int secLevel,      /* IN - AuthNoPriv, authPriv etc.       */
00774                      u_char * scopedPdu,        /* IN */
00775                      /*
00776                       * Pointer to scopedPdu will be encrypted by USM if needed
00777                       * * and written to packet buffer immediately following
00778                       * * securityParameters, entire msg will be authenticated by
00779                       * * USM if needed.
00780                       */
00781                      size_t scopedPduLen,       /* IN - scopedPdu length. */
00782                      void *secStateRef, /* IN */
00783                      /*
00784                       * secStateRef, pointer to cached info provided only for
00785                       * * Response, otherwise NULL.
00786                       */
00787                      u_char * secParams,        /* OUT */
00788                      /*
00789                       * BER encoded securityParameters pointer to offset within
00790                       * * packet buffer where secParams should be written, the
00791                       * * entire BER encoded OCTET STRING (including header) is
00792                       * * written here by USM secParams = globalData +
00793                       * * globalDataLen.
00794                       */
00795                      size_t * secParamsLen,     /* IN/OUT - Len available, len returned. */
00796                      u_char ** wholeMsg,        /* OUT */
00797                      /*
00798                       * Complete authenticated/encrypted message - typically
00799                       * * the pointer to start of packet buffer provided in
00800                       * * globalData is returned here, could also be a separate
00801                       * * buffer.
00802                       */
00803                      size_t * wholeMsgLen)
00804 {                               /* IN/OUT - Len available, len returned. */
00805     size_t          otstlen;
00806     size_t          seq_len;
00807     size_t          msgAuthParmLen;
00808     size_t          msgPrivParmLen;
00809     size_t          msgSecParmLen;
00810     size_t          authParamsOffset;
00811     size_t          privParamsOffset;
00812     size_t          datalen;
00813     size_t          dataOffset;
00814     size_t          theTotalLength;
00815 
00816     u_char         *ptr;
00817     size_t          ptr_len;
00818     size_t          remaining;
00819     size_t          offSet;
00820     u_int           boots_uint;
00821     u_int           time_uint;
00822     long            boots_long;
00823     long            time_long;
00824 
00825     /*
00826      * Indirection because secStateRef values override parameters.
00827      * 
00828      * None of these are to be free'd - they are either pointing to
00829      * what's in the secStateRef or to something either in the
00830      * actual prarmeter list or the user list.
00831      */
00832 
00833     char           *theName = NULL;
00834     u_int           theNameLength = 0;
00835     u_char         *theEngineID = NULL;
00836     u_int           theEngineIDLength = 0;
00837     u_char         *theAuthKey = NULL;
00838     u_int           theAuthKeyLength = 0;
00839     const oid      *theAuthProtocol = NULL;
00840     u_int           theAuthProtocolLength = 0;
00841     u_char         *thePrivKey = NULL;
00842     u_int           thePrivKeyLength = 0;
00843     const oid      *thePrivProtocol = NULL;
00844     u_int           thePrivProtocolLength = 0;
00845     int             theSecLevel = 0;    /* No defined const for bad
00846                                          * value (other then err).
00847                                          */
00848 
00849     DEBUGMSGTL(("usm", "USM processing has begun.\n"));
00850 
00851     if (secStateRef != NULL) {
00852         /*
00853          * To hush the compiler for now.  XXX 
00854          */
00855         struct usmStateReference *ref
00856             = (struct usmStateReference *) secStateRef;
00857 
00858         theName = ref->usr_name;
00859         theNameLength = ref->usr_name_length;
00860         theEngineID = ref->usr_engine_id;
00861         theEngineIDLength = ref->usr_engine_id_length;
00862 
00863         if (!theEngineIDLength) {
00864             theEngineID = secEngineID;
00865             theEngineIDLength = secEngineIDLen;
00866         }
00867 
00868         theAuthProtocol = ref->usr_auth_protocol;
00869         theAuthProtocolLength = ref->usr_auth_protocol_length;
00870         theAuthKey = ref->usr_auth_key;
00871         theAuthKeyLength = ref->usr_auth_key_length;
00872         thePrivProtocol = ref->usr_priv_protocol;
00873         thePrivProtocolLength = ref->usr_priv_protocol_length;
00874         thePrivKey = ref->usr_priv_key;
00875         thePrivKeyLength = ref->usr_priv_key_length;
00876         theSecLevel = ref->usr_sec_level;
00877     }
00878 
00879     /*
00880      * Identify the user record.
00881      */
00882     else {
00883         struct usmUser *user;
00884 
00885         /*
00886          * we do allow an unknown user name for
00887          * unauthenticated requests. 
00888          */
00889         if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
00890             == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
00891             DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
00892             usm_free_usmStateReference(secStateRef);
00893             return SNMPERR_USM_UNKNOWNSECURITYNAME;
00894         }
00895 
00896         theName = secName;
00897         theNameLength = secNameLen;
00898         theEngineID = secEngineID;
00899         theSecLevel = secLevel;
00900         theEngineIDLength = secEngineIDLen;
00901         if (user) {
00902             theAuthProtocol = user->authProtocol;
00903             theAuthProtocolLength = user->authProtocolLen;
00904             theAuthKey = user->authKey;
00905             theAuthKeyLength = user->authKeyLen;
00906             thePrivProtocol = user->privProtocol;
00907             thePrivProtocolLength = user->privProtocolLen;
00908             thePrivKey = user->privKey;
00909             thePrivKeyLength = user->privKeyLen;
00910         } else {
00911             /*
00912              * unknown users can not do authentication (obviously) 
00913              */
00914             theAuthProtocol = usmNoAuthProtocol;
00915             theAuthProtocolLength =
00916                 sizeof(usmNoAuthProtocol) / sizeof(oid);
00917             theAuthKey = NULL;
00918             theAuthKeyLength = 0;
00919             thePrivProtocol = usmNoPrivProtocol;
00920             thePrivProtocolLength =
00921                 sizeof(usmNoPrivProtocol) / sizeof(oid);
00922             thePrivKey = NULL;
00923             thePrivKeyLength = 0;
00924         }
00925     }                           /* endif -- secStateRef==NULL */
00926 
00927 
00928     /*
00929      * From here to the end of the function, avoid reference to
00930      * secName, secEngineID, secLevel, and associated lengths.
00931      */
00932 
00933 
00934     /*
00935      * Check to see if the user can use the requested sec services.
00936      */
00937     if (usm_check_secLevel_vs_protocols(theSecLevel,
00938                                         theAuthProtocol,
00939                                         theAuthProtocolLength,
00940                                         thePrivProtocol,
00941                                         thePrivProtocolLength) == 1) {
00942         DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
00943                     theSecLevel));
00944         usm_free_usmStateReference(secStateRef);
00945         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
00946     }
00947 
00948 
00949     /*
00950      * Retrieve the engine information.
00951      *
00952      * XXX  No error is declared in the EoP when sending messages to
00953      *      unknown engines, processing continues w/ boots/time == (0,0).
00954      */
00955     if (get_enginetime(theEngineID, theEngineIDLength,
00956                        &boots_uint, &time_uint, FALSE) == -1) {
00957         DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
00958     }
00959 
00960     boots_long = boots_uint;
00961     time_long = time_uint;
00962 
00963 
00964     /*
00965      * Set up the Offsets.
00966      */
00967     if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength,
00968                          theNameLength, scopedPduLen, boots_long,
00969                          time_long, &theTotalLength, &authParamsOffset,
00970                          &privParamsOffset, &dataOffset, &datalen,
00971                          &msgAuthParmLen, &msgPrivParmLen, &otstlen,
00972                          &seq_len, &msgSecParmLen) == -1) {
00973         DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
00974         usm_free_usmStateReference(secStateRef);
00975         return SNMPERR_USM_GENERICERROR;
00976     }
00977 
00978     /*
00979      * So, we have the offsets for the three parts that need to be
00980      * determined, and an overall length.  Now we need to make
00981      * sure all of this would fit in the outgoing buffer, and
00982      * whether or not we need to make a new buffer, etc.
00983      */
00984 
00985 
00986     /*
00987      * Set wholeMsg as a pointer to globalData.  Sanity check for
00988      * the proper size.
00989      * 
00990      * Mark workspace in the message with bytes of all 1's to make it
00991      * easier to find mistakes in raw message dumps.
00992      */
00993     ptr = *wholeMsg = globalData;
00994     if (theTotalLength > *wholeMsgLen) {
00995         DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
00996         usm_free_usmStateReference(secStateRef);
00997         return SNMPERR_USM_GENERICERROR;
00998     }
00999 
01000     ptr_len = *wholeMsgLen = theTotalLength;
01001 
01002 #ifdef NETSNMP_ENABLE_TESTING_CODE
01003     memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);
01004 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
01005 
01006     /*
01007      * Do the encryption.
01008      */
01009     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01010         size_t          encrypted_length = theTotalLength - dataOffset;
01011         size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
01012         u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
01013 
01014         /*
01015          * XXX  Hardwired to seek into a 1DES private key!
01016          */
01017 #ifdef HAVE_AES
01018         if (ISTRANSFORM(thePrivProtocol, AESPriv)) {
01019             if (!thePrivKey ||
01020                 usm_set_aes_iv(salt, &salt_length,
01021                                htonl(boots_uint), htonl(time_uint),
01022                                &ptr[privParamsOffset]) == -1) {
01023                 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
01024                 usm_free_usmStateReference(secStateRef);
01025                 return SNMPERR_USM_GENERICERROR;
01026             }
01027         } 
01028 #endif
01029 #ifndef NETSNMP_DISABLE_DES
01030         if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
01031             if (!thePrivKey ||
01032                 (usm_set_salt(salt, &salt_length,
01033                               thePrivKey + 8, thePrivKeyLength - 8,
01034                               &ptr[privParamsOffset])
01035                  == -1)) {
01036                 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
01037                 usm_free_usmStateReference(secStateRef);
01038                 return SNMPERR_USM_GENERICERROR;
01039             }
01040         }
01041 #endif
01042 
01043         if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
01044                        thePrivKey, thePrivKeyLength,
01045                        salt, salt_length,
01046                        scopedPdu, scopedPduLen,
01047                        &ptr[dataOffset], &encrypted_length)
01048             != SNMP_ERR_NOERROR) {
01049             DEBUGMSGTL(("usm", "encryption error.\n"));
01050             usm_free_usmStateReference(secStateRef);
01051             return SNMPERR_USM_ENCRYPTIONERROR;
01052         }
01053 #ifdef NETSNMP_ENABLE_TESTING_CODE
01054         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
01055             dump_chunk("usm/dump", "This data was encrypted:",
01056                        scopedPdu, scopedPduLen);
01057             dump_chunk("usm/dump", "salt + Encrypted form:",
01058                        salt, salt_length);
01059             dump_chunk("usm/dump", NULL,
01060                        &ptr[dataOffset], encrypted_length);
01061             dump_chunk("usm/dump", "*wholeMsg:",
01062                        *wholeMsg, theTotalLength);
01063         }
01064 #endif
01065 
01066 
01067         ptr = *wholeMsg;
01068         ptr_len = *wholeMsgLen = theTotalLength;
01069 
01070 
01071         /*
01072          * XXX  Sanity check for salt length should be moved up
01073          *      under usm_calc_offsets() or tossed.
01074          */
01075         if ((encrypted_length != (theTotalLength - dataOffset))
01076             || (salt_length != msgPrivParmLen)) {
01077             DEBUGMSGTL(("usm", "encryption length error.\n"));
01078             usm_free_usmStateReference(secStateRef);
01079             return SNMPERR_USM_ENCRYPTIONERROR;
01080         }
01081 
01082         DEBUGMSGTL(("usm", "Encryption successful.\n"));
01083     }
01084 
01085     /*
01086      * No encryption for you!
01087      */
01088     else {
01089         memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen);
01090     }
01091 
01092 
01093 
01094     /*
01095      * Start filling in the other fields (in prep for authentication).
01096      * 
01097      * offSet is an octet string header, which is different from all
01098      * the other headers.
01099      */
01100     remaining = ptr_len - globalDataLen;
01101 
01102     offSet = ptr_len - remaining;
01103     asn_build_header(&ptr[offSet], &remaining,
01104                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01105                                ASN_OCTET_STR), otstlen);
01106 
01107     offSet = ptr_len - remaining;
01108     asn_build_sequence(&ptr[offSet], &remaining,
01109                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
01110 
01111     offSet = ptr_len - remaining;
01112     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
01113     asn_build_string(&ptr[offSet], &remaining,
01114                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01115                                ASN_OCTET_STR), theEngineID,
01116                      theEngineIDLength);
01117     DEBUGINDENTLESS();
01118 
01119     offSet = ptr_len - remaining;
01120     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
01121     asn_build_int(&ptr[offSet], &remaining,
01122                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
01123                   &boots_long, sizeof(long));
01124     DEBUGINDENTLESS();
01125 
01126     offSet = ptr_len - remaining;
01127     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
01128     asn_build_int(&ptr[offSet], &remaining,
01129                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
01130                   &time_long, sizeof(long));
01131     DEBUGINDENTLESS();
01132 
01133     offSet = ptr_len - remaining;
01134     DEBUGDUMPHEADER("send", "msgUserName");
01135     asn_build_string(&ptr[offSet], &remaining,
01136                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01137                                ASN_OCTET_STR), (u_char *) theName,
01138                      theNameLength);
01139     DEBUGINDENTLESS();
01140 
01141 
01142     /*
01143      * Note: if there is no authentication being done,
01144      * msgAuthParmLen is 0, and there is no effect (other than
01145      * inserting a zero-length header) of the following
01146      * statements.
01147      */
01148 
01149     offSet = ptr_len - remaining;
01150     asn_build_header(&ptr[offSet],
01151                      &remaining,
01152                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01153                                ASN_OCTET_STR), msgAuthParmLen);
01154 
01155     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
01156         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01157         offSet = ptr_len - remaining;
01158         memset(&ptr[offSet], 0, msgAuthParmLen);
01159     }
01160 
01161     remaining -= msgAuthParmLen;
01162 
01163 
01164     /*
01165      * Note: if there is no encryption being done, msgPrivParmLen
01166      * is 0, and there is no effect (other than inserting a
01167      * zero-length header) of the following statements.
01168      */
01169 
01170     offSet = ptr_len - remaining;
01171     asn_build_header(&ptr[offSet],
01172                      &remaining,
01173                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01174                                ASN_OCTET_STR), msgPrivParmLen);
01175 
01176     remaining -= msgPrivParmLen;        /* Skipping the IV already there. */
01177 
01178 
01179     /*
01180      * For privacy, need to add the octet string header for it.
01181      */
01182     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01183         offSet = ptr_len - remaining;
01184         asn_build_header(&ptr[offSet],
01185                          &remaining,
01186                          (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01187                                    ASN_OCTET_STR),
01188                          theTotalLength - dataOffset);
01189     }
01190 
01191 
01192     /*
01193      * Adjust overall length and store it as the first SEQ length
01194      * of the SNMPv3Message.
01195      *
01196      * FIX  4 is a magic number!
01197      */
01198     remaining = theTotalLength;
01199     asn_build_sequence(ptr, &remaining,
01200                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
01201                        theTotalLength - 4);
01202 
01203 
01204     /*
01205      * Now, time to consider / do authentication.
01206      */
01207     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
01208         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01209         size_t          temp_sig_len = msgAuthParmLen;
01210         u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
01211 
01212         if (temp_sig == NULL) {
01213             DEBUGMSGTL(("usm", "Out of memory.\n"));
01214             usm_free_usmStateReference(secStateRef);
01215             return SNMPERR_USM_GENERICERROR;
01216         }
01217 
01218         if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
01219                                    theAuthKey, theAuthKeyLength,
01220                                    ptr, ptr_len, temp_sig, &temp_sig_len)
01221             != SNMP_ERR_NOERROR) {
01222             /*
01223              * FIX temp_sig_len defined?!
01224              */
01225             SNMP_ZERO(temp_sig, temp_sig_len);
01226             SNMP_FREE(temp_sig);
01227             DEBUGMSGTL(("usm", "Signing failed.\n"));
01228             usm_free_usmStateReference(secStateRef);
01229             return SNMPERR_USM_AUTHENTICATIONFAILURE;
01230         }
01231 
01232         if (temp_sig_len != msgAuthParmLen) {
01233             SNMP_ZERO(temp_sig, temp_sig_len);
01234             SNMP_FREE(temp_sig);
01235             DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
01236             usm_free_usmStateReference(secStateRef);
01237             return SNMPERR_USM_AUTHENTICATIONFAILURE;
01238         }
01239 
01240         memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
01241 
01242         SNMP_ZERO(temp_sig, temp_sig_len);
01243         SNMP_FREE(temp_sig);
01244 
01245     }
01246 
01247     /*
01248      * endif -- create keyed hash 
01249      */
01250     usm_free_usmStateReference(secStateRef);
01251 
01252     DEBUGMSGTL(("usm", "USM processing completed.\n"));
01253 
01254     return SNMPERR_SUCCESS;
01255 
01256 }                               /* end usm_generate_out_msg() */
01257 
01258 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
01259 int
01260 usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
01261 {
01262     if (!parms)
01263         return SNMPERR_GENERR;
01264 
01265     return usm_rgenerate_out_msg(parms->msgProcModel,
01266                                  parms->globalData, parms->globalDataLen,
01267                                  parms->maxMsgSize, parms->secModel,
01268                                  parms->secEngineID, parms->secEngineIDLen,
01269                                  parms->secName, parms->secNameLen,
01270                                  parms->secLevel,
01271                                  parms->scopedPdu, parms->scopedPduLen,
01272                                  parms->secStateRef,
01273                                  parms->wholeMsg, parms->wholeMsgLen,
01274                                  parms->wholeMsgOffset);
01275 }
01276 
01277 int
01278 usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
01279                       u_char * globalData,      /* IN */
01280                       /*
01281                        * points at the msgGlobalData, which is of length given by next 
01282                        * parameter.  
01283                        */
01284                       size_t globalDataLen,     /* IN - Length of msg header data.      */
01285                       int maxMsgSize,   /* (UNUSED) */
01286                       int secModel,     /* (UNUSED) */
01287                       u_char * secEngineID,     /* IN - Pointer snmpEngineID.           */
01288                       size_t secEngineIDLen,    /* IN - SnmpEngineID length.            */
01289                       char *secName,    /* IN - Pointer to securityName.        */
01290                       size_t secNameLen,        /* IN - SecurityName length.            */
01291                       int secLevel,     /* IN - AuthNoPriv, authPriv etc.       */
01292                       u_char * scopedPdu,       /* IN */
01293                       /*
01294                        * Pointer to scopedPdu will be encrypted by USM if needed
01295                        * * and written to packet buffer immediately following
01296                        * * securityParameters, entire msg will be authenticated by
01297                        * * USM if needed.
01298                        */
01299                       size_t scopedPduLen,      /* IN - scopedPdu length. */
01300                       void *secStateRef,        /* IN */
01301                       /*
01302                        * secStateRef, pointer to cached info provided only for
01303                        * * Response, otherwise NULL.
01304                        */
01305                       u_char ** wholeMsg,       /*  IN/OUT  */
01306                       /*
01307                        * Points at the pointer to the packet buffer, which might get extended
01308                        * if necessary via realloc().  
01309                        */
01310                       size_t * wholeMsgLen,     /*  IN/OUT  */
01311                       /*
01312                        * Length of the entire packet buffer, **not** the length of the
01313                        * packet.  
01314                        */
01315                       size_t * offset   /*  IN/OUT  */
01316                       /*
01317                        * Offset from the end of the packet buffer to the start of the packet,
01318                        * also known as the packet length.  
01319                        */
01320     )
01321 {
01322     size_t          msgAuthParmLen = 0;
01323 #ifdef NETSNMP_ENABLE_TESTING_CODE
01324     size_t          theTotalLength;
01325 #endif
01326 
01327     u_int           boots_uint;
01328     u_int           time_uint;
01329     long            boots_long;
01330     long            time_long;
01331 
01332     /*
01333      * Indirection because secStateRef values override parameters.
01334      * 
01335      * None of these are to be free'd - they are either pointing to
01336      * what's in the secStateRef or to something either in the
01337      * actual parameter list or the user list.
01338      */
01339 
01340     char           *theName = NULL;
01341     u_int           theNameLength = 0;
01342     u_char         *theEngineID = NULL;
01343     u_int           theEngineIDLength = 0;
01344     u_char         *theAuthKey = NULL;
01345     u_int           theAuthKeyLength = 0;
01346     const oid      *theAuthProtocol = NULL;
01347     u_int           theAuthProtocolLength = 0;
01348     u_char         *thePrivKey = NULL;
01349     u_int           thePrivKeyLength = 0;
01350     const oid      *thePrivProtocol = NULL;
01351     u_int           thePrivProtocolLength = 0;
01352     int             theSecLevel = 0;    /* No defined const for bad
01353                                          * value (other then err). */
01354     size_t          salt_length = 0, save_salt_length = 0, save_salt_offset = 0;
01355     u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
01356     u_char          authParams[USM_MAX_AUTHSIZE];
01357     u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
01358     size_t          sp_offset = 0, mac_offset = 0;
01359     int             rc = 0;
01360 
01361     DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", *offset));
01362 
01363     if (secStateRef != NULL) {
01364         /*
01365          * To hush the compiler for now.  XXX 
01366          */
01367         struct usmStateReference *ref
01368             = (struct usmStateReference *) secStateRef;
01369 
01370         theName = ref->usr_name;
01371         theNameLength = ref->usr_name_length;
01372         theEngineID = ref->usr_engine_id;
01373         theEngineIDLength = ref->usr_engine_id_length;
01374 
01375         if (!theEngineIDLength) {
01376             theEngineID = secEngineID;
01377             theEngineIDLength = secEngineIDLen;
01378         }
01379 
01380         theAuthProtocol = ref->usr_auth_protocol;
01381         theAuthProtocolLength = ref->usr_auth_protocol_length;
01382         theAuthKey = ref->usr_auth_key;
01383         theAuthKeyLength = ref->usr_auth_key_length;
01384         thePrivProtocol = ref->usr_priv_protocol;
01385         thePrivProtocolLength = ref->usr_priv_protocol_length;
01386         thePrivKey = ref->usr_priv_key;
01387         thePrivKeyLength = ref->usr_priv_key_length;
01388         theSecLevel = ref->usr_sec_level;
01389     }
01390 
01391     /*
01392      * * Identify the user record.
01393      */
01394     else {
01395         struct usmUser *user;
01396 
01397         /*
01398          * we do allow an unknown user name for
01399          * unauthenticated requests. 
01400          */
01401         if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
01402             == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
01403             DEBUGMSGTL(("usm", "Unknown User\n"));
01404             usm_free_usmStateReference(secStateRef);
01405             return SNMPERR_USM_UNKNOWNSECURITYNAME;
01406         }
01407 
01408         theName = secName;
01409         theNameLength = secNameLen;
01410         theEngineID = secEngineID;
01411         theSecLevel = secLevel;
01412         theEngineIDLength = secEngineIDLen;
01413         if (user) {
01414             theAuthProtocol = user->authProtocol;
01415             theAuthProtocolLength = user->authProtocolLen;
01416             theAuthKey = user->authKey;
01417             theAuthKeyLength = user->authKeyLen;
01418             thePrivProtocol = user->privProtocol;
01419             thePrivProtocolLength = user->privProtocolLen;
01420             thePrivKey = user->privKey;
01421             thePrivKeyLength = user->privKeyLen;
01422         } else {
01423             /*
01424              * unknown users can not do authentication (obviously) 
01425              */
01426             theAuthProtocol = usmNoAuthProtocol;
01427             theAuthProtocolLength =
01428                 sizeof(usmNoAuthProtocol) / sizeof(oid);
01429             theAuthKey = NULL;
01430             theAuthKeyLength = 0;
01431             thePrivProtocol = usmNoPrivProtocol;
01432             thePrivProtocolLength =
01433                 sizeof(usmNoPrivProtocol) / sizeof(oid);
01434             thePrivKey = NULL;
01435             thePrivKeyLength = 0;
01436         }
01437     }                           /* endif -- secStateRef==NULL */
01438 
01439 
01440     /*
01441      * From here to the end of the function, avoid reference to
01442      * secName, secEngineID, secLevel, and associated lengths.
01443      */
01444 
01445 
01446     /*
01447      * Check to see if the user can use the requested sec services.
01448      */
01449     if (usm_check_secLevel_vs_protocols(theSecLevel,
01450                                         theAuthProtocol,
01451                                         theAuthProtocolLength,
01452                                         thePrivProtocol,
01453                                         thePrivProtocolLength) == 1) {
01454         DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
01455                     theSecLevel));
01456 
01457         usm_free_usmStateReference(secStateRef);
01458         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
01459     }
01460 
01461 
01462     /*
01463      * * Retrieve the engine information.
01464      * *
01465      * * XXX    No error is declared in the EoP when sending messages to
01466      * *        unknown engines, processing continues w/ boots/time == (0,0).
01467      */
01468     if (get_enginetime(theEngineID, theEngineIDLength,
01469                        &boots_uint, &time_uint, FALSE) == -1) {
01470         DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
01471     }
01472 
01473     boots_long = boots_uint;
01474     time_long = time_uint;
01475 
01476     if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01477         /*
01478          * Initially assume that the ciphertext will end up the same size as
01479          * the plaintext plus some padding.  Really sc_encrypt ought to be able
01480          * to grow this for us, a la asn_realloc_rbuild_<type> functions, but
01481          * this will do for now.  
01482          */
01483         u_char         *ciphertext = NULL;
01484         size_t          ciphertextlen = scopedPduLen + 64;
01485 
01486         if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) {
01487             DEBUGMSGTL(("usm",
01488                         "couldn't malloc %d bytes for encrypted PDU\n",
01489                         ciphertextlen));
01490             usm_free_usmStateReference(secStateRef);
01491             return SNMPERR_MALLOC;
01492         }
01493 
01494         /*
01495          * XXX Hardwired to seek into a 1DES private key!  
01496          */
01497 #ifdef HAVE_AES
01498         if (ISTRANSFORM(thePrivProtocol, AESPriv)) {
01499             salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
01500             save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
01501             save_salt_offset = 0;
01502             if (!thePrivKey ||
01503                 usm_set_aes_iv(salt, &salt_length,
01504                                htonl(boots_uint), htonl(time_uint),
01505                                iv) == -1) {
01506                 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
01507                 usm_free_usmStateReference(secStateRef);
01508                 SNMP_FREE(ciphertext);
01509                 return SNMPERR_USM_GENERICERROR;
01510             }
01511         } 
01512 #endif
01513 #ifndef NETSNMP_DISABLE_DES
01514         if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
01515             salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
01516             save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
01517             save_salt_offset = 0;
01518             if (!thePrivKey || (usm_set_salt(salt, &salt_length,
01519                                              thePrivKey + 8,
01520                                              thePrivKeyLength - 8,
01521                                              iv) == -1)) {
01522                 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
01523                 usm_free_usmStateReference(secStateRef);
01524                 SNMP_FREE(ciphertext);
01525                 return SNMPERR_USM_GENERICERROR;
01526             }
01527         }
01528 #endif
01529 #ifdef NETSNMP_ENABLE_TESTING_CODE
01530         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
01531             dump_chunk("usm/dump", "This data was encrypted:",
01532                        scopedPdu, scopedPduLen);
01533         }
01534 #endif
01535 
01536         if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
01537                        thePrivKey, thePrivKeyLength,
01538                        salt, salt_length,
01539                        scopedPdu, scopedPduLen,
01540                        ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
01541             DEBUGMSGTL(("usm", "encryption error.\n"));
01542             usm_free_usmStateReference(secStateRef);
01543             SNMP_FREE(ciphertext);
01544             return SNMPERR_USM_ENCRYPTIONERROR;
01545         }
01546 
01547         /*
01548          * Write the encrypted scopedPdu back into the packet buffer.  
01549          */
01550 
01551 #ifdef NETSNMP_ENABLE_TESTING_CODE
01552         theTotalLength = *wholeMsgLen;
01553 #endif
01554         *offset = 0;
01555         rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
01556                                        (u_char) (ASN_UNIVERSAL |
01557                                                  ASN_PRIMITIVE |
01558                                                  ASN_OCTET_STR),
01559                                        ciphertext, ciphertextlen);
01560 #ifdef NETSNMP_ENABLE_TESTING_CODE
01561         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
01562             dump_chunk("usm/dump", "salt + Encrypted form: ", salt,
01563                        salt_length);
01564             dump_chunk("usm/dump", "wholeMsg:",
01565                        (*wholeMsg + *wholeMsgLen - *offset), *offset);
01566         }
01567 #endif
01568 
01569         DEBUGMSGTL(("usm", "Encryption successful.\n"));
01570         SNMP_FREE(ciphertext);
01571     } else {
01572         /*
01573          * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV  
01574          */
01575     }
01576 
01577     /*
01578      * Start encoding the msgSecurityParameters.  
01579      */
01580 
01581     sp_offset = *offset;
01582 
01583     DEBUGDUMPHEADER("send", "msgPrivacyParameters");
01584     /*
01585      * msgPrivacyParameters (warning: assumes DES salt).  
01586      */
01587     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
01588                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
01589                                              | ASN_OCTET_STR),
01590                                    iv,
01591                                    save_salt_length);
01592     DEBUGINDENTLESS();
01593     if (rc == 0) {
01594         DEBUGMSGTL(("usm", "building privParams failed.\n"));
01595         usm_free_usmStateReference(secStateRef);
01596         return SNMPERR_TOO_LONG;
01597     }
01598 
01599     DEBUGDUMPHEADER("send", "msgAuthenticationParameters");
01600     /*
01601      * msgAuthenticationParameters (warnings assumes 0x00 by 12).  
01602      */
01603     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
01604         || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01605         memset(authParams, 0, USM_MD5_AND_SHA_AUTH_LEN);
01606         msgAuthParmLen = USM_MD5_AND_SHA_AUTH_LEN;
01607     }
01608 
01609     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
01610                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
01611                                              | ASN_OCTET_STR), authParams,
01612                                    msgAuthParmLen);
01613     DEBUGINDENTLESS();
01614     if (rc == 0) {
01615         DEBUGMSGTL(("usm", "building authParams failed.\n"));
01616         usm_free_usmStateReference(secStateRef);
01617         return SNMPERR_TOO_LONG;
01618     }
01619 
01620     /*
01621      * Remember where to put the actual HMAC we calculate later on.  An
01622      * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1
01623      * header of length 2, hence the fudge factor.  
01624      */
01625 
01626     mac_offset = *offset - 2;
01627 
01628     /*
01629      * msgUserName.  
01630      */
01631     DEBUGDUMPHEADER("send", "msgUserName");
01632     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
01633                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
01634                                              | ASN_OCTET_STR),
01635                                    (u_char *) theName, theNameLength);
01636     DEBUGINDENTLESS();
01637     if (rc == 0) {
01638         DEBUGMSGTL(("usm", "building authParams failed.\n"));
01639         usm_free_usmStateReference(secStateRef);
01640         return SNMPERR_TOO_LONG;
01641     }
01642 
01643     /*
01644      * msgAuthoritativeEngineTime.  
01645      */
01646     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
01647     rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
01648                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01649                                           ASN_INTEGER), &time_long,
01650                                 sizeof(long));
01651     DEBUGINDENTLESS();
01652     if (rc == 0) {
01653         DEBUGMSGTL(("usm",
01654                     "building msgAuthoritativeEngineTime failed.\n"));
01655         usm_free_usmStateReference(secStateRef);
01656         return SNMPERR_TOO_LONG;
01657     }
01658 
01659     /*
01660      * msgAuthoritativeEngineBoots.  
01661      */
01662     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
01663     rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
01664                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
01665                                           ASN_INTEGER), &boots_long,
01666                                 sizeof(long));
01667     DEBUGINDENTLESS();
01668     if (rc == 0) {
01669         DEBUGMSGTL(("usm",
01670                     "building msgAuthoritativeEngineBoots failed.\n"));
01671         usm_free_usmStateReference(secStateRef);
01672         return SNMPERR_TOO_LONG;
01673     }
01674 
01675     DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
01676     rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
01677                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
01678                                              | ASN_OCTET_STR), theEngineID,
01679                                    theEngineIDLength);
01680     DEBUGINDENTLESS();
01681     if (rc == 0) {
01682         DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
01683         usm_free_usmStateReference(secStateRef);
01684         return SNMPERR_TOO_LONG;
01685     }
01686 
01687     /*
01688      * USM msgSecurityParameters sequence header  
01689      */
01690     rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
01691                                      (u_char) (ASN_SEQUENCE |
01692                                                ASN_CONSTRUCTOR),
01693                                      *offset - sp_offset);
01694     if (rc == 0) {
01695         DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
01696         usm_free_usmStateReference(secStateRef);
01697         return SNMPERR_TOO_LONG;
01698     }
01699 
01700     /*
01701      * msgSecurityParameters OCTET STRING wrapper.  
01702      */
01703     rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
01704                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
01705                                              | ASN_OCTET_STR),
01706                                    *offset - sp_offset);
01707 
01708     if (rc == 0) {
01709         DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
01710         usm_free_usmStateReference(secStateRef);
01711         return SNMPERR_TOO_LONG;
01712     }
01713 
01714     /*
01715      * Copy in the msgGlobalData and msgVersion.  
01716      */
01717     while ((*wholeMsgLen - *offset) < globalDataLen) {
01718         if (!asn_realloc(wholeMsg, wholeMsgLen)) {
01719             DEBUGMSGTL(("usm", "building global data failed.\n"));
01720             usm_free_usmStateReference(secStateRef);
01721             return SNMPERR_TOO_LONG;
01722         }
01723     }
01724 
01725     *offset += globalDataLen;
01726     memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen);
01727 
01728     /*
01729      * Total packet sequence.  
01730      */
01731     rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
01732                                      (u_char) (ASN_SEQUENCE |
01733                                                ASN_CONSTRUCTOR), *offset);
01734     if (rc == 0) {
01735         DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
01736         usm_free_usmStateReference(secStateRef);
01737         return SNMPERR_TOO_LONG;
01738     }
01739 
01740     /*
01741      * Now consider / do authentication.  
01742      */
01743 
01744     if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV ||
01745         theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01746         size_t          temp_sig_len = msgAuthParmLen;
01747         u_char         *temp_sig = (u_char *) malloc(temp_sig_len);
01748         u_char         *proto_msg = *wholeMsg + *wholeMsgLen - *offset;
01749         size_t          proto_msg_len = *offset;
01750 
01751 
01752         if (temp_sig == NULL) {
01753             DEBUGMSGTL(("usm", "Out of memory.\n"));
01754             usm_free_usmStateReference(secStateRef);
01755             return SNMPERR_USM_GENERICERROR;
01756         }
01757 
01758         if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
01759                                    theAuthKey, theAuthKeyLength,
01760                                    proto_msg, proto_msg_len,
01761                                    temp_sig, &temp_sig_len)
01762             != SNMP_ERR_NOERROR) {
01763             SNMP_FREE(temp_sig);
01764             DEBUGMSGTL(("usm", "Signing failed.\n"));
01765             usm_free_usmStateReference(secStateRef);
01766             return SNMPERR_USM_AUTHENTICATIONFAILURE;
01767         }
01768 
01769         if (temp_sig_len != msgAuthParmLen) {
01770             SNMP_FREE(temp_sig);
01771             DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
01772             usm_free_usmStateReference(secStateRef);
01773             return SNMPERR_USM_AUTHENTICATIONFAILURE;
01774         }
01775 
01776         memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig,
01777                msgAuthParmLen);
01778         SNMP_FREE(temp_sig);
01779     }
01780     /*
01781      * endif -- create keyed hash 
01782      */
01783     usm_free_usmStateReference(secStateRef);
01784     DEBUGMSGTL(("usm", "USM processing completed.\n"));
01785     return SNMPERR_SUCCESS;
01786 }                               /* end usm_rgenerate_out_msg() */
01787 
01788 #endif                          /* */
01789 
01790 
01791 
01792 /*******************************************************************-o-******
01793  * usm_parse_security_parameters
01794  *
01795  * Parameters:
01796  *      (See list below...)
01797  *      
01798  * Returns:
01799  *      0       On success,
01800  *      -1      Otherwise.
01801  *
01802  *      tab stop 4
01803  *
01804  *      Extracts values from the security header and data portions of the
01805  *      incoming buffer.
01806  */
01807 int
01808 usm_parse_security_parameters(u_char * secParams,
01809                               size_t remaining,
01810                               u_char * secEngineID,
01811                               size_t * secEngineIDLen,
01812                               u_int * boots_uint,
01813                               u_int * time_uint,
01814                               char *secName,
01815                               size_t * secNameLen,
01816                               u_char * signature,
01817                               size_t * signature_length,
01818                               u_char * salt,
01819                               size_t * salt_length, u_char ** data_ptr)
01820 {
01821     u_char         *parse_ptr = secParams;
01822     u_char         *value_ptr;
01823     u_char         *next_ptr;
01824     u_char          type_value;
01825 
01826     size_t          octet_string_length = remaining;
01827     size_t          sequence_length;
01828     size_t          remaining_bytes;
01829 
01830     long            boots_long;
01831     long            time_long;
01832 
01833     u_int           origNameLen;
01834 
01835 
01836     /*
01837      * Eat the first octet header.
01838      */
01839     if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length,
01840                                         &type_value,
01841                                         (ASN_UNIVERSAL | ASN_PRIMITIVE |
01842                                          ASN_OCTET_STR),
01843                                         "usm first octet")) == NULL) {
01844         /*
01845          * RETURN parse error 
01846          */ return -1;
01847     }
01848 
01849 
01850     /*
01851      * Eat the sequence header.
01852      */
01853     parse_ptr = value_ptr;
01854     sequence_length = octet_string_length;
01855 
01856     if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length,
01857                                         &type_value,
01858                                         (ASN_SEQUENCE | ASN_CONSTRUCTOR),
01859                                         "usm sequence")) == NULL) {
01860         /*
01861          * RETURN parse error 
01862          */ return -1;
01863     }
01864 
01865 
01866     /*
01867      * Retrieve the engineID.
01868      */
01869     parse_ptr = value_ptr;
01870     remaining_bytes = sequence_length;
01871 
01872     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID");
01873     if ((next_ptr
01874          = asn_parse_string(parse_ptr, &remaining_bytes, &type_value,
01875                             secEngineID, secEngineIDLen)) == NULL) {
01876         DEBUGINDENTLESS();
01877         /*
01878          * RETURN parse error 
01879          */ return -1;
01880     }
01881     DEBUGINDENTLESS();
01882 
01883     if (type_value !=
01884         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
01885         /*
01886          * RETURN parse error 
01887          */ return -1;
01888     }
01889 
01890 
01891     /*
01892      * Retrieve the engine boots, notice switch in the way next_ptr and
01893      * remaining_bytes are used (to accomodate the asn code).
01894      */
01895     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots");
01896     if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
01897                                   &boots_long, sizeof(long))) == NULL) {
01898         DEBUGINDENTLESS();
01899         /*
01900          * RETURN parse error 
01901          */ return -1;
01902     }
01903     DEBUGINDENTLESS();
01904 
01905     if (type_value !=
01906         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
01907         DEBUGINDENTLESS();
01908         /*
01909          * RETURN parse error 
01910          */ return -1;
01911     }
01912 
01913     *boots_uint = (u_int) boots_long;
01914 
01915 
01916     /*
01917      * Retrieve the time value.
01918      */
01919     DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime");
01920     if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
01921                                   &time_long, sizeof(long))) == NULL) {
01922         /*
01923          * RETURN parse error 
01924          */ return -1;
01925     }
01926     DEBUGINDENTLESS();
01927 
01928     if (type_value !=
01929         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
01930         /*
01931          * RETURN parse error 
01932          */ return -1;
01933     }
01934 
01935     *time_uint = (u_int) time_long;
01936 
01937     if (*boots_uint > ENGINEBOOT_MAX || *time_uint > ENGINETIME_MAX) {
01938         return -1;
01939     }
01940 
01941     /*
01942      * Retrieve the secName.
01943      */
01944     origNameLen = *secNameLen;
01945 
01946 
01947     DEBUGDUMPHEADER("recv", "msgUserName");
01948     if ((next_ptr
01949          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
01950                             (u_char *) secName, secNameLen)) == NULL) {
01951         DEBUGINDENTLESS();
01952         /*
01953          * RETURN parse error 
01954          */ return -1;
01955     }
01956     DEBUGINDENTLESS();
01957 
01958     /*
01959      * FIX -- doesn't this also indicate a buffer overrun?
01960      */
01961     if ((int) origNameLen < *secNameLen + 1) {
01962         /*
01963          * RETURN parse error, but it's really a parameter error 
01964          */
01965         return -1;
01966     }
01967 
01968     if (*secNameLen > 32) {
01969         /*
01970          * This is a USM-specific limitation over and above the above
01971          * limitation (which will probably default to the length of an
01972          * SnmpAdminString, i.e. 255).  See RFC 2574, sec. 2.4.  
01973          */
01974         return -1;
01975     }
01976 
01977     secName[*secNameLen] = '\0';
01978 
01979     if (type_value !=
01980         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
01981         /*
01982          * RETURN parse error 
01983          */ return -1;
01984     }
01985 
01986 
01987     /*
01988      * Retrieve the signature and blank it if there.
01989      */
01990     DEBUGDUMPHEADER("recv", "msgAuthenticationParameters");
01991     if ((next_ptr
01992          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
01993                             signature, signature_length)) == NULL) {
01994         DEBUGINDENTLESS();
01995         /*
01996          * RETURN parse error 
01997          */ return -1;
01998     }
01999     DEBUGINDENTLESS();
02000 
02001     if (type_value !=
02002         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
02003         /*
02004          * RETURN parse error 
02005          */ return -1;
02006     }
02007 
02008     if (*signature_length != 0) {       /* Blanking for authentication step later */
02009         memset(next_ptr - (u_long) * signature_length,
02010                0, *signature_length);
02011     }
02012 
02013 
02014     /*
02015      * Retrieve the salt.
02016      *
02017      * Note that the next ptr is where the data section starts.
02018      */
02019     DEBUGDUMPHEADER("recv", "msgPrivacyParameters");
02020     if ((*data_ptr
02021          = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
02022                             salt, salt_length)) == NULL) {
02023         DEBUGINDENTLESS();
02024         /*
02025          * RETURN parse error 
02026          */ return -2;
02027     }
02028     DEBUGINDENTLESS();
02029 
02030     if (type_value !=
02031         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
02032         /*
02033          * RETURN parse error 
02034          */ return -2;
02035     }
02036 
02037     return 0;
02038 
02039 }                               /* end usm_parse_security_parameters() */
02040 
02041 
02042 
02043 
02044 /*******************************************************************-o-******
02045  * usm_check_and_update_timeliness
02046  *
02047  * Parameters:
02048  *      *secEngineID
02049  *       secEngineIDen
02050  *       boots_uint
02051  *       time_uint
02052  *      *error
02053  *      
02054  * Returns:
02055  *      0       On success,
02056  *      -1      Otherwise.
02057  *      
02058  *
02059  * Performs the incoming timeliness checking and setting.
02060  */
02061 int
02062 usm_check_and_update_timeliness(u_char * secEngineID,
02063                                 size_t secEngineIDLen,
02064                                 u_int boots_uint,
02065                                 u_int time_uint, int *error)
02066 {
02067     u_char          myID[USM_MAX_ID_LENGTH];
02068     u_long          myIDLength =
02069         snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
02070     u_int           myBoots;
02071     u_int           myTime;
02072 
02073 
02074 
02075     if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) {
02076         /*
02077          * We're probably already screwed...buffer overwrite.  XXX? 
02078          */
02079         DEBUGMSGTL(("usm", "Buffer overflow.\n"));
02080         *error = SNMPERR_USM_GENERICERROR;
02081         return -1;
02082     }
02083 
02084     myBoots = snmpv3_local_snmpEngineBoots();
02085     myTime = snmpv3_local_snmpEngineTime();
02086 
02087 
02088     /*
02089      * IF the time involved is local
02090      *     Make sure  message is inside the time window 
02091      * ELSE 
02092      *      IF boots is higher or boots is the same and time is higher
02093      *              remember this new data
02094      *      ELSE
02095      *              IF !(boots same and time within USM_TIME_WINDOW secs)
02096      *                      Message is too old 
02097      *              ELSE    
02098      *                      Message is ok, but don't take time
02099      *              ENDIF
02100      *      ENDIF
02101      * ENDIF
02102      */
02103 
02104     /*
02105      * This is a local reference.
02106      */
02107     if ((int) secEngineIDLen == myIDLength
02108         && memcmp(secEngineID, myID, myIDLength) == 0) {
02109         u_int           time_difference = myTime > time_uint ?
02110             myTime - time_uint : time_uint - myTime;
02111 
02112         if (boots_uint == ENGINEBOOT_MAX
02113             || boots_uint != myBoots
02114             || time_difference > USM_TIME_WINDOW) {
02115             if (snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS) ==
02116                 0) {
02117                 DEBUGMSGTL(("usm", "%s\n",
02118                             "Failed to increment statistic."));
02119             }
02120 
02121             DEBUGMSGTL(("usm",
02122                         "boot_uint %u myBoots %u time_diff %u => not in time window\n",
02123                         boots_uint, myBoots, time_difference));
02124             *error = SNMPERR_USM_NOTINTIMEWINDOW;
02125             return -1;
02126         }
02127 
02128         *error = SNMPERR_SUCCESS;
02129         return 0;
02130     }
02131 
02132     /*
02133      * This is a remote reference.
02134      */
02135     else {
02136         u_int           theirBoots, theirTime, theirLastTime;
02137         u_int           time_difference;
02138 
02139         if (get_enginetime_ex(secEngineID, secEngineIDLen,
02140                               &theirBoots, &theirTime,
02141                               &theirLastTime, TRUE)
02142             != SNMPERR_SUCCESS) {
02143             DEBUGMSGTL(("usm", "%s\n",
02144                         "Failed to get remote engine's times."));
02145 
02146             *error = SNMPERR_USM_GENERICERROR;
02147             return -1;
02148         }
02149 
02150         time_difference = theirTime > time_uint ?
02151             theirTime - time_uint : time_uint - theirTime;
02152 
02153 
02154         /*
02155          * XXX  Contrary to the pseudocode:
02156          *      See if boots is invalid first.
02157          */
02158         if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
02159             DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid."));
02160 
02161             *error = SNMPERR_USM_NOTINTIMEWINDOW;
02162             return -1;
02163         }
02164 
02165 
02166         /*
02167          * Boots is ok, see if the boots is the same but the time
02168          * is old.
02169          */
02170         if (theirBoots == boots_uint && time_uint < theirLastTime) {
02171             if (time_difference > USM_TIME_WINDOW) {
02172                 DEBUGMSGTL(("usm", "%s\n", "Message too old."));
02173                 *error = SNMPERR_USM_NOTINTIMEWINDOW;
02174                 return -1;
02175             }
02176 
02177             else {              /* Old, but acceptable */
02178 
02179                 *error = SNMPERR_SUCCESS;
02180                 return 0;
02181             }
02182         }
02183 
02184 
02185         /*
02186          * Message is ok, either boots has been advanced, or
02187          * time is greater than before with the same boots.
02188          */
02189 
02190         if (set_enginetime(secEngineID, secEngineIDLen,
02191                            boots_uint, time_uint, TRUE)
02192             != SNMPERR_SUCCESS) {
02193             DEBUGMSGTL(("usm", "%s\n",
02194                         "Failed updating remote boot/time."));
02195             *error = SNMPERR_USM_GENERICERROR;
02196             return -1;
02197         }
02198 
02199         *error = SNMPERR_SUCCESS;
02200         return 0;               /* Fresh message and time updated */
02201 
02202     }                           /* endif -- local or remote time reference. */
02203 
02204 
02205 }                               /* end usm_check_and_update_timeliness() */
02206 
02207 
02208 
02209 int
02210 usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms)
02211 {
02212     if (!parms)
02213         return SNMPERR_GENERR;
02214 
02215     return usm_process_in_msg(parms->msgProcModel,
02216                               parms->maxMsgSize,
02217                               parms->secParams,
02218                               parms->secModel,
02219                               parms->secLevel,
02220                               parms->wholeMsg,
02221                               parms->wholeMsgLen,
02222                               parms->secEngineID,
02223                               parms->secEngineIDLen,
02224                               parms->secName,
02225                               parms->secNameLen,
02226                               parms->scopedPdu,
02227                               parms->scopedPduLen,
02228                               parms->maxSizeResponse,
02229                               parms->secStateRef,
02230                               parms->sess, parms->msg_flags);
02231 }
02232 
02233 /*******************************************************************-o-******
02234  * usm_process_in_msg
02235  *
02236  * Parameters:
02237  *      (See list below...)
02238  *      
02239  * Returns:
02240  *      SNMPERR_SUCCESS                 On success.
02241  *      SNMPERR_USM_AUTHENTICATIONFAILURE
02242  *      SNMPERR_USM_DECRYPTIONERROR
02243  *      SNMPERR_USM_GENERICERROR
02244  *      SNMPERR_USM_PARSEERROR
02245  *      SNMPERR_USM_UNKNOWNENGINEID
02246  *      SNMPERR_USM_PARSEERROR
02247  *      SNMPERR_USM_UNKNOWNSECURITYNAME
02248  *      SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
02249  *
02250  *
02251  * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
02252  *
02253  * FIX  Memory leaks if secStateRef is allocated and a return occurs
02254  *      without cleaning up.  May contain secrets...
02255  */
02256 int
02257 usm_process_in_msg(int msgProcModel,    /* (UNUSED) */
02258                    size_t maxMsgSize,   /* IN     - Used to calc maxSizeResponse.  */
02259                    u_char * secParams,  /* IN     - BER encoded securityParameters. */
02260                    int secModel,        /* (UNUSED) */
02261                    int secLevel,        /* IN     - AuthNoPriv, authPriv etc.      */
02262                    u_char * wholeMsg,   /* IN     - Original v3 message.           */
02263                    size_t wholeMsgLen,  /* IN     - Msg length.                    */
02264                    u_char * secEngineID,        /* OUT    - Pointer snmpEngineID.          */
02265                    size_t * secEngineIDLen,     /* IN/OUT - Len available, len returned.   */
02266                    /*
02267                     * NOTE: Memory provided by caller.      
02268                     */
02269                    char *secName,       /* OUT    - Pointer to securityName.       */
02270                    size_t * secNameLen, /* IN/OUT - Len available, len returned.   */
02271                    u_char ** scopedPdu, /* OUT    - Pointer to plaintext scopedPdu. */
02272                    size_t * scopedPduLen,       /* IN/OUT - Len available, len returned.   */
02273                    size_t * maxSizeResponse,    /* OUT    - Max size of Response PDU.      */
02274                    void **secStateRf,   /* OUT    - Ref to security state.         */
02275                    netsnmp_session * sess,      /* IN     - session which got the message  */
02276                    u_char msg_flags)
02277 {                               /* IN     - v3 Message flags.              */
02278     size_t          remaining = wholeMsgLen - (u_int)
02279         ((u_long) * secParams - (u_long) * wholeMsg);
02280     u_int           boots_uint;
02281     u_int           time_uint;
02282 #ifdef HAVE_AES
02283     u_int           net_boots, net_time;
02284 #endif
02285     u_char          signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
02286     size_t          signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
02287     u_char          salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
02288     size_t          salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
02289     u_char          iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
02290     u_int           iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
02291     u_char         *data_ptr;
02292     u_char         *value_ptr;
02293     u_char          type_value;
02294     u_char         *end_of_overhead = NULL;
02295     int             error;
02296     int             i, rc = 0;
02297     struct usmStateReference **secStateRef =
02298         (struct usmStateReference **) secStateRf;
02299 
02300     struct usmUser *user;
02301 
02302 
02303     DEBUGMSGTL(("usm", "USM processing begun...\n"));
02304 
02305 
02306     if (secStateRef) {
02307         usm_free_usmStateReference(*secStateRef);
02308         *secStateRef = usm_malloc_usmStateReference();
02309         if (*secStateRef == NULL) {
02310             DEBUGMSGTL(("usm", "Out of memory.\n"));
02311             return SNMPERR_USM_GENERICERROR;
02312         }
02313     }
02314 
02315 
02316     /*
02317      * Make sure the *secParms is an OCTET STRING.
02318      * Extract the user name, engine ID, and security level.
02319      */
02320     if ((rc = usm_parse_security_parameters(secParams, remaining,
02321                                             secEngineID, secEngineIDLen,
02322                                             &boots_uint, &time_uint,
02323                                             secName, secNameLen,
02324                                             signature, &signature_length,
02325                                             salt, &salt_length,
02326                                             &data_ptr)) < 0) {
02327         DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc));
02328         if (rc == -2) {
02329             /*
02330              * This indicates a decryptionError.  
02331              */
02332             if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
02333                 0) {
02334                 DEBUGMSGTL(("usm", "%s\n",
02335                             "Failed to increment statistic."));
02336             }
02337             return SNMPERR_USM_DECRYPTIONERROR;
02338         }
02339         if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
02340             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
02341         }
02342         return SNMPERR_USM_PARSEERROR;
02343     }
02344 
02345     /*
02346      * RFC 2574 section 8.3.2
02347      * 1)  If the privParameters field is not an 8-octet OCTET STRING,
02348      * then an error indication (decryptionError) is returned to the
02349      * calling module.
02350      */
02351     if ((secLevel == SNMP_SEC_LEVEL_AUTHPRIV) && (salt_length != 8)) {
02352         if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) == 
02353             0) {
02354             DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
02355         }
02356         return SNMPERR_USM_DECRYPTIONERROR;
02357     }
02358 
02359     if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) {
02360         /*
02361          * pull these out now so reports can use them 
02362          */
02363         *scopedPdu = data_ptr;
02364         *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
02365         end_of_overhead = data_ptr;
02366     }
02367 
02368     if (secStateRef) {
02369         /*
02370          * Cache the name, engine ID, and security level,
02371          * * per step 2 (section 3.2)
02372          */
02373         if (usm_set_usmStateReference_name
02374             (*secStateRef, secName, *secNameLen) == -1) {
02375             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name."));
02376             return SNMPERR_USM_GENERICERROR;
02377         }
02378 
02379         if (usm_set_usmStateReference_engine_id
02380             (*secStateRef, secEngineID, *secEngineIDLen) == -1) {
02381             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id."));
02382             return SNMPERR_USM_GENERICERROR;
02383         }
02384 
02385         if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) ==
02386             -1) {
02387             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level."));
02388             return SNMPERR_USM_GENERICERROR;
02389         }
02390     }
02391 
02392 
02393     /*
02394      * Locate the engine ID record.
02395      * If it is unknown, then either create one or note this as an error.
02396      */
02397     if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE ||
02398                   (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH &&
02399                    (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) ||
02400         (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) {
02401         if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) {
02402             DEBUGMSGTL(("usm", "Unknown Engine ID.\n"));
02403             if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS) ==
02404                 0) {
02405                 DEBUGMSGTL(("usm", "%s\n",
02406                             "Failed to increment statistic."));
02407             }
02408             return SNMPERR_USM_UNKNOWNENGINEID;
02409         }
02410     } else {
02411         if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen)
02412             != SNMPERR_SUCCESS) {
02413             DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record."));
02414             return SNMPERR_USM_GENERICERROR;
02415         }
02416 
02417     }
02418 
02419 
02420     /*
02421      * Locate the User record.
02422      * If the user/engine ID is unknown, report this as an error.
02423      */
02424     if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen,
02425                                        secName, userList,
02426                                        (((sess && sess->isAuthoritative ==
02427                                           SNMP_SESS_AUTHORITATIVE) ||
02428                                          (!sess)) ? 0 : 1)))
02429         == NULL) {
02430         DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
02431         if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES) == 0) {
02432             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
02433         }
02434         return SNMPERR_USM_UNKNOWNSECURITYNAME;
02435     }
02436 
02437 
02438     /*
02439      * Make sure the security level is appropriate.
02440      */
02441     if (usm_check_secLevel(secLevel, user) == 1) {
02442         DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n",
02443                     secLevel));
02444         if (snmp_increment_statistic
02445             (STAT_USMSTATSUNSUPPORTEDSECLEVELS) == 0) {
02446             DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
02447         }
02448         return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
02449     }
02450 
02451 
02452     /*
02453      * Check the authentication credentials of the message.
02454      */
02455     if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
02456         || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
02457         if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen,
02458                                 user->authKey, user->authKeyLen,
02459                                 wholeMsg, wholeMsgLen,
02460                                 signature, signature_length)
02461             != SNMP_ERR_NOERROR) {
02462             DEBUGMSGTL(("usm", "Verification failed.\n"));
02463             if (snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS) == 0) {
02464                 DEBUGMSGTL(("usm", "%s\n",
02465                             "Failed to increment statistic."));
02466             }
02467             snmp_log(LOG_WARNING, "Authentication failed for %s\n",
02468                                 user->name);
02469             return SNMPERR_USM_AUTHENTICATIONFAILURE;
02470         }
02471 
02472         DEBUGMSGTL(("usm", "Verification succeeded.\n"));
02473     }
02474 
02475 
02476     /*
02477      * Steps 10-11  user is already set - relocated before timeliness 
02478      * check in case it fails - still save user data for response.
02479      *
02480      * Cache the keys and protocol oids, per step 11 (s3.2).
02481      */
02482     if (secStateRef) {
02483         if (usm_set_usmStateReference_auth_protocol(*secStateRef,
02484                                                     user->authProtocol,
02485                                                     user->
02486                                                     authProtocolLen) ==
02487             -1) {
02488             DEBUGMSGTL(("usm", "%s\n",
02489                         "Couldn't cache authentication protocol."));
02490             return SNMPERR_USM_GENERICERROR;
02491         }
02492 
02493         if (usm_set_usmStateReference_auth_key(*secStateRef,
02494                                                user->authKey,
02495                                                user->authKeyLen) == -1) {
02496             DEBUGMSGTL(("usm", "%s\n",
02497                         "Couldn't cache authentication key."));
02498             return SNMPERR_USM_GENERICERROR;
02499         }
02500 
02501         if (usm_set_usmStateReference_priv_protocol(*secStateRef,
02502                                                     user->privProtocol,
02503                                                     user->
02504                                                     privProtocolLen) ==
02505             -1) {
02506             DEBUGMSGTL(("usm", "%s\n",
02507                         "Couldn't cache privacy protocol."));
02508             return SNMPERR_USM_GENERICERROR;
02509         }
02510 
02511         if (usm_set_usmStateReference_priv_key(*secStateRef,
02512                                                user->privKey,
02513                                                user->privKeyLen) == -1) {
02514             DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key."));
02515             return SNMPERR_USM_GENERICERROR;
02516         }
02517     }
02518 
02519 
02520     /*
02521      * Perform the timeliness/time manager functions.
02522      */
02523     if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
02524         || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
02525         if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen,
02526                                             boots_uint, time_uint,
02527                                             &error) == -1) {
02528             return error;
02529         }
02530     }
02531 #ifdef                                                  LCD_TIME_SYNC_OPT
02532     /*
02533      * Cache the unauthenticated time to use in case we don't have
02534      * anything better - this guess will be no worse than (0,0)
02535      * that we normally use.
02536      */
02537     else {
02538         set_enginetime(secEngineID, *secEngineIDLen,
02539                        boots_uint, time_uint, FALSE);
02540     }
02541 #endif                          /* LCD_TIME_SYNC_OPT */
02542 
02543 
02544     /*
02545      * If needed, decrypt the scoped PDU.
02546      */
02547     if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
02548         remaining = wholeMsgLen - (data_ptr - wholeMsg);
02549 
02550         if ((value_ptr = asn_parse_sequence(data_ptr, &remaining,
02551                                             &type_value,
02552                                             (ASN_UNIVERSAL | ASN_PRIMITIVE
02553                                              | ASN_OCTET_STR),
02554                                             "encrypted sPDU")) == NULL) {
02555             DEBUGMSGTL(("usm", "%s\n",
02556                         "Failed while parsing encrypted sPDU."));
02557             if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
02558                 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
02559             }
02560             usm_free_usmStateReference(*secStateRef);
02561             *secStateRef = NULL;
02562             return SNMPERR_USM_PARSEERROR;
02563         }
02564 
02565 #ifndef NETSNMP_DISABLE_DES
02566         if (ISTRANSFORM(user->privProtocol, DESPriv)) {
02567             /*
02568              * From RFC2574:
02569              * 
02570              * "Before decryption, the encrypted data length is verified.
02571              * If the length of the OCTET STRING to be decrypted is not
02572              * an integral multiple of 8 octets, the decryption process
02573              * is halted and an appropriate exception noted."  
02574              */
02575 
02576             if (remaining % 8 != 0) {
02577                 DEBUGMSGTL(("usm",
02578                             "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
02579                             remaining, remaining % 8));
02580                 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
02581                     0) {
02582                     DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
02583                 }
02584                 usm_free_usmStateReference(*secStateRef);
02585                 *secStateRef = NULL;
02586                 return SNMPERR_USM_DECRYPTIONERROR;
02587             }
02588 
02589             end_of_overhead = value_ptr;
02590 
02591             /*
02592              * XOR the salt with the last (iv_length) bytes
02593              * of the priv_key to obtain the IV.
02594              */
02595             iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
02596             for (i = 0; i < (int) iv_length; i++)
02597                 iv[i] = salt[i] ^ user->privKey[iv_length + i];
02598         }
02599 #endif
02600 #ifdef HAVE_AES
02601         if (ISTRANSFORM(user->privProtocol, AESPriv)) {
02602             iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
02603             net_boots = ntohl(boots_uint);
02604             net_time = ntohl(time_uint);
02605             memcpy(iv, &net_boots, 4);
02606             memcpy(iv+4, &net_time, 4);
02607             memcpy(iv+8, salt, salt_length);
02608         }
02609 #endif
02610         
02611         if (sc_decrypt(user->privProtocol, user->privProtocolLen,
02612                        user->privKey, user->privKeyLen,
02613                        iv, iv_length,
02614                        value_ptr, remaining, *scopedPdu, scopedPduLen)
02615             != SNMP_ERR_NOERROR) {
02616             DEBUGMSGTL(("usm", "%s\n", "Failed decryption."));
02617             if (snmp_increment_statistic
02618                 (STAT_USMSTATSDECRYPTIONERRORS) == 0) {
02619                 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
02620             }
02621             return SNMPERR_USM_DECRYPTIONERROR;
02622         }
02623 #ifdef NETSNMP_ENABLE_TESTING_CODE
02624         if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
02625             dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining);
02626             dump_chunk("usm/dump", "salt + Encrypted form:",
02627                        salt, salt_length);
02628             dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length);
02629             dump_chunk("usm/dump", "Decrypted chunk:",
02630                        *scopedPdu, *scopedPduLen);
02631         }
02632 #endif
02633     }
02634     /*
02635      * sPDU is plaintext.
02636      */
02637     else {
02638         *scopedPdu = data_ptr;
02639         *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
02640         end_of_overhead = data_ptr;
02641 
02642     }                           /* endif -- PDU decryption */
02643 
02644 
02645     /*
02646      * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
02647      *
02648      * FIX  Correct? 
02649      */
02650     *maxSizeResponse = maxMsgSize - (int)
02651         ((u_long) end_of_overhead - (u_long) wholeMsg);
02652 
02653 
02654     DEBUGMSGTL(("usm", "USM processing completed.\n"));
02655 
02656     return SNMPERR_SUCCESS;
02657 
02658 }                               /* end usm_process_in_msg() */
02659 
02660 void
02661 usm_handle_report(void *sessp,
02662                   netsnmp_transport *transport, netsnmp_session *session,
02663                   int result, netsnmp_pdu *pdu)
02664 {
02665     /*
02666      * handle reportable errors 
02667      */
02668 
02669     /* this will get in our way */
02670     usm_free_usmStateReference(pdu->securityStateRef);
02671     pdu->securityStateRef = NULL;
02672 
02673     switch (result) {
02674     case SNMPERR_USM_AUTHENTICATIONFAILURE:
02675     {
02676         int res = session->s_snmp_errno;
02677         session->s_snmp_errno = result;
02678         if (session->callback) {
02679             session->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
02680                               session, pdu->reqid, pdu,
02681                               session->callback_magic);
02682         }
02683         session->s_snmp_errno = res;
02684     }  
02685     case SNMPERR_USM_UNKNOWNENGINEID:
02686     case SNMPERR_USM_UNKNOWNSECURITYNAME:
02687     case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
02688     case SNMPERR_USM_NOTINTIMEWINDOW:
02689     case SNMPERR_USM_DECRYPTIONERROR:
02690 
02691         if (SNMP_CMD_CONFIRMED(pdu->command) ||
02692             (pdu->command == 0
02693              && (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT))) {
02694             netsnmp_pdu    *pdu2;
02695             int             flags = pdu->flags;
02696 
02697             pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
02698             pdu2 = snmp_clone_pdu(pdu);
02699             pdu->flags = pdu2->flags = flags;
02700             snmpv3_make_report(pdu2, result);
02701             if (0 == snmp_sess_send(sessp, pdu2)) {
02702                 snmp_free_pdu(pdu2);
02703                 /*
02704                  * TODO: indicate error 
02705                  */
02706             }
02707         }
02708         break;
02709     }       
02710 }
02711 void
02712 init_usm(void)
02713 {
02714     struct snmp_secmod_def *def;
02715 
02716     DEBUGMSGTL(("init_usm", "unit_usm: %d %d\n", usmNoPrivProtocol[0],
02717                 usmNoPrivProtocol[1]));
02718 
02719     sc_init();                  /* initalize scapi code */
02720 
02721     /*
02722      * register ourselves as a security service 
02723      */
02724     def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
02725     /*
02726      * XXX: def->init_sess_secmod move stuff from snmp_api.c 
02727      */
02728     def->encode_reverse = usm_secmod_rgenerate_out_msg;
02729     def->encode_forward = usm_secmod_generate_out_msg;
02730     def->decode = usm_secmod_process_in_msg;
02731     def->pdu_free_state_ref = usm_free_usmStateReference;
02732     def->handle_report = usm_handle_report;
02733     register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def);
02734 
02735     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
02736                            SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
02737                            init_usm_post_config, NULL);
02738 
02739     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
02740                            SNMP_CALLBACK_SHUTDOWN,
02741                            deinit_usm_post_config, NULL);
02742 
02743     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
02744                            SNMP_CALLBACK_SHUTDOWN,
02745                            free_engineID, NULL);
02746 
02747 }
02748 
02749 void
02750 init_usm_conf(const char *app)
02751 {
02752     register_config_handler(app, "usmUser",
02753                                   usm_parse_config_usmUser, NULL, NULL);
02754     register_config_handler(app, "createUser",
02755                                   usm_parse_create_usmUser, NULL,
02756                                   "username (MD5|SHA) passphrase [DES [passphrase]]");
02757 
02758     /*
02759      * we need to be called back later 
02760      */
02761     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
02762                            usm_store_users, NULL);
02763 }
02764 
02765 /*
02766  * initializations for the USM.
02767  *
02768  * Should be called after the (engineid) configuration files have been read.
02769  *
02770  * Set "arbitrary" portion of salt to a random number.
02771  */
02772 int
02773 init_usm_post_config(int majorid, int minorid, void *serverarg,
02774                      void *clientarg)
02775 {
02776     size_t          salt_integer_len = sizeof(salt_integer);
02777 
02778     if (sc_random((u_char *) & salt_integer, &salt_integer_len) !=
02779         SNMPERR_SUCCESS) {
02780         DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
02781         salt_integer = (u_int) time(NULL);
02782     }
02783 
02784 #ifdef HAVE_AES
02785     salt_integer_len = sizeof (salt_integer64_1);
02786     if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
02787         SNMPERR_SUCCESS) {
02788         DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
02789         salt_integer64_1 = (u_int) time(NULL);
02790     }
02791     salt_integer_len = sizeof (salt_integer64_1);
02792     if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
02793         SNMPERR_SUCCESS) {
02794         DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
02795         salt_integer64_2 = (u_int) time(NULL);
02796     }
02797 #endif
02798     
02799 #ifndef NETSNMP_DISABLE_MD5
02800     noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
02801                                          USM_LENGTH_OID_TRANSFORM,
02802 #ifndef NETSNMP_DISABLE_DES
02803                                          usmDESPrivProtocol,
02804 #else
02805                                          usmAESPrivProtocol,
02806 #endif
02807                                          USM_LENGTH_OID_TRANSFORM);
02808 #else
02809     noNameUser = usm_create_initial_user("", usmHMACSHA1AuthProtocol,
02810                                          USM_LENGTH_OID_TRANSFORM,
02811 #ifndef NETSNMP_DISABLE_DES
02812                                          usmDESPrivProtocol,
02813 #else
02814                                          usmAESPrivProtocol,
02815 #endif
02816                                          USM_LENGTH_OID_TRANSFORM);
02817 #endif
02818 
02819     if ( noNameUser ) {
02820         SNMP_FREE(noNameUser->engineID);
02821         noNameUser->engineIDLen = 0;
02822     }
02823 
02824     return SNMPERR_SUCCESS;
02825 }                               /* end init_usm_post_config() */
02826 
02827 int
02828 deinit_usm_post_config(int majorid, int minorid, void *serverarg,
02829                        void *clientarg)
02830 {
02831     if (usm_free_user(noNameUser) != NULL) {
02832         DEBUGMSGTL(("deinit_usm_post_config", "could not free initial user\n"));
02833         return SNMPERR_GENERR;
02834     }
02835     noNameUser = NULL;
02836 
02837     DEBUGMSGTL(("deinit_usm_post_config", "initial user removed\n"));
02838     return SNMPERR_SUCCESS;
02839 }                               /* end deinit_usm_post_config() */
02840 
02841 void
02842 clear_user_list(void)
02843 {
02844     struct usmUser *tmp = userList, *next = NULL;
02845 
02846     while (tmp != NULL) {
02847         next = tmp->next;
02848         usm_free_user(tmp);
02849         tmp = next;
02850     }
02851     userList = NULL;
02852 
02853 }
02854 
02855 /*******************************************************************-o-******
02856  * usm_check_secLevel
02857  *
02858  * Parameters:
02859  *       level
02860  *      *user
02861  *      
02862  * Returns:
02863  *      0       On success,
02864  *      -1      Otherwise.
02865  *
02866  * Checks that a given security level is valid for a given user.
02867  */
02868 int
02869 usm_check_secLevel(int level, struct usmUser *user)
02870 {
02871 
02872     if (user->userStatus != RS_ACTIVE)
02873         return -1;
02874 
02875     DEBUGMSGTL(("comparex", "Comparing: %d %d ", usmNoPrivProtocol[0],
02876                 usmNoPrivProtocol[1]));
02877     DEBUGMSGOID(("comparex", usmNoPrivProtocol,
02878                  sizeof(usmNoPrivProtocol) / sizeof(oid)));
02879     DEBUGMSG(("comparex", "\n"));
02880     if (level == SNMP_SEC_LEVEL_AUTHPRIV
02881         && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen,
02882                              usmNoPrivProtocol,
02883                              sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
02884             0)) {
02885         DEBUGMSGTL(("usm", "Level: %d\n", level));
02886         DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
02887         DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
02888         DEBUGMSG(("usm", ", User Priv Protocol: "));
02889         DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
02890         DEBUGMSG(("usm", "\n"));
02891         return 1;
02892     }
02893     if ((level == SNMP_SEC_LEVEL_AUTHPRIV
02894          || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
02895         &&
02896         (netsnmp_oid_equals
02897          (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol,
02898           sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
02899         DEBUGMSGTL(("usm", "Level: %d\n", level));
02900         DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
02901         DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
02902         DEBUGMSG(("usm", ", User Priv Protocol: "));
02903         DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
02904         DEBUGMSG(("usm", "\n"));
02905         return 1;
02906     }
02907 
02908     return 0;
02909 
02910 }                               /* end usm_check_secLevel() */
02911 
02912 
02913 
02914 
02915 /*******************************************************************-o-******
02916  * usm_check_secLevel_vs_protocols
02917  *
02918  * Parameters:
02919  *       level
02920  *      *authProtocol
02921  *       authProtocolLen
02922  *      *privProtocol
02923  *       privProtocolLen
02924  *      
02925  * Returns:
02926  *      0       On success,
02927  *      1       Otherwise.
02928  *
02929  * Same as above but with explicitly named transform types instead of taking
02930  * from the usmUser structure.
02931  */
02932 int
02933 usm_check_secLevel_vs_protocols(int level,
02934                                 const oid * authProtocol,
02935                                 u_int authProtocolLen,
02936                                 const oid * privProtocol,
02937                                 u_int privProtocolLen)
02938 {
02939 
02940     if (level == SNMP_SEC_LEVEL_AUTHPRIV
02941         &&
02942         (netsnmp_oid_equals
02943          (privProtocol, privProtocolLen, usmNoPrivProtocol,
02944           sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0)) {
02945         DEBUGMSGTL(("usm", "Level: %d\n", level));
02946         DEBUGMSGTL(("usm", "Auth Protocol: "));
02947         DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
02948         DEBUGMSG(("usm", ", Priv Protocol: "));
02949         DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
02950         DEBUGMSG(("usm", "\n"));
02951         return 1;
02952     }
02953     if ((level == SNMP_SEC_LEVEL_AUTHPRIV
02954          || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
02955         &&
02956         (netsnmp_oid_equals
02957          (authProtocol, authProtocolLen, usmNoAuthProtocol,
02958           sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
02959         DEBUGMSGTL(("usm", "Level: %d\n", level));
02960         DEBUGMSGTL(("usm", "Auth Protocol: "));
02961         DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
02962         DEBUGMSG(("usm", ", Priv Protocol: "));
02963         DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
02964         DEBUGMSG(("usm", "\n"));
02965         return 1;
02966     }
02967 
02968     return 0;
02969 
02970 }                               /* end usm_check_secLevel_vs_protocols() */
02971 
02972 
02973 
02974 
02975 /*
02976  * usm_get_user(): Returns a user from userList based on the engineID,
02977  * engineIDLen and name of the requested user. 
02978  */
02979 
02980 struct usmUser *
02981 usm_get_user(u_char * engineID, size_t engineIDLen, char *name)
02982 {
02983     DEBUGMSGTL(("usm", "getting user %s\n", name));
02984     return usm_get_user_from_list(engineID, engineIDLen, name, userList,
02985                                   1);
02986 }
02987 
02988 struct usmUser *
02989 usm_get_user_from_list(u_char * engineID, size_t engineIDLen,
02990                        char *name, struct usmUser *puserList,
02991                        int use_default)
02992 {
02993     struct usmUser *ptr;
02994     char            noName[] = "";
02995     if (name == NULL)
02996         name = noName;
02997     for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
02998         if (ptr->name && !strcmp(ptr->name, name)) {
02999           DEBUGMSGTL(("usm", "match on user %s\n", ptr->name));
03000           if (ptr->engineIDLen == engineIDLen &&
03001             ((ptr->engineID == NULL && engineID == NULL) ||
03002              (ptr->engineID != NULL && engineID != NULL &&
03003               memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
03004             return ptr;
03005           DEBUGMSGTL(("usm", "no match on engineID ("));
03006           DEBUGMSGHEX(("usm", engineID, engineIDLen));
03007           DEBUGMSG(("usm", ")\n"));
03008         }
03009     }
03010 
03011     /*
03012      * return "" user used to facilitate engineID discovery 
03013      */
03014     if (use_default && !strcmp(name, ""))
03015         return noNameUser;
03016     return NULL;
03017 }
03018 
03019 /*
03020  * usm_add_user(): Add's a user to the userList, sorted by the
03021  * engineIDLength then the engineID then the name length then the name
03022  * to facilitate getNext calls on a usmUser table which is indexed by
03023  * these values.
03024  * 
03025  * Note: userList must not be NULL (obviously), as thats a rather trivial
03026  * addition and is left to the API user.
03027  * 
03028  * returns the head of the list (which could change due to this add).
03029  */
03030 
03031 struct usmUser *
03032 usm_add_user(struct usmUser *user)
03033 {
03034     struct usmUser *uptr;
03035     uptr = usm_add_user_to_list(user, userList);
03036     if (uptr != NULL)
03037         userList = uptr;
03038     return uptr;
03039 }
03040 
03041 struct usmUser *
03042 usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
03043 {
03044     struct usmUser *nptr, *pptr, *optr;
03045 
03046     /*
03047      * loop through puserList till we find the proper, sorted place to
03048      * insert the new user 
03049      */
03050     /* XXX - how to handle a NULL user->name ?? */
03051     /* XXX - similarly for a NULL nptr->name ?? */
03052     for (nptr = puserList, pptr = NULL; nptr != NULL;
03053          pptr = nptr, nptr = nptr->next) {
03054         if (nptr->engineIDLen > user->engineIDLen)
03055             break;
03056 
03057         if (user->engineID == NULL && nptr->engineID != NULL)
03058             break;
03059 
03060         if (nptr->engineIDLen == user->engineIDLen &&
03061             (nptr->engineID != NULL && user->engineID != NULL &&
03062              memcmp(nptr->engineID, user->engineID,
03063                     user->engineIDLen) > 0))
03064             break;
03065 
03066         if (!(nptr->engineID == NULL && user->engineID != NULL)) {
03067             if (nptr->engineIDLen == user->engineIDLen &&
03068                 ((nptr->engineID == NULL && user->engineID == NULL) ||
03069                  memcmp(nptr->engineID, user->engineID,
03070                         user->engineIDLen) == 0)
03071                 && strlen(nptr->name) > strlen(user->name))
03072                 break;
03073 
03074             if (nptr->engineIDLen == user->engineIDLen &&
03075                 ((nptr->engineID == NULL && user->engineID == NULL) ||
03076                  memcmp(nptr->engineID, user->engineID,
03077                         user->engineIDLen) == 0)
03078                 && strlen(nptr->name) == strlen(user->name)
03079                 && strcmp(nptr->name, user->name) > 0)
03080                 break;
03081 
03082             if (nptr->engineIDLen == user->engineIDLen &&
03083                 ((nptr->engineID == NULL && user->engineID == NULL) ||
03084                  memcmp(nptr->engineID, user->engineID,
03085                         user->engineIDLen) == 0)
03086                 && strlen(nptr->name) == strlen(user->name)
03087                 && strcmp(nptr->name, user->name) == 0) {
03088                 /*
03089                  * the user is an exact match of a previous entry.
03090                  * Credentials may be different, though, so remove
03091                  * the old entry (and add the new one)!
03092                  */
03093                 if (pptr) { /* change prev's next pointer */
03094                   pptr->next = nptr->next;
03095                 }
03096                 if (nptr->next) { /* change next's prev pointer */
03097                   nptr->next->prev = pptr;
03098                 } 
03099                 optr = nptr;
03100                 nptr = optr->next; /* add new user at this position */
03101                 /* free the old user */
03102                 optr->next=NULL;
03103                 optr->prev=NULL;
03104                 usm_free_user(optr); 
03105                 break; /* new user will be added below */
03106             }
03107         }
03108     }
03109 
03110     /*
03111      * nptr should now point to the user that we need to add ourselves
03112      * in front of, and pptr should be our new 'prev'. 
03113      */
03114 
03115     /*
03116      * change our pointers 
03117      */
03118     user->prev = pptr;
03119     user->next = nptr;
03120 
03121     /*
03122      * change the next's prev pointer 
03123      */
03124     if (user->next)
03125         user->next->prev = user;
03126 
03127     /*
03128      * change the prev's next pointer 
03129      */
03130     if (user->prev)
03131         user->prev->next = user;
03132 
03133     /*
03134      * rewind to the head of the list and return it (since the new head
03135      * could be us, we need to notify the above routine who the head now is. 
03136      */
03137     for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
03138     return pptr;
03139 }
03140 
03141 /*
03142  * usm_remove_user(): finds and removes a user from a list 
03143  */
03144 struct usmUser *
03145 usm_remove_user(struct usmUser *user)
03146 {
03147     return usm_remove_user_from_list(user, &userList);
03148 }
03149 
03150 struct usmUser *
03151 usm_remove_user_from_list(struct usmUser *user,
03152                           struct usmUser **ppuserList)
03153 {
03154     struct usmUser *nptr, *pptr;
03155 
03156     /*
03157      * NULL pointers aren't allowed 
03158      */
03159     if (ppuserList == NULL)
03160         return NULL;
03161 
03162     if (*ppuserList == NULL)
03163         return NULL;
03164 
03165     /*
03166      * find the user in the list 
03167      */
03168     for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
03169          pptr = nptr, nptr = nptr->next) {
03170         if (nptr == user)
03171             break;
03172     }
03173 
03174     if (nptr) {
03175         /*
03176          * remove the user from the linked list 
03177          */
03178         if (pptr) {
03179             pptr->next = nptr->next;
03180         }
03181         if (nptr->next) {
03182             nptr->next->prev = pptr;
03183         }
03184     } else {
03185         /*
03186          * user didn't exist 
03187          */
03188         return NULL;
03189     }
03190     if (nptr == *ppuserList)    /* we're the head of the list, need to change
03191                                  * * the head to the next user */
03192         *ppuserList = nptr->next;
03193     return *ppuserList;
03194 }                               /* end usm_remove_user_from_list() */
03195 
03196 
03197 
03198 
03199 /*
03200  * usm_free_user():  calls free() on all needed parts of struct usmUser and
03201  * the user himself.
03202  * 
03203  * Note: This should *not* be called on an object in a list (IE,
03204  * remove it from the list first, and set next and prev to NULL), but
03205  * will try to reconnect the list pieces again if it is called this
03206  * way.  If called on the head of the list, the entire list will be
03207  * lost. 
03208  */
03209 struct usmUser *
03210 usm_free_user(struct usmUser *user)
03211 {
03212     if (user == NULL)
03213         return NULL;
03214 
03215     SNMP_FREE(user->engineID);
03216     SNMP_FREE(user->name);
03217     SNMP_FREE(user->secName);
03218     SNMP_FREE(user->cloneFrom);
03219     SNMP_FREE(user->userPublicString);
03220     SNMP_FREE(user->authProtocol);
03221     SNMP_FREE(user->privProtocol);
03222 
03223     if (user->authKey != NULL) {
03224         SNMP_ZERO(user->authKey, user->authKeyLen);
03225         SNMP_FREE(user->authKey);
03226     }
03227 
03228     if (user->privKey != NULL) {
03229         SNMP_ZERO(user->privKey, user->privKeyLen);
03230         SNMP_FREE(user->privKey);
03231     }
03232 
03233 
03234     /*
03235      * FIX  Why not put this check *first?*
03236      */
03237     if (user->prev != NULL) {   /* ack, this shouldn't happen */
03238         user->prev->next = user->next;
03239     }
03240     if (user->next != NULL) {
03241         user->next->prev = user->prev;
03242         if (user->prev != NULL) /* ack this is really bad, because it means
03243                                  * * we'll loose the head of some structure tree */
03244             DEBUGMSGTL(("usm",
03245                         "Severe: Asked to free the head of a usmUser tree somewhere."));
03246     }
03247 
03248 
03249     SNMP_ZERO(user, sizeof(*user));
03250     SNMP_FREE(user);
03251 
03252     return NULL;                /* for convenience to returns from calling functions */
03253 
03254 }                               /* end usm_free_user() */
03255 
03256 
03257 
03258 
03259 /*
03260  * take a given user and clone the security info into another 
03261  */
03262 struct usmUser *
03263 usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
03264 {
03265     /*
03266      * copy the authProtocol oid row pointer 
03267      */
03268     SNMP_FREE(to->authProtocol);
03269 
03270     if ((to->authProtocol =
03271          snmp_duplicate_objid(from->authProtocol,
03272                               from->authProtocolLen)) != NULL)
03273         to->authProtocolLen = from->authProtocolLen;
03274     else
03275         to->authProtocolLen = 0;
03276 
03277 
03278     /*
03279      * copy the authKey 
03280      */
03281     SNMP_FREE(to->authKey);
03282 
03283     if (from->authKeyLen > 0 &&
03284         (to->authKey = (u_char *) malloc(from->authKeyLen))
03285         != NULL) {
03286         to->authKeyLen = from->authKeyLen;
03287         memcpy(to->authKey, from->authKey, to->authKeyLen);
03288     } else {
03289         to->authKey = NULL;
03290         to->authKeyLen = 0;
03291     }
03292 
03293 
03294     /*
03295      * copy the privProtocol oid row pointer 
03296      */
03297     SNMP_FREE(to->privProtocol);
03298 
03299     if ((to->privProtocol =
03300          snmp_duplicate_objid(from->privProtocol,
03301                               from->privProtocolLen)) != NULL)
03302         to->privProtocolLen = from->privProtocolLen;
03303     else
03304         to->privProtocolLen = 0;
03305 
03306     /*
03307      * copy the privKey 
03308      */
03309     SNMP_FREE(to->privKey);
03310 
03311     if (from->privKeyLen > 0 &&
03312         (to->privKey = (u_char *) malloc(from->privKeyLen))
03313         != NULL) {
03314         to->privKeyLen = from->privKeyLen;
03315         memcpy(to->privKey, from->privKey, to->privKeyLen);
03316     } else {
03317         to->privKey = NULL;
03318         to->privKeyLen = 0;
03319     }
03320     return to;
03321 }
03322 
03323 /*
03324  * usm_create_user(void):
03325  * create a default empty user, instantiating only the auth/priv
03326  * protocols to noAuth and noPriv OID pointers
03327  */
03328 struct usmUser *
03329 usm_create_user(void)
03330 {
03331     struct usmUser *newUser;
03332 
03333     /*
03334      * create the new user 
03335      */
03336     newUser = (struct usmUser *) calloc(1, sizeof(struct usmUser));
03337     if (newUser == NULL)
03338         return NULL;
03339 
03340     /*
03341      * fill the auth/priv protocols 
03342      */
03343     if ((newUser->authProtocol =
03344          snmp_duplicate_objid(usmNoAuthProtocol,
03345                               sizeof(usmNoAuthProtocol) / sizeof(oid))) ==
03346         NULL)
03347         return usm_free_user(newUser);
03348     newUser->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
03349 
03350     if ((newUser->privProtocol =
03351          snmp_duplicate_objid(usmNoPrivProtocol,
03352                               sizeof(usmNoPrivProtocol) / sizeof(oid))) ==
03353         NULL)
03354         return usm_free_user(newUser);
03355     newUser->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
03356 
03357     /*
03358      * set the storage type to nonvolatile, and the status to ACTIVE 
03359      */
03360     newUser->userStorageType = ST_NONVOLATILE;
03361     newUser->userStatus = RS_ACTIVE;
03362     return newUser;
03363 
03364 }                               /* end usm_clone_user() */
03365 
03366 
03367 
03368 
03369 /*
03370  * usm_create_initial_user(void):
03371  * creates an initial user, filled with the defaults defined in the
03372  * USM document.
03373  */
03374 struct usmUser *
03375 usm_create_initial_user(const char *name,
03376                         const oid * authProtocol, size_t authProtocolLen,
03377                         const oid * privProtocol, size_t privProtocolLen)
03378 {
03379     struct usmUser *newUser = usm_create_user();
03380     if (newUser == NULL)
03381         return NULL;
03382 
03383     if ((newUser->name = strdup(name)) == NULL)
03384         return usm_free_user(newUser);
03385 
03386     if ((newUser->secName = strdup(name)) == NULL)
03387         return usm_free_user(newUser);
03388 
03389     if ((newUser->engineID =
03390          snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
03391         return usm_free_user(newUser);
03392 
03393     if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL)
03394         return usm_free_user(newUser);
03395     newUser->cloneFrom[0] = 0;
03396     newUser->cloneFrom[1] = 0;
03397     newUser->cloneFromLen = 2;
03398 
03399     SNMP_FREE(newUser->privProtocol);
03400     if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol,
03401                                                       privProtocolLen)) ==
03402         NULL) {
03403         return usm_free_user(newUser);
03404     }
03405     newUser->privProtocolLen = privProtocolLen;
03406 
03407     SNMP_FREE(newUser->authProtocol);
03408     if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol,
03409                                                       authProtocolLen)) ==
03410         NULL) {
03411         return usm_free_user(newUser);
03412     }
03413     newUser->authProtocolLen = authProtocolLen;
03414 
03415     newUser->userStatus = RS_ACTIVE;
03416     newUser->userStorageType = ST_READONLY;
03417 
03418     return newUser;
03419 }
03420 
03421 /*
03422  * this is a callback that can store all known users based on a
03423  * previously registered application ID 
03424  */
03425 int
03426 usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
03427 {
03428     /*
03429      * figure out our application name 
03430      */
03431     char           *appname = (char *) clientarg;
03432     if (appname == NULL) {
03433         appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
03434                                         NETSNMP_DS_LIB_APPTYPE);
03435     }
03436 
03437     /*
03438      * save the user base 
03439      */
03440     usm_save_users("usmUser", appname);
03441 
03442     /*
03443      * never fails 
03444      */
03445     return SNMPERR_SUCCESS;
03446 }
03447 
03448 
03449 /*
03450  * usm_save_users(): saves a list of users to the persistent cache 
03451  */
03452 void
03453 usm_save_users(const char *token, const char *type)
03454 {
03455     usm_save_users_from_list(userList, token, type);
03456 }
03457 
03458 void
03459 usm_save_users_from_list(struct usmUser *puserList, const char *token,
03460                          const char *type)
03461 {
03462     struct usmUser *uptr;
03463     for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
03464         if (uptr->userStorageType == ST_NONVOLATILE)
03465             usm_save_user(uptr, token, type);
03466     }
03467 }
03468 
03469 /*
03470  * usm_save_user(): saves a user to the persistent cache 
03471  */
03472 void
03473 usm_save_user(struct usmUser *user, const char *token, const char *type)
03474 {
03475     char            line[4096];
03476     char           *cptr;
03477 
03478     memset(line, 0, sizeof(line));
03479 
03480     sprintf(line, "%s %d %d ", token, user->userStatus,
03481             user->userStorageType);
03482     cptr = &line[strlen(line)]; /* the NULL */
03483     cptr =
03484         read_config_save_octet_string(cptr, user->engineID,
03485                                       user->engineIDLen);
03486     *cptr++ = ' ';
03487     cptr = read_config_save_octet_string(cptr, (u_char *) user->name,
03488                                          (user->name == NULL) ? 0 :
03489                                          strlen(user->name) + 1);
03490     *cptr++ = ' ';
03491     cptr = read_config_save_octet_string(cptr, (u_char *) user->secName,
03492                                          (user->secName == NULL) ? 0 :
03493                                          strlen(user->secName) + 1);
03494     *cptr++ = ' ';
03495     cptr =
03496         read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
03497     *cptr++ = ' ';
03498     cptr = read_config_save_objid(cptr, user->authProtocol,
03499                                   user->authProtocolLen);
03500     *cptr++ = ' ';
03501     cptr =
03502         read_config_save_octet_string(cptr, user->authKey,
03503                                       user->authKeyLen);
03504     *cptr++ = ' ';
03505     cptr = read_config_save_objid(cptr, user->privProtocol,
03506                                   user->privProtocolLen);
03507     *cptr++ = ' ';
03508     cptr =
03509         read_config_save_octet_string(cptr, user->privKey,
03510                                       user->privKeyLen);
03511     *cptr++ = ' ';
03512     cptr = read_config_save_octet_string(cptr, user->userPublicString,
03513                                          (user->userPublicString ==
03514                                           NULL) ? 0 : strlen((char *)
03515                                                              user->
03516                                                              userPublicString)
03517                                          + 1);
03518     read_config_store(type, line);
03519 }
03520 
03521 /*
03522  * usm_parse_user(): reads in a line containing a saved user profile
03523  * and returns a pointer to a newly created struct usmUser. 
03524  */
03525 struct usmUser *
03526 usm_read_user(char *line)
03527 {
03528     struct usmUser *user;
03529     size_t          len;
03530     size_t expected_privKeyLen = 0;
03531 
03532     user = usm_create_user();
03533     if (user == NULL)
03534         return NULL;
03535 
03536     user->userStatus = atoi(line);
03537     line = skip_token(line);
03538     user->userStorageType = atoi(line);
03539     line = skip_token(line);
03540     line = read_config_read_octet_string(line, &user->engineID,
03541                                          &user->engineIDLen);
03542 
03543     /*
03544      * set the lcd entry for this engineID to the minimum boots/time
03545      * values so that its a known engineid and won't return a report pdu.
03546      * This is mostly important when receiving v3 traps so that the usm
03547      * will at least continue processing them. 
03548      */
03549     set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
03550 
03551     line = read_config_read_octet_string(line, (u_char **) & user->name,
03552                                          &len);
03553     line = read_config_read_octet_string(line, (u_char **) & user->secName,
03554                                          &len);
03555     SNMP_FREE(user->cloneFrom);
03556     user->cloneFromLen = 0;
03557 
03558     line =
03559         read_config_read_objid(line, &user->cloneFrom,
03560                                &user->cloneFromLen);
03561 
03562     SNMP_FREE(user->authProtocol);
03563     user->authProtocolLen = 0;
03564 
03565     line = read_config_read_objid(line, &user->authProtocol,
03566                                   &user->authProtocolLen);
03567     line = read_config_read_octet_string(line, &user->authKey,
03568                                          &user->authKeyLen);
03569     SNMP_FREE(user->privProtocol);
03570     user->privProtocolLen = 0;
03571 
03572     line = read_config_read_objid(line, &user->privProtocol,
03573                                   &user->privProtocolLen);
03574     line = read_config_read_octet_string(line, &user->privKey,
03575                                          &user->privKeyLen);
03576 #ifndef NETSNMP_DISABLE_DES
03577     if (ISTRANSFORM(user->privProtocol, DESPriv)) {
03578         /* DES uses a 128 bit key, 64 bits of which is a salt */
03579         expected_privKeyLen = 16;
03580     }
03581 #endif
03582 #ifdef HAVE_AES
03583     if (ISTRANSFORM(user->privProtocol, AESPriv)) {
03584         expected_privKeyLen = 16;
03585     }
03586 #endif
03587     /* For backwards compatibility */
03588     if (user->privKeyLen > expected_privKeyLen) {
03589           user->privKeyLen = expected_privKeyLen;
03590     }
03591 
03592     line = read_config_read_octet_string(line, &user->userPublicString,
03593                                          &len);
03594     return user;
03595 }
03596 
03597 /*
03598  * snmpd.conf parsing routines 
03599  */
03600 void
03601 usm_parse_config_usmUser(const char *token, char *line)
03602 {
03603     struct usmUser *uptr;
03604 
03605     uptr = usm_read_user(line);
03606     usm_add_user(uptr);
03607 }
03608 
03609 
03610 
03611 
03612 /*******************************************************************-o-******
03613  * usm_set_password
03614  *
03615  * Parameters:
03616  *      *token
03617  *      *line
03618  *      
03619  *
03620  * format: userSetAuthPass     secname engineIDLen engineID pass
03621  *     or: userSetPrivPass     secname engineIDLen engineID pass 
03622  *     or: userSetAuthKey      secname engineIDLen engineID KuLen Ku
03623  *     or: userSetPrivKey      secname engineIDLen engineID KuLen Ku 
03624  *     or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
03625  *     or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul 
03626  *
03627  * type is:     1=passphrase; 2=Ku; 3=Kul.
03628  *
03629  *
03630  * ASSUMES  Passwords are null-terminated printable strings.
03631  */
03632 void
03633 usm_set_password(const char *token, char *line)
03634 {
03635     char           *cp;
03636     char            nameBuf[SNMP_MAXBUF];
03637     u_char         *engineID;
03638     size_t          engineIDLen;
03639     struct usmUser *user;
03640 
03641     cp = copy_nword(line, nameBuf, sizeof(nameBuf));
03642     if (cp == NULL) {
03643         config_perror("invalid name specifier");
03644         return;
03645     }
03646 
03647     DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
03648     if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
03649         /*
03650          * match against all engineIDs we know about 
03651          */
03652         cp = skip_token(cp);
03653         for (user = userList; user != NULL; user = user->next) {
03654             if (user->secName && strcmp(user->secName, nameBuf) == 0) {
03655                 usm_set_user_password(user, token, cp);
03656             }
03657         }
03658     } else {
03659         cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
03660         if (cp == NULL) {
03661             config_perror("invalid engineID specifier");
03662             return;
03663         }
03664 
03665         user = usm_get_user(engineID, engineIDLen, nameBuf);
03666         if (user == NULL) {
03667             config_perror("not a valid user/engineID pair");
03668             return;
03669         }
03670         usm_set_user_password(user, token, cp);
03671     }
03672 }
03673 
03674 /*
03675  * uses the rest of LINE to configure USER's password of type TOKEN 
03676  */
03677 void
03678 usm_set_user_password(struct usmUser *user, const char *token, char *line)
03679 {
03680     char           *cp = line;
03681     u_char         *engineID = user->engineID;
03682     size_t          engineIDLen = user->engineIDLen;
03683 
03684     u_char        **key;
03685     size_t         *keyLen;
03686     u_char          userKey[SNMP_MAXBUF_SMALL];
03687     size_t          userKeyLen = SNMP_MAXBUF_SMALL;
03688     u_char         *userKeyP = userKey;
03689     int             type, ret;
03690 
03691     /*
03692      * Retrieve the "old" key and set the key type.
03693      */
03694     if (!token) {
03695         return;
03696     } else if (strcmp(token, "userSetAuthPass") == 0) {
03697         key = &user->authKey;
03698         keyLen = &user->authKeyLen;
03699         type = 0;
03700     } else if (strcmp(token, "userSetPrivPass") == 0) {
03701         key = &user->privKey;
03702         keyLen = &user->privKeyLen;
03703         type = 0;
03704     } else if (strcmp(token, "userSetAuthKey") == 0) {
03705         key = &user->authKey;
03706         keyLen = &user->authKeyLen;
03707         type = 1;
03708     } else if (strcmp(token, "userSetPrivKey") == 0) {
03709         key = &user->privKey;
03710         keyLen = &user->privKeyLen;
03711         type = 1;
03712     } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
03713         key = &user->authKey;
03714         keyLen = &user->authKeyLen;
03715         type = 2;
03716     } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
03717         key = &user->privKey;
03718         keyLen = &user->privKeyLen;
03719         type = 2;
03720     } else {
03721         /*
03722          * no old key, or token was not recognized 
03723          */
03724         return;
03725     }
03726 
03727     if (*key) {
03728         /*
03729          * (destroy and) free the old key 
03730          */
03731         memset(*key, 0, *keyLen);
03732         SNMP_FREE(*key);
03733     }
03734 
03735     if (type == 0) {
03736         /*
03737          * convert the password into a key 
03738          */
03739         if (cp == NULL) {
03740             config_perror("missing user password");
03741             return;
03742         }
03743         ret = generate_Ku(user->authProtocol, user->authProtocolLen,
03744                           (u_char *) cp, strlen(cp), userKey, &userKeyLen);
03745 
03746         if (ret != SNMPERR_SUCCESS) {
03747             config_perror("setting key failed (in sc_genKu())");
03748             return;
03749         }
03750     } else if (type == 1) {
03751         cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen);
03752 
03753         if (cp == NULL) {
03754             config_perror("invalid user key");
03755             return;
03756         }
03757     }
03758 
03759     if (type < 2) {
03760         *key = (u_char *) malloc(SNMP_MAXBUF_SMALL);
03761         *keyLen = SNMP_MAXBUF_SMALL;
03762         ret = generate_kul(user->authProtocol, user->authProtocolLen,
03763                            engineID, engineIDLen,
03764                            userKey, userKeyLen, *key, keyLen);
03765         if (ret != SNMPERR_SUCCESS) {
03766             config_perror("setting key failed (in generate_kul())");
03767             return;
03768         }
03769 
03770         /*
03771          * (destroy and) free the old key 
03772          */
03773         memset(userKey, 0, sizeof(userKey));
03774 
03775     } else {
03776         /*
03777          * the key is given, copy it in 
03778          */
03779         cp = read_config_read_octet_string(cp, key, keyLen);
03780 
03781         if (cp == NULL) {
03782             config_perror("invalid localized user key");
03783             return;
03784         }
03785     }
03786 }                               /* end usm_set_password() */