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

net-snmpに対してSat Sep 5 13:14:25 2009に生成されました。  doxygen 1.4.7