snmp_api.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:144k
源码类别:

SNMP编程

开发平台:

C/C++

  1. /******************************************************************
  2. Copyright 1989, 1991, 1992 by Carnegie Mellon University
  3.                       All Rights Reserved
  4. Permission to use, copy, modify, and distribute this software and its
  5. documentation for any purpose and without fee is hereby granted,
  6. provided that the above copyright notice appear in all copies and that
  7. both that copyright notice and this permission notice appear in
  8. supporting documentation, and that the name of CMU not be
  9. used in advertising or publicity pertaining to distribution of the
  10. software without specific, written prior permission.
  11. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  12. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  13. CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  14. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  15. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  16. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  17. SOFTWARE.
  18. ******************************************************************/
  19. /*
  20.  * snmp_api.c - API for access to snmp.
  21.  */
  22. #include <config.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #if HAVE_STDLIB_H
  26. #include <stdlib.h>
  27. #endif
  28. #if HAVE_STRING_H
  29. #include <string.h>
  30. #else
  31. #include <strings.h>
  32. #endif
  33. #if HAVE_UNISTD_H
  34. #include <unistd.h>
  35. #endif
  36. #include <sys/types.h>
  37. #if HAVE_SYS_PARAM_H
  38. #include <sys/param.h>
  39. #endif
  40. #if TIME_WITH_SYS_TIME
  41. # ifdef WIN32
  42. #  include <sys/timeb.h>
  43. # else
  44. #  include <time.h>
  45. # endif
  46. # include <time.h>
  47. #else
  48. # if HAVE_SYS_TIME_H
  49. #  include <sys/time.h>
  50. # else
  51. #  include <time.h>
  52. # endif
  53. #endif
  54. #ifdef OS_VXWORKS
  55. #include <sys/times.h>
  56. #endif
  57. #if HAVE_NETINET_IN_H
  58. #include <netinet/in.h>
  59. #endif
  60. #if HAVE_ARPA_INET_H
  61. #include <arpa/inet.h>
  62. #endif
  63. #if HAVE_SYS_SELECT_H
  64. #include <sys/select.h>
  65. #endif
  66. #if HAVE_WINSOCK_H
  67. #include <ip/socket.h>
  68. #endif
  69. #if HAVE_SYS_SOCKET_H
  70. #include <sys/socket.h>
  71. #endif
  72. #if HAVE_SYS_UN_H
  73. #include <sys/un.h>
  74. #endif
  75. #if HAVE_NETDB_H
  76. #include <netdb.h>
  77. #endif
  78. #if HAVE_NET_IF_DL_H
  79. #include <net/if_dl.h>
  80. #endif
  81. #include <errno.h>
  82. #if HAVE_LOCALE_H
  83. #include <locale.h>
  84. #endif
  85. #if HAVE_DMALLOC_H
  86. #include <dmalloc.h>
  87. #endif
  88. #include <ip/inet.h>
  89. #include "asn1.h"
  90. #include "snmp.h"
  91. #define SNMP_NEED_REQUEST_LIST
  92. #include "snmp_api.h"
  93. #include "snmp_client.h"
  94. #include "snmp_impl.h"
  95. #include "parse.h"
  96. #include "mib.h"
  97. #include "system.h"
  98. #include "int64.h"
  99. #include "snmpv3.h"
  100. #include "read_config.h"
  101. #include "snmp_debug.h"
  102. #include "callback.h"
  103. #include "snmpusm.h"
  104. #include "tools.h"
  105. #include "keytools.h"
  106. #include "lcd_time.h"
  107. #include "snmp_alarm.h"
  108. #include "snmp_logging.h"
  109. #include "default_store.h"
  110. #include "mt_support.h"
  111. #include <ip/netdb.h>
  112. #include <snmp/config_struct.h>
  113. static void _init_snmp (void);
  114. extern char *strdup (char*);
  115. extern ULONG snmp_source_ip;
  116. #include "transform_oids.h"
  117. #ifndef timercmp
  118. #define timercmp(tvp, uvp, cmp) 
  119. /* CSTYLED */ 
  120. ((tvp)->tv_sec cmp (uvp)->tv_sec || 
  121. ((tvp)->tv_sec == (uvp)->tv_sec && 
  122. /* CSTYLED */ 
  123. (tvp)->tv_usec cmp (uvp)->tv_usec))
  124. #endif
  125. #ifndef timerclear
  126. #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
  127. #endif
  128. /*
  129.  * Globals.
  130.  */
  131. #define PACKET_LENGTH (8 * 1024)
  132. #define MAX_PACKET_LENGTH (32768)
  133. #ifndef SNMP_STREAM_QUEUE_LEN
  134. #define SNMP_STREAM_QUEUE_LEN  5
  135. #endif
  136. #ifndef BSD4_3
  137. #define BSD4_2
  138. #endif
  139. #ifndef FD_SET
  140. typedef long fd_mask;
  141. #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
  142. #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  143. #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  144. #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  145. #define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
  146. #endif
  147. #define DEFAULT_COMMUNITY   "public"
  148. #define DEFAULT_RETRIES     5
  149. #define DEFAULT_TIMEOUT     1000000L
  150. #define DEFAULT_REMPORT     SNMP_PORT
  151. #define DEFAULT_ENTERPRISE  default_enterprise
  152. #define DEFAULT_TIME     0
  153. /*
  154.  * Internal information about the state of the snmp session.
  155.  */
  156. struct snmp_internal_session {
  157.     int     sd; /* socket descriptor for this connection */
  158.     struct soaddr  addr; /* address of connected peer */
  159.     struct soaddr  me; /* address of local socket */
  160.     struct request_list *requests;/* Info about outstanding requests */
  161.     struct request_list *requestsEnd; /* ptr to end of list */
  162.     int (*hook_pre)  ( struct snmp_session*, struct soaddr);
  163.     int (*hook_parse)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
  164.     int (*hook_post) ( struct snmp_session*, struct snmp_pdu*, int );
  165.     int (*hook_build)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
  166.     int (*check_packet) ( u_char *, size_t );
  167.     u_char *packet;
  168.     long packet_len, proper_len;
  169.     size_t packet_size;
  170.     char newpkt;
  171. };
  172. /*
  173.  * The list of active/open sessions.
  174.  */
  175. struct session_list {
  176.     struct session_list *next;
  177.     struct snmp_session *session;
  178.     struct snmp_internal_session *internal;
  179. };
  180. static const char *api_errors[-SNMPERR_MAX+1] = {
  181.     "No error",                            /* SNMPERR_SUCCESS */
  182.     "Generic error",                       /* SNMPERR_GENERR */
  183.     "Invalid local port",                  /* SNMPERR_BAD_LOCPORT */
  184.     "Unknown host",                        /* SNMPERR_BAD_ADDRESS */
  185.     "Unknown session",                     /* SNMPERR_BAD_SESSION */
  186.     "Too long",                            /* SNMPERR_TOO_LONG */
  187.     "No socket",                           /* SNMPERR_NO_SOCKET */
  188.     "Cannot send V2 PDU on V1 session",    /* SNMPERR_V2_IN_V1 */
  189.     "Cannot send V1 PDU on V2 session",    /* SNMPERR_V1_IN_V2 */
  190.     "Bad value for non-repeaters",         /* SNMPERR_BAD_REPEATERS */
  191.     "Bad value for max-repetitions",       /* SNMPERR_BAD_REPETITIONS */
  192.     "Error building ASN.1 representation", /* SNMPERR_BAD_ASN1_BUILD */
  193.     "Failure in sendto",                   /* SNMPERR_BAD_SENDTO */
  194.     "Bad parse of ASN.1 type",             /* SNMPERR_BAD_PARSE */
  195.     "Bad version specified",               /* SNMPERR_BAD_VERSION */
  196.     "Bad source party specified",          /* SNMPERR_BAD_SRC_PARTY */
  197.     "Bad destination party specified",     /* SNMPERR_BAD_DST_PARTY */
  198.     "Bad context specified",               /* SNMPERR_BAD_CONTEXT */
  199.     "Bad community specified",             /* SNMPERR_BAD_COMMUNITY */
  200.     "Cannot send noAuth/desPriv",          /* SNMPERR_NOAUTH_DESPRIV */
  201.     "Bad ACL definition",                  /* SNMPERR_BAD_ACL */
  202.     "Bad Party definition",                /* SNMPERR_BAD_PARTY */
  203.     "Session abort failure",               /* SNMPERR_ABORT */
  204.     "Unknown PDU type",                    /* SNMPERR_UNKNOWN_PDU */
  205.     "Timeout",                             /* SNMPERR_TIMEOUT */
  206.     "Failure in recvfrom",                 /* SNMPERR_BAD_RECVFROM */
  207.     "Unable to determine contextEngineID", /* SNMPERR_BAD_ENG_ID */
  208.     "Unable to determine securityName",    /* SNMPERR_BAD_SEC_NAME */
  209.     "Unable to determine securityLevel",   /* SNMPERR_BAD_SEC_LEVEL  */
  210.     "ASN.1 parse error in message",        /* SNMPERR_ASN_PARSE_ERR */
  211.     "Unknown security model in message",   /* SNMPERR_UNKNOWN_SEC_MODEL */
  212.     "Invalid message (e.g. msgFlags)",     /* SNMPERR_INVALID_MSG */
  213.     "Unknown engine ID",                   /* SNMPERR_UNKNOWN_ENG_ID */
  214.     "Unknown user name",                   /* SNMPERR_UNKNOWN_USER_NAME */
  215.     "Unsupported security level",          /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
  216.     "Authentication failure",              /* SNMPERR_AUTHENTICATION_FAILURE */
  217.     "Not in time window",                  /* SNMPERR_NOT_IN_TIME_WINDOW */
  218.     "Decryption error",                    /* SNMPERR_DECRYPTION_ERR */
  219.     "SCAPI general failure",    /* SNMPERR_SC_GENERAL_FAILURE */
  220.     "SCAPI sub-system not configured",    /* SNMPERR_SC_NOT_CONFIGURED */
  221.     "Key tools not available",    /* SNMPERR_KT_NOT_AVAILABLE */
  222.     "Unknown Report message",            /* SNMPERR_UNKNOWN_REPORT */
  223.     "USM generic error",            /* SNMPERR_USM_GENERICERROR */
  224.     "USM unknown security name",           /* SNMPERR_USM_UNKNOWNSECURITYNAME */
  225.     "USM unsupported security level",      /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
  226.     "USM encryption error",            /* SNMPERR_USM_ENCRYPTIONERROR */
  227.     "USM authentication failure",          /* SNMPERR_USM_AUTHENTICATIONFAILURE */
  228.     "USM parse error",            /* SNMPERR_USM_PARSEERROR */
  229.     "USM unknown engineID",            /* SNMPERR_USM_UNKNOWNENGINEID */
  230.     "USM not in time window",            /* SNMPERR_USM_NOTINTIMEWINDOW */
  231.     "USM decryption error",            /* SNMPERR_USM_DECRYPTIONERROR */
  232.     "MIB not initialized",    /* SNMPERR_NOMIB */
  233.     "Value out of range",    /* SNMPERR_RANGE */
  234.     "Sub-id out of range",    /* SNMPERR_MAX_SUBID */
  235.     "Bad sub-id in object identifier",    /* SNMPERR_BAD_SUBID */
  236.     "Object identifier too long",    /* SNMPERR_LONG_OID */
  237.     "Bad value name",    /* SNMPERR_BAD_NAME */
  238.     "Bad value notation",    /* SNMPERR_VALUE */
  239.     "Unknown Object Identifier",    /* SNMPERR_UNKNOWN_OBJID */
  240.     "No PDU in snmp_send",    /* SNMPERR_NULL_PDU */
  241.     "Missing variables in PDU",    /* SNMPERR_NO_VARS */
  242.     "Bad variable type",    /* SNMPERR_VAR_TYPE */
  243.     "Out of memory (malloc failure)",    /* SNMPERR_MALLOC */
  244.     "Bind VRF",    /* SNMPERR_BIND_VRF */
  245. };
  246. static const char * usmSecLevelName[] =
  247. {
  248. "BAD_SEC_LEVEL",
  249. "noAuthNoPriv",
  250. "authNoPriv",
  251. "authPriv"
  252. };
  253. /*
  254.  * Multiple threads may changes these variables.
  255.  * Suggest using the Single API, which does not use Sessions.
  256.  *
  257.  * Reqid may need to be protected. Time will tell...
  258.  *
  259.  */
  260. /*MTCRITICAL_RESOURCE*/
  261. /* use token in comments to individually protect these resources */
  262. struct session_list *Sessions  = NULL; /* MT_LIB_SESSION */
  263. static long  Reqid  = 0;    /* MT_LIB_REQUESTID */
  264. static long  Msgid  = 0;    /* MT_LIB_MESSAGEID */
  265. static long  Sessid  = 0;    /* MT_LIB_SESSIONID */
  266. static long  Transid  = 0;    /* MT_LIB_TRANSID */
  267. int              snmp_errno  = 0;
  268. /*END MTCRITICAL_RESOURCE*/
  269. /*struct timeval Now;*/
  270. /*
  271.  * global error detail storage
  272.  */
  273. static char snmp_detail[192];
  274. static int  snmp_detail_f  = 0;
  275. static char packet_buffer_read[PACKET_LENGTH];
  276. /*static char packet_buffer_send[PACKET_LENGTH];*/
  277. static char *snmp_current_community = NULL;
  278. /*
  279.  * Prototypes.
  280.  */
  281. int snmp_build (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
  282. static int snmp_parse (void *, struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
  283. static void * snmp_sess_pointer (struct snmp_session *);
  284. static void snmpv3_calc_msg_flags (int, int, u_char *);
  285. static int snmpv3_verify_msg (struct request_list *, struct snmp_pdu *);
  286. static int snmpv3_build_probe_pdu (struct snmp_pdu **);
  287. static int snmpv3_build (struct snmp_session *, struct snmp_pdu *, 
  288.      u_char *, size_t *);
  289. static int snmp_parse_version (u_char *, size_t);
  290. static int snmp_resend_request (struct session_list *slp, 
  291. struct request_list *rp, 
  292. int incr_retries);
  293. static void *trapdSessionPtr;
  294. #ifndef HAVE_STRERROR
  295. const char *strerror(int err)
  296. {
  297.   extern const char *sys_errlist[];
  298.   extern int sys_nerr;
  299.   if (err < 0 || err >= sys_nerr) return "Unknown error";
  300.   return sys_errlist[err];
  301. }
  302. #endif
  303. #ifndef SWITCH
  304. /*fanghao(A):2005-06-17*/
  305. extern int so_bind_udp_vrf_byname (int s, char *name, DEVICE_ID diID);
  306. extern int so_bind_udp_vrf_byid(int s, unsigned long vrf_id, DEVICE_ID diID);
  307. extern int udp_bind_localaddr(s, sa, namelen);
  308. #endif
  309. long
  310. snmp_get_next_reqid (void)
  311.     long retVal;
  312.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
  313.     retVal = 1 + Reqid; /*MTCRITICAL_RESOURCE*/
  314.     if (!retVal) retVal = 2;
  315.     Reqid = retVal;
  316.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
  317.     return retVal;
  318. }
  319. long
  320. snmp_get_next_msgid (void)
  321. {
  322.     long retVal;
  323.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
  324.     retVal = 1 + Msgid; /*MTCRITICAL_RESOURCE*/
  325.     if (!retVal) retVal = 2;
  326.     Msgid = retVal;
  327.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
  328.     return retVal;
  329. }
  330. long
  331. snmp_get_next_sessid (void)
  332.     long retVal;
  333.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
  334.     retVal = 1 + Sessid; /*MTCRITICAL_RESOURCE*/
  335.     if (!retVal) retVal = 2;
  336.     Sessid = retVal;
  337.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
  338.     return retVal;
  339. }
  340. long
  341. snmp_get_next_transid (void)
  342. {
  343.     long retVal;
  344.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
  345.     retVal = 1 + Transid; /*MTCRITICAL_RESOURCE*/
  346.     if (!retVal) retVal = 2;
  347.     Transid = retVal;
  348.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
  349.     return retVal;
  350. }
  351. void
  352. snmp_perror(const char *prog_string)
  353. {
  354.     const char *str;
  355.     int xerr;
  356.     xerr = snmp_errno; /*MTCRITICAL_RESOURCE*/
  357.     str = snmp_api_errstring(xerr);
  358.     snmp_log(LOG_ERR,"%s: %sn",prog_string, str);
  359. }
  360. void
  361. snmp_set_detail(const char *detail_string)
  362. {
  363.   if (detail_string != NULL) {
  364.     strncpy((char *)snmp_detail, detail_string, sizeof(snmp_detail));
  365.     snmp_detail[sizeof(snmp_detail)-1] = '';
  366.     snmp_detail_f = 1;
  367.   }
  368. }
  369. /* returns pointer to static data */
  370. /* results not guaranteed in multi-threaded use */
  371. const char *
  372. snmp_api_errstring(int snmp_errnumber)
  373. {
  374.     const char *msg = "";
  375.     static char msg_buf [256];
  376.     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
  377.         msg = api_errors[-snmp_errnumber];
  378.     } else if (snmp_errnumber != SNMPERR_SUCCESS) {
  379.         msg = "Unknown Error";
  380.     }
  381.     if (snmp_detail_f) {
  382.         sprintf (msg_buf, "%s (%s)", msg, snmp_detail);
  383.         snmp_detail_f = 0;
  384.     }
  385.     else
  386.         strcpy(msg_buf,msg);
  387.     return (msg_buf);
  388. }
  389. /*
  390.  * snmp_error - return error data
  391.  * Inputs :  address of errno, address of snmp_errno, address of string
  392.  * Caller must free the string returned after use.
  393.  */
  394. void
  395. snmp_error(struct snmp_session *psess,
  396.    int *p_errno,
  397.    int *p_snmp_errno,
  398.    char **p_str)
  399. {
  400.     char buf[SPRINT_MAX_LEN];
  401.     int snmp_errnumber;
  402.     if (p_errno) *p_errno = psess->s_errno;
  403.     if (p_snmp_errno) *p_snmp_errno = psess->s_snmp_errno;
  404.     if (p_str == NULL) return;
  405.     strcpy(buf, "");
  406.     snmp_errnumber = psess->s_snmp_errno;
  407.     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
  408. strcpy(buf, api_errors[-snmp_errnumber]);
  409.     } else {
  410. if (snmp_errnumber)
  411. sprintf(buf, "Unknown Error %d", snmp_errnumber);
  412.     }
  413.     /* append a useful system errno interpretation. */
  414.     if (psess->s_errno)
  415.         sprintf (&buf[strlen(buf)], " (%s)", strerror(psess->s_errno));
  416.     *p_str = strdup(buf);
  417. }
  418. /*
  419.  * snmp_sess_error - same as snmp_error for single session API use.
  420.  */
  421. void
  422. snmp_sess_error(void *sessp,
  423. int *p_errno,
  424. int *p_snmp_errno,
  425. char **p_str)
  426. {
  427.     struct session_list *slp = (struct session_list*)sessp;
  428.     if ((slp) && (slp->session))
  429. snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
  430. }
  431. /* snmp_sess_perror(): print a error stored in a session pointer */ 
  432. void
  433. snmp_sess_perror(const char *prog_string, struct snmp_session *ss) {
  434.   char *err;
  435.   snmp_error(ss, NULL, NULL, &err);
  436.   if (err != NULL)
  437.   {
  438. snmp_log(LOG_ERR, "%s: %sn", prog_string, err);
  439. free(err);
  440.   }
  441. }
  442. /*
  443.  * Primordial SNMP library initialization.
  444.  * Initializes mutex locks.
  445.  * Invokes minimum required initialization for displaying MIB objects.
  446.  * Gets initial request ID for all transactions,
  447.  * and finds which port SNMP over UDP uses.
  448.  * SNMP over AppleTalk or IPX is not currently supported.
  449.  *
  450.  * Warning: no debug messages here.
  451.  */
  452. static void
  453. _init_snmp (void)
  454. {
  455. #ifdef  HAVE_GETSERVBYNAME
  456.     struct servent *servp;
  457. #endif
  458.     
  459.     struct timeval tv;
  460.     long tmpReqid, tmpMsgid;
  461.     u_short s_port = SNMP_PORT;
  462.     if (Reqid) return;
  463.     Reqid = 1; /* quick set to avoid multiple inits */
  464.     snmp_res_init(); /* initialize the mt locking structures */
  465.     init_mib_internals();
  466.     gettimeofday(&tv,(struct timezone *)0);
  467.     /*Now = tv;*/
  468.     /* get pseudo-random values for request ID and message ID */
  469.     /* don't allow zero value to repeat init */
  470. #ifdef SVR4
  471.     srand48(tv.tv_sec ^ tv.tv_usec);
  472.     tmpReqid = lrand48();
  473.     tmpMsgid = lrand48();
  474. #else
  475.     srandom(tv.tv_sec ^ tv.tv_usec);
  476.     tmpReqid = random();
  477.     tmpMsgid = random();
  478. #endif
  479.     if (tmpReqid == 0) tmpReqid = 1;
  480.     if (tmpMsgid == 0) tmpMsgid = 1;
  481.     Reqid = tmpReqid;
  482.     Msgid = tmpMsgid;
  483. #ifdef HAVE_GETSERVBYNAME   
  484.     servp = getservbyname("snmp", "udp");
  485.     if (servp) {
  486.       /* store it in host byte order */
  487.       s_port = ntohs(servp->s_port);
  488.     }
  489. #endif
  490.     ds_set_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT, s_port);
  491. }
  492. /*
  493.  * Initializes the session structure.
  494.  * May perform one time minimal library initialization.
  495.  * No MIB file processing is done via this call.
  496.  */
  497. void
  498. snmp_sess_init(struct snmp_session *session)
  499. {
  500.     _init_snmp();
  501.     /* initialize session to default values */
  502.     memset(session, 0, sizeof(struct snmp_session));
  503.     session->remote_port = SNMP_DEFAULT_REMPORT;
  504.     session->timeout = SNMP_DEFAULT_TIMEOUT;
  505.     session->retries = SNMP_DEFAULT_RETRIES;
  506.     session->version = SNMP_DEFAULT_VERSION;
  507. }
  508. void
  509. register_default_handlers(void) {
  510.   ds_register_config(ASN_BOOLEAN, "snmp","dumpPacket",
  511.                      DS_LIBRARY_ID, DS_LIB_DUMP_PACKET);
  512.   ds_register_config(ASN_INTEGER, "snmp","defaultPort",
  513.                      DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
  514.   ds_register_config(ASN_OCTET_STR, "snmp","defCommunity",
  515.      DS_LIBRARY_ID, DS_LIB_COMMUNITY);
  516.   ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
  517.                      DS_LIBRARY_ID, DS_LIB_NO_TOKEN_WARNINGS);
  518.   ds_register_config(ASN_OCTET_STR, "snmp","noRangeCheck",
  519.      DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE );
  520. }
  521. /*******************************************************************-o-******
  522.  * init_snmp
  523.  *
  524.  * Parameters:
  525.  *      *type   Label for the config file "type" used by calling entity.
  526.  *
  527.  * Call appropriately the functions to do config file loading and
  528.  * mib module parsing in the correct order.
  529.  */
  530. void
  531. init_snmp(const char *type)
  532. {
  533.   static int done_init = 0; /* To prevent double init's. */
  534.   if (done_init) {
  535.     return;
  536.   }
  537.   
  538.   done_init = 1;
  539.   _init_snmp();
  540. /* set our current locale properly to initialize isprint() type functions */
  541. #ifdef HAVE_SETLOCALE
  542.   setlocale(LC_CTYPE, "");
  543. #endif
  544.   if ( type != NULL )
  545.     ds_set_string(DS_LIBRARY_ID, DS_LIB_APPTYPE, type);
  546.   init_callbacks();
  547.   snmp_init_statistics();
  548.   register_mib_handlers();
  549.   register_default_handlers();
  550.   init_snmpv3(type);
  551.   init_snmp_alarm();
  552.   read_premib_configs();
  553.   init_mib();
  554. #ifdef INCLUDE_SNMPV3
  555.   read_configs();
  556. #endif
  557. }  /* end init_snmp() */
  558. void
  559. snmp_store(const char *type) {
  560.   DEBUGMSGTL(("snmp_store","storing stuff...n"));
  561.   snmp_save_persistent(type);
  562.   snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
  563.   snmp_clean_persistent(type);
  564. }
  565. /* snmp_shutdown(const char *type):
  566.    Parameters:
  567.         *type   Label for the config file "type" used by calling entity.
  568.    Does the appropriate shutdown calls for the library, saving
  569.    persistent data, clean up, etc...
  570. */
  571. void
  572. snmp_shutdown(const char *type) {
  573.   snmp_store(type);
  574.   snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
  575.   snmp_close_sessions();
  576. }
  577. /*
  578.  * Sets up the session with the snmp_session information provided
  579.  * by the user.  Then opens and binds the necessary UDP port.
  580.  * A handle to the created session is returned (this is different than
  581.  * the pointer passed to snmp_open()).  On any error, NULL is returned
  582.  * and snmp_errno is set to the appropriate error code.
  583.  */
  584. struct snmp_session *
  585. snmp_open(struct snmp_session *session)
  586. {
  587.     struct session_list *slp;
  588.     slp = (struct session_list *)snmp_sess_open(session);
  589.     if (!slp) return NULL;
  590.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  591.     slp->next = Sessions;
  592.     Sessions = slp;
  593.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  594.     return (slp->session);
  595. }
  596. /* extended open */
  597. struct snmp_session *snmp_open_ex (
  598.   struct snmp_session *session,
  599.   int (*fpre_parse) (struct snmp_session *, struct soaddr),
  600.   int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
  601.   int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
  602.   int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
  603.   int (*fcheck) (u_char *, size_t )
  604. )
  605. {
  606.     struct session_list *slp;
  607.     slp = (struct session_list *)snmp_sess_open(session);
  608.     if (!slp) return NULL;
  609.     slp->internal->hook_pre = fpre_parse;
  610.     slp->internal->hook_parse = fparse;
  611.     slp->internal->hook_post = fpost_parse;
  612.     slp->internal->hook_build = fbuild;
  613.     slp->internal->check_packet = fcheck;
  614.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  615.     slp->next = Sessions;
  616.     Sessions = slp;
  617.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  618.     return (slp->session);
  619. }
  620. static struct session_list *
  621. _sess_copy( struct snmp_session *in_session)
  622. {
  623.     struct session_list *slp;
  624.     struct snmp_internal_session *isp;
  625.     struct snmp_session *session;
  626.     char *cp;
  627.     u_char *ucp;
  628.     size_t i;
  629.     in_session->s_snmp_errno = 0;
  630.     in_session->s_errno = 0;
  631.     /* Copy session structure and link into list */
  632.     slp = (struct session_list *)calloc(1,sizeof(struct session_list));
  633.     if (slp == NULL) { 
  634.       in_session->s_snmp_errno = SNMPERR_MALLOC;
  635.       return(NULL);
  636.     }
  637.     isp = (struct snmp_internal_session *)calloc(1,sizeof(struct snmp_internal_session));
  638.     if (isp == NULL) { 
  639.       snmp_sess_close(slp);
  640.       in_session->s_snmp_errno = SNMPERR_MALLOC;
  641.       return(NULL);
  642.     }
  643.     slp->internal = isp;
  644.     slp->internal->sd = -1; /* mark it not set */
  645.     slp->session = (struct snmp_session *)malloc(sizeof(struct snmp_session));
  646.     if (slp->session == NULL) {
  647.       snmp_sess_close(slp);
  648.       in_session->s_snmp_errno = SNMPERR_MALLOC;
  649.       return(NULL);
  650.     }
  651. memset (slp->session, 0, sizeof (struct snmp_session));
  652.     memmove(slp->session, in_session, sizeof(struct snmp_session));
  653.     session = slp->session;
  654.     /* zero out pointers so if we have to free the session we wont free mem
  655.        owned by in_session */
  656.     session->peername = NULL;
  657.     session->community = NULL;
  658.     session->contextEngineID = NULL;
  659.     session->contextName = NULL;
  660.     session->securityEngineID = NULL;
  661.     session->securityName = NULL;
  662.     session->securityAuthProto = NULL;
  663.     session->securityPrivProto = NULL;
  664.     /*
  665.      * session now points to the new structure that still contains pointers to
  666.      * data allocated elsewhere.  Some of this data is copied to space malloc'd
  667.      * here, and the pointer replaced with the new one.
  668.      */
  669.     if (in_session->peername != NULL){
  670. session->peername = (char *)malloc(strlen(in_session->peername) + 1);
  671. if (session->peername == NULL) {
  672.           snmp_sess_close(slp);
  673.   in_session->s_snmp_errno = SNMPERR_MALLOC;
  674.           return(NULL);
  675.         }
  676. strcpy(session->peername, in_session->peername);
  677.     }
  678.     /* Fill in defaults if necessary */
  679.     if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN)
  680. {
  681. ucp = (u_char *)malloc(1+in_session->community_len);
  682. if (ucp != NULL)
  683. {
  684. memmove(ucp, in_session->community, in_session->community_len);
  685. ucp[in_session->community_len] = '';
  686. }
  687. session->community_len = in_session->community_len;
  688.     } else {
  689. if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_COMMUNITY)) != NULL) 
  690. {
  691. session->community_len = strlen(cp);
  692. ucp = (u_char *)malloc(1+session->community_len);
  693. if (ucp)
  694. {
  695. memmove(ucp, cp, session->community_len);
  696. ucp[session->community_len] = '';
  697. }
  698. }
  699. else 
  700. {
  701. #ifdef NO_ZEROLENGTH_COMMUNITY
  702. session->community_len = strlen(DEFAULT_COMMUNITY);
  703. ucp = (u_char *)malloc(1+session->community_len);
  704. if (ucp)
  705. {
  706. memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
  707. ucp[session->community_len] = '';
  708. }
  709. #else
  710. ucp = (u_char *)strdup("");
  711. #endif
  712. }
  713.     }
  714.     if (ucp == NULL) {
  715.       snmp_sess_close(slp);
  716.       in_session->s_snmp_errno = SNMPERR_MALLOC;
  717.       return(NULL);
  718.     }
  719.     session->community = ucp; /* replace pointer with pointer to new data */
  720.     if (session->securityLevel <= 0)
  721.       session->securityLevel = ds_get_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL);
  722.     if (session->securityLevel == 0)
  723.       session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  724.     if (in_session->securityAuthProtoLen > 0) 
  725. {
  726. session->securityAuthProto = 
  727.   (oid*)malloc(in_session->securityAuthProtoLen * sizeof(oid));
  728. if (session->securityAuthProto == NULL) 
  729. {
  730. snmp_sess_close(slp);
  731. in_session->s_snmp_errno = SNMPERR_MALLOC;
  732. return(NULL);
  733. }
  734. memmove(session->securityAuthProto, in_session->securityAuthProto,
  735. in_session->securityAuthProtoLen * sizeof(oid));
  736.     } 
  737. else if (get_default_authtype(&i) != NULL) 
  738. {
  739.         session->securityAuthProto =
  740.           snmp_duplicate_objid(get_default_authtype(NULL), i);
  741. if (session->securityAuthProto == NULL)
  742. {
  743.       snmp_sess_close(slp);
  744.   in_session->s_snmp_errno = SNMPERR_MALLOC;
  745.   return(NULL);
  746. }
  747.         session->securityAuthProtoLen = i;
  748.     }
  749.     if (in_session->securityPrivProtoLen > 0) 
  750. {
  751. session->securityPrivProto = 
  752. (oid*)malloc((unsigned)in_session->securityPrivProtoLen * sizeof(oid));
  753. if (session->securityPrivProto == NULL) 
  754. {
  755. snmp_sess_close(slp);
  756. in_session->s_snmp_errno = SNMPERR_MALLOC;
  757. return(NULL);
  758. }
  759. memmove(session->securityPrivProto, in_session->securityPrivProto,
  760. in_session->securityPrivProtoLen * sizeof(oid));
  761.     } 
  762. else if (get_default_privtype(&i) != NULL) 
  763. {
  764.         session->securityPrivProto =
  765.           snmp_duplicate_objid(get_default_privtype(NULL), i);
  766. if (session->securityPrivProto == NULL)
  767. {
  768.       snmp_sess_close(slp);
  769.   in_session->s_snmp_errno = SNMPERR_MALLOC;
  770.   return(NULL);
  771. }
  772.         session->securityPrivProtoLen = i;
  773.     }
  774.     if (in_session->securityEngineIDLen > 0) {
  775.       ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
  776.    sizeof(u_char));
  777.       if (ucp == NULL) {
  778. snmp_sess_close(slp);
  779. in_session->s_snmp_errno = SNMPERR_MALLOC;
  780. return(NULL);
  781.       }
  782.       memmove(ucp, in_session->securityEngineID,
  783.       in_session->securityEngineIDLen * sizeof(u_char));
  784.       session->securityEngineID = ucp;
  785.     }
  786.     if (in_session->contextEngineIDLen > 0) {
  787.       ucp = (u_char*)malloc((unsigned)in_session->contextEngineIDLen *
  788.    sizeof(u_char));
  789.       if (ucp == NULL) {
  790. snmp_sess_close(slp);
  791. in_session->s_snmp_errno = SNMPERR_MALLOC;
  792. return(NULL);
  793.       }
  794.       memmove(ucp, in_session->contextEngineID,
  795.       in_session->contextEngineIDLen * sizeof(u_char));
  796.       session->contextEngineID = ucp;
  797.     } else if (in_session->securityEngineIDLen > 0) {
  798.       /* default contextEngineID to securityEngineIDLen if defined */
  799.       ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
  800.    sizeof(u_char));
  801.       if (ucp == NULL) {
  802. snmp_sess_close(slp);
  803. in_session->s_snmp_errno = SNMPERR_MALLOC;
  804. return(NULL);
  805.       }
  806.       memmove(ucp, in_session->securityEngineID,
  807.       in_session->securityEngineIDLen * sizeof(u_char));
  808.       session->contextEngineID = ucp;
  809.       session->contextEngineIDLen = in_session->securityEngineIDLen;
  810.     }
  811.     if (in_session->contextName) {
  812.       session->contextName = strdup(in_session->contextName);
  813.       if (session->contextName == NULL) {
  814. snmp_sess_close(slp);
  815. return(NULL);
  816.       }
  817.     } else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_CONTEXT)) != NULL) {
  818.       cp = strdup(cp);
  819.       if (cp == NULL) {
  820. snmp_sess_close(slp);
  821. return(NULL);
  822.       }
  823.       session->contextName = cp;
  824.       session->contextNameLen = strlen(cp);
  825.     } else {
  826.       cp = strdup(SNMP_DEFAULT_CONTEXT);
  827.       session->contextName = cp;
  828.       session->contextNameLen = strlen(cp);
  829.     }
  830.     if (in_session->securityName) {
  831.       session->securityName = strdup(in_session->securityName);
  832.       if (session->securityName == NULL) {
  833. snmp_sess_close(slp);
  834. return(NULL);
  835.       }
  836.     } else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_SECNAME)) != NULL) {
  837.       cp = strdup(cp);
  838.       if (cp == NULL) {
  839. snmp_sess_close(slp);
  840. return(NULL);
  841.       }
  842.       session->securityName = cp;
  843.       session->securityNameLen = strlen(cp);
  844.     }
  845.     if ((in_session->securityAuthKeyLen <= 0) &&
  846. (cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_AUTHPASSPHRASE))) {
  847.       session->securityAuthKeyLen = USM_AUTH_KU_LEN;
  848.       if (generate_Ku(session->securityAuthProto,
  849.                       session->securityAuthProtoLen,
  850.                       (u_char*)cp, strlen(cp),
  851.                       session->securityAuthKey,
  852.                       &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
  853.         snmp_set_detail("Error generating Ku from authentication pass phrase.");
  854. snmp_sess_close(slp);
  855.         return NULL;
  856.       }
  857.     }
  858.     if ((in_session->securityPrivKeyLen <= 0) && 
  859.        (cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_PRIVPASSPHRASE))) {
  860.       session->securityPrivKeyLen = USM_PRIV_KU_LEN;
  861.       if (generate_Ku(session->securityAuthProto,
  862.                       session->securityAuthProtoLen,
  863.                       (u_char *)cp, strlen(cp),
  864.                       session->securityPrivKey,
  865.                       &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
  866.         snmp_set_detail("Error generating Ku from privacy pass phrase.");
  867. snmp_sess_close(slp);
  868.         return NULL;
  869.       }
  870.     }
  871.     if (session->retries == SNMP_DEFAULT_RETRIES)
  872. session->retries = DEFAULT_RETRIES;
  873.     if (session->timeout == SNMP_DEFAULT_TIMEOUT)
  874. session->timeout = DEFAULT_TIMEOUT;
  875.     session->sessid = snmp_get_next_sessid();
  876.     return( slp );
  877. }
  878. struct session_list *
  879. snmp_sess_copy( struct snmp_session *pss)
  880. {
  881.     struct session_list * psl;
  882.     psl = _sess_copy(pss);
  883.     if ( !psl) {
  884.         if ( !pss->s_snmp_errno)
  885.         pss->s_snmp_errno = SNMPERR_GENERR;
  886.     SET_SNMP_ERROR(pss->s_snmp_errno);
  887.     }
  888.     return psl;
  889. }
  890. /*******************************************************************-o-******
  891.  * snmp_sess_open
  892.  *
  893.  * Parameters:
  894.  * *in_session
  895.  *
  896.  * Returns:
  897.  *      Pointer to a session in the session list   -OR- FIX -- right?
  898.  * NULL on failure.
  899.  *
  900.  * The "spin-free" version of snmp_open.
  901.  */
  902. static void *
  903. _sess_open(struct snmp_session *in_session)
  904. {
  905.     struct session_list *slp;
  906.     struct snmp_internal_session *isp;
  907.     struct snmp_session *session;
  908.     int sd;
  909.     in_addr_t addr;
  910.     struct soaddr_in *isp_addr = NULL, *meIp;
  911. #ifdef HAVE_GETHOSTBYNAME
  912.     struct hostent *hp;
  913. #endif
  914.     struct snmp_pdu *pdu, *response;
  915.     int status;
  916.     size_t i, addr_size;
  917.     char *cp = NULL;
  918.     in_session->s_snmp_errno = 0;
  919.     in_session->s_errno = 0;
  920.     if (Reqid == 0)
  921.       _init_snmp();
  922.     if ((slp = snmp_sess_copy( in_session )) == NULL )
  923.         return( NULL );
  924.     isp     = slp->internal;
  925.     session = slp->session;
  926.     if ( isp->addr.sa_family == AF_UNSPEC ) {
  927.         if ( session->peername && session->peername[0] == '/' ) {
  928. #ifdef AF_UNIX
  929.             isp->addr.sa_family = AF_UNIX;
  930.             strcpy( isp->addr.sa_data, session->peername);
  931. #else /* AF_UNIX */
  932.             snmp_log(LOG_ERR,"%s:%d: _sess_open invalid session name %s- unix sockets not supported  n",
  933.                     __FILE__,__LINE__,
  934.                     session->peername);
  935.             return(NULL);
  936. #endif /* AF_UNIX */
  937.             
  938.         } else {
  939.             isp->addr.sa_family = AF_INET;
  940.             isp_addr = (struct soaddr_in *)&(isp->addr);
  941.             if (session->peername != SNMP_DEFAULT_PEERNAME){
  942. /* Try and extract an appended port number */
  943. cp = strchr( session->peername, ':' );
  944. if ( cp ) {
  945.     *cp = '';
  946.     cp++;
  947.     session->remote_port = (u_short)atoi( cp );
  948.     if ( session->local_port ) /* i.e. server */
  949. session->local_port = session->remote_port;
  950. }
  951. /* Interpret the peername as an IP port ... */
  952. cp = strchr( session->peername, '.' );
  953. if ( !cp && (( i = atoi( session->peername )) != 0 )) {
  954.     session->remote_port = (u_short)i;
  955.     if ( session->local_port ) /* i.e. server */
  956. session->local_port = session->remote_port;
  957. }
  958. /* ... failing that, as an IP address ... */
  959.                 else if ((int)(addr = inet_addr(session->peername)) != -1){
  960.                     memmove(&isp_addr->sin_addr, &addr, sizeof(isp_addr->sin_addr));
  961.                 } else {
  962. /* .... failing that, as a hostname */
  963. #ifdef HAVE_GETHOSTBYNAME
  964.                     hp = gethostbyname(session->peername);
  965.                     if (hp == NULL){
  966.                         in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
  967.                         in_session->s_errno = errno;
  968.                         snmp_set_detail(session->peername);
  969.                         snmp_sess_close(slp);
  970.                         return 0;
  971.                     } else {
  972.                         memmove(&isp_addr->sin_addr, hp->h_addr, hp->h_length);
  973.                     }
  974. #else /* HAVE_GETHOSTBYNAME */
  975.                     snmp_log(LOG_ERR,"%s:%d: _sess_open do not have get host by name - cannot resolve %s n",
  976.                             __FILE__,__LINE__,
  977.                             session->peername);
  978.                     return(0);
  979. #endif /* HAVE_GETHOSTBYNAME */
  980.                 }
  981.                 if (session->remote_port == (u_short)SNMP_DEFAULT_REMPORT){
  982.                     short iport = (short)ds_get_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
  983.                     isp_addr->sin_port = htons(iport);
  984.                 } else {
  985.                     isp_addr->sin_port = htons(session->remote_port);
  986.                 }
  987.             } else {
  988.                 isp_addr->sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
  989.             }
  990.         }
  991.     }
  992. isp_addr->sin_len = sizeof(struct soaddr_in);
  993.     if ( session->local_port ) {
  994. /*
  995.  *  If the session structure includes a non-null value for
  996.  *    local_port, then this session is intended as a server.
  997.  *    This means that the isp->addr structure will not be 
  998.  *    needed to contact a remote entity.
  999.  *
  1000.  *  By using this address as the local address to bind to,
  1001.  *    we can provide a facility for listening on selected
  1002.  *    (rather than all) interfaces.
  1003.  */
  1004. memcpy( &isp->me, &isp->addr, sizeof(isp->me));
  1005. if ( isp->addr.sa_family == AF_INET ) {
  1006. /*
  1007.  * Remember to use the specified local port,
  1008.  *   rather than the (default?) remote one.
  1009.  * If no local interface address is specified,
  1010.  *   default to listening on all interfaces,
  1011.  *   rather than the default connection host
  1012.  *   (SNMP_DEFAULT_ADDRESS)
  1013.  */
  1014.     meIp = (struct soaddr_in*)&(isp->me);
  1015.     meIp->sin_port = htons(session->local_port);
  1016.             if (session->peername == SNMP_DEFAULT_PEERNAME)
  1017.                 meIp->sin_addr.s_addr = htonl(snmp_source_ip);/*INADDR_ANY;*/
  1018. }
  1019.     }
  1020.     else {
  1021.         memset(&isp->me, '', sizeof(isp->me));
  1022.         isp->me.sa_family = isp->addr.sa_family;
  1023.         if ( isp->me.sa_family == AF_INET ) {
  1024.     meIp = (struct soaddr_in*)&(isp->me);
  1025.             meIp->sin_addr.s_addr =  htonl(snmp_source_ip);/*INADDR_ANY;*/
  1026.             meIp->sin_port = htons(session->local_port);
  1027.         }
  1028. #ifdef AF_UNIX
  1029.         else if ( isp->me.sa_family == AF_UNIX ) {
  1030.      /* Need a unique socket name */
  1031. #ifndef UNIX_SOCKET_BASE_NAME
  1032. #define UNIX_SOCKET_BASE_NAME  "/tmp/s."
  1033. #endif
  1034. #ifdef UCD_SNMP    
  1035. #ifndef WIN32
  1036.                 strcpy( isp->me.sa_data, UNIX_SOCKET_BASE_NAME );
  1037.                 strcat( isp->me.sa_data, "XXXXXX" );
  1038.                 mktemp( isp->me.sa_data );
  1039. #endif
  1040. #endif
  1041.         }
  1042. #endif /* AF_UNIX */
  1043.     }
  1044.     addr_size = snmp_socket_length(isp->me.sa_family);
  1045.     /* Set up connections */
  1046.     sd = so_socket(isp->me.sa_family, SOCK_DGRAM, 0);
  1047.          /*fanghao(A):2005-06-17*/
  1048.         if( sd > 0 ){
  1049. int value=1;
  1050.              so_setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value));
  1051.              so_setsockopt(sd,SOL_SOCKET,SO_REUSEPORT,&value,sizeof(value));
  1052.         }
  1053.     if (sd < 0){
  1054. in_session->s_snmp_errno = SNMPERR_NO_SOCKET;
  1055. in_session->s_errno = errno;
  1056. snmp_set_detail(strerror(errno));
  1057. snmp_sess_close(slp);
  1058. return 0;
  1059.     }
  1060.     isp->sd = sd;
  1061. #ifdef SO_BSDCOMPAT
  1062.     /* Patch for Linux.  Without this, UDP packets that fail get an ICMP
  1063.      * response.  Linux turns the failed ICMP response into an error message
  1064.      * and return value, unlike all other OS's.
  1065.      */
  1066.     {
  1067. int one=1;
  1068. so_setsockopt(sd, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
  1069.     }
  1070. #endif /* SO_BSDCOMPAT */
  1071. #ifndef SERVER_REQUIRES_CLIENT_SOCKET
  1072.     if (!(( session->flags & SNMP_FLAGS_STREAM_SOCKET ) &&
  1073. #ifdef AF_UNIX
  1074.         ( isp->me.sa_family == AF_UNIX ) &&
  1075. #endif /* AF_UNIX */
  1076.         ( session->local_port == 0 ))) {
  1077. /* Client Unix-domain stream sockets don't need to 'bind' */
  1078. #endif
  1079.   
  1080.     if (so_bind(sd, (struct soaddr *)&isp->me, (int)addr_size) != 0){
  1081. in_session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
  1082. in_session->s_errno = errno;
  1083. snmp_set_detail(strerror(errno));
  1084. snmp_sess_close(slp);
  1085. return 0;
  1086.         }
  1087. #ifndef SERVER_REQUIRES_CLIENT_SOCKET
  1088.     }
  1089. #endif
  1090.     /* if we are opening a V3 session and we don't know engineID
  1091.        we must probe it - this must be done after the session is
  1092.        created and inserted in the list so that the response can
  1093.        handled correctly */
  1094.     if (session->version == SNMP_VERSION_3) {
  1095.       if (session->securityEngineIDLen == 0 &&
  1096.           (session->securityEngineIDLen & SNMP_FLAGS_DONT_PROBE) !=
  1097.           SNMP_FLAGS_DONT_PROBE) {
  1098. if (snmpv3_build_probe_pdu(&pdu) == -1)
  1099. {
  1100. in_session->s_snmp_errno = SNMPERR_MALLOC;
  1101. in_session->s_errno = errno;
  1102. snmp_set_detail(strerror(errno));
  1103. snmp_sess_close(slp);
  1104. return 0;
  1105. }
  1106. DEBUGMSGTL(("snmp_api","probing for engineID...n"));
  1107. status = snmp_sess_synch_response(slp, pdu, &response);
  1108. if ((response == NULL) && (status == STAT_SUCCESS)) status = STAT_ERROR;
  1109. switch (status) {
  1110. case STAT_SUCCESS:
  1111.   in_session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
  1112.   DEBUGMSGTL(("snmp_sess_open",
  1113.                       "error: expected Report as response to probe: %s (%d)n",
  1114.                       snmp_errstring(response->errstat), response->errstat));
  1115.   break;
  1116. case STAT_ERROR: /* this is what we expected -> Report == STAT_ERROR */
  1117.   in_session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
  1118.   break; 
  1119. case STAT_TIMEOUT:
  1120.   in_session->s_snmp_errno = SNMPERR_TIMEOUT;
  1121. default:
  1122.   DEBUGMSGTL(("snmp_sess_open",
  1123.                       "unable to connect with remote engine: %s (%d)n",
  1124.                       snmp_api_errstring(session->s_snmp_errno),
  1125.                       session->s_snmp_errno));
  1126.   break;
  1127. }
  1128. if (slp->session->securityEngineIDLen == 0) {
  1129.   DEBUGMSGTL(("snmp_api","unable to determine remote engine IDn"));
  1130.   snmp_sess_close(slp);
  1131.   return NULL;
  1132. }
  1133. in_session->s_snmp_errno = SNMPERR_SUCCESS;
  1134. if (snmp_get_do_debugging()) {
  1135.           DEBUGMSGTL(("snmp_sess_open", "  probe found engineID:  "));
  1136.   for(i = 0; i < slp->session->securityEngineIDLen; i++)
  1137.     DEBUGMSG(("snmp_sess_open", "%02x",
  1138.                       slp->session->securityEngineID[i]));
  1139.   DEBUGMSG(("snmp_sess_open","n"));
  1140. }
  1141.       }
  1142.       /* if boot/time supplied set it for this engineID */
  1143.       if (session->engineBoots || session->engineTime) {
  1144. set_enginetime(session->securityEngineID, session->securityEngineIDLen,
  1145.        session->engineBoots, session->engineTime, TRUE);
  1146.       }
  1147.       if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
  1148.   in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME; /* XX?? */
  1149. DEBUGMSGTL(("snmp_api","snmp_sess_open(): failed(2) to create a new user from sessionn"));
  1150.   snmp_sess_close(slp);
  1151.   return NULL;
  1152.       }
  1153.     }
  1154.     return (void *)slp;
  1155. }  /* end snmp_sess_open() */
  1156. void *
  1157. snmp_sess_open(struct snmp_session *pss)
  1158. {
  1159.     void * pvoid;
  1160.     pvoid = _sess_open(pss);
  1161.     if ( !pvoid) {
  1162.         SET_SNMP_ERROR(pss->s_snmp_errno);
  1163.     }
  1164.     return pvoid;
  1165. }
  1166. /* create_user_from_session(struct snmp_session *session):
  1167.    creates a user in the usm table from the information in a session
  1168.    Parameters:
  1169.         session -- IN: pointer to the session to use when creating the user.
  1170.    Returns:
  1171.         SNMPERR_SUCCESS
  1172.         SNMPERR_GENERR
  1173. */
  1174. int
  1175. create_user_from_session(struct snmp_session *session)
  1176. {
  1177.   struct usmUser *user;
  1178.   /* now that we have the engineID, create an entry in the USM list
  1179.      for this user using the information in the session */
  1180.   user = usm_get_user_from_list(session->securityEngineID,
  1181.                                 session->securityEngineIDLen,
  1182.                                 session->securityName,
  1183.                                 usm_get_userList(), 0);
  1184.   if (user == NULL) {
  1185.     DEBUGMSGTL(("snmp_api","Building user %s...n",session->securityName));
  1186.     /* user doesn't exist so we create and add it */
  1187.     user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
  1188.     if (user == NULL)
  1189.       return SNMPERR_GENERR;
  1190.     /* copy in the securityName */
  1191.     if (session->securityName) {
  1192.       user->name = strdup(session->securityName);
  1193.       user->secName = strdup(session->securityName);
  1194.       if (user->name == NULL || user->secName == NULL) {
  1195.         usm_free_user(user);
  1196.         return SNMPERR_GENERR;
  1197.       }
  1198.     }
  1199.     /* copy in the engineID */
  1200.     if (snmp_memdup(&user->engineID, session->securityEngineID,
  1201.                session->securityEngineIDLen) != SNMPERR_SUCCESS) {
  1202.       usm_free_user(user);
  1203.       return SNMPERR_GENERR;
  1204.     }
  1205.     user->engineIDLen = session->securityEngineIDLen;
  1206.     /* copy the auth protocol */
  1207.     if (session->securityAuthProto != NULL) {
  1208.       user->authProtocol =
  1209.         snmp_duplicate_objid(session->securityAuthProto,
  1210.                              session->securityAuthProtoLen);
  1211.       if (user->authProtocol == NULL) {
  1212.         usm_free_user(user);
  1213.         return SNMPERR_GENERR;
  1214.       }
  1215.       user->authProtocolLen = session->securityAuthProtoLen;
  1216.     }
  1217.     /* copy the priv protocol */
  1218.     if (session->securityPrivProto != NULL) {
  1219.       user->privProtocol =
  1220.         snmp_duplicate_objid(session->securityPrivProto,
  1221.                              session->securityPrivProtoLen);
  1222.       if (user->privProtocol == NULL) {
  1223.         usm_free_user(user);
  1224.         return SNMPERR_GENERR;
  1225.       }
  1226.       user->privProtocolLen = session->securityPrivProtoLen;
  1227.     }
  1228.     /* copy in the authentication Key, and convert to the localized version */
  1229.     if (session->securityAuthKey != NULL && session->securityAuthKeyLen != 0) {
  1230.       user->authKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
  1231.   if (user->authKey == NULL)
  1232.   {
  1233.   usm_free_user (user);
  1234.   return SNMPERR_GENERR;
  1235.   }
  1236.       user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
  1237.       if (generate_kul( user->authProtocol, user->authProtocolLen,
  1238.                         session->securityEngineID, session->securityEngineIDLen,
  1239.                         session->securityAuthKey, session->securityAuthKeyLen,
  1240.                         user->authKey, &user->authKeyLen ) != SNMPERR_SUCCESS) {
  1241.         usm_free_user(user);
  1242.         return SNMPERR_GENERR;
  1243.       }
  1244.     }
  1245.     /* copy in the privacy Key, and convert to the localized version */
  1246.     if (session->securityPrivKey != NULL && session->securityPrivKeyLen != 0) {
  1247.       user->privKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
  1248.   if (user->privKey == NULL)
  1249.   {
  1250.   usm_free_user (user);
  1251.   return SNMPERR_GENERR;
  1252.   }
  1253.       user->privKeyLen = USM_LENGTH_KU_HASHBLOCK;
  1254.       if (generate_kul( user->authProtocol, user->authProtocolLen,
  1255.                         session->securityEngineID, session->securityEngineIDLen,
  1256.                         session->securityPrivKey, session->securityPrivKeyLen,
  1257.                         user->privKey, &user->privKeyLen ) != SNMPERR_SUCCESS) {
  1258.         usm_free_user(user);
  1259.         return SNMPERR_GENERR;
  1260.       }
  1261.     }
  1262.     /* add the user into the database */
  1263.     usm_add_user(user);
  1264.   }
  1265.   return  SNMPERR_SUCCESS;
  1266. }  /* end create_user_from_session() */
  1267. /*
  1268.  * Close the input session.  Frees all data allocated for the session,
  1269.  * dequeues any pending requests, and closes any sockets allocated for
  1270.  * the session.  Returns 0 on error, 1 otherwise.
  1271.  */
  1272. int
  1273. snmp_sess_close(void *sessp)
  1274. {
  1275.     struct session_list *slp = (struct session_list *)sessp;
  1276.     struct snmp_internal_session *isp;
  1277.     struct snmp_session *sesp;
  1278.     if (slp == NULL)
  1279. return 0;
  1280.     isp = slp->internal; slp->internal = 0;
  1281.     if (isp) {
  1282. struct request_list *rp, *orp;
  1283.         SNMP_FREE(isp->packet);
  1284. if (isp->sd != -1)
  1285. {
  1286.     so_close(isp->sd);
  1287. #ifdef UCD_SNMP
  1288. #ifdef AF_UNIX
  1289.             if ( isp->me.sa_family == AF_UNIX )
  1290.                 unlink( isp->me.sa_data );
  1291. #endif /* AF_UNIX */
  1292. #endif
  1293. }
  1294. /* Free each element in the input request list.  */
  1295. rp = isp->requests;
  1296. while(rp){
  1297.     orp = rp;
  1298.     rp = rp->next_request;
  1299. snmp_free_pdu(orp->pdu);
  1300.     free(orp);
  1301. }
  1302.      free(isp);
  1303.     }
  1304.     sesp = slp->session; slp->session = 0;
  1305.     if (sesp) {
  1306.         SNMP_FREE(sesp->peername);
  1307.         SNMP_FREE(sesp->community);
  1308.         SNMP_FREE(sesp->contextEngineID);
  1309.         SNMP_FREE(sesp->contextName);
  1310.         SNMP_FREE(sesp->securityEngineID);
  1311.         SNMP_FREE(sesp->securityName);
  1312.         SNMP_FREE(sesp->securityAuthProto);
  1313.         SNMP_FREE(sesp->securityPrivProto);
  1314.         free(sesp);
  1315.     }
  1316.     free(slp);
  1317.     return 1;
  1318. }
  1319. int 
  1320. snmp_close(struct snmp_session *session)
  1321. {
  1322.     struct session_list *slp = NULL, *oslp = NULL;
  1323.     { /*MTCRITICAL_RESOURCE*/
  1324. snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1325.     if (Sessions && Sessions->session == session){ /* If first entry */
  1326. slp = Sessions;
  1327. Sessions = slp->next;
  1328.     } else {
  1329. for(slp = Sessions; slp; slp = slp->next){
  1330.     if (slp->session == session){
  1331. if (oslp)   /* if we found entry that points here */
  1332.     oslp->next = slp->next; /* link around this entry */
  1333. break;
  1334.     }
  1335.     oslp = slp;
  1336. }
  1337.     }
  1338. snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1339.     } /*END MTCRITICAL_RESOURCE*/
  1340.     if (slp == NULL){
  1341. return 0;
  1342.     }
  1343.     return snmp_sess_close((void *)slp);
  1344. }
  1345. int
  1346. snmp_close_sessions( void )
  1347. {
  1348.     struct session_list *slp;
  1349.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1350.     while ( Sessions ) {
  1351.         slp = Sessions;
  1352.         Sessions = Sessions->next;
  1353.         snmp_sess_close((void *)slp);
  1354.     }
  1355.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1356.     return 1;
  1357. }
  1358. static int
  1359. snmpv3_build_probe_pdu (struct snmp_pdu **pdu)
  1360. {
  1361.   struct usmUser *user;
  1362.   /* create the pdu */
  1363.   if (!pdu) return -1;
  1364.   *pdu = snmp_pdu_create(SNMP_MSG_GET);
  1365.   if (*pdu == NULL)
  1366.   return -1;
  1367.   (*pdu)->version = SNMP_VERSION_3;
  1368.   (*pdu)->securityName = strdup("");
  1369.   (*pdu)->securityNameLen = strlen((*pdu)->securityName);
  1370.   (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  1371.   (*pdu)->securityModel = SNMP_SEC_MODEL_USM;
  1372.   /* create the empty user */
  1373.   user = usm_get_user(NULL, 0, (*pdu)->securityName);
  1374.   if (user == NULL) {
  1375.     user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
  1376. if (user == NULL)
  1377. {
  1378. snmp_free_pdu (*pdu);
  1379. *pdu = NULL;
  1380. return -1;
  1381. }
  1382.     user->name = strdup((*pdu)->securityName);
  1383.     user->secName = strdup((*pdu)->securityName);
  1384.     user->authProtocolLen = sizeof(usmNoAuthProtocol)/sizeof(oid);
  1385.     user->authProtocol =
  1386.       snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
  1387.     user->privProtocolLen = sizeof(usmNoPrivProtocol)/sizeof(oid);
  1388.     user->privProtocol =
  1389.       snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
  1390. if (user->name == NULL || user->secName == NULL || user->authProtocol == NULL
  1391. || user->privProtocol == NULL)
  1392. {
  1393. snmp_free_pdu (*pdu);
  1394. *pdu = NULL;
  1395. usm_free_user(user);
  1396. return -1;
  1397. }
  1398.     usm_add_user(user);
  1399.   }
  1400.   return 0;
  1401. }
  1402. static void
  1403. snmpv3_calc_msg_flags (int sec_level, int msg_command, u_char *flags)
  1404. {
  1405.   *flags = 0;
  1406.   if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
  1407.     *flags = SNMP_MSG_FLAG_AUTH_BIT;
  1408.   else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
  1409.     *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
  1410.   if (SNMP_CMD_CONFIRMED(msg_command)) *flags |= SNMP_MSG_FLAG_RPRT_BIT;
  1411.   return;
  1412. }
  1413. static int
  1414. snmpv3_verify_msg(struct request_list *rp, struct snmp_pdu *pdu)
  1415. {
  1416.   struct snmp_pdu     *rpdu;
  1417.   
  1418.   if (!rp || !rp->pdu || !pdu) return 0;
  1419.   /* Reports don't have to match anything according to the spec */
  1420.   if (pdu->command == SNMP_MSG_REPORT) return 1;
  1421.   rpdu = rp->pdu;
  1422.   if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid) return 0;
  1423.   if (rpdu->version != pdu->version) return 0;
  1424.   if (rpdu->securityModel != pdu->securityModel) return 0;
  1425.   if (rpdu->securityLevel != pdu->securityLevel) return 0;
  1426.   if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen || 
  1427.       memcmp(rpdu->contextEngineID, pdu->contextEngineID, 
  1428.      pdu->contextEngineIDLen))
  1429.     return 0;
  1430.   if (rpdu->contextNameLen != pdu->contextNameLen || 
  1431.       memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen)) 
  1432.     return 0;
  1433.   if (rpdu->securityEngineIDLen != pdu->securityEngineIDLen || 
  1434.       memcmp(rpdu->securityEngineID, pdu->securityEngineID, 
  1435.      pdu->securityEngineIDLen))
  1436.     return 0;
  1437.   if (rpdu->securityNameLen != pdu->securityNameLen || 
  1438.       memcmp(rpdu->securityName, pdu->securityName, pdu->securityNameLen)) 
  1439.     return 0;
  1440.   return 1;
  1441. }
  1442. /* SNMPv3
  1443.  * Takes a session and a pdu and serializes the ASN PDU into the area
  1444.  * pointed to by packet.  out_length is the size of the data area available.
  1445.  * Returns the length of the completed packet in out_length.  If any errors
  1446.  * occur, -1 is returned.  If all goes well, 0 is returned.
  1447.  */
  1448. static int
  1449. snmpv3_build(struct snmp_session *session,
  1450.              struct snmp_pdu         *pdu,
  1451.              u_char          *packet,
  1452.              size_t *out_length)
  1453. {
  1454.   int ret;
  1455.     session->s_snmp_errno = 0;
  1456.     session->s_errno = 0;
  1457. /* do validation for PDU types */
  1458.   switch (pdu->command) {
  1459. case SNMP_MSG_RESPONSE:
  1460. case SNMP_MSG_TRAP2:
  1461. case SNMP_MSG_REPORT:
  1462.     pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  1463.     /* Fallthrough */
  1464. case SNMP_MSG_GET:
  1465. case SNMP_MSG_GETNEXT:
  1466. case SNMP_MSG_SET:
  1467. case SNMP_MSG_INFORM:
  1468.     if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  1469.         pdu->errstat = 0;
  1470.     if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  1471.         pdu->errindex = 0;
  1472.     break;
  1473. case SNMP_MSG_GETBULK:
  1474.     if (pdu->max_repetitions < 0) {
  1475.         session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
  1476.         return -1;
  1477.     }
  1478.     if (pdu->non_repeaters < 0) {
  1479.         session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
  1480.         return -1;
  1481.     }
  1482.     break;
  1483. case SNMP_MSG_TRAP:
  1484.     session->s_snmp_errno = SNMPERR_V1_IN_V2;
  1485.     return -1;
  1486. default:
  1487.     session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
  1488.     return -1;
  1489.   }
  1490.       if (pdu->securityEngineIDLen == 0) {
  1491. if (session->securityEngineIDLen) {
  1492.   snmpv3_clone_engineID(&pdu->securityEngineID, 
  1493. &pdu->securityEngineIDLen,
  1494. session->securityEngineID,
  1495. session->securityEngineIDLen);
  1496. }
  1497.       }
  1498.       if (pdu->contextEngineIDLen == 0) {
  1499. if (session->contextEngineIDLen) {
  1500.   snmpv3_clone_engineID(&pdu->contextEngineID, 
  1501. &pdu->contextEngineIDLen,
  1502. session->contextEngineID,
  1503. session->contextEngineIDLen);
  1504. } else if (pdu->securityEngineIDLen) {
  1505.   snmpv3_clone_engineID(&pdu->contextEngineID, 
  1506. &pdu->contextEngineIDLen,
  1507. pdu->securityEngineID,
  1508. pdu->securityEngineIDLen);
  1509. }
  1510.       }
  1511.       if (pdu->contextName == NULL) {
  1512. if (!session->contextName){
  1513.   session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
  1514.   return -1;
  1515. }
  1516. pdu->contextName = strdup(session->contextName);
  1517. if (pdu->contextName == NULL) {
  1518.   session->s_snmp_errno = SNMPERR_GENERR;
  1519.   return -1;
  1520. }
  1521. pdu->contextNameLen = session->contextNameLen;
  1522.       }
  1523.       pdu->securityModel = SNMP_SEC_MODEL_USM;
  1524.       if (pdu->securityNameLen == 0 && pdu->securityName == 0) {
  1525. if (session->securityNameLen == 0){
  1526.   session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
  1527.   return -1;
  1528. }
  1529. pdu->securityName = strdup(session->securityName);
  1530. if (pdu->securityName == NULL) {
  1531.   session->s_snmp_errno = SNMPERR_GENERR;
  1532.   return -1;
  1533. }
  1534. pdu->securityNameLen = session->securityNameLen;
  1535.       }
  1536.       if (pdu->securityLevel == 0) {
  1537. if (session->securityLevel == 0) {
  1538.     session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
  1539.     return -1;
  1540. }
  1541. pdu->securityLevel = session->securityLevel;
  1542.       }
  1543.       DEBUGMSGTL(("snmp_build",
  1544.                   "Building SNMPv3 message (secName:"%s", secLevel:%s)...n",
  1545.                   ((session->securityName) ? (char *)session->securityName :
  1546.                    ((pdu->securityName) ? (char *)pdu->securityName : 
  1547.                     "ERROR: undefined")),
  1548.                   usmSecLevelName[pdu->securityLevel]));
  1549.   ret = snmpv3_packet_build(pdu, packet, out_length, NULL, 0);
  1550.   if (-1 != ret) {
  1551.       session->s_snmp_errno = ret;
  1552.   }
  1553.   return ret;
  1554. }  /* end snmpv3_build() */
  1555. static u_char *
  1556. snmpv3_header_build(struct snmp_pdu *pdu, u_char *packet,
  1557.                     size_t *out_length, size_t length, u_char **msg_hdr_e)
  1558. {
  1559.     u_char *global_hdr, *global_hdr_e;
  1560.     u_char  *cp;
  1561.     u_char  msg_flags;
  1562.     long  max_size;
  1563.     long  sec_model;
  1564.     u_char *pb, *pb0e;
  1565.     /* Save current location and build SEQUENCE tag and length placeholder
  1566.      * for SNMP message sequence (actual length inserted later)
  1567.      */
  1568.     cp = asn_build_sequence(packet, out_length,
  1569.     (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), length);
  1570.     if (cp == NULL) return NULL;
  1571.     if (msg_hdr_e != NULL)
  1572.       *msg_hdr_e = cp;
  1573.     pb0e = cp;
  1574.     /* store the version field - msgVersion
  1575.      */
  1576.     cp = asn_build_int(cp, out_length,
  1577.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1578.        (long *) &pdu->version, sizeof(pdu->version));
  1579.     if (cp == NULL) return NULL;
  1580.     global_hdr = cp;
  1581.     /* msgGlobalData HeaderData */
  1582.     cp = asn_build_sequence(cp, out_length,
  1583.     (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
  1584.     if (cp == NULL) return NULL;
  1585.     global_hdr_e = cp;
  1586.     /* msgID */
  1587.     cp = asn_build_int(cp, out_length,
  1588.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1589.        &pdu->msgid, sizeof(pdu->msgid));
  1590.     if (cp == NULL) return NULL;
  1591.      /* msgMaxSize */
  1592.     max_size = SNMP_MAX_MSG_SIZE;
  1593.     cp = asn_build_int(cp, out_length,
  1594.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1595.        &max_size, sizeof(max_size));
  1596.     if (cp == NULL) return NULL;
  1597.     /* msgFlags */
  1598.     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
  1599.     cp = asn_build_string(cp, out_length,
  1600.   (u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
  1601.   &msg_flags, sizeof(msg_flags));
  1602.     if (cp == NULL) return NULL;
  1603.      /* msgSecurityModel */
  1604.     sec_model = SNMP_SEC_MODEL_USM;
  1605.     cp = asn_build_int(cp, out_length,
  1606.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1607.        &sec_model, sizeof(sec_model));
  1608.     if (cp == NULL) return NULL;
  1609.     /* insert actual length of globalData
  1610.      */
  1611.     pb = asn_build_sequence(global_hdr, out_length,
  1612.                             (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1613.                             cp - global_hdr_e);
  1614.     if (pb == NULL) return NULL;
  1615.     /* insert the actual length of the entire packet
  1616.      */
  1617.     pb = asn_build_sequence(packet, out_length,
  1618.     (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1619.                             length + (cp - pb0e));
  1620.     if (pb == NULL) return NULL;
  1621.     return cp;
  1622. }  /* end snmpv3_header_build() */
  1623. static u_char *
  1624. snmpv3_scopedPDU_header_build(struct snmp_pdu *pdu,
  1625.                               u_char *packet, size_t *out_length,
  1626.                               u_char **spdu_e)
  1627. {
  1628.   size_t  init_length;
  1629.   u_char *scopedPdu, *pb;
  1630.   init_length = *out_length;
  1631.   pb = scopedPdu = packet;
  1632.   pb = asn_build_sequence(pb, out_length,
  1633.                           (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
  1634.   if (pb == NULL) return NULL;
  1635.   if (spdu_e)
  1636.     *spdu_e = pb;
  1637.   pb = asn_build_string(pb, out_length,
  1638.                         (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
  1639.                         pdu->contextEngineID, pdu->contextEngineIDLen);
  1640.   if (pb == NULL) return NULL;
  1641.   pb = asn_build_string(pb, out_length,
  1642.                         (ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
  1643.                         (u_char *)pdu->contextName, pdu->contextNameLen);
  1644.   if (pb == NULL) return NULL;
  1645.   return pb;
  1646. }  /* end snmpv3_scopedPDU_header_build() */
  1647. /* returns 0 if success, -1 if fail, not 0 if USM build failure */
  1648. int
  1649. snmpv3_packet_build(struct snmp_pdu *pdu, u_char *packet, size_t *out_length,
  1650.     u_char *pdu_data, size_t pdu_data_len)
  1651. {
  1652.     u_char *global_data, *sec_params, *spdu_hdr_e;
  1653.     size_t  global_data_len,  sec_params_len;
  1654.     u_char  spdu_buf[SNMP_MAX_MSG_SIZE];
  1655.     size_t  spdu_buf_len, spdu_len;
  1656.     u_char *cp;
  1657.     int      result;
  1658.     global_data = packet;
  1659.     /* 
  1660.      * build the headers for the packet, returned addr = start of secParams
  1661.      */
  1662.     sec_params = snmpv3_header_build(pdu, global_data, out_length, 0, NULL);
  1663.     if (sec_params == NULL) return -1;
  1664.     global_data_len = sec_params - global_data;
  1665.     sec_params_len = *out_length; /* length left in packet buf for sec_params */
  1666.     /* 
  1667.      * build a scopedPDU structure into spdu_buf
  1668.      */
  1669.     spdu_buf_len = SNMP_MAX_MSG_SIZE;
  1670.     cp = snmpv3_scopedPDU_header_build(pdu,spdu_buf,&spdu_buf_len,&spdu_hdr_e);
  1671.     if (cp == NULL) return -1;
  1672.     /* build the PDU structure onto the end of spdu_buf 
  1673.      */
  1674.     if (pdu_data) {
  1675.       memcpy(cp, pdu_data, pdu_data_len);
  1676.       cp += pdu_data_len;
  1677.     } else {
  1678.       cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
  1679.       if (cp == NULL) return -1;
  1680.     }
  1681.     /* 
  1682.      * re-encode the actual ASN.1 length of the scopedPdu
  1683.      */
  1684.     spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
  1685.     spdu_buf_len = SNMP_MAX_MSG_SIZE;
  1686.     if (asn_build_sequence(spdu_buf, &spdu_buf_len,
  1687.                            (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1688.                            spdu_len) == NULL)
  1689.       return -1;
  1690.     spdu_len = cp - spdu_buf; /* the length of the entire scopedPdu */
  1691.     /* 
  1692.      * call the security module to possibly encrypt and authenticate the
  1693.      * message - the entire message to transmitted on the wire is returned
  1694.      */
  1695.     cp = NULL; *out_length = SNMP_MAX_MSG_SIZE;
  1696.     result =
  1697.       usm_generate_out_msg(
  1698. SNMP_VERSION_3,
  1699. global_data, global_data_len,
  1700.                         SNMP_MAX_MSG_SIZE,
  1701. SNMP_SEC_MODEL_USM,
  1702.                         pdu->securityEngineID, pdu->securityEngineIDLen,
  1703.                         pdu->securityName, pdu->securityNameLen,
  1704.                         pdu->securityLevel,
  1705. spdu_buf, spdu_len, 
  1706. pdu->securityStateRef,
  1707. sec_params, &sec_params_len,
  1708.                         &cp, out_length);
  1709.     return result;
  1710. }  /* end snmpv3_packet_build() */
  1711. /*
  1712.  * Takes a session and a pdu and serializes the ASN PDU into the area
  1713.  * pointed to by packet.  out_length is the size of the data area available.
  1714.  * Returns the length of the completed packet in out_length.  If any errors
  1715.  * occur, -1 is returned.  If all goes well, 0 is returned.
  1716.  */
  1717. static int
  1718. _snmp_build(struct snmp_session *session,
  1719.    struct snmp_pdu *pdu,
  1720.    u_char *packet,
  1721.    size_t *out_length)
  1722. {
  1723.     u_char *h0, *h0e = 0, *h1;
  1724.     u_char  *cp;
  1725.     size_t length;
  1726.     long version;
  1727.     session->s_snmp_errno = 0;
  1728.     session->s_errno = 0;
  1729.     if (pdu->version == SNMP_VERSION_3)
  1730.       return snmpv3_build(session, pdu, packet, out_length);
  1731.     switch (pdu->command) {
  1732. case SNMP_MSG_RESPONSE:
  1733.     pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  1734. /* Fallthrough */
  1735. case SNMP_MSG_GET:
  1736. case SNMP_MSG_GETNEXT:
  1737. case SNMP_MSG_SET:
  1738.             /* all versions support these PDU types */
  1739.             /* initialize defaulted PDU fields */
  1740.     if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  1741.         pdu->errstat = 0;
  1742.     if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  1743.         pdu->errindex = 0;
  1744.     break;
  1745. case SNMP_MSG_TRAP2:
  1746.     pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  1747. /* Fallthrough */
  1748. case SNMP_MSG_INFORM:
  1749.             /* not supported in SNMPv1 and SNMPsec */
  1750.     if (pdu->version == SNMP_VERSION_1) {
  1751.             session->s_snmp_errno = SNMPERR_V2_IN_V1;
  1752.             return -1;
  1753.     }
  1754.     if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  1755.         pdu->errstat = 0;
  1756.     if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  1757.         pdu->errindex = 0;
  1758.     break;
  1759. case SNMP_MSG_GETBULK:
  1760.             /* not supported in SNMPv1 and SNMPsec */
  1761.     if (pdu->version == SNMP_VERSION_1) {
  1762.             session->s_snmp_errno = SNMPERR_V2_IN_V1;
  1763.             return -1;
  1764.             }
  1765.     if (pdu->max_repetitions < 0) {
  1766.         session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
  1767.         return -1;
  1768.     }
  1769.     if (pdu->non_repeaters < 0) {
  1770.         session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
  1771.         return -1;
  1772.     }
  1773.     break;
  1774. case SNMP_MSG_TRAP:
  1775.             /* *only* supported in SNMPv1 and SNMPsec */
  1776.     if (pdu->version != SNMP_VERSION_1) {
  1777.             session->s_snmp_errno = SNMPERR_V1_IN_V2;
  1778.             return -1;
  1779.             }
  1780.             /* initialize defaulted Trap PDU fields */
  1781.     pdu->reqid = 1; /* give a bogus non-error reqid for traps */
  1782.     if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH){
  1783.         pdu->enterprise = (oid *)malloc(sizeof(DEFAULT_ENTERPRISE));
  1784. if (pdu->enterprise == NULL)
  1785. {
  1786. session->s_snmp_errno = SNMPERR_MALLOC;
  1787. return -1;
  1788. }
  1789.         memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
  1790.     sizeof(DEFAULT_ENTERPRISE));
  1791.         pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
  1792.     }
  1793.     if (pdu->time == SNMP_DEFAULT_TIME)
  1794.         pdu->time = DEFAULT_TIME;
  1795.             /* don't expect a response */
  1796.     pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  1797.     break;
  1798. case SNMP_MSG_REPORT: /* SNMPv3 only */
  1799. default:
  1800.             session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
  1801.             return -1;
  1802.     }
  1803.     /* save length */
  1804.     length = *out_length;
  1805.     /* setup administrative fields based on version */
  1806.     /* build the message wrapper and all the administrative fields
  1807.        upto the PDU sequence
  1808.        (note that actual length of message will be inserted later) */
  1809.     h0 = packet;
  1810.     switch (pdu->version) {
  1811.     case SNMP_VERSION_1:
  1812.     case SNMP_VERSION_2c:
  1813. #ifdef NO_ZEROLENGTH_COMMUNITY
  1814. if (pdu->community_len == 0){
  1815.     if (session->community_len == 0){
  1816. session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
  1817. return -1;
  1818.     }
  1819.     pdu->community = (u_char *)malloc(1+session->community_len);
  1820. if (pdu->community == NULL)
  1821. {
  1822. session->s_snmp_errno = SNMPERR_MALLOC;
  1823. return -1;
  1824. }
  1825.     memmove(pdu->community, session->community,
  1826.                         session->community_len);
  1827. pdu->community[session->community_len] = '';
  1828.     pdu->community_len = session->community_len;
  1829. }
  1830. #else /* !NO_ZEROLENGTH_COMMUNITY */
  1831. if ((pdu->community_len == 0 ||
  1832.        pdu->command != SNMP_MSG_RESPONSE ) &&
  1833.            !pdu->available_community) {
  1834. /* copy session community exactly to pdu community */
  1835.     if (0 == session->community_len) {
  1836. SNMP_FREE(pdu->community); pdu->community = 0;
  1837.     }
  1838.     else if (pdu->community_len == session->community_len) {
  1839. memmove(pdu->community, session->community,
  1840.     session->community_len);
  1841.     }
  1842.     else {
  1843.     SNMP_FREE(pdu->community);
  1844.     pdu->community = (u_char *)malloc(1+session->community_len);
  1845. if (pdu->community == NULL)
  1846. {
  1847. session->s_snmp_errno = SNMPERR_MALLOC;
  1848. return -1;
  1849. }
  1850.     memmove(pdu->community, session->community,
  1851.                         session->community_len);
  1852. pdu->community[session->community_len] = '';
  1853.     }
  1854.     pdu->community_len = session->community_len;
  1855. }
  1856. #endif /* !NO_ZEROLENGTH_COMMUNITY */
  1857.         DEBUGMSGTL(("snmp_send","Building SNMPv%d message...n", (1 + pdu->version)));
  1858.         /* Save current location and build SEQUENCE tag and length
  1859.            placeholder for SNMP message sequence
  1860.           (actual length will be inserted later) */
  1861.         cp = asn_build_sequence(packet, out_length,
  1862.                                 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1863.                                 0);
  1864.         if (cp == NULL)
  1865.             return -1;
  1866.         h0e = cp;
  1867.         /* store the version field */
  1868.         version = pdu->version;
  1869.         cp = asn_build_int(cp, out_length,
  1870.                     (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1871.                     (long *) &version, sizeof(version));
  1872.         if (cp == NULL)
  1873.             return -1;
  1874.         /* store the community string */
  1875.         cp = asn_build_string(cp, out_length,
  1876.                     (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  1877.                     pdu->community, pdu->community_len);
  1878.         if (cp == NULL)
  1879.             return -1;
  1880.         break;
  1881.     case SNMP_VERSION_2p:
  1882.     case SNMP_VERSION_sec:
  1883.     case SNMP_VERSION_2u:
  1884.     case SNMP_VERSION_2star:
  1885.     default:
  1886.         session->s_snmp_errno = SNMPERR_BAD_VERSION;
  1887. return -1;
  1888.     }
  1889.     h1 = cp;
  1890.     cp = snmp_pdu_build(pdu, cp, out_length);
  1891.     if (cp == NULL)
  1892. return -1;
  1893.     /* insert the actual length of the message sequence */
  1894.     switch (pdu->version) {
  1895.     case SNMP_VERSION_1:
  1896.     case SNMP_VERSION_2c:
  1897.         asn_build_sequence(packet, &length,
  1898.        (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1899.                        cp - h0e);
  1900.         break;
  1901.     case SNMP_VERSION_2p:
  1902.     case SNMP_VERSION_sec:
  1903.     case SNMP_VERSION_2u:
  1904.     case SNMP_VERSION_2star:
  1905.     default:
  1906. session->s_snmp_errno = SNMPERR_BAD_VERSION;
  1907. return -1;
  1908.     }
  1909.     *out_length = cp - packet;
  1910.     return 0;
  1911. }
  1912. int
  1913. snmp_build(struct snmp_session *pss,
  1914.    struct snmp_pdu *pdu,
  1915.    u_char *packet,
  1916.    size_t *out_length)
  1917. {
  1918.     int rc;
  1919.     rc = _snmp_build(pss,pdu,packet,out_length);
  1920.     if (rc) {
  1921.         if ( !pss->s_snmp_errno)
  1922.             pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
  1923.         SET_SNMP_ERROR(pss->s_snmp_errno);
  1924.         rc = -1;
  1925.     }
  1926.     return rc;
  1927. }
  1928. /* on error, returns NULL (likely an encoding problem). */
  1929. u_char *
  1930. snmp_pdu_build (struct snmp_pdu *pdu, u_char *cp, size_t *out_length)
  1931. {
  1932.   u_char *h1, *h1e, *h2, *h2e;
  1933.   struct variable_list *vp;
  1934.   struct soaddr_in *pduIp = (struct soaddr_in *)&(pdu->agent_addr);
  1935.   size_t length;
  1936.   length = *out_length;
  1937.   /* Save current location and build PDU tag and length placeholder
  1938.      (actual length will be inserted later) */
  1939.   h1 = cp;
  1940.   cp = asn_build_sequence(cp, out_length, (u_char)pdu->command, 0);
  1941.   if (cp == NULL)
  1942.     return NULL;
  1943.   h1e = cp;
  1944.   /* store fields in the PDU preceeding the variable-bindings sequence */
  1945.   if (pdu->command != SNMP_MSG_TRAP){
  1946.     /* PDU is not an SNMPv1 trap */
  1947.     /* request id */
  1948.     cp = asn_build_int(cp, out_length,
  1949.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1950.        &pdu->reqid, sizeof(pdu->reqid));
  1951.     if (cp == NULL)
  1952.       return NULL;
  1953.     /* error status (getbulk non-repeaters) */
  1954.     cp = asn_build_int(cp, out_length,
  1955.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1956.        &pdu->errstat, sizeof(pdu->errstat));
  1957.     if (cp == NULL)
  1958.       return NULL;
  1959.     /* error index (getbulk max-repetitions) */
  1960.     cp = asn_build_int(cp, out_length,
  1961.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1962.        &pdu->errindex, sizeof(pdu->errindex));
  1963.     if (cp == NULL)
  1964.       return NULL;
  1965.   } else {
  1966.     /* an SNMPv1 trap PDU */
  1967.         /* enterprise */
  1968.     cp = asn_build_objid(cp, out_length,
  1969.  (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  1970.  (oid *)pdu->enterprise, pdu->enterprise_length);
  1971.     if (cp == NULL)
  1972.       return NULL;
  1973.         /* agent-addr */
  1974.     cp = asn_build_string(cp, out_length,
  1975.   (u_char)(ASN_IPADDRESS | ASN_PRIMITIVE),
  1976.   (u_char *)&pduIp->sin_addr.s_addr,
  1977.   sizeof(pduIp->sin_addr.s_addr));
  1978.     if (cp == NULL)
  1979.       return NULL;
  1980.         /* generic trap */
  1981.     cp = asn_build_int(cp, out_length,
  1982.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1983.        (long *)&pdu->trap_type, sizeof(pdu->trap_type));
  1984.     if (cp == NULL)
  1985.       return NULL;
  1986.         /* specific trap */
  1987.     cp = asn_build_int(cp, out_length,
  1988.        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1989.        (long *)&pdu->specific_type, sizeof(pdu->specific_type));
  1990.     if (cp == NULL)
  1991.       return NULL;
  1992.         /* timestamp  */
  1993.     cp = asn_build_unsigned_int(cp, out_length,
  1994. (u_char)(ASN_TIMETICKS | ASN_PRIMITIVE),
  1995. &pdu->time, sizeof(pdu->time));
  1996.     if (cp == NULL)
  1997.       return NULL;
  1998.   }
  1999.   /* Save current location and build SEQUENCE tag and length placeholder
  2000.        for variable-bindings sequence
  2001.        (actual length will be inserted later) */
  2002.   h2 = cp;
  2003.   cp = asn_build_sequence(cp, out_length,
  2004.                           (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  2005.                           0);
  2006.   if (cp == NULL)
  2007.     return NULL;
  2008.   h2e = cp;
  2009.   /* Store variable-bindings */
  2010.   for(vp = pdu->variables; vp; vp = vp->next_variable){
  2011.     cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
  2012.    vp->val_len, (u_char *)vp->val.string,
  2013.    out_length);
  2014.     if (cp == NULL)
  2015.       return NULL;
  2016.   }
  2017.   /* insert actual length of variable-bindings sequence */
  2018.   asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),cp-h2e);
  2019.   /* insert actual length of PDU sequence */
  2020.   asn_build_sequence(h1, &length, (u_char)pdu->command, cp - h1e);
  2021.   return cp;
  2022. }
  2023. /*
  2024.  * Parses the packet received to determine version, either directly
  2025.  * from packets version field or inferred from ASN.1 construct.
  2026.  */
  2027. static int
  2028. snmp_parse_version (u_char *data, size_t length)
  2029. {
  2030.   u_char type;
  2031.   long version = SNMPERR_BAD_VERSION;
  2032.   data = asn_parse_sequence(data, &length, &type,
  2033.                         (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
  2034.   if (data) {
  2035.     data = asn_parse_int(data, &length, &type, &version, sizeof(version));
  2036.     if (!data) return SNMPERR_BAD_VERSION;
  2037.   }
  2038.   return version;
  2039. }
  2040. int
  2041. snmpv3_parse(
  2042.      struct snmp_pdu  *pdu,
  2043.      u_char   *data,
  2044.      size_t   *length,
  2045.      u_char  **after_header)
  2046. {
  2047.   u_char  type, msg_flags;
  2048.   long  ver, msg_max_size, msg_sec_model;
  2049.   size_t  max_size_response;
  2050.   u_char  tmp_buf[SNMP_MAX_MSG_SIZE];
  2051.   size_t  tmp_buf_len;
  2052.   u_char  pdu_buf[SNMP_MAX_MSG_SIZE];
  2053.   size_t  pdu_buf_len = SNMP_MAX_MSG_SIZE;
  2054.   u_char *sec_params;
  2055.   u_char *msg_data;
  2056.   u_char *cp;
  2057.   size_t  asn_len, msg_len;
  2058.   int  ret, ret_val;
  2059.   msg_data =  data;
  2060.   msg_len  = *length;
  2061.   /* message is an ASN.1 SEQUENCE
  2062.    */
  2063.   DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Messagen");
  2064.   data = asn_parse_sequence(data, length, &type,
  2065.                         (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
  2066.   if (data == NULL){
  2067.     /* error msg detail is set */
  2068.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2069.     DEBUGINDENTLESS();
  2070.     return SNMPERR_ASN_PARSE_ERR;
  2071.   }
  2072.   /* parse msgVersion
  2073.    */
  2074.   DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Version Numbern");
  2075.   data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
  2076.   DEBUGINDENTLESS();
  2077.   if (data == NULL){
  2078.     ERROR_MSG("bad parse of version");
  2079.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2080.     DEBUGINDENTLESS();
  2081.     return SNMPERR_ASN_PARSE_ERR;
  2082.   }
  2083.   pdu->version = ver;
  2084.   /* parse msgGlobalData sequence
  2085.    */
  2086.   cp   = data;
  2087.   asn_len = *length;
  2088.   DEBUGDUMPHEADER("dump_recv", "Parsing msgGlobalDatan");
  2089.   data = asn_parse_sequence(data, &asn_len, &type,
  2090.                         (ASN_SEQUENCE | ASN_CONSTRUCTOR), "msgGlobalData");
  2091.   if (data == NULL){
  2092.     /* error msg detail is set */
  2093.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2094.     DEBUGINDENTADD(-4);
  2095.     return SNMPERR_ASN_PARSE_ERR;
  2096.   }
  2097.   *length -= data - cp;  /* subtract off the length of the header */
  2098.   /* msgID */
  2099.   DEBUGDUMPHEADER("dump_recv", "Parsing msgIDn");
  2100.   data = asn_parse_int(data, length, &type, &pdu->msgid, sizeof(pdu->msgid));
  2101.   DEBUGINDENTLESS();
  2102.   if (data == NULL) {
  2103.     ERROR_MSG("error parsing msgID");
  2104.     DEBUGINDENTADD(-4);
  2105.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2106.     return SNMPERR_ASN_PARSE_ERR;
  2107.   }
  2108.   /* msgMaxSize */
  2109.   DEBUGDUMPHEADER("dump_recv", "Parsing msgMaxSizen");
  2110.   data = asn_parse_int(data, length, &type, &msg_max_size,
  2111.        sizeof(msg_max_size));
  2112.   DEBUGINDENTLESS();
  2113.   if (data == NULL) {
  2114.     ERROR_MSG("error parsing msgMaxSize");
  2115.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2116.     DEBUGINDENTADD(-4);
  2117.     return SNMPERR_ASN_PARSE_ERR;
  2118.   }
  2119.   /* msgFlags */
  2120.   tmp_buf_len = SNMP_MAX_MSG_SIZE;
  2121.   DEBUGDUMPHEADER("dump_recv", "Parsing msgFlagsn");
  2122.   data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
  2123.   DEBUGINDENTLESS();
  2124.   if (data == NULL || tmp_buf_len != 1) {
  2125.     ERROR_MSG("error parsing msgFlags");
  2126.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2127.     DEBUGINDENTADD(-4);
  2128.     return SNMPERR_ASN_PARSE_ERR;
  2129.   }
  2130.   msg_flags = *tmp_buf;
  2131.   if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
  2132.     pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
  2133.   else
  2134.     pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
  2135.   /* msgSecurityModel */
  2136.   DEBUGDUMPHEADER("dump_recv", "Parsing msgSecurityModeln");
  2137.   data = asn_parse_int(data, length, &type, &msg_sec_model,
  2138.        sizeof(msg_sec_model));
  2139.   DEBUGINDENTADD(-4); /* return from global data indent */
  2140.   if (data == NULL) {
  2141.     ERROR_MSG("error parsing msgSecurityModel");
  2142.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2143.     DEBUGINDENTLESS();
  2144.     return SNMPERR_ASN_PARSE_ERR;
  2145.   }
  2146.   if (msg_sec_model != SNMP_SEC_MODEL_USM) {
  2147.     ERROR_MSG("unknown security model");
  2148.     snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
  2149.     DEBUGINDENTLESS();
  2150.     return SNMPERR_UNKNOWN_SEC_MODEL;
  2151.   }
  2152.   pdu->securityModel = msg_sec_model;
  2153.   if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT && 
  2154.       !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
  2155.     ERROR_MSG("invalid message, illegal msgFlags");
  2156.     snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
  2157.     DEBUGINDENTLESS();
  2158.     return SNMPERR_INVALID_MSG;
  2159.   }
  2160.   pdu->securityLevel = ( (msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
  2161. ?  ( (msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
  2162. ? SNMP_SEC_LEVEL_AUTHPRIV
  2163. : SNMP_SEC_LEVEL_AUTHNOPRIV )
  2164. : SNMP_SEC_LEVEL_NOAUTH );
  2165.   /* end of msgGlobalData */
  2166.   /* securtityParameters OCTET STRING begins after msgGlobalData */
  2167.   sec_params = data;
  2168.   pdu->contextEngineID = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
  2169.   pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
  2170.   pdu->securityEngineID         = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
  2171.   pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE;
  2172.   pdu->securityName = (char *)calloc(1,SNMP_MAX_SEC_NAME_SIZE);
  2173.   pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
  2174.   memset(pdu_buf, 0, pdu_buf_len);
  2175.   cp = pdu_buf;
  2176.   DEBUGDUMPHEADER("dump_recv", "Parsing USM msgSecurityParametersn");
  2177.   ret_val = usm_process_in_msg(SNMP_VERSION_3, msg_max_size,
  2178.        sec_params, msg_sec_model, pdu->securityLevel,
  2179.        msg_data, msg_len,
  2180.        pdu->securityEngineID, &pdu->securityEngineIDLen,
  2181.        pdu->securityName, &pdu->securityNameLen,
  2182.        &cp,
  2183.        &pdu_buf_len, &max_size_response,
  2184.        &pdu->securityStateRef);
  2185.   DEBUGINDENTLESS();
  2186.   if (ret_val != SNMPERR_SUCCESS) {
  2187.     snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len); /* DO ignore return code */
  2188.     DEBUGINDENTLESS();
  2189.     return ret_val;
  2190.   }
  2191.   
  2192.   /* parse plaintext ScopedPDU sequence */
  2193.   *length = pdu_buf_len;
  2194.   DEBUGDUMPHEADER("dump_recv", "Parsing ScopedPdun");
  2195.   data = snmpv3_scopedPDU_parse(pdu, cp, length);
  2196.   if (data == NULL) {
  2197.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  2198.     DEBUGINDENTADD(-4);
  2199.     return SNMPERR_ASN_PARSE_ERR;
  2200.   }
  2201.   /* parse the PDU.
  2202.    */
  2203.   if (after_header != NULL) {
  2204.     tmp_buf_len  = *length;
  2205.     *after_header  = data;
  2206.   }
  2207.   DEBUGDUMPHEADER("dump_recv", "Parsing PDUn");
  2208.   ret = snmp_pdu_parse(pdu, data, length);