net-snmp  5.4.1
snmp_api.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /******************************************************************
00006         Copyright 1989, 1991, 1992 by Carnegie Mellon University
00007 
00008                       All Rights Reserved
00009 
00010 Permission to use, copy, modify, and distribute this software and its
00011 documentation for any purpose and without fee is hereby granted,
00012 provided that the above copyright notice appear in all copies and that
00013 both that copyright notice and this permission notice appear in
00014 supporting documentation, and that the name of CMU not be
00015 used in advertising or publicity pertaining to distribution of the
00016 software without specific, written prior permission.
00017 
00018 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00019 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00020 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00021 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00022 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00023 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00024 SOFTWARE.
00025 ******************************************************************/
00026 /*
00027  * Portions of this file are copyrighted by:
00028  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
00029  * Use is subject to license terms specified in the COPYING file
00030  * distributed with the Net-SNMP package.
00031  */
00032 
00036 /*
00037  * snmp_api.c - API for access to snmp.
00038  */
00039 #include <net-snmp/net-snmp-config.h>
00040 
00041 #include <stdio.h>
00042 #include <ctype.h>
00043 #if HAVE_STDLIB_H
00044 #include <stdlib.h>
00045 #endif
00046 #if HAVE_STRING_H
00047 #include <string.h>
00048 #else
00049 #include <strings.h>
00050 #endif
00051 #if HAVE_UNISTD_H
00052 #include <unistd.h>
00053 #endif
00054 #include <sys/types.h>
00055 #if HAVE_SYS_PARAM_H
00056 #include <sys/param.h>
00057 #endif
00058 #if TIME_WITH_SYS_TIME
00059 # ifdef WIN32
00060 #  include <sys/timeb.h>
00061 # else
00062 #  include <sys/time.h>
00063 # endif
00064 # include <time.h>
00065 #else
00066 # if HAVE_SYS_TIME_H
00067 #  include <sys/time.h>
00068 # else
00069 #  include <time.h>
00070 # endif
00071 #endif
00072 #if HAVE_NETINET_IN_H
00073 #include <netinet/in.h>
00074 #endif
00075 #if HAVE_ARPA_INET_H
00076 #include <arpa/inet.h>
00077 #endif
00078 #if HAVE_SYS_SELECT_H
00079 #include <sys/select.h>
00080 #endif
00081 #if HAVE_IO_H
00082 #include <io.h>
00083 #endif
00084 #if HAVE_WINSOCK_H
00085 #include <winsock.h>
00086 #endif
00087 #if HAVE_SYS_SOCKET_H
00088 #include <sys/socket.h>
00089 #endif
00090 #if HAVE_SYS_UN_H
00091 #include <sys/un.h>
00092 #endif
00093 #if HAVE_NETDB_H
00094 #include <netdb.h>
00095 #endif
00096 #if HAVE_NET_IF_DL_H
00097 #ifndef dynix
00098 #include <net/if_dl.h>
00099 #else
00100 #include <sys/net/if_dl.h>
00101 #endif
00102 #endif
00103 #include <errno.h>
00104 
00105 #if HAVE_LOCALE_H
00106 #include <locale.h>
00107 #endif
00108 
00109 #if HAVE_DMALLOC_H
00110 #include <dmalloc.h>
00111 #endif
00112 
00113 #define SNMP_NEED_REQUEST_LIST
00114 #include <net-snmp/types.h>
00115 #include <net-snmp/output_api.h>
00116 #include <net-snmp/config_api.h>
00117 #include <net-snmp/utilities.h>
00118 
00119 #include <net-snmp/library/asn1.h>
00120 #include <net-snmp/library/snmp.h>      /* for xdump & {build,parse}_var_op */
00121 #include <net-snmp/library/snmp_api.h>
00122 #include <net-snmp/library/snmp_client.h>
00123 #include <net-snmp/library/parse.h>
00124 #include <net-snmp/library/mib.h>
00125 #include <net-snmp/library/int64.h>
00126 #include <net-snmp/library/snmpv3.h>
00127 #include <net-snmp/library/callback.h>
00128 #include <net-snmp/library/container.h>
00129 #include <net-snmp/library/snmp_secmod.h>
00130 #ifdef NETSNMP_SECMOD_USM
00131 #include <net-snmp/library/snmpusm.h>
00132 #endif
00133 #ifdef NETSNMP_SECMOD_KSM
00134 #include <net-snmp/library/snmpksm.h>
00135 #endif
00136 #include <net-snmp/library/keytools.h>
00137 #include <net-snmp/library/lcd_time.h>
00138 #include <net-snmp/library/snmp_alarm.h>
00139 #include <net-snmp/library/snmp_transport.h>
00140 #include <net-snmp/library/snmp_service.h>
00141 #include <net-snmp/library/vacm.h>
00142 
00143 static void     _init_snmp(void);
00144 
00145 #include "../agent/mibgroup/agentx/protocol.h"
00146 #include <net-snmp/library/transform_oids.h>
00147 #ifndef timercmp
00148 #define timercmp(tvp, uvp, cmp) \
00149         /* CSTYLED */ \
00150         ((tvp)->tv_sec cmp (uvp)->tv_sec || \
00151         ((tvp)->tv_sec == (uvp)->tv_sec && \
00152         /* CSTYLED */ \
00153         (tvp)->tv_usec cmp (uvp)->tv_usec))
00154 #endif
00155 #ifndef timerclear
00156 #define timerclear(tvp)         (tvp)->tv_sec = (tvp)->tv_usec = 0
00157 #endif
00158 
00159 /*
00160  * Globals.
00161  */
00162 #define MAX_PACKET_LENGTH       (0x7fffffff)
00163 #ifndef NETSNMP_STREAM_QUEUE_LEN
00164 #define NETSNMP_STREAM_QUEUE_LEN  5
00165 #endif
00166 
00167 #ifndef BSD4_3
00168 #define BSD4_2
00169 #endif
00170 
00171 #ifndef FD_SET
00172 
00173 typedef long    fd_mask;
00174 #define NFDBITS (sizeof(fd_mask) * NBBY)        /* bits per mask */
00175 
00176 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
00177 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
00178 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
00179 #define FD_ZERO(p)      memset((p), 0, sizeof(*(p)))
00180 #endif
00181 
00182 static oid      default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
00183 /*
00184  * enterprises.cmu.systems.cmuSNMP 
00185  */
00186 
00187 #define DEFAULT_COMMUNITY   "public"
00188 #define DEFAULT_RETRIES     5
00189 #define DEFAULT_TIMEOUT     1000000L
00190 #define DEFAULT_REMPORT     SNMP_PORT
00191 #define DEFAULT_ENTERPRISE  default_enterprise
00192 #define DEFAULT_TIME        0
00193 
00194 /*
00195  * don't set higher than 0x7fffffff, and I doubt it should be that high
00196  * * = 4 gig snmp messages max 
00197  */
00198 #define MAXIMUM_PACKET_SIZE 0x7fffffff
00199 
00200 /*
00201  * Internal information about the state of the snmp session.
00202  */
00203 struct snmp_internal_session {
00204     netsnmp_request_list *requests;     /* Info about outstanding requests */
00205     netsnmp_request_list *requestsEnd;  /* ptr to end of list */
00206     int             (*hook_pre) (netsnmp_session *, netsnmp_transport *,
00207                                  void *, int);
00208     int             (*hook_parse) (netsnmp_session *, netsnmp_pdu *,
00209                                    u_char *, size_t);
00210     int             (*hook_post) (netsnmp_session *, netsnmp_pdu *, int);
00211     int             (*hook_build) (netsnmp_session *, netsnmp_pdu *,
00212                                    u_char *, size_t *);
00213     int             (*hook_realloc_build) (netsnmp_session *,
00214                                            netsnmp_pdu *, u_char **,
00215                                            size_t *, size_t *);
00216     int             (*check_packet) (u_char *, size_t);
00217     netsnmp_pdu    *(*hook_create_pdu) (netsnmp_transport *,
00218                                         void *, size_t);
00219 
00220     u_char         *packet;
00221     size_t          packet_len, packet_size;
00222 };
00223 
00224 /*
00225  * The list of active/open sessions.
00226  */
00227 struct session_list {
00228     struct session_list *next;
00229     netsnmp_session *session;
00230     netsnmp_transport *transport;
00231     struct snmp_internal_session *internal;
00232 };
00233 
00234 
00235 
00236 static const char *api_errors[-SNMPERR_MAX + 1] = {
00237     "No error",                 /* SNMPERR_SUCCESS */
00238     "Generic error",            /* SNMPERR_GENERR */
00239     "Invalid local port",       /* SNMPERR_BAD_LOCPORT */
00240     "Unknown host",             /* SNMPERR_BAD_ADDRESS */
00241     "Unknown session",          /* SNMPERR_BAD_SESSION */
00242     "Too long",                 /* SNMPERR_TOO_LONG */
00243     "No socket",                /* SNMPERR_NO_SOCKET */
00244     "Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
00245     "Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
00246     "Bad value for non-repeaters",      /* SNMPERR_BAD_REPEATERS */
00247     "Bad value for max-repetitions",    /* SNMPERR_BAD_REPETITIONS */
00248     "Error building ASN.1 representation",      /* SNMPERR_BAD_ASN1_BUILD */
00249     "Failure in sendto",        /* SNMPERR_BAD_SENDTO */
00250     "Bad parse of ASN.1 type",  /* SNMPERR_BAD_PARSE */
00251     "Bad version specified",    /* SNMPERR_BAD_VERSION */
00252     "Bad source party specified",       /* SNMPERR_BAD_SRC_PARTY */
00253     "Bad destination party specified",  /* SNMPERR_BAD_DST_PARTY */
00254     "Bad context specified",    /* SNMPERR_BAD_CONTEXT */
00255     "Bad community specified",  /* SNMPERR_BAD_COMMUNITY */
00256     "Cannot send noAuth/Priv",       /* SNMPERR_NOAUTH_DESPRIV */
00257     "Bad ACL definition",       /* SNMPERR_BAD_ACL */
00258     "Bad Party definition",     /* SNMPERR_BAD_PARTY */
00259     "Session abort failure",    /* SNMPERR_ABORT */
00260     "Unknown PDU type",         /* SNMPERR_UNKNOWN_PDU */
00261     "Timeout",                  /* SNMPERR_TIMEOUT */
00262     "Failure in recvfrom",      /* SNMPERR_BAD_RECVFROM */
00263     "Unable to determine contextEngineID",      /* SNMPERR_BAD_ENG_ID */
00264     "No securityName specified",        /* SNMPERR_BAD_SEC_NAME */
00265     "Unable to determine securityLevel",        /* SNMPERR_BAD_SEC_LEVEL  */
00266     "ASN.1 parse error in message",     /* SNMPERR_ASN_PARSE_ERR */
00267     "Unknown security model in message",        /* SNMPERR_UNKNOWN_SEC_MODEL */
00268     "Invalid message (e.g. msgFlags)",  /* SNMPERR_INVALID_MSG */
00269     "Unknown engine ID",        /* SNMPERR_UNKNOWN_ENG_ID */
00270     "Unknown user name",        /* SNMPERR_UNKNOWN_USER_NAME */
00271     "Unsupported security level",       /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
00272     "Authentication failure (incorrect password, community or key)",    /* SNMPERR_AUTHENTICATION_FAILURE */
00273     "Not in time window",       /* SNMPERR_NOT_IN_TIME_WINDOW */
00274     "Decryption error",         /* SNMPERR_DECRYPTION_ERR */
00275     "SCAPI general failure",    /* SNMPERR_SC_GENERAL_FAILURE */
00276     "SCAPI sub-system not configured",  /* SNMPERR_SC_NOT_CONFIGURED */
00277     "Key tools not available",  /* SNMPERR_KT_NOT_AVAILABLE */
00278     "Unknown Report message",   /* SNMPERR_UNKNOWN_REPORT */
00279     "USM generic error",        /* SNMPERR_USM_GENERICERROR */
00280     "USM unknown security name (no such user exists)",  /* SNMPERR_USM_UNKNOWNSECURITYNAME */
00281     "USM unsupported security level (this user has not been configured for that level of security)",    /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
00282     "USM encryption error",     /* SNMPERR_USM_ENCRYPTIONERROR */
00283     "USM authentication failure (incorrect password or key)",   /* SNMPERR_USM_AUTHENTICATIONFAILURE */
00284     "USM parse error",          /* SNMPERR_USM_PARSEERROR */
00285     "USM unknown engineID",     /* SNMPERR_USM_UNKNOWNENGINEID */
00286     "USM not in time window",   /* SNMPERR_USM_NOTINTIMEWINDOW */
00287     "USM decryption error",     /* SNMPERR_USM_DECRYPTIONERROR */
00288     "MIB not initialized",      /* SNMPERR_NOMIB */
00289     "Value out of range",       /* SNMPERR_RANGE */
00290     "Sub-id out of range",      /* SNMPERR_MAX_SUBID */
00291     "Bad sub-id in object identifier",  /* SNMPERR_BAD_SUBID */
00292     "Object identifier too long",       /* SNMPERR_LONG_OID */
00293     "Bad value name",           /* SNMPERR_BAD_NAME */
00294     "Bad value notation",       /* SNMPERR_VALUE */
00295     "Unknown Object Identifier",        /* SNMPERR_UNKNOWN_OBJID */
00296     "No PDU in snmp_send",      /* SNMPERR_NULL_PDU */
00297     "Missing variables in PDU", /* SNMPERR_NO_VARS */
00298     "Bad variable type",        /* SNMPERR_VAR_TYPE */
00299     "Out of memory (malloc failure)",   /* SNMPERR_MALLOC */
00300     "Kerberos related error",   /* SNMPERR_KRB5 */
00301     "Protocol error",           /* SNMPERR_PROTOCOL */
00302     "OID not increasing",       /* SNMPERR_OID_NONINCREASING */
00303 };
00304 
00305 static const char *secLevelName[] = {
00306     "BAD_SEC_LEVEL",
00307     "noAuthNoPriv",
00308     "authNoPriv",
00309     "authPriv"
00310 };
00311 
00312 /*
00313  * Multiple threads may changes these variables.
00314  * Suggest using the Single API, which does not use Sessions.
00315  *
00316  * Reqid may need to be protected. Time will tell...
00317  *
00318  */
00319 /*
00320  * MTCRITICAL_RESOURCE
00321  */
00322 /*
00323  * use token in comments to individually protect these resources 
00324  */
00325 struct session_list *Sessions = NULL;   /* MT_LIB_SESSION */
00326 static long     Reqid = 0;      /* MT_LIB_REQUESTID */
00327 static long     Msgid = 0;      /* MT_LIB_MESSAGEID */
00328 static long     Sessid = 0;     /* MT_LIB_SESSIONID */
00329 static long     Transid = 0;    /* MT_LIB_TRANSID */
00330 int             snmp_errno = 0;
00331 /*
00332  * END MTCRITICAL_RESOURCE
00333  */
00334 
00335 /*
00336  * global error detail storage
00337  */
00338 static char     snmp_detail[192];
00339 static int      snmp_detail_f = 0;
00340 
00341 /*
00342  * Prototypes.
00343  */
00344 int             snmp_build(u_char ** pkt, size_t * pkt_len,
00345                            size_t * offset, netsnmp_session * pss,
00346                            netsnmp_pdu *pdu);
00347 static int      snmp_parse(void *, netsnmp_session *, netsnmp_pdu *,
00348                            u_char *, size_t);
00349 
00350 static void     snmpv3_calc_msg_flags(int, int, u_char *);
00351 static int      snmpv3_verify_msg(netsnmp_request_list *, netsnmp_pdu *);
00352 static int      snmpv3_build_probe_pdu(netsnmp_pdu **);
00353 static int      snmpv3_build(u_char ** pkt, size_t * pkt_len,
00354                              size_t * offset, netsnmp_session * session,
00355                              netsnmp_pdu *pdu);
00356 static int      snmp_parse_version(u_char *, size_t);
00357 static int      snmp_resend_request(struct session_list *slp,
00358                                     netsnmp_request_list *rp,
00359                                     int incr_retries);
00360 static void     register_default_handlers(void);
00361 static struct session_list *snmp_sess_copy(netsnmp_session * pss);
00362 int             snmp_get_errno(void);
00363 void            snmp_synch_reset(netsnmp_session * notused);
00364 void            snmp_synch_setup(netsnmp_session * notused);
00365 
00366 #ifndef HAVE_STRERROR
00367 const char     *
00368 strerror(int err)
00369 {
00370     extern const char *sys_errlist[];
00371     extern int      sys_nerr;
00372 
00373     if (err < 0 || err >= sys_nerr)
00374         return "Unknown error";
00375     return sys_errlist[err];
00376 }
00377 #endif
00378 
00379 const char *
00380 snmp_pdu_type(int type)
00381 {
00382     static char unknown[20];
00383     switch(type) {
00384     case SNMP_MSG_GET:
00385         return "GET";
00386     case SNMP_MSG_GETNEXT:
00387         return "GETNEXT";
00388     case SNMP_MSG_RESPONSE:
00389         return "RESPONSE";
00390     case SNMP_MSG_SET:
00391         return "SET";
00392     case SNMP_MSG_GETBULK:
00393         return "GETBULK";
00394     case SNMP_MSG_INFORM:
00395         return "INFORM";
00396     case SNMP_MSG_TRAP2:
00397         return "TRAP2";
00398     case SNMP_MSG_REPORT:
00399         return "REPORT";
00400     default:
00401         snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
00402         return unknown;
00403     }
00404 }
00405 
00406 #define DEBUGPRINTPDUTYPE(token, type) \
00407     DEBUGDUMPSECTION(token, snmp_pdu_type(type))
00408 
00409 long
00410 snmp_get_next_reqid(void)
00411 {
00412     long            retVal;
00413     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
00414     retVal = 1 + Reqid;         /*MTCRITICAL_RESOURCE */
00415     if (!retVal)
00416         retVal = 2;
00417     Reqid = retVal;
00418     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
00419     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
00420         return (retVal & 0x7fff);       /* mask to 15 bits */
00421     else
00422         return (retVal & 0x7fffffff);  /* mask to 31 bits */
00423 }
00424 
00425 long
00426 snmp_get_next_msgid(void)
00427 {
00428     long            retVal;
00429     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
00430     retVal = 1 + Msgid;         /*MTCRITICAL_RESOURCE */
00431     if (!retVal)
00432         retVal = 2;
00433     Msgid = retVal;
00434     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
00435     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
00436         return (retVal & 0x7fff);       /* mask to 15 bits */
00437     else
00438         return (retVal & 0x7fffffff);  /* mask to 31 bits */
00439 }
00440 
00441 long
00442 snmp_get_next_sessid(void)
00443 {
00444     long            retVal;
00445     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
00446     retVal = 1 + Sessid;        /*MTCRITICAL_RESOURCE */
00447     if (!retVal)
00448         retVal = 2;
00449     Sessid = retVal;
00450     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
00451     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
00452         return (retVal & 0x7fff);       /* mask to 15 bits */
00453     else
00454         return (retVal & 0x7fffffff);  /* mask to 31 bits */
00455 }
00456 
00457 long
00458 snmp_get_next_transid(void)
00459 {
00460     long            retVal;
00461     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
00462     retVal = 1 + Transid;       /*MTCRITICAL_RESOURCE */
00463     if (!retVal)
00464         retVal = 2;
00465     Transid = retVal;
00466     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
00467     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
00468         return (retVal & 0x7fff);       /* mask to 15 bits */
00469     else
00470         return (retVal & 0x7fffffff);  /* mask to 31 bits */
00471 }
00472 
00473 void
00474 snmp_perror(const char *prog_string)
00475 {
00476     const char     *str;
00477     int             xerr;
00478     xerr = snmp_errno;          /*MTCRITICAL_RESOURCE */
00479     str = snmp_api_errstring(xerr);
00480     snmp_log(LOG_ERR, "%s: %s\n", prog_string, str);
00481 }
00482 
00483 void
00484 snmp_set_detail(const char *detail_string)
00485 {
00486     if (detail_string != NULL) {
00487         strncpy((char *) snmp_detail, detail_string, sizeof(snmp_detail));
00488         snmp_detail[sizeof(snmp_detail) - 1] = '\0';
00489         snmp_detail_f = 1;
00490     }
00491 }
00492 
00493 /*
00494  * returns pointer to static data 
00495  */
00496 /*
00497  * results not guaranteed in multi-threaded use 
00498  */
00499 const char     *
00500 snmp_api_errstring(int snmp_errnumber)
00501 {
00502     const char     *msg = "";
00503     static char     msg_buf[SPRINT_MAX_LEN];
00504     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
00505         msg = api_errors[-snmp_errnumber];
00506     } else if (snmp_errnumber != SNMPERR_SUCCESS) {
00507         msg = NULL;
00508     }
00509     if (!msg)
00510         snprintf(msg_buf, sizeof(msg_buf), "Unknown error: %d", snmp_errnumber);
00511     else if (snmp_detail_f) {
00512         snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
00513         snmp_detail_f = 0;
00514     } else {
00515         strncpy(msg_buf, msg, sizeof(msg_buf));
00516     }
00517     msg_buf[sizeof(msg_buf)-1] = '\0';
00518 
00519     return (msg_buf);
00520 }
00521 
00522 /*
00523  * snmp_error - return error data
00524  * Inputs :  address of errno, address of snmp_errno, address of string
00525  * Caller must free the string returned after use.
00526  */
00527 void
00528 snmp_error(netsnmp_session * psess,
00529            int *p_errno, int *p_snmp_errno, char **p_str)
00530 {
00531     char            buf[SPRINT_MAX_LEN];
00532     int             snmp_errnumber;
00533 
00534     if (p_errno)
00535         *p_errno = psess->s_errno;
00536     if (p_snmp_errno)
00537         *p_snmp_errno = psess->s_snmp_errno;
00538     if (p_str == NULL)
00539         return;
00540 
00541     strcpy(buf, "");
00542     snmp_errnumber = psess->s_snmp_errno;
00543     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
00544         if (snmp_detail_f) {
00545             snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
00546                     snmp_detail);
00547             snmp_detail_f = 0;
00548         }
00549         else
00550             strncpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
00551     } else {
00552         if (snmp_errnumber)
00553             snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
00554     }
00555     buf[sizeof(buf)-1] = '\0';
00556 
00557     /*
00558      * append a useful system errno interpretation. 
00559      */
00560     if (psess->s_errno) {
00561         const char* error = strerror(psess->s_errno);
00562         if(error == NULL)
00563             error = "Unknown Error";
00564         snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
00565                  " (%s)", error);
00566     }
00567     buf[sizeof(buf)-1] = '\0';
00568     *p_str = strdup(buf);
00569 }
00570 
00571 /*
00572  * snmp_sess_error - same as snmp_error for single session API use.
00573  */
00574 void
00575 snmp_sess_error(void *sessp, int *p_errno, int *p_snmp_errno, char **p_str)
00576 {
00577     struct session_list *slp = (struct session_list *) sessp;
00578 
00579     if ((slp) && (slp->session))
00580         snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
00581 }
00582 
00583 /*
00584  * snmp_sess_perror(): print a error stored in a session pointer 
00585  */
00586 void
00587 netsnmp_sess_log_error(int priority,
00588                        const char *prog_string, netsnmp_session * ss)
00589 {
00590     char           *err;
00591     snmp_error(ss, NULL, NULL, &err);
00592     snmp_log(priority, "%s: %s\n", prog_string, err);
00593     SNMP_FREE(err);
00594 }
00595 
00596 /*
00597  * snmp_sess_perror(): print a error stored in a session pointer 
00598  */
00599 void
00600 snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
00601 {
00602     netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
00603 }
00604 
00605 
00606 
00607 /*
00608  * Primordial SNMP library initialization.
00609  * Initializes mutex locks.
00610  * Invokes minimum required initialization for displaying MIB objects.
00611  * Gets initial request ID for all transactions,
00612  * and finds which port SNMP over UDP uses.
00613  * SNMP over AppleTalk is not currently supported.
00614  *
00615  * Warning: no debug messages here.
00616  */
00617 static void
00618 _init_snmp(void)
00619 {
00620     static char     have_done_init = 0;
00621 
00622     struct timeval  tv;
00623     long            tmpReqid, tmpMsgid;
00624 
00625     if (have_done_init)
00626         return;
00627     have_done_init = 1;
00628     Reqid = 1;
00629 
00630     snmp_res_init();            /* initialize the mt locking structures */
00631 #ifndef NETSNMP_DISABLE_MIB_LOADING
00632     netsnmp_init_mib_internals();
00633 #endif /* NETSNMP_DISABLE_MIB_LOADING */
00634     netsnmp_tdomain_init();
00635 
00636     gettimeofday(&tv, (struct timezone *) 0);
00637     /*
00638      * Now = tv;
00639      */
00640 
00641     /*
00642      * get pseudo-random values for request ID and message ID 
00643      */
00644     /*
00645      * don't allow zero value to repeat init 
00646      */
00647 #ifdef SVR4
00648     srand48(tv.tv_sec ^ tv.tv_usec);
00649     tmpReqid = lrand48();
00650     tmpMsgid = lrand48();
00651 #else
00652     srandom(tv.tv_sec ^ tv.tv_usec);
00653     tmpReqid = random();
00654     tmpMsgid = random();
00655 #endif
00656 
00657     if (tmpReqid == 0)
00658         tmpReqid = 1;
00659     if (tmpMsgid == 0)
00660         tmpMsgid = 1;
00661     Reqid = tmpReqid;
00662     Msgid = tmpMsgid;
00663 
00664     netsnmp_register_default_domain("snmp", "udp");
00665     netsnmp_register_default_domain("snmptrap", "udp");
00666 
00667     netsnmp_register_default_target("snmp", "udp", ":161");
00668     netsnmp_register_default_target("snmp", "tcp", ":161");
00669     netsnmp_register_default_target("snmp", "udp6", ":161");
00670     netsnmp_register_default_target("snmp", "tcp6", ":161");
00671     netsnmp_register_default_target("snmp", "ipx", "/36879");
00672     netsnmp_register_default_target("snmptrap", "udp", ":162");
00673     netsnmp_register_default_target("snmptrap", "tcp", ":162");
00674     netsnmp_register_default_target("snmptrap", "udp6", ":162");
00675     netsnmp_register_default_target("snmptrap", "tcp6", ":162");
00676     netsnmp_register_default_target("snmptrap", "ipx", "/36880");
00677 
00678     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
00679                        NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
00680 
00681 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
00682     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00683                            NETSNMP_DS_LIB_REVERSE_ENCODE,
00684                            NETSNMP_DEFAULT_ASNENCODING_DIRECTION);
00685 #endif
00686 }
00687 
00688 /*
00689  * Initializes the session structure.
00690  * May perform one time minimal library initialization.
00691  * No MIB file processing is done via this call.
00692  */
00693 void
00694 snmp_sess_init(netsnmp_session * session)
00695 {
00696     _init_snmp();
00697 
00698     /*
00699      * initialize session to default values 
00700      */
00701 
00702     memset(session, 0, sizeof(netsnmp_session));
00703     session->remote_port = SNMP_DEFAULT_REMPORT;
00704     session->timeout = SNMP_DEFAULT_TIMEOUT;
00705     session->retries = SNMP_DEFAULT_RETRIES;
00706     session->version = SNMP_DEFAULT_VERSION;
00707     session->securityModel = SNMP_DEFAULT_SECMODEL;
00708     session->rcvMsgMaxSize = SNMP_MAX_MSG_SIZE;
00709     session->flags |= SNMP_FLAGS_DONT_PROBE;
00710 }
00711 
00712 
00713 static void
00714 register_default_handlers(void)
00715 {
00716     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
00717                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
00718     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
00719                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
00720     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
00721                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
00722 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
00723     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
00724                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
00725 #endif
00726     netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
00727                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
00728     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
00729                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
00730     netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
00731                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
00732     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
00733                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
00734     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
00735                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
00736     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
00737                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
00738     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "clientaddr",
00739                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
00740     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
00741                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
00742     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
00743                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
00744     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
00745                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
00746     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
00747                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
00748     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentLoad",
00749                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD);
00750     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentSave",
00751                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE);
00752     netsnmp_register_service_handlers();
00753 }
00754 
00755 void
00756 init_snmp_enums(void)
00757 {
00758     se_add_pair_to_slist("asntypes", strdup("integer"), ASN_INTEGER);
00759     se_add_pair_to_slist("asntypes", strdup("counter"), ASN_COUNTER);
00760     se_add_pair_to_slist("asntypes", strdup("uinteger"), ASN_GAUGE);
00761     se_add_pair_to_slist("asntypes", strdup("unsigned"), ASN_UNSIGNED); /* RFC 1902 - same as GAUGE */
00762     se_add_pair_to_slist("asntypes", strdup("timeticks"), ASN_TIMETICKS);
00763     se_add_pair_to_slist("asntypes", strdup("counter64"), ASN_COUNTER64);
00764     se_add_pair_to_slist("asntypes", strdup("octet_str"), ASN_OCTET_STR);
00765     se_add_pair_to_slist("asntypes", strdup("ipaddress"), ASN_IPADDRESS);
00766     se_add_pair_to_slist("asntypes", strdup("opaque"), ASN_OPAQUE);
00767     se_add_pair_to_slist("asntypes", strdup("nsap"), ASN_NSAP);
00768     se_add_pair_to_slist("asntypes", strdup("object_id"), ASN_OBJECT_ID);
00769     se_add_pair_to_slist("asntypes", strdup("null"), ASN_NULL);
00770 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
00771     se_add_pair_to_slist("asntypes", strdup("opaque_counter64"),
00772                          ASN_OPAQUE_COUNTER64);
00773     se_add_pair_to_slist("asntypes", strdup("opaque_u64"), ASN_OPAQUE_U64);
00774     se_add_pair_to_slist("asntypes", strdup("opaque_float"),
00775                          ASN_OPAQUE_FLOAT);
00776     se_add_pair_to_slist("asntypes", strdup("opaque_double"),
00777                          ASN_OPAQUE_DOUBLE);
00778     se_add_pair_to_slist("asntypes", strdup("opaque_i64"), ASN_OPAQUE_I64);
00779 #endif
00780 }
00781 
00782 
00783 
00794 void
00795 init_snmp(const char *type)
00796 {
00797     static int      done_init = 0;      /* To prevent double init's. */
00798 
00799     if (done_init) {
00800         return;
00801     }
00802 
00803     done_init = 1;
00804 
00805     /*
00806      * make the type available everywhere else 
00807      */
00808     if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
00809                                        NETSNMP_DS_LIB_APPTYPE)) {
00810         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
00811                               NETSNMP_DS_LIB_APPTYPE, type);
00812     }
00813 
00814     _init_snmp();
00815 
00816     /*
00817      * set our current locale properly to initialize isprint() type functions 
00818      */
00819 #ifdef HAVE_SETLOCALE
00820     setlocale(LC_CTYPE, "");
00821 #endif
00822 
00823     snmp_debug_init();    /* should be done first, to turn on debugging ASAP */
00824     netsnmp_container_init_list();
00825     init_callbacks();
00826     init_snmp_logging();
00827     snmp_init_statistics();
00828     register_mib_handlers();
00829     register_default_handlers();
00830     init_snmpv3(type);
00831     init_snmp_alarm();
00832     init_snmp_enum(type);
00833     init_snmp_enums();
00834     init_vacm();
00835 
00836     read_premib_configs();
00837 #ifndef NETSNMP_DISABLE_MIB_LOADING
00838     netsnmp_init_mib();
00839 #endif /* NETSNMP_DISABLE_MIB_LOADING */
00840 
00841     read_configs();
00842 
00843 }                               /* end init_snmp() */
00844 
00845 void
00846 snmp_store(const char *type)
00847 {
00848     DEBUGMSGTL(("snmp_store", "storing stuff...\n"));
00849     snmp_save_persistent(type);
00850     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
00851     snmp_clean_persistent(type);
00852 }
00853 
00854 
00863 void
00864 snmp_shutdown(const char *type)
00865 {
00866     snmp_store(type);
00867     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
00868     shutdown_snmp_logging();
00869     snmp_alarm_unregister_all();
00870     snmp_close_sessions();
00871 #ifndef NETSNMP_DISABLE_MIB_LOADING
00872     shutdown_mib();
00873 #endif /* NETSNMP_DISABLE_MIB_LOADING */
00874     unregister_all_config_handlers();
00875     netsnmp_container_free_list();
00876     clear_sec_mod();
00877     clear_snmp_enum();
00878     netsnmp_clear_tdomain_list();
00879     clear_callback();
00880     netsnmp_ds_shutdown();
00881     clear_user_list();
00882     netsnmp_clear_default_target();
00883     netsnmp_clear_default_domain();
00884     free_etimelist();
00885 }
00886 
00887 
00888 /*
00889  * Sets up the session with the snmp_session information provided by the user.
00890  * Then opens and binds the necessary low-level transport.  A handle to the
00891  * created session is returned (this is NOT the same as the pointer passed to
00892  * snmp_open()).  On any error, NULL is returned and snmp_errno is set to the
00893  * appropriate error code.
00894  */
00895 netsnmp_session *
00896 snmp_open(netsnmp_session *session)
00897 {
00898     struct session_list *slp;
00899     slp = (struct session_list *) snmp_sess_open(session);
00900     if (!slp) {
00901         return NULL;
00902     }
00903 
00904     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
00905     slp->next = Sessions;
00906     Sessions = slp;
00907     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
00908 
00909     return (slp->session);
00910 }
00911 
00912 /*
00913  * extended open 
00914  */
00915 netsnmp_session *
00916 snmp_open_ex(netsnmp_session *session,
00917              int (*fpre_parse)  (netsnmp_session *, netsnmp_transport *,
00918                                 void *, int),
00919              int (*fparse)      (netsnmp_session *, netsnmp_pdu *, u_char *,
00920                                  size_t),
00921              int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
00922 
00923              int (*fbuild)      (netsnmp_session *, netsnmp_pdu *, u_char *,
00924                                  size_t *),
00925              int (*frbuild)     (netsnmp_session *, netsnmp_pdu *,
00926                                  u_char **, size_t *, size_t *),
00927              int (*fcheck)      (u_char *, size_t)
00928              )
00929 {
00930     struct session_list *slp;
00931     slp = (struct session_list *) snmp_sess_open(session);
00932     if (!slp) {
00933         return NULL;
00934     }
00935     slp->internal->hook_pre = fpre_parse;
00936     slp->internal->hook_parse = fparse;
00937     slp->internal->hook_post = fpost_parse;
00938     slp->internal->hook_build = fbuild;
00939     slp->internal->hook_realloc_build = frbuild;
00940     slp->internal->check_packet = fcheck;
00941 
00942     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
00943     slp->next = Sessions;
00944     Sessions = slp;
00945     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
00946 
00947     return (slp->session);
00948 }
00949 
00950 static struct session_list *
00951 _sess_copy(netsnmp_session * in_session)
00952 {
00953     struct session_list *slp;
00954     struct snmp_internal_session *isp;
00955     netsnmp_session *session;
00956     struct snmp_secmod_def *sptr;
00957     char           *cp;
00958     u_char         *ucp;
00959     size_t          i;
00960 
00961     in_session->s_snmp_errno = 0;
00962     in_session->s_errno = 0;
00963 
00964     /*
00965      * Copy session structure and link into list 
00966      */
00967     slp = (struct session_list *) calloc(1, sizeof(struct session_list));
00968     if (slp == NULL) {
00969         in_session->s_snmp_errno = SNMPERR_MALLOC;
00970         return (NULL);
00971     }
00972 
00973     slp->transport = NULL;
00974 
00975     isp = (struct snmp_internal_session *)calloc(1, sizeof(struct snmp_internal_session));
00976 
00977     if (isp == NULL) {
00978         snmp_sess_close(slp);
00979         in_session->s_snmp_errno = SNMPERR_MALLOC;
00980         return (NULL);
00981     }
00982 
00983     slp->internal = isp;
00984     slp->session = (netsnmp_session *)malloc(sizeof(netsnmp_session));
00985     if (slp->session == NULL) {
00986         snmp_sess_close(slp);
00987         in_session->s_snmp_errno = SNMPERR_MALLOC;
00988         return (NULL);
00989     }
00990     memmove(slp->session, in_session, sizeof(netsnmp_session));
00991     session = slp->session;
00992 
00993     /*
00994      * zero out pointers so if we have to free the session we wont free mem
00995      * owned by in_session 
00996      */
00997     session->peername = NULL;
00998     session->community = NULL;
00999     session->contextEngineID = NULL;
01000     session->contextName = NULL;
01001     session->securityEngineID = NULL;
01002     session->securityName = NULL;
01003     session->securityAuthProto = NULL;
01004     session->securityPrivProto = NULL;
01005     /*
01006      * session now points to the new structure that still contains pointers to
01007      * data allocated elsewhere.  Some of this data is copied to space malloc'd
01008      * here, and the pointer replaced with the new one.
01009      */
01010 
01011     if (in_session->peername != NULL) {
01012         session->peername = (char *)malloc(strlen(in_session->peername) + 1);
01013         if (session->peername == NULL) {
01014             snmp_sess_close(slp);
01015             in_session->s_snmp_errno = SNMPERR_MALLOC;
01016             return (NULL);
01017         }
01018         strcpy(session->peername, in_session->peername);
01019     }
01020 
01021     /*
01022      * Fill in defaults if necessary 
01023      */
01024 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01025     if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
01026         ucp = (u_char *) malloc(in_session->community_len);
01027         if (ucp != NULL)
01028             memmove(ucp, in_session->community, in_session->community_len);
01029     } else {
01030         if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01031                                         NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
01032             session->community_len = strlen(cp);
01033             ucp = (u_char *) malloc(session->community_len);
01034             if (ucp)
01035                 memmove(ucp, cp, session->community_len);
01036         } else {
01037 #ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
01038             session->community_len = strlen(DEFAULT_COMMUNITY);
01039             ucp = (u_char *) malloc(session->community_len);
01040             if (ucp)
01041                 memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
01042 #else
01043             ucp = (u_char *) strdup("");
01044 #endif
01045         }
01046     }
01047 
01048     if (ucp == NULL) {
01049         snmp_sess_close(slp);
01050         in_session->s_snmp_errno = SNMPERR_MALLOC;
01051         return (NULL);
01052     }
01053     session->community = ucp;   /* replace pointer with pointer to new data */
01054 #endif
01055 
01056     if (session->securityLevel <= 0) {
01057         session->securityLevel =
01058             netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
01059     }
01060 
01061     if (session->securityLevel == 0)
01062         session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
01063 
01064     if (in_session->securityAuthProtoLen > 0) {
01065         session->securityAuthProto =
01066             snmp_duplicate_objid(in_session->securityAuthProto,
01067                                  in_session->securityAuthProtoLen);
01068         if (session->securityAuthProto == NULL) {
01069             snmp_sess_close(slp);
01070             in_session->s_snmp_errno = SNMPERR_MALLOC;
01071             return (NULL);
01072         }
01073     } else if (get_default_authtype(&i) != NULL) {
01074         session->securityAuthProto =
01075             snmp_duplicate_objid(get_default_authtype(NULL), i);
01076         session->securityAuthProtoLen = i;
01077     }
01078 
01079     if (in_session->securityPrivProtoLen > 0) {
01080         session->securityPrivProto =
01081             snmp_duplicate_objid(in_session->securityPrivProto,
01082                                  in_session->securityPrivProtoLen);
01083         if (session->securityPrivProto == NULL) {
01084             snmp_sess_close(slp);
01085             in_session->s_snmp_errno = SNMPERR_MALLOC;
01086             return (NULL);
01087         }
01088     } else if (get_default_privtype(&i) != NULL) {
01089         session->securityPrivProto =
01090             snmp_duplicate_objid(get_default_privtype(NULL), i);
01091         session->securityPrivProtoLen = i;
01092     }
01093 
01094     if (in_session->securityEngineIDLen > 0) {
01095         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
01096         if (ucp == NULL) {
01097             snmp_sess_close(slp);
01098             in_session->s_snmp_errno = SNMPERR_MALLOC;
01099             return (NULL);
01100         }
01101         memmove(ucp, in_session->securityEngineID,
01102                 in_session->securityEngineIDLen);
01103         session->securityEngineID = ucp;
01104 
01105     }
01106 
01107     if (in_session->contextEngineIDLen > 0) {
01108         ucp = (u_char *) malloc(in_session->contextEngineIDLen);
01109         if (ucp == NULL) {
01110             snmp_sess_close(slp);
01111             in_session->s_snmp_errno = SNMPERR_MALLOC;
01112             return (NULL);
01113         }
01114         memmove(ucp, in_session->contextEngineID,
01115                 in_session->contextEngineIDLen);
01116         session->contextEngineID = ucp;
01117     } else if (in_session->securityEngineIDLen > 0) {
01118         /*
01119          * default contextEngineID to securityEngineIDLen if defined 
01120          */
01121         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
01122         if (ucp == NULL) {
01123             snmp_sess_close(slp);
01124             in_session->s_snmp_errno = SNMPERR_MALLOC;
01125             return (NULL);
01126         }
01127         memmove(ucp, in_session->securityEngineID,
01128                 in_session->securityEngineIDLen);
01129         session->contextEngineID = ucp;
01130         session->contextEngineIDLen = in_session->securityEngineIDLen;
01131     }
01132 
01133     if (in_session->contextName) {
01134         session->contextName = strdup(in_session->contextName);
01135         if (session->contextName == NULL) {
01136             snmp_sess_close(slp);
01137             return (NULL);
01138         }
01139     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01140                                            NETSNMP_DS_LIB_CONTEXT)) != NULL) {
01141         cp = strdup(cp);
01142         if (cp == NULL) {
01143             snmp_sess_close(slp);
01144             return (NULL);
01145         }
01146         session->contextName = cp;
01147         session->contextNameLen = strlen(cp);
01148     } else {
01149         cp = strdup(SNMP_DEFAULT_CONTEXT);
01150         session->contextName = cp;
01151         session->contextNameLen = strlen(cp);
01152     }
01153 
01154     if (in_session->securityName) {
01155         session->securityName = strdup(in_session->securityName);
01156         if (session->securityName == NULL) {
01157             snmp_sess_close(slp);
01158             return (NULL);
01159         }
01160     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01161                                            NETSNMP_DS_LIB_SECNAME)) != NULL) {
01162         cp = strdup(cp);
01163         if (cp == NULL) {
01164             snmp_sess_close(slp);
01165             return (NULL);
01166         }
01167         session->securityName = cp;
01168         session->securityNameLen = strlen(cp);
01169     }
01170 
01171     if ((in_session->securityAuthKeyLen <= 0) &&
01172         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01173                                      NETSNMP_DS_LIB_AUTHMASTERKEY)))) {
01174         size_t buflen = sizeof(session->securityAuthKey);
01175         u_char *tmpp = session->securityAuthKey;
01176         session->securityAuthKeyLen = 0;
01177         /* it will be a hex string */
01178         if (!snmp_hex_to_binary(&tmpp, &buflen,
01179                                 &session->securityAuthKeyLen, 0, cp)) {
01180             snmp_set_detail("error parsing authentication master key");
01181             snmp_sess_close(slp);
01182             return NULL;
01183         }
01184     } else if ((in_session->securityAuthKeyLen <= 0) &&
01185         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01186                                      NETSNMP_DS_LIB_AUTHPASSPHRASE)) ||
01187          (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01188                                      NETSNMP_DS_LIB_PASSPHRASE)))) {
01189         session->securityAuthKeyLen = USM_AUTH_KU_LEN;
01190         if (generate_Ku(session->securityAuthProto,
01191                         session->securityAuthProtoLen,
01192                         (u_char *) cp, strlen(cp),
01193                         session->securityAuthKey,
01194                         &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
01195             snmp_set_detail
01196                 ("Error generating a key (Ku) from the supplied authentication pass phrase.");
01197             snmp_sess_close(slp);
01198             return NULL;
01199         }
01200     }
01201 
01202     
01203     if ((in_session->securityPrivKeyLen <= 0) &&
01204         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01205                                      NETSNMP_DS_LIB_PRIVMASTERKEY)))) {
01206         size_t buflen = sizeof(session->securityPrivKey);
01207         u_char *tmpp = session->securityPrivKey;
01208         session->securityPrivKeyLen = 0;
01209         /* it will be a hex string */
01210         if (!snmp_hex_to_binary(&tmpp, &buflen,
01211                                 &session->securityPrivKeyLen, 0, cp)) {
01212             snmp_set_detail("error parsing encryption master key");
01213             snmp_sess_close(slp);
01214             return NULL;
01215         }
01216     } else if ((in_session->securityPrivKeyLen <= 0) &&
01217         ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01218                                      NETSNMP_DS_LIB_PRIVPASSPHRASE)) ||
01219          (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01220                                      NETSNMP_DS_LIB_PASSPHRASE)))) {
01221         session->securityPrivKeyLen = USM_PRIV_KU_LEN;
01222         if (generate_Ku(session->securityAuthProto,
01223                         session->securityAuthProtoLen,
01224                         (u_char *) cp, strlen(cp),
01225                         session->securityPrivKey,
01226                         &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
01227             snmp_set_detail
01228                 ("Error generating a key (Ku) from the supplied privacy pass phrase.");
01229             snmp_sess_close(slp);
01230             return NULL;
01231         }
01232     }
01233 
01234     if (session->retries == SNMP_DEFAULT_RETRIES)
01235         session->retries = DEFAULT_RETRIES;
01236     if (session->timeout == SNMP_DEFAULT_TIMEOUT)
01237         session->timeout = DEFAULT_TIMEOUT;
01238     session->sessid = snmp_get_next_sessid();
01239 
01240     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
01241                         session);
01242 
01243     if ((sptr = find_sec_mod(session->securityModel)) != NULL &&
01244         sptr->session_open != NULL) {
01245         /*
01246          * security module specific inialization 
01247          */
01248         (*sptr->session_open) (session);
01249     }
01250 
01251     return (slp);
01252 }
01253 
01254 static struct session_list *
01255 snmp_sess_copy(netsnmp_session * pss)
01256 {
01257     struct session_list *psl;
01258     psl = _sess_copy(pss);
01259     if (!psl) {
01260         if (!pss->s_snmp_errno) {
01261             pss->s_snmp_errno = SNMPERR_GENERR;
01262         }
01263         SET_SNMP_ERROR(pss->s_snmp_errno);
01264     }
01265     return psl;
01266 }
01267 
01268 
01284 int
01285 snmpv3_engineID_probe(struct session_list *slp,
01286                       netsnmp_session * in_session)
01287 {
01288     netsnmp_pdu    *pdu = NULL, *response = NULL;
01289     netsnmp_session *session;
01290     unsigned int    i;
01291     int             status;
01292 
01293     if (slp == NULL || slp->session == NULL) {
01294         return 0;
01295     }
01296 
01297     session = slp->session;
01298 
01299     /*
01300      * If we are opening a V3 session and we don't know engineID we must probe
01301      * it -- this must be done after the session is created and inserted in the
01302      * list so that the response can handled correctly. 
01303      */
01304 
01305     if ((session->flags & SNMP_FLAGS_DONT_PROBE) == SNMP_FLAGS_DONT_PROBE)
01306         return 1;
01307 
01308     if (session->version == SNMP_VERSION_3) {
01309         if (session->securityEngineIDLen == 0) {
01310             if (snmpv3_build_probe_pdu(&pdu) != 0) {
01311                 DEBUGMSGTL(("snmp_api", "unable to create probe PDU\n"));
01312                 return 0;
01313             }
01314             DEBUGMSGTL(("snmp_api", "probing for engineID...\n"));
01315             session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
01316             status = snmp_sess_synch_response(slp, pdu, &response);
01317 
01318             if ((response == NULL) && (status == STAT_SUCCESS)) {
01319                 status = STAT_ERROR;
01320             }
01321 
01322             switch (status) {
01323             case STAT_SUCCESS:
01324                 in_session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
01325                 DEBUGMSGTL(("snmp_sess_open",
01326                             "error: expected Report as response to probe: %s (%d)\n",
01327                             snmp_errstring(response->errstat),
01328                             response->errstat));
01329                 break;
01330             case STAT_ERROR:   /* this is what we expected -> Report == STAT_ERROR */
01331                 in_session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
01332                 break;
01333             case STAT_TIMEOUT:
01334                 in_session->s_snmp_errno = SNMPERR_TIMEOUT;
01335             default:
01336                 DEBUGMSGTL(("snmp_sess_open",
01337                             "unable to connect with remote engine: %s (%d)\n",
01338                             snmp_api_errstring(session->s_snmp_errno),
01339                             session->s_snmp_errno));
01340                 break;
01341             }
01342 
01343             if (slp->session->securityEngineIDLen == 0) {
01344                 DEBUGMSGTL(("snmp_api",
01345                             "unable to determine remote engine ID\n"));
01346                 return 0;
01347             }
01348 
01349             in_session->s_snmp_errno = SNMPERR_SUCCESS;
01350             if (snmp_get_do_debugging()) {
01351                 DEBUGMSGTL(("snmp_sess_open",
01352                             "  probe found engineID:  "));
01353                 for (i = 0; i < slp->session->securityEngineIDLen; i++)
01354                     DEBUGMSG(("snmp_sess_open", "%02x",
01355                               slp->session->securityEngineID[i]));
01356                 DEBUGMSG(("snmp_sess_open", "\n"));
01357             }
01358         }
01359 
01360         /*
01361          * if boot/time supplied set it for this engineID 
01362          */
01363         if (session->engineBoots || session->engineTime) {
01364             set_enginetime(session->securityEngineID,
01365                            session->securityEngineIDLen,
01366                            session->engineBoots, session->engineTime,
01367                            TRUE);
01368         }
01369 
01370         if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
01371             in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME;       /* XX?? */
01372             DEBUGMSGTL(("snmp_api",
01373                         "snmpv3_engine_probe(): failed(2) to create a new user from session\n"));
01374             return 0;
01375         }
01376     }
01377 
01378     return 1;
01379 }
01380 
01381 
01382 
01383 /*******************************************************************-o-******
01384  * snmp_sess_open
01385  *
01386  * Parameters:
01387  *      *in_session
01388  *
01389  * Returns:
01390  *      Pointer to a session in the session list   -OR-         FIX -- right?
01391  *      NULL on failure.
01392  *
01393  * The "spin-free" version of snmp_open.
01394  */
01395 static void    *
01396 _sess_open(netsnmp_session * in_session)
01397 {
01398     struct session_list *slp;
01399     netsnmp_session *session;
01400     char            *clientaddr_save = NULL;
01401 
01402     in_session->s_snmp_errno = 0;
01403     in_session->s_errno = 0;
01404 
01405     _init_snmp();
01406 
01407     if ((slp = snmp_sess_copy(in_session)) == NULL) {
01408         return (NULL);
01409     }
01410     session = slp->session;
01411     slp->transport = NULL;
01412 
01413     if (NULL != session->localname) {
01414         clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
01415                                                 NETSNMP_DS_LIB_CLIENT_ADDR);
01416         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
01417                               NETSNMP_DS_LIB_CLIENT_ADDR, session->localname);
01418     }
01419 
01420     if (session->flags & SNMP_FLAGS_STREAM_SOCKET) {
01421         slp->transport =
01422           netsnmp_tdomain_transport_full("snmp", session->peername,
01423                                          session->local_port, "tcp", NULL);
01424     } else {
01425         slp->transport =
01426           netsnmp_tdomain_transport_full("snmp", session->peername,
01427                                          session->local_port, "udp", NULL);
01428     }
01429 
01430     if (NULL != session->localname)
01431         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
01432                               NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
01433 
01434     if (slp->transport == NULL) {
01435         DEBUGMSGTL(("_sess_open", "couldn't interpret peername\n"));
01436         in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
01437         in_session->s_errno = errno;
01438         snmp_set_detail(session->peername);
01439         snmp_sess_close(slp);
01440         return NULL;
01441     }
01442 
01443     session->rcvMsgMaxSize = slp->transport->msgMaxSize;
01444 
01445     if (!snmpv3_engineID_probe(slp, in_session)) {
01446         snmp_sess_close(slp);
01447         return NULL;
01448     }
01449     if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
01450         in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME;       /* XX?? */
01451         DEBUGMSGTL(("snmp_api",
01452                     "_sess_open(): failed(2) to create a new user from session\n"));
01453         snmp_sess_close(slp);
01454         return NULL;
01455     }
01456     
01457     session->flags &= ~SNMP_FLAGS_DONT_PROBE;
01458 
01459 
01460     return (void *) slp;
01461 }                               /* end snmp_sess_open() */
01462 
01463 
01464 
01465 /*
01466  * EXPERIMENTAL API EXTENSIONS ------------------------------------------ 
01467  * 
01468  * snmp_sess_add_ex, snmp_sess_add, snmp_add 
01469  * 
01470  * Analogous to snmp_open family of functions, but taking a netsnmp_transport
01471  * pointer as an extra argument.  Unlike snmp_open et al. it doesn't attempt
01472  * to interpret the in_session->peername as a transport endpoint specifier,
01473  * but instead uses the supplied transport.  JBPN
01474  * 
01475  */
01476 
01477 netsnmp_session *
01478 snmp_add(netsnmp_session * in_session,
01479          netsnmp_transport *transport,
01480          int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
01481                             int), int (*fpost_parse) (netsnmp_session *,
01482                                                       netsnmp_pdu *, int))
01483 {
01484     struct session_list *slp;
01485     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
01486                                                    fpre_parse, NULL,
01487                                                    fpost_parse, NULL, NULL,
01488                                                    NULL, NULL);
01489     if (slp == NULL) {
01490         return NULL;
01491     }
01492 
01493     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
01494     slp->next = Sessions;
01495     Sessions = slp;
01496     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
01497 
01498     return (slp->session);
01499 }
01500 
01501 netsnmp_session *
01502 snmp_add_full(netsnmp_session * in_session,
01503               netsnmp_transport *transport,
01504               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
01505                                  void *, int),
01506               int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
01507                              size_t),
01508               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
01509               int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
01510                              size_t *), int (*frbuild) (netsnmp_session *,
01511                                                         netsnmp_pdu *,
01512                                                         u_char **,
01513                                                         size_t *,
01514                                                         size_t *),
01515               int (*fcheck) (u_char *, size_t),
01516               netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
01517                                            size_t))
01518 {
01519     struct session_list *slp;
01520     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
01521                                                    fpre_parse, fparse,
01522                                                    fpost_parse, fbuild,
01523                                                    frbuild, fcheck,
01524                                                    fcreate_pdu);
01525     if (slp == NULL) {
01526         return NULL;
01527     }
01528 
01529     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
01530     slp->next = Sessions;
01531     Sessions = slp;
01532     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
01533 
01534     return (slp->session);
01535 }
01536 
01537 
01538 
01539 void           *
01540 snmp_sess_add_ex(netsnmp_session * in_session,
01541                  netsnmp_transport *transport,
01542                  int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
01543                                     void *, int),
01544                  int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
01545                                 size_t),
01546                  int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
01547                                      int),
01548                  int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
01549                                 size_t *),
01550                  int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
01551                                  u_char **, size_t *, size_t *),
01552                  int (*fcheck) (u_char *, size_t),
01553                  netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
01554                                               size_t))
01555 {
01556     struct session_list *slp;
01557 
01558     _init_snmp();
01559 
01560     if (transport == NULL)
01561         return NULL;
01562 
01563     if (in_session == NULL) {
01564         transport->f_close(transport);
01565         netsnmp_transport_free(transport);
01566         return NULL;
01567     }
01568 
01569     DEBUGMSGTL(("snmp_sess_add", "fd %d\n", transport->sock));
01570 
01571     if ((slp = snmp_sess_copy(in_session)) == NULL) {
01572         transport->f_close(transport);
01573         netsnmp_transport_free(transport);
01574         return (NULL);
01575     }
01576 
01577     slp->transport = transport;
01578     slp->internal->hook_pre = fpre_parse;
01579     slp->internal->hook_parse = fparse;
01580     slp->internal->hook_post = fpost_parse;
01581     slp->internal->hook_build = fbuild;
01582     slp->internal->hook_realloc_build = frbuild;
01583     slp->internal->check_packet = fcheck;
01584     slp->internal->hook_create_pdu = fcreate_pdu;
01585 
01586     slp->session->rcvMsgMaxSize = transport->msgMaxSize;
01587 
01588     if (slp->session->version == SNMP_VERSION_3) {
01589         DEBUGMSGTL(("snmp_sess_add",
01590                     "adding v3 session -- engineID probe now\n"));
01591         if (!snmpv3_engineID_probe(slp, in_session)) {
01592             DEBUGMSGTL(("snmp_sess_add", "engine ID probe failed\n"));
01593             snmp_sess_close(slp);
01594             return NULL;
01595         }
01596         if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
01597             in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME;
01598             DEBUGMSGTL(("snmp_api",
01599                         "snmp_sess_add(): failed(2) to create a new user from session\n"));
01600             snmp_sess_close(slp);
01601             return NULL;
01602         }
01603     }
01604 
01605     slp->session->flags &= ~SNMP_FLAGS_DONT_PROBE;
01606 
01607     return (void *) slp;
01608 }                               /*  end snmp_sess_add_ex()  */
01609 
01610 
01611 
01612 void           *
01613 snmp_sess_add(netsnmp_session * in_session,
01614               netsnmp_transport *transport,
01615               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
01616                                  void *, int),
01617               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
01618 {
01619     return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
01620                             fpost_parse, NULL, NULL, NULL, NULL);
01621 }
01622 
01623 
01624 
01625 void           *
01626 snmp_sess_open(netsnmp_session * pss)
01627 {
01628     void           *pvoid;
01629     pvoid = _sess_open(pss);
01630     if (!pvoid) {
01631         SET_SNMP_ERROR(pss->s_snmp_errno);
01632     }
01633     return pvoid;
01634 }
01635 
01636 
01637 
01638 /*
01639  * create_user_from_session(netsnmp_session *session):
01640  * 
01641  * creates a user in the usm table from the information in a session.
01642  * If the user already exists, it is updated with the current
01643  * information from the session
01644  * 
01645  * Parameters:
01646  * session -- IN: pointer to the session to use when creating the user.
01647  * 
01648  * Returns:
01649  * SNMPERR_SUCCESS
01650  * SNMPERR_GENERR 
01651  */
01652 int
01653 create_user_from_session(netsnmp_session * session)
01654 {
01655     struct usmUser *user;
01656     int             user_just_created = 0;
01657     char *cp;
01658 
01659     /*
01660      * - don't create-another/copy-into user for this session by default
01661      * - bail now (no error) if we don't have an engineID
01662      */
01663     if (SNMP_FLAGS_USER_CREATED == (session->flags & SNMP_FLAGS_USER_CREATED) ||
01664         session->securityModel != SNMP_SEC_MODEL_USM ||
01665         session->version != SNMP_VERSION_3 ||
01666         session->securityEngineIDLen == 0)
01667         return SNMPERR_SUCCESS;
01668 
01669     session->flags |= SNMP_FLAGS_USER_CREATED;
01670 
01671     /*
01672      * now that we have the engineID, create an entry in the USM list
01673      * for this user using the information in the session 
01674      */
01675     user = usm_get_user_from_list(session->securityEngineID,
01676                                   session->securityEngineIDLen,
01677                                   session->securityName,
01678                                   usm_get_userList(), 0);
01679     if (user == NULL) {
01680         DEBUGMSGTL(("snmp_api", "Building user %s...\n",
01681                     session->securityName));
01682         /*
01683          * user doesn't exist so we create and add it 
01684          */
01685         user = (struct usmUser *) calloc(1, sizeof(struct usmUser));
01686         if (user == NULL)
01687             return SNMPERR_GENERR;
01688 
01689         /*
01690          * copy in the securityName 
01691          */
01692         if (session->securityName) {
01693             user->name = strdup(session->securityName);
01694             user->secName = strdup(session->securityName);
01695             if (user->name == NULL || user->secName == NULL) {
01696                 usm_free_user(user);
01697                 return SNMPERR_GENERR;
01698             }
01699         }
01700 
01701         /*
01702          * copy in the engineID 
01703          */
01704         if (memdup(&user->engineID, session->securityEngineID,
01705                    session->securityEngineIDLen) != SNMPERR_SUCCESS) {
01706             usm_free_user(user);
01707             return SNMPERR_GENERR;
01708         }
01709         user->engineIDLen = session->securityEngineIDLen;
01710 
01711         user_just_created = 1;
01712     }
01713     /*
01714      * copy the auth protocol 
01715      */
01716     if (session->securityAuthProto != NULL) {
01717         SNMP_FREE(user->authProtocol);
01718         user->authProtocol =
01719             snmp_duplicate_objid(session->securityAuthProto,
01720                                  session->securityAuthProtoLen);
01721         if (user->authProtocol == NULL) {
01722             usm_free_user(user);
01723             return SNMPERR_GENERR;
01724         }
01725         user->authProtocolLen = session->securityAuthProtoLen;
01726     }
01727 
01728     /*
01729      * copy the priv protocol 
01730      */
01731     if (session->securityPrivProto != NULL) {
01732         SNMP_FREE(user->privProtocol);
01733         user->privProtocol =
01734             snmp_duplicate_objid(session->securityPrivProto,
01735                                  session->securityPrivProtoLen);
01736         if (user->privProtocol == NULL) {
01737             usm_free_user(user);
01738             return SNMPERR_GENERR;
01739         }
01740         user->privProtocolLen = session->securityPrivProtoLen;
01741     }
01742 
01743     /*
01744      * copy in the authentication Key.  If not localized, localize it 
01745      */
01746     if (session->securityAuthLocalKey != NULL
01747         && session->securityAuthLocalKeyLen != 0) {
01748         /* already localized key passed in.  use it */
01749         SNMP_FREE(user->authKey);
01750         if (memdup(&user->authKey, session->securityAuthLocalKey,
01751                    session->securityAuthLocalKeyLen) != SNMPERR_SUCCESS) {
01752             usm_free_user(user);
01753             return SNMPERR_GENERR;
01754         }
01755         user->authKeyLen = session->securityAuthLocalKeyLen;
01756     } else if (session->securityAuthKey != NULL
01757         && session->securityAuthKeyLen != 0) {
01758         SNMP_FREE(user->authKey);
01759         user->authKey = (u_char *) calloc(1, USM_LENGTH_KU_HASHBLOCK);
01760         if (user->authKey == NULL) {
01761             usm_free_user(user);
01762             return SNMPERR_GENERR;
01763         }
01764         user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
01765         if (generate_kul(user->authProtocol, user->authProtocolLen,
01766                          session->securityEngineID,
01767                          session->securityEngineIDLen,
01768                          session->securityAuthKey,
01769                          session->securityAuthKeyLen, user->authKey,
01770                          &user->authKeyLen) != SNMPERR_SUCCESS) {
01771             usm_free_user(user);
01772             return SNMPERR_GENERR;
01773         }
01774     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01775                                            NETSNMP_DS_LIB_AUTHLOCALIZEDKEY))) {
01776         size_t buflen = USM_AUTH_KU_LEN;
01777         SNMP_FREE(user->authKey);
01778         user->authKey = (u_char *)malloc(buflen); /* max length needed */
01779         user->authKeyLen = 0;
01780         /* it will be a hex string */
01781         if (!snmp_hex_to_binary(&user->authKey, &buflen, &user->authKeyLen,
01782                                 0, cp)) {
01783             usm_free_user(user);
01784             return SNMPERR_GENERR;
01785         }
01786     }
01787 
01788     /*
01789      * copy in the privacy Key.  If not localized, localize it 
01790      */
01791     if (session->securityPrivLocalKey != NULL
01792         && session->securityPrivLocalKeyLen != 0) {
01793         /* already localized key passed in.  use it */
01794         SNMP_FREE(user->privKey);
01795         if (memdup(&user->privKey, session->securityPrivLocalKey,
01796                    session->securityPrivLocalKeyLen) != SNMPERR_SUCCESS) {
01797             usm_free_user(user);
01798             return SNMPERR_GENERR;
01799         }
01800         user->privKeyLen = session->securityPrivLocalKeyLen;
01801     } else if (session->securityPrivKey != NULL
01802         && session->securityPrivKeyLen != 0) {
01803         SNMP_FREE(user->privKey);
01804         user->privKey = (u_char *) calloc(1, USM_LENGTH_KU_HASHBLOCK);
01805         if (user->privKey == NULL) {
01806             usm_free_user(user);
01807             return SNMPERR_GENERR;
01808         }
01809         user->privKeyLen = USM_LENGTH_KU_HASHBLOCK;
01810         if (generate_kul(user->authProtocol, user->authProtocolLen,
01811                          session->securityEngineID,
01812                          session->securityEngineIDLen,
01813                          session->securityPrivKey,
01814                          session->securityPrivKeyLen, user->privKey,
01815                          &user->privKeyLen) != SNMPERR_SUCCESS) {
01816             usm_free_user(user);
01817             return SNMPERR_GENERR;
01818         }
01819     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01820                                            NETSNMP_DS_LIB_PRIVLOCALIZEDKEY))) {
01821         size_t buflen = USM_PRIV_KU_LEN;
01822         SNMP_FREE(user->privKey);
01823         user->privKey = (u_char *)malloc(buflen); /* max length needed */
01824         user->privKeyLen = 0;
01825         /* it will be a hex string */
01826         if (!snmp_hex_to_binary(&user->privKey, &buflen, &user->privKeyLen,
01827                                 0, cp)) {
01828             usm_free_user(user);
01829             return SNMPERR_GENERR;
01830         }
01831     }
01832 
01833     if (user_just_created) {
01834         /*
01835          * add the user into the database 
01836          */
01837         user->userStatus = RS_ACTIVE;
01838         user->userStorageType = ST_READONLY;
01839         usm_add_user(user);
01840     }
01841 
01842     return SNMPERR_SUCCESS;
01843 
01844 
01845 }                               /* end create_user_from_session() */
01846 
01847 /*
01848  *  Do a "deep free()" of a netsnmp_session.
01849  *
01850  *  CAUTION:  SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
01851  *                                                      (hence it is static)
01852  */
01853 
01854 static void
01855 snmp_free_session(netsnmp_session * s)
01856 {
01857     if (s) {
01858         SNMP_FREE(s->peername);
01859         SNMP_FREE(s->community);
01860         SNMP_FREE(s->contextEngineID);
01861         SNMP_FREE(s->contextName);
01862         SNMP_FREE(s->securityEngineID);
01863         SNMP_FREE(s->securityName);
01864         SNMP_FREE(s->securityAuthProto);
01865         SNMP_FREE(s->securityPrivProto);
01866         SNMP_FREE(s->paramName);
01867 
01868         /*
01869          * clear session from any callbacks
01870          */
01871         netsnmp_callback_clear_client_arg(s, 0, 0);
01872 
01873         free((char *) s);
01874     }
01875 }
01876 
01877 /*
01878  * Close the input session.  Frees all data allocated for the session,
01879  * dequeues any pending requests, and closes any sockets allocated for
01880  * the session.  Returns 0 on error, 1 otherwise.
01881  */
01882 int
01883 snmp_sess_close(void *sessp)
01884 {
01885     struct session_list *slp = (struct session_list *) sessp;
01886     netsnmp_transport *transport;
01887     struct snmp_internal_session *isp;
01888     netsnmp_session *sesp = NULL;
01889     struct snmp_secmod_def *sptr;
01890 
01891     if (slp == NULL) {
01892         return 0;
01893     }
01894 
01895     if (slp->session != NULL &&
01896         (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
01897         sptr->session_close != NULL) {
01898         (*sptr->session_close) (slp->session);
01899     }
01900 
01901     isp = slp->internal;
01902     slp->internal = 0;
01903 
01904     if (isp) {
01905         netsnmp_request_list *rp, *orp;
01906 
01907         SNMP_FREE(isp->packet);
01908 
01909         /*
01910          * Free each element in the input request list.  
01911          */
01912         rp = isp->requests;
01913         while (rp) {
01914             orp = rp;
01915             rp = rp->next_request;
01916             snmp_free_pdu(orp->pdu);
01917             free((char *) orp);
01918         }
01919 
01920         free((char *) isp);
01921     }
01922 
01923     transport = slp->transport;
01924     slp->transport = 0;
01925 
01926     if (transport) {
01927         transport->f_close(transport);
01928         netsnmp_transport_free(transport);
01929     }
01930 
01931     sesp = slp->session;
01932     slp->session = 0;
01933 
01934     /*
01935      * The following is necessary to avoid memory leakage when closing AgentX 
01936      * sessions that may have multiple subsessions.  These hang off the main
01937      * session at ->subsession, and chain through ->next.  
01938      */
01939 
01940     if (sesp != NULL && sesp->subsession != NULL) {
01941         netsnmp_session *subsession = sesp->subsession, *tmpsub;
01942 
01943         while (subsession != NULL) {
01944             DEBUGMSGTL(("snmp_sess_close",
01945                         "closing session %p, subsession %p\n", sesp,
01946                         subsession));
01947             tmpsub = subsession->next;
01948             snmp_free_session(subsession);
01949             subsession = tmpsub;
01950         }
01951     }
01952 
01953     snmp_free_session(sesp);
01954     free((char *) slp);
01955     return 1;
01956 }
01957 
01958 int
01959 snmp_close(netsnmp_session * session)
01960 {
01961     struct session_list *slp = NULL, *oslp = NULL;
01962 
01963     {                           /*MTCRITICAL_RESOURCE */
01964         snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
01965         if (Sessions && Sessions->session == session) { /* If first entry */
01966             slp = Sessions;
01967             Sessions = slp->next;
01968         } else {
01969             for (slp = Sessions; slp; slp = slp->next) {
01970                 if (slp->session == session) {
01971                     if (oslp)   /* if we found entry that points here */
01972                         oslp->next = slp->next; /* link around this entry */
01973                     break;
01974                 }
01975                 oslp = slp;
01976             }
01977         }
01978         snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
01979     }                           /*END MTCRITICAL_RESOURCE */
01980     if (slp == NULL) {
01981         return 0;
01982     }
01983     return snmp_sess_close((void *) slp);
01984 }
01985 
01986 int
01987 snmp_close_sessions(void)
01988 {
01989     struct session_list *slp;
01990 
01991     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
01992     while (Sessions) {
01993         slp = Sessions;
01994         Sessions = Sessions->next;
01995         snmp_sess_close((void *) slp);
01996     }
01997     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
01998     return 1;
01999 }
02000 
02001 static int
02002 snmpv3_build_probe_pdu(netsnmp_pdu **pdu)
02003 {
02004     struct usmUser *user;
02005 
02006     /*
02007      * create the pdu 
02008      */
02009     if (!pdu)
02010         return -1;
02011     *pdu = snmp_pdu_create(SNMP_MSG_GET);
02012     if (!(*pdu))
02013         return -1;
02014     (*pdu)->version = SNMP_VERSION_3;
02015     (*pdu)->securityName = strdup("");
02016     (*pdu)->securityNameLen = strlen((*pdu)->securityName);
02017     (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
02018     (*pdu)->securityModel = SNMP_SEC_MODEL_USM;
02019 
02020     /*
02021      * create the empty user 
02022      */
02023     user = usm_get_user(NULL, 0, (*pdu)->securityName);
02024     if (user == NULL) {
02025         user = (struct usmUser *) calloc(1, sizeof(struct usmUser));
02026         if (user == NULL) {
02027             snmp_free_pdu(*pdu);
02028             *pdu = (netsnmp_pdu *) NULL;
02029             return -1;
02030         }
02031         user->name = strdup((*pdu)->securityName);
02032         user->secName = strdup((*pdu)->securityName);
02033         user->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid);
02034         user->authProtocol =
02035             snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
02036         user->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid);
02037         user->privProtocol =
02038             snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
02039         usm_add_user(user);
02040     }
02041     return 0;
02042 }
02043 
02044 static void
02045 snmpv3_calc_msg_flags(int sec_level, int msg_command, u_char * flags)
02046 {
02047     *flags = 0;
02048     if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
02049         *flags = SNMP_MSG_FLAG_AUTH_BIT;
02050     else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
02051         *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
02052 
02053     if (SNMP_CMD_CONFIRMED(msg_command))
02054         *flags |= SNMP_MSG_FLAG_RPRT_BIT;
02055 
02056     return;
02057 }
02058 
02059 static int
02060 snmpv3_verify_msg(netsnmp_request_list *rp, netsnmp_pdu *pdu)
02061 {
02062     netsnmp_pdu    *rpdu;
02063 
02064     if (!rp || !rp->pdu || !pdu)
02065         return 0;
02066     /*
02067      * Reports don't have to match anything according to the spec 
02068      */
02069     if (pdu->command == SNMP_MSG_REPORT)
02070         return 1;
02071     rpdu = rp->pdu;
02072     if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid)
02073         return 0;
02074     if (rpdu->version != pdu->version)
02075         return 0;
02076     if (rpdu->securityModel != pdu->securityModel)
02077         return 0;
02078     if (rpdu->securityLevel != pdu->securityLevel)
02079         return 0;
02080 
02081     if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen ||
02082         memcmp(rpdu->contextEngineID, pdu->contextEngineID,
02083                pdu->contextEngineIDLen))
02084         return 0;
02085     if (rpdu->contextNameLen != pdu->contextNameLen ||
02086         memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
02087         return 0;
02088     if (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
02089         memcmp(rpdu->securityEngineID, pdu->securityEngineID,
02090                pdu->securityEngineIDLen))
02091         return 0;
02092     if (rpdu->securityNameLen != pdu->securityNameLen ||
02093         memcmp(rpdu->securityName, pdu->securityName,
02094                pdu->securityNameLen))
02095         return 0;
02096     return 1;
02097 }
02098 
02099 
02100 /*
02101  * SNMPv3
02102  * * Takes a session and a pdu and serializes the ASN PDU into the area
02103  * * pointed to by packet.  out_length is the size of the data area available.
02104  * * Returns the length of the completed packet in out_length.  If any errors
02105  * * occur, -1 is returned.  If all goes well, 0 is returned.
02106  */
02107 static int
02108 snmpv3_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
02109              netsnmp_session * session, netsnmp_pdu *pdu)
02110 {
02111     int             ret;
02112 
02113     session->s_snmp_errno = 0;
02114     session->s_errno = 0;
02115 
02116     /*
02117      * do validation for PDU types 
02118      */
02119     switch (pdu->command) {
02120     case SNMP_MSG_RESPONSE:
02121     case SNMP_MSG_TRAP2:
02122     case SNMP_MSG_REPORT:
02123         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
02124         /*
02125          * Fallthrough 
02126          */
02127     case SNMP_MSG_GET:
02128     case SNMP_MSG_GETNEXT:
02129     case SNMP_MSG_SET:
02130     case SNMP_MSG_INFORM:
02131         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
02132             pdu->errstat = 0;
02133         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
02134             pdu->errindex = 0;
02135         break;
02136 
02137     case SNMP_MSG_GETBULK:
02138         if (pdu->max_repetitions < 0) {
02139             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
02140             return -1;
02141         }
02142         if (pdu->non_repeaters < 0) {
02143             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
02144             return -1;
02145         }
02146         break;
02147 
02148     case SNMP_MSG_TRAP:
02149         session->s_snmp_errno = SNMPERR_V1_IN_V2;
02150         return -1;
02151 
02152     default:
02153         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
02154         return -1;
02155     }
02156 
02157     /* Do we need to set the session security engineid? */
02158     if (pdu->securityEngineIDLen == 0) {
02159         if (session->securityEngineIDLen) {
02160             snmpv3_clone_engineID(&pdu->securityEngineID,
02161                                   &pdu->securityEngineIDLen,
02162                                   session->securityEngineID,
02163                                   session->securityEngineIDLen);
02164         }
02165     }
02166     
02167     /* Do we need to set the session context engineid? */
02168     if (pdu->contextEngineIDLen == 0) {
02169         if (session->contextEngineIDLen) {
02170             snmpv3_clone_engineID(&pdu->contextEngineID,
02171                                   &pdu->contextEngineIDLen,
02172                                   session->contextEngineID,
02173                                   session->contextEngineIDLen);
02174         } else if (pdu->securityEngineIDLen) {
02175             snmpv3_clone_engineID(&pdu->contextEngineID,
02176                                   &pdu->contextEngineIDLen,
02177                                   pdu->securityEngineID,
02178                                   pdu->securityEngineIDLen);
02179         }
02180     }
02181 
02182     if (pdu->contextName == NULL) {
02183         if (!session->contextName) {
02184             session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
02185             return -1;
02186         }
02187         pdu->contextName = strdup(session->contextName);
02188         if (pdu->contextName == NULL) {
02189             session->s_snmp_errno = SNMPERR_GENERR;
02190             return -1;
02191         }
02192         pdu->contextNameLen = session->contextNameLen;
02193     }
02194     if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
02195         pdu->securityModel = session->securityModel;
02196         if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
02197             pdu->securityModel = SNMP_SEC_MODEL_USM;
02198         }
02199     }
02200     if (pdu->securityNameLen == 0 && pdu->securityName == 0) {
02201         if (session->securityNameLen == 0) {
02202             session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
02203             return -1;
02204         }
02205         pdu->securityName = strdup(session->securityName);
02206         if (pdu->securityName == NULL) {
02207             session->s_snmp_errno = SNMPERR_GENERR;
02208             return -1;
02209         }
02210         pdu->securityNameLen = session->securityNameLen;
02211     }
02212     if (pdu->securityLevel == 0) {
02213         if (session->securityLevel == 0) {
02214             session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
02215             return -1;
02216         }
02217         pdu->securityLevel = session->securityLevel;
02218     }
02219     DEBUGMSGTL(("snmp_build",
02220                 "Building SNMPv3 message (secName:\"%s\", secLevel:%s)...\n",
02221                 ((session->securityName) ? (char *) session->securityName :
02222                  ((pdu->securityName) ? (char *) pdu->securityName :
02223                   "ERROR: undefined")), secLevelName[pdu->securityLevel]));
02224 
02225     DEBUGDUMPSECTION("send", "SNMPv3 Message");
02226 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02227     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
02228         ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
02229                                            session, pdu, NULL, 0);
02230     } else {
02231 #endif
02232         ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
02233 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02234     }
02235 #endif
02236     DEBUGINDENTLESS();
02237     if (-1 != ret) {
02238         session->s_snmp_errno = ret;
02239     }
02240 
02241     return ret;
02242 
02243 }                               /* end snmpv3_build() */
02244 
02245 
02246 
02247 
02248 static u_char  *
02249 snmpv3_header_build(netsnmp_session * session, netsnmp_pdu *pdu,
02250                     u_char * packet, size_t * out_length,
02251                     size_t length, u_char ** msg_hdr_e)
02252 {
02253     u_char         *global_hdr, *global_hdr_e;
02254     u_char         *cp;
02255     u_char          msg_flags;
02256     long            max_size;
02257     long            sec_model;
02258     u_char         *pb, *pb0e;
02259 
02260     /*
02261      * Save current location and build SEQUENCE tag and length placeholder
02262      * * for SNMP message sequence (actual length inserted later)
02263      */
02264     cp = asn_build_sequence(packet, out_length,
02265                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
02266                             length);
02267     if (cp == NULL)
02268         return NULL;
02269     if (msg_hdr_e != NULL)
02270         *msg_hdr_e = cp;
02271     pb0e = cp;
02272 
02273 
02274     /*
02275      * store the version field - msgVersion
02276      */
02277     DEBUGDUMPHEADER("send", "SNMP Version Number");
02278     cp = asn_build_int(cp, out_length,
02279                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02280                                  ASN_INTEGER), (long *) &pdu->version,
02281                        sizeof(pdu->version));
02282     DEBUGINDENTLESS();
02283     if (cp == NULL)
02284         return NULL;
02285 
02286     global_hdr = cp;
02287     /*
02288      * msgGlobalData HeaderData 
02289      */
02290     DEBUGDUMPSECTION("send", "msgGlobalData");
02291     cp = asn_build_sequence(cp, out_length,
02292                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
02293     if (cp == NULL)
02294         return NULL;
02295     global_hdr_e = cp;
02296 
02297 
02298     /*
02299      * msgID 
02300      */
02301     DEBUGDUMPHEADER("send", "msgID");
02302     cp = asn_build_int(cp, out_length,
02303                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02304                                  ASN_INTEGER), &pdu->msgid,
02305                        sizeof(pdu->msgid));
02306     DEBUGINDENTLESS();
02307     if (cp == NULL)
02308         return NULL;
02309 
02310     /*
02311      * msgMaxSize 
02312      */
02313     max_size = session->rcvMsgMaxSize;
02314     DEBUGDUMPHEADER("send", "msgMaxSize");
02315     cp = asn_build_int(cp, out_length,
02316                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02317                                  ASN_INTEGER), &max_size,
02318                        sizeof(max_size));
02319     DEBUGINDENTLESS();
02320     if (cp == NULL)
02321         return NULL;
02322 
02323     /*
02324      * msgFlags 
02325      */
02326     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
02327     DEBUGDUMPHEADER("send", "msgFlags");
02328     cp = asn_build_string(cp, out_length,
02329                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02330                                     ASN_OCTET_STR), &msg_flags,
02331                           sizeof(msg_flags));
02332     DEBUGINDENTLESS();
02333     if (cp == NULL)
02334         return NULL;
02335 
02336     /*
02337      * msgSecurityModel 
02338      */
02339     sec_model = pdu->securityModel;
02340     DEBUGDUMPHEADER("send", "msgSecurityModel");
02341     cp = asn_build_int(cp, out_length,
02342                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02343                                  ASN_INTEGER), &sec_model,
02344                        sizeof(sec_model));
02345     DEBUGINDENTADD(-4);         /* return from global data indent */
02346     if (cp == NULL)
02347         return NULL;
02348 
02349 
02350     /*
02351      * insert actual length of globalData
02352      */
02353     pb = asn_build_sequence(global_hdr, out_length,
02354                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
02355                             cp - global_hdr_e);
02356     if (pb == NULL)
02357         return NULL;
02358 
02359 
02360     /*
02361      * insert the actual length of the entire packet
02362      */
02363     pb = asn_build_sequence(packet, out_length,
02364                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
02365                             length + (cp - pb0e));
02366     if (pb == NULL)
02367         return NULL;
02368 
02369     return cp;
02370 
02371 }                               /* end snmpv3_header_build() */
02372 
02373 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02374 
02375 int
02376 snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
02377                              size_t * offset, netsnmp_session * session,
02378                              netsnmp_pdu *pdu)
02379 {
02380     size_t          start_offset = *offset;
02381     u_char          msg_flags;
02382     long            max_size, sec_model;
02383     int             rc = 0;
02384 
02385     /*
02386      * msgSecurityModel.  
02387      */
02388     sec_model = pdu->securityModel;
02389     DEBUGDUMPHEADER("send", "msgSecurityModel");
02390     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
02391                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02392                                           ASN_INTEGER), &sec_model,
02393                                 sizeof(sec_model));
02394     DEBUGINDENTLESS();
02395     if (rc == 0) {
02396         return 0;
02397     }
02398 
02399     /*
02400      * msgFlags.  
02401      */
02402     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
02403     DEBUGDUMPHEADER("send", "msgFlags");
02404     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
02405                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
02406                                              | ASN_OCTET_STR), &msg_flags,
02407                                    sizeof(msg_flags));
02408     DEBUGINDENTLESS();
02409     if (rc == 0) {
02410         return 0;
02411     }
02412 
02413     /*
02414      * msgMaxSize.  
02415      */
02416     max_size = session->rcvMsgMaxSize;
02417     DEBUGDUMPHEADER("send", "msgMaxSize");
02418     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
02419                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02420                                           ASN_INTEGER), &max_size,
02421                                 sizeof(max_size));
02422     DEBUGINDENTLESS();
02423     if (rc == 0) {
02424         return 0;
02425     }
02426 
02427     /*
02428      * msgID.  
02429      */
02430     DEBUGDUMPHEADER("send", "msgID");
02431     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
02432                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02433                                           ASN_INTEGER), &pdu->msgid,
02434                                 sizeof(pdu->msgid));
02435     DEBUGINDENTLESS();
02436     if (rc == 0) {
02437         return 0;
02438     }
02439 
02440     /*
02441      * Global data sequence.  
02442      */
02443     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
02444                                      (u_char) (ASN_SEQUENCE |
02445                                                ASN_CONSTRUCTOR),
02446                                      *offset - start_offset);
02447     if (rc == 0) {
02448         return 0;
02449     }
02450 
02451     /*
02452      * Store the version field - msgVersion.  
02453      */
02454     DEBUGDUMPHEADER("send", "SNMP Version Number");
02455     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
02456                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
02457                                           ASN_INTEGER),
02458                                 (long *) &pdu->version,
02459                                 sizeof(pdu->version));
02460     DEBUGINDENTLESS();
02461     return rc;
02462 }                               /* end snmpv3_header_realloc_rbuild() */
02463 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
02464 
02465 static u_char  *
02466 snmpv3_scopedPDU_header_build(netsnmp_pdu *pdu,
02467                               u_char * packet, size_t * out_length,
02468                               u_char ** spdu_e)
02469 {
02470     size_t          init_length;
02471     u_char         *scopedPdu, *pb;
02472 
02473 
02474     init_length = *out_length;
02475 
02476     pb = scopedPdu = packet;
02477     pb = asn_build_sequence(pb, out_length,
02478                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
02479     if (pb == NULL)
02480         return NULL;
02481     if (spdu_e)
02482         *spdu_e = pb;
02483 
02484     DEBUGDUMPHEADER("send", "contextEngineID");
02485     pb = asn_build_string(pb, out_length,
02486                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
02487                           pdu->contextEngineID, pdu->contextEngineIDLen);
02488     DEBUGINDENTLESS();
02489     if (pb == NULL)
02490         return NULL;
02491 
02492     DEBUGDUMPHEADER("send", "contextName");
02493     pb = asn_build_string(pb, out_length,
02494                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
02495                           (u_char *) pdu->contextName,
02496                           pdu->contextNameLen);
02497     DEBUGINDENTLESS();
02498     if (pb == NULL)
02499         return NULL;
02500 
02501     return pb;
02502 
02503 }                               /* end snmpv3_scopedPDU_header_build() */
02504 
02505 
02506 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02507 int
02508 snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
02509                                        size_t * offset, netsnmp_pdu *pdu,
02510                                        size_t body_len)
02511 {
02512     size_t          start_offset = *offset;
02513     int             rc = 0;
02514 
02515     /*
02516      * contextName.  
02517      */
02518     DEBUGDUMPHEADER("send", "contextName");
02519     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
02520                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
02521                                              | ASN_OCTET_STR),
02522                                    (u_char *) pdu->contextName,
02523                                    pdu->contextNameLen);
02524     DEBUGINDENTLESS();
02525     if (rc == 0) {
02526         return 0;
02527     }
02528 
02529     /*
02530      * contextEngineID.  
02531      */
02532     DEBUGDUMPHEADER("send", "contextEngineID");
02533     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
02534                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
02535                                              | ASN_OCTET_STR),
02536                                    pdu->contextEngineID,
02537                                    pdu->contextEngineIDLen);
02538     DEBUGINDENTLESS();
02539     if (rc == 0) {
02540         return 0;
02541     }
02542 
02543     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
02544                                      (u_char) (ASN_SEQUENCE |
02545                                                ASN_CONSTRUCTOR),
02546                                      *offset - start_offset + body_len);
02547 
02548     return rc;
02549 }                               /* end snmpv3_scopedPDU_header_realloc_rbuild() */
02550 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
02551 
02552 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02553 /*
02554  * returns 0 if success, -1 if fail, not 0 if SM build failure 
02555  */
02556 int
02557 snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
02558                              size_t * offset, netsnmp_session * session,
02559                              netsnmp_pdu *pdu, u_char * pdu_data,
02560                              size_t pdu_data_len)
02561 {
02562     u_char         *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
02563     size_t          hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
02564         0, spdu_offset = 0;
02565     size_t          body_end_offset = *offset, body_len = 0;
02566     struct snmp_secmod_def *sptr = NULL;
02567     int             rc = 0;
02568 
02569     /*
02570      * Build a scopedPDU structure into the packet buffer.  
02571      */
02572     DEBUGPRINTPDUTYPE("send", pdu->command);
02573     if (pdu_data) {
02574         while ((*pkt_len - *offset) < pdu_data_len) {
02575             if (!asn_realloc(pkt, pkt_len)) {
02576                 return -1;
02577             }
02578         }
02579 
02580         *offset += pdu_data_len;
02581         memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
02582     } else {
02583         rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
02584         if (rc == 0) {
02585             return -1;
02586         }
02587     }
02588     body_len = *offset - body_end_offset;
02589 
02590     DEBUGDUMPSECTION("send", "ScopedPdu");
02591     rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
02592                                                 pdu, body_len);
02593     if (rc == 0) {
02594         return -1;
02595     }
02596     spdu_offset = *offset;
02597     DEBUGINDENTADD(-4);         /*  Return from Scoped PDU.  */
02598 
02599     if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
02600         return -1;
02601     }
02602 
02603     rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
02604                                       session, pdu);
02605     if (rc == 0) {
02606         SNMP_FREE(hdrbuf);
02607         return -1;
02608     }
02609     hdr = hdrbuf + hdrbuf_len - hdr_offset;
02610     scoped_pdu = *pkt + *pkt_len - spdu_offset;
02611 
02612     /*
02613      * Call the security module to possibly encrypt and authenticate the
02614      * message---the entire message to transmitted on the wire is returned.  
02615      */
02616 
02617     sptr = find_sec_mod(pdu->securityModel);
02618     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
02619     if (sptr && sptr->encode_reverse) {
02620         struct snmp_secmod_outgoing_params parms;
02621 
02622         parms.msgProcModel = pdu->msgParseModel;
02623         parms.globalData = hdr;
02624         parms.globalDataLen = hdr_offset;
02625         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
02626         parms.secModel = pdu->securityModel;
02627         parms.secEngineID = pdu->securityEngineID;
02628         parms.secEngineIDLen = pdu->securityEngineIDLen;
02629         parms.secName = pdu->securityName;
02630         parms.secNameLen = pdu->securityNameLen;
02631         parms.secLevel = pdu->securityLevel;
02632         parms.scopedPdu = scoped_pdu;
02633         parms.scopedPduLen = spdu_offset;
02634         parms.secStateRef = pdu->securityStateRef;
02635         parms.wholeMsg = pkt;
02636         parms.wholeMsgLen = pkt_len;
02637         parms.wholeMsgOffset = offset;
02638         parms.session = session;
02639         parms.pdu = pdu;
02640 
02641         rc = (*sptr->encode_reverse) (&parms);
02642     } else {
02643         if (!sptr) {
02644             snmp_log(LOG_ERR,
02645                      "no such security service available: %d\n",
02646                      pdu->securityModel);
02647         } else if (!sptr->encode_reverse) {
02648             snmp_log(LOG_ERR,
02649                      "security service %d doesn't support reverse encoding.\n",
02650                      pdu->securityModel);
02651         }
02652         rc = -1;
02653     }
02654 
02655     DEBUGINDENTLESS();
02656     SNMP_FREE(hdrbuf);
02657     return rc;
02658 }                               /* end snmpv3_packet_realloc_rbuild() */
02659 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
02660 
02661 /*
02662  * returns 0 if success, -1 if fail, not 0 if SM build failure 
02663  */
02664 int
02665 snmpv3_packet_build(netsnmp_session * session, netsnmp_pdu *pdu,
02666                     u_char * packet, size_t * out_length,
02667                     u_char * pdu_data, size_t pdu_data_len)
02668 {
02669     u_char         *global_data, *sec_params, *spdu_hdr_e;
02670     size_t          global_data_len, sec_params_len;
02671     u_char          spdu_buf[SNMP_MAX_MSG_SIZE];
02672     size_t          spdu_buf_len, spdu_len;
02673     u_char         *cp;
02674     int             result;
02675     struct snmp_secmod_def *sptr;
02676 
02677     global_data = packet;
02678 
02679     /*
02680      * build the headers for the packet, returned addr = start of secParams
02681      */
02682     sec_params = snmpv3_header_build(session, pdu, global_data,
02683                                      out_length, 0, NULL);
02684     if (sec_params == NULL)
02685         return -1;
02686     global_data_len = sec_params - global_data;
02687     sec_params_len = *out_length;       /* length left in packet buf for sec_params */
02688 
02689 
02690     /*
02691      * build a scopedPDU structure into spdu_buf
02692      */
02693     spdu_buf_len = SNMP_MAX_MSG_SIZE;
02694     DEBUGDUMPSECTION("send", "ScopedPdu");
02695     cp = snmpv3_scopedPDU_header_build(pdu, spdu_buf, &spdu_buf_len,
02696                                        &spdu_hdr_e);
02697     if (cp == NULL)
02698         return -1;
02699 
02700     /*
02701      * build the PDU structure onto the end of spdu_buf 
02702      */
02703     DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
02704     if (pdu_data) {
02705         memcpy(cp, pdu_data, pdu_data_len);
02706         cp += pdu_data_len;
02707     } else {
02708         cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
02709         if (cp == NULL)
02710             return -1;
02711     }
02712     DEBUGINDENTADD(-4);         /* return from Scoped PDU */
02713 
02714     /*
02715      * re-encode the actual ASN.1 length of the scopedPdu
02716      */
02717     spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
02718     spdu_buf_len = SNMP_MAX_MSG_SIZE;
02719     if (asn_build_sequence(spdu_buf, &spdu_buf_len,
02720                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
02721                            spdu_len) == NULL)
02722         return -1;
02723     spdu_len = cp - spdu_buf;   /* the length of the entire scopedPdu */
02724 
02725 
02726     /*
02727      * call the security module to possibly encrypt and authenticate the
02728      * message - the entire message to transmitted on the wire is returned
02729      */
02730     cp = NULL;
02731     *out_length = SNMP_MAX_MSG_SIZE;
02732     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
02733     sptr = find_sec_mod(pdu->securityModel);
02734     if (sptr && sptr->encode_forward) {
02735         struct snmp_secmod_outgoing_params parms;
02736         parms.msgProcModel = pdu->msgParseModel;
02737         parms.globalData = global_data;
02738         parms.globalDataLen = global_data_len;
02739         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
02740         parms.secModel = pdu->securityModel;
02741         parms.secEngineID = pdu->securityEngineID;
02742         parms.secEngineIDLen = pdu->securityEngineIDLen;
02743         parms.secName = pdu->securityName;
02744         parms.secNameLen = pdu->securityNameLen;
02745         parms.secLevel = pdu->securityLevel;
02746         parms.scopedPdu = spdu_buf;
02747         parms.scopedPduLen = spdu_len;
02748         parms.secStateRef = pdu->securityStateRef;
02749         parms.secParams = sec_params;
02750         parms.secParamsLen = &sec_params_len;
02751         parms.wholeMsg = &cp;
02752         parms.wholeMsgLen = out_length;
02753         parms.session = session;
02754         parms.pdu = pdu;
02755         result = (*sptr->encode_forward) (&parms);
02756     } else {
02757         if (!sptr) {
02758             snmp_log(LOG_ERR, "no such security service available: %d\n",
02759                      pdu->securityModel);
02760         } else if (!sptr->encode_forward) {
02761             snmp_log(LOG_ERR,
02762                      "security service %d doesn't support forward out encoding.\n",
02763                      pdu->securityModel);
02764         }
02765         result = -1;
02766     }
02767     DEBUGINDENTLESS();
02768     return result;
02769 
02770 }                               /* end snmpv3_packet_build() */
02771 
02772 
02773 /*
02774  * Takes a session and a pdu and serializes the ASN PDU into the area
02775  * pointed to by *pkt.  *pkt_len is the size of the data area available.
02776  * Returns the length of the completed packet in *offset.  If any errors
02777  * occur, -1 is returned.  If all goes well, 0 is returned.
02778  */
02779 
02780 static int
02781 _snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
02782             netsnmp_session * session, netsnmp_pdu *pdu)
02783 {
02784 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
02785     u_char         *h0e = 0;
02786     size_t          start_offset = *offset;
02787     long            version;
02788     int             rc = 0;
02789 #endif /* support for community based SNMP */
02790     
02791     u_char         *h0, *h1;
02792     u_char         *cp;
02793     size_t          length;
02794 
02795     session->s_snmp_errno = 0;
02796     session->s_errno = 0;
02797 
02798     if (pdu->version == SNMP_VERSION_3) {
02799         return snmpv3_build(pkt, pkt_len, offset, session, pdu);
02800     }
02801 
02802     switch (pdu->command) {
02803     case SNMP_MSG_RESPONSE:
02804         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
02805         /*
02806          * Fallthrough 
02807          */
02808     case SNMP_MSG_GET:
02809     case SNMP_MSG_GETNEXT:
02810     case SNMP_MSG_SET:
02811         /*
02812          * all versions support these PDU types 
02813          */
02814         /*
02815          * initialize defaulted PDU fields 
02816          */
02817 
02818         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
02819             pdu->errstat = 0;
02820         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
02821             pdu->errindex = 0;
02822         break;
02823 
02824     case SNMP_MSG_TRAP2:
02825         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
02826         /*
02827          * Fallthrough 
02828          */
02829     case SNMP_MSG_INFORM:
02830 #ifndef NETSNMP_DISABLE_SNMPV1
02831         /*
02832          * not supported in SNMPv1 and SNMPsec 
02833          */
02834         if (pdu->version == SNMP_VERSION_1) {
02835             session->s_snmp_errno = SNMPERR_V2_IN_V1;
02836             return -1;
02837         }
02838 #endif
02839         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
02840             pdu->errstat = 0;
02841         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
02842             pdu->errindex = 0;
02843         break;
02844 
02845     case SNMP_MSG_GETBULK:
02846         /*
02847          * not supported in SNMPv1 and SNMPsec 
02848          */
02849 #ifndef NETSNMP_DISABLE_SNMPV1
02850         if (pdu->version == SNMP_VERSION_1) {
02851             session->s_snmp_errno = SNMPERR_V2_IN_V1;
02852             return -1;
02853         }
02854 #endif
02855         if (pdu->max_repetitions < 0) {
02856             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
02857             return -1;
02858         }
02859         if (pdu->non_repeaters < 0) {
02860             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
02861             return -1;
02862         }
02863         break;
02864 
02865     case SNMP_MSG_TRAP:
02866         /*
02867          * *only* supported in SNMPv1 and SNMPsec 
02868          */
02869 #ifndef NETSNMP_DISABLE_SNMPV1
02870         if (pdu->version != SNMP_VERSION_1) {
02871             session->s_snmp_errno = SNMPERR_V1_IN_V2;
02872             return -1;
02873         }
02874 #endif
02875         /*
02876          * initialize defaulted Trap PDU fields 
02877          */
02878         pdu->reqid = 1;         /* give a bogus non-error reqid for traps */
02879         if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
02880             pdu->enterprise = (oid *) malloc(sizeof(DEFAULT_ENTERPRISE));
02881             if (pdu->enterprise == NULL) {
02882                 session->s_snmp_errno = SNMPERR_MALLOC;
02883                 return -1;
02884             }
02885             memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
02886                     sizeof(DEFAULT_ENTERPRISE));
02887             pdu->enterprise_length =
02888                 sizeof(DEFAULT_ENTERPRISE) / sizeof(oid);
02889         }
02890         if (pdu->time == SNMP_DEFAULT_TIME)
02891             pdu->time = DEFAULT_TIME;
02892         /*
02893          * don't expect a response 
02894          */
02895         pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
02896         break;
02897 
02898     case SNMP_MSG_REPORT:      /* SNMPv3 only */
02899     default:
02900         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
02901         return -1;
02902     }
02903 
02904     /*
02905      * save length 
02906      */
02907     length = *pkt_len;
02908 
02909     /*
02910      * setup administrative fields based on version 
02911      */
02912     /*
02913      * build the message wrapper and all the administrative fields
02914      * upto the PDU sequence
02915      * (note that actual length of message will be inserted later) 
02916      */
02917     h0 = *pkt;
02918     switch (pdu->version) {
02919 #ifndef NETSNMP_DISABLE_SNMPV1
02920     case SNMP_VERSION_1:
02921 #endif
02922 #ifndef NETSNMP_DISABLE_SNMPV2C
02923     case SNMP_VERSION_2c:
02924 #endif
02925 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
02926 #ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
02927         if (pdu->community_len == 0) {
02928             if (session->community_len == 0) {
02929                 session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
02930                 return -1;
02931             }
02932             pdu->community = (u_char *) malloc(session->community_len);
02933             if (pdu->community == NULL) {
02934                 session->s_snmp_errno = SNMPERR_MALLOC;
02935                 return -1;
02936             }
02937             memmove(pdu->community,
02938                     session->community, session->community_len);
02939             pdu->community_len = session->community_len;
02940         }
02941 #else                           /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
02942         if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
02943             /*
02944              * copy session community exactly to pdu community 
02945              */
02946             if (0 == session->community_len) {
02947                 SNMP_FREE(pdu->community);
02948                 pdu->community = NULL;
02949             } else if (pdu->community_len == session->community_len) {
02950                 memmove(pdu->community,
02951                         session->community, session->community_len);
02952             } else {
02953                 SNMP_FREE(pdu->community);
02954                 pdu->community = (u_char *) malloc(session->community_len);
02955                 if (pdu->community == NULL) {
02956                     session->s_snmp_errno = SNMPERR_MALLOC;
02957                     return -1;
02958                 }
02959                 memmove(pdu->community,
02960                         session->community, session->community_len);
02961             }
02962             pdu->community_len = session->community_len;
02963         }
02964 #endif                          /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
02965 
02966         DEBUGMSGTL(("snmp_send", "Building SNMPv%d message...\n",
02967                     (1 + pdu->version)));
02968 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02969         if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
02970             DEBUGPRINTPDUTYPE("send", pdu->command);
02971             rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
02972             if (rc == 0) {
02973                 return -1;
02974             }
02975 
02976             DEBUGDUMPHEADER("send", "Community String");
02977             rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
02978                                            (u_char) (ASN_UNIVERSAL |
02979                                                      ASN_PRIMITIVE |
02980                                                      ASN_OCTET_STR),
02981                                            pdu->community,
02982                                            pdu->community_len);
02983             DEBUGINDENTLESS();
02984             if (rc == 0) {
02985                 return -1;
02986             }
02987 
02988 
02989             /*
02990              * Store the version field.  
02991              */
02992             DEBUGDUMPHEADER("send", "SNMP Version Number");
02993 
02994             version = pdu->version;
02995             rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
02996                                         (u_char) (ASN_UNIVERSAL |
02997                                                   ASN_PRIMITIVE |
02998                                                   ASN_INTEGER),
02999                                         (long *) &version,
03000                                         sizeof(version));
03001             DEBUGINDENTLESS();
03002             if (rc == 0) {
03003                 return -1;
03004             }
03005 
03006             /*
03007              * Build the final sequence.  
03008              */
03009 #ifndef NETSNMP_DISABLE_SNMPV1
03010             if (pdu->version == SNMP_VERSION_1) {
03011                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
03012             } else {
03013 #endif
03014                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
03015 #ifndef NETSNMP_DISABLE_SNMPV1
03016             }
03017 #endif
03018             rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
03019                                              (u_char) (ASN_SEQUENCE |
03020                                                        ASN_CONSTRUCTOR),
03021                                              *offset - start_offset);
03022             DEBUGINDENTLESS();
03023 
03024             if (rc == 0) {
03025                 return -1;
03026             }
03027             return 0;
03028         } else {
03029 
03030 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
03031             /*
03032              * Save current location and build SEQUENCE tag and length
03033              * placeholder for SNMP message sequence
03034              * (actual length will be inserted later) 
03035              */
03036             cp = asn_build_sequence(*pkt, pkt_len,
03037                                     (u_char) (ASN_SEQUENCE |
03038                                               ASN_CONSTRUCTOR), 0);
03039             if (cp == NULL) {
03040                 return -1;
03041             }
03042             h0e = cp;
03043 
03044 #ifndef NETSNMP_DISABLE_SNMPV1
03045             if (pdu->version == SNMP_VERSION_1) {
03046                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
03047             } else {
03048 #endif
03049                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
03050 #ifndef NETSNMP_DISABLE_SNMPV1
03051             }
03052 #endif
03053 
03054             /*
03055              * store the version field 
03056              */
03057             DEBUGDUMPHEADER("send", "SNMP Version Number");
03058 
03059             version = pdu->version;
03060             cp = asn_build_int(cp, pkt_len,
03061                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03062                                          ASN_INTEGER), (long *) &version,
03063                                sizeof(version));
03064             DEBUGINDENTLESS();
03065             if (cp == NULL)
03066                 return -1;
03067 
03068             /*
03069              * store the community string 
03070              */
03071             DEBUGDUMPHEADER("send", "Community String");
03072             cp = asn_build_string(cp, pkt_len,
03073                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03074                                             ASN_OCTET_STR), pdu->community,
03075                                   pdu->community_len);
03076             DEBUGINDENTLESS();
03077             if (cp == NULL)
03078                 return -1;
03079             break;
03080 
03081 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
03082         }
03083 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
03084         break;
03085 #endif /* support for community based SNMP */
03086     case SNMP_VERSION_2p:
03087     case SNMP_VERSION_sec:
03088     case SNMP_VERSION_2u:
03089     case SNMP_VERSION_2star:
03090     default:
03091         session->s_snmp_errno = SNMPERR_BAD_VERSION;
03092         return -1;
03093     }
03094 
03095     h1 = cp;
03096     DEBUGPRINTPDUTYPE("send", pdu->command);
03097     cp = snmp_pdu_build(pdu, cp, pkt_len);
03098     DEBUGINDENTADD(-4);         /* return from entire v1/v2c message */
03099     if (cp == NULL)
03100         return -1;
03101 
03102     /*
03103      * insert the actual length of the message sequence 
03104      */
03105     switch (pdu->version) {
03106 #ifndef NETSNMP_DISABLE_SNMPV1
03107     case SNMP_VERSION_1:
03108 #endif
03109 #ifndef NETSNMP_DISABLE_SNMPV2C
03110     case SNMP_VERSION_2c:
03111 #endif
03112 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
03113         asn_build_sequence(*pkt, &length,
03114                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
03115                            cp - h0e);
03116         break;
03117 #endif /* support for community based SNMP */
03118 
03119     case SNMP_VERSION_2p:
03120     case SNMP_VERSION_sec:
03121     case SNMP_VERSION_2u:
03122     case SNMP_VERSION_2star:
03123     default:
03124         session->s_snmp_errno = SNMPERR_BAD_VERSION;
03125         return -1;
03126     }
03127     *pkt_len = cp - *pkt;
03128     return 0;
03129 }
03130 
03131 int
03132 snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
03133            netsnmp_session * pss, netsnmp_pdu *pdu)
03134 {
03135     int             rc;
03136     rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
03137     if (rc) {
03138         if (!pss->s_snmp_errno) {
03139             snmp_log(LOG_ERR, "snmp_build: unknown failure");
03140             pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
03141         }
03142         SET_SNMP_ERROR(pss->s_snmp_errno);
03143         rc = -1;
03144     }
03145     return rc;
03146 }
03147 
03148 /*
03149  * on error, returns NULL (likely an encoding problem). 
03150  */
03151 u_char         *
03152 snmp_pdu_build(netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
03153 {
03154     u_char         *h1, *h1e, *h2, *h2e;
03155     netsnmp_variable_list *vp;
03156     size_t          length;
03157 
03158     length = *out_length;
03159     /*
03160      * Save current location and build PDU tag and length placeholder
03161      * (actual length will be inserted later) 
03162      */
03163     h1 = cp;
03164     cp = asn_build_sequence(cp, out_length, (u_char) pdu->command, 0);
03165     if (cp == NULL)
03166         return NULL;
03167     h1e = cp;
03168 
03169     /*
03170      * store fields in the PDU preceeding the variable-bindings sequence 
03171      */
03172     if (pdu->command != SNMP_MSG_TRAP) {
03173         /*
03174          * PDU is not an SNMPv1 trap 
03175          */
03176 
03177         DEBUGDUMPHEADER("send", "request_id");
03178         /*
03179          * request id 
03180          */
03181         cp = asn_build_int(cp, out_length,
03182                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03183                                      ASN_INTEGER), &pdu->reqid,
03184                            sizeof(pdu->reqid));
03185         DEBUGINDENTLESS();
03186         if (cp == NULL)
03187             return NULL;
03188 
03189         /*
03190          * error status (getbulk non-repeaters) 
03191          */
03192         DEBUGDUMPHEADER("send", "error status");
03193         cp = asn_build_int(cp, out_length,
03194                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03195                                      ASN_INTEGER), &pdu->errstat,
03196                            sizeof(pdu->errstat));
03197         DEBUGINDENTLESS();
03198         if (cp == NULL)
03199             return NULL;
03200 
03201         /*
03202          * error index (getbulk max-repetitions) 
03203          */
03204         DEBUGDUMPHEADER("send", "error index");
03205         cp = asn_build_int(cp, out_length,
03206                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03207                                      ASN_INTEGER), &pdu->errindex,
03208                            sizeof(pdu->errindex));
03209         DEBUGINDENTLESS();
03210         if (cp == NULL)
03211             return NULL;
03212     } else {
03213         /*
03214          * an SNMPv1 trap PDU 
03215          */
03216 
03217         /*
03218          * enterprise 
03219          */
03220         DEBUGDUMPHEADER("send", "enterprise OBJID");
03221         cp = asn_build_objid(cp, out_length,
03222                              (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03223                                        ASN_OBJECT_ID),
03224                              (oid *) pdu->enterprise,
03225                              pdu->enterprise_length);
03226         DEBUGINDENTLESS();
03227         if (cp == NULL)
03228             return NULL;
03229 
03230         /*
03231          * agent-addr 
03232          */
03233         DEBUGDUMPHEADER("send", "agent Address");
03234         cp = asn_build_string(cp, out_length,
03235                               (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
03236                               (u_char *) pdu->agent_addr, 4);
03237         DEBUGINDENTLESS();
03238         if (cp == NULL)
03239             return NULL;
03240 
03241         /*
03242          * generic trap 
03243          */
03244         DEBUGDUMPHEADER("send", "generic trap number");
03245         cp = asn_build_int(cp, out_length,
03246                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03247                                      ASN_INTEGER),
03248                            (long *) &pdu->trap_type,
03249                            sizeof(pdu->trap_type));
03250         DEBUGINDENTLESS();
03251         if (cp == NULL)
03252             return NULL;
03253 
03254         /*
03255          * specific trap 
03256          */
03257         DEBUGDUMPHEADER("send", "specific trap number");
03258         cp = asn_build_int(cp, out_length,
03259                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
03260                                      ASN_INTEGER),
03261                            (long *) &pdu->specific_type,
03262                            sizeof(pdu->specific_type));
03263         DEBUGINDENTLESS();
03264         if (cp == NULL)
03265             return NULL;
03266 
03267         /*
03268          * timestamp  
03269          */
03270         DEBUGDUMPHEADER("send", "timestamp");
03271         cp = asn_build_unsigned_int(cp, out_length,
03272                                     (u_char) (ASN_TIMETICKS |
03273                                               ASN_PRIMITIVE), &pdu->time,
03274                                     sizeof(pdu->time));
03275         DEBUGINDENTLESS();
03276         if (cp == NULL)
03277             return NULL;
03278     }
03279 
03280     /*
03281      * Save current location and build SEQUENCE tag and length placeholder
03282      * for variable-bindings sequence
03283      * (actual length will be inserted later) 
03284      */
03285     h2 = cp;
03286     cp = asn_build_sequence(cp, out_length,
03287                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
03288     if (cp == NULL)
03289         return NULL;
03290     h2e = cp;
03291 
03292     /*
03293      * Store variable-bindings 
03294      */
03295     DEBUGDUMPSECTION("send", "VarBindList");
03296     for (vp = pdu->variables; vp; vp = vp->next_variable) {
03297         DEBUGDUMPSECTION("send", "VarBind");
03298         cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
03299                                vp->val_len, (u_char *) vp->val.string,
03300                                out_length);
03301         DEBUGINDENTLESS();
03302         if (cp == NULL)
03303             return NULL;
03304     }
03305     DEBUGINDENTLESS();
03306 
03307     /*
03308      * insert actual length of variable-bindings sequence 
03309      */
03310     asn_build_sequence(h2, &length,
03311                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
03312                        cp - h2e);
03313 
03314     /*
03315      * insert actual length of PDU sequence 
03316      */
03317     asn_build_sequence(h1, &length, (u_char) pdu->command, cp - h1e);
03318 
03319     return cp;
03320 }
03321 
03322 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
03323 /*
03324  * On error, returns 0 (likely an encoding problem).  
03325  */
03326 int
03327 snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
03328                         netsnmp_pdu *pdu)
03329 {
03330 #ifndef VPCACHE_SIZE
03331 #define VPCACHE_SIZE 50
03332 #endif
03333     netsnmp_variable_list *vpcache[VPCACHE_SIZE];
03334     netsnmp_variable_list *vp, *tmpvp;
03335     size_t          start_offset = *offset;
03336     int             i, wrapped = 0, notdone, final, rc = 0;
03337 
03338     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "starting\n"));
03339     for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
03340          vp = vp->next_variable, i--) {
03341         if (i < 0) {
03342             wrapped = notdone = 1;
03343             i = VPCACHE_SIZE - 1;
03344             DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
03345         }
03346         vpcache[i] = vp;
03347     }
03348     final = i + 1;
03349 
03350     do {
03351         for (i = final; i < VPCACHE_SIZE; i++) {
03352             vp = vpcache[i];
03353             DEBUGDUMPSECTION("send", "VarBind");
03354             rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
03355                                             vp->name, &vp->name_length,
03356                                             vp->type,
03357                                             (u_char *) vp->val.string,
03358                                             vp->val_len);
03359             DEBUGINDENTLESS();
03360             if (rc == 0) {
03361                 return 0;
03362             }
03363         }
03364 
03365         DEBUGINDENTLESS();
03366         if (wrapped) {
03367             notdone = 1;
03368             for (i = 0; i < final; i++) {
03369                 vp = vpcache[i];
03370                 DEBUGDUMPSECTION("send", "VarBind");
03371                 rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
03372                                                 vp->name, &vp->name_length,
03373                                                 vp->type,
03374                                                 (u_char *) vp->val.string,
03375                                                 vp->val_len);
03376                 DEBUGINDENTLESS();
03377                 if (rc == 0) {
03378                     return 0;
03379                 }
03380             }
03381 
03382             if (final == 0) {
03383                 tmpvp = vpcache[VPCACHE_SIZE - 1];
03384             } else {
03385                 tmpvp = vpcache[final - 1];
03386             }
03387             wrapped = 0;
03388 
03389             for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
03390                  vp && vp != tmpvp; vp = vp->next_variable, i--) {
03391                 if (i < 0) {
03392                     wrapped = 1;
03393                     i = VPCACHE_SIZE - 1;
03394                     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
03395                 }
03396                 vpcache[i] = vp;
03397             }
03398             final = i + 1;
03399         } else {
03400             notdone = 0;
03401         }
03402     } while (notdone);
03403 
03404     /*
03405      * Save current location and build SEQUENCE tag and length placeholder for
03406      * variable-bindings sequence (actual length will be inserted later).  
03407      */
03408 
03409     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
03410                                      (u_char) (ASN_SEQUENCE |
03411                                                ASN_CONSTRUCTOR),
03412                                      *offset - start_offset);
03413 
03414     /*
03415      * Store fields in the PDU preceeding the variable-bindings sequence.  
03416      */
03417     if (pdu->command != SNMP_MSG_TRAP) {
03418         /*
03419          * Error index (getbulk max-repetitions).  
03420          */
03421         DEBUGDUMPHEADER("send", "error index");
03422         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
03423                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
03424                                               | ASN_INTEGER),
03425                                     &pdu->errindex, sizeof(pdu->errindex));
03426         DEBUGINDENTLESS();
03427         if (rc == 0) {
03428             return 0;
03429         }
03430 
03431         /*
03432          * Error status (getbulk non-repeaters).  
03433          */
03434         DEBUGDUMPHEADER("send", "error status");
03435         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
03436                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
03437                                               | ASN_INTEGER),
03438                                     &pdu->errstat, sizeof(pdu->errstat));
03439         DEBUGINDENTLESS();
03440         if (rc == 0) {
03441             return 0;
03442         }
03443 
03444         /*
03445          * Request ID.  
03446          */
03447         DEBUGDUMPHEADER("send", "request_id");
03448         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
03449                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
03450                                               | ASN_INTEGER), &pdu->reqid,
03451                                     sizeof(pdu->reqid));
03452         DEBUGINDENTLESS();
03453         if (rc == 0) {
03454             return 0;
03455         }
03456     } else {
03457         /*
03458          * An SNMPv1 trap PDU.  
03459          */
03460 
03461         /*
03462          * Timestamp.  
03463          */
03464         DEBUGDUMPHEADER("send", "timestamp");
03465         rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
03466                                              (u_char) (ASN_TIMETICKS |
03467                                                        ASN_PRIMITIVE),
03468                                              &pdu->time,
03469                                              sizeof(pdu->time));
03470         DEBUGINDENTLESS();
03471         if (rc == 0) {
03472             return 0;
03473         }
03474 
03475         /*
03476          * Specific trap.  
03477          */
03478         DEBUGDUMPHEADER("send", "specific trap number");
03479         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
03480                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
03481                                               | ASN_INTEGER),
03482                                     (long *) &pdu->specific_type,
03483                                     sizeof(pdu->specific_type));
03484         DEBUGINDENTLESS();
03485         if (rc == 0) {
03486             return 0;
03487         }
03488 
03489         /*
03490          * Generic trap.  
03491          */
03492         DEBUGDUMPHEADER("send", "generic trap number");
03493         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
03494                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
03495                                               | ASN_INTEGER),
03496                                     (long *) &pdu->trap_type,
03497                                     sizeof(pdu->trap_type));
03498         DEBUGINDENTLESS();
03499         if (rc == 0) {
03500             return 0;
03501         }
03502 
03503         /*
03504          * Agent-addr.  
03505          */
03506         DEBUGDUMPHEADER("send", "agent Address");
03507         rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
03508                                        (u_char) (ASN_IPADDRESS |
03509                                                  ASN_PRIMITIVE),
03510                                        (u_char *) pdu->agent_addr, 4);
03511         DEBUGINDENTLESS();
03512         if (rc == 0) {
03513             return 0;
03514         }
03515 
03516         /*
03517          * Enterprise.  
03518          */
03519         DEBUGDUMPHEADER("send", "enterprise OBJID");
03520         rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
03521                                       (u_char) (ASN_UNIVERSAL |
03522                                                 ASN_PRIMITIVE |
03523                                                 ASN_OBJECT_ID),
03524                                       (oid *) pdu->enterprise,
03525                                       pdu->enterprise_length);
03526         DEBUGINDENTLESS();
03527         if (rc == 0) {
03528             return 0;
03529         }
03530     }
03531 
03532     /*
03533      * Build the PDU sequence.  
03534      */
03535     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
03536                                      (u_char) pdu->command,
03537                                      *offset - start_offset);
03538     return rc;
03539 }
03540 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
03541 
03542 /*
03543  * Parses the packet received to determine version, either directly
03544  * from packets version field or inferred from ASN.1 construct.
03545  */
03546 static int
03547 snmp_parse_version(u_char * data, size_t length)
03548 {
03549     u_char          type;
03550     long            version = SNMPERR_BAD_VERSION;
03551 
03552     data = asn_parse_sequence(data, &length, &type,
03553                               (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
03554     if (data) {
03555         data =
03556             asn_parse_int(data, &length, &type, &version, sizeof(version));
03557         if (!data || type != ASN_INTEGER) {
03558             return SNMPERR_BAD_VERSION;
03559         }
03560     }
03561     return version;
03562 }
03563 
03564 
03565 int
03566 snmpv3_parse(netsnmp_pdu *pdu,
03567              u_char * data,
03568              size_t * length,
03569              u_char ** after_header, netsnmp_session * sess)
03570 {
03571     u_char          type, msg_flags;
03572     long            ver, msg_max_size, msg_sec_model;
03573     size_t          max_size_response;
03574     u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
03575     size_t          tmp_buf_len;
03576     u_char          pdu_buf[SNMP_MAX_MSG_SIZE];
03577     u_char         *mallocbuf = NULL;
03578     size_t          pdu_buf_len = SNMP_MAX_MSG_SIZE;
03579     u_char         *sec_params;
03580     u_char         *msg_data;
03581     u_char         *cp;
03582     size_t          asn_len, msg_len;
03583     int             ret, ret_val;
03584     struct snmp_secmod_def *sptr;
03585 
03586 
03587     msg_data = data;
03588     msg_len = *length;
03589 
03590 
03591     /*
03592      * message is an ASN.1 SEQUENCE  
03593      */
03594     DEBUGDUMPSECTION("recv", "SNMPv3 Message");
03595     data = asn_parse_sequence(data, length, &type,
03596                               (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
03597     if (data == NULL) {
03598         /*
03599          * error msg detail is set 
03600          */
03601         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03602         DEBUGINDENTLESS();
03603         return SNMPERR_ASN_PARSE_ERR;
03604     }
03605 
03606     /*
03607      * parse msgVersion  
03608      */
03609     DEBUGDUMPHEADER("recv", "SNMP Version Number");
03610     data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
03611     DEBUGINDENTLESS();
03612     if (data == NULL) {
03613         ERROR_MSG("bad parse of version");
03614         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03615         DEBUGINDENTLESS();
03616         return SNMPERR_ASN_PARSE_ERR;
03617     }
03618     pdu->version = ver;
03619 
03620     /*
03621      * parse msgGlobalData sequence  
03622      */
03623     cp = data;
03624     asn_len = *length;
03625     DEBUGDUMPSECTION("recv", "msgGlobalData");
03626     data = asn_parse_sequence(data, &asn_len, &type,
03627                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
03628                               "msgGlobalData");
03629     if (data == NULL) {
03630         /*
03631          * error msg detail is set 
03632          */
03633         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03634         DEBUGINDENTADD(-4);
03635         return SNMPERR_ASN_PARSE_ERR;
03636     }
03637     *length -= data - cp;       /* subtract off the length of the header */
03638 
03639     /*
03640      * msgID 
03641      */
03642     DEBUGDUMPHEADER("recv", "msgID");
03643     data =
03644         asn_parse_int(data, length, &type, &pdu->msgid,
03645                       sizeof(pdu->msgid));
03646     DEBUGINDENTLESS();
03647     if (data == NULL || type != ASN_INTEGER) {
03648         ERROR_MSG("error parsing msgID");
03649         DEBUGINDENTADD(-4);
03650         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03651         return SNMPERR_ASN_PARSE_ERR;
03652     }
03653 
03654     /*
03655      * Check the msgID we received is a legal value.  If not, then increment
03656      * snmpInASNParseErrs and return the appropriate error (see RFC 2572,
03657      * para. 7.2, section 2 -- note that a bad msgID means that the received
03658      * message is NOT a serialiization of an SNMPv3Message, since the msgID
03659      * field is out of bounds).  
03660      */
03661 
03662     if (pdu->msgid < 0 || pdu->msgid > 0x7fffffff) {
03663         snmp_log(LOG_ERR, "Received bad msgID (%ld %s %s).\n", pdu->msgid,
03664                  (pdu->msgid < 0) ? "<" : ">",
03665                  (pdu->msgid < 0) ? "0" : "2^31 - 1");
03666         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03667         DEBUGINDENTADD(-4);
03668         return SNMPERR_ASN_PARSE_ERR;
03669     }
03670 
03671     /*
03672      * msgMaxSize 
03673      */
03674     DEBUGDUMPHEADER("recv", "msgMaxSize");
03675     data = asn_parse_int(data, length, &type, &msg_max_size,
03676                          sizeof(msg_max_size));
03677     DEBUGINDENTLESS();
03678     if (data == NULL || type != ASN_INTEGER) {
03679         ERROR_MSG("error parsing msgMaxSize");
03680         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03681         DEBUGINDENTADD(-4);
03682         return SNMPERR_ASN_PARSE_ERR;
03683     }
03684 
03685     /*
03686      * Check the msgMaxSize we received is a legal value.  If not, then
03687      * increment snmpInASNParseErrs and return the appropriate error (see RFC
03688      * 2572, para. 7.2, section 2 -- note that a bad msgMaxSize means that the
03689      * received message is NOT a serialiization of an SNMPv3Message, since the
03690      * msgMaxSize field is out of bounds).
03691      * 
03692      * Note we store the msgMaxSize on a per-session basis which also seems
03693      * reasonable; it could vary from PDU to PDU but that would be strange
03694      * (also since we deal with a PDU at a time, it wouldn't make any
03695      * difference to our responses, if any).  
03696      */
03697 
03698     if (msg_max_size < 484) {
03699         snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu < 484).\n",
03700                  msg_max_size);
03701         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03702         DEBUGINDENTADD(-4);
03703         return SNMPERR_ASN_PARSE_ERR;
03704     } else if (msg_max_size > 0x7fffffff) {
03705         snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu > 2^31 - 1).\n",
03706                  msg_max_size);
03707         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03708         DEBUGINDENTADD(-4);
03709         return SNMPERR_ASN_PARSE_ERR;
03710     } else {
03711         DEBUGMSGTL(("snmpv3_parse", "msgMaxSize %lu received\n",
03712                     msg_max_size));
03713         sess->sndMsgMaxSize = msg_max_size;
03714     }
03715 
03716     /*
03717      * msgFlags 
03718      */
03719     tmp_buf_len = SNMP_MAX_MSG_SIZE;
03720     DEBUGDUMPHEADER("recv", "msgFlags");
03721     data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
03722     DEBUGINDENTLESS();
03723     if (data == NULL || type != ASN_OCTET_STR || tmp_buf_len != 1) {
03724         ERROR_MSG("error parsing msgFlags");
03725         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03726         DEBUGINDENTADD(-4);
03727         return SNMPERR_ASN_PARSE_ERR;
03728     }
03729     msg_flags = *tmp_buf;
03730     if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
03731         pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
03732     else
03733         pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
03734 
03735     /*
03736      * msgSecurityModel 
03737      */
03738     DEBUGDUMPHEADER("recv", "msgSecurityModel");
03739     data = asn_parse_int(data, length, &type, &msg_sec_model,
03740                          sizeof(msg_sec_model));
03741     DEBUGINDENTADD(-4);         /* return from global data indent */
03742     if (data == NULL || type != ASN_INTEGER ||
03743         msg_sec_model < 1 || msg_sec_model > 0x7fffffff) {
03744         ERROR_MSG("error parsing msgSecurityModel");
03745         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03746         DEBUGINDENTLESS();
03747         return SNMPERR_ASN_PARSE_ERR;
03748     }
03749     sptr = find_sec_mod(msg_sec_model);
03750     if (!sptr) {
03751         snmp_log(LOG_WARNING, "unknown security model: %ld\n",
03752                  msg_sec_model);
03753         snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
03754         DEBUGINDENTLESS();
03755         return SNMPERR_UNKNOWN_SEC_MODEL;
03756     }
03757     pdu->securityModel = msg_sec_model;
03758 
03759     if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
03760         !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
03761         ERROR_MSG("invalid message, illegal msgFlags");
03762         snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
03763         DEBUGINDENTLESS();
03764         return SNMPERR_INVALID_MSG;
03765     }
03766     pdu->securityLevel = ((msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
03767                           ? ((msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
03768                              ? SNMP_SEC_LEVEL_AUTHPRIV
03769                              : SNMP_SEC_LEVEL_AUTHNOPRIV)
03770                           : SNMP_SEC_LEVEL_NOAUTH);
03771     /*
03772      * end of msgGlobalData 
03773      */
03774 
03775     /*
03776      * securtityParameters OCTET STRING begins after msgGlobalData 
03777      */
03778     sec_params = data;
03779     pdu->contextEngineID = (u_char *) calloc(1, SNMP_MAX_ENG_SIZE);
03780     pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
03781 
03782     /*
03783      * Note: there is no length limit on the msgAuthoritativeEngineID field,
03784      * although we would EXPECT it to be limited to 32 (the SnmpEngineID TC
03785      * limit).  We'll use double that here to be on the safe side.  
03786      */
03787 
03788     pdu->securityEngineID = (u_char *) calloc(1, SNMP_MAX_ENG_SIZE * 2);
03789     pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE * 2;
03790     pdu->securityName = (char *) calloc(1, SNMP_MAX_SEC_NAME_SIZE);
03791     pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
03792 
03793     if ((pdu->securityName == NULL) ||
03794         (pdu->securityEngineID == NULL) ||
03795         (pdu->contextEngineID == NULL)) {
03796         return SNMPERR_MALLOC;
03797     }
03798 
03799     if (pdu_buf_len < msg_len
03800         && pdu->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
03801         /*
03802          * space needed is larger than we have in the default buffer 
03803          */
03804         mallocbuf = (u_char *) calloc(1, msg_len);
03805         pdu_buf_len = msg_len;
03806         cp = mallocbuf;
03807     } else {
03808         memset(pdu_buf, 0, pdu_buf_len);
03809         cp = pdu_buf;
03810     }
03811 
03812     DEBUGDUMPSECTION("recv", "SM msgSecurityParameters");
03813     if (sptr->decode) {
03814         struct snmp_secmod_incoming_params parms;
03815         parms.msgProcModel = pdu->msgParseModel;
03816         parms.maxMsgSize = msg_max_size;
03817         parms.secParams = sec_params;
03818         parms.secModel = msg_sec_model;
03819         parms.secLevel = pdu->securityLevel;
03820         parms.wholeMsg = msg_data;
03821         parms.wholeMsgLen = msg_len;
03822         parms.secEngineID = pdu->securityEngineID;
03823         parms.secEngineIDLen = &pdu->securityEngineIDLen;
03824         parms.secName = pdu->securityName;
03825         parms.secNameLen = &pdu->securityNameLen;
03826         parms.scopedPdu = &cp;
03827         parms.scopedPduLen = &pdu_buf_len;
03828         parms.maxSizeResponse = &max_size_response;
03829         parms.secStateRef = &pdu->securityStateRef;
03830         parms.sess = sess;
03831         parms.pdu = pdu;
03832         parms.msg_flags = msg_flags;
03833         ret_val = (*sptr->decode) (&parms);
03834     } else {
03835         SNMP_FREE(mallocbuf);
03836         DEBUGINDENTLESS();
03837         snmp_log(LOG_WARNING, "security service %ld can't decode packets\n",
03838                  msg_sec_model);
03839         return (-1);
03840     }
03841 
03842     if (ret_val != SNMPERR_SUCCESS) {
03843         DEBUGDUMPSECTION("recv", "ScopedPDU");
03844         /*
03845          * Parse as much as possible -- though I don't see the point? [jbpn].  
03846          */
03847         if (cp) {
03848             cp = snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len);
03849         }
03850         if (cp) {
03851             DEBUGPRINTPDUTYPE("recv", *cp);
03852             snmp_pdu_parse(pdu, cp, &pdu_buf_len);
03853             DEBUGINDENTADD(-8);
03854         } else {
03855             DEBUGINDENTADD(-4);
03856         }
03857 
03858         if (mallocbuf) {
03859             SNMP_FREE(mallocbuf);
03860         }
03861         return ret_val;
03862     }
03863 
03864     /*
03865      * parse plaintext ScopedPDU sequence 
03866      */
03867     *length = pdu_buf_len;
03868     DEBUGDUMPSECTION("recv", "ScopedPDU");
03869     data = snmpv3_scopedPDU_parse(pdu, cp, length);
03870     if (data == NULL) {
03871         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03872         DEBUGINDENTADD(-4);
03873         if (mallocbuf) {
03874             SNMP_FREE(mallocbuf);
03875         }
03876         return SNMPERR_ASN_PARSE_ERR;
03877     }
03878 
03879     /*
03880      * parse the PDU.  
03881      */
03882     if (after_header != NULL) {
03883         *after_header = data;
03884         tmp_buf_len = *length;
03885     }
03886 
03887     DEBUGPRINTPDUTYPE("recv", *data);
03888     ret = snmp_pdu_parse(pdu, data, length);
03889     DEBUGINDENTADD(-8);
03890 
03891     if (after_header != NULL) {
03892         *length = tmp_buf_len;
03893     }
03894 
03895     if (ret != SNMPERR_SUCCESS) {
03896         ERROR_MSG("error parsing PDU");
03897         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
03898         if (mallocbuf) {
03899             SNMP_FREE(mallocbuf);
03900         }
03901         return SNMPERR_ASN_PARSE_ERR;
03902     }
03903 
03904     if (mallocbuf) {
03905         SNMP_FREE(mallocbuf);
03906     }
03907     return SNMPERR_SUCCESS;
03908 }                               /* end snmpv3_parse() */
03909 
03910 #define ERROR_STAT_LENGTH 11
03911 
03912 int
03913 snmpv3_make_report(netsnmp_pdu *pdu, int error)
03914 {
03915 
03916     long            ltmp;
03917     static oid      unknownSecurityLevel[] =
03918         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
03919     static oid      notInTimeWindow[] =
03920         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
03921     static oid      unknownUserName[] =
03922         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
03923     static oid      unknownEngineID[] =
03924         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
03925     static oid      wrongDigest[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
03926     static oid      decryptionError[] =
03927         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
03928     oid            *err_var;
03929     int             err_var_len;
03930     int             stat_ind;
03931     struct snmp_secmod_def *sptr;
03932 
03933     switch (error) {
03934     case SNMPERR_USM_UNKNOWNENGINEID:
03935         stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
03936         err_var = unknownEngineID;
03937         err_var_len = ERROR_STAT_LENGTH;
03938         break;
03939     case SNMPERR_USM_UNKNOWNSECURITYNAME:
03940         stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
03941         err_var = unknownUserName;
03942         err_var_len = ERROR_STAT_LENGTH;
03943         break;
03944     case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
03945         stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
03946         err_var = unknownSecurityLevel;
03947         err_var_len = ERROR_STAT_LENGTH;
03948         break;
03949     case SNMPERR_USM_AUTHENTICATIONFAILURE:
03950         stat_ind = STAT_USMSTATSWRONGDIGESTS;
03951         err_var = wrongDigest;
03952         err_var_len = ERROR_STAT_LENGTH;
03953         break;
03954     case SNMPERR_USM_NOTINTIMEWINDOW:
03955         stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
03956         err_var = notInTimeWindow;
03957         err_var_len = ERROR_STAT_LENGTH;
03958         break;
03959     case SNMPERR_USM_DECRYPTIONERROR:
03960         stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
03961         err_var = decryptionError;
03962         err_var_len = ERROR_STAT_LENGTH;
03963         break;
03964     default:
03965         return SNMPERR_GENERR;
03966     }
03967 
03968     snmp_free_varbind(pdu->variables);  /* free the current varbind */
03969 
03970     pdu->variables = NULL;
03971     SNMP_FREE(pdu->securityEngineID);
03972     pdu->securityEngineID =
03973         snmpv3_generate_engineID(&pdu->securityEngineIDLen);
03974     SNMP_FREE(pdu->contextEngineID);
03975     pdu->contextEngineID =
03976         snmpv3_generate_engineID(&pdu->contextEngineIDLen);
03977     pdu->command = SNMP_MSG_REPORT;
03978     pdu->errstat = 0;
03979     pdu->errindex = 0;
03980     SNMP_FREE(pdu->contextName);
03981     pdu->contextName = strdup("");
03982     pdu->contextNameLen = strlen(pdu->contextName);
03983 
03984     /*
03985      * reports shouldn't cache previous data. 
03986      */
03987     /*
03988      * FIX - yes they should but USM needs to follow new EoP to determine
03989      * which cached values to use 
03990      */
03991     if (pdu->securityStateRef) {
03992         sptr = find_sec_mod(pdu->securityModel);
03993         if (sptr) {
03994             if (sptr->pdu_free_state_ref) {
03995                 (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
03996             } else {
03997                 snmp_log(LOG_ERR,
03998                          "Security Model %d can't free state references\n",
03999                          pdu->securityModel);
04000             }
04001         } else {
04002             snmp_log(LOG_ERR,
04003                      "Can't find security model to free ptr: %d\n",
04004                      pdu->securityModel);
04005         }
04006         pdu->securityStateRef = NULL;
04007     }
04008 
04009     if (error == SNMPERR_USM_NOTINTIMEWINDOW) {
04010         pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
04011     } else {
04012         pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
04013     }
04014 
04015     /*
04016      * find the appropriate error counter  
04017      */
04018     ltmp = snmp_get_statistic(stat_ind);
04019 
04020     /*
04021      * return the appropriate error counter  
04022      */
04023     snmp_pdu_add_variable(pdu, err_var, err_var_len,
04024                           ASN_COUNTER, (u_char *) & ltmp, sizeof(ltmp));
04025 
04026     return SNMPERR_SUCCESS;
04027 }                               /* end snmpv3_make_report() */
04028 
04029 
04030 int
04031 snmpv3_get_report_type(netsnmp_pdu *pdu)
04032 {
04033     static oid      snmpMPDStats[] = { 1, 3, 6, 1, 6, 3, 11, 2, 1 };
04034     static oid      usmStats[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1 };
04035     netsnmp_variable_list *vp;
04036     int             rpt_type = SNMPERR_UNKNOWN_REPORT;
04037 
04038     if (pdu == NULL || pdu->variables == NULL)
04039         return rpt_type;
04040     vp = pdu->variables;
04041     if (vp->name_length == REPORT_STATS_LEN + 2) {
04042         if (memcmp(snmpMPDStats, vp->name, REPORT_STATS_LEN * sizeof(oid))
04043             == 0) {
04044             switch (vp->name[REPORT_STATS_LEN]) {
04045             case REPORT_snmpUnknownSecurityModels_NUM:
04046                 rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
04047                 break;
04048             case REPORT_snmpInvalidMsgs_NUM:
04049                 rpt_type = SNMPERR_INVALID_MSG;
04050                 break;
04051             }
04052         } else
04053             if (memcmp(usmStats, vp->name, REPORT_STATS_LEN * sizeof(oid))
04054                 == 0) {
04055             switch (vp->name[REPORT_STATS_LEN]) {
04056             case REPORT_usmStatsUnsupportedSecLevels_NUM:
04057                 rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
04058                 break;
04059             case REPORT_usmStatsNotInTimeWindows_NUM:
04060                 rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
04061                 break;
04062             case REPORT_usmStatsUnknownUserNames_NUM:
04063                 rpt_type = SNMPERR_UNKNOWN_USER_NAME;
04064                 break;
04065             case REPORT_usmStatsUnknownEngineIDs_NUM:
04066                 rpt_type = SNMPERR_UNKNOWN_ENG_ID;
04067                 break;
04068             case REPORT_usmStatsWrongDigests_NUM:
04069                 rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
04070                 break;
04071             case REPORT_usmStatsDecryptionErrors_NUM:
04072                 rpt_type = SNMPERR_DECRYPTION_ERR;
04073                 break;
04074             }
04075         }
04076     }
04077     DEBUGMSGTL(("report", "Report type: %d\n", rpt_type));
04078     return rpt_type;
04079 }
04080 
04081 /*
04082  * Parses the packet received on the input session, and places the data into
04083  * the input pdu.  length is the length of the input packet.
04084  * If any errors are encountered, -1 or USM error is returned.
04085  * Otherwise, a 0 is returned.
04086  */
04087 static int
04088 _snmp_parse(void *sessp,
04089             netsnmp_session * session,
04090             netsnmp_pdu *pdu, u_char * data, size_t length)
04091 {
04092 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
04093     u_char          community[COMMUNITY_MAX_LEN];
04094     size_t          community_length = COMMUNITY_MAX_LEN;
04095 #endif
04096     int             result = -1;
04097 
04098     session->s_snmp_errno = 0;
04099     session->s_errno = 0;
04100 
04101     /*
04102      * Ensure all incoming PDUs have a unique means of identification 
04103      * (This is not restricted to AgentX handling,
04104      * though that is where the need becomes visible)   
04105      */
04106     pdu->transid = snmp_get_next_transid();
04107 
04108     if (session->version != SNMP_DEFAULT_VERSION) {
04109         pdu->version = session->version;
04110     } else {
04111         pdu->version = snmp_parse_version(data, length);
04112     }
04113 
04114     switch (pdu->version) {
04115 #ifndef NETSNMP_DISABLE_SNMPV1
04116     case SNMP_VERSION_1:
04117 #endif
04118 #ifndef NETSNMP_DISABLE_SNMPV2C
04119     case SNMP_VERSION_2c:
04120 #endif
04121 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
04122         DEBUGMSGTL(("snmp_api", "Parsing SNMPv%d message...\n",
04123                     (1 + pdu->version)));
04124 
04125         /*
04126          * authenticates message and returns length if valid 
04127          */
04128 #ifndef NETSNMP_DISABLE_SNMPV1
04129         if (pdu->version == SNMP_VERSION_1) {
04130             DEBUGDUMPSECTION("recv", "SNMPv1 message\n");
04131         } else {
04132 #endif
04133             DEBUGDUMPSECTION("recv", "SNMPv2c message\n");
04134 #ifndef NETSNMP_DISABLE_SNMPV1
04135         }
04136 #endif
04137         data = snmp_comstr_parse(data, &length,
04138                                  community, &community_length,
04139                                  &pdu->version);
04140         if (data == NULL)
04141             return -1;
04142 
04143         if (pdu->version != session->version &&
04144             session->version != SNMP_DEFAULT_VERSION) {
04145             session->s_snmp_errno = SNMPERR_BAD_VERSION;
04146             return -1;
04147         }
04148 
04149         /*
04150          * maybe get the community string. 
04151          */
04152         pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
04153         pdu->securityModel = 
04154 #ifndef NETSNMP_DISABLE_SNMPV1
04155             (pdu->version == SNMP_VERSION_1) ? SNMP_SEC_MODEL_SNMPv1 : 
04156 #endif
04157                                                SNMP_SEC_MODEL_SNMPv2c;
04158         SNMP_FREE(pdu->community);
04159         pdu->community_len = 0;
04160         pdu->community = (u_char *) 0;
04161         if (community_length) {
04162             pdu->community_len = community_length;
04163             pdu->community = (u_char *) malloc(community_length);
04164             if (pdu->community == NULL) {
04165                 session->s_snmp_errno = SNMPERR_MALLOC;
04166                 return -1;
04167             }
04168             memmove(pdu->community, community, community_length);
04169         }
04170         if (session->authenticator) {
04171             data = session->authenticator(data, &length,
04172                                           community, community_length);
04173             if (data == NULL) {
04174                 session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
04175                 return -1;
04176             }
04177         }
04178 
04179         DEBUGDUMPSECTION("recv", "PDU");
04180         result = snmp_pdu_parse(pdu, data, &length);
04181         if (result < 0) {
04182             /*
04183              * This indicates a parse error.  
04184              */
04185             snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
04186         }
04187         DEBUGINDENTADD(-6);
04188         break;
04189 #endif /* support for community based SNMP */
04190 
04191     case SNMP_VERSION_3:
04192         result = snmpv3_parse(pdu, data, &length, NULL, session);
04193         DEBUGMSGTL(("snmp_parse",
04194                     "Parsed SNMPv3 message (secName:%s, secLevel:%s): %s\n",
04195                     pdu->securityName, secLevelName[pdu->securityLevel],
04196                     snmp_api_errstring(result)));
04197 
04198         if (result) {
04199             struct snmp_secmod_def *secmod =
04200                 find_sec_mod(pdu->securityModel);
04201             if (!sessp) {
04202                 session->s_snmp_errno = result;
04203             } else {
04204                 /*
04205                  * Call the security model to special handle any errors
04206                  */
04207 
04208                 if (secmod && secmod->handle_report) {
04209                     struct session_list *slp = (struct session_list *) sessp;
04210                     (*secmod->handle_report)(sessp, slp->transport, session,
04211                                              result, pdu);
04212                 }
04213             }
04214             if (pdu->securityStateRef != NULL) {
04215                 if (secmod && secmod->pdu_free_state_ref) {
04216                     secmod->pdu_free_state_ref(pdu->securityStateRef);
04217                     pdu->securityStateRef = NULL;
04218                 }
04219             }
04220         }
04221         break;
04222     case SNMPERR_BAD_VERSION:
04223         ERROR_MSG("error parsing snmp message version");
04224         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
04225         session->s_snmp_errno = SNMPERR_BAD_VERSION;
04226         break;
04227     case SNMP_VERSION_sec:
04228     case SNMP_VERSION_2u:
04229     case SNMP_VERSION_2star:
04230     case SNMP_VERSION_2p:
04231     default:
04232         ERROR_MSG("unsupported snmp message version");
04233         snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
04234 
04235         /*
04236          * need better way to determine OS independent
04237          * INT32_MAX value, for now hardcode
04238          */
04239         if (pdu->version < 0 || pdu->version > 2147483647) {
04240             snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
04241         }
04242         session->s_snmp_errno = SNMPERR_BAD_VERSION;
04243         break;
04244     }
04245 
04246     return result;
04247 }
04248 
04249 static int
04250 snmp_parse(void *sessp,
04251            netsnmp_session * pss,
04252            netsnmp_pdu *pdu, u_char * data, size_t length)
04253 {
04254     int             rc;
04255 
04256     rc = _snmp_parse(sessp, pss, pdu, data, length);
04257     if (rc) {
04258         if (!pss->s_snmp_errno) {
04259             pss->s_snmp_errno = SNMPERR_BAD_PARSE;
04260         }
04261         SET_SNMP_ERROR(pss->s_snmp_errno);
04262     }
04263 
04264     return rc;
04265 }
04266 
04267 int
04268 snmp_pdu_parse(netsnmp_pdu *pdu, u_char * data, size_t * length)
04269 {
04270     u_char          type;
04271     u_char          msg_type;
04272     u_char         *var_val;
04273     int             badtype = 0;
04274     size_t          len;
04275     size_t          four;
04276     netsnmp_variable_list *vp = NULL;
04277     oid             objid[MAX_OID_LEN];
04278 
04279     /*
04280      * Get the PDU type 
04281      */
04282     data = asn_parse_header(data, length, &msg_type);
04283     if (data == NULL)
04284         return -1;
04285     DEBUGMSGTL(("dumpv_recv","    Command %s\n", snmp_pdu_type(msg_type)));
04286     pdu->command = msg_type;
04287     pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
04288 
04289     /*
04290      * get the fields in the PDU preceeding the variable-bindings sequence 
04291      */
04292     switch (pdu->command) {
04293     case SNMP_MSG_TRAP:
04294         /*
04295          * enterprise 
04296          */
04297         pdu->enterprise_length = MAX_OID_LEN;
04298         data = asn_parse_objid(data, length, &type, objid,
04299                                &pdu->enterprise_length);
04300         if (data == NULL)
04301             return -1;
04302         pdu->enterprise =
04303             (oid *) malloc(pdu->enterprise_length * sizeof(oid));
04304         if (pdu->enterprise == NULL) {
04305             return -1;
04306         }
04307         memmove(pdu->enterprise, objid,
04308                 pdu->enterprise_length * sizeof(oid));
04309 
04310         /*
04311          * agent-addr 
04312          */
04313         four = 4;
04314         data = asn_parse_string(data, length, &type,
04315                                 (u_char *) pdu->agent_addr, &four);
04316         if (data == NULL)
04317             return -1;
04318 
04319         /*
04320          * generic trap 
04321          */
04322         data = asn_parse_int(data, length, &type, (long *) &pdu->trap_type,
04323                              sizeof(pdu->trap_type));
04324         if (data == NULL)
04325             return -1;
04326         /*
04327          * specific trap 
04328          */
04329         data =
04330             asn_parse_int(data, length, &type,
04331                           (long *) &pdu->specific_type,
04332                           sizeof(pdu->specific_type));
04333         if (data == NULL)
04334             return -1;
04335 
04336         /*
04337          * timestamp  
04338          */
04339         data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
04340                                       sizeof(pdu->time));
04341         if (data == NULL)
04342             return -1;
04343 
04344         break;
04345 
04346     case SNMP_MSG_RESPONSE:
04347     case SNMP_MSG_REPORT:
04348         pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
04349         /*
04350          * fallthrough 
04351          */
04352 
04353     case SNMP_MSG_GET:
04354     case SNMP_MSG_GETNEXT:
04355     case SNMP_MSG_GETBULK:
04356     case SNMP_MSG_TRAP2:
04357     case SNMP_MSG_INFORM:
04358     case SNMP_MSG_SET:
04359         /*
04360          * PDU is not an SNMPv1 TRAP 
04361          */
04362 
04363         /*
04364          * request id 
04365          */
04366         DEBUGDUMPHEADER("recv", "request_id");
04367         data = asn_parse_int(data, length, &type, &pdu->reqid,
04368                              sizeof(pdu->reqid));
04369         DEBUGINDENTLESS();
04370         if (data == NULL) {
04371             return -1;
04372         }
04373 
04374         /*
04375          * error status (getbulk non-repeaters) 
04376          */
04377         DEBUGDUMPHEADER("recv", "error status");
04378         data = asn_parse_int(data, length, &type, &pdu->errstat,
04379                              sizeof(pdu->errstat));
04380         DEBUGINDENTLESS();
04381         if (data == NULL) {
04382             return -1;
04383         }
04384 
04385         /*
04386          * error index (getbulk max-repetitions) 
04387          */
04388         DEBUGDUMPHEADER("recv", "error index");
04389         data = asn_parse_int(data, length, &type, &pdu->errindex,
04390                              sizeof(pdu->errindex));
04391         DEBUGINDENTLESS();
04392         if (data == NULL) {
04393             return -1;
04394         }
04395         break;
04396 
04397     default:
04398         snmp_log(LOG_ERR, "Bad PDU type received: 0x%.2x\n", pdu->command);
04399         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
04400         return -1;
04401     }
04402 
04403     /*
04404      * get header for variable-bindings sequence 
04405      */
04406     DEBUGDUMPSECTION("recv", "VarBindList");
04407     data = asn_parse_sequence(data, length, &type,
04408                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
04409                               "varbinds");
04410     if (data == NULL)
04411         return -1;
04412 
04413     /*
04414      * get each varBind sequence 
04415      */
04416     while ((int) *length > 0) {
04417         netsnmp_variable_list *vptemp;
04418         vptemp = (netsnmp_variable_list *) malloc(sizeof(*vptemp));
04419         if (0 == vptemp) {
04420             return -1;
04421         }
04422         if (0 == vp) {
04423             pdu->variables = vptemp;
04424         } else {
04425             vp->next_variable = vptemp;
04426         }
04427         vp = vptemp;
04428 
04429         vp->next_variable = NULL;
04430         vp->val.string = NULL;
04431         vp->name_length = MAX_OID_LEN;
04432         vp->name = 0;
04433         vp->index = 0;
04434         vp->data = 0;
04435         vp->dataFreeHook = 0;
04436         DEBUGDUMPSECTION("recv", "VarBind");
04437         data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
04438                                  &vp->val_len, &var_val, length);
04439         if (data == NULL)
04440             return -1;
04441         if (snmp_set_var_objid(vp, objid, vp->name_length))
04442             return -1;
04443 
04444         len = MAX_PACKET_LENGTH;
04445         DEBUGDUMPHEADER("recv", "Value");
04446         switch ((short) vp->type) {
04447         case ASN_INTEGER:
04448             vp->val.integer = (long *) vp->buf;
04449             vp->val_len = sizeof(long);
04450             asn_parse_int(var_val, &len, &vp->type,
04451                           (long *) vp->val.integer,
04452                           sizeof(*vp->val.integer));
04453             break;
04454         case ASN_COUNTER:
04455         case ASN_GAUGE:
04456         case ASN_TIMETICKS:
04457         case ASN_UINTEGER:
04458             vp->val.integer = (long *) vp->buf;
04459             vp->val_len = sizeof(u_long);
04460             asn_parse_unsigned_int(var_val, &len, &vp->type,
04461                                    (u_long *) vp->val.integer,
04462                                    vp->val_len);
04463             break;
04464 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
04465         case ASN_OPAQUE_COUNTER64:
04466         case ASN_OPAQUE_U64:
04467 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
04468         case ASN_COUNTER64:
04469             vp->val.counter64 = (struct counter64 *) vp->buf;
04470             vp->val_len = sizeof(struct counter64);
04471             asn_parse_unsigned_int64(var_val, &len, &vp->type,
04472                                      (struct counter64 *) vp->val.
04473                                      counter64, vp->val_len);
04474             break;
04475 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
04476         case ASN_OPAQUE_FLOAT:
04477             vp->val.floatVal = (float *) vp->buf;
04478             vp->val_len = sizeof(float);
04479             asn_parse_float(var_val, &len, &vp->type,
04480                             vp->val.floatVal, vp->val_len);
04481             break;
04482         case ASN_OPAQUE_DOUBLE:
04483             vp->val.doubleVal = (double *) vp->buf;
04484             vp->val_len = sizeof(double);
04485             asn_parse_double(var_val, &len, &vp->type,
04486                              vp->val.doubleVal, vp->val_len);
04487             break;
04488         case ASN_OPAQUE_I64:
04489             vp->val.counter64 = (struct counter64 *) vp->buf;
04490             vp->val_len = sizeof(struct counter64);
04491             asn_parse_signed_int64(var_val, &len, &vp->type,
04492                                    (struct counter64 *) vp->val.counter64,
04493                                    sizeof(*vp->val.counter64));
04494 
04495             break;
04496 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
04497         case ASN_OCTET_STR:
04498         case ASN_IPADDRESS:
04499         case ASN_OPAQUE:
04500         case ASN_NSAP:
04501             if (vp->val_len < sizeof(vp->buf)) {
04502                 vp->val.string = (u_char *) vp->buf;
04503             } else {
04504                 vp->val.string = (u_char *) malloc(vp->val_len);
04505             }
04506             if (vp->val.string == NULL) {
04507                 return -1;
04508             }
04509             asn_parse_string(var_val, &len, &vp->type, vp->val.string,
04510                              &vp->val_len);
04511             break;
04512         case ASN_OBJECT_ID:
04513             vp->val_len = MAX_OID_LEN;
04514             asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
04515             vp->val_len *= sizeof(oid);
04516             vp->val.objid = (oid *) malloc(vp->val_len);
04517             if (vp->val.objid == NULL) {
04518                 return -1;
04519             }
04520             memmove(vp->val.objid, objid, vp->val_len);
04521             break;
04522         case SNMP_NOSUCHOBJECT:
04523         case SNMP_NOSUCHINSTANCE:
04524         case SNMP_ENDOFMIBVIEW:
04525         case ASN_NULL:
04526             break;
04527         case ASN_BIT_STR:
04528             vp->val.bitstring = (u_char *) malloc(vp->val_len);
04529             if (vp->val.bitstring == NULL) {
04530                 return -1;
04531             }
04532             asn_parse_bitstring(var_val, &len, &vp->type,
04533                                 vp->val.bitstring, &vp->val_len);
04534             break;
04535         default:
04536             snmp_log(LOG_ERR, "bad type returned (%x)\n", vp->type);
04537             badtype = -1;
04538             break;
04539         }
04540         DEBUGINDENTADD(-4);
04541     }
04542     return badtype;
04543 }
04544 
04545 /*
04546  * snmp v3 utility function to parse into the scopedPdu. stores contextName
04547  * and contextEngineID in pdu struct. Also stores pdu->command (handy for 
04548  * Report generation).
04549  * 
04550  * returns pointer to begining of PDU or NULL on error.
04551  */
04552 u_char         *
04553 snmpv3_scopedPDU_parse(netsnmp_pdu *pdu, u_char * cp, size_t * length)
04554 {
04555     u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
04556     size_t          tmp_buf_len;
04557     u_char          type;
04558     size_t          asn_len;
04559     u_char         *data;
04560 
04561     pdu->command = 0;           /* initialize so we know if it got parsed */
04562     asn_len = *length;
04563     data = asn_parse_sequence(cp, &asn_len, &type,
04564                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
04565                               "plaintext scopedPDU");
04566     if (data == NULL) {
04567         return NULL;
04568     }
04569     *length -= data - cp;
04570 
04571     /*
04572      * contextEngineID from scopedPdu  
04573      */
04574     DEBUGDUMPHEADER("recv", "contextEngineID");
04575     data = asn_parse_string(data, length, &type, pdu->contextEngineID,
04576                             &pdu->contextEngineIDLen);
04577     DEBUGINDENTLESS();
04578     if (data == NULL) {
04579         ERROR_MSG("error parsing contextEngineID from scopedPdu");
04580         return NULL;
04581     }
04582 
04583     /*
04584      * check that it agrees with engineID returned from USM above
04585      * * only a warning because this could be legal if we are a proxy
04586      */
04587     if (pdu->securityEngineIDLen != pdu->contextEngineIDLen ||
04588         memcmp(pdu->securityEngineID, pdu->contextEngineID,
04589                pdu->securityEngineIDLen) != 0) {
04590         DEBUGMSGTL(("scopedPDU_parse",
04591                     "inconsistent engineID information in message\n"));
04592     }
04593 
04594     /*
04595      * parse contextName from scopedPdu
04596      */
04597     tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
04598     DEBUGDUMPHEADER("recv", "contextName");
04599     data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
04600     DEBUGINDENTLESS();
04601     if (data == NULL) {
04602         ERROR_MSG("error parsing contextName from scopedPdu");
04603         return NULL;
04604     }
04605 
04606     if (tmp_buf_len) {
04607         pdu->contextName = (char *) malloc(tmp_buf_len);
04608         memmove(pdu->contextName, tmp_buf, tmp_buf_len);
04609         pdu->contextNameLen = tmp_buf_len;
04610     } else {
04611         pdu->contextName = strdup("");
04612         pdu->contextNameLen = 0;
04613     }
04614     if (pdu->contextName == NULL) {
04615         ERROR_MSG("error copying contextName from scopedPdu");
04616         return NULL;
04617     }
04618 
04619     /*
04620      * Get the PDU type 
04621      */
04622     asn_len = *length;
04623     cp = asn_parse_header(data, &asn_len, &type);
04624     if (cp == NULL)
04625         return NULL;
04626 
04627     pdu->command = type;
04628 
04629     return data;
04630 }
04631 
04632 /*
04633  * These functions send PDUs using an active session:
04634  * snmp_send             - traditional API, no callback
04635  * snmp_async_send       - traditional API, with callback
04636  * snmp_sess_send        - single session API, no callback
04637  * snmp_sess_async_send  - single session API, with callback
04638  *
04639  * Call snmp_build to create a serialized packet (the pdu).
04640  * If necessary, set some of the pdu data from the
04641  * session defaults.
04642  * If there is an expected response for this PDU,
04643  * queue a corresponding request on the list
04644  * of outstanding requests for this session,
04645  * and store the callback vectors in the request.
04646  *
04647  * Send the pdu to the target identified by this session.
04648  * Return on success:
04649  *   The request id of the pdu is returned, and the pdu is freed.
04650  * Return on failure:
04651  *   Zero (0) is returned.
04652  *   The caller must call snmp_free_pdu if 0 is returned.
04653  */
04654 int
04655 snmp_send(netsnmp_session * session, netsnmp_pdu *pdu)
04656 {
04657     return snmp_async_send(session, pdu, NULL, NULL);
04658 }
04659 
04660 int
04661 snmp_sess_send(void *sessp, netsnmp_pdu *pdu)
04662 {
04663     return snmp_sess_async_send(sessp, pdu, NULL, NULL);
04664 }
04665 
04666 int
04667 snmp_async_send(netsnmp_session * session,
04668                 netsnmp_pdu *pdu, snmp_callback callback, void *cb_data)
04669 {
04670     void           *sessp = snmp_sess_pointer(session);
04671     return snmp_sess_async_send(sessp, pdu, callback, cb_data);
04672 }
04673 
04674 static int
04675 _sess_async_send(void *sessp,
04676                  netsnmp_pdu *pdu, snmp_callback callback, void *cb_data)
04677 {
04678     struct session_list *slp = (struct session_list *) sessp;
04679     netsnmp_session *session;
04680     struct snmp_internal_session *isp;
04681     netsnmp_transport *transport = NULL;
04682     u_char         *pktbuf = NULL, *packet = NULL;
04683     size_t          pktbuf_len = 0, offset = 0, length = 0;
04684     int             result;
04685     long            reqid;
04686 
04687     if (slp == NULL) {
04688         return 0;
04689     } else {
04690         session = slp->session;
04691         isp = slp->internal;
04692         transport = slp->transport;
04693         if (!session || !isp || !transport) {
04694             DEBUGMSGTL(("sess_async_send", "send fail: closing...\n"));
04695             return 0;
04696         }
04697     }
04698 
04699     if (pdu == NULL) {
04700         session->s_snmp_errno = SNMPERR_NULL_PDU;
04701         return 0;
04702     }
04703 
04704     session->s_snmp_errno = 0;
04705     session->s_errno = 0;
04706 
04707     /*
04708      * Check/setup the version.  
04709      */
04710     if (pdu->version == SNMP_DEFAULT_VERSION) {
04711         if (session->version == SNMP_DEFAULT_VERSION) {
04712             session->s_snmp_errno = SNMPERR_BAD_VERSION;
04713             return 0;
04714         }
04715         pdu->version = session->version;
04716     } else if (session->version == SNMP_DEFAULT_VERSION) {
04717         /*
04718          * It's OK  
04719          */
04720     } else if (pdu->version != session->version) {
04721         /*
04722          * ENHANCE: we should support multi-lingual sessions  
04723          */
04724         session->s_snmp_errno = SNMPERR_BAD_VERSION;
04725         return 0;
04726     }
04727 
04728     /*
04729      * do we expect a response?
04730      */
04731     switch (pdu->command) {
04732 
04733         case SNMP_MSG_RESPONSE:
04734         case SNMP_MSG_TRAP:
04735         case SNMP_MSG_TRAP2:
04736         case SNMP_MSG_REPORT:
04737         case AGENTX_MSG_CLEANUPSET:
04738         case AGENTX_MSG_RESPONSE:
04739             pdu->flags &= ~UCD_MSG_FLAG_EXPECT_RESPONSE;
04740             break;
04741             
04742         default:
04743             pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
04744             break;
04745     }
04746 
04747     /*
04748      * check to see if we need a v3 engineID probe
04749      */
04750     if ((pdu->version == SNMP_VERSION_3) &&
04751         (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) &&
04752         (session->securityEngineIDLen == 0) &&
04753         (0 == (session->flags & SNMP_FLAGS_DONT_PROBE))) {
04754         int rc;
04755         DEBUGMSGTL(("snmpv3_build", "delayed probe for engineID\n"));
04756         rc = snmpv3_engineID_probe(slp, session);
04757         if (rc == 0)
04758             return 0; /* s_snmp_errno already set */
04759     }
04760 
04761     /*
04762      * check to see if we need to create a v3 user from the session info
04763      */
04764     if (create_user_from_session(session) != SNMPERR_SUCCESS) {
04765         session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME;  /* XX?? */
04766         DEBUGMSGTL(("snmp_api",
04767                     "snmp_send(): failed(2) to create a new user from session\n"));
04768         return 0;
04769     }
04770 
04771     if ((pktbuf = (u_char *)malloc(2048)) == NULL) {
04772         DEBUGMSGTL(("sess_async_send",
04773                     "couldn't malloc initial packet buffer\n"));
04774         session->s_snmp_errno = SNMPERR_MALLOC;
04775         return 0;
04776     } else {
04777         pktbuf_len = 2048;
04778     }
04779 
04780 #if TEMPORARILY_DISABLED
04781     /*
04782      *  NULL variable are allowed in certain PDU types.
04783      *  In particular, SNMPv3 engineID probes are of this form.
04784      *  There is an internal PDU flag to indicate that this
04785      *    is acceptable, but until the construction of engineID
04786      *    probes can be amended to set this flag, we'll simply
04787      *    skip this test altogether.
04788      */
04789     if (pdu->variables == NULL) {
04790         switch (pdu->command) {
04791         case SNMP_MSG_GET:
04792         case SNMP_MSG_SET:
04793         case SNMP_MSG_GETNEXT:
04794         case SNMP_MSG_GETBULK:
04795         case SNMP_MSG_RESPONSE:
04796         case SNMP_MSG_TRAP2:
04797         case SNMP_MSG_REPORT:
04798         case SNMP_MSG_INFORM:
04799             session->s_snmp_errno = snmp_errno = SNMPERR_NO_VARS;
04800             return 0;
04801         case SNMP_MSG_TRAP:
04802             break;
04803         }
04804     }
04805 #endif
04806 
04807 
04808     /*
04809      * Build the message to send.  
04810      */
04811     if (isp->hook_realloc_build) {
04812         result = isp->hook_realloc_build(session, pdu,
04813                                          &pktbuf, &pktbuf_len, &offset);
04814         packet = pktbuf;
04815         length = offset;
04816     } else if (isp->hook_build) {
04817         packet = pktbuf;
04818         length = pktbuf_len;
04819         result = isp->hook_build(session, pdu, pktbuf, &length);
04820     } else {
04821 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
04822         if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
04823             result =
04824                 snmp_build(&pktbuf, &pktbuf_len, &offset, session, pdu);
04825             packet = pktbuf + pktbuf_len - offset;
04826             length = offset;
04827         } else {
04828 #endif
04829             packet = pktbuf;
04830             length = pktbuf_len;
04831             result = snmp_build(&pktbuf, &length, &offset, session, pdu);
04832 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
04833         }
04834 #endif
04835     }
04836 
04837     if (result < 0) {
04838         DEBUGMSGTL(("sess_async_send", "encoding failure\n"));
04839         SNMP_FREE(pktbuf);
04840         return 0;
04841     }
04842 
04843     /*
04844      * Make sure we don't send something that is bigger than the msgMaxSize
04845      * specified in the received PDU.  
04846      */
04847 
04848     if (session->sndMsgMaxSize != 0 && length > session->sndMsgMaxSize) {
04849         DEBUGMSGTL(("sess_async_send",
04850                     "length of packet (%lu) exceeds session maximum (%lu)\n",
04851                     length, session->sndMsgMaxSize));
04852         session->s_snmp_errno = SNMPERR_TOO_LONG;
04853         SNMP_FREE(pktbuf);
04854         return 0;
04855     }
04856 
04857     /*
04858      * Check that the underlying transport is capable of sending a packet as
04859      * large as length.  
04860      */
04861 
04862     if (transport->msgMaxSize != 0 && length > transport->msgMaxSize) {
04863         DEBUGMSGTL(("sess_async_send",
04864                     "length of packet (%lu) exceeds transport maximum (%lu)\n",
04865                     length, transport->msgMaxSize));
04866         session->s_snmp_errno = SNMPERR_TOO_LONG;
04867         SNMP_FREE(pktbuf);
04868         return 0;
04869     }
04870 
04871     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET)) {
04872         if (transport->f_fmtaddr != NULL) {
04873             char           *dest_txt =
04874                 transport->f_fmtaddr(transport, pdu->transport_data,
04875                                      pdu->transport_data_length);
04876             if (dest_txt != NULL) {
04877                 snmp_log(LOG_DEBUG, "\nSending %lu bytes to %s\n", (unsigned long)length,
04878                          dest_txt);
04879                 SNMP_FREE(dest_txt);
04880             } else {
04881                 snmp_log(LOG_DEBUG, "\nSending %lu bytes to <UNKNOWN>\n",
04882                          (unsigned long)length);
04883             }
04884         }
04885         xdump(packet, length, "");
04886     }
04887 
04888     /*
04889      * Send the message.  
04890      */
04891 
04892     result = transport->f_send(transport, packet, length,
04893                                &(pdu->transport_data),
04894                                &(pdu->transport_data_length));
04895 
04896     SNMP_FREE(pktbuf);
04897 
04898     if (result < 0) {
04899         session->s_snmp_errno = SNMPERR_BAD_SENDTO;
04900         session->s_errno = errno;
04901         return 0;
04902     }
04903 
04904     reqid = pdu->reqid;
04905 
04906     /*
04907      * Add to pending requests list if we expect a response.  
04908      */
04909     if (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) {
04910         netsnmp_request_list *rp;
04911         struct timeval  tv;
04912 
04913         rp = (netsnmp_request_list *) calloc(1,
04914                                              sizeof(netsnmp_request_list));
04915         if (rp == NULL) {
04916             session->s_snmp_errno = SNMPERR_GENERR;
04917             return 0;
04918         }
04919 
04920         gettimeofday(&tv, (struct timezone *) 0);
04921         rp->pdu = pdu;
04922         rp->request_id = pdu->reqid;
04923         rp->message_id = pdu->msgid;
04924         rp->callback = callback;
04925         rp->cb_data = cb_data;
04926         rp->retries = 0;
04927         if (pdu->flags & UCD_MSG_FLAG_PDU_TIMEOUT) {
04928             rp->timeout = pdu->time * 1000000L;
04929         } else {
04930             rp->timeout = session->timeout;
04931         }
04932         rp->time = tv;
04933         tv.tv_usec += rp->timeout;
04934         tv.tv_sec += tv.tv_usec / 1000000L;
04935         tv.tv_usec %= 1000000L;
04936         rp->expire = tv;
04937 
04938         /*
04939          * XX lock should be per session ! 
04940          */
04941         snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
04942         if (isp->requestsEnd) {
04943             rp->next_request = isp->requestsEnd->next_request;
04944             isp->requestsEnd->next_request = rp;
04945             isp->requestsEnd = rp;
04946         } else {
04947             rp->next_request = isp->requests;
04948             isp->requests = rp;
04949             isp->requestsEnd = rp;
04950         }
04951         snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
04952     } else {
04953         /*
04954          * No response expected...  
04955          */
04956         if (reqid) {
04957             /*
04958              * Free v1 or v2 TRAP PDU iff no error  
04959              */
04960             snmp_free_pdu(pdu);
04961         }
04962     }
04963 
04964     return reqid;
04965 }
04966 
04967 int
04968 snmp_sess_async_send(void *sessp,
04969                      netsnmp_pdu *pdu,
04970                      snmp_callback callback, void *cb_data)
04971 {
04972     int             rc;
04973 
04974     if (sessp == NULL) {
04975         snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
04976         return (0);
04977     }
04978     /*
04979      * send pdu
04980      */
04981     rc = _sess_async_send(sessp, pdu, callback, cb_data);
04982     if (rc == 0) {
04983         struct session_list *psl;
04984         netsnmp_session *pss;
04985         psl = (struct session_list *) sessp;
04986         pss = psl->session;
04987         SET_SNMP_ERROR(pss->s_snmp_errno);
04988     }
04989     return rc;
04990 }
04991 
04992 
04993 /*
04994  * Frees the variable and any malloc'd data associated with it.
04995  */
04996 void
04997 snmp_free_var(netsnmp_variable_list * var)
04998 {
04999     if (!var)
05000         return;
05001 
05002     if (var->name != var->name_loc)
05003         SNMP_FREE(var->name);
05004     if (var->val.string != var->buf)
05005         SNMP_FREE(var->val.string);
05006     if (var->data) {
05007         if (var->dataFreeHook) {
05008             var->dataFreeHook(var->data);
05009             var->data = NULL;
05010         } else {
05011             SNMP_FREE(var->data);
05012         }
05013     }
05014 
05015     free((char *) var);
05016 }
05017 
05018 void
05019 snmp_free_varbind(netsnmp_variable_list * var)
05020 {
05021     netsnmp_variable_list *ptr;
05022     while (var) {
05023         ptr = var->next_variable;
05024         snmp_free_var(var);
05025         var = ptr;
05026     }
05027 }
05028 
05029 /*
05030  * Frees the pdu and any malloc'd data associated with it.
05031  */
05032 void
05033 snmp_free_pdu(netsnmp_pdu *pdu)
05034 {
05035     struct snmp_secmod_def *sptr;
05036 
05037     if (!pdu)
05038         return;
05039 
05040     /*
05041      * If the command field is empty, that probably indicates
05042      *   that this PDU structure has already been freed.
05043      *   Log a warning and return (rather than freeing things again)
05044      *
05045      * Note that this does not pick up dual-frees where the
05046      *   memory is set to random junk, which is probably more serious.
05047      *
05048      * rks: while this is a good idea, there are two problems.
05049      *         1) agentx sets command to 0 in some cases
05050      *         2) according to Wes, a bad decode of a v3 message could
05051      *            result in a 0 at this offset.
05052      *      so I'm commenting it out until a better solution is found.
05053      *      note that I'm leaving the memset, below....
05054      *
05055     if (pdu->command == 0) {
05056         snmp_log(LOG_WARNING, "snmp_free_pdu probably called twice\n");
05057         return;
05058     }
05059      */
05060     if ((sptr = find_sec_mod(pdu->securityModel)) != NULL &&
05061         sptr->pdu_free != NULL) {
05062         (*sptr->pdu_free) (pdu);
05063     }
05064     snmp_free_varbind(pdu->variables);
05065     SNMP_FREE(pdu->enterprise);
05066     SNMP_FREE(pdu->community);
05067     SNMP_FREE(pdu->contextEngineID);
05068     SNMP_FREE(pdu->securityEngineID);
05069     SNMP_FREE(pdu->contextName);
05070     SNMP_FREE(pdu->securityName);
05071     SNMP_FREE(pdu->transport_data);
05072     memset(pdu, 0, sizeof(netsnmp_pdu));
05073     free((char *) pdu);
05074 }
05075 
05076 netsnmp_pdu    *
05077 snmp_create_sess_pdu(netsnmp_transport *transport, void *opaque,
05078                      size_t olength)
05079 {
05080     netsnmp_pdu *pdu = (netsnmp_pdu *)calloc(1, sizeof(netsnmp_pdu));
05081     if (pdu == NULL) {
05082         DEBUGMSGTL(("sess_process_packet", "can't malloc space for PDU\n"));
05083         return NULL;
05084     }
05085 
05086     /*
05087      * Save the transport-level data specific to this reception (e.g. UDP
05088      * source address).  
05089      */
05090 
05091     pdu->transport_data = opaque;
05092     pdu->transport_data_length = olength;
05093     pdu->tDomain = transport->domain;
05094     pdu->tDomainLen = transport->domain_length;
05095     return pdu;
05096 }
05097 
05098 
05099 /*
05100  * This function processes a complete (according to asn_check_packet or the
05101  * AgentX equivalent) packet, parsing it into a PDU and calling the relevant
05102  * callbacks.  On entry, packetptr points at the packet in the session's
05103  * buffer and length is the length of the packet.  
05104  */
05105 
05106 static int
05107 _sess_process_packet(void *sessp, netsnmp_session * sp,
05108                      struct snmp_internal_session *isp,
05109                      netsnmp_transport *transport,
05110                      void *opaque, int olength,
05111                      u_char * packetptr, int length)
05112 {
05113   struct session_list *slp = (struct session_list *) sessp;
05114   netsnmp_pdu    *pdu;
05115   netsnmp_request_list *rp, *orp = NULL;
05116   struct snmp_secmod_def *sptr;
05117   int             ret = 0, handled = 0;
05118 
05119   DEBUGMSGTL(("sess_process_packet",
05120               "session %p fd %d pkt %p length %d\n", sessp,
05121               transport->sock, packetptr, length));
05122 
05123   if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
05124                              NETSNMP_DS_LIB_DUMP_PACKET)) {
05125     if (transport->f_fmtaddr != NULL) {
05126       char *addrtxt = transport->f_fmtaddr(transport, opaque, olength);
05127       if (addrtxt != NULL) {
05128         snmp_log(LOG_DEBUG, "\nReceived %d bytes from %s\n",
05129                  length, addrtxt);
05130         SNMP_FREE(addrtxt);
05131       } else {
05132         snmp_log(LOG_DEBUG, "\nReceived %d bytes from <UNKNOWN>\n",
05133                  length);
05134       }
05135     }
05136     xdump(packetptr, length, "");
05137   }
05138 
05139   /*
05140    * Do transport-level filtering (e.g. IP-address based allow/deny).  
05141    */
05142 
05143   if (isp->hook_pre) {
05144     if (isp->hook_pre(sp, transport, opaque, olength) == 0) {
05145       DEBUGMSGTL(("sess_process_packet", "pre-parse fail\n"));
05146       if (opaque != NULL) {
05147         SNMP_FREE(opaque);
05148       }
05149       return -1;
05150     }
05151   }
05152 
05153   if (isp->hook_create_pdu) {
05154     pdu = isp->hook_create_pdu(transport, opaque, olength);
05155   } else {
05156     pdu = snmp_create_sess_pdu(transport, opaque, olength);
05157   }
05158   if (pdu == NULL) {
05159     snmp_log(LOG_ERR, "pdu failed to be created\n");
05160     if (opaque != NULL) {
05161       SNMP_FREE(opaque);
05162     }
05163     return -1;
05164   }
05165 
05166   if (isp->hook_parse) {
05167     ret = isp->hook_parse(sp, pdu, packetptr, length);
05168   } else {
05169     ret = snmp_parse(sessp, sp, pdu, packetptr, length);
05170   }
05171 
05172   if (ret != SNMP_ERR_NOERROR) {
05173     DEBUGMSGTL(("sess_process_packet", "parse fail\n"));
05174   }
05175 
05176   if (isp->hook_post) {
05177     if (isp->hook_post(sp, pdu, ret) == 0) {
05178       DEBUGMSGTL(("sess_process_packet", "post-parse fail\n"));
05179       ret = SNMPERR_ASN_PARSE_ERR;
05180     }
05181   }
05182 
05183   if (ret != SNMP_ERR_NOERROR) {
05184     /*
05185      * Call the security model to free any securityStateRef supplied w/ msg.  
05186      */
05187     if (pdu->securityStateRef != NULL) {
05188       sptr = find_sec_mod(pdu->securityModel);
05189       if (sptr != NULL) {
05190         if (sptr->pdu_free_state_ref != NULL) {
05191           (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
05192         } else {
05193           snmp_log(LOG_ERR,
05194                    "Security Model %d can't free state references\n",
05195                    pdu->securityModel);
05196         }
05197       } else {
05198         snmp_log(LOG_ERR,
05199                  "Can't find security model to free ptr: %d\n",
05200                  pdu->securityModel);
05201       }
05202       pdu->securityStateRef = NULL;
05203     }
05204     snmp_free_pdu(pdu);
05205     return -1;
05206   }
05207 
05208   if (pdu->flags & UCD_MSG_FLAG_RESPONSE_PDU) {
05209     /*
05210      * Call USM to free any securityStateRef supplied with the message.  
05211      */
05212     if (pdu->securityStateRef) {
05213       sptr = find_sec_mod(pdu->securityModel);
05214       if (sptr) {
05215         if (sptr->pdu_free_state_ref) {
05216           (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
05217         } else {
05218           snmp_log(LOG_ERR,
05219                    "Security Model %d can't free state references\n",
05220                    pdu->securityModel);
05221         }
05222       } else {
05223         snmp_log(LOG_ERR,
05224                  "Can't find security model to free ptr: %d\n",
05225                  pdu->securityModel);
05226       }
05227       pdu->securityStateRef = NULL;
05228     }
05229 
05230     for (rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
05231       snmp_callback   callback;
05232       void           *magic;
05233 
05234       if (pdu->version == SNMP_VERSION_3) {
05235         /*
05236          * msgId must match for v3 messages.  
05237          */
05238         if (rp->message_id != pdu->msgid) {
05239           continue;
05240         }
05241 
05242         /*
05243          * Check that message fields match original, if not, no further
05244          * processing.  
05245          */
05246         if (!snmpv3_verify_msg(rp, pdu)) {
05247           break;
05248         }
05249       } else {
05250         if (rp->request_id != pdu->reqid) {
05251           continue;
05252         }
05253       }
05254 
05255       if (rp->callback) {
05256         callback = rp->callback;
05257         magic = rp->cb_data;
05258       } else {
05259         callback = sp->callback;
05260         magic = sp->callback_magic;
05261       }
05262       handled = 1;
05263 
05264       /*
05265        * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock
05266        * should be per session ! 
05267        */
05268 
05269       if (callback == NULL
05270           || callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, sp,
05271                       pdu->reqid, pdu, magic) == 1) {
05272         if (pdu->command == SNMP_MSG_REPORT) {
05273           if (sp->s_snmp_errno == SNMPERR_NOT_IN_TIME_WINDOW ||
05274               snmpv3_get_report_type(pdu) ==
05275               SNMPERR_NOT_IN_TIME_WINDOW) {
05276             /*
05277              * trigger immediate retry on recoverable Reports 
05278              * * (notInTimeWindow), incr_retries == TRUE to prevent
05279              * * inifinite resend                      
05280              */
05281             if (rp->retries <= sp->retries) {
05282               snmp_resend_request(slp, rp, TRUE);
05283               break;
05284             }
05285           } else {
05286             if (SNMPV3_IGNORE_UNAUTH_REPORTS) {
05287               break;
05288             }
05289           }
05290 
05291           /*
05292            * Handle engineID discovery.  
05293            */
05294           if (!sp->securityEngineIDLen && pdu->securityEngineIDLen) {
05295             sp->securityEngineID =
05296               (u_char *) malloc(pdu->securityEngineIDLen);
05297             if (sp->securityEngineID == NULL) {
05298               /*
05299                * TODO FIX: recover after message callback *?
05300                * return -1;
05301                */
05302             }
05303             memcpy(sp->securityEngineID, pdu->securityEngineID,
05304                    pdu->securityEngineIDLen);
05305             sp->securityEngineIDLen = pdu->securityEngineIDLen;
05306             if (!sp->contextEngineIDLen) {
05307               sp->contextEngineID =
05308                 (u_char *) malloc(pdu->
05309                                   securityEngineIDLen);
05310               if (sp->contextEngineID == NULL) {
05311                 /*
05312                  * TODO FIX: recover after message callback *?
05313                  * return -1;
05314                  */
05315               }
05316               memcpy(sp->contextEngineID,
05317                      pdu->securityEngineID,
05318                      pdu->securityEngineIDLen);
05319               sp->contextEngineIDLen =
05320                 pdu->securityEngineIDLen;
05321             }
05322           }
05323         }
05324 
05325         /*
05326          * Successful, so delete request.  
05327          */
05328         if (isp->requests == rp) {
05329           isp->requests = rp->next_request;
05330           if (isp->requestsEnd == rp) {
05331             isp->requestsEnd = NULL;
05332           }
05333         } else {
05334           orp->next_request = rp->next_request;
05335           if (isp->requestsEnd == rp) {
05336             isp->requestsEnd = orp;
05337           }
05338         }
05339         snmp_free_pdu(rp->pdu);
05340         free((char *) rp);
05341         /*
05342          * There shouldn't be any more requests with the same reqid.  
05343          */
05344         break;
05345       }
05346       /*
05347        * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock should be per session ! 
05348        */
05349     }
05350   } else {
05351     if (sp->callback) {
05352       /*
05353        * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); 
05354        */
05355       handled = 1;
05356       sp->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
05357                    sp, pdu->reqid, pdu, sp->callback_magic);
05358       /*
05359        * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); 
05360        */
05361     }
05362   }
05363 
05364   /*
05365    * Call USM to free any securityStateRef supplied with the message.  
05366    */
05367   if (pdu != NULL && pdu->securityStateRef &&
05368       pdu->command == SNMP_MSG_TRAP2) {
05369     sptr = find_sec_mod(pdu->securityModel);
05370     if (sptr) {
05371       if (sptr->pdu_free_state_ref) {
05372         (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
05373       } else {
05374         snmp_log(LOG_ERR,
05375                  "Security Model %d can't free state references\n",
05376                  pdu->securityModel);
05377       }
05378     } else {
05379       snmp_log(LOG_ERR,
05380                "Can't find security model to free ptr: %d\n",
05381                pdu->securityModel);
05382     }
05383     pdu->securityStateRef = NULL;
05384   }
05385 
05386   if (!handled) {
05387     snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
05388     DEBUGMSGTL(("sess_process_packet", "unhandled PDU\n"));
05389   }
05390 
05391   snmp_free_pdu(pdu);
05392   return 0;
05393 }
05394 
05395 /*
05396  * Checks to see if any of the fd's set in the fdset belong to
05397  * snmp.  Each socket with it's fd set has a packet read from it
05398  * and snmp_parse is called on the packet received.  The resulting pdu
05399  * is passed to the callback routine for that session.  If the callback
05400  * routine returns successfully, the pdu and it's request are deleted.
05401  */
05402 void
05403 snmp_read(fd_set * fdset)
05404 {
05405     struct session_list *slp;
05406     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
05407     for (slp = Sessions; slp; slp = slp->next) {
05408         snmp_sess_read((void *) slp, fdset);
05409     }
05410     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
05411 }
05412 
05413 /*
05414  * Same as snmp_read, but works just one session. 
05415  * returns 0 if success, -1 if fail 
05416  * MTR: can't lock here and at snmp_read 
05417  * Beware recursive send maybe inside snmp_read callback function. 
05418  */
05419 int
05420 _sess_read(void *sessp, fd_set * fdset)
05421 {
05422     struct session_list *slp = (struct session_list *) sessp;
05423     netsnmp_session *sp = slp ? slp->session : NULL;
05424     struct snmp_internal_session *isp = slp ? slp->internal : NULL;
05425     netsnmp_transport *transport = slp ? slp->transport : NULL;
05426     size_t          pdulen = 0, rxbuf_len = 65536;
05427     u_char         *rxbuf = NULL;
05428     int             length = 0, olength = 0, rc = 0;
05429     void           *opaque = NULL;
05430 
05431     if (!sp || !isp || !transport) {
05432         DEBUGMSGTL(("sess_read", "read fail: closing...\n"));
05433         return 0;
05434     }
05435 
05436     /* to avoid subagent crash */ 
05437     if (transport->sock < 0) { 
05438         snmp_log (LOG_INFO, "transport->sock got negative fd value %d\n", transport->sock);
05439         return 0; 
05440     }
05441 
05442     if (!fdset || !(FD_ISSET(transport->sock, fdset))) {
05443         DEBUGMSGTL(("sess_read", "not reading %d (fdset %p set %d)\n",
05444                     transport->sock, fdset,
05445                     fdset ? FD_ISSET(transport->sock, fdset) : -9));
05446         return 0;
05447     }
05448 
05449     sp->s_snmp_errno = 0;
05450     sp->s_errno = 0;
05451 
05452     if (transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN) {
05453         int             data_sock = transport->f_accept(transport);
05454 
05455         if (data_sock >= 0) {
05456             /*
05457              * We've successfully accepted a new stream-based connection.
05458              * It's not too clear what should happen here if we are using the
05459              * single-session API at this point.  Basically a "session
05460              * accepted" callback is probably needed to hand the new session
05461              * over to the application.
05462              * 
05463              * However, for now, as in the original snmp_api, we will ASSUME
05464              * that we're using the traditional API, and simply add the new
05465              * session to the list.  Note we don't have to get the Session
05466              * list lock here, because under that assumption we already hold
05467              * it (this is also why we don't just use snmp_add).
05468              * 
05469              * The moral of the story is: don't use listening stream-based
05470              * transports in a multi-threaded environment because something
05471              * will go HORRIBLY wrong (and also that SNMP/TCP is not trivial).
05472              * 
05473              * Another open issue: what should happen to sockets that have
05474              * been accept()ed from a listening socket when that original
05475              * socket is closed?  If they are left open, then attempting to
05476              * re-open the listening socket will fail, which is semantically
05477              * confusing.  Perhaps there should be some kind of chaining in
05478              * the transport structure so that they can all be closed.
05479              * Discuss.  ;-)
05480              */
05481 
05482             netsnmp_transport *new_transport=netsnmp_transport_copy(transport);
05483             if (new_transport != NULL) {
05484                 struct session_list *nslp = NULL;
05485 
05486                 new_transport->sock = data_sock;
05487                 new_transport->flags &= ~NETSNMP_TRANSPORT_FLAG_LISTEN;
05488 
05489                 nslp = (struct session_list *)snmp_sess_add_ex(sp,
05490                           new_transport, isp->hook_pre, isp->hook_parse,
05491                           isp->hook_post, isp->hook_build,
05492                           isp->hook_realloc_build, isp->check_packet,
05493                           isp->hook_create_pdu);
05494 
05495                 if (nslp != NULL) {
05496                     nslp->next = Sessions;
05497                     Sessions = nslp;
05498                     /*
05499                      * Tell the new session about its existance if possible.
05500                      */
05501                     DEBUGMSGTL(("sess_read",
05502                                 "perform callback with op=CONNECT\n"));
05503                     (void)nslp->session->callback(NETSNMP_CALLBACK_OP_CONNECT,
05504                                                   nslp->session, 0, NULL,
05505                                                   sp->callback_magic);
05506                 }
05507                 return 0;
05508             } else {
05509                 sp->s_snmp_errno = SNMPERR_MALLOC;
05510                 sp->s_errno = errno;
05511                 snmp_set_detail(strerror(errno));
05512                 return -1;
05513             }
05514         } else {
05515             sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
05516             sp->s_errno = errno;
05517             snmp_set_detail(strerror(errno));
05518             return -1;
05519         }
05520     }
05521 
05522     /*
05523      * Work out where to receive the data to.  
05524      */
05525 
05526     if (transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM) {
05527         if (isp->packet == NULL) {
05528             /*
05529              * We have no saved packet.  Allocate one.  
05530              */
05531             if ((isp->packet = (u_char *) malloc(rxbuf_len)) == NULL) {
05532                 DEBUGMSGTL(("sess_read", "can't malloc %d bytes for rxbuf\n",
05533                             rxbuf_len));
05534                 return 0;
05535             } else {
05536                 rxbuf = isp->packet;
05537                 isp->packet_size = rxbuf_len;
05538                 isp->packet_len = 0;
05539             }
05540         } else {
05541             /*
05542              * We have saved a partial packet from last time.  Extend that, if
05543              * necessary, and receive new data after the old data.  
05544              */
05545             u_char         *newbuf;
05546 
05547             if (isp->packet_size < isp->packet_len + rxbuf_len) {
05548                 newbuf =
05549                     (u_char *) realloc(isp->packet,
05550                                        isp->packet_len + rxbuf_len);
05551                 if (newbuf == NULL) {
05552                     DEBUGMSGTL(("sess_read",
05553                                 "can't malloc %d more for rxbuf (%d tot)\n",
05554                                 rxbuf_len, isp->packet_len + rxbuf_len));
05555                     return 0;
05556                 } else {
05557                     isp->packet = newbuf;
05558                     isp->packet_size = isp->packet_len + rxbuf_len;
05559                     rxbuf = isp->packet + isp->packet_len;
05560                 }
05561             } else {
05562                 rxbuf = isp->packet + isp->packet_len;
05563                 rxbuf_len = isp->packet_size - isp->packet_len;
05564             }
05565         }
05566     } else {
05567         if ((rxbuf = (u_char *) malloc(rxbuf_len)) == NULL) {
05568             DEBUGMSGTL(("sess_read", "can't malloc %d bytes for rxbuf\n",
05569                         rxbuf_len));
05570             return 0;
05571         }
05572     }
05573 
05574     length = transport->f_recv(transport, rxbuf, rxbuf_len, &opaque, &olength);
05575 
05576     if (length == -1 && !(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM)) {
05577         sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
05578         sp->s_errno = errno;
05579         snmp_set_detail(strerror(errno));
05580         SNMP_FREE(rxbuf);
05581         if (opaque != NULL) {
05582             SNMP_FREE(opaque);
05583         }
05584         return -1;
05585     }
05586 
05587     /*
05588      * Remote end closed connection.  
05589      */
05590 
05591     if (length <= 0 && transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM) {
05592         /*
05593          * Alert the application if possible.  
05594          */
05595         if (sp->callback != NULL) {
05596             DEBUGMSGTL(("sess_read", "perform callback with op=DISCONNECT\n"));
05597             (void) sp->callback(NETSNMP_CALLBACK_OP_DISCONNECT, sp, 0,
05598                                 NULL, sp->callback_magic);
05599         }
05600         /*
05601          * Close socket and mark session for deletion.  
05602          */
05603         DEBUGMSGTL(("sess_read", "fd %d closed\n", transport->sock));
05604         transport->f_close(transport);
05605         SNMP_FREE(isp->packet);
05606         if (opaque != NULL) {
05607             SNMP_FREE(opaque);
05608         }
05609         return -1;
05610     }
05611 
05612     if (transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM) {
05613         u_char *pptr = isp->packet;
05614         void *ocopy = NULL;
05615 
05616         isp->packet_len += length;
05617 
05618         while (isp->packet_len > 0) {
05619 
05620             /*
05621              * Get the total data length we're expecting (and need to wait
05622              * for).
05623              */
05624             if (isp->check_packet) {
05625                 pdulen = isp->check_packet(pptr, isp->packet_len);
05626             } else {
05627                 pdulen = asn_check_packet(pptr, isp->packet_len);
05628             }
05629 
05630             DEBUGMSGTL(("sess_read", "  loop packet_len %d, PDU length %d\n",
05631                         isp->packet_len, pdulen));
05632              
05633             if ((pdulen > MAX_PACKET_LENGTH) || (pdulen < 0)) {
05634                 /*
05635                  * Illegal length, drop the connection.  
05636                  */
05637                 snmp_log(LOG_ERR, 
05638                          "Received broken packet. Closing session.\n");
05639                 if (sp->callback != NULL) {
05640                   DEBUGMSGTL(("sess_read",
05641                               "perform callback with op=DISCONNECT\n"));
05642                   (void)sp->callback(NETSNMP_CALLBACK_OP_DISCONNECT,
05643                                      sp, 0, NULL, sp->callback_magic);
05644                 }
05645                 DEBUGMSGTL(("sess_read", "fd %d closed\n", transport->sock));
05646                 transport->f_close(transport);
05647                 if (opaque != NULL) {
05648                     SNMP_FREE(opaque);
05649                 }
05651                 return -1;
05652             }
05653 
05654             if (pdulen > isp->packet_len || pdulen == 0) {
05655                 /*
05656                  * We don't have a complete packet yet.  If we've already
05657                  * processed a packet, break out so we'll shift this packet
05658                  * to the start of the buffer. If we're already at the
05659                  * start, simply return and wait for more data to arrive.
05660                  */
05661                 DEBUGMSGTL(("sess_read",
05662                             "pkt not complete (need %d got %d so far)\n",
05663                             pdulen, isp->packet_len));
05664 
05665                 if (pptr != isp->packet)
05666                     break; /* opaque freed for us outside of loop. */
05667 
05668                 if (opaque != NULL) {
05669                     SNMP_FREE(opaque);
05670                 }
05671                 return 0;
05672             }
05673 
05674             /*  We have *at least* one complete packet in the buffer now.  If
05675                 we have possibly more than one packet, we must copy the opaque
05676                 pointer because we may need to reuse it for a later packet.  */
05677 
05678             if (pdulen < isp->packet_len) {
05679                 if (olength > 0 && opaque != NULL) {
05680                     ocopy = malloc(olength);
05681                     if (ocopy != NULL) {
05682                         memcpy(ocopy, opaque, olength);
05683                     }
05684                 }
05685             } else if (pdulen == isp->packet_len) {
05686                 /*  Common case -- exactly one packet.  No need to copy the
05687                     opaque pointer.  */
05688                 ocopy = opaque;
05689                 opaque = NULL;
05690             }
05691 
05692             if ((rc = _sess_process_packet(sessp, sp, isp, transport,
05693                                            ocopy, ocopy?olength:0, pptr,
05694                                            pdulen))) {
05695                 /*
05696                  * Something went wrong while processing this packet -- set the
05697                  * errno.  
05698                  */
05699                 if (sp->s_snmp_errno != 0) {
05700                     SET_SNMP_ERROR(sp->s_snmp_errno);
05701                 }
05702             }
05703 
05704             /*  ocopy has been free()d by _sess_process_packet by this point,
05705                 so set it to NULL.  */
05706 
05707             ocopy = NULL;
05708 
05709             /*  Step past the packet we've just dealt with.  */
05710 
05711             pptr += pdulen;
05712             isp->packet_len -= pdulen;
05713         }
05714 
05715         /*  If we had more than one packet, then we were working with copies
05716             of the opaque pointer, so we still need to free() the opaque
05717             pointer itself.  */
05718 
05719         if (opaque != NULL) {
05720             SNMP_FREE(opaque);
05721         }
05722 
05723         if (isp->packet_len >= MAXIMUM_PACKET_SIZE) {
05724             /*
05725              * Obviously this should never happen!  
05726              */
05727             snmp_log(LOG_ERR,
05728                      "too large packet_len = %lu, dropping connection %d\n",
05729                      (unsigned long)(isp->packet_len), transport->sock);
05730             transport->f_close(transport);
05732             return -1;
05733         } else if (isp->packet_len == 0) {
05734             /*
05735              * This is good: it means the packet buffer contained an integral
05736              * number of PDUs, so we don't have to save any data for next
05737              * time.  We can free() the buffer now to keep the memory
05738              * footprint down.
05739              */
05740             SNMP_FREE(isp->packet);
05741             isp->packet = NULL;
05742             isp->packet_size = 0;
05743             isp->packet_len = 0;
05744             return rc;
05745         }
05746 
05747         /*
05748          * If we get here, then there is a partial packet of length
05749          * isp->packet_len bytes starting at pptr left over.  Move that to the
05750          * start of the buffer, and then realloc() the buffer down to size to
05751          * reduce the memory footprint.  
05752          */
05753 
05754         memmove(isp->packet, pptr, isp->packet_len);
05755         DEBUGMSGTL(("sess_read", "end: memmove(%p, %p, %d); realloc(%p, %d)\n",
05756                     isp->packet, pptr, isp->packet_len, isp->packet,
05757                     isp->packet_len));
05758 
05759         if ((rxbuf = (u_char *)realloc(isp->packet, isp->packet_len)) == NULL) {
05760             /*
05761              * I don't see why this should ever fail, but it's not a big deal.
05762              */
05763             DEBUGMSGTL(("sess_read", "realloc() failed\n"));
05764         } else {
05765             DEBUGMSGTL(("sess_read", "realloc() okay, old buffer %p, new %p\n",
05766                         isp->packet, rxbuf));
05767             isp->packet = rxbuf;
05768             isp->packet_size = isp->packet_len;
05769         }
05770         return rc;
05771     } else {
05772         rc = _sess_process_packet(sessp, sp, isp, transport, opaque,
05773                                   olength, rxbuf, length);
05774         SNMP_FREE(rxbuf);
05775         return rc;
05776     }
05777 }
05778 
05779 
05780 
05781 /*
05782  * returns 0 if success, -1 if fail 
05783  */
05784 int
05785 snmp_sess_read(void *sessp, fd_set * fdset)
05786 {
05787     struct session_list *psl;
05788     netsnmp_session *pss;
05789     int             rc;
05790 
05791     rc = _sess_read(sessp, fdset);
05792     psl = (struct session_list *) sessp;
05793     pss = psl->session;
05794     if (rc && pss->s_snmp_errno) {
05795         SET_SNMP_ERROR(pss->s_snmp_errno);
05796     }
05797     return rc;
05798 }
05799 
05800 
05801 /*
05802  * Returns info about what snmp requires from a select statement.
05803  * numfds is the number of fds in the list that are significant.
05804  * All file descriptors opened for SNMP are OR'd into the fdset.
05805  * If activity occurs on any of these file descriptors, snmp_read
05806  * should be called with that file descriptor set
05807  *
05808  * The timeout is the latest time that SNMP can wait for a timeout.  The
05809  * select should be done with the minimum time between timeout and any other
05810  * timeouts necessary.  This should be checked upon each invocation of select.
05811  * If a timeout is received, snmp_timeout should be called to check if the
05812  * timeout was for SNMP.  (snmp_timeout is idempotent)
05813  *
05814  * The value of block indicates how the timeout value is interpreted.
05815  * If block is true on input, the timeout value will be treated as undefined,
05816  * but it must be available for setting in snmp_select_info.  On return,
05817  * block is set to true if the value returned for timeout is undefined;
05818  * when block is set to false, timeout may be used as a parmeter to 'select'.
05819  *
05820  * snmp_select_info returns the number of open sockets.  (i.e. The number of
05821  * sessions open)
05822  */
05823 
05824 int
05825 snmp_select_info(int *numfds,
05826                  fd_set * fdset, struct timeval *timeout, int *block)
05827     /*
05828      * input:  set to 1 if input timeout value is undefined  
05829      * set to 0 if input timeout value is defined    
05830      * output: set to 1 if output timeout value is undefined 
05831      * set to 0 if output rimeout vlaue id defined   
05832      */
05833 {
05834     return snmp_sess_select_info((void *) 0, numfds, fdset, timeout,
05835                                  block);
05836 }
05837 
05838 /*
05839  * Same as snmp_select_info, but works just one session. 
05840  */
05841 int
05842 snmp_sess_select_info(void *sessp,
05843                       int *numfds,
05844                       fd_set * fdset, struct timeval *timeout, int *block)
05845 {
05846     struct session_list *slptest = (struct session_list *) sessp;
05847     struct session_list *slp, *next = NULL;
05848     netsnmp_request_list *rp;
05849     struct timeval  now, earliest, delta;
05850     int             active = 0, requests = 0;
05851     int             next_alarm = 0;
05852 
05853     timerclear(&earliest);
05854 
05855     /*
05856      * For each request outstanding, add its socket to the fdset,
05857      * and if it is the earliest timeout to expire, mark it as lowest.
05858      * If a single session is specified, do just for that session.
05859      */
05860 
05861     if (sessp) {
05862         slp = slptest;
05863     } else {
05864         slp = Sessions;
05865     }
05866 
05867     DEBUGMSGTL(("sess_select", "for %s session%s: ",
05868                 sessp ? "single" : "all", sessp ? "" : "s"));
05869 
05870     for (; slp; slp = next) {
05871         next = slp->next;
05872 
05873         if (slp->transport == NULL) {
05874             /*
05875              * Close in progress -- skip this one.  
05876              */
05877             DEBUGMSG(("sess_select", "skip "));
05878             continue;
05879         }
05880 
05881         if (slp->transport->sock == -1) {
05882             /*
05883              * This session was marked for deletion.  
05884              */
05885             DEBUGMSG(("sess_select", "delete\n"));
05886             if (sessp == NULL) {
05887                 snmp_close(slp->session);
05888             } else {
05889                 snmp_sess_close(slp);
05890             }
05891             DEBUGMSGTL(("sess_select", "for %s session%s: ",
05892                         sessp ? "single" : "all", sessp ? "" : "s"));
05893             continue;
05894         }
05895 
05896         DEBUGMSG(("sess_select", "%d ", slp->transport->sock));
05897         if ((slp->transport->sock + 1) > *numfds) {
05898             *numfds = (slp->transport->sock + 1);
05899         }
05900 
05901         FD_SET(slp->transport->sock, fdset);
05902         if (slp->internal != NULL && slp->internal->requests) {
05903             /*
05904              * Found another session with outstanding requests.  
05905              */
05906             requests++;
05907             for (rp = slp->internal->requests; rp; rp = rp->next_request) {
05908                 if ((!timerisset(&earliest)
05909                      || (timercmp(&rp->expire, &earliest, <)))) {
05910                     earliest = rp->expire;
05911                     DEBUGMSG(("verbose:sess_select","(to in %d.%d sec) ",
05912                                earliest.tv_sec, earliest.tv_usec));
05913                 }
05914             }
05915         }
05916 
05917         active++;
05918         if (sessp) {
05919             /*
05920              * Single session processing.  
05921              */
05922             break;
05923         }
05924     }
05925     DEBUGMSG(("sess_select", "\n"));
05926 
05927     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) {
05928         next_alarm = get_next_alarm_delay_time(&delta);
05929         DEBUGMSGT(("sess_select","next alarm %d.%d sec\n",
05930                    delta.tv_sec, delta.tv_usec));
05931     }
05932     if (next_alarm == 0 && requests == 0) {
05933         /*
05934          * If none are active, skip arithmetic.  
05935          */
05936         DEBUGMSGT(("sess_select","blocking:no session requests or alarms.\n"));
05937         *block = 1; /* can block - timeout value is undefined if no requests */
05938         return active;
05939     }
05940 
05941     /*
05942      * * Now find out how much time until the earliest timeout.  This
05943      * * transforms earliest from an absolute time into a delta time, the
05944      * * time left until the select should timeout.
05945      */
05946     gettimeofday(&now, (struct timezone *) 0);
05947     /*
05948      * Now = now;
05949      */
05950 
05951     if (next_alarm) {
05952         delta.tv_sec += now.tv_sec;
05953         delta.tv_usec += now.tv_usec;
05954         while (delta.tv_usec >= 1000000) {
05955             delta.tv_usec -= 1000000;
05956             delta.tv_sec += 1;
05957         }
05958         if (!timerisset(&earliest) ||
05959             ((earliest.tv_sec > delta.tv_sec) ||
05960              ((earliest.tv_sec == delta.tv_sec) &&
05961               (earliest.tv_usec > delta.tv_usec)))) {
05962             earliest.tv_sec = delta.tv_sec;
05963             earliest.tv_usec = delta.tv_usec;
05964         }
05965     }
05966 
05967     if (earliest.tv_sec < now.tv_sec) {
05968         DEBUGMSGT(("verbose:sess_select","timer overdue\n"));
05969         earliest.tv_sec = 0;
05970         earliest.tv_usec = 0;
05971     } else if (earliest.tv_sec == now.tv_sec) {
05972         earliest.tv_sec = 0;
05973         earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
05974         if (earliest.tv_usec < 0) {
05975             earliest.tv_usec = 100;
05976         }
05977         DEBUGMSGT(("verbose:sess_select","timer due *real* soon. %d usec\n",
05978                    earliest.tv_usec));
05979     } else {
05980         earliest.tv_sec = (earliest.tv_sec - now.tv_sec);
05981         earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
05982         if (earliest.tv_usec < 0) {
05983             earliest.tv_sec--;
05984             earliest.tv_usec = (1000000L + earliest.tv_usec);
05985         }
05986         DEBUGMSGT(("verbose:sess_select","timer due in %d.%d sec\n",
05987                    earliest.tv_sec, earliest.tv_usec));
05988     }
05989 
05990     /*
05991      * if it was blocking before or our delta time is less, reset timeout 
05992      */
05993     if ((*block || (timercmp(&earliest, timeout, <)))) {
05994         DEBUGMSGT(("verbose:sess_select",
05995                    "setting timer to %d.%d sec, clear block (was %d)\n",
05996                    earliest.tv_sec, earliest.tv_usec, *block));
05997         *timeout = earliest;
05998         *block = 0;
05999     }
06000     return active;
06001 }
06002 
06003 /*
06004  * snmp_timeout should be called whenever the timeout from snmp_select_info
06005  * expires, but it is idempotent, so snmp_timeout can be polled (probably a
06006  * cpu expensive proposition).  snmp_timeout checks to see if any of the
06007  * sessions have an outstanding request that has timed out.  If it finds one
06008  * (or more), and that pdu has more retries available, a new packet is formed
06009  * from the pdu and is resent.  If there are no more retries available, the
06010  *  callback for the session is used to alert the user of the timeout.
06011  */
06012 void
06013 snmp_timeout(void)
06014 {
06015     struct session_list *slp;
06016     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
06017     for (slp = Sessions; slp; slp = slp->next) {
06018         snmp_sess_timeout((void *) slp);
06019     }
06020     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
06021 }
06022 
06023 static int
06024 snmp_resend_request(struct session_list *slp, netsnmp_request_list *rp,
06025                     int incr_retries)
06026 {
06027     struct snmp_internal_session *isp;
06028     netsnmp_session *sp;
06029     netsnmp_transport *transport;
06030     u_char         *pktbuf = NULL, *packet = NULL;
06031     size_t          pktbuf_len = 0, offset = 0, length = 0;
06032     struct timeval  tv, now;
06033     int             result = 0;
06034 
06035     sp = slp->session;
06036     isp = slp->internal;
06037     transport = slp->transport;
06038     if (!sp || !isp || !transport) {
06039         DEBUGMSGTL(("sess_read", "resend fail: closing...\n"));
06040         return 0;
06041     }
06042 
06043     if ((pktbuf = (u_char *)malloc(2048)) == NULL) {
06044         DEBUGMSGTL(("sess_resend",
06045                     "couldn't malloc initial packet buffer\n"));
06046         return 0;
06047     } else {
06048         pktbuf_len = 2048;
06049     }
06050 
06051     if (incr_retries) {
06052         rp->retries++;
06053     }
06054 
06055     /*
06056      * Always increment msgId for resent messages.  
06057      */
06058     rp->pdu->msgid = rp->message_id = snmp_get_next_msgid();
06059 
06060     if (isp->hook_realloc_build) {
06061         result = isp->hook_realloc_build(sp, rp->pdu,
06062                                          &pktbuf, &pktbuf_len, &offset);
06063 
06064         packet = pktbuf;
06065         length = offset;
06066     } else if (isp->hook_build) {
06067         packet = pktbuf;
06068         length = pktbuf_len;
06069         result = isp->hook_build(sp, rp->pdu, pktbuf, &length);
06070     } else {
06071 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
06072         if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE)) {
06073             result =
06074                 snmp_build(&pktbuf, &pktbuf_len, &offset, sp, rp->pdu);
06075             packet = pktbuf + pktbuf_len - offset;
06076             length = offset;
06077         } else {
06078 #endif
06079             packet = pktbuf;
06080             length = pktbuf_len;
06081             result = snmp_build(&pktbuf, &length, &offset, sp, rp->pdu);
06082 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
06083         }
06084 #endif
06085     }
06086 
06087     if (result < 0) {
06088         /*
06089          * This should never happen.  
06090          */
06091         DEBUGMSGTL(("sess_resend", "encoding failure\n"));
06092         if (pktbuf != NULL) {
06093             SNMP_FREE(pktbuf);
06094         }
06095         return -1;
06096     }
06097 
06098     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET)) {
06099         if (transport->f_fmtaddr != NULL) {
06100             char           *str = NULL;
06101             str = transport->f_fmtaddr(transport, rp->pdu->transport_data,
06102                                        rp->pdu->transport_data_length);
06103             if (str != NULL) {
06104                 snmp_log(LOG_DEBUG, "\nResending %lu bytes to %s\n", 
06105                          (unsigned long)length, str);
06106                 SNMP_FREE(str);
06107             } else {
06108                 snmp_log(LOG_DEBUG, "\nResending %lu bytes to <UNKNOWN>\n",
06109                          (unsigned long)length);
06110             }
06111         }
06112         xdump(packet, length, "");
06113     }
06114 
06115     result = transport->f_send(transport, packet, length,
06116                                &(rp->pdu->transport_data),
06117                                &(rp->pdu->transport_data_length));
06118 
06119     /*
06120      * We are finished with the local packet buffer, if we allocated one (due
06121      * to there being no saved packet).  
06122      */
06123 
06124     if (pktbuf != NULL) {
06125         SNMP_FREE(pktbuf);
06126         pktbuf = packet = NULL;
06127     }
06128 
06129     if (result < 0) {
06130         sp->s_snmp_errno = SNMPERR_BAD_SENDTO;
06131         sp->s_errno = errno;
06132         snmp_set_detail(strerror(errno));
06133         return -1;
06134     } else {
06135         gettimeofday(&now, (struct timezone *) 0);
06136         tv = now;
06137         rp->time = tv;
06138         tv.tv_usec += rp->timeout;
06139         tv.tv_sec += tv.tv_usec / 1000000L;
06140         tv.tv_usec %= 1000000L;
06141         rp->expire = tv;
06142     }
06143     return 0;
06144 }
06145 
06146 
06147 
06148 void
06149 snmp_sess_timeout(void *sessp)
06150 {
06151     struct session_list *slp = (struct session_list *) sessp;
06152     netsnmp_session *sp;
06153     struct snmp_internal_session *isp;
06154     netsnmp_request_list *rp, *orp = NULL, *freeme = NULL;
06155     struct timeval  now;
06156     snmp_callback   callback;
06157     void           *magic;
06158     struct snmp_secmod_def *sptr;
06159 
06160     sp = slp->session;
06161     isp = slp->internal;
06162     if (!sp || !isp) {
06163         DEBUGMSGTL(("sess_read", "timeout fail: closing...\n"));
06164         return;
06165     }
06166 
06167     gettimeofday(&now, (struct timezone *) 0);
06168 
06169     /*
06170      * For each request outstanding, check to see if it has expired.
06171      */
06172     for (rp = isp->requests; rp; rp = rp->next_request) {
06173         if (freeme != NULL) {
06174             /*
06175              * frees rp's after the for loop goes on to the next_request 
06176              */
06177             free((char *) freeme);
06178             freeme = NULL;
06179         }
06180 
06181         if ((timercmp(&rp->expire, &now, <))) {
06182             if ((sptr = find_sec_mod(rp->pdu->securityModel)) != NULL &&
06183                 sptr->pdu_timeout != NULL) {
06184                 /*
06185                  * call security model if it needs to know about this 
06186                  */
06187                 (*sptr->pdu_timeout) (rp->pdu);
06188             }
06189 
06190             /*
06191              * this timer has expired 
06192              */
06193             if (rp->retries >= sp->retries) {
06194                 if (rp->callback) {
06195                     callback = rp->callback;
06196                     magic = rp->cb_data;
06197                 } else {
06198                     callback = sp->callback;
06199                     magic = sp->callback_magic;
06200                 }
06201 
06202                 /*
06203                  * No more chances, delete this entry 
06204                  */
06205                 if (callback) {
06206                     callback(NETSNMP_CALLBACK_OP_TIMED_OUT, sp,
06207                              rp->pdu->reqid, rp->pdu, magic);
06208                 }
06209                 if (isp->requests == rp) {
06210                     isp->requests = rp->next_request;
06211                     if (isp->requestsEnd == rp) {
06212                         isp->requestsEnd = NULL;
06213                     }
06214                 } else {
06215                     orp->next_request = rp->next_request;
06216                     if (isp->requestsEnd == rp) {
06217                         isp->requestsEnd = orp;
06218                     }
06219                 }
06220                 snmp_free_pdu(rp->pdu); /* FIX  rp is already free'd! */
06221                 freeme = rp;
06222                 continue;       /* don't update orp below */
06223             } else {
06224                 if (snmp_resend_request(slp, rp, TRUE)) {
06225                     break;
06226                 }
06227             }
06228         }
06229         orp = rp;
06230     }
06231 
06232     if (freeme != NULL) {
06233         free((char *) freeme);
06234         freeme = NULL;
06235     }
06236 }
06237 
06238 /*
06239  * lexicographical compare two object identifiers.
06240  * * Returns -1 if name1 < name2,
06241  * *          0 if name1 = name2,
06242  * *          1 if name1 > name2
06243  * *
06244  * * Caution: this method is called often by
06245  * *          command responder applications (ie, agent).
06246  */
06247 int
06248 snmp_oid_ncompare(const oid * in_name1,
06249                   size_t len1,
06250                   const oid * in_name2, size_t len2, size_t max_len)
06251 {
06252     register int    len;
06253     register const oid *name1 = in_name1;
06254     register const oid *name2 = in_name2;
06255     size_t          min_len;
06256 
06257     /*
06258      * len = minimum of len1 and len2 
06259      */
06260     if (len1 < len2)
06261         min_len = len1;
06262     else
06263         min_len = len2;
06264 
06265     if (min_len > max_len)
06266         min_len = max_len;
06267 
06268     len = min_len;
06269 
06270     /*
06271      * find first non-matching OID 
06272      */
06273     while (len-- > 0) {
06274         /*
06275          * these must be done in seperate comparisons, since
06276          * subtracting them and using that result has problems with
06277          * subids > 2^31. 
06278          */
06279         if (*(name1) != *(name2)) {
06280             if (*(name1) < *(name2))
06281                 return -1;
06282             return 1;
06283         }
06284         name1++;
06285         name2++;
06286     }
06287 
06288     if (min_len != max_len) {
06289         /*
06290          * both OIDs equal up to length of shorter OID 
06291          */
06292         if (len1 < len2)
06293             return -1;
06294         if (len2 < len1)
06295             return 1;
06296     }
06297 
06298     return 0;
06299 }
06300 
06308 int
06309 snmp_oid_compare(const oid * in_name1,
06310                  size_t len1, const oid * in_name2, size_t len2)
06311 {
06312     register int    len;
06313     register const oid *name1 = in_name1;
06314     register const oid *name2 = in_name2;
06315 
06316     /*
06317      * len = minimum of len1 and len2 
06318      */
06319     if (len1 < len2)
06320         len = len1;
06321     else
06322         len = len2;
06323     /*
06324      * find first non-matching OID 
06325      */
06326     while (len-- > 0) {
06327         /*
06328          * these must be done in seperate comparisons, since
06329          * subtracting them and using that result has problems with
06330          * subids > 2^31. 
06331          */
06332         if (*(name1) != *(name2)) {
06333             if (*(name1) < *(name2))
06334                 return -1;
06335             return 1;
06336         }
06337         name1++;
06338         name2++;
06339     }
06340     /*
06341      * both OIDs equal up to length of shorter OID 
06342      */
06343     if (len1 < len2)
06344         return -1;
06345     if (len2 < len1)
06346         return 1;
06347     return 0;
06348 }
06349 
06357 int
06358 netsnmp_oid_compare_ll(const oid * in_name1,
06359                        size_t len1, const oid * in_name2, size_t len2,
06360                        size_t *offpt)
06361 {
06362     register int    len;
06363     register const oid *name1 = in_name1;
06364     register const oid *name2 = in_name2;
06365     int initlen;
06366 
06367     /*
06368      * len = minimum of len1 and len2 
06369      */
06370     if (len1 < len2)
06371         initlen = len = len1;
06372     else
06373         initlen = len = len2;
06374     /*
06375      * find first non-matching OID 
06376      */
06377     while (len-- > 0) {
06378         /*
06379          * these must be done in seperate comparisons, since
06380          * subtracting them and using that result has problems with
06381          * subids > 2^31. 
06382          */
06383         if (*(name1) != *(name2)) {
06384             *offpt = initlen - len;
06385             if (*(name1) < *(name2))
06386                 return -1;
06387             return 1;
06388         }
06389         name1++;
06390         name2++;
06391     }
06392     /*
06393      * both OIDs equal up to length of shorter OID 
06394      */
06395     *offpt = initlen - len;
06396     if (len1 < len2)
06397         return -1;
06398     if (len2 < len1)
06399         return 1;
06400     return 0;
06401 }
06402 
06410 int
06411 snmp_oidtree_compare(const oid * in_name1,
06412                      size_t len1, const oid * in_name2, size_t len2)
06413 {
06414     int             len = ((len1 < len2) ? len1 : len2);
06415 
06416     return (snmp_oid_compare(in_name1, len, in_name2, len));
06417 }
06418 
06419 int
06420 snmp_oidsubtree_compare(const oid * in_name1,
06421                      size_t len1, const oid * in_name2, size_t len2)
06422 {
06423     int             len = ((len1 < len2) ? len1 : len2);
06424 
06425     return (snmp_oid_compare(in_name1, len1, in_name2, len));
06426 }
06427 
06438 int
06439 netsnmp_oid_equals(const oid * in_name1,
06440                    size_t len1, const oid * in_name2, size_t len2)
06441 {
06442     register const oid *name1 = in_name1;
06443     register const oid *name2 = in_name2;
06444     register int    len = len1;
06445 
06446     /*
06447      * len = minimum of len1 and len2 
06448      */
06449     if (len1 != len2)
06450         return 1;
06451     /*
06452      * find first non-matching OID 
06453      */
06454     while (len-- > 0) {
06455         /*
06456          * these must be done in seperate comparisons, since
06457          * subtracting them and using that result has problems with
06458          * subids > 2^31. 
06459          */
06460         if (*(name1++) != *(name2++))
06461             return 1;
06462     }
06463     return 0;
06464 }
06465 
06474 int
06475 netsnmp_oid_is_subtree(const oid * in_name1,
06476                        size_t len1, const oid * in_name2, size_t len2)
06477 {
06478     if (len1 > len2)
06479         return 1;
06480 
06481     if (memcmp(in_name1, in_name2, len1 * sizeof(oid)))
06482         return 1;
06483 
06484     return 0;
06485 }
06486 
06494 int
06495 netsnmp_oid_find_prefix(const oid * in_name1, size_t len1,
06496                         const oid * in_name2, size_t len2)
06497 {
06498     int i;
06499     size_t min_size;
06500 
06501     if (!in_name1 || !in_name2 || !len1 || !len2)
06502         return -1;
06503 
06504     if (in_name1[0] != in_name2[0])
06505         return 0;   /* No match */
06506     min_size = SNMP_MIN(len1, len2);
06507     for(i = 0; i < (int)min_size; i++) {
06508         if (in_name1[i] != in_name2[i])
06509             return i + 1;    /* Why +1 ?? */
06510     }
06511     return min_size;    /* or +1? - the spec isn't totally clear */
06512 }
06513 
06514 static int _check_range(struct tree *tp, long ltmp, int *resptr,
06515                         const char *errmsg)
06516 {
06517     char *cp   = NULL;
06518     char *temp = NULL;
06519     int   temp_len = 0;
06520     int check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
06521                                         NETSNMP_DS_LIB_DONT_CHECK_RANGE);
06522   
06523     if (check && tp && tp->ranges) {
06524         struct range_list *rp = tp->ranges;
06525         while (rp) {
06526             if (rp->low <= ltmp && ltmp <= rp->high) break;
06527                                   /* Allow four digits per range value */
06528             temp_len += ((rp->low != rp->high) ? 14 : 8 );
06529             rp = rp->next;
06530         }
06531         if (!rp) {
06532             *resptr = SNMPERR_RANGE;
06533             temp = (char *)malloc( temp_len+strlen(errmsg)+7);
06534             if ( temp ) {
06535                 /* Append the Display Hint range information to the error message */
06536                 sprintf( temp, "%s :: {", errmsg );
06537                 cp = temp+(strlen(temp));
06538                 for ( rp = tp->ranges; rp; rp=rp->next ) {
06539                     if ( rp->low != rp->high ) 
06540                         sprintf( cp, "(%d..%d), ", rp->low, rp->high );
06541                     else
06542                         sprintf( cp, "(%d), ", rp->low );
06543                     cp += strlen(cp);
06544                 }
06545                 *(cp-2) = '}';   /* Replace the final comma with a '}' */
06546                 *(cp-1) = 0;
06547                 snmp_set_detail(temp);
06548                 free(temp);
06549             }
06550             return 0;
06551         }
06552     }
06553     free(temp);
06554     return 1;
06555 }
06556         
06557 
06558 /*
06559  * Add a variable with the requested name to the end of the list of
06560  * variables for this pdu.
06561  */
06562 netsnmp_variable_list *
06563 snmp_pdu_add_variable(netsnmp_pdu *pdu,
06564                       const oid * name,
06565                       size_t name_length,
06566                       u_char type, const u_char * value, size_t len)
06567 {
06568     return snmp_varlist_add_variable(&pdu->variables, name, name_length,
06569                                      type, value, len);
06570 }
06571 
06572 /*
06573  * Add a variable with the requested name to the end of the list of
06574  * variables for this pdu.
06575  */
06576 netsnmp_variable_list *
06577 snmp_varlist_add_variable(netsnmp_variable_list ** varlist,
06578                           const oid * name,
06579                           size_t name_length,
06580                           u_char type, const u_char * value, size_t len)
06581 {
06582     netsnmp_variable_list *vars, *vtmp;
06583     int rc;
06584 
06585     if (varlist == NULL)
06586         return NULL;
06587 
06588     vars = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
06589     if (vars == NULL)
06590         return NULL;
06591 
06592     vars->type = type;
06593 
06594     rc = snmp_set_var_value( vars, value, len );
06595     if (( 0 != rc ) ||
06596         (name != NULL && snmp_set_var_objid(vars, name, name_length))) {
06597         snmp_free_var(vars);
06598         return (0);
06599     }
06600 
06601     /*
06602      * put only qualified variable onto varlist 
06603      */
06604     if (*varlist == NULL) {
06605         *varlist = vars;
06606     } else {
06607         for (vtmp = *varlist; vtmp->next_variable;
06608              vtmp = vtmp->next_variable);
06609 
06610         vtmp->next_variable = vars;
06611     }
06612 
06613     return vars;
06614 }
06615 
06616 
06617 
06618 /*
06619  * Add a variable with the requested name to the end of the list of
06620  * variables for this pdu.
06621  * Returns:
06622  * may set these error types :
06623  * SNMPERR_RANGE - type, value, or length not found or out of range
06624  * SNMPERR_VALUE - value is not correct
06625  * SNMPERR_BAD_NAME - name is not found
06626  *
06627  * returns 0 if success, error if failure.
06628  */
06629 int
06630 snmp_add_var(netsnmp_pdu *pdu,
06631              const oid * name, size_t name_length, char type, const char *value)
06632 {
06633     char           *st;
06634     const char     *cp;
06635     char           *ecp, *vp;
06636     int             result = SNMPERR_SUCCESS;
06637 #ifndef NETSNMP_DISABLE_MIB_LOADING
06638     int             check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
06639                                              NETSNMP_DS_LIB_DONT_CHECK_RANGE);
06640     int             do_hint = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
06641                                              NETSNMP_DS_LIB_NO_DISPLAY_HINT);
06642     u_char         *hintptr;
06643     struct tree    *tp;
06644 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06645     u_char         *buf = NULL;
06646     const u_char   *buf_ptr = NULL;
06647     size_t          buf_len = 0, value_len = 0, tint;
06648     in_addr_t       atmp;
06649     long            ltmp;
06650     int             itmp;
06651     struct enum_list *ep;
06652 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
06653     double          dtmp;
06654     float           ftmp;
06655 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
06656     struct counter64 c64tmp;
06657 
06658 #ifndef NETSNMP_DISABLE_MIB_LOADING
06659     tp = get_tree(name, name_length, get_tree_head());
06660     if (!tp || !tp->type || tp->type > TYPE_SIMPLE_LAST) {
06661         check = 0;
06662     }
06663     if (!(tp && tp->hint))
06664         do_hint = 0;
06665 
06666     if (tp && type == '=') {
06667         /*
06668          * generic assignment - let the tree node decide value format 
06669          */
06670         switch (tp->type) {
06671         case TYPE_INTEGER:
06672         case TYPE_INTEGER32:
06673             type = 'i';
06674             break;
06675         case TYPE_GAUGE:
06676         case TYPE_UNSIGNED32:
06677             type = 'u';
06678             break;
06679         case TYPE_UINTEGER:
06680             type = '3';
06681             break;
06682         case TYPE_COUNTER:
06683             type = 'c';
06684             break;
06685         case TYPE_COUNTER64:
06686             type = 'C';
06687             break;
06688         case TYPE_TIMETICKS:
06689             type = 't';
06690             break;
06691         case TYPE_OCTETSTR:
06692             type = 's';
06693             break;
06694         case TYPE_BITSTRING:
06695             type = 'b';
06696             break;
06697         case TYPE_IPADDR:
06698             type = 'a';
06699             break;
06700         case TYPE_OBJID:
06701             type = 'o';
06702             break;
06703         }
06704     }
06705 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06706 
06707     switch (type) {
06708     case 'i':
06709 #ifndef NETSNMP_DISABLE_MIB_LOADING
06710         if (check && tp->type != TYPE_INTEGER
06711             && tp->type != TYPE_INTEGER32) {
06712             value = "INTEGER";
06713             result = SNMPERR_VALUE;
06714             goto type_error;
06715         }
06716 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06717         if (!*value)
06718             goto fail;
06719         ltmp = strtol(value, &ecp, 10);
06720         if (*ecp) {
06721 #ifndef NETSNMP_DISABLE_MIB_LOADING
06722             ep = tp ? tp->enums : NULL;
06723             while (ep) {
06724                 if (strcmp(value, ep->label) == 0) {
06725                     ltmp = ep->value;
06726                     break;
06727                 }
06728                 ep = ep->next;
06729             }
06730             if (!ep) {
06731 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06732                 result = SNMPERR_BAD_NAME;
06733                 snmp_set_detail(value);
06734                 break;
06735 #ifndef NETSNMP_DISABLE_MIB_LOADING
06736             }
06737 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06738         }
06739 
06740 #ifndef NETSNMP_DISABLE_MIB_LOADING
06741         if (!_check_range(tp, ltmp, &result, value))
06742             break;
06743 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06744         snmp_pdu_add_variable(pdu, name, name_length, ASN_INTEGER,
06745                               (u_char *) & ltmp, sizeof(ltmp));
06746         break;
06747 
06748     case 'u':
06749 #ifndef NETSNMP_DISABLE_MIB_LOADING
06750         if (check && tp->type != TYPE_GAUGE && tp->type != TYPE_UNSIGNED32) {
06751             value = "Unsigned32";
06752             result = SNMPERR_VALUE;
06753             goto type_error;
06754         }
06755 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06756         ltmp = strtoul(value, &ecp, 10);
06757         if (*value && !*ecp)
06758             snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
06759                                   (u_char *) & ltmp, sizeof(ltmp));
06760         else
06761             goto fail;
06762         break;
06763 
06764     case '3':
06765 #ifndef NETSNMP_DISABLE_MIB_LOADING
06766         if (check && tp->type != TYPE_UINTEGER) {
06767             value = "UInteger32";
06768             result = SNMPERR_VALUE;
06769             goto type_error;
06770         }
06771 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06772         ltmp = strtoul(value, &ecp, 10);
06773         if (*value && !*ecp)
06774             snmp_pdu_add_variable(pdu, name, name_length, ASN_UINTEGER,
06775                                   (u_char *) & ltmp, sizeof(ltmp));
06776         else
06777             goto fail;
06778         break;
06779 
06780     case 'c':
06781 #ifndef NETSNMP_DISABLE_MIB_LOADING
06782         if (check && tp->type != TYPE_COUNTER) {
06783             value = "Counter32";
06784             result = SNMPERR_VALUE;
06785             goto type_error;
06786         }
06787 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06788         ltmp = strtoul(value, &ecp, 10);
06789         if (*value && !*ecp)
06790             snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
06791                                   (u_char *) & ltmp, sizeof(ltmp));
06792         else
06793             goto fail;
06794         break;
06795 
06796     case 'C':
06797 #ifndef NETSNMP_DISABLE_MIB_LOADING
06798         if (check && tp->type != TYPE_COUNTER64) {
06799             value = "Counter64";
06800             result = SNMPERR_VALUE;
06801             goto type_error;
06802         }
06803 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06804         if (read64(&c64tmp, value))
06805             snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER64,
06806                                   (u_char *) & c64tmp, sizeof(c64tmp));
06807         else
06808             goto fail;
06809         break;
06810 
06811     case 't':
06812 #ifndef NETSNMP_DISABLE_MIB_LOADING
06813         if (check && tp->type != TYPE_TIMETICKS) {
06814             value = "Timeticks";
06815             result = SNMPERR_VALUE;
06816             goto type_error;
06817         }
06818 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06819         ltmp = strtoul(value, &ecp, 10);
06820         if (*value && !*ecp)
06821             snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
06822                                   (u_char *) & ltmp, sizeof(long));
06823         else
06824             goto fail;
06825         break;
06826 
06827     case 'a':
06828 #ifndef NETSNMP_DISABLE_MIB_LOADING
06829         if (check && tp->type != TYPE_IPADDR) {
06830             value = "IpAddress";
06831             result = SNMPERR_VALUE;
06832             goto type_error;
06833         }
06834 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06835         atmp = inet_addr(value);
06836         if (atmp != (long) -1 || !strcmp(value, "255.255.255.255"))
06837             snmp_pdu_add_variable(pdu, name, name_length, ASN_IPADDRESS,
06838                                   (u_char *) & atmp, sizeof(atmp));
06839         else
06840             goto fail;
06841         break;
06842 
06843     case 'o':
06844 #ifndef NETSNMP_DISABLE_MIB_LOADING
06845         if (check && tp->type != TYPE_OBJID) {
06846             value = "OBJECT IDENTIFIER";
06847             result = SNMPERR_VALUE;
06848             goto type_error;
06849         }
06850 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06851         if ((buf = (u_char *)malloc(sizeof(oid) * MAX_OID_LEN)) == NULL) {
06852             result = SNMPERR_MALLOC;
06853         } else {
06854             tint = MAX_OID_LEN;
06855             if (snmp_parse_oid(value, (oid *) buf, &tint)) {
06856                 snmp_pdu_add_variable(pdu, name, name_length,
06857                                       ASN_OBJECT_ID, buf,
06858                                       sizeof(oid) * tint);
06859             } else {
06860                 result = snmp_errno;    /*MTCRITICAL_RESOURCE */
06861             }
06862         }
06863         break;
06864 
06865     case 's':
06866     case 'x':
06867     case 'd':
06868 #ifndef NETSNMP_DISABLE_MIB_LOADING
06869         if (check && tp->type != TYPE_OCTETSTR && tp->type != TYPE_BITSTRING) {
06870             value = "OCTET STRING";
06871             result = SNMPERR_VALUE;
06872             goto type_error;
06873         }
06874         if ('s' == type && do_hint && !parse_octet_hint(tp->hint, value, &hintptr, &itmp)) {
06875             if (_check_range(tp, itmp, &result, "Value does not match DISPLAY-HINT")) {
06876                 snmp_pdu_add_variable(pdu, name, name_length,
06877                                       ASN_OCTET_STR, hintptr, itmp);
06878             }
06879             SNMP_FREE(hintptr);
06880             hintptr = buf;
06881             break;
06882         }
06883 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06884         if (type == 'd') {
06885             if (!snmp_decimal_to_binary
06886                 (&buf, &buf_len, &value_len, 1, value)) {
06887                 result = SNMPERR_VALUE;
06888                 snmp_set_detail(value);
06889                 break;
06890             }
06891             buf_ptr = buf;
06892         } else if (type == 'x') {
06893             if (!snmp_hex_to_binary(&buf, &buf_len, &value_len, 1, value)) {
06894                 result = SNMPERR_VALUE;
06895                 snmp_set_detail(value);
06896                 break;
06897             }
06898             /* initialize itmp value so that range check below works */
06899             itmp = value_len;
06900             buf_ptr = buf;
06901         } else if (type == 's') {
06902             buf_ptr = (const u_char *)value;
06903             value_len = strlen(value);
06904         }
06905 #ifndef NETSNMP_DISABLE_MIB_LOADING
06906         if (!_check_range(tp, value_len, &result, "Bad string length"))
06907             break;
06908 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06909         snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
06910                               buf_ptr, value_len);
06911         break;
06912 
06913     case 'n':
06914         snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, 0, 0);
06915         break;
06916 
06917     case 'b':
06918 #ifndef NETSNMP_DISABLE_MIB_LOADING
06919         if (check && (tp->type != TYPE_BITSTRING || !tp->enums)) {
06920             value = "BITS";
06921             result = SNMPERR_VALUE;
06922             goto type_error;
06923         }
06924 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06925         tint = 0;
06926         if ((buf = (u_char *) malloc(256)) == NULL) {
06927             result = SNMPERR_MALLOC;
06928             break;
06929         } else {
06930             buf_len = 256;
06931             memset(buf, 0, buf_len);
06932         }
06933 
06934 #ifndef NETSNMP_DISABLE_MIB_LOADING
06935         for (ep = tp ? tp->enums : NULL; ep; ep = ep->next) {
06936             if (ep->value / 8 >= (int) tint) {
06937                 tint = ep->value / 8 + 1;
06938             }
06939         }
06940 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06941 
06942         vp = strdup(value);
06943         for (cp = strtok_r(vp, " ,\t", &st); cp; cp = strtok_r(NULL, " ,\t", &st)) {
06944             int             ix, bit;
06945 
06946             ltmp = strtoul(cp, &ecp, 0);
06947             if (*ecp != 0) {
06948 #ifndef NETSNMP_DISABLE_MIB_LOADING
06949                 for (ep = tp ? tp->enums : NULL; ep != NULL; ep = ep->next) {
06950                     if (strncmp(ep->label, cp, strlen(ep->label)) == 0) {
06951                         break;
06952                     }
06953                 }
06954                 if (ep != NULL) {
06955                     ltmp = ep->value;
06956                 } else {
06957 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06958                     result = SNMPERR_BAD_NAME;
06959                     snmp_set_detail(cp);
06960                     SNMP_FREE(buf);
06961                     SNMP_FREE(vp);
06962                     goto out;
06963 #ifndef NETSNMP_DISABLE_MIB_LOADING
06964                 }
06965 #endif /* NETSNMP_DISABLE_MIB_LOADING */
06966             }
06967 
06968             ix = ltmp / 8;
06969             if (ix >= (int) tint) {
06970                 tint = ix + 1;
06971             }
06972             if (ix >= (int)buf_len && !snmp_realloc(&buf, &buf_len)) {
06973                 result = SNMPERR_MALLOC;
06974                 break;
06975             }
06976             bit = 0x80 >> ltmp % 8;
06977             buf[ix] |= bit;
06978             
06979         }
06980         SNMP_FREE(vp);
06981         snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
06982                               buf, tint);
06983         break;
06984 
06985 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
06986     case 'U':
06987         if (read64(&c64tmp, value))
06988             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_U64,
06989                                   (u_char *) & c64tmp, sizeof(c64tmp));
06990         else
06991             goto fail;
06992         break;
06993 
06994     case 'I':
06995         if (read64(&c64tmp, value))
06996             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_I64,
06997                                   (u_char *) & c64tmp, sizeof(c64tmp));
06998         else
06999             goto fail;
07000         break;
07001 
07002     case 'F':
07003         if (sscanf(value, "%f", &ftmp) == 1)
07004             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_FLOAT,
07005                                   (u_char *) & ftmp, sizeof(ftmp));
07006         else
07007             goto fail;
07008         break;
07009 
07010     case 'D':
07011         if (sscanf(value, "%lf", &dtmp) == 1)
07012             snmp_pdu_add_variable(pdu, name, name_length,
07013                                   ASN_OPAQUE_DOUBLE, (u_char *) & dtmp,
07014                                   sizeof(dtmp));
07015         else
07016             goto fail;
07017         break;
07018 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
07019 
07020     default:
07021         result = SNMPERR_VAR_TYPE;
07022         buf = (u_char *)calloc(1, 4);
07023         if (buf != NULL) {
07024             sprintf((char *)buf, "\"%c\"", type);
07025             snmp_set_detail((char *)buf);
07026         }
07027         break;
07028     }
07029 
07030     SNMP_FREE(buf);
07031     SET_SNMP_ERROR(result);
07032     return result;
07033 
07034 #ifndef NETSNMP_DISABLE_MIB_LOADING
07035   type_error:
07036     {
07037         char            error_msg[256];
07038         char            undef_msg[32];
07039         const char     *var_type;
07040         switch (tp->type) {
07041         case TYPE_OBJID:
07042             var_type = "OBJECT IDENTIFIER";
07043             break;
07044         case TYPE_OCTETSTR:
07045             var_type = "OCTET STRING";
07046             break;
07047         case TYPE_INTEGER:
07048             var_type = "INTEGER";
07049             break;
07050         case TYPE_NETADDR:
07051             var_type = "NetworkAddress";
07052             break;
07053         case TYPE_IPADDR:
07054             var_type = "IpAddress";
07055             break;
07056         case TYPE_COUNTER:
07057             var_type = "Counter32";
07058             break;
07059         case TYPE_GAUGE:
07060             var_type = "Gauge32";
07061             break;
07062         case TYPE_TIMETICKS:
07063             var_type = "Timeticks";
07064             break;
07065         case TYPE_OPAQUE:
07066             var_type = "Opaque";
07067             break;
07068         case TYPE_NULL:
07069             var_type = "Null";
07070             break;
07071         case TYPE_COUNTER64:
07072             var_type = "Counter64";
07073             break;
07074         case TYPE_BITSTRING:
07075             var_type = "BITS";
07076             break;
07077         case TYPE_NSAPADDRESS:
07078             var_type = "NsapAddress";
07079             break;
07080         case TYPE_UINTEGER:
07081             var_type = "UInteger";
07082             break;
07083         case TYPE_UNSIGNED32:
07084             var_type = "Unsigned32";
07085             break;
07086         case TYPE_INTEGER32:
07087             var_type = "Integer32";
07088             break;
07089         default:
07090             sprintf(undef_msg, "TYPE_%d", tp->type);
07091             var_type = undef_msg;
07092         }
07093         snprintf(error_msg, sizeof(error_msg),
07094                "Type of attribute is %s, not %s", var_type, value);
07095         error_msg[ sizeof(error_msg)-1 ] = 0;
07096         result = SNMPERR_VAR_TYPE;
07097         snmp_set_detail(error_msg);
07098         goto out;
07099     }
07100 #endif /* NETSNMP_DISABLE_MIB_LOADING */
07101   fail:
07102     result = SNMPERR_VALUE;
07103     snmp_set_detail(value);
07104   out:
07105     SET_SNMP_ERROR(result);
07106     return result;
07107 }
07108 
07109 /*
07110  * returns NULL or internal pointer to session
07111  * use this pointer for the other snmp_sess* routines,
07112  * which guarantee action will occur ONLY for this given session.
07113  */
07114 void           *
07115 snmp_sess_pointer(netsnmp_session * session)
07116 {
07117     struct session_list *slp;
07118 
07119     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
07120     for (slp = Sessions; slp; slp = slp->next) {
07121         if (slp->session == session) {
07122             break;
07123         }
07124     }
07125     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
07126 
07127     if (slp == NULL) {
07128         snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
07129         return (NULL);
07130     }
07131     return ((void *) slp);
07132 }
07133 
07134 /*
07135  * Input : an opaque pointer, returned by snmp_sess_open.
07136  * returns NULL or pointer to session.
07137  */
07138 netsnmp_session *
07139 snmp_sess_session(void *sessp)
07140 {
07141     struct session_list *slp = (struct session_list *) sessp;
07142     if (slp == NULL)
07143         return (NULL);
07144     return (slp->session);
07145 }
07146 
07147 
07148 
07149 /*
07150  * snmp_sess_transport: takes an opaque pointer (as returned by
07151  * snmp_sess_open or snmp_sess_pointer) and returns the corresponding
07152  * netsnmp_transport pointer (or NULL if the opaque pointer does not correspond
07153  * to an active internal session).  
07154  */
07155 
07156 netsnmp_transport *
07157 snmp_sess_transport(void *sessp)
07158 {
07159     struct session_list *slp = (struct session_list *) sessp;
07160     if (slp == NULL) {
07161         return NULL;
07162     } else {
07163         return slp->transport;
07164     }
07165 }
07166 
07167 
07168 
07169 /*
07170  * snmp_sess_transport_set: set the transport pointer for the opaque
07171  * session pointer sp.  
07172  */
07173 
07174 void
07175 snmp_sess_transport_set(void *sp, netsnmp_transport *t)
07176 {
07177     struct session_list *slp = (struct session_list *) sp;
07178     if (slp != NULL) {
07179         slp->transport = t;
07180     }
07181 }
07182 
07183 
07184 /*
07185  * snmp_duplicate_objid: duplicates (mallocs) an objid based on the
07186  * input objid 
07187  */
07188 oid            *
07189 snmp_duplicate_objid(const oid * objToCopy, size_t objToCopyLen)
07190 {
07191     oid            *returnOid = NULL;
07192     if (objToCopy != NULL && objToCopyLen != 0) {
07193         returnOid = (oid *) malloc(objToCopyLen * sizeof(oid));
07194         if (returnOid) {
07195             memmove(returnOid, objToCopy, objToCopyLen * sizeof(oid));
07196         }
07197     }
07198     return returnOid;
07199 }
07200 
07201 /*
07202  * generic statistics counter functions 
07203  */
07204 static u_int    statistics[MAX_STATS];
07205 
07206 u_int
07207 snmp_increment_statistic(int which)
07208 {
07209     if (which >= 0 && which < MAX_STATS) {
07210         statistics[which]++;
07211         return statistics[which];
07212     }
07213     return 0;
07214 }
07215 
07216 u_int
07217 snmp_increment_statistic_by(int which, int count)
07218 {
07219     if (which >= 0 && which < MAX_STATS) {
07220         statistics[which] += count;
07221         return statistics[which];
07222     }
07223     return 0;
07224 }
07225 
07226 u_int
07227 snmp_get_statistic(int which)
07228 {
07229     if (which >= 0 && which < MAX_STATS)
07230         return statistics[which];
07231     return 0;
07232 }
07233 
07234 void
07235 snmp_init_statistics(void)
07236 {
07237     memset(statistics, 0, sizeof(statistics));
07238 }