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