1 //==========================================================================
3 // ./lib/current/src/snmpusm.c
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
41 // -------------------------------------------
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project, <http://ucd-snmp.ucdavis.edu/> from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation. Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
49 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
50 // -------------------------------------------
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
59 // Purpose: Port of UCD-SNMP distribution to eCos.
63 //####DESCRIPTIONEND####
65 //==========================================================================
66 /********************************************************************
67 Copyright 1989, 1991, 1992 by Carnegie Mellon University
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
95 * Routines to manipulate a information about a "user" as
96 * defined by the SNMP-USER-BASED-SM-MIB MIB.
98 * All functions usm_set_usmStateReference_*() return 0 on success, -1
101 * !! Tab stops set to 4 in some parts of this file. !!
102 * (Designated on a per function.)
107 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
108 #include <sys/types.h>
116 #if TIME_WITH_SYS_TIME
118 # include <sys/timeb.h>
120 # include <sys/time.h>
125 # include <sys/time.h>
135 #ifdef HAVE_NETINET_IN_H
136 #include <netinet/in.h>
144 #include "snmp_api.h"
145 #include "snmp_debug.h"
146 #include "callback.h"
148 #include "keytools.h"
150 #include "read_config.h"
153 #include "lcd_time.h"
155 #include "callback.h"
156 #include "default_store.h"
159 #include "transform_oids.h"
161 static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */
166 static u_int salt_integer;
167 /* 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1.
170 int reportErrorOnUnknownID = 0;
171 /* Should be determined based on msg type.
174 static struct usmUser *initialUser = NULL;
175 static struct usmUser *noNameUser = NULL;
181 usm_check_secLevel_vs_protocols(int level,
182 oid *authProtocol, u_int authProtocolLen,
183 oid *privProtocol, u_int privProtocolLen);
186 * Set a given field of the secStateRef.
188 * Allocate <len> bytes for type <type> pointed to by ref-><field>.
189 * Then copy in <item> and record its length in ref-><field_len>.
191 * Return 0 on success, -1 otherwise.
193 #define MAKE_ENTRY( type, item, len, field, field_len ) \
197 if (ref->field != NULL) { \
198 SNMP_ZERO(ref->field, ref->field_len); \
199 SNMP_FREE(ref->field); \
201 ref->field_len = 0; \
202 if (len == 0 || item == NULL) { \
205 if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
210 memcpy (ref->field, item, len * sizeof(type)); \
211 ref->field_len = len; \
218 usm_set_reportErrorOnUnknownID (int value)
220 reportErrorOnUnknownID = value;
224 struct usmStateReference *
225 usm_malloc_usmStateReference(void)
227 struct usmStateReference *retval = (struct usmStateReference *)
228 calloc(1,sizeof(struct usmStateReference));
231 } /* end usm_malloc_usmStateReference() */
235 usm_free_usmStateReference (void *old)
237 struct usmStateReference *old_ref = (struct usmStateReference *)old;
241 SNMP_FREE(old_ref->usr_name);
242 SNMP_FREE(old_ref->usr_engine_id);
243 SNMP_FREE(old_ref->usr_auth_protocol);
244 SNMP_FREE(old_ref->usr_priv_protocol);
246 if (old_ref->usr_auth_key) {
247 SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
248 SNMP_FREE(old_ref->usr_auth_key);
250 if (old_ref->usr_priv_key) {
251 SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
252 SNMP_FREE(old_ref->usr_priv_key);
255 SNMP_ZERO(old_ref, sizeof(*old_ref));
260 } /* end usm_free_usmStateReference() */
265 usm_set_usmStateReference_name (
266 struct usmStateReference *ref,
270 MAKE_ENTRY (char,name,name_len,usr_name,usr_name_length);
274 usm_set_usmStateReference_engine_id (
275 struct usmStateReference *ref,
277 size_t engine_id_len)
279 MAKE_ENTRY (u_char,engine_id,engine_id_len,
280 usr_engine_id,usr_engine_id_length);
284 usm_set_usmStateReference_auth_protocol (
285 struct usmStateReference *ref,
287 size_t auth_protocol_len)
289 MAKE_ENTRY (oid ,auth_protocol,auth_protocol_len,
290 usr_auth_protocol,usr_auth_protocol_length);
294 usm_set_usmStateReference_auth_key (
295 struct usmStateReference *ref,
299 MAKE_ENTRY (u_char,auth_key,auth_key_len,
300 usr_auth_key,usr_auth_key_length);
304 usm_set_usmStateReference_priv_protocol (
305 struct usmStateReference *ref,
307 size_t priv_protocol_len)
309 MAKE_ENTRY (oid,priv_protocol,priv_protocol_len,
310 usr_priv_protocol,usr_priv_protocol_length);
314 usm_set_usmStateReference_priv_key (
315 struct usmStateReference *ref,
319 MAKE_ENTRY (u_char,priv_key,priv_key_len,
320 usr_priv_key,usr_priv_key_length);
324 usm_set_usmStateReference_sec_level (
325 struct usmStateReference *ref,
328 if (ref == NULL) return -1;
329 ref->usr_sec_level = sec_level;
335 #ifdef SNMP_TESTING_CODE
336 /*******************************************************************-o-******
343 * This is a print routine that is solely included so that it can be
344 * used in gdb. Don't use it as a function, it will be pulled before
345 * a real release of the code.
349 * XXX fflush() only works on FreeBSD; core dumps on Sun OS's
352 emergency_print (u_char *field, u_int length)
360 for (iindex = start; iindex < stop; iindex++)
361 printf ("%02X ", field[iindex]);
365 stop = stop+25<length?stop+25:length;
369 } /* end emergency_print() */
370 #endif /* SNMP_TESTING_CODE */
373 /*******************************************************************-o-******
374 * asn_predict_int_length
382 * Number of bytes necessary to store the ASN.1 encoded value of 'number'.
385 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
386 * use to encode a particular integer value.
388 * Returns the length of the integer -- NOT THE HEADER!
390 * Do this the same way as asn_build_int()...
393 asn_predict_int_length (int type, long number, size_t len)
395 register u_long mask;
398 if (len != sizeof (long)) return -1;
400 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
401 /* mask is 0xFF800000 on a big-endian machine */
403 while((((number & mask) == 0) || ((number & mask) == mask)) && len > 1)
411 } /* end asn_predict_length() */
416 /*******************************************************************-o-******
425 * Length in bytes: 1 + <n> + <u_char_len>, where
427 * 1 For the ASN.1 type.
428 * <n> # of bytes to store length of data.
429 * <u_char_len> Length of data associated with ASN.1 type.
431 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
432 * use to encode a particular integer value. This is as broken as the
433 * currently used encoder.
435 * XXX How is <n> chosen, exactly??
438 asn_predict_length (int type, u_char *ptr, size_t u_char_len)
441 if (type & ASN_SEQUENCE) return 1+3+u_char_len;
443 if (type & ASN_INTEGER)
446 memcpy (&value, ptr, u_char_len);
447 u_char_len = asn_predict_int_length (type, value, u_char_len);
450 if (u_char_len < 0x80)
451 return 1+1+u_char_len;
452 else if (u_char_len < 0xFF)
453 return 1+2+u_char_len;
455 return 1+3+u_char_len;
457 } /* end asn_predict_length() */
462 /*******************************************************************-o-******
466 * (See list below...)
473 * This routine calculates the offsets into an outgoing message buffer
474 * for the necessary values. The outgoing buffer will generically
484 * OST len msgFlags (OST = OCTET STRING)
485 * INT len msgSecurityModel
486 * MsgSecurityParameters
489 * OST len msgAuthoritativeEngineID
490 * INT len msgAuthoritativeEngineBoots
491 * INT len msgAuthoritativeEngineTime
492 * OST len msgUserName
493 * OST len[4] [5] msgAuthenticationParameters
494 * OST len[6] [7] msgPrivacyParameters
496 * [8] OST len[9] [10] encryptedPDU
498 * [8,10] SEQUENCE len[9] scopedPDU
501 * The bracketed points will be needed to be identified ([x] is an index
502 * value, len[x] means a length value). Here is a semantic guide to them:
504 * [1] = globalDataLen (input)
507 * [4] = msgAuthParmLen (may be 0 or 12)
508 * [5] = authParamsOffset
509 * [6] = msgPrivParmLen (may be 0 or 8)
510 * [7] = privParamsOffset
511 * [8] = globalDataLen + msgSecParmLen
514 * [11] = theTotalLength - the length of the header itself
515 * [12] = theTotalLength
519 size_t globalDataLen, /* SNMPv3Message + HeaderData */
521 size_t secEngineIDLen,
523 size_t scopedPduLen, /* An BER encoded sequence. */
524 u_long engineboots, /* XXX (asn1.c works in long, not int.) */
525 long engine_time, /* XXX (asn1.c works in long, not int.) */
527 size_t *theTotalLength, /* globalDataLen + msgSecurityP. + msgData */
528 size_t *authParamsOffset,/* Distance to auth bytes. */
529 size_t *privParamsOffset,/* Distance to priv bytes. */
530 size_t *dataOffset, /* Distance to scopedPdu SEQ -or- the
531 * crypted (data) portion of msgData. */
533 size_t *datalen, /* Size of msgData OCTET STRING encoding. */
534 size_t *msgAuthParmLen, /* Size of msgAuthenticationParameters. */
535 size_t *msgPrivParmLen, /* Size of msgPrivacyParameters. */
536 size_t *otstlen, /* Size of msgSecurityP. O.S. encoding. */
537 size_t *seq_len, /* Size of msgSecurityP. SEQ data. */
538 size_t *msgSecParmLen) /* Size of msgSecurityP. SEQ. */
540 int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */
541 engBtlen, /* for fields within */
542 engTmlen, /* msgSecurityParameters portion of */
543 namelen, /* SNMPv3Message. */
548 * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
549 * If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0.
551 *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
552 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?12:0;
554 *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?8:0;
560 if ( (engIDlen = asn_predict_length(ASN_OCTET_STR,
561 0, secEngineIDLen)) == -1 )
566 if ( (engBtlen = asn_predict_length (ASN_INTEGER,
567 (u_char*)&engineboots,sizeof(long))) == -1 )
572 if ( (engTmlen = asn_predict_length (ASN_INTEGER,
573 (u_char*)&engine_time,sizeof(long))) == -1 )
578 if ( (namelen = asn_predict_length (ASN_OCTET_STR,0,secNameLen))==-1 )
583 if ( (authlen = asn_predict_length (ASN_OCTET_STR,
584 0,*msgAuthParmLen)) == -1 )
589 if ( (privlen = asn_predict_length (ASN_OCTET_STR,
590 0,*msgPrivParmLen)) == -1 )
595 *seq_len = engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
597 if ( (*otstlen = asn_predict_length (ASN_SEQUENCE,
598 0, *seq_len)) == -1 )
603 if ( (*msgSecParmLen = asn_predict_length (ASN_OCTET_STR,
609 *authParamsOffset = globalDataLen +
610 + (*msgSecParmLen - *seq_len)
611 + engIDlen + engBtlen + engTmlen + namelen
612 + (authlen - *msgAuthParmLen);
614 *privParamsOffset = *authParamsOffset + *msgAuthParmLen
615 + (privlen - *msgPrivParmLen);
619 * Compute the size of the plaintext. Round up to account for cipher
620 * block size, if necessary.
622 * XXX This is hardwired for 1DES... If scopedPduLen is already
623 * a multiple of 8, then *add* 8 more; otherwise, round up
624 * to the next multiple of 8.
626 * FIX Calculation of encrypted portion of msgData and consequent
627 * setting and sanity checking of theTotalLength, et al. should
628 * occur *after* encryption has taken place.
630 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
632 scopedPduLen = ( scopedPduLen % 8 )
633 ? ROUNDUP8(scopedPduLen)
637 asn_predict_length (ASN_OCTET_STR,0,scopedPduLen))==-1)
644 *datalen = scopedPduLen;
647 *dataOffset = globalDataLen + *msgSecParmLen +
648 (*datalen - scopedPduLen);
649 *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
653 } /* end usm_calc_offsets() */
659 /*******************************************************************-o-******
663 * *iv (O) Buffer to contain IV.
664 * *iv_length (O) Length of iv.
665 * *priv_salt (I) Salt portion of private key.
666 * priv_salt_length (I) Length of priv_salt.
667 * *msgSalt (I/O) Pointer salt portion of outgoing msg buffer.
673 * Determine the initialization vector for the DES-CBC encryption.
674 * (Cf. RFC 2274, 8.1.1.1.)
676 * iv is defined as the concatenation of engineBoots and the
678 * The salt integer is incremented.
679 * The resulting salt is copied into the msgSalt buffer.
680 * The result of the concatenation is then XORed with the salt
681 * portion of the private key (last 8 bytes).
682 * The IV result is returned individually for further use.
685 usm_set_salt ( u_char *iv,
688 size_t priv_salt_length,
691 size_t propersize_salt = BYTESIZE(USM_MAX_SALT_LENGTH);
694 /* net_* should be encoded in network byte order. XXX Why?
702 if ( !iv || !iv_length || !priv_salt || !msgSalt
703 || (*iv_length != propersize_salt)
704 || (priv_salt_length < propersize_salt) )
710 net_boots = htonl(snmpv3_local_snmpEngineBoots());
711 net_salt_int = htonl(salt_integer);
715 memcpy(iv, &net_boots, propersize_salt/2);
716 memcpy(iv+(propersize_salt/2), &net_salt_int, propersize_salt/2);
718 memcpy(msgSalt, iv, propersize_salt);
722 * Turn the salt into an IV: XOR <boots, salt_int> with salt
723 * portion of priv_key.
725 for (iindex = 0; iindex < (int)propersize_salt; iindex++)
726 iv[iindex] ^= priv_salt[iindex];
731 } /* end usm_set_salt() */
736 /*******************************************************************-o-******
737 * usm_generate_out_msg
740 * (See list below...)
743 * SNMPERR_SUCCESS On success.
744 * SNMPERR_USM_AUTHENTICATIONFAILURE
745 * SNMPERR_USM_ENCRYPTIONERROR
746 * SNMPERR_USM_GENERICERROR
747 * SNMPERR_USM_UNKNOWNSECURITYNAME
748 * SNMPERR_USM_GENERICERROR
749 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
752 * Generates an outgoing message.
754 * XXX Beware of misnomers!
757 usm_generate_out_msg (
758 int msgProcModel, /* (UNUSED) */
760 u_char *globalData, /* IN */
761 /* Pointer to msg header data will point to the beginning
762 * of the entire packet buffer to be transmitted on wire,
763 * memory will be contiguous with secParams, typically
764 * this pointer will be passed back as beginning of
765 * wholeMsg below. asn seq. length is updated w/ new length.
767 * While this points to a buffer that should be big enough
768 * for the whole message, only the first two parts
769 * of the message are completed, namely SNMPv3Message and
770 * HeaderData. globalDataLen (next parameter) represents
771 * the length of these two completed parts.
774 size_t globalDataLen, /* IN - Length of msg header data. */
775 int maxMsgSize, /* (UNUSED) */
776 int secModel, /* (UNUSED) */
777 u_char *secEngineID, /* IN - Pointer snmpEngineID. */
778 size_t secEngineIDLen, /* IN - SnmpEngineID length. */
779 char *secName, /* IN - Pointer to securityName. */
780 size_t secNameLen, /* IN - SecurityName length. */
781 int secLevel, /* IN - AuthNoPriv, authPriv etc. */
783 u_char *scopedPdu, /* IN */
784 /* Pointer to scopedPdu will be encrypted by USM if needed
785 * and written to packet buffer immediately following
786 * securityParameters, entire msg will be authenticated by
790 size_t scopedPduLen, /* IN - scopedPdu length. */
792 void *secStateRef, /* IN */
793 /* secStateRef, pointer to cached info provided only for
794 * Response, otherwise NULL.
797 u_char *secParams, /* OUT */
798 /* BER encoded securityParameters pointer to offset within
799 * packet buffer where secParams should be written, the
800 * entire BER encoded OCTET STRING (including header) is
801 * written here by USM secParams = globalData +
805 size_t *secParamsLen, /* IN/OUT - Len available, len returned. */
807 u_char **wholeMsg, /* OUT */
808 /* Complete authenticated/encrypted message - typically
809 * the pointer to start of packet buffer provided in
810 * globalData is returned here, could also be a separate
814 size_t *wholeMsgLen) /* IN/OUT - Len available, len returned. */
818 size_t msgAuthParmLen;
819 size_t msgPrivParmLen;
820 size_t msgSecParmLen;
821 size_t authParamsOffset;
822 size_t privParamsOffset;
825 size_t theTotalLength;
837 Indirection because secStateRef values override parameters.
839 None of these are to be free'd - they are either pointing to
840 what's in the secStateRef or to something either in the
841 actual prarmeter list or the user list.
844 char *theName = NULL;
845 u_int theNameLength = 0;
846 u_char *theEngineID = NULL;
847 u_int theEngineIDLength = 0;
848 u_char *theAuthKey = NULL;
849 u_int theAuthKeyLength = 0;
850 oid *theAuthProtocol = NULL;
851 u_int theAuthProtocolLength = 0;
852 u_char *thePrivKey = NULL;
853 u_int thePrivKeyLength = 0;
854 oid *thePrivProtocol = NULL;
855 u_int thePrivProtocolLength = 0;
856 int theSecLevel = 0; /* No defined const for bad
857 * value (other then err).
861 DEBUGMSGTL(("usm","USM processing has begun.\n"));
863 if (secStateRef != NULL)
865 /* To hush the compiler for now. XXX */
866 struct usmStateReference *ref
867 = (struct usmStateReference *)secStateRef;
869 theName = ref->usr_name;
870 theNameLength = ref->usr_name_length;
871 theEngineID = ref->usr_engine_id;
872 theEngineIDLength = ref->usr_engine_id_length;
874 if (!theEngineIDLength) {
875 theEngineID = secEngineID;
876 theEngineIDLength = secEngineIDLen;
879 theAuthProtocol = ref->usr_auth_protocol;
880 theAuthProtocolLength = ref->usr_auth_protocol_length;
881 theAuthKey = ref->usr_auth_key;
882 theAuthKeyLength = ref->usr_auth_key_length;
883 thePrivProtocol = ref->usr_priv_protocol;
884 thePrivProtocolLength = ref->usr_priv_protocol_length;
885 thePrivKey = ref->usr_priv_key;
886 thePrivKeyLength = ref->usr_priv_key_length;
887 theSecLevel = ref->usr_sec_level;
891 * Identify the user record.
895 struct usmUser *user;
897 /* we do allow an unknown user name for
898 unauthenticated requests. */
900 usm_get_user(secEngineID, secEngineIDLen, secName))
902 secLevel != SNMP_SEC_LEVEL_NOAUTH)
904 DEBUGMSGTL(("usm","Unknown User\n"));
905 usm_free_usmStateReference (secStateRef);
906 return SNMPERR_USM_UNKNOWNSECURITYNAME;
910 theNameLength = secNameLen;
911 theEngineID = secEngineID;
912 theSecLevel = secLevel;
913 theEngineIDLength = secEngineIDLen;
915 theAuthProtocol = user->authProtocol;
916 theAuthProtocolLength = user->authProtocolLen;
917 theAuthKey = user->authKey;
918 theAuthKeyLength = user->authKeyLen;
919 thePrivProtocol = user->privProtocol;
920 thePrivProtocolLength = user->privProtocolLen;
921 thePrivKey = user->privKey;
922 thePrivKeyLength = user->privKeyLen;
924 /* unknown users can not do authentication (obviously) */
925 theAuthProtocol = usmNoAuthProtocol;
926 theAuthProtocolLength = sizeof(usmNoAuthProtocol)/sizeof(oid);
928 theAuthKeyLength = 0;
929 thePrivProtocol = usmNoPrivProtocol;
930 thePrivProtocolLength = sizeof(usmNoPrivProtocol)/sizeof(oid);
932 thePrivKeyLength = 0;
934 } /* endif -- secStateRef==NULL */
938 From here to the end of the function, avoid reference to
939 secName, secEngineID, secLevel, and associated lengths.
944 * Check to see if the user can use the requested sec services.
946 if (usm_check_secLevel_vs_protocols(
948 theAuthProtocol, theAuthProtocolLength,
949 theAuthProtocol, theAuthProtocolLength) == 1)
951 DEBUGMSGTL(("usm","Unsupported Security Level\n"));
952 usm_free_usmStateReference (secStateRef);
953 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
958 * Retrieve the engine information.
960 * XXX No error is declared in the EoP when sending messages to
961 * unknown engines, processing continues w/ boots/time == (0,0).
963 if (get_enginetime (theEngineID, theEngineIDLength,
964 &boots_uint, &time_uint, FALSE) == -1)
966 DEBUGMSGTL(("usm","%s\n", "Failed to find engine data."));
969 boots_long = boots_uint;
970 time_long = time_uint;
974 * Set up the Offsets.
976 if (usm_calc_offsets (globalDataLen, theSecLevel, theEngineIDLength,
977 theNameLength, scopedPduLen, boots_long, time_long,
978 &theTotalLength, &authParamsOffset,
979 &privParamsOffset, &dataOffset, &datalen,
980 &msgAuthParmLen, &msgPrivParmLen,
981 &otstlen, &seq_len, &msgSecParmLen) == -1)
983 DEBUGMSGTL(("usm","Failed calculating offsets.\n"));
984 usm_free_usmStateReference (secStateRef);
985 return SNMPERR_USM_GENERICERROR;
989 So, we have the offsets for the three parts that need to be
990 determined, and an overall length. Now we need to make
991 sure all of this would fit in the outgoing buffer, and
992 whether or not we need to make a new buffer, etc.
997 * Set wholeMsg as a pointer to globalData. Sanity check for
1000 * Mark workspace in the message with bytes of all 1's to make it
1001 * easier to find mistakes in raw message dumps.
1003 ptr = *wholeMsg = globalData;
1004 if (theTotalLength > *wholeMsgLen)
1006 DEBUGMSGTL(("usm","Message won't fit in buffer.\n"));
1007 usm_free_usmStateReference (secStateRef);
1008 return SNMPERR_USM_GENERICERROR;
1011 ptr_len = *wholeMsgLen = theTotalLength;
1013 #ifdef SNMP_TESTING_CODE
1014 memset (&ptr[globalDataLen], 0xFF, theTotalLength-globalDataLen);
1015 #endif /* SNMP_TESTING_CODE */
1019 * Do the encryption.
1021 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1023 size_t encrypted_length = theTotalLength - dataOffset;
1024 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1025 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1027 /* XXX Hardwired to seek into a 1DES private key!
1029 if ( usm_set_salt( salt, &salt_length,
1030 thePrivKey+8, thePrivKeyLength-8,
1031 &ptr[privParamsOffset])
1034 DEBUGMSGTL(("usm","Can't set DES-CBC salt.\n"));
1035 usm_free_usmStateReference (secStateRef);
1036 return SNMPERR_USM_GENERICERROR;
1040 thePrivProtocol, thePrivProtocolLength,
1041 thePrivKey, thePrivKeyLength,
1043 scopedPdu, scopedPduLen,
1044 &ptr[dataOffset], &encrypted_length)
1045 != SNMP_ERR_NOERROR )
1047 DEBUGMSGTL(("usm","DES-CBC error.\n"));
1048 usm_free_usmStateReference (secStateRef);
1049 return SNMPERR_USM_ENCRYPTIONERROR;
1053 #ifdef SNMP_TESTING_CODE
1054 if ( debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1055 dump_chunk("usm/dump", "This data was encrypted:",
1056 scopedPdu, scopedPduLen);
1057 dump_chunk("usm/dump", "salt + Encrypted form:",
1059 dump_chunk("usm/dump", NULL,
1060 &ptr[dataOffset], encrypted_length);
1061 dump_chunk("usm/dump", "*wholeMsg:",
1062 *wholeMsg, theTotalLength);
1068 ptr_len = *wholeMsgLen = theTotalLength;
1072 * XXX Sanity check for salt length should be moved up
1073 * under usm_calc_offsets() or tossed.
1075 if ( (encrypted_length != (theTotalLength - dataOffset))
1076 || (salt_length != msgPrivParmLen) )
1078 DEBUGMSGTL(("usm","DES-CBC length error.\n"));
1079 usm_free_usmStateReference (secStateRef);
1080 return SNMPERR_USM_ENCRYPTIONERROR;
1083 DEBUGMSGTL(("usm","Encryption successful.\n"));
1087 * No encryption for you!
1091 memcpy( &ptr[dataOffset], scopedPdu, scopedPduLen );
1097 * Start filling in the other fields (in prep for authentication).
1099 * offSet is an octet string header, which is different from all
1100 * the other headers.
1102 remaining = ptr_len - globalDataLen;
1104 offSet = ptr_len - remaining;
1105 asn_build_header (&ptr[offSet], &remaining,
1106 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR), otstlen);
1108 offSet = ptr_len - remaining;
1109 asn_build_sequence (&ptr[offSet], &remaining,
1110 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
1112 offSet = ptr_len - remaining;
1113 asn_build_string (&ptr[offSet], &remaining,
1114 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1115 theEngineID, theEngineIDLength);
1117 offSet = ptr_len - remaining;
1118 asn_build_int (&ptr[offSet], &remaining,
1119 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1120 &boots_long, sizeof(long));
1122 offSet = ptr_len - remaining;
1123 asn_build_int (&ptr[offSet], &remaining,
1124 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1125 &time_long, sizeof(long));
1127 offSet = ptr_len - remaining;
1128 asn_build_string (&ptr[offSet], &remaining,
1129 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1130 (u_char *)theName, theNameLength);
1134 Note: if there is no authentication being done,
1135 msgAuthParmLen is 0, and there is no effect (other than
1136 inserting a zero-length header) of the following
1140 offSet = ptr_len - remaining;
1144 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1147 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1148 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1150 offSet = ptr_len - remaining;
1151 memset (&ptr[offSet],0,msgAuthParmLen);
1154 remaining -= msgAuthParmLen;
1158 Note: if there is no encryption being done, msgPrivParmLen
1159 is 0, and there is no effect (other than inserting a
1160 zero-length header) of the following statements.
1163 offSet = ptr_len - remaining;
1167 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1170 remaining -= msgPrivParmLen; /* Skipping the IV already there. */
1174 * For privacy, need to add the octet string header for it.
1176 if (theSecLevel==SNMP_SEC_LEVEL_AUTHPRIV)
1178 offSet = ptr_len - remaining;
1182 (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1183 theTotalLength - dataOffset );
1188 * Adjust overall length and store it as the first SEQ length
1189 * of the SNMPv3Message.
1191 * FIX 4 is a magic number!
1193 remaining = theTotalLength;
1194 asn_build_sequence (ptr, &remaining,
1195 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), theTotalLength-4);
1199 * Now, time to consider / do authentication.
1201 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1202 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1204 size_t temp_sig_len = msgAuthParmLen;
1205 u_char *temp_sig = (u_char *) malloc (temp_sig_len);
1207 if (temp_sig == NULL)
1209 DEBUGMSGTL(("usm","Out of memory.\n"));
1210 usm_free_usmStateReference (secStateRef);
1211 return SNMPERR_USM_GENERICERROR;
1214 if ( sc_generate_keyed_hash (
1215 theAuthProtocol, theAuthProtocolLength,
1216 theAuthKey, theAuthKeyLength,
1218 temp_sig, &temp_sig_len)
1219 != SNMP_ERR_NOERROR )
1221 /* FIX temp_sig_len defined?!
1223 SNMP_ZERO(temp_sig, temp_sig_len);
1224 SNMP_FREE(temp_sig);
1225 DEBUGMSGTL(("usm","Signing failed.\n"));
1226 usm_free_usmStateReference (secStateRef);
1227 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1230 if (temp_sig_len != msgAuthParmLen)
1232 SNMP_ZERO(temp_sig, temp_sig_len);
1233 SNMP_FREE(temp_sig);
1234 DEBUGMSGTL(("usm","Signing lengths failed.\n"));
1235 usm_free_usmStateReference (secStateRef);
1236 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1239 memcpy (&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
1241 SNMP_ZERO(temp_sig, temp_sig_len);
1242 SNMP_FREE(temp_sig);
1244 } /* endif -- create keyed hash */
1247 usm_free_usmStateReference (secStateRef);
1249 DEBUGMSGTL(("usm","USM processing completed.\n"));
1251 return SNMPERR_SUCCESS;
1253 } /* end usm_generate_out_msg() */
1258 /*******************************************************************-o-******
1259 * usm_parse_security_parameters
1262 * (See list below...)
1270 * Extracts values from the security header and data portions of the
1274 usm_parse_security_parameters (
1277 u_char *secEngineID,
1278 size_t *secEngineIDLen,
1284 size_t *signature_length,
1286 size_t *salt_length,
1289 u_char *parse_ptr = secParams;
1294 size_t octet_string_length = remaining;
1295 size_t sequence_length;
1296 size_t remaining_bytes;
1305 * Eat the first octet header.
1307 if ((value_ptr = asn_parse_sequence (parse_ptr, &octet_string_length,
1309 (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1310 "usm first octet")) == NULL)
1312 /* RETURN parse error */ return -1;
1317 * Eat the sequence header.
1319 parse_ptr = value_ptr;
1320 sequence_length = octet_string_length;
1322 if ((value_ptr = asn_parse_sequence (parse_ptr, &sequence_length,
1324 (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1325 "usm sequence")) == NULL)
1327 /* RETURN parse error */ return -1;
1332 * Retrieve the engineID.
1334 parse_ptr = value_ptr;
1335 remaining_bytes = sequence_length;
1337 DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineID\n");
1339 = asn_parse_string (parse_ptr, &remaining_bytes, &type_value,
1340 secEngineID, secEngineIDLen)) == NULL )
1343 /* RETURN parse error */ return -1;
1347 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1349 /* RETURN parse error */ return -1;
1354 * Retrieve the engine boots, notice switch in the way next_ptr and
1355 * remaining_bytes are used (to accomodate the asn code).
1357 DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineBoots\n");
1358 if ((next_ptr = asn_parse_int (next_ptr, &remaining_bytes, &type_value,
1359 &boots_long, sizeof(long))) == NULL)
1362 /* RETURN parse error */ return -1;
1366 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_INTEGER))
1369 /* RETURN parse error */ return -1;
1372 *boots_uint = (u_int) boots_long;
1376 * Retrieve the time value.
1378 DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthoritativeEngineTime\n");
1379 if ((next_ptr = asn_parse_int (next_ptr, &remaining_bytes, &type_value,
1380 &time_long, sizeof(long))) == NULL)
1382 /* RETURN parse error */ return -1;
1385 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_INTEGER))
1388 /* RETURN parse error */ return -1;
1391 *time_uint = (u_int) time_long;
1395 * Retrieve the secName.
1397 origNameLen = *secNameLen;
1399 DEBUGDUMPHEADER("dump_recv", "Parsing msgUserName\n");
1401 = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1402 (u_char *)secName, secNameLen)) == NULL )
1405 /* RETURN parse error */ return -1;
1409 /* FIX -- doesn't this also indicate a buffer overrun?
1411 if ((int)origNameLen < *secNameLen + 1)
1413 /* RETURN parse error, but it's really a parameter error */
1417 secName[*secNameLen] = '\0';
1419 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1421 /* RETURN parse error */ return -1;
1426 * Retrieve the signature and blank it if there.
1428 DEBUGDUMPHEADER("dump_recv", "Parsing msgAuthenticationParameters\n");
1430 = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1431 signature, signature_length)) == NULL )
1434 /* RETURN parse error */ return -1;
1438 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1440 /* RETURN parse error */ return -1;
1443 if (*signature_length != 0) /* Blanking for authentication step later */
1445 memset (next_ptr-(u_long)*signature_length,
1446 0, *signature_length);
1451 * Retrieve the salt.
1453 * Note that the next ptr is where the data section starts.
1455 DEBUGDUMPHEADER("dump_recv", "Parsing msgPrivacyParameters\n");
1457 = asn_parse_string (next_ptr, &remaining_bytes, &type_value,
1458 salt, salt_length)) == NULL )
1461 /* RETURN parse error */ return -1;
1465 if (type_value != (u_char) (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR))
1467 /* RETURN parse error */ return -1;
1472 } /* end usm_parse_security_parameters() */
1477 /*******************************************************************-o-******
1478 * usm_check_and_update_timeliness
1492 * Performs the incoming timeliness checking and setting.
1495 usm_check_and_update_timeliness(
1496 u_char *secEngineID,
1497 size_t secEngineIDLen,
1502 u_char myID[USM_MAX_ID_LENGTH];
1503 int myIDLength = snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
1509 if ( (myIDLength > USM_MAX_ID_LENGTH) || (myIDLength < 0) )
1511 /* We're probably already screwed...buffer overwrite. XXX? */
1512 DEBUGMSGTL(("usm","Buffer overflow.\n"));
1513 *error = SNMPERR_USM_GENERICERROR;
1517 myBoots = snmpv3_local_snmpEngineBoots();
1518 myTime = snmpv3_local_snmpEngineTime();
1522 * IF the time involved is local
1523 * Make sure message is inside the time window
1525 * IF boots is higher or boots is the same and time is higher
1526 * remember this new data
1528 * IF !(boots same and time within USM_TIME_WINDOW secs)
1529 * Message is too old
1531 * Message is ok, but don't take time
1538 * This is a local reference.
1540 if ( (int)secEngineIDLen == myIDLength
1541 && memcmp (secEngineID, myID, myIDLength) == 0 )
1543 u_int time_difference = myTime > time_uint ?
1544 myTime - time_uint : time_uint - myTime;
1546 if (boots_uint == ENGINEBOOT_MAX
1547 || boots_uint != myBoots
1548 || time_difference > USM_TIME_WINDOW)
1550 if ( snmp_increment_statistic(
1551 STAT_USMSTATSNOTINTIMEWINDOWS) == 0 )
1553 DEBUGMSGTL(("usm","%s\n",
1554 "Failed to increment statistic."));
1557 DEBUGMSGTL(("usm","%s\n", "Not in local time window."));
1558 *error = SNMPERR_USM_NOTINTIMEWINDOW;
1562 *error = SNMPERR_SUCCESS;
1567 * This is a remote reference.
1574 u_int time_difference;
1576 if ( get_enginetime_ex( secEngineID, secEngineIDLen,
1577 &theirBoots, &theirTime,
1582 DEBUGMSGTL(("usm","%s\n",
1583 "Failed to get remote engine's times."));
1585 *error = SNMPERR_USM_GENERICERROR;
1589 time_difference = theirTime > time_uint ?
1590 theirTime - time_uint : time_uint - theirTime;
1594 * XXX Contrary to the pseudocode:
1595 * See if boots is invalid first.
1597 if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint)
1599 DEBUGMSGTL(("usm","%s\n", "Remote boot count invalid."));
1601 *error = SNMPERR_USM_NOTINTIMEWINDOW;
1607 * Boots is ok, see if the boots is the same but the time
1610 if (theirBoots == boots_uint && time_uint < theirLastTime)
1612 if(time_difference > USM_TIME_WINDOW)
1614 DEBUGMSGTL(("usm","%s\n", "Message too old."));
1615 *error = SNMPERR_USM_NOTINTIMEWINDOW;
1619 else /* Old, but acceptable */
1621 *error = SNMPERR_SUCCESS;
1628 Message is ok, either boots has been advanced, or
1629 time is greater than before with the same boots.
1632 if ( set_enginetime( secEngineID, secEngineIDLen,
1633 boots_uint, time_uint,
1637 DEBUGMSGTL(("usm","%s\n", "Failed updating remote boot/time."));
1638 *error = SNMPERR_USM_GENERICERROR;
1642 *error = SNMPERR_SUCCESS;
1643 return 0; /* Fresh message and time updated */
1645 } /* endif -- local or remote time reference. */
1648 } /* end usm_check_and_update_timeliness() */
1653 /*******************************************************************-o-******
1654 * usm_process_in_msg
1657 * (See list below...)
1660 * SNMPERR_SUCCESS On success.
1661 * SNMPERR_USM_AUTHENTICATIONFAILURE
1662 * SNMPERR_USM_DECRYPTIONERROR
1663 * SNMPERR_USM_GENERICERROR
1664 * SNMPERR_USM_PARSEERROR
1665 * SNMPERR_USM_UNKNOWNENGINEID
1666 * SNMPERR_USM_PARSEERROR
1667 * SNMPERR_USM_UNKNOWNSECURITYNAME
1668 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
1671 * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
1673 * FIX Memory leaks if secStateRef is allocated and a return occurs
1674 * without cleaning up. May contain secrets...
1677 usm_process_in_msg (
1678 int msgProcModel, /* (UNUSED) */
1679 size_t maxMsgSize, /* IN - Used to calc maxSizeResponse. */
1681 u_char *secParams, /* IN - BER encoded securityParameters.*/
1682 int secModel, /* (UNUSED) */
1683 int secLevel, /* IN - AuthNoPriv, authPriv etc. */
1685 u_char *wholeMsg, /* IN - Original v3 message. */
1686 size_t wholeMsgLen, /* IN - Msg length. */
1688 u_char *secEngineID, /* OUT - Pointer snmpEngineID. */
1689 size_t *secEngineIDLen, /* IN/OUT - Len available, len returned. */
1690 /* NOTE: Memory provided by caller. */
1692 char *secName, /* OUT - Pointer to securityName. */
1693 size_t *secNameLen, /* IN/OUT - Len available, len returned. */
1695 u_char **scopedPdu, /* OUT - Pointer to plaintext scopedPdu.*/
1696 size_t *scopedPduLen, /* IN/OUT - Len available, len returned. */
1698 size_t *maxSizeResponse, /* OUT - Max size of Response PDU. */
1699 void **secStateRf) /* OUT - Ref to security state. */
1701 size_t remaining = wholeMsgLen
1703 ((u_long)*secParams-(u_long)*wholeMsg);
1706 u_char signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
1707 size_t signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
1708 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1709 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1710 u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
1711 u_int iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
1715 u_char *end_of_overhead;
1718 struct usmStateReference **secStateRef = (struct usmStateReference **)secStateRf;
1720 struct usmUser *user;
1723 DEBUGMSGTL(("usm","USM processing begun...\n"));
1726 if (secStateRef) /* FIX -- huh? destroy it? */
1728 *secStateRef = usm_malloc_usmStateReference();
1729 if (*secStateRef == NULL)
1731 DEBUGMSGTL(("usm", "Out of memory.\n"));
1732 return SNMPERR_USM_GENERICERROR;
1738 * Make sure the *secParms is an OCTET STRING.
1739 * Extract the user name, engine ID, and security level.
1741 if ( usm_parse_security_parameters (
1742 secParams, remaining,
1743 secEngineID, secEngineIDLen,
1744 &boots_uint, &time_uint,
1745 secName, secNameLen,
1746 signature, &signature_length,
1751 DEBUGMSGTL(("usm","Parsing failed.\n"));
1752 if (snmp_increment_statistic (STAT_SNMPINASNPARSEERRS)==0)
1754 DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1756 return SNMPERR_USM_PARSEERROR;
1762 /* Cache the name, engine ID, and security level,
1763 * per step 2 (section 3.2)
1765 if ( usm_set_usmStateReference_name (
1766 *secStateRef, secName, *secNameLen) == -1 )
1768 DEBUGMSGTL(("usm","%s\n", "Couldn't cache name."));
1769 return SNMPERR_USM_GENERICERROR;
1772 if ( usm_set_usmStateReference_engine_id (
1773 *secStateRef, secEngineID, *secEngineIDLen) == -1 )
1775 DEBUGMSGTL(("usm","%s\n", "Couldn't cache engine id."));
1776 return SNMPERR_USM_GENERICERROR;
1779 if ( usm_set_usmStateReference_sec_level (
1780 *secStateRef, secLevel) == -1 )
1782 DEBUGMSGTL(("usm","%s\n", "Couldn't cache security level."));
1783 return SNMPERR_USM_GENERICERROR;
1789 * Locate the engine ID record.
1790 * If it is unknown, then either create one or note this as an error.
1792 if (reportErrorOnUnknownID)
1794 if (ISENGINEKNOWN(secEngineID, *secEngineIDLen)==FALSE)
1796 DEBUGMSGTL(("usm","Unknown Engine ID.\n"));
1797 if (snmp_increment_statistic (
1798 STAT_USMSTATSUNKNOWNENGINEIDS)==0)
1800 DEBUGMSGTL(("usm","%s\n",
1801 "Failed to increment statistic."));
1803 return SNMPERR_USM_UNKNOWNENGINEID;
1808 if ( ENSURE_ENGINE_RECORD(secEngineID,*secEngineIDLen)
1809 != SNMPERR_SUCCESS )
1811 DEBUGMSGTL(("usm","%s\n", "Couldn't ensure engine record."));
1812 return SNMPERR_USM_GENERICERROR;
1819 * Locate the User record.
1820 * If the user/engine ID is unknown, report this as an error.
1823 usm_get_user(secEngineID, *secEngineIDLen, secName))
1826 DEBUGMSGTL(("usm","Unknown User.\n"));
1827 if (snmp_increment_statistic (STAT_USMSTATSUNKNOWNUSERNAMES)==0)
1829 DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1831 return SNMPERR_USM_UNKNOWNSECURITYNAME;
1836 * Make sure the security level is appropriate.
1838 if (usm_check_secLevel(secLevel, user) == 1)
1840 DEBUGMSGTL(("usm","Unsupported Security Level.\n"));
1841 if (snmp_increment_statistic
1842 (STAT_USMSTATSUNSUPPORTEDSECLEVELS)==0)
1844 DEBUGMSGTL(("usm","%s\n", "Failed to increment statistic."));
1846 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
1851 * Check the authentication credentials of the message.
1853 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1854 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1856 if ( sc_check_keyed_hash (
1857 user->authProtocol, user->authProtocolLen,
1858 user->authKey, user->authKeyLen,
1859 wholeMsg, wholeMsgLen,
1860 signature, signature_length)
1861 != SNMP_ERR_NOERROR )
1863 DEBUGMSGTL(("usm","Verification failed.\n"));
1864 if (snmp_increment_statistic
1865 (STAT_USMSTATSWRONGDIGESTS)==0)
1867 DEBUGMSGTL(("usm","%s\n",
1868 "Failed to increment statistic."));
1870 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1873 DEBUGMSGTL(("usm","Verification succeeded.\n"));
1878 * Steps 10-11 user is already set - relocated before timeliness
1879 * check in case it fails - still save user data for response.
1881 * Cache the keys and protocol oids, per step 11 (s3.2).
1885 if (usm_set_usmStateReference_auth_protocol (*secStateRef,
1886 user->authProtocol, user->authProtocolLen) ==-1)
1888 DEBUGMSGTL(("usm","%s\n",
1889 "Couldn't cache authentication protocol."));
1890 return SNMPERR_USM_GENERICERROR;
1893 if (usm_set_usmStateReference_auth_key (*secStateRef,
1894 user->authKey, user->authKeyLen) == -1)
1896 DEBUGMSGTL(("usm","%s\n", "Couldn't cache authentiation key."));
1897 return SNMPERR_USM_GENERICERROR;
1900 if (usm_set_usmStateReference_priv_protocol (*secStateRef,
1901 user->privProtocol, user->privProtocolLen) ==-1)
1903 DEBUGMSGTL(("usm","%s\n", "Couldn't cache privacy protocol."));
1904 return SNMPERR_USM_GENERICERROR;
1907 if (usm_set_usmStateReference_priv_key (*secStateRef,
1908 user->privKey, user->privKeyLen) == -1)
1910 DEBUGMSGTL(("usm","%s\n", "Couldn't cache privacy key."));
1911 return SNMPERR_USM_GENERICERROR;
1917 * Perform the timeliness/time manager functions.
1919 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1920 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1922 if ( usm_check_and_update_timeliness (
1923 secEngineID, *secEngineIDLen,
1924 boots_uint, time_uint, &error) == -1 )
1930 #ifdef LCD_TIME_SYNC_OPT
1932 * Cache the unauthenticated time to use in case we don't have
1933 * anything better - this guess will be no worse than (0,0)
1934 * that we normally use.
1938 set_enginetime(secEngineID, *secEngineIDLen,
1939 boots_uint, time_uint, FALSE);
1941 #endif /* LCD_TIME_SYNC_OPT */
1945 * If needed, decrypt the scoped PDU.
1947 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
1949 remaining = wholeMsgLen - (data_ptr - wholeMsg);
1951 if ((value_ptr = asn_parse_sequence (data_ptr, &remaining,
1953 (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
1954 "encrypted sPDU")) == NULL)
1956 DEBUGMSGTL(("usm","%s\n",
1957 "Failed while parsing encrypted sPDU."));
1958 if (snmp_increment_statistic
1959 (STAT_SNMPINASNPARSEERRS)==0)
1961 DEBUGMSGTL(("usm","%s\n",
1962 "Failed increment statistic."));
1964 return SNMPERR_USM_PARSEERROR;
1967 end_of_overhead = value_ptr;
1970 * XOR the salt with the last (iv_length) bytes
1971 * of the priv_key to obtain the IV.
1973 for (i = 0; i < (int)iv_length; i++)
1974 iv[i] = salt[i] ^ user->privKey[iv_length + i];
1977 user->privProtocol, user->privProtocolLen,
1978 user->privKey, user->privKeyLen,
1980 value_ptr, remaining,
1981 *scopedPdu, scopedPduLen)
1982 != SNMP_ERR_NOERROR)
1984 DEBUGMSGTL(("usm","%s\n", "Failed decryption."));
1985 if (snmp_increment_statistic
1986 (STAT_USMSTATSDECRYPTIONERRORS)==0)
1988 DEBUGMSGTL(("usm","%s\n",
1989 "Failed increment statistic."));
1991 return SNMPERR_USM_DECRYPTIONERROR;
1994 #ifdef SNMP_TESTING_CODE
1995 if ( debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1996 dump_chunk("usm/dump", "Decrypted chunk:",
1997 *scopedPdu, *scopedPduLen);
1998 dump_chunk("usm/dump", "IV + Encrypted form:",
2000 dump_chunk("usm/dump", NULL,
2001 value_ptr, remaining);
2007 * sPDU is plaintext.
2011 *scopedPdu = data_ptr;
2012 *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
2013 end_of_overhead = data_ptr;
2015 } /* endif -- PDU decryption */
2019 * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
2023 *maxSizeResponse = maxMsgSize - (int)
2024 ((u_long)end_of_overhead - (u_long)wholeMsg);
2027 DEBUGMSGTL(("usm","USM processing completed.\n"));
2029 return SNMPERR_SUCCESS;
2031 } /* end usm_process_in_msg() */
2035 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
2036 init_usm_post_config, NULL);
2040 * initializations for the USM.
2042 * Should be called after the configuration files have been read.
2044 * Set "arbitrary" portion of salt to a random number.
2047 init_usm_post_config(int majorid, int minorid, void *serverarg,
2049 size_t salt_integer_len = sizeof(salt_integer);
2051 initialUser = usm_create_initial_user("initial", usmHMACMD5AuthProtocol,
2052 USM_LENGTH_OID_TRANSFORM,
2054 USM_LENGTH_OID_TRANSFORM);
2055 SNMP_FREE(initialUser->engineID);
2056 initialUser->engineIDLen = 0;
2058 if ( sc_random((u_char *) &salt_integer, &salt_integer_len) != SNMPERR_SUCCESS )
2060 DEBUGMSGTL(("usm","sc_random() failed: using time() as salt.\n"));
2061 salt_integer = (u_int) time(NULL);
2062 salt_integer_len = sizeof(salt_integer);
2065 noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
2066 USM_LENGTH_OID_TRANSFORM,
2068 USM_LENGTH_OID_TRANSFORM);
2069 SNMP_FREE(noNameUser->engineID);
2070 noNameUser->engineIDLen = 0;
2072 return SNMPERR_SUCCESS;
2073 } /* end init_usm_post_config() */
2077 * Local storage (LCD) of the default user list.
2079 static struct usmUser *userList=NULL;
2082 usm_get_userList(void)
2089 /*******************************************************************-o-******
2090 * usm_check_secLevel
2100 * Checks that a given security level is valid for a given user.
2103 usm_check_secLevel(int level, struct usmUser *user)
2106 if ( level == SNMP_SEC_LEVEL_AUTHPRIV
2107 && (snmp_oid_compare(user->privProtocol, user->privProtocolLen,
2108 usmNoPrivProtocol, sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
2112 if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2113 && (snmp_oid_compare(user->authProtocol, user->authProtocolLen,
2114 usmNoAuthProtocol, sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
2121 } /* end usm_check_secLevel() */
2126 /*******************************************************************-o-******
2127 * usm_check_secLevel_vs_protocols
2140 * Same as above but with explicitly named transform types instead of taking
2141 * from the usmUser structure.
2144 usm_check_secLevel_vs_protocols(int level,
2145 oid *authProtocol, u_int authProtocolLen,
2146 oid *privProtocol, u_int privProtocolLen)
2149 if ( level == SNMP_SEC_LEVEL_AUTHPRIV
2150 && (snmp_oid_compare(privProtocol, privProtocolLen, usmNoPrivProtocol,
2151 sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
2155 if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2156 && (snmp_oid_compare(authProtocol, authProtocolLen, usmNoAuthProtocol,
2157 sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
2164 } /* end usm_check_secLevel_vs_protocols() */
2167 /* usm_update_engine_time(): Updates engine_time for all registered users.
2168 * This function would be useful for systems that start up with default time
2169 * settings and then update their timing reference using NTP at a later stage
2171 void usm_update_engine_time(void) {
2173 struct usmUser *ptr;
2177 boots_long = snmpv3_local_snmpEngineBoots();
2178 time_long = snmpv3_local_snmpEngineTime();
2180 for (ptr = userList; ptr != NULL; ptr = ptr->next) {
2181 set_enginetime( ptr->engineID, ptr->engineIDLen,
2182 boots_long, time_long, TRUE );
2187 /* usm_get_user(): Returns a user from userList based on the engineID,
2188 engineIDLen and name of the requested user. */
2191 usm_get_user(u_char *engineID, size_t engineIDLen, char *name)
2193 DEBUGMSGTL(("usm","getting user %s\n", name));
2194 return usm_get_user_from_list(engineID, engineIDLen, name, userList, 1);
2198 usm_get_user_from_list(u_char *engineID, size_t engineIDLen,
2199 char *name, struct usmUser *puserList, int use_default)
2201 struct usmUser *ptr;
2205 for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
2206 if (!strcmp(ptr->name, name) &&
2207 ptr->engineIDLen == engineIDLen &&
2208 ((ptr->engineID == NULL && engineID == NULL) ||
2209 (ptr->engineID != NULL && engineID != NULL &&
2210 memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
2213 /* return "" user used to facilitate engineID discovery */
2214 if (use_default && !strcmp(name, "")) return noNameUser;
2215 /* this next line may be vestigial from when the draft used 'initial'
2216 to discover engineID, also did not remove creation if 'inital' user
2218 if (use_default && !strcmp(name, "initial")) return initialUser;
2222 /* usm_add_user(): Add's a user to the userList, sorted by the
2223 engineIDLength then the engineID then the name length then the name
2224 to facilitate getNext calls on a usmUser table which is indexed by
2227 Note: userList must not be NULL (obviously), as thats a rather trivial
2228 addition and is left to the API user.
2230 returns the head of the list (which could change due to this add).
2234 usm_add_user(struct usmUser *user)
2236 struct usmUser *uptr;
2237 uptr = usm_add_user_to_list(user, userList);
2244 usm_add_user_to_list(struct usmUser *user,
2245 struct usmUser *puserList)
2247 struct usmUser *nptr, *pptr;
2249 /* loop through puserList till we find the proper, sorted place to
2250 insert the new user */
2251 for (nptr = puserList, pptr = NULL; nptr != NULL;
2252 pptr = nptr, nptr = nptr->next) {
2253 if (nptr->engineIDLen > user->engineIDLen)
2256 if (user->engineID == NULL && nptr->engineID != NULL)
2259 if (nptr->engineIDLen == user->engineIDLen &&
2260 (nptr->engineID != NULL && user->engineID != NULL &&
2261 memcmp(nptr->engineID, user->engineID, user->engineIDLen) > 0))
2264 if (!(nptr->engineID == NULL && user->engineID != NULL)) {
2265 if (nptr->engineIDLen == user->engineIDLen &&
2266 ((nptr->engineID == NULL && user->engineID == NULL) ||
2267 memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2268 strlen(nptr->name) > strlen(user->name))
2271 if (nptr->engineIDLen == user->engineIDLen &&
2272 ((nptr->engineID == NULL && user->engineID == NULL) ||
2273 memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2274 strlen(nptr->name) == strlen(user->name) &&
2275 strcmp(nptr->name, user->name) > 0)
2278 if (nptr->engineIDLen == user->engineIDLen &&
2279 ((nptr->engineID == NULL && user->engineID == NULL) ||
2280 memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
2281 strlen(nptr->name) == strlen(user->name) &&
2282 strcmp(nptr->name, user->name) == 0)
2283 /* the user is an exact match of a previous entry. Bail */
2288 /* nptr should now point to the user that we need to add ourselves
2289 in front of, and pptr should be our new 'prev'. */
2291 /* change our pointers */
2295 /* change the next's prev pointer */
2297 user->next->prev = user;
2299 /* change the prev's next pointer */
2301 user->prev->next = user;
2303 /* rewind to the head of the list and return it (since the new head
2304 could be us, we need to notify the above routine who the head now is. */
2305 for(pptr = user; pptr->prev != NULL; pptr = pptr->prev);
2309 /* usm_remove_user(): finds and removes a user from a list */
2311 usm_remove_user(struct usmUser *user)
2313 return usm_remove_user_from_list(user, &userList);
2317 usm_remove_user_from_list(struct usmUser *user,
2318 struct usmUser **ppuserList)
2320 struct usmUser *nptr, *pptr;
2322 /* NULL pointers aren't allowed */
2323 if (ppuserList == NULL)
2326 /* find the user in the list */
2327 for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
2328 pptr = nptr, nptr = nptr->next) {
2334 /* remove the user from the linked list */
2336 pptr->next = nptr->next;
2339 nptr->next->prev = pptr;
2342 /* user didn't exit */
2345 if (nptr == *ppuserList) /* we're the head of the list, need to change
2346 the head to the next user */
2347 *ppuserList = nptr->next;
2349 } /* end usm_remove_user_from_list() */
2354 /* usm_free_user(): calls free() on all needed parts of struct usmUser and
2357 Note: This should *not* be called on an object in a list (IE,
2358 remove it from the list first, and set next and prev to NULL), but
2359 will try to reconnect the list pieces again if it is called this
2360 way. If called on the head of the list, the entire list will be
2363 usm_free_user(struct usmUser *user)
2368 SNMP_FREE(user->engineID);
2369 SNMP_FREE(user->name);
2370 SNMP_FREE(user->secName);
2371 SNMP_FREE(user->cloneFrom);
2372 SNMP_FREE(user->userPublicString);
2373 SNMP_FREE(user->authProtocol);
2374 SNMP_FREE(user->privProtocol);
2376 if (user->authKey != NULL) {
2377 SNMP_ZERO(user->authKey, user->authKeyLen);
2378 SNMP_FREE(user->authKey);
2381 if (user->privKey != NULL) {
2382 SNMP_ZERO(user->privKey, user->privKeyLen);
2383 SNMP_FREE(user->privKey);
2387 /* FIX Why not put this check *first?*
2389 if (user->prev != NULL) { /* ack, this shouldn't happen */
2390 user->prev->next = user->next;
2392 if (user->next != NULL) {
2393 user->next->prev = user->prev;
2394 if (user->prev != NULL) /* ack this is really bad, because it means
2395 we'll loose the head of some structure tree */
2396 DEBUGMSGTL(("usm","Severe: Asked to free the head of a usmUser tree somewhere."));
2400 SNMP_ZERO(user, sizeof(*user));
2403 return NULL; /* for convenience to returns from calling functions */
2405 } /* end usm_free_user() */
2410 /* take a given user and clone the security info into another */
2412 usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
2414 /* copy the authProtocol oid row pointer */
2415 SNMP_FREE(to->authProtocol);
2417 if ((to->authProtocol =
2418 snmp_duplicate_objid(from->authProtocol,from->authProtocolLen)) != NULL)
2419 to->authProtocolLen = from->authProtocolLen;
2421 to->authProtocolLen = 0;
2424 /* copy the authKey */
2425 SNMP_FREE(to->authKey);
2427 if (from->authKeyLen > 0 &&
2428 (to->authKey = (u_char *) malloc(from->authKeyLen))
2430 to->authKeyLen = from->authKeyLen;
2431 memcpy(to->authKey, from->authKey, to->authKeyLen);
2438 /* copy the privProtocol oid row pointer */
2439 SNMP_FREE(to->privProtocol);
2441 if ((to->privProtocol =
2442 snmp_duplicate_objid(from->privProtocol,from->privProtocolLen)) != NULL)
2443 to->privProtocolLen = from->privProtocolLen;
2445 to->privProtocolLen = 0;
2447 /* copy the privKey */
2448 SNMP_FREE(to->privKey);
2450 if (from->privKeyLen > 0 &&
2451 (to->privKey = (u_char *) malloc(from->privKeyLen))
2453 to->privKeyLen = from->privKeyLen;
2454 memcpy(to->privKey, from->privKey, to->privKeyLen);
2462 /* usm_create_user(void):
2463 create a default empty user, instantiating only the auth/priv
2464 protocols to noAuth and noPriv OID pointers
2467 usm_create_user(void)
2469 struct usmUser *newUser;
2471 /* create the new user */
2472 newUser = (struct usmUser *) calloc(1,sizeof(struct usmUser));
2473 if (newUser == NULL)
2476 /* fill the auth/priv protocols */
2477 if ((newUser->authProtocol =
2478 snmp_duplicate_objid(usmNoAuthProtocol,
2479 sizeof(usmNoAuthProtocol)/sizeof(oid))) == NULL)
2480 return usm_free_user(newUser);
2481 newUser->authProtocolLen = sizeof(usmNoAuthProtocol)/sizeof(oid);
2483 if ((newUser->privProtocol =
2484 snmp_duplicate_objid(usmNoPrivProtocol,
2485 sizeof(usmNoPrivProtocol)/sizeof(oid))) == NULL)
2486 return usm_free_user(newUser);
2487 newUser->privProtocolLen = sizeof(usmNoPrivProtocol)/sizeof(oid);
2489 /* set the storage type to nonvolatile, and the status to ACTIVE */
2490 newUser->userStorageType = ST_NONVOLATILE;
2491 newUser->userStatus = RS_ACTIVE;
2494 } /* end usm_clone_user() */
2499 /* usm_create_initial_user(void):
2500 creates an initial user, filled with the defaults defined in the
2504 usm_create_initial_user(const char *name, oid *authProtocol, size_t authProtocolLen,
2505 oid *privProtocol, size_t privProtocolLen)
2507 struct usmUser *newUser = usm_create_user();
2508 if (newUser == NULL)
2511 if ((newUser->name = strdup(name)) == NULL)
2512 return usm_free_user(newUser);
2514 if ((newUser->secName = strdup(name)) == NULL)
2515 return usm_free_user(newUser);
2517 if ((newUser->engineID = snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
2518 return usm_free_user(newUser);
2520 if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid)*2)) == NULL)
2521 return usm_free_user(newUser);
2522 newUser->cloneFrom[0] = 0;
2523 newUser->cloneFrom[1] = 0;
2524 newUser->cloneFromLen = 2;
2526 SNMP_FREE(newUser->privProtocol);
2527 if ((newUser->privProtocol = (oid *) malloc(privProtocolLen*sizeof(oid)))
2529 return usm_free_user(newUser);
2530 newUser->privProtocolLen = privProtocolLen;
2531 memcpy(newUser->privProtocol, privProtocol, privProtocolLen*sizeof(oid));
2533 SNMP_FREE(newUser->authProtocol);
2534 if ((newUser->authProtocol = (oid *) malloc(authProtocolLen*sizeof(oid)))
2536 return usm_free_user(newUser);
2537 newUser->authProtocolLen = authProtocolLen;
2538 memcpy(newUser->authProtocol, authProtocol, authProtocolLen*sizeof(oid));
2540 newUser->userStatus = RS_ACTIVE;
2541 newUser->userStorageType = ST_READONLY;
2546 /* this is a callback that can store all known users based on a
2547 previously registered application ID */
2549 usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
2551 /* figure out our application name */
2552 char *appname = (char *) clientarg;
2553 if (appname == NULL)
2554 appname = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE);
2556 /* save the user base */
2557 usm_save_users("usmUser", appname);
2560 return SNMPERR_SUCCESS;
2564 /* usm_save_users(): saves a list of users to the persistent cache */
2566 usm_save_users(const char *token, const char *type)
2568 usm_save_users_from_list(userList, token, type);
2572 usm_save_users_from_list(struct usmUser *puserList, const char *token,
2575 struct usmUser *uptr;
2576 for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
2577 if (uptr->userStorageType == ST_NONVOLATILE)
2578 usm_save_user(uptr, token, type);
2582 /* usm_save_user(): saves a user to the persistent cache */
2584 usm_save_user(struct usmUser *user, const char *token, const char *type)
2589 memset(line, 0, sizeof(line));
2591 sprintf(line, "%s %d %d ", token, user->userStatus, user->userStorageType);
2592 cptr = &line[strlen(line)]; /* the NULL */
2593 cptr = read_config_save_octet_string(cptr, user->engineID, user->engineIDLen);
2595 cptr = read_config_save_octet_string(cptr, (u_char *)user->name,
2596 (user->name == NULL) ? 0 :
2597 strlen(user->name)+1);
2599 cptr = read_config_save_octet_string(cptr, (u_char *)user->secName,
2600 (user->secName == NULL) ? 0 :
2601 strlen(user->secName)+1);
2603 cptr = read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
2605 cptr = read_config_save_objid(cptr, user->authProtocol,
2606 user->authProtocolLen);
2608 cptr = read_config_save_octet_string(cptr, user->authKey, user->authKeyLen);
2610 cptr = read_config_save_objid(cptr, user->privProtocol,
2611 user->privProtocolLen);
2613 cptr = read_config_save_octet_string(cptr, user->privKey, user->privKeyLen);
2615 cptr = read_config_save_octet_string(cptr, user->userPublicString,
2616 (user->userPublicString == NULL) ? 0 :
2617 strlen((char *)user->userPublicString)+1);
2618 read_config_store(type, line);
2621 /* usm_parse_user(): reads in a line containing a saved user profile
2622 and returns a pointer to a newly created struct usmUser. */
2624 usm_read_user(char *line)
2626 struct usmUser *user;
2629 user = usm_create_user();
2633 user->userStatus = atoi(line);
2634 line = skip_token(line);
2635 user->userStorageType = atoi(line);
2636 line = skip_token(line);
2637 line = read_config_read_octet_string(line, &user->engineID,
2638 &user->engineIDLen);
2640 /* set the lcd entry for this engineID to the minimum boots/time
2641 values so that its a known engineid and won't return a report pdu.
2642 This is mostly important when receiving v3 traps so that the usm
2643 will at least continue processing them. */
2644 set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
2646 line = read_config_read_octet_string(line, (u_char **)&user->name,
2648 line = read_config_read_octet_string(line, (u_char **)&user->secName,
2650 SNMP_FREE(user->cloneFrom);
2651 user->cloneFromLen = 0;
2653 line = read_config_read_objid(line, &user->cloneFrom, &user->cloneFromLen);
2655 SNMP_FREE(user->authProtocol);
2656 user->authProtocolLen = 0;
2658 line = read_config_read_objid(line, &user->authProtocol,
2659 &user->authProtocolLen);
2660 line = read_config_read_octet_string(line, &user->authKey,
2662 SNMP_FREE(user->privProtocol);
2663 user->privProtocolLen = 0;
2665 line = read_config_read_objid(line, &user->privProtocol,
2666 &user->privProtocolLen);
2667 line = read_config_read_octet_string(line, &user->privKey,
2669 line = read_config_read_octet_string(line, &user->userPublicString,
2674 /* snmpd.conf parsing routines */
2676 usm_parse_config_usmUser(const char *token, char *line)
2678 struct usmUser *uptr;
2680 uptr = usm_read_user(line);
2687 /*******************************************************************-o-******
2695 * format: userSetAuthPass secname engineIDLen engineID pass
2696 * or: userSetPrivPass secname engineIDLen engineID pass
2697 * or: userSetAuthKey secname engineIDLen engineID KuLen Ku
2698 * or: userSetPrivKey secname engineIDLen engineID KuLen Ku
2699 * or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
2700 * or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul
2702 * type is: 1=passphrase; 2=Ku; 3=Kul.
2705 * ASSUMES Passwords are null-terminated printable strings.
2708 usm_set_password(const char *token, char *line)
2711 char nameBuf[SNMP_MAXBUF];
2714 struct usmUser *user;
2716 cp = copy_word(line, nameBuf);
2718 config_perror("invalid name specifier");
2722 DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
2723 if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
2724 /* match against all engineIDs we know about */
2725 cp = skip_token(cp);
2726 for(user = userList; user != NULL; user = user->next) {
2727 if (strcmp(user->secName, nameBuf) == 0) {
2728 usm_set_user_password(user, token, cp);
2732 cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
2734 config_perror("invalid engineID specifier");
2738 user = usm_get_user(engineID, engineIDLen, nameBuf);
2740 config_perror("not a valid user/engineID pair");
2743 usm_set_user_password(user, token, cp);
2747 /* uses the rest of LINE to configure USER's password of type TOKEN */
2749 usm_set_user_password(struct usmUser *user, const char *token, char *line)
2752 u_char *engineID = user->engineID;
2753 size_t engineIDLen = user->engineIDLen;
2757 u_char userKey[SNMP_MAXBUF_SMALL];
2758 size_t userKeyLen = SNMP_MAXBUF_SMALL;
2762 * Retrieve the "old" key and set the key type.
2764 if (strcmp(token, "userSetAuthPass") == 0) {
2765 key = &user->authKey;
2766 keyLen = &user->authKeyLen;
2768 } else if (strcmp(token, "userSetPrivPass") == 0) {
2769 key = &user->privKey;
2770 keyLen = &user->privKeyLen;
2772 } else if (strcmp(token, "userSetAuthKey") == 0) {
2773 key = &user->authKey;
2774 keyLen = &user->authKeyLen;
2776 } else if (strcmp(token, "userSetPrivKey") == 0) {
2777 key = &user->privKey;
2778 keyLen = &user->privKeyLen;
2780 } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
2781 key = &user->authKey;
2782 keyLen = &user->authKeyLen;
2784 } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
2785 key = &user->privKey;
2786 keyLen = &user->privKeyLen;
2789 /* no old key, or token was not recognized */
2794 /* (destroy and) free the old key */
2795 memset(*key, 0, *keyLen);
2800 /* convert the password into a key
2802 ret = generate_Ku( user->authProtocol, user->authProtocolLen,
2803 (u_char *)cp, strlen(cp),
2804 userKey, &userKeyLen );
2806 if (ret != SNMPERR_SUCCESS) {
2807 config_perror("setting key failed (in sc_genKu())");
2810 } else if (type == 1) {
2811 cp = read_config_read_octet_string(cp, (u_char **) &userKey, &userKeyLen);
2814 config_perror("invalid user key");
2820 *key = (u_char *)malloc(SNMP_MAXBUF_SMALL);
2821 *keyLen = SNMP_MAXBUF_SMALL;
2822 ret = generate_kul( user->authProtocol, user->authProtocolLen,
2823 engineID, engineIDLen,
2824 userKey, userKeyLen,
2826 if (ret != SNMPERR_SUCCESS) {
2827 config_perror("setting key failed (in generate_kul())");
2831 /* (destroy and) free the old key */
2832 memset(userKey, 0, sizeof(userKey));
2835 /* the key is given, copy it in */
2836 cp = read_config_read_octet_string(cp, key, keyLen);
2839 config_perror("invalid localized user key");
2843 } /* end usm_set_password() */
2845 #endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */