snmp_api.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:217k
- /* Portions of this file are subject to the following copyright(s). See
- * the Net-SNMP's COPYING file for more details and other copyrights
- * that may apply:
- */
- /******************************************************************
- 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.
- ******************************************************************/
- /*
- * Portions of this file are copyrighted by:
- * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms specified in the COPYING file
- * distributed with the Net-SNMP package.
- */
- /** @defgroup library The Net-SNMP library
- * @{
- */
- /*
- * snmp_api.c - API for access to snmp.
- */
- #include <net-snmp/net-snmp-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 <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_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_IO_H
- #include <io.h>
- #endif
- #if HAVE_WINSOCK_H
- #include <winsock.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
- #ifndef dynix
- #include <net/if_dl.h>
- #else
- #include <sys/net/if_dl.h>
- #endif
- #endif
- #include <errno.h>
- #if HAVE_LOCALE_H
- #include <locale.h>
- #endif
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- #define SNMP_NEED_REQUEST_LIST
- #include <net-snmp/types.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.h> /* for xdump & {build,parse}_var_op */
- #include <net-snmp/library/snmp_api.h>
- #include <net-snmp/library/snmp_client.h>
- #include <net-snmp/library/parse.h>
- #include <net-snmp/library/mib.h>
- #include <net-snmp/library/int64.h>
- #include <net-snmp/library/snmpv3.h>
- #include <net-snmp/library/callback.h>
- #include <net-snmp/library/container.h>
- #include <net-snmp/library/snmp_secmod.h>
- #ifdef SNMP_SECMOD_USM
- #include <net-snmp/library/snmpusm.h>
- #endif
- #ifdef SNMP_SECMOD_KSM
- #include <net-snmp/library/snmpksm.h>
- #endif
- #include <net-snmp/library/keytools.h>
- #include <net-snmp/library/lcd_time.h>
- #include <net-snmp/library/snmp_alarm.h>
- #include <net-snmp/library/snmp_transport.h>
- static void _init_snmp(void);
- #include "../agent/mibgroup/agentx/protocol.h"
- #include <net-snmp/library/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 MAX_PACKET_LENGTH (0x7fffffff)
- #ifndef NETSNMP_STREAM_QUEUE_LEN
- #define NETSNMP_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
- static oid default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
- /*
- * enterprises.cmu.systems.cmuSNMP
- */
- #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
- /*
- * don't set higher than 0x7fffffff, and I doubt it should be that high
- * * = 4 gig snmp messages max
- */
- #define MAXIMUM_PACKET_SIZE 0x7fffffff
- /*
- * Internal information about the state of the snmp session.
- */
- struct snmp_internal_session {
- netsnmp_request_list *requests; /* Info about outstanding requests */
- netsnmp_request_list *requestsEnd; /* ptr to end of list */
- int (*hook_pre) (netsnmp_session *, netsnmp_transport *,
- void *, int);
- int (*hook_parse) (netsnmp_session *, netsnmp_pdu *,
- u_char *, size_t);
- int (*hook_post) (netsnmp_session *, netsnmp_pdu *, int);
- int (*hook_build) (netsnmp_session *, netsnmp_pdu *,
- u_char *, size_t *);
- int (*hook_realloc_build) (netsnmp_session *,
- netsnmp_pdu *, u_char **,
- size_t *, size_t *);
- int (*check_packet) (u_char *, size_t);
- netsnmp_pdu *(*hook_create_pdu) (netsnmp_transport *,
- void *, size_t);
- u_char *packet;
- size_t packet_len, packet_size;
- };
- /*
- * The list of active/open sessions.
- */
- struct session_list {
- struct session_list *next;
- netsnmp_session *session;
- netsnmp_transport *transport;
- 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/Priv", /* 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 */
- "No securityName specified", /* 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 (incorrect password, community or key)", /* 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 (no such user exists)", /* SNMPERR_USM_UNKNOWNSECURITYNAME */
- "USM unsupported security level (this user has not been configured for that level of security)", /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
- "USM encryption error", /* SNMPERR_USM_ENCRYPTIONERROR */
- "USM authentication failure (incorrect password or key)", /* 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 */
- "Kerberos related error", /* SNMPERR_KRB5 */
- "Protocol error", /* SNMPERR_PROTOCOL */
- };
- static const char *secLevelName[] = {
- "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
- */
- /*
- * global error detail storage
- */
- static char snmp_detail[192];
- static int snmp_detail_f = 0;
- /*
- * Prototypes.
- */
- int snmp_build(u_char ** pkt, size_t * pkt_len,
- size_t * offset, netsnmp_session * pss,
- netsnmp_pdu *pdu);
- static int snmp_parse(void *, netsnmp_session *, netsnmp_pdu *,
- u_char *, size_t);
- static void snmpv3_calc_msg_flags(int, int, u_char *);
- static int snmpv3_verify_msg(netsnmp_request_list *, netsnmp_pdu *);
- static int snmpv3_build_probe_pdu(netsnmp_pdu **);
- static int snmpv3_build(u_char ** pkt, size_t * pkt_len,
- size_t * offset, netsnmp_session * session,
- netsnmp_pdu *pdu);
- static int snmp_parse_version(u_char *, size_t);
- static int snmp_resend_request(struct session_list *slp,
- netsnmp_request_list *rp,
- int incr_retries);
- static void register_default_handlers(void);
- static struct session_list *snmp_sess_copy(netsnmp_session * pss);
- int snmp_get_errno(void);
- void snmp_synch_reset(netsnmp_session * notused);
- void snmp_synch_setup(netsnmp_session * notused);
- #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
- const char *
- snmp_pdu_type(int type)
- {
- static char unknown[20];
- switch(type) {
- case SNMP_MSG_GET:
- return "GET";
- case SNMP_MSG_GETNEXT:
- return "GETNEXT";
- case SNMP_MSG_RESPONSE:
- return "RESPONSE";
- case SNMP_MSG_SET:
- return "SET";
- case SNMP_MSG_GETBULK:
- return "GETBULK";
- case SNMP_MSG_INFORM:
- return "INFORM";
- case SNMP_MSG_TRAP2:
- return "TRAP2";
- case SNMP_MSG_REPORT:
- return "REPORT";
- default:
- snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
- return unknown;
- }
- }
- #define DEBUGPRINTPDUTYPE(token, type)
- DEBUGDUMPSECTION(token, snmp_pdu_type(type))
- 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);
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
- return (retVal & 0x7fff); /* mask to 15 bits */
- else
- 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);
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
- return (retVal & 0x7fff); /* mask to 15 bits */
- else
- 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);
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
- return (retVal & 0x7fff); /* mask to 15 bits */
- else
- 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);
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
- return (retVal & 0x7fff); /* mask to 15 bits */
- else
- 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[SPRINT_MAX_LEN];
- if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
- msg = api_errors[-snmp_errnumber];
- } else if (snmp_errnumber != SNMPERR_SUCCESS) {
- msg = NULL;
- }
- if (!msg)
- snprintf(msg_buf, sizeof(msg_buf), "Unknown error: %d", snmp_errnumber);
- else if (snmp_detail_f) {
- snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
- snmp_detail_f = 0;
- } else {
- strncpy(msg_buf, msg, sizeof(msg_buf));
- }
- msg_buf[sizeof(msg_buf)-1] = ' ';
- 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(netsnmp_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) {
- if (snmp_detail_f) {
- snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
- snmp_detail);
- snmp_detail_f = 0;
- }
- else
- strncpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
- } else {
- if (snmp_errnumber)
- snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
- }
- buf[sizeof(buf)-1] = ' ';
- /*
- * append a useful system errno interpretation.
- */
- if (psess->s_errno) {
- const char* error = strerror(psess->s_errno);
- if(error == NULL)
- error = "Unknown Error";
- snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
- " (%s)", error);
- }
- buf[sizeof(buf)-1] = ' ';
- *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
- netsnmp_sess_log_error(int priority,
- const char *prog_string, netsnmp_session * ss)
- {
- char *err;
- snmp_error(ss, NULL, NULL, &err);
- snmp_log(priority, "%s: %sn", prog_string, err);
- SNMP_FREE(err);
- }
- /*
- * snmp_sess_perror(): print a error stored in a session pointer
- */
- void
- snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
- {
- netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
- }
- /*
- * 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 is not currently supported.
- *
- * Warning: no debug messages here.
- */
- static void
- _init_snmp(void)
- {
- #ifdef HAVE_GETSERVBYNAME
- struct servent *servp;
- #endif
- static char have_done_init = 0;
- struct timeval tv;
- long tmpReqid, tmpMsgid;
- u_short s_port = SNMP_PORT;
- if (have_done_init)
- return;
- have_done_init = 1;
- Reqid = 1;
- snmp_res_init(); /* initialize the mt locking structures */
- #ifndef DISABLE_MIB_LOADING
- init_mib_internals();
- #endif /* DISABLE_MIB_LOADING */
- netsnmp_tdomain_init();
- 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
- netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_DEFAULT_PORT, s_port);
- netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
- #ifdef USE_REVERSE_ASNENCODING
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_REVERSE_ENCODE,
- DEFAULT_ASNENCODING_DIRECTION);
- #endif
- }
- /*
- * Initializes the session structure.
- * May perform one time minimal library initialization.
- * No MIB file processing is done via this call.
- */
- void
- snmp_sess_init(netsnmp_session * session)
- {
- _init_snmp();
- /*
- * initialize session to default values
- */
- memset(session, 0, sizeof(netsnmp_session));
- session->remote_port = SNMP_DEFAULT_REMPORT;
- session->timeout = SNMP_DEFAULT_TIMEOUT;
- session->retries = SNMP_DEFAULT_RETRIES;
- session->version = SNMP_DEFAULT_VERSION;
- session->securityModel = SNMP_DEFAULT_SECMODEL;
- session->rcvMsgMaxSize = SNMP_MAX_MSG_SIZE;
- session->flags |= SNMP_FLAGS_DONT_PROBE;
- }
- static void
- register_default_handlers(void)
- {
- netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
- netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
- netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
- #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
- netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
- #endif
- netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
- netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
- netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
- netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
- netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
- netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
- netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "clientaddr",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
- netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
- netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
- netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
- netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
- NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
- }
- void
- init_snmp_enums(void)
- {
- se_add_pair_to_slist("asntypes", strdup("integer"), ASN_INTEGER);
- se_add_pair_to_slist("asntypes", strdup("counter"), ASN_COUNTER);
- se_add_pair_to_slist("asntypes", strdup("uinteger"), ASN_GAUGE);
- se_add_pair_to_slist("asntypes", strdup("timeticks"), ASN_TIMETICKS);
- se_add_pair_to_slist("asntypes", strdup("counter64"), ASN_COUNTER64);
- se_add_pair_to_slist("asntypes", strdup("octet_str"), ASN_OCTET_STR);
- se_add_pair_to_slist("asntypes", strdup("ipaddress"), ASN_IPADDRESS);
- se_add_pair_to_slist("asntypes", strdup("opaque"), ASN_OPAQUE);
- se_add_pair_to_slist("asntypes", strdup("nsap"), ASN_NSAP);
- se_add_pair_to_slist("asntypes", strdup("object_id"), ASN_OBJECT_ID);
- se_add_pair_to_slist("asntypes", strdup("null"), ASN_NULL);
- #ifdef OPAQUE_SPECIAL_TYPES
- se_add_pair_to_slist("asntypes", strdup("opaque_counter64"),
- ASN_OPAQUE_COUNTER64);
- se_add_pair_to_slist("asntypes", strdup("opaque_u64"), ASN_OPAQUE_U64);
- se_add_pair_to_slist("asntypes", strdup("opaque_float"),
- ASN_OPAQUE_FLOAT);
- se_add_pair_to_slist("asntypes", strdup("opaque_double"),
- ASN_OPAQUE_DOUBLE);
- se_add_pair_to_slist("asntypes", strdup("opaque_i64"), ASN_OPAQUE_I64);
- #endif
- }
- /**
- * Calls the functions to do config file loading and mib module parsing
- * in the correct order.
- *
- * @param type label for the config file "type"
- *
- * @return void
- *
- * @see init_agent
- */
- void
- init_snmp(const char *type)
- {
- static int done_init = 0; /* To prevent double init's. */
- if (done_init) {
- return;
- }
- done_init = 1;
- /*
- * make the type available everywhere else
- */
- if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_APPTYPE)) {
- netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_APPTYPE, type);
- }
- _init_snmp();
- /*
- * set our current locale properly to initialize isprint() type functions
- */
- #ifdef HAVE_SETLOCALE
- setlocale(LC_CTYPE, "");
- #endif
- snmp_debug_init(); /* should be done first, to turn on debugging ASAP */
- netsnmp_container_init_list();
- init_callbacks();
- init_snmp_logging();
- snmp_init_statistics();
- register_mib_handlers();
- register_default_handlers();
- init_snmpv3(type);
- init_snmp_alarm();
- init_snmp_enum(type);
- init_snmp_enums();
- read_premib_configs();
- #ifndef DISABLE_MIB_LOADING
- init_mib();
- #endif /* DISABLE_MIB_LOADING */
- read_configs();
- } /* 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);
- }
- /**
- * Shuts down the application, saving any needed persistent storage,
- * and appropriate clean up.
- *
- * @param type Label for the config file "type" used
- *
- * @return void
- */
- void
- snmp_shutdown(const char *type)
- {
- snmp_store(type);
- snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
- snmp_alarm_unregister_all();
- snmp_close_sessions();
- #ifndef DISABLE_MIB_LOADING
- shutdown_mib();
- #endif /* DISABLE_MIB_LOADING */
- unregister_all_config_handlers();
- netsnmp_container_free_list();
- clear_sec_mod();
- clear_snmp_enum();
- netsnmp_clear_tdomain_list();
- clear_callback();
- netsnmp_ds_shutdown();
- }
- /*
- * Sets up the session with the snmp_session information provided by the user.
- * Then opens and binds the necessary low-level transport. A handle to the
- * created session is returned (this is NOT the same as the pointer passed to
- * snmp_open()). On any error, NULL is returned and snmp_errno is set to the
- * appropriate error code.
- */
- netsnmp_session *
- snmp_open(netsnmp_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
- */
- netsnmp_session *
- snmp_open_ex(netsnmp_session *session,
- int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
- void *, int),
- int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t),
- int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
- int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t *),
- int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
- u_char **, size_t *, 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->hook_realloc_build = frbuild;
- 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(netsnmp_session * in_session)
- {
- struct session_list *slp;
- struct snmp_internal_session *isp;
- netsnmp_session *session;
- struct snmp_secmod_def *sptr;
- 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);
- }
- slp->transport = 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->session = (netsnmp_session *)malloc(sizeof(netsnmp_session));
- if (slp->session == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- memmove(slp->session, in_session, sizeof(netsnmp_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 !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
- if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
- ucp = (u_char *) malloc(in_session->community_len);
- if (ucp != NULL)
- memmove(ucp, in_session->community, in_session->community_len);
- } else {
- if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
- session->community_len = strlen(cp);
- ucp = (u_char *) malloc(session->community_len);
- if (ucp)
- memmove(ucp, cp, session->community_len);
- } else {
- #ifdef NO_ZEROLENGTH_COMMUNITY
- session->community_len = strlen(DEFAULT_COMMUNITY);
- ucp = (u_char *) malloc(session->community_len);
- if (ucp)
- memmove(ucp, DEFAULT_COMMUNITY, 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 */
- #endif
- if (session->securityLevel <= 0) {
- session->securityLevel =
- netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
- }
- if (session->securityLevel == 0)
- session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
- if (in_session->securityAuthProtoLen > 0) {
- session->securityAuthProto =
- snmp_duplicate_objid(in_session->securityAuthProto,
- in_session->securityAuthProtoLen);
- if (session->securityAuthProto == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- } else if (get_default_authtype(&i) != NULL) {
- session->securityAuthProto =
- snmp_duplicate_objid(get_default_authtype(NULL), i);
- session->securityAuthProtoLen = i;
- }
- if (in_session->securityPrivProtoLen > 0) {
- session->securityPrivProto =
- snmp_duplicate_objid(in_session->securityPrivProto,
- in_session->securityPrivProtoLen);
- if (session->securityPrivProto == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- } else if (get_default_privtype(&i) != NULL) {
- session->securityPrivProto =
- snmp_duplicate_objid(get_default_privtype(NULL), i);
- session->securityPrivProtoLen = i;
- }
- if (in_session->securityEngineIDLen > 0) {
- ucp = (u_char *) malloc(in_session->securityEngineIDLen);
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- memmove(ucp, in_session->securityEngineID,
- in_session->securityEngineIDLen);
- session->securityEngineID = ucp;
- }
- if (in_session->contextEngineIDLen > 0) {
- ucp = (u_char *) malloc(in_session->contextEngineIDLen);
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- memmove(ucp, in_session->contextEngineID,
- in_session->contextEngineIDLen);
- session->contextEngineID = ucp;
- } else if (in_session->securityEngineIDLen > 0) {
- /*
- * default contextEngineID to securityEngineIDLen if defined
- */
- ucp = (u_char *) malloc(in_session->securityEngineIDLen);
- if (ucp == NULL) {
- snmp_sess_close(slp);
- in_session->s_snmp_errno = SNMPERR_MALLOC;
- return (NULL);
- }
- memmove(ucp, in_session->securityEngineID,
- in_session->securityEngineIDLen);
- 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 = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_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 = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_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 = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_AUTHMASTERKEY)))) {
- size_t buflen = sizeof(session->securityAuthKey);
- u_char *tmpp = session->securityAuthKey;
- session->securityAuthKeyLen = 0;
- /* it will be a hex string */
- if (!snmp_hex_to_binary(&tmpp, &buflen,
- &session->securityAuthKeyLen, 0, cp)) {
- snmp_set_detail("error parsing authentication master key");
- snmp_sess_close(slp);
- return NULL;
- }
- } else if ((in_session->securityAuthKeyLen <= 0) &&
- ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_AUTHPASSPHRASE)) ||
- (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PASSPHRASE)))) {
- 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 a key (Ku) from the supplied authentication pass phrase.");
- snmp_sess_close(slp);
- return NULL;
- }
- }
-
- if ((in_session->securityPrivKeyLen <= 0) &&
- ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRIVMASTERKEY)))) {
- size_t buflen = sizeof(session->securityPrivKey);
- u_char *tmpp = session->securityPrivKey;
- session->securityPrivKeyLen = 0;
- /* it will be a hex string */
- if (!snmp_hex_to_binary(&tmpp, &buflen,
- &session->securityPrivKeyLen, 0, cp)) {
- snmp_set_detail("error parsing encryption master key");
- snmp_sess_close(slp);
- return NULL;
- }
- } else if ((in_session->securityPrivKeyLen <= 0) &&
- ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRIVPASSPHRASE)) ||
- (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PASSPHRASE)))) {
- 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 a key (Ku) from the supplied 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();
- snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
- session);
- if ((sptr = find_sec_mod(session->securityModel)) != NULL &&
- sptr->session_open != NULL) {
- /*
- * security module specific inialization
- */
- (*sptr->session_open) (session);
- }
- return (slp);
- }
- static struct session_list *
- snmp_sess_copy(netsnmp_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;
- }
- /**
- * probe for peer engineID
- *
- * @param slp session list pointer.
- * @param in_session session for errors
- *
- * @note
- * - called by _sess_open(), snmp_sess_add_ex()
- * - in_session is the user supplied session provided to those functions.
- * - the first session in slp should the internal allocated copy of in_session
- *
- * @return 0 : error
- * @return 1 : ok
- *
- */
- int
- snmpv3_engineID_probe(struct session_list *slp,
- netsnmp_session * in_session)
- {
- netsnmp_pdu *pdu = NULL, *response = NULL;
- netsnmp_session *session;
- unsigned int i;
- int status;
- if (slp == NULL || slp->session == NULL) {
- return 0;
- }
- session = slp->session;
- /*
- * 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->flags & SNMP_FLAGS_DONT_PROBE) == SNMP_FLAGS_DONT_PROBE)
- return 1;
- if (session->version == SNMP_VERSION_3) {
- if (session->securityEngineIDLen == 0) {
- if (snmpv3_build_probe_pdu(&pdu) != 0) {
- DEBUGMSGTL(("snmp_api", "unable to create probe PDUn"));
- return 0;
- }
- DEBUGMSGTL(("snmp_api", "probing for engineID...n"));
- session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
- 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"));
- return 0;
- }
- 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"));
- return 0;
- }
- }
- return 1;
- }
- /*******************************************************************-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(netsnmp_session * in_session)
- {
- struct session_list *slp;
- netsnmp_session *session;
- char *clientaddr_save = NULL;
- in_session->s_snmp_errno = 0;
- in_session->s_errno = 0;
- _init_snmp();
- if ((slp = snmp_sess_copy(in_session)) == NULL) {
- return (NULL);
- }
- session = slp->session;
- slp->transport = NULL;
- if (NULL != session->localname) {
- clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_CLIENT_ADDR);
- netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_CLIENT_ADDR, session->localname);
- }
- if (session->flags & SNMP_FLAGS_STREAM_SOCKET) {
- slp->transport = netsnmp_tdomain_transport(session->peername,
- session->local_port,
- "tcp");
- } else {
- slp->transport = netsnmp_tdomain_transport(session->peername,
- session->local_port,
- "udp");
- }
- if (NULL != session->localname)
- netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
- if (slp->transport == NULL) {
- DEBUGMSGTL(("_sess_open", "couldn't interpret peernamen"));
- in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
- in_session->s_errno = errno;
- snmp_set_detail(session->peername);
- snmp_sess_close(slp);
- return NULL;
- }
- session->rcvMsgMaxSize = slp->transport->msgMaxSize;
- if (!snmpv3_engineID_probe(slp, in_session)) {
- snmp_sess_close(slp);
- return 0;
- }
- session->flags &= ~SNMP_FLAGS_DONT_PROBE;
- return (void *) slp;
- } /* end snmp_sess_open() */
- /*
- * EXPERIMENTAL API EXTENSIONS ------------------------------------------
- *
- * snmp_sess_add_ex, snmp_sess_add, snmp_add
- *
- * Analogous to snmp_open family of functions, but taking a netsnmp_transport
- * pointer as an extra argument. Unlike snmp_open et al. it doesn't attempt
- * to interpret the in_session->peername as a transport endpoint specifier,
- * but instead uses the supplied transport. JBPN
- *
- */
- netsnmp_session *
- snmp_add(netsnmp_session * in_session,
- netsnmp_transport *transport,
- int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
- int), int (*fpost_parse) (netsnmp_session *,
- netsnmp_pdu *, int))
- {
- struct session_list *slp;
- slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
- fpre_parse, NULL,
- fpost_parse, NULL, NULL,
- NULL, NULL);
- if (slp == NULL) {
- 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);
- }
- netsnmp_session *
- snmp_add_full(netsnmp_session * in_session,
- netsnmp_transport *transport,
- int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
- void *, int),
- int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t),
- int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
- int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t *), int (*frbuild) (netsnmp_session *,
- netsnmp_pdu *,
- u_char **,
- size_t *,
- size_t *),
- int (*fcheck) (u_char *, size_t),
- netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
- size_t))
- {
- struct session_list *slp;
- slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
- fpre_parse, fparse,
- fpost_parse, fbuild,
- frbuild, fcheck,
- fcreate_pdu);
- if (slp == NULL) {
- 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);
- }
- void *
- snmp_sess_add_ex(netsnmp_session * in_session,
- netsnmp_transport *transport,
- int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
- void *, int),
- int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t),
- int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
- int),
- int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
- size_t *),
- int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
- u_char **, size_t *, size_t *),
- int (*fcheck) (u_char *, size_t),
- netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
- size_t))
- {
- struct session_list *slp;
- _init_snmp();
- if (in_session == NULL || transport == NULL) {
- return NULL;
- }
- DEBUGMSGTL(("snmp_sess_add", "fd %dn", transport->sock));
- if ((slp = snmp_sess_copy(in_session)) == NULL) {
- return (NULL);
- }
- slp->transport = transport;
- slp->internal->hook_pre = fpre_parse;
- slp->internal->hook_parse = fparse;
- slp->internal->hook_post = fpost_parse;
- slp->internal->hook_build = fbuild;
- slp->internal->hook_realloc_build = frbuild;
- slp->internal->check_packet = fcheck;
- slp->internal->hook_create_pdu = fcreate_pdu;
- slp->session->rcvMsgMaxSize = transport->msgMaxSize;
- if (slp->session->version == SNMP_VERSION_3) {
- DEBUGMSGTL(("snmp_sess_add",
- "adding v3 session -- engineID probe nown"));
- if (!snmpv3_engineID_probe(slp, in_session)) {
- DEBUGMSGTL(("snmp_sess_add", "engine ID probe failedn"));
- snmp_sess_close(slp);
- slp = NULL;
- }
- }
- return (void *) slp;
- } /* end snmp_sess_add_ex() */
- void *
- snmp_sess_add(netsnmp_session * in_session,
- netsnmp_transport *transport,
- int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
- void *, int),
- int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
- {
- return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
- fpost_parse, NULL, NULL, NULL, NULL);
- }
- void *
- snmp_sess_open(netsnmp_session * pss)
- {
- void *pvoid;
- pvoid = _sess_open(pss);
- if (!pvoid) {
- SET_SNMP_ERROR(pss->s_snmp_errno);
- }
- return pvoid;
- }
- /*
- * create_user_from_session(netsnmp_session *session):
- *
- * creates a user in the usm table from the information in a session.
- * If the user already exists, it is updated with the current
- * information from the session
- *
- * Parameters:
- * session -- IN: pointer to the session to use when creating the user.
- *
- * Returns:
- * SNMPERR_SUCCESS
- * SNMPERR_GENERR
- */
- int
- create_user_from_session(netsnmp_session * session)
- {
- struct usmUser *user;
- int user_just_created = 0;
- u_char *cp;
- /*
- * 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 (memdup(&user->engineID, session->securityEngineID,
- session->securityEngineIDLen) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->engineIDLen = session->securityEngineIDLen;
- user_just_created = 1;
- }
- /*
- * copy the auth protocol
- */
- if (session->securityAuthProto != NULL) {
- SNMP_FREE(user->authProtocol);
- 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) {
- SNMP_FREE(user->privProtocol);
- 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. If not localized, localize it
- */
- if (session->securityAuthLocalKey != NULL
- && session->securityAuthLocalKeyLen != 0) {
- /* already localized key passed in. use it */
- if (memdup(&user->authKey, session->securityAuthLocalKey,
- session->securityAuthLocalKeyLen) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->authKeyLen = session->securityAuthLocalKeyLen;
- } else if (session->securityAuthKey != NULL
- && session->securityAuthKeyLen != 0) {
- SNMP_FREE(user->authKey);
- user->authKey = (u_char *) calloc(1, 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;
- }
- } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_AUTHLOCALIZEDKEY))) {
- size_t buflen = USM_AUTH_KU_LEN;
- user->authKey = malloc(buflen); /* max length needed */
- user->authKeyLen = 0;
- /* it will be a hex string */
- if (!snmp_hex_to_binary(&user->authKey, &buflen, &user->authKeyLen,
- 0, cp)) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- }
- /*
- * copy in the privacy Key. If not localized, localize it
- */
- if (session->securityPrivLocalKey != NULL
- && session->securityPrivLocalKeyLen != 0) {
- /* already localized key passed in. use it */
- if (memdup(&user->privKey, session->securityPrivLocalKey,
- session->securityPrivLocalKeyLen) != SNMPERR_SUCCESS) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- user->privKeyLen = session->securityPrivLocalKeyLen;
- } else if (session->securityPrivKey != NULL
- && session->securityPrivKeyLen != 0) {
- SNMP_FREE(user->privKey);
- user->privKey = (u_char *) calloc(1, 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;
- }
- } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRIVLOCALIZEDKEY))) {
- size_t buflen = USM_PRIV_KU_LEN;
- user->privKey = malloc(buflen); /* max length needed */
- user->privKeyLen = 0;
- /* it will be a hex string */
- if (!snmp_hex_to_binary(&user->privKey, &buflen, &user->privKeyLen,
- 0, cp)) {
- usm_free_user(user);
- return SNMPERR_GENERR;
- }
- }
- user->userStatus = RS_ACTIVE;
- user->userStorageType = ST_READONLY;
- if (user_just_created) {
- /*
- * add the user into the database
- */
- usm_add_user(user);
- }
- return SNMPERR_SUCCESS;
- } /* end create_user_from_session() */
- /*
- * Do a "deep free()" of a netsnmp_session.
- *
- * CAUTION: SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
- * (hence it is static)
- */
- static void
- snmp_free_session(netsnmp_session * s)
- {
- if (s) {
- SNMP_FREE(s->peername);
- SNMP_FREE(s->community);
- SNMP_FREE(s->contextEngineID);
- SNMP_FREE(s->contextName);
- SNMP_FREE(s->securityEngineID);
- SNMP_FREE(s->securityName);
- SNMP_FREE(s->securityAuthProto);
- SNMP_FREE(s->securityPrivProto);
- /*
- * clear session from any callbacks
- */
- netsnmp_callback_clear_client_arg(s, 0, 0);
- free((char *) s);
- }
- }
- /*
- * 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;
- netsnmp_transport *transport;
- struct snmp_internal_session *isp;
- netsnmp_session *sesp = NULL;
- struct snmp_secmod_def *sptr;
- if (slp == NULL) {
- return 0;
- }
- if (slp->session != NULL &&
- (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
- sptr->session_close != NULL) {
- (*sptr->session_close) (slp->session);
- }
- isp = slp->internal;
- slp->internal = 0;
- if (isp) {
- netsnmp_request_list *rp, *orp;
- SNMP_FREE(isp->packet);
- /*
- * 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((char *) orp);
- }
- free((char *) isp);
- }
- transport = slp->transport;
- slp->transport = 0;
- if (transport) {
- transport->f_close(transport);
- netsnmp_transport_free(transport);
- }
- sesp = slp->session;
- slp->session = 0;
- /*
- * The following is necessary to avoid memory leakage when closing AgentX
- * sessions that may have multiple subsessions. These hang off the main
- * session at ->subsession, and chain through ->next.
- */
- if (sesp != NULL && sesp->subsession != NULL) {
- netsnmp_session *subsession = sesp->subsession, *tmpsub;
- while (subsession != NULL) {
- DEBUGMSGTL(("snmp_sess_close",
- "closing session %p, subsession %pn", sesp,
- subsession));
- tmpsub = subsession->next;
- snmp_free_session(subsession);
- subsession = tmpsub;
- }
- }
- snmp_free_session(sesp);
- free((char *) slp);
- return 1;
- }
- int
- snmp_close(netsnmp_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(netsnmp_pdu **pdu)
- {
- struct usmUser *user;
- /*
- * create the pdu
- */
- if (!pdu)
- return -1;
- *pdu = snmp_pdu_create(SNMP_MSG_GET);
- if (!(*pdu))
- 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 = (netsnmp_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);
- 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(netsnmp_request_list *rp, netsnmp_pdu *pdu)
- {
- netsnmp_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(u_char ** pkt, size_t * pkt_len, size_t * offset,
- netsnmp_session * session, netsnmp_pdu *pdu)
- {
- 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:
- netsnmp_assert(0 == (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;
- }
- /* Do we need to set the session security engineid? */
- if (pdu->securityEngineIDLen == 0) {
- if (session->securityEngineIDLen) {
- snmpv3_clone_engineID(&pdu->securityEngineID,
- &pdu->securityEngineIDLen,
- session->securityEngineID,
- session->securityEngineIDLen);
- }
- }
-
- /* Do we need to set the session context engineid? */
- 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;
- }
- if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
- pdu->securityModel = session->securityModel;
- if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
- 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")), secLevelName[pdu->securityLevel]));
- DEBUGDUMPSECTION("send", "SNMPv3 Message");
- #ifdef USE_REVERSE_ASNENCODING
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
- ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
- session, pdu, NULL, 0);
- } else {
- #endif
- ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
- #ifdef USE_REVERSE_ASNENCODING
- }
- #endif
- DEBUGINDENTLESS();
- if (-1 != ret) {
- session->s_snmp_errno = ret;
- }
- return ret;
- } /* end snmpv3_build() */
- static u_char *
- snmpv3_header_build(netsnmp_session * session, netsnmp_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
- */
- DEBUGDUMPHEADER("send", "SNMP Version Number");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), (long *) &pdu->version,
- sizeof(pdu->version));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- global_hdr = cp;
- /*
- * msgGlobalData HeaderData
- */
- DEBUGDUMPSECTION("send", "msgGlobalData");
- cp = asn_build_sequence(cp, out_length,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
- if (cp == NULL)
- return NULL;
- global_hdr_e = cp;
- /*
- * msgID
- */
- DEBUGDUMPHEADER("send", "msgID");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &pdu->msgid,
- sizeof(pdu->msgid));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * msgMaxSize
- */
- max_size = session->rcvMsgMaxSize;
- DEBUGDUMPHEADER("send", "msgMaxSize");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &max_size,
- sizeof(max_size));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * msgFlags
- */
- snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
- DEBUGDUMPHEADER("send", "msgFlags");
- cp = asn_build_string(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), &msg_flags,
- sizeof(msg_flags));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * msgSecurityModel
- */
- sec_model = pdu->securityModel;
- DEBUGDUMPHEADER("send", "msgSecurityModel");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &sec_model,
- sizeof(sec_model));
- DEBUGINDENTADD(-4); /* return from global data indent */
- 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() */
- #ifdef USE_REVERSE_ASNENCODING
- int
- snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
- size_t * offset, netsnmp_session * session,
- netsnmp_pdu *pdu)
- {
- size_t start_offset = *offset;
- u_char msg_flags;
- long max_size, sec_model;
- int rc = 0;
- /*
- * msgSecurityModel.
- */
- sec_model = pdu->securityModel;
- DEBUGDUMPHEADER("send", "msgSecurityModel");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &sec_model,
- sizeof(sec_model));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * msgFlags.
- */
- snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
- DEBUGDUMPHEADER("send", "msgFlags");
- rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR), &msg_flags,
- sizeof(msg_flags));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * msgMaxSize.
- */
- max_size = session->rcvMsgMaxSize;
- DEBUGDUMPHEADER("send", "msgMaxSize");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &max_size,
- sizeof(max_size));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * msgID.
- */
- DEBUGDUMPHEADER("send", "msgID");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &pdu->msgid,
- sizeof(pdu->msgid));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Global data sequence.
- */
- rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR),
- *offset - start_offset);
- if (rc == 0) {
- return 0;
- }
- /*
- * Store the version field - msgVersion.
- */
- DEBUGDUMPHEADER("send", "SNMP Version Number");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER),
- (long *) &pdu->version,
- sizeof(pdu->version));
- DEBUGINDENTLESS();
- return rc;
- } /* end snmpv3_header_realloc_rbuild() */
- #endif /* USE_REVERSE_ASNENCODING */
- static u_char *
- snmpv3_scopedPDU_header_build(netsnmp_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;
- DEBUGDUMPHEADER("send", "contextEngineID");
- pb = asn_build_string(pb, out_length,
- (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
- pdu->contextEngineID, pdu->contextEngineIDLen);
- DEBUGINDENTLESS();
- if (pb == NULL)
- return NULL;
- DEBUGDUMPHEADER("send", "contextName");
- pb = asn_build_string(pb, out_length,
- (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
- (u_char *) pdu->contextName,
- pdu->contextNameLen);
- DEBUGINDENTLESS();
- if (pb == NULL)
- return NULL;
- return pb;
- } /* end snmpv3_scopedPDU_header_build() */
- #ifdef USE_REVERSE_ASNENCODING
- int
- snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
- size_t * offset, netsnmp_pdu *pdu,
- size_t body_len)
- {
- size_t start_offset = *offset;
- int rc = 0;
- /*
- * contextName.
- */
- DEBUGDUMPHEADER("send", "contextName");
- rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- (u_char *) pdu->contextName,
- pdu->contextNameLen);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * contextEngineID.
- */
- DEBUGDUMPHEADER("send", "contextEngineID");
- rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR),
- pdu->contextEngineID,
- pdu->contextEngineIDLen);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR),
- *offset - start_offset + body_len);
- return rc;
- } /* end snmpv3_scopedPDU_header_realloc_rbuild() */
- #endif /* USE_REVERSE_ASNENCODING */
- #ifdef USE_REVERSE_ASNENCODING
- /*
- * returns 0 if success, -1 if fail, not 0 if SM build failure
- */
- int
- snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
- size_t * offset, netsnmp_session * session,
- netsnmp_pdu *pdu, u_char * pdu_data,
- size_t pdu_data_len)
- {
- u_char *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
- size_t hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
- 0, spdu_offset = 0;
- size_t body_end_offset = *offset, body_len = 0;
- struct snmp_secmod_def *sptr = NULL;
- int rc = 0;
- /*
- * Build a scopedPDU structure into the packet buffer.
- */
- DEBUGPRINTPDUTYPE("send", pdu->command);
- if (pdu_data) {
- while ((*pkt_len - *offset) < pdu_data_len) {
- if (!asn_realloc(pkt, pkt_len)) {
- return -1;
- }
- }
- *offset += pdu_data_len;
- memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
- } else {
- rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
- if (rc == 0) {
- return -1;
- }
- }
- body_len = *offset - body_end_offset;
- DEBUGDUMPSECTION("send", "ScopedPdu");
- rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
- pdu, body_len);
- if (rc == 0) {
- return -1;
- }
- spdu_offset = *offset;
- DEBUGINDENTADD(-4); /* Return from Scoped PDU. */
- if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
- return -1;
- }
- rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
- session, pdu);
- if (rc == 0) {
- SNMP_FREE(hdrbuf);
- return -1;
- }
- hdr = hdrbuf + hdrbuf_len - hdr_offset;
- scoped_pdu = *pkt + *pkt_len - spdu_offset;
- /*
- * Call the security module to possibly encrypt and authenticate the
- * message---the entire message to transmitted on the wire is returned.
- */
- sptr = find_sec_mod(pdu->securityModel);
- DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
- if (sptr && sptr->encode_reverse) {
- struct snmp_secmod_outgoing_params parms;
- parms.msgProcModel = pdu->msgParseModel;
- parms.globalData = hdr;
- parms.globalDataLen = hdr_offset;
- parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
- parms.secModel = pdu->securityModel;
- parms.secEngineID = pdu->securityEngineID;
- parms.secEngineIDLen = pdu->securityEngineIDLen;
- parms.secName = pdu->securityName;
- parms.secNameLen = pdu->securityNameLen;
- parms.secLevel = pdu->securityLevel;
- parms.scopedPdu = scoped_pdu;
- parms.scopedPduLen = spdu_offset;
- parms.secStateRef = pdu->securityStateRef;
- parms.wholeMsg = pkt;
- parms.wholeMsgLen = pkt_len;
- parms.wholeMsgOffset = offset;
- parms.session = session;
- parms.pdu = pdu;
- rc = (*sptr->encode_reverse) (&parms);
- } else {
- if (!sptr) {
- snmp_log(LOG_ERR,
- "no such security service available: %dn",
- pdu->securityModel);
- } else if (!sptr->encode_reverse) {
- snmp_log(LOG_ERR,
- "security service %d doesn't support reverse encoding.n",
- pdu->securityModel);
- }
- rc = -1;
- }
- DEBUGINDENTLESS();
- SNMP_FREE(hdrbuf);
- return rc;
- } /* end snmpv3_packet_realloc_rbuild() */
- #endif /* USE_REVERSE_ASNENCODING */
- /*
- * returns 0 if success, -1 if fail, not 0 if SM build failure
- */
- int
- snmpv3_packet_build(netsnmp_session * session, netsnmp_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;
- struct snmp_secmod_def *sptr;
- global_data = packet;
- /*
- * build the headers for the packet, returned addr = start of secParams
- */
- sec_params = snmpv3_header_build(session, 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;
- DEBUGDUMPSECTION("send", "ScopedPdu");
- 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
- */
- DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
- 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;
- }
- DEBUGINDENTADD(-4); /* return from Scoped PDU */
- /*
- * 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;
- DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
- sptr = find_sec_mod(pdu->securityModel);
- if (sptr && sptr->encode_forward) {
- struct snmp_secmod_outgoing_params parms;
- parms.msgProcModel = pdu->msgParseModel;
- parms.globalData = global_data;
- parms.globalDataLen = global_data_len;
- parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
- parms.secModel = pdu->securityModel;
- parms.secEngineID = pdu->securityEngineID;
- parms.secEngineIDLen = pdu->securityEngineIDLen;
- parms.secName = pdu->securityName;
- parms.secNameLen = pdu->securityNameLen;
- parms.secLevel = pdu->securityLevel;
- parms.scopedPdu = spdu_buf;
- parms.scopedPduLen = spdu_len;
- parms.secStateRef = pdu->securityStateRef;
- parms.secParams = sec_params;
- parms.secParamsLen = &sec_params_len;
- parms.wholeMsg = &cp;
- parms.wholeMsgLen = out_length;
- parms.session = session;
- parms.pdu = pdu;
- result = (*sptr->encode_forward) (&parms);
- } else {
- if (!sptr) {
- snmp_log(LOG_ERR, "no such security service available: %dn",
- pdu->securityModel);
- } else if (!sptr->encode_forward) {
- snmp_log(LOG_ERR,
- "security service %d doesn't support forward out encoding.n",
- pdu->securityModel);
- }
- result = -1;
- }
- DEBUGINDENTLESS();
- return result;
- } /* end snmpv3_packet_build() */
- /*
- * Takes a session and a pdu and serializes the ASN PDU into the area
- * pointed to by *pkt. *pkt_len is the size of the data area available.
- * Returns the length of the completed packet in *offset. If any errors
- * occur, -1 is returned. If all goes well, 0 is returned.
- */
- static int
- _snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
- netsnmp_session * session, netsnmp_pdu *pdu)
- {
- #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
- u_char *h0e = 0;
- size_t start_offset = *offset;
- long version;
- int rc = 0;
- #endif /* support for community based SNMP */
-
- u_char *h0, *h1;
- u_char *cp;
- size_t length;
- session->s_snmp_errno = 0;
- session->s_errno = 0;
- if (pdu->version == SNMP_VERSION_3) {
- return snmpv3_build(pkt, pkt_len, offset, session, pdu);
- }
- switch (pdu->command) {
- case SNMP_MSG_RESPONSE:
- netsnmp_assert(0 == (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:
- netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
- /*
- * Fallthrough
- */
- case SNMP_MSG_INFORM:
- #ifndef DISABLE_SNMPV1
- /*
- * not supported in SNMPv1 and SNMPsec
- */
- if (pdu->version == SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V2_IN_V1;
- return -1;
- }
- #endif
- 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
- */
- #ifndef DISABLE_SNMPV1
- if (pdu->version == SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V2_IN_V1;
- return -1;
- }
- #endif
- 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
- */
- #ifndef DISABLE_SNMPV1
- if (pdu->version != SNMP_VERSION_1) {
- session->s_snmp_errno = SNMPERR_V1_IN_V2;
- return -1;
- }
- #endif
- /*
- * 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 = *pkt_len;
- /*
- * 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 = *pkt;
- switch (pdu->version) {
- #ifndef DISABLE_SNMPV1
- case SNMP_VERSION_1:
- #endif
- #ifndef DISABLE_SNMPV2C
- case SNMP_VERSION_2c:
- #endif
- #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
- #ifdef NO_ZEROLENGTH_COMMUNITY
- if (pdu->community_len == 0) {
- if (session->community_len == 0) {
- session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
- return -1;
- }
- pdu->community = (u_char *) malloc(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_len = session->community_len;
- }
- #else /* !NO_ZEROLENGTH_COMMUNITY */
- if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
- /*
- * copy session community exactly to pdu community
- */
- if (0 == session->community_len) {
- SNMP_FREE(pdu->community);
- pdu->community = NULL;
- } 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(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_len = session->community_len;
- }
- #endif /* !NO_ZEROLENGTH_COMMUNITY */
- DEBUGMSGTL(("snmp_send", "Building SNMPv%d message...n",
- (1 + pdu->version)));
- #ifdef USE_REVERSE_ASNENCODING
- if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
- DEBUGPRINTPDUTYPE("send", pdu->command);
- rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
- if (rc == 0) {
- return -1;
- }
- DEBUGDUMPHEADER("send", "Community String");
- rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_OCTET_STR),
- pdu->community,
- pdu->community_len);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return -1;
- }
- /*
- * Store the version field.
- */
- DEBUGDUMPHEADER("send", "SNMP Version Number");
- version = pdu->version;
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_INTEGER),
- (long *) &version,
- sizeof(version));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return -1;
- }
- /*
- * Build the final sequence.
- */
- if (pdu->version == SNMP_VERSION_1) {
- DEBUGDUMPSECTION("send", "SNMPv1 Message");
- } else {
- DEBUGDUMPSECTION("send", "SNMPv2c Message");
- }
- rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR),
- *offset - start_offset);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return -1;
- }
- return 0;
- } else {
- #endif /* USE_REVERSE_ASNENCODING */
- /*
- * Save current location and build SEQUENCE tag and length
- * placeholder for SNMP message sequence
- * (actual length will be inserted later)
- */
- cp = asn_build_sequence(*pkt, pkt_len,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR), 0);
- if (cp == NULL) {
- return -1;
- }
- h0e = cp;
- if (pdu->version == SNMP_VERSION_1) {
- DEBUGDUMPSECTION("send", "SNMPv1 Message");
- } else {
- DEBUGDUMPSECTION("send", "SNMPv2c Message");
- }
- /*
- * store the version field
- */
- DEBUGDUMPHEADER("send", "SNMP Version Number");
- version = pdu->version;
- cp = asn_build_int(*pkt, pkt_len,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), (long *) &version,
- sizeof(version));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return -1;
- /*
- * store the community string
- */
- DEBUGDUMPHEADER("send", "Community String");
- cp = asn_build_string(*pkt, pkt_len,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OCTET_STR), pdu->community,
- pdu->community_len);
- DEBUGINDENTLESS();
- if (cp == NULL)
- return -1;
- break;
- #ifdef USE_REVERSE_ASNENCODING
- }
- #endif /* USE_REVERSE_ASNENCODING */
- break;
- #endif /* support for community based SNMP */
- 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;
- DEBUGPRINTPDUTYPE("send", pdu->command);
- cp = snmp_pdu_build(pdu, cp, pkt_len);
- DEBUGINDENTADD(-4); /* return from entire v1/v2c message */
- if (cp == NULL)
- return -1;
- /*
- * insert the actual length of the message sequence
- */
- switch (pdu->version) {
- #ifndef DISABLE_SNMPV1
- case SNMP_VERSION_1:
- #endif
- #ifndef DISABLE_SNMPV2C
- case SNMP_VERSION_2c:
- #endif
- #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
- asn_build_sequence(*pkt, &length,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- cp - h0e);
- break;
- #endif /* support for community based SNMP */
- 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;
- }
- *pkt_len = cp - *pkt;
- return 0;
- }
- int
- snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
- netsnmp_session * pss, netsnmp_pdu *pdu)
- {
- int rc;
- rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
- 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(netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
- {
- u_char *h1, *h1e, *h2, *h2e;
- netsnmp_variable_list *vp;
- 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
- */
- DEBUGDUMPHEADER("send", "request_id");
- /*
- * request id
- */
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &pdu->reqid,
- sizeof(pdu->reqid));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * error status (getbulk non-repeaters)
- */
- DEBUGDUMPHEADER("send", "error status");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &pdu->errstat,
- sizeof(pdu->errstat));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * error index (getbulk max-repetitions)
- */
- DEBUGDUMPHEADER("send", "error index");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER), &pdu->errindex,
- sizeof(pdu->errindex));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- } else {
- /*
- * an SNMPv1 trap PDU
- */
- /*
- * enterprise
- */
- DEBUGDUMPHEADER("send", "enterprise OBJID");
- cp = asn_build_objid(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_OBJECT_ID),
- (oid *) pdu->enterprise,
- pdu->enterprise_length);
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * agent-addr
- */
- DEBUGDUMPHEADER("send", "agent Address");
- cp = asn_build_string(cp, out_length,
- (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
- (u_char *) pdu->agent_addr, 4);
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * generic trap
- */
- DEBUGDUMPHEADER("send", "generic trap number");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER),
- (long *) &pdu->trap_type,
- sizeof(pdu->trap_type));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * specific trap
- */
- DEBUGDUMPHEADER("send", "specific trap number");
- cp = asn_build_int(cp, out_length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
- ASN_INTEGER),
- (long *) &pdu->specific_type,
- sizeof(pdu->specific_type));
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- /*
- * timestamp
- */
- DEBUGDUMPHEADER("send", "timestamp");
- cp = asn_build_unsigned_int(cp, out_length,
- (u_char) (ASN_TIMETICKS |
- ASN_PRIMITIVE), &pdu->time,
- sizeof(pdu->time));
- DEBUGINDENTLESS();
- 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
- */
- DEBUGDUMPSECTION("send", "VarBindList");
- for (vp = pdu->variables; vp; vp = vp->next_variable) {
- DEBUGDUMPSECTION("send", "VarBind");
- cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
- vp->val_len, (u_char *) vp->val.string,
- out_length);
- DEBUGINDENTLESS();
- if (cp == NULL)
- return NULL;
- }
- DEBUGINDENTLESS();
- /*
- * 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;
- }
- #ifdef USE_REVERSE_ASNENCODING
- /*
- * On error, returns 0 (likely an encoding problem).
- */
- int
- snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
- netsnmp_pdu *pdu)
- {
- #ifndef VPCACHE_SIZE
- #define VPCACHE_SIZE 50
- #endif
- netsnmp_variable_list *vpcache[VPCACHE_SIZE];
- netsnmp_variable_list *vp, *tmpvp;
- size_t start_offset = *offset;
- int i, wrapped = 0, notdone, final, rc = 0;
- DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "startingn"));
- for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
- vp = vp->next_variable, i--) {
- if (i < 0) {
- wrapped = notdone = 1;
- i = VPCACHE_SIZE - 1;
- DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrappedn"));
- }
- vpcache[i] = vp;
- }
- final = i + 1;
- do {
- for (i = final; i < VPCACHE_SIZE; i++) {
- vp = vpcache[i];
- DEBUGDUMPSECTION("send", "VarBind");
- rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
- vp->name, &vp->name_length,
- vp->type,
- (u_char *) vp->val.string,
- vp->val_len);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- }
- DEBUGINDENTLESS();
- if (wrapped) {
- notdone = 1;
- for (i = 0; i < final; i++) {
- vp = vpcache[i];
- DEBUGDUMPSECTION("send", "VarBind");
- rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
- vp->name, &vp->name_length,
- vp->type,
- (u_char *) vp->val.string,
- vp->val_len);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- }
- if (final == 0) {
- tmpvp = vpcache[VPCACHE_SIZE - 1];
- } else {
- tmpvp = vpcache[final - 1];
- }
- wrapped = 0;
- for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
- vp && vp != tmpvp; vp = vp->next_variable, i--) {
- if (i < 0) {
- wrapped = 1;
- i = VPCACHE_SIZE - 1;
- DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrappedn"));
- }
- vpcache[i] = vp;
- }
- final = i + 1;
- } else {
- notdone = 0;
- }
- } while (notdone);
- /*
- * Save current location and build SEQUENCE tag and length placeholder for
- * variable-bindings sequence (actual length will be inserted later).
- */
- rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
- (u_char) (ASN_SEQUENCE |
- ASN_CONSTRUCTOR),
- *offset - start_offset);
- /*
- * Store fields in the PDU preceeding the variable-bindings sequence.
- */
- if (pdu->command != SNMP_MSG_TRAP) {
- /*
- * Error index (getbulk max-repetitions).
- */
- DEBUGDUMPHEADER("send", "error index");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_INTEGER),
- &pdu->errindex, sizeof(pdu->errindex));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Error status (getbulk non-repeaters).
- */
- DEBUGDUMPHEADER("send", "error status");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_INTEGER),
- &pdu->errstat, sizeof(pdu->errstat));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Request ID.
- */
- DEBUGDUMPHEADER("send", "request_id");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_INTEGER), &pdu->reqid,
- sizeof(pdu->reqid));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- } else {
- /*
- * An SNMPv1 trap PDU.
- */
- /*
- * Timestamp.
- */
- DEBUGDUMPHEADER("send", "timestamp");
- rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_TIMETICKS |
- ASN_PRIMITIVE),
- &pdu->time,
- sizeof(pdu->time));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Specific trap.
- */
- DEBUGDUMPHEADER("send", "specific trap number");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_INTEGER),
- (long *) &pdu->specific_type,
- sizeof(pdu->specific_type));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Generic trap.
- */
- DEBUGDUMPHEADER("send", "generic trap number");
- rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_INTEGER),
- (long *) &pdu->trap_type,
- sizeof(pdu->trap_type));
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Agent-addr.
- */
- DEBUGDUMPHEADER("send", "agent Address");
- rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
- (u_char) (ASN_IPADDRESS |
- ASN_PRIMITIVE),
- (u_char *) pdu->agent_addr, 4);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- /*
- * Enterprise.
- */
- DEBUGDUMPHEADER("send", "enterprise OBJID");
- rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
- (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_OBJECT_ID),
- (oid *) pdu->enterprise,
- pdu->enterprise_length);
- DEBUGINDENTLESS();
- if (rc == 0) {
- return 0;
- }
- }
- /*
- * Build the PDU sequence.
- */
- rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
- (u_char) pdu->command,
- *offset - start_offset);
- return rc;
- }
- #endif /* USE_REVERSE_ASNENCODING */
- /*
- * 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 || type != ASN_INTEGER) {
- return SNMPERR_BAD_VERSION;
- }
- }
- return version;
- }
- int
- snmpv3_parse(netsnmp_pdu *pdu,
- u_char * data,
- size_t * length,
- u_char ** after_header, netsnmp_session * sess)
- {
- 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];
- u_char *mallocbuf = NULL;
- 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;
- struct snmp_secmod_def *sptr;
- msg_data = data;
- msg_len = *length;