diff -up net-snmp-5.7.2/include/net-snmp/library/snmpusm.h.bz1809076 net-snmp-5.7.2/include/net-snmp/library/snmpusm.h --- net-snmp-5.7.2/include/net-snmp/library/snmpusm.h.bz1809076 2020-03-02 14:11:34.000000000 +0100 +++ net-snmp-5.7.2/include/net-snmp/library/snmpusm.h 2020-03-02 14:05:12.000000000 +0100 @@ -34,6 +34,7 @@ extern "C" { * Structures. */ struct usmStateReference { + int refcnt; char *usr_name; size_t usr_name_length; u_char *usr_engine_id; diff -up net-snmp-5.7.2/snmplib/snmp_client.c.bz1809076 net-snmp-5.7.2/snmplib/snmp_client.c --- net-snmp-5.7.2/snmplib/snmp_client.c.bz1809076 2020-03-02 14:11:27.000000000 +0100 +++ net-snmp-5.7.2/snmplib/snmp_client.c 2020-03-02 14:03:40.000000000 +0100 @@ -391,27 +391,16 @@ _clone_pdu_header(netsnmp_pdu *pdu) return NULL; } - if (pdu != NULL && pdu->securityStateRef && - pdu->command == SNMP_MSG_TRAP2) { - - ret = usm_clone_usmStateReference((struct usmStateReference *) pdu->securityStateRef, - (struct usmStateReference **) &newpdu->securityStateRef ); - - if (ret) - { + sptr = find_sec_mod(newpdu->securityModel); + if (sptr && sptr->pdu_clone) { + /* call security model if it needs to know about this */ + ret = sptr->pdu_clone(pdu, newpdu); + if (ret) { snmp_free_pdu(newpdu); return 0; } } - if ((sptr = find_sec_mod(newpdu->securityModel)) != NULL && - sptr->pdu_clone != NULL) { - /* - * call security model if it needs to know about this - */ - (*sptr->pdu_clone) (pdu, newpdu); - } - return newpdu; } diff -up net-snmp-5.7.2/snmplib/snmpusm.c.bz1809076 net-snmp-5.7.2/snmplib/snmpusm.c --- net-snmp-5.7.2/snmplib/snmpusm.c.bz1809076 2020-03-02 14:11:20.000000000 +0100 +++ net-snmp-5.7.2/snmplib/snmpusm.c 2020-03-02 14:08:30.000000000 +0100 @@ -192,43 +192,63 @@ free_enginetime_on_shutdown(int majorid, struct usmStateReference * usm_malloc_usmStateReference(void) { - struct usmStateReference *retval = (struct usmStateReference *) - calloc(1, sizeof(struct usmStateReference)); + struct usmStateReference *retval; + + retval = calloc(1, sizeof(struct usmStateReference)); + if (retval) + retval->refcnt = 1; return retval; } /* end usm_malloc_usmStateReference() */ +static int +usm_clone(netsnmp_pdu *pdu, netsnmp_pdu *new_pdu) +{ + struct usmStateReference *ref = pdu->securityStateRef; + struct usmStateReference **new_ref = + (struct usmStateReference **)&new_pdu->securityStateRef; + int ret = 0; + + if (!ref) + return ret; + + if (pdu->command == SNMP_MSG_TRAP2) { + netsnmp_assert(pdu->securityModel == SNMP_DEFAULT_SECMODEL); + ret = usm_clone_usmStateReference(ref, new_ref); + } else { + netsnmp_assert(ref == *new_ref); + ref->refcnt++; + } + + return ret; +} void usm_free_usmStateReference(void *old) { - struct usmStateReference *old_ref = (struct usmStateReference *) old; + struct usmStateReference *ref = old; - if (old_ref) { + if (!ref) + return; - if (old_ref->usr_name_length) - SNMP_FREE(old_ref->usr_name); - if (old_ref->usr_engine_id_length) - SNMP_FREE(old_ref->usr_engine_id); - if (old_ref->usr_auth_protocol_length) - SNMP_FREE(old_ref->usr_auth_protocol); - if (old_ref->usr_priv_protocol_length) - SNMP_FREE(old_ref->usr_priv_protocol); - - if (old_ref->usr_auth_key_length && old_ref->usr_auth_key) { - SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length); - SNMP_FREE(old_ref->usr_auth_key); - } - if (old_ref->usr_priv_key_length && old_ref->usr_priv_key) { - SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length); - SNMP_FREE(old_ref->usr_priv_key); - } + if (--ref->refcnt > 0) + return; - SNMP_ZERO(old_ref, sizeof(*old_ref)); - SNMP_FREE(old_ref); + SNMP_FREE(ref->usr_name); + SNMP_FREE(ref->usr_engine_id); + SNMP_FREE(ref->usr_auth_protocol); + SNMP_FREE(ref->usr_priv_protocol); + if (ref->usr_auth_key_length && ref->usr_auth_key) { + SNMP_ZERO(ref->usr_auth_key, ref->usr_auth_key_length); + SNMP_FREE(ref->usr_auth_key); + } + if (ref->usr_priv_key_length && ref->usr_priv_key) { + SNMP_ZERO(ref->usr_priv_key, ref->usr_priv_key_length); + SNMP_FREE(ref->usr_priv_key); } + SNMP_FREE(ref); } /* end usm_free_usmStateReference() */ struct usmUser * @@ -3184,6 +3204,7 @@ init_usm(void) def->encode_reverse = usm_secmod_rgenerate_out_msg; def->encode_forward = usm_secmod_generate_out_msg; def->decode = usm_secmod_process_in_msg; + def->pdu_clone = usm_clone; def->pdu_free_state_ref = usm_free_usmStateReference; def->session_setup = usm_session_init; def->handle_report = usm_handle_report;