summaryrefslogtreecommitdiff
path: root/cleopatre/application/spidnetsnmp/snmplib/snmpusm.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/spidnetsnmp/snmplib/snmpusm.c')
-rw-r--r--cleopatre/application/spidnetsnmp/snmplib/snmpusm.c3793
1 files changed, 0 insertions, 3793 deletions
diff --git a/cleopatre/application/spidnetsnmp/snmplib/snmpusm.c b/cleopatre/application/spidnetsnmp/snmplib/snmpusm.c
deleted file mode 100644
index 6ceb0525df..0000000000
--- a/cleopatre/application/spidnetsnmp/snmplib/snmpusm.c
+++ /dev/null
@@ -1,3793 +0,0 @@
-/* Portions of this file are subject to the following copyright(s). See
- * the Net-SNMP's COPYING file for more details and other copyrights
- * that may apply:
- */
-/*
- * Portions of this file are copyrighted by:
- * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms specified in the COPYING file
- * distributed with the Net-SNMP package.
- */
-/*
- * snmpusm.c
- *
- * Routines to manipulate a information about a "user" as
- * defined by the SNMP-USER-BASED-SM-MIB MIB.
- *
- * All functions usm_set_usmStateReference_*() return 0 on success, -1
- * otherwise.
- *
- * !! Tab stops set to 4 in some parts of this file. !!
- * (Designated on a per function.)
- */
-
-#include <net-snmp/net-snmp-config.h>
-
-#include <sys/types.h>
-#if HAVE_WINSOCK_H
-#include <winsock.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if TIME_WITH_SYS_TIME
-# ifdef WIN32
-# include <sys/timeb.h>
-# else
-# include <sys/time.h>
-# endif
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#else
-#include <strings.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
-#if HAVE_DMALLOC_H
-#include <dmalloc.h>
-#endif
-
-#include <net-snmp/types.h>
-#include <net-snmp/output_api.h>
-#include <net-snmp/config_api.h>
-#include <net-snmp/utilities.h>
-
-#include <net-snmp/library/asn1.h>
-#include <net-snmp/library/snmp_api.h>
-#include <net-snmp/library/callback.h>
-#include <net-snmp/library/tools.h>
-#include <net-snmp/library/keytools.h>
-#include <net-snmp/library/snmpv3.h>
-#include <net-snmp/library/lcd_time.h>
-#include <net-snmp/library/scapi.h>
-#include <net-snmp/library/callback.h>
-#include <net-snmp/library/snmp_secmod.h>
-#include <net-snmp/library/snmpusm.h>
-
-oid usmNoAuthProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 };
-#ifndef NETSNMP_DISABLE_MD5
-oid usmHMACMD5AuthProtocol[10] =
- { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 };
-#endif
-oid usmHMACSHA1AuthProtocol[10] =
- { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 };
-oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
-#ifndef NETSNMP_DISABLE_DES
-oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
-#endif
-oid usmAESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 };
-/* backwards compat */
-oid *usmAES128PrivProtocol = usmAESPrivProtocol;
-
-static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */
-
-/*
- * Globals.
- */
-static u_int salt_integer;
-#ifdef HAVE_AES
-static u_int salt_integer64_1, salt_integer64_2;
-#endif
- /*
- * 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1.
- */
-
-static struct usmUser *noNameUser = NULL;
-/*
- * Local storage (LCD) of the default user list.
- */
-static struct usmUser *userList = NULL;
-
-/*
- * Prototypes
- */
-int
- usm_check_secLevel_vs_protocols(int level,
- const oid * authProtocol,
- u_int authProtocolLen,
- const oid * privProtocol,
- u_int privProtocolLen);
-int
- usm_calc_offsets(size_t globalDataLen,
- int secLevel, size_t secEngineIDLen,
- size_t secNameLen, size_t scopedPduLen,
- u_long engineboots, long engine_time,
- size_t * theTotalLength,
- size_t * authParamsOffset,
- size_t * privParamsOffset,
- size_t * dataOffset, size_t * datalen,
- size_t * msgAuthParmLen,
- size_t * msgPrivParmLen, size_t * otstlen,
- size_t * seq_len, size_t * msgSecParmLen);
-/*
- * Set a given field of the secStateRef.
- *
- * Allocate <len> bytes for type <type> pointed to by ref-><field>.
- * Then copy in <item> and record its length in ref-><field_len>.
- *
- * Return 0 on success, -1 otherwise.
- */
-#define MAKE_ENTRY( type, item, len, field, field_len ) \
-{ \
- if (ref == NULL) \
- return -1; \
- if (ref->field != NULL) { \
- SNMP_ZERO(ref->field, ref->field_len); \
- SNMP_FREE(ref->field); \
- } \
- ref->field_len = 0; \
- if (len == 0 || item == NULL) { \
- return 0; \
- } \
- if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
- { \
- return -1; \
- } \
- \
- memcpy (ref->field, item, len * sizeof(type)); \
- ref->field_len = len; \
- \
- return 0; \
-}
-
-
-struct usmStateReference *
-usm_malloc_usmStateReference(void)
-{
- struct usmStateReference *retval = (struct usmStateReference *)
- calloc(1, sizeof(struct usmStateReference));
-
- return retval;
-} /* end usm_malloc_usmStateReference() */
-
-
-void
-usm_free_usmStateReference(void *old)
-{
- struct usmStateReference *old_ref = (struct usmStateReference *) old;
-
- if (old_ref) {
-
- SNMP_FREE(old_ref->usr_name);
- SNMP_FREE(old_ref->usr_engine_id);
- SNMP_FREE(old_ref->usr_auth_protocol);
- SNMP_FREE(old_ref->usr_priv_protocol);
-
- if (old_ref->usr_auth_key) {
- SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
- SNMP_FREE(old_ref->usr_auth_key);
- }
- if (old_ref->usr_priv_key) {
- SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
- SNMP_FREE(old_ref->usr_priv_key);
- }
-
- SNMP_ZERO(old_ref, sizeof(*old_ref));
- SNMP_FREE(old_ref);
-
- }
-
-} /* end usm_free_usmStateReference() */
-
-struct usmUser *
-usm_get_userList(void)
-{
- return userList;
-}
-
-int
-usm_set_usmStateReference_name(struct usmStateReference *ref,
- char *name, size_t name_len)
-{
- MAKE_ENTRY(char, name, name_len, usr_name, usr_name_length);
-}
-
-int
-usm_set_usmStateReference_engine_id(struct usmStateReference *ref,
- u_char * engine_id,
- size_t engine_id_len)
-{
- MAKE_ENTRY(u_char, engine_id, engine_id_len,
- usr_engine_id, usr_engine_id_length);
-}
-
-int
-usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref,
- oid * auth_protocol,
- size_t auth_protocol_len)
-{
- MAKE_ENTRY(oid, auth_protocol, auth_protocol_len,
- usr_auth_protocol, usr_auth_protocol_length);
-}
-
-int
-usm_set_usmStateReference_auth_key(struct usmStateReference *ref,
- u_char * auth_key, size_t auth_key_len)
-{
- MAKE_ENTRY(u_char, auth_key, auth_key_len,
- usr_auth_key, usr_auth_key_length);
-}
-
-int
-usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref,
- oid * priv_protocol,
- size_t priv_protocol_len)
-{
- MAKE_ENTRY(oid, priv_protocol, priv_protocol_len,
- usr_priv_protocol, usr_priv_protocol_length);
-}
-
-int
-usm_set_usmStateReference_priv_key(struct usmStateReference *ref,
- u_char * priv_key, size_t priv_key_len)
-{
- MAKE_ENTRY(u_char, priv_key, priv_key_len,
- usr_priv_key, usr_priv_key_length);
-}
-
-int
-usm_set_usmStateReference_sec_level(struct usmStateReference *ref,
- int sec_level)
-{
- if (ref == NULL)
- return -1;
- ref->usr_sec_level = sec_level;
- return 0;
-}
-
-
-
-#ifdef NETSNMP_ENABLE_TESTING_CODE
-/*******************************************************************-o-******
- * emergency_print
- *
- * Parameters:
- * *field
- * length
- *
- * This is a print routine that is solely included so that it can be
- * used in gdb. Don't use it as a function, it will be pulled before
- * a real release of the code.
- *
- * tab stop 4
- *
- * XXX fflush() only works on FreeBSD; core dumps on Sun OS's
- */
-void
-emergency_print(u_char * field, u_int length)
-{
- int iindex;
- int start = 0;
- int stop = 25;
-
- while (start < stop) {
- for (iindex = start; iindex < stop; iindex++)
- printf("%02X ", field[iindex]);
-
- printf("\n");
- start = stop;
- stop = stop + 25 < length ? stop + 25 : length;
- }
- fflush(0);
-
-} /* end emergency_print() */
-#endif /* NETSNMP_ENABLE_TESTING_CODE */
-
-
-/*******************************************************************-o-******
- * asn_predict_int_length
- *
- * Parameters:
- * type (UNUSED)
- * number
- * len
- *
- * Returns:
- * Number of bytes necessary to store the ASN.1 encoded value of 'number'.
- *
- *
- * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
- * use to encode a particular integer value.
- *
- * Returns the length of the integer -- NOT THE HEADER!
- *
- * Do this the same way as asn_build_int()...
- */
-int
-asn_predict_int_length(int type, long number, size_t len)
-{
- register u_long mask;
-
-
- if (len != sizeof(long))
- return -1;
-
- mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
- /*
- * mask is 0xFF800000 on a big-endian machine
- */
-
- while ((((number & mask) == 0) || ((number & mask) == mask))
- && len > 1) {
- len--;
- number <<= 8;
- }
-
- return len;
-
-} /* end asn_predict_length() */
-
-
-
-
-/*******************************************************************-o-******
- * asn_predict_length
- *
- * Parameters:
- * type
- * *ptr
- * u_char_len
- *
- * Returns:
- * Length in bytes: 1 + <n> + <u_char_len>, where
- *
- * 1 For the ASN.1 type.
- * <n> # of bytes to store length of data.
- * <u_char_len> Length of data associated with ASN.1 type.
- *
- * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
- * use to encode a particular integer value. This is as broken as the
- * currently used encoder.
- *
- * XXX How is <n> chosen, exactly??
- */
-int
-asn_predict_length(int type, u_char * ptr, size_t u_char_len)
-{
-
- if (type & ASN_SEQUENCE)
- return 1 + 3 + u_char_len;
-
- if (type & ASN_INTEGER) {
- u_long value;
- memcpy(&value, ptr, u_char_len);
- u_char_len = asn_predict_int_length(type, value, u_char_len);
- }
-
- if (u_char_len < 0x80)
- return 1 + 1 + u_char_len;
- else if (u_char_len < 0xFF)
- return 1 + 2 + u_char_len;
- else
- return 1 + 3 + u_char_len;
-
-} /* end asn_predict_length() */
-
-
-
-
-/*******************************************************************-o-******
- * usm_calc_offsets
- *
- * Parameters:
- * (See list below...)
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- *
- * This routine calculates the offsets into an outgoing message buffer
- * for the necessary values. The outgoing buffer will generically
- * look like this:
- *
- * SNMPv3 Message
- * SEQ len[11]
- * INT len version
- * Header
- * SEQ len
- * INT len MsgID
- * INT len msgMaxSize
- * OST len msgFlags (OST = OCTET STRING)
- * INT len msgSecurityModel
- * MsgSecurityParameters
- * [1] OST len[2]
- * SEQ len[3]
- * OST len msgAuthoritativeEngineID
- * INT len msgAuthoritativeEngineBoots
- * INT len msgAuthoritativeEngineTime
- * OST len msgUserName
- * OST len[4] [5] msgAuthenticationParameters
- * OST len[6] [7] msgPrivacyParameters
- * MsgData
- * [8] OST len[9] [10] encryptedPDU
- * or
- * [8,10] SEQUENCE len[9] scopedPDU
- * [12]
- *
- * The bracketed points will be needed to be identified ([x] is an index
- * value, len[x] means a length value). Here is a semantic guide to them:
- *
- * [1] = globalDataLen (input)
- * [2] = otstlen
- * [3] = seq_len
- * [4] = msgAuthParmLen (may be 0 or 12)
- * [5] = authParamsOffset
- * [6] = msgPrivParmLen (may be 0 or 8)
- * [7] = privParamsOffset
- * [8] = globalDataLen + msgSecParmLen
- * [9] = datalen
- * [10] = dataOffset
- * [11] = theTotalLength - the length of the header itself
- * [12] = theTotalLength
- */
-int
-usm_calc_offsets(size_t globalDataLen, /* SNMPv3Message + HeaderData */
- int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen, /* An BER encoded sequence. */
- u_long engineboots, /* XXX (asn1.c works in long, not int.) */
- long engine_time, /* XXX (asn1.c works in long, not int.) */
- size_t * theTotalLength, /* globalDataLen + msgSecurityP. + msgData */
- size_t * authParamsOffset, /* Distance to auth bytes. */
- size_t * privParamsOffset, /* Distance to priv bytes. */
- size_t * dataOffset, /* Distance to scopedPdu SEQ -or- the
- * crypted (data) portion of msgData. */
- size_t * datalen, /* Size of msgData OCTET STRING encoding. */
- size_t * msgAuthParmLen, /* Size of msgAuthenticationParameters. */
- size_t * msgPrivParmLen, /* Size of msgPrivacyParameters. */
- size_t * otstlen, /* Size of msgSecurityP. O.S. encoding. */
- size_t * seq_len, /* Size of msgSecurityP. SEQ data. */
- size_t * msgSecParmLen)
-{ /* Size of msgSecurityP. SEQ. */
- int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */
- engBtlen, /* for fields within */
- engTmlen, /* msgSecurityParameters portion of */
- namelen, /* SNMPv3Message. */
- authlen, privlen;
-
- /*
- * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
- * If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0.
- */
- *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0;
-
- *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0;
-
-
- /*
- * Calculate lengths.
- */
- if ((engIDlen = asn_predict_length(ASN_OCTET_STR,
- 0, secEngineIDLen)) == -1) {
- return -1;
- }
-
- if ((engBtlen = asn_predict_length(ASN_INTEGER,
- (u_char *) & engineboots,
- sizeof(long))) == -1) {
- return -1;
- }
-
- if ((engTmlen = asn_predict_length(ASN_INTEGER,
- (u_char *) & engine_time,
- sizeof(long))) == -1) {
- return -1;
- }
-
- if ((namelen = asn_predict_length(ASN_OCTET_STR, 0, secNameLen)) == -1) {
- return -1;
- }
-
- if ((authlen = asn_predict_length(ASN_OCTET_STR,
- 0, *msgAuthParmLen)) == -1) {
- return -1;
- }
-
- if ((privlen = asn_predict_length(ASN_OCTET_STR,
- 0, *msgPrivParmLen)) == -1) {
- return -1;
- }
-
- *seq_len =
- engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
-
- if ((*otstlen = asn_predict_length(ASN_SEQUENCE, 0, *seq_len)) == -1) {
- return -1;
- }
-
- if ((*msgSecParmLen = asn_predict_length(ASN_OCTET_STR,
- 0, *otstlen)) == -1) {
- return -1;
- }
-
- *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len)
- + engIDlen + engBtlen + engTmlen + namelen
- + (authlen - *msgAuthParmLen);
-
- *privParamsOffset = *authParamsOffset + *msgAuthParmLen
- + (privlen - *msgPrivParmLen);
-
-
- /*
- * Compute the size of the plaintext. Round up to account for cipher
- * block size, if necessary.
- *
- * XXX This is hardwired for 1DES... If scopedPduLen is already
- * a multiple of 8, then *add* 8 more; otherwise, round up
- * to the next multiple of 8.
- *
- * FIX Calculation of encrypted portion of msgData and consequent
- * setting and sanity checking of theTotalLength, et al. should
- * occur *after* encryption has taken place.
- */
- if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- scopedPduLen = ROUNDUP8(scopedPduLen);
-
- if ((*datalen =
- asn_predict_length(ASN_OCTET_STR, 0, scopedPduLen)) == -1) {
- return -1;
- }
- } else {
- *datalen = scopedPduLen;
- }
-
- *dataOffset = globalDataLen + *msgSecParmLen +
- (*datalen - scopedPduLen);
- *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
-
- return 0;
-
-} /* end usm_calc_offsets() */
-
-
-
-
-
-#ifndef NETSNMP_DISABLE_DES
-/*******************************************************************-o-******
- * usm_set_salt
- *
- * Parameters:
- * *iv (O) Buffer to contain IV.
- * *iv_length (O) Length of iv.
- * *priv_salt (I) Salt portion of private key.
- * priv_salt_length (I) Length of priv_salt.
- * *msgSalt (I/O) Pointer salt portion of outgoing msg buffer.
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- * Determine the initialization vector for the DES-CBC encryption.
- * (Cf. RFC 2274, 8.1.1.1.)
- *
- * iv is defined as the concatenation of engineBoots and the
- * salt integer.
- * The salt integer is incremented.
- * The resulting salt is copied into the msgSalt buffer.
- * The result of the concatenation is then XORed with the salt
- * portion of the private key (last 8 bytes).
- * The IV result is returned individually for further use.
- */
-int
-usm_set_salt(u_char * iv,
- size_t * iv_length,
- u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
-{
- size_t propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
- int net_boots;
- int net_salt_int;
- /*
- * net_* should be encoded in network byte order. XXX Why?
- */
- int iindex;
-
-
- /*
- * Sanity check.
- */
- if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt)
- || (priv_salt_length < propersize_salt)) {
- return -1;
- }
-
-
- net_boots = htonl(snmpv3_local_snmpEngineBoots());
- net_salt_int = htonl(salt_integer);
-
- salt_integer += 1;
-
- memcpy(iv, &net_boots, propersize_salt / 2);
- memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2);
-
- if (msgSalt)
- memcpy(msgSalt, iv, propersize_salt);
-
-
- /*
- * Turn the salt into an IV: XOR <boots, salt_int> with salt
- * portion of priv_key.
- */
- for (iindex = 0; iindex < (int) propersize_salt; iindex++)
- iv[iindex] ^= priv_salt[iindex];
-
-
- return 0;
-
-} /* end usm_set_salt() */
-#endif
-
-#ifdef HAVE_AES
-/*******************************************************************-o-******
- * usm_set_aes_iv
- *
- * Parameters:
- * *iv (O) Buffer to contain IV.
- * *iv_length (O) Length of iv.
- * net_boots (I) the network byte order of the authEng boots val
- * net_time (I) the network byte order of the authEng time val
- * *salt (O) A buffer for the outgoing salt (= 8 bytes of iv)
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- * Determine the initialization vector for AES encryption.
- * (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
- *
- * iv is defined as the concatenation of engineBoots, engineTime
- and a 64 bit salt-integer.
- * The 64 bit salt integer is incremented.
- * The resulting salt is copied into the salt buffer.
- * The IV result is returned individually for further use.
- */
-int
-usm_set_aes_iv(u_char * iv,
- size_t * iv_length,
- u_int net_boots,
- u_int net_time,
- u_char * salt)
-{
- /*
- * net_* should be encoded in network byte order.
- */
- int net_salt_int1, net_salt_int2;
-#define PROPER_AES_IV_SIZE 64
-
- /*
- * Sanity check.
- */
- if (!iv || !iv_length) {
- return -1;
- }
-
- net_salt_int1 = htonl(salt_integer64_1);
- net_salt_int2 = htonl(salt_integer64_2);
-
- if ((salt_integer64_2 += 1) == 0)
- salt_integer64_2 += 1;
-
- /* XXX: warning: hard coded proper lengths */
- memcpy(iv, &net_boots, 4);
- memcpy(iv+4, &net_time, 4);
- memcpy(iv+8, &net_salt_int1, 4);
- memcpy(iv+12, &net_salt_int2, 4);
-
- memcpy(salt, iv+8, 8); /* only copy the needed portion */
- return 0;
-} /* end usm_set_salt() */
-#endif /* HAVE_AES */
-
-int
-usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
-{
- if (!parms)
- return SNMPERR_GENERR;
-
- return usm_generate_out_msg(parms->msgProcModel,
- parms->globalData, parms->globalDataLen,
- parms->maxMsgSize, parms->secModel,
- parms->secEngineID, parms->secEngineIDLen,
- parms->secName, parms->secNameLen,
- parms->secLevel,
- parms->scopedPdu, parms->scopedPduLen,
- parms->secStateRef,
- parms->secParams, parms->secParamsLen,
- parms->wholeMsg, parms->wholeMsgLen);
-}
-
-/*******************************************************************-o-******
- * usm_generate_out_msg
- *
- * Parameters:
- * (See list below...)
- *
- * Returns:
- * SNMPERR_SUCCESS On success.
- * SNMPERR_USM_AUTHENTICATIONFAILURE
- * SNMPERR_USM_ENCRYPTIONERROR
- * SNMPERR_USM_GENERICERROR
- * SNMPERR_USM_UNKNOWNSECURITYNAME
- * SNMPERR_USM_GENERICERROR
- * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
- *
- *
- * Generates an outgoing message.
- *
- * XXX Beware of misnomers!
- */
-int
-usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
- u_char * globalData, /* IN */
- /*
- * Pointer to msg header data will point to the beginning
- * * of the entire packet buffer to be transmitted on wire,
- * * memory will be contiguous with secParams, typically
- * * this pointer will be passed back as beginning of
- * * wholeMsg below. asn seq. length is updated w/ new length.
- * *
- * * While this points to a buffer that should be big enough
- * * for the whole message, only the first two parts
- * * of the message are completed, namely SNMPv3Message and
- * * HeaderData. globalDataLen (next parameter) represents
- * * the length of these two completed parts.
- */
- size_t globalDataLen, /* IN - Length of msg header data. */
- int maxMsgSize, /* (UNUSED) */
- int secModel, /* (UNUSED) */
- u_char * secEngineID, /* IN - Pointer snmpEngineID. */
- size_t secEngineIDLen, /* IN - SnmpEngineID length. */
- char *secName, /* IN - Pointer to securityName. */
- size_t secNameLen, /* IN - SecurityName length. */
- int secLevel, /* IN - AuthNoPriv, authPriv etc. */
- u_char * scopedPdu, /* IN */
- /*
- * Pointer to scopedPdu will be encrypted by USM if needed
- * * and written to packet buffer immediately following
- * * securityParameters, entire msg will be authenticated by
- * * USM if needed.
- */
- size_t scopedPduLen, /* IN - scopedPdu length. */
- void *secStateRef, /* IN */
- /*
- * secStateRef, pointer to cached info provided only for
- * * Response, otherwise NULL.
- */
- u_char * secParams, /* OUT */
- /*
- * BER encoded securityParameters pointer to offset within
- * * packet buffer where secParams should be written, the
- * * entire BER encoded OCTET STRING (including header) is
- * * written here by USM secParams = globalData +
- * * globalDataLen.
- */
- size_t * secParamsLen, /* IN/OUT - Len available, len returned. */
- u_char ** wholeMsg, /* OUT */
- /*
- * Complete authenticated/encrypted message - typically
- * * the pointer to start of packet buffer provided in
- * * globalData is returned here, could also be a separate
- * * buffer.
- */
- size_t * wholeMsgLen)
-{ /* IN/OUT - Len available, len returned. */
- size_t otstlen;
- size_t seq_len;
- size_t msgAuthParmLen;
- size_t msgPrivParmLen;
- size_t msgSecParmLen;
- size_t authParamsOffset;
- size_t privParamsOffset;
- size_t datalen;
- size_t dataOffset;
- size_t theTotalLength;
-
- u_char *ptr;
- size_t ptr_len;
- size_t remaining;
- size_t offSet;
- u_int boots_uint;
- u_int time_uint;
- long boots_long;
- long time_long;
-
- /*
- * Indirection because secStateRef values override parameters.
- *
- * None of these are to be free'd - they are either pointing to
- * what's in the secStateRef or to something either in the
- * actual prarmeter list or the user list.
- */
-
- char *theName = NULL;
- u_int theNameLength = 0;
- u_char *theEngineID = NULL;
- u_int theEngineIDLength = 0;
- u_char *theAuthKey = NULL;
- u_int theAuthKeyLength = 0;
- const oid *theAuthProtocol = NULL;
- u_int theAuthProtocolLength = 0;
- u_char *thePrivKey = NULL;
- u_int thePrivKeyLength = 0;
- const oid *thePrivProtocol = NULL;
- u_int thePrivProtocolLength = 0;
- int theSecLevel = 0; /* No defined const for bad
- * value (other then err).
- */
-
- DEBUGMSGTL(("usm", "USM processing has begun.\n"));
-
- if (secStateRef != NULL) {
- /*
- * To hush the compiler for now. XXX
- */
- struct usmStateReference *ref
- = (struct usmStateReference *) secStateRef;
-
- theName = ref->usr_name;
- theNameLength = ref->usr_name_length;
- theEngineID = ref->usr_engine_id;
- theEngineIDLength = ref->usr_engine_id_length;
-
- if (!theEngineIDLength) {
- theEngineID = secEngineID;
- theEngineIDLength = secEngineIDLen;
- }
-
- theAuthProtocol = ref->usr_auth_protocol;
- theAuthProtocolLength = ref->usr_auth_protocol_length;
- theAuthKey = ref->usr_auth_key;
- theAuthKeyLength = ref->usr_auth_key_length;
- thePrivProtocol = ref->usr_priv_protocol;
- thePrivProtocolLength = ref->usr_priv_protocol_length;
- thePrivKey = ref->usr_priv_key;
- thePrivKeyLength = ref->usr_priv_key_length;
- theSecLevel = ref->usr_sec_level;
- }
-
- /*
- * Identify the user record.
- */
- else {
- struct usmUser *user;
-
- /*
- * we do allow an unknown user name for
- * unauthenticated requests.
- */
- if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
- == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
- DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_UNKNOWNSECURITYNAME;
- }
-
- theName = secName;
- theNameLength = secNameLen;
- theEngineID = secEngineID;
- theSecLevel = secLevel;
- theEngineIDLength = secEngineIDLen;
- if (user) {
- theAuthProtocol = user->authProtocol;
- theAuthProtocolLength = user->authProtocolLen;
- theAuthKey = user->authKey;
- theAuthKeyLength = user->authKeyLen;
- thePrivProtocol = user->privProtocol;
- thePrivProtocolLength = user->privProtocolLen;
- thePrivKey = user->privKey;
- thePrivKeyLength = user->privKeyLen;
- } else {
- /*
- * unknown users can not do authentication (obviously)
- */
- theAuthProtocol = usmNoAuthProtocol;
- theAuthProtocolLength =
- sizeof(usmNoAuthProtocol) / sizeof(oid);
- theAuthKey = NULL;
- theAuthKeyLength = 0;
- thePrivProtocol = usmNoPrivProtocol;
- thePrivProtocolLength =
- sizeof(usmNoPrivProtocol) / sizeof(oid);
- thePrivKey = NULL;
- thePrivKeyLength = 0;
- }
- } /* endif -- secStateRef==NULL */
-
-
- /*
- * From here to the end of the function, avoid reference to
- * secName, secEngineID, secLevel, and associated lengths.
- */
-
-
- /*
- * Check to see if the user can use the requested sec services.
- */
- if (usm_check_secLevel_vs_protocols(theSecLevel,
- theAuthProtocol,
- theAuthProtocolLength,
- thePrivProtocol,
- thePrivProtocolLength) == 1) {
- DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
- theSecLevel));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
- }
-
-
- /*
- * Retrieve the engine information.
- *
- * XXX No error is declared in the EoP when sending messages to
- * unknown engines, processing continues w/ boots/time == (0,0).
- */
- if (get_enginetime(theEngineID, theEngineIDLength,
- &boots_uint, &time_uint, FALSE) == -1) {
- DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
- }
-
- boots_long = boots_uint;
- time_long = time_uint;
-
-
- /*
- * Set up the Offsets.
- */
- if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength,
- theNameLength, scopedPduLen, boots_long,
- time_long, &theTotalLength, &authParamsOffset,
- &privParamsOffset, &dataOffset, &datalen,
- &msgAuthParmLen, &msgPrivParmLen, &otstlen,
- &seq_len, &msgSecParmLen) == -1) {
- DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
-
- /*
- * So, we have the offsets for the three parts that need to be
- * determined, and an overall length. Now we need to make
- * sure all of this would fit in the outgoing buffer, and
- * whether or not we need to make a new buffer, etc.
- */
-
-
- /*
- * Set wholeMsg as a pointer to globalData. Sanity check for
- * the proper size.
- *
- * Mark workspace in the message with bytes of all 1's to make it
- * easier to find mistakes in raw message dumps.
- */
- ptr = *wholeMsg = globalData;
- if (theTotalLength > *wholeMsgLen) {
- DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
-
- ptr_len = *wholeMsgLen = theTotalLength;
-
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);
-#endif /* NETSNMP_ENABLE_TESTING_CODE */
-
- /*
- * Do the encryption.
- */
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- size_t encrypted_length = theTotalLength - dataOffset;
- size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
- u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
-
- /*
- * XXX Hardwired to seek into a 1DES private key!
- */
-#ifdef HAVE_AES
- if (ISTRANSFORM(thePrivProtocol, AESPriv)) {
- if (!thePrivKey ||
- usm_set_aes_iv(salt, &salt_length,
- htonl(boots_uint), htonl(time_uint),
- &ptr[privParamsOffset]) == -1) {
- DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
- }
-#endif
-#ifndef NETSNMP_DISABLE_DES
- if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
- if (!thePrivKey ||
- (usm_set_salt(salt, &salt_length,
- thePrivKey + 8, thePrivKeyLength - 8,
- &ptr[privParamsOffset])
- == -1)) {
- DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
- }
-#endif
-
- if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
- thePrivKey, thePrivKeyLength,
- salt, salt_length,
- scopedPdu, scopedPduLen,
- &ptr[dataOffset], &encrypted_length)
- != SNMP_ERR_NOERROR) {
- DEBUGMSGTL(("usm", "encryption error.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_ENCRYPTIONERROR;
- }
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
- dump_chunk("usm/dump", "This data was encrypted:",
- scopedPdu, scopedPduLen);
- dump_chunk("usm/dump", "salt + Encrypted form:",
- salt, salt_length);
- dump_chunk("usm/dump", NULL,
- &ptr[dataOffset], encrypted_length);
- dump_chunk("usm/dump", "*wholeMsg:",
- *wholeMsg, theTotalLength);
- }
-#endif
-
-
- ptr = *wholeMsg;
- ptr_len = *wholeMsgLen = theTotalLength;
-
-
- /*
- * XXX Sanity check for salt length should be moved up
- * under usm_calc_offsets() or tossed.
- */
- if ((encrypted_length != (theTotalLength - dataOffset))
- || (salt_length != msgPrivParmLen)) {
- DEBUGMSGTL(("usm", "encryption length error.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_ENCRYPTIONERROR;
- }
-
- DEBUGMSGTL(("usm", "Encryption successful.\n"));
- }
-
- /*
- * No encryption for you!
- */
- else {
- memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen);
- }
-
-
-
- /*
- * Start filling in the other fields (in prep for authentication).
- *
- * offSet is an octet string header, which is different from all
- * the other headers.
- */
- remaining = ptr_len - globalDataLen;
-
- offSet = ptr_len - remaining;
- asn_build_header(&ptr[offSet], &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), otstlen);
-
- offSet = ptr_len - remaining;
- asn_build_sequence(&ptr[offSet], &remaining,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
-
- offSet = ptr_len - remaining;
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
- asn_build_string(&ptr[offSet], &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), theEngineID,
- theEngineIDLength);
- DEBUGINDENTLESS();
-
- offSet = ptr_len - remaining;
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
- asn_build_int(&ptr[offSet], &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &boots_long, sizeof(long));
- DEBUGINDENTLESS();
-
- offSet = ptr_len - remaining;
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
- asn_build_int(&ptr[offSet], &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &time_long, sizeof(long));
- DEBUGINDENTLESS();
-
- offSet = ptr_len - remaining;
- DEBUGDUMPHEADER("send", "msgUserName");
- asn_build_string(&ptr[offSet], &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), (u_char *) theName,
- theNameLength);
- DEBUGINDENTLESS();
-
-
- /*
- * Note: if there is no authentication being done,
- * msgAuthParmLen is 0, and there is no effect (other than
- * inserting a zero-length header) of the following
- * statements.
- */
-
- offSet = ptr_len - remaining;
- asn_build_header(&ptr[offSet],
- &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), msgAuthParmLen);
-
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- offSet = ptr_len - remaining;
- memset(&ptr[offSet], 0, msgAuthParmLen);
- }
-
- remaining -= msgAuthParmLen;
-
-
- /*
- * Note: if there is no encryption being done, msgPrivParmLen
- * is 0, and there is no effect (other than inserting a
- * zero-length header) of the following statements.
- */
-
- offSet = ptr_len - remaining;
- asn_build_header(&ptr[offSet],
- &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), msgPrivParmLen);
-
- remaining -= msgPrivParmLen; /* Skipping the IV already there. */
-
-
- /*
- * For privacy, need to add the octet string header for it.
- */
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- offSet = ptr_len - remaining;
- asn_build_header(&ptr[offSet],
- &remaining,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR),
- theTotalLength - dataOffset);
- }
-
-
- /*
- * Adjust overall length and store it as the first SEQ length
- * of the SNMPv3Message.
- *
- * FIX 4 is a magic number!
- */
- remaining = theTotalLength;
- asn_build_sequence(ptr, &remaining,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- theTotalLength - 4);
-
-
- /*
- * Now, time to consider / do authentication.
- */
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- size_t temp_sig_len = msgAuthParmLen;
- u_char *temp_sig = (u_char *) malloc(temp_sig_len);
-
- if (temp_sig == NULL) {
- DEBUGMSGTL(("usm", "Out of memory.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
- theAuthKey, theAuthKeyLength,
- ptr, ptr_len, temp_sig, &temp_sig_len)
- != SNMP_ERR_NOERROR) {
- /*
- * FIX temp_sig_len defined?!
- */
- SNMP_ZERO(temp_sig, temp_sig_len);
- SNMP_FREE(temp_sig);
- DEBUGMSGTL(("usm", "Signing failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_AUTHENTICATIONFAILURE;
- }
-
- if (temp_sig_len != msgAuthParmLen) {
- SNMP_ZERO(temp_sig, temp_sig_len);
- SNMP_FREE(temp_sig);
- DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_AUTHENTICATIONFAILURE;
- }
-
- memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
-
- SNMP_ZERO(temp_sig, temp_sig_len);
- SNMP_FREE(temp_sig);
-
- }
-
- /*
- * endif -- create keyed hash
- */
- usm_free_usmStateReference(secStateRef);
-
- DEBUGMSGTL(("usm", "USM processing completed.\n"));
-
- return SNMPERR_SUCCESS;
-
-} /* end usm_generate_out_msg() */
-
-#ifdef NETSNMP_USE_REVERSE_ASNENCODING
-int
-usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
-{
- if (!parms)
- return SNMPERR_GENERR;
-
- return usm_rgenerate_out_msg(parms->msgProcModel,
- parms->globalData, parms->globalDataLen,
- parms->maxMsgSize, parms->secModel,
- parms->secEngineID, parms->secEngineIDLen,
- parms->secName, parms->secNameLen,
- parms->secLevel,
- parms->scopedPdu, parms->scopedPduLen,
- parms->secStateRef,
- parms->wholeMsg, parms->wholeMsgLen,
- parms->wholeMsgOffset);
-}
-
-int
-usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
- u_char * globalData, /* IN */
- /*
- * points at the msgGlobalData, which is of length given by next
- * parameter.
- */
- size_t globalDataLen, /* IN - Length of msg header data. */
- int maxMsgSize, /* (UNUSED) */
- int secModel, /* (UNUSED) */
- u_char * secEngineID, /* IN - Pointer snmpEngineID. */
- size_t secEngineIDLen, /* IN - SnmpEngineID length. */
- char *secName, /* IN - Pointer to securityName. */
- size_t secNameLen, /* IN - SecurityName length. */
- int secLevel, /* IN - AuthNoPriv, authPriv etc. */
- u_char * scopedPdu, /* IN */
- /*
- * Pointer to scopedPdu will be encrypted by USM if needed
- * * and written to packet buffer immediately following
- * * securityParameters, entire msg will be authenticated by
- * * USM if needed.
- */
- size_t scopedPduLen, /* IN - scopedPdu length. */
- void *secStateRef, /* IN */
- /*
- * secStateRef, pointer to cached info provided only for
- * * Response, otherwise NULL.
- */
- u_char ** wholeMsg, /* IN/OUT */
- /*
- * Points at the pointer to the packet buffer, which might get extended
- * if necessary via realloc().
- */
- size_t * wholeMsgLen, /* IN/OUT */
- /*
- * Length of the entire packet buffer, **not** the length of the
- * packet.
- */
- size_t * offset /* IN/OUT */
- /*
- * Offset from the end of the packet buffer to the start of the packet,
- * also known as the packet length.
- */
- )
-{
- size_t msgAuthParmLen = 0;
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- size_t theTotalLength;
-#endif
-
- u_int boots_uint;
- u_int time_uint;
- long boots_long;
- long time_long;
-
- /*
- * Indirection because secStateRef values override parameters.
- *
- * None of these are to be free'd - they are either pointing to
- * what's in the secStateRef or to something either in the
- * actual parameter list or the user list.
- */
-
- char *theName = NULL;
- u_int theNameLength = 0;
- u_char *theEngineID = NULL;
- u_int theEngineIDLength = 0;
- u_char *theAuthKey = NULL;
- u_int theAuthKeyLength = 0;
- const oid *theAuthProtocol = NULL;
- u_int theAuthProtocolLength = 0;
- u_char *thePrivKey = NULL;
- u_int thePrivKeyLength = 0;
- const oid *thePrivProtocol = NULL;
- u_int thePrivProtocolLength = 0;
- int theSecLevel = 0; /* No defined const for bad
- * value (other then err). */
- size_t salt_length = 0, save_salt_length = 0, save_salt_offset = 0;
- u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
- u_char authParams[USM_MAX_AUTHSIZE];
- u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
- size_t sp_offset = 0, mac_offset = 0;
- int rc = 0;
-
- DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", *offset));
-
- if (secStateRef != NULL) {
- /*
- * To hush the compiler for now. XXX
- */
- struct usmStateReference *ref
- = (struct usmStateReference *) secStateRef;
-
- theName = ref->usr_name;
- theNameLength = ref->usr_name_length;
- theEngineID = ref->usr_engine_id;
- theEngineIDLength = ref->usr_engine_id_length;
-
- if (!theEngineIDLength) {
- theEngineID = secEngineID;
- theEngineIDLength = secEngineIDLen;
- }
-
- theAuthProtocol = ref->usr_auth_protocol;
- theAuthProtocolLength = ref->usr_auth_protocol_length;
- theAuthKey = ref->usr_auth_key;
- theAuthKeyLength = ref->usr_auth_key_length;
- thePrivProtocol = ref->usr_priv_protocol;
- thePrivProtocolLength = ref->usr_priv_protocol_length;
- thePrivKey = ref->usr_priv_key;
- thePrivKeyLength = ref->usr_priv_key_length;
- theSecLevel = ref->usr_sec_level;
- }
-
- /*
- * * Identify the user record.
- */
- else {
- struct usmUser *user;
-
- /*
- * we do allow an unknown user name for
- * unauthenticated requests.
- */
- if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
- == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
- DEBUGMSGTL(("usm", "Unknown User\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_UNKNOWNSECURITYNAME;
- }
-
- theName = secName;
- theNameLength = secNameLen;
- theEngineID = secEngineID;
- theSecLevel = secLevel;
- theEngineIDLength = secEngineIDLen;
- if (user) {
- theAuthProtocol = user->authProtocol;
- theAuthProtocolLength = user->authProtocolLen;
- theAuthKey = user->authKey;
- theAuthKeyLength = user->authKeyLen;
- thePrivProtocol = user->privProtocol;
- thePrivProtocolLength = user->privProtocolLen;
- thePrivKey = user->privKey;
- thePrivKeyLength = user->privKeyLen;
- } else {
- /*
- * unknown users can not do authentication (obviously)
- */
- theAuthProtocol = usmNoAuthProtocol;
- theAuthProtocolLength =
- sizeof(usmNoAuthProtocol) / sizeof(oid);
- theAuthKey = NULL;
- theAuthKeyLength = 0;
- thePrivProtocol = usmNoPrivProtocol;
- thePrivProtocolLength =
- sizeof(usmNoPrivProtocol) / sizeof(oid);
- thePrivKey = NULL;
- thePrivKeyLength = 0;
- }
- } /* endif -- secStateRef==NULL */
-
-
- /*
- * From here to the end of the function, avoid reference to
- * secName, secEngineID, secLevel, and associated lengths.
- */
-
-
- /*
- * Check to see if the user can use the requested sec services.
- */
- if (usm_check_secLevel_vs_protocols(theSecLevel,
- theAuthProtocol,
- theAuthProtocolLength,
- thePrivProtocol,
- thePrivProtocolLength) == 1) {
- DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
- theSecLevel));
-
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
- }
-
-
- /*
- * * Retrieve the engine information.
- * *
- * * XXX No error is declared in the EoP when sending messages to
- * * unknown engines, processing continues w/ boots/time == (0,0).
- */
- if (get_enginetime(theEngineID, theEngineIDLength,
- &boots_uint, &time_uint, FALSE) == -1) {
- DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
- }
-
- boots_long = boots_uint;
- time_long = time_uint;
-
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- /*
- * Initially assume that the ciphertext will end up the same size as
- * the plaintext plus some padding. Really sc_encrypt ought to be able
- * to grow this for us, a la asn_realloc_rbuild_<type> functions, but
- * this will do for now.
- */
- u_char *ciphertext = NULL;
- size_t ciphertextlen = scopedPduLen + 64;
-
- if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) {
- DEBUGMSGTL(("usm",
- "couldn't malloc %d bytes for encrypted PDU\n",
- ciphertextlen));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_MALLOC;
- }
-
- /*
- * XXX Hardwired to seek into a 1DES private key!
- */
-#ifdef HAVE_AES
- if (ISTRANSFORM(thePrivProtocol, AESPriv)) {
- salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
- save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
- save_salt_offset = 0;
- if (!thePrivKey ||
- usm_set_aes_iv(salt, &salt_length,
- htonl(boots_uint), htonl(time_uint),
- iv) == -1) {
- DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
- usm_free_usmStateReference(secStateRef);
- SNMP_FREE(ciphertext);
- return SNMPERR_USM_GENERICERROR;
- }
- }
-#endif
-#ifndef NETSNMP_DISABLE_DES
- if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
- salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
- save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
- save_salt_offset = 0;
- if (!thePrivKey || (usm_set_salt(salt, &salt_length,
- thePrivKey + 8,
- thePrivKeyLength - 8,
- iv) == -1)) {
- DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
- usm_free_usmStateReference(secStateRef);
- SNMP_FREE(ciphertext);
- return SNMPERR_USM_GENERICERROR;
- }
- }
-#endif
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
- dump_chunk("usm/dump", "This data was encrypted:",
- scopedPdu, scopedPduLen);
- }
-#endif
-
- if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
- thePrivKey, thePrivKeyLength,
- salt, salt_length,
- scopedPdu, scopedPduLen,
- ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
- DEBUGMSGTL(("usm", "encryption error.\n"));
- usm_free_usmStateReference(secStateRef);
- SNMP_FREE(ciphertext);
- return SNMPERR_USM_ENCRYPTIONERROR;
- }
-
- /*
- * Write the encrypted scopedPdu back into the packet buffer.
- */
-
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- theTotalLength = *wholeMsgLen;
-#endif
- *offset = 0;
- rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_OCTET_STR),
- ciphertext, ciphertextlen);
- if (rc == 0) {
- DEBUGMSGTL(("usm", "Encryption failed.\n"));
- usm_free_usmStateReference(secStateRef);
- SNMP_FREE(ciphertext);
- return SNMPERR_USM_ENCRYPTIONERROR;
- }
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
- dump_chunk("usm/dump", "salt + Encrypted form: ", salt,
- salt_length);
- dump_chunk("usm/dump", "wholeMsg:",
- (*wholeMsg + *wholeMsgLen - *offset), *offset);
- }
-#endif
-
- DEBUGMSGTL(("usm", "Encryption successful.\n"));
- SNMP_FREE(ciphertext);
- } else {
- /*
- * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV
- */
- }
-
- /*
- * Start encoding the msgSecurityParameters.
- */
-
- sp_offset = *offset;
-
- DEBUGDUMPHEADER("send", "msgPrivacyParameters");
- /*
- * msgPrivacyParameters (warning: assumes DES salt).
- */
- rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- iv,
- save_salt_length);
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building privParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- DEBUGDUMPHEADER("send", "msgAuthenticationParameters");
- /*
- * msgAuthenticationParameters (warnings assumes 0x00 by 12).
- */
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- memset(authParams, 0, USM_MD5_AND_SHA_AUTH_LEN);
- msgAuthParmLen = USM_MD5_AND_SHA_AUTH_LEN;
- }
-
- rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR), authParams,
- msgAuthParmLen);
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building authParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * Remember where to put the actual HMAC we calculate later on. An
- * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1
- * header of length 2, hence the fudge factor.
- */
-
- mac_offset = *offset - 2;
-
- /*
- * msgUserName.
- */
- DEBUGDUMPHEADER("send", "msgUserName");
- rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- (u_char *) theName, theNameLength);
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building authParams failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * msgAuthoritativeEngineTime.
- */
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
- rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &time_long,
- sizeof(long));
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm",
- "building msgAuthoritativeEngineTime failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * msgAuthoritativeEngineBoots.
- */
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
- rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &boots_long,
- sizeof(long));
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm",
- "building msgAuthoritativeEngineBoots failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
- rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR), theEngineID,
- theEngineIDLength);
- DEBUGINDENTLESS();
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * USM msgSecurityParameters sequence header
- */
- rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR),
- *offset - sp_offset);
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * msgSecurityParameters OCTET STRING wrapper.
- */
- rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- *offset - sp_offset);
-
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * Copy in the msgGlobalData and msgVersion.
- */
- while ((*wholeMsgLen - *offset) < globalDataLen) {
- if (!asn_realloc(wholeMsg, wholeMsgLen)) {
- DEBUGMSGTL(("usm", "building global data failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
- }
-
- *offset += globalDataLen;
- memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen);
-
- /*
- * Total packet sequence.
- */
- rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR), *offset);
- if (rc == 0) {
- DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_TOO_LONG;
- }
-
- /*
- * Now consider / do authentication.
- */
-
- if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV ||
- theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- size_t temp_sig_len = msgAuthParmLen;
- u_char *temp_sig = (u_char *) malloc(temp_sig_len);
- u_char *proto_msg = *wholeMsg + *wholeMsgLen - *offset;
- size_t proto_msg_len = *offset;
-
-
- if (temp_sig == NULL) {
- DEBUGMSGTL(("usm", "Out of memory.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
- theAuthKey, theAuthKeyLength,
- proto_msg, proto_msg_len,
- temp_sig, &temp_sig_len)
- != SNMP_ERR_NOERROR) {
- SNMP_FREE(temp_sig);
- DEBUGMSGTL(("usm", "Signing failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_AUTHENTICATIONFAILURE;
- }
-
- if (temp_sig_len != msgAuthParmLen) {
- SNMP_FREE(temp_sig);
- DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
- usm_free_usmStateReference(secStateRef);
- return SNMPERR_USM_AUTHENTICATIONFAILURE;
- }
-
- memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig,
- msgAuthParmLen);
- SNMP_FREE(temp_sig);
- }
- /*
- * endif -- create keyed hash
- */
- usm_free_usmStateReference(secStateRef);
- DEBUGMSGTL(("usm", "USM processing completed.\n"));
- return SNMPERR_SUCCESS;
-} /* end usm_rgenerate_out_msg() */
-
-#endif /* */
-
-
-
-/*******************************************************************-o-******
- * usm_parse_security_parameters
- *
- * Parameters:
- * (See list below...)
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- * tab stop 4
- *
- * Extracts values from the security header and data portions of the
- * incoming buffer.
- */
-int
-usm_parse_security_parameters(u_char * secParams,
- size_t remaining,
- u_char * secEngineID,
- size_t * secEngineIDLen,
- u_int * boots_uint,
- u_int * time_uint,
- char *secName,
- size_t * secNameLen,
- u_char * signature,
- size_t * signature_length,
- u_char * salt,
- size_t * salt_length, u_char ** data_ptr)
-{
- u_char *parse_ptr = secParams;
- u_char *value_ptr;
- u_char *next_ptr;
- u_char type_value;
-
- size_t octet_string_length = remaining;
- size_t sequence_length;
- size_t remaining_bytes;
-
- long boots_long;
- long time_long;
-
- u_int origNameLen;
-
-
- /*
- * Eat the first octet header.
- */
- if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length,
- &type_value,
- (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR),
- "usm first octet")) == NULL) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
-
- /*
- * Eat the sequence header.
- */
- parse_ptr = value_ptr;
- sequence_length = octet_string_length;
-
- if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length,
- &type_value,
- (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- "usm sequence")) == NULL) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
-
- /*
- * Retrieve the engineID.
- */
- parse_ptr = value_ptr;
- remaining_bytes = sequence_length;
-
- DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID");
- if ((next_ptr
- = asn_parse_string(parse_ptr, &remaining_bytes, &type_value,
- secEngineID, secEngineIDLen)) == NULL) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -1;
- }
- DEBUGINDENTLESS();
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
-
- /*
- * Retrieve the engine boots, notice switch in the way next_ptr and
- * remaining_bytes are used (to accomodate the asn code).
- */
- DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots");
- if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
- &boots_long, sizeof(long))) == NULL) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -1;
- }
- DEBUGINDENTLESS();
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -1;
- }
-
- *boots_uint = (u_int) boots_long;
-
-
- /*
- * Retrieve the time value.
- */
- DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime");
- if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
- &time_long, sizeof(long))) == NULL) {
- /*
- * RETURN parse error
- */ return -1;
- }
- DEBUGINDENTLESS();
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
- *time_uint = (u_int) time_long;
-
- if (*boots_uint > ENGINEBOOT_MAX || *time_uint > ENGINETIME_MAX) {
- return -1;
- }
-
- /*
- * Retrieve the secName.
- */
- origNameLen = *secNameLen;
-
-
- DEBUGDUMPHEADER("recv", "msgUserName");
- if ((next_ptr
- = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
- (u_char *) secName, secNameLen)) == NULL) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -1;
- }
- DEBUGINDENTLESS();
-
- /*
- * FIX -- doesn't this also indicate a buffer overrun?
- */
- if ((int) origNameLen < *secNameLen + 1) {
- /*
- * RETURN parse error, but it's really a parameter error
- */
- return -1;
- }
-
- if (*secNameLen > 32) {
- /*
- * This is a USM-specific limitation over and above the above
- * limitation (which will probably default to the length of an
- * SnmpAdminString, i.e. 255). See RFC 2574, sec. 2.4.
- */
- return -1;
- }
-
- secName[*secNameLen] = '\0';
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
-
- /*
- * Retrieve the signature and blank it if there.
- */
- DEBUGDUMPHEADER("recv", "msgAuthenticationParameters");
- if ((next_ptr
- = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
- signature, signature_length)) == NULL) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -1;
- }
- DEBUGINDENTLESS();
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
- /*
- * RETURN parse error
- */ return -1;
- }
-
- if (*signature_length != 0) { /* Blanking for authentication step later */
- memset(next_ptr - (u_long) * signature_length,
- 0, *signature_length);
- }
-
-
- /*
- * Retrieve the salt.
- *
- * Note that the next ptr is where the data section starts.
- */
- DEBUGDUMPHEADER("recv", "msgPrivacyParameters");
- if ((*data_ptr
- = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
- salt, salt_length)) == NULL) {
- DEBUGINDENTLESS();
- /*
- * RETURN parse error
- */ return -2;
- }
- DEBUGINDENTLESS();
-
- if (type_value !=
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
- /*
- * RETURN parse error
- */ return -2;
- }
-
- return 0;
-
-} /* end usm_parse_security_parameters() */
-
-
-
-
-/*******************************************************************-o-******
- * usm_check_and_update_timeliness
- *
- * Parameters:
- * *secEngineID
- * secEngineIDen
- * boots_uint
- * time_uint
- * *error
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- *
- * Performs the incoming timeliness checking and setting.
- */
-int
-usm_check_and_update_timeliness(u_char * secEngineID,
- size_t secEngineIDLen,
- u_int boots_uint,
- u_int time_uint, int *error)
-{
- u_char myID[USM_MAX_ID_LENGTH];
- u_long myIDLength =
- snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
- u_int myBoots;
- u_int myTime;
-
-
-
- if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) {
- /*
- * We're probably already screwed...buffer overwrite. XXX?
- */
- DEBUGMSGTL(("usm", "Buffer overflow.\n"));
- *error = SNMPERR_USM_GENERICERROR;
- return -1;
- }
-
- myBoots = snmpv3_local_snmpEngineBoots();
- myTime = snmpv3_local_snmpEngineTime();
-
-
- /*
- * IF the time involved is local
- * Make sure message is inside the time window
- * ELSE
- * IF boots is higher or boots is the same and time is higher
- * remember this new data
- * ELSE
- * IF !(boots same and time within USM_TIME_WINDOW secs)
- * Message is too old
- * ELSE
- * Message is ok, but don't take time
- * ENDIF
- * ENDIF
- * ENDIF
- */
-
- /*
- * This is a local reference.
- */
- if ((int) secEngineIDLen == myIDLength
- && memcmp(secEngineID, myID, myIDLength) == 0) {
- u_int time_difference = myTime > time_uint ?
- myTime - time_uint : time_uint - myTime;
-
- if (boots_uint == ENGINEBOOT_MAX
- || boots_uint != myBoots
- || time_difference > USM_TIME_WINDOW) {
- if (snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed to increment statistic."));
- }
-
- DEBUGMSGTL(("usm",
- "boot_uint %u myBoots %u time_diff %u => not in time window\n",
- boots_uint, myBoots, time_difference));
- *error = SNMPERR_USM_NOTINTIMEWINDOW;
- return -1;
- }
-
- *error = SNMPERR_SUCCESS;
- return 0;
- }
-
- /*
- * This is a remote reference.
- */
- else {
- u_int theirBoots, theirTime, theirLastTime;
- u_int time_difference;
-
- if (get_enginetime_ex(secEngineID, secEngineIDLen,
- &theirBoots, &theirTime,
- &theirLastTime, TRUE)
- != SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed to get remote engine's times."));
-
- *error = SNMPERR_USM_GENERICERROR;
- return -1;
- }
-
- time_difference = theirTime > time_uint ?
- theirTime - time_uint : time_uint - theirTime;
-
-
- /*
- * XXX Contrary to the pseudocode:
- * See if boots is invalid first.
- */
- if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
- DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid."));
-
- *error = SNMPERR_USM_NOTINTIMEWINDOW;
- return -1;
- }
-
-
- /*
- * Boots is ok, see if the boots is the same but the time
- * is old.
- */
- if (theirBoots == boots_uint && time_uint < theirLastTime) {
- if (time_difference > USM_TIME_WINDOW) {
- DEBUGMSGTL(("usm", "%s\n", "Message too old."));
- *error = SNMPERR_USM_NOTINTIMEWINDOW;
- return -1;
- }
-
- else { /* Old, but acceptable */
-
- *error = SNMPERR_SUCCESS;
- return 0;
- }
- }
-
-
- /*
- * Message is ok, either boots has been advanced, or
- * time is greater than before with the same boots.
- */
-
- if (set_enginetime(secEngineID, secEngineIDLen,
- boots_uint, time_uint, TRUE)
- != SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed updating remote boot/time."));
- *error = SNMPERR_USM_GENERICERROR;
- return -1;
- }
-
- *error = SNMPERR_SUCCESS;
- return 0; /* Fresh message and time updated */
-
- } /* endif -- local or remote time reference. */
-
-
-} /* end usm_check_and_update_timeliness() */
-
-
-
-int
-usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms)
-{
- if (!parms)
- return SNMPERR_GENERR;
-
- return usm_process_in_msg(parms->msgProcModel,
- parms->maxMsgSize,
- parms->secParams,
- parms->secModel,
- parms->secLevel,
- parms->wholeMsg,
- parms->wholeMsgLen,
- parms->secEngineID,
- parms->secEngineIDLen,
- parms->secName,
- parms->secNameLen,
- parms->scopedPdu,
- parms->scopedPduLen,
- parms->maxSizeResponse,
- parms->secStateRef,
- parms->sess, parms->msg_flags);
-}
-
-/*******************************************************************-o-******
- * usm_process_in_msg
- *
- * Parameters:
- * (See list below...)
- *
- * Returns:
- * SNMPERR_SUCCESS On success.
- * SNMPERR_USM_AUTHENTICATIONFAILURE
- * SNMPERR_USM_DECRYPTIONERROR
- * SNMPERR_USM_GENERICERROR
- * SNMPERR_USM_PARSEERROR
- * SNMPERR_USM_UNKNOWNENGINEID
- * SNMPERR_USM_PARSEERROR
- * SNMPERR_USM_UNKNOWNSECURITYNAME
- * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
- *
- *
- * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
- *
- * FIX Memory leaks if secStateRef is allocated and a return occurs
- * without cleaning up. May contain secrets...
- */
-int
-usm_process_in_msg(int msgProcModel, /* (UNUSED) */
- size_t maxMsgSize, /* IN - Used to calc maxSizeResponse. */
- u_char * secParams, /* IN - BER encoded securityParameters. */
- int secModel, /* (UNUSED) */
- int secLevel, /* IN - AuthNoPriv, authPriv etc. */
- u_char * wholeMsg, /* IN - Original v3 message. */
- size_t wholeMsgLen, /* IN - Msg length. */
- u_char * secEngineID, /* OUT - Pointer snmpEngineID. */
- size_t * secEngineIDLen, /* IN/OUT - Len available, len returned. */
- /*
- * NOTE: Memory provided by caller.
- */
- char *secName, /* OUT - Pointer to securityName. */
- size_t * secNameLen, /* IN/OUT - Len available, len returned. */
- u_char ** scopedPdu, /* OUT - Pointer to plaintext scopedPdu. */
- size_t * scopedPduLen, /* IN/OUT - Len available, len returned. */
- size_t * maxSizeResponse, /* OUT - Max size of Response PDU. */
- void **secStateRf, /* OUT - Ref to security state. */
- netsnmp_session * sess, /* IN - session which got the message */
- u_char msg_flags)
-{ /* IN - v3 Message flags. */
- size_t remaining = wholeMsgLen - (u_int)
- ((u_long) * secParams - (u_long) * wholeMsg);
- u_int boots_uint;
- u_int time_uint;
-#ifdef HAVE_AES
- u_int net_boots, net_time;
-#endif
- u_char signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
- size_t signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
- u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
- size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
- u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
- u_int iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
- u_char *data_ptr;
- u_char *value_ptr;
- u_char type_value;
- u_char *end_of_overhead = NULL;
- int error;
- int i, rc = 0;
- struct usmStateReference **secStateRef =
- (struct usmStateReference **) secStateRf;
-
- struct usmUser *user;
-
-
- DEBUGMSGTL(("usm", "USM processing begun...\n"));
-
-
- if (secStateRef) {
- usm_free_usmStateReference(*secStateRef);
- *secStateRef = usm_malloc_usmStateReference();
- if (*secStateRef == NULL) {
- DEBUGMSGTL(("usm", "Out of memory.\n"));
- return SNMPERR_USM_GENERICERROR;
- }
- }
-
-
- /*
- * Make sure the *secParms is an OCTET STRING.
- * Extract the user name, engine ID, and security level.
- */
- if ((rc = usm_parse_security_parameters(secParams, remaining,
- secEngineID, secEngineIDLen,
- &boots_uint, &time_uint,
- secName, secNameLen,
- signature, &signature_length,
- salt, &salt_length,
- &data_ptr)) < 0) {
- DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc));
- if (rc == -2) {
- /*
- * This indicates a decryptionError.
- */
- if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed to increment statistic."));
- }
- return SNMPERR_USM_DECRYPTIONERROR;
- }
- if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
- }
- return SNMPERR_USM_PARSEERROR;
- }
-
- /*
- * RFC 2574 section 8.3.2
- * 1) If the privParameters field is not an 8-octet OCTET STRING,
- * then an error indication (decryptionError) is returned to the
- * calling module.
- */
- if ((secLevel == SNMP_SEC_LEVEL_AUTHPRIV) && (salt_length != 8)) {
- if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
- }
- return SNMPERR_USM_DECRYPTIONERROR;
- }
-
- if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) {
- /*
- * pull these out now so reports can use them
- */
- *scopedPdu = data_ptr;
- *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
- end_of_overhead = data_ptr;
- }
-
- if (secStateRef) {
- /*
- * Cache the name, engine ID, and security level,
- * * per step 2 (section 3.2)
- */
- if (usm_set_usmStateReference_name
- (*secStateRef, secName, *secNameLen) == -1) {
- DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (usm_set_usmStateReference_engine_id
- (*secStateRef, secEngineID, *secEngineIDLen) == -1) {
- DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) ==
- -1) {
- DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level."));
- return SNMPERR_USM_GENERICERROR;
- }
- }
-
-
- /*
- * Locate the engine ID record.
- * If it is unknown, then either create one or note this as an error.
- */
- if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE ||
- (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH &&
- (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) ||
- (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) {
- if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) {
- DEBUGMSGTL(("usm", "Unknown Engine ID.\n"));
- if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed to increment statistic."));
- }
- return SNMPERR_USM_UNKNOWNENGINEID;
- }
- } else {
- if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen)
- != SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- }
-
-
- /*
- * Locate the User record.
- * If the user/engine ID is unknown, report this as an error.
- */
- if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen,
- secName, userList,
- (((sess && sess->isAuthoritative ==
- SNMP_SESS_AUTHORITATIVE) ||
- (!sess)) ? 0 : 1)))
- == NULL) {
- DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
- if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES) == 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
- }
- return SNMPERR_USM_UNKNOWNSECURITYNAME;
- }
-
-
- /*
- * Make sure the security level is appropriate.
- */
- if (usm_check_secLevel(secLevel, user) == 1) {
- DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n",
- secLevel));
- if (snmp_increment_statistic
- (STAT_USMSTATSUNSUPPORTEDSECLEVELS) == 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
- }
- return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
- }
-
-
- /*
- * Check the authentication credentials of the message.
- */
- if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen,
- user->authKey, user->authKeyLen,
- wholeMsg, wholeMsgLen,
- signature, signature_length)
- != SNMP_ERR_NOERROR) {
- DEBUGMSGTL(("usm", "Verification failed.\n"));
- if (snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS) == 0) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed to increment statistic."));
- }
- snmp_log(LOG_WARNING, "Authentication failed for %s\n",
- user->name);
- return SNMPERR_USM_AUTHENTICATIONFAILURE;
- }
-
- DEBUGMSGTL(("usm", "Verification succeeded.\n"));
- }
-
-
- /*
- * Steps 10-11 user is already set - relocated before timeliness
- * check in case it fails - still save user data for response.
- *
- * Cache the keys and protocol oids, per step 11 (s3.2).
- */
- if (secStateRef) {
- if (usm_set_usmStateReference_auth_protocol(*secStateRef,
- user->authProtocol,
- user->
- authProtocolLen) ==
- -1) {
- DEBUGMSGTL(("usm", "%s\n",
- "Couldn't cache authentication protocol."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (usm_set_usmStateReference_auth_key(*secStateRef,
- user->authKey,
- user->authKeyLen) == -1) {
- DEBUGMSGTL(("usm", "%s\n",
- "Couldn't cache authentication key."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (usm_set_usmStateReference_priv_protocol(*secStateRef,
- user->privProtocol,
- user->
- privProtocolLen) ==
- -1) {
- DEBUGMSGTL(("usm", "%s\n",
- "Couldn't cache privacy protocol."));
- return SNMPERR_USM_GENERICERROR;
- }
-
- if (usm_set_usmStateReference_priv_key(*secStateRef,
- user->privKey,
- user->privKeyLen) == -1) {
- DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key."));
- return SNMPERR_USM_GENERICERROR;
- }
- }
-
-
- /*
- * Perform the timeliness/time manager functions.
- */
- if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
- || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen,
- boots_uint, time_uint,
- &error) == -1) {
- return error;
- }
- }
-#ifdef LCD_TIME_SYNC_OPT
- /*
- * Cache the unauthenticated time to use in case we don't have
- * anything better - this guess will be no worse than (0,0)
- * that we normally use.
- */
- else {
- set_enginetime(secEngineID, *secEngineIDLen,
- boots_uint, time_uint, FALSE);
- }
-#endif /* LCD_TIME_SYNC_OPT */
-
-
- /*
- * If needed, decrypt the scoped PDU.
- */
- if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
- remaining = wholeMsgLen - (data_ptr - wholeMsg);
-
- if ((value_ptr = asn_parse_sequence(data_ptr, &remaining,
- &type_value,
- (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- "encrypted sPDU")) == NULL) {
- DEBUGMSGTL(("usm", "%s\n",
- "Failed while parsing encrypted sPDU."));
- if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
- }
- usm_free_usmStateReference(*secStateRef);
- *secStateRef = NULL;
- return SNMPERR_USM_PARSEERROR;
- }
-
-#ifndef NETSNMP_DISABLE_DES
- if (ISTRANSFORM(user->privProtocol, DESPriv)) {
- /*
- * From RFC2574:
- *
- * "Before decryption, the encrypted data length is verified.
- * If the length of the OCTET STRING to be decrypted is not
- * an integral multiple of 8 octets, the decryption process
- * is halted and an appropriate exception noted."
- */
-
- if (remaining % 8 != 0) {
- DEBUGMSGTL(("usm",
- "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
- remaining, remaining % 8));
- if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
- }
- usm_free_usmStateReference(*secStateRef);
- *secStateRef = NULL;
- return SNMPERR_USM_DECRYPTIONERROR;
- }
-
- end_of_overhead = value_ptr;
-
- /*
- * XOR the salt with the last (iv_length) bytes
- * of the priv_key to obtain the IV.
- */
- iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
- for (i = 0; i < (int) iv_length; i++)
- iv[i] = salt[i] ^ user->privKey[iv_length + i];
- }
-#endif
-#ifdef HAVE_AES
- if (ISTRANSFORM(user->privProtocol, AESPriv)) {
- iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
- net_boots = ntohl(boots_uint);
- net_time = ntohl(time_uint);
- memcpy(iv, &net_boots, 4);
- memcpy(iv+4, &net_time, 4);
- memcpy(iv+8, salt, salt_length);
- }
-#endif
-
- if (sc_decrypt(user->privProtocol, user->privProtocolLen,
- user->privKey, user->privKeyLen,
- iv, iv_length,
- value_ptr, remaining, *scopedPdu, scopedPduLen)
- != SNMP_ERR_NOERROR) {
- DEBUGMSGTL(("usm", "%s\n", "Failed decryption."));
- if (snmp_increment_statistic
- (STAT_USMSTATSDECRYPTIONERRORS) == 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
- }
- return SNMPERR_USM_DECRYPTIONERROR;
- }
-#ifdef NETSNMP_ENABLE_TESTING_CODE
- if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
- dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining);
- dump_chunk("usm/dump", "salt + Encrypted form:",
- salt, salt_length);
- dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length);
- dump_chunk("usm/dump", "Decrypted chunk:",
- *scopedPdu, *scopedPduLen);
- }
-#endif
- }
- /*
- * sPDU is plaintext.
- */
- else {
- *scopedPdu = data_ptr;
- *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
- end_of_overhead = data_ptr;
-
- } /* endif -- PDU decryption */
-
-
- /*
- * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
- *
- * FIX Correct?
- */
- *maxSizeResponse = maxMsgSize - (int)
- ((u_long) end_of_overhead - (u_long) wholeMsg);
-
-
- DEBUGMSGTL(("usm", "USM processing completed.\n"));
-
- return SNMPERR_SUCCESS;
-
-} /* end usm_process_in_msg() */
-
-void
-usm_handle_report(void *sessp,
- netsnmp_transport *transport, netsnmp_session *session,
- int result, netsnmp_pdu *pdu)
-{
- /*
- * handle reportable errors
- */
-
- /* this will get in our way */
- usm_free_usmStateReference(pdu->securityStateRef);
- pdu->securityStateRef = NULL;
-
- switch (result) {
- case SNMPERR_USM_AUTHENTICATIONFAILURE:
- {
- int res = session->s_snmp_errno;
- session->s_snmp_errno = result;
- if (session->callback) {
- session->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
- session, pdu->reqid, pdu,
- session->callback_magic);
- }
- session->s_snmp_errno = res;
- }
- case SNMPERR_USM_UNKNOWNENGINEID:
- case SNMPERR_USM_UNKNOWNSECURITYNAME:
- case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
- case SNMPERR_USM_NOTINTIMEWINDOW:
- case SNMPERR_USM_DECRYPTIONERROR:
-
- if (SNMP_CMD_CONFIRMED(pdu->command) ||
- (pdu->command == 0
- && (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT))) {
- netsnmp_pdu *pdu2;
- int flags = pdu->flags;
-
- pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
- pdu2 = snmp_clone_pdu(pdu);
- pdu->flags = pdu2->flags = flags;
- snmpv3_make_report(pdu2, result);
- if (0 == snmp_sess_send(sessp, pdu2)) {
- snmp_free_pdu(pdu2);
- /*
- * TODO: indicate error
- */
- }
- }
- break;
- }
-}
-void
-init_usm(void)
-{
- struct snmp_secmod_def *def;
-
- DEBUGMSGTL(("init_usm", "unit_usm: %d %d\n", usmNoPrivProtocol[0],
- usmNoPrivProtocol[1]));
-
- sc_init(); /* initalize scapi code */
-
- /*
- * register ourselves as a security service
- */
- def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
- /*
- * XXX: def->init_sess_secmod move stuff from snmp_api.c
- */
- def->encode_reverse = usm_secmod_rgenerate_out_msg;
- def->encode_forward = usm_secmod_generate_out_msg;
- def->decode = usm_secmod_process_in_msg;
- def->pdu_free_state_ref = usm_free_usmStateReference;
- def->handle_report = usm_handle_report;
- register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def);
-
- snmp_register_callback(SNMP_CALLBACK_LIBRARY,
- SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
- init_usm_post_config, NULL);
-
- snmp_register_callback(SNMP_CALLBACK_LIBRARY,
- SNMP_CALLBACK_SHUTDOWN,
- deinit_usm_post_config, NULL);
-
- snmp_register_callback(SNMP_CALLBACK_LIBRARY,
- SNMP_CALLBACK_SHUTDOWN,
- free_engineID, NULL);
-
-}
-
-void
-init_usm_conf(const char *app)
-{
- register_config_handler(app, "usmUser",
- usm_parse_config_usmUser, NULL, NULL);
- register_config_handler(app, "createUser",
- usm_parse_create_usmUser, NULL,
- "username [-e ENGINEID] (MD5|SHA) authpassphrase [DES [privpassphrase]]");
-
- /*
- * we need to be called back later
- */
- snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
- usm_store_users, NULL);
-}
-
-/*
- * initializations for the USM.
- *
- * Should be called after the (engineid) configuration files have been read.
- *
- * Set "arbitrary" portion of salt to a random number.
- */
-int
-init_usm_post_config(int majorid, int minorid, void *serverarg,
- void *clientarg)
-{
- size_t salt_integer_len = sizeof(salt_integer);
-
- if (sc_random((u_char *) & salt_integer, &salt_integer_len) !=
- SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
- salt_integer = (u_int) time(NULL);
- }
-
-#ifdef HAVE_AES
- salt_integer_len = sizeof (salt_integer64_1);
- if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
- SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
- salt_integer64_1 = (u_int) time(NULL);
- }
- salt_integer_len = sizeof (salt_integer64_1);
- if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
- SNMPERR_SUCCESS) {
- DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
- salt_integer64_2 = (u_int) time(NULL);
- }
-#endif
-
-#ifndef NETSNMP_DISABLE_MD5
- noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
- USM_LENGTH_OID_TRANSFORM,
-#ifndef NETSNMP_DISABLE_DES
- usmDESPrivProtocol,
-#else
- usmAESPrivProtocol,
-#endif
- USM_LENGTH_OID_TRANSFORM);
-#else
- noNameUser = usm_create_initial_user("", usmHMACSHA1AuthProtocol,
- USM_LENGTH_OID_TRANSFORM,
-#ifndef NETSNMP_DISABLE_DES
- usmDESPrivProtocol,
-#else
- usmAESPrivProtocol,
-#endif
- USM_LENGTH_OID_TRANSFORM);
-#endif
-
- if ( noNameUser ) {
- SNMP_FREE(noNameUser->engineID);
- noNameUser->engineIDLen = 0;
- }
-
- return SNMPERR_SUCCESS;
-} /* end init_usm_post_config() */
-
-int
-deinit_usm_post_config(int majorid, int minorid, void *serverarg,
- void *clientarg)
-{
- if (usm_free_user(noNameUser) != NULL) {
- DEBUGMSGTL(("deinit_usm_post_config", "could not free initial user\n"));
- return SNMPERR_GENERR;
- }
- noNameUser = NULL;
-
- DEBUGMSGTL(("deinit_usm_post_config", "initial user removed\n"));
- return SNMPERR_SUCCESS;
-} /* end deinit_usm_post_config() */
-
-void
-clear_user_list(void)
-{
- struct usmUser *tmp = userList, *next = NULL;
-
- while (tmp != NULL) {
- next = tmp->next;
- usm_free_user(tmp);
- tmp = next;
- }
- userList = NULL;
-
-}
-
-/*******************************************************************-o-******
- * usm_check_secLevel
- *
- * Parameters:
- * level
- * *user
- *
- * Returns:
- * 0 On success,
- * -1 Otherwise.
- *
- * Checks that a given security level is valid for a given user.
- */
-int
-usm_check_secLevel(int level, struct usmUser *user)
-{
-
- if (user->userStatus != RS_ACTIVE)
- return -1;
-
- DEBUGMSGTL(("comparex", "Comparing: %d %d ", usmNoPrivProtocol[0],
- usmNoPrivProtocol[1]));
- DEBUGMSGOID(("comparex", usmNoPrivProtocol,
- sizeof(usmNoPrivProtocol) / sizeof(oid)));
- DEBUGMSG(("comparex", "\n"));
- if (level == SNMP_SEC_LEVEL_AUTHPRIV
- && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen,
- usmNoPrivProtocol,
- sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
- 0)) {
- DEBUGMSGTL(("usm", "Level: %d\n", level));
- DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
- DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
- DEBUGMSG(("usm", ", User Priv Protocol: "));
- DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
- DEBUGMSG(("usm", "\n"));
- return 1;
- }
- if ((level == SNMP_SEC_LEVEL_AUTHPRIV
- || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
- &&
- (netsnmp_oid_equals
- (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol,
- sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
- DEBUGMSGTL(("usm", "Level: %d\n", level));
- DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
- DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
- DEBUGMSG(("usm", ", User Priv Protocol: "));
- DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
- DEBUGMSG(("usm", "\n"));
- return 1;
- }
-
- return 0;
-
-} /* end usm_check_secLevel() */
-
-
-
-
-/*******************************************************************-o-******
- * usm_check_secLevel_vs_protocols
- *
- * Parameters:
- * level
- * *authProtocol
- * authProtocolLen
- * *privProtocol
- * privProtocolLen
- *
- * Returns:
- * 0 On success,
- * 1 Otherwise.
- *
- * Same as above but with explicitly named transform types instead of taking
- * from the usmUser structure.
- */
-int
-usm_check_secLevel_vs_protocols(int level,
- const oid * authProtocol,
- u_int authProtocolLen,
- const oid * privProtocol,
- u_int privProtocolLen)
-{
-
- if (level == SNMP_SEC_LEVEL_AUTHPRIV
- &&
- (netsnmp_oid_equals
- (privProtocol, privProtocolLen, usmNoPrivProtocol,
- sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0)) {
- DEBUGMSGTL(("usm", "Level: %d\n", level));
- DEBUGMSGTL(("usm", "Auth Protocol: "));
- DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
- DEBUGMSG(("usm", ", Priv Protocol: "));
- DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
- DEBUGMSG(("usm", "\n"));
- return 1;
- }
- if ((level == SNMP_SEC_LEVEL_AUTHPRIV
- || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
- &&
- (netsnmp_oid_equals
- (authProtocol, authProtocolLen, usmNoAuthProtocol,
- sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
- DEBUGMSGTL(("usm", "Level: %d\n", level));
- DEBUGMSGTL(("usm", "Auth Protocol: "));
- DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
- DEBUGMSG(("usm", ", Priv Protocol: "));
- DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
- DEBUGMSG(("usm", "\n"));
- return 1;
- }
-
- return 0;
-
-} /* end usm_check_secLevel_vs_protocols() */
-
-
-
-
-/*
- * usm_get_user(): Returns a user from userList based on the engineID,
- * engineIDLen and name of the requested user.
- */
-
-struct usmUser *
-usm_get_user(u_char * engineID, size_t engineIDLen, char *name)
-{
- DEBUGMSGTL(("usm", "getting user %s\n", name));
- return usm_get_user_from_list(engineID, engineIDLen, name, userList,
- 1);
-}
-
-struct usmUser *
-usm_get_user_from_list(u_char * engineID, size_t engineIDLen,
- char *name, struct usmUser *puserList,
- int use_default)
-{
- struct usmUser *ptr;
- char noName[] = "";
- if (name == NULL)
- name = noName;
- for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
- if (ptr->name && !strcmp(ptr->name, name)) {
- DEBUGMSGTL(("usm", "match on user %s\n", ptr->name));
- if (ptr->engineIDLen == engineIDLen &&
- ((ptr->engineID == NULL && engineID == NULL) ||
- (ptr->engineID != NULL && engineID != NULL &&
- memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
- return ptr;
- DEBUGMSGTL(("usm", "no match on engineID ("));
- DEBUGMSGHEX(("usm", engineID, engineIDLen));
- DEBUGMSG(("usm", ")\n"));
- }
- }
-
- /*
- * return "" user used to facilitate engineID discovery
- */
- if (use_default && !strcmp(name, ""))
- return noNameUser;
- return NULL;
-}
-
-/*
- * usm_add_user(): Add's a user to the userList, sorted by the
- * engineIDLength then the engineID then the name length then the name
- * to facilitate getNext calls on a usmUser table which is indexed by
- * these values.
- *
- * Note: userList must not be NULL (obviously), as thats a rather trivial
- * addition and is left to the API user.
- *
- * returns the head of the list (which could change due to this add).
- */
-
-struct usmUser *
-usm_add_user(struct usmUser *user)
-{
- struct usmUser *uptr;
- uptr = usm_add_user_to_list(user, userList);
- if (uptr != NULL)
- userList = uptr;
- return uptr;
-}
-
-struct usmUser *
-usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
-{
- struct usmUser *nptr, *pptr, *optr;
-
- /*
- * loop through puserList till we find the proper, sorted place to
- * insert the new user
- */
- /* XXX - how to handle a NULL user->name ?? */
- /* XXX - similarly for a NULL nptr->name ?? */
- for (nptr = puserList, pptr = NULL; nptr != NULL;
- pptr = nptr, nptr = nptr->next) {
- if (nptr->engineIDLen > user->engineIDLen)
- break;
-
- if (user->engineID == NULL && nptr->engineID != NULL)
- break;
-
- if (nptr->engineIDLen == user->engineIDLen &&
- (nptr->engineID != NULL && user->engineID != NULL &&
- memcmp(nptr->engineID, user->engineID,
- user->engineIDLen) > 0))
- break;
-
- if (!(nptr->engineID == NULL && user->engineID != NULL)) {
- if (nptr->engineIDLen == user->engineIDLen &&
- ((nptr->engineID == NULL && user->engineID == NULL) ||
- memcmp(nptr->engineID, user->engineID,
- user->engineIDLen) == 0)
- && strlen(nptr->name) > strlen(user->name))
- break;
-
- if (nptr->engineIDLen == user->engineIDLen &&
- ((nptr->engineID == NULL && user->engineID == NULL) ||
- memcmp(nptr->engineID, user->engineID,
- user->engineIDLen) == 0)
- && strlen(nptr->name) == strlen(user->name)
- && strcmp(nptr->name, user->name) > 0)
- break;
-
- if (nptr->engineIDLen == user->engineIDLen &&
- ((nptr->engineID == NULL && user->engineID == NULL) ||
- memcmp(nptr->engineID, user->engineID,
- user->engineIDLen) == 0)
- && strlen(nptr->name) == strlen(user->name)
- && strcmp(nptr->name, user->name) == 0) {
- /*
- * the user is an exact match of a previous entry.
- * Credentials may be different, though, so remove
- * the old entry (and add the new one)!
- */
- if (pptr) { /* change prev's next pointer */
- pptr->next = nptr->next;
- }
- if (nptr->next) { /* change next's prev pointer */
- nptr->next->prev = pptr;
- }
- optr = nptr;
- nptr = optr->next; /* add new user at this position */
- /* free the old user */
- optr->next=NULL;
- optr->prev=NULL;
- usm_free_user(optr);
- break; /* new user will be added below */
- }
- }
- }
-
- /*
- * nptr should now point to the user that we need to add ourselves
- * in front of, and pptr should be our new 'prev'.
- */
-
- /*
- * change our pointers
- */
- user->prev = pptr;
- user->next = nptr;
-
- /*
- * change the next's prev pointer
- */
- if (user->next)
- user->next->prev = user;
-
- /*
- * change the prev's next pointer
- */
- if (user->prev)
- user->prev->next = user;
-
- /*
- * rewind to the head of the list and return it (since the new head
- * could be us, we need to notify the above routine who the head now is.
- */
- for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
- return pptr;
-}
-
-/*
- * usm_remove_user(): finds and removes a user from a list
- */
-struct usmUser *
-usm_remove_user(struct usmUser *user)
-{
- return usm_remove_user_from_list(user, &userList);
-}
-
-struct usmUser *
-usm_remove_user_from_list(struct usmUser *user,
- struct usmUser **ppuserList)
-{
- struct usmUser *nptr, *pptr;
-
- /*
- * NULL pointers aren't allowed
- */
- if (ppuserList == NULL)
- return NULL;
-
- if (*ppuserList == NULL)
- return NULL;
-
- /*
- * find the user in the list
- */
- for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
- pptr = nptr, nptr = nptr->next) {
- if (nptr == user)
- break;
- }
-
- if (nptr) {
- /*
- * remove the user from the linked list
- */
- if (pptr) {
- pptr->next = nptr->next;
- }
- if (nptr->next) {
- nptr->next->prev = pptr;
- }
- } else {
- /*
- * user didn't exist
- */
- return NULL;
- }
- if (nptr == *ppuserList) /* we're the head of the list, need to change
- * * the head to the next user */
- *ppuserList = nptr->next;
- return *ppuserList;
-} /* end usm_remove_user_from_list() */
-
-
-
-
-/*
- * usm_free_user(): calls free() on all needed parts of struct usmUser and
- * the user himself.
- *
- * Note: This should *not* be called on an object in a list (IE,
- * remove it from the list first, and set next and prev to NULL), but
- * will try to reconnect the list pieces again if it is called this
- * way. If called on the head of the list, the entire list will be
- * lost.
- */
-struct usmUser *
-usm_free_user(struct usmUser *user)
-{
- if (user == NULL)
- return NULL;
-
- SNMP_FREE(user->engineID);
- SNMP_FREE(user->name);
- SNMP_FREE(user->secName);
- SNMP_FREE(user->cloneFrom);
- SNMP_FREE(user->userPublicString);
- SNMP_FREE(user->authProtocol);
- SNMP_FREE(user->privProtocol);
-
- if (user->authKey != NULL) {
- SNMP_ZERO(user->authKey, user->authKeyLen);
- SNMP_FREE(user->authKey);
- }
-
- if (user->privKey != NULL) {
- SNMP_ZERO(user->privKey, user->privKeyLen);
- SNMP_FREE(user->privKey);
- }
-
-
- /*
- * FIX Why not put this check *first?*
- */
- if (user->prev != NULL) { /* ack, this shouldn't happen */
- user->prev->next = user->next;
- }
- if (user->next != NULL) {
- user->next->prev = user->prev;
- if (user->prev != NULL) /* ack this is really bad, because it means
- * * we'll loose the head of some structure tree */
- DEBUGMSGTL(("usm",
- "Severe: Asked to free the head of a usmUser tree somewhere."));
- }
-
-
- SNMP_ZERO(user, sizeof(*user));
- SNMP_FREE(user);
-
- return NULL; /* for convenience to returns from calling functions */
-
-} /* end usm_free_user() */
-
-
-
-
-/*
- * take a given user and clone the security info into another
- */
-struct usmUser *
-usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
-{
- /*
- * copy the authProtocol oid row pointer
- */
- SNMP_FREE(to->authProtocol);
-
- if ((to->authProtocol =
- snmp_duplicate_objid(from->authProtocol,
- from->authProtocolLen)) != NULL)
- to->authProtocolLen = from->authProtocolLen;
- else
- to->authProtocolLen = 0;
-
-
- /*
- * copy the authKey
- */
- SNMP_FREE(to->authKey);
-
- if (from->authKeyLen > 0 &&
- (to->authKey = (u_char *) malloc(from->authKeyLen))
- != NULL) {
- to->authKeyLen = from->authKeyLen;
- memcpy(to->authKey, from->authKey, to->authKeyLen);
- } else {
- to->authKey = NULL;
- to->authKeyLen = 0;
- }
-
-
- /*
- * copy the privProtocol oid row pointer
- */
- SNMP_FREE(to->privProtocol);
-
- if ((to->privProtocol =
- snmp_duplicate_objid(from->privProtocol,
- from->privProtocolLen)) != NULL)
- to->privProtocolLen = from->privProtocolLen;
- else
- to->privProtocolLen = 0;
-
- /*
- * copy the privKey
- */
- SNMP_FREE(to->privKey);
-
- if (from->privKeyLen > 0 &&
- (to->privKey = (u_char *) malloc(from->privKeyLen))
- != NULL) {
- to->privKeyLen = from->privKeyLen;
- memcpy(to->privKey, from->privKey, to->privKeyLen);
- } else {
- to->privKey = NULL;
- to->privKeyLen = 0;
- }
- return to;
-}
-
-/*
- * usm_create_user(void):
- * create a default empty user, instantiating only the auth/priv
- * protocols to noAuth and noPriv OID pointers
- */
-struct usmUser *
-usm_create_user(void)
-{
- struct usmUser *newUser;
-
- /*
- * create the new user
- */
- newUser = (struct usmUser *) calloc(1, sizeof(struct usmUser));
- if (newUser == NULL)
- return NULL;
-
- /*
- * fill the auth/priv protocols
- */
- if ((newUser->authProtocol =
- snmp_duplicate_objid(usmNoAuthProtocol,
- sizeof(usmNoAuthProtocol) / sizeof(oid))) ==
- NULL)
- return usm_free_user(newUser);
- newUser->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
-
- if ((newUser->privProtocol =
- snmp_duplicate_objid(usmNoPrivProtocol,
- sizeof(usmNoPrivProtocol) / sizeof(oid))) ==
- NULL)
- return usm_free_user(newUser);
- newUser->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
-
- /*
- * set the storage type to nonvolatile, and the status to ACTIVE
- */
- newUser->userStorageType = ST_NONVOLATILE;
- newUser->userStatus = RS_ACTIVE;
- return newUser;
-
-} /* end usm_clone_user() */
-
-
-
-
-/*
- * usm_create_initial_user(void):
- * creates an initial user, filled with the defaults defined in the
- * USM document.
- */
-struct usmUser *
-usm_create_initial_user(const char *name,
- const oid * authProtocol, size_t authProtocolLen,
- const oid * privProtocol, size_t privProtocolLen)
-{
- struct usmUser *newUser = usm_create_user();
- if (newUser == NULL)
- return NULL;
-
- if ((newUser->name = strdup(name)) == NULL)
- return usm_free_user(newUser);
-
- if ((newUser->secName = strdup(name)) == NULL)
- return usm_free_user(newUser);
-
- if ((newUser->engineID =
- snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
- return usm_free_user(newUser);
-
- if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL)
- return usm_free_user(newUser);
- newUser->cloneFrom[0] = 0;
- newUser->cloneFrom[1] = 0;
- newUser->cloneFromLen = 2;
-
- SNMP_FREE(newUser->privProtocol);
- if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol,
- privProtocolLen)) ==
- NULL) {
- return usm_free_user(newUser);
- }
- newUser->privProtocolLen = privProtocolLen;
-
- SNMP_FREE(newUser->authProtocol);
- if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol,
- authProtocolLen)) ==
- NULL) {
- return usm_free_user(newUser);
- }
- newUser->authProtocolLen = authProtocolLen;
-
- newUser->userStatus = RS_ACTIVE;
- newUser->userStorageType = ST_READONLY;
-
- return newUser;
-}
-
-/*
- * this is a callback that can store all known users based on a
- * previously registered application ID
- */
-int
-usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
-{
- /*
- * figure out our application name
- */
- char *appname = (char *) clientarg;
- if (appname == NULL) {
- appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_APPTYPE);
- }
-
- /*
- * save the user base
- */
- usm_save_users("usmUser", appname);
-
- /*
- * never fails
- */
- return SNMPERR_SUCCESS;
-}
-
-
-/*
- * usm_save_users(): saves a list of users to the persistent cache
- */
-void
-usm_save_users(const char *token, const char *type)
-{
- usm_save_users_from_list(userList, token, type);
-}
-
-void
-usm_save_users_from_list(struct usmUser *puserList, const char *token,
- const char *type)
-{
- struct usmUser *uptr;
- for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
- if (uptr->userStorageType == ST_NONVOLATILE)
- usm_save_user(uptr, token, type);
- }
-}
-
-/*
- * usm_save_user(): saves a user to the persistent cache
- */
-void
-usm_save_user(struct usmUser *user, const char *token, const char *type)
-{
- char line[4096];
- char *cptr;
-
- memset(line, 0, sizeof(line));
-
- sprintf(line, "%s %d %d ", token, user->userStatus,
- user->userStorageType);
- cptr = &line[strlen(line)]; /* the NULL */
- cptr =
- read_config_save_octet_string(cptr, user->engineID,
- user->engineIDLen);
- *cptr++ = ' ';
- cptr = read_config_save_octet_string(cptr, (u_char *) user->name,
- (user->name == NULL) ? 0 :
- strlen(user->name) + 1);
- *cptr++ = ' ';
- cptr = read_config_save_octet_string(cptr, (u_char *) user->secName,
- (user->secName == NULL) ? 0 :
- strlen(user->secName) + 1);
- *cptr++ = ' ';
- cptr =
- read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
- *cptr++ = ' ';
- cptr = read_config_save_objid(cptr, user->authProtocol,
- user->authProtocolLen);
- *cptr++ = ' ';
- cptr =
- read_config_save_octet_string(cptr, user->authKey,
- user->authKeyLen);
- *cptr++ = ' ';
- cptr = read_config_save_objid(cptr, user->privProtocol,
- user->privProtocolLen);
- *cptr++ = ' ';
- cptr =
- read_config_save_octet_string(cptr, user->privKey,
- user->privKeyLen);
- *cptr++ = ' ';
- cptr = read_config_save_octet_string(cptr, user->userPublicString,
- (user->userPublicString ==
- NULL) ? 0 : strlen((char *)
- user->
- userPublicString)
- + 1);
- read_config_store(type, line);
-}
-
-/*
- * usm_parse_user(): reads in a line containing a saved user profile
- * and returns a pointer to a newly created struct usmUser.
- */
-struct usmUser *
-usm_read_user(char *line)
-{
- struct usmUser *user;
- size_t len;
- size_t expected_privKeyLen = 0;
-
- user = usm_create_user();
- if (user == NULL)
- return NULL;
-
- user->userStatus = atoi(line);
- line = skip_token(line);
- user->userStorageType = atoi(line);
- line = skip_token(line);
- line = read_config_read_octet_string(line, &user->engineID,
- &user->engineIDLen);
-
- /*
- * set the lcd entry for this engineID to the minimum boots/time
- * values so that its a known engineid and won't return a report pdu.
- * This is mostly important when receiving v3 traps so that the usm
- * will at least continue processing them.
- */
- set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
-
- line = read_config_read_octet_string(line, (u_char **) & user->name,
- &len);
- line = read_config_read_octet_string(line, (u_char **) & user->secName,
- &len);
- SNMP_FREE(user->cloneFrom);
- user->cloneFromLen = 0;
-
- line =
- read_config_read_objid(line, &user->cloneFrom,
- &user->cloneFromLen);
-
- SNMP_FREE(user->authProtocol);
- user->authProtocolLen = 0;
-
- line = read_config_read_objid(line, &user->authProtocol,
- &user->authProtocolLen);
- line = read_config_read_octet_string(line, &user->authKey,
- &user->authKeyLen);
- SNMP_FREE(user->privProtocol);
- user->privProtocolLen = 0;
-
- line = read_config_read_objid(line, &user->privProtocol,
- &user->privProtocolLen);
- line = read_config_read_octet_string(line, &user->privKey,
- &user->privKeyLen);
-#ifndef NETSNMP_DISABLE_DES
- if (ISTRANSFORM(user->privProtocol, DESPriv)) {
- /* DES uses a 128 bit key, 64 bits of which is a salt */
- expected_privKeyLen = 16;
- }
-#endif
-#ifdef HAVE_AES
- if (ISTRANSFORM(user->privProtocol, AESPriv)) {
- expected_privKeyLen = 16;
- }
-#endif
- /* For backwards compatibility */
- if (user->privKeyLen > expected_privKeyLen) {
- user->privKeyLen = expected_privKeyLen;
- }
-
- line = read_config_read_octet_string(line, &user->userPublicString,
- &len);
- return user;
-}
-
-/*
- * snmpd.conf parsing routines
- */
-void
-usm_parse_config_usmUser(const char *token, char *line)
-{
- struct usmUser *uptr;
-
- uptr = usm_read_user(line);
- if ( uptr)
- usm_add_user(uptr);
-}
-
-
-
-
-/*******************************************************************-o-******
- * usm_set_password
- *
- * Parameters:
- * *token
- * *line
- *
- *
- * format: userSetAuthPass secname engineIDLen engineID pass
- * or: userSetPrivPass secname engineIDLen engineID pass
- * or: userSetAuthKey secname engineIDLen engineID KuLen Ku
- * or: userSetPrivKey secname engineIDLen engineID KuLen Ku
- * or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
- * or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul
- *
- * type is: 1=passphrase; 2=Ku; 3=Kul.
- *
- *
- * ASSUMES Passwords are null-terminated printable strings.
- */
-void
-usm_set_password(const char *token, char *line)
-{
- char *cp;
- char nameBuf[SNMP_MAXBUF];
- u_char *engineID;
- size_t engineIDLen;
- struct usmUser *user;
-
- cp = copy_nword(line, nameBuf, sizeof(nameBuf));
- if (cp == NULL) {
- config_perror("invalid name specifier");
- return;
- }
-
- DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
- if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
- /*
- * match against all engineIDs we know about
- */
- cp = skip_token(cp);
- for (user = userList; user != NULL; user = user->next) {
- if (user->secName && strcmp(user->secName, nameBuf) == 0) {
- usm_set_user_password(user, token, cp);
- }
- }
- } else {
- cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
- if (cp == NULL) {
- config_perror("invalid engineID specifier");
- return;
- }
-
- user = usm_get_user(engineID, engineIDLen, nameBuf);
- if (user == NULL) {
- config_perror("not a valid user/engineID pair");
- return;
- }
- usm_set_user_password(user, token, cp);
- }
-}
-
-/*
- * uses the rest of LINE to configure USER's password of type TOKEN
- */
-void
-usm_set_user_password(struct usmUser *user, const char *token, char *line)
-{
- char *cp = line;
- u_char *engineID = user->engineID;
- size_t engineIDLen = user->engineIDLen;
-
- u_char **key;
- size_t *keyLen;
- u_char userKey[SNMP_MAXBUF_SMALL];
- size_t userKeyLen = SNMP_MAXBUF_SMALL;
- u_char *userKeyP = userKey;
- int type, ret;
-
- /*
- * Retrieve the "old" key and set the key type.
- */
- if (!token) {
- return;
- } else if (strcmp(token, "userSetAuthPass") == 0) {
- key = &user->authKey;
- keyLen = &user->authKeyLen;
- type = 0;
- } else if (strcmp(token, "userSetPrivPass") == 0) {
- key = &user->privKey;
- keyLen = &user->privKeyLen;
- type = 0;
- } else if (strcmp(token, "userSetAuthKey") == 0) {
- key = &user->authKey;
- keyLen = &user->authKeyLen;
- type = 1;
- } else if (strcmp(token, "userSetPrivKey") == 0) {
- key = &user->privKey;
- keyLen = &user->privKeyLen;
- type = 1;
- } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
- key = &user->authKey;
- keyLen = &user->authKeyLen;
- type = 2;
- } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
- key = &user->privKey;
- keyLen = &user->privKeyLen;
- type = 2;
- } else {
- /*
- * no old key, or token was not recognized
- */
- return;
- }
-
- if (*key) {
- /*
- * (destroy and) free the old key
- */
- memset(*key, 0, *keyLen);
- SNMP_FREE(*key);
- }
-
- if (type == 0) {
- /*
- * convert the password into a key
- */
- if (cp == NULL) {
- config_perror("missing user password");
- return;
- }
- ret = generate_Ku(user->authProtocol, user->authProtocolLen,
- (u_char *) cp, strlen(cp), userKey, &userKeyLen);
-
- if (ret != SNMPERR_SUCCESS) {
- config_perror("setting key failed (in sc_genKu())");
- return;
- }
- } else if (type == 1) {
- cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen);
-
- if (cp == NULL) {
- config_perror("invalid user key");
- return;
- }
- }
-
- if (type < 2) {
- *key = (u_char *) malloc(SNMP_MAXBUF_SMALL);
- *keyLen = SNMP_MAXBUF_SMALL;
- ret = generate_kul(user->authProtocol, user->authProtocolLen,
- engineID, engineIDLen,
- userKey, userKeyLen, *key, keyLen);
- if (ret != SNMPERR_SUCCESS) {
- config_perror("setting key failed (in generate_kul())");
- return;
- }
-
- /*
- * (destroy and) free the old key
- */
- memset(userKey, 0, sizeof(userKey));
-
- } else {
- /*
- * the key is given, copy it in
- */
- cp = read_config_read_octet_string(cp, key, keyLen);
-
- if (cp == NULL) {
- config_perror("invalid localized user key");
- return;
- }
- }
-} /* end usm_set_password() */