snmp_api.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:217k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /* Portions of this file are subject to the following copyright(s).  See
  2.  * the Net-SNMP's COPYING file for more details and other copyrights
  3.  * that may apply:
  4.  */
  5. /******************************************************************
  6. Copyright 1989, 1991, 1992 by Carnegie Mellon University
  7.                       All Rights Reserved
  8. Permission to use, copy, modify, and distribute this software and its
  9. documentation for any purpose and without fee is hereby granted,
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in
  12. supporting documentation, and that the name of CMU not be
  13. used in advertising or publicity pertaining to distribution of the
  14. software without specific, written prior permission.
  15. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22. ******************************************************************/
  23. /*
  24.  * Portions of this file are copyrighted by:
  25.  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  26.  * Use is subject to license terms specified in the COPYING file
  27.  * distributed with the Net-SNMP package.
  28.  */
  29. /** @defgroup library The Net-SNMP library
  30.  *  @{
  31.  */
  32. /*
  33.  * snmp_api.c - API for access to snmp.
  34.  */
  35. #include <net-snmp/net-snmp-config.h>
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #if HAVE_STDLIB_H
  39. #include <stdlib.h>
  40. #endif
  41. #if HAVE_STRING_H
  42. #include <string.h>
  43. #else
  44. #include <strings.h>
  45. #endif
  46. #if HAVE_UNISTD_H
  47. #include <unistd.h>
  48. #endif
  49. #include <sys/types.h>
  50. #if HAVE_SYS_PARAM_H
  51. #include <sys/param.h>
  52. #endif
  53. #if TIME_WITH_SYS_TIME
  54. # ifdef WIN32
  55. #  include <sys/timeb.h>
  56. # else
  57. #  include <sys/time.h>
  58. # endif
  59. # include <time.h>
  60. #else
  61. # if HAVE_SYS_TIME_H
  62. #  include <sys/time.h>
  63. # else
  64. #  include <time.h>
  65. # endif
  66. #endif
  67. #if HAVE_NETINET_IN_H
  68. #include <netinet/in.h>
  69. #endif
  70. #if HAVE_ARPA_INET_H
  71. #include <arpa/inet.h>
  72. #endif
  73. #if HAVE_SYS_SELECT_H
  74. #include <sys/select.h>
  75. #endif
  76. #if HAVE_IO_H
  77. #include <io.h>
  78. #endif
  79. #if HAVE_WINSOCK_H
  80. #include <winsock.h>
  81. #endif
  82. #if HAVE_SYS_SOCKET_H
  83. #include <sys/socket.h>
  84. #endif
  85. #if HAVE_SYS_UN_H
  86. #include <sys/un.h>
  87. #endif
  88. #if HAVE_NETDB_H
  89. #include <netdb.h>
  90. #endif
  91. #if HAVE_NET_IF_DL_H
  92. #ifndef dynix
  93. #include <net/if_dl.h>
  94. #else
  95. #include <sys/net/if_dl.h>
  96. #endif
  97. #endif
  98. #include <errno.h>
  99. #if HAVE_LOCALE_H
  100. #include <locale.h>
  101. #endif
  102. #if HAVE_DMALLOC_H
  103. #include <dmalloc.h>
  104. #endif
  105. #define SNMP_NEED_REQUEST_LIST
  106. #include <net-snmp/types.h>
  107. #include <net-snmp/output_api.h>
  108. #include <net-snmp/config_api.h>
  109. #include <net-snmp/utilities.h>
  110. #include <net-snmp/library/asn1.h>
  111. #include <net-snmp/library/snmp.h>      /* for xdump & {build,parse}_var_op */
  112. #include <net-snmp/library/snmp_api.h>
  113. #include <net-snmp/library/snmp_client.h>
  114. #include <net-snmp/library/parse.h>
  115. #include <net-snmp/library/mib.h>
  116. #include <net-snmp/library/int64.h>
  117. #include <net-snmp/library/snmpv3.h>
  118. #include <net-snmp/library/callback.h>
  119. #include <net-snmp/library/container.h>
  120. #include <net-snmp/library/snmp_secmod.h>
  121. #ifdef SNMP_SECMOD_USM
  122. #include <net-snmp/library/snmpusm.h>
  123. #endif
  124. #ifdef SNMP_SECMOD_KSM
  125. #include <net-snmp/library/snmpksm.h>
  126. #endif
  127. #include <net-snmp/library/keytools.h>
  128. #include <net-snmp/library/lcd_time.h>
  129. #include <net-snmp/library/snmp_alarm.h>
  130. #include <net-snmp/library/snmp_transport.h>
  131. static void     _init_snmp(void);
  132. #include "../agent/mibgroup/agentx/protocol.h"
  133. #include <net-snmp/library/transform_oids.h>
  134. #ifndef timercmp
  135. #define timercmp(tvp, uvp, cmp) 
  136. /* CSTYLED */ 
  137. ((tvp)->tv_sec cmp (uvp)->tv_sec || 
  138. ((tvp)->tv_sec == (uvp)->tv_sec && 
  139. /* CSTYLED */ 
  140. (tvp)->tv_usec cmp (uvp)->tv_usec))
  141. #endif
  142. #ifndef timerclear
  143. #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
  144. #endif
  145. /*
  146.  * Globals.
  147.  */
  148. #define MAX_PACKET_LENGTH (0x7fffffff)
  149. #ifndef NETSNMP_STREAM_QUEUE_LEN
  150. #define NETSNMP_STREAM_QUEUE_LEN  5
  151. #endif
  152. #ifndef BSD4_3
  153. #define BSD4_2
  154. #endif
  155. #ifndef FD_SET
  156. typedef long    fd_mask;
  157. #define NFDBITS (sizeof(fd_mask) * NBBY)        /* bits per mask */
  158. #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  159. #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  160. #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  161. #define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
  162. #endif
  163. static oid      default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
  164. /*
  165.  * enterprises.cmu.systems.cmuSNMP 
  166.  */
  167. #define DEFAULT_COMMUNITY   "public"
  168. #define DEFAULT_RETRIES     5
  169. #define DEFAULT_TIMEOUT     1000000L
  170. #define DEFAULT_REMPORT     SNMP_PORT
  171. #define DEFAULT_ENTERPRISE  default_enterprise
  172. #define DEFAULT_TIME     0
  173. /*
  174.  * don't set higher than 0x7fffffff, and I doubt it should be that high
  175.  * * = 4 gig snmp messages max 
  176.  */
  177. #define MAXIMUM_PACKET_SIZE 0x7fffffff
  178. /*
  179.  * Internal information about the state of the snmp session.
  180.  */
  181. struct snmp_internal_session {
  182.     netsnmp_request_list *requests;     /* Info about outstanding requests */
  183.     netsnmp_request_list *requestsEnd;  /* ptr to end of list */
  184.     int             (*hook_pre) (netsnmp_session *, netsnmp_transport *,
  185.                                  void *, int);
  186.     int             (*hook_parse) (netsnmp_session *, netsnmp_pdu *,
  187.                                    u_char *, size_t);
  188.     int             (*hook_post) (netsnmp_session *, netsnmp_pdu *, int);
  189.     int             (*hook_build) (netsnmp_session *, netsnmp_pdu *,
  190.                                    u_char *, size_t *);
  191.     int             (*hook_realloc_build) (netsnmp_session *,
  192.                                            netsnmp_pdu *, u_char **,
  193.                                            size_t *, size_t *);
  194.     int             (*check_packet) (u_char *, size_t);
  195.     netsnmp_pdu    *(*hook_create_pdu) (netsnmp_transport *,
  196.                                         void *, size_t);
  197.     u_char         *packet;
  198.     size_t          packet_len, packet_size;
  199. };
  200. /*
  201.  * The list of active/open sessions.
  202.  */
  203. struct session_list {
  204.     struct session_list *next;
  205.     netsnmp_session *session;
  206.     netsnmp_transport *transport;
  207.     struct snmp_internal_session *internal;
  208. };
  209. static const char *api_errors[-SNMPERR_MAX + 1] = {
  210.     "No error",                 /* SNMPERR_SUCCESS */
  211.     "Generic error",            /* SNMPERR_GENERR */
  212.     "Invalid local port",       /* SNMPERR_BAD_LOCPORT */
  213.     "Unknown host",             /* SNMPERR_BAD_ADDRESS */
  214.     "Unknown session",          /* SNMPERR_BAD_SESSION */
  215.     "Too long",                 /* SNMPERR_TOO_LONG */
  216.     "No socket",                /* SNMPERR_NO_SOCKET */
  217.     "Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
  218.     "Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
  219.     "Bad value for non-repeaters",      /* SNMPERR_BAD_REPEATERS */
  220.     "Bad value for max-repetitions",    /* SNMPERR_BAD_REPETITIONS */
  221.     "Error building ASN.1 representation",      /* SNMPERR_BAD_ASN1_BUILD */
  222.     "Failure in sendto",        /* SNMPERR_BAD_SENDTO */
  223.     "Bad parse of ASN.1 type",  /* SNMPERR_BAD_PARSE */
  224.     "Bad version specified",    /* SNMPERR_BAD_VERSION */
  225.     "Bad source party specified",       /* SNMPERR_BAD_SRC_PARTY */
  226.     "Bad destination party specified",  /* SNMPERR_BAD_DST_PARTY */
  227.     "Bad context specified",    /* SNMPERR_BAD_CONTEXT */
  228.     "Bad community specified",  /* SNMPERR_BAD_COMMUNITY */
  229.     "Cannot send noAuth/Priv",       /* SNMPERR_NOAUTH_DESPRIV */
  230.     "Bad ACL definition",       /* SNMPERR_BAD_ACL */
  231.     "Bad Party definition",     /* SNMPERR_BAD_PARTY */
  232.     "Session abort failure",    /* SNMPERR_ABORT */
  233.     "Unknown PDU type",         /* SNMPERR_UNKNOWN_PDU */
  234.     "Timeout",                  /* SNMPERR_TIMEOUT */
  235.     "Failure in recvfrom",      /* SNMPERR_BAD_RECVFROM */
  236.     "Unable to determine contextEngineID",      /* SNMPERR_BAD_ENG_ID */
  237.     "No securityName specified",        /* SNMPERR_BAD_SEC_NAME */
  238.     "Unable to determine securityLevel",        /* SNMPERR_BAD_SEC_LEVEL  */
  239.     "ASN.1 parse error in message",     /* SNMPERR_ASN_PARSE_ERR */
  240.     "Unknown security model in message",        /* SNMPERR_UNKNOWN_SEC_MODEL */
  241.     "Invalid message (e.g. msgFlags)",  /* SNMPERR_INVALID_MSG */
  242.     "Unknown engine ID",        /* SNMPERR_UNKNOWN_ENG_ID */
  243.     "Unknown user name",        /* SNMPERR_UNKNOWN_USER_NAME */
  244.     "Unsupported security level",       /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
  245.     "Authentication failure (incorrect password, community or key)",    /* SNMPERR_AUTHENTICATION_FAILURE */
  246.     "Not in time window",       /* SNMPERR_NOT_IN_TIME_WINDOW */
  247.     "Decryption error",         /* SNMPERR_DECRYPTION_ERR */
  248.     "SCAPI general failure",    /* SNMPERR_SC_GENERAL_FAILURE */
  249.     "SCAPI sub-system not configured",  /* SNMPERR_SC_NOT_CONFIGURED */
  250.     "Key tools not available",  /* SNMPERR_KT_NOT_AVAILABLE */
  251.     "Unknown Report message",   /* SNMPERR_UNKNOWN_REPORT */
  252.     "USM generic error",        /* SNMPERR_USM_GENERICERROR */
  253.     "USM unknown security name (no such user exists)",  /* SNMPERR_USM_UNKNOWNSECURITYNAME */
  254.     "USM unsupported security level (this user has not been configured for that level of security)",    /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
  255.     "USM encryption error",     /* SNMPERR_USM_ENCRYPTIONERROR */
  256.     "USM authentication failure (incorrect password or key)",   /* SNMPERR_USM_AUTHENTICATIONFAILURE */
  257.     "USM parse error",          /* SNMPERR_USM_PARSEERROR */
  258.     "USM unknown engineID",     /* SNMPERR_USM_UNKNOWNENGINEID */
  259.     "USM not in time window",   /* SNMPERR_USM_NOTINTIMEWINDOW */
  260.     "USM decryption error",     /* SNMPERR_USM_DECRYPTIONERROR */
  261.     "MIB not initialized",      /* SNMPERR_NOMIB */
  262.     "Value out of range",       /* SNMPERR_RANGE */
  263.     "Sub-id out of range",      /* SNMPERR_MAX_SUBID */
  264.     "Bad sub-id in object identifier",  /* SNMPERR_BAD_SUBID */
  265.     "Object identifier too long",       /* SNMPERR_LONG_OID */
  266.     "Bad value name",           /* SNMPERR_BAD_NAME */
  267.     "Bad value notation",       /* SNMPERR_VALUE */
  268.     "Unknown Object Identifier",        /* SNMPERR_UNKNOWN_OBJID */
  269.     "No PDU in snmp_send",      /* SNMPERR_NULL_PDU */
  270.     "Missing variables in PDU", /* SNMPERR_NO_VARS */
  271.     "Bad variable type",        /* SNMPERR_VAR_TYPE */
  272.     "Out of memory (malloc failure)",   /* SNMPERR_MALLOC */
  273.     "Kerberos related error",   /* SNMPERR_KRB5 */
  274.     "Protocol error", /* SNMPERR_PROTOCOL */
  275. };
  276. static const char *secLevelName[] = {
  277.     "BAD_SEC_LEVEL",
  278.     "noAuthNoPriv",
  279.     "authNoPriv",
  280.     "authPriv"
  281. };
  282. /*
  283.  * Multiple threads may changes these variables.
  284.  * Suggest using the Single API, which does not use Sessions.
  285.  *
  286.  * Reqid may need to be protected. Time will tell...
  287.  *
  288.  */
  289. /*
  290.  * MTCRITICAL_RESOURCE
  291.  */
  292. /*
  293.  * use token in comments to individually protect these resources 
  294.  */
  295. struct session_list *Sessions = NULL;   /* MT_LIB_SESSION */
  296. static long     Reqid = 0;      /* MT_LIB_REQUESTID */
  297. static long     Msgid = 0;      /* MT_LIB_MESSAGEID */
  298. static long     Sessid = 0;     /* MT_LIB_SESSIONID */
  299. static long     Transid = 0;    /* MT_LIB_TRANSID */
  300. int             snmp_errno = 0;
  301. /*
  302.  * END MTCRITICAL_RESOURCE
  303.  */
  304. /*
  305.  * global error detail storage
  306.  */
  307. static char     snmp_detail[192];
  308. static int      snmp_detail_f = 0;
  309. /*
  310.  * Prototypes.
  311.  */
  312. int             snmp_build(u_char ** pkt, size_t * pkt_len,
  313.                            size_t * offset, netsnmp_session * pss,
  314.                            netsnmp_pdu *pdu);
  315. static int      snmp_parse(void *, netsnmp_session *, netsnmp_pdu *,
  316.                            u_char *, size_t);
  317. static void     snmpv3_calc_msg_flags(int, int, u_char *);
  318. static int      snmpv3_verify_msg(netsnmp_request_list *, netsnmp_pdu *);
  319. static int      snmpv3_build_probe_pdu(netsnmp_pdu **);
  320. static int      snmpv3_build(u_char ** pkt, size_t * pkt_len,
  321.                              size_t * offset, netsnmp_session * session,
  322.                              netsnmp_pdu *pdu);
  323. static int      snmp_parse_version(u_char *, size_t);
  324. static int      snmp_resend_request(struct session_list *slp,
  325.                                     netsnmp_request_list *rp,
  326.                                     int incr_retries);
  327. static void     register_default_handlers(void);
  328. static struct session_list *snmp_sess_copy(netsnmp_session * pss);
  329. int             snmp_get_errno(void);
  330. void            snmp_synch_reset(netsnmp_session * notused);
  331. void            snmp_synch_setup(netsnmp_session * notused);
  332. #ifndef HAVE_STRERROR
  333. const char     *
  334. strerror(int err)
  335. {
  336.     extern const char *sys_errlist[];
  337.     extern int      sys_nerr;
  338.     if (err < 0 || err >= sys_nerr)
  339.         return "Unknown error";
  340.     return sys_errlist[err];
  341. }
  342. #endif
  343. const char *
  344. snmp_pdu_type(int type)
  345. {
  346.     static char unknown[20];
  347.     switch(type) {
  348.     case SNMP_MSG_GET:
  349.         return "GET";
  350.     case SNMP_MSG_GETNEXT:
  351.         return "GETNEXT";
  352.     case SNMP_MSG_RESPONSE:
  353.         return "RESPONSE";
  354.     case SNMP_MSG_SET:
  355.         return "SET";
  356.     case SNMP_MSG_GETBULK:
  357.         return "GETBULK";
  358.     case SNMP_MSG_INFORM:
  359.         return "INFORM";
  360.     case SNMP_MSG_TRAP2:
  361.         return "TRAP2";
  362.     case SNMP_MSG_REPORT:
  363.         return "REPORT";
  364.     default:
  365.         snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
  366. return unknown;
  367.     }
  368. }
  369. #define DEBUGPRINTPDUTYPE(token, type) 
  370.     DEBUGDUMPSECTION(token, snmp_pdu_type(type))
  371. long
  372. snmp_get_next_reqid(void)
  373. {
  374.     long            retVal;
  375.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
  376.     retVal = 1 + Reqid;         /*MTCRITICAL_RESOURCE */
  377.     if (!retVal)
  378.         retVal = 2;
  379.     Reqid = retVal;
  380.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
  381.     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
  382.         return (retVal & 0x7fff); /* mask to 15 bits */
  383.     else
  384.         return retVal;
  385. }
  386. long
  387. snmp_get_next_msgid(void)
  388. {
  389.     long            retVal;
  390.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
  391.     retVal = 1 + Msgid;         /*MTCRITICAL_RESOURCE */
  392.     if (!retVal)
  393.         retVal = 2;
  394.     Msgid = retVal;
  395.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
  396.     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
  397.         return (retVal & 0x7fff); /* mask to 15 bits */
  398.     else
  399.         return retVal;
  400. }
  401. long
  402. snmp_get_next_sessid(void)
  403. {
  404.     long            retVal;
  405.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
  406.     retVal = 1 + Sessid;        /*MTCRITICAL_RESOURCE */
  407.     if (!retVal)
  408.         retVal = 2;
  409.     Sessid = retVal;
  410.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
  411.     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
  412.         return (retVal & 0x7fff); /* mask to 15 bits */
  413.     else
  414.         return retVal;
  415. }
  416. long
  417. snmp_get_next_transid(void)
  418. {
  419.     long            retVal;
  420.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
  421.     retVal = 1 + Transid;       /*MTCRITICAL_RESOURCE */
  422.     if (!retVal)
  423.         retVal = 2;
  424.     Transid = retVal;
  425.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
  426.     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
  427.         return (retVal & 0x7fff); /* mask to 15 bits */
  428.     else
  429.         return retVal;
  430. }
  431. void
  432. snmp_perror(const char *prog_string)
  433. {
  434.     const char     *str;
  435.     int             xerr;
  436.     xerr = snmp_errno;          /*MTCRITICAL_RESOURCE */
  437.     str = snmp_api_errstring(xerr);
  438.     snmp_log(LOG_ERR, "%s: %sn", prog_string, str);
  439. }
  440. void
  441. snmp_set_detail(const char *detail_string)
  442. {
  443.     if (detail_string != NULL) {
  444.         strncpy((char *) snmp_detail, detail_string, sizeof(snmp_detail));
  445.         snmp_detail[sizeof(snmp_detail) - 1] = '';
  446.         snmp_detail_f = 1;
  447.     }
  448. }
  449. /*
  450.  * returns pointer to static data 
  451.  */
  452. /*
  453.  * results not guaranteed in multi-threaded use 
  454.  */
  455. const char     *
  456. snmp_api_errstring(int snmp_errnumber)
  457. {
  458.     const char     *msg = "";
  459.     static char     msg_buf[SPRINT_MAX_LEN];
  460.     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
  461.         msg = api_errors[-snmp_errnumber];
  462.     } else if (snmp_errnumber != SNMPERR_SUCCESS) {
  463.         msg = NULL;
  464.     }
  465.     if (!msg)
  466. snprintf(msg_buf, sizeof(msg_buf), "Unknown error: %d", snmp_errnumber);
  467.     else if (snmp_detail_f) {
  468.         snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
  469.         snmp_detail_f = 0;
  470.     } else {
  471.         strncpy(msg_buf, msg, sizeof(msg_buf));
  472.     }
  473.     msg_buf[sizeof(msg_buf)-1] = '';
  474.     return (msg_buf);
  475. }
  476. /*
  477.  * snmp_error - return error data
  478.  * Inputs :  address of errno, address of snmp_errno, address of string
  479.  * Caller must free the string returned after use.
  480.  */
  481. void
  482. snmp_error(netsnmp_session * psess,
  483.            int *p_errno, int *p_snmp_errno, char **p_str)
  484. {
  485.     char            buf[SPRINT_MAX_LEN];
  486.     int             snmp_errnumber;
  487.     if (p_errno)
  488.         *p_errno = psess->s_errno;
  489.     if (p_snmp_errno)
  490.         *p_snmp_errno = psess->s_snmp_errno;
  491.     if (p_str == NULL)
  492.         return;
  493.     strcpy(buf, "");
  494.     snmp_errnumber = psess->s_snmp_errno;
  495.     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
  496. if (snmp_detail_f) {
  497.             snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
  498.     snmp_detail);
  499.     snmp_detail_f = 0;
  500. }
  501. else
  502.     strncpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
  503.     } else {
  504.         if (snmp_errnumber)
  505.             snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
  506.     }
  507.     buf[sizeof(buf)-1] = '';
  508.     /*
  509.      * append a useful system errno interpretation. 
  510.      */
  511.     if (psess->s_errno) {
  512.         const char* error = strerror(psess->s_errno);
  513.         if(error == NULL)
  514.             error = "Unknown Error";
  515.         snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
  516.                  " (%s)", error);
  517.     }
  518.     buf[sizeof(buf)-1] = '';
  519.     *p_str = strdup(buf);
  520. }
  521. /*
  522.  * snmp_sess_error - same as snmp_error for single session API use.
  523.  */
  524. void
  525. snmp_sess_error(void *sessp, int *p_errno, int *p_snmp_errno, char **p_str)
  526. {
  527.     struct session_list *slp = (struct session_list *) sessp;
  528.     if ((slp) && (slp->session))
  529.         snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
  530. }
  531. /*
  532.  * snmp_sess_perror(): print a error stored in a session pointer 
  533.  */
  534. void
  535. netsnmp_sess_log_error(int priority,
  536.                        const char *prog_string, netsnmp_session * ss)
  537. {
  538.     char           *err;
  539.     snmp_error(ss, NULL, NULL, &err);
  540.     snmp_log(priority, "%s: %sn", prog_string, err);
  541.     SNMP_FREE(err);
  542. }
  543. /*
  544.  * snmp_sess_perror(): print a error stored in a session pointer 
  545.  */
  546. void
  547. snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
  548. {
  549.     netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
  550. }
  551. /*
  552.  * Primordial SNMP library initialization.
  553.  * Initializes mutex locks.
  554.  * Invokes minimum required initialization for displaying MIB objects.
  555.  * Gets initial request ID for all transactions,
  556.  * and finds which port SNMP over UDP uses.
  557.  * SNMP over AppleTalk is not currently supported.
  558.  *
  559.  * Warning: no debug messages here.
  560.  */
  561. static void
  562. _init_snmp(void)
  563. {
  564. #ifdef  HAVE_GETSERVBYNAME
  565.     struct servent *servp;
  566. #endif
  567.     static char     have_done_init = 0;
  568.     struct timeval  tv;
  569.     long            tmpReqid, tmpMsgid;
  570.     u_short         s_port = SNMP_PORT;
  571.     if (have_done_init)
  572.         return;
  573.     have_done_init = 1;
  574.     Reqid = 1;
  575.     snmp_res_init();            /* initialize the mt locking structures */
  576. #ifndef DISABLE_MIB_LOADING
  577.     init_mib_internals();
  578. #endif /* DISABLE_MIB_LOADING */
  579.     netsnmp_tdomain_init();
  580.     gettimeofday(&tv, (struct timezone *) 0);
  581.     /*
  582.      * Now = tv;
  583.      */
  584.     /*
  585.      * get pseudo-random values for request ID and message ID 
  586.      */
  587.     /*
  588.      * don't allow zero value to repeat init 
  589.      */
  590. #ifdef SVR4
  591.     srand48(tv.tv_sec ^ tv.tv_usec);
  592.     tmpReqid = lrand48();
  593.     tmpMsgid = lrand48();
  594. #else
  595.     srandom(tv.tv_sec ^ tv.tv_usec);
  596.     tmpReqid = random();
  597.     tmpMsgid = random();
  598. #endif
  599.     if (tmpReqid == 0)
  600.         tmpReqid = 1;
  601.     if (tmpMsgid == 0)
  602.         tmpMsgid = 1;
  603.     Reqid = tmpReqid;
  604.     Msgid = tmpMsgid;
  605. #ifdef HAVE_GETSERVBYNAME
  606.     servp = getservbyname("snmp", "udp");
  607.     if (servp) {
  608.         /*
  609.          * store it in host byte order 
  610.          */
  611.         s_port = ntohs(servp->s_port);
  612.     }
  613. #endif
  614.     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
  615.        NETSNMP_DS_LIB_DEFAULT_PORT, s_port);
  616.     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
  617.                        NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
  618. #ifdef USE_REVERSE_ASNENCODING
  619.     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
  620.    NETSNMP_DS_LIB_REVERSE_ENCODE,
  621.    DEFAULT_ASNENCODING_DIRECTION);
  622. #endif
  623. }
  624. /*
  625.  * Initializes the session structure.
  626.  * May perform one time minimal library initialization.
  627.  * No MIB file processing is done via this call.
  628.  */
  629. void
  630. snmp_sess_init(netsnmp_session * session)
  631. {
  632.     _init_snmp();
  633.     /*
  634.      * initialize session to default values 
  635.      */
  636.     memset(session, 0, sizeof(netsnmp_session));
  637.     session->remote_port = SNMP_DEFAULT_REMPORT;
  638.     session->timeout = SNMP_DEFAULT_TIMEOUT;
  639.     session->retries = SNMP_DEFAULT_RETRIES;
  640.     session->version = SNMP_DEFAULT_VERSION;
  641.     session->securityModel = SNMP_DEFAULT_SECMODEL;
  642.     session->rcvMsgMaxSize = SNMP_MAX_MSG_SIZE;
  643.     session->flags |= SNMP_FLAGS_DONT_PROBE;
  644. }
  645. static void
  646. register_default_handlers(void)
  647. {
  648.     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
  649.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
  650.     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
  651.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
  652.     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
  653.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
  654. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  655.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
  656.                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
  657. #endif
  658.     netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
  659.                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
  660.     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
  661.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
  662.     netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
  663.               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
  664.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
  665.               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
  666.     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
  667.               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
  668.     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
  669.               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
  670.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "clientaddr",
  671.                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
  672.     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
  673.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
  674.     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
  675.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
  676.     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
  677.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
  678.     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
  679.       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
  680. }
  681. void
  682. init_snmp_enums(void)
  683. {
  684.     se_add_pair_to_slist("asntypes", strdup("integer"), ASN_INTEGER);
  685.     se_add_pair_to_slist("asntypes", strdup("counter"), ASN_COUNTER);
  686.     se_add_pair_to_slist("asntypes", strdup("uinteger"), ASN_GAUGE);
  687.     se_add_pair_to_slist("asntypes", strdup("timeticks"), ASN_TIMETICKS);
  688.     se_add_pair_to_slist("asntypes", strdup("counter64"), ASN_COUNTER64);
  689.     se_add_pair_to_slist("asntypes", strdup("octet_str"), ASN_OCTET_STR);
  690.     se_add_pair_to_slist("asntypes", strdup("ipaddress"), ASN_IPADDRESS);
  691.     se_add_pair_to_slist("asntypes", strdup("opaque"), ASN_OPAQUE);
  692.     se_add_pair_to_slist("asntypes", strdup("nsap"), ASN_NSAP);
  693.     se_add_pair_to_slist("asntypes", strdup("object_id"), ASN_OBJECT_ID);
  694.     se_add_pair_to_slist("asntypes", strdup("null"), ASN_NULL);
  695. #ifdef OPAQUE_SPECIAL_TYPES
  696.     se_add_pair_to_slist("asntypes", strdup("opaque_counter64"),
  697.                          ASN_OPAQUE_COUNTER64);
  698.     se_add_pair_to_slist("asntypes", strdup("opaque_u64"), ASN_OPAQUE_U64);
  699.     se_add_pair_to_slist("asntypes", strdup("opaque_float"),
  700.                          ASN_OPAQUE_FLOAT);
  701.     se_add_pair_to_slist("asntypes", strdup("opaque_double"),
  702.                          ASN_OPAQUE_DOUBLE);
  703.     se_add_pair_to_slist("asntypes", strdup("opaque_i64"), ASN_OPAQUE_I64);
  704. #endif
  705. }
  706. /**
  707.  * Calls the functions to do config file loading and  mib module parsing
  708.  * in the correct order.
  709.  *
  710.  * @param type label for the config file "type"
  711.  *
  712.  * @return void
  713.  *
  714.  * @see init_agent
  715.  */
  716. void
  717. init_snmp(const char *type)
  718. {
  719.     static int      done_init = 0;      /* To prevent double init's. */
  720.     if (done_init) {
  721.         return;
  722.     }
  723.     done_init = 1;
  724.     /*
  725.      * make the type available everywhere else 
  726.      */
  727.     if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  728.        NETSNMP_DS_LIB_APPTYPE)) {
  729.         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
  730.       NETSNMP_DS_LIB_APPTYPE, type);
  731.     }
  732.     _init_snmp();
  733.     /*
  734.      * set our current locale properly to initialize isprint() type functions 
  735.      */
  736. #ifdef HAVE_SETLOCALE
  737.     setlocale(LC_CTYPE, "");
  738. #endif
  739.     snmp_debug_init();    /* should be done first, to turn on debugging ASAP */
  740.     netsnmp_container_init_list();
  741.     init_callbacks();
  742.     init_snmp_logging();
  743.     snmp_init_statistics();
  744.     register_mib_handlers();
  745.     register_default_handlers();
  746.     init_snmpv3(type);
  747.     init_snmp_alarm();
  748.     init_snmp_enum(type);
  749.     init_snmp_enums();
  750.     read_premib_configs();
  751. #ifndef DISABLE_MIB_LOADING
  752.     init_mib();
  753. #endif /* DISABLE_MIB_LOADING */
  754.     read_configs();
  755. }                               /* end init_snmp() */
  756. void
  757. snmp_store(const char *type)
  758. {
  759.     DEBUGMSGTL(("snmp_store", "storing stuff...n"));
  760.     snmp_save_persistent(type);
  761.     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
  762.     snmp_clean_persistent(type);
  763. }
  764. /**
  765.  * Shuts down the application, saving any needed persistent storage,
  766.  * and appropriate clean up.
  767.  * 
  768.  * @param type Label for the config file "type" used
  769.  *
  770.  * @return void
  771.  */
  772. void
  773. snmp_shutdown(const char *type)
  774. {
  775.     snmp_store(type);
  776.     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
  777.     snmp_alarm_unregister_all();
  778.     snmp_close_sessions();
  779. #ifndef DISABLE_MIB_LOADING
  780.     shutdown_mib();
  781. #endif /* DISABLE_MIB_LOADING */
  782.     unregister_all_config_handlers();
  783.     netsnmp_container_free_list();
  784.     clear_sec_mod();
  785.     clear_snmp_enum();
  786.     netsnmp_clear_tdomain_list();
  787.     clear_callback();
  788.     netsnmp_ds_shutdown();
  789. }
  790. /*
  791.  * Sets up the session with the snmp_session information provided by the user.
  792.  * Then opens and binds the necessary low-level transport.  A handle to the
  793.  * created session is returned (this is NOT the same as the pointer passed to
  794.  * snmp_open()).  On any error, NULL is returned and snmp_errno is set to the
  795.  * appropriate error code.
  796.  */
  797. netsnmp_session *
  798. snmp_open(netsnmp_session *session)
  799. {
  800.     struct session_list *slp;
  801.     slp = (struct session_list *) snmp_sess_open(session);
  802.     if (!slp) {
  803.         return NULL;
  804.     }
  805.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  806.     slp->next = Sessions;
  807.     Sessions = slp;
  808.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  809.     return (slp->session);
  810. }
  811. /*
  812.  * extended open 
  813.  */
  814. netsnmp_session *
  815. snmp_open_ex(netsnmp_session *session,
  816.              int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
  817.                                 void *, int),
  818.              int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
  819.  size_t),
  820.      int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
  821.              int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
  822.  size_t *),
  823.      int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
  824.  u_char **, size_t *, size_t *),
  825.              int (*fcheck) (u_char *, size_t)
  826.      )
  827. {
  828.     struct session_list *slp;
  829.     slp = (struct session_list *) snmp_sess_open(session);
  830.     if (!slp) {
  831.         return NULL;
  832.     }
  833.     slp->internal->hook_pre = fpre_parse;
  834.     slp->internal->hook_parse = fparse;
  835.     slp->internal->hook_post = fpost_parse;
  836.     slp->internal->hook_build = fbuild;
  837.     slp->internal->hook_realloc_build = frbuild;
  838.     slp->internal->check_packet = fcheck;
  839.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  840.     slp->next = Sessions;
  841.     Sessions = slp;
  842.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  843.     return (slp->session);
  844. }
  845. static struct session_list *
  846. _sess_copy(netsnmp_session * in_session)
  847. {
  848.     struct session_list *slp;
  849.     struct snmp_internal_session *isp;
  850.     netsnmp_session *session;
  851.     struct snmp_secmod_def *sptr;
  852.     char           *cp;
  853.     u_char         *ucp;
  854.     size_t          i;
  855.     in_session->s_snmp_errno = 0;
  856.     in_session->s_errno = 0;
  857.     /*
  858.      * Copy session structure and link into list 
  859.      */
  860.     slp = (struct session_list *) calloc(1, sizeof(struct session_list));
  861.     if (slp == NULL) {
  862.         in_session->s_snmp_errno = SNMPERR_MALLOC;
  863.         return (NULL);
  864.     }
  865.     slp->transport = NULL;
  866.     isp = (struct snmp_internal_session *)calloc(1, sizeof(struct snmp_internal_session));
  867.     if (isp == NULL) {
  868.         snmp_sess_close(slp);
  869.         in_session->s_snmp_errno = SNMPERR_MALLOC;
  870.         return (NULL);
  871.     }
  872.     slp->internal = isp;
  873.     slp->session = (netsnmp_session *)malloc(sizeof(netsnmp_session));
  874.     if (slp->session == NULL) {
  875.         snmp_sess_close(slp);
  876.         in_session->s_snmp_errno = SNMPERR_MALLOC;
  877.         return (NULL);
  878.     }
  879.     memmove(slp->session, in_session, sizeof(netsnmp_session));
  880.     session = slp->session;
  881.     /*
  882.      * zero out pointers so if we have to free the session we wont free mem
  883.      * owned by in_session 
  884.      */
  885.     session->peername = NULL;
  886.     session->community = NULL;
  887.     session->contextEngineID = NULL;
  888.     session->contextName = NULL;
  889.     session->securityEngineID = NULL;
  890.     session->securityName = NULL;
  891.     session->securityAuthProto = NULL;
  892.     session->securityPrivProto = NULL;
  893.     /*
  894.      * session now points to the new structure that still contains pointers to
  895.      * data allocated elsewhere.  Some of this data is copied to space malloc'd
  896.      * here, and the pointer replaced with the new one.
  897.      */
  898.     if (in_session->peername != NULL) {
  899.         session->peername = (char *)malloc(strlen(in_session->peername) + 1);
  900.         if (session->peername == NULL) {
  901.             snmp_sess_close(slp);
  902.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  903.             return (NULL);
  904.         }
  905.         strcpy(session->peername, in_session->peername);
  906.     }
  907.     /*
  908.      * Fill in defaults if necessary 
  909.      */
  910. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  911.     if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
  912.         ucp = (u_char *) malloc(in_session->community_len);
  913.         if (ucp != NULL)
  914.             memmove(ucp, in_session->community, in_session->community_len);
  915.     } else {
  916.         if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  917. NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
  918.             session->community_len = strlen(cp);
  919.             ucp = (u_char *) malloc(session->community_len);
  920.             if (ucp)
  921.                 memmove(ucp, cp, session->community_len);
  922.         } else {
  923. #ifdef NO_ZEROLENGTH_COMMUNITY
  924.             session->community_len = strlen(DEFAULT_COMMUNITY);
  925.             ucp = (u_char *) malloc(session->community_len);
  926.             if (ucp)
  927.                 memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
  928. #else
  929.             ucp = (u_char *) strdup("");
  930. #endif
  931.         }
  932.     }
  933.     if (ucp == NULL) {
  934.         snmp_sess_close(slp);
  935.         in_session->s_snmp_errno = SNMPERR_MALLOC;
  936.         return (NULL);
  937.     }
  938.     session->community = ucp;   /* replace pointer with pointer to new data */
  939. #endif
  940.     if (session->securityLevel <= 0) {
  941.         session->securityLevel =
  942.             netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
  943.     }
  944.     if (session->securityLevel == 0)
  945.         session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  946.     if (in_session->securityAuthProtoLen > 0) {
  947.         session->securityAuthProto =
  948.             snmp_duplicate_objid(in_session->securityAuthProto,
  949.                                  in_session->securityAuthProtoLen);
  950.         if (session->securityAuthProto == NULL) {
  951.             snmp_sess_close(slp);
  952.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  953.             return (NULL);
  954.         }
  955.     } else if (get_default_authtype(&i) != NULL) {
  956.         session->securityAuthProto =
  957.             snmp_duplicate_objid(get_default_authtype(NULL), i);
  958.         session->securityAuthProtoLen = i;
  959.     }
  960.     if (in_session->securityPrivProtoLen > 0) {
  961.         session->securityPrivProto =
  962.             snmp_duplicate_objid(in_session->securityPrivProto,
  963.                                  in_session->securityPrivProtoLen);
  964.         if (session->securityPrivProto == NULL) {
  965.             snmp_sess_close(slp);
  966.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  967.             return (NULL);
  968.         }
  969.     } else if (get_default_privtype(&i) != NULL) {
  970.         session->securityPrivProto =
  971.             snmp_duplicate_objid(get_default_privtype(NULL), i);
  972.         session->securityPrivProtoLen = i;
  973.     }
  974.     if (in_session->securityEngineIDLen > 0) {
  975.         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
  976.         if (ucp == NULL) {
  977.             snmp_sess_close(slp);
  978.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  979.             return (NULL);
  980.         }
  981.         memmove(ucp, in_session->securityEngineID,
  982.                 in_session->securityEngineIDLen);
  983.         session->securityEngineID = ucp;
  984.     }
  985.     if (in_session->contextEngineIDLen > 0) {
  986.         ucp = (u_char *) malloc(in_session->contextEngineIDLen);
  987.         if (ucp == NULL) {
  988.             snmp_sess_close(slp);
  989.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  990.             return (NULL);
  991.         }
  992.         memmove(ucp, in_session->contextEngineID,
  993.                 in_session->contextEngineIDLen);
  994.         session->contextEngineID = ucp;
  995.     } else if (in_session->securityEngineIDLen > 0) {
  996.         /*
  997.          * default contextEngineID to securityEngineIDLen if defined 
  998.          */
  999.         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
  1000.         if (ucp == NULL) {
  1001.             snmp_sess_close(slp);
  1002.             in_session->s_snmp_errno = SNMPERR_MALLOC;
  1003.             return (NULL);
  1004.         }
  1005.         memmove(ucp, in_session->securityEngineID,
  1006.                 in_session->securityEngineIDLen);
  1007.         session->contextEngineID = ucp;
  1008.         session->contextEngineIDLen = in_session->securityEngineIDLen;
  1009.     }
  1010.     if (in_session->contextName) {
  1011.         session->contextName = strdup(in_session->contextName);
  1012.         if (session->contextName == NULL) {
  1013.             snmp_sess_close(slp);
  1014.             return (NULL);
  1015.         }
  1016.     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1017.    NETSNMP_DS_LIB_CONTEXT)) != NULL) {
  1018.         cp = strdup(cp);
  1019.         if (cp == NULL) {
  1020.             snmp_sess_close(slp);
  1021.             return (NULL);
  1022.         }
  1023.         session->contextName = cp;
  1024.         session->contextNameLen = strlen(cp);
  1025.     } else {
  1026.         cp = strdup(SNMP_DEFAULT_CONTEXT);
  1027.         session->contextName = cp;
  1028.         session->contextNameLen = strlen(cp);
  1029.     }
  1030.     if (in_session->securityName) {
  1031.         session->securityName = strdup(in_session->securityName);
  1032.         if (session->securityName == NULL) {
  1033.             snmp_sess_close(slp);
  1034.             return (NULL);
  1035.         }
  1036.     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1037.    NETSNMP_DS_LIB_SECNAME)) != NULL) {
  1038.         cp = strdup(cp);
  1039.         if (cp == NULL) {
  1040.             snmp_sess_close(slp);
  1041.             return (NULL);
  1042.         }
  1043.         session->securityName = cp;
  1044.         session->securityNameLen = strlen(cp);
  1045.     }
  1046.     if ((in_session->securityAuthKeyLen <= 0) &&
  1047.         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1048.      NETSNMP_DS_LIB_AUTHMASTERKEY)))) {
  1049.         size_t buflen = sizeof(session->securityAuthKey);
  1050.         u_char *tmpp = session->securityAuthKey;
  1051.         session->securityAuthKeyLen = 0;
  1052.         /* it will be a hex string */
  1053.         if (!snmp_hex_to_binary(&tmpp, &buflen,
  1054.                                 &session->securityAuthKeyLen, 0, cp)) {
  1055.             snmp_set_detail("error parsing authentication master key");
  1056.             snmp_sess_close(slp);
  1057.             return NULL;
  1058.         }
  1059.     } else if ((in_session->securityAuthKeyLen <= 0) &&
  1060.         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1061.      NETSNMP_DS_LIB_AUTHPASSPHRASE)) ||
  1062.          (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1063.      NETSNMP_DS_LIB_PASSPHRASE)))) {
  1064.         session->securityAuthKeyLen = USM_AUTH_KU_LEN;
  1065.         if (generate_Ku(session->securityAuthProto,
  1066.                         session->securityAuthProtoLen,
  1067.                         (u_char *) cp, strlen(cp),
  1068.                         session->securityAuthKey,
  1069.                         &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
  1070.             snmp_set_detail
  1071.                 ("Error generating a key (Ku) from the supplied authentication pass phrase.");
  1072.             snmp_sess_close(slp);
  1073.             return NULL;
  1074.         }
  1075.     }
  1076.     
  1077.     if ((in_session->securityPrivKeyLen <= 0) &&
  1078.         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1079.      NETSNMP_DS_LIB_PRIVMASTERKEY)))) {
  1080.         size_t buflen = sizeof(session->securityPrivKey);
  1081.         u_char *tmpp = session->securityPrivKey;
  1082.         session->securityPrivKeyLen = 0;
  1083.         /* it will be a hex string */
  1084.         if (!snmp_hex_to_binary(&tmpp, &buflen,
  1085.                                 &session->securityPrivKeyLen, 0, cp)) {
  1086.             snmp_set_detail("error parsing encryption master key");
  1087.             snmp_sess_close(slp);
  1088.             return NULL;
  1089.         }
  1090.     } else if ((in_session->securityPrivKeyLen <= 0) &&
  1091.         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1092.      NETSNMP_DS_LIB_PRIVPASSPHRASE)) ||
  1093.          (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1094.      NETSNMP_DS_LIB_PASSPHRASE)))) {
  1095.         session->securityPrivKeyLen = USM_PRIV_KU_LEN;
  1096.         if (generate_Ku(session->securityAuthProto,
  1097.                         session->securityAuthProtoLen,
  1098.                         (u_char *) cp, strlen(cp),
  1099.                         session->securityPrivKey,
  1100.                         &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
  1101.             snmp_set_detail
  1102.                 ("Error generating a key (Ku) from the supplied privacy pass phrase.");
  1103.             snmp_sess_close(slp);
  1104.             return NULL;
  1105.         }
  1106.     }
  1107.     if (session->retries == SNMP_DEFAULT_RETRIES)
  1108.         session->retries = DEFAULT_RETRIES;
  1109.     if (session->timeout == SNMP_DEFAULT_TIMEOUT)
  1110.         session->timeout = DEFAULT_TIMEOUT;
  1111.     session->sessid = snmp_get_next_sessid();
  1112.     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
  1113.                         session);
  1114.     if ((sptr = find_sec_mod(session->securityModel)) != NULL &&
  1115.         sptr->session_open != NULL) {
  1116.         /*
  1117.          * security module specific inialization 
  1118.          */
  1119.         (*sptr->session_open) (session);
  1120.     }
  1121.     return (slp);
  1122. }
  1123. static struct session_list *
  1124. snmp_sess_copy(netsnmp_session * pss)
  1125. {
  1126.     struct session_list *psl;
  1127.     psl = _sess_copy(pss);
  1128.     if (!psl) {
  1129.         if (!pss->s_snmp_errno) {
  1130.             pss->s_snmp_errno = SNMPERR_GENERR;
  1131.         }
  1132.         SET_SNMP_ERROR(pss->s_snmp_errno);
  1133.     }
  1134.     return psl;
  1135. }
  1136. /**
  1137.  * probe for peer engineID
  1138.  *
  1139.  * @param slp         session list pointer.
  1140.  * @param in_session  session for errors
  1141.  *
  1142.  * @note
  1143.  *  - called by _sess_open(), snmp_sess_add_ex()
  1144.  *  - in_session is the user supplied session provided to those functions.
  1145.  *  - the first session in slp should the internal allocated copy of in_session
  1146.  *
  1147.  * @return 0 : error
  1148.  * @return 1 : ok
  1149.  *
  1150.  */
  1151. int
  1152. snmpv3_engineID_probe(struct session_list *slp,
  1153.                       netsnmp_session * in_session)
  1154. {
  1155.     netsnmp_pdu    *pdu = NULL, *response = NULL;
  1156.     netsnmp_session *session;
  1157.     unsigned int    i;
  1158.     int             status;
  1159.     if (slp == NULL || slp->session == NULL) {
  1160.         return 0;
  1161.     }
  1162.     session = slp->session;
  1163.     /*
  1164.      * If we are opening a V3 session and we don't know engineID we must probe
  1165.      * it -- this must be done after the session is created and inserted in the
  1166.      * list so that the response can handled correctly. 
  1167.      */
  1168.     if ((session->flags & SNMP_FLAGS_DONT_PROBE) == SNMP_FLAGS_DONT_PROBE)
  1169.         return 1;
  1170.     if (session->version == SNMP_VERSION_3) {
  1171.         if (session->securityEngineIDLen == 0) {
  1172.             if (snmpv3_build_probe_pdu(&pdu) != 0) {
  1173.                 DEBUGMSGTL(("snmp_api", "unable to create probe PDUn"));
  1174.                 return 0;
  1175.             }
  1176.             DEBUGMSGTL(("snmp_api", "probing for engineID...n"));
  1177.             session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
  1178.             status = snmp_sess_synch_response(slp, pdu, &response);
  1179.             if ((response == NULL) && (status == STAT_SUCCESS)) {
  1180.                 status = STAT_ERROR;
  1181.             }
  1182.             switch (status) {
  1183.             case STAT_SUCCESS:
  1184.                 in_session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
  1185.                 DEBUGMSGTL(("snmp_sess_open",
  1186.                             "error: expected Report as response to probe: %s (%d)n",
  1187.                             snmp_errstring(response->errstat),
  1188.                             response->errstat));
  1189.                 break;
  1190.             case STAT_ERROR:   /* this is what we expected -> Report == STAT_ERROR */
  1191.                 in_session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
  1192.                 break;
  1193.             case STAT_TIMEOUT:
  1194.                 in_session->s_snmp_errno = SNMPERR_TIMEOUT;
  1195.             default:
  1196.                 DEBUGMSGTL(("snmp_sess_open",
  1197.                             "unable to connect with remote engine: %s (%d)n",
  1198.                             snmp_api_errstring(session->s_snmp_errno),
  1199.                             session->s_snmp_errno));
  1200.                 break;
  1201.             }
  1202.             if (slp->session->securityEngineIDLen == 0) {
  1203.                 DEBUGMSGTL(("snmp_api",
  1204.                             "unable to determine remote engine IDn"));
  1205.                 return 0;
  1206.             }
  1207.             in_session->s_snmp_errno = SNMPERR_SUCCESS;
  1208.             if (snmp_get_do_debugging()) {
  1209.                 DEBUGMSGTL(("snmp_sess_open",
  1210.                             "  probe found engineID:  "));
  1211.                 for (i = 0; i < slp->session->securityEngineIDLen; i++)
  1212.                     DEBUGMSG(("snmp_sess_open", "%02x",
  1213.                               slp->session->securityEngineID[i]));
  1214.                 DEBUGMSG(("snmp_sess_open", "n"));
  1215.             }
  1216.         }
  1217.         /*
  1218.          * if boot/time supplied set it for this engineID 
  1219.          */
  1220.         if (session->engineBoots || session->engineTime) {
  1221.             set_enginetime(session->securityEngineID,
  1222.                            session->securityEngineIDLen,
  1223.                            session->engineBoots, session->engineTime,
  1224.                            TRUE);
  1225.         }
  1226.         if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
  1227.             in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME;       /* XX?? */
  1228.             DEBUGMSGTL(("snmp_api",
  1229.                         "snmp_sess_open(): failed(2) to create a new user from sessionn"));
  1230.             return 0;
  1231.         }
  1232.     }
  1233.     return 1;
  1234. }
  1235. /*******************************************************************-o-******
  1236.  * snmp_sess_open
  1237.  *
  1238.  * Parameters:
  1239.  * *in_session
  1240.  *
  1241.  * Returns:
  1242.  *      Pointer to a session in the session list   -OR- FIX -- right?
  1243.  * NULL on failure.
  1244.  *
  1245.  * The "spin-free" version of snmp_open.
  1246.  */
  1247. static void    *
  1248. _sess_open(netsnmp_session * in_session)
  1249. {
  1250.     struct session_list *slp;
  1251.     netsnmp_session *session;
  1252.     char            *clientaddr_save = NULL;
  1253.     in_session->s_snmp_errno = 0;
  1254.     in_session->s_errno = 0;
  1255.     _init_snmp();
  1256.     if ((slp = snmp_sess_copy(in_session)) == NULL) {
  1257.         return (NULL);
  1258.     }
  1259.     session = slp->session;
  1260.     slp->transport = NULL;
  1261.     if (NULL != session->localname) {
  1262.         clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
  1263.                                                 NETSNMP_DS_LIB_CLIENT_ADDR);
  1264.         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
  1265.                               NETSNMP_DS_LIB_CLIENT_ADDR, session->localname);
  1266.     }
  1267.     if (session->flags & SNMP_FLAGS_STREAM_SOCKET) {
  1268.         slp->transport = netsnmp_tdomain_transport(session->peername,
  1269.                                                    session->local_port,
  1270.                                                    "tcp");
  1271.     } else {
  1272.         slp->transport = netsnmp_tdomain_transport(session->peername,
  1273.                                                    session->local_port,
  1274.                                                    "udp");
  1275.     }
  1276.     if (NULL != session->localname)
  1277.         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
  1278.                               NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
  1279.     if (slp->transport == NULL) {
  1280.         DEBUGMSGTL(("_sess_open", "couldn't interpret peernamen"));
  1281.         in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
  1282.         in_session->s_errno = errno;
  1283.         snmp_set_detail(session->peername);
  1284.         snmp_sess_close(slp);
  1285.         return NULL;
  1286.     }
  1287.     session->rcvMsgMaxSize = slp->transport->msgMaxSize;
  1288.     if (!snmpv3_engineID_probe(slp, in_session)) {
  1289.         snmp_sess_close(slp);
  1290.         return 0;
  1291.     }
  1292.     session->flags &= ~SNMP_FLAGS_DONT_PROBE;
  1293.     return (void *) slp;
  1294. }                               /* end snmp_sess_open() */
  1295. /*
  1296.  * EXPERIMENTAL API EXTENSIONS ------------------------------------------ 
  1297.  * 
  1298.  * snmp_sess_add_ex, snmp_sess_add, snmp_add 
  1299.  * 
  1300.  * Analogous to snmp_open family of functions, but taking a netsnmp_transport
  1301.  * pointer as an extra argument.  Unlike snmp_open et al. it doesn't attempt
  1302.  * to interpret the in_session->peername as a transport endpoint specifier,
  1303.  * but instead uses the supplied transport.  JBPN
  1304.  * 
  1305.  */
  1306. netsnmp_session *
  1307. snmp_add(netsnmp_session * in_session,
  1308.          netsnmp_transport *transport,
  1309.          int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
  1310.                             int), int (*fpost_parse) (netsnmp_session *,
  1311.                                                       netsnmp_pdu *, int))
  1312. {
  1313.     struct session_list *slp;
  1314.     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
  1315.                                                    fpre_parse, NULL,
  1316.                                                    fpost_parse, NULL, NULL,
  1317.                                                    NULL, NULL);
  1318.     if (slp == NULL) {
  1319.         return NULL;
  1320.     }
  1321.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1322.     slp->next = Sessions;
  1323.     Sessions = slp;
  1324.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1325.     return (slp->session);
  1326. }
  1327. netsnmp_session *
  1328. snmp_add_full(netsnmp_session * in_session,
  1329.               netsnmp_transport *transport,
  1330.               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
  1331.                                  void *, int),
  1332.               int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
  1333.                              size_t),
  1334.               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
  1335.               int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
  1336.                              size_t *), int (*frbuild) (netsnmp_session *,
  1337.                                                         netsnmp_pdu *,
  1338.                                                         u_char **,
  1339.                                                         size_t *,
  1340.                                                         size_t *),
  1341.               int (*fcheck) (u_char *, size_t),
  1342.               netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
  1343.                                            size_t))
  1344. {
  1345.     struct session_list *slp;
  1346.     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
  1347.                                                    fpre_parse, fparse,
  1348.                                                    fpost_parse, fbuild,
  1349.                                                    frbuild, fcheck,
  1350.                                                    fcreate_pdu);
  1351.     if (slp == NULL) {
  1352.         return NULL;
  1353.     }
  1354.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1355.     slp->next = Sessions;
  1356.     Sessions = slp;
  1357.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1358.     return (slp->session);
  1359. }
  1360. void           *
  1361. snmp_sess_add_ex(netsnmp_session * in_session,
  1362.                  netsnmp_transport *transport,
  1363.                  int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
  1364.                                     void *, int),
  1365.                  int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
  1366.                                 size_t),
  1367.                  int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
  1368.                                      int),
  1369.                  int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
  1370.                                 size_t *),
  1371.                  int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
  1372.                                  u_char **, size_t *, size_t *),
  1373.                  int (*fcheck) (u_char *, size_t),
  1374.                  netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
  1375.                                               size_t))
  1376. {
  1377.     struct session_list *slp;
  1378.     _init_snmp();
  1379.     if (in_session == NULL || transport == NULL) {
  1380.         return NULL;
  1381.     }
  1382.     DEBUGMSGTL(("snmp_sess_add", "fd %dn", transport->sock));
  1383.     if ((slp = snmp_sess_copy(in_session)) == NULL) {
  1384.         return (NULL);
  1385.     }
  1386.     slp->transport = transport;
  1387.     slp->internal->hook_pre = fpre_parse;
  1388.     slp->internal->hook_parse = fparse;
  1389.     slp->internal->hook_post = fpost_parse;
  1390.     slp->internal->hook_build = fbuild;
  1391.     slp->internal->hook_realloc_build = frbuild;
  1392.     slp->internal->check_packet = fcheck;
  1393.     slp->internal->hook_create_pdu = fcreate_pdu;
  1394.     slp->session->rcvMsgMaxSize = transport->msgMaxSize;
  1395.     if (slp->session->version == SNMP_VERSION_3) {
  1396.         DEBUGMSGTL(("snmp_sess_add",
  1397.                     "adding v3 session -- engineID probe nown"));
  1398.         if (!snmpv3_engineID_probe(slp, in_session)) {
  1399.             DEBUGMSGTL(("snmp_sess_add", "engine ID probe failedn"));
  1400.             snmp_sess_close(slp);
  1401.             slp = NULL;
  1402.         }
  1403.     }
  1404.     return (void *) slp;
  1405. }                               /*  end snmp_sess_add_ex()  */
  1406. void           *
  1407. snmp_sess_add(netsnmp_session * in_session,
  1408.               netsnmp_transport *transport,
  1409.               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
  1410.                                  void *, int),
  1411.               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
  1412. {
  1413.     return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
  1414.                             fpost_parse, NULL, NULL, NULL, NULL);
  1415. }
  1416. void           *
  1417. snmp_sess_open(netsnmp_session * pss)
  1418. {
  1419.     void           *pvoid;
  1420.     pvoid = _sess_open(pss);
  1421.     if (!pvoid) {
  1422.         SET_SNMP_ERROR(pss->s_snmp_errno);
  1423.     }
  1424.     return pvoid;
  1425. }
  1426. /*
  1427.  * create_user_from_session(netsnmp_session *session):
  1428.  * 
  1429.  * creates a user in the usm table from the information in a session.
  1430.  * If the user already exists, it is updated with the current
  1431.  * information from the session
  1432.  * 
  1433.  * Parameters:
  1434.  * session -- IN: pointer to the session to use when creating the user.
  1435.  * 
  1436.  * Returns:
  1437.  * SNMPERR_SUCCESS
  1438.  * SNMPERR_GENERR 
  1439.  */
  1440. int
  1441. create_user_from_session(netsnmp_session * session)
  1442. {
  1443.     struct usmUser *user;
  1444.     int             user_just_created = 0;
  1445.     u_char *cp;
  1446.     /*
  1447.      * now that we have the engineID, create an entry in the USM list
  1448.      * for this user using the information in the session 
  1449.      */
  1450.     user = usm_get_user_from_list(session->securityEngineID,
  1451.                                   session->securityEngineIDLen,
  1452.                                   session->securityName,
  1453.                                   usm_get_userList(), 0);
  1454.     if (user == NULL) {
  1455.         DEBUGMSGTL(("snmp_api", "Building user %s...n",
  1456.                     session->securityName));
  1457.         /*
  1458.          * user doesn't exist so we create and add it 
  1459.          */
  1460.         user = (struct usmUser *) calloc(1, sizeof(struct usmUser));
  1461.         if (user == NULL)
  1462.             return SNMPERR_GENERR;
  1463.         /*
  1464.          * copy in the securityName 
  1465.          */
  1466.         if (session->securityName) {
  1467.             user->name = strdup(session->securityName);
  1468.             user->secName = strdup(session->securityName);
  1469.             if (user->name == NULL || user->secName == NULL) {
  1470.                 usm_free_user(user);
  1471.                 return SNMPERR_GENERR;
  1472.             }
  1473.         }
  1474.         /*
  1475.          * copy in the engineID 
  1476.          */
  1477.         if (memdup(&user->engineID, session->securityEngineID,
  1478.                    session->securityEngineIDLen) != SNMPERR_SUCCESS) {
  1479.             usm_free_user(user);
  1480.             return SNMPERR_GENERR;
  1481.         }
  1482.         user->engineIDLen = session->securityEngineIDLen;
  1483.         user_just_created = 1;
  1484.     }
  1485.     /*
  1486.      * copy the auth protocol 
  1487.      */
  1488.     if (session->securityAuthProto != NULL) {
  1489.         SNMP_FREE(user->authProtocol);
  1490.         user->authProtocol =
  1491.             snmp_duplicate_objid(session->securityAuthProto,
  1492.                                  session->securityAuthProtoLen);
  1493.         if (user->authProtocol == NULL) {
  1494.             usm_free_user(user);
  1495.             return SNMPERR_GENERR;
  1496.         }
  1497.         user->authProtocolLen = session->securityAuthProtoLen;
  1498.     }
  1499.     /*
  1500.      * copy the priv protocol 
  1501.      */
  1502.     if (session->securityPrivProto != NULL) {
  1503.         SNMP_FREE(user->privProtocol);
  1504.         user->privProtocol =
  1505.             snmp_duplicate_objid(session->securityPrivProto,
  1506.                                  session->securityPrivProtoLen);
  1507.         if (user->privProtocol == NULL) {
  1508.             usm_free_user(user);
  1509.             return SNMPERR_GENERR;
  1510.         }
  1511.         user->privProtocolLen = session->securityPrivProtoLen;
  1512.     }
  1513.     /*
  1514.      * copy in the authentication Key.  If not localized, localize it 
  1515.      */
  1516.     if (session->securityAuthLocalKey != NULL
  1517.         && session->securityAuthLocalKeyLen != 0) {
  1518.         /* already localized key passed in.  use it */
  1519.         if (memdup(&user->authKey, session->securityAuthLocalKey,
  1520.                    session->securityAuthLocalKeyLen) != SNMPERR_SUCCESS) {
  1521.             usm_free_user(user);
  1522.             return SNMPERR_GENERR;
  1523.         }
  1524.         user->authKeyLen = session->securityAuthLocalKeyLen;
  1525.     } else if (session->securityAuthKey != NULL
  1526.         && session->securityAuthKeyLen != 0) {
  1527.         SNMP_FREE(user->authKey);
  1528.         user->authKey = (u_char *) calloc(1, USM_LENGTH_KU_HASHBLOCK);
  1529.         if (user->authKey == NULL) {
  1530.             usm_free_user(user);
  1531.             return SNMPERR_GENERR;
  1532.         }
  1533.         user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
  1534.         if (generate_kul(user->authProtocol, user->authProtocolLen,
  1535.                          session->securityEngineID,
  1536.                          session->securityEngineIDLen,
  1537.                          session->securityAuthKey,
  1538.                          session->securityAuthKeyLen, user->authKey,
  1539.                          &user->authKeyLen) != SNMPERR_SUCCESS) {
  1540.             usm_free_user(user);
  1541.             return SNMPERR_GENERR;
  1542.         }
  1543.     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1544.                                            NETSNMP_DS_LIB_AUTHLOCALIZEDKEY))) {
  1545.         size_t buflen = USM_AUTH_KU_LEN;
  1546.         user->authKey = malloc(buflen); /* max length needed */
  1547.         user->authKeyLen = 0;
  1548.         /* it will be a hex string */
  1549.         if (!snmp_hex_to_binary(&user->authKey, &buflen, &user->authKeyLen,
  1550.                                 0, cp)) {
  1551.             usm_free_user(user);
  1552.             return SNMPERR_GENERR;
  1553.         }
  1554.     }
  1555.     /*
  1556.      * copy in the privacy Key.  If not localized, localize it 
  1557.      */
  1558.     if (session->securityPrivLocalKey != NULL
  1559.         && session->securityPrivLocalKeyLen != 0) {
  1560.         /* already localized key passed in.  use it */
  1561.         if (memdup(&user->privKey, session->securityPrivLocalKey,
  1562.                    session->securityPrivLocalKeyLen) != SNMPERR_SUCCESS) {
  1563.             usm_free_user(user);
  1564.             return SNMPERR_GENERR;
  1565.         }
  1566.         user->privKeyLen = session->securityPrivLocalKeyLen;
  1567.     } else if (session->securityPrivKey != NULL
  1568.         && session->securityPrivKeyLen != 0) {
  1569.         SNMP_FREE(user->privKey);
  1570.         user->privKey = (u_char *) calloc(1, USM_LENGTH_KU_HASHBLOCK);
  1571.         if (user->privKey == NULL) {
  1572.             usm_free_user(user);
  1573.             return SNMPERR_GENERR;
  1574.         }
  1575.         user->privKeyLen = USM_LENGTH_KU_HASHBLOCK;
  1576.         if (generate_kul(user->authProtocol, user->authProtocolLen,
  1577.                          session->securityEngineID,
  1578.                          session->securityEngineIDLen,
  1579.                          session->securityPrivKey,
  1580.                          session->securityPrivKeyLen, user->privKey,
  1581.                          &user->privKeyLen) != SNMPERR_SUCCESS) {
  1582.             usm_free_user(user);
  1583.             return SNMPERR_GENERR;
  1584.         }
  1585.     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
  1586.                                            NETSNMP_DS_LIB_PRIVLOCALIZEDKEY))) {
  1587.         size_t buflen = USM_PRIV_KU_LEN;
  1588.         user->privKey = malloc(buflen); /* max length needed */
  1589.         user->privKeyLen = 0;
  1590.         /* it will be a hex string */
  1591.         if (!snmp_hex_to_binary(&user->privKey, &buflen, &user->privKeyLen,
  1592.                                 0, cp)) {
  1593.             usm_free_user(user);
  1594.             return SNMPERR_GENERR;
  1595.         }
  1596.     }
  1597.     user->userStatus = RS_ACTIVE;
  1598.     user->userStorageType = ST_READONLY;
  1599.     if (user_just_created) {
  1600.         /*
  1601.          * add the user into the database 
  1602.          */
  1603.         usm_add_user(user);
  1604.     }
  1605.     return SNMPERR_SUCCESS;
  1606. }                               /* end create_user_from_session() */
  1607. /*
  1608.  *  Do a "deep free()" of a netsnmp_session.
  1609.  *
  1610.  *  CAUTION:  SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
  1611.  *                                                      (hence it is static)
  1612.  */
  1613. static void
  1614. snmp_free_session(netsnmp_session * s)
  1615. {
  1616.     if (s) {
  1617.         SNMP_FREE(s->peername);
  1618.         SNMP_FREE(s->community);
  1619.         SNMP_FREE(s->contextEngineID);
  1620.         SNMP_FREE(s->contextName);
  1621.         SNMP_FREE(s->securityEngineID);
  1622.         SNMP_FREE(s->securityName);
  1623.         SNMP_FREE(s->securityAuthProto);
  1624.         SNMP_FREE(s->securityPrivProto);
  1625.         /*
  1626.          * clear session from any callbacks
  1627.          */
  1628.         netsnmp_callback_clear_client_arg(s, 0, 0);
  1629.         free((char *) s);
  1630.     }
  1631. }
  1632. /*
  1633.  * Close the input session.  Frees all data allocated for the session,
  1634.  * dequeues any pending requests, and closes any sockets allocated for
  1635.  * the session.  Returns 0 on error, 1 otherwise.
  1636.  */
  1637. int
  1638. snmp_sess_close(void *sessp)
  1639. {
  1640.     struct session_list *slp = (struct session_list *) sessp;
  1641.     netsnmp_transport *transport;
  1642.     struct snmp_internal_session *isp;
  1643.     netsnmp_session *sesp = NULL;
  1644.     struct snmp_secmod_def *sptr;
  1645.     if (slp == NULL) {
  1646.         return 0;
  1647.     }
  1648.     if (slp->session != NULL &&
  1649.         (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
  1650.         sptr->session_close != NULL) {
  1651.         (*sptr->session_close) (slp->session);
  1652.     }
  1653.     isp = slp->internal;
  1654.     slp->internal = 0;
  1655.     if (isp) {
  1656.         netsnmp_request_list *rp, *orp;
  1657.         SNMP_FREE(isp->packet);
  1658.         /*
  1659.          * Free each element in the input request list.  
  1660.          */
  1661.         rp = isp->requests;
  1662.         while (rp) {
  1663.             orp = rp;
  1664.             rp = rp->next_request;
  1665.             snmp_free_pdu(orp->pdu);
  1666.             free((char *) orp);
  1667.         }
  1668.         free((char *) isp);
  1669.     }
  1670.     transport = slp->transport;
  1671.     slp->transport = 0;
  1672.     if (transport) {
  1673.         transport->f_close(transport);
  1674.         netsnmp_transport_free(transport);
  1675.     }
  1676.     sesp = slp->session;
  1677.     slp->session = 0;
  1678.     /*
  1679.      * The following is necessary to avoid memory leakage when closing AgentX 
  1680.      * sessions that may have multiple subsessions.  These hang off the main
  1681.      * session at ->subsession, and chain through ->next.  
  1682.      */
  1683.     if (sesp != NULL && sesp->subsession != NULL) {
  1684.         netsnmp_session *subsession = sesp->subsession, *tmpsub;
  1685.         while (subsession != NULL) {
  1686.             DEBUGMSGTL(("snmp_sess_close",
  1687.                         "closing session %p, subsession %pn", sesp,
  1688.                         subsession));
  1689.             tmpsub = subsession->next;
  1690.             snmp_free_session(subsession);
  1691.             subsession = tmpsub;
  1692.         }
  1693.     }
  1694.     snmp_free_session(sesp);
  1695.     free((char *) slp);
  1696.     return 1;
  1697. }
  1698. int
  1699. snmp_close(netsnmp_session * session)
  1700. {
  1701.     struct session_list *slp = NULL, *oslp = NULL;
  1702.     {                           /*MTCRITICAL_RESOURCE */
  1703.         snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1704.         if (Sessions && Sessions->session == session) { /* If first entry */
  1705.             slp = Sessions;
  1706.             Sessions = slp->next;
  1707.         } else {
  1708.             for (slp = Sessions; slp; slp = slp->next) {
  1709.                 if (slp->session == session) {
  1710.                     if (oslp)   /* if we found entry that points here */
  1711.                         oslp->next = slp->next; /* link around this entry */
  1712.                     break;
  1713.                 }
  1714.                 oslp = slp;
  1715.             }
  1716.         }
  1717.         snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1718.     }                           /*END MTCRITICAL_RESOURCE */
  1719.     if (slp == NULL) {
  1720.         return 0;
  1721.     }
  1722.     return snmp_sess_close((void *) slp);
  1723. }
  1724. int
  1725. snmp_close_sessions(void)
  1726. {
  1727.     struct session_list *slp;
  1728.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1729.     while (Sessions) {
  1730.         slp = Sessions;
  1731.         Sessions = Sessions->next;
  1732.         snmp_sess_close((void *) slp);
  1733.     }
  1734.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1735.     return 1;
  1736. }
  1737. static int
  1738. snmpv3_build_probe_pdu(netsnmp_pdu **pdu)
  1739. {
  1740.     struct usmUser *user;
  1741.     /*
  1742.      * create the pdu 
  1743.      */
  1744.     if (!pdu)
  1745.         return -1;
  1746.     *pdu = snmp_pdu_create(SNMP_MSG_GET);
  1747.     if (!(*pdu))
  1748.         return -1;
  1749.     (*pdu)->version = SNMP_VERSION_3;
  1750.     (*pdu)->securityName = strdup("");
  1751.     (*pdu)->securityNameLen = strlen((*pdu)->securityName);
  1752.     (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  1753.     (*pdu)->securityModel = SNMP_SEC_MODEL_USM;
  1754.     /*
  1755.      * create the empty user 
  1756.      */
  1757.     user = usm_get_user(NULL, 0, (*pdu)->securityName);
  1758.     if (user == NULL) {
  1759.         user = (struct usmUser *) calloc(1, sizeof(struct usmUser));
  1760.         if (user == NULL) {
  1761.             snmp_free_pdu(*pdu);
  1762.             *pdu = (netsnmp_pdu *) NULL;
  1763.             return -1;
  1764.         }
  1765.         user->name = strdup((*pdu)->securityName);
  1766.         user->secName = strdup((*pdu)->securityName);
  1767.         user->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
  1768.         user->authProtocol =
  1769.             snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
  1770.         user->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
  1771.         user->privProtocol =
  1772.             snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
  1773.         usm_add_user(user);
  1774.     }
  1775.     return 0;
  1776. }
  1777. static void
  1778. snmpv3_calc_msg_flags(int sec_level, int msg_command, u_char * flags)
  1779. {
  1780.     *flags = 0;
  1781.     if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
  1782.         *flags = SNMP_MSG_FLAG_AUTH_BIT;
  1783.     else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
  1784.         *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
  1785.     if (SNMP_CMD_CONFIRMED(msg_command))
  1786.         *flags |= SNMP_MSG_FLAG_RPRT_BIT;
  1787.     return;
  1788. }
  1789. static int
  1790. snmpv3_verify_msg(netsnmp_request_list *rp, netsnmp_pdu *pdu)
  1791. {
  1792.     netsnmp_pdu    *rpdu;
  1793.     if (!rp || !rp->pdu || !pdu)
  1794.         return 0;
  1795.     /*
  1796.      * Reports don't have to match anything according to the spec 
  1797.      */
  1798.     if (pdu->command == SNMP_MSG_REPORT)
  1799.         return 1;
  1800.     rpdu = rp->pdu;
  1801.     if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid)
  1802.         return 0;
  1803.     if (rpdu->version != pdu->version)
  1804.         return 0;
  1805.     if (rpdu->securityModel != pdu->securityModel)
  1806.         return 0;
  1807.     if (rpdu->securityLevel != pdu->securityLevel)
  1808.         return 0;
  1809.     if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen ||
  1810.         memcmp(rpdu->contextEngineID, pdu->contextEngineID,
  1811.                pdu->contextEngineIDLen))
  1812.         return 0;
  1813.     if (rpdu->contextNameLen != pdu->contextNameLen ||
  1814.         memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
  1815.         return 0;
  1816.     if (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
  1817.         memcmp(rpdu->securityEngineID, pdu->securityEngineID,
  1818.                pdu->securityEngineIDLen))
  1819.         return 0;
  1820.     if (rpdu->securityNameLen != pdu->securityNameLen ||
  1821.         memcmp(rpdu->securityName, pdu->securityName,
  1822.                pdu->securityNameLen))
  1823.         return 0;
  1824.     return 1;
  1825. }
  1826. /*
  1827.  * SNMPv3
  1828.  * * Takes a session and a pdu and serializes the ASN PDU into the area
  1829.  * * pointed to by packet.  out_length is the size of the data area available.
  1830.  * * Returns the length of the completed packet in out_length.  If any errors
  1831.  * * occur, -1 is returned.  If all goes well, 0 is returned.
  1832.  */
  1833. static int
  1834. snmpv3_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
  1835.              netsnmp_session * session, netsnmp_pdu *pdu)
  1836. {
  1837.     int             ret;
  1838.     session->s_snmp_errno = 0;
  1839.     session->s_errno = 0;
  1840.     /*
  1841.      * do validation for PDU types 
  1842.      */
  1843.     switch (pdu->command) {
  1844.     case SNMP_MSG_RESPONSE:
  1845.     case SNMP_MSG_TRAP2:
  1846.     case SNMP_MSG_REPORT:
  1847.         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
  1848.         /*
  1849.          * Fallthrough 
  1850.          */
  1851.     case SNMP_MSG_GET:
  1852.     case SNMP_MSG_GETNEXT:
  1853.     case SNMP_MSG_SET:
  1854.     case SNMP_MSG_INFORM:
  1855.         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  1856.             pdu->errstat = 0;
  1857.         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  1858.             pdu->errindex = 0;
  1859.         break;
  1860.     case SNMP_MSG_GETBULK:
  1861.         if (pdu->max_repetitions < 0) {
  1862.             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
  1863.             return -1;
  1864.         }
  1865.         if (pdu->non_repeaters < 0) {
  1866.             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
  1867.             return -1;
  1868.         }
  1869.         break;
  1870.     case SNMP_MSG_TRAP:
  1871.         session->s_snmp_errno = SNMPERR_V1_IN_V2;
  1872.         return -1;
  1873.     default:
  1874.         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
  1875.         return -1;
  1876.     }
  1877.     /* Do we need to set the session security engineid? */
  1878.     if (pdu->securityEngineIDLen == 0) {
  1879.         if (session->securityEngineIDLen) {
  1880.             snmpv3_clone_engineID(&pdu->securityEngineID,
  1881.                                   &pdu->securityEngineIDLen,
  1882.                                   session->securityEngineID,
  1883.                                   session->securityEngineIDLen);
  1884.         }
  1885.     }
  1886.     
  1887.     /* Do we need to set the session context engineid? */
  1888.     if (pdu->contextEngineIDLen == 0) {
  1889.         if (session->contextEngineIDLen) {
  1890.             snmpv3_clone_engineID(&pdu->contextEngineID,
  1891.                                   &pdu->contextEngineIDLen,
  1892.                                   session->contextEngineID,
  1893.                                   session->contextEngineIDLen);
  1894.         } else if (pdu->securityEngineIDLen) {
  1895.             snmpv3_clone_engineID(&pdu->contextEngineID,
  1896.                                   &pdu->contextEngineIDLen,
  1897.                                   pdu->securityEngineID,
  1898.                                   pdu->securityEngineIDLen);
  1899.         }
  1900.     }
  1901.     if (pdu->contextName == NULL) {
  1902.         if (!session->contextName) {
  1903.             session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
  1904.             return -1;
  1905.         }
  1906.         pdu->contextName = strdup(session->contextName);
  1907.         if (pdu->contextName == NULL) {
  1908.             session->s_snmp_errno = SNMPERR_GENERR;
  1909.             return -1;
  1910.         }
  1911.         pdu->contextNameLen = session->contextNameLen;
  1912.     }
  1913.     if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
  1914.         pdu->securityModel = session->securityModel;
  1915.         if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
  1916.             pdu->securityModel = SNMP_SEC_MODEL_USM;
  1917.         }
  1918.     }
  1919.     if (pdu->securityNameLen == 0 && pdu->securityName == 0) {
  1920.         if (session->securityNameLen == 0) {
  1921.             session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
  1922.             return -1;
  1923.         }
  1924.         pdu->securityName = strdup(session->securityName);
  1925.         if (pdu->securityName == NULL) {
  1926.             session->s_snmp_errno = SNMPERR_GENERR;
  1927.             return -1;
  1928.         }
  1929.         pdu->securityNameLen = session->securityNameLen;
  1930.     }
  1931.     if (pdu->securityLevel == 0) {
  1932.         if (session->securityLevel == 0) {
  1933.             session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
  1934.             return -1;
  1935.         }
  1936.         pdu->securityLevel = session->securityLevel;
  1937.     }
  1938.     DEBUGMSGTL(("snmp_build",
  1939.                 "Building SNMPv3 message (secName:"%s", secLevel:%s)...n",
  1940.                 ((session->securityName) ? (char *) session->securityName :
  1941.                  ((pdu->securityName) ? (char *) pdu->securityName :
  1942.                   "ERROR: undefined")), secLevelName[pdu->securityLevel]));
  1943.     DEBUGDUMPSECTION("send", "SNMPv3 Message");
  1944. #ifdef USE_REVERSE_ASNENCODING
  1945.     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
  1946.         ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
  1947.                                            session, pdu, NULL, 0);
  1948.     } else {
  1949. #endif
  1950.         ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
  1951. #ifdef USE_REVERSE_ASNENCODING
  1952.     }
  1953. #endif
  1954.     DEBUGINDENTLESS();
  1955.     if (-1 != ret) {
  1956.         session->s_snmp_errno = ret;
  1957.     }
  1958.     return ret;
  1959. }                               /* end snmpv3_build() */
  1960. static u_char  *
  1961. snmpv3_header_build(netsnmp_session * session, netsnmp_pdu *pdu,
  1962.                     u_char * packet, size_t * out_length,
  1963.                     size_t length, u_char ** msg_hdr_e)
  1964. {
  1965.     u_char         *global_hdr, *global_hdr_e;
  1966.     u_char         *cp;
  1967.     u_char          msg_flags;
  1968.     long            max_size;
  1969.     long            sec_model;
  1970.     u_char         *pb, *pb0e;
  1971.     /*
  1972.      * Save current location and build SEQUENCE tag and length placeholder
  1973.      * * for SNMP message sequence (actual length inserted later)
  1974.      */
  1975.     cp = asn_build_sequence(packet, out_length,
  1976.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1977.                             length);
  1978.     if (cp == NULL)
  1979.         return NULL;
  1980.     if (msg_hdr_e != NULL)
  1981.         *msg_hdr_e = cp;
  1982.     pb0e = cp;
  1983.     /*
  1984.      * store the version field - msgVersion
  1985.      */
  1986.     DEBUGDUMPHEADER("send", "SNMP Version Number");
  1987.     cp = asn_build_int(cp, out_length,
  1988.                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  1989.                                  ASN_INTEGER), (long *) &pdu->version,
  1990.                        sizeof(pdu->version));
  1991.     DEBUGINDENTLESS();
  1992.     if (cp == NULL)
  1993.         return NULL;
  1994.     global_hdr = cp;
  1995.     /*
  1996.      * msgGlobalData HeaderData 
  1997.      */
  1998.     DEBUGDUMPSECTION("send", "msgGlobalData");
  1999.     cp = asn_build_sequence(cp, out_length,
  2000.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
  2001.     if (cp == NULL)
  2002.         return NULL;
  2003.     global_hdr_e = cp;
  2004.     /*
  2005.      * msgID 
  2006.      */
  2007.     DEBUGDUMPHEADER("send", "msgID");
  2008.     cp = asn_build_int(cp, out_length,
  2009.                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2010.                                  ASN_INTEGER), &pdu->msgid,
  2011.                        sizeof(pdu->msgid));
  2012.     DEBUGINDENTLESS();
  2013.     if (cp == NULL)
  2014.         return NULL;
  2015.     /*
  2016.      * msgMaxSize 
  2017.      */
  2018.     max_size = session->rcvMsgMaxSize;
  2019.     DEBUGDUMPHEADER("send", "msgMaxSize");
  2020.     cp = asn_build_int(cp, out_length,
  2021.                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2022.                                  ASN_INTEGER), &max_size,
  2023.                        sizeof(max_size));
  2024.     DEBUGINDENTLESS();
  2025.     if (cp == NULL)
  2026.         return NULL;
  2027.     /*
  2028.      * msgFlags 
  2029.      */
  2030.     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
  2031.     DEBUGDUMPHEADER("send", "msgFlags");
  2032.     cp = asn_build_string(cp, out_length,
  2033.                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2034.                                     ASN_OCTET_STR), &msg_flags,
  2035.                           sizeof(msg_flags));
  2036.     DEBUGINDENTLESS();
  2037.     if (cp == NULL)
  2038.         return NULL;
  2039.     /*
  2040.      * msgSecurityModel 
  2041.      */
  2042.     sec_model = pdu->securityModel;
  2043.     DEBUGDUMPHEADER("send", "msgSecurityModel");
  2044.     cp = asn_build_int(cp, out_length,
  2045.                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2046.                                  ASN_INTEGER), &sec_model,
  2047.                        sizeof(sec_model));
  2048.     DEBUGINDENTADD(-4);         /* return from global data indent */
  2049.     if (cp == NULL)
  2050.         return NULL;
  2051.     /*
  2052.      * insert actual length of globalData
  2053.      */
  2054.     pb = asn_build_sequence(global_hdr, out_length,
  2055.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2056.                             cp - global_hdr_e);
  2057.     if (pb == NULL)
  2058.         return NULL;
  2059.     /*
  2060.      * insert the actual length of the entire packet
  2061.      */
  2062.     pb = asn_build_sequence(packet, out_length,
  2063.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2064.                             length + (cp - pb0e));
  2065.     if (pb == NULL)
  2066.         return NULL;
  2067.     return cp;
  2068. }                               /* end snmpv3_header_build() */
  2069. #ifdef USE_REVERSE_ASNENCODING
  2070. int
  2071. snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
  2072.                              size_t * offset, netsnmp_session * session,
  2073.                              netsnmp_pdu *pdu)
  2074. {
  2075.     size_t          start_offset = *offset;
  2076.     u_char          msg_flags;
  2077.     long            max_size, sec_model;
  2078.     int             rc = 0;
  2079.     /*
  2080.      * msgSecurityModel.  
  2081.      */
  2082.     sec_model = pdu->securityModel;
  2083.     DEBUGDUMPHEADER("send", "msgSecurityModel");
  2084.     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  2085.                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2086.                                           ASN_INTEGER), &sec_model,
  2087.                                 sizeof(sec_model));
  2088.     DEBUGINDENTLESS();
  2089.     if (rc == 0) {
  2090.         return 0;
  2091.     }
  2092.     /*
  2093.      * msgFlags.  
  2094.      */
  2095.     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
  2096.     DEBUGDUMPHEADER("send", "msgFlags");
  2097.     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
  2098.                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  2099.                                              | ASN_OCTET_STR), &msg_flags,
  2100.                                    sizeof(msg_flags));
  2101.     DEBUGINDENTLESS();
  2102.     if (rc == 0) {
  2103.         return 0;
  2104.     }
  2105.     /*
  2106.      * msgMaxSize.  
  2107.      */
  2108.     max_size = session->rcvMsgMaxSize;
  2109.     DEBUGDUMPHEADER("send", "msgMaxSize");
  2110.     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  2111.                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2112.                                           ASN_INTEGER), &max_size,
  2113.                                 sizeof(max_size));
  2114.     DEBUGINDENTLESS();
  2115.     if (rc == 0) {
  2116.         return 0;
  2117.     }
  2118.     /*
  2119.      * msgID.  
  2120.      */
  2121.     DEBUGDUMPHEADER("send", "msgID");
  2122.     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  2123.                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2124.                                           ASN_INTEGER), &pdu->msgid,
  2125.                                 sizeof(pdu->msgid));
  2126.     DEBUGINDENTLESS();
  2127.     if (rc == 0) {
  2128.         return 0;
  2129.     }
  2130.     /*
  2131.      * Global data sequence.  
  2132.      */
  2133.     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
  2134.                                      (u_char) (ASN_SEQUENCE |
  2135.                                                ASN_CONSTRUCTOR),
  2136.                                      *offset - start_offset);
  2137.     if (rc == 0) {
  2138.         return 0;
  2139.     }
  2140.     /*
  2141.      * Store the version field - msgVersion.  
  2142.      */
  2143.     DEBUGDUMPHEADER("send", "SNMP Version Number");
  2144.     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  2145.                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2146.                                           ASN_INTEGER),
  2147.                                 (long *) &pdu->version,
  2148.                                 sizeof(pdu->version));
  2149.     DEBUGINDENTLESS();
  2150.     return rc;
  2151. }                               /* end snmpv3_header_realloc_rbuild() */
  2152. #endif                          /* USE_REVERSE_ASNENCODING */
  2153. static u_char  *
  2154. snmpv3_scopedPDU_header_build(netsnmp_pdu *pdu,
  2155.                               u_char * packet, size_t * out_length,
  2156.                               u_char ** spdu_e)
  2157. {
  2158.     size_t          init_length;
  2159.     u_char         *scopedPdu, *pb;
  2160.     init_length = *out_length;
  2161.     pb = scopedPdu = packet;
  2162.     pb = asn_build_sequence(pb, out_length,
  2163.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
  2164.     if (pb == NULL)
  2165.         return NULL;
  2166.     if (spdu_e)
  2167.         *spdu_e = pb;
  2168.     DEBUGDUMPHEADER("send", "contextEngineID");
  2169.     pb = asn_build_string(pb, out_length,
  2170.                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  2171.                           pdu->contextEngineID, pdu->contextEngineIDLen);
  2172.     DEBUGINDENTLESS();
  2173.     if (pb == NULL)
  2174.         return NULL;
  2175.     DEBUGDUMPHEADER("send", "contextName");
  2176.     pb = asn_build_string(pb, out_length,
  2177.                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  2178.                           (u_char *) pdu->contextName,
  2179.                           pdu->contextNameLen);
  2180.     DEBUGINDENTLESS();
  2181.     if (pb == NULL)
  2182.         return NULL;
  2183.     return pb;
  2184. }                               /* end snmpv3_scopedPDU_header_build() */
  2185. #ifdef USE_REVERSE_ASNENCODING
  2186. int
  2187. snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
  2188.                                        size_t * offset, netsnmp_pdu *pdu,
  2189.                                        size_t body_len)
  2190. {
  2191.     size_t          start_offset = *offset;
  2192.     int             rc = 0;
  2193.     /*
  2194.      * contextName.  
  2195.      */
  2196.     DEBUGDUMPHEADER("send", "contextName");
  2197.     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
  2198.                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  2199.                                              | ASN_OCTET_STR),
  2200.                                    (u_char *) pdu->contextName,
  2201.                                    pdu->contextNameLen);
  2202.     DEBUGINDENTLESS();
  2203.     if (rc == 0) {
  2204.         return 0;
  2205.     }
  2206.     /*
  2207.      * contextEngineID.  
  2208.      */
  2209.     DEBUGDUMPHEADER("send", "contextEngineID");
  2210.     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
  2211.                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  2212.                                              | ASN_OCTET_STR),
  2213.                                    pdu->contextEngineID,
  2214.                                    pdu->contextEngineIDLen);
  2215.     DEBUGINDENTLESS();
  2216.     if (rc == 0) {
  2217.         return 0;
  2218.     }
  2219.     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
  2220.                                      (u_char) (ASN_SEQUENCE |
  2221.                                                ASN_CONSTRUCTOR),
  2222.                                      *offset - start_offset + body_len);
  2223.     return rc;
  2224. }                               /* end snmpv3_scopedPDU_header_realloc_rbuild() */
  2225. #endif                          /* USE_REVERSE_ASNENCODING */
  2226. #ifdef USE_REVERSE_ASNENCODING
  2227. /*
  2228.  * returns 0 if success, -1 if fail, not 0 if SM build failure 
  2229.  */
  2230. int
  2231. snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
  2232.                              size_t * offset, netsnmp_session * session,
  2233.                              netsnmp_pdu *pdu, u_char * pdu_data,
  2234.                              size_t pdu_data_len)
  2235. {
  2236.     u_char         *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
  2237.     size_t          hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
  2238.         0, spdu_offset = 0;
  2239.     size_t          body_end_offset = *offset, body_len = 0;
  2240.     struct snmp_secmod_def *sptr = NULL;
  2241.     int             rc = 0;
  2242.     /*
  2243.      * Build a scopedPDU structure into the packet buffer.  
  2244.      */
  2245.     DEBUGPRINTPDUTYPE("send", pdu->command);
  2246.     if (pdu_data) {
  2247.         while ((*pkt_len - *offset) < pdu_data_len) {
  2248.             if (!asn_realloc(pkt, pkt_len)) {
  2249.                 return -1;
  2250.             }
  2251.         }
  2252.         *offset += pdu_data_len;
  2253.         memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
  2254.     } else {
  2255.         rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
  2256.         if (rc == 0) {
  2257.             return -1;
  2258.         }
  2259.     }
  2260.     body_len = *offset - body_end_offset;
  2261.     DEBUGDUMPSECTION("send", "ScopedPdu");
  2262.     rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
  2263.                                                 pdu, body_len);
  2264.     if (rc == 0) {
  2265.         return -1;
  2266.     }
  2267.     spdu_offset = *offset;
  2268.     DEBUGINDENTADD(-4);         /*  Return from Scoped PDU.  */
  2269.     if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
  2270.         return -1;
  2271.     }
  2272.     rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
  2273.                                       session, pdu);
  2274.     if (rc == 0) {
  2275.         SNMP_FREE(hdrbuf);
  2276.         return -1;
  2277.     }
  2278.     hdr = hdrbuf + hdrbuf_len - hdr_offset;
  2279.     scoped_pdu = *pkt + *pkt_len - spdu_offset;
  2280.     /*
  2281.      * Call the security module to possibly encrypt and authenticate the
  2282.      * message---the entire message to transmitted on the wire is returned.  
  2283.      */
  2284.     sptr = find_sec_mod(pdu->securityModel);
  2285.     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
  2286.     if (sptr && sptr->encode_reverse) {
  2287.         struct snmp_secmod_outgoing_params parms;
  2288.         parms.msgProcModel = pdu->msgParseModel;
  2289.         parms.globalData = hdr;
  2290.         parms.globalDataLen = hdr_offset;
  2291.         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
  2292.         parms.secModel = pdu->securityModel;
  2293.         parms.secEngineID = pdu->securityEngineID;
  2294.         parms.secEngineIDLen = pdu->securityEngineIDLen;
  2295.         parms.secName = pdu->securityName;
  2296.         parms.secNameLen = pdu->securityNameLen;
  2297.         parms.secLevel = pdu->securityLevel;
  2298.         parms.scopedPdu = scoped_pdu;
  2299.         parms.scopedPduLen = spdu_offset;
  2300.         parms.secStateRef = pdu->securityStateRef;
  2301.         parms.wholeMsg = pkt;
  2302.         parms.wholeMsgLen = pkt_len;
  2303.         parms.wholeMsgOffset = offset;
  2304.         parms.session = session;
  2305.         parms.pdu = pdu;
  2306.         rc = (*sptr->encode_reverse) (&parms);
  2307.     } else {
  2308.         if (!sptr) {
  2309.             snmp_log(LOG_ERR,
  2310.                      "no such security service available: %dn",
  2311.                      pdu->securityModel);
  2312.         } else if (!sptr->encode_reverse) {
  2313.             snmp_log(LOG_ERR,
  2314.                      "security service %d doesn't support reverse encoding.n",
  2315.                      pdu->securityModel);
  2316.         }
  2317.         rc = -1;
  2318.     }
  2319.     DEBUGINDENTLESS();
  2320.     SNMP_FREE(hdrbuf);
  2321.     return rc;
  2322. }                               /* end snmpv3_packet_realloc_rbuild() */
  2323. #endif                          /* USE_REVERSE_ASNENCODING */
  2324. /*
  2325.  * returns 0 if success, -1 if fail, not 0 if SM build failure 
  2326.  */
  2327. int
  2328. snmpv3_packet_build(netsnmp_session * session, netsnmp_pdu *pdu,
  2329.                     u_char * packet, size_t * out_length,
  2330.                     u_char * pdu_data, size_t pdu_data_len)
  2331. {
  2332.     u_char         *global_data, *sec_params, *spdu_hdr_e;
  2333.     size_t          global_data_len, sec_params_len;
  2334.     u_char          spdu_buf[SNMP_MAX_MSG_SIZE];
  2335.     size_t          spdu_buf_len, spdu_len;
  2336.     u_char         *cp;
  2337.     int             result;
  2338.     struct snmp_secmod_def *sptr;
  2339.     global_data = packet;
  2340.     /*
  2341.      * build the headers for the packet, returned addr = start of secParams
  2342.      */
  2343.     sec_params = snmpv3_header_build(session, pdu, global_data,
  2344.                                      out_length, 0, NULL);
  2345.     if (sec_params == NULL)
  2346.         return -1;
  2347.     global_data_len = sec_params - global_data;
  2348.     sec_params_len = *out_length;       /* length left in packet buf for sec_params */
  2349.     /*
  2350.      * build a scopedPDU structure into spdu_buf
  2351.      */
  2352.     spdu_buf_len = SNMP_MAX_MSG_SIZE;
  2353.     DEBUGDUMPSECTION("send", "ScopedPdu");
  2354.     cp = snmpv3_scopedPDU_header_build(pdu, spdu_buf, &spdu_buf_len,
  2355.                                        &spdu_hdr_e);
  2356.     if (cp == NULL)
  2357.         return -1;
  2358.     /*
  2359.      * build the PDU structure onto the end of spdu_buf 
  2360.      */
  2361.     DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
  2362.     if (pdu_data) {
  2363.         memcpy(cp, pdu_data, pdu_data_len);
  2364.         cp += pdu_data_len;
  2365.     } else {
  2366.         cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
  2367.         if (cp == NULL)
  2368.             return -1;
  2369.     }
  2370.     DEBUGINDENTADD(-4);         /* return from Scoped PDU */
  2371.     /*
  2372.      * re-encode the actual ASN.1 length of the scopedPdu
  2373.      */
  2374.     spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
  2375.     spdu_buf_len = SNMP_MAX_MSG_SIZE;
  2376.     if (asn_build_sequence(spdu_buf, &spdu_buf_len,
  2377.                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2378.                            spdu_len) == NULL)
  2379.         return -1;
  2380.     spdu_len = cp - spdu_buf;   /* the length of the entire scopedPdu */
  2381.     /*
  2382.      * call the security module to possibly encrypt and authenticate the
  2383.      * message - the entire message to transmitted on the wire is returned
  2384.      */
  2385.     cp = NULL;
  2386.     *out_length = SNMP_MAX_MSG_SIZE;
  2387.     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
  2388.     sptr = find_sec_mod(pdu->securityModel);
  2389.     if (sptr && sptr->encode_forward) {
  2390.         struct snmp_secmod_outgoing_params parms;
  2391.         parms.msgProcModel = pdu->msgParseModel;
  2392.         parms.globalData = global_data;
  2393.         parms.globalDataLen = global_data_len;
  2394.         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
  2395.         parms.secModel = pdu->securityModel;
  2396.         parms.secEngineID = pdu->securityEngineID;
  2397.         parms.secEngineIDLen = pdu->securityEngineIDLen;
  2398.         parms.secName = pdu->securityName;
  2399.         parms.secNameLen = pdu->securityNameLen;
  2400.         parms.secLevel = pdu->securityLevel;
  2401.         parms.scopedPdu = spdu_buf;
  2402.         parms.scopedPduLen = spdu_len;
  2403.         parms.secStateRef = pdu->securityStateRef;
  2404.         parms.secParams = sec_params;
  2405.         parms.secParamsLen = &sec_params_len;
  2406.         parms.wholeMsg = &cp;
  2407.         parms.wholeMsgLen = out_length;
  2408.         parms.session = session;
  2409.         parms.pdu = pdu;
  2410.         result = (*sptr->encode_forward) (&parms);
  2411.     } else {
  2412.         if (!sptr) {
  2413.             snmp_log(LOG_ERR, "no such security service available: %dn",
  2414.                      pdu->securityModel);
  2415.         } else if (!sptr->encode_forward) {
  2416.             snmp_log(LOG_ERR,
  2417.                      "security service %d doesn't support forward out encoding.n",
  2418.                      pdu->securityModel);
  2419.         }
  2420.         result = -1;
  2421.     }
  2422.     DEBUGINDENTLESS();
  2423.     return result;
  2424. }                               /* end snmpv3_packet_build() */
  2425. /*
  2426.  * Takes a session and a pdu and serializes the ASN PDU into the area
  2427.  * pointed to by *pkt.  *pkt_len is the size of the data area available.
  2428.  * Returns the length of the completed packet in *offset.  If any errors
  2429.  * occur, -1 is returned.  If all goes well, 0 is returned.
  2430.  */
  2431. static int
  2432. _snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
  2433.             netsnmp_session * session, netsnmp_pdu *pdu)
  2434. {
  2435. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  2436.     u_char         *h0e = 0;
  2437.     size_t          start_offset = *offset;
  2438.     long            version;
  2439.     int             rc = 0;
  2440. #endif /* support for community based SNMP */
  2441.     
  2442.     u_char         *h0, *h1;
  2443.     u_char         *cp;
  2444.     size_t          length;
  2445.     session->s_snmp_errno = 0;
  2446.     session->s_errno = 0;
  2447.     if (pdu->version == SNMP_VERSION_3) {
  2448.         return snmpv3_build(pkt, pkt_len, offset, session, pdu);
  2449.     }
  2450.     switch (pdu->command) {
  2451.     case SNMP_MSG_RESPONSE:
  2452.         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
  2453.         /*
  2454.          * Fallthrough 
  2455.          */
  2456.     case SNMP_MSG_GET:
  2457.     case SNMP_MSG_GETNEXT:
  2458.     case SNMP_MSG_SET:
  2459.         /*
  2460.          * all versions support these PDU types 
  2461.          */
  2462.         /*
  2463.          * initialize defaulted PDU fields 
  2464.          */
  2465.         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  2466.             pdu->errstat = 0;
  2467.         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  2468.             pdu->errindex = 0;
  2469.         break;
  2470.     case SNMP_MSG_TRAP2:
  2471.         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
  2472.         /*
  2473.          * Fallthrough 
  2474.          */
  2475.     case SNMP_MSG_INFORM:
  2476. #ifndef DISABLE_SNMPV1
  2477.         /*
  2478.          * not supported in SNMPv1 and SNMPsec 
  2479.          */
  2480.         if (pdu->version == SNMP_VERSION_1) {
  2481.             session->s_snmp_errno = SNMPERR_V2_IN_V1;
  2482.             return -1;
  2483.         }
  2484. #endif
  2485.         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  2486.             pdu->errstat = 0;
  2487.         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  2488.             pdu->errindex = 0;
  2489.         break;
  2490.     case SNMP_MSG_GETBULK:
  2491.         /*
  2492.          * not supported in SNMPv1 and SNMPsec 
  2493.          */
  2494. #ifndef DISABLE_SNMPV1
  2495.         if (pdu->version == SNMP_VERSION_1) {
  2496.             session->s_snmp_errno = SNMPERR_V2_IN_V1;
  2497.             return -1;
  2498.         }
  2499. #endif
  2500.         if (pdu->max_repetitions < 0) {
  2501.             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
  2502.             return -1;
  2503.         }
  2504.         if (pdu->non_repeaters < 0) {
  2505.             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
  2506.             return -1;
  2507.         }
  2508.         break;
  2509.     case SNMP_MSG_TRAP:
  2510.         /*
  2511.          * *only* supported in SNMPv1 and SNMPsec 
  2512.          */
  2513. #ifndef DISABLE_SNMPV1
  2514.         if (pdu->version != SNMP_VERSION_1) {
  2515.             session->s_snmp_errno = SNMPERR_V1_IN_V2;
  2516.             return -1;
  2517.         }
  2518. #endif
  2519.         /*
  2520.          * initialize defaulted Trap PDU fields 
  2521.          */
  2522.         pdu->reqid = 1;         /* give a bogus non-error reqid for traps */
  2523.         if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
  2524.             pdu->enterprise = (oid *) malloc(sizeof(DEFAULT_ENTERPRISE));
  2525.             if (pdu->enterprise == NULL) {
  2526.                 session->s_snmp_errno = SNMPERR_MALLOC;
  2527.                 return -1;
  2528.             }
  2529.             memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
  2530.                     sizeof(DEFAULT_ENTERPRISE));
  2531.             pdu->enterprise_length =
  2532.                 sizeof(DEFAULT_ENTERPRISE) / sizeof(oid);
  2533.         }
  2534.         if (pdu->time == SNMP_DEFAULT_TIME)
  2535.             pdu->time = DEFAULT_TIME;
  2536.         /*
  2537.          * don't expect a response 
  2538.          */
  2539.         pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  2540.         break;
  2541.     case SNMP_MSG_REPORT:      /* SNMPv3 only */
  2542.     default:
  2543.         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
  2544.         return -1;
  2545.     }
  2546.     /*
  2547.      * save length 
  2548.      */
  2549.     length = *pkt_len;
  2550.     /*
  2551.      * setup administrative fields based on version 
  2552.      */
  2553.     /*
  2554.      * build the message wrapper and all the administrative fields
  2555.      * upto the PDU sequence
  2556.      * (note that actual length of message will be inserted later) 
  2557.      */
  2558.     h0 = *pkt;
  2559.     switch (pdu->version) {
  2560. #ifndef DISABLE_SNMPV1
  2561.     case SNMP_VERSION_1:
  2562. #endif
  2563. #ifndef DISABLE_SNMPV2C
  2564.     case SNMP_VERSION_2c:
  2565. #endif
  2566. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  2567. #ifdef NO_ZEROLENGTH_COMMUNITY
  2568.         if (pdu->community_len == 0) {
  2569.             if (session->community_len == 0) {
  2570.                 session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
  2571.                 return -1;
  2572.             }
  2573.             pdu->community = (u_char *) malloc(session->community_len);
  2574.             if (pdu->community == NULL) {
  2575.                 session->s_snmp_errno = SNMPERR_MALLOC;
  2576.                 return -1;
  2577.             }
  2578.             memmove(pdu->community,
  2579.                     session->community, session->community_len);
  2580.             pdu->community_len = session->community_len;
  2581.         }
  2582. #else                           /* !NO_ZEROLENGTH_COMMUNITY */
  2583.         if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
  2584.             /*
  2585.              * copy session community exactly to pdu community 
  2586.              */
  2587.             if (0 == session->community_len) {
  2588.                 SNMP_FREE(pdu->community);
  2589.                 pdu->community = NULL;
  2590.             } else if (pdu->community_len == session->community_len) {
  2591.                 memmove(pdu->community,
  2592.                         session->community, session->community_len);
  2593.             } else {
  2594.                 SNMP_FREE(pdu->community);
  2595.                 pdu->community = (u_char *) malloc(session->community_len);
  2596.                 if (pdu->community == NULL) {
  2597.                     session->s_snmp_errno = SNMPERR_MALLOC;
  2598.                     return -1;
  2599.                 }
  2600.                 memmove(pdu->community,
  2601.                         session->community, session->community_len);
  2602.             }
  2603.             pdu->community_len = session->community_len;
  2604.         }
  2605. #endif                          /* !NO_ZEROLENGTH_COMMUNITY */
  2606.         DEBUGMSGTL(("snmp_send", "Building SNMPv%d message...n",
  2607.                     (1 + pdu->version)));
  2608. #ifdef USE_REVERSE_ASNENCODING
  2609.         if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
  2610.             DEBUGPRINTPDUTYPE("send", pdu->command);
  2611.             rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
  2612.             if (rc == 0) {
  2613.                 return -1;
  2614.             }
  2615.             DEBUGDUMPHEADER("send", "Community String");
  2616.             rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
  2617.                                            (u_char) (ASN_UNIVERSAL |
  2618.                                                      ASN_PRIMITIVE |
  2619.                                                      ASN_OCTET_STR),
  2620.                                            pdu->community,
  2621.                                            pdu->community_len);
  2622.             DEBUGINDENTLESS();
  2623.             if (rc == 0) {
  2624.                 return -1;
  2625.             }
  2626.             /*
  2627.              * Store the version field.  
  2628.              */
  2629.             DEBUGDUMPHEADER("send", "SNMP Version Number");
  2630.             version = pdu->version;
  2631.             rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  2632.                                         (u_char) (ASN_UNIVERSAL |
  2633.                                                   ASN_PRIMITIVE |
  2634.                                                   ASN_INTEGER),
  2635.                                         (long *) &version,
  2636.                                         sizeof(version));
  2637.             DEBUGINDENTLESS();
  2638.             if (rc == 0) {
  2639.                 return -1;
  2640.             }
  2641.             /*
  2642.              * Build the final sequence.  
  2643.              */
  2644.             if (pdu->version == SNMP_VERSION_1) {
  2645.                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
  2646.             } else {
  2647.                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
  2648.             }
  2649.             rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
  2650.                                              (u_char) (ASN_SEQUENCE |
  2651.                                                        ASN_CONSTRUCTOR),
  2652.                                              *offset - start_offset);
  2653.             DEBUGINDENTLESS();
  2654.             if (rc == 0) {
  2655.                 return -1;
  2656.             }
  2657.             return 0;
  2658.         } else {
  2659. #endif                          /* USE_REVERSE_ASNENCODING */
  2660.             /*
  2661.              * Save current location and build SEQUENCE tag and length
  2662.              * placeholder for SNMP message sequence
  2663.              * (actual length will be inserted later) 
  2664.              */
  2665.             cp = asn_build_sequence(*pkt, pkt_len,
  2666.                                     (u_char) (ASN_SEQUENCE |
  2667.                                               ASN_CONSTRUCTOR), 0);
  2668.             if (cp == NULL) {
  2669.                 return -1;
  2670.             }
  2671.             h0e = cp;
  2672.             if (pdu->version == SNMP_VERSION_1) {
  2673.                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
  2674.             } else {
  2675.                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
  2676.             }
  2677.             /*
  2678.              * store the version field 
  2679.              */
  2680.             DEBUGDUMPHEADER("send", "SNMP Version Number");
  2681.             version = pdu->version;
  2682.             cp = asn_build_int(*pkt, pkt_len,
  2683.                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2684.                                          ASN_INTEGER), (long *) &version,
  2685.                                sizeof(version));
  2686.             DEBUGINDENTLESS();
  2687.             if (cp == NULL)
  2688.                 return -1;
  2689.             /*
  2690.              * store the community string 
  2691.              */
  2692.             DEBUGDUMPHEADER("send", "Community String");
  2693.             cp = asn_build_string(*pkt, pkt_len,
  2694.                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2695.                                             ASN_OCTET_STR), pdu->community,
  2696.                                   pdu->community_len);
  2697.             DEBUGINDENTLESS();
  2698.             if (cp == NULL)
  2699.                 return -1;
  2700.             break;
  2701. #ifdef USE_REVERSE_ASNENCODING
  2702.         }
  2703. #endif                          /* USE_REVERSE_ASNENCODING */
  2704.         break;
  2705. #endif /* support for community based SNMP */
  2706.     case SNMP_VERSION_2p:
  2707.     case SNMP_VERSION_sec:
  2708.     case SNMP_VERSION_2u:
  2709.     case SNMP_VERSION_2star:
  2710.     default:
  2711.         session->s_snmp_errno = SNMPERR_BAD_VERSION;
  2712.         return -1;
  2713.     }
  2714.     h1 = cp;
  2715.     DEBUGPRINTPDUTYPE("send", pdu->command);
  2716.     cp = snmp_pdu_build(pdu, cp, pkt_len);
  2717.     DEBUGINDENTADD(-4);         /* return from entire v1/v2c message */
  2718.     if (cp == NULL)
  2719.         return -1;
  2720.     /*
  2721.      * insert the actual length of the message sequence 
  2722.      */
  2723.     switch (pdu->version) {
  2724. #ifndef DISABLE_SNMPV1
  2725.     case SNMP_VERSION_1:
  2726. #endif
  2727. #ifndef DISABLE_SNMPV2C
  2728.     case SNMP_VERSION_2c:
  2729. #endif
  2730. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  2731.         asn_build_sequence(*pkt, &length,
  2732.                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2733.                            cp - h0e);
  2734.         break;
  2735. #endif /* support for community based SNMP */
  2736.     case SNMP_VERSION_2p:
  2737.     case SNMP_VERSION_sec:
  2738.     case SNMP_VERSION_2u:
  2739.     case SNMP_VERSION_2star:
  2740.     default:
  2741.         session->s_snmp_errno = SNMPERR_BAD_VERSION;
  2742.         return -1;
  2743.     }
  2744.     *pkt_len = cp - *pkt;
  2745.     return 0;
  2746. }
  2747. int
  2748. snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
  2749.            netsnmp_session * pss, netsnmp_pdu *pdu)
  2750. {
  2751.     int             rc;
  2752.     rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
  2753.     if (rc) {
  2754.         if (!pss->s_snmp_errno) {
  2755.             pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
  2756.         }
  2757.         SET_SNMP_ERROR(pss->s_snmp_errno);
  2758.         rc = -1;
  2759.     }
  2760.     return rc;
  2761. }
  2762. /*
  2763.  * on error, returns NULL (likely an encoding problem). 
  2764.  */
  2765. u_char         *
  2766. snmp_pdu_build(netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
  2767. {
  2768.     u_char         *h1, *h1e, *h2, *h2e;
  2769.     netsnmp_variable_list *vp;
  2770.     size_t          length;
  2771.     length = *out_length;
  2772.     /*
  2773.      * Save current location and build PDU tag and length placeholder
  2774.      * (actual length will be inserted later) 
  2775.      */
  2776.     h1 = cp;
  2777.     cp = asn_build_sequence(cp, out_length, (u_char) pdu->command, 0);
  2778.     if (cp == NULL)
  2779.         return NULL;
  2780.     h1e = cp;
  2781.     /*
  2782.      * store fields in the PDU preceeding the variable-bindings sequence 
  2783.      */
  2784.     if (pdu->command != SNMP_MSG_TRAP) {
  2785.         /*
  2786.          * PDU is not an SNMPv1 trap 
  2787.          */
  2788.         DEBUGDUMPHEADER("send", "request_id");
  2789.         /*
  2790.          * request id 
  2791.          */
  2792.         cp = asn_build_int(cp, out_length,
  2793.                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2794.                                      ASN_INTEGER), &pdu->reqid,
  2795.                            sizeof(pdu->reqid));
  2796.         DEBUGINDENTLESS();
  2797.         if (cp == NULL)
  2798.             return NULL;
  2799.         /*
  2800.          * error status (getbulk non-repeaters) 
  2801.          */
  2802.         DEBUGDUMPHEADER("send", "error status");
  2803.         cp = asn_build_int(cp, out_length,
  2804.                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2805.                                      ASN_INTEGER), &pdu->errstat,
  2806.                            sizeof(pdu->errstat));
  2807.         DEBUGINDENTLESS();
  2808.         if (cp == NULL)
  2809.             return NULL;
  2810.         /*
  2811.          * error index (getbulk max-repetitions) 
  2812.          */
  2813.         DEBUGDUMPHEADER("send", "error index");
  2814.         cp = asn_build_int(cp, out_length,
  2815.                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2816.                                      ASN_INTEGER), &pdu->errindex,
  2817.                            sizeof(pdu->errindex));
  2818.         DEBUGINDENTLESS();
  2819.         if (cp == NULL)
  2820.             return NULL;
  2821.     } else {
  2822.         /*
  2823.          * an SNMPv1 trap PDU 
  2824.          */
  2825.         /*
  2826.          * enterprise 
  2827.          */
  2828.         DEBUGDUMPHEADER("send", "enterprise OBJID");
  2829.         cp = asn_build_objid(cp, out_length,
  2830.                              (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2831.                                        ASN_OBJECT_ID),
  2832.                              (oid *) pdu->enterprise,
  2833.                              pdu->enterprise_length);
  2834.         DEBUGINDENTLESS();
  2835.         if (cp == NULL)
  2836.             return NULL;
  2837.         /*
  2838.          * agent-addr 
  2839.          */
  2840.         DEBUGDUMPHEADER("send", "agent Address");
  2841.         cp = asn_build_string(cp, out_length,
  2842.                               (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
  2843.                               (u_char *) pdu->agent_addr, 4);
  2844.         DEBUGINDENTLESS();
  2845.         if (cp == NULL)
  2846.             return NULL;
  2847.         /*
  2848.          * generic trap 
  2849.          */
  2850.         DEBUGDUMPHEADER("send", "generic trap number");
  2851.         cp = asn_build_int(cp, out_length,
  2852.                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2853.                                      ASN_INTEGER),
  2854.                            (long *) &pdu->trap_type,
  2855.                            sizeof(pdu->trap_type));
  2856.         DEBUGINDENTLESS();
  2857.         if (cp == NULL)
  2858.             return NULL;
  2859.         /*
  2860.          * specific trap 
  2861.          */
  2862.         DEBUGDUMPHEADER("send", "specific trap number");
  2863.         cp = asn_build_int(cp, out_length,
  2864.                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
  2865.                                      ASN_INTEGER),
  2866.                            (long *) &pdu->specific_type,
  2867.                            sizeof(pdu->specific_type));
  2868.         DEBUGINDENTLESS();
  2869.         if (cp == NULL)
  2870.             return NULL;
  2871.         /*
  2872.          * timestamp  
  2873.          */
  2874.         DEBUGDUMPHEADER("send", "timestamp");
  2875.         cp = asn_build_unsigned_int(cp, out_length,
  2876.                                     (u_char) (ASN_TIMETICKS |
  2877.                                               ASN_PRIMITIVE), &pdu->time,
  2878.                                     sizeof(pdu->time));
  2879.         DEBUGINDENTLESS();
  2880.         if (cp == NULL)
  2881.             return NULL;
  2882.     }
  2883.     /*
  2884.      * Save current location and build SEQUENCE tag and length placeholder
  2885.      * for variable-bindings sequence
  2886.      * (actual length will be inserted later) 
  2887.      */
  2888.     h2 = cp;
  2889.     cp = asn_build_sequence(cp, out_length,
  2890.                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
  2891.     if (cp == NULL)
  2892.         return NULL;
  2893.     h2e = cp;
  2894.     /*
  2895.      * Store variable-bindings 
  2896.      */
  2897.     DEBUGDUMPSECTION("send", "VarBindList");
  2898.     for (vp = pdu->variables; vp; vp = vp->next_variable) {
  2899.         DEBUGDUMPSECTION("send", "VarBind");
  2900.         cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
  2901.                                vp->val_len, (u_char *) vp->val.string,
  2902.                                out_length);
  2903.         DEBUGINDENTLESS();
  2904.         if (cp == NULL)
  2905.             return NULL;
  2906.     }
  2907.     DEBUGINDENTLESS();
  2908.     /*
  2909.      * insert actual length of variable-bindings sequence 
  2910.      */
  2911.     asn_build_sequence(h2, &length,
  2912.                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2913.                        cp - h2e);
  2914.     /*
  2915.      * insert actual length of PDU sequence 
  2916.      */
  2917.     asn_build_sequence(h1, &length, (u_char) pdu->command, cp - h1e);
  2918.     return cp;
  2919. }
  2920. #ifdef USE_REVERSE_ASNENCODING
  2921. /*
  2922.  * On error, returns 0 (likely an encoding problem).  
  2923.  */
  2924. int
  2925. snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
  2926.                         netsnmp_pdu *pdu)
  2927. {
  2928. #ifndef VPCACHE_SIZE
  2929. #define VPCACHE_SIZE 50
  2930. #endif
  2931.     netsnmp_variable_list *vpcache[VPCACHE_SIZE];
  2932.     netsnmp_variable_list *vp, *tmpvp;
  2933.     size_t          start_offset = *offset;
  2934.     int             i, wrapped = 0, notdone, final, rc = 0;
  2935.     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "startingn"));
  2936.     for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
  2937.          vp = vp->next_variable, i--) {
  2938.         if (i < 0) {
  2939.             wrapped = notdone = 1;
  2940.             i = VPCACHE_SIZE - 1;
  2941.             DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrappedn"));
  2942.         }
  2943.         vpcache[i] = vp;
  2944.     }
  2945.     final = i + 1;
  2946.     do {
  2947.         for (i = final; i < VPCACHE_SIZE; i++) {
  2948.             vp = vpcache[i];
  2949.             DEBUGDUMPSECTION("send", "VarBind");
  2950.             rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
  2951.                                             vp->name, &vp->name_length,
  2952.                                             vp->type,
  2953.                                             (u_char *) vp->val.string,
  2954.                                             vp->val_len);
  2955.             DEBUGINDENTLESS();
  2956.             if (rc == 0) {
  2957.                 return 0;
  2958.             }
  2959.         }
  2960.         DEBUGINDENTLESS();
  2961.         if (wrapped) {
  2962.             notdone = 1;
  2963.             for (i = 0; i < final; i++) {
  2964.                 vp = vpcache[i];
  2965.                 DEBUGDUMPSECTION("send", "VarBind");
  2966.                 rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
  2967.                                                 vp->name, &vp->name_length,
  2968.                                                 vp->type,
  2969.                                                 (u_char *) vp->val.string,
  2970.                                                 vp->val_len);
  2971.                 DEBUGINDENTLESS();
  2972.                 if (rc == 0) {
  2973.                     return 0;
  2974.                 }
  2975.             }
  2976.             if (final == 0) {
  2977.                 tmpvp = vpcache[VPCACHE_SIZE - 1];
  2978.             } else {
  2979.                 tmpvp = vpcache[final - 1];
  2980.             }
  2981.             wrapped = 0;
  2982.             for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
  2983.                  vp && vp != tmpvp; vp = vp->next_variable, i--) {
  2984.                 if (i < 0) {
  2985.                     wrapped = 1;
  2986.                     i = VPCACHE_SIZE - 1;
  2987.                     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrappedn"));
  2988.                 }
  2989.                 vpcache[i] = vp;
  2990.             }
  2991.             final = i + 1;
  2992.         } else {
  2993.             notdone = 0;
  2994.         }
  2995.     } while (notdone);
  2996.     /*
  2997.      * Save current location and build SEQUENCE tag and length placeholder for
  2998.      * variable-bindings sequence (actual length will be inserted later).  
  2999.      */
  3000.     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
  3001.                                      (u_char) (ASN_SEQUENCE |
  3002.                                                ASN_CONSTRUCTOR),
  3003.                                      *offset - start_offset);
  3004.     /*
  3005.      * Store fields in the PDU preceeding the variable-bindings sequence.  
  3006.      */
  3007.     if (pdu->command != SNMP_MSG_TRAP) {
  3008.         /*
  3009.          * Error index (getbulk max-repetitions).  
  3010.          */
  3011.         DEBUGDUMPHEADER("send", "error index");
  3012.         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  3013.                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  3014.                                               | ASN_INTEGER),
  3015.                                     &pdu->errindex, sizeof(pdu->errindex));
  3016.         DEBUGINDENTLESS();
  3017.         if (rc == 0) {
  3018.             return 0;
  3019.         }
  3020.         /*
  3021.          * Error status (getbulk non-repeaters).  
  3022.          */
  3023.         DEBUGDUMPHEADER("send", "error status");
  3024.         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  3025.                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  3026.                                               | ASN_INTEGER),
  3027.                                     &pdu->errstat, sizeof(pdu->errstat));
  3028.         DEBUGINDENTLESS();
  3029.         if (rc == 0) {
  3030.             return 0;
  3031.         }
  3032.         /*
  3033.          * Request ID.  
  3034.          */
  3035.         DEBUGDUMPHEADER("send", "request_id");
  3036.         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  3037.                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  3038.                                               | ASN_INTEGER), &pdu->reqid,
  3039.                                     sizeof(pdu->reqid));
  3040.         DEBUGINDENTLESS();
  3041.         if (rc == 0) {
  3042.             return 0;
  3043.         }
  3044.     } else {
  3045.         /*
  3046.          * An SNMPv1 trap PDU.  
  3047.          */
  3048.         /*
  3049.          * Timestamp.  
  3050.          */
  3051.         DEBUGDUMPHEADER("send", "timestamp");
  3052.         rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
  3053.                                              (u_char) (ASN_TIMETICKS |
  3054.                                                        ASN_PRIMITIVE),
  3055.                                              &pdu->time,
  3056.                                              sizeof(pdu->time));
  3057.         DEBUGINDENTLESS();
  3058.         if (rc == 0) {
  3059.             return 0;
  3060.         }
  3061.         /*
  3062.          * Specific trap.  
  3063.          */
  3064.         DEBUGDUMPHEADER("send", "specific trap number");
  3065.         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  3066.                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  3067.                                               | ASN_INTEGER),
  3068.                                     (long *) &pdu->specific_type,
  3069.                                     sizeof(pdu->specific_type));
  3070.         DEBUGINDENTLESS();
  3071.         if (rc == 0) {
  3072.             return 0;
  3073.         }
  3074.         /*
  3075.          * Generic trap.  
  3076.          */
  3077.         DEBUGDUMPHEADER("send", "generic trap number");
  3078.         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
  3079.                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
  3080.                                               | ASN_INTEGER),
  3081.                                     (long *) &pdu->trap_type,
  3082.                                     sizeof(pdu->trap_type));
  3083.         DEBUGINDENTLESS();
  3084.         if (rc == 0) {
  3085.             return 0;
  3086.         }
  3087.         /*
  3088.          * Agent-addr.  
  3089.          */
  3090.         DEBUGDUMPHEADER("send", "agent Address");
  3091.         rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
  3092.                                        (u_char) (ASN_IPADDRESS |
  3093.                                                  ASN_PRIMITIVE),
  3094.                                        (u_char *) pdu->agent_addr, 4);
  3095.         DEBUGINDENTLESS();
  3096.         if (rc == 0) {
  3097.             return 0;
  3098.         }
  3099.         /*
  3100.          * Enterprise.  
  3101.          */
  3102.         DEBUGDUMPHEADER("send", "enterprise OBJID");
  3103.         rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
  3104.                                       (u_char) (ASN_UNIVERSAL |
  3105.                                                 ASN_PRIMITIVE |
  3106.                                                 ASN_OBJECT_ID),
  3107.                                       (oid *) pdu->enterprise,
  3108.                                       pdu->enterprise_length);
  3109.         DEBUGINDENTLESS();
  3110.         if (rc == 0) {
  3111.             return 0;
  3112.         }
  3113.     }
  3114.     /*
  3115.      * Build the PDU sequence.  
  3116.      */
  3117.     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
  3118.                                      (u_char) pdu->command,
  3119.                                      *offset - start_offset);
  3120.     return rc;
  3121. }
  3122. #endif                          /* USE_REVERSE_ASNENCODING */
  3123. /*
  3124.  * Parses the packet received to determine version, either directly
  3125.  * from packets version field or inferred from ASN.1 construct.
  3126.  */
  3127. static int
  3128. snmp_parse_version(u_char * data, size_t length)
  3129. {
  3130.     u_char          type;
  3131.     long            version = SNMPERR_BAD_VERSION;
  3132.     data = asn_parse_sequence(data, &length, &type,
  3133.                               (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
  3134.     if (data) {
  3135.         data =
  3136.             asn_parse_int(data, &length, &type, &version, sizeof(version));
  3137.         if (!data || type != ASN_INTEGER) {
  3138.             return SNMPERR_BAD_VERSION;
  3139.         }
  3140.     }
  3141.     return version;
  3142. }
  3143. int
  3144. snmpv3_parse(netsnmp_pdu *pdu,
  3145.              u_char * data,
  3146.              size_t * length,
  3147.              u_char ** after_header, netsnmp_session * sess)
  3148. {
  3149.     u_char          type, msg_flags;
  3150.     long            ver, msg_max_size, msg_sec_model;
  3151.     size_t          max_size_response;
  3152.     u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
  3153.     size_t          tmp_buf_len;
  3154.     u_char          pdu_buf[SNMP_MAX_MSG_SIZE];
  3155.     u_char         *mallocbuf = NULL;
  3156.     size_t          pdu_buf_len = SNMP_MAX_MSG_SIZE;
  3157.     u_char         *sec_params;
  3158.     u_char         *msg_data;
  3159.     u_char         *cp;
  3160.     size_t          asn_len, msg_len;
  3161.     int             ret, ret_val;
  3162.     struct snmp_secmod_def *sptr;
  3163.     msg_data = data;
  3164.     msg_len = *length;