snmp_api.c
资源名称:snmp.src.rar [点击查看]
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:144k
源码类别:
SNMP编程
开发平台:
C/C++
- /******************************************************************
- Copyright 1989, 1991, 1992 by Carnegie Mellon University
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of CMU not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- ******************************************************************/
- /*
- * snmp_api.c - API for access to snmp.
- */
- #include <config.h>
- #include <stdio.h>
- #include <ctype.h>
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <sys/types.h>
- #if HAVE_SYS_PARAM_H
- #include <sys/param.h>
- #endif
- #if TIME_WITH_SYS_TIME
- # ifdef WIN32
- # include <sys/timeb.h>
- # else
- # include <time.h>
- # endif
- # include <time.h>
- #else
- # if HAVE_SYS_TIME_H
- # include <sys/time.h>
- # else
- # include <time.h>
- # endif
- #endif
- #ifdef OS_VXWORKS
- #include <sys/times.h>
- #endif
- #if HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #if HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #if HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif
- #if HAVE_WINSOCK_H
- #include <ip/socket.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_SYS_UN_H
- #include <sys/un.h>
- #endif
- #if HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #if HAVE_NET_IF_DL_H
- #include <net/if_dl.h>
- #endif
- #include <errno.h>
- #if HAVE_LOCALE_H
- #include <locale.h>
- #endif
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- #include <ip/inet.h>
- #include "asn1.h"
- #include "snmp.h"
- #define SNMP_NEED_REQUEST_LIST
- #include "snmp_api.h"
- #include "snmp_client.h"
- #include "snmp_impl.h"
- #include "parse.h"
- #include "mib.h"
- #include "system.h"
- #include "int64.h"
- #include "snmpv3.h"
- #include "read_config.h"
- #include "snmp_debug.h"
- #include "callback.h"
- #include "snmpusm.h"
- #include "tools.h"
- #include "keytools.h"
- #include "lcd_time.h"
- #include "snmp_alarm.h"
- #include "snmp_logging.h"
- #include "default_store.h"
- #include "mt_support.h"
- #include <ip/netdb.h>
- #include <snmp/config_struct.h>
- static void _init_snmp (void);
- extern char *strdup (char*);
- extern ULONG snmp_source_ip;
- #include "transform_oids.h"
- #ifndef timercmp
- #define timercmp(tvp, uvp, cmp)
- /* CSTYLED */
- ((tvp)->tv_sec cmp (uvp)->tv_sec ||
- ((tvp)->tv_sec == (uvp)->tv_sec &&
- /* CSTYLED */
- (tvp)->tv_usec cmp (uvp)->tv_usec))
- #endif
- #ifndef timerclear
- #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
- #endif
- /*
- * Globals.
- */
- #define PACKET_LENGTH (8 * 1024)
- #define MAX_PACKET_LENGTH (32768)
- #ifndef SNMP_STREAM_QUEUE_LEN
- #define SNMP_STREAM_QUEUE_LEN 5
- #endif
- #ifndef BSD4_3
- #define BSD4_2
- #endif
- #ifndef FD_SET
- typedef long fd_mask;
- #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
- #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
- #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
- #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
- #define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
- #endif
- #define DEFAULT_COMMUNITY "public"
- #define DEFAULT_RETRIES 5
- #define DEFAULT_TIMEOUT 1000000L
- #define DEFAULT_REMPORT SNMP_PORT
- #define DEFAULT_ENTERPRISE default_enterprise
- #define DEFAULT_TIME 0
- /*
- * Internal information about the state of the snmp session.
- */
- struct snmp_internal_session {
- int sd; /* socket descriptor for this connection */
- struct soaddr addr; /* address of connected peer */
- struct soaddr me; /* address of local socket */
- struct request_list *requests;/* Info about outstanding requests */
- struct request_list *requestsEnd; /* ptr to end of list */
- int (*hook_pre) ( struct snmp_session*, struct soaddr);
- int (*hook_parse)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
- int (*hook_post) ( struct snmp_session*, struct snmp_pdu*, int );
- int (*hook_build)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
- int (*check_packet) ( u_char *, size_t );
- u_char *packet;
- long packet_len, proper_len;
- size_t packet_size;
- char newpkt;
- };
- /*
- * The list of active/open sessions.
- */
- struct session_list {
- struct session_list *next;
- struct snmp_session *session;
- struct snmp_internal_session *internal;
- };
- static const char *api_errors[-SNMPERR_MAX+1] = {
- "No error", /* SNMPERR_SUCCESS */
- "Generic error", /* SNMPERR_GENERR */
- "Invalid local port", /* SNMPERR_BAD_LOCPORT */
- "Unknown host", /* SNMPERR_BAD_ADDRESS */
- "Unknown session", /* SNMPERR_BAD_SESSION */
- "Too long", /* SNMPERR_TOO_LONG */
- "No socket", /* SNMPERR_NO_SOCKET */
- "Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
- "Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
- "Bad value for non-repeaters", /* SNMPERR_BAD_REPEATERS */
- "Bad value for max-repetitions", /* SNMPERR_BAD_REPETITIONS */
- "Error building ASN.1 representation", /* SNMPERR_BAD_ASN1_BUILD */
- "Failure in sendto", /* SNMPERR_BAD_SENDTO */
- "Bad parse of ASN.1 type", /* SNMPERR_BAD_PARSE */
- "Bad version specified", /* SNMPERR_BAD_VERSION */
- "Bad source party specified", /* SNMPERR_BAD_SRC_PARTY */
- "Bad destination party specified", /* SNMPERR_BAD_DST_PARTY */
- "Bad context specified", /* SNMPERR_BAD_CONTEXT */
- "Bad community specified", /* SNMPERR_BAD_COMMUNITY */
- "Cannot send noAuth/desPriv", /* SNMPERR_NOAUTH_DESPRIV */
- "Bad ACL definition", /* SNMPERR_BAD_ACL */
- "Bad Party definition", /* SNMPERR_BAD_PARTY */
- "Session abort failure", /* SNMPERR_ABORT */
- "Unknown PDU type", /* SNMPERR_UNKNOWN_PDU */
- "Timeout", /* SNMPERR_TIMEOUT */
- "Failure in recvfrom", /* SNMPERR_BAD_RECVFROM */
- "Unable to determine contextEngineID", /* SNMPERR_BAD_ENG_ID */
- "Unable to determine securityName", /* SNMPERR_BAD_SEC_NAME */
- "Unable to determine securityLevel", /* SNMPERR_BAD_SEC_LEVEL */
- "ASN.1 parse error in message", /* SNMPERR_ASN_PARSE_ERR */
- "Unknown security model in message", /* SNMPERR_UNKNOWN_SEC_MODEL */
- "Invalid message (e.g. msgFlags)", /* SNMPERR_INVALID_MSG */
- "Unknown engine ID", /* SNMPERR_UNKNOWN_ENG_ID */
- "Unknown user name", /* SNMPERR_UNKNOWN_USER_NAME */
- "Unsupported security level", /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
- "Authentication failure", /* SNMPERR_AUTHENTICATION_FAILURE */
- "Not in time window", /* SNMPERR_NOT_IN_TIME_WINDOW */
- "Decryption error", /* SNMPERR_DECRYPTION_ERR */
- "SCAPI general failure", /* SNMPERR_SC_GENERAL_FAILURE */
- "SCAPI sub-system not configured", /* SNMPERR_SC_NOT_CONFIGURED */
- "Key tools not available", /* SNMPERR_KT_NOT_AVAILABLE */
- "Unknown Report message", /* SNMPERR_UNKNOWN_REPORT */
- "USM generic error", /* SNMPERR_USM_GENERICERROR */
- "USM unknown security name", /* SNMPERR_USM_UNKNOWNSECURITYNAME */
- "USM unsupported security level", /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
- "USM encryption error", /* SNMPERR_USM_ENCRYPTIONERROR */
- "USM authentication failure", /* SNMPERR_USM_AUTHENTICATIONFAILURE */
- "USM parse error", /* SNMPERR_USM_PARSEERROR */
- "USM unknown engineID", /* SNMPERR_USM_UNKNOWNENGINEID */
- "USM not in time window", /* SNMPERR_USM_NOTINTIMEWINDOW */
- "USM decryption error", /* SNMPERR_USM_DECRYPTIONERROR */
- "MIB not initialized", /* SNMPERR_NOMIB */
- "Value out of range", /* SNMPERR_RANGE */
- "Sub-id out of range", /* SNMPERR_MAX_SUBID */
- "Bad sub-id in object identifier", /* SNMPERR_BAD_SUBID */
- "Object identifier too long", /* SNMPERR_LONG_OID */
- "Bad value name", /* SNMPERR_BAD_NAME */
- "Bad value notation", /* SNMPERR_VALUE */
- "Unknown Object Identifier", /* SNMPERR_UNKNOWN_OBJID */
- "No PDU in snmp_send", /* SNMPERR_NULL_PDU */
- "Missing variables in PDU", /* SNMPERR_NO_VARS */
- "Bad variable type", /* SNMPERR_VAR_TYPE */
- "Out of memory (malloc failure)", /* SNMPERR_MALLOC */
- "Bind VRF", /* SNMPERR_BIND_VRF */
- };
- static const char * usmSecLevelName[] =
- {
- "BAD_SEC_LEVEL",
- "noAuthNoPriv",
- "authNoPriv",
- "authPriv"
- };
- /*
- * Multiple threads may changes these variables.
- * Suggest using the Single API, which does not use Sessions.
- *
- * Reqid may need to be protected. Time will tell...
- *
- */
- /*MTCRITICAL_RESOURCE*/
- /* use token in comments to individually protect these resources */
- struct session_list *Sessions = NULL; /* MT_LIB_SESSION */
- static long Reqid = 0; /* MT_LIB_REQUESTID */
- static long Msgid = 0; /* MT_LIB_MESSAGEID */
- static long Sessid = 0; /* MT_LIB_SESSIONID */
- static long Transid = 0; /* MT_LIB_TRANSID */
- int snmp_errno = 0;
- /*END MTCRITICAL_RESOURCE*/
- /*struct timeval Now;*/
- /*
- * global error detail storage
- */
- static char snmp_detail[192];
- static int snmp_detail_f = 0;
- static char packet_buffer_read[PACKET_LENGTH];
- /*static char packet_buffer_send[PACKET_LENGTH];*/
- static char *snmp_current_community = NULL;
- /*
- * Prototypes.
- */
- int snmp_build (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
- static int snmp_parse (void *, struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
- static void * snmp_sess_pointer (struct snmp_session *);
- static void snmpv3_calc_msg_flags (int, int, u_char *);
- static int snmpv3_verify_msg (struct request_list *, struct snmp_pdu *);
- static int snmpv3_build_probe_pdu (struct snmp_pdu **);
- static int snmpv3_build (struct snmp_session *, struct snmp_pdu *,
- u_char *, size_t *);
- static int snmp_parse_version (u_char *, size_t);
- static int snmp_resend_request (struct session_list *slp,
- struct request_list *rp,
- int incr_retries);
- static void *trapdSessionPtr;
- #ifndef HAVE_STRERROR
- const char *strerror(int err)
- {
- extern const char *sys_errlist[];
- extern int sys_nerr;
- if (err < 0 || err >= sys_nerr) return "Unknown error";
- return sys_errlist[err];
- }
- #endif
- #ifndef SWITCH
- /*fanghao(A):2005-06-17*/
- extern int so_bind_udp_vrf_byname (int s, char *name, DEVICE_ID diID);
- extern int so_bind_udp_vrf_byid(int s, unsigned long vrf_id, DEVICE_ID diID);
- extern int udp_bind_localaddr(s, sa, namelen);
- #endif
- long
- snmp_get_next_reqid (void)
- {
- long retVal;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
- retVal = 1 + Reqid; /*MTCRITICAL_RESOURCE*/
- if (!retVal) retVal = 2;
- Reqid = retVal;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
- return retVal;
- }
- long
- snmp_get_next_msgid (void)
- {
- long retVal;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
- retVal = 1 + Msgid; /*MTCRITICAL_RESOURCE*/
- if (!retVal) retVal = 2;
- Msgid = retVal;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
- return retVal;
- }
- long
- snmp_get_next_sessid (void)
- {
- long retVal;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
- retVal = 1 + Sessid; /*MTCRITICAL_RESOURCE*/
- if (!retVal) retVal = 2;
- Sessid = retVal;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
- return retVal;
- }
- long
- snmp_get_next_transid (void)
- {
- long retVal;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
- retVal = 1 + Transid; /*MTCRITICAL_RESOURCE*/
- if (!retVal) retVal = 2;
- Transid = retVal;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
- return retVal;
- }
- void
- snmp_perror(const char *prog_string)
- {
- const char *str;
- int xerr;
- xerr = snmp_errno; /*MTCRITICAL_RESOURCE*/
- str = snmp_api_errstring(xerr);
- snmp_log(LOG_ERR,"%s: %sn",prog_string, str);
- }
- void
- snmp_set_detail(const char *detail_string)
- {
- if (detail_string != NULL) {
- strncpy((char *)snmp_detail, detail_string, sizeof(snmp_detail));
- snmp_detail[sizeof(snmp_detail)-1] = ' ';
- snmp_detail_f = 1;
- }
- }
- /* returns pointer to static data */
- /* results not guaranteed in multi-threaded use */
- const char *
- snmp_api_errstring(int snmp_errnumber)
- {
- const char *msg = "";
- static char msg_buf [256];
- if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
- msg = api_errors[-snmp_errnumber];
- } else if (snmp_errnumber != SNMPERR_SUCCESS) {
- msg = "Unknown Error";
- }
- if (snmp_detail_f) {
- sprintf (msg_buf, "%s (%s)", msg, snmp_detail);
- snmp_detail_f = 0;
- }
- else
- strcpy(msg_buf,msg);
- return (msg_buf);
- }
- /*
- * snmp_error - return error data
- * Inputs : address of errno, address of snmp_errno, address of string
- * Caller must free the string returned after use.
- */
- void
- snmp_error(struct snmp_session *psess,
- int *p_errno,
- int *p_snmp_errno,
- char **p_str)
- {
- char buf[SPRINT_MAX_LEN];
- int snmp_errnumber;
- if (p_errno) *p_errno = psess->s_errno;
- if (p_snmp_errno) *p_snmp_errno = psess->s_snmp_errno;
- if (p_str == NULL) return;
- strcpy(buf, "");
- snmp_errnumber = psess->s_snmp_errno;
- if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
- strcpy(buf, api_errors[-snmp_errnumber]);
- } else {
- if (snmp_errnumber)
- sprintf(buf, "Unknown Error %d", snmp_errnumber);
- }
- /* append a useful system errno interpretation. */
- if (psess->s_errno)
- sprintf (&buf[strlen(buf)], " (%s)", strerror(psess->s_errno));
- *p_str = strdup(buf);
- }
- /*
- * snmp_sess_error - same as snmp_error for single session API use.
- */
- void
- snmp_sess_error(void *sessp,
- int *p_errno,
- int *p_snmp_errno,
- char **p_str)
- {
- struct session_list *slp = (struct session_list*)sessp;
- if ((slp) && (slp->session))
- snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
- }
- /* snmp_sess_perror(): print a error stored in a session pointer */
- void
- snmp_sess_perror(const char *prog_string, struct snmp_session *ss) {
- char *err;
- snmp_error(ss, NULL, NULL, &err);
- if (err != NULL)
- {
- snmp_log(LOG_ERR, "%s: %sn", prog_string, err);
- free(err);
- }
- }
- /*
- * Primordial SNMP library initialization.
- * Initializes mutex locks.
- * Invokes minimum required initialization for displaying MIB objects.
- * Gets initial request ID for all transactions,
- * and finds which port SNMP over UDP uses.
- * SNMP over AppleTalk or IPX is not currently supported.
- *
- * Warning: no debug messages here.
- */
- static void
- _init_snmp (void)
- {
- #ifdef HAVE_GETSERVBYNAME
- struct servent *servp;
- #endif
- struct timeval tv;
- long tmpReqid, tmpMsgid;
- u_short s_port = SNMP_PORT;
- if (Reqid) return;
- Reqid = 1; /* quick set to avoid multiple inits */
- snmp_res_init(); /* initialize the mt locking structures */
- init_mib_internals();
- gettimeofday(&tv,(struct timezone *)0);
- /*Now = tv;*/
- /* get pseudo-random values for request ID and message ID */
- /* don't allow zero value to repeat init */
- #ifdef SVR4
- srand48(tv.tv_sec ^ tv.tv_usec);
- tmpReqid = lrand48();
- tmpMsgid = lrand48();
- #else
- srandom(tv.tv_sec ^ tv.tv_usec);
- tmpReqid = random();
- tmpMsgid = random();
- #endif
- if (tmpReqid == 0) tmpReqid = 1;
- if (tmpMsgid == 0) tmpMsgid = 1;
- Reqid = tmpReqid;
- Msgid = tmpMsgid;
- #ifdef HAVE_GETSERVBYNAME
- servp = getservbyname("snmp", "udp");
- if (servp) {
- /* store it in host byte order */
- s_port = ntohs(servp->s_port);
- }
- #endif
- ds_set_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT, s_port);
- }
- /*
- * Initializes the session structure.
- * May perform one time minimal library initialization.
- * No MIB file processing is done via this call.
- */
- void
- snmp_sess_init(struct snmp_session *session)
- {
- _init_snmp();
- /* initialize session to default values */
- memset(session, 0, sizeof(struct snmp_session));
- session->remote_port = SNMP_DEFAULT_REMPORT;
- session->timeout = SNMP_DEFAULT_TIMEOUT;
- session->retries = SNMP_DEFAULT_RETRIES;
- session->version = SNMP_DEFAULT_VERSION;
- }
- void
- register_default_handlers(void) {
- ds_register_config(ASN_BOOLEAN, "snmp","dumpPacket",
- DS_LIBRARY_ID, DS_LIB_DUMP_PACKET);
- ds_register_config(ASN_INTEGER, "snmp","defaultPort",
- DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
- ds_register_config(ASN_OCTET_STR, "snmp","defCommunity",
- DS_LIBRARY_ID, DS_LIB_COMMUNITY);
- ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
- DS_LIBRARY_ID, DS_LIB_NO_TOKEN_WARNINGS);
- ds_register_config(ASN_OCTET_STR, "snmp","noRangeCheck",
- DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE );
- }
- /*******************************************************************-o-******
- * init_snmp
- *
- * Parameters:
- * *type Label for the config file "type" used by calling entity.
- *
- * Call appropriately the functions to do config file loading and
- * mib module parsing in the correct order.
- */
- void
- init_snmp(const char *type)
- {
- static int done_init = 0; /* To prevent double init's. */
- if (done_init) {
- return;
- }
- done_init = 1;
- _init_snmp();
- /* set our current locale properly to initialize isprint() type functions */
- #ifdef HAVE_SETLOCALE
- setlocale(LC_CTYPE, "");
- #endif
- if ( type != NULL )
- ds_set_string(DS_LIBRARY_ID, DS_LIB_APPTYPE, type);
- init_callbacks();
- snmp_init_statistics();
- register_mib_handlers();
- register_default_handlers();
- init_snmpv3(type);
- init_snmp_alarm();
- read_premib_configs();
- init_mib();
- #ifdef INCLUDE_SNMPV3
- read_configs();
- #endif
- } /* end init_snmp() */
- void
- snmp_store(const char *type) {
- DEBUGMSGTL(("snmp_store","storing stuff...n"));
- snmp_save_persistent(type);
- snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
- snmp_clean_persistent(type);
- }
- /* snmp_shutdown(const char *type):
- Parameters:
- *type Label for the config file "type" used by calling entity.
- Does the appropriate shutdown calls for the library, saving
- persistent data, clean up, etc...
- */
- void
- snmp_shutdown(const char *type) {
- snmp_store(type);
- snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
- snmp_close_sessions();
- }
- /*
- * Sets up the session with the snmp_session information provided
- * by the user. Then opens and binds the necessary UDP port.
- * A handle to the created session is returned (this is different than
- * the pointer passed to snmp_open()). On any error, NULL is returned
- * and snmp_errno is set to the appropriate error code.
- */
- struct snmp_session *
- snmp_open(struct snmp_session *session)
- {
- struct session_list *slp;
- slp = (struct session_list *)snmp_sess_open(session);
- if (!slp) return NULL;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
- slp->next = Sessions;
- Sessions = slp;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
- return (slp->session);
- }
- /* extended open */
- struct snmp_session *snmp_open_ex (
- struct snmp_session *session,
- int (*fpre_parse) (struct snmp_session *, struct soaddr),
- int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
- int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
- int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
- int (*fcheck) (u_char *, size_t )
- )
- {
- struct session_list *slp;
- slp = (struct session_list *)snmp_sess_open(session);
- if (!slp) return NULL;
- slp->internal->hook_pre = fpre_parse;
- slp->internal->hook_parse = fparse;
- slp->internal->hook_post = fpost_parse;
- slp->internal->hook_build = fbuild;
- slp->internal->check_packet = fcheck;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
- slp->next = Sessions;
- Sessions = slp;
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
- return (slp->session);
- }
- static struct session_list *
- _sess_copy( struct snmp_session *in_session)
- {
- struct session_list *slp;
- struct snmp_internal_session *isp;
- struct snmp_session *session;
- char *cp;
- u_char *ucp;
- size_t i;
- in_session->s_snmp_errno = 0;
- in_session->s_errno = 0;
- /* Copy session structure and link into list */
- slp = (struct session_list *)calloc(1,sizeof(struct session_list));
- if (slp == NULL) {
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- isp = (struct snmp_internal_session *)calloc(1,sizeof(struct snmp_internal_session));
- if (isp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- slp->internal = isp;
- slp->internal->sd = -1; /* mark it not set */
- slp->session = (struct snmp_session *)malloc(sizeof(struct snmp_session));
- if (slp->session == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memset (slp->session, 0, sizeof (struct snmp_session));
- memmove(slp->session, in_session, sizeof(struct snmp_session));
- session = slp->session;
- /* zero out pointers so if we have to free the session we wont free mem
- owned by in_session */
- session->peername = NULL;
- session->community = NULL;
- session->contextEngineID = NULL;
- session->contextName = NULL;
- session->securityEngineID = NULL;
- session->securityName = NULL;
- session->securityAuthProto = NULL;
- session->securityPrivProto = NULL;
- /*
- * session now points to the new structure that still contains pointers to
- * data allocated elsewhere. Some of this data is copied to space malloc'd
- * here, and the pointer replaced with the new one.
- */
- if (in_session->peername != NULL){
- session->peername = (char *)malloc(strlen(in_session->peername) + 1);
- if (session->peername == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- strcpy(session->peername, in_session->peername);
- }
- /* Fill in defaults if necessary */
- if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN)
- {
- ucp = (u_char *)malloc(1+in_session->community_len);
- if (ucp != NULL)
- {
- memmove(ucp, in_session->community, in_session->community_len);
- ucp[in_session->community_len] = ' ';
- }
- session->community_len = in_session->community_len;
- } else {
- if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_COMMUNITY)) != NULL)
- {
- session->community_len = strlen(cp);
- ucp = (u_char *)malloc(1+session->community_len);
- if (ucp)
- {
- memmove(ucp, cp, session->community_len);
- ucp[session->community_len] = ' ';
- }
- }
- else
- {
- #ifdef NO_ZEROLENGTH_COMMUNITY
- session->community_len = strlen(DEFAULT_COMMUNITY);
- ucp = (u_char *)malloc(1+session->community_len);
- if (ucp)
- {
- memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
- ucp[session->community_len] = ' ';
- }
- #else
- ucp = (u_char *)strdup("");
- #endif
- }
- }
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- session->community = ucp; /* replace pointer with pointer to new data */
- if (session->securityLevel <= 0)
- session->securityLevel = ds_get_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL);
- if (session->securityLevel == 0)
- session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
- if (in_session->securityAuthProtoLen > 0)
- {
- session->securityAuthProto =
- (oid*)malloc(in_session->securityAuthProtoLen * sizeof(oid));
- if (session->securityAuthProto == NULL)
- {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memmove(session->securityAuthProto, in_session->securityAuthProto,
- in_session->securityAuthProtoLen * sizeof(oid));
- }
- else if (get_default_authtype(&i) != NULL)
- {
- session->securityAuthProto =
- snmp_duplicate_objid(get_default_authtype(NULL), i);
- if (session->securityAuthProto == NULL)
- {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- session->securityAuthProtoLen = i;
- }
- if (in_session->securityPrivProtoLen > 0)
- {
- session->securityPrivProto =
- (oid*)malloc((unsigned)in_session->securityPrivProtoLen * sizeof(oid));
- if (session->securityPrivProto == NULL)
- {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memmove(session->securityPrivProto, in_session->securityPrivProto,
- in_session->securityPrivProtoLen * sizeof(oid));
- }
- else if (get_default_privtype(&i) != NULL)
- {
- session->securityPrivProto =
- snmp_duplicate_objid(get_default_privtype(NULL), i);
- if (session->securityPrivProto == NULL)
- {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- session->securityPrivProtoLen = i;
- }
- if (in_session->securityEngineIDLen > 0) {
- ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
- sizeof(u_char));
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memmove(ucp, in_session->securityEngineID,
- in_session->securityEngineIDLen * sizeof(u_char));
- session->securityEngineID = ucp;
- }
- if (in_session->contextEngineIDLen > 0) {
- ucp = (u_char*)malloc((unsigned)in_session->contextEngineIDLen *
- sizeof(u_char));
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memmove(ucp, in_session->contextEngineID,
- in_session->contextEngineIDLen * sizeof(u_char));
- session->contextEngineID = ucp;
- } else if (in_session->securityEngineIDLen > 0) {
- /* default contextEngineID to securityEngineIDLen if defined */
- ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
- sizeof(u_char));
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return(NULL);
- }
- memmove(ucp, in_session->securityEngineID,
- in_session->securityEngineIDLen * sizeof(u_char));
- session->contextEngineID = ucp;
- session->contextEngineIDLen = in_session->securityEngineIDLen;
- }
- if (in_session->contextName) {
- session->contextName = strdup(in_session->contextName);
- if (session->contextName == NULL) {
- snmp_sess_close(slp);
- return(NULL);
- }
- } else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_CONTEXT)) != NULL) {
- cp = strdup(cp);
- if (cp == NULL) {
- snmp_sess_close(slp);
- return(NULL);
- }
- session->contextName = cp;
- session->contextNameLen = strlen(cp);
- } else {
- cp = strdup(SNMP_DEFAULT_CONTEXT);
- session->contextName = cp;
- session->contextNameLen = strlen(cp);
- }
- if (in_session->securityName) {
- session->securityName = strdup(in_session->securityName);
- if (session->securityName == NULL) {
- snmp_sess_close(slp);
- return(NULL);
- }
- } else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_SECNAME)) != NULL) {
- cp = strdup(cp);
- if (cp == NULL) {
- snmp_sess_close(slp);
- return(NULL);
- }
- session->securityName = cp;
- session->securityNameLen = strlen(cp);
- }
- if ((in_session->securityAuthKeyLen <= 0) &&
- (cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_AUTHPASSPHRASE))) {
- session->securityAuthKeyLen = USM_AUTH_KU_LEN;
- if (generate_Ku(session->securityAuthProto,
- session->securityAuthProtoLen,
- (u_char*)cp, strlen(cp),
- session->securityAuthKey,
- &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
- snmp_set_detail("Error generating Ku from authentication pass phrase.");
- snmp_sess_close(slp);
- return NULL;
- }
- }
- if ((in_session->securityPrivKeyLen <= 0) &&
- (cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_PRIVPASSPHRASE))) {
- session->securityPrivKeyLen = USM_PRIV_KU_LEN;
- if (generate_Ku(session->securityAuthProto,
- session->securityAuthProtoLen,
- (u_char *)cp, strlen(cp),
- session->securityPrivKey,
- &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
- snmp_set_detail("Error generating Ku from privacy pass phrase.");
- snmp_sess_close(slp);
- return NULL;
- }
- }
- if (session->retries == SNMP_DEFAULT_RETRIES)
- session->retries = DEFAULT_RETRIES;
- if (session->timeout == SNMP_DEFAULT_TIMEOUT)
- session->timeout = DEFAULT_TIMEOUT;
- session->sessid = snmp_get_next_sessid();
- return( slp );
- }
- struct session_list *
- snmp_sess_copy( struct snmp_session *pss)
- {
- struct session_list * psl;
- psl = _sess_copy(pss);
- if ( !psl) {
- if ( !pss->s_snmp_errno)
- pss->s_snmp_errno = SNMPERR_GENERR;
- SET_SNMP_ERROR(pss->s_snmp_errno);
- }
- return psl;
- }
- /*******************************************************************-o-******
- * snmp_sess_open
- *
- * Parameters:
- * *in_session
- *
- * Returns:
- * Pointer to a session in the session list -OR- FIX -- right?
- * NULL on failure.
- *
- * The "spin-free" version of snmp_open.
- */
- static void *
- _sess_open(struct snmp_session *in_session)
- {
- struct session_list *slp;
- struct snmp_internal_session *isp;
- struct snmp_session *session;
- int sd;
- in_addr_t addr;
- struct soaddr_in *isp_addr = NULL, *meIp;
- #ifdef HAVE_GETHOSTBYNAME
- struct hostent *hp;
- #endif
- struct snmp_pdu *pdu, *response;
- int status;
- size_t i, addr_size;
- char *cp = NULL;
- in_session->s_snmp_errno = 0;
- in_session->s_errno = 0;
- if (Reqid == 0)
- _init_snmp();
- if ((slp = snmp_sess_copy( in_session )) == NULL )
- return( NULL );
- isp = slp->internal;
- session = slp->session;
- if ( isp->addr.sa_family == AF_UNSPEC ) {
- if ( session->peername && session->peername[0] == '/' ) {
- #ifdef AF_UNIX
- isp->addr.sa_family = AF_UNIX;
- strcpy( isp->addr.sa_data, session->peername);
- #else /* AF_UNIX */
- snmp_log(LOG_ERR,"%s:%d: _sess_open invalid session name %s- unix sockets not supported n",
- __FILE__,__LINE__,
- session->peername);
- return(NULL);
- #endif /* AF_UNIX */
- } else {
- isp->addr.sa_family = AF_INET;
- isp_addr = (struct soaddr_in *)&(isp->addr);
- if (session->peername != SNMP_DEFAULT_PEERNAME){
- /* Try and extract an appended port number */
- cp = strchr( session->peername, ':' );
- if ( cp ) {
- *cp = ' ';
- cp++;
- session->remote_port = (u_short)atoi( cp );
- if ( session->local_port ) /* i.e. server */
- session->local_port = session->remote_port;
- }
- /* Interpret the peername as an IP port ... */
- cp = strchr( session->peername, '.' );
- if ( !cp && (( i = atoi( session->peername )) != 0 )) {
- session->remote_port = (u_short)i;
- if ( session->local_port ) /* i.e. server */
- session->local_port = session->remote_port;
- }
- /* ... failing that, as an IP address ... */
- else if ((int)(addr = inet_addr(session->peername)) != -1){
- memmove(&isp_addr->sin_addr, &addr, sizeof(isp_addr->sin_addr));
- } else {
- /* .... failing that, as a hostname */
- #ifdef HAVE_GETHOSTBYNAME
- hp = gethostbyname(session->peername);
- if (hp == NULL){
- in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
- in_session->s_errno = errno;
- snmp_set_detail(session->peername);
- snmp_sess_close(slp);
- return 0;
- } else {
- memmove(&isp_addr->sin_addr, hp->h_addr, hp->h_length);
- }
- #else /* HAVE_GETHOSTBYNAME */
- snmp_log(LOG_ERR,"%s:%d: _sess_open do not have get host by name - cannot resolve %s n",
- __FILE__,__LINE__,
- session->peername);
- return(0);
- #endif /* HAVE_GETHOSTBYNAME */
- }
- if (session->remote_port == (u_short)SNMP_DEFAULT_REMPORT){
- short iport = (short)ds_get_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
- isp_addr->sin_port = htons(iport);
- } else {
- isp_addr->sin_port = htons(session->remote_port);
- }
- } else {
- isp_addr->sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
- }
- }
- }
- isp_addr->sin_len = sizeof(struct soaddr_in);
- if ( session->local_port ) {
- /*
- * If the session structure includes a non-null value for
- * local_port, then this session is intended as a server.
- * This means that the isp->addr structure will not be
- * needed to contact a remote entity.
- *
- * By using this address as the local address to bind to,
- * we can provide a facility for listening on selected
- * (rather than all) interfaces.
- */
- memcpy( &isp->me, &isp->addr, sizeof(isp->me));
- if ( isp->addr.sa_family == AF_INET ) {
- /*
- * Remember to use the specified local port,
- * rather than the (default?) remote one.
- * If no local interface address is specified,
- * default to listening on all interfaces,
- * rather than the default connection host
- * (SNMP_DEFAULT_ADDRESS)
- */
- meIp = (struct soaddr_in*)&(isp->me);
- meIp->sin_port = htons(session->local_port);
- if (session->peername == SNMP_DEFAULT_PEERNAME)
- meIp->sin_addr.s_addr = htonl(snmp_source_ip);/*INADDR_ANY;*/
- }
- }
- else {
- memset(&isp->me, ' ', sizeof(isp->me));
- isp->me.sa_family = isp->addr.sa_family;
- if ( isp->me.sa_family == AF_INET ) {
- meIp = (struct soaddr_in*)&(isp->me);
- meIp->sin_addr.s_addr = htonl(snmp_source_ip);/*INADDR_ANY;*/
- meIp->sin_port = htons(session->local_port);
- }
- #ifdef AF_UNIX
- else if ( isp->me.sa_family == AF_UNIX ) {
- /* Need a unique socket name */
- #ifndef UNIX_SOCKET_BASE_NAME
- #define UNIX_SOCKET_BASE_NAME "/tmp/s."
- #endif
- #ifdef UCD_SNMP
- #ifndef WIN32
- strcpy( isp->me.sa_data, UNIX_SOCKET_BASE_NAME );
- strcat( isp->me.sa_data, "XXXXXX" );
- mktemp( isp->me.sa_data );
- #endif
- #endif
- }
- #endif /* AF_UNIX */
- }
- addr_size = snmp_socket_length(isp->me.sa_family);
- /* Set up connections */
- sd = so_socket(isp->me.sa_family, SOCK_DGRAM, 0);
- /*fanghao(A):2005-06-17*/
- if( sd > 0 ){
- int value=1;
- so_setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value));
- so_setsockopt(sd,SOL_SOCKET,SO_REUSEPORT,&value,sizeof(value));
- }
- if (sd < 0){
- in_session->s_snmp_errno = SNMPERR_NO_SOCKET;
- in_session->s_errno = errno;
- snmp_set_detail(strerror(errno));
- snmp_sess_close(slp);
- return 0;
- }
- isp->sd = sd;
- #ifdef SO_BSDCOMPAT
- /* Patch for Linux. Without this, UDP packets that fail get an ICMP
- * response. Linux turns the failed ICMP response into an error message
- * and return value, unlike all other OS's.
- */
- {
- int one=1;
- so_setsockopt(sd, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
- }
- #endif /* SO_BSDCOMPAT */
- #ifndef SERVER_REQUIRES_CLIENT_SOCKET
- if (!(( session->flags & SNMP_FLAGS_STREAM_SOCKET ) &&
- #ifdef AF_UNIX
- ( isp->me.sa_family == AF_UNIX ) &&
- #endif /* AF_UNIX */
- ( session->local_port == 0 ))) {
- /* Client Unix-domain stream sockets don't need to 'bind' */
- #endif
- if (so_bind(sd, (struct soaddr *)&isp->me, (int)addr_size) != 0){
- in_session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
- in_session->s_errno = errno;
- snmp_set_detail(strerror(errno));
- snmp_sess_close(slp);
- return 0;
- }
- #ifndef SERVER_REQUIRES_CLIENT_SOCKET
- }
- #endif
- /* if we are opening a V3 session and we don't know engineID
- we must probe it - this must be done after the session is
- created and inserted in the list so that the response can
- handled correctly */
- if (session->version == SNMP_VERSION_3) {
- if (session->securityEngineIDLen == 0 &&
- (session->securityEngineIDLen & SNMP_FLAGS_DONT_PROBE) !=
- SNMP_FLAGS_DONT_PROBE) {
- if (snmpv3_build_probe_pdu(&pdu) == -1)
- {
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- in_session->s_errno = errno;
- snmp_set_detail(strerror(errno));
- snmp_sess_close(slp);
- return 0;
- }
- DEBUGMSGTL(("snmp_api","probing for engineID...n"));
- status = snmp_sess_synch_response(slp, pdu, &response);
- if ((response == NULL) && (status == STAT_SUCCESS)) status = STAT_ERROR;
- switch (status) {
- case STAT_SUCCESS:
- in_session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
- DEBUGMSGTL(("snmp_sess_open",
- "error: expected Report as response to probe: %s (%d)n",
- snmp_errstring(response->errstat), response->errstat));
- break;
- case STAT_ERROR: /* this is what we expected -> Report == STAT_ERROR */
- in_session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
- break;
- case STAT_TIMEOUT:
- in_session->s_snmp_errno = SNMPERR_TIMEOUT;
- default:
- DEBUGMSGTL(("snmp_sess_open",
- "unable to connect with remote engine: %s (%d)n",
- snmp_api_errstring(session->s_snmp_errno),
- session->s_snmp_errno));
- break;
- }
- if (slp->session->securityEngineIDLen == 0) {
- DEBUGMSGTL(("snmp_api","unable to determine remote engine IDn"));
- snmp_sess_close(slp);
- return NULL;
- }
- in_session->s_snmp_errno = SNMPERR_SUCCESS;
- if (snmp_get_do_debugging()) {
- DEBUGMSGTL(("snmp_sess_open", " probe found engineID: "));
- for(i = 0; i < slp->session->securityEngineIDLen; i++)
- DEBUGMSG(("snmp_sess_open", "%02x",
- slp->session->securityEngineID[i]));
- DEBUGMSG(("snmp_sess_open","n"));
- }
- }
- /* if boot/time supplied set it for this engineID */
- if (session->engineBoots || session->engineTime) {
- set_enginetime(session->securityEngineID, session->securityEngineIDLen,
- session->engineBoots, session->engineTime, TRUE);
- }
- if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
- in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME; /* XX?? */
- DEBUGMSGTL(("snmp_api","snmp_sess_open(): failed(2) to create a new user from sessionn"));
- snmp_sess_close(slp);
- return NULL;
- }
- }
- return (void *)slp;
- } /* end snmp_sess_open() */
- void *
- snmp_sess_open(struct snmp_session *pss)
- {
- void * pvoid;
- pvoid = _sess_open(pss);
- if ( !pvoid) {
- SET_SNMP_ERROR(pss->s_snmp_errno);
- }
- return pvoid;
- }
- /* create_user_from_session(struct snmp_session *session):
- creates a user in the usm table from the information in a session
- Parameters:
- session -- IN: pointer to the session to use when creating the user.
- Returns:
- SNMPERR_SUCCESS
- SNMPERR_GENERR
- */
- int
- create_user_from_session(struct snmp_session *session)
- {
- struct usmUser *user;
- /* now that we have the engineID, create an entry in the USM list
- for this user using the information in the session */
- user = usm_get_user_from_list(session->securityEngineID,
- session->securityEngineIDLen,
- session->securityName,
- usm_get_userList(), 0);
- if (user == NULL) {
- DEBUGMSGTL(("snmp_api","Building user %s...n",session->securityName));
- /* user doesn't exist so we create and add it */
- user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
- if (user == NULL)
- return SNMPERR_GENERR;
- /* copy in the securityName */
- if (session->securityName) {
- user->name = strdup(session->securityName);
- user->secName = strdup(session->securityName);
- if (user->name == NULL || user->secName == NULL) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- }
- /* copy in the engineID */
- if (snmp_memdup(&user->engineID, session->securityEngineID,
- session->securityEngineIDLen) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->engineIDLen = session->securityEngineIDLen;
- /* copy the auth protocol */
- if (session->securityAuthProto != NULL) {
- user->authProtocol =
- snmp_duplicate_objid(session->securityAuthProto,
- session->securityAuthProtoLen);
- if (user->authProtocol == NULL) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->authProtocolLen = session->securityAuthProtoLen;
- }
- /* copy the priv protocol */
- if (session->securityPrivProto != NULL) {
- user->privProtocol =
- snmp_duplicate_objid(session->securityPrivProto,
- session->securityPrivProtoLen);
- if (user->privProtocol == NULL) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->privProtocolLen = session->securityPrivProtoLen;
- }
- /* copy in the authentication Key, and convert to the localized version */
- if (session->securityAuthKey != NULL && session->securityAuthKeyLen != 0) {
- user->authKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
- if (user->authKey == NULL)
- {
- usm_free_user (user);
- return SNMPERR_GENERR;
- }
- user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
- if (generate_kul( user->authProtocol, user->authProtocolLen,
- session->securityEngineID, session->securityEngineIDLen,
- session->securityAuthKey, session->securityAuthKeyLen,
- user->authKey, &user->authKeyLen ) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- }
- /* copy in the privacy Key, and convert to the localized version */
- if (session->securityPrivKey != NULL && session->securityPrivKeyLen != 0) {
- user->privKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
- if (user->privKey == NULL)
- {
- usm_free_user (user);
- return SNMPERR_GENERR;
- }
- user->privKeyLen = USM_LENGTH_KU_HASHBLOCK;
- if (generate_kul( user->authProtocol, user->authProtocolLen,
- session->securityEngineID, session->securityEngineIDLen,
- session->securityPrivKey, session->securityPrivKeyLen,
- user->privKey, &user->privKeyLen ) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- }
- /* add the user into the database */
- usm_add_user(user);
- }
- return SNMPERR_SUCCESS;
- } /* end create_user_from_session() */
- /*
- * Close the input session. Frees all data allocated for the session,
- * dequeues any pending requests, and closes any sockets allocated for
- * the session. Returns 0 on error, 1 otherwise.
- */
- int
- snmp_sess_close(void *sessp)
- {
- struct session_list *slp = (struct session_list *)sessp;
- struct snmp_internal_session *isp;
- struct snmp_session *sesp;
- if (slp == NULL)
- return 0;
- isp = slp->internal; slp->internal = 0;
- if (isp) {
- struct request_list *rp, *orp;
- SNMP_FREE(isp->packet);
- if (isp->sd != -1)
- {
- so_close(isp->sd);
- #ifdef UCD_SNMP
- #ifdef AF_UNIX
- if ( isp->me.sa_family == AF_UNIX )
- unlink( isp->me.sa_data );
- #endif /* AF_UNIX */
- #endif
- }
- /* Free each element in the input request list. */
- rp = isp->requests;
- while(rp){
- orp = rp;
- rp = rp->next_request;
- snmp_free_pdu(orp->pdu);
- free(orp);
- }
- free(isp);
- }
- sesp = slp->session; slp->session = 0;
- if (sesp) {
- SNMP_FREE(sesp->peername);
- SNMP_FREE(sesp->community);
- SNMP_FREE(sesp->contextEngineID);
- SNMP_FREE(sesp->contextName);
- SNMP_FREE(sesp->securityEngineID);
- SNMP_FREE(sesp->securityName);
- SNMP_FREE(sesp->securityAuthProto);
- SNMP_FREE(sesp->securityPrivProto);
- free(sesp);
- }
- free(slp);
- return 1;
- }
- int
- snmp_close(struct snmp_session *session)
- {
- struct session_list *slp = NULL, *oslp = NULL;
- { /*MTCRITICAL_RESOURCE*/
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
- if (Sessions && Sessions->session == session){ /* If first entry */
- slp = Sessions;
- Sessions = slp->next;
- } else {
- for(slp = Sessions; slp; slp = slp->next){
- if (slp->session == session){
- if (oslp) /* if we found entry that points here */
- oslp->next = slp->next; /* link around this entry */
- break;
- }
- oslp = slp;
- }
- }
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
- } /*END MTCRITICAL_RESOURCE*/
- if (slp == NULL){
- return 0;
- }
- return snmp_sess_close((void *)slp);
- }
- int
- snmp_close_sessions( void )
- {
- struct session_list *slp;
- snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
- while ( Sessions ) {
- slp = Sessions;
- Sessions = Sessions->next;
- snmp_sess_close((void *)slp);
- }
- snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
- return 1;
- }
- static int
- snmpv3_build_probe_pdu (struct snmp_pdu **pdu)
- {
- struct usmUser *user;
- /* create the pdu */
- if (!pdu) return -1;
- *pdu = snmp_pdu_create(SNMP_MSG_GET);
- if (*pdu == NULL)
- return -1;
- (*pdu)->version = SNMP_VERSION_3;
- (*pdu)->securityName = strdup("");
- (*pdu)->securityNameLen = strlen((*pdu)->securityName);
- (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
- (*pdu)->securityModel = SNMP_SEC_MODEL_USM;
- /* create the empty user */
- user = usm_get_user(NULL, 0, (*pdu)->securityName);
- if (user == NULL) {
- user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
- if (user == NULL)
- {
- snmp_free_pdu (*pdu);
- *pdu = NULL;
- return -1;
- }
- user->name = strdup((*pdu)->securityName);
- user->secName = strdup((*pdu)->securityName);
- user->authProtocolLen = sizeof(usmNoAuthProtocol)/sizeof(oid);
- user->authProtocol =
- snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
- user->privProtocolLen = sizeof(usmNoPrivProtocol)/sizeof(oid);
- user->privProtocol =
- snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
- if (user->name == NULL || user->secName == NULL || user->authProtocol == NULL
- || user->privProtocol == NULL)
- {
- snmp_free_pdu (*pdu);
- *pdu = NULL;
- usm_free_user(user);
- return -1;
- }
- usm_add_user(user);
- }
- return 0;
- }
- static void
- snmpv3_calc_msg_flags (int sec_level, int msg_command, u_char *flags)
- {
- *flags = 0;
- if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
- *flags = SNMP_MSG_FLAG_AUTH_BIT;
- else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
- *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
- if (SNMP_CMD_CONFIRMED(msg_command)) *flags |= SNMP_MSG_FLAG_RPRT_BIT;
- return;
- }
- static int
- snmpv3_verify_msg(struct request_list *rp, struct snmp_pdu *pdu)
- {
- struct snmp_pdu *rpdu;
- if (!rp || !rp->pdu || !pdu) return 0;
- /* Reports don't have to match anything according to the spec */
- if (pdu->command == SNMP_MSG_REPORT) return 1;
- rpdu = rp->pdu;
- if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid) return 0;
- if (rpdu->version != pdu->version) return 0;
- if (rpdu->securityModel != pdu->securityModel) return 0;
- if (rpdu->securityLevel != pdu->securityLevel) return 0;
- if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen ||
- memcmp(rpdu->contextEngineID, pdu->contextEngineID,
- pdu->contextEngineIDLen))
- return 0;
- if (rpdu->contextNameLen != pdu->contextNameLen ||
- memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
- return 0;
- if (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
- memcmp(rpdu->securityEngineID, pdu->securityEngineID,
- pdu->securityEngineIDLen))
- return 0;
- if (rpdu->securityNameLen != pdu->securityNameLen ||
- memcmp(rpdu->securityName, pdu->securityName, pdu->securityNameLen))
- return 0;
- return 1;
- }
- /* SNMPv3
- * Takes a session and a pdu and serializes the ASN PDU into the area
- * pointed to by packet. out_length is the size of the data area available.
- * Returns the length of the completed packet in out_length. If any errors
- * occur, -1 is returned. If all goes well, 0 is returned.
- */
- static int
- snmpv3_build(struct snmp_session *session,
- struct snmp_pdu *pdu,
- u_char *packet,
- size_t *out_length)
- {
- int ret;
- session->s_snmp_errno = 0;
- session->s_errno = 0;
- /* do validation for PDU types */
- switch (pdu->command) {
- case SNMP_MSG_RESPONSE:
- case SNMP_MSG_TRAP2:
- case SNMP_MSG_REPORT:
- pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
- /* Fallthrough */
- case SNMP_MSG_GET:
- case SNMP_MSG_GETNEXT:
- case SNMP_MSG_SET:
- case SNMP_MSG_INFORM:
- if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
- pdu->errstat = 0;
- if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
- pdu->errindex = 0;
- break;
- case SNMP_MSG_GETBULK:
- if (pdu->max_repetitions < 0) {
- session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
- return -1;
- }
- if (pdu->non_repeaters < 0) {
- session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
- return -1;
- }
- break;
- case SNMP_MSG_TRAP:
- session->s_snmp_errno = SNMPERR_V1_IN_V2;
- return -1;
- default:
- session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
- return -1;
- }
- if (pdu->securityEngineIDLen == 0) {
- if (session->securityEngineIDLen) {
- snmpv3_clone_engineID(&pdu->securityEngineID,
- &pdu->securityEngineIDLen,
- session->securityEngineID,
- session->securityEngineIDLen);
- }
- }
- if (pdu->contextEngineIDLen == 0) {
- if (session->contextEngineIDLen) {
- snmpv3_clone_engineID(&pdu->contextEngineID,
- &pdu->contextEngineIDLen,
- session->contextEngineID,
- session->contextEngineIDLen);
- } else if (pdu->securityEngineIDLen) {
- snmpv3_clone_engineID(&pdu->contextEngineID,
- &pdu->contextEngineIDLen,
- pdu->securityEngineID,
- pdu->securityEngineIDLen);
- }
- }
- if (pdu->contextName == NULL) {
- if (!session->contextName){
- session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
- return -1;
- }
- pdu->contextName = strdup(session->contextName);
- if (pdu->contextName == NULL) {
- session->s_snmp_errno = SNMPERR_GENERR;
- return -1;
- }
- pdu->contextNameLen = session->contextNameLen;
- }
- pdu->securityModel = SNMP_SEC_MODEL_USM;
- if (pdu->securityNameLen == 0 && pdu->securityName == 0) {
- if (session->securityNameLen == 0){
- session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
- return -1;
- }
- pdu->securityName = strdup(session->securityName);
- if (pdu->securityName == NULL) {
- session->s_snmp_errno = SNMPERR_GENERR;
- return -1;
- }
- pdu->securityNameLen = session->securityNameLen;
- }
- if (pdu->securityLevel == 0) {
- if (session->securityLevel == 0) {
- session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
- return -1;
- }
- pdu->securityLevel = session->securityLevel;
- }
- DEBUGMSGTL(("snmp_build",
- "Building SNMPv3 message (secName:"%s", secLevel:%s)...n",
- ((session->securityName) ? (char *)session->securityName :
- ((pdu->securityName) ? (char *)pdu->securityName :
- "ERROR: undefined")),
- usmSecLevelName[pdu->securityLevel]));
- ret = snmpv3_packet_build(pdu, packet, out_length, NULL, 0);
- if (-1 != ret) {
- session->s_snmp_errno = ret;
- }
- return ret;
- } /* end snmpv3_build() */
- static u_char *
- snmpv3_header_build(struct snmp_pdu *pdu, u_char *packet,
- size_t *out_length, size_t length, u_char **msg_hdr_e)
- {
- u_char *global_hdr, *global_hdr_e;
- u_char *cp;
- u_char msg_flags;
- long max_size;
- long sec_model;
- u_char *pb, *pb0e;
- /* Save current location and build SEQUENCE tag and length placeholder
- * for SNMP message sequence (actual length inserted later)
- */
- cp = asn_build_sequence(packet, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), length);
- if (cp == NULL) return NULL;
- if (msg_hdr_e != NULL)
- *msg_hdr_e = cp;
- pb0e = cp;
- /* store the version field - msgVersion
- */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->version, sizeof(pdu->version));
- if (cp == NULL) return NULL;
- global_hdr = cp;
- /* msgGlobalData HeaderData */
- cp = asn_build_sequence(cp, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
- if (cp == NULL) return NULL;
- global_hdr_e = cp;
- /* msgID */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &pdu->msgid, sizeof(pdu->msgid));
- if (cp == NULL) return NULL;
- /* msgMaxSize */
- max_size = SNMP_MAX_MSG_SIZE;
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &max_size, sizeof(max_size));
- if (cp == NULL) return NULL;
- /* msgFlags */
- snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
- cp = asn_build_string(cp, out_length,
- (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
- &msg_flags, sizeof(msg_flags));
- if (cp == NULL) return NULL;
- /* msgSecurityModel */
- sec_model = SNMP_SEC_MODEL_USM;
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &sec_model, sizeof(sec_model));
- if (cp == NULL) return NULL;
- /* insert actual length of globalData
- */
- pb = asn_build_sequence(global_hdr, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- cp - global_hdr_e);
- if (pb == NULL) return NULL;
- /* insert the actual length of the entire packet
- */
- pb = asn_build_sequence(packet, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- length + (cp - pb0e));
- if (pb == NULL) return NULL;
- return cp;
- } /* end snmpv3_header_build() */
- static u_char *
- snmpv3_scopedPDU_header_build(struct snmp_pdu *pdu,
- u_char *packet, size_t *out_length,
- u_char **spdu_e)
- {
- size_t init_length;
- u_char *scopedPdu, *pb;
- init_length = *out_length;
- pb = scopedPdu = packet;
- pb = asn_build_sequence(pb, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
- if (pb == NULL) return NULL;
- if (spdu_e)
- *spdu_e = pb;
- pb = asn_build_string(pb, out_length,
- (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
- pdu->contextEngineID, pdu->contextEngineIDLen);
- if (pb == NULL) return NULL;
- pb = asn_build_string(pb, out_length,
- (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
- (u_char *)pdu->contextName, pdu->contextNameLen);
- if (pb == NULL) return NULL;
- return pb;
- } /* end snmpv3_scopedPDU_header_build() */
- /* returns 0 if success, -1 if fail, not 0 if USM build failure */
- int
- snmpv3_packet_build(struct snmp_pdu *pdu, u_char *packet, size_t *out_length,
- u_char *pdu_data, size_t pdu_data_len)
- {
- u_char *global_data, *sec_params, *spdu_hdr_e;
- size_t global_data_len, sec_params_len;
- u_char spdu_buf[SNMP_MAX_MSG_SIZE];
- size_t spdu_buf_len, spdu_len;
- u_char *cp;
- int result;
- global_data = packet;
- /*
- * build the headers for the packet, returned addr = start of secParams
- */
- sec_params = snmpv3_header_build(pdu, global_data, out_length, 0, NULL);
- if (sec_params == NULL) return -1;
- global_data_len = sec_params - global_data;
- sec_params_len = *out_length; /* length left in packet buf for sec_params */
- /*
- * build a scopedPDU structure into spdu_buf
- */
- spdu_buf_len = SNMP_MAX_MSG_SIZE;
- cp = snmpv3_scopedPDU_header_build(pdu,spdu_buf,&spdu_buf_len,&spdu_hdr_e);
- if (cp == NULL) return -1;
- /* build the PDU structure onto the end of spdu_buf
- */
- if (pdu_data) {
- memcpy(cp, pdu_data, pdu_data_len);
- cp += pdu_data_len;
- } else {
- cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
- if (cp == NULL) return -1;
- }
- /*
- * re-encode the actual ASN.1 length of the scopedPdu
- */
- spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
- spdu_buf_len = SNMP_MAX_MSG_SIZE;
- if (asn_build_sequence(spdu_buf, &spdu_buf_len,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- spdu_len) == NULL)
- return -1;
- spdu_len = cp - spdu_buf; /* the length of the entire scopedPdu */
- /*
- * call the security module to possibly encrypt and authenticate the
- * message - the entire message to transmitted on the wire is returned
- */
- cp = NULL; *out_length = SNMP_MAX_MSG_SIZE;
- result =
- usm_generate_out_msg(
- SNMP_VERSION_3,
- global_data, global_data_len,
- SNMP_MAX_MSG_SIZE,
- SNMP_SEC_MODEL_USM,
- pdu->securityEngineID, pdu->securityEngineIDLen,
- pdu->securityName, pdu->securityNameLen,
- pdu->securityLevel,
- spdu_buf, spdu_len,
- pdu->securityStateRef,
- sec_params, &sec_params_len,
- &cp, out_length);
- return result;
- } /* end snmpv3_packet_build() */
- /*
- * Takes a session and a pdu and serializes the ASN PDU into the area
- * pointed to by packet. out_length is the size of the data area available.
- * Returns the length of the completed packet in out_length. If any errors
- * occur, -1 is returned. If all goes well, 0 is returned.
- */
- static int
- _snmp_build(struct snmp_session *session,
- struct snmp_pdu *pdu,
- u_char *packet,
- size_t *out_length)
- {
- u_char *h0, *h0e = 0, *h1;
- u_char *cp;
- size_t length;
- long version;
- session->s_snmp_errno = 0;
- session->s_errno = 0;
- if (pdu->version == SNMP_VERSION_3)
- return snmpv3_build(session, pdu, packet, out_length);
- switch (pdu->command) {
- case SNMP_MSG_RESPONSE:
- pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
- /* Fallthrough */
- case SNMP_MSG_GET:
- case SNMP_MSG_GETNEXT:
- case SNMP_MSG_SET:
- /* all versions support these PDU types */
- /* initialize defaulted PDU fields */
- if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
- pdu->errstat = 0;
- if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
- pdu->errindex = 0;
- break;
- case SNMP_MSG_TRAP2:
- pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
- /* Fallthrough */
- case SNMP_MSG_INFORM:
- /* not supported in SNMPv1 and SNMPsec */
- if (pdu->version == SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V2_IN_V1;
- return -1;
- }
- if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
- pdu->errstat = 0;
- if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
- pdu->errindex = 0;
- break;
- case SNMP_MSG_GETBULK:
- /* not supported in SNMPv1 and SNMPsec */
- if (pdu->version == SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V2_IN_V1;
- return -1;
- }
- if (pdu->max_repetitions < 0) {
- session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
- return -1;
- }
- if (pdu->non_repeaters < 0) {
- session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
- return -1;
- }
- break;
- case SNMP_MSG_TRAP:
- /* *only* supported in SNMPv1 and SNMPsec */
- if (pdu->version != SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V1_IN_V2;
- return -1;
- }
- /* initialize defaulted Trap PDU fields */
- pdu->reqid = 1; /* give a bogus non-error reqid for traps */
- if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH){
- pdu->enterprise = (oid *)malloc(sizeof(DEFAULT_ENTERPRISE));
- if (pdu->enterprise == NULL)
- {
- session->s_snmp_errno = SNMPERR_MALLOC;
- return -1;
- }
- memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
- sizeof(DEFAULT_ENTERPRISE));
- pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
- }
- if (pdu->time == SNMP_DEFAULT_TIME)
- pdu->time = DEFAULT_TIME;
- /* don't expect a response */
- pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
- break;
- case SNMP_MSG_REPORT: /* SNMPv3 only */
- default:
- session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
- return -1;
- }
- /* save length */
- length = *out_length;
- /* setup administrative fields based on version */
- /* build the message wrapper and all the administrative fields
- upto the PDU sequence
- (note that actual length of message will be inserted later) */
- h0 = packet;
- switch (pdu->version) {
- case SNMP_VERSION_1:
- case SNMP_VERSION_2c:
- #ifdef NO_ZEROLENGTH_COMMUNITY
- if (pdu->community_len == 0){
- if (session->community_len == 0){
- session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
- return -1;
- }
- pdu->community = (u_char *)malloc(1+session->community_len);
- if (pdu->community == NULL)
- {
- session->s_snmp_errno = SNMPERR_MALLOC;
- return -1;
- }
- memmove(pdu->community, session->community,
- session->community_len);
- pdu->community[session->community_len] = ' ';
- pdu->community_len = session->community_len;
- }
- #else /* !NO_ZEROLENGTH_COMMUNITY */
- if ((pdu->community_len == 0 ||
- pdu->command != SNMP_MSG_RESPONSE ) &&
- !pdu->available_community) {
- /* copy session community exactly to pdu community */
- if (0 == session->community_len) {
- SNMP_FREE(pdu->community); pdu->community = 0;
- }
- else if (pdu->community_len == session->community_len) {
- memmove(pdu->community, session->community,
- session->community_len);
- }
- else {
- SNMP_FREE(pdu->community);
- pdu->community = (u_char *)malloc(1+session->community_len);
- if (pdu->community == NULL)
- {
- session->s_snmp_errno = SNMPERR_MALLOC;
- return -1;
- }
- memmove(pdu->community, session->community,
- session->community_len);
- pdu->community[session->community_len] = ' ';
- }
- pdu->community_len = session->community_len;
- }
- #endif /* !NO_ZEROLENGTH_COMMUNITY */
- DEBUGMSGTL(("snmp_send","Building SNMPv%d message...n", (1 + pdu->version)));
- /* Save current location and build SEQUENCE tag and length
- placeholder for SNMP message sequence
- (actual length will be inserted later) */
- cp = asn_build_sequence(packet, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- 0);
- if (cp == NULL)
- return -1;
- h0e = cp;
- /* store the version field */
- version = pdu->version;
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &version, sizeof(version));
- if (cp == NULL)
- return -1;
- /* store the community string */
- cp = asn_build_string(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
- pdu->community, pdu->community_len);
- if (cp == NULL)
- return -1;
- break;
- case SNMP_VERSION_2p:
- case SNMP_VERSION_sec:
- case SNMP_VERSION_2u:
- case SNMP_VERSION_2star:
- default:
- session->s_snmp_errno = SNMPERR_BAD_VERSION;
- return -1;
- }
- h1 = cp;
- cp = snmp_pdu_build(pdu, cp, out_length);
- if (cp == NULL)
- return -1;
- /* insert the actual length of the message sequence */
- switch (pdu->version) {
- case SNMP_VERSION_1:
- case SNMP_VERSION_2c:
- asn_build_sequence(packet, &length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- cp - h0e);
- break;
- case SNMP_VERSION_2p:
- case SNMP_VERSION_sec:
- case SNMP_VERSION_2u:
- case SNMP_VERSION_2star:
- default:
- session->s_snmp_errno = SNMPERR_BAD_VERSION;
- return -1;
- }
- *out_length = cp - packet;
- return 0;
- }
- int
- snmp_build(struct snmp_session *pss,
- struct snmp_pdu *pdu,
- u_char *packet,
- size_t *out_length)
- {
- int rc;
- rc = _snmp_build(pss,pdu,packet,out_length);
- if (rc) {
- if ( !pss->s_snmp_errno)
- pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
- SET_SNMP_ERROR(pss->s_snmp_errno);
- rc = -1;
- }
- return rc;
- }
- /* on error, returns NULL (likely an encoding problem). */
- u_char *
- snmp_pdu_build (struct snmp_pdu *pdu, u_char *cp, size_t *out_length)
- {
- u_char *h1, *h1e, *h2, *h2e;
- struct variable_list *vp;
- struct soaddr_in *pduIp = (struct soaddr_in *)&(pdu->agent_addr);
- size_t length;
- length = *out_length;
- /* Save current location and build PDU tag and length placeholder
- (actual length will be inserted later) */
- h1 = cp;
- cp = asn_build_sequence(cp, out_length, (u_char)pdu->command, 0);
- if (cp == NULL)
- return NULL;
- h1e = cp;
- /* store fields in the PDU preceeding the variable-bindings sequence */
- if (pdu->command != SNMP_MSG_TRAP){
- /* PDU is not an SNMPv1 trap */
- /* request id */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &pdu->reqid, sizeof(pdu->reqid));
- if (cp == NULL)
- return NULL;
- /* error status (getbulk non-repeaters) */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &pdu->errstat, sizeof(pdu->errstat));
- if (cp == NULL)
- return NULL;
- /* error index (getbulk max-repetitions) */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- &pdu->errindex, sizeof(pdu->errindex));
- if (cp == NULL)
- return NULL;
- } else {
- /* an SNMPv1 trap PDU */
- /* enterprise */
- cp = asn_build_objid(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
- (oid *)pdu->enterprise, pdu->enterprise_length);
- if (cp == NULL)
- return NULL;
- /* agent-addr */
- cp = asn_build_string(cp, out_length,
- (u_char)(ASN_IPADDRESS | ASN_PRIMITIVE),
- (u_char *)&pduIp->sin_addr.s_addr,
- sizeof(pduIp->sin_addr.s_addr));
- if (cp == NULL)
- return NULL;
- /* generic trap */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *)&pdu->trap_type, sizeof(pdu->trap_type));
- if (cp == NULL)
- return NULL;
- /* specific trap */
- cp = asn_build_int(cp, out_length,
- (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *)&pdu->specific_type, sizeof(pdu->specific_type));
- if (cp == NULL)
- return NULL;
- /* timestamp */
- cp = asn_build_unsigned_int(cp, out_length,
- (u_char)(ASN_TIMETICKS | ASN_PRIMITIVE),
- &pdu->time, sizeof(pdu->time));
- if (cp == NULL)
- return NULL;
- }
- /* Save current location and build SEQUENCE tag and length placeholder
- for variable-bindings sequence
- (actual length will be inserted later) */
- h2 = cp;
- cp = asn_build_sequence(cp, out_length,
- (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
- 0);
- if (cp == NULL)
- return NULL;
- h2e = cp;
- /* Store variable-bindings */
- for(vp = pdu->variables; vp; vp = vp->next_variable){
- cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
- vp->val_len, (u_char *)vp->val.string,
- out_length);
- if (cp == NULL)
- return NULL;
- }
- /* insert actual length of variable-bindings sequence */
- asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),cp-h2e);
- /* insert actual length of PDU sequence */
- asn_build_sequence(h1, &length, (u_char)pdu->command, cp - h1e);
- return cp;
- }
- /*
- * Parses the packet received to determine version, either directly
- * from packets version field or inferred from ASN.1 construct.
- */
- static int
- snmp_parse_version (u_char *data, size_t length)
- {
- u_char type;
- long version = SNMPERR_BAD_VERSION;
- data = asn_parse_sequence(data, &length, &type,
- (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
- if (data) {
- data = asn_parse_int(data, &length, &type, &version, sizeof(version));
- if (!data) return SNMPERR_BAD_VERSION;
- }
- return version;
- }
- int
- snmpv3_parse(
- struct snmp_pdu *pdu,
- u_char *data,
- size_t *length,
- u_char **after_header)
- {
- u_char type, msg_flags;
- long ver, msg_max_size, msg_sec_model;
- size_t max_size_response;
- u_char tmp_buf[SNMP_MAX_MSG_SIZE];
- size_t tmp_buf_len;
- u_char pdu_buf[SNMP_MAX_MSG_SIZE];
- size_t pdu_buf_len = SNMP_MAX_MSG_SIZE;
- u_char *sec_params;
- u_char *msg_data;
- u_char *cp;
- size_t asn_len, msg_len;
- int ret, ret_val;
- msg_data = data;
- msg_len = *length;
- /* message is an ASN.1 SEQUENCE
- */
- DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Messagen");
- data = asn_parse_sequence(data, length, &type,
- (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
- if (data == NULL){
- /* error msg detail is set */
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTLESS();
- return SNMPERR_ASN_PARSE_ERR;
- }
- /* parse msgVersion
- */
- DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Version Numbern");
- data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
- DEBUGINDENTLESS();
- if (data == NULL){
- ERROR_MSG("bad parse of version");
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTLESS();
- return SNMPERR_ASN_PARSE_ERR;
- }
- pdu->version = ver;
- /* parse msgGlobalData sequence
- */
- cp = data;
- asn_len = *length;
- DEBUGDUMPHEADER("dump_recv", "Parsing msgGlobalDatan");
- data = asn_parse_sequence(data, &asn_len, &type,
- (ASN_SEQUENCE | ASN_CONSTRUCTOR), "msgGlobalData");
- if (data == NULL){
- /* error msg detail is set */
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTADD(-4);
- return SNMPERR_ASN_PARSE_ERR;
- }
- *length -= data - cp; /* subtract off the length of the header */
- /* msgID */
- DEBUGDUMPHEADER("dump_recv", "Parsing msgIDn");
- data = asn_parse_int(data, length, &type, &pdu->msgid, sizeof(pdu->msgid));
- DEBUGINDENTLESS();
- if (data == NULL) {
- ERROR_MSG("error parsing msgID");
- DEBUGINDENTADD(-4);
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- return SNMPERR_ASN_PARSE_ERR;
- }
- /* msgMaxSize */
- DEBUGDUMPHEADER("dump_recv", "Parsing msgMaxSizen");
- data = asn_parse_int(data, length, &type, &msg_max_size,
- sizeof(msg_max_size));
- DEBUGINDENTLESS();
- if (data == NULL) {
- ERROR_MSG("error parsing msgMaxSize");
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTADD(-4);
- return SNMPERR_ASN_PARSE_ERR;
- }
- /* msgFlags */
- tmp_buf_len = SNMP_MAX_MSG_SIZE;
- DEBUGDUMPHEADER("dump_recv", "Parsing msgFlagsn");
- data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
- DEBUGINDENTLESS();
- if (data == NULL || tmp_buf_len != 1) {
- ERROR_MSG("error parsing msgFlags");
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTADD(-4);
- return SNMPERR_ASN_PARSE_ERR;
- }
- msg_flags = *tmp_buf;
- if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
- pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
- else
- pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
- /* msgSecurityModel */
- DEBUGDUMPHEADER("dump_recv", "Parsing msgSecurityModeln");
- data = asn_parse_int(data, length, &type, &msg_sec_model,
- sizeof(msg_sec_model));
- DEBUGINDENTADD(-4); /* return from global data indent */
- if (data == NULL) {
- ERROR_MSG("error parsing msgSecurityModel");
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTLESS();
- return SNMPERR_ASN_PARSE_ERR;
- }
- if (msg_sec_model != SNMP_SEC_MODEL_USM) {
- ERROR_MSG("unknown security model");
- snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
- DEBUGINDENTLESS();
- return SNMPERR_UNKNOWN_SEC_MODEL;
- }
- pdu->securityModel = msg_sec_model;
- if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
- !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
- ERROR_MSG("invalid message, illegal msgFlags");
- snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
- DEBUGINDENTLESS();
- return SNMPERR_INVALID_MSG;
- }
- pdu->securityLevel = ( (msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
- ? ( (msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
- ? SNMP_SEC_LEVEL_AUTHPRIV
- : SNMP_SEC_LEVEL_AUTHNOPRIV )
- : SNMP_SEC_LEVEL_NOAUTH );
- /* end of msgGlobalData */
- /* securtityParameters OCTET STRING begins after msgGlobalData */
- sec_params = data;
- pdu->contextEngineID = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
- pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
- pdu->securityEngineID = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
- pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE;
- pdu->securityName = (char *)calloc(1,SNMP_MAX_SEC_NAME_SIZE);
- pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
- memset(pdu_buf, 0, pdu_buf_len);
- cp = pdu_buf;
- DEBUGDUMPHEADER("dump_recv", "Parsing USM msgSecurityParametersn");
- ret_val = usm_process_in_msg(SNMP_VERSION_3, msg_max_size,
- sec_params, msg_sec_model, pdu->securityLevel,
- msg_data, msg_len,
- pdu->securityEngineID, &pdu->securityEngineIDLen,
- pdu->securityName, &pdu->securityNameLen,
- &cp,
- &pdu_buf_len, &max_size_response,
- &pdu->securityStateRef);
- DEBUGINDENTLESS();
- if (ret_val != SNMPERR_SUCCESS) {
- snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len); /* DO ignore return code */
- DEBUGINDENTLESS();
- return ret_val;
- }
- /* parse plaintext ScopedPDU sequence */
- *length = pdu_buf_len;
- DEBUGDUMPHEADER("dump_recv", "Parsing ScopedPdun");
- data = snmpv3_scopedPDU_parse(pdu, cp, length);
- if (data == NULL) {
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- DEBUGINDENTADD(-4);
- return SNMPERR_ASN_PARSE_ERR;
- }
- /* parse the PDU.
- */
- if (after_header != NULL) {
- tmp_buf_len = *length;
- *after_header = data;
- }
- DEBUGDUMPHEADER("dump_recv", "Parsing PDUn");
- ret = snmp_pdu_parse(pdu, data, length);