snmpusm.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:74k
源码类别:

SNMP编程

开发平台:

C/C++

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