1 #ifdef BRCM_SNMP_MIB_SUPPORT
5 * Routines to manipulate a information about a "user" as
6 * defined by the SNMP-USER-BASED-SM-MIB MIB.
8 * All functions usm_set_usmStateReference_*() return 0 on success, -1
11 * !! Tab stops set to 4 in some parts of this file. !!
12 * (Designated on a per function.)
15 #include <net-snmp/net-snmp-config.h>
17 #include <sys/types.h>
25 #if TIME_WITH_SYS_TIME
27 # include <sys/timeb.h>
29 # include <sys/time.h>
34 # include <sys/time.h>
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
52 #include <net-snmp/types.h>
53 #include <net-snmp/output_api.h>
54 #include <net-snmp/config_api.h>
55 #include <net-snmp/utilities.h>
57 #include <net-snmp/library/asn1.h>
58 #include <net-snmp/library/snmp_api.h>
59 #include <net-snmp/library/callback.h>
60 #include <net-snmp/library/keytools.h>
61 #include <net-snmp/library/snmpv3.h>
62 #include <net-snmp/library/lcd_time.h>
63 #include <net-snmp/library/scapi.h>
64 #include <net-snmp/library/callback.h>
65 #include <net-snmp/library/snmp_secmod.h>
66 #include <net-snmp/library/snmpusm.h>
68 oid usmNoAuthProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 };
69 oid usmHMACMD5AuthProtocol[10] =
70 { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 };
71 oid usmHMACSHA1AuthProtocol[10] =
72 { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 };
73 oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
74 oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
75 oid usmAES128PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,128 };
76 oid usmAES192PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,192 };
77 oid usmAES256PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,256 };
79 static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */
84 static u_int salt_integer;
86 static u_int salt_integer64_1, salt_integer64_2;
89 * 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1.
92 static struct usmUser *noNameUser = NULL;
94 * Local storage (LCD) of the default user list.
96 static struct usmUser *userList = NULL;
102 usm_check_secLevel_vs_protocols(int level,
103 const oid * authProtocol,
104 u_int authProtocolLen,
105 const oid * privProtocol,
106 u_int privProtocolLen);
108 usm_calc_offsets(size_t globalDataLen,
109 int secLevel, size_t secEngineIDLen,
110 size_t secNameLen, size_t scopedPduLen,
111 u_long engineboots, long engine_time,
112 size_t * theTotalLength,
113 size_t * authParamsOffset,
114 size_t * privParamsOffset,
115 size_t * dataOffset, size_t * datalen,
116 size_t * msgAuthParmLen,
117 size_t * msgPrivParmLen, size_t * otstlen,
118 size_t * seq_len, size_t * msgSecParmLen);
120 * Set a given field of the secStateRef.
122 * Allocate <len> bytes for type <type> pointed to by ref-><field>.
123 * Then copy in <item> and record its length in ref-><field_len>.
125 * Return 0 on success, -1 otherwise.
127 #define MAKE_ENTRY( type, item, len, field, field_len ) \
131 if (ref->field != NULL) { \
132 SNMP_ZERO(ref->field, ref->field_len); \
133 SNMP_FREE(ref->field); \
135 ref->field_len = 0; \
136 if (len == 0 || item == NULL) { \
139 if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \
144 memcpy (ref->field, item, len * sizeof(type)); \
145 ref->field_len = len; \
151 struct usmStateReference *
152 usm_malloc_usmStateReference(void)
154 struct usmStateReference *retval = (struct usmStateReference *)
155 calloc(1, sizeof(struct usmStateReference));
158 } /* end usm_malloc_usmStateReference() */
162 usm_free_usmStateReference(void *old)
164 struct usmStateReference *old_ref = (struct usmStateReference *) old;
168 SNMP_FREE(old_ref->usr_name);
169 SNMP_FREE(old_ref->usr_engine_id);
170 SNMP_FREE(old_ref->usr_auth_protocol);
171 SNMP_FREE(old_ref->usr_priv_protocol);
173 if (old_ref->usr_auth_key) {
174 SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length);
175 SNMP_FREE(old_ref->usr_auth_key);
177 if (old_ref->usr_priv_key) {
178 SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length);
179 SNMP_FREE(old_ref->usr_priv_key);
182 SNMP_ZERO(old_ref, sizeof(*old_ref));
187 } /* end usm_free_usmStateReference() */
190 usm_get_userList(void)
196 usm_set_usmStateReference_name(struct usmStateReference *ref,
197 char *name, size_t name_len)
199 MAKE_ENTRY(char, name, name_len, usr_name, usr_name_length);
203 usm_set_usmStateReference_engine_id(struct usmStateReference *ref,
205 size_t engine_id_len)
207 MAKE_ENTRY(u_char, engine_id, engine_id_len,
208 usr_engine_id, usr_engine_id_length);
212 usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref,
214 size_t auth_protocol_len)
216 MAKE_ENTRY(oid, auth_protocol, auth_protocol_len,
217 usr_auth_protocol, usr_auth_protocol_length);
221 usm_set_usmStateReference_auth_key(struct usmStateReference *ref,
222 u_char * auth_key, size_t auth_key_len)
224 MAKE_ENTRY(u_char, auth_key, auth_key_len,
225 usr_auth_key, usr_auth_key_length);
229 usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref,
231 size_t priv_protocol_len)
233 MAKE_ENTRY(oid, priv_protocol, priv_protocol_len,
234 usr_priv_protocol, usr_priv_protocol_length);
238 usm_set_usmStateReference_priv_key(struct usmStateReference *ref,
239 u_char * priv_key, size_t priv_key_len)
241 MAKE_ENTRY(u_char, priv_key, priv_key_len,
242 usr_priv_key, usr_priv_key_length);
246 usm_set_usmStateReference_sec_level(struct usmStateReference *ref,
251 ref->usr_sec_level = sec_level;
257 #ifdef SNMP_TESTING_CODE
258 /*******************************************************************-o-******
265 * This is a print routine that is solely included so that it can be
266 * used in gdb. Don't use it as a function, it will be pulled before
267 * a real release of the code.
271 * XXX fflush() only works on FreeBSD; core dumps on Sun OS's
274 emergency_print(u_char * field, u_int length)
280 while (start < stop) {
281 for (iindex = start; iindex < stop; iindex++)
282 printf("%02X ", field[iindex]);
286 stop = stop + 25 < length ? stop + 25 : length;
290 } /* end emergency_print() */
291 #endif /* SNMP_TESTING_CODE */
294 /*******************************************************************-o-******
295 * asn_predict_int_length
303 * Number of bytes necessary to store the ASN.1 encoded value of 'number'.
306 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
307 * use to encode a particular integer value.
309 * Returns the length of the integer -- NOT THE HEADER!
311 * Do this the same way as asn_build_int()...
314 asn_predict_int_length(int type, long number, size_t len)
316 register u_long mask;
319 if (len != sizeof(long))
322 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
324 * mask is 0xFF800000 on a big-endian machine
327 while ((((number & mask) == 0) || ((number & mask) == mask))
335 } /* end asn_predict_length() */
340 /*******************************************************************-o-******
349 * Length in bytes: 1 + <n> + <u_char_len>, where
351 * 1 For the ASN.1 type.
352 * <n> # of bytes to store length of data.
353 * <u_char_len> Length of data associated with ASN.1 type.
355 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will
356 * use to encode a particular integer value. This is as broken as the
357 * currently used encoder.
359 * XXX How is <n> chosen, exactly??
362 asn_predict_length(int type, u_char * ptr, size_t u_char_len)
365 if (type & ASN_SEQUENCE)
366 return 1 + 3 + u_char_len;
368 if (type & ASN_INTEGER) {
370 memcpy(&value, ptr, u_char_len);
371 u_char_len = asn_predict_int_length(type, value, u_char_len);
374 if (u_char_len < 0x80)
375 return 1 + 1 + u_char_len;
376 else if (u_char_len < 0xFF)
377 return 1 + 2 + u_char_len;
379 return 1 + 3 + u_char_len;
381 } /* end asn_predict_length() */
386 /*******************************************************************-o-******
390 * (See list below...)
397 * This routine calculates the offsets into an outgoing message buffer
398 * for the necessary values. The outgoing buffer will generically
408 * OST len msgFlags (OST = OCTET STRING)
409 * INT len msgSecurityModel
410 * MsgSecurityParameters
413 * OST len msgAuthoritativeEngineID
414 * INT len msgAuthoritativeEngineBoots
415 * INT len msgAuthoritativeEngineTime
416 * OST len msgUserName
417 * OST len[4] [5] msgAuthenticationParameters
418 * OST len[6] [7] msgPrivacyParameters
420 * [8] OST len[9] [10] encryptedPDU
422 * [8,10] SEQUENCE len[9] scopedPDU
425 * The bracketed points will be needed to be identified ([x] is an index
426 * value, len[x] means a length value). Here is a semantic guide to them:
428 * [1] = globalDataLen (input)
431 * [4] = msgAuthParmLen (may be 0 or 12)
432 * [5] = authParamsOffset
433 * [6] = msgPrivParmLen (may be 0 or 8)
434 * [7] = privParamsOffset
435 * [8] = globalDataLen + msgSecParmLen
438 * [11] = theTotalLength - the length of the header itself
439 * [12] = theTotalLength
442 usm_calc_offsets(size_t globalDataLen, /* SNMPv3Message + HeaderData */
443 int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen, /* An BER encoded sequence. */
444 u_long engineboots, /* XXX (asn1.c works in long, not int.) */
445 long engine_time, /* XXX (asn1.c works in long, not int.) */
446 size_t * theTotalLength, /* globalDataLen + msgSecurityP. + msgData */
447 size_t * authParamsOffset, /* Distance to auth bytes. */
448 size_t * privParamsOffset, /* Distance to priv bytes. */
449 size_t * dataOffset, /* Distance to scopedPdu SEQ -or- the
450 * crypted (data) portion of msgData. */
451 size_t * datalen, /* Size of msgData OCTET STRING encoding. */
452 size_t * msgAuthParmLen, /* Size of msgAuthenticationParameters. */
453 size_t * msgPrivParmLen, /* Size of msgPrivacyParameters. */
454 size_t * otstlen, /* Size of msgSecurityP. O.S. encoding. */
455 size_t * seq_len, /* Size of msgSecurityP. SEQ data. */
456 size_t * msgSecParmLen)
457 { /* Size of msgSecurityP. SEQ. */
458 int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */
459 engBtlen, /* for fields within */
460 engTmlen, /* msgSecurityParameters portion of */
461 namelen, /* SNMPv3Message. */
465 * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
466 * If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0.
468 *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
469 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0;
471 *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0;
477 if ((engIDlen = asn_predict_length(ASN_OCTET_STR,
478 0, secEngineIDLen)) == -1) {
482 if ((engBtlen = asn_predict_length(ASN_INTEGER,
483 (u_char *) & engineboots,
484 sizeof(long))) == -1) {
488 if ((engTmlen = asn_predict_length(ASN_INTEGER,
489 (u_char *) & engine_time,
490 sizeof(long))) == -1) {
494 if ((namelen = asn_predict_length(ASN_OCTET_STR, 0, secNameLen)) == -1) {
498 if ((authlen = asn_predict_length(ASN_OCTET_STR,
499 0, *msgAuthParmLen)) == -1) {
503 if ((privlen = asn_predict_length(ASN_OCTET_STR,
504 0, *msgPrivParmLen)) == -1) {
509 engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
511 if ((*otstlen = asn_predict_length(ASN_SEQUENCE, 0, *seq_len)) == -1) {
515 if ((*msgSecParmLen = asn_predict_length(ASN_OCTET_STR,
516 0, *otstlen)) == -1) {
520 *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len)
521 + engIDlen + engBtlen + engTmlen + namelen
522 + (authlen - *msgAuthParmLen);
524 *privParamsOffset = *authParamsOffset + *msgAuthParmLen
525 + (privlen - *msgPrivParmLen);
529 * Compute the size of the plaintext. Round up to account for cipher
530 * block size, if necessary.
532 * XXX This is hardwired for 1DES... If scopedPduLen is already
533 * a multiple of 8, then *add* 8 more; otherwise, round up
534 * to the next multiple of 8.
536 * FIX Calculation of encrypted portion of msgData and consequent
537 * setting and sanity checking of theTotalLength, et al. should
538 * occur *after* encryption has taken place.
540 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
541 scopedPduLen = ROUNDUP8(scopedPduLen);
544 asn_predict_length(ASN_OCTET_STR, 0, scopedPduLen)) == -1) {
548 *datalen = scopedPduLen;
551 *dataOffset = globalDataLen + *msgSecParmLen +
552 (*datalen - scopedPduLen);
553 *theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
557 } /* end usm_calc_offsets() */
563 /*******************************************************************-o-******
567 * *iv (O) Buffer to contain IV.
568 * *iv_length (O) Length of iv.
569 * *priv_salt (I) Salt portion of private key.
570 * priv_salt_length (I) Length of priv_salt.
571 * *msgSalt (I/O) Pointer salt portion of outgoing msg buffer.
577 * Determine the initialization vector for the DES-CBC encryption.
578 * (Cf. RFC 2274, 8.1.1.1.)
580 * iv is defined as the concatenation of engineBoots and the
582 * The salt integer is incremented.
583 * The resulting salt is copied into the msgSalt buffer.
584 * The result of the concatenation is then XORed with the salt
585 * portion of the private key (last 8 bytes).
586 * The IV result is returned individually for further use.
589 usm_set_salt(u_char * iv,
591 u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
593 size_t propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
597 * net_* should be encoded in network byte order. XXX Why?
605 if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt)
606 || (priv_salt_length < propersize_salt)) {
611 net_boots = htonl(snmpv3_local_snmpEngineBoots());
612 net_salt_int = htonl(salt_integer);
616 memcpy(iv, &net_boots, propersize_salt / 2);
617 memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2);
620 memcpy(msgSalt, iv, propersize_salt);
624 * Turn the salt into an IV: XOR <boots, salt_int> with salt
625 * portion of priv_key.
627 for (iindex = 0; iindex < (int) propersize_salt; iindex++)
628 iv[iindex] ^= priv_salt[iindex];
633 } /* end usm_set_salt() */
636 /*******************************************************************-o-******
640 * *iv (O) Buffer to contain IV.
641 * *iv_length (O) Length of iv.
642 * net_boots (I) the network byte order of the authEng boots val
643 * net_time (I) the network byte order of the authEng time val
644 * *salt (O) A buffer for the outgoing salt (= 8 bytes of iv)
650 * Determine the initialization vector for AES encryption.
651 * (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
653 * iv is defined as the concatenation of engineBoots, engineTime
654 and a 64 bit salt-integer.
655 * The 64 bit salt integer is incremented.
656 * The resulting salt is copied into the salt buffer.
657 * The IV result is returned individually for further use.
660 usm_set_aes_iv(u_char * iv,
667 * net_* should be encoded in network byte order.
669 int net_salt_int1, net_salt_int2;
670 #define PROPER_AES_IV_SIZE 64
675 if (!iv || !iv_length) {
679 net_salt_int1 = htonl(salt_integer64_1);
680 net_salt_int2 = htonl(salt_integer64_2);
682 if ((salt_integer64_2 += 1) == 0)
683 salt_integer64_2 += 1;
685 /* XXX: warning: hard coded proper lengths */
686 memcpy(iv, &net_boots, 4);
687 memcpy(iv+4, &net_time, 4);
688 memcpy(iv+8, &net_salt_int1, 4);
689 memcpy(iv+12, &net_salt_int2, 4);
691 memcpy(salt, iv+8, 8); /* only copy the needed portion */
693 } /* end usm_set_salt() */
694 #endif /* HAVE_AES */
697 usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
700 return SNMPERR_GENERR;
702 return usm_generate_out_msg(parms->msgProcModel,
703 parms->globalData, parms->globalDataLen,
704 parms->maxMsgSize, parms->secModel,
705 parms->secEngineID, parms->secEngineIDLen,
706 parms->secName, parms->secNameLen,
708 parms->scopedPdu, parms->scopedPduLen,
710 parms->secParams, parms->secParamsLen,
711 parms->wholeMsg, parms->wholeMsgLen);
714 /*******************************************************************-o-******
715 * usm_generate_out_msg
718 * (See list below...)
721 * SNMPERR_SUCCESS On success.
722 * SNMPERR_USM_AUTHENTICATIONFAILURE
723 * SNMPERR_USM_ENCRYPTIONERROR
724 * SNMPERR_USM_GENERICERROR
725 * SNMPERR_USM_UNKNOWNSECURITYNAME
726 * SNMPERR_USM_GENERICERROR
727 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
730 * Generates an outgoing message.
732 * XXX Beware of misnomers!
735 usm_generate_out_msg(int msgProcModel, /* (UNUSED) */
736 u_char * globalData, /* IN */
738 * Pointer to msg header data will point to the beginning
739 * * of the entire packet buffer to be transmitted on wire,
740 * * memory will be contiguous with secParams, typically
741 * * this pointer will be passed back as beginning of
742 * * wholeMsg below. asn seq. length is updated w/ new length.
744 * * While this points to a buffer that should be big enough
745 * * for the whole message, only the first two parts
746 * * of the message are completed, namely SNMPv3Message and
747 * * HeaderData. globalDataLen (next parameter) represents
748 * * the length of these two completed parts.
750 size_t globalDataLen, /* IN - Length of msg header data. */
751 int maxMsgSize, /* (UNUSED) */
752 int secModel, /* (UNUSED) */
753 u_char * secEngineID, /* IN - Pointer snmpEngineID. */
754 size_t secEngineIDLen, /* IN - SnmpEngineID length. */
755 char *secName, /* IN - Pointer to securityName. */
756 size_t secNameLen, /* IN - SecurityName length. */
757 int secLevel, /* IN - AuthNoPriv, authPriv etc. */
758 u_char * scopedPdu, /* IN */
760 * Pointer to scopedPdu will be encrypted by USM if needed
761 * * and written to packet buffer immediately following
762 * * securityParameters, entire msg will be authenticated by
765 size_t scopedPduLen, /* IN - scopedPdu length. */
766 void *secStateRef, /* IN */
768 * secStateRef, pointer to cached info provided only for
769 * * Response, otherwise NULL.
771 u_char * secParams, /* OUT */
773 * BER encoded securityParameters pointer to offset within
774 * * packet buffer where secParams should be written, the
775 * * entire BER encoded OCTET STRING (including header) is
776 * * written here by USM secParams = globalData +
779 size_t * secParamsLen, /* IN/OUT - Len available, len returned. */
780 u_char ** wholeMsg, /* OUT */
782 * Complete authenticated/encrypted message - typically
783 * * the pointer to start of packet buffer provided in
784 * * globalData is returned here, could also be a separate
787 size_t * wholeMsgLen)
788 { /* IN/OUT - Len available, len returned. */
791 size_t msgAuthParmLen;
792 size_t msgPrivParmLen;
793 size_t msgSecParmLen;
794 size_t authParamsOffset;
795 size_t privParamsOffset;
798 size_t theTotalLength;
810 * Indirection because secStateRef values override parameters.
812 * None of these are to be free'd - they are either pointing to
813 * what's in the secStateRef or to something either in the
814 * actual prarmeter list or the user list.
817 char *theName = NULL;
818 u_int theNameLength = 0;
819 u_char *theEngineID = NULL;
820 u_int theEngineIDLength = 0;
821 u_char *theAuthKey = NULL;
822 u_int theAuthKeyLength = 0;
823 const oid *theAuthProtocol = NULL;
824 u_int theAuthProtocolLength = 0;
825 u_char *thePrivKey = NULL;
826 u_int thePrivKeyLength = 0;
827 const oid *thePrivProtocol = NULL;
828 u_int thePrivProtocolLength = 0;
829 int theSecLevel = 0; /* No defined const for bad
830 * value (other then err).
833 DEBUGMSGTL(("usm", "USM processing has begun.\n"));
835 if (secStateRef != NULL) {
837 * To hush the compiler for now. XXX
839 struct usmStateReference *ref
840 = (struct usmStateReference *) secStateRef;
842 theName = ref->usr_name;
843 theNameLength = ref->usr_name_length;
844 theEngineID = ref->usr_engine_id;
845 theEngineIDLength = ref->usr_engine_id_length;
847 if (!theEngineIDLength) {
848 theEngineID = secEngineID;
849 theEngineIDLength = secEngineIDLen;
852 theAuthProtocol = ref->usr_auth_protocol;
853 theAuthProtocolLength = ref->usr_auth_protocol_length;
854 theAuthKey = ref->usr_auth_key;
855 theAuthKeyLength = ref->usr_auth_key_length;
856 thePrivProtocol = ref->usr_priv_protocol;
857 thePrivProtocolLength = ref->usr_priv_protocol_length;
858 thePrivKey = ref->usr_priv_key;
859 thePrivKeyLength = ref->usr_priv_key_length;
860 theSecLevel = ref->usr_sec_level;
864 * Identify the user record.
867 struct usmUser *user;
870 * we do allow an unknown user name for
871 * unauthenticated requests.
873 if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
874 == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
875 DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
876 usm_free_usmStateReference(secStateRef);
877 return SNMPERR_USM_UNKNOWNSECURITYNAME;
881 theNameLength = secNameLen;
882 theEngineID = secEngineID;
883 theSecLevel = secLevel;
884 theEngineIDLength = secEngineIDLen;
886 theAuthProtocol = user->authProtocol;
887 theAuthProtocolLength = user->authProtocolLen;
888 theAuthKey = user->authKey;
889 theAuthKeyLength = user->authKeyLen;
890 thePrivProtocol = user->privProtocol;
891 thePrivProtocolLength = user->privProtocolLen;
892 thePrivKey = user->privKey;
893 thePrivKeyLength = user->privKeyLen;
896 * unknown users can not do authentication (obviously)
898 theAuthProtocol = usmNoAuthProtocol;
899 theAuthProtocolLength =
900 sizeof(usmNoAuthProtocol) / sizeof(oid);
902 theAuthKeyLength = 0;
903 thePrivProtocol = usmNoPrivProtocol;
904 thePrivProtocolLength =
905 sizeof(usmNoPrivProtocol) / sizeof(oid);
907 thePrivKeyLength = 0;
909 } /* endif -- secStateRef==NULL */
913 * From here to the end of the function, avoid reference to
914 * secName, secEngineID, secLevel, and associated lengths.
919 * Check to see if the user can use the requested sec services.
921 if (usm_check_secLevel_vs_protocols(theSecLevel,
923 theAuthProtocolLength,
925 thePrivProtocolLength) == 1) {
926 DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n",
928 usm_free_usmStateReference(secStateRef);
929 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
934 * Retrieve the engine information.
936 * XXX No error is declared in the EoP when sending messages to
937 * unknown engines, processing continues w/ boots/time == (0,0).
939 if (get_enginetime(theEngineID, theEngineIDLength,
940 &boots_uint, &time_uint, FALSE) == -1) {
941 DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
944 boots_long = boots_uint;
945 time_long = time_uint;
949 * Set up the Offsets.
951 if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength,
952 theNameLength, scopedPduLen, boots_long,
953 time_long, &theTotalLength, &authParamsOffset,
954 &privParamsOffset, &dataOffset, &datalen,
955 &msgAuthParmLen, &msgPrivParmLen, &otstlen,
956 &seq_len, &msgSecParmLen) == -1) {
957 DEBUGMSGTL(("usm", "Failed calculating offsets.\n"));
958 usm_free_usmStateReference(secStateRef);
959 return SNMPERR_USM_GENERICERROR;
963 * So, we have the offsets for the three parts that need to be
964 * determined, and an overall length. Now we need to make
965 * sure all of this would fit in the outgoing buffer, and
966 * whether or not we need to make a new buffer, etc.
971 * Set wholeMsg as a pointer to globalData. Sanity check for
974 * Mark workspace in the message with bytes of all 1's to make it
975 * easier to find mistakes in raw message dumps.
977 ptr = *wholeMsg = globalData;
978 if (theTotalLength > *wholeMsgLen) {
979 DEBUGMSGTL(("usm", "Message won't fit in buffer.\n"));
980 usm_free_usmStateReference(secStateRef);
981 return SNMPERR_USM_GENERICERROR;
984 ptr_len = *wholeMsgLen = theTotalLength;
986 #ifdef SNMP_TESTING_CODE
987 memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);
988 #endif /* SNMP_TESTING_CODE */
993 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
994 size_t encrypted_length = theTotalLength - dataOffset;
995 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
996 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
999 * XXX Hardwired to seek into a 1DES private key!
1002 if (ISTRANSFORM(thePrivProtocol, AES128Priv) &&
1003 ISTRANSFORM(thePrivProtocol, AES192Priv) &&
1004 ISTRANSFORM(thePrivProtocol, AES256Priv)) {
1006 usm_set_aes_iv(salt, &salt_length,
1007 htonl(boots_uint), htonl(time_uint),
1008 &ptr[privParamsOffset]) == -1) {
1009 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
1010 usm_free_usmStateReference(secStateRef);
1011 return SNMPERR_USM_GENERICERROR;
1013 } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
1016 (usm_set_salt(salt, &salt_length,
1017 thePrivKey + 8, thePrivKeyLength - 8,
1018 &ptr[privParamsOffset])
1020 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
1021 usm_free_usmStateReference(secStateRef);
1022 return SNMPERR_USM_GENERICERROR;
1028 if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
1029 thePrivKey, thePrivKeyLength,
1031 scopedPdu, scopedPduLen,
1032 &ptr[dataOffset], &encrypted_length)
1033 != SNMP_ERR_NOERROR) {
1034 DEBUGMSGTL(("usm", "DES-CBC error.\n"));
1035 usm_free_usmStateReference(secStateRef);
1036 return SNMPERR_USM_ENCRYPTIONERROR;
1038 #ifdef SNMP_TESTING_CODE
1039 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1040 dump_chunk("usm/dump", "This data was encrypted:",
1041 scopedPdu, scopedPduLen);
1042 dump_chunk("usm/dump", "salt + Encrypted form:",
1044 dump_chunk("usm/dump", NULL,
1045 &ptr[dataOffset], encrypted_length);
1046 dump_chunk("usm/dump", "*wholeMsg:",
1047 *wholeMsg, theTotalLength);
1053 ptr_len = *wholeMsgLen = theTotalLength;
1057 * XXX Sanity check for salt length should be moved up
1058 * under usm_calc_offsets() or tossed.
1060 if ((encrypted_length != (theTotalLength - dataOffset))
1061 || (salt_length != msgPrivParmLen)) {
1062 DEBUGMSGTL(("usm", "DES-CBC length error.\n"));
1063 usm_free_usmStateReference(secStateRef);
1064 return SNMPERR_USM_ENCRYPTIONERROR;
1067 DEBUGMSGTL(("usm", "Encryption successful.\n"));
1071 * No encryption for you!
1074 memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen);
1080 * Start filling in the other fields (in prep for authentication).
1082 * offSet is an octet string header, which is different from all
1083 * the other headers.
1085 remaining = ptr_len - globalDataLen;
1087 offSet = ptr_len - remaining;
1088 asn_build_header(&ptr[offSet], &remaining,
1089 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1090 ASN_OCTET_STR), otstlen);
1092 offSet = ptr_len - remaining;
1093 asn_build_sequence(&ptr[offSet], &remaining,
1094 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len);
1096 offSet = ptr_len - remaining;
1097 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
1098 asn_build_string(&ptr[offSet], &remaining,
1099 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1100 ASN_OCTET_STR), theEngineID,
1104 offSet = ptr_len - remaining;
1105 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
1106 asn_build_int(&ptr[offSet], &remaining,
1107 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1108 &boots_long, sizeof(long));
1111 offSet = ptr_len - remaining;
1112 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
1113 asn_build_int(&ptr[offSet], &remaining,
1114 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1115 &time_long, sizeof(long));
1118 offSet = ptr_len - remaining;
1119 DEBUGDUMPHEADER("send", "msgUserName");
1120 asn_build_string(&ptr[offSet], &remaining,
1121 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1122 ASN_OCTET_STR), (u_char *) theName,
1128 * Note: if there is no authentication being done,
1129 * msgAuthParmLen is 0, and there is no effect (other than
1130 * inserting a zero-length header) of the following
1134 offSet = ptr_len - remaining;
1135 asn_build_header(&ptr[offSet],
1137 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1138 ASN_OCTET_STR), msgAuthParmLen);
1140 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1141 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1142 offSet = ptr_len - remaining;
1143 memset(&ptr[offSet], 0, msgAuthParmLen);
1146 remaining -= msgAuthParmLen;
1150 * Note: if there is no encryption being done, msgPrivParmLen
1151 * is 0, and there is no effect (other than inserting a
1152 * zero-length header) of the following statements.
1155 offSet = ptr_len - remaining;
1156 asn_build_header(&ptr[offSet],
1158 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1159 ASN_OCTET_STR), msgPrivParmLen);
1161 remaining -= msgPrivParmLen; /* Skipping the IV already there. */
1165 * For privacy, need to add the octet string header for it.
1167 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1168 offSet = ptr_len - remaining;
1169 asn_build_header(&ptr[offSet],
1171 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1173 theTotalLength - dataOffset);
1178 * Adjust overall length and store it as the first SEQ length
1179 * of the SNMPv3Message.
1181 * FIX 4 is a magic number!
1183 remaining = theTotalLength;
1184 asn_build_sequence(ptr, &remaining,
1185 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1186 theTotalLength - 4);
1190 * Now, time to consider / do authentication.
1192 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1193 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1194 size_t temp_sig_len = msgAuthParmLen;
1195 u_char *temp_sig = (u_char *) malloc(temp_sig_len);
1197 if (temp_sig == NULL) {
1198 DEBUGMSGTL(("usm", "Out of memory.\n"));
1199 usm_free_usmStateReference(secStateRef);
1200 return SNMPERR_USM_GENERICERROR;
1203 if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
1204 theAuthKey, theAuthKeyLength,
1205 ptr, ptr_len, temp_sig, &temp_sig_len)
1206 != SNMP_ERR_NOERROR) {
1208 * FIX temp_sig_len defined?!
1210 SNMP_ZERO(temp_sig, temp_sig_len);
1211 SNMP_FREE(temp_sig);
1212 DEBUGMSGTL(("usm", "Signing failed.\n"));
1213 usm_free_usmStateReference(secStateRef);
1214 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1217 if (temp_sig_len != msgAuthParmLen) {
1218 SNMP_ZERO(temp_sig, temp_sig_len);
1219 SNMP_FREE(temp_sig);
1220 DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
1221 usm_free_usmStateReference(secStateRef);
1222 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1225 memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen);
1227 SNMP_ZERO(temp_sig, temp_sig_len);
1228 SNMP_FREE(temp_sig);
1233 * endif -- create keyed hash
1235 usm_free_usmStateReference(secStateRef);
1237 DEBUGMSGTL(("usm", "USM processing completed.\n"));
1239 return SNMPERR_SUCCESS;
1241 } /* end usm_generate_out_msg() */
1243 #ifdef USE_REVERSE_ASNENCODING
1245 usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
1248 return SNMPERR_GENERR;
1250 return usm_rgenerate_out_msg(parms->msgProcModel,
1251 parms->globalData, parms->globalDataLen,
1252 parms->maxMsgSize, parms->secModel,
1253 parms->secEngineID, parms->secEngineIDLen,
1254 parms->secName, parms->secNameLen,
1256 parms->scopedPdu, parms->scopedPduLen,
1258 parms->wholeMsg, parms->wholeMsgLen,
1259 parms->wholeMsgOffset);
1263 usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */
1264 u_char * globalData, /* IN */
1266 * points at the msgGlobalData, which is of length given by next
1269 size_t globalDataLen, /* IN - Length of msg header data. */
1270 int maxMsgSize, /* (UNUSED) */
1271 int secModel, /* (UNUSED) */
1272 u_char * secEngineID, /* IN - Pointer snmpEngineID. */
1273 size_t secEngineIDLen, /* IN - SnmpEngineID length. */
1274 char *secName, /* IN - Pointer to securityName. */
1275 size_t secNameLen, /* IN - SecurityName length. */
1276 int secLevel, /* IN - AuthNoPriv, authPriv etc. */
1277 u_char * scopedPdu, /* IN */
1279 * Pointer to scopedPdu will be encrypted by USM if needed
1280 * * and written to packet buffer immediately following
1281 * * securityParameters, entire msg will be authenticated by
1284 size_t scopedPduLen, /* IN - scopedPdu length. */
1285 void *secStateRef, /* IN */
1287 * secStateRef, pointer to cached info provided only for
1288 * * Response, otherwise NULL.
1290 u_char ** wholeMsg, /* IN/OUT */
1292 * Points at the pointer to the packet buffer, which might get extended
1293 * if necessary via realloc().
1295 size_t * wholeMsgLen, /* IN/OUT */
1297 * Length of the entire packet buffer, **not** the length of the
1300 size_t * offset /* IN/OUT */
1302 * Offset from the end of the packet buffer to the start of the packet,
1303 * also known as the packet length.
1307 size_t msgAuthParmLen = 0;
1308 #ifdef SNMP_TESTING_CODE
1309 size_t theTotalLength;
1318 * Indirection because secStateRef values override parameters.
1320 * None of these are to be free'd - they are either pointing to
1321 * what's in the secStateRef or to something either in the
1322 * actual prarmeter list or the user list.
1325 char *theName = NULL;
1326 u_int theNameLength = 0;
1327 u_char *theEngineID = NULL;
1328 u_int theEngineIDLength = 0;
1329 u_char *theAuthKey = NULL;
1330 u_int theAuthKeyLength = 0;
1331 const oid *theAuthProtocol = NULL;
1332 u_int theAuthProtocolLength = 0;
1333 u_char *thePrivKey = NULL;
1334 u_int thePrivKeyLength = 0;
1335 const oid *thePrivProtocol = NULL;
1336 u_int thePrivProtocolLength = 0;
1337 int theSecLevel = 0; /* No defined const for bad
1338 * value (other then err). */
1339 size_t salt_length = 0, save_salt_length = 0, save_salt_offset = 0;
1340 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
1341 u_char authParams[USM_MAX_AUTHSIZE];
1342 u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
1343 size_t sp_offset = 0, mac_offset = 0;
1346 DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", *offset));
1348 if (secStateRef != NULL) {
1350 * To hush the compiler for now. XXX
1352 struct usmStateReference *ref
1353 = (struct usmStateReference *) secStateRef;
1355 theName = ref->usr_name;
1356 theNameLength = ref->usr_name_length;
1357 theEngineID = ref->usr_engine_id;
1358 theEngineIDLength = ref->usr_engine_id_length;
1360 if (!theEngineIDLength) {
1361 theEngineID = secEngineID;
1362 theEngineIDLength = secEngineIDLen;
1365 theAuthProtocol = ref->usr_auth_protocol;
1366 theAuthProtocolLength = ref->usr_auth_protocol_length;
1367 theAuthKey = ref->usr_auth_key;
1368 theAuthKeyLength = ref->usr_auth_key_length;
1369 thePrivProtocol = ref->usr_priv_protocol;
1370 thePrivProtocolLength = ref->usr_priv_protocol_length;
1371 thePrivKey = ref->usr_priv_key;
1372 thePrivKeyLength = ref->usr_priv_key_length;
1373 theSecLevel = ref->usr_sec_level;
1377 * * Identify the user record.
1380 struct usmUser *user;
1383 * we do allow an unknown user name for
1384 * unauthenticated requests.
1386 if ((user = usm_get_user(secEngineID, secEngineIDLen, secName))
1387 == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) {
1388 DEBUGMSGTL(("usm", "Unknown User\n"));
1389 usm_free_usmStateReference(secStateRef);
1390 return SNMPERR_USM_UNKNOWNSECURITYNAME;
1394 theNameLength = secNameLen;
1395 theEngineID = secEngineID;
1396 theSecLevel = secLevel;
1397 theEngineIDLength = secEngineIDLen;
1399 theAuthProtocol = user->authProtocol;
1400 theAuthProtocolLength = user->authProtocolLen;
1401 theAuthKey = user->authKey;
1402 theAuthKeyLength = user->authKeyLen;
1403 thePrivProtocol = user->privProtocol;
1404 thePrivProtocolLength = user->privProtocolLen;
1405 thePrivKey = user->privKey;
1406 thePrivKeyLength = user->privKeyLen;
1409 * unknown users can not do authentication (obviously)
1411 theAuthProtocol = usmNoAuthProtocol;
1412 theAuthProtocolLength =
1413 sizeof(usmNoAuthProtocol) / sizeof(oid);
1415 theAuthKeyLength = 0;
1416 thePrivProtocol = usmNoPrivProtocol;
1417 thePrivProtocolLength =
1418 sizeof(usmNoPrivProtocol) / sizeof(oid);
1420 thePrivKeyLength = 0;
1422 } /* endif -- secStateRef==NULL */
1426 * From here to the end of the function, avoid reference to
1427 * secName, secEngineID, secLevel, and associated lengths.
1432 * Check to see if the user can use the requested sec services.
1434 if (usm_check_secLevel_vs_protocols(theSecLevel,
1436 theAuthProtocolLength,
1438 thePrivProtocolLength) == 1) {
1439 DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n",
1442 usm_free_usmStateReference(secStateRef);
1443 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
1448 * * Retrieve the engine information.
1450 * * XXX No error is declared in the EoP when sending messages to
1451 * * unknown engines, processing continues w/ boots/time == (0,0).
1453 if (get_enginetime(theEngineID, theEngineIDLength,
1454 &boots_uint, &time_uint, FALSE) == -1) {
1455 DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data."));
1458 boots_long = boots_uint;
1459 time_long = time_uint;
1461 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1463 * Initially assume that the ciphertext will end up the same size as
1464 * the plaintext plus some padding. Really sc_encrypt ought to be able
1465 * to grow this for us, a la asn_realloc_rbuild_<type> functions, but
1466 * this will do for now.
1468 u_char *ciphertext = NULL;
1469 size_t ciphertextlen = scopedPduLen + 64;
1471 if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) {
1473 "couldn't malloc %d bytes for encrypted PDU\n",
1475 usm_free_usmStateReference(secStateRef);
1476 return SNMPERR_MALLOC;
1480 * XXX Hardwired to seek into a 1DES private key!
1483 if (ISTRANSFORM(thePrivProtocol, AES128Priv) ||
1484 ISTRANSFORM(thePrivProtocol, AES192Priv) ||
1485 ISTRANSFORM(thePrivProtocol, AES256Priv)) {
1486 salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
1487 save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
1488 save_salt_offset = 0;
1490 usm_set_aes_iv(salt, &salt_length,
1491 htonl(boots_uint), htonl(time_uint),
1493 DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
1494 usm_free_usmStateReference(secStateRef);
1496 return SNMPERR_USM_GENERICERROR;
1498 } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
1500 salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
1501 save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
1502 save_salt_offset = 0;
1503 if (!thePrivKey || (usm_set_salt(salt, &salt_length,
1505 thePrivKeyLength - 8,
1507 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
1508 usm_free_usmStateReference(secStateRef);
1510 return SNMPERR_USM_GENERICERROR;
1515 #ifdef SNMP_TESTING_CODE
1516 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1517 dump_chunk("usm/dump", "This data was encrypted:",
1518 scopedPdu, scopedPduLen);
1522 if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
1523 thePrivKey, thePrivKeyLength,
1525 scopedPdu, scopedPduLen,
1526 ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) {
1527 DEBUGMSGTL(("usm", "DES-CBC error.\n"));
1528 usm_free_usmStateReference(secStateRef);
1530 return SNMPERR_USM_ENCRYPTIONERROR;
1534 * Write the encrypted scopedPdu back into the packet buffer.
1537 #ifdef SNMP_TESTING_CODE
1538 theTotalLength = *wholeMsgLen;
1541 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1542 (u_char) (ASN_UNIVERSAL |
1545 ciphertext, ciphertextlen);
1546 #ifdef SNMP_TESTING_CODE
1547 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
1548 dump_chunk("usm/dump", "salt + Encrypted form: ", salt,
1550 dump_chunk("usm/dump", "wholeMsg:",
1551 (*wholeMsg + *wholeMsgLen - *offset), *offset);
1555 DEBUGMSGTL(("usm", "Encryption successful.\n"));
1559 * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV
1564 * Start encoding the msgSecurityParameters.
1567 sp_offset = *offset;
1569 DEBUGDUMPHEADER("send", "msgPrivacyParameters");
1571 * msgPrivacyParameters (warning: assumes DES salt).
1573 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1574 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1580 DEBUGMSGTL(("usm", "building privParams failed.\n"));
1581 usm_free_usmStateReference(secStateRef);
1582 return SNMPERR_TOO_LONG;
1585 DEBUGDUMPHEADER("send", "msgAuthenticationParameters");
1587 * msgAuthenticationParameters (warnings assumes 0x00 by 12).
1589 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
1590 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1591 memset(authParams, 0, USM_MD5_AND_SHA_AUTH_LEN);
1592 msgAuthParmLen = USM_MD5_AND_SHA_AUTH_LEN;
1595 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1596 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1597 | ASN_OCTET_STR), authParams,
1601 DEBUGMSGTL(("usm", "building authParams failed.\n"));
1602 usm_free_usmStateReference(secStateRef);
1603 return SNMPERR_TOO_LONG;
1607 * Remember where to put the actual HMAC we calculate later on. An
1608 * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1
1609 * header of length 2, hence the fudge factor.
1612 mac_offset = *offset - 2;
1617 DEBUGDUMPHEADER("send", "msgUserName");
1618 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1619 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1621 (u_char *) theName, theNameLength);
1624 DEBUGMSGTL(("usm", "building authParams failed.\n"));
1625 usm_free_usmStateReference(secStateRef);
1626 return SNMPERR_TOO_LONG;
1630 * msgAuthoritativeEngineTime.
1632 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime");
1633 rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
1634 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1635 ASN_INTEGER), &time_long,
1640 "building msgAuthoritativeEngineTime failed.\n"));
1641 usm_free_usmStateReference(secStateRef);
1642 return SNMPERR_TOO_LONG;
1646 * msgAuthoritativeEngineBoots.
1648 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots");
1649 rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1,
1650 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1651 ASN_INTEGER), &boots_long,
1656 "building msgAuthoritativeEngineBoots failed.\n"));
1657 usm_free_usmStateReference(secStateRef);
1658 return SNMPERR_TOO_LONG;
1661 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID");
1662 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
1663 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1664 | ASN_OCTET_STR), theEngineID,
1668 DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n"));
1669 usm_free_usmStateReference(secStateRef);
1670 return SNMPERR_TOO_LONG;
1674 * USM msgSecurityParameters sequence header
1676 rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
1677 (u_char) (ASN_SEQUENCE |
1679 *offset - sp_offset);
1681 DEBUGMSGTL(("usm", "building usm security parameters failed.\n"));
1682 usm_free_usmStateReference(secStateRef);
1683 return SNMPERR_TOO_LONG;
1687 * msgSecurityParameters OCTET STRING wrapper.
1689 rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
1690 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
1692 *offset - sp_offset);
1695 DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n"));
1696 usm_free_usmStateReference(secStateRef);
1697 return SNMPERR_TOO_LONG;
1701 * Copy in the msgGlobalData and msgVersion.
1703 while ((*wholeMsgLen - *offset) < globalDataLen) {
1704 if (!asn_realloc(wholeMsg, wholeMsgLen)) {
1705 DEBUGMSGTL(("usm", "building global data failed.\n"));
1706 usm_free_usmStateReference(secStateRef);
1707 return SNMPERR_TOO_LONG;
1711 *offset += globalDataLen;
1712 memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen);
1715 * Total packet sequence.
1717 rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
1718 (u_char) (ASN_SEQUENCE |
1719 ASN_CONSTRUCTOR), *offset);
1721 DEBUGMSGTL(("usm", "building master packet sequence failed.\n"));
1722 usm_free_usmStateReference(secStateRef);
1723 return SNMPERR_TOO_LONG;
1727 * Now consider / do authentication.
1730 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV ||
1731 theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1732 size_t temp_sig_len = msgAuthParmLen;
1733 u_char *temp_sig = (u_char *) malloc(temp_sig_len);
1734 u_char *proto_msg = *wholeMsg + *wholeMsgLen - *offset;
1735 size_t proto_msg_len = *offset;
1738 if (temp_sig == NULL) {
1739 DEBUGMSGTL(("usm", "Out of memory.\n"));
1740 usm_free_usmStateReference(secStateRef);
1741 return SNMPERR_USM_GENERICERROR;
1744 if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength,
1745 theAuthKey, theAuthKeyLength,
1746 proto_msg, proto_msg_len,
1747 temp_sig, &temp_sig_len)
1748 != SNMP_ERR_NOERROR) {
1749 SNMP_FREE(temp_sig);
1750 DEBUGMSGTL(("usm", "Signing failed.\n"));
1751 usm_free_usmStateReference(secStateRef);
1752 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1755 if (temp_sig_len != msgAuthParmLen) {
1756 SNMP_FREE(temp_sig);
1757 DEBUGMSGTL(("usm", "Signing lengths failed.\n"));
1758 usm_free_usmStateReference(secStateRef);
1759 return SNMPERR_USM_AUTHENTICATIONFAILURE;
1762 memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig,
1764 SNMP_FREE(temp_sig);
1767 * endif -- create keyed hash
1769 usm_free_usmStateReference(secStateRef);
1770 DEBUGMSGTL(("usm", "USM processing completed.\n"));
1771 return SNMPERR_SUCCESS;
1772 } /* end usm_rgenerate_out_msg() */
1778 /*******************************************************************-o-******
1779 * usm_parse_security_parameters
1782 * (See list below...)
1790 * Extracts values from the security header and data portions of the
1794 usm_parse_security_parameters(u_char * secParams,
1796 u_char * secEngineID,
1797 size_t * secEngineIDLen,
1801 size_t * secNameLen,
1803 size_t * signature_length,
1805 size_t * salt_length, u_char ** data_ptr)
1807 u_char *parse_ptr = secParams;
1812 size_t octet_string_length = remaining;
1813 size_t sequence_length;
1814 size_t remaining_bytes;
1823 * Eat the first octet header.
1825 if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length,
1827 (ASN_UNIVERSAL | ASN_PRIMITIVE |
1829 "usm first octet")) == NULL) {
1831 * RETURN parse error
1837 * Eat the sequence header.
1839 parse_ptr = value_ptr;
1840 sequence_length = octet_string_length;
1842 if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length,
1844 (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1845 "usm sequence")) == NULL) {
1847 * RETURN parse error
1853 * Retrieve the engineID.
1855 parse_ptr = value_ptr;
1856 remaining_bytes = sequence_length;
1858 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID");
1860 = asn_parse_string(parse_ptr, &remaining_bytes, &type_value,
1861 secEngineID, secEngineIDLen)) == NULL) {
1864 * RETURN parse error
1870 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1872 * RETURN parse error
1878 * Retrieve the engine boots, notice switch in the way next_ptr and
1879 * remaining_bytes are used (to accomodate the asn code).
1881 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots");
1882 if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
1883 &boots_long, sizeof(long))) == NULL) {
1886 * RETURN parse error
1892 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
1895 * RETURN parse error
1899 *boots_uint = (u_int) boots_long;
1903 * Retrieve the time value.
1905 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime");
1906 if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value,
1907 &time_long, sizeof(long))) == NULL) {
1909 * RETURN parse error
1915 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) {
1917 * RETURN parse error
1921 *time_uint = (u_int) time_long;
1925 * Retrieve the secName.
1927 origNameLen = *secNameLen;
1930 DEBUGDUMPHEADER("recv", "msgUserName");
1932 = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
1933 (u_char *) secName, secNameLen)) == NULL) {
1936 * RETURN parse error
1942 * FIX -- doesn't this also indicate a buffer overrun?
1944 if ((int) origNameLen < *secNameLen + 1) {
1946 * RETURN parse error, but it's really a parameter error
1951 if (*secNameLen > 32) {
1953 * This is a USM-specific limitation over and above the above
1954 * limitation (which will probably default to the length of an
1955 * SnmpAdminString, i.e. 255). See RFC 2574, sec. 2.4.
1960 secName[*secNameLen] = '\0';
1963 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1965 * RETURN parse error
1971 * Retrieve the signature and blank it if there.
1973 DEBUGDUMPHEADER("recv", "msgAuthenticationParameters");
1975 = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
1976 signature, signature_length)) == NULL) {
1979 * RETURN parse error
1985 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
1987 * RETURN parse error
1991 if (*signature_length != 0) { /* Blanking for authentication step later */
1992 memset(next_ptr - (u_long) * signature_length,
1993 0, *signature_length);
1998 * Retrieve the salt.
2000 * Note that the next ptr is where the data section starts.
2002 DEBUGDUMPHEADER("recv", "msgPrivacyParameters");
2004 = asn_parse_string(next_ptr, &remaining_bytes, &type_value,
2005 salt, salt_length)) == NULL) {
2008 * RETURN parse error
2014 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) {
2016 * RETURN parse error
2022 } /* end usm_parse_security_parameters() */
2027 /*******************************************************************-o-******
2028 * usm_check_and_update_timeliness
2042 * Performs the incoming timeliness checking and setting.
2045 usm_check_and_update_timeliness(u_char * secEngineID,
2046 size_t secEngineIDLen,
2048 u_int time_uint, int *error)
2050 u_char myID[USM_MAX_ID_LENGTH];
2052 snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH);
2058 if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) {
2060 * We're probably already screwed...buffer overwrite. XXX?
2062 DEBUGMSGTL(("usm", "Buffer overflow.\n"));
2063 *error = SNMPERR_USM_GENERICERROR;
2067 myBoots = snmpv3_local_snmpEngineBoots();
2068 myTime = snmpv3_local_snmpEngineTime();
2072 * IF the time involved is local
2073 * Make sure message is inside the time window
2075 * IF boots is higher or boots is the same and time is higher
2076 * remember this new data
2078 * IF !(boots same and time within USM_TIME_WINDOW secs)
2079 * Message is too old
2081 * Message is ok, but don't take time
2088 * This is a local reference.
2090 if ((int) secEngineIDLen == myIDLength
2091 && memcmp(secEngineID, myID, myIDLength) == 0) {
2092 u_int time_difference = myTime > time_uint ?
2093 myTime - time_uint : time_uint - myTime;
2095 if (boots_uint == ENGINEBOOT_MAX
2096 || boots_uint != myBoots
2097 || time_difference > USM_TIME_WINDOW) {
2098 if (snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS) ==
2100 DEBUGMSGTL(("usm", "%s\n",
2101 "Failed to increment statistic."));
2105 "boot_uint %u myBoots %u time_diff %u => not in time window\n",
2106 boots_uint, myBoots, time_difference));
2107 *error = SNMPERR_USM_NOTINTIMEWINDOW;
2111 *error = SNMPERR_SUCCESS;
2116 * This is a remote reference.
2119 u_int theirBoots, theirTime, theirLastTime;
2120 u_int time_difference;
2122 if (get_enginetime_ex(secEngineID, secEngineIDLen,
2123 &theirBoots, &theirTime,
2124 &theirLastTime, TRUE)
2125 != SNMPERR_SUCCESS) {
2126 DEBUGMSGTL(("usm", "%s\n",
2127 "Failed to get remote engine's times."));
2129 *error = SNMPERR_USM_GENERICERROR;
2133 time_difference = theirTime > time_uint ?
2134 theirTime - time_uint : time_uint - theirTime;
2138 * XXX Contrary to the pseudocode:
2139 * See if boots is invalid first.
2141 if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
2142 DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid."));
2144 *error = SNMPERR_USM_NOTINTIMEWINDOW;
2150 * Boots is ok, see if the boots is the same but the time
2153 if (theirBoots == boots_uint && time_uint < theirLastTime) {
2154 if (time_difference > USM_TIME_WINDOW) {
2155 DEBUGMSGTL(("usm", "%s\n", "Message too old."));
2156 *error = SNMPERR_USM_NOTINTIMEWINDOW;
2160 else { /* Old, but acceptable */
2162 *error = SNMPERR_SUCCESS;
2169 * Message is ok, either boots has been advanced, or
2170 * time is greater than before with the same boots.
2173 if (set_enginetime(secEngineID, secEngineIDLen,
2174 boots_uint, time_uint, TRUE)
2175 != SNMPERR_SUCCESS) {
2176 DEBUGMSGTL(("usm", "%s\n",
2177 "Failed updating remote boot/time."));
2178 *error = SNMPERR_USM_GENERICERROR;
2182 *error = SNMPERR_SUCCESS;
2183 return 0; /* Fresh message and time updated */
2185 } /* endif -- local or remote time reference. */
2188 } /* end usm_check_and_update_timeliness() */
2193 usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms)
2196 return SNMPERR_GENERR;
2198 return usm_process_in_msg(parms->msgProcModel,
2206 parms->secEngineIDLen,
2210 parms->scopedPduLen,
2211 parms->maxSizeResponse,
2213 parms->sess, parms->msg_flags);
2216 /*******************************************************************-o-******
2217 * usm_process_in_msg
2220 * (See list below...)
2223 * SNMPERR_SUCCESS On success.
2224 * SNMPERR_USM_AUTHENTICATIONFAILURE
2225 * SNMPERR_USM_DECRYPTIONERROR
2226 * SNMPERR_USM_GENERICERROR
2227 * SNMPERR_USM_PARSEERROR
2228 * SNMPERR_USM_UNKNOWNENGINEID
2229 * SNMPERR_USM_PARSEERROR
2230 * SNMPERR_USM_UNKNOWNSECURITYNAME
2231 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
2234 * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU.
2236 * FIX Memory leaks if secStateRef is allocated and a return occurs
2237 * without cleaning up. May contain secrets...
2240 usm_process_in_msg(int msgProcModel, /* (UNUSED) */
2241 size_t maxMsgSize, /* IN - Used to calc maxSizeResponse. */
2242 u_char * secParams, /* IN - BER encoded securityParameters. */
2243 int secModel, /* (UNUSED) */
2244 int secLevel, /* IN - AuthNoPriv, authPriv etc. */
2245 u_char * wholeMsg, /* IN - Original v3 message. */
2246 size_t wholeMsgLen, /* IN - Msg length. */
2247 u_char * secEngineID, /* OUT - Pointer snmpEngineID. */
2248 size_t * secEngineIDLen, /* IN/OUT - Len available, len returned. */
2250 * NOTE: Memory provided by caller.
2252 char *secName, /* OUT - Pointer to securityName. */
2253 size_t * secNameLen, /* IN/OUT - Len available, len returned. */
2254 u_char ** scopedPdu, /* OUT - Pointer to plaintext scopedPdu. */
2255 size_t * scopedPduLen, /* IN/OUT - Len available, len returned. */
2256 size_t * maxSizeResponse, /* OUT - Max size of Response PDU. */
2257 void **secStateRf, /* OUT - Ref to security state. */
2258 netsnmp_session * sess, /* IN - session which got the message */
2260 { /* IN - v3 Message flags. */
2261 size_t remaining = wholeMsgLen - (u_int)
2262 ((u_long) * secParams - (u_long) * wholeMsg);
2266 u_int net_boots, net_time;
2268 u_char signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
2269 size_t signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
2270 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
2271 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2272 u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
2273 u_int iv_length = BYTESIZE(USM_MAX_SALT_LENGTH);
2277 u_char *end_of_overhead;
2280 struct usmStateReference **secStateRef =
2281 (struct usmStateReference **) secStateRf;
2283 struct usmUser *user;
2286 DEBUGMSGTL(("usm", "USM processing begun...\n"));
2290 usm_free_usmStateReference(*secStateRef);
2291 *secStateRef = usm_malloc_usmStateReference();
2292 if (*secStateRef == NULL) {
2293 DEBUGMSGTL(("usm", "Out of memory.\n"));
2294 return SNMPERR_USM_GENERICERROR;
2300 * Make sure the *secParms is an OCTET STRING.
2301 * Extract the user name, engine ID, and security level.
2303 if ((rc = usm_parse_security_parameters(secParams, remaining,
2304 secEngineID, secEngineIDLen,
2305 &boots_uint, &time_uint,
2306 secName, secNameLen,
2307 signature, &signature_length,
2310 DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc));
2313 * This indicates a decryptionError.
2315 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
2317 DEBUGMSGTL(("usm", "%s\n",
2318 "Failed to increment statistic."));
2320 return SNMPERR_USM_DECRYPTIONERROR;
2322 if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
2323 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2325 return SNMPERR_USM_PARSEERROR;
2329 if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) {
2331 * pull these out now so reports can use them
2333 *scopedPdu = data_ptr;
2334 *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
2335 end_of_overhead = data_ptr;
2340 * Cache the name, engine ID, and security level,
2341 * * per step 2 (section 3.2)
2343 if (usm_set_usmStateReference_name
2344 (*secStateRef, secName, *secNameLen) == -1) {
2345 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name."));
2346 return SNMPERR_USM_GENERICERROR;
2349 if (usm_set_usmStateReference_engine_id
2350 (*secStateRef, secEngineID, *secEngineIDLen) == -1) {
2351 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id."));
2352 return SNMPERR_USM_GENERICERROR;
2355 if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) ==
2357 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level."));
2358 return SNMPERR_USM_GENERICERROR;
2364 * Locate the engine ID record.
2365 * If it is unknown, then either create one or note this as an error.
2367 if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE ||
2368 (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH &&
2369 (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) ||
2370 (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) {
2371 if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) {
2372 DEBUGMSGTL(("usm", "Unknown Engine ID.\n"));
2373 if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS) ==
2375 DEBUGMSGTL(("usm", "%s\n",
2376 "Failed to increment statistic."));
2378 return SNMPERR_USM_UNKNOWNENGINEID;
2381 if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen)
2382 != SNMPERR_SUCCESS) {
2383 DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record."));
2384 return SNMPERR_USM_GENERICERROR;
2391 * Locate the User record.
2392 * If the user/engine ID is unknown, report this as an error.
2394 if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen,
2396 (sess->isAuthoritative ==
2397 SNMP_SESS_AUTHORITATIVE) ? 0 : 1))
2399 DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName));
2400 if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES) == 0) {
2401 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2403 return SNMPERR_USM_UNKNOWNSECURITYNAME;
2408 * Make sure the security level is appropriate.
2410 if (usm_check_secLevel(secLevel, user) == 1) {
2411 DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n",
2413 if (snmp_increment_statistic
2414 (STAT_USMSTATSUNSUPPORTEDSECLEVELS) == 0) {
2415 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic."));
2417 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
2422 * Check the authentication credentials of the message.
2424 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
2425 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2426 if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen,
2427 user->authKey, user->authKeyLen,
2428 wholeMsg, wholeMsgLen,
2429 signature, signature_length)
2430 != SNMP_ERR_NOERROR) {
2431 DEBUGMSGTL(("usm", "Verification failed.\n"));
2432 if (snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS) == 0) {
2433 DEBUGMSGTL(("usm", "%s\n",
2434 "Failed to increment statistic."));
2436 return SNMPERR_USM_AUTHENTICATIONFAILURE;
2439 DEBUGMSGTL(("usm", "Verification succeeded.\n"));
2444 * Steps 10-11 user is already set - relocated before timeliness
2445 * check in case it fails - still save user data for response.
2447 * Cache the keys and protocol oids, per step 11 (s3.2).
2450 if (usm_set_usmStateReference_auth_protocol(*secStateRef,
2455 DEBUGMSGTL(("usm", "%s\n",
2456 "Couldn't cache authentication protocol."));
2457 return SNMPERR_USM_GENERICERROR;
2460 if (usm_set_usmStateReference_auth_key(*secStateRef,
2462 user->authKeyLen) == -1) {
2463 DEBUGMSGTL(("usm", "%s\n",
2464 "Couldn't cache authentiation key."));
2465 return SNMPERR_USM_GENERICERROR;
2468 if (usm_set_usmStateReference_priv_protocol(*secStateRef,
2473 DEBUGMSGTL(("usm", "%s\n",
2474 "Couldn't cache privacy protocol."));
2475 return SNMPERR_USM_GENERICERROR;
2478 if (usm_set_usmStateReference_priv_key(*secStateRef,
2480 user->privKeyLen) == -1) {
2481 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key."));
2482 return SNMPERR_USM_GENERICERROR;
2488 * Perform the timeliness/time manager functions.
2490 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
2491 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2492 if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen,
2493 boots_uint, time_uint,
2498 #ifdef LCD_TIME_SYNC_OPT
2500 * Cache the unauthenticated time to use in case we don't have
2501 * anything better - this guess will be no worse than (0,0)
2502 * that we normally use.
2505 set_enginetime(secEngineID, *secEngineIDLen,
2506 boots_uint, time_uint, FALSE);
2508 #endif /* LCD_TIME_SYNC_OPT */
2512 * If needed, decrypt the scoped PDU.
2514 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
2515 remaining = wholeMsgLen - (data_ptr - wholeMsg);
2517 if ((value_ptr = asn_parse_sequence(data_ptr, &remaining,
2519 (ASN_UNIVERSAL | ASN_PRIMITIVE
2521 "encrypted sPDU")) == NULL) {
2522 DEBUGMSGTL(("usm", "%s\n",
2523 "Failed while parsing encrypted sPDU."));
2524 if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) {
2525 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2527 usm_free_usmStateReference(*secStateRef);
2528 *secStateRef = NULL;
2529 return SNMPERR_USM_PARSEERROR;
2532 if (ISTRANSFORM(user->privProtocol, DESPriv)) {
2536 * "Before decryption, the encrypted data length is verified.
2537 * If the length of the OCTET STRING to be decrypted is not
2538 * an integral multiple of 8 octets, the decryption process
2539 * is halted and an appropriate exception noted."
2542 if (remaining % 8 != 0) {
2544 "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
2545 remaining, remaining % 8));
2546 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
2548 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2550 usm_free_usmStateReference(*secStateRef);
2551 *secStateRef = NULL;
2552 return SNMPERR_USM_DECRYPTIONERROR;
2555 end_of_overhead = value_ptr;
2558 * XOR the salt with the last (iv_length) bytes
2559 * of the priv_key to obtain the IV.
2561 iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
2562 for (i = 0; i < (int) iv_length; i++)
2563 iv[i] = salt[i] ^ user->privKey[iv_length + i];
2566 else if (ISTRANSFORM(user->privProtocol, AES128Priv) ||
2567 ISTRANSFORM(user->privProtocol, AES192Priv) ||
2568 ISTRANSFORM(user->privProtocol, AES256Priv)) {
2569 iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
2570 net_boots = ntohl(boots_uint);
2571 net_time = ntohl(time_uint);
2572 memcpy(iv, &net_boots, 4);
2573 memcpy(iv+4, &net_time, 4);
2574 memcpy(iv+8, salt, salt_length);
2578 if (sc_decrypt(user->privProtocol, user->privProtocolLen,
2579 user->privKey, user->privKeyLen,
2581 value_ptr, remaining, *scopedPdu, scopedPduLen)
2582 != SNMP_ERR_NOERROR) {
2583 DEBUGMSGTL(("usm", "%s\n", "Failed decryption."));
2584 if (snmp_increment_statistic
2585 (STAT_USMSTATSDECRYPTIONERRORS) == 0) {
2586 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
2588 return SNMPERR_USM_DECRYPTIONERROR;
2590 #ifdef SNMP_TESTING_CODE
2591 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
2592 dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining);
2593 dump_chunk("usm/dump", "salt + Encrypted form:",
2595 dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length);
2596 dump_chunk("usm/dump", "Decrypted chunk:",
2597 *scopedPdu, *scopedPduLen);
2602 * sPDU is plaintext.
2605 *scopedPdu = data_ptr;
2606 *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg);
2607 end_of_overhead = data_ptr;
2609 } /* endif -- PDU decryption */
2613 * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
2617 *maxSizeResponse = maxMsgSize - (int)
2618 ((u_long) end_of_overhead - (u_long) wholeMsg);
2621 DEBUGMSGTL(("usm", "USM processing completed.\n"));
2623 return SNMPERR_SUCCESS;
2625 } /* end usm_process_in_msg() */
2630 struct snmp_secmod_def *def;
2632 DEBUGMSGTL(("init_usm", "unit_usm: %d %d\n", usmNoPrivProtocol[0],
2633 usmNoPrivProtocol[1]));
2635 sc_init(); /* initalize scapi code */
2638 * register ourselves as a security service
2640 def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
2642 * XXX: def->init_sess_secmod move stuff from snmp_api.c
2644 def->encode_reverse = usm_secmod_rgenerate_out_msg;
2645 def->encode_forward = usm_secmod_generate_out_msg;
2646 def->decode = usm_secmod_process_in_msg;
2647 def->pdu_free_state_ref = usm_free_usmStateReference;
2648 register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def);
2650 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
2651 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
2652 init_usm_post_config, NULL);
2656 * initializations for the USM.
2658 * Should be called after the (engineid) configuration files have been read.
2660 * Set "arbitrary" portion of salt to a random number.
2663 init_usm_post_config(int majorid, int minorid, void *serverarg,
2666 size_t salt_integer_len = sizeof(salt_integer);
2668 if (sc_random((u_char *) & salt_integer, &salt_integer_len) !=
2670 DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
2671 salt_integer = (u_int) time(NULL);
2675 salt_integer_len = sizeof (salt_integer64_1);
2676 if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
2678 DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
2679 salt_integer64_1 = (u_int) time(NULL);
2681 salt_integer_len = sizeof (salt_integer64_1);
2682 if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
2684 DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
2685 salt_integer64_2 = (u_int) time(NULL);
2689 noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
2690 USM_LENGTH_OID_TRANSFORM,
2692 USM_LENGTH_OID_TRANSFORM);
2694 SNMP_FREE(noNameUser->engineID);
2695 noNameUser->engineIDLen = 0;
2697 return SNMPERR_SUCCESS;
2698 } /* end init_usm_post_config() */
2701 /*******************************************************************-o-******
2702 * usm_check_secLevel
2712 * Checks that a given security level is valid for a given user.
2715 usm_check_secLevel(int level, struct usmUser *user)
2718 DEBUGMSGTL(("comparex", "Comparing: %d %d ", usmNoPrivProtocol[0],
2719 usmNoPrivProtocol[1]));
2720 DEBUGMSGOID(("comparex", usmNoPrivProtocol,
2721 sizeof(usmNoPrivProtocol) / sizeof(oid)));
2722 DEBUGMSG(("comparex", "\n"));
2723 if (level == SNMP_SEC_LEVEL_AUTHPRIV
2724 && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen,
2726 sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
2728 DEBUGMSGTL(("usm", "Level: %d\n", level));
2729 DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2730 DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2731 DEBUGMSG(("usm", ", User Priv Protocol: "));
2732 DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2733 DEBUGMSG(("usm", "\n"));
2736 if ((level == SNMP_SEC_LEVEL_AUTHPRIV
2737 || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2740 (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol,
2741 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
2742 DEBUGMSGTL(("usm", "Level: %d\n", level));
2743 DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name));
2744 DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen));
2745 DEBUGMSG(("usm", ", User Priv Protocol: "));
2746 DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen));
2747 DEBUGMSG(("usm", "\n"));
2753 } /* end usm_check_secLevel() */
2758 /*******************************************************************-o-******
2759 * usm_check_secLevel_vs_protocols
2772 * Same as above but with explicitly named transform types instead of taking
2773 * from the usmUser structure.
2776 usm_check_secLevel_vs_protocols(int level,
2777 const oid * authProtocol,
2778 u_int authProtocolLen,
2779 const oid * privProtocol,
2780 u_int privProtocolLen)
2783 if (level == SNMP_SEC_LEVEL_AUTHPRIV
2786 (privProtocol, privProtocolLen, usmNoPrivProtocol,
2787 sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0)) {
2788 DEBUGMSGTL(("usm", "Level: %d\n", level));
2789 DEBUGMSGTL(("usm", "Auth Protocol: "));
2790 DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
2791 DEBUGMSG(("usm", ", Priv Protocol: "));
2792 DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
2793 DEBUGMSG(("usm", "\n"));
2796 if ((level == SNMP_SEC_LEVEL_AUTHPRIV
2797 || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2800 (authProtocol, authProtocolLen, usmNoAuthProtocol,
2801 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) {
2802 DEBUGMSGTL(("usm", "Level: %d\n", level));
2803 DEBUGMSGTL(("usm", "Auth Protocol: "));
2804 DEBUGMSGOID(("usm", authProtocol, authProtocolLen));
2805 DEBUGMSG(("usm", ", Priv Protocol: "));
2806 DEBUGMSGOID(("usm", privProtocol, privProtocolLen));
2807 DEBUGMSG(("usm", "\n"));
2813 } /* end usm_check_secLevel_vs_protocols() */
2819 * usm_get_user(): Returns a user from userList based on the engineID,
2820 * engineIDLen and name of the requested user.
2824 usm_get_user(u_char * engineID, size_t engineIDLen, char *name)
2826 DEBUGMSGTL(("usm", "getting user %s\n", name));
2827 return usm_get_user_from_list(engineID, engineIDLen, name, userList,
2832 usm_get_user_from_list(u_char * engineID, size_t engineIDLen,
2833 char *name, struct usmUser *puserList,
2836 struct usmUser *ptr;
2840 for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
2841 if (!strcmp(ptr->name, name) &&
2842 ptr->engineIDLen == engineIDLen &&
2843 ((ptr->engineID == NULL && engineID == NULL) ||
2844 (ptr->engineID != NULL && engineID != NULL &&
2845 memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
2850 * return "" user used to facilitate engineID discovery
2852 if (use_default && !strcmp(name, ""))
2858 * usm_add_user(): Add's a user to the userList, sorted by the
2859 * engineIDLength then the engineID then the name length then the name
2860 * to facilitate getNext calls on a usmUser table which is indexed by
2863 * Note: userList must not be NULL (obviously), as thats a rather trivial
2864 * addition and is left to the API user.
2866 * returns the head of the list (which could change due to this add).
2870 usm_add_user(struct usmUser *user)
2872 struct usmUser *uptr;
2873 uptr = usm_add_user_to_list(user, userList);
2880 usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
2882 struct usmUser *nptr, *pptr;
2885 * loop through puserList till we find the proper, sorted place to
2886 * insert the new user
2888 for (nptr = puserList, pptr = NULL; nptr != NULL;
2889 pptr = nptr, nptr = nptr->next) {
2890 if (nptr->engineIDLen > user->engineIDLen)
2893 if (user->engineID == NULL && nptr->engineID != NULL)
2896 if (nptr->engineIDLen == user->engineIDLen &&
2897 (nptr->engineID != NULL && user->engineID != NULL &&
2898 memcmp(nptr->engineID, user->engineID,
2899 user->engineIDLen) > 0))
2902 if (!(nptr->engineID == NULL && user->engineID != NULL)) {
2903 if (nptr->engineIDLen == user->engineIDLen &&
2904 ((nptr->engineID == NULL && user->engineID == NULL) ||
2905 memcmp(nptr->engineID, user->engineID,
2906 user->engineIDLen) == 0)
2907 && strlen(nptr->name) > strlen(user->name))
2910 if (nptr->engineIDLen == user->engineIDLen &&
2911 ((nptr->engineID == NULL && user->engineID == NULL) ||
2912 memcmp(nptr->engineID, user->engineID,
2913 user->engineIDLen) == 0)
2914 && strlen(nptr->name) == strlen(user->name)
2915 && strcmp(nptr->name, user->name) > 0)
2918 if (nptr->engineIDLen == user->engineIDLen &&
2919 ((nptr->engineID == NULL && user->engineID == NULL) ||
2920 memcmp(nptr->engineID, user->engineID,
2921 user->engineIDLen) == 0)
2922 && strlen(nptr->name) == strlen(user->name)
2923 && strcmp(nptr->name, user->name) == 0)
2925 * the user is an exact match of a previous entry. Bail
2932 * nptr should now point to the user that we need to add ourselves
2933 * in front of, and pptr should be our new 'prev'.
2937 * change our pointers
2943 * change the next's prev pointer
2946 user->next->prev = user;
2949 * change the prev's next pointer
2952 user->prev->next = user;
2955 * rewind to the head of the list and return it (since the new head
2956 * could be us, we need to notify the above routine who the head now is.
2958 for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
2963 * usm_remove_user(): finds and removes a user from a list
2966 usm_remove_user(struct usmUser *user)
2968 return usm_remove_user_from_list(user, &userList);
2972 usm_remove_user_from_list(struct usmUser *user,
2973 struct usmUser **ppuserList)
2975 struct usmUser *nptr, *pptr;
2978 * NULL pointers aren't allowed
2980 if (ppuserList == NULL)
2984 * find the user in the list
2986 for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
2987 pptr = nptr, nptr = nptr->next) {
2994 * remove the user from the linked list
2997 pptr->next = nptr->next;
3000 nptr->next->prev = pptr;
3008 if (nptr == *ppuserList) /* we're the head of the list, need to change
3009 * * the head to the next user */
3010 *ppuserList = nptr->next;
3012 } /* end usm_remove_user_from_list() */
3018 * usm_free_user(): calls free() on all needed parts of struct usmUser and
3021 * Note: This should *not* be called on an object in a list (IE,
3022 * remove it from the list first, and set next and prev to NULL), but
3023 * will try to reconnect the list pieces again if it is called this
3024 * way. If called on the head of the list, the entire list will be
3028 usm_free_user(struct usmUser *user)
3033 SNMP_FREE(user->engineID);
3034 SNMP_FREE(user->name);
3035 SNMP_FREE(user->secName);
3036 SNMP_FREE(user->cloneFrom);
3037 SNMP_FREE(user->userPublicString);
3038 SNMP_FREE(user->authProtocol);
3039 SNMP_FREE(user->privProtocol);
3041 if (user->authKey != NULL) {
3042 SNMP_ZERO(user->authKey, user->authKeyLen);
3043 SNMP_FREE(user->authKey);
3046 if (user->privKey != NULL) {
3047 SNMP_ZERO(user->privKey, user->privKeyLen);
3048 SNMP_FREE(user->privKey);
3053 * FIX Why not put this check *first?*
3055 if (user->prev != NULL) { /* ack, this shouldn't happen */
3056 user->prev->next = user->next;
3058 if (user->next != NULL) {
3059 user->next->prev = user->prev;
3060 if (user->prev != NULL) /* ack this is really bad, because it means
3061 * * we'll loose the head of some structure tree */
3063 "Severe: Asked to free the head of a usmUser tree somewhere."));
3067 SNMP_ZERO(user, sizeof(*user));
3070 return NULL; /* for convenience to returns from calling functions */
3072 } /* end usm_free_user() */
3078 * take a given user and clone the security info into another
3081 usm_cloneFrom_user(struct usmUser *from, struct usmUser *to)
3084 * copy the authProtocol oid row pointer
3086 SNMP_FREE(to->authProtocol);
3088 if ((to->authProtocol =
3089 snmp_duplicate_objid(from->authProtocol,
3090 from->authProtocolLen)) != NULL)
3091 to->authProtocolLen = from->authProtocolLen;
3093 to->authProtocolLen = 0;
3099 SNMP_FREE(to->authKey);
3101 if (from->authKeyLen > 0 &&
3102 (to->authKey = (u_char *) malloc(from->authKeyLen))
3104 to->authKeyLen = from->authKeyLen;
3105 memcpy(to->authKey, from->authKey, to->authKeyLen);
3113 * copy the privProtocol oid row pointer
3115 SNMP_FREE(to->privProtocol);
3117 if ((to->privProtocol =
3118 snmp_duplicate_objid(from->privProtocol,
3119 from->privProtocolLen)) != NULL)
3120 to->privProtocolLen = from->privProtocolLen;
3122 to->privProtocolLen = 0;
3127 SNMP_FREE(to->privKey);
3129 if (from->privKeyLen > 0 &&
3130 (to->privKey = (u_char *) malloc(from->privKeyLen))
3132 to->privKeyLen = from->privKeyLen;
3133 memcpy(to->privKey, from->privKey, to->privKeyLen);
3142 * usm_create_user(void):
3143 * create a default empty user, instantiating only the auth/priv
3144 * protocols to noAuth and noPriv OID pointers
3147 usm_create_user(void)
3149 struct usmUser *newUser;
3152 * create the new user
3154 newUser = (struct usmUser *) calloc(1, sizeof(struct usmUser));
3155 if (newUser == NULL)
3159 * fill the auth/priv protocols
3161 if ((newUser->authProtocol =
3162 snmp_duplicate_objid(usmNoAuthProtocol,
3163 sizeof(usmNoAuthProtocol) / sizeof(oid))) ==
3165 return usm_free_user(newUser);
3166 newUser->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
3168 if ((newUser->privProtocol =
3169 snmp_duplicate_objid(usmNoPrivProtocol,
3170 sizeof(usmNoPrivProtocol) / sizeof(oid))) ==
3172 return usm_free_user(newUser);
3173 newUser->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
3176 * set the storage type to nonvolatile, and the status to ACTIVE
3178 newUser->userStorageType = ST_NONVOLATILE;
3179 newUser->userStatus = RS_ACTIVE;
3182 } /* end usm_clone_user() */
3188 * usm_create_initial_user(void):
3189 * creates an initial user, filled with the defaults defined in the
3193 usm_create_initial_user(const char *name,
3194 const oid * authProtocol, size_t authProtocolLen,
3195 const oid * privProtocol, size_t privProtocolLen)
3197 struct usmUser *newUser = usm_create_user();
3198 if (newUser == NULL)
3201 if ((newUser->name = strdup(name)) == NULL)
3202 return usm_free_user(newUser);
3204 if ((newUser->secName = strdup(name)) == NULL)
3205 return usm_free_user(newUser);
3207 if ((newUser->engineID =
3208 snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL)
3209 return usm_free_user(newUser);
3211 if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL)
3212 return usm_free_user(newUser);
3213 newUser->cloneFrom[0] = 0;
3214 newUser->cloneFrom[1] = 0;
3215 newUser->cloneFromLen = 2;
3217 SNMP_FREE(newUser->privProtocol);
3218 if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol,
3219 privProtocolLen)) ==
3221 return usm_free_user(newUser);
3223 newUser->privProtocolLen = privProtocolLen;
3225 SNMP_FREE(newUser->authProtocol);
3226 if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol,
3227 authProtocolLen)) ==
3229 return usm_free_user(newUser);
3231 newUser->authProtocolLen = authProtocolLen;
3233 newUser->userStatus = RS_ACTIVE;
3234 newUser->userStorageType = ST_READONLY;
3240 * this is a callback that can store all known users based on a
3241 * previously registered application ID
3244 usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg)
3247 * figure out our application name
3249 char *appname = (char *) clientarg;
3250 if (appname == NULL) {
3251 appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
3252 NETSNMP_DS_LIB_APPTYPE);
3256 * save the user base
3258 usm_save_users("usmUser", appname);
3263 return SNMPERR_SUCCESS;
3268 * usm_save_users(): saves a list of users to the persistent cache
3271 usm_save_users(const char *token, const char *type)
3273 usm_save_users_from_list(userList, token, type);
3277 usm_save_users_from_list(struct usmUser *puserList, const char *token,
3280 struct usmUser *uptr;
3281 for (uptr = puserList; uptr != NULL; uptr = uptr->next) {
3282 if (uptr->userStorageType == ST_NONVOLATILE)
3283 usm_save_user(uptr, token, type);
3288 * usm_save_user(): saves a user to the persistent cache
3291 usm_save_user(struct usmUser *user, const char *token, const char *type)
3296 memset(line, 0, sizeof(line));
3298 sprintf(line, "%s %d %d ", token, user->userStatus,
3299 user->userStorageType);
3300 cptr = &line[strlen(line)]; /* the NULL */
3302 read_config_save_octet_string(cptr, user->engineID,
3305 cptr = read_config_save_octet_string(cptr, (u_char *) user->name,
3306 (user->name == NULL) ? 0 :
3307 strlen(user->name) + 1);
3309 cptr = read_config_save_octet_string(cptr, (u_char *) user->secName,
3310 (user->secName == NULL) ? 0 :
3311 strlen(user->secName) + 1);
3314 read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen);
3316 cptr = read_config_save_objid(cptr, user->authProtocol,
3317 user->authProtocolLen);
3320 read_config_save_octet_string(cptr, user->authKey,
3323 cptr = read_config_save_objid(cptr, user->privProtocol,
3324 user->privProtocolLen);
3327 read_config_save_octet_string(cptr, user->privKey,
3330 cptr = read_config_save_octet_string(cptr, user->userPublicString,
3331 (user->userPublicString ==
3332 NULL) ? 0 : strlen((char *)
3336 read_config_store(type, line);
3340 * usm_parse_user(): reads in a line containing a saved user profile
3341 * and returns a pointer to a newly created struct usmUser.
3344 usm_read_user(char *line)
3346 struct usmUser *user;
3349 user = usm_create_user();
3353 user->userStatus = atoi(line);
3354 line = skip_token(line);
3355 user->userStorageType = atoi(line);
3356 line = skip_token(line);
3357 line = read_config_read_octet_string(line, &user->engineID,
3358 &user->engineIDLen);
3361 * set the lcd entry for this engineID to the minimum boots/time
3362 * values so that its a known engineid and won't return a report pdu.
3363 * This is mostly important when receiving v3 traps so that the usm
3364 * will at least continue processing them.
3366 set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0);
3368 line = read_config_read_octet_string(line, (u_char **) & user->name,
3370 line = read_config_read_octet_string(line, (u_char **) & user->secName,
3372 SNMP_FREE(user->cloneFrom);
3373 user->cloneFromLen = 0;
3376 read_config_read_objid(line, &user->cloneFrom,
3377 &user->cloneFromLen);
3379 SNMP_FREE(user->authProtocol);
3380 user->authProtocolLen = 0;
3382 line = read_config_read_objid(line, &user->authProtocol,
3383 &user->authProtocolLen);
3384 line = read_config_read_octet_string(line, &user->authKey,
3386 SNMP_FREE(user->privProtocol);
3387 user->privProtocolLen = 0;
3389 line = read_config_read_objid(line, &user->privProtocol,
3390 &user->privProtocolLen);
3391 line = read_config_read_octet_string(line, &user->privKey,
3393 line = read_config_read_octet_string(line, &user->userPublicString,
3399 * snmpd.conf parsing routines
3402 usm_parse_config_usmUser(const char *token, char *line)
3404 struct usmUser *uptr;
3406 uptr = usm_read_user(line);
3413 /*******************************************************************-o-******
3421 * format: userSetAuthPass secname engineIDLen engineID pass
3422 * or: userSetPrivPass secname engineIDLen engineID pass
3423 * or: userSetAuthKey secname engineIDLen engineID KuLen Ku
3424 * or: userSetPrivKey secname engineIDLen engineID KuLen Ku
3425 * or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul
3426 * or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul
3428 * type is: 1=passphrase; 2=Ku; 3=Kul.
3431 * ASSUMES Passwords are null-terminated printable strings.
3434 usm_set_password(const char *token, char *line)
3437 char nameBuf[SNMP_MAXBUF];
3440 struct usmUser *user;
3442 cp = copy_nword(line, nameBuf, sizeof(nameBuf));
3444 config_perror("invalid name specifier");
3448 DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING));
3449 if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) {
3451 * match against all engineIDs we know about
3453 cp = skip_token(cp);
3454 for (user = userList; user != NULL; user = user->next) {
3455 if (strcmp(user->secName, nameBuf) == 0) {
3456 usm_set_user_password(user, token, cp);
3460 cp = read_config_read_octet_string(cp, &engineID, &engineIDLen);
3462 config_perror("invalid engineID specifier");
3466 user = usm_get_user(engineID, engineIDLen, nameBuf);
3468 config_perror("not a valid user/engineID pair");
3471 usm_set_user_password(user, token, cp);
3476 * uses the rest of LINE to configure USER's password of type TOKEN
3479 usm_set_user_password(struct usmUser *user, const char *token, char *line)
3482 u_char *engineID = user->engineID;
3483 size_t engineIDLen = user->engineIDLen;
3487 u_char userKey[SNMP_MAXBUF_SMALL];
3488 size_t userKeyLen = SNMP_MAXBUF_SMALL;
3489 u_char *userKeyP = userKey;
3493 * Retrieve the "old" key and set the key type.
3495 if (strcmp(token, "userSetAuthPass") == 0) {
3496 key = &user->authKey;
3497 keyLen = &user->authKeyLen;
3499 } else if (strcmp(token, "userSetPrivPass") == 0) {
3500 key = &user->privKey;
3501 keyLen = &user->privKeyLen;
3503 } else if (strcmp(token, "userSetAuthKey") == 0) {
3504 key = &user->authKey;
3505 keyLen = &user->authKeyLen;
3507 } else if (strcmp(token, "userSetPrivKey") == 0) {
3508 key = &user->privKey;
3509 keyLen = &user->privKeyLen;
3511 } else if (strcmp(token, "userSetAuthLocalKey") == 0) {
3512 key = &user->authKey;
3513 keyLen = &user->authKeyLen;
3515 } else if (strcmp(token, "userSetPrivLocalKey") == 0) {
3516 key = &user->privKey;
3517 keyLen = &user->privKeyLen;
3521 * no old key, or token was not recognized
3528 * (destroy and) free the old key
3530 memset(*key, 0, *keyLen);
3536 * convert the password into a key
3538 ret = generate_Ku(user->authProtocol, user->authProtocolLen,
3539 (u_char *) cp, strlen(cp), userKey, &userKeyLen);
3541 if (ret != SNMPERR_SUCCESS) {
3542 config_perror("setting key failed (in sc_genKu())");
3545 } else if (type == 1) {
3546 cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen);
3549 config_perror("invalid user key");
3555 *key = (u_char *) malloc(SNMP_MAXBUF_SMALL);
3556 *keyLen = SNMP_MAXBUF_SMALL;
3557 ret = generate_kul(user->authProtocol, user->authProtocolLen,
3558 engineID, engineIDLen,
3559 userKey, userKeyLen, *key, keyLen);
3560 if (ret != SNMPERR_SUCCESS) {
3561 config_perror("setting key failed (in generate_kul())");
3566 * (destroy and) free the old key
3568 memset(userKey, 0, sizeof(userKey));
3572 * the key is given, copy it in
3574 cp = read_config_read_octet_string(cp, key, keyLen);
3577 config_perror("invalid localized user key");
3581 } /* end usm_set_password() */
3584 #endif /* BRCM_SNMP_MIB_SUPPORT (snmpv3) */