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 <mp, 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 <mp, 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 <mp, 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 <mp, 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 <mp, 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