1 
2 /* Portions of this file are subject to the following copyright(s).  See
3  * the Net-SNMP's COPYING file for more details and other copyrights
4  * that may apply:
5  */
6 /******************************************************************
7 	Copyright 1989, 1991, 1992 by Carnegie Mellon University
8 
9                       All Rights Reserved
10 
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted,
13 provided that the above copyright notice appear in all copies and that
14 both that copyright notice and this permission notice appear in
15 supporting documentation, and that the name of CMU not be
16 used in advertising or publicity pertaining to distribution of the
17 software without specific, written prior permission.
18 
19 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25 SOFTWARE.
26 ******************************************************************/
27 /*
28  * Portions of this file are copyrighted by:
29  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
30  * Use is subject to license terms specified in the COPYING file
31  * distributed with the Net-SNMP package.
32  *
33  * Portions of this file are copyrighted by:
34  * Copyright (c) 2016 VMware, Inc. All rights reserved.
35  * Use is subject to license terms specified in the COPYING file
36  * distributed with the Net-SNMP package.
37  */
38 
39 /** @defgroup library The Net-SNMP library
40  *  @{
41  */
42 /*
43  * snmp_api.c - API for access to snmp.
44  */
45 #include <net-snmp/net-snmp-config.h>
46 #include <net-snmp/net-snmp-features.h>
47 
48 #include <stdio.h>
49 #include <ctype.h>
50 #if HAVE_STDLIB_H
51 #include <stdlib.h>
52 #endif
53 #if HAVE_STRING_H
54 #include <string.h>
55 #else
56 #include <strings.h>
57 #endif
58 #if HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #include <sys/types.h>
62 #if HAVE_SYS_PARAM_H
63 #include <sys/param.h>
64 #endif
65 #if TIME_WITH_SYS_TIME
66 # include <sys/time.h>
67 # include <time.h>
68 #else
69 # if HAVE_SYS_TIME_H
70 #  include <sys/time.h>
71 # else
72 #  include <time.h>
73 # endif
74 #endif
75 #if HAVE_NETINET_IN_H
76 #include <netinet/in.h>
77 #endif
78 #if HAVE_ARPA_INET_H
79 #include <arpa/inet.h>
80 #endif
81 #if HAVE_SYS_SELECT_H
82 #include <sys/select.h>
83 #endif
84 #if HAVE_IO_H
85 #include <io.h>
86 #endif
87 #if HAVE_SYS_SOCKET_H
88 #include <sys/socket.h>
89 #endif
90 #if HAVE_SYS_UN_H
91 #include <sys/un.h>
92 #endif
93 #if HAVE_NETDB_H
94 #include <netdb.h>
95 #endif
96 #if HAVE_NET_IF_DL_H
97 #ifndef dynix
98 #include <net/if_dl.h>
99 #else
100 #include <sys/net/if_dl.h>
101 #endif
102 #endif
103 #include <errno.h>
104 
105 #if HAVE_LOCALE_H
106 #include <locale.h>
107 #endif
108 
109 #define SNMP_NEED_REQUEST_LIST
110 #include <net-snmp/types.h>
111 #include <net-snmp/output_api.h>
112 #include <net-snmp/config_api.h>
113 #include <net-snmp/utilities.h>
114 
115 #include <net-snmp/library/asn1.h>
116 #include <net-snmp/library/snmp.h>      /* for xdump & {build,parse}_var_op */
117 #include <net-snmp/library/snmp_api.h>
118 #include <net-snmp/library/snmp_client.h>
119 #include <net-snmp/library/parse.h>
120 #include <net-snmp/library/mib.h>
121 #include <net-snmp/library/int64.h>
122 #include <net-snmp/library/snmpv3.h>
123 #include <net-snmp/library/callback.h>
124 #include <net-snmp/library/container.h>
125 #include <net-snmp/library/snmp_secmod.h>
126 #include <net-snmp/library/large_fd_set.h>
127 #ifdef NETSNMP_SECMOD_USM
128 #include <net-snmp/library/snmpusm.h>
129 #endif
130 #ifdef NETSNMP_SECMOD_KSM
131 #include <net-snmp/library/snmpksm.h>
132 #endif
133 #include <net-snmp/library/keytools.h>
134 #include <net-snmp/library/lcd_time.h>
135 #include <net-snmp/library/snmp_alarm.h>
136 #include <net-snmp/library/snmp_transport.h>
137 #include <net-snmp/library/snmp_service.h>
138 #include <net-snmp/library/vacm.h>
139 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
140 #include <openssl/ssl.h>
141 #include <net-snmp/library/cert_util.h>
142 #endif
143 
144 netsnmp_feature_child_of(statistics, libnetsnmp);
145 netsnmp_feature_child_of(snmp_api, libnetsnmp);
146 netsnmp_feature_child_of(oid_is_subtree, snmp_api);
147 netsnmp_feature_child_of(snmpv3_probe_contextEngineID_rfc5343, snmp_api);
148 
149 static void     _init_snmp(void);
150 
151 static int      _snmp_store_needed = 0;
152 
153 #include "../agent/mibgroup/agentx/protocol.h"
154 #include <net-snmp/library/transform_oids.h>
155 #ifndef timercmp
156 #define	timercmp(tvp, uvp, cmp) \
157 	/* CSTYLED */ \
158 	((tvp)->tv_sec cmp (uvp)->tv_sec || \
159 	((tvp)->tv_sec == (uvp)->tv_sec && \
160 	/* CSTYLED */ \
161 	(tvp)->tv_usec cmp (uvp)->tv_usec))
162 #endif
163 #ifndef timerclear
164 #define	timerclear(tvp)		(tvp)->tv_sec = (tvp)->tv_usec = 0
165 #endif
166 
167 /*
168  * Globals.
169  */
170 #ifndef NETSNMP_STREAM_QUEUE_LEN
171 #define NETSNMP_STREAM_QUEUE_LEN  5
172 #endif
173 
174 #ifndef BSD4_3
175 #define BSD4_2
176 #endif
177 
178 static oid      default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
179 /*
180  * enterprises.cmu.systems.cmuSNMP
181  */
182 
183 #define DEFAULT_COMMUNITY   "public"
184 #define DEFAULT_RETRIES	    5
185 #define DEFAULT_TIMEOUT	    ONE_SEC
186 #define DEFAULT_REMPORT	    SNMP_PORT
187 #define DEFAULT_ENTERPRISE  default_enterprise
188 #define DEFAULT_TIME	    0
189 
190 /*
191  * Internal information about the state of the snmp session.
192  */
193 struct snmp_internal_session {
194     netsnmp_request_list *requests;     /* Info about outstanding requests */
195     netsnmp_request_list *requestsEnd;  /* ptr to end of list */
196     int             (*hook_pre) (netsnmp_session *, netsnmp_transport *,
197                                  void *, int);
198     int             (*hook_parse) (netsnmp_session *, netsnmp_pdu *,
199                                    u_char *, size_t);
200     int             (*hook_post) (netsnmp_session *, netsnmp_pdu *, int);
201     int             (*hook_build) (netsnmp_session *, netsnmp_pdu *,
202                                    u_char *, size_t *);
203     int             (*hook_realloc_build) (netsnmp_session *,
204                                            netsnmp_pdu *, u_char **,
205                                            size_t *, size_t *);
206     int             (*check_packet) (u_char *, size_t);
207     netsnmp_pdu    *(*hook_create_pdu) (netsnmp_transport *,
208                                         void *, size_t);
209 
210     u_char       *packet;      /* curr rcv packet data (may be incomplete) */
211     size_t        packet_len;  /* length of data received so far */
212     size_t        packet_size; /* size of buffer for packet data */
213 
214     u_char       *obuf;         /* send packet buffer */
215     size_t        obuf_size;    /* size of buffer for packet data */
216     u_char       *opacket;      /* send packet data (within obuf) */
217     size_t        opacket_len;  /* length of data */
218 };
219 
220 /*
221  * information about received packet
222  */
223 typedef struct snmp_rcv_packet_s {
224     u_char   *packet;
225     size_t    packet_len;
226     void     *opaque;
227     int       olength;
228 } snmp_rcv_packet;
229 
230 static const char *api_errors[-SNMPERR_MAX + 1] = {
231     "No error",                 /* SNMPERR_SUCCESS */
232     "Generic error",            /* SNMPERR_GENERR */
233     "Invalid local port",       /* SNMPERR_BAD_LOCPORT */
234     "Unknown host",             /* SNMPERR_BAD_ADDRESS */
235     "Unknown session",          /* SNMPERR_BAD_SESSION */
236     "Too long",                 /* SNMPERR_TOO_LONG */
237     "No socket",                /* SNMPERR_NO_SOCKET */
238     "Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
239     "Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
240     "Bad value for non-repeaters",      /* SNMPERR_BAD_REPEATERS */
241     "Bad value for max-repetitions",    /* SNMPERR_BAD_REPETITIONS */
242     "Error building ASN.1 representation",      /* SNMPERR_BAD_ASN1_BUILD */
243     "Failure in sendto",        /* SNMPERR_BAD_SENDTO */
244     "Bad parse of ASN.1 type",  /* SNMPERR_BAD_PARSE */
245     "Bad version specified",    /* SNMPERR_BAD_VERSION */
246     "Bad source party specified",       /* SNMPERR_BAD_SRC_PARTY */
247     "Bad destination party specified",  /* SNMPERR_BAD_DST_PARTY */
248     "Bad context specified",    /* SNMPERR_BAD_CONTEXT */
249     "Bad community specified",  /* SNMPERR_BAD_COMMUNITY */
250     "Cannot send noAuth/Priv",       /* SNMPERR_NOAUTH_DESPRIV */
251     "Bad ACL definition",       /* SNMPERR_BAD_ACL */
252     "Bad Party definition",     /* SNMPERR_BAD_PARTY */
253     "Session abort failure",    /* SNMPERR_ABORT */
254     "Unknown PDU type",         /* SNMPERR_UNKNOWN_PDU */
255     "Timeout",                  /* SNMPERR_TIMEOUT */
256     "Failure in recvfrom",      /* SNMPERR_BAD_RECVFROM */
257     "Unable to determine contextEngineID",      /* SNMPERR_BAD_ENG_ID */
258     "No securityName specified",        /* SNMPERR_BAD_SEC_NAME */
259     "Unable to determine securityLevel",        /* SNMPERR_BAD_SEC_LEVEL  */
260     "ASN.1 parse error in message",     /* SNMPERR_ASN_PARSE_ERR */
261     "Unknown security model in message",        /* SNMPERR_UNKNOWN_SEC_MODEL */
262     "Invalid message (e.g. msgFlags)",  /* SNMPERR_INVALID_MSG */
263     "Unknown engine ID",        /* SNMPERR_UNKNOWN_ENG_ID */
264     "Unknown user name",        /* SNMPERR_UNKNOWN_USER_NAME */
265     "Unsupported security level",       /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
266     "Authentication failure (incorrect password, community or key)",    /* SNMPERR_AUTHENTICATION_FAILURE */
267     "Not in time window",       /* SNMPERR_NOT_IN_TIME_WINDOW */
268     "Decryption error",         /* SNMPERR_DECRYPTION_ERR */
269     "SCAPI general failure",    /* SNMPERR_SC_GENERAL_FAILURE */
270     "SCAPI sub-system not configured",  /* SNMPERR_SC_NOT_CONFIGURED */
271     "Key tools not available",  /* SNMPERR_KT_NOT_AVAILABLE */
272     "Unknown Report message",   /* SNMPERR_UNKNOWN_REPORT */
273     "USM generic error",        /* SNMPERR_USM_GENERICERROR */
274     "USM unknown security name (no such user exists)",  /* SNMPERR_USM_UNKNOWNSECURITYNAME */
275     "USM unsupported security level (this user has not been configured for that level of security)",    /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
276     "USM encryption error",     /* SNMPERR_USM_ENCRYPTIONERROR */
277     "USM authentication failure (incorrect password or key)",   /* SNMPERR_USM_AUTHENTICATIONFAILURE */
278     "USM parse error",          /* SNMPERR_USM_PARSEERROR */
279     "USM unknown engineID",     /* SNMPERR_USM_UNKNOWNENGINEID */
280     "USM not in time window",   /* SNMPERR_USM_NOTINTIMEWINDOW */
281     "USM decryption error",     /* SNMPERR_USM_DECRYPTIONERROR */
282     "MIB not initialized",      /* SNMPERR_NOMIB */
283     "Value out of range",       /* SNMPERR_RANGE */
284     "Sub-id out of range",      /* SNMPERR_MAX_SUBID */
285     "Bad sub-id in object identifier",  /* SNMPERR_BAD_SUBID */
286     "Object identifier too long",       /* SNMPERR_LONG_OID */
287     "Bad value name",           /* SNMPERR_BAD_NAME */
288     "Bad value notation",       /* SNMPERR_VALUE */
289     "Unknown Object Identifier",        /* SNMPERR_UNKNOWN_OBJID */
290     "No PDU in snmp_send",      /* SNMPERR_NULL_PDU */
291     "Missing variables in PDU", /* SNMPERR_NO_VARS */
292     "Bad variable type",        /* SNMPERR_VAR_TYPE */
293     "Out of memory (malloc failure)",   /* SNMPERR_MALLOC */
294     "Kerberos related error",   /* SNMPERR_KRB5 */
295     "Protocol error",		/* SNMPERR_PROTOCOL */
296     "OID not increasing",       /* SNMPERR_OID_NONINCREASING */
297     "Context probe",            /* SNMPERR_JUST_A_CONTEXT_PROBE */
298     "Configuration data found but the transport can't be configured", /* SNMPERR_TRANSPORT_NO_CONFIG */
299     "Transport configuration failed", /* SNMPERR_TRANSPORT_CONFIG_ERROR */
300 };
301 
302 static const char *secLevelName[] = {
303     "BAD_SEC_LEVEL",
304     "noAuthNoPriv",
305     "authNoPriv",
306     "authPriv"
307 };
308 
309 /*
310  * Multiple threads may changes these variables.
311  * Suggest using the Single API, which does not use Sessions.
312  *
313  * Reqid may need to be protected. Time will tell...
314  *
315  */
316 /*
317  * MTCRITICAL_RESOURCE
318  */
319 /*
320  * use token in comments to individually protect these resources
321  */
322 struct session_list *Sessions = NULL;   /* MT_LIB_SESSION */
323 static long     Reqid = 0;      /* MT_LIB_REQUESTID */
324 static long     Msgid = 0;      /* MT_LIB_MESSAGEID */
325 static long     Sessid = 0;     /* MT_LIB_SESSIONID */
326 static long     Transid = 0;    /* MT_LIB_TRANSID */
327 int             snmp_errno = 0;
328 /*
329  * END MTCRITICAL_RESOURCE
330  */
331 
332 /*
333  * global error detail storage
334  */
335 static char     snmp_detail[192];
336 static int      snmp_detail_f = 0;
337 
338 /*
339  * Prototypes.
340  */
341 static void     snmpv3_calc_msg_flags(int, int, u_char *);
342 static int      snmpv3_verify_msg(netsnmp_request_list *, netsnmp_pdu *);
343 static int      snmpv3_build(u_char ** pkt, size_t * pkt_len,
344                              size_t * offset, netsnmp_session * session,
345                              netsnmp_pdu *pdu);
346 static int      snmp_parse_version(u_char *, size_t);
347 static int      snmp_resend_request(struct session_list *slp,
348                                     netsnmp_request_list *orp,
349                                     netsnmp_request_list *rp,
350                                     int incr_retries);
351 static void     register_default_handlers(void);
352 static struct session_list *snmp_sess_copy(netsnmp_session * pss);
353 
354 /*
355  * return configured max message size for outgoing packets
356  */
357 int
netsnmp_max_send_msg_size(void)358 netsnmp_max_send_msg_size(void)
359 {
360     u_int max = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
361                                    NETSNMP_DS_LIB_MSG_SEND_MAX);
362     if (0 == max)
363         max = SNMP_MAX_PACKET_LEN;
364     else if (max < SNMP_MIN_MAX_LEN)
365         max = SNMP_MIN_MAX_LEN; /* minimum max size per SNMP specs */
366     else if (max > SNMP_MAX_PACKET_LEN)
367         max = SNMP_MAX_PACKET_LEN;
368 
369     return max;
370 }
371 
372 #ifndef HAVE_STRERROR
373 const char     *
strerror(int err)374 strerror(int err)
375 {
376     extern const char *sys_errlist[];
377     extern int      sys_nerr;
378 
379     if (err < 0 || err >= sys_nerr)
380         return "Unknown error";
381     return sys_errlist[err];
382 }
383 #endif
384 
385 const char *
snmp_pdu_type(int type)386 snmp_pdu_type(int type)
387 {
388     static char unknown[20];
389     switch(type) {
390     case SNMP_MSG_GET:
391         return "GET";
392     case SNMP_MSG_GETNEXT:
393         return "GETNEXT";
394     case SNMP_MSG_GETBULK:
395         return "GETBULK";
396 #ifndef NETSNMP_NO_WRITE_SUPPORT
397     case SNMP_MSG_SET:
398         return "SET";
399 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
400     case SNMP_MSG_RESPONSE:
401         return "RESPONSE";
402     case SNMP_MSG_INFORM:
403         return "INFORM";
404     case SNMP_MSG_TRAP2:
405         return "TRAP2";
406     case SNMP_MSG_REPORT:
407         return "REPORT";
408     default:
409         snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
410 	return unknown;
411     }
412 }
413 
414 #define DEBUGPRINTPDUTYPE(token, type) \
415     DEBUGDUMPSECTION(token, snmp_pdu_type(type))
416 
417 long
snmp_get_next_reqid(void)418 snmp_get_next_reqid(void)
419 {
420     long            retVal;
421     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
422     retVal = 1 + Reqid;         /*MTCRITICAL_RESOURCE */
423     if (!retVal)
424         retVal = 2;
425     Reqid = retVal;
426     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
427         retVal &= 0x7fff;	/* mask to 15 bits */
428     else
429         retVal &= 0x7fffffff;	/* mask to 31 bits */
430 
431     if (!retVal) {
432         Reqid = retVal = 2;
433     }
434     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
435     return retVal;
436 }
437 
438 long
snmp_get_next_msgid(void)439 snmp_get_next_msgid(void)
440 {
441     long            retVal;
442     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
443     retVal = 1 + Msgid;         /*MTCRITICAL_RESOURCE */
444     if (!retVal)
445         retVal = 2;
446     Msgid = retVal;
447     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
448         retVal &= 0x7fff;	/* mask to 15 bits */
449     else
450         retVal &= 0x7fffffff;	/* mask to 31 bits */
451 
452     if (!retVal) {
453         Msgid = retVal = 2;
454     }
455     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
456     return retVal;
457 }
458 
459 long
snmp_get_next_sessid(void)460 snmp_get_next_sessid(void)
461 {
462     long            retVal;
463     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
464     retVal = 1 + Sessid;        /*MTCRITICAL_RESOURCE */
465     if (!retVal)
466         retVal = 2;
467     Sessid = retVal;
468     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
469         retVal &= 0x7fff;	/* mask to 15 bits */
470     else
471         retVal &= 0x7fffffff;	/* mask to 31 bits */
472 
473     if (!retVal) {
474         Sessid = retVal = 2;
475     }
476     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
477     return retVal;
478 }
479 
480 long
snmp_get_next_transid(void)481 snmp_get_next_transid(void)
482 {
483     long            retVal;
484     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
485     retVal = 1 + Transid;       /*MTCRITICAL_RESOURCE */
486     if (!retVal)
487         retVal = 2;
488     Transid = retVal;
489     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
490         retVal &= 0x7fff;	/* mask to 15 bits */
491     else
492         retVal &= 0x7fffffff;	/* mask to 31 bits */
493 
494     if (!retVal) {
495         Transid = retVal = 2;
496     }
497     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
498     return retVal;
499 }
500 
501 void
snmp_perror(const char * prog_string)502 snmp_perror(const char *prog_string)
503 {
504     const char     *str;
505     int             xerr;
506     xerr = snmp_errno;          /*MTCRITICAL_RESOURCE */
507     str = snmp_api_errstring(xerr);
508     snmp_log(LOG_ERR, "%s: %s\n", prog_string, str);
509 }
510 
511 void
snmp_set_detail(const char * detail_string)512 snmp_set_detail(const char *detail_string)
513 {
514     if (detail_string != NULL) {
515         strlcpy((char *) snmp_detail, detail_string, sizeof(snmp_detail));
516         snmp_detail_f = 1;
517     }
518 }
519 
520 /*
521  * returns pointer to static data
522  */
523 /*
524  * results not guaranteed in multi-threaded use
525  */
526 const char     *
snmp_api_errstring(int snmp_errnumber)527 snmp_api_errstring(int snmp_errnumber)
528 {
529     const char     *msg = "";
530     static char     msg_buf[SPRINT_MAX_LEN];
531 
532     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
533         msg = api_errors[-snmp_errnumber];
534     } else if (snmp_errnumber != SNMPERR_SUCCESS) {
535         msg = NULL;
536     }
537     if (!msg) {
538 	snprintf(msg_buf, sizeof(msg_buf), "Unknown error: %d", snmp_errnumber);
539         msg_buf[sizeof(msg_buf)-1] = '\0';
540     } else if (snmp_detail_f) {
541         snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
542         msg_buf[sizeof(msg_buf)-1] = '\0';
543         snmp_detail_f = 0;
544     } else {
545         strlcpy(msg_buf, msg, sizeof(msg_buf));
546     }
547 
548     return (msg_buf);
549 }
550 
551 /*
552  * snmp_error - return error data
553  * Inputs :  address of errno, address of snmp_errno, address of string
554  * Caller must free the string returned after use.
555  */
556 void
snmp_error(netsnmp_session * psess,int * p_errno,int * p_snmp_errno,char ** p_str)557 snmp_error(netsnmp_session * psess,
558            int *p_errno, int *p_snmp_errno, char **p_str)
559 {
560     char            buf[SPRINT_MAX_LEN];
561     int             snmp_errnumber;
562 
563     if (p_errno)
564         *p_errno = psess->s_errno;
565     if (p_snmp_errno)
566         *p_snmp_errno = psess->s_snmp_errno;
567     if (p_str == NULL)
568         return;
569 
570     strcpy(buf, "");
571     snmp_errnumber = psess->s_snmp_errno;
572     if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
573 	if (snmp_detail_f) {
574             snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
575 		    snmp_detail);
576             buf[sizeof(buf)-1] = '\0';
577 	    snmp_detail_f = 0;
578 	}
579 	else
580 	    strlcpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
581     } else {
582         if (snmp_errnumber) {
583             snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
584             buf[sizeof(buf)-1] = '\0';
585         }
586     }
587 
588     /*
589      * append a useful system errno interpretation.
590      */
591     if (psess->s_errno) {
592         const char* error = strerror(psess->s_errno);
593         if(error == NULL)
594             error = "Unknown Error";
595         snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
596                  " (%s)", error);
597     }
598     buf[sizeof(buf)-1] = '\0';
599     *p_str = strdup(buf);
600 }
601 
602 /*
603  * snmp_sess_error - same as snmp_error for single session API use.
604  */
605 void
snmp_sess_error(void * sessp,int * p_errno,int * p_snmp_errno,char ** p_str)606 snmp_sess_error(void *sessp, int *p_errno, int *p_snmp_errno, char **p_str)
607 {
608     struct session_list *slp = (struct session_list *) sessp;
609 
610     if ((slp) && (slp->session))
611         snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
612 }
613 
614 /*
615  * netsnmp_sess_log_error(): print a error stored in a session pointer
616  */
617 void
netsnmp_sess_log_error(int priority,const char * prog_string,netsnmp_session * ss)618 netsnmp_sess_log_error(int priority,
619                        const char *prog_string, netsnmp_session * ss)
620 {
621     char           *err;
622     snmp_error(ss, NULL, NULL, &err);
623     snmp_log(priority, "%s: %s\n", prog_string, err);
624     SNMP_FREE(err);
625 }
626 
627 /*
628  * snmp_sess_perror(): print a error stored in a session pointer
629  */
630 void
snmp_sess_perror(const char * prog_string,netsnmp_session * ss)631 snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
632 {
633     netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
634 }
635 
netsnmp_random(void)636 long int netsnmp_random(void)
637 {
638 #if defined(HAVE_RANDOM)
639     return random();
640 #elif defined(HAVE_LRAND48)
641     return lrand48();
642 #elif defined(HAVE_RAND)
643     return rand();
644 #else
645 #error "Neither random(), nor lrand48() nor rand() are available"
646 #endif
647 }
648 
netsnmp_srandom(unsigned int seed)649 void netsnmp_srandom(unsigned int seed)
650 {
651 #if defined(HAVE_SRANDOM)
652     srandom(seed);
653 #elif defined(HAVE_SRAND48)
654     srand48(seed);
655 #elif defined(HAVE_SRAND)
656     srand(seed);
657 #else
658 #error "Neither srandom(), nor srand48() nor srand() are available"
659 #endif
660 }
661 
662 /*
663  * Primordial SNMP library initialization.
664  * Initializes mutex locks.
665  * Invokes minimum required initialization for displaying MIB objects.
666  * Gets initial request ID for all transactions,
667  * and finds which port SNMP over UDP uses.
668  * SNMP over AppleTalk is not currently supported.
669  *
670  * Warning: no debug messages here.
671  */
672 static char _init_snmp_init_done = 0;
673 static void
_init_snmp(void)674 _init_snmp(void)
675 {
676 
677     struct timeval  tv;
678     long            tmpReqid, tmpMsgid;
679 
680     if (_init_snmp_init_done)
681         return;
682     _init_snmp_init_done = 1;
683     Reqid = 1;
684 
685     snmp_res_init();            /* initialize the mt locking structures */
686 #ifndef NETSNMP_DISABLE_MIB_LOADING
687     netsnmp_init_mib_internals();
688 #endif /* NETSNMP_DISABLE_MIB_LOADING */
689     netsnmp_tdomain_init();
690 
691     gettimeofday(&tv, (struct timezone *) 0);
692     /*
693      * Now = tv;
694      */
695 
696     /*
697      * get pseudo-random values for request ID and message ID
698      */
699     netsnmp_srandom((unsigned)(tv.tv_sec ^ tv.tv_usec));
700     tmpReqid = netsnmp_random();
701     tmpMsgid = netsnmp_random();
702 
703     /*
704      * don't allow zero value to repeat init
705      */
706     if (tmpReqid == 0)
707         tmpReqid = 1;
708     if (tmpMsgid == 0)
709         tmpMsgid = 1;
710     Reqid = tmpReqid;
711     Msgid = tmpMsgid;
712 
713     netsnmp_register_default_domain("snmp", "udp udp6");
714     netsnmp_register_default_domain("snmptrap", "udp udp6");
715 
716     netsnmp_register_default_target("snmp", "udp", ":161");
717     netsnmp_register_default_target("snmp", "tcp", ":161");
718     netsnmp_register_default_target("snmp", "udp6", ":161");
719     netsnmp_register_default_target("snmp", "tcp6", ":161");
720     netsnmp_register_default_target("snmp", "dtlsudp", ":10161");
721     netsnmp_register_default_target("snmp", "tlstcp", ":10161");
722     netsnmp_register_default_target("snmp", "ipx", "/36879");
723 
724     netsnmp_register_default_target("snmptrap", "udp", ":162");
725     netsnmp_register_default_target("snmptrap", "tcp", ":162");
726     netsnmp_register_default_target("snmptrap", "udp6", ":162");
727     netsnmp_register_default_target("snmptrap", "tcp6", ":162");
728     netsnmp_register_default_target("snmptrap", "dtlsudp", ":10162");
729     netsnmp_register_default_target("snmptrap", "tlstcp", ":10162");
730     netsnmp_register_default_target("snmptrap", "ipx", "/36880");
731 
732     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
733                        NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
734     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES,
735                        DEFAULT_RETRIES);
736     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
737 			   NETSNMP_DS_LIB_MIB_ERRORS, 1);
738 
739 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
740     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
741 			   NETSNMP_DS_LIB_REVERSE_ENCODE,
742 			   NETSNMP_DEFAULT_ASNENCODING_DIRECTION);
743 #endif
744 }
745 
746 /*
747  * Initializes the session structure.
748  * May perform one time minimal library initialization.
749  * No MIB file processing is done via this call.
750  */
751 void
snmp_sess_init(netsnmp_session * session)752 snmp_sess_init(netsnmp_session * session)
753 {
754     _init_snmp();
755 
756     /*
757      * initialize session to default values
758      */
759 
760     memset(session, 0, sizeof(netsnmp_session));
761     session->timeout = SNMP_DEFAULT_TIMEOUT;
762     session->retries = SNMP_DEFAULT_RETRIES;
763     session->version = SNMP_DEFAULT_VERSION;
764     session->securityModel = SNMP_DEFAULT_SECMODEL;
765     session->rcvMsgMaxSize = netsnmp_max_send_msg_size();
766     session->sndMsgMaxSize = netsnmp_max_send_msg_size();
767     session->flags |= SNMP_FLAGS_DONT_PROBE;
768 }
769 
770 
771 static void
register_default_handlers(void)772 register_default_handlers(void)
773 {
774     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
775 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
776     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
777 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
778     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
779 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
780 #ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
781     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv3",
782                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V3);
783 #endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
784 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
785 #ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
786 #if !defined(NETSNMP_DISABLE_SNMPV1)
787     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv1",
788                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V1);
789 #endif
790 #if !defined(NETSNMP_DISABLE_SNMPV2C)
791     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv2c",
792                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V2c);
793 #endif
794 #endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
795     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
796                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
797 #endif /* !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) */
798     netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
799                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
800     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
801 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
802     netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
803 	              NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
804     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
805 	              NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
806     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
807 	              NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
808     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
809 	              NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
810     netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "clientaddr",
811                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
812     netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "clientaddrUsesPort",
813                       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR_USES_PORT);
814     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
815 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
816     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
817 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
818     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
819 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
820     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
821 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
822     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "sendMessageMaxSize",
823                                NETSNMP_DS_LIBRARY_ID,
824                                NETSNMP_DS_LIB_MSG_SEND_MAX);
825     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentLoad",
826 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD);
827     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentSave",
828 		      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE);
829     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp",
830                                "noContextEngineIDDiscovery",
831                                NETSNMP_DS_LIBRARY_ID,
832                                NETSNMP_DS_LIB_NO_DISCOVERY);
833     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "timeout",
834 		               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TIMEOUT);
835     netsnmp_ds_register_config(ASN_INTEGER, "snmp", "retries",
836 		               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES);
837     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "outputPrecision",
838                                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION);
839 
840 
841     netsnmp_register_service_handlers();
842 }
843 
844 static int init_snmp_init_done = 0; /* To prevent double init's. */
845 /**
846  * Calls the functions to do config file loading and  mib module parsing
847  * in the correct order.
848  *
849  * @param type label for the config file "type"
850  *
851  * @return void
852  *
853  * @see init_agent
854  */
855 void
init_snmp(const char * type)856 init_snmp(const char *type)
857 {
858     if (init_snmp_init_done) {
859         return;
860     }
861 
862     init_snmp_init_done = 1;
863 
864     /*
865      * make the type available everywhere else
866      */
867     if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
868 				       NETSNMP_DS_LIB_APPTYPE)) {
869         netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
870 			      NETSNMP_DS_LIB_APPTYPE, type);
871     }
872 
873     _init_snmp();
874 
875     /*
876      * set our current locale properly to initialize isprint() type functions
877      */
878 #ifdef HAVE_SETLOCALE
879     setlocale(LC_CTYPE, "");
880 #endif
881 
882     snmp_debug_init();    /* should be done first, to turn on debugging ASAP */
883     netsnmp_container_init_list();
884     init_callbacks();
885     init_snmp_logging();
886     snmp_init_statistics();
887     register_mib_handlers();
888     register_default_handlers();
889     init_snmp_transport();
890     init_snmpv3(type);
891     init_snmp_alarm();
892     init_snmp_enum(type);
893     init_vacm();
894 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
895     netsnmp_certs_init();
896 #endif
897 #ifdef DNSSEC_LOCAL_VALIDATION
898     netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dnssecWarnOnly",
899                                NETSNMP_DS_LIBRARY_ID,
900                                NETSNMP_DS_LIB_DNSSEC_WARN_ONLY);
901 #endif
902 
903     read_premib_configs();
904 #ifndef NETSNMP_DISABLE_MIB_LOADING
905     netsnmp_init_mib();
906 #endif /* NETSNMP_DISABLE_MIB_LOADING */
907 
908     read_configs();
909 
910 }                               /* end init_snmp() */
911 
912 /**
913  * set a flag indicating that the persistent store needs to be saved.
914  */
915 void
snmp_store_needed(const char * type)916 snmp_store_needed(const char *type)
917 {
918     DEBUGMSGTL(("snmp_store", "setting needed flag...\n"));
919     _snmp_store_needed = 1;
920 }
921 
922 void
snmp_store_if_needed(void)923 snmp_store_if_needed(void)
924 {
925     if (0 == _snmp_store_needed)
926         return;
927 
928     DEBUGMSGTL(("snmp_store", "store needed...\n"));
929     snmp_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
930                                      NETSNMP_DS_LIB_APPTYPE));
931     _snmp_store_needed = 0;
932 }
933 
934 void
snmp_store(const char * type)935 snmp_store(const char *type)
936 {
937     DEBUGMSGTL(("snmp_store", "storing stuff...\n"));
938     snmp_save_persistent(type);
939     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
940     snmp_clean_persistent(type);
941 }
942 
943 
944 /**
945  * Shuts down the application, saving any needed persistent storage,
946  * and appropriate clean up.
947  *
948  * @param type Label for the config file "type" used
949  *
950  * @return void
951  */
952 void
snmp_shutdown(const char * type)953 snmp_shutdown(const char *type)
954 {
955     snmp_store(type);
956     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
957     shutdown_snmp_logging();
958     snmp_alarm_unregister_all();
959     snmp_close_sessions();
960 #ifndef NETSNMP_DISABLE_MIB_LOADING
961     shutdown_mib();
962 #endif /* NETSNMP_DISABLE_MIB_LOADING */
963 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
964     netsnmp_certs_shutdown();
965 #endif
966 #if !defined(NETSNMP_FEATURE_REMOVE_FILTER_SOURCE)
967     netsnmp_transport_filter_cleanup();
968 #endif
969     unregister_all_config_handlers();
970     netsnmp_container_free_list();
971     clear_sec_mod();
972     clear_snmp_enum();
973     netsnmp_clear_tdomain_list();
974     clear_callback();
975     netsnmp_ds_shutdown();
976     netsnmp_clear_default_target();
977     netsnmp_clear_default_domain();
978     shutdown_secmod();
979     shutdown_snmp_transport();
980     shutdown_data_list();
981     snmp_debug_shutdown();    /* should be done last */
982 
983     init_snmp_init_done  = 0;
984     _init_snmp_init_done = 0;
985 }
986 
987 /*
988  * inserts session into session list
989  */
snmp_session_insert(struct session_list * slp)990 void  snmp_session_insert(struct session_list *slp)
991 {
992     if (NULL == slp)
993         return;
994 
995     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
996     slp->next = Sessions;
997     Sessions = slp;
998     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
999 }
1000 
1001 /*
1002  * Sets up the session with the snmp_session information provided by the user.
1003  * Then opens and binds the necessary low-level transport.  A handle to the
1004  * created session is returned (this is NOT the same as the pointer passed to
1005  * snmp_open()).  On any error, NULL is returned and snmp_errno is set to the
1006  * appropriate error code.
1007  */
1008 netsnmp_session *
snmp_open(netsnmp_session * session)1009 snmp_open(netsnmp_session *session)
1010 {
1011     struct session_list *slp;
1012     slp = (struct session_list *) snmp_sess_open(session);
1013     if (!slp) {
1014         return NULL;
1015     }
1016 
1017     snmp_session_insert(slp);
1018 
1019     return (slp->session);
1020 }
1021 
1022 /*
1023  * extended open
1024  */
1025 netsnmp_feature_child_of(snmp_open_ex, netsnmp_unused);
1026 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX
1027 netsnmp_session *
snmp_open_ex(netsnmp_session * session,int (* fpre_parse)(netsnmp_session *,netsnmp_transport *,void *,int),int (* fparse)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t),int (* fpost_parse)(netsnmp_session *,netsnmp_pdu *,int),int (* fbuild)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t *),int (* frbuild)(netsnmp_session *,netsnmp_pdu *,u_char **,size_t *,size_t *),int (* fcheck)(u_char *,size_t))1028 snmp_open_ex(netsnmp_session *session,
1029              int (*fpre_parse)	(netsnmp_session *, netsnmp_transport *,
1030                                 void *, int),
1031              int (*fparse)	(netsnmp_session *, netsnmp_pdu *, u_char *,
1032 				 size_t),
1033 	     int (*fpost_parse)	(netsnmp_session *, netsnmp_pdu *, int),
1034 
1035              int (*fbuild)	(netsnmp_session *, netsnmp_pdu *, u_char *,
1036 				 size_t *),
1037 	     int (*frbuild)	(netsnmp_session *, netsnmp_pdu *,
1038 				 u_char **, size_t *, size_t *),
1039              int (*fcheck)	(u_char *, size_t)
1040 	     )
1041 {
1042     struct session_list *slp;
1043     slp = (struct session_list *) snmp_sess_open(session);
1044     if (!slp) {
1045         return NULL;
1046     }
1047     slp->internal->hook_pre = fpre_parse;
1048     slp->internal->hook_parse = fparse;
1049     slp->internal->hook_post = fpost_parse;
1050     slp->internal->hook_build = fbuild;
1051     slp->internal->hook_realloc_build = frbuild;
1052     slp->internal->check_packet = fcheck;
1053 
1054     snmp_session_insert(slp);
1055 
1056     return (slp->session);
1057 }
1058 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX */
1059 
1060 static struct session_list *
_sess_copy(netsnmp_session * in_session)1061 _sess_copy(netsnmp_session * in_session)
1062 {
1063     struct session_list *slp;
1064     struct snmp_internal_session *isp;
1065     netsnmp_session *session;
1066     struct snmp_secmod_def *sptr;
1067     char           *cp;
1068     u_char         *ucp;
1069 
1070     in_session->s_snmp_errno = 0;
1071     in_session->s_errno = 0;
1072 
1073     /*
1074      * Copy session structure and link into list
1075      */
1076     slp = (struct session_list *) calloc(1, sizeof(struct session_list));
1077     if (slp == NULL) {
1078         in_session->s_snmp_errno = SNMPERR_MALLOC;
1079         return (NULL);
1080     }
1081 
1082     slp->transport = NULL;
1083 
1084     isp = (struct snmp_internal_session *)calloc(1, sizeof(struct snmp_internal_session));
1085 
1086     if (isp == NULL) {
1087         snmp_sess_close(slp);
1088         in_session->s_snmp_errno = SNMPERR_MALLOC;
1089         return (NULL);
1090     }
1091 
1092     slp->internal = isp;
1093     slp->session = (netsnmp_session *)malloc(sizeof(netsnmp_session));
1094     if (slp->session == NULL) {
1095         snmp_sess_close(slp);
1096         in_session->s_snmp_errno = SNMPERR_MALLOC;
1097         return (NULL);
1098     }
1099     memmove(slp->session, in_session, sizeof(netsnmp_session));
1100     session = slp->session;
1101 
1102     /*
1103      * zero out pointers so if we have to free the session we wont free mem
1104      * owned by in_session
1105      */
1106     session->localname = NULL;
1107     session->peername = NULL;
1108     session->community = NULL;
1109     session->contextEngineID = NULL;
1110     session->contextName = NULL;
1111     session->securityEngineID = NULL;
1112     session->securityName = NULL;
1113     session->securityAuthProto = NULL;
1114     session->securityPrivProto = NULL;
1115     /*
1116      * session now points to the new structure that still contains pointers to
1117      * data allocated elsewhere.  Some of this data is copied to space malloc'd
1118      * here, and the pointer replaced with the new one.
1119      */
1120 
1121     if (in_session->peername != NULL) {
1122         session->peername =
1123             netsnmp_strdup_and_null((u_char*)in_session->peername,
1124                                     strlen(in_session->peername));
1125         if (session->peername == NULL) {
1126             snmp_sess_close(slp);
1127             in_session->s_snmp_errno = SNMPERR_MALLOC;
1128             return (NULL);
1129         }
1130     }
1131 
1132     /*
1133      * Fill in defaults if necessary
1134      */
1135 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1136     if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
1137         ucp = (u_char *) malloc(in_session->community_len);
1138         if (ucp != NULL)
1139             memmove(ucp, in_session->community, in_session->community_len);
1140     } else {
1141         if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1142 					NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
1143             session->community_len = strlen(cp);
1144             ucp = (u_char *) strdup(cp);
1145         } else {
1146 #ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
1147             session->community_len = strlen(DEFAULT_COMMUNITY);
1148             ucp = (u_char *) malloc(session->community_len);
1149             if (ucp)
1150                 memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
1151 #else
1152             ucp = (u_char *) strdup("");
1153 #endif
1154         }
1155     }
1156 
1157     if (ucp == NULL) {
1158         snmp_sess_close(slp);
1159         in_session->s_snmp_errno = SNMPERR_MALLOC;
1160         return (NULL);
1161     }
1162     session->community = ucp;   /* replace pointer with pointer to new data */
1163 #endif
1164 
1165     if (session->securityLevel <= 0) {
1166         session->securityLevel =
1167             netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
1168     }
1169 
1170     if (in_session->securityEngineIDLen > 0) {
1171         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
1172         if (ucp == NULL) {
1173             snmp_sess_close(slp);
1174             in_session->s_snmp_errno = SNMPERR_MALLOC;
1175             return (NULL);
1176         }
1177         memmove(ucp, in_session->securityEngineID,
1178                 in_session->securityEngineIDLen);
1179         session->securityEngineID = ucp;
1180 
1181     }
1182 
1183     if (in_session->contextEngineIDLen > 0) {
1184         ucp = (u_char *) malloc(in_session->contextEngineIDLen);
1185         if (ucp == NULL) {
1186             snmp_sess_close(slp);
1187             in_session->s_snmp_errno = SNMPERR_MALLOC;
1188             return (NULL);
1189         }
1190         memmove(ucp, in_session->contextEngineID,
1191                 in_session->contextEngineIDLen);
1192         session->contextEngineID = ucp;
1193     } else if (in_session->securityEngineIDLen > 0) {
1194         /*
1195          * default contextEngineID to securityEngineIDLen if defined
1196          */
1197         ucp = (u_char *) malloc(in_session->securityEngineIDLen);
1198         if (ucp == NULL) {
1199             snmp_sess_close(slp);
1200             in_session->s_snmp_errno = SNMPERR_MALLOC;
1201             return (NULL);
1202         }
1203         memmove(ucp, in_session->securityEngineID,
1204                 in_session->securityEngineIDLen);
1205         session->contextEngineID = ucp;
1206         session->contextEngineIDLen = in_session->securityEngineIDLen;
1207     }
1208 
1209     if (in_session->contextName) {
1210         session->contextName = strdup(in_session->contextName);
1211         if (session->contextName == NULL) {
1212             snmp_sess_close(slp);
1213             return (NULL);
1214         }
1215         session->contextNameLen = in_session->contextNameLen;
1216     } else {
1217         if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1218                                         NETSNMP_DS_LIB_CONTEXT)) != NULL)
1219             cp = strdup(cp);
1220         else
1221             cp = strdup(SNMP_DEFAULT_CONTEXT);
1222         if (cp == NULL) {
1223             snmp_sess_close(slp);
1224             return (NULL);
1225         }
1226         session->contextName = cp;
1227         session->contextNameLen = strlen(cp);
1228     }
1229 
1230     if (in_session->securityName) {
1231         session->securityName = strdup(in_session->securityName);
1232         if (session->securityName == NULL) {
1233             snmp_sess_close(slp);
1234             return (NULL);
1235         }
1236     } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1237 					   NETSNMP_DS_LIB_SECNAME)) != NULL) {
1238         cp = strdup(cp);
1239         if (cp == NULL) {
1240             snmp_sess_close(slp);
1241             return (NULL);
1242         }
1243         session->securityName = cp;
1244         session->securityNameLen = strlen(cp);
1245     }
1246 
1247     if (session->retries == SNMP_DEFAULT_RETRIES) {
1248         int retry = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1249                                        NETSNMP_DS_LIB_RETRIES);
1250         if (retry < 0)
1251             session->retries = DEFAULT_RETRIES;
1252         else
1253             session->retries = retry;
1254     }
1255     if (session->timeout == SNMP_DEFAULT_TIMEOUT) {
1256         int timeout = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1257                                          NETSNMP_DS_LIB_TIMEOUT);
1258         if (timeout <= 0)
1259             session->timeout = DEFAULT_TIMEOUT;
1260         else
1261             session->timeout = timeout * ONE_SEC;
1262     }
1263     session->sessid = snmp_get_next_sessid();
1264 
1265     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
1266                         session);
1267 
1268     if ((sptr = find_sec_mod(session->securityModel)) != NULL) {
1269         /*
1270          * security module specific copying
1271          */
1272         if (sptr->session_setup) {
1273             int ret = (*sptr->session_setup) (in_session, session);
1274             if (ret != SNMPERR_SUCCESS) {
1275                 snmp_sess_close(slp);
1276                 return NULL;
1277             }
1278         }
1279 
1280         /*
1281          * security module specific opening
1282          */
1283         if (sptr->session_open) {
1284             int ret = (*sptr->session_open) (session);
1285             if (ret != SNMPERR_SUCCESS) {
1286                 snmp_sess_close(slp);
1287                 return NULL;
1288             }
1289         }
1290     }
1291 
1292     /* Anything below this point should only be done if the transport
1293        had no say in the matter */
1294     if (session->securityLevel == 0)
1295         session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1296 
1297     return (slp);
1298 }
1299 
1300 static struct session_list *
snmp_sess_copy(netsnmp_session * pss)1301 snmp_sess_copy(netsnmp_session * pss)
1302 {
1303     struct session_list *psl;
1304     psl = _sess_copy(pss);
1305     if (!psl) {
1306         if (!pss->s_snmp_errno) {
1307             pss->s_snmp_errno = SNMPERR_GENERR;
1308         }
1309         SET_SNMP_ERROR(pss->s_snmp_errno);
1310     }
1311     return psl;
1312 }
1313 
1314 #ifndef NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343
1315 /**
1316  * probe for engineID using RFC 5343 probing mechanisms
1317  *
1318  * Designed to be a callback for within a security model's probe_engineid hook.
1319  * Since it's likely multiple security models won't have engineIDs to
1320  * probe for then this function is a callback likely to be used by
1321  * multiple future security models.  E.G. both SSH and DTLS.
1322  */
1323 int
snmpv3_probe_contextEngineID_rfc5343(struct session_list * slp,netsnmp_session * session)1324 snmpv3_probe_contextEngineID_rfc5343(struct session_list *slp,
1325                                      netsnmp_session *session)
1326 {
1327     netsnmp_pdu    *pdu = NULL, *response = NULL;
1328     static oid      snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
1329     static size_t   snmpEngineIDoid_len = 11;
1330 
1331     static char     probeEngineID[] = { (char)0x80, 0, 0, 0, 6 };
1332     static size_t   probeEngineID_len = sizeof(probeEngineID);
1333 
1334     int status;
1335 
1336     pdu = snmp_pdu_create(SNMP_MSG_GET);
1337     if (!pdu)
1338         return SNMP_ERR_GENERR;
1339     pdu->version = SNMP_VERSION_3;
1340     /* don't require a securityName */
1341     if (session->securityName) {
1342         pdu->securityName = strdup(session->securityName);
1343         pdu->securityNameLen = strlen(pdu->securityName);
1344     }
1345     pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1346     pdu->securityModel = session->securityModel;
1347     pdu->contextEngineID = netsnmp_memdup(probeEngineID, probeEngineID_len);
1348     if (!pdu->contextEngineID) {
1349         snmp_log(LOG_ERR, "failed to clone memory for rfc5343 probe\n");
1350         snmp_free_pdu(pdu);
1351         return SNMP_ERR_GENERR;
1352     }
1353     pdu->contextEngineIDLen = probeEngineID_len;
1354 
1355     snmp_add_null_var(pdu, snmpEngineIDoid, snmpEngineIDoid_len);
1356 
1357     DEBUGMSGTL(("snmp_api", "probing for engineID using rfc5343 methods...\n"));
1358     session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
1359     status = snmp_sess_synch_response(slp, pdu, &response);
1360 
1361     if ((response == NULL) || (status != STAT_SUCCESS)) {
1362         snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing\n");
1363         return SNMP_ERR_GENERR;
1364     }
1365 
1366     /* check that the response makes sense */
1367     if (NULL != response->variables &&
1368         NULL != response->variables->name &&
1369         snmp_oid_compare(response->variables->name,
1370                          response->variables->name_length,
1371                          snmpEngineIDoid, snmpEngineIDoid_len) == 0 &&
1372         ASN_OCTET_STR == response->variables->type  &&
1373         NULL != response->variables->val.string &&
1374         response->variables->val_len > 0) {
1375         session->contextEngineID =
1376             netsnmp_memdup(response->variables->val.string,
1377                            response->variables->val_len);
1378         if (!session->contextEngineID) {
1379             snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing: memory allocation failed\n");
1380             return SNMP_ERR_GENERR;
1381         }
1382 
1383         /* technically there likely isn't a securityEngineID but just
1384            in case anyone goes looking we might as well have one */
1385         session->securityEngineID =
1386             netsnmp_memdup(response->variables->val.string,
1387                            response->variables->val_len);
1388         if (!session->securityEngineID) {
1389             snmp_log(LOG_ERR, "failed rfc5343 securityEngineID probing: memory allocation failed\n");
1390             return SNMP_ERR_GENERR;
1391         }
1392 
1393         session->securityEngineIDLen = session->contextEngineIDLen =
1394             response->variables->val_len;
1395 
1396         if (snmp_get_do_debugging()) {
1397             size_t i;
1398             DEBUGMSGTL(("snmp_sess_open",
1399                         "  probe found engineID:  "));
1400             for (i = 0; i < session->securityEngineIDLen; i++)
1401                 DEBUGMSG(("snmp_sess_open", "%02x",
1402                           session->securityEngineID[i]));
1403             DEBUGMSG(("snmp_sess_open", "\n"));
1404         }
1405     }
1406     return SNMPERR_SUCCESS;
1407 }
1408 #endif /* NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343 */
1409 
1410 
1411 /**
1412  * probe for peer engineID
1413  *
1414  * @param slp         session list pointer.
1415  * @param in_session  session for errors
1416  *
1417  * @note
1418  *  - called by _sess_open(), snmp_sess_add_ex()
1419  *  - in_session is the user supplied session provided to those functions.
1420  *  - the first session in slp should the internal allocated copy of in_session
1421  *
1422  * @return 0 : error
1423  * @return 1 : ok
1424  *
1425  */
1426 int
snmpv3_engineID_probe(struct session_list * slp,netsnmp_session * in_session)1427 snmpv3_engineID_probe(struct session_list *slp,
1428                       netsnmp_session * in_session)
1429 {
1430     netsnmp_session *session;
1431     int             status;
1432     struct snmp_secmod_def *sptr = NULL;
1433 
1434     if (slp == NULL || slp->session == NULL) {
1435         return 0;
1436     }
1437 
1438     session = slp->session;
1439     netsnmp_assert_or_return(session != NULL, 0);
1440     sptr = find_sec_mod(session->securityModel);
1441 
1442     /*
1443      * If we are opening a V3 session and we don't know engineID we must probe
1444      * it -- this must be done after the session is created and inserted in the
1445      * list so that the response can handled correctly.
1446      */
1447 
1448     if (session->version == SNMP_VERSION_3 &&
1449         (0 == (session->flags & SNMP_FLAGS_DONT_PROBE))) {
1450         if (NULL != sptr && NULL != sptr->probe_engineid) {
1451             DEBUGMSGTL(("snmp_api", "probing for engineID using security model callback...\n"));
1452             /* security model specific mechanism of determining engineID */
1453             status = (*sptr->probe_engineid) (slp, in_session);
1454             if (status != SNMPERR_SUCCESS)
1455                 return 0;
1456         } else {
1457             /* XXX: default to the default RFC5343 contextEngineID Probe? */
1458             return 0;
1459         }
1460     }
1461 
1462     /*
1463      * see if there is a hook to call now that we're done probing for an
1464      * engineID
1465      */
1466     if (sptr && sptr->post_probe_engineid) {
1467         status = (*sptr->post_probe_engineid)(slp, in_session);
1468         if (status != SNMPERR_SUCCESS)
1469             return 0;
1470     }
1471 
1472     return 1;
1473 }
1474 
1475 /*******************************************************************-o-******
1476  * netsnmp_sess_config_transport
1477  *
1478  * Parameters:
1479  *	*in_session
1480  *	*in_transport
1481  *
1482  * Returns:
1483  *      SNMPERR_SUCCESS                     - Yay
1484  *      SNMPERR_GENERR                      - Generic Error
1485  *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1486  *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1487  */
1488 int
netsnmp_sess_config_transport(netsnmp_container * transport_configuration,netsnmp_transport * transport)1489 netsnmp_sess_config_transport(netsnmp_container *transport_configuration,
1490                               netsnmp_transport *transport)
1491 {
1492     /* Optional supplimental transport configuration information and
1493        final call to actually open the transport */
1494     if (transport_configuration) {
1495         DEBUGMSGTL(("snmp_sess", "configuring transport\n"));
1496         if (transport->f_config) {
1497             netsnmp_iterator *iter;
1498             netsnmp_transport_config *config_data;
1499             int ret = 0;
1500 
1501             iter = CONTAINER_ITERATOR(transport_configuration);
1502             if (NULL == iter) {
1503                 return SNMPERR_GENERR;
1504             }
1505 
1506             for(config_data = (netsnmp_transport_config*)ITERATOR_FIRST(iter); config_data;
1507                 config_data = (netsnmp_transport_config*)ITERATOR_NEXT(iter)) {
1508                 ret = transport->f_config(transport, config_data->key,
1509                                           config_data->value);
1510                 if (ret)
1511                     break;
1512             }
1513             ITERATOR_RELEASE(iter);
1514             if (ret)
1515                 return SNMPERR_TRANSPORT_CONFIG_ERROR;
1516         } else {
1517             return SNMPERR_TRANSPORT_NO_CONFIG;
1518         }
1519     }
1520     return SNMPERR_SUCCESS;
1521 }
1522 
1523 
1524 /**
1525  * Copies configuration from the session and calls f_open
1526  * This function copies any configuration stored in the session
1527  * pointer to the transport if it has a f_config pointer and then
1528  * calls the transport's f_open function to actually open the
1529  * connection.
1530  *
1531  * @param in_session A pointer to the session that config information is in.
1532  * @param transport A pointer to the transport to config/open.
1533  *
1534  * @return SNMPERR_SUCCESS : on success
1535  */
1536 
1537 /*******************************************************************-o-******
1538  * netsnmp_sess_config_transport
1539  *
1540  * Parameters:
1541  *	*in_session
1542  *	*in_transport
1543  *
1544  * Returns:
1545  *      SNMPERR_SUCCESS                     - Yay
1546  *      SNMPERR_GENERR                      - Generic Error
1547  *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1548  *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1549  */
1550 int
netsnmp_sess_config_and_open_transport(netsnmp_session * in_session,netsnmp_transport * transport)1551 netsnmp_sess_config_and_open_transport(netsnmp_session *in_session,
1552                                        netsnmp_transport *transport)
1553 {
1554     int rc;
1555 
1556     DEBUGMSGTL(("snmp_sess", "opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1557 
1558     /* don't double open */
1559     if (transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED)
1560         return SNMPERR_SUCCESS;
1561 
1562     if ((rc = netsnmp_sess_config_transport(in_session->transport_configuration,
1563                                             transport)) != SNMPERR_SUCCESS) {
1564         in_session->s_snmp_errno = rc;
1565         in_session->s_errno = 0;
1566         return rc;
1567     }
1568 
1569     if (transport->f_open)
1570         transport = transport->f_open(transport);
1571 
1572     if (transport == NULL) {
1573         DEBUGMSGTL(("snmp_sess", "couldn't interpret peername\n"));
1574         in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1575         in_session->s_errno = errno;
1576         snmp_set_detail(in_session->peername);
1577         return SNMPERR_BAD_ADDRESS;
1578     }
1579 
1580     /** if transport has a max size, make sure session is the same (or less) */
1581     if (in_session->rcvMsgMaxSize > transport->msgMaxSize) {
1582         DEBUGMSGTL(("snmp_sess",
1583                     "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1584                     in_session->rcvMsgMaxSize, transport->msgMaxSize));
1585         in_session->rcvMsgMaxSize = transport->msgMaxSize;
1586     }
1587 
1588     if (in_session->sndMsgMaxSize > transport->msgMaxSize) {
1589         DEBUGMSGTL(("snmp_sess",
1590                     "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1591                     in_session->sndMsgMaxSize, transport->msgMaxSize));
1592         in_session->sndMsgMaxSize = transport->msgMaxSize;
1593     }
1594 
1595     transport->flags |= NETSNMP_TRANSPORT_FLAG_OPENED;
1596     DEBUGMSGTL(("snmp_sess", "done opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1597     return SNMPERR_SUCCESS;
1598 }
1599 
1600 /*******************************************************************-o-******
1601  * snmp_sess_open
1602  *
1603  * Parameters:
1604  *	*in_session
1605  *
1606  * Returns:
1607  *      Pointer to a session in the session list   -OR-		FIX -- right?
1608  *	NULL on failure.
1609  *
1610  * The "spin-free" version of snmp_open.
1611  */
1612 static void    *
_sess_open(netsnmp_session * in_session)1613 _sess_open(netsnmp_session * in_session)
1614 {
1615     netsnmp_transport *transport = NULL;
1616     int rc;
1617 
1618     in_session->s_snmp_errno = 0;
1619     in_session->s_errno = 0;
1620 
1621     _init_snmp();
1622 
1623     {
1624         char *clientaddr_save = NULL;
1625 
1626         if (NULL != in_session->localname) {
1627             clientaddr_save =
1628                 netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1629                                       NETSNMP_DS_LIB_CLIENT_ADDR);
1630             if (clientaddr_save)
1631                 clientaddr_save = strdup(clientaddr_save);
1632 
1633             netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1634                                   NETSNMP_DS_LIB_CLIENT_ADDR,
1635                                   in_session->localname);
1636         }
1637 
1638         if (in_session->flags & SNMP_FLAGS_STREAM_SOCKET) {
1639             transport =
1640                 netsnmp_tdomain_transport_full("snmp", in_session->peername,
1641                                                in_session->local_port, "tcp,tcp6",
1642                                                NULL);
1643         } else {
1644             transport =
1645                 netsnmp_tdomain_transport_full("snmp", in_session->peername,
1646                                                in_session->local_port, "udp,udp6",
1647                                                NULL);
1648         }
1649 
1650         if (NULL != in_session->localname)
1651             netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1652                                   NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
1653         free(clientaddr_save);
1654     }
1655 
1656     if (transport == NULL) {
1657         DEBUGMSGTL(("_sess_open", "couldn't interpret peername\n"));
1658         in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1659         in_session->s_errno = errno;
1660         snmp_set_detail(in_session->peername);
1661         return NULL;
1662     }
1663 
1664     /* Optional supplimental transport configuration information and
1665        final call to actually open the transport */
1666     if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1667         != SNMPERR_SUCCESS) {
1668         transport = NULL;
1669         return NULL;
1670     }
1671 
1672 #if defined(SO_BROADCAST) && defined(SOL_SOCKET)
1673     if ( in_session->flags & SNMP_FLAGS_UDP_BROADCAST) {
1674         int   b = 1;
1675         int   rc;
1676 
1677         rc = setsockopt(transport->sock, SOL_SOCKET, SO_BROADCAST,
1678                         (char *)&b, sizeof(b));
1679 
1680         if ( rc != 0 ) {
1681             in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS; /* good as any? */
1682             in_session->s_errno = errno;
1683 
1684             DEBUGMSGTL(("_sess_open", "couldn't enable UDP_BROADCAST\n"));
1685             return NULL;
1686         }
1687     }
1688 #endif
1689 
1690     return snmp_sess_add(in_session, transport, NULL, NULL);
1691 }
1692 
1693 /*
1694  * EXTENDED SESSION API ------------------------------------------
1695  *
1696  * snmp_sess_add_ex, snmp_sess_add, snmp_add
1697  *
1698  * Analogous to snmp_open family of functions, but taking a netsnmp_transport
1699  * pointer as an extra argument.  Unlike snmp_open et al. it doesn't attempt
1700  * to interpret the in_session->peername as a transport endpoint specifier,
1701  * but instead uses the supplied transport.  JBPN
1702  *
1703  */
1704 
1705 netsnmp_session *
snmp_add(netsnmp_session * in_session,netsnmp_transport * transport,int (* fpre_parse)(netsnmp_session *,netsnmp_transport *,void *,int),int (* fpost_parse)(netsnmp_session *,netsnmp_pdu *,int))1706 snmp_add(netsnmp_session * in_session,
1707          netsnmp_transport *transport,
1708          int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
1709                             int), int (*fpost_parse) (netsnmp_session *,
1710                                                       netsnmp_pdu *, int))
1711 {
1712     struct session_list *slp;
1713     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
1714                                                    fpre_parse, NULL,
1715                                                    fpost_parse, NULL, NULL,
1716                                                    NULL, NULL);
1717     if (slp == NULL) {
1718         return NULL;
1719     }
1720 
1721     snmp_session_insert(slp);
1722 
1723     return (slp->session);
1724 }
1725 
1726 netsnmp_session *
snmp_add_full(netsnmp_session * in_session,netsnmp_transport * transport,int (* fpre_parse)(netsnmp_session *,netsnmp_transport *,void *,int),int (* fparse)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t),int (* fpost_parse)(netsnmp_session *,netsnmp_pdu *,int),int (* fbuild)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t *),int (* frbuild)(netsnmp_session *,netsnmp_pdu *,u_char **,size_t *,size_t *),int (* fcheck)(u_char *,size_t),netsnmp_pdu * (* fcreate_pdu)(netsnmp_transport *,void *,size_t))1727 snmp_add_full(netsnmp_session * in_session,
1728               netsnmp_transport *transport,
1729               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1730                                  void *, int),
1731               int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1732                              size_t),
1733               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
1734               int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1735                              size_t *), int (*frbuild) (netsnmp_session *,
1736                                                         netsnmp_pdu *,
1737                                                         u_char **,
1738                                                         size_t *,
1739                                                         size_t *),
1740               int (*fcheck) (u_char *, size_t),
1741               netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1742                                            size_t))
1743 {
1744     struct session_list *slp;
1745     slp = (struct session_list *) snmp_sess_add_ex(in_session, transport,
1746                                                    fpre_parse, fparse,
1747                                                    fpost_parse, fbuild,
1748                                                    frbuild, fcheck,
1749                                                    fcreate_pdu);
1750     if (slp == NULL) {
1751         return NULL;
1752     }
1753 
1754     snmp_session_insert(slp);
1755 
1756     return (slp->session);
1757 }
1758 
1759 
1760 
1761 void           *
snmp_sess_add_ex(netsnmp_session * in_session,netsnmp_transport * transport,int (* fpre_parse)(netsnmp_session *,netsnmp_transport *,void *,int),int (* fparse)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t),int (* fpost_parse)(netsnmp_session *,netsnmp_pdu *,int),int (* fbuild)(netsnmp_session *,netsnmp_pdu *,u_char *,size_t *),int (* frbuild)(netsnmp_session *,netsnmp_pdu *,u_char **,size_t *,size_t *),int (* fcheck)(u_char *,size_t),netsnmp_pdu * (* fcreate_pdu)(netsnmp_transport *,void *,size_t))1762 snmp_sess_add_ex(netsnmp_session * in_session,
1763                  netsnmp_transport *transport,
1764                  int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1765                                     void *, int),
1766                  int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1767                                 size_t),
1768                  int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
1769                                      int),
1770                  int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1771                                 size_t *),
1772                  int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
1773                                  u_char **, size_t *, size_t *),
1774                  int (*fcheck) (u_char *, size_t),
1775                  netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1776                                               size_t))
1777 {
1778     struct session_list *slp;
1779     int rc;
1780 
1781     _init_snmp();
1782 
1783     if (transport == NULL)
1784         return NULL;
1785 
1786     if (NULL != in_session && (in_session->rcvMsgMaxSize < SNMP_MIN_MAX_LEN ||
1787                                in_session->sndMsgMaxSize < SNMP_MIN_MAX_LEN)) {
1788         DEBUGMSGTL(("snmp_sess_add",
1789                     "invalid session (msg sizes). need snmp_sess_init"));
1790         in_session = NULL; /* force transport cleanup below */
1791     }
1792 
1793     if (in_session == NULL) {
1794         transport->f_close(transport);
1795         netsnmp_transport_free(transport);
1796         return NULL;
1797     }
1798 
1799     /* if the transport hasn't been fully opened yet, open it now */
1800     if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1801         != SNMPERR_SUCCESS) {
1802         return NULL;
1803     }
1804 
1805     if (transport->f_setup_session) {
1806         if (SNMPERR_SUCCESS !=
1807             transport->f_setup_session(transport, in_session)) {
1808             netsnmp_transport_free(transport);
1809             return NULL;
1810         }
1811     }
1812 
1813 
1814     DEBUGMSGTL(("snmp_sess_add", "fd %d\n", transport->sock));
1815 
1816 
1817     if ((slp = snmp_sess_copy(in_session)) == NULL) {
1818         transport->f_close(transport);
1819         netsnmp_transport_free(transport);
1820         return (NULL);
1821     }
1822 
1823     slp->transport = transport;
1824     slp->internal->hook_pre = fpre_parse;
1825     slp->internal->hook_parse = fparse;
1826     slp->internal->hook_post = fpost_parse;
1827     slp->internal->hook_build = fbuild;
1828     slp->internal->hook_realloc_build = frbuild;
1829     slp->internal->check_packet = fcheck;
1830     slp->internal->hook_create_pdu = fcreate_pdu;
1831 
1832     /** don't let session max exceed transport max */
1833     if (slp->session->rcvMsgMaxSize > transport->msgMaxSize) {
1834         DEBUGMSGTL(("snmp_sess_add",
1835                     "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1836                     slp->session->rcvMsgMaxSize, transport->msgMaxSize));
1837         slp->session->rcvMsgMaxSize = transport->msgMaxSize;
1838     }
1839     if (slp->session->sndMsgMaxSize > transport->msgMaxSize) {
1840         DEBUGMSGTL(("snmp_sess_add",
1841                     "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1842                     slp->session->sndMsgMaxSize, transport->msgMaxSize));
1843         slp->session->sndMsgMaxSize = transport->msgMaxSize;
1844     }
1845 
1846     if (slp->session->version == SNMP_VERSION_3) {
1847         DEBUGMSGTL(("snmp_sess_add",
1848                     "adding v3 session -- maybe engineID probe now\n"));
1849         if (!snmpv3_engineID_probe(slp, slp->session)) {
1850             DEBUGMSGTL(("snmp_sess_add", "engine ID probe failed\n"));
1851             snmp_sess_close(slp);
1852             return NULL;
1853         }
1854     }
1855 
1856     slp->session->flags &= ~SNMP_FLAGS_DONT_PROBE;
1857 
1858     return (void *) slp;
1859 }                               /*  end snmp_sess_add_ex()  */
1860 
1861 
1862 
1863 void           *
snmp_sess_add(netsnmp_session * in_session,netsnmp_transport * transport,int (* fpre_parse)(netsnmp_session *,netsnmp_transport *,void *,int),int (* fpost_parse)(netsnmp_session *,netsnmp_pdu *,int))1864 snmp_sess_add(netsnmp_session * in_session,
1865               netsnmp_transport *transport,
1866               int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1867                                  void *, int),
1868               int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
1869 {
1870     return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
1871                             fpost_parse, NULL, NULL, NULL, NULL);
1872 }
1873 
1874 
1875 
1876 void           *
snmp_sess_open(netsnmp_session * pss)1877 snmp_sess_open(netsnmp_session * pss)
1878 {
1879     void           *pvoid;
1880     pvoid = _sess_open(pss);
1881     if (!pvoid) {
1882         SET_SNMP_ERROR(pss->s_snmp_errno);
1883     }
1884     return pvoid;
1885 }
1886 
1887 int
create_user_from_session(netsnmp_session * session)1888 create_user_from_session(netsnmp_session * session) {
1889 #ifdef NETSNMP_SECMOD_USM
1890     return usm_create_user_from_session(session);
1891 #else
1892     snmp_log(LOG_ERR, "create_user_from_session called when USM wasn't compiled in");
1893     netsnmp_assert(0 == 1);
1894     return SNMP_ERR_GENERR;
1895 #endif
1896 }
1897 
1898 
1899 /*
1900  *  Do a "deep free()" of a netsnmp_session.
1901  *
1902  *  CAUTION:  SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
1903  *                                                      (hence it is static)
1904  */
1905 
1906 static void
snmp_free_session(netsnmp_session * s)1907 snmp_free_session(netsnmp_session * s)
1908 {
1909     if (s) {
1910         SNMP_FREE(s->localname);
1911         SNMP_FREE(s->peername);
1912         SNMP_FREE(s->community);
1913         SNMP_FREE(s->contextEngineID);
1914         SNMP_FREE(s->contextName);
1915         SNMP_FREE(s->securityEngineID);
1916         SNMP_FREE(s->securityName);
1917         SNMP_FREE(s->securityAuthProto);
1918         SNMP_FREE(s->securityPrivProto);
1919         SNMP_FREE(s->paramName);
1920 #ifndef NETSNMP_NO_TRAP_STATS
1921         SNMP_FREE(s->trap_stats);
1922 #endif /* NETSNMP_NO_TRAP_STATS */
1923 
1924         /*
1925          * clear session from any callbacks
1926          */
1927         netsnmp_callback_clear_client_arg(s, 0, 0);
1928 
1929         free((char *) s);
1930     }
1931 }
1932 
1933 /*
1934  * Close the input session.  Frees all data allocated for the session,
1935  * dequeues any pending requests, and closes any sockets allocated for
1936  * the session.  Returns 0 on error, 1 otherwise.
1937  */
1938 int
snmp_sess_close(void * sessp)1939 snmp_sess_close(void *sessp)
1940 {
1941     struct session_list *slp = (struct session_list *) sessp;
1942     netsnmp_transport *transport;
1943     struct snmp_internal_session *isp;
1944     netsnmp_session *sesp = NULL;
1945     struct snmp_secmod_def *sptr;
1946 
1947     if (slp == NULL) {
1948         return 0;
1949     }
1950 
1951     if (slp->session != NULL &&
1952         (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
1953         sptr->session_close != NULL) {
1954         (*sptr->session_close) (slp->session);
1955     }
1956 
1957     isp = slp->internal;
1958     slp->internal = NULL;
1959 
1960     if (isp) {
1961         netsnmp_request_list *rp, *orp;
1962 
1963         SNMP_FREE(isp->packet);
1964 
1965         /*
1966          * Free each element in the input request list.
1967          */
1968         rp = isp->requests;
1969         while (rp) {
1970             orp = rp;
1971             rp = rp->next_request;
1972             if (orp->callback) {
1973                 orp->callback(NETSNMP_CALLBACK_OP_TIMED_OUT,
1974                               slp->session, orp->pdu->reqid,
1975                               orp->pdu, orp->cb_data);
1976             }
1977             snmp_free_pdu(orp->pdu);
1978             free((char *) orp);
1979         }
1980 
1981         free((char *) isp);
1982     }
1983 
1984     transport = slp->transport;
1985     slp->transport = NULL;
1986 
1987     if (transport) {
1988         transport->f_close(transport);
1989         netsnmp_transport_free(transport);
1990     }
1991 
1992     sesp = slp->session;
1993     slp->session = NULL;
1994 
1995     /*
1996      * The following is necessary to avoid memory leakage when closing AgentX
1997      * sessions that may have multiple subsessions.  These hang off the main
1998      * session at ->subsession, and chain through ->next.
1999      */
2000 
2001     if (sesp != NULL && sesp->subsession != NULL) {
2002         netsnmp_session *subsession = sesp->subsession, *tmpsub;
2003 
2004         while (subsession != NULL) {
2005             DEBUGMSGTL(("snmp_sess_close",
2006                         "closing session %p, subsession %p\n", sesp,
2007                         subsession));
2008             tmpsub = subsession->next;
2009             snmp_free_session(subsession);
2010             subsession = tmpsub;
2011         }
2012     }
2013 
2014     snmp_free_session(sesp);
2015     free((char *) slp);
2016     return 1;
2017 }
2018 
2019 int
snmp_close(netsnmp_session * session)2020 snmp_close(netsnmp_session * session)
2021 {
2022     struct session_list *slp = NULL, *oslp = NULL;
2023 
2024     {                           /*MTCRITICAL_RESOURCE */
2025         snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2026         if (Sessions && Sessions->session == session) { /* If first entry */
2027             slp = Sessions;
2028             Sessions = slp->next;
2029         } else {
2030             for (slp = Sessions; slp; slp = slp->next) {
2031                 if (slp->session == session) {
2032                     if (oslp)   /* if we found entry that points here */
2033                         oslp->next = slp->next; /* link around this entry */
2034                     break;
2035                 }
2036                 oslp = slp;
2037             }
2038         }
2039         snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2040     }                           /*END MTCRITICAL_RESOURCE */
2041     if (slp == NULL) {
2042         return 0;
2043     }
2044     return snmp_sess_close((void *) slp);
2045 }
2046 
2047 int
snmp_close_sessions(void)2048 snmp_close_sessions(void)
2049 {
2050     struct session_list *slp;
2051 
2052     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2053     while (Sessions) {
2054         slp = Sessions;
2055         Sessions = Sessions->next;
2056         snmp_sess_close((void *) slp);
2057     }
2058     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2059     return 1;
2060 }
2061 
2062 static void
snmpv3_calc_msg_flags(int sec_level,int msg_command,u_char * flags)2063 snmpv3_calc_msg_flags(int sec_level, int msg_command, u_char * flags)
2064 {
2065     *flags = 0;
2066     if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2067         *flags = SNMP_MSG_FLAG_AUTH_BIT;
2068     else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
2069         *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
2070 
2071     if (SNMP_CMD_CONFIRMED(msg_command))
2072         *flags |= SNMP_MSG_FLAG_RPRT_BIT;
2073 
2074     return;
2075 }
2076 
2077 static int
snmpv3_verify_msg(netsnmp_request_list * rp,netsnmp_pdu * pdu)2078 snmpv3_verify_msg(netsnmp_request_list *rp, netsnmp_pdu *pdu)
2079 {
2080     netsnmp_pdu    *rpdu;
2081 
2082     if (!rp || !rp->pdu || !pdu)
2083         return 0;
2084     /*
2085      * Reports don't have to match anything according to the spec
2086      */
2087     if (pdu->command == SNMP_MSG_REPORT)
2088         return 1;
2089     rpdu = rp->pdu;
2090     if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid)
2091         return 0;
2092     if (rpdu->version != pdu->version)
2093         return 0;
2094     if (rpdu->securityModel != pdu->securityModel)
2095         return 0;
2096     if (rpdu->securityLevel != pdu->securityLevel)
2097         return 0;
2098 
2099     if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen ||
2100         memcmp(rpdu->contextEngineID, pdu->contextEngineID,
2101                pdu->contextEngineIDLen))
2102         return 0;
2103     if (rpdu->contextNameLen != pdu->contextNameLen ||
2104         memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
2105         return 0;
2106 
2107     /* tunneled transports don't have a securityEngineID...  that's
2108        USM specific (and maybe other future ones) */
2109     if (pdu->securityModel == SNMP_SEC_MODEL_USM &&
2110         (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
2111         memcmp(rpdu->securityEngineID, pdu->securityEngineID,
2112                pdu->securityEngineIDLen)))
2113         return 0;
2114 
2115     /* the securityName must match though regardless of secmodel */
2116     if (rpdu->securityNameLen != pdu->securityNameLen ||
2117         memcmp(rpdu->securityName, pdu->securityName,
2118                pdu->securityNameLen))
2119         return 0;
2120     return 1;
2121 }
2122 
2123 
2124 /*
2125  * SNMPv3
2126  * * Takes a session and a pdu and serializes the ASN PDU into the area
2127  * * pointed to by packet.  out_length is the size of the data area available.
2128  * * Returns the length of the completed packet in out_length.  If any errors
2129  * * occur, -1 is returned.  If all goes well, 0 is returned.
2130  */
2131 static int
snmpv3_build(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_session * session,netsnmp_pdu * pdu)2132 snmpv3_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
2133              netsnmp_session * session, netsnmp_pdu *pdu)
2134 {
2135     int             ret;
2136 
2137     session->s_snmp_errno = 0;
2138     session->s_errno = 0;
2139 
2140     /*
2141      * do validation for PDU types
2142      */
2143     switch (pdu->command) {
2144     case SNMP_MSG_RESPONSE:
2145     case SNMP_MSG_TRAP2:
2146     case SNMP_MSG_REPORT:
2147         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2148         /* FALL THROUGH */
2149     case SNMP_MSG_INFORM:
2150 #ifndef NETSNMP_NOTIFY_ONLY
2151     case SNMP_MSG_GET:
2152     case SNMP_MSG_GETNEXT:
2153 #endif /* ! NETSNMP_NOTIFY_ONLY */
2154 #ifndef NETSNMP_NO_WRITE_SUPPORT
2155     case SNMP_MSG_SET:
2156 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
2157         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2158             pdu->errstat = 0;
2159         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2160             pdu->errindex = 0;
2161         break;
2162 
2163 #ifndef NETSNMP_NOTIFY_ONLY
2164     case SNMP_MSG_GETBULK:
2165         if (pdu->max_repetitions < 0) {
2166             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
2167             return -1;
2168         }
2169         if (pdu->non_repeaters < 0) {
2170             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
2171             return -1;
2172         }
2173         break;
2174 #endif /* ! NETSNMP_NOTIFY_ONLY */
2175 
2176     case SNMP_MSG_TRAP:
2177         session->s_snmp_errno = SNMPERR_V1_IN_V2;
2178         return -1;
2179 
2180     default:
2181         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
2182         return -1;
2183     }
2184 
2185     /* Do we need to set the session security engineid? */
2186     if (pdu->securityEngineIDLen == 0) {
2187         if (session->securityEngineIDLen) {
2188             snmpv3_clone_engineID(&pdu->securityEngineID,
2189                                   &pdu->securityEngineIDLen,
2190                                   session->securityEngineID,
2191                                   session->securityEngineIDLen);
2192         }
2193     }
2194 
2195     /* Do we need to set the session context engineid? */
2196     if (pdu->contextEngineIDLen == 0) {
2197         if (session->contextEngineIDLen) {
2198             snmpv3_clone_engineID(&pdu->contextEngineID,
2199                                   &pdu->contextEngineIDLen,
2200                                   session->contextEngineID,
2201                                   session->contextEngineIDLen);
2202         } else if (pdu->securityEngineIDLen) {
2203             snmpv3_clone_engineID(&pdu->contextEngineID,
2204                                   &pdu->contextEngineIDLen,
2205                                   pdu->securityEngineID,
2206                                   pdu->securityEngineIDLen);
2207         }
2208     }
2209 
2210     if (pdu->contextName == NULL) {
2211         if (!session->contextName) {
2212             session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
2213             return -1;
2214         }
2215         pdu->contextName = strdup(session->contextName);
2216         if (pdu->contextName == NULL) {
2217             session->s_snmp_errno = SNMPERR_GENERR;
2218             return -1;
2219         }
2220         pdu->contextNameLen = session->contextNameLen;
2221     }
2222     if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2223         pdu->securityModel = session->securityModel;
2224         if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2225             pdu->securityModel = se_find_value_in_slist("snmp_secmods", netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECMODEL));
2226 
2227             if (pdu->securityModel <= 0) {
2228                 pdu->securityModel = SNMP_SEC_MODEL_USM;
2229             }
2230         }
2231     }
2232     if (pdu->securityNameLen == 0 && pdu->securityName == NULL) {
2233         if (session->securityModel != SNMP_SEC_MODEL_TSM &&
2234             session->securityNameLen == 0) {
2235             session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
2236             return -1;
2237         }
2238         if (session->securityName) {
2239             pdu->securityName = strdup(session->securityName);
2240             if (pdu->securityName == NULL) {
2241                 session->s_snmp_errno = SNMPERR_GENERR;
2242                 return -1;
2243             }
2244             pdu->securityNameLen = session->securityNameLen;
2245         } else {
2246             pdu->securityName = strdup("");
2247             session->securityName = strdup("");
2248         }
2249     }
2250     if (pdu->securityLevel == 0) {
2251         if (session->securityLevel == 0) {
2252             session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
2253             return -1;
2254         }
2255         pdu->securityLevel = session->securityLevel;
2256     }
2257     DEBUGMSGTL(("snmp_build",
2258                 "Building SNMPv3 message (secName:\"%s\", secLevel:%s)...\n",
2259                 ((session->securityName) ? (char *) session->securityName :
2260                  ((pdu->securityName) ? (char *) pdu->securityName :
2261                   "ERROR: undefined")), secLevelName[pdu->securityLevel]));
2262 
2263     DEBUGDUMPSECTION("send", "SNMPv3 Message");
2264 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2265     if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
2266         ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
2267                                            session, pdu, NULL, 0);
2268     } else {
2269 #endif
2270         ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
2271 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2272     }
2273 #endif
2274     DEBUGINDENTLESS();
2275     if (-1 != ret) {
2276         session->s_snmp_errno = ret;
2277     }
2278 
2279     return ret;
2280 
2281 }                               /* end snmpv3_build() */
2282 
2283 
2284 
2285 
2286 static u_char  *
snmpv3_header_build(netsnmp_session * session,netsnmp_pdu * pdu,u_char * packet,size_t * out_length,size_t length,u_char ** msg_hdr_e)2287 snmpv3_header_build(netsnmp_session * session, netsnmp_pdu *pdu,
2288                     u_char * packet, size_t * out_length,
2289                     size_t length, u_char ** msg_hdr_e)
2290 {
2291     u_char         *global_hdr, *global_hdr_e;
2292     u_char         *cp;
2293     u_char          msg_flags;
2294     long            max_size;
2295     long            sec_model;
2296     u_char         *pb, *pb0e;
2297 
2298     /*
2299      * Save current location and build SEQUENCE tag and length placeholder
2300      * * for SNMP message sequence (actual length inserted later)
2301      */
2302     cp = asn_build_sequence(packet, out_length,
2303                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2304                             length);
2305     if (cp == NULL)
2306         return NULL;
2307     if (msg_hdr_e != NULL)
2308         *msg_hdr_e = cp;
2309     pb0e = cp;
2310 
2311 
2312     /*
2313      * store the version field - msgVersion
2314      */
2315     DEBUGDUMPHEADER("send", "SNMP Version Number");
2316     cp = asn_build_int(cp, out_length,
2317                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2318                                  ASN_INTEGER), (long *) &pdu->version,
2319                        sizeof(pdu->version));
2320     DEBUGINDENTLESS();
2321     if (cp == NULL)
2322         return NULL;
2323 
2324     global_hdr = cp;
2325     /*
2326      * msgGlobalData HeaderData
2327      */
2328     DEBUGDUMPSECTION("send", "msgGlobalData");
2329     cp = asn_build_sequence(cp, out_length,
2330                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2331     if (cp == NULL)
2332         return NULL;
2333     global_hdr_e = cp;
2334 
2335 
2336     /*
2337      * msgID
2338      */
2339     DEBUGDUMPHEADER("send", "msgID");
2340     cp = asn_build_int(cp, out_length,
2341                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2342                                  ASN_INTEGER), &pdu->msgid,
2343                        sizeof(pdu->msgid));
2344     DEBUGINDENTLESS();
2345     if (cp == NULL)
2346         return NULL;
2347 
2348     /*
2349      * msgMaxSize
2350      */
2351     max_size = netsnmp_max_send_msg_size();
2352     if (session->rcvMsgMaxSize < max_size)
2353         max_size = session->rcvMsgMaxSize;
2354     DEBUGDUMPHEADER("send:msgMaxSize1", "msgMaxSize");
2355     cp = asn_build_int(cp, out_length,
2356                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2357                                  ASN_INTEGER), &max_size,
2358                        sizeof(max_size));
2359     DEBUGINDENTLESS();
2360     if (cp == NULL)
2361         return NULL;
2362 
2363     /*
2364      * msgFlags
2365      */
2366     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2367     DEBUGDUMPHEADER("send", "msgFlags");
2368     cp = asn_build_string(cp, out_length,
2369                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2370                                     ASN_OCTET_STR), &msg_flags,
2371                           sizeof(msg_flags));
2372     DEBUGINDENTLESS();
2373     if (cp == NULL)
2374         return NULL;
2375 
2376     /*
2377      * msgSecurityModel
2378      */
2379     sec_model = pdu->securityModel;
2380     DEBUGDUMPHEADER("send", "msgSecurityModel");
2381     cp = asn_build_int(cp, out_length,
2382                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2383                                  ASN_INTEGER), &sec_model,
2384                        sizeof(sec_model));
2385     DEBUGINDENTADD(-4);         /* return from global data indent */
2386     if (cp == NULL)
2387         return NULL;
2388 
2389 
2390     /*
2391      * insert actual length of globalData
2392      */
2393     pb = asn_build_sequence(global_hdr, out_length,
2394                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2395                             cp - global_hdr_e);
2396     if (pb == NULL)
2397         return NULL;
2398 
2399 
2400     /*
2401      * insert the actual length of the entire packet
2402      */
2403     pb = asn_build_sequence(packet, out_length,
2404                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2405                             length + (cp - pb0e));
2406     if (pb == NULL)
2407         return NULL;
2408 
2409     return cp;
2410 
2411 }                               /* end snmpv3_header_build() */
2412 
2413 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2414 
2415 int
snmpv3_header_realloc_rbuild(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_session * session,netsnmp_pdu * pdu)2416 snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2417                              size_t * offset, netsnmp_session * session,
2418                              netsnmp_pdu *pdu)
2419 {
2420     size_t          start_offset = *offset;
2421     u_char          msg_flags;
2422     long            max_size, sec_model;
2423     int             rc = 0;
2424 
2425     /*
2426      * msgSecurityModel.
2427      */
2428     sec_model = pdu->securityModel;
2429     DEBUGDUMPHEADER("send", "msgSecurityModel");
2430     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2431                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2432                                           ASN_INTEGER), &sec_model,
2433                                 sizeof(sec_model));
2434     DEBUGINDENTLESS();
2435     if (rc == 0) {
2436         return 0;
2437     }
2438 
2439     /*
2440      * msgFlags.
2441      */
2442     snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2443     DEBUGDUMPHEADER("send", "msgFlags");
2444     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2445                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2446                                              | ASN_OCTET_STR), &msg_flags,
2447                                    sizeof(msg_flags));
2448     DEBUGINDENTLESS();
2449     if (rc == 0) {
2450         return 0;
2451     }
2452 
2453     /*
2454      * msgMaxSize.
2455      */
2456     max_size = netsnmp_max_send_msg_size();
2457     if (session->rcvMsgMaxSize < max_size)
2458         max_size = session->rcvMsgMaxSize;
2459     DEBUGDUMPHEADER("send:msgMaxSize2", "msgMaxSize");
2460     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2461                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2462                                           ASN_INTEGER), &max_size,
2463                                 sizeof(max_size));
2464     DEBUGINDENTLESS();
2465     if (rc == 0) {
2466         return 0;
2467     }
2468 
2469     /*
2470      * msgID.
2471      */
2472     DEBUGDUMPHEADER("send", "msgID");
2473     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2474                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2475                                           ASN_INTEGER), &pdu->msgid,
2476                                 sizeof(pdu->msgid));
2477     DEBUGINDENTLESS();
2478     if (rc == 0) {
2479         return 0;
2480     }
2481 
2482     /*
2483      * Global data sequence.
2484      */
2485     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2486                                      (u_char) (ASN_SEQUENCE |
2487                                                ASN_CONSTRUCTOR),
2488                                      *offset - start_offset);
2489     if (rc == 0) {
2490         return 0;
2491     }
2492 
2493     /*
2494      * Store the version field - msgVersion.
2495      */
2496     DEBUGDUMPHEADER("send", "SNMP Version Number");
2497     rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2498                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2499                                           ASN_INTEGER),
2500                                 (long *) &pdu->version,
2501                                 sizeof(pdu->version));
2502     DEBUGINDENTLESS();
2503     return rc;
2504 }                               /* end snmpv3_header_realloc_rbuild() */
2505 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2506 
2507 static u_char  *
snmpv3_scopedPDU_header_build(netsnmp_pdu * pdu,u_char * packet,size_t * out_length,u_char ** spdu_e)2508 snmpv3_scopedPDU_header_build(netsnmp_pdu *pdu,
2509                               u_char * packet, size_t * out_length,
2510                               u_char ** spdu_e)
2511 {
2512     u_char         *scopedPdu, *pb;
2513 
2514     pb = scopedPdu = packet;
2515     pb = asn_build_sequence(pb, out_length,
2516                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2517     if (pb == NULL)
2518         return NULL;
2519     if (spdu_e)
2520         *spdu_e = pb;
2521 
2522     DEBUGDUMPHEADER("send", "contextEngineID");
2523     pb = asn_build_string(pb, out_length,
2524                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2525                           pdu->contextEngineID, pdu->contextEngineIDLen);
2526     DEBUGINDENTLESS();
2527     if (pb == NULL)
2528         return NULL;
2529 
2530     DEBUGDUMPHEADER("send", "contextName");
2531     pb = asn_build_string(pb, out_length,
2532                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2533                           (u_char *) pdu->contextName,
2534                           pdu->contextNameLen);
2535     DEBUGINDENTLESS();
2536     if (pb == NULL)
2537         return NULL;
2538 
2539     return pb;
2540 
2541 }                               /* end snmpv3_scopedPDU_header_build() */
2542 
2543 
2544 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2545 int
snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_pdu * pdu,size_t body_len)2546 snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2547                                        size_t * offset, netsnmp_pdu *pdu,
2548                                        size_t body_len)
2549 {
2550     size_t          start_offset = *offset;
2551     int             rc = 0;
2552 
2553     /*
2554      * contextName.
2555      */
2556     DEBUGDUMPHEADER("send", "contextName");
2557     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2558                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2559                                              | ASN_OCTET_STR),
2560                                    (u_char *) pdu->contextName,
2561                                    pdu->contextNameLen);
2562     DEBUGINDENTLESS();
2563     if (rc == 0) {
2564         return 0;
2565     }
2566 
2567     /*
2568      * contextEngineID.
2569      */
2570     DEBUGDUMPHEADER("send", "contextEngineID");
2571     rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2572                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2573                                              | ASN_OCTET_STR),
2574                                    pdu->contextEngineID,
2575                                    pdu->contextEngineIDLen);
2576     DEBUGINDENTLESS();
2577     if (rc == 0) {
2578         return 0;
2579     }
2580 
2581     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2582                                      (u_char) (ASN_SEQUENCE |
2583                                                ASN_CONSTRUCTOR),
2584                                      *offset - start_offset + body_len);
2585 
2586     return rc;
2587 }                               /* end snmpv3_scopedPDU_header_realloc_rbuild() */
2588 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2589 
2590 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2591 /*
2592  * returns 0 if success, -1 if fail, not 0 if SM build failure
2593  */
2594 int
snmpv3_packet_realloc_rbuild(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_session * session,netsnmp_pdu * pdu,u_char * pdu_data,size_t pdu_data_len)2595 snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2596                              size_t * offset, netsnmp_session * session,
2597                              netsnmp_pdu *pdu, u_char * pdu_data,
2598                              size_t pdu_data_len)
2599 {
2600     u_char         *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
2601     size_t          hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
2602         0, spdu_offset = 0;
2603     size_t          body_end_offset = *offset, body_len = 0;
2604     struct snmp_secmod_def *sptr = NULL;
2605     int             rc = 0;
2606 
2607     /*
2608      * Build a scopedPDU structure into the packet buffer.
2609      */
2610     DEBUGPRINTPDUTYPE("send", pdu->command);
2611     if (pdu_data) {
2612         while ((*pkt_len - *offset) < pdu_data_len) {
2613             if (!asn_realloc(pkt, pkt_len)) {
2614                 return -1;
2615             }
2616         }
2617 
2618         *offset += pdu_data_len;
2619         memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
2620     } else {
2621         rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
2622         if (rc == 0) {
2623             return -1;
2624         }
2625     }
2626     body_len = *offset - body_end_offset;
2627 
2628     DEBUGDUMPSECTION("send", "ScopedPdu");
2629     rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
2630                                                 pdu, body_len);
2631     if (rc == 0) {
2632         return -1;
2633     }
2634     spdu_offset = *offset;
2635     DEBUGINDENTADD(-4);         /*  Return from Scoped PDU.  */
2636 
2637     if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
2638         return -1;
2639     }
2640 
2641     rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
2642                                       session, pdu);
2643     if (rc == 0) {
2644         SNMP_FREE(hdrbuf);
2645         return -1;
2646     }
2647     hdr = hdrbuf + hdrbuf_len - hdr_offset;
2648     scoped_pdu = *pkt + *pkt_len - spdu_offset;
2649 
2650     /*
2651      * Call the security module to possibly encrypt and authenticate the
2652      * message---the entire message to transmitted on the wire is returned.
2653      */
2654 
2655     sptr = find_sec_mod(pdu->securityModel);
2656     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2657     if (sptr && sptr->encode_reverse) {
2658         struct snmp_secmod_outgoing_params parms;
2659 
2660         parms.msgProcModel = pdu->msgParseModel;
2661         parms.globalData = hdr;
2662         parms.globalDataLen = hdr_offset;
2663         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2664         parms.secModel = pdu->securityModel;
2665         parms.secEngineID = pdu->securityEngineID;
2666         parms.secEngineIDLen = pdu->securityEngineIDLen;
2667         parms.secName = pdu->securityName;
2668         parms.secNameLen = pdu->securityNameLen;
2669         parms.secLevel = pdu->securityLevel;
2670         parms.scopedPdu = scoped_pdu;
2671         parms.scopedPduLen = spdu_offset;
2672         parms.secStateRef = pdu->securityStateRef;
2673         parms.wholeMsg = pkt;
2674         parms.wholeMsgLen = pkt_len;
2675         parms.wholeMsgOffset = offset;
2676         parms.session = session;
2677         parms.pdu = pdu;
2678 
2679         rc = (*sptr->encode_reverse) (&parms);
2680     } else {
2681         if (!sptr) {
2682             snmp_log(LOG_ERR,
2683                      "no such security service available: %d\n",
2684                      pdu->securityModel);
2685         } else if (!sptr->encode_reverse) {
2686             snmp_log(LOG_ERR,
2687                      "security service %d doesn't support reverse encoding.\n",
2688                      pdu->securityModel);
2689         }
2690         rc = -1;
2691     }
2692 
2693     DEBUGINDENTLESS();
2694     SNMP_FREE(hdrbuf);
2695     return rc;
2696 }                               /* end snmpv3_packet_realloc_rbuild() */
2697 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2698 
2699 /*
2700  * returns 0 if success, -1 if fail, not 0 if SM build failure
2701  */
2702 int
snmpv3_packet_build(netsnmp_session * session,netsnmp_pdu * pdu,u_char * packet,size_t * out_length,u_char * pdu_data,size_t pdu_data_len)2703 snmpv3_packet_build(netsnmp_session * session, netsnmp_pdu *pdu,
2704                     u_char * packet, size_t * out_length,
2705                     u_char * pdu_data, size_t pdu_data_len)
2706 {
2707     u_char         *global_data, *sec_params, *spdu_hdr_e;
2708     size_t          global_data_len, sec_params_len;
2709     u_char          spdu_buf[SNMP_MAX_MSG_SIZE];
2710     size_t          spdu_buf_len, spdu_len;
2711     u_char         *cp;
2712     int             result;
2713     struct snmp_secmod_def *sptr;
2714 
2715     global_data = packet;
2716 
2717     /*
2718      * build the headers for the packet, returned addr = start of secParams
2719      */
2720     sec_params = snmpv3_header_build(session, pdu, global_data,
2721                                      out_length, 0, NULL);
2722     if (sec_params == NULL)
2723         return -1;
2724     global_data_len = sec_params - global_data;
2725     sec_params_len = *out_length;       /* length left in packet buf for sec_params */
2726 
2727 
2728     /*
2729      * build a scopedPDU structure into spdu_buf
2730      */
2731     spdu_buf_len = sizeof(spdu_buf);
2732     DEBUGDUMPSECTION("send", "ScopedPdu");
2733     cp = snmpv3_scopedPDU_header_build(pdu, spdu_buf, &spdu_buf_len,
2734                                        &spdu_hdr_e);
2735     if (cp == NULL)
2736         return -1;
2737 
2738     /*
2739      * build the PDU structure onto the end of spdu_buf
2740      */
2741     DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
2742     if (pdu_data) {
2743         if (cp + pdu_data_len > spdu_buf + sizeof(spdu_buf)) {
2744             snmp_log(LOG_ERR, "%s: PDU too big (%" NETSNMP_PRIz "d > %" NETSNMP_PRIz "d)\n",
2745                      __func__, pdu_data_len, sizeof(spdu_buf));
2746             return -1;
2747         }
2748         memcpy(cp, pdu_data, pdu_data_len);
2749         cp += pdu_data_len;
2750     } else {
2751         cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
2752         if (cp == NULL)
2753             return -1;
2754     }
2755     DEBUGINDENTADD(-4);         /* return from Scoped PDU */
2756 
2757     /*
2758      * re-encode the actual ASN.1 length of the scopedPdu
2759      */
2760     spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
2761     spdu_buf_len = sizeof(spdu_buf);
2762     if (asn_build_sequence(spdu_buf, &spdu_buf_len,
2763                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2764                            spdu_len) == NULL)
2765         return -1;
2766     spdu_len = cp - spdu_buf;   /* the length of the entire scopedPdu */
2767 
2768 
2769     /*
2770      * call the security module to possibly encrypt and authenticate the
2771      * message - the entire message to transmitted on the wire is returned
2772      */
2773     cp = NULL;
2774     *out_length = sizeof(spdu_buf);
2775     DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2776     sptr = find_sec_mod(pdu->securityModel);
2777     if (sptr && sptr->encode_forward) {
2778         struct snmp_secmod_outgoing_params parms;
2779         parms.msgProcModel = pdu->msgParseModel;
2780         parms.globalData = global_data;
2781         parms.globalDataLen = global_data_len;
2782         parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2783         parms.secModel = pdu->securityModel;
2784         parms.secEngineID = pdu->securityEngineID;
2785         parms.secEngineIDLen = pdu->securityEngineIDLen;
2786         parms.secName = pdu->securityName;
2787         parms.secNameLen = pdu->securityNameLen;
2788         parms.secLevel = pdu->securityLevel;
2789         parms.scopedPdu = spdu_buf;
2790         parms.scopedPduLen = spdu_len;
2791         parms.secStateRef = pdu->securityStateRef;
2792         parms.secParams = sec_params;
2793         parms.secParamsLen = &sec_params_len;
2794         parms.wholeMsg = &cp;
2795         parms.wholeMsgLen = out_length;
2796         parms.session = session;
2797         parms.pdu = pdu;
2798         result = (*sptr->encode_forward) (&parms);
2799     } else {
2800         if (!sptr) {
2801             snmp_log(LOG_ERR, "no such security service available: %d\n",
2802                      pdu->securityModel);
2803         } else if (!sptr->encode_forward) {
2804             snmp_log(LOG_ERR,
2805                      "security service %d doesn't support forward out encoding.\n",
2806                      pdu->securityModel);
2807         }
2808         result = -1;
2809     }
2810     DEBUGINDENTLESS();
2811     return result;
2812 
2813 }                               /* end snmpv3_packet_build() */
2814 
2815 
2816 /*
2817  * Takes a session and a pdu and serializes the ASN PDU into the area
2818  * pointed to by *pkt.  *pkt_len is the size of the data area available.
2819  * Returns the length of the completed packet in *offset.  If any errors
2820  * occur, -1 is returned.  If all goes well, 0 is returned.
2821  */
2822 
2823 static int
_snmp_build(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_session * session,netsnmp_pdu * pdu)2824 _snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
2825             netsnmp_session * session, netsnmp_pdu *pdu)
2826 {
2827 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2828     u_char         *h0e = NULL;
2829     size_t          start_offset = *offset;
2830     long            version;
2831     int             rc = 0;
2832     size_t          length;
2833 #endif /* support for community based SNMP */
2834 
2835     u_char         *cp;
2836 
2837     if (NETSNMP_RUNTIME_PROTOCOL_SKIP(pdu->version)) {
2838         DEBUGMSGTL(("snmp_send", "build packet (version 0x%02x disabled)\n",
2839                     (u_int)pdu->version));
2840         session->s_snmp_errno = SNMPERR_BAD_VERSION;
2841         return -1;
2842     }
2843 
2844     session->s_snmp_errno = 0;
2845     session->s_errno = 0;
2846 
2847 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2848     if ((pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG) ||
2849         (0 == netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2850                                      NETSNMP_DS_LIB_REVERSE_ENCODE))) {
2851         pdu->flags |= UCD_MSG_FLAG_FORWARD_ENCODE;
2852     }
2853 #endif /* NETSNMP_USE_REVERSE_ASNENCODING */
2854 
2855     if (pdu->version == SNMP_VERSION_3) {
2856         return snmpv3_build(pkt, pkt_len, offset, session, pdu);
2857     }
2858 
2859     switch (pdu->command) {
2860     case SNMP_MSG_RESPONSE:
2861         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2862 #ifndef NETSNMP_NOTIFY_ONLY
2863         /* FALL THROUGH */
2864     case SNMP_MSG_GET:
2865     case SNMP_MSG_GETNEXT:
2866         /* FALL THROUGH */
2867 #endif /* ! NETSNMP_NOTIFY_ONLY */
2868 #ifndef NETSNMP_NO_WRITE_SUPPORT
2869     case SNMP_MSG_SET:
2870 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
2871         /*
2872          * all versions support these PDU types
2873          */
2874         /*
2875          * initialize defaulted PDU fields
2876          */
2877 
2878         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2879             pdu->errstat = 0;
2880         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2881             pdu->errindex = 0;
2882         break;
2883 
2884     case SNMP_MSG_TRAP2:
2885         netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2886         /* FALL THROUGH */
2887     case SNMP_MSG_INFORM:
2888 #ifndef NETSNMP_DISABLE_SNMPV1
2889         /*
2890          * not supported in SNMPv1 and SNMPsec
2891          */
2892         if (pdu->version == SNMP_VERSION_1) {
2893             session->s_snmp_errno = SNMPERR_V2_IN_V1;
2894             return -1;
2895         }
2896 #endif
2897         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2898             pdu->errstat = 0;
2899         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2900             pdu->errindex = 0;
2901         break;
2902 
2903 #ifndef NETSNMP_NOTIFY_ONLY
2904     case SNMP_MSG_GETBULK:
2905         /*
2906          * not supported in SNMPv1 and SNMPsec
2907          */
2908 #ifndef NETSNMP_DISABLE_SNMPV1
2909         if (pdu->version == SNMP_VERSION_1) {
2910             session->s_snmp_errno = SNMPERR_V2_IN_V1;
2911             return -1;
2912         }
2913 #endif
2914         if (pdu->max_repetitions < 0) {
2915             session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
2916             return -1;
2917         }
2918         if (pdu->non_repeaters < 0) {
2919             session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
2920             return -1;
2921         }
2922         break;
2923 #endif /* ! NETSNMP_NOTIFY_ONLY */
2924 
2925     case SNMP_MSG_TRAP:
2926         /*
2927          * *only* supported in SNMPv1 and SNMPsec
2928          */
2929 #ifndef NETSNMP_DISABLE_SNMPV1
2930         if (pdu->version != SNMP_VERSION_1) {
2931             session->s_snmp_errno = SNMPERR_V1_IN_V2;
2932             return -1;
2933         }
2934 #endif
2935         /*
2936          * initialize defaulted Trap PDU fields
2937          */
2938         pdu->reqid = 1;         /* give a bogus non-error reqid for traps */
2939         if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
2940             pdu->enterprise = (oid *) malloc(sizeof(DEFAULT_ENTERPRISE));
2941             if (pdu->enterprise == NULL) {
2942                 session->s_snmp_errno = SNMPERR_MALLOC;
2943                 return -1;
2944             }
2945             memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
2946                     sizeof(DEFAULT_ENTERPRISE));
2947             pdu->enterprise_length =
2948                 sizeof(DEFAULT_ENTERPRISE) / sizeof(oid);
2949         }
2950         if (pdu->time == SNMP_DEFAULT_TIME)
2951             pdu->time = DEFAULT_TIME;
2952         /*
2953          * don't expect a response
2954          */
2955         pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
2956         break;
2957 
2958     case SNMP_MSG_REPORT:      /* SNMPv3 only */
2959     default:
2960         session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
2961         return -1;
2962     }
2963 
2964     /*
2965      * save length
2966      */
2967 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2968     length = *pkt_len;
2969 #endif
2970 
2971     /*
2972      * setup administrative fields based on version
2973      */
2974     /*
2975      * build the message wrapper and all the administrative fields
2976      * upto the PDU sequence
2977      * (note that actual length of message will be inserted later)
2978      */
2979     switch (pdu->version) {
2980 #ifndef NETSNMP_DISABLE_SNMPV1
2981     case SNMP_VERSION_1:
2982 #endif
2983 #ifndef NETSNMP_DISABLE_SNMPV2C
2984     case SNMP_VERSION_2c:
2985 #endif
2986 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2987 #ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
2988         if (pdu->community_len == 0) {
2989             if (session->community_len == 0) {
2990                 session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
2991                 return -1;
2992             }
2993             pdu->community = (u_char *) malloc(session->community_len);
2994             if (pdu->community == NULL) {
2995                 session->s_snmp_errno = SNMPERR_MALLOC;
2996                 return -1;
2997             }
2998             memmove(pdu->community,
2999                     session->community, session->community_len);
3000             pdu->community_len = session->community_len;
3001         }
3002 #else                           /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3003         if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
3004             /*
3005              * copy session community exactly to pdu community
3006              */
3007             if (0 == session->community_len) {
3008                 SNMP_FREE(pdu->community);
3009             } else if (pdu->community_len == session->community_len) {
3010                 memmove(pdu->community,
3011                         session->community, session->community_len);
3012             } else {
3013                 SNMP_FREE(pdu->community);
3014                 pdu->community = (u_char *) malloc(session->community_len);
3015                 if (pdu->community == NULL) {
3016                     session->s_snmp_errno = SNMPERR_MALLOC;
3017                     return -1;
3018                 }
3019                 memmove(pdu->community,
3020                         session->community, session->community_len);
3021             }
3022             pdu->community_len = session->community_len;
3023         }
3024 #endif                          /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3025 
3026         DEBUGMSGTL(("snmp_send", "Building SNMPv%ld message...\n",
3027                     (1 + pdu->version)));
3028 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
3029         if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
3030             DEBUGPRINTPDUTYPE("send", pdu->command);
3031             rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
3032             if (rc == 0) {
3033                 return -1;
3034             }
3035 
3036             DEBUGDUMPHEADER("send", "Community String");
3037             rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3038                                            (u_char) (ASN_UNIVERSAL |
3039                                                      ASN_PRIMITIVE |
3040                                                      ASN_OCTET_STR),
3041                                            pdu->community,
3042                                            pdu->community_len);
3043             DEBUGINDENTLESS();
3044             if (rc == 0) {
3045                 return -1;
3046             }
3047 
3048 
3049             /*
3050              * Store the version field.
3051              */
3052             DEBUGDUMPHEADER("send", "SNMP Version Number");
3053 
3054             version = pdu->version;
3055             rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3056                                         (u_char) (ASN_UNIVERSAL |
3057                                                   ASN_PRIMITIVE |
3058                                                   ASN_INTEGER),
3059                                         (long *) &version,
3060                                         sizeof(version));
3061             DEBUGINDENTLESS();
3062             if (rc == 0) {
3063                 return -1;
3064             }
3065 
3066             /*
3067              * Build the final sequence.
3068              */
3069 #ifndef NETSNMP_DISABLE_SNMPV1
3070             if (pdu->version == SNMP_VERSION_1) {
3071                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
3072             } else {
3073 #endif
3074                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
3075 #ifndef NETSNMP_DISABLE_SNMPV1
3076             }
3077 #endif
3078             rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3079                                              (u_char) (ASN_SEQUENCE |
3080                                                        ASN_CONSTRUCTOR),
3081                                              *offset - start_offset);
3082             DEBUGINDENTLESS();
3083 
3084             if (rc == 0) {
3085                 return -1;
3086             }
3087             return 0;
3088         } else {
3089 
3090 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3091             /*
3092              * Save current location and build SEQUENCE tag and length
3093              * placeholder for SNMP message sequence
3094              * (actual length will be inserted later)
3095              */
3096             cp = asn_build_sequence(*pkt, pkt_len,
3097                                     (u_char) (ASN_SEQUENCE |
3098                                               ASN_CONSTRUCTOR), 0);
3099             if (cp == NULL) {
3100                 return -1;
3101             }
3102             h0e = cp;
3103 
3104 #ifndef NETSNMP_DISABLE_SNMPV1
3105             if (pdu->version == SNMP_VERSION_1) {
3106                 DEBUGDUMPSECTION("send", "SNMPv1 Message");
3107             } else {
3108 #endif
3109                 DEBUGDUMPSECTION("send", "SNMPv2c Message");
3110 #ifndef NETSNMP_DISABLE_SNMPV1
3111             }
3112 #endif
3113 
3114             /*
3115              * store the version field
3116              */
3117             DEBUGDUMPHEADER("send", "SNMP Version Number");
3118 
3119             version = pdu->version;
3120             cp = asn_build_int(cp, pkt_len,
3121                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3122                                          ASN_INTEGER), (long *) &version,
3123                                sizeof(version));
3124             DEBUGINDENTLESS();
3125             if (cp == NULL)
3126                 return -1;
3127 
3128             /*
3129              * store the community string
3130              */
3131             DEBUGDUMPHEADER("send", "Community String");
3132             cp = asn_build_string(cp, pkt_len,
3133                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3134                                             ASN_OCTET_STR), pdu->community,
3135                                   pdu->community_len);
3136             DEBUGINDENTLESS();
3137             if (cp == NULL)
3138                 return -1;
3139             break;
3140 
3141 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
3142         }
3143 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3144         break;
3145 #endif /* support for community based SNMP */
3146     case SNMP_VERSION_2p:
3147     case SNMP_VERSION_sec:
3148     case SNMP_VERSION_2u:
3149     case SNMP_VERSION_2star:
3150     default:
3151         session->s_snmp_errno = SNMPERR_BAD_VERSION;
3152         return -1;
3153     }
3154 
3155     DEBUGPRINTPDUTYPE("send", pdu->command);
3156     cp = snmp_pdu_build(pdu, cp, pkt_len);
3157     DEBUGINDENTADD(-4);         /* return from entire v1/v2c message */
3158     if (cp == NULL)
3159         return -1;
3160 
3161     /*
3162      * insert the actual length of the message sequence
3163      */
3164     switch (pdu->version) {
3165 #ifndef NETSNMP_DISABLE_SNMPV1
3166     case SNMP_VERSION_1:
3167 #endif
3168 #ifndef NETSNMP_DISABLE_SNMPV2C
3169     case SNMP_VERSION_2c:
3170 #endif
3171 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3172         asn_build_sequence(*pkt, &length,
3173                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3174                            cp - h0e);
3175         break;
3176 #endif /* support for community based SNMP */
3177 
3178     case SNMP_VERSION_2p:
3179     case SNMP_VERSION_sec:
3180     case SNMP_VERSION_2u:
3181     case SNMP_VERSION_2star:
3182     default:
3183         session->s_snmp_errno = SNMPERR_BAD_VERSION;
3184         return -1;
3185     }
3186     *pkt_len = cp - *pkt;
3187     return 0;
3188 }
3189 
3190 /**
3191  * Serialize a PDU into ASN format.
3192  * @param pkt     [out] Serialized PDU.
3193  * @param pkt_len [out] Size of pkt.
3194  * @param offset  [out] Number of bytes written into *pkt.
3195  * @param pss     [in]  Session pointer.
3196  * @param pdu     [in]  PDU to serialize.
3197  *
3198  * @returns 0 upon success; -1 upon failure.
3199  */
3200 int
snmp_build(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_session * pss,netsnmp_pdu * pdu)3201 snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
3202            netsnmp_session * pss, netsnmp_pdu *pdu)
3203 {
3204     int             rc;
3205 
3206     rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
3207     if (rc) {
3208         if (!pss->s_snmp_errno) {
3209             snmp_log(LOG_ERR, "snmp_build: unknown failure\n");
3210             pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
3211         }
3212         SET_SNMP_ERROR(pss->s_snmp_errno);
3213         rc = -1;
3214     }
3215     return rc;
3216 }
3217 
3218 /*
3219  * on error, returns NULL (likely an encoding problem).
3220  */
3221 u_char         *
snmp_pdu_build(netsnmp_pdu * pdu,u_char * cp,size_t * out_length)3222 snmp_pdu_build(netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
3223 {
3224     u_char         *h1, *h1e, *h2, *h2e, *save_ptr;
3225     netsnmp_variable_list *vp, *save_vp = NULL;
3226     size_t          length, save_length;
3227 
3228     length = *out_length;
3229     /*
3230      * Save current location and build PDU tag and length placeholder
3231      * (actual length will be inserted later)
3232      */
3233     h1 = cp;
3234     cp = asn_build_sequence(cp, out_length, (u_char) pdu->command, 0);
3235     if (cp == NULL)
3236         return NULL;
3237     h1e = cp;
3238 
3239     /*
3240      * store fields in the PDU preceding the variable-bindings sequence
3241      */
3242     if (pdu->command != SNMP_MSG_TRAP) {
3243         /*
3244          * PDU is not an SNMPv1 trap
3245          */
3246 
3247         DEBUGDUMPHEADER("send", "request_id");
3248         /*
3249          * request id
3250          */
3251         cp = asn_build_int(cp, out_length,
3252                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3253                                      ASN_INTEGER), &pdu->reqid,
3254                            sizeof(pdu->reqid));
3255         DEBUGINDENTLESS();
3256         if (cp == NULL)
3257             return NULL;
3258 
3259         /*
3260          * error status (getbulk non-repeaters)
3261          */
3262         DEBUGDUMPHEADER("send", "error status");
3263         cp = asn_build_int(cp, out_length,
3264                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3265                                      ASN_INTEGER), &pdu->errstat,
3266                            sizeof(pdu->errstat));
3267         DEBUGINDENTLESS();
3268         if (cp == NULL)
3269             return NULL;
3270 
3271         /*
3272          * error index (getbulk max-repetitions)
3273          */
3274         DEBUGDUMPHEADER("send", "error index");
3275         cp = asn_build_int(cp, out_length,
3276                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3277                                      ASN_INTEGER), &pdu->errindex,
3278                            sizeof(pdu->errindex));
3279         DEBUGINDENTLESS();
3280         if (cp == NULL)
3281             return NULL;
3282     } else {
3283         /*
3284          * an SNMPv1 trap PDU
3285          */
3286 
3287         /*
3288          * enterprise
3289          */
3290         DEBUGDUMPHEADER("send", "enterprise OBJID");
3291         cp = asn_build_objid(cp, out_length,
3292                              (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3293                                        ASN_OBJECT_ID),
3294                              (oid *) pdu->enterprise,
3295                              pdu->enterprise_length);
3296         DEBUGINDENTLESS();
3297         if (cp == NULL)
3298             return NULL;
3299 
3300         /*
3301          * agent-addr
3302          */
3303         DEBUGDUMPHEADER("send", "agent Address");
3304         cp = asn_build_string(cp, out_length,
3305                               (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
3306                               (u_char *) pdu->agent_addr, 4);
3307         DEBUGINDENTLESS();
3308         if (cp == NULL)
3309             return NULL;
3310 
3311         /*
3312          * generic trap
3313          */
3314         DEBUGDUMPHEADER("send", "generic trap number");
3315         cp = asn_build_int(cp, out_length,
3316                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3317                                      ASN_INTEGER),
3318                            (long *) &pdu->trap_type,
3319                            sizeof(pdu->trap_type));
3320         DEBUGINDENTLESS();
3321         if (cp == NULL)
3322             return NULL;
3323 
3324         /*
3325          * specific trap
3326          */
3327         DEBUGDUMPHEADER("send", "specific trap number");
3328         cp = asn_build_int(cp, out_length,
3329                            (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3330                                      ASN_INTEGER),
3331                            (long *) &pdu->specific_type,
3332                            sizeof(pdu->specific_type));
3333         DEBUGINDENTLESS();
3334         if (cp == NULL)
3335             return NULL;
3336 
3337         /*
3338          * timestamp
3339          */
3340         DEBUGDUMPHEADER("send", "timestamp");
3341         cp = asn_build_unsigned_int(cp, out_length,
3342                                     (u_char) (ASN_TIMETICKS |
3343                                               ASN_PRIMITIVE), &pdu->time,
3344                                     sizeof(pdu->time));
3345         DEBUGINDENTLESS();
3346         if (cp == NULL)
3347             return NULL;
3348     }
3349 
3350     /*
3351      * Save current location and build SEQUENCE tag and length placeholder
3352      * for variable-bindings sequence
3353      * (actual length will be inserted later)
3354      */
3355     h2 = cp;
3356     cp = asn_build_sequence(cp, out_length,
3357                             (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
3358     if (cp == NULL)
3359         return NULL;
3360     h2e = cp;
3361 
3362     /*
3363      * Store variable-bindings
3364      */
3365     DEBUGDUMPSECTION("send", "VarBindList");
3366     for (vp = pdu->variables; vp; vp = vp->next_variable) {
3367         /*
3368          * if estimated getbulk response size exceeded packet max size,
3369          * processing was stopped before bulk cache was filled and type
3370          * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3371          * in the cache are empty and we can stop encoding them.
3372          */
3373         if (ASN_PRIV_STOP == vp->type)
3374             break;
3375 
3376         /*
3377          * save current ptr and length so that if we exceed the packet length
3378          * encoding this varbind and this is a bulk response, we can drop
3379          * the failed varbind (and any that follow it) and continue encoding
3380          * the (shorter) bulk response.
3381          */
3382         save_ptr = cp;
3383         save_length = *out_length;
3384 
3385         DEBUGDUMPSECTION("send", "VarBind");
3386         cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
3387                                vp->val_len, (u_char *) vp->val.string,
3388                                out_length);
3389         DEBUGINDENTLESS();
3390         if (cp == NULL) {
3391             if (save_vp && (pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG)) {
3392                 DEBUGDUMPSECTION("send",
3393                                  "VarBind would exceed packet size; dropped");
3394                 cp = save_ptr;
3395                 *out_length = save_length;
3396                 break;
3397             } else
3398                 return NULL;
3399         }
3400         save_vp = vp;
3401     }
3402     DEBUGINDENTLESS();
3403 
3404     /** did we run out of room? (should only happen for bulk reponses) */
3405     if (vp && save_vp) {
3406         save_vp->next_variable = NULL; /* truncate variable list */
3407         /** count remaining varbinds in list, then free them */
3408         save_vp = vp;
3409         for(save_length = 0; save_vp; save_vp = save_vp->next_variable)
3410             ++save_length;
3411         DEBUGMSGTL(("send", "trimmed %" NETSNMP_PRIz "d variables\n", save_length));
3412         snmp_free_varbind(vp);
3413     }
3414 
3415     /*
3416      * insert actual length of variable-bindings sequence
3417      */
3418     asn_build_sequence(h2, &length,
3419                        (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3420                        cp - h2e);
3421 
3422     /*
3423      * insert actual length of PDU sequence
3424      */
3425     asn_build_sequence(h1, &length, (u_char) pdu->command, cp - h1e);
3426 
3427     return cp;
3428 }
3429 
3430 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
3431 /*
3432  * On error, returns 0 (likely an encoding problem).
3433  */
3434 int
snmp_pdu_realloc_rbuild(u_char ** pkt,size_t * pkt_len,size_t * offset,netsnmp_pdu * pdu)3435 snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
3436                         netsnmp_pdu *pdu)
3437 {
3438 #ifndef VPCACHE_SIZE
3439 #define VPCACHE_SIZE 50
3440 #endif
3441     netsnmp_variable_list *vpcache[VPCACHE_SIZE];
3442     netsnmp_variable_list *vp, *tmpvp;
3443     size_t          start_offset = *offset;
3444     int             i, wrapped = 0, notdone, final, rc = 0;
3445 
3446     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "starting\n"));
3447     for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
3448          vp = vp->next_variable, i--) {
3449         /*
3450          * if estimated getbulk response size exceeded packet max size,
3451          * processing was stopped before bulk cache was filled and type
3452          * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3453          * in the cache are empty and we can stop encoding them.
3454          */
3455         if (ASN_PRIV_STOP == vp->type)
3456             break;
3457         if (i < 0) {
3458             wrapped = notdone = 1;
3459             i = VPCACHE_SIZE - 1;
3460             DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3461         }
3462         vpcache[i] = vp;
3463     }
3464     final = i + 1;
3465 
3466     do {
3467         for (i = final; i < VPCACHE_SIZE; i++) {
3468             vp = vpcache[i];
3469             DEBUGDUMPSECTION("send", "VarBind");
3470             rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3471                                             vp->name, &vp->name_length,
3472                                             vp->type,
3473                                             (u_char *) vp->val.string,
3474                                             vp->val_len);
3475             DEBUGINDENTLESS();
3476             if (rc == 0) {
3477                 return 0;
3478             }
3479         }
3480 
3481         DEBUGINDENTLESS();
3482         if (wrapped) {
3483             notdone = 1;
3484             for (i = 0; i < final; i++) {
3485                 vp = vpcache[i];
3486                 DEBUGDUMPSECTION("send", "VarBind");
3487                 rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3488                                                 vp->name, &vp->name_length,
3489                                                 vp->type,
3490                                                 (u_char *) vp->val.string,
3491                                                 vp->val_len);
3492                 DEBUGINDENTLESS();
3493                 if (rc == 0) {
3494                     return 0;
3495                 }
3496             }
3497 
3498             if (final == 0) {
3499                 tmpvp = vpcache[VPCACHE_SIZE - 1];
3500             } else {
3501                 tmpvp = vpcache[final - 1];
3502             }
3503             wrapped = 0;
3504 
3505             for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
3506                  vp && vp != tmpvp; vp = vp->next_variable, i--) {
3507                 if (i < 0) {
3508                     wrapped = 1;
3509                     i = VPCACHE_SIZE - 1;
3510                     DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3511                 }
3512                 vpcache[i] = vp;
3513             }
3514             final = i + 1;
3515         } else {
3516             notdone = 0;
3517         }
3518     } while (notdone);
3519 
3520     /*
3521      * Save current location and build SEQUENCE tag and length placeholder for
3522      * variable-bindings sequence (actual length will be inserted later).
3523      */
3524 
3525     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3526                                      (u_char) (ASN_SEQUENCE |
3527                                                ASN_CONSTRUCTOR),
3528                                      *offset - start_offset);
3529 
3530     /*
3531      * Store fields in the PDU preceding the variable-bindings sequence.
3532      */
3533     if (pdu->command != SNMP_MSG_TRAP) {
3534         /*
3535          * Error index (getbulk max-repetitions).
3536          */
3537         DEBUGDUMPHEADER("send", "error index");
3538         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3539                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3540                                               | ASN_INTEGER),
3541                                     &pdu->errindex, sizeof(pdu->errindex));
3542         DEBUGINDENTLESS();
3543         if (rc == 0) {
3544             return 0;
3545         }
3546 
3547         /*
3548          * Error status (getbulk non-repeaters).
3549          */
3550         DEBUGDUMPHEADER("send", "error status");
3551         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3552                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3553                                               | ASN_INTEGER),
3554                                     &pdu->errstat, sizeof(pdu->errstat));
3555         DEBUGINDENTLESS();
3556         if (rc == 0) {
3557             return 0;
3558         }
3559 
3560         /*
3561          * Request ID.
3562          */
3563         DEBUGDUMPHEADER("send", "request_id");
3564         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3565                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3566                                               | ASN_INTEGER), &pdu->reqid,
3567                                     sizeof(pdu->reqid));
3568         DEBUGINDENTLESS();
3569         if (rc == 0) {
3570             return 0;
3571         }
3572     } else {
3573         /*
3574          * An SNMPv1 trap PDU.
3575          */
3576 
3577         /*
3578          * Timestamp.
3579          */
3580         DEBUGDUMPHEADER("send", "timestamp");
3581         rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
3582                                              (u_char) (ASN_TIMETICKS |
3583                                                        ASN_PRIMITIVE),
3584                                              &pdu->time,
3585                                              sizeof(pdu->time));
3586         DEBUGINDENTLESS();
3587         if (rc == 0) {
3588             return 0;
3589         }
3590 
3591         /*
3592          * Specific trap.
3593          */
3594         DEBUGDUMPHEADER("send", "specific trap number");
3595         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3596                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3597                                               | ASN_INTEGER),
3598                                     (long *) &pdu->specific_type,
3599                                     sizeof(pdu->specific_type));
3600         DEBUGINDENTLESS();
3601         if (rc == 0) {
3602             return 0;
3603         }
3604 
3605         /*
3606          * Generic trap.
3607          */
3608         DEBUGDUMPHEADER("send", "generic trap number");
3609         rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3610                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3611                                               | ASN_INTEGER),
3612                                     (long *) &pdu->trap_type,
3613                                     sizeof(pdu->trap_type));
3614         DEBUGINDENTLESS();
3615         if (rc == 0) {
3616             return 0;
3617         }
3618 
3619         /*
3620          * Agent-addr.
3621          */
3622         DEBUGDUMPHEADER("send", "agent Address");
3623         rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3624                                        (u_char) (ASN_IPADDRESS |
3625                                                  ASN_PRIMITIVE),
3626                                        (u_char *) pdu->agent_addr, 4);
3627         DEBUGINDENTLESS();
3628         if (rc == 0) {
3629             return 0;
3630         }
3631 
3632         /*
3633          * Enterprise.
3634          */
3635         DEBUGDUMPHEADER("send", "enterprise OBJID");
3636         rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
3637                                       (u_char) (ASN_UNIVERSAL |
3638                                                 ASN_PRIMITIVE |
3639                                                 ASN_OBJECT_ID),
3640                                       (oid *) pdu->enterprise,
3641                                       pdu->enterprise_length);
3642         DEBUGINDENTLESS();
3643         if (rc == 0) {
3644             return 0;
3645         }
3646     }
3647 
3648     /*
3649      * Build the PDU sequence.
3650      */
3651     rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3652                                      (u_char) pdu->command,
3653                                      *offset - start_offset);
3654     return rc;
3655 }
3656 #endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3657 
3658 /*
3659  * Parses the packet received to determine version, either directly
3660  * from packets version field or inferred from ASN.1 construct.
3661  */
3662 static int
snmp_parse_version(u_char * data,size_t length)3663 snmp_parse_version(u_char * data, size_t length)
3664 {
3665     u_char          type;
3666     long            version = SNMPERR_BAD_VERSION;
3667 
3668     data = asn_parse_sequence(data, &length, &type,
3669                               (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
3670     if (data) {
3671         DEBUGDUMPHEADER("recv", "SNMP Version");
3672         data =
3673             asn_parse_int(data, &length, &type, &version, sizeof(version));
3674         DEBUGINDENTLESS();
3675         if (!data || type != ASN_INTEGER) {
3676             return SNMPERR_BAD_VERSION;
3677         }
3678     }
3679     return version;
3680 }
3681 
3682 
3683 int
snmpv3_parse(netsnmp_pdu * pdu,u_char * data,size_t * length,u_char ** after_header,netsnmp_session * sess)3684 snmpv3_parse(netsnmp_pdu *pdu,
3685              u_char * data,
3686              size_t * length,
3687              u_char ** after_header, netsnmp_session * sess)
3688 {
3689     u_char          type, msg_flags;
3690     long            ver, msg_sec_model;
3691     size_t          max_size_response;
3692     u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
3693     size_t          tmp_buf_len;
3694     u_char          pdu_buf[SNMP_MAX_MSG_SIZE];
3695     u_char         *mallocbuf = NULL;
3696     size_t          pdu_buf_len = SNMP_MAX_MSG_SIZE;
3697     u_char         *sec_params;
3698     u_char         *msg_data;
3699     u_char         *cp;
3700     size_t          asn_len, msg_len;
3701     int             ret, ret_val;
3702     struct snmp_secmod_def *sptr;
3703 
3704 
3705     msg_data = data;
3706     msg_len = *length;
3707 
3708 
3709     /*
3710      * message is an ASN.1 SEQUENCE
3711      */
3712     DEBUGDUMPSECTION("recv", "SNMPv3 Message");
3713     data = asn_parse_sequence(data, length, &type,
3714                               (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
3715     if (data == NULL) {
3716         /*
3717          * error msg detail is set
3718          */
3719         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3720         DEBUGINDENTLESS();
3721         return SNMPERR_ASN_PARSE_ERR;
3722     }
3723 
3724     /*
3725      * parse msgVersion
3726      */
3727     DEBUGDUMPHEADER("recv", "SNMP Version Number");
3728     data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
3729     DEBUGINDENTLESS();
3730     if (data == NULL) {
3731         ERROR_MSG("bad parse of version");
3732         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3733         DEBUGINDENTLESS();
3734         return SNMPERR_ASN_PARSE_ERR;
3735     }
3736     pdu->version = ver;
3737 
3738     /*
3739      * parse msgGlobalData sequence
3740      */
3741     cp = data;
3742     asn_len = *length;
3743     DEBUGDUMPSECTION("recv", "msgGlobalData");
3744     data = asn_parse_sequence(data, &asn_len, &type,
3745                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3746                               "msgGlobalData");
3747     if (data == NULL) {
3748         /*
3749          * error msg detail is set
3750          */
3751         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3752         DEBUGINDENTADD(-4);
3753         return SNMPERR_ASN_PARSE_ERR;
3754     }
3755     *length -= data - cp;       /* subtract off the length of the header */
3756 
3757     /*
3758      * msgID
3759      */
3760     DEBUGDUMPHEADER("recv", "msgID");
3761     data =
3762         asn_parse_int(data, length, &type, &pdu->msgid,
3763                       sizeof(pdu->msgid));
3764     DEBUGINDENTLESS();
3765     if (data == NULL || type != ASN_INTEGER) {
3766         ERROR_MSG("error parsing msgID");
3767         DEBUGINDENTADD(-4);
3768         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3769         return SNMPERR_ASN_PARSE_ERR;
3770     }
3771 
3772     /*
3773      * Check the msgID we received is a legal value.  If not, then increment
3774      * snmpInASNParseErrs and return the appropriate error (see RFC 2572,
3775      * para. 7.2, section 2 -- note that a bad msgID means that the received
3776      * message is NOT a serialiization of an SNMPv3Message, since the msgID
3777      * field is out of bounds).
3778      */
3779 
3780     if (pdu->msgid < 0 || pdu->msgid > SNMP_MAX_PACKET_LEN) {
3781         snmp_log(LOG_ERR, "Received bad msgID (%ld %s %s).\n", pdu->msgid,
3782                  (pdu->msgid < 0) ? "<" : ">",
3783                  (pdu->msgid < 0) ? "0" : "2^31 - 1");
3784         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3785         DEBUGINDENTADD(-4);
3786         return SNMPERR_ASN_PARSE_ERR;
3787     }
3788 
3789     /*
3790      * msgMaxSize
3791      */
3792     DEBUGDUMPHEADER("recv:msgMaxSize", "msgMaxSize");
3793     data = asn_parse_int(data, length, &type, &pdu->msgMaxSize,
3794                          sizeof(pdu->msgMaxSize));
3795     DEBUGINDENTLESS();
3796     if (data == NULL || type != ASN_INTEGER) {
3797         ERROR_MSG("error parsing msgMaxSize");
3798         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3799         DEBUGINDENTADD(-4);
3800         return SNMPERR_ASN_PARSE_ERR;
3801     }
3802 
3803     /*
3804      * Check the msgMaxSize we received is a legal value.  If not, then
3805      * increment snmpInASNParseErrs and return the appropriate error (see RFC
3806      * 2572, para. 7.2, section 2 -- note that a bad msgMaxSize means that the
3807      * received message is NOT a serialiization of an SNMPv3Message, since the
3808      * msgMaxSize field is out of bounds).
3809      */
3810 
3811     if (pdu->msgMaxSize < SNMP_MIN_MAX_LEN) {
3812         snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu < 484).\n",
3813                  pdu->msgMaxSize);
3814         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3815         DEBUGINDENTADD(-4);
3816         return SNMPERR_ASN_PARSE_ERR;
3817     } else if (pdu->msgMaxSize > SNMP_MAX_PACKET_LEN) {
3818         snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu > 2^31 - 1).\n",
3819                  pdu->msgMaxSize);
3820         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3821         DEBUGINDENTADD(-4);
3822         return SNMPERR_ASN_PARSE_ERR;
3823     } else {
3824         DEBUGMSGTL(("snmpv3_parse:msgMaxSize", "msgMaxSize %lu received\n",
3825                     pdu->msgMaxSize));
3826         /** don't increase max msg size if we've already got one */
3827         if (sess->sndMsgMaxSize < pdu->msgMaxSize) {
3828             DEBUGMSGTL(("snmpv3_parse:msgMaxSize",
3829                         "msgMaxSize %" NETSNMP_PRIz "d greater than session max %ld; reducing\n",
3830                         sess->sndMsgMaxSize, pdu->msgMaxSize));
3831             pdu->msgMaxSize = sess->sndMsgMaxSize;
3832         }
3833     }
3834 
3835     /*
3836      * msgFlags
3837      */
3838     tmp_buf_len = SNMP_MAX_MSG_SIZE;
3839     DEBUGDUMPHEADER("recv", "msgFlags");
3840     data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
3841     DEBUGINDENTLESS();
3842     if (data == NULL || type != ASN_OCTET_STR || tmp_buf_len != 1) {
3843         ERROR_MSG("error parsing msgFlags");
3844         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3845         DEBUGINDENTADD(-4);
3846         return SNMPERR_ASN_PARSE_ERR;
3847     }
3848     msg_flags = *tmp_buf;
3849     if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
3850         pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
3851     else
3852         pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
3853 
3854     /*
3855      * msgSecurityModel
3856      */
3857     DEBUGDUMPHEADER("recv", "msgSecurityModel");
3858     data = asn_parse_int(data, length, &type, &msg_sec_model,
3859                          sizeof(msg_sec_model));
3860     DEBUGINDENTADD(-4);         /* return from global data indent */
3861     if (data == NULL || type != ASN_INTEGER ||
3862         msg_sec_model < 1 || msg_sec_model > 0x7fffffff) {
3863         ERROR_MSG("error parsing msgSecurityModel");
3864         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3865         DEBUGINDENTLESS();
3866         return SNMPERR_ASN_PARSE_ERR;
3867     }
3868     sptr = find_sec_mod(msg_sec_model);
3869     if (!sptr) {
3870         snmp_log(LOG_WARNING, "unknown security model: %ld\n",
3871                  msg_sec_model);
3872         snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
3873         DEBUGINDENTLESS();
3874         return SNMPERR_UNKNOWN_SEC_MODEL;
3875     }
3876     pdu->securityModel = msg_sec_model;
3877 
3878     if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
3879         !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
3880         ERROR_MSG("invalid message, illegal msgFlags");
3881         snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
3882         DEBUGINDENTLESS();
3883         return SNMPERR_INVALID_MSG;
3884     }
3885     pdu->securityLevel = ((msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
3886                           ? ((msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
3887                              ? SNMP_SEC_LEVEL_AUTHPRIV
3888                              : SNMP_SEC_LEVEL_AUTHNOPRIV)
3889                           : SNMP_SEC_LEVEL_NOAUTH);
3890     /*
3891      * end of msgGlobalData
3892      */
3893 
3894     /*
3895      * securtityParameters OCTET STRING begins after msgGlobalData
3896      */
3897     sec_params = data;
3898     pdu->contextEngineID = (u_char *) calloc(1, SNMP_MAX_ENG_SIZE);
3899     pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
3900 
3901     /*
3902      * Note: there is no length limit on the msgAuthoritativeEngineID field,
3903      * although we would EXPECT it to be limited to 32 (the SnmpEngineID TC
3904      * limit).  We'll use double that here to be on the safe side.
3905      */
3906 
3907     pdu->securityEngineID = (u_char *) calloc(1, SNMP_MAX_ENG_SIZE * 2);
3908     pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE * 2;
3909     pdu->securityName = (char *) calloc(1, SNMP_MAX_SEC_NAME_SIZE);
3910     pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
3911 
3912     if ((pdu->securityName == NULL) ||
3913         (pdu->securityEngineID == NULL) ||
3914         (pdu->contextEngineID == NULL)) {
3915         return SNMPERR_MALLOC;
3916     }
3917 
3918     if (pdu_buf_len < msg_len
3919         && pdu->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
3920         /*
3921          * space needed is larger than we have in the default buffer
3922          */
3923         mallocbuf = (u_char *) calloc(1, msg_len);
3924         pdu_buf_len = msg_len;
3925         cp = mallocbuf;
3926     } else {
3927         memset(pdu_buf, 0, pdu_buf_len);
3928         cp = pdu_buf;
3929     }
3930 
3931     DEBUGDUMPSECTION("recv", "SM msgSecurityParameters");
3932     if (sptr->decode) {
3933         struct snmp_secmod_incoming_params parms;
3934         parms.msgProcModel = pdu->msgParseModel;
3935         parms.maxMsgSize = pdu->msgMaxSize;
3936         parms.secParams = sec_params;
3937         parms.secModel = msg_sec_model;
3938         parms.secLevel = pdu->securityLevel;
3939         parms.wholeMsg = msg_data;
3940         parms.wholeMsgLen = msg_len;
3941         parms.secEngineID = pdu->securityEngineID;
3942         parms.secEngineIDLen = &pdu->securityEngineIDLen;
3943         parms.secName = pdu->securityName;
3944         parms.secNameLen = &pdu->securityNameLen;
3945         parms.scopedPdu = &cp;
3946         parms.scopedPduLen = &pdu_buf_len;
3947         parms.maxSizeResponse = &max_size_response;
3948         parms.secStateRef = &pdu->securityStateRef;
3949         parms.sess = sess;
3950         parms.pdu = pdu;
3951         parms.msg_flags = msg_flags;
3952         ret_val = (*sptr->decode) (&parms);
3953     } else {
3954         SNMP_FREE(mallocbuf);
3955         DEBUGINDENTLESS();
3956         snmp_log(LOG_WARNING, "security service %ld can't decode packets\n",
3957                  msg_sec_model);
3958         return (-1);
3959     }
3960 
3961     if (ret_val != SNMPERR_SUCCESS) {
3962         DEBUGDUMPSECTION("recv", "ScopedPDU");
3963         /*
3964          * Parse as much as possible -- though I don't see the point? [jbpn].
3965          */
3966         if (cp) {
3967             cp = snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len);
3968         }
3969         if (cp) {
3970             DEBUGPRINTPDUTYPE("recv", *cp);
3971             snmp_pdu_parse(pdu, cp, &pdu_buf_len);
3972             DEBUGINDENTADD(-8);
3973         } else {
3974             DEBUGINDENTADD(-4);
3975         }
3976 
3977         SNMP_FREE(mallocbuf);
3978         return ret_val;
3979     }
3980 
3981     /*
3982      * parse plaintext ScopedPDU sequence
3983      */
3984     *length = pdu_buf_len;
3985     DEBUGDUMPSECTION("recv", "ScopedPDU");
3986     data = snmpv3_scopedPDU_parse(pdu, cp, length);
3987     if (data == NULL) {
3988         snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
3989                  msg_sec_model);
3990         ERROR_MSG("error parsing PDU");
3991         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3992         DEBUGINDENTADD(-4);
3993         SNMP_FREE(mallocbuf);
3994         return SNMPERR_ASN_PARSE_ERR;
3995     }
3996 
3997     /*
3998      * parse the PDU.
3999      */
4000     if (after_header != NULL) {
4001         *after_header = data;
4002         tmp_buf_len = *length;
4003     }
4004 
4005     DEBUGPRINTPDUTYPE("recv", *data);
4006     ret = snmp_pdu_parse(pdu, data, length);
4007     DEBUGINDENTADD(-8);
4008 
4009     if (after_header != NULL) {
4010         *length = tmp_buf_len;
4011     }
4012 
4013     if (ret != SNMPERR_SUCCESS) {
4014         snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
4015                  msg_sec_model);
4016         ERROR_MSG("error parsing PDU");
4017         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4018         SNMP_FREE(mallocbuf);
4019         return SNMPERR_ASN_PARSE_ERR;
4020     }
4021 
4022     SNMP_FREE(mallocbuf);
4023     return SNMPERR_SUCCESS;
4024 }                               /* end snmpv3_parse() */
4025 
4026 static void
free_securityStateRef(netsnmp_pdu * pdu)4027 free_securityStateRef(netsnmp_pdu* pdu)
4028 {
4029     struct snmp_secmod_def *sptr;
4030 
4031     if (!pdu->securityStateRef)
4032         return;
4033 
4034     sptr = find_sec_mod(pdu->securityModel);
4035     if (sptr) {
4036         if (sptr->pdu_free_state_ref) {
4037             (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
4038         } else {
4039             snmp_log(LOG_ERR,
4040                      "Security Model %d can't free state references\n",
4041                      pdu->securityModel);
4042 	}
4043     } else {
4044 	snmp_log(LOG_ERR,
4045 		 "Can't find security model to free ptr: %d\n",
4046 		 pdu->securityModel);
4047     }
4048     pdu->securityStateRef = NULL;
4049 }
4050 
4051 #define ERROR_STAT_LENGTH 11
4052 
4053 int
snmpv3_make_report(netsnmp_pdu * pdu,int error)4054 snmpv3_make_report(netsnmp_pdu *pdu, int error)
4055 {
4056 
4057     long            ltmp;
4058     static oid      unknownSecurityLevel[] =
4059         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
4060     static oid      notInTimeWindow[] =
4061         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
4062     static oid      unknownUserName[] =
4063         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
4064     static oid      unknownEngineID[] =
4065         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
4066     static oid      wrongDigest[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
4067     static oid      decryptionError[] =
4068         { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
4069     oid            *err_var;
4070     int             err_var_len;
4071 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4072     int             stat_ind;
4073 #endif
4074 
4075     switch (error) {
4076     case SNMPERR_USM_UNKNOWNENGINEID:
4077 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4078         stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
4079 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4080         err_var = unknownEngineID;
4081         err_var_len = ERROR_STAT_LENGTH;
4082         break;
4083     case SNMPERR_USM_UNKNOWNSECURITYNAME:
4084 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4085         stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
4086 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4087         err_var = unknownUserName;
4088         err_var_len = ERROR_STAT_LENGTH;
4089         break;
4090     case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
4091 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4092         stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
4093 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4094         err_var = unknownSecurityLevel;
4095         err_var_len = ERROR_STAT_LENGTH;
4096         break;
4097     case SNMPERR_USM_AUTHENTICATIONFAILURE:
4098 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4099         stat_ind = STAT_USMSTATSWRONGDIGESTS;
4100 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4101         err_var = wrongDigest;
4102         err_var_len = ERROR_STAT_LENGTH;
4103         break;
4104     case SNMPERR_USM_NOTINTIMEWINDOW:
4105 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4106         stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
4107 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4108         err_var = notInTimeWindow;
4109         err_var_len = ERROR_STAT_LENGTH;
4110         break;
4111     case SNMPERR_USM_DECRYPTIONERROR:
4112 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4113         stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
4114 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4115         err_var = decryptionError;
4116         err_var_len = ERROR_STAT_LENGTH;
4117         break;
4118     default:
4119         return SNMPERR_GENERR;
4120     }
4121 
4122     snmp_free_varbind(pdu->variables);  /* free the current varbind */
4123 
4124     pdu->variables = NULL;
4125     SNMP_FREE(pdu->securityEngineID);
4126     pdu->securityEngineID =
4127         snmpv3_generate_engineID(&pdu->securityEngineIDLen);
4128     SNMP_FREE(pdu->contextEngineID);
4129     pdu->contextEngineID =
4130         snmpv3_generate_engineID(&pdu->contextEngineIDLen);
4131     pdu->command = SNMP_MSG_REPORT;
4132     pdu->errstat = 0;
4133     pdu->errindex = 0;
4134     SNMP_FREE(pdu->contextName);
4135     pdu->contextName = strdup("");
4136     pdu->contextNameLen = strlen(pdu->contextName);
4137 
4138     /*
4139      * reports shouldn't cache previous data.
4140      */
4141     /*
4142      * FIX - yes they should but USM needs to follow new EoP to determine
4143      * which cached values to use
4144      */
4145     free_securityStateRef(pdu);
4146 
4147     if (error == SNMPERR_USM_NOTINTIMEWINDOW) {
4148         pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
4149     } else {
4150         pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4151     }
4152 
4153     /*
4154      * find the appropriate error counter
4155      */
4156 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4157     ltmp = snmp_get_statistic(stat_ind);
4158 #else /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4159     ltmp = 1;
4160 #endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4161 
4162     /*
4163      * return the appropriate error counter
4164      */
4165     snmp_pdu_add_variable(pdu, err_var, err_var_len,
4166                           ASN_COUNTER, & ltmp, sizeof(ltmp));
4167 
4168     return SNMPERR_SUCCESS;
4169 }                               /* end snmpv3_make_report() */
4170 
4171 
4172 int
snmpv3_get_report_type(netsnmp_pdu * pdu)4173 snmpv3_get_report_type(netsnmp_pdu *pdu)
4174 {
4175     static oid      snmpMPDStats[] = { 1, 3, 6, 1, 6, 3, 11, 2, 1 };
4176     static oid      targetStats[]  = { 1, 3, 6, 1, 6, 3, 12, 1    };
4177     static oid      usmStats[]     = { 1, 3, 6, 1, 6, 3, 15, 1, 1 };
4178     netsnmp_variable_list *vp;
4179     int             rpt_type = SNMPERR_UNKNOWN_REPORT;
4180 
4181     if (pdu == NULL || pdu->variables == NULL)
4182         return rpt_type;
4183     vp = pdu->variables;
4184     /* MPD or USM based report statistics objects have the same length prefix
4185      *   so the actual statistics OID will have this length,
4186      *   plus one subidentifier for the scalar MIB object itself,
4187      *   and one for the instance subidentifier
4188      */
4189     if (vp->name_length == REPORT_STATS_LEN + 2) {
4190         if (memcmp(snmpMPDStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4191             switch (vp->name[REPORT_STATS_LEN]) {
4192             case REPORT_snmpUnknownSecurityModels_NUM:
4193                 rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
4194                 break;
4195             case REPORT_snmpInvalidMsgs_NUM:
4196                 rpt_type = SNMPERR_INVALID_MSG;
4197                 break;
4198             case REPORT_snmpUnknownPDUHandlers_NUM:
4199                 rpt_type = SNMPERR_BAD_VERSION;
4200                 break;
4201             }
4202         } else if (memcmp(usmStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4203             switch (vp->name[REPORT_STATS_LEN]) {
4204             case REPORT_usmStatsUnsupportedSecLevels_NUM:
4205                 rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
4206                 break;
4207             case REPORT_usmStatsNotInTimeWindows_NUM:
4208                 rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
4209                 break;
4210             case REPORT_usmStatsUnknownUserNames_NUM:
4211                 rpt_type = SNMPERR_UNKNOWN_USER_NAME;
4212                 break;
4213             case REPORT_usmStatsUnknownEngineIDs_NUM:
4214                 rpt_type = SNMPERR_UNKNOWN_ENG_ID;
4215                 break;
4216             case REPORT_usmStatsWrongDigests_NUM:
4217                 rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
4218                 break;
4219             case REPORT_usmStatsDecryptionErrors_NUM:
4220                 rpt_type = SNMPERR_DECRYPTION_ERR;
4221                 break;
4222             }
4223         }
4224     }
4225     /* Context-based report statistics from the Target MIB are similar
4226      *   but the OID prefix has a different length
4227      */
4228     if (vp->name_length == REPORT_STATS_LEN2 + 2) {
4229         if (memcmp(targetStats, vp->name, REPORT_STATS_LEN2 * sizeof(oid)) == 0) {
4230             switch (vp->name[REPORT_STATS_LEN2]) {
4231             case REPORT_snmpUnavailableContexts_NUM:
4232                 rpt_type = SNMPERR_BAD_CONTEXT;
4233                 break;
4234             case REPORT_snmpUnknownContexts_NUM:
4235                 rpt_type = SNMPERR_BAD_CONTEXT;
4236                 break;
4237             }
4238         }
4239     }
4240     DEBUGMSGTL(("report", "Report type: %d\n", rpt_type));
4241     return rpt_type;
4242 }
4243 
4244 /*
4245  * Parses the packet received on the input session, and places the data into
4246  * the input pdu.  length is the length of the input packet.
4247  * If any errors are encountered, -1 or USM error is returned.
4248  * Otherwise, a 0 is returned.
4249  */
4250 static int
_snmp_parse(void * sessp,netsnmp_session * session,netsnmp_pdu * pdu,u_char * data,size_t length)4251 _snmp_parse(void *sessp,
4252             netsnmp_session * session,
4253             netsnmp_pdu *pdu, u_char * data, size_t length)
4254 {
4255 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4256     u_char          community[COMMUNITY_MAX_LEN];
4257     size_t          community_length = COMMUNITY_MAX_LEN;
4258 #endif
4259     int             result = -1;
4260 
4261     static oid      snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
4262     static size_t   snmpEngineIDoid_len = 11;
4263 
4264     static char     ourEngineID[SNMP_SEC_PARAM_BUF_SIZE];
4265     static size_t   ourEngineID_len = sizeof(ourEngineID);
4266 
4267     netsnmp_pdu    *pdu2 = NULL;
4268 
4269     session->s_snmp_errno = 0;
4270     session->s_errno = 0;
4271 
4272     /*
4273      * Ensure all incoming PDUs have a unique means of identification
4274      * (This is not restricted to AgentX handling,
4275      * though that is where the need becomes visible)
4276      */
4277     pdu->transid = snmp_get_next_transid();
4278 
4279     if (session->version != SNMP_DEFAULT_VERSION) {
4280         pdu->version = session->version;
4281     } else {
4282         pdu->version = snmp_parse_version(data, length);
4283     }
4284 
4285     switch (pdu->version) {
4286 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4287 #ifndef NETSNMP_DISABLE_SNMPV1
4288     case SNMP_VERSION_1:
4289 #endif
4290 #ifndef NETSNMP_DISABLE_SNMPV2C
4291     case SNMP_VERSION_2c:
4292 #endif
4293         NETSNMP_RUNTIME_PROTOCOL_CHECK_V1V2(pdu->version,unsupported_version);
4294         DEBUGMSGTL(("snmp_api", "Parsing SNMPv%ld message...\n",
4295                     (1 + pdu->version)));
4296 
4297         /*
4298          * authenticates message and returns length if valid
4299          */
4300 #ifndef NETSNMP_DISABLE_SNMPV1
4301         if (pdu->version == SNMP_VERSION_1) {
4302             DEBUGDUMPSECTION("recv", "SNMPv1 message\n");
4303         } else {
4304 #endif
4305             DEBUGDUMPSECTION("recv", "SNMPv2c message\n");
4306 #ifndef NETSNMP_DISABLE_SNMPV1
4307         }
4308 #endif
4309         data = snmp_comstr_parse(data, &length,
4310                                  community, &community_length,
4311                                  &pdu->version);
4312         if (data == NULL)
4313             return -1;
4314 
4315         if (pdu->version != session->version &&
4316             session->version != SNMP_DEFAULT_VERSION) {
4317             session->s_snmp_errno = SNMPERR_BAD_VERSION;
4318             return -1;
4319         }
4320 
4321         /*
4322          * maybe get the community string.
4323          */
4324         pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4325         pdu->securityModel =
4326 #ifndef NETSNMP_DISABLE_SNMPV1
4327             (pdu->version == SNMP_VERSION_1) ? SNMP_SEC_MODEL_SNMPv1 :
4328 #endif
4329                                                SNMP_SEC_MODEL_SNMPv2c;
4330         SNMP_FREE(pdu->community);
4331         pdu->community_len = 0;
4332         pdu->community = (u_char *) 0;
4333         if (community_length) {
4334             pdu->community_len = community_length;
4335             pdu->community = (u_char *) malloc(community_length);
4336             if (pdu->community == NULL) {
4337                 session->s_snmp_errno = SNMPERR_MALLOC;
4338                 return -1;
4339             }
4340             memmove(pdu->community, community, community_length);
4341         }
4342         if (session->authenticator) {
4343             data = session->authenticator(data, &length,
4344                                           community, community_length);
4345             if (data == NULL) {
4346                 session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
4347                 return -1;
4348             }
4349         }
4350 
4351         DEBUGDUMPSECTION("recv", "PDU");
4352         result = snmp_pdu_parse(pdu, data, &length);
4353         if (result < 0) {
4354             /*
4355              * This indicates a parse error.
4356              */
4357             snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4358         }
4359         DEBUGINDENTADD(-6);
4360         break;
4361 #endif /* support for community based SNMP */
4362 
4363     case SNMP_VERSION_3:
4364         NETSNMP_RUNTIME_PROTOCOL_CHECK_V3(SNMP_VERSION_3,unsupported_version);
4365         result = snmpv3_parse(pdu, data, &length, NULL, session);
4366         DEBUGMSGTL(("snmp_parse",
4367                     "Parsed SNMPv3 message (secName:%s, secLevel:%s): %s\n",
4368                     pdu->securityName, secLevelName[pdu->securityLevel],
4369                     snmp_api_errstring(result)));
4370 
4371         if (result) {
4372             struct snmp_secmod_def *secmod =
4373                 find_sec_mod(pdu->securityModel);
4374             if (!sessp) {
4375                 session->s_snmp_errno = result;
4376             } else {
4377                 /*
4378                  * Call the security model to special handle any errors
4379                  */
4380 
4381                 if (secmod && secmod->handle_report) {
4382                     struct session_list *slp = (struct session_list *) sessp;
4383                     (*secmod->handle_report)(sessp, slp->transport, session,
4384                                              result, pdu);
4385                 }
4386             }
4387             free_securityStateRef(pdu);
4388         }
4389 
4390         /* Implement RFC5343 here for two reasons:
4391            1) From a security perspective it handles this otherwise
4392               always approved request earlier.  It bypasses the need
4393               for authorization to the snmpEngineID scalar, which is
4394               what is what RFC3415 appendix A species as ok.  Note
4395               that we haven't bypassed authentication since if there
4396               was an authentication eror it would have been handled
4397               above in the if(result) part at the lastet.
4398            2) From an application point of view if we let this request
4399               get all the way to the application, it'd require that
4400               all application types supporting discovery also fire up
4401               a minimal agent in order to handle just this request
4402               which seems like overkill.  Though there is no other
4403               application types that currently need discovery (NRs
4404               accept notifications from contextEngineIDs that derive
4405               from the NO not the NR).  Also a lame excuse for doing
4406               it here.
4407            3) Less important technically, but the net-snmp agent
4408               doesn't currently handle registrations of different
4409               engineIDs either and it would have been a lot more work
4410               to implement there since we'd need to support that
4411               first. :-/ Supporting multiple context engineIDs should
4412               be done anyway, so it's not a valid excuse here.
4413            4) There is a lot less to do if we trump the agent at this
4414               point; IE, the agent does a lot more unnecessary
4415               processing when the only thing that should ever be in
4416               this context by definition is the single scalar.
4417         */
4418 
4419         /* special RFC5343 engineID discovery engineID check */
4420         if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
4421                                     NETSNMP_DS_LIB_NO_DISCOVERY) &&
4422             SNMP_MSG_RESPONSE       != pdu->command &&
4423             NULL                    != pdu->contextEngineID &&
4424             pdu->contextEngineIDLen == 5 &&
4425             pdu->contextEngineID[0] == 0x80 &&
4426             pdu->contextEngineID[1] == 0x00 &&
4427             pdu->contextEngineID[2] == 0x00 &&
4428             pdu->contextEngineID[3] == 0x00 &&
4429             pdu->contextEngineID[4] == 0x06) {
4430 
4431             /* define a result so it doesn't get past us at this point
4432                and gets dropped by future parts of the stack */
4433             result = SNMPERR_JUST_A_CONTEXT_PROBE;
4434 
4435             DEBUGMSGTL(("snmpv3_contextid", "starting context ID discovery\n"));
4436             /* ensure exactly one variable */
4437             if (NULL != pdu->variables &&
4438                 NULL == pdu->variables->next_variable &&
4439 
4440                 /* if it's a GET, match it exactly */
4441                 ((SNMP_MSG_GET == pdu->command &&
4442                   snmp_oid_compare(snmpEngineIDoid,
4443                                    snmpEngineIDoid_len,
4444                                    pdu->variables->name,
4445                                    pdu->variables->name_length) == 0)
4446                  /* if it's a GETNEXT ensure it's less than the engineID oid */
4447                  ||
4448                  (SNMP_MSG_GETNEXT == pdu->command &&
4449                   snmp_oid_compare(snmpEngineIDoid,
4450                                    snmpEngineIDoid_len,
4451                                    pdu->variables->name,
4452                                    pdu->variables->name_length) > 0)
4453                     )) {
4454 
4455                 DEBUGMSGTL(("snmpv3_contextid",
4456                             "  One correct variable found\n"));
4457 
4458                 /* Note: we're explictly not handling a GETBULK.  Deal. */
4459 
4460                 /* set up the response */
4461                 pdu2 = snmp_clone_pdu(pdu);
4462 
4463                 /* free the current varbind */
4464                 snmp_free_varbind(pdu2->variables);
4465 
4466                 /* set the variables */
4467                 pdu2->variables = NULL;
4468                 pdu2->command = SNMP_MSG_RESPONSE;
4469                 pdu2->errstat = 0;
4470                 pdu2->errindex = 0;
4471 
4472                 ourEngineID_len =
4473                     snmpv3_get_engineID((u_char*)ourEngineID, ourEngineID_len);
4474                 if (0 != ourEngineID_len) {
4475 
4476                     DEBUGMSGTL(("snmpv3_contextid",
4477                                 "  responding with our engineID\n"));
4478 
4479                     snmp_pdu_add_variable(pdu2,
4480                                           snmpEngineIDoid, snmpEngineIDoid_len,
4481                                           ASN_OCTET_STR,
4482                                           ourEngineID, ourEngineID_len);
4483 
4484                     /* send the response */
4485                     if (0 == snmp_sess_send(sessp, pdu2)) {
4486 
4487                         DEBUGMSGTL(("snmpv3_contextid",
4488                                     "  sent it off!\n"));
4489 
4490                         snmp_free_pdu(pdu2);
4491 
4492                         snmp_log(LOG_ERR, "sending a response to the context engineID probe failed\n");
4493                     }
4494                 } else {
4495                     snmp_log(LOG_ERR, "failed to get our own engineID!\n");
4496                 }
4497             } else {
4498                 snmp_log(LOG_WARNING,
4499                          "received an odd context engineID probe\n");
4500             }
4501         }
4502 
4503         break;
4504     case SNMPERR_BAD_VERSION:
4505         ERROR_MSG("error parsing snmp message version");
4506         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4507         session->s_snmp_errno = SNMPERR_BAD_VERSION;
4508         break;
4509 
4510         unsupported_version:  /* goto label */
4511     case SNMP_VERSION_sec:
4512     case SNMP_VERSION_2u:
4513     case SNMP_VERSION_2star:
4514     case SNMP_VERSION_2p:
4515     default:
4516         ERROR_MSG("unsupported snmp message version");
4517         snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
4518 
4519         /*
4520          * need better way to determine OS independent
4521          * INT32_MAX value, for now hardcode
4522          */
4523         if (pdu->version < 0 || pdu->version > 2147483647) {
4524             snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4525         }
4526         session->s_snmp_errno = SNMPERR_BAD_VERSION;
4527         break;
4528     }
4529 
4530     return result;
4531 }
4532 
4533 /**
4534  * Parse a PDU.
4535  * @param slp    [in]  Session pointer (struct session_list).
4536  * @param pss    [in]  Session pointer (netsnmp_session).
4537  * @param pdu    [out] Parsed PDU.
4538  * @param data   [in]  PDU to parse.
4539  * @param length [in]  Length of data.
4540  *
4541  * @returns 0 upon success; -1 upon failure.
4542  */
4543 int
snmp_parse(struct session_list * slp,netsnmp_session * pss,netsnmp_pdu * pdu,u_char * data,size_t length)4544 snmp_parse(struct session_list *slp,
4545            netsnmp_session * pss,
4546            netsnmp_pdu *pdu, u_char * data, size_t length)
4547 {
4548     int             rc;
4549 
4550     rc = _snmp_parse(slp, pss, pdu, data, length);
4551     if (rc) {
4552         if (!pss->s_snmp_errno) {
4553             pss->s_snmp_errno = SNMPERR_BAD_PARSE;
4554         }
4555         SET_SNMP_ERROR(pss->s_snmp_errno);
4556     }
4557 
4558     return rc;
4559 }
4560 
4561 int
snmp_pdu_parse(netsnmp_pdu * pdu,u_char * data,size_t * length)4562 snmp_pdu_parse(netsnmp_pdu *pdu, u_char * data, size_t * length)
4563 {
4564     u_char          type;
4565     u_char          msg_type;
4566     u_char         *var_val;
4567     size_t          len;
4568     size_t          four;
4569     netsnmp_variable_list *vp = NULL, *vplast = NULL;
4570     oid             objid[MAX_OID_LEN];
4571     u_char         *p;
4572 
4573     /*
4574      * Get the PDU type
4575      */
4576     data = asn_parse_header(data, length, &msg_type);
4577     if (data == NULL)
4578         return -1;
4579     DEBUGMSGTL(("dumpv_recv","    Command %s\n", snmp_pdu_type(msg_type)));
4580     pdu->command = msg_type;
4581     pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
4582 
4583     /*
4584      * get the fields in the PDU preceding the variable-bindings sequence
4585      */
4586     switch (pdu->command) {
4587     case SNMP_MSG_TRAP:
4588         /*
4589          * enterprise
4590          */
4591         pdu->enterprise_length = MAX_OID_LEN;
4592         data = asn_parse_objid(data, length, &type, objid,
4593                                &pdu->enterprise_length);
4594         if (data == NULL)
4595             return -1;
4596         pdu->enterprise =
4597             (oid *) malloc(pdu->enterprise_length * sizeof(oid));
4598         if (pdu->enterprise == NULL) {
4599             return -1;
4600         }
4601         memmove(pdu->enterprise, objid,
4602                 pdu->enterprise_length * sizeof(oid));
4603 
4604         /*
4605          * agent-addr
4606          */
4607         four = 4;
4608         data = asn_parse_string(data, length, &type,
4609                                 (u_char *) pdu->agent_addr, &four);
4610         if (data == NULL)
4611             return -1;
4612 
4613         /*
4614          * generic trap
4615          */
4616         data = asn_parse_int(data, length, &type, (long *) &pdu->trap_type,
4617                              sizeof(pdu->trap_type));
4618         if (data == NULL)
4619             return -1;
4620         /*
4621          * specific trap
4622          */
4623         data =
4624             asn_parse_int(data, length, &type,
4625                           (long *) &pdu->specific_type,
4626                           sizeof(pdu->specific_type));
4627         if (data == NULL)
4628             return -1;
4629 
4630         /*
4631          * timestamp
4632          */
4633         data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
4634                                       sizeof(pdu->time));
4635         if (data == NULL)
4636             return -1;
4637 
4638         break;
4639 
4640     case SNMP_MSG_RESPONSE:
4641     case SNMP_MSG_REPORT:
4642         pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
4643         /* FALL THROUGH */
4644 
4645     case SNMP_MSG_TRAP2:
4646     case SNMP_MSG_INFORM:
4647 #ifndef NETSNMP_NOTIFY_ONLY
4648     case SNMP_MSG_GET:
4649     case SNMP_MSG_GETNEXT:
4650     case SNMP_MSG_GETBULK:
4651 #endif /* ! NETSNMP_NOTIFY_ONLY */
4652 #ifndef NETSNMP_NO_WRITE_SUPPORT
4653     case SNMP_MSG_SET:
4654 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
4655         /*
4656          * PDU is not an SNMPv1 TRAP
4657          */
4658 
4659         /*
4660          * request id
4661          */
4662         DEBUGDUMPHEADER("recv", "request_id");
4663         data = asn_parse_int(data, length, &type, &pdu->reqid,
4664                              sizeof(pdu->reqid));
4665         DEBUGINDENTLESS();
4666         if (data == NULL) {
4667             return -1;
4668         }
4669 
4670         /*
4671          * error status (getbulk non-repeaters)
4672          */
4673         DEBUGDUMPHEADER("recv", "error status");
4674         data = asn_parse_int(data, length, &type, &pdu->errstat,
4675                              sizeof(pdu->errstat));
4676         DEBUGINDENTLESS();
4677         if (data == NULL) {
4678             return -1;
4679         }
4680 
4681         /*
4682          * error index (getbulk max-repetitions)
4683          */
4684         DEBUGDUMPHEADER("recv", "error index");
4685         data = asn_parse_int(data, length, &type, &pdu->errindex,
4686                              sizeof(pdu->errindex));
4687         DEBUGINDENTLESS();
4688         if (data == NULL) {
4689             return -1;
4690         }
4691 	break;
4692 
4693     default:
4694         snmp_log(LOG_ERR, "Bad PDU type received: 0x%.2x\n", pdu->command);
4695         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4696         return -1;
4697     }
4698 
4699     /*
4700      * get header for variable-bindings sequence
4701      */
4702     DEBUGDUMPSECTION("recv", "VarBindList");
4703     data = asn_parse_sequence(data, length, &type,
4704                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
4705                               "varbinds");
4706     if (data == NULL)
4707         goto fail;
4708 
4709     /*
4710      * get each varBind sequence
4711      */
4712     while ((int) *length > 0) {
4713         vp = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
4714         if (NULL == vp)
4715             goto fail;
4716 
4717         vp->name_length = MAX_OID_LEN;
4718         DEBUGDUMPSECTION("recv", "VarBind");
4719         data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
4720                                  &vp->val_len, &var_val, length);
4721         if (data == NULL)
4722             goto fail;
4723         if (snmp_set_var_objid(vp, objid, vp->name_length))
4724             goto fail;
4725 
4726         len = SNMP_MAX_PACKET_LEN;
4727         DEBUGDUMPHEADER("recv", "Value");
4728         switch ((short) vp->type) {
4729         case ASN_INTEGER:
4730             vp->val.integer = (long *) vp->buf;
4731             vp->val_len = sizeof(long);
4732             p = asn_parse_int(var_val, &len, &vp->type,
4733                           (long *) vp->val.integer,
4734                           sizeof(*vp->val.integer));
4735             if (!p)
4736                 goto fail;
4737             break;
4738         case ASN_COUNTER:
4739         case ASN_GAUGE:
4740         case ASN_TIMETICKS:
4741         case ASN_UINTEGER:
4742             vp->val.integer = (long *) vp->buf;
4743             vp->val_len = sizeof(u_long);
4744             p = asn_parse_unsigned_int(var_val, &len, &vp->type,
4745                                    (u_long *) vp->val.integer,
4746                                    vp->val_len);
4747             if (!p)
4748                 goto fail;
4749             break;
4750 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4751         case ASN_OPAQUE_COUNTER64:
4752         case ASN_OPAQUE_U64:
4753 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
4754         case ASN_COUNTER64:
4755             vp->val.counter64 = (struct counter64 *) vp->buf;
4756             vp->val_len = sizeof(struct counter64);
4757             p = asn_parse_unsigned_int64(var_val, &len, &vp->type,
4758                                      (struct counter64 *) vp->val.
4759                                      counter64, vp->val_len);
4760             if (!p)
4761                 goto fail;
4762             break;
4763 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4764         case ASN_OPAQUE_FLOAT:
4765             vp->val.floatVal = (float *) vp->buf;
4766             vp->val_len = sizeof(float);
4767             p = asn_parse_float(var_val, &len, &vp->type,
4768                             vp->val.floatVal, vp->val_len);
4769             if (!p)
4770                 goto fail;
4771             break;
4772         case ASN_OPAQUE_DOUBLE:
4773             vp->val.doubleVal = (double *) vp->buf;
4774             vp->val_len = sizeof(double);
4775             p = asn_parse_double(var_val, &len, &vp->type,
4776                              vp->val.doubleVal, vp->val_len);
4777             if (!p)
4778                 goto fail;
4779             break;
4780         case ASN_OPAQUE_I64:
4781             vp->val.counter64 = (struct counter64 *) vp->buf;
4782             vp->val_len = sizeof(struct counter64);
4783             p = asn_parse_signed_int64(var_val, &len, &vp->type,
4784                                    (struct counter64 *) vp->val.counter64,
4785                                    sizeof(*vp->val.counter64));
4786 
4787             if (!p)
4788                 goto fail;
4789             break;
4790 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
4791         case ASN_IPADDRESS:
4792             if (vp->val_len != 4)
4793                 goto fail;
4794             /* fallthrough */
4795         case ASN_OCTET_STR:
4796         case ASN_OPAQUE:
4797         case ASN_NSAP:
4798             if (vp->val_len < sizeof(vp->buf)) {
4799                 vp->val.string = (u_char *) vp->buf;
4800             } else {
4801                 vp->val.string = (u_char *) malloc(vp->val_len);
4802             }
4803             if (vp->val.string == NULL) {
4804                 goto fail;
4805             }
4806             p = asn_parse_string(var_val, &len, &vp->type, vp->val.string,
4807                              &vp->val_len);
4808             if (!p)
4809                 goto fail;
4810             break;
4811         case ASN_OBJECT_ID:
4812             vp->val_len = MAX_OID_LEN;
4813             p = asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
4814             if (!p)
4815                 goto fail;
4816             vp->val_len *= sizeof(oid);
4817             vp->val.objid = (oid *) malloc(vp->val_len);
4818             if (vp->val.objid == NULL) {
4819                 goto fail;
4820             }
4821             memmove(vp->val.objid, objid, vp->val_len);
4822             break;
4823         case SNMP_NOSUCHOBJECT:
4824         case SNMP_NOSUCHINSTANCE:
4825         case SNMP_ENDOFMIBVIEW:
4826         case ASN_NULL:
4827             break;
4828         case ASN_BIT_STR:
4829             vp->val.bitstring = (u_char *) malloc(vp->val_len);
4830             if (vp->val.bitstring == NULL) {
4831                 goto fail;
4832             }
4833             p = asn_parse_bitstring(var_val, &len, &vp->type,
4834                                 vp->val.bitstring, &vp->val_len);
4835             if (!p)
4836                 goto fail;
4837             break;
4838         default:
4839             snmp_log(LOG_ERR, "bad type returned (%x)\n", vp->type);
4840             goto fail;
4841             break;
4842         }
4843         DEBUGINDENTADD(-4);
4844 
4845         if (NULL == vplast) {
4846             pdu->variables = vp;
4847         } else {
4848             vplast->next_variable = vp;
4849         }
4850         vplast = vp;
4851         vp = NULL;
4852     }
4853     return 0;
4854 
4855   fail:
4856     {
4857         const char *errstr = snmp_api_errstring(SNMPERR_SUCCESS);
4858         DEBUGMSGTL(("recv", "error while parsing VarBindList:%s\n", errstr));
4859     }
4860     /** if we were parsing a var, remove it from the pdu and free it */
4861     if (vp)
4862         snmp_free_var(vp);
4863 
4864     return -1;
4865 }
4866 
4867 /*
4868  * snmp v3 utility function to parse into the scopedPdu. stores contextName
4869  * and contextEngineID in pdu struct. Also stores pdu->command (handy for
4870  * Report generation).
4871  *
4872  * returns pointer to begining of PDU or NULL on error.
4873  */
4874 u_char         *
snmpv3_scopedPDU_parse(netsnmp_pdu * pdu,u_char * cp,size_t * length)4875 snmpv3_scopedPDU_parse(netsnmp_pdu *pdu, u_char * cp, size_t * length)
4876 {
4877     u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
4878     size_t          tmp_buf_len;
4879     u_char          type;
4880     size_t          asn_len;
4881     u_char         *data;
4882 
4883     pdu->command = 0;           /* initialize so we know if it got parsed */
4884     asn_len = *length;
4885     data = asn_parse_sequence(cp, &asn_len, &type,
4886                               (ASN_SEQUENCE | ASN_CONSTRUCTOR),
4887                               "plaintext scopedPDU");
4888     if (data == NULL) {
4889         return NULL;
4890     }
4891     *length -= data - cp;
4892 
4893     /*
4894      * contextEngineID from scopedPdu
4895      */
4896     DEBUGDUMPHEADER("recv", "contextEngineID");
4897     data = asn_parse_string(data, length, &type, pdu->contextEngineID,
4898                             &pdu->contextEngineIDLen);
4899     DEBUGINDENTLESS();
4900     if (data == NULL) {
4901         ERROR_MSG("error parsing contextEngineID from scopedPdu");
4902         return NULL;
4903     }
4904 
4905     /*
4906      * parse contextName from scopedPdu
4907      */
4908     tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
4909     DEBUGDUMPHEADER("recv", "contextName");
4910     data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
4911     DEBUGINDENTLESS();
4912     if (data == NULL) {
4913         ERROR_MSG("error parsing contextName from scopedPdu");
4914         return NULL;
4915     }
4916 
4917     if (tmp_buf_len) {
4918         pdu->contextName = (char *) malloc(tmp_buf_len);
4919         memmove(pdu->contextName, tmp_buf, tmp_buf_len);
4920         pdu->contextNameLen = tmp_buf_len;
4921     } else {
4922         pdu->contextName = strdup("");
4923         pdu->contextNameLen = 0;
4924     }
4925     if (pdu->contextName == NULL) {
4926         ERROR_MSG("error copying contextName from scopedPdu");
4927         return NULL;
4928     }
4929 
4930     /*
4931      * Get the PDU type
4932      */
4933     asn_len = *length;
4934     cp = asn_parse_header(data, &asn_len, &type);
4935     if (cp == NULL)
4936         return NULL;
4937 
4938     pdu->command = type;
4939 
4940     return data;
4941 }
4942 
4943 
4944 /* ===========================================================================
4945  *
4946  * build pdu packet
4947  */
4948 int
netsnmp_build_packet(struct snmp_internal_session * isp,netsnmp_session * sp,netsnmp_pdu * pdu,u_char ** pktbuf_p,size_t * pktbuf_len_p,u_char ** pkt_p,size_t * len_p)4949 netsnmp_build_packet(struct snmp_internal_session *isp, netsnmp_session *sp,
4950                      netsnmp_pdu *pdu, u_char **pktbuf_p,
4951                      size_t *pktbuf_len_p, u_char **pkt_p, size_t *len_p)
4952 {
4953     size_t offset = 0;
4954     int    result;
4955 
4956     if (isp && isp->hook_realloc_build) {
4957         result = isp->hook_realloc_build(sp, pdu, pktbuf_p, pktbuf_len_p,
4958                                          &offset);
4959 
4960         *pkt_p = *pktbuf_p;
4961         *len_p = offset;
4962     } else if (isp && isp->hook_build) {
4963         *pkt_p = *pktbuf_p;
4964         *len_p = *pktbuf_len_p;
4965         result = isp->hook_build(sp, pdu, *pktbuf_p, len_p);
4966     } else {
4967 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
4968         if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
4969             result = snmp_build(pktbuf_p, pktbuf_len_p, &offset, sp, pdu);
4970             *pkt_p = *pktbuf_p + *pktbuf_len_p - offset;
4971             *len_p = offset;
4972         } else {
4973 #endif
4974             *pkt_p = *pktbuf_p;
4975             *len_p = *pktbuf_len_p;
4976             result = snmp_build(pktbuf_p, len_p, &offset, sp, pdu);
4977 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
4978         }
4979 #endif
4980     }
4981 
4982     return result;
4983 }
4984 
4985 int
_build_initial_pdu_packet(struct session_list * slp,netsnmp_pdu * pdu,int bulk)4986 _build_initial_pdu_packet(struct session_list *slp, netsnmp_pdu *pdu, int bulk)
4987 {
4988     netsnmp_session *session;
4989     struct snmp_internal_session *isp;
4990     netsnmp_transport *transport = NULL;
4991     u_char         *pktbuf = NULL, *packet = NULL;
4992     size_t          pktbuf_len = 0, offset = 0, length = 0, orig_length = 0;
4993     int             result, orig_count = 0, curr_count = 0;
4994 
4995     if (slp == NULL) {
4996         return SNMPERR_GENERR;
4997     }
4998     session = slp->session;
4999 
5000     isp = slp->internal;
5001     transport = slp->transport;
5002     if (!session || !isp || !transport) {
5003         DEBUGMSGTL(("sess_async_send", "send fail: closing...\n"));
5004         return SNMPERR_GENERR;
5005     }
5006 
5007     if (pdu == NULL) {
5008         session->s_snmp_errno = SNMPERR_NULL_PDU;
5009         return SNMPERR_GENERR;
5010     }
5011 
5012     SNMP_FREE(isp->obuf); /* should already be NULL */
5013 
5014     session->s_snmp_errno = 0;
5015     session->s_errno = 0;
5016 
5017     /*
5018      * Check/setup the version.
5019      */
5020     if (pdu->version == SNMP_DEFAULT_VERSION) {
5021         if (session->version == SNMP_DEFAULT_VERSION) {
5022             session->s_snmp_errno = SNMPERR_BAD_VERSION;
5023             return SNMPERR_GENERR;
5024         }
5025         pdu->version = session->version;
5026     } else if (session->version == SNMP_DEFAULT_VERSION) {
5027         /*
5028          * It's OK
5029          */
5030     } else if (pdu->version != session->version) {
5031         /*
5032          * ENHANCE: we should support multi-lingual sessions
5033          */
5034         session->s_snmp_errno = SNMPERR_BAD_VERSION;
5035         return SNMPERR_GENERR;
5036     }
5037     if (NETSNMP_RUNTIME_PROTOCOL_SKIP(pdu->version)) {
5038         DEBUGMSGTL(("sess_async_send", "version disabled at runtime\n"));
5039         session->s_snmp_errno = SNMPERR_BAD_VERSION;
5040         return SNMPERR_GENERR;
5041     }
5042 
5043     /*
5044      * do we expect a response?
5045      */
5046     switch (pdu->command) {
5047 
5048         case SNMP_MSG_RESPONSE:
5049         case SNMP_MSG_TRAP:
5050         case SNMP_MSG_TRAP2:
5051         case SNMP_MSG_REPORT:
5052         case AGENTX_MSG_CLEANUPSET:
5053         case AGENTX_MSG_RESPONSE:
5054             pdu->flags &= ~UCD_MSG_FLAG_EXPECT_RESPONSE;
5055             break;
5056 
5057         default:
5058             pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
5059             break;
5060     }
5061 
5062     /*
5063      * check to see if we need a v3 engineID probe
5064      */
5065     if ((pdu->version == SNMP_VERSION_3) &&
5066         (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) &&
5067         (session->securityEngineIDLen == 0) &&
5068         (0 == (session->flags & SNMP_FLAGS_DONT_PROBE))) {
5069         int rc;
5070         DEBUGMSGTL(("snmpv3_build", "delayed probe for engineID\n"));
5071         rc = snmpv3_engineID_probe(slp, session);
5072         if (rc == 0)
5073             return 0; /* s_snmp_errno already set */
5074     }
5075 
5076     /*
5077      * determine max packet size
5078      */
5079     if (pdu->msgMaxSize == 0) {
5080         pdu->msgMaxSize = netsnmp_max_send_msg_size();
5081         if (pdu->msgMaxSize > transport->msgMaxSize)
5082             pdu->msgMaxSize = transport->msgMaxSize;
5083         if (pdu->msgMaxSize > session->sndMsgMaxSize)
5084             pdu->msgMaxSize = session->sndMsgMaxSize;
5085         DEBUGMSGTL(("sess_async_send", "max PDU size: %ld\n",
5086                     pdu->msgMaxSize));
5087     }
5088     netsnmp_assert(pdu->msgMaxSize > 0);
5089 
5090     /*
5091      * allocate initial packet buffer. Buffer will be grown as needed
5092      * while building the packet.
5093      */
5094     pktbuf_len = SNMP_MIN_MAX_LEN;
5095     if ((pktbuf = (u_char *)malloc(pktbuf_len)) == NULL) {
5096         DEBUGMSGTL(("sess_async_send",
5097                     "couldn't malloc initial packet buffer\n"));
5098         session->s_snmp_errno = SNMPERR_MALLOC;
5099         return SNMPERR_MALLOC;
5100     }
5101 
5102 #if TEMPORARILY_DISABLED
5103     /*
5104      *  NULL variable are allowed in certain PDU types.
5105      *  In particular, SNMPv3 engineID probes are of this form.
5106      *  There is an internal PDU flag to indicate that this
5107      *    is acceptable, but until the construction of engineID
5108      *    probes can be amended to set this flag, we'll simply
5109      *    skip this test altogether.
5110      */
5111     if (pdu->variables == NULL) {
5112         switch (pdu->command) {
5113 #ifndef NETSNMP_NO_WRITE_SUPPORT
5114         case SNMP_MSG_SET:
5115 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
5116         case SNMP_MSG_GET:
5117         case SNMP_MSG_GETNEXT:
5118         case SNMP_MSG_GETBULK:
5119         case SNMP_MSG_RESPONSE:
5120         case SNMP_MSG_TRAP2:
5121         case SNMP_MSG_REPORT:
5122         case SNMP_MSG_INFORM:
5123             session->s_snmp_errno = snmp_errno = SNMPERR_NO_VARS;
5124             return SNMPERR_NO_VARS;
5125         case SNMP_MSG_TRAP:
5126             break;
5127         }
5128     }
5129 #endif
5130 
5131 
5132     /*
5133      * Build the message to send. If a bulk response is too big, switch to
5134      * forward encoding and set a flag to drop varbinds to make it fit.
5135      */
5136     do {
5137         packet = pktbuf;
5138         length = offset = 0;
5139         result = netsnmp_build_packet(isp, session, pdu, &pktbuf, &pktbuf_len,
5140                                       &packet, &length);
5141         if (0 != result)
5142             break;
5143 
5144         if (orig_count) { /* 2nd pass, see how many varbinds remain */
5145             curr_count = count_varbinds(pdu->variables);
5146             DEBUGMSGTL(("sess_async_send", " vb count: %d -> %d\n", orig_count,
5147                         curr_count));
5148             DEBUGMSGTL(("sess_async_send", " pdu_len: %" NETSNMP_PRIz "d -> %" NETSNMP_PRIz "d (max %ld)\n",
5149                         orig_length, length, pdu->msgMaxSize));
5150         }
5151 
5152         /** if length is less than max size, we're done (success). */
5153         if (length <= pdu->msgMaxSize)
5154             break;
5155 
5156         DEBUGMSGTL(("sess_async_send", "length %" NETSNMP_PRIz "d exceeds maximum %ld\n",
5157                     length, pdu->msgMaxSize));
5158 
5159         /** packet too big. if this is not a bulk request, we're done (err). */
5160         if (!bulk) {
5161            session->s_snmp_errno = SNMPERR_TOO_LONG;
5162            break;
5163         }
5164 
5165         /** rebuild bulk response with truncation and fixed size */
5166         pdu->flags |= UCD_MSG_FLAG_FORWARD_ENCODE | UCD_MSG_FLAG_BULK_TOOBIG;
5167         pktbuf_len = pdu->msgMaxSize;
5168 
5169         /** save original number of vabinds & length */
5170         if (0 == orig_count) {
5171             curr_count = orig_count = count_varbinds(pdu->variables);
5172             orig_length = length;
5173         }
5174 
5175     } while(1);
5176 
5177     DEBUGMSGTL(("sess_async_send",
5178                 "final pktbuf_len after building packet %" NETSNMP_PRIz "u\n",
5179                 pktbuf_len));
5180     if (curr_count != orig_count)
5181         DEBUGMSGTL(("sess_async_send",
5182                     "sending %d of %d varbinds (-%d) from bulk response\n",
5183                     curr_count, orig_count, orig_count - curr_count));
5184 
5185     if (length > pdu->msgMaxSize) {
5186         DEBUGMSGTL(("sess_async_send",
5187                     "length of packet (%" NETSNMP_PRIz "u) exceeded pdu maximum (%lu)\n",
5188                     length, pdu->msgMaxSize));
5189         netsnmp_assert(SNMPERR_TOO_LONG == session->s_snmp_errno);
5190     }
5191 
5192     if ((SNMPERR_TOO_LONG == session->s_snmp_errno) || (result < 0)) {
5193         DEBUGMSGTL(("sess_async_send", "encoding failure\n"));
5194         SNMP_FREE(pktbuf);
5195         return SNMPERR_GENERR;
5196     }
5197 
5198     isp->obuf = pktbuf;
5199     isp->obuf_size = pktbuf_len;
5200     isp->opacket = packet;
5201     isp->opacket_len = length;
5202 
5203     return SNMPERR_SUCCESS;
5204 }
5205 
5206 /*
5207  * These functions send PDUs using an active session:
5208  * snmp_send             - traditional API, no callback
5209  * snmp_async_send       - traditional API, with callback
5210  * snmp_sess_send        - single session API, no callback
5211  * snmp_sess_async_send  - single session API, with callback
5212  *
5213  * Call snmp_build to create a serialized packet (the pdu).
5214  * If necessary, set some of the pdu data from the
5215  * session defaults.
5216  * If there is an expected response for this PDU,
5217  * queue a corresponding request on the list
5218  * of outstanding requests for this session,
5219  * and store the callback vectors in the request.
5220  *
5221  * Send the pdu to the target identified by this session.
5222  * Return on success:
5223  *   The request id of the pdu is returned, and the pdu is freed.
5224  * Return on failure:
5225  *   Zero (0) is returned.
5226  *   The caller must call snmp_free_pdu if 0 is returned.
5227  */
5228 int
snmp_send(netsnmp_session * session,netsnmp_pdu * pdu)5229 snmp_send(netsnmp_session * session, netsnmp_pdu *pdu)
5230 {
5231     return snmp_async_send(session, pdu, NULL, NULL);
5232 }
5233 
5234 int
snmp_sess_send(void * sessp,netsnmp_pdu * pdu)5235 snmp_sess_send(void *sessp, netsnmp_pdu *pdu)
5236 {
5237     return snmp_sess_async_send(sessp, pdu, NULL, NULL);
5238 }
5239 
5240 int
snmp_async_send(netsnmp_session * session,netsnmp_pdu * pdu,snmp_callback callback,void * cb_data)5241 snmp_async_send(netsnmp_session * session,
5242                 netsnmp_pdu *pdu, snmp_callback callback, void *cb_data)
5243 {
5244     void           *sessp = snmp_sess_pointer(session);
5245     return snmp_sess_async_send(sessp, pdu, callback, cb_data);
5246 }
5247 
5248 /**
5249  * Send a PDU asynchronously.
5250  *
5251  * @param[in] slp      Session pointer.
5252  * @param[in] pdu      PDU to send.
5253  * @param[in] callback Callback function called after processing of the PDU
5254  *                     finished. This function is called if the PDU has not
5255  *                     been sent or after a response has been received. Must
5256  *                     not free @pdu.
5257  * @param[in] cb_data  Will be passed as fifth argument to @callback.
5258  *
5259  * @return If successful, returns the request id of @pdu and frees @pdu.
5260  * If not successful, returns zero and expects the caller to free @pdu.
5261  */
5262 static int
_sess_async_send(void * sessp,netsnmp_pdu * pdu,snmp_callback callback,void * cb_data)5263 _sess_async_send(void *sessp,
5264                  netsnmp_pdu *pdu, snmp_callback callback, void *cb_data)
5265 {
5266     struct session_list *slp = (struct session_list *) sessp;
5267     netsnmp_session *session;
5268     struct snmp_internal_session *isp;
5269     netsnmp_transport *transport = NULL;
5270     int             result;
5271     long            reqid;
5272 
5273     if (slp == NULL || NULL == slp->session || NULL ==slp->internal ||
5274                 NULL == slp->transport) {
5275         return 0;
5276     }
5277 
5278     session = slp->session;
5279     isp = slp->internal;
5280     transport = slp->transport;
5281 
5282     if (NULL == isp->opacket) {
5283         result = _build_initial_pdu_packet(slp, pdu, 0);
5284         if ((SNMPERR_SUCCESS != result) || (NULL == isp->opacket)) {
5285             if (callback) {
5286                 switch (session->s_snmp_errno) {
5287                     /*
5288                      * some of these probably don't make sense here, but
5289                      * it's a rough first cut.
5290                      */
5291                     case SNMPERR_BAD_ENG_ID:
5292                     case SNMPERR_BAD_SEC_LEVEL:
5293                     case SNMPERR_UNKNOWN_SEC_MODEL:
5294                     case SNMPERR_UNKNOWN_ENG_ID:
5295                     case SNMPERR_UNKNOWN_USER_NAME:
5296                     case SNMPERR_UNSUPPORTED_SEC_LEVEL:
5297                     case SNMPERR_AUTHENTICATION_FAILURE:
5298                     case SNMPERR_NOT_IN_TIME_WINDOW:
5299                     case SNMPERR_USM_GENERICERROR:
5300                     case SNMPERR_USM_UNKNOWNSECURITYNAME:
5301                     case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
5302                     case SNMPERR_USM_ENCRYPTIONERROR:
5303                     case SNMPERR_USM_AUTHENTICATIONFAILURE:
5304                     case SNMPERR_USM_PARSEERROR:
5305                     case SNMPERR_USM_UNKNOWNENGINEID:
5306                     case SNMPERR_USM_NOTINTIMEWINDOW:
5307                         callback(NETSNMP_CALLBACK_OP_SEC_ERROR, session,
5308                                  pdu->reqid, pdu, cb_data);
5309                         break;
5310                     case SNMPERR_TIMEOUT: /* engineID probe timed out */
5311                         callback(NETSNMP_CALLBACK_OP_TIMED_OUT, session,
5312                                  pdu->reqid, pdu, cb_data);
5313                         break;
5314                     default:
5315                         callback(NETSNMP_CALLBACK_OP_SEND_FAILED, session,
5316                                  pdu->reqid, pdu, cb_data);
5317                         break;
5318                 }
5319             }
5320             /** no packet to send?? */
5321             return 0;
5322         }
5323     }
5324 
5325     /*
5326      * Send the message.
5327      */
5328 
5329     DEBUGMSGTL(("sess_process_packet", "sending message id#%ld reqid#%ld len %"
5330                 NETSNMP_PRIz "u\n", pdu->msgid, pdu->reqid, isp->opacket_len));
5331     result = netsnmp_transport_send(transport, isp->opacket, isp->opacket_len,
5332                                     &(pdu->transport_data),
5333                                     &(pdu->transport_data_length));
5334 
5335     SNMP_FREE(isp->obuf);
5336     isp->opacket = NULL; /* opacket was in obuf, so no free needed */
5337     isp->opacket_len = 0;
5338 
5339     if (result < 0) {
5340         session->s_snmp_errno = SNMPERR_BAD_SENDTO;
5341         session->s_errno = errno;
5342         if (callback)
5343             callback(NETSNMP_CALLBACK_OP_SEND_FAILED, session,
5344                      pdu->reqid, pdu, cb_data);
5345         return 0;
5346     }
5347 
5348     reqid = pdu->reqid;
5349 
5350     /*
5351      * Bug 2387: 0 is a valid request id, so since reqid is used as a return
5352      * code with 0 meaning an error, set reqid to 1 if there is no error. This
5353      * does not affect the request id in the packet and fixes a memory leak
5354      * for incoming PDUs with a request id of 0. This could cause some
5355      * confusion if the caller is expecting the request id to match the
5356      * return code, as the documentation states it will. Most example code
5357      * just checks for non-zero, so hopefully this wont be an issue.
5358      */
5359     if (0 == reqid && (SNMPERR_SUCCESS == session->s_snmp_errno))
5360         ++reqid;
5361 
5362     /*
5363      * Add to pending requests list if we expect a response.
5364      */
5365     if (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) {
5366         netsnmp_request_list *rp;
5367         struct timeval  tv;
5368 
5369         rp = (netsnmp_request_list *) calloc(1,
5370                                              sizeof(netsnmp_request_list));
5371         if (rp == NULL) {
5372             session->s_snmp_errno = SNMPERR_GENERR;
5373             return 0;
5374         }
5375 
5376         netsnmp_get_monotonic_clock(&tv);
5377         rp->pdu = pdu;
5378         rp->request_id = pdu->reqid;
5379         rp->message_id = pdu->msgid;
5380         rp->callback = callback;
5381         rp->cb_data = cb_data;
5382         rp->retries = 0;
5383         if (pdu->flags & UCD_MSG_FLAG_PDU_TIMEOUT) {
5384             rp->timeout = pdu->time * 1000000L;
5385         } else {
5386             rp->timeout = session->timeout;
5387         }
5388         rp->timeM = tv;
5389         tv.tv_usec += rp->timeout;
5390         tv.tv_sec += tv.tv_usec / 1000000L;
5391         tv.tv_usec %= 1000000L;
5392         rp->expireM = tv;
5393 
5394         /*
5395          * XX lock should be per session !
5396          */
5397         snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
5398         if (isp->requestsEnd) {
5399             rp->next_request = isp->requestsEnd->next_request;
5400             isp->requestsEnd->next_request = rp;
5401             isp->requestsEnd = rp;
5402         } else {
5403             rp->next_request = isp->requests;
5404             isp->requests = rp;
5405             isp->requestsEnd = rp;
5406         }
5407         snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
5408     } else {
5409         /*
5410          * No response expected...
5411          */
5412         if (reqid) {
5413             /*
5414              * Free v1 or v2 TRAP PDU iff no error
5415              */
5416             snmp_free_pdu(pdu);
5417         }
5418     }
5419 
5420     return reqid;
5421 }
5422 
5423 /**
5424  * Send a PDU asynchronously.
5425  *
5426  * @param[in] slp      Session pointer.
5427  * @param[in] pdu      PDU to send.
5428  * @param[in] callback Callback function called after processing of the PDU
5429  *                     finished. This function is called if the PDU has not
5430  *                     been sent or after a response has been received. Must
5431  *                     not free @pdu.
5432  * @param[in] cb_data  Will be passed as fifth argument to @callback.
5433  *
5434  * @return If successful, returns the request id of @pdu and frees @pdu.
5435  * If not successful, returns zero and expects the caller to free @pdu.
5436  */
5437 int
snmp_sess_async_send(void * sessp,netsnmp_pdu * pdu,snmp_callback callback,void * cb_data)5438 snmp_sess_async_send(void *sessp,
5439                      netsnmp_pdu *pdu,
5440                      snmp_callback callback, void *cb_data)
5441 {
5442     int             rc;
5443 
5444     if (sessp == NULL) {
5445         snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
5446         return (0);
5447     }
5448     /*
5449      * send pdu
5450      */
5451     rc = _sess_async_send(sessp, pdu, callback, cb_data);
5452     if (rc == 0) {
5453         struct session_list *psl;
5454         netsnmp_session *pss;
5455         psl = (struct session_list *) sessp;
5456         pss = psl->session;
5457         SET_SNMP_ERROR(pss->s_snmp_errno);
5458     }
5459     return rc;
5460 }
5461 
5462 
5463 /*
5464  * Frees the variable and any malloc'd data associated with it.
5465  */
5466 void
snmp_free_var_internals(netsnmp_variable_list * var)5467 snmp_free_var_internals(netsnmp_variable_list * var)
5468 {
5469     if (!var)
5470         return;
5471 
5472     if (var->name != var->name_loc)
5473         SNMP_FREE(var->name);
5474     if (var->val.string != var->buf)
5475         SNMP_FREE(var->val.string);
5476     if (var->data) {
5477         if (var->dataFreeHook) {
5478             var->dataFreeHook(var->data);
5479             var->data = NULL;
5480         } else {
5481             SNMP_FREE(var->data);
5482         }
5483     }
5484 }
5485 
5486 void
snmp_free_var(netsnmp_variable_list * var)5487 snmp_free_var(netsnmp_variable_list * var)
5488 {
5489     snmp_free_var_internals(var);
5490     free((char *) var);
5491 }
5492 
5493 void
snmp_free_varbind(netsnmp_variable_list * var)5494 snmp_free_varbind(netsnmp_variable_list * var)
5495 {
5496     netsnmp_variable_list *ptr;
5497     while (var) {
5498         ptr = var->next_variable;
5499         snmp_free_var(var);
5500         var = ptr;
5501     }
5502 }
5503 
5504 /*
5505  * Frees the pdu and any malloc'd data associated with it.
5506  */
5507 void
snmp_free_pdu(netsnmp_pdu * pdu)5508 snmp_free_pdu(netsnmp_pdu *pdu)
5509 {
5510     struct snmp_secmod_def *sptr;
5511 
5512     if (!pdu)
5513         return;
5514 
5515     free_securityStateRef(pdu);
5516 
5517     if ((sptr = find_sec_mod(pdu->securityModel)) != NULL &&
5518         sptr->pdu_free != NULL) {
5519         (*sptr->pdu_free) (pdu);
5520     }
5521     snmp_free_varbind(pdu->variables);
5522     free(pdu->enterprise);
5523     free(pdu->community);
5524     free(pdu->contextEngineID);
5525     free(pdu->securityEngineID);
5526     free(pdu->contextName);
5527     free(pdu->securityName);
5528     free(pdu->transport_data);
5529     free(pdu);
5530 }
5531 
5532 netsnmp_pdu    *
snmp_create_sess_pdu(netsnmp_transport * transport,void * opaque,size_t olength)5533 snmp_create_sess_pdu(netsnmp_transport *transport, void *opaque,
5534                      size_t olength)
5535 {
5536     netsnmp_pdu *pdu = (netsnmp_pdu *)calloc(1, sizeof(netsnmp_pdu));
5537     if (pdu == NULL) {
5538         DEBUGMSGTL(("sess_process_packet", "can't malloc space for PDU\n"));
5539         return NULL;
5540     }
5541 
5542     /*
5543      * Save the transport-level data specific to this reception (e.g. UDP
5544      * source address).
5545      */
5546 
5547     pdu->transport_data = opaque;
5548     pdu->transport_data_length = olength;
5549     pdu->tDomain = transport->domain;
5550     pdu->tDomainLen = transport->domain_length;
5551     return pdu;
5552 }
5553 
5554 
5555 /*
5556  * This function parses a packet into a PDU
5557  */
5558 static netsnmp_pdu *
_sess_process_packet_parse_pdu(void * sessp,netsnmp_session * sp,struct snmp_internal_session * isp,netsnmp_transport * transport,void * opaque,int olength,u_char * packetptr,int length)5559 _sess_process_packet_parse_pdu(void *sessp, netsnmp_session * sp,
5560                                struct snmp_internal_session *isp,
5561                                netsnmp_transport *transport,
5562                                void *opaque, int olength,
5563                                u_char * packetptr, int length)
5564 {
5565   netsnmp_pdu    *pdu;
5566   int             ret = 0;
5567   int             dump = 0, filter = 0;
5568 
5569   debug_indent_reset();
5570 
5571   DEBUGMSGTL(("sess_process_packet",
5572 	      "session %p fd %d pkt %p length %d\n", sessp,
5573 	      transport->sock, packetptr, length));
5574 
5575   dump = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
5576                                 NETSNMP_DS_LIB_DUMP_PACKET);
5577 #ifndef NETSNMP_FEATURE_REMOVE_FILTER_SOURCE
5578   filter = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
5579                                   NETSNMP_DS_LIB_FILTER_TYPE);
5580 #endif
5581   if (dump || filter) {
5582       int filtered = 0;
5583       char *addrtxt = netsnmp_transport_peer_string(transport, opaque, olength);
5584       snmp_log(LOG_DEBUG, "\nReceived %d byte packet from %s\n",
5585                length, addrtxt);
5586 
5587       if (dump)
5588           xdump(packetptr, length, "");
5589 
5590 #ifndef NETSNMP_FEATURE_REMOVE_FILTER_SOURCE
5591       if (filter) {
5592           char *sourceaddr = NULL, *c = strchr(addrtxt, '[');
5593           const char *dropstr = NULL;
5594           if (c) {
5595               sourceaddr = ++c;
5596               c = strchr(sourceaddr, ']');
5597               if (c)
5598                   *c = 0;
5599               filtered = netsnmp_transport_filter_check(sourceaddr);
5600           }
5601           if ((filter == -1) && filtered)
5602               dropstr = "matched blocklist";
5603           else if ((filter == 1) && !filtered)
5604               dropstr = "didn't match acceptlist";
5605           if (dropstr) {
5606               DEBUGMSGTL(("sess_process_packet:filter",
5607                           "packet from %s %s\n",
5608                           sourceaddr ? sourceaddr : "UNKNOWN", dropstr));
5609               SNMP_FREE(opaque);
5610               SNMP_FREE(addrtxt);
5611               return NULL;
5612           }
5613       }
5614 #endif
5615 
5616       SNMP_FREE(addrtxt);
5617   }
5618 
5619   /*
5620    * Do transport-level filtering (e.g. IP-address based allow/deny).
5621    */
5622 
5623   if (isp->hook_pre) {
5624     if (isp->hook_pre(sp, transport, opaque, olength) == 0) {
5625       DEBUGMSGTL(("sess_process_packet", "pre-parse fail\n"));
5626       SNMP_FREE(opaque);
5627       return NULL;
5628     }
5629   }
5630 
5631   if (isp->hook_create_pdu) {
5632     pdu = isp->hook_create_pdu(transport, opaque, olength);
5633   } else {
5634     pdu = snmp_create_sess_pdu(transport, opaque, olength);
5635   }
5636 
5637   if (pdu == NULL) {
5638     snmp_log(LOG_ERR, "pdu failed to be created\n");
5639     SNMP_FREE(opaque);
5640     return NULL;
5641   }
5642 
5643   /* if the transport was a magic tunnel, mark the PDU as having come
5644      through one. */
5645   if (transport->flags & NETSNMP_TRANSPORT_FLAG_TUNNELED) {
5646       pdu->flags |= UCD_MSG_FLAG_TUNNELED;
5647   }
5648 
5649   if (isp->hook_parse) {
5650     ret = isp->hook_parse(sp, pdu, packetptr, length);
5651   } else {
5652     ret = snmp_parse(sessp, sp, pdu, packetptr, length);
5653   }
5654 
5655   DEBUGMSGTL(("sess_process_packet", "received message id#%ld reqid#%ld len "
5656               "%u\n", pdu->msgid, pdu->reqid, length));
5657 
5658   if (ret != SNMP_ERR_NOERROR) {
5659     DEBUGMSGTL(("sess_process_packet", "parse fail\n"));
5660   }
5661 
5662   if (isp->hook_post) {
5663     if (isp->hook_post(sp, pdu, ret) == 0) {
5664       DEBUGMSGTL(("sess_process_packet", "post-parse fail\n"));
5665       ret = SNMPERR_ASN_PARSE_ERR;
5666     }
5667   }
5668 
5669   if (ret != SNMP_ERR_NOERROR) {
5670     snmp_free_pdu(pdu);
5671     return NULL;
5672   }
5673 
5674   return pdu;
5675 }
5676 
5677 /* Remove request @rp from session @isp. @orp is the request before @rp. */
5678 static void
remove_request(struct snmp_internal_session * isp,netsnmp_request_list * orp,netsnmp_request_list * rp)5679 remove_request(struct snmp_internal_session *isp,
5680                netsnmp_request_list *orp, netsnmp_request_list *rp)
5681 {
5682     if (orp)
5683         orp->next_request = rp->next_request;
5684     else
5685         isp->requests = rp->next_request;
5686     if (isp->requestsEnd == rp)
5687         isp->requestsEnd = orp;
5688     snmp_free_pdu(rp->pdu);
5689 }
5690 
5691 /*
5692  * This function processes a PDU and calls the relevant callbacks.
5693  */
5694 static int
_sess_process_packet_handle_pdu(void * sessp,netsnmp_session * sp,struct snmp_internal_session * isp,netsnmp_transport * transport,netsnmp_pdu * pdu)5695 _sess_process_packet_handle_pdu(void *sessp, netsnmp_session * sp,
5696                                 struct snmp_internal_session *isp,
5697                                 netsnmp_transport *transport, netsnmp_pdu *pdu)
5698 {
5699   struct session_list *slp = (struct session_list *) sessp;
5700   netsnmp_request_list *rp, *orp = NULL;
5701   int             handled = 0;
5702 
5703   if (pdu->flags & UCD_MSG_FLAG_RESPONSE_PDU) {
5704     /*
5705      * Call USM to free any securityStateRef supplied with the message.
5706      */
5707     free_securityStateRef(pdu);
5708 
5709     for (rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
5710       snmp_callback   callback;
5711       void           *magic;
5712 
5713       if (pdu->version == SNMP_VERSION_3) {
5714 	/*
5715 	 * msgId must match for v3 messages.
5716 	 */
5717 	if (rp->message_id != pdu->msgid) {
5718             DEBUGMSGTL(("sess_process_packet", "unmatched msg id: %ld != %ld\n",
5719                         rp->message_id, pdu->msgid));
5720 	    continue;
5721 	}
5722 
5723 	/*
5724 	 * Check that message fields match original, if not, no further
5725 	 * processing.
5726 	 */
5727 	if (!snmpv3_verify_msg(rp, pdu)) {
5728 	  break;
5729 	}
5730       } else {
5731 	if (rp->request_id != pdu->reqid) {
5732 	  continue;
5733 	}
5734       }
5735 
5736       if (rp->callback) {
5737 	callback = rp->callback;
5738 	magic = rp->cb_data;
5739       } else {
5740 	callback = sp->callback;
5741 	magic = sp->callback_magic;
5742       }
5743       handled = 1;
5744 
5745       /*
5746        * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock
5747        * should be per session !
5748        */
5749 
5750       if (callback == NULL
5751 	  || callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, sp,
5752 		      pdu->reqid, pdu, magic) == 1) {
5753 	if (pdu->command == SNMP_MSG_REPORT) {
5754 	  if (sp->s_snmp_errno == SNMPERR_NOT_IN_TIME_WINDOW ||
5755 	      snmpv3_get_report_type(pdu) ==
5756 	      SNMPERR_NOT_IN_TIME_WINDOW) {
5757 	    /*
5758 	     * trigger immediate retry on recoverable Reports
5759 	     * * (notInTimeWindow), incr_retries == TRUE to prevent
5760 	     * * inifinite resend
5761 	     */
5762 	    if (rp->retries <= sp->retries) {
5763 	      snmp_resend_request(slp, orp, rp, TRUE);
5764 	      break;
5765 	    } else {
5766 	      /* We're done with retries, so no longer waiting for a response */
5767 	      if (callback) {
5768 	        callback(NETSNMP_CALLBACK_OP_SEC_ERROR, sp,
5769 	                 pdu->reqid, pdu, magic);
5770 	      }
5771 	    }
5772 	  } else {
5773 	    if (SNMPV3_IGNORE_UNAUTH_REPORTS) {
5774 	      break;
5775 	    } else { /* We're done with retries */
5776 	      if (callback) {
5777 	        callback(NETSNMP_CALLBACK_OP_SEC_ERROR, sp,
5778 	                 pdu->reqid, pdu, magic);
5779 	      }
5780 	    }
5781 	  }
5782 
5783 	  /*
5784 	   * Handle engineID discovery.
5785 	   */
5786 	  if (!sp->securityEngineIDLen && pdu->securityEngineIDLen) {
5787 	    sp->securityEngineID =
5788 	      (u_char *) malloc(pdu->securityEngineIDLen);
5789 	    if (sp->securityEngineID == NULL) {
5790 	      /*
5791 	       * TODO FIX: recover after message callback *?
5792                */
5793                 snmp_log(LOG_ERR, "malloc failed handling pdu\n");
5794                 snmp_free_pdu(pdu);
5795                 return -1;
5796 	    }
5797 	    memcpy(sp->securityEngineID, pdu->securityEngineID,
5798 		   pdu->securityEngineIDLen);
5799 	    sp->securityEngineIDLen = pdu->securityEngineIDLen;
5800 	    if (!sp->contextEngineIDLen) {
5801 	      sp->contextEngineID =
5802 		(u_char *) malloc(pdu->
5803 				  securityEngineIDLen);
5804 	      if (sp->contextEngineID == NULL) {
5805 		/*
5806 		 * TODO FIX: recover after message callback *?
5807 		 */
5808                 snmp_log(LOG_ERR, "malloc failed handling pdu\n");
5809                 snmp_free_pdu(pdu);
5810                 return -1;
5811 	      }
5812 	      memcpy(sp->contextEngineID,
5813 		     pdu->securityEngineID,
5814 		     pdu->securityEngineIDLen);
5815 	      sp->contextEngineIDLen =
5816 		pdu->securityEngineIDLen;
5817 	    }
5818 	  }
5819 	}
5820 
5821 	/*
5822 	 * Successful, so delete request.
5823 	 */
5824 	remove_request(isp, orp, rp);
5825 	free(rp);
5826 	/*
5827 	 * There shouldn't be any more requests with the same reqid.
5828 	 */
5829 	break;
5830       }
5831       /*
5832        * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock should be per session !
5833        */
5834     }
5835   } else {
5836     if (sp->callback) {
5837       /*
5838        * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
5839        */
5840       handled = 1;
5841       sp->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
5842 		   sp, pdu->reqid, pdu, sp->callback_magic);
5843       /*
5844        * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
5845        */
5846     }
5847   }
5848 
5849   if (!handled) {
5850     if (sp->flags & SNMP_FLAGS_SHARED_SOCKET)
5851       return -2;
5852     snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
5853     DEBUGMSGTL(("sess_process_packet", "unhandled PDU\n"));
5854   }
5855 
5856   snmp_free_pdu(pdu);
5857   return 0;
5858 }
5859 
5860 /*
5861  * This function processes a complete (according to asn_check_packet or the
5862  * AgentX equivalent) packet, parsing it into a PDU and calling the relevant
5863  * callbacks.  On entry, packetptr points at the packet in the session's
5864  * buffer and length is the length of the packet.  Return codes:
5865  *   0: pdu handled (pdu deleted)
5866  *  -1: parse error (pdu deleted)
5867  *  -2: pdu not found for shared session (pdu NOT deleted)
5868  */
5869 static int
_sess_process_packet(void * sessp,netsnmp_session * sp,struct snmp_internal_session * isp,netsnmp_transport * transport,void * opaque,int olength,u_char * packetptr,int length)5870 _sess_process_packet(void *sessp, netsnmp_session * sp,
5871                      struct snmp_internal_session *isp,
5872                      netsnmp_transport *transport,
5873                      void *opaque, int olength,
5874                      u_char * packetptr, int length)
5875 {
5876     struct session_list *slp = (struct session_list *) sessp;
5877     netsnmp_pdu         *pdu;
5878     int                  rc;
5879 
5880     pdu = _sess_process_packet_parse_pdu(sessp, sp, isp, transport, opaque,
5881                                          olength, packetptr, length);
5882     if (NULL == pdu)
5883         return -1;
5884 
5885     /*
5886      * find session to process pdu. usually that will be the current session,
5887      * but with the introduction of shared transports, another session may
5888      * have the same socket.
5889      */
5890     do {
5891         rc = _sess_process_packet_handle_pdu(sessp, sp, isp, transport, pdu);
5892         if (-2 != rc || !(transport->flags & NETSNMP_TRANSPORT_FLAG_SHARED))
5893             break;
5894 
5895         /** -2 means pdu not in request list. check other sessions */
5896         do  {
5897             slp = slp->next;
5898         } while (slp && slp->transport->sock != transport->sock);
5899         if (!slp)
5900             break; /* no more sessions with same socket */
5901 
5902         sp = slp->session;
5903         isp = slp->internal;
5904         transport = slp->transport;
5905     } while(slp);
5906 
5907     if (-2 == rc) { /* did not find session for pdu */
5908         snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
5909         DEBUGMSGTL(("sess_process_packet", "unhandled PDU\n"));
5910         snmp_free_pdu(pdu);
5911     }
5912 
5913   return rc;
5914 }
5915 
5916 /*
5917  * Checks to see if any of the fd's set in the fdset belong to
5918  * snmp.  Each socket with it's fd set has a packet read from it
5919  * and snmp_parse is called on the packet received.  The resulting pdu
5920  * is passed to the callback routine for that session.  If the callback
5921  * routine returns successfully, the pdu and it's request are deleted.
5922  */
5923 void
snmp_read(fd_set * fdset)5924 snmp_read(fd_set * fdset)
5925 {
5926     netsnmp_large_fd_set lfdset;
5927 
5928     netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
5929     netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
5930     snmp_read2(&lfdset);
5931     netsnmp_large_fd_set_cleanup(&lfdset);
5932 }
5933 
5934 void
snmp_read2(netsnmp_large_fd_set * fdset)5935 snmp_read2(netsnmp_large_fd_set * fdset)
5936 {
5937     struct session_list *slp;
5938     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
5939     for (slp = Sessions; slp; slp = slp->next) {
5940         snmp_sess_read2((void *) slp, fdset);
5941     }
5942     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
5943 }
5944 
5945 /*
5946  * accept new connections
5947  * returns 0 if success, -1 if fail
5948  */
5949 static int
_sess_read_accept(void * sessp)5950 _sess_read_accept(void *sessp)
5951 {
5952     struct session_list *slp = (struct session_list *) sessp;
5953     netsnmp_session *sp = slp ? slp->session : NULL;
5954     struct snmp_internal_session *isp = slp ? slp->internal : NULL;
5955     netsnmp_transport *transport = slp ? slp->transport : NULL;
5956     netsnmp_transport *new_transport;
5957     struct session_list *nslp;
5958     int               data_sock;
5959 
5960     if (NULL == sessp || NULL == sp || NULL == transport || NULL == isp ||
5961         !(transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN))
5962         return -1;
5963 
5964     data_sock = transport->f_accept(transport);
5965     if (data_sock < 0) {
5966         sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
5967         sp->s_errno = errno;
5968         snmp_set_detail(strerror(errno));
5969         return -1;
5970     }
5971 
5972     /*
5973      * We've successfully accepted a new stream-based connection.
5974      * It's not too clear what should happen here if we are using the
5975      * single-session API at this point.  Basically a "session
5976      * accepted" callback is probably needed to hand the new session
5977      * over to the application.
5978      *
5979      * However, for now, as in th original snmp_api, we will ASSUME
5980      * that we're using the traditional API, and simply add the new
5981      * session to the list.  Note we don't have to get the Session
5982      * list lock here, because under that assumption we already hold
5983      * it (this is also why we don't just use snmp_add).
5984      *
5985      * The moral of the story is: don't use listening stream-based
5986      * transports in a multi-threaded environment because something
5987      * will go HORRIBLY wrong (and also that SNMP/TCP is not trivial).
5988      *
5989      * Another open issue: what should happen to sockets that have
5990      * been accept()ed from a listening socket when that original
5991      * socket is closed?  If they are left open, then attempting to
5992      * re-open the listening socket will fail, which is semantically
5993      * confusing.  Perhaps there should be some kind of chaining in
5994      * the transport structure so that they can all be closed.
5995      * Discuss.  ;-)
5996      */
5997     new_transport=netsnmp_transport_copy(transport);
5998     if (new_transport == NULL) {
5999         sp->s_snmp_errno = SNMPERR_MALLOC;
6000         sp->s_errno = errno;
6001         snmp_set_detail(strerror(errno));
6002         return -1;
6003     }
6004     nslp = NULL;
6005 
6006     new_transport->sock = data_sock;
6007     new_transport->flags &= ~NETSNMP_TRANSPORT_FLAG_LISTEN;
6008 
6009     nslp = (struct session_list *)
6010         snmp_sess_add_ex(sp, new_transport, isp->hook_pre, isp->hook_parse,
6011                          isp->hook_post, isp->hook_build,
6012                          isp->hook_realloc_build, isp->check_packet,
6013                          isp->hook_create_pdu);
6014 
6015     if (nslp != NULL) {
6016         snmp_session_insert(nslp);
6017         /** Tell the new session about its existance if possible. */
6018         DEBUGMSGTL(("sess_read",
6019                     "perform callback with op=CONNECT\n"));
6020         (void)nslp->session->callback(NETSNMP_CALLBACK_OP_CONNECT,
6021                                       nslp->session, 0, NULL,
6022                                       sp->callback_magic);
6023     }
6024 
6025     return 0;
6026 }
6027 
6028 /*
6029  * Same as snmp_read, but works just one non-stream session.
6030  * returns 0 if success, -1 if protocol err, -2 if no packet to process
6031  * MTR: can't lock here and at snmp_read
6032  * Beware recursive send maybe inside snmp_read callback function.
6033  */
6034 static int
_sess_read_dgram_packet(void * sessp,netsnmp_large_fd_set * fdset,snmp_rcv_packet * rcvp)6035 _sess_read_dgram_packet(void *sessp, netsnmp_large_fd_set * fdset,
6036                         snmp_rcv_packet *rcvp)
6037 {
6038     struct session_list *slp = (struct session_list *) sessp;
6039     netsnmp_session *sp = slp ? slp->session : NULL;
6040     struct snmp_internal_session *isp = slp ? slp->internal : NULL;
6041     netsnmp_transport *transport = slp ? slp->transport : NULL;
6042 
6043     if (!sp || !isp || !transport || !rcvp ) {
6044         DEBUGMSGTL(("sess_read_packet", "missing arguments\n"));
6045         return -2;
6046     }
6047 
6048     if (transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM)
6049         return -2;
6050 
6051     if (NULL != rcvp->packet) {
6052         snmp_log(LOG_WARNING, "overwriting existing saved packet; sess %p\n",
6053                  sp);
6054         SNMP_FREE(rcvp->packet);
6055     }
6056 
6057     if ((rcvp->packet = (u_char *) malloc(SNMP_MAX_RCV_MSG_SIZE)) == NULL) {
6058         DEBUGMSGTL(("sess_read_packet", "can't malloc %u bytes for packet\n",
6059                     SNMP_MAX_RCV_MSG_SIZE));
6060         return -2;
6061     }
6062 
6063     rcvp->packet_len = netsnmp_transport_recv(transport, rcvp->packet,
6064                                               SNMP_MAX_RCV_MSG_SIZE,
6065                                               &rcvp->opaque, &rcvp->olength);
6066     if (rcvp->packet_len == -1) {
6067         sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
6068         sp->s_errno = errno;
6069         snmp_set_detail(strerror(errno));
6070         SNMP_FREE(rcvp->packet);
6071         SNMP_FREE(rcvp->opaque);
6072         return -1;
6073     }
6074 
6075     /** clear so any other sess sharing this socket won't try reading again */
6076     NETSNMP_LARGE_FD_CLR(transport->sock, fdset);
6077 
6078     if (0 == rcvp->packet_len &&
6079         transport->flags & NETSNMP_TRANSPORT_FLAG_EMPTY_PKT) {
6080         /* this allows for a transport that needs to return from
6081          * packet processing that doesn't necessarily have any
6082          * consumable data in it. */
6083 
6084         /* reset the flag since it's a per-message flag */
6085         transport->flags &= (~NETSNMP_TRANSPORT_FLAG_EMPTY_PKT);
6086 
6087         /** free packet */
6088         SNMP_FREE(rcvp->packet);
6089         SNMP_FREE(rcvp->opaque);
6090 
6091         return -2;
6092     }
6093 
6094     return 0;
6095 }
6096 
6097 /*
6098  * Same as snmp_read, but works just one session.
6099  * returns 0 if success, -1 if fail
6100  * MTR: can't lock here and at snmp_read
6101  * Beware recursive send maybe inside snmp_read callback function.
6102  */
6103 int
_sess_read(void * sessp,netsnmp_large_fd_set * fdset)6104 _sess_read(void *sessp, netsnmp_large_fd_set * fdset)
6105 {
6106     struct session_list *slp = (struct session_list *) sessp;
6107     netsnmp_session *sp = slp ? slp->session : NULL;
6108     struct snmp_internal_session *isp = slp ? slp->internal : NULL;
6109     netsnmp_transport *transport = slp ? slp->transport : NULL;
6110     size_t          pdulen = 0, rxbuf_len = SNMP_MAX_RCV_MSG_SIZE;
6111     u_char         *rxbuf = NULL;
6112     int             length = 0, olength = 0, rc = 0;
6113     void           *opaque = NULL;
6114 
6115     if (NULL == slp || NULL == sp || NULL == isp || NULL == transport) {
6116         snmp_log(LOG_ERR, "bad parameters to _sess_read\n");
6117         return SNMPERR_GENERR;
6118     }
6119 
6120     /* to avoid subagent crash */
6121     if (transport->sock < 0) {
6122         snmp_log (LOG_INFO, "transport->sock got negative fd value %d\n",
6123                   transport->sock);
6124         return 0;
6125     }
6126 
6127     if (!fdset || !(NETSNMP_LARGE_FD_ISSET(transport->sock, fdset))) {
6128         DEBUGMSGTL(("sess_read", "not reading %d (fdset %p set %d)\n",
6129                     transport->sock, fdset,
6130                     fdset ? NETSNMP_LARGE_FD_ISSET(transport->sock, fdset)
6131 		    : -9));
6132         return 0;
6133     }
6134 
6135     sp->s_snmp_errno = 0;
6136     sp->s_errno = 0;
6137 
6138     if (transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN)
6139         return _sess_read_accept(sessp);
6140 
6141     if (!(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM)) {
6142         snmp_rcv_packet rcvp;
6143         memset(&rcvp, 0x0, sizeof(rcvp));
6144 
6145         /** read the packet */
6146         rc = _sess_read_dgram_packet(sessp, fdset, &rcvp);
6147         if (-1 == rc) /* protocol error */
6148             return -1;
6149         else if (-2 == rc) /* no packet to process */
6150             return 0;
6151 
6152         rc = _sess_process_packet(sessp, sp, isp, transport,
6153                                   rcvp.opaque, rcvp.olength,
6154                                   rcvp.packet, rcvp.packet_len);
6155         SNMP_FREE(rcvp.packet);
6156         /** opaque is freed in _sess_process_packet */
6157         return rc;
6158     }
6159 
6160     /** stream transport */
6161 
6162         if (isp->packet == NULL) {
6163             /*
6164              * We have no saved packet.  Allocate one.
6165              */
6166             if ((isp->packet = (u_char *) malloc(rxbuf_len)) == NULL) {
6167                 DEBUGMSGTL(("sess_read", "can't malloc %" NETSNMP_PRIz
6168                             "u bytes for rxbuf\n", rxbuf_len));
6169                 return 0;
6170             } else {
6171                 rxbuf = isp->packet;
6172                 isp->packet_size = rxbuf_len;
6173                 isp->packet_len = 0;
6174             }
6175         } else {
6176             /*
6177              * We have saved a partial packet from last time.  Extend that, if
6178              * necessary, and receive new data after the old data.
6179              */
6180             u_char         *newbuf;
6181 
6182             if (isp->packet_size < isp->packet_len + rxbuf_len) {
6183                 newbuf =
6184                     (u_char *) realloc(isp->packet,
6185                                        isp->packet_len + rxbuf_len);
6186                 if (newbuf == NULL) {
6187                     DEBUGMSGTL(("sess_read",
6188                                 "can't malloc %" NETSNMP_PRIz
6189                                 "u more for rxbuf (%" NETSNMP_PRIz "u tot)\n",
6190                                 rxbuf_len, isp->packet_len + rxbuf_len));
6191                     return 0;
6192                 } else {
6193                     isp->packet = newbuf;
6194                     isp->packet_size = isp->packet_len + rxbuf_len;
6195                     rxbuf = isp->packet + isp->packet_len;
6196                 }
6197             } else {
6198                 rxbuf = isp->packet + isp->packet_len;
6199                 rxbuf_len = isp->packet_size - isp->packet_len;
6200             }
6201         }
6202 
6203     length = netsnmp_transport_recv(transport, rxbuf, rxbuf_len, &opaque,
6204                                     &olength);
6205 
6206     if (0 == length && transport->flags & NETSNMP_TRANSPORT_FLAG_EMPTY_PKT) {
6207         /* this allows for a transport that needs to return from
6208          * packet processing that doesn't necessarily have any
6209          * consumable data in it. */
6210 
6211         /* reset the flag since it's a per-message flag */
6212         transport->flags &= (~NETSNMP_TRANSPORT_FLAG_EMPTY_PKT);
6213 
6214         return 0;
6215     }
6216 
6217     /*
6218      * Remote end closed connection.
6219      */
6220     if (length <= 0) {
6221         /*
6222          * Alert the application if possible.
6223          */
6224         if (sp->callback != NULL) {
6225             DEBUGMSGTL(("sess_read", "perform callback with op=DISCONNECT\n"));
6226             (void) sp->callback(NETSNMP_CALLBACK_OP_DISCONNECT, sp, 0,
6227                                 NULL, sp->callback_magic);
6228         }
6229         /*
6230          * Close socket and mark session for deletion.
6231          */
6232         DEBUGMSGTL(("sess_read", "fd %d closed\n", transport->sock));
6233         transport->f_close(transport);
6234         SNMP_FREE(isp->packet);
6235         SNMP_FREE(opaque);
6236         return -1;
6237     }
6238 
6239     {
6240         u_char *pptr = isp->packet;
6241 	void *ocopy = NULL;
6242 
6243         isp->packet_len += length;
6244 
6245         while (isp->packet_len > 0) {
6246 
6247             /*
6248              * Get the total data length we're expecting (and need to wait
6249              * for).
6250              */
6251             if (isp->check_packet) {
6252                 pdulen = isp->check_packet(pptr, isp->packet_len);
6253             } else {
6254                 pdulen = asn_check_packet(pptr, isp->packet_len);
6255             }
6256 
6257             DEBUGMSGTL(("sess_read",
6258                         "  loop packet_len %" NETSNMP_PRIz "u, PDU length %"
6259                         NETSNMP_PRIz "u\n", isp->packet_len, pdulen));
6260 
6261             if (pdulen > SNMP_MAX_PACKET_LEN) {
6262                 /*
6263                  * Illegal length, drop the connection.
6264                  */
6265                 snmp_log(LOG_ERR,
6266 			 "Received broken packet. Closing session.\n");
6267 		if (sp->callback != NULL) {
6268 		  DEBUGMSGTL(("sess_read",
6269 			      "perform callback with op=DISCONNECT\n"));
6270 		  (void)sp->callback(NETSNMP_CALLBACK_OP_DISCONNECT,
6271 				     sp, 0, NULL, sp->callback_magic);
6272 		}
6273 		DEBUGMSGTL(("sess_read", "fd %d closed\n", transport->sock));
6274                 transport->f_close(transport);
6275                 SNMP_FREE(opaque);
6276                 /** XXX-rks: why no SNMP_FREE(isp->packet); ?? */
6277                 return -1;
6278             }
6279 
6280             if (pdulen > isp->packet_len || pdulen == 0) {
6281                 /*
6282                  * We don't have a complete packet yet.  If we've already
6283                  * processed a packet, break out so we'll shift this packet
6284                  * to the start of the buffer. If we're already at the
6285                  * start, simply return and wait for more data to arrive.
6286                  */
6287                 DEBUGMSGTL(("sess_read",
6288                             "pkt not complete (need %" NETSNMP_PRIz "u got %"
6289                             NETSNMP_PRIz "u so far)\n", pdulen,
6290                             isp->packet_len));
6291 
6292                 if (pptr != isp->packet)
6293                     break; /* opaque freed for us outside of loop. */
6294 
6295                 SNMP_FREE(opaque);
6296                 return 0;
6297             }
6298 
6299             /*  We have *at least* one complete packet in the buffer now.  If
6300 		we have possibly more than one packet, we must copy the opaque
6301 		pointer because we may need to reuse it for a later packet.  */
6302 
6303 	    if (pdulen < isp->packet_len) {
6304 		if (olength > 0 && opaque != NULL) {
6305 		    ocopy = malloc(olength);
6306 		    if (ocopy != NULL) {
6307 			memcpy(ocopy, opaque, olength);
6308 		    }
6309 		}
6310 	    } else if (pdulen == isp->packet_len) {
6311 		/*  Common case -- exactly one packet.  No need to copy the
6312 		    opaque pointer.  */
6313 		ocopy = opaque;
6314 		opaque = NULL;
6315 	    }
6316 
6317             if ((rc = _sess_process_packet(sessp, sp, isp, transport,
6318                                            ocopy, ocopy?olength:0, pptr,
6319                                            pdulen))) {
6320                 /*
6321                  * Something went wrong while processing this packet -- set the
6322                  * errno.
6323                  */
6324                 if (sp->s_snmp_errno != 0) {
6325                     SET_SNMP_ERROR(sp->s_snmp_errno);
6326                 }
6327             }
6328 
6329 	    /*  ocopy has been free()d by _sess_process_packet by this point,
6330 		so set it to NULL.  */
6331 
6332 	    ocopy = NULL;
6333 
6334 	    /*  Step past the packet we've just dealt with.  */
6335 
6336             pptr += pdulen;
6337             isp->packet_len -= pdulen;
6338         }
6339 
6340 	/*  If we had more than one packet, then we were working with copies
6341 	    of the opaque pointer, so we still need to free() the opaque
6342 	    pointer itself.  */
6343 
6344 	SNMP_FREE(opaque);
6345 
6346         if (isp->packet_len >= SNMP_MAX_PACKET_LEN) {
6347             /*
6348              * Obviously this should never happen!
6349              */
6350             snmp_log(LOG_ERR,
6351                      "too large packet_len = %" NETSNMP_PRIz
6352                      "u, dropping connection %d\n",
6353                      isp->packet_len, transport->sock);
6354             transport->f_close(transport);
6355             /** XXX-rks: why no SNMP_FREE(isp->packet); ?? */
6356             return -1;
6357         } else if (isp->packet_len == 0) {
6358             /*
6359              * This is good: it means the packet buffer contained an integral
6360              * number of PDUs, so we don't have to save any data for next
6361              * time.  We can free() the buffer now to keep the memory
6362              * footprint down.
6363              */
6364             SNMP_FREE(isp->packet);
6365             isp->packet_size = 0;
6366             isp->packet_len = 0;
6367             return rc;
6368         }
6369 
6370         /*
6371          * If we get here, then there is a partial packet of length
6372          * isp->packet_len bytes starting at pptr left over.  Move that to the
6373          * start of the buffer, and then realloc() the buffer down to size to
6374          * reduce the memory footprint.
6375          */
6376 
6377         memmove(isp->packet, pptr, isp->packet_len);
6378         DEBUGMSGTL(("sess_read",
6379                     "end: memmove(%p, %p, %" NETSNMP_PRIz "u); realloc(%p, %"
6380                     NETSNMP_PRIz "u)\n",
6381                     isp->packet, pptr, isp->packet_len,
6382 		    isp->packet, isp->packet_len));
6383 
6384         if ((rxbuf = (u_char *)realloc(isp->packet, isp->packet_len)) == NULL) {
6385             /*
6386              * I don't see why this should ever fail, but it's not a big deal.
6387              */
6388             DEBUGMSGTL(("sess_read", "realloc() failed\n"));
6389         } else {
6390             DEBUGMSGTL(("sess_read", "realloc() okay, old buffer %p, new %p\n",
6391                         isp->packet, rxbuf));
6392             isp->packet = rxbuf;
6393             isp->packet_size = isp->packet_len;
6394         }
6395     }
6396 
6397     return rc;
6398 }
6399 
6400 
6401 
6402 /*
6403  * returns 0 if success, -1 if fail
6404  */
6405 int
snmp_sess_read(void * sessp,fd_set * fdset)6406 snmp_sess_read(void *sessp, fd_set * fdset)
6407 {
6408   int rc;
6409   netsnmp_large_fd_set lfdset;
6410 
6411   netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
6412   netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
6413   rc = snmp_sess_read2(sessp, &lfdset);
6414   netsnmp_large_fd_set_cleanup(&lfdset);
6415   return rc;
6416 }
6417 
6418 int
snmp_sess_read2(void * sessp,netsnmp_large_fd_set * fdset)6419 snmp_sess_read2(void *sessp, netsnmp_large_fd_set * fdset)
6420 {
6421     struct session_list *psl;
6422     netsnmp_session *pss;
6423     int             rc;
6424 
6425     rc = _sess_read(sessp, fdset);
6426     psl = (struct session_list *) sessp;
6427     pss = psl->session;
6428     if (rc && pss->s_snmp_errno) {
6429         SET_SNMP_ERROR(pss->s_snmp_errno);
6430     }
6431     return rc;
6432 }
6433 
6434 
6435 /**
6436  * Returns info about what snmp requires from a select statement.
6437  * numfds is the number of fds in the list that are significant.
6438  * All file descriptors opened for SNMP are OR'd into the fdset.
6439  * If activity occurs on any of these file descriptors, snmp_read
6440  * should be called with that file descriptor set
6441  *
6442  * The timeout is the latest time that SNMP can wait for a timeout.  The
6443  * select should be done with the minimum time between timeout and any other
6444  * timeouts necessary.  This should be checked upon each invocation of select.
6445  * If a timeout is received, snmp_timeout should be called to check if the
6446  * timeout was for SNMP.  (snmp_timeout is idempotent)
6447  *
6448  * The value of block indicates how the timeout value is interpreted.
6449  * If block is true on input, the timeout value will be treated as undefined,
6450  * but it must be available for setting in snmp_select_info.  On return,
6451  * block is set to true if the value returned for timeout is undefined;
6452  * when block is set to false, timeout may be used as a parmeter to 'select'.
6453  *
6454  * snmp_select_info returns the number of open sockets.  (i.e. The number of
6455  * sessions open)
6456  *
6457  * @see See also snmp_sess_select_info2_flags().
6458  */
6459 int
snmp_select_info(int * numfds,fd_set * fdset,struct timeval * timeout,int * block)6460 snmp_select_info(int *numfds, fd_set *fdset, struct timeval *timeout,
6461                  int *block)
6462 {
6463     return snmp_sess_select_info(NULL, numfds, fdset, timeout, block);
6464 }
6465 
6466 /**
6467  * @see See also snmp_sess_select_info2_flags().
6468  */
6469 int
snmp_select_info2(int * numfds,netsnmp_large_fd_set * fdset,struct timeval * timeout,int * block)6470 snmp_select_info2(int *numfds, netsnmp_large_fd_set *fdset,
6471 		  struct timeval *timeout, int *block)
6472 {
6473     return snmp_sess_select_info2(NULL, numfds, fdset, timeout, block);
6474 }
6475 
6476 /**
6477  * @see See also snmp_sess_select_info2_flags().
6478  */
6479 int
snmp_sess_select_info(void * sessp,int * numfds,fd_set * fdset,struct timeval * timeout,int * block)6480 snmp_sess_select_info(void *sessp, int *numfds, fd_set *fdset,
6481                       struct timeval *timeout, int *block)
6482 {
6483     return snmp_sess_select_info_flags(sessp, numfds, fdset, timeout, block,
6484                                        NETSNMP_SELECT_NOFLAGS);
6485 }
6486 
6487 /**
6488  * @see See also snmp_sess_select_info2_flags().
6489  */
6490 int
snmp_sess_select_info_flags(void * sessp,int * numfds,fd_set * fdset,struct timeval * timeout,int * block,int flags)6491 snmp_sess_select_info_flags(void *sessp, int *numfds, fd_set *fdset,
6492                             struct timeval *timeout, int *block, int flags)
6493 {
6494   int rc;
6495   netsnmp_large_fd_set lfdset;
6496 
6497   netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
6498   netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
6499   rc = snmp_sess_select_info2_flags(sessp, numfds, &lfdset, timeout,
6500                                     block, flags);
6501   if (netsnmp_copy_large_fd_set_to_fd_set(fdset, &lfdset) < 0) {
6502       snmp_log(LOG_ERR,
6503 	     "Use snmp_sess_select_info2() for processing"
6504 	     " large file descriptors\n");
6505   }
6506   netsnmp_large_fd_set_cleanup(&lfdset);
6507   return rc;
6508 }
6509 
6510 /**
6511  * @see See also snmp_sess_select_info2_flags().
6512  */
6513 int
snmp_sess_select_info2(void * sessp,int * numfds,netsnmp_large_fd_set * fdset,struct timeval * timeout,int * block)6514 snmp_sess_select_info2(void *sessp, int *numfds, netsnmp_large_fd_set *fdset,
6515 		       struct timeval *timeout, int *block)
6516 {
6517     return snmp_sess_select_info2_flags(sessp, numfds, fdset, timeout, block,
6518                                         NETSNMP_SELECT_NOFLAGS);
6519 }
6520 
6521 /**
6522  * Compute/update the arguments to be passed to select().
6523  *
6524  * @param[in]     sessp   Which sessions to process: either a pointer to a
6525  *   specific session or NULL which means to process all sessions.
6526  * @param[in,out] numfds  On POSIX systems one more than the the largest file
6527  *   descriptor that is present in *fdset. On systems that use Winsock (MinGW
6528  *   and MSVC), do not use the value written into *numfds.
6529  * @param[in,out] fdset   A large file descriptor set to which all file
6530  *   descriptors will be added that are associated with one of the examined
6531  *   sessions.
6532  * @param[in,out] timeout On input, if *block = 1, the maximum time the caller
6533  *   will block while waiting for Net-SNMP activity. On output, if this function
6534  *   has set *block to 0, the maximum time the caller is allowed to wait before
6535  *   invoking the Net-SNMP processing functions (snmp_read(), snmp_timeout()
6536  *   and run_alarms()). If this function has set *block to 1, *timeout won't
6537  *   have been modified and no alarms are active.
6538  * @param[in,out] block   On input, whether the caller prefers to block forever
6539  *   when no alarms are active. On output, 0 means that no alarms are active
6540  *   nor that there is a timeout pending for any of the processed sessions.
6541  * @param[in]     flags   Either 0 or NETSNMP_SELECT_NOALARMS.
6542  *
6543  * @return Number of sessions processed by this function.
6544  *
6545  * @see See also agent_check_and_process() for an example of how to use this
6546  *   function.
6547  */
6548 int
snmp_sess_select_info2_flags(void * sessp,int * numfds,netsnmp_large_fd_set * fdset,struct timeval * timeout,int * block,int flags)6549 snmp_sess_select_info2_flags(void *sessp, int *numfds,
6550                              netsnmp_large_fd_set * fdset,
6551                              struct timeval *timeout, int *block, int flags)
6552 {
6553     struct session_list *slp, *next = NULL;
6554     netsnmp_request_list *rp;
6555     struct timeval  now, earliest, alarm_tm;
6556     int             active = 0, requests = 0;
6557     int             next_alarm = 0;
6558 
6559     timerclear(&earliest);
6560 
6561     /*
6562      * For each session examined, add its socket to the fdset,
6563      * and if it is the earliest timeout to expire, mark it as lowest.
6564      * If a single session is specified, do just for that session.
6565      */
6566 
6567     DEBUGMSGTL(("sess_select", "for %s session%s: ",
6568                 sessp ? "single" : "all", sessp ? "" : "s"));
6569 
6570     for (slp = sessp ? sessp : Sessions; slp; slp = next) {
6571         next = slp->next;
6572 
6573         if (slp->transport == NULL) {
6574             /*
6575              * Close in progress -- skip this one.
6576              */
6577             DEBUGMSG(("sess_select", "skip "));
6578             continue;
6579         }
6580 
6581         if (slp->transport->sock == -1) {
6582             /*
6583              * This session was marked for deletion.
6584              */
6585             DEBUGMSG(("sess_select", "delete\n"));
6586             if (sessp == NULL) {
6587                 snmp_close(slp->session);
6588             } else {
6589                 snmp_sess_close(slp);
6590             }
6591             DEBUGMSGTL(("sess_select", "for %s session%s: ",
6592                         sessp ? "single" : "all", sessp ? "" : "s"));
6593             continue;
6594         }
6595 
6596         DEBUGMSG(("sess_select", "%d ", slp->transport->sock));
6597         if ((slp->transport->sock + 1) > *numfds) {
6598             *numfds = (slp->transport->sock + 1);
6599         }
6600 
6601         NETSNMP_LARGE_FD_SET(slp->transport->sock, fdset);
6602         if (slp->internal != NULL && slp->internal->requests) {
6603             /*
6604              * Found another session with outstanding requests.
6605              */
6606             requests++;
6607             for (rp = slp->internal->requests; rp; rp = rp->next_request) {
6608                 if (!timerisset(&earliest)
6609                     || (timerisset(&rp->expireM)
6610                         && timercmp(&rp->expireM, &earliest, <))) {
6611                     earliest = rp->expireM;
6612                     DEBUGMSG(("verbose:sess_select","(to in %d.%06d sec) ",
6613                                (int)earliest.tv_sec, (int)earliest.tv_usec));
6614                 }
6615             }
6616         }
6617 
6618         active++;
6619         if (sessp) {
6620             /*
6621              * Single session processing.
6622              */
6623             break;
6624         }
6625     }
6626     DEBUGMSG(("sess_select", "\n"));
6627 
6628     netsnmp_get_monotonic_clock(&now);
6629 
6630     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
6631                                NETSNMP_DS_LIB_ALARM_DONT_USE_SIG) &&
6632         !(flags & NETSNMP_SELECT_NOALARMS)) {
6633         next_alarm = netsnmp_get_next_alarm_time(&alarm_tm, &now);
6634         if (next_alarm)
6635             DEBUGMSGT(("sess_select","next alarm at %ld.%06ld sec\n",
6636                        (long)alarm_tm.tv_sec, (long)alarm_tm.tv_usec));
6637     }
6638     if (next_alarm == 0 && requests == 0) {
6639         /*
6640          * If none are active, skip arithmetic.
6641          */
6642         DEBUGMSGT(("sess_select","blocking:no session requests or alarms.\n"));
6643         *block = 1; /* can block - timeout value is undefined if no requests */
6644         return active;
6645     }
6646 
6647     if (next_alarm &&
6648         (!timerisset(&earliest) || timercmp(&alarm_tm, &earliest, <)))
6649         earliest = alarm_tm;
6650 
6651     NETSNMP_TIMERSUB(&earliest, &now, &earliest);
6652     if (earliest.tv_sec < 0) {
6653         time_t overdue_ms = -(earliest.tv_sec * 1000 + earliest.tv_usec / 1000);
6654         if (overdue_ms >= 10)
6655             DEBUGMSGT(("verbose:sess_select","timer overdue by %ld ms\n",
6656                        (long) overdue_ms));
6657         timerclear(&earliest);
6658     } else {
6659         DEBUGMSGT(("verbose:sess_select","timer due in %d.%06d sec\n",
6660                    (int)earliest.tv_sec, (int)earliest.tv_usec));
6661     }
6662 
6663     /*
6664      * if it was blocking before or our delta time is less, reset timeout
6665      */
6666     if ((*block || (timercmp(&earliest, timeout, <)))) {
6667         DEBUGMSGT(("verbose:sess_select",
6668                    "setting timer to %d.%06d sec, clear block (was %d)\n",
6669                    (int)earliest.tv_sec, (int)earliest.tv_usec, *block));
6670         *timeout = earliest;
6671         *block = 0;
6672     }
6673     return active;
6674 }
6675 
6676 /*
6677  * snmp_timeout should be called whenever the timeout from snmp_select_info
6678  * expires, but it is idempotent, so snmp_timeout can be polled (probably a
6679  * cpu expensive proposition).  snmp_timeout checks to see if any of the
6680  * sessions have an outstanding request that has timed out.  If it finds one
6681  * (or more), and that pdu has more retries available, a new packet is formed
6682  * from the pdu and is resent.  If there are no more retries available, the
6683  *  callback for the session is used to alert the user of the timeout.
6684  */
6685 void
snmp_timeout(void)6686 snmp_timeout(void)
6687 {
6688     struct session_list *slp;
6689     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
6690     for (slp = Sessions; slp; slp = slp->next) {
6691         snmp_sess_timeout((void *) slp);
6692     }
6693     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
6694 }
6695 
6696 static int
snmp_resend_request(struct session_list * slp,netsnmp_request_list * orp,netsnmp_request_list * rp,int incr_retries)6697 snmp_resend_request(struct session_list *slp, netsnmp_request_list *orp,
6698                     netsnmp_request_list *rp, int incr_retries)
6699 {
6700     struct snmp_internal_session *isp;
6701     netsnmp_session *sp;
6702     netsnmp_transport *transport;
6703     u_char         *pktbuf = NULL, *packet = NULL;
6704     size_t          pktbuf_len = 0, length = 0;
6705     struct timeval  tv, now;
6706     int             result = 0;
6707 
6708     sp = slp->session;
6709     isp = slp->internal;
6710     transport = slp->transport;
6711     if (!sp || !isp || !transport) {
6712         DEBUGMSGTL(("sess_read", "resend fail: closing...\n"));
6713         return 0;
6714     }
6715 
6716     if ((pktbuf = (u_char *)malloc(2048)) == NULL) {
6717         DEBUGMSGTL(("sess_resend",
6718                     "couldn't malloc initial packet buffer\n"));
6719         return 0;
6720     } else {
6721         pktbuf_len = 2048;
6722     }
6723 
6724     if (incr_retries) {
6725         rp->retries++;
6726     }
6727 
6728     /*
6729      * Always increment msgId for resent messages.
6730      */
6731     rp->pdu->msgid = rp->message_id = snmp_get_next_msgid();
6732 
6733     result = netsnmp_build_packet(isp, sp, rp->pdu, &pktbuf, &pktbuf_len,
6734                                   &packet, &length);
6735     if (result < 0) {
6736         /*
6737          * This should never happen.
6738          */
6739         DEBUGMSGTL(("sess_resend", "encoding failure\n"));
6740         SNMP_FREE(pktbuf);
6741         return -1;
6742     }
6743 
6744     DEBUGMSGTL(("sess_process_packet", "resending message id#%ld reqid#%ld "
6745                 "rp_reqid#%ld rp_msgid#%ld len %" NETSNMP_PRIz "u\n",
6746                 rp->pdu->msgid, rp->pdu->reqid, rp->request_id, rp->message_id, length));
6747     result = netsnmp_transport_send(transport, packet, length,
6748                                     &(rp->pdu->transport_data),
6749                                     &(rp->pdu->transport_data_length));
6750 
6751     /*
6752      * We are finished with the local packet buffer, if we allocated one (due
6753      * to there being no saved packet).
6754      */
6755 
6756     if (pktbuf != NULL) {
6757         SNMP_FREE(pktbuf);
6758         packet = NULL;
6759     }
6760 
6761     if (result < 0) {
6762         sp->s_snmp_errno = SNMPERR_BAD_SENDTO;
6763         sp->s_errno = errno;
6764         snmp_set_detail(strerror(errno));
6765         if (rp->callback) {
6766             rp->callback(NETSNMP_CALLBACK_OP_SEND_FAILED, sp,
6767                          rp->pdu->reqid, rp->pdu, rp->cb_data);
6768             remove_request(isp, orp, rp);
6769 	}
6770         return -1;
6771     } else {
6772         netsnmp_get_monotonic_clock(&now);
6773         tv = now;
6774         rp->timeM = tv;
6775         tv.tv_usec += rp->timeout;
6776         tv.tv_sec += tv.tv_usec / 1000000L;
6777         tv.tv_usec %= 1000000L;
6778         rp->expireM = tv;
6779         if (rp->callback)
6780             rp->callback(NETSNMP_CALLBACK_OP_RESEND, sp,
6781                          rp->pdu->reqid, rp->pdu, rp->cb_data);
6782     }
6783     return 0;
6784 }
6785 
6786 
6787 
6788 void
snmp_sess_timeout(void * sessp)6789 snmp_sess_timeout(void *sessp)
6790 {
6791     struct session_list *slp = (struct session_list *) sessp;
6792     netsnmp_session *sp;
6793     struct snmp_internal_session *isp;
6794     netsnmp_request_list *rp, *orp = NULL, *freeme = NULL;
6795     struct timeval  now;
6796     snmp_callback   callback;
6797     void           *magic;
6798     struct snmp_secmod_def *sptr;
6799 
6800     sp = slp->session;
6801     isp = slp->internal;
6802     if (!sp || !isp) {
6803         DEBUGMSGTL(("sess_read", "timeout fail: closing...\n"));
6804         return;
6805     }
6806 
6807     netsnmp_get_monotonic_clock(&now);
6808 
6809     /*
6810      * For each request outstanding, check to see if it has expired.
6811      */
6812     for (rp = isp->requests; rp; rp = rp->next_request) {
6813         if (freeme != NULL) {
6814             /*
6815              * frees rp's after the for loop goes on to the next_request
6816              */
6817             free((char *) freeme);
6818             freeme = NULL;
6819         }
6820 
6821         if ((timercmp(&rp->expireM, &now, <))) {
6822             if ((sptr = find_sec_mod(rp->pdu->securityModel)) != NULL &&
6823                 sptr->pdu_timeout != NULL) {
6824                 /*
6825                  * call security model if it needs to know about this
6826                  */
6827                 (*sptr->pdu_timeout) (rp->pdu);
6828             }
6829 
6830             /*
6831              * this timer has expired
6832              */
6833             if (rp->retries >= sp->retries) {
6834                 if (rp->callback) {
6835                     callback = rp->callback;
6836                     magic = rp->cb_data;
6837                 } else {
6838                     callback = sp->callback;
6839                     magic = sp->callback_magic;
6840                 }
6841 
6842                 /*
6843                  * No more chances, delete this entry
6844                  */
6845                 if (callback) {
6846                     callback(NETSNMP_CALLBACK_OP_TIMED_OUT, sp,
6847                              rp->pdu->reqid, rp->pdu, magic);
6848                 }
6849                 remove_request(isp, orp, rp);
6850                 freeme = rp;
6851                 continue;       /* don't update orp below */
6852             } else {
6853                 if (snmp_resend_request(slp, orp, rp, TRUE)) {
6854                     break;
6855                 }
6856             }
6857         }
6858         orp = rp;
6859     }
6860 
6861     if (freeme != NULL) {
6862         free((char *) freeme);
6863         freeme = NULL;
6864     }
6865 }
6866 
6867 /*
6868  * lexicographical compare two object identifiers.
6869  * * Returns -1 if name1 < name2,
6870  * *          0 if name1 = name2,
6871  * *          1 if name1 > name2
6872  * *
6873  * * Caution: this method is called often by
6874  * *          command responder applications (ie, agent).
6875  */
6876 int
snmp_oid_ncompare(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2,size_t max_len)6877 snmp_oid_ncompare(const oid * in_name1,
6878                   size_t len1,
6879                   const oid * in_name2, size_t len2, size_t max_len)
6880 {
6881     register int    len;
6882     register const oid *name1 = in_name1;
6883     register const oid *name2 = in_name2;
6884     size_t          min_len;
6885 
6886     /*
6887      * len = minimum of len1 and len2
6888      */
6889     if (len1 < len2)
6890         min_len = len1;
6891     else
6892         min_len = len2;
6893 
6894     if (min_len > max_len)
6895         min_len = max_len;
6896 
6897     len = min_len;
6898 
6899     /*
6900      * find first non-matching OID
6901      */
6902     while (len-- > 0) {
6903         /*
6904          * these must be done in seperate comparisons, since
6905          * subtracting them and using that result has problems with
6906          * subids > 2^31.
6907          */
6908         if (*(name1) != *(name2)) {
6909             if (*(name1) < *(name2))
6910                 return -1;
6911             return 1;
6912         }
6913         name1++;
6914         name2++;
6915     }
6916 
6917     if (min_len != max_len) {
6918         /*
6919          * both OIDs equal up to length of shorter OID
6920          */
6921         if (len1 < len2)
6922             return -1;
6923         if (len2 < len1)
6924             return 1;
6925     }
6926 
6927     return 0;
6928 }
6929 
6930 /** lexicographical compare two object identifiers.
6931  *
6932  * Caution: this method is called often by
6933  *          command responder applications (ie, agent).
6934  *
6935  * @return -1 if name1 < name2, 0 if name1 = name2, 1 if name1 > name2
6936  */
6937 int
snmp_oid_compare(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)6938 snmp_oid_compare(const oid * in_name1,
6939                  size_t len1, const oid * in_name2, size_t len2)
6940 {
6941     register int    len;
6942     register const oid *name1 = in_name1;
6943     register const oid *name2 = in_name2;
6944 
6945     /*
6946      * len = minimum of len1 and len2
6947      */
6948     if (len1 < len2)
6949         len = len1;
6950     else
6951         len = len2;
6952     /*
6953      * find first non-matching OID
6954      */
6955     while (len-- > 0) {
6956         /*
6957          * these must be done in seperate comparisons, since
6958          * subtracting them and using that result has problems with
6959          * subids > 2^31.
6960          */
6961         if (*(name1) != *(name2)) {
6962             if (*(name1) < *(name2))
6963                 return -1;
6964             return 1;
6965         }
6966         name1++;
6967         name2++;
6968     }
6969     /*
6970      * both OIDs equal up to length of shorter OID
6971      */
6972     if (len1 < len2)
6973         return -1;
6974     if (len2 < len1)
6975         return 1;
6976     return 0;
6977 }
6978 
6979 /** lexicographical compare two object identifiers and return the point where they differ
6980  *
6981  * Caution: this method is called often by
6982  *          command responder applications (ie, agent).
6983  *
6984  * @return -1 if name1 < name2, 0 if name1 = name2, 1 if name1 > name2 and offpt = len where name1 != name2
6985  */
6986 int
netsnmp_oid_compare_ll(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2,size_t * offpt)6987 netsnmp_oid_compare_ll(const oid * in_name1,
6988                        size_t len1, const oid * in_name2, size_t len2,
6989                        size_t *offpt)
6990 {
6991     register int    len;
6992     register const oid *name1 = in_name1;
6993     register const oid *name2 = in_name2;
6994     int initlen;
6995 
6996     /*
6997      * len = minimum of len1 and len2
6998      */
6999     if (len1 < len2)
7000         initlen = len = len1;
7001     else
7002         initlen = len = len2;
7003     /*
7004      * find first non-matching OID
7005      */
7006     while (len-- > 0) {
7007         /*
7008          * these must be done in seperate comparisons, since
7009          * subtracting them and using that result has problems with
7010          * subids > 2^31.
7011          */
7012         if (*(name1) != *(name2)) {
7013             *offpt = initlen - len;
7014             if (*(name1) < *(name2))
7015                 return -1;
7016             return 1;
7017         }
7018         name1++;
7019         name2++;
7020     }
7021     /*
7022      * both OIDs equal up to length of shorter OID
7023      */
7024     *offpt = initlen - len;
7025     if (len1 < len2)
7026         return -1;
7027     if (len2 < len1)
7028         return 1;
7029     return 0;
7030 }
7031 
7032 /** Compares 2 OIDs to determine if they are equal up until the shortest length.
7033  * @param in_name1 A pointer to the first oid.
7034  * @param len1     length of the first OID (in segments, not bytes)
7035  * @param in_name2 A pointer to the second oid.
7036  * @param len2     length of the second OID (in segments, not bytes)
7037  * @return 0 if they are equal, 1 if in_name1 is > in_name2, or -1 if <.
7038  */
7039 int
snmp_oidtree_compare(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)7040 snmp_oidtree_compare(const oid * in_name1,
7041                      size_t len1, const oid * in_name2, size_t len2)
7042 {
7043     int             len = ((len1 < len2) ? len1 : len2);
7044 
7045     return (snmp_oid_compare(in_name1, len, in_name2, len));
7046 }
7047 
7048 int
snmp_oidsubtree_compare(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)7049 snmp_oidsubtree_compare(const oid * in_name1,
7050                      size_t len1, const oid * in_name2, size_t len2)
7051 {
7052     int             len = ((len1 < len2) ? len1 : len2);
7053 
7054     return (snmp_oid_compare(in_name1, len1, in_name2, len));
7055 }
7056 
7057 /** Compares 2 OIDs to determine if they are exactly equal.
7058  *  This should be faster than doing a snmp_oid_compare for different
7059  *  length OIDs, since the length is checked first and if != returns
7060  *  immediately.  Might be very slighly faster if lengths are ==.
7061  * @param in_name1 A pointer to the first oid.
7062  * @param len1     length of the first OID (in segments, not bytes)
7063  * @param in_name2 A pointer to the second oid.
7064  * @param len2     length of the second OID (in segments, not bytes)
7065  * @return 0 if they are equal, 1 if they are not.
7066  */
7067 int
netsnmp_oid_equals(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)7068 netsnmp_oid_equals(const oid * in_name1,
7069                    size_t len1, const oid * in_name2, size_t len2)
7070 {
7071     register const oid *name1 = in_name1;
7072     register const oid *name2 = in_name2;
7073     register int    len = len1;
7074 
7075     /*
7076      * len = minimum of len1 and len2
7077      */
7078     if (len1 != len2)
7079         return 1;
7080     /*
7081      * Handle 'null' OIDs
7082      */
7083     if (len1 == 0)
7084         return 0;   /* Two null OIDs are (trivially) the same */
7085     if (!name1 || !name2)
7086         return 1;   /* Otherwise something's wrong, so report a non-match */
7087     /*
7088      * find first non-matching OID
7089      */
7090     while (len-- > 0) {
7091         /*
7092          * these must be done in seperate comparisons, since
7093          * subtracting them and using that result has problems with
7094          * subids > 2^31.
7095          */
7096         if (*(name1++) != *(name2++))
7097             return 1;
7098     }
7099     return 0;
7100 }
7101 
7102 #ifndef NETSNMP_FEATURE_REMOVE_OID_IS_SUBTREE
7103 /** Identical to netsnmp_oid_equals, except only the length up to len1 is compared.
7104  * Functionally, this determines if in_name2 is equal or a subtree of in_name1
7105  * @param in_name1 A pointer to the first oid.
7106  * @param len1     length of the first OID (in segments, not bytes)
7107  * @param in_name2 A pointer to the second oid.
7108  * @param len2     length of the second OID (in segments, not bytes)
7109  * @return 0 if one is a common prefix of the other.
7110  */
7111 int
netsnmp_oid_is_subtree(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)7112 netsnmp_oid_is_subtree(const oid * in_name1,
7113                        size_t len1, const oid * in_name2, size_t len2)
7114 {
7115     if (len1 > len2)
7116         return 1;
7117 
7118     if (memcmp(in_name1, in_name2, len1 * sizeof(oid)))
7119         return 1;
7120 
7121     return 0;
7122 }
7123 #endif /* NETSNMP_FEATURE_REMOVE_OID_IS_SUBTREE */
7124 
7125 /** Given two OIDs, determine the common prefix to them both.
7126  * @param in_name1 A pointer to the first oid.
7127  * @param len1     Length of the first oid.
7128  * @param in_name2 A pointer to the second oid.
7129  * @param len2     Length of the second oid.
7130  * @return         length of common prefix
7131  *                 0 if no common prefix, -1 on error.
7132  */
7133 int
netsnmp_oid_find_prefix(const oid * in_name1,size_t len1,const oid * in_name2,size_t len2)7134 netsnmp_oid_find_prefix(const oid * in_name1, size_t len1,
7135                         const oid * in_name2, size_t len2)
7136 {
7137     int i;
7138     size_t min_size;
7139 
7140     if (!in_name1 || !in_name2 || !len1 || !len2)
7141         return -1;
7142 
7143     if (in_name1[0] != in_name2[0])
7144         return 0;   /* No match */
7145     min_size = SNMP_MIN(len1, len2);
7146     for(i = 0; i < (int)min_size; i++) {
7147         if (in_name1[i] != in_name2[i])
7148             return i;    /* '�' is the first differing subidentifier
7149                             So the common prefix is 0..(i-1), of length i */
7150     }
7151     return min_size;	/* The shorter OID is a prefix of the longer, and
7152                            hence is precisely the common prefix of the two.
7153                            Return its length. */
7154 }
7155 
7156 #ifndef NETSNMP_DISABLE_MIB_LOADING
_check_range(struct tree * tp,long ltmp,int * resptr,const char * errmsg)7157 static int _check_range(struct tree *tp, long ltmp, int *resptr,
7158 	                const char *errmsg)
7159 {
7160     char *cp   = NULL;
7161     char *temp = NULL;
7162     int   temp_len = 0;
7163     int check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7164 	                                NETSNMP_DS_LIB_DONT_CHECK_RANGE);
7165 
7166     if (check && tp && tp->ranges) {
7167 	struct range_list *rp = tp->ranges;
7168 	while (rp) {
7169 	    if (rp->low <= ltmp && ltmp <= rp->high) break;
7170                                   /* Allow four digits per range value */
7171             temp_len += ((rp->low != rp->high) ? 27 : 15 );
7172 	    rp = rp->next;
7173 	}
7174 	if (!rp) {
7175 	    *resptr = SNMPERR_RANGE;
7176             temp = (char *)malloc( temp_len+strlen(errmsg)+7);
7177             if ( temp ) {
7178                 /* Append the Display Hint range information to the error message */
7179                 sprintf( temp, "%s :: {", errmsg );
7180                 cp = temp+(strlen(temp));
7181                 for ( rp = tp->ranges; rp; rp=rp->next ) {
7182                     if ( rp->low != rp->high )
7183                         sprintf( cp, "(%d..%d), ", rp->low, rp->high );
7184                     else
7185                         sprintf( cp, "(%d), ", rp->low );
7186                     cp += strlen(cp);
7187                 }
7188                 *(cp-2) = '}';   /* Replace the final comma with a '}' */
7189                 *(cp-1) = 0;
7190 	        snmp_set_detail(temp);
7191 	        free(temp);
7192             }
7193 	    return 0;
7194 	}
7195     }
7196     free(temp);
7197     return 1;
7198 }
7199 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7200 
7201 /*
7202  * Add a variable with the requested name to the end of the list of
7203  * variables for this pdu.
7204  */
7205 netsnmp_variable_list *
snmp_pdu_add_variable(netsnmp_pdu * pdu,const oid * name,size_t name_length,u_char type,const void * value,size_t len)7206 snmp_pdu_add_variable(netsnmp_pdu *pdu,
7207                       const oid * name,
7208                       size_t name_length,
7209                       u_char type, const void * value, size_t len)
7210 {
7211     return snmp_varlist_add_variable(&pdu->variables, name, name_length,
7212                                      type, value, len);
7213 }
7214 
7215 /*
7216  * Add a variable with the requested name to the end of the list of
7217  * variables for this pdu.
7218  */
7219 netsnmp_variable_list *
snmp_varlist_add_variable(netsnmp_variable_list ** varlist,const oid * name,size_t name_length,u_char type,const void * value,size_t len)7220 snmp_varlist_add_variable(netsnmp_variable_list ** varlist,
7221                           const oid * name,
7222                           size_t name_length,
7223                           u_char type, const void * value, size_t len)
7224 {
7225     netsnmp_variable_list *vars, *vtmp;
7226     int rc;
7227 
7228     if (varlist == NULL)
7229         return NULL;
7230 
7231     vars = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
7232     if (vars == NULL)
7233         return NULL;
7234 
7235     vars->type = type;
7236 
7237     rc = snmp_set_var_value( vars, value, len );
7238     if (( 0 != rc ) ||
7239         (name != NULL && snmp_set_var_objid(vars, name, name_length))) {
7240         snmp_free_var(vars);
7241         return NULL;
7242     }
7243 
7244     /*
7245      * put only qualified variable onto varlist
7246      */
7247     if (*varlist == NULL) {
7248         *varlist = vars;
7249     } else {
7250         for (vtmp = *varlist; vtmp->next_variable;
7251              vtmp = vtmp->next_variable);
7252 
7253         vtmp->next_variable = vars;
7254     }
7255 
7256     return vars;
7257 }
7258 
7259 
7260 
7261 /*
7262  * Add a variable with the requested name to the end of the list of
7263  * variables for this pdu.
7264  * Returns:
7265  * may set these error types :
7266  * SNMPERR_RANGE - type, value, or length not found or out of range
7267  * SNMPERR_VALUE - value is not correct
7268  * SNMPERR_VAR_TYPE - type is not correct
7269  * SNMPERR_BAD_NAME - name is not found
7270  *
7271  * returns 0 if success, error if failure.
7272  */
7273 int
snmp_add_var(netsnmp_pdu * pdu,const oid * name,size_t name_length,char type,const char * value)7274 snmp_add_var(netsnmp_pdu *pdu,
7275              const oid * name, size_t name_length, char type, const char *value)
7276 {
7277     char           *st;
7278     const char     *cp;
7279     char           *ecp, *vp;
7280     int             result = SNMPERR_SUCCESS;
7281 #ifndef NETSNMP_DISABLE_MIB_LOADING
7282     int             check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7283 					     NETSNMP_DS_LIB_DONT_CHECK_RANGE);
7284     int             do_hint = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7285 					     NETSNMP_DS_LIB_NO_DISPLAY_HINT);
7286     u_char         *hintptr;
7287     struct tree    *tp;
7288     struct enum_list *ep;
7289     int             itmp;
7290 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7291     u_char         *buf = NULL;
7292     const u_char   *buf_ptr = NULL;
7293     size_t          buf_len = 0, value_len = 0, tint;
7294     in_addr_t       atmp;
7295     long            ltmp;
7296 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
7297     double          dtmp;
7298     float           ftmp;
7299 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
7300     struct counter64 c64tmp;
7301 
7302 #ifndef NETSNMP_DISABLE_MIB_LOADING
7303     tp = get_tree(name, name_length, get_tree_head());
7304     if (!tp || !tp->type || tp->type > TYPE_SIMPLE_LAST) {
7305         check = 0;
7306     }
7307     if (!(tp && tp->hint))
7308 	do_hint = 0;
7309 
7310     if (tp && type == '=') {
7311         /*
7312          * generic assignment - let the tree node decide value format
7313          */
7314         switch (tp->type) {
7315         case TYPE_INTEGER:
7316         case TYPE_INTEGER32:
7317             type = 'i';
7318             break;
7319         case TYPE_GAUGE:
7320         case TYPE_UNSIGNED32:
7321             type = 'u';
7322             break;
7323         case TYPE_UINTEGER:
7324             type = '3';
7325             break;
7326         case TYPE_COUNTER:
7327             type = 'c';
7328             break;
7329         case TYPE_COUNTER64:
7330             type = 'C';
7331             break;
7332         case TYPE_TIMETICKS:
7333             type = 't';
7334             break;
7335         case TYPE_OCTETSTR:
7336             type = 's';
7337             break;
7338         case TYPE_BITSTRING:
7339             type = 'b';
7340             break;
7341         case TYPE_IPADDR:
7342             type = 'a';
7343             break;
7344         case TYPE_OBJID:
7345             type = 'o';
7346             break;
7347         }
7348     }
7349 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7350 
7351     switch (type) {
7352     case 'i':
7353 #ifndef NETSNMP_DISABLE_MIB_LOADING
7354         if (check && tp->type != TYPE_INTEGER
7355             && tp->type != TYPE_INTEGER32) {
7356             value = "INTEGER";
7357             result = SNMPERR_VALUE;
7358             goto type_error;
7359         }
7360 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7361         if (!*value)
7362             goto fail;
7363         ltmp = strtol(value, &ecp, 10);
7364         if (*ecp) {
7365 #ifndef NETSNMP_DISABLE_MIB_LOADING
7366             ep = tp ? tp->enums : NULL;
7367             while (ep) {
7368                 if (strcmp(value, ep->label) == 0) {
7369                     ltmp = ep->value;
7370                     break;
7371                 }
7372                 ep = ep->next;
7373             }
7374             if (!ep) {
7375 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7376                 result = SNMPERR_RANGE;   /* ?? or SNMPERR_VALUE; */
7377                 snmp_set_detail(value);
7378                 break;
7379 #ifndef NETSNMP_DISABLE_MIB_LOADING
7380             }
7381 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7382         }
7383 
7384 #ifndef NETSNMP_DISABLE_MIB_LOADING
7385         if (!_check_range(tp, ltmp, &result, value))
7386             break;
7387 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7388         snmp_pdu_add_variable(pdu, name, name_length, ASN_INTEGER,
7389                               &ltmp, sizeof(ltmp));
7390         break;
7391 
7392     case 'u':
7393 #ifndef NETSNMP_DISABLE_MIB_LOADING
7394         if (check && tp->type != TYPE_GAUGE && tp->type != TYPE_UNSIGNED32) {
7395             value = "Unsigned32";
7396             result = SNMPERR_VALUE;
7397             goto type_error;
7398         }
7399 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7400         ltmp = strtoul(value, &ecp, 10);
7401         if (*value && !*ecp)
7402             snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
7403                                   &ltmp, sizeof(ltmp));
7404         else
7405             goto fail;
7406         break;
7407 
7408     case '3':
7409 #ifndef NETSNMP_DISABLE_MIB_LOADING
7410         if (check && tp->type != TYPE_UINTEGER) {
7411             value = "UInteger32";
7412             result = SNMPERR_VALUE;
7413             goto type_error;
7414         }
7415 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7416         ltmp = strtoul(value, &ecp, 10);
7417         if (*value && !*ecp)
7418             snmp_pdu_add_variable(pdu, name, name_length, ASN_UINTEGER,
7419                                   &ltmp, sizeof(ltmp));
7420         else
7421             goto fail;
7422         break;
7423 
7424     case 'c':
7425 #ifndef NETSNMP_DISABLE_MIB_LOADING
7426         if (check && tp->type != TYPE_COUNTER) {
7427             value = "Counter32";
7428             result = SNMPERR_VALUE;
7429             goto type_error;
7430         }
7431 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7432         ltmp = strtoul(value, &ecp, 10);
7433         if (*value && !*ecp)
7434             snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
7435                                   &ltmp, sizeof(ltmp));
7436         else
7437             goto fail;
7438         break;
7439 
7440     case 'C':
7441 #ifndef NETSNMP_DISABLE_MIB_LOADING
7442         if (check && tp->type != TYPE_COUNTER64) {
7443             value = "Counter64";
7444             result = SNMPERR_VALUE;
7445             goto type_error;
7446         }
7447 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7448         if (read64(&c64tmp, value))
7449             snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER64,
7450                                   &c64tmp, sizeof(c64tmp));
7451         else
7452             goto fail;
7453         break;
7454 
7455     case 't':
7456 #ifndef NETSNMP_DISABLE_MIB_LOADING
7457         if (check && tp->type != TYPE_TIMETICKS) {
7458             value = "Timeticks";
7459             result = SNMPERR_VALUE;
7460             goto type_error;
7461         }
7462 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7463         ltmp = strtoul(value, &ecp, 10);
7464         if (*value && !*ecp)
7465             snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
7466                                   &ltmp, sizeof(long));
7467         else
7468             goto fail;
7469         break;
7470 
7471     case 'a':
7472 #ifndef NETSNMP_DISABLE_MIB_LOADING
7473         if (check && tp->type != TYPE_IPADDR) {
7474             value = "IpAddress";
7475             result = SNMPERR_VALUE;
7476             goto type_error;
7477         }
7478 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7479         atmp = inet_addr(value);
7480         if (atmp != (in_addr_t) -1 || !strcmp(value, "255.255.255.255"))
7481             snmp_pdu_add_variable(pdu, name, name_length, ASN_IPADDRESS,
7482                                   &atmp, sizeof(atmp));
7483         else
7484             goto fail;
7485         break;
7486 
7487     case 'o':
7488 #ifndef NETSNMP_DISABLE_MIB_LOADING
7489         if (check && tp->type != TYPE_OBJID) {
7490             value = "OBJECT IDENTIFIER";
7491             result = SNMPERR_VALUE;
7492             goto type_error;
7493         }
7494 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7495         if ((buf = (u_char *)malloc(sizeof(oid) * MAX_OID_LEN)) == NULL) {
7496             result = SNMPERR_MALLOC;
7497         } else {
7498             tint = MAX_OID_LEN;
7499             if (snmp_parse_oid(value, (oid *) buf, &tint)) {
7500                 snmp_pdu_add_variable(pdu, name, name_length, ASN_OBJECT_ID,
7501                                       buf, sizeof(oid) * tint);
7502             } else {
7503                 result = snmp_errno;    /*MTCRITICAL_RESOURCE */
7504             }
7505         }
7506         break;
7507 
7508     case 's':
7509     case 'x':
7510     case 'd':
7511 #ifndef NETSNMP_DISABLE_MIB_LOADING
7512         if (check && tp->type != TYPE_OCTETSTR && tp->type != TYPE_BITSTRING) {
7513             value = "OCTET STRING";
7514             result = SNMPERR_VALUE;
7515             goto type_error;
7516         }
7517 	if ('s' == type && do_hint && !parse_octet_hint(tp->hint, value, &hintptr, &itmp)) {
7518             if (_check_range(tp, itmp, &result, "Value does not match DISPLAY-HINT")) {
7519                 snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
7520                                       hintptr, itmp);
7521             }
7522             SNMP_FREE(hintptr);
7523             hintptr = buf;
7524             break;
7525         }
7526 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7527         if (type == 'd') {
7528             if (!snmp_decimal_to_binary
7529                 (&buf, &buf_len, &value_len, 1, value)) {
7530                 result = SNMPERR_VALUE;
7531                 snmp_set_detail(value);
7532                 break;
7533             }
7534             buf_ptr = buf;
7535         } else if (type == 'x') {
7536             if (!snmp_hex_to_binary(&buf, &buf_len, &value_len, 1, value)) {
7537                 result = SNMPERR_VALUE;
7538                 snmp_set_detail(value);
7539                 break;
7540             }
7541             buf_ptr = buf;
7542         } else if (type == 's') {
7543             buf_ptr = (const u_char *)value;
7544             value_len = strlen(value);
7545         }
7546 #ifndef NETSNMP_DISABLE_MIB_LOADING
7547         if (!_check_range(tp, value_len, &result, "Bad string length"))
7548             break;
7549 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7550         snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
7551                               buf_ptr, value_len);
7552         break;
7553 
7554     case 'n':
7555         snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, NULL, 0);
7556         break;
7557 
7558     case 'b':
7559 #ifndef NETSNMP_DISABLE_MIB_LOADING
7560         if (check && (tp->type != TYPE_BITSTRING || !tp->enums)) {
7561             value = "BITS";
7562             result = SNMPERR_VALUE;
7563             goto type_error;
7564         }
7565 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7566         tint = 0;
7567         if ((buf = (u_char *) malloc(256)) == NULL) {
7568             result = SNMPERR_MALLOC;
7569             break;
7570         } else {
7571             buf_len = 256;
7572             memset(buf, 0, buf_len);
7573         }
7574 
7575 #ifndef NETSNMP_DISABLE_MIB_LOADING
7576         for (ep = tp ? tp->enums : NULL; ep; ep = ep->next) {
7577             if (ep->value / 8 >= (int) tint) {
7578                 tint = ep->value / 8 + 1;
7579             }
7580         }
7581 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7582 
7583 	vp = strdup(value);
7584         if (!vp) {
7585             SNMP_FREE(buf);
7586             goto fail;
7587         }
7588 	for (cp = strtok_r(vp, " ,\t", &st); cp; cp = strtok_r(NULL, " ,\t", &st)) {
7589             int             ix, bit;
7590 
7591             ltmp = strtoul(cp, &ecp, 0);
7592             if (*ecp != 0) {
7593 #ifndef NETSNMP_DISABLE_MIB_LOADING
7594                 for (ep = tp ? tp->enums : NULL; ep != NULL; ep = ep->next) {
7595                     if (strcmp(ep->label, cp) == 0) {
7596                         break;
7597                     }
7598                 }
7599                 if (ep != NULL) {
7600                     ltmp = ep->value;
7601                 } else {
7602 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7603                     result = SNMPERR_RANGE;   /* ?? or SNMPERR_VALUE; */
7604                     snmp_set_detail(cp);
7605                     SNMP_FREE(buf);
7606 		    SNMP_FREE(vp);
7607                     goto out;
7608 #ifndef NETSNMP_DISABLE_MIB_LOADING
7609                 }
7610 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7611             }
7612 
7613             ix = ltmp / 8;
7614             if (ix >= (int) tint) {
7615                 tint = ix + 1;
7616             }
7617             if (ix >= (int)buf_len && !snmp_realloc(&buf, &buf_len)) {
7618                 result = SNMPERR_MALLOC;
7619                 break;
7620             }
7621             bit = 0x80 >> ltmp % 8;
7622             buf[ix] |= bit;
7623 
7624         }
7625 	SNMP_FREE(vp);
7626         snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
7627                               buf, tint);
7628         break;
7629 
7630 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
7631     case 'U':
7632         if (read64(&c64tmp, value))
7633             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_U64,
7634                                   &c64tmp, sizeof(c64tmp));
7635         else
7636             goto fail;
7637         break;
7638 
7639     case 'I':
7640         if (read64(&c64tmp, value))
7641             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_I64,
7642                                   &c64tmp, sizeof(c64tmp));
7643         else
7644             goto fail;
7645         break;
7646 
7647     case 'F':
7648         if (sscanf(value, "%f", &ftmp) == 1)
7649             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_FLOAT,
7650                                   &ftmp, sizeof(ftmp));
7651         else
7652             goto fail;
7653         break;
7654 
7655     case 'D':
7656         if (sscanf(value, "%lf", &dtmp) == 1)
7657             snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_DOUBLE,
7658                                   &dtmp, sizeof(dtmp));
7659         else
7660             goto fail;
7661         break;
7662 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
7663 
7664     default:
7665         result = SNMPERR_VAR_TYPE;
7666 	buf = (u_char *)calloc(1, 4);
7667 	if (buf != NULL) {
7668 	    sprintf((char *)buf, "\"%c\"", type);
7669 	    snmp_set_detail((char *)buf);
7670 	}
7671         break;
7672     }
7673 
7674     SNMP_FREE(buf);
7675     SET_SNMP_ERROR(result);
7676     return result;
7677 
7678 #ifndef NETSNMP_DISABLE_MIB_LOADING
7679   type_error:
7680     {
7681         char            error_msg[256];
7682         char            undef_msg[32];
7683         const char     *var_type;
7684         switch (tp->type) {
7685         case TYPE_OBJID:
7686             var_type = "OBJECT IDENTIFIER";
7687             break;
7688         case TYPE_OCTETSTR:
7689             var_type = "OCTET STRING";
7690             break;
7691         case TYPE_INTEGER:
7692             var_type = "INTEGER";
7693             break;
7694         case TYPE_NETADDR:
7695             var_type = "NetworkAddress";
7696             break;
7697         case TYPE_IPADDR:
7698             var_type = "IpAddress";
7699             break;
7700         case TYPE_COUNTER:
7701             var_type = "Counter32";
7702             break;
7703         case TYPE_GAUGE:
7704             var_type = "Gauge32";
7705             break;
7706         case TYPE_TIMETICKS:
7707             var_type = "Timeticks";
7708             break;
7709         case TYPE_OPAQUE:
7710             var_type = "Opaque";
7711             break;
7712         case TYPE_NULL:
7713             var_type = "Null";
7714             break;
7715         case TYPE_COUNTER64:
7716             var_type = "Counter64";
7717             break;
7718         case TYPE_BITSTRING:
7719             var_type = "BITS";
7720             break;
7721         case TYPE_NSAPADDRESS:
7722             var_type = "NsapAddress";
7723             break;
7724         case TYPE_UINTEGER:
7725             var_type = "UInteger";
7726             break;
7727         case TYPE_UNSIGNED32:
7728             var_type = "Unsigned32";
7729             break;
7730         case TYPE_INTEGER32:
7731             var_type = "Integer32";
7732             break;
7733         default:
7734             sprintf(undef_msg, "TYPE_%d", tp->type);
7735             var_type = undef_msg;
7736         }
7737         snprintf(error_msg, sizeof(error_msg),
7738                "Type of attribute is %s, not %s", var_type, value);
7739         error_msg[ sizeof(error_msg)-1 ] = 0;
7740         result = SNMPERR_VAR_TYPE;
7741         snmp_set_detail(error_msg);
7742         goto out;
7743     }
7744 #endif /* NETSNMP_DISABLE_MIB_LOADING */
7745   fail:
7746     result = SNMPERR_VALUE;
7747     snmp_set_detail(value);
7748   out:
7749     SET_SNMP_ERROR(result);
7750     return result;
7751 }
7752 
7753 /*
7754  * returns NULL or internal pointer to session
7755  * use this pointer for the other snmp_sess* routines,
7756  * which guarantee action will occur ONLY for this given session.
7757  */
7758 void           *
snmp_sess_pointer(netsnmp_session * session)7759 snmp_sess_pointer(netsnmp_session * session)
7760 {
7761     struct session_list *slp;
7762 
7763     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
7764     for (slp = Sessions; slp; slp = slp->next) {
7765         if (slp->session == session) {
7766             break;
7767         }
7768     }
7769     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
7770 
7771     if (slp == NULL) {
7772         snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
7773         return (NULL);
7774     }
7775     return ((void *) slp);
7776 }
7777 
7778 /*
7779  * Input : an opaque pointer, returned by snmp_sess_open.
7780  * returns NULL or pointer to session.
7781  */
7782 netsnmp_session *
snmp_sess_session(void * sessp)7783 snmp_sess_session(void *sessp)
7784 {
7785     struct session_list *slp = (struct session_list *) sessp;
7786     if (slp == NULL)
7787         return (NULL);
7788     return (slp->session);
7789 }
7790 
7791 /**
7792  * Look up a session that already may have been closed.
7793  *
7794  * @param sessp Opaque pointer, returned by snmp_sess_open.
7795  *
7796  * @return Pointer to session upon success or NULL upon failure.
7797  *
7798  * @see snmp_sess_session()
7799  */
7800 netsnmp_session *
snmp_sess_session_lookup(void * sessp)7801 snmp_sess_session_lookup(void *sessp)
7802 {
7803     struct session_list *slp;
7804 
7805     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
7806     for (slp = Sessions; slp; slp = slp->next) {
7807         if (slp == sessp) {
7808             break;
7809         }
7810     }
7811     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
7812 
7813     return (netsnmp_session *)slp;
7814 }
7815 
7816 
7817 /*
7818  * returns NULL or internal pointer to session
7819  * use this pointer for the other snmp_sess* routines,
7820  * which guarantee action will occur ONLY for this given session.
7821  */
7822 netsnmp_session *
snmp_sess_lookup_by_name(const char * paramName)7823 snmp_sess_lookup_by_name(const char *paramName)
7824 {
7825     struct session_list *slp;
7826 
7827     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
7828     for (slp = Sessions; slp; slp = slp->next) {
7829         if (NULL == slp->session->paramName)
7830             continue;
7831         if (strcmp(paramName, slp->session->paramName)  == 0)
7832             break;
7833     }
7834     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
7835 
7836     if (slp == NULL)
7837         return NULL;
7838 
7839     return slp->session;
7840 }
7841 
7842 
7843 /*
7844  * snmp_sess_transport: takes an opaque pointer (as returned by
7845  * snmp_sess_open or snmp_sess_pointer) and returns the corresponding
7846  * netsnmp_transport pointer (or NULL if the opaque pointer does not correspond
7847  * to an active internal session).
7848  */
7849 
7850 netsnmp_transport *
snmp_sess_transport(void * sessp)7851 snmp_sess_transport(void *sessp)
7852 {
7853     struct session_list *slp = (struct session_list *) sessp;
7854     if (slp == NULL) {
7855         return NULL;
7856     } else {
7857         return slp->transport;
7858     }
7859 }
7860 
7861 
7862 
7863 /*
7864  * snmp_sess_transport_set: set the transport pointer for the opaque
7865  * session pointer sp.
7866  */
7867 
7868 void
snmp_sess_transport_set(void * sp,netsnmp_transport * t)7869 snmp_sess_transport_set(void *sp, netsnmp_transport *t)
7870 {
7871     struct session_list *slp = (struct session_list *) sp;
7872     if (slp != NULL) {
7873         slp->transport = t;
7874     }
7875 }
7876 
7877 
7878 /*
7879  * snmp_duplicate_objid: duplicates (mallocs) an objid based on the
7880  * input objid
7881  */
7882 oid            *
snmp_duplicate_objid(const oid * objToCopy,size_t objToCopyLen)7883 snmp_duplicate_objid(const oid * objToCopy, size_t objToCopyLen)
7884 {
7885     oid            *returnOid;
7886     if (objToCopy != NULL && objToCopyLen != 0) {
7887         returnOid = (oid *) malloc(objToCopyLen * sizeof(oid));
7888         if (returnOid) {
7889             memcpy(returnOid, objToCopy, objToCopyLen * sizeof(oid));
7890         }
7891     } else
7892         returnOid = NULL;
7893     return returnOid;
7894 }
7895 
7896 #ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
7897 /*
7898  * generic statistics counter functions
7899  */
7900 static u_int    statistics[NETSNMP_STAT_MAX_STATS];
7901 
7902 u_int
snmp_increment_statistic(int which)7903 snmp_increment_statistic(int which)
7904 {
7905     if (which >= 0 && which < NETSNMP_STAT_MAX_STATS) {
7906         statistics[which]++;
7907         return statistics[which];
7908     }
7909     return 0;
7910 }
7911 
7912 u_int
snmp_increment_statistic_by(int which,int count)7913 snmp_increment_statistic_by(int which, int count)
7914 {
7915     if (which >= 0 && which < NETSNMP_STAT_MAX_STATS) {
7916         statistics[which] += count;
7917         return statistics[which];
7918     }
7919     return 0;
7920 }
7921 
7922 u_int
snmp_get_statistic(int which)7923 snmp_get_statistic(int which)
7924 {
7925     if (which >= 0 && which < NETSNMP_STAT_MAX_STATS)
7926         return statistics[which];
7927     return 0;
7928 }
7929 
7930 void
snmp_init_statistics(void)7931 snmp_init_statistics(void)
7932 {
7933     memset(statistics, 0, sizeof(statistics));
7934 }
7935 #endif /* NETSNMP_FEATURE_REMOVE_STATISTICS */
7936 /**  @} */
7937