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