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