📄 snmpksm.c
字号:
/* * snmpksm.c * * This code implements the Kerberos Security Model (KSM) for SNMP. * * Security number - 2066432 */#include <net-snmp/net-snmp-config.h>#include <sys/types.h>#if HAVE_WINSOCK_H#include <winsock.h>#endif#include <stdio.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#if TIME_WITH_SYS_TIME# ifdef WIN32# include <sys/timeb.h># else# include <sys/time.h># endif# include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#if HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#include <errno.h>#if HAVE_DMALLOC_H#include <dmalloc.h>#endif#include <krb5.h>#include <com_err.h>#include <net-snmp/output_api.h>#include <net-snmp/config_api.h>#include <net-snmp/utilities.h>#include <net-snmp/library/asn1.h>#include <net-snmp/library/snmp_api.h>#include <net-snmp/library/callback.h>#include <net-snmp/library/keytools.h>#include <net-snmp/library/snmpv3.h>#include <net-snmp/library/lcd_time.h>#include <net-snmp/library/scapi.h>#include <net-snmp/library/callback.h>#include <net-snmp/library/snmp_secmod.h>#include <net-snmp/library/snmpksm.h>static krb5_context kcontext = NULL;static krb5_rcache rcache = NULL;static int ksm_session_init(netsnmp_session *);static void ksm_free_state_ref(void *);static int ksm_free_pdu(netsnmp_pdu *);static int ksm_clone_pdu(netsnmp_pdu *, netsnmp_pdu *);static int ksm_insert_cache(long, krb5_auth_context, u_char *, size_t);static void ksm_decrement_ref_count(long);static void ksm_increment_ref_count(long);static struct ksm_cache_entry *ksm_get_cache(long);#define HASHSIZE 64/* * Our information stored for the response PDU. */struct ksm_secStateRef { krb5_auth_context auth_context; krb5_cksumtype cksumtype;};/* * A KSM outgoing pdu cache entry */struct ksm_cache_entry { long msgid; int refcount; krb5_auth_context auth_context; u_char *secName; size_t secNameLen; struct ksm_cache_entry *next;};/* * Poor man's hash table */static struct ksm_cache_entry *ksm_hash_table[HASHSIZE];/* * Initialize all of the state required for Kerberos (right now, just call * krb5_init_context). */voidinit_ksm(void){ krb5_error_code retval; struct snmp_secmod_def *def; int i; if (kcontext == NULL) { retval = krb5_init_context(&kcontext); if (retval) { DEBUGMSGTL(("ksm", "krb5_init_context failed (%s), not " "registering KSM\n", error_message(retval))); return; } } for (i = 0; i < HASHSIZE; i++) ksm_hash_table[i] = NULL; def = SNMP_MALLOC_STRUCT(snmp_secmod_def); if (!def) { DEBUGMSGTL(("ksm", "Unable to malloc snmp_secmod struct, not " "registering KSM\n")); return; } def->encode_reverse = ksm_rgenerate_out_msg; def->decode = ksm_process_in_msg; def->session_open = ksm_session_init; def->pdu_free_state_ref = ksm_free_state_ref; def->pdu_free = ksm_free_pdu; def->pdu_clone = ksm_clone_pdu; register_sec_mod(2066432, "ksm", def);}/* * These routines implement a simple cache for information we need to * process responses. When we send out a request, it contains an AP_REQ; * we get back an AP_REP, and we need the authorization context from the * AP_REQ to decrypt the AP_REP. But because right now there's nothing * that gets preserved across calls to rgenerate_out_msg to process_in_msg, * we cache these internally based on the message ID (we also cache the * passed-in security name, for reasons that are mostly stupid). */static intksm_insert_cache(long msgid, krb5_auth_context auth_context, u_char * secName, size_t secNameLen){ struct ksm_cache_entry *entry; int bucket; int retval; entry = SNMP_MALLOC_STRUCT(ksm_cache_entry); if (!entry) return SNMPERR_MALLOC; entry->msgid = msgid; entry->auth_context = auth_context; entry->refcount = 1; retval = memdup(&entry->secName, secName, secNameLen); if (retval != SNMPERR_SUCCESS) { free(entry); return retval; } entry->secNameLen = secNameLen; bucket = msgid % HASHSIZE; entry->next = ksm_hash_table[bucket]; ksm_hash_table[bucket] = entry; return SNMPERR_SUCCESS;}static struct ksm_cache_entry *ksm_get_cache(long msgid){ struct ksm_cache_entry *entry; int bucket; bucket = msgid % HASHSIZE; for (entry = ksm_hash_table[bucket]; entry != NULL; entry = entry->next) if (entry->msgid == msgid) return entry; return NULL;}static voidksm_decrement_ref_count(long msgid){ struct ksm_cache_entry *entry, *entry1; int bucket; bucket = msgid % HASHSIZE; if (ksm_hash_table[bucket] && ksm_hash_table[bucket]->msgid == msgid) { entry = ksm_hash_table[bucket]; /* * If the reference count is zero, then free it */ if (--entry->refcount <= 0) { DEBUGMSGTL(("ksm", "Freeing entry for msgid %ld\n", msgid)); krb5_auth_con_free(kcontext, entry->auth_context); free(entry->secName); ksm_hash_table[bucket] = entry->next; free(entry); } return; } else if (ksm_hash_table[bucket]) for (entry1 = ksm_hash_table[bucket], entry = entry1->next; entry != NULL; entry1 = entry, entry = entry->next) if (entry->msgid == msgid) { if (--entry->refcount <= 0) { DEBUGMSGTL(("ksm", "Freeing entry for msgid %ld\n", msgid)); krb5_auth_con_free(kcontext, entry->auth_context); free(entry->secName); entry1->next = entry->next; free(entry); } return; } DEBUGMSGTL(("ksm", "KSM: Unable to decrement cache entry for msgid %ld.\n", msgid));}static voidksm_increment_ref_count(long msgid){ struct ksm_cache_entry *entry = ksm_get_cache(msgid); if (!entry) { DEBUGMSGTL(("ksm", "Unable to find cache entry for msgid %ld " "for increment\n", msgid)); return; } entry->refcount++;}/* * Initialize specific session information (right now, just set up things to * not do an engineID probe) */static intksm_session_init(netsnmp_session * sess){ DEBUGMSGTL(("ksm", "KSM: Reached our session initialization callback\n")); sess->flags |= SNMP_FLAGS_DONT_PROBE; return SNMPERR_SUCCESS;}/* * Free our state information (this is only done on the agent side) */static voidksm_free_state_ref(void *ptr){ struct ksm_secStateRef *ref = (struct ksm_secStateRef *) ptr; DEBUGMSGTL(("ksm", "KSM: Freeing state reference\n")); krb5_auth_con_free(kcontext, ref->auth_context); free(ref);}/* * This is called when the PDU is freed; this will decrement reference counts * for entries in our state cache. */static intksm_free_pdu(netsnmp_pdu *pdu){ ksm_decrement_ref_count(pdu->msgid); DEBUGMSGTL(("ksm", "Decrementing cache entry for PDU msgid %ld\n", pdu->msgid)); return SNMPERR_SUCCESS;}/* * This is called when a PDU is cloned (to increase reference counts) */static intksm_clone_pdu(netsnmp_pdu *pdu, netsnmp_pdu *pdu2){ ksm_increment_ref_count(pdu->msgid); DEBUGMSGTL(("ksm", "Incrementing cache entry for PDU msgid %ld\n", pdu->msgid)); return SNMPERR_SUCCESS;}/**************************************************************************** * * ksm_generate_out_msg * * Parameters: * (See list below...) * * Returns: * SNMPERR_GENERIC On success. * SNMPERR_KRB5 * ... and others * * * Generate an outgoing message. * ****************************************************************************/intksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms){ krb5_auth_context auth_context = NULL; krb5_error_code retcode; krb5_ccache cc = NULL; int retval = SNMPERR_SUCCESS; krb5_data outdata, ivector; krb5_keyblock *subkey = NULL;#ifdef MIT_NEW_CRYPTO krb5_data input; krb5_enc_data output;#else /* MIT_NEW_CRYPTO */ krb5_encrypt_block eblock;#endif /* MIT_NEW_CRYPTO */ size_t blocksize, encrypted_length; unsigned char *encrypted_data = NULL; int zero = 0, i; u_char *cksum_pointer, *endp = *parms->wholeMsg; krb5_cksumtype cksumtype = CKSUMTYPE_RSA_MD5_DES; krb5_checksum pdu_checksum; u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset, seq_offset; struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *) parms->secStateRef; int rc; DEBUGMSGTL(("ksm", "Starting KSM processing\n")); outdata.length = 0; outdata.data = NULL; ivector.length = 0; ivector.data = NULL; pdu_checksum.contents = NULL; if (!ksm_state) { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -