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