net-snmp 5.7
|
00001 /* 00002 * agent_trap.c 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 00013 */ 00020 #include <net-snmp/net-snmp-config.h> 00021 #include <net-snmp/net-snmp-features.h> 00022 00023 #if HAVE_UNISTD_H 00024 #include <unistd.h> 00025 #endif 00026 #if HAVE_NETDB_H 00027 #include <netdb.h> 00028 #endif 00029 #if HAVE_STDLIB_H 00030 #include <stdlib.h> 00031 #endif 00032 #if HAVE_STRING_H 00033 #include <string.h> 00034 #else 00035 #include <strings.h> 00036 #endif 00037 #if TIME_WITH_SYS_TIME 00038 # include <sys/time.h> 00039 # include <time.h> 00040 #else 00041 # if HAVE_SYS_TIME_H 00042 # include <sys/time.h> 00043 # else 00044 # include <time.h> 00045 # endif 00046 #endif 00047 #if HAVE_SYS_SOCKET_H 00048 #include <sys/socket.h> 00049 #endif 00050 #if HAVE_NETINET_IN_H 00051 #include <netinet/in.h> 00052 #endif 00053 #include <net-snmp/utilities.h> 00054 00055 #include <net-snmp/net-snmp-includes.h> 00056 #include <net-snmp/agent/net-snmp-agent-includes.h> 00057 #include <net-snmp/agent/agent_trap.h> 00058 #include <net-snmp/agent/snmp_agent.h> 00059 #include <net-snmp/agent/agent_callbacks.h> 00060 00061 #include <net-snmp/agent/agent_module_config.h> 00062 #include <net-snmp/agent/mib_module_config.h> 00063 00064 #ifdef USING_AGENTX_PROTOCOL_MODULE 00065 #include "agentx/protocol.h" 00066 #endif 00067 00068 netsnmp_feature_child_of(agent_trap_all, libnetsnmpagent) 00069 00070 netsnmp_feature_child_of(trap_vars_with_context, agent_trap_all) 00071 netsnmp_feature_child_of(remove_trap_session, agent_trap_all) 00072 00073 netsnmp_feature_child_of(send_v3trap,netsnmp_unused) 00074 netsnmp_feature_child_of(send_trap_pdu,netsnmp_unused) 00075 00076 struct trap_sink { 00077 netsnmp_session *sesp; 00078 struct trap_sink *next; 00079 int pdutype; 00080 int version; 00081 }; 00082 00083 struct trap_sink *sinks = NULL; 00084 00085 const oid objid_enterprisetrap[] = { NETSNMP_NOTIFICATION_MIB }; 00086 const oid trap_version_id[] = { NETSNMP_SYSTEM_MIB }; 00087 const int enterprisetrap_len = OID_LENGTH(objid_enterprisetrap); 00088 const int trap_version_id_len = OID_LENGTH(trap_version_id); 00089 00090 #define SNMPV2_TRAPS_PREFIX SNMP_OID_SNMPMODULES,1,1,5 00091 const oid trap_prefix[] = { SNMPV2_TRAPS_PREFIX }; 00092 const oid cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 }; /* SNMPv2-MIB */ 00093 00094 #define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4 00095 const oid snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 }; 00096 const oid snmptrapenterprise_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 }; 00097 const oid sysuptime_oid[] = { SNMP_OID_MIB2, 1, 3, 0 }; 00098 const size_t snmptrap_oid_len = OID_LENGTH(snmptrap_oid); 00099 const size_t snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid); 00100 const size_t sysuptime_oid_len = OID_LENGTH(sysuptime_oid); 00101 00102 #define SNMPV2_COMM_OBJS_PREFIX SNMP_OID_SNMPMODULES,18,1 00103 const oid agentaddr_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 3, 0 }; 00104 const size_t agentaddr_oid_len = OID_LENGTH(agentaddr_oid); 00105 const oid community_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 4, 0 }; 00106 const size_t community_oid_len = OID_LENGTH(community_oid); 00107 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 00108 char *snmp_trapcommunity = NULL; 00109 #endif 00110 00111 00112 #define SNMP_AUTHENTICATED_TRAPS_ENABLED 1 00113 #define SNMP_AUTHENTICATED_TRAPS_DISABLED 2 00114 00115 int snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED; 00116 int snmp_enableauthentrapsset = 0; 00117 00118 /* 00119 * Prototypes 00120 */ 00121 /* 00122 * static int create_v1_trap_session (const char *, u_short, const char *); 00123 * static int create_v2_trap_session (const char *, u_short, const char *); 00124 * static int create_v2_inform_session (const char *, u_short, const char *); 00125 * static void free_trap_session (struct trap_sink *sp); 00126 * static void send_v1_trap (netsnmp_session *, int, int); 00127 * static void send_v2_trap (netsnmp_session *, int, int, int); 00128 */ 00129 00130 00131 /******************* 00132 * 00133 * Trap session handling 00134 * 00135 *******************/ 00136 00137 void 00138 init_traps(void) 00139 { 00140 } 00141 00142 static void 00143 free_trap_session(struct trap_sink *sp) 00144 { 00145 DEBUGMSGTL(("trap", "freeing callback trap session (%p, %p)\n", sp, sp->sesp)); 00146 snmp_close(sp->sesp); 00147 free(sp); 00148 } 00149 00150 int 00151 add_trap_session(netsnmp_session * ss, int pdutype, int confirm, 00152 int version) 00153 { 00154 if (snmp_callback_available(SNMP_CALLBACK_APPLICATION, 00155 SNMPD_CALLBACK_REGISTER_NOTIFICATIONS) == 00156 SNMPERR_SUCCESS) { 00157 /* 00158 * something else wants to handle notification registrations 00159 */ 00160 struct agent_add_trap_args args; 00161 DEBUGMSGTL(("trap", "adding callback trap sink (%p)\n", ss)); 00162 args.ss = ss; 00163 args.confirm = confirm; 00164 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00165 SNMPD_CALLBACK_REGISTER_NOTIFICATIONS, 00166 (void *) &args); 00167 } else { 00168 /* 00169 * no other support exists, handle it ourselves. 00170 */ 00171 struct trap_sink *new_sink; 00172 00173 DEBUGMSGTL(("trap", "adding internal trap sink\n")); 00174 new_sink = (struct trap_sink *) malloc(sizeof(*new_sink)); 00175 if (new_sink == NULL) 00176 return 0; 00177 00178 new_sink->sesp = ss; 00179 new_sink->pdutype = pdutype; 00180 new_sink->version = version; 00181 new_sink->next = sinks; 00182 sinks = new_sink; 00183 } 00184 return 1; 00185 } 00186 00187 #ifndef NETSNMP_FEATURE_REMOVE_REMOVE_TRAP_SESSION 00188 int 00189 remove_trap_session(netsnmp_session * ss) 00190 { 00191 struct trap_sink *sp = sinks, *prev = NULL; 00192 00193 DEBUGMSGTL(("trap", "removing trap sessions\n")); 00194 while (sp) { 00195 if (sp->sesp == ss) { 00196 if (prev) { 00197 prev->next = sp->next; 00198 } else { 00199 sinks = sp->next; 00200 } 00201 /* 00202 * I don't believe you *really* want to close the session here; 00203 * it may still be in use for other purposes. In particular this 00204 * is awkward for AgentX, since we want to call this function 00205 * from the session's callback. Let's just free the trapsink 00206 * data structure. [jbpn] 00207 */ 00208 /* 00209 * free_trap_session(sp); 00210 */ 00211 DEBUGMSGTL(("trap", "removing trap session (%p, %p)\n", sp, sp->sesp)); 00212 free(sp); 00213 return 1; 00214 } 00215 prev = sp; 00216 sp = sp->next; 00217 } 00218 return 0; 00219 } 00220 #endif /* NETSNMP_FEATURE_REMOVE_REMOVE_TRAP_SESSION */ 00221 00222 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 00223 static int 00224 create_trap_session2(const char *sink, const char* sinkport, 00225 char *com, int version, int pdutype) 00226 { 00227 netsnmp_transport *t; 00228 netsnmp_session session, *sesp; 00229 00230 memset(&session, 0, sizeof(netsnmp_session)); 00231 session.version = version; 00232 if (com) { 00233 session.community = (u_char *) com; 00234 session.community_len = strlen(com); 00235 } 00236 00237 /* 00238 * for informs, set retries to default 00239 */ 00240 if (SNMP_MSG_INFORM == pdutype) { 00241 session.timeout = SNMP_DEFAULT_TIMEOUT; 00242 session.retries = SNMP_DEFAULT_RETRIES; 00243 } 00244 00245 /* 00246 * if the sink is localhost, bind to localhost, to reduce open ports. 00247 */ 00248 if ((NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00249 NETSNMP_DS_LIB_CLIENT_ADDR)) && 00250 ((0 == strcmp("localhost",sink)) || (0 == strcmp("127.0.0.1",sink)))) 00251 session.localname = strdup("localhost"); 00252 00253 t = netsnmp_tdomain_transport_full("snmptrap", sink, 0, NULL, sinkport); 00254 if (t != NULL) { 00255 sesp = snmp_add(&session, t, NULL, NULL); 00256 00257 if (sesp) { 00258 return add_trap_session(sesp, pdutype, 00259 (pdutype == SNMP_MSG_INFORM), version); 00260 } 00261 } 00262 /* 00263 * diagnose snmp_open errors with the input netsnmp_session pointer 00264 */ 00265 snmp_sess_perror("snmpd: create_trap_session", &session); 00266 return 0; 00267 } 00268 00269 int 00270 create_trap_session(char *sink, u_short sinkport, 00271 char *com, int version, int pdutype) 00272 { 00273 char buf[sizeof(sinkport) * 3 + 2]; 00274 if (sinkport != 0) { 00275 sprintf(buf, ":%hu", sinkport); 00276 snmp_log(LOG_NOTICE, 00277 "Using a separate port number is deprecated, please correct " 00278 "the sink specification instead"); 00279 } 00280 return create_trap_session2(sink, sinkport ? buf : NULL, com, version, 00281 pdutype); 00282 } 00283 00284 #endif /* support for community based SNMP */ 00285 00286 #ifndef NETSNMP_DISABLE_SNMPV1 00287 static int 00288 create_v1_trap_session(char *sink, const char *sinkport, char *com) 00289 { 00290 return create_trap_session2(sink, sinkport, com, 00291 SNMP_VERSION_1, SNMP_MSG_TRAP); 00292 } 00293 #endif 00294 00295 #ifndef NETSNMP_DISABLE_SNMPV2C 00296 static int 00297 create_v2_trap_session(const char *sink, const char *sinkport, char *com) 00298 { 00299 return create_trap_session2(sink, sinkport, com, 00300 SNMP_VERSION_2c, SNMP_MSG_TRAP2); 00301 } 00302 00303 static int 00304 create_v2_inform_session(const char *sink, const char *sinkport, char *com) 00305 { 00306 return create_trap_session2(sink, sinkport, com, 00307 SNMP_VERSION_2c, SNMP_MSG_INFORM); 00308 } 00309 #endif 00310 00311 void 00312 snmpd_free_trapsinks(void) 00313 { 00314 struct trap_sink *sp = sinks; 00315 DEBUGMSGTL(("trap", "freeing trap sessions\n")); 00316 while (sp) { 00317 sinks = sinks->next; 00318 free_trap_session(sp); 00319 sp = sinks; 00320 } 00321 } 00322 00323 /******************* 00324 * 00325 * Trap handling 00326 * 00327 *******************/ 00328 00329 00330 netsnmp_pdu* 00331 convert_v2pdu_to_v1( netsnmp_pdu* template_v2pdu ) 00332 { 00333 netsnmp_pdu *template_v1pdu; 00334 netsnmp_variable_list *first_vb, *vblist; 00335 netsnmp_variable_list *var; 00336 00337 /* 00338 * Make a copy of the v2 Trap PDU 00339 * before starting to convert this 00340 * into a v1 Trap PDU. 00341 */ 00342 template_v1pdu = snmp_clone_pdu( template_v2pdu); 00343 if (!template_v1pdu) { 00344 snmp_log(LOG_WARNING, 00345 "send_trap: failed to copy v1 template PDU\n"); 00346 return NULL; 00347 } 00348 template_v1pdu->command = SNMP_MSG_TRAP; 00349 first_vb = template_v1pdu->variables; 00350 vblist = template_v1pdu->variables; 00351 00352 /* 00353 * The first varbind should be the system uptime. 00354 */ 00355 if (!vblist || 00356 snmp_oid_compare(vblist->name, vblist->name_length, 00357 sysuptime_oid, sysuptime_oid_len)) { 00358 snmp_log(LOG_WARNING, 00359 "send_trap: no v2 sysUptime varbind to set from\n"); 00360 snmp_free_pdu(template_v1pdu); 00361 return NULL; 00362 } 00363 template_v1pdu->time = *vblist->val.integer; 00364 vblist = vblist->next_variable; 00365 00366 /* 00367 * The second varbind should be the snmpTrapOID. 00368 */ 00369 if (!vblist || 00370 snmp_oid_compare(vblist->name, vblist->name_length, 00371 snmptrap_oid, snmptrap_oid_len)) { 00372 snmp_log(LOG_WARNING, 00373 "send_trap: no v2 trapOID varbind to set from\n"); 00374 snmp_free_pdu(template_v1pdu); 00375 return NULL; 00376 } 00377 00378 /* 00379 * Check the v2 varbind list for any varbinds 00380 * that are not valid in an SNMPv1 trap. 00381 * This basically means Counter64 values. 00382 * 00383 * RFC 2089 said to omit such varbinds from the list. 00384 * RFC 2576/3584 say to drop the trap completely. 00385 */ 00386 for (var = vblist->next_variable; var; var = var->next_variable) { 00387 if ( var->type == ASN_COUNTER64 ) { 00388 snmp_log(LOG_WARNING, 00389 "send_trap: v1 traps can't carry Counter64 varbinds\n"); 00390 snmp_free_pdu(template_v1pdu); 00391 return NULL; 00392 } 00393 } 00394 00395 /* 00396 * Set the generic & specific trap types, 00397 * and the enterprise field from the v2 varbind list. 00398 * If there's an agentIPAddress varbind, set the agent_addr too 00399 */ 00400 if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), 00401 trap_prefix, OID_LENGTH(trap_prefix))) { 00402 /* 00403 * For 'standard' traps, extract the generic trap type 00404 * from the snmpTrapOID value, and take the enterprise 00405 * value from the 'snmpEnterprise' varbind. 00406 */ 00407 template_v1pdu->trap_type = 00408 vblist->val.objid[OID_LENGTH(trap_prefix)] - 1; 00409 template_v1pdu->specific_type = 0; 00410 00411 var = find_varbind_in_list( vblist, 00412 snmptrapenterprise_oid, 00413 snmptrapenterprise_oid_len); 00414 if (var) { 00415 template_v1pdu->enterprise_length = var->val_len/sizeof(oid); 00416 template_v1pdu->enterprise = 00417 snmp_duplicate_objid(var->val.objid, 00418 template_v1pdu->enterprise_length); 00419 } else { 00420 template_v1pdu->enterprise = NULL; 00421 template_v1pdu->enterprise_length = 0; /* XXX ??? */ 00422 } 00423 } else { 00424 /* 00425 * For enterprise-specific traps, split the snmpTrapOID value 00426 * into enterprise and specific trap 00427 */ 00428 size_t len = vblist->val_len / sizeof(oid); 00429 if ( len <= 2 ) { 00430 snmp_log(LOG_WARNING, 00431 "send_trap: v2 trapOID too short (%d)\n", (int)len); 00432 snmp_free_pdu(template_v1pdu); 00433 return NULL; 00434 } 00435 template_v1pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC; 00436 template_v1pdu->specific_type = vblist->val.objid[len - 1]; 00437 len--; 00438 if (vblist->val.objid[len-1] == 0) 00439 len--; 00440 SNMP_FREE(template_v1pdu->enterprise); 00441 template_v1pdu->enterprise = 00442 snmp_duplicate_objid(vblist->val.objid, len); 00443 template_v1pdu->enterprise_length = len; 00444 } 00445 var = find_varbind_in_list( vblist, agentaddr_oid, 00446 agentaddr_oid_len); 00447 if (var) { 00448 memcpy(template_v1pdu->agent_addr, 00449 var->val.string, 4); 00450 } 00451 00452 /* 00453 * The remainder of the v2 varbind list is kept 00454 * as the v2 varbind list. Update the PDU and 00455 * free the two redundant varbinds. 00456 */ 00457 template_v1pdu->variables = vblist->next_variable; 00458 vblist->next_variable = NULL; 00459 snmp_free_varbind( first_vb ); 00460 00461 return template_v1pdu; 00462 } 00463 00464 netsnmp_pdu* 00465 convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu ) 00466 { 00467 netsnmp_pdu *template_v2pdu; 00468 netsnmp_variable_list *first_vb; 00469 netsnmp_variable_list *var; 00470 oid enterprise[MAX_OID_LEN]; 00471 size_t enterprise_len; 00472 00473 /* 00474 * Make a copy of the v1 Trap PDU 00475 * before starting to convert this 00476 * into a v2 Trap PDU. 00477 */ 00478 template_v2pdu = snmp_clone_pdu( template_v1pdu); 00479 if (!template_v2pdu) { 00480 snmp_log(LOG_WARNING, 00481 "send_trap: failed to copy v2 template PDU\n"); 00482 return NULL; 00483 } 00484 template_v2pdu->command = SNMP_MSG_TRAP2; 00485 first_vb = template_v2pdu->variables; 00486 00487 /* 00488 * Insert an snmpTrapOID varbind before the original v1 varbind list 00489 * either using one of the standard defined trap OIDs, 00490 * or constructing this from the PDU enterprise & specific trap fields 00491 */ 00492 if (template_v1pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) { 00493 memcpy(enterprise, template_v1pdu->enterprise, 00494 template_v1pdu->enterprise_length*sizeof(oid)); 00495 enterprise_len = template_v1pdu->enterprise_length; 00496 enterprise[enterprise_len++] = 0; 00497 enterprise[enterprise_len++] = template_v1pdu->specific_type; 00498 } else { 00499 memcpy(enterprise, cold_start_oid, sizeof(cold_start_oid)); 00500 enterprise[9] = template_v1pdu->trap_type+1; 00501 enterprise_len = sizeof(cold_start_oid)/sizeof(oid); 00502 } 00503 00504 var = NULL; 00505 if (!snmp_varlist_add_variable( &var, 00506 snmptrap_oid, snmptrap_oid_len, 00507 ASN_OBJECT_ID, 00508 (u_char*)enterprise, enterprise_len*sizeof(oid))) { 00509 snmp_log(LOG_WARNING, 00510 "send_trap: failed to insert copied snmpTrapOID varbind\n"); 00511 snmp_free_pdu(template_v2pdu); 00512 return NULL; 00513 } 00514 var->next_variable = template_v2pdu->variables; 00515 template_v2pdu->variables = var; 00516 00517 /* 00518 * Insert a sysUptime varbind at the head of the v2 varbind list 00519 */ 00520 var = NULL; 00521 if (!snmp_varlist_add_variable( &var, 00522 sysuptime_oid, sysuptime_oid_len, 00523 ASN_TIMETICKS, 00524 (u_char*)&(template_v1pdu->time), 00525 sizeof(template_v1pdu->time))) { 00526 snmp_log(LOG_WARNING, 00527 "send_trap: failed to insert copied sysUptime varbind\n"); 00528 snmp_free_pdu(template_v2pdu); 00529 return NULL; 00530 } 00531 var->next_variable = template_v2pdu->variables; 00532 template_v2pdu->variables = var; 00533 00534 /* 00535 * Append the other three conversion varbinds, 00536 * (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise) 00537 * if they're not already present. 00538 * But don't bomb out completely if there are problems. 00539 */ 00540 var = find_varbind_in_list( template_v2pdu->variables, 00541 agentaddr_oid, agentaddr_oid_len); 00542 if (!var && (template_v1pdu->agent_addr[0] 00543 || template_v1pdu->agent_addr[1] 00544 || template_v1pdu->agent_addr[2] 00545 || template_v1pdu->agent_addr[3])) { 00546 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00547 agentaddr_oid, agentaddr_oid_len, 00548 ASN_IPADDRESS, 00549 (u_char*)&(template_v1pdu->agent_addr), 00550 sizeof(template_v1pdu->agent_addr))) 00551 snmp_log(LOG_WARNING, 00552 "send_trap: failed to append snmpTrapAddr varbind\n"); 00553 } 00554 var = find_varbind_in_list( template_v2pdu->variables, 00555 community_oid, community_oid_len); 00556 if (!var && template_v1pdu->community) { 00557 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00558 community_oid, community_oid_len, 00559 ASN_OCTET_STR, 00560 template_v1pdu->community, 00561 template_v1pdu->community_len)) 00562 snmp_log(LOG_WARNING, 00563 "send_trap: failed to append snmpTrapCommunity varbind\n"); 00564 } 00565 var = find_varbind_in_list( template_v2pdu->variables, 00566 snmptrapenterprise_oid, 00567 snmptrapenterprise_oid_len); 00568 if (!var) { 00569 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00570 snmptrapenterprise_oid, snmptrapenterprise_oid_len, 00571 ASN_OBJECT_ID, 00572 (u_char*)template_v1pdu->enterprise, 00573 template_v1pdu->enterprise_length*sizeof(oid))) 00574 snmp_log(LOG_WARNING, 00575 "send_trap: failed to append snmpEnterprise varbind\n"); 00576 } 00577 return template_v2pdu; 00578 } 00579 00623 int 00624 netsnmp_send_traps(int trap, int specific, 00625 const oid * enterprise, int enterprise_length, 00626 netsnmp_variable_list * vars, 00627 const char * context, int flags) 00628 { 00629 netsnmp_pdu *template_v1pdu; 00630 netsnmp_pdu *template_v2pdu; 00631 netsnmp_variable_list *vblist = NULL; 00632 netsnmp_variable_list *trap_vb; 00633 netsnmp_variable_list *var; 00634 in_addr_t *pdu_in_addr_t; 00635 u_long uptime; 00636 struct trap_sink *sink; 00637 const char *v1trapaddress; 00638 int res = 0; 00639 00640 DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific)); 00641 DEBUGMSGOID(("trap", enterprise, enterprise_length)); 00642 DEBUGMSG(( "trap", "\n")); 00643 00644 if (vars) { 00645 vblist = snmp_clone_varbind( vars ); 00646 if (!vblist) { 00647 snmp_log(LOG_WARNING, 00648 "send_trap: failed to clone varbind list\n"); 00649 return -1; 00650 } 00651 } 00652 00653 if ( trap == -1 ) { 00654 /* 00655 * Construct the SNMPv2-style notification PDU 00656 */ 00657 if (!vblist) { 00658 snmp_log(LOG_WARNING, 00659 "send_trap: called with NULL v2 information\n"); 00660 return -1; 00661 } 00662 template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2); 00663 if (!template_v2pdu) { 00664 snmp_log(LOG_WARNING, 00665 "send_trap: failed to construct v2 template PDU\n"); 00666 snmp_free_varbind(vblist); 00667 return -1; 00668 } 00669 00670 /* 00671 * Check the varbind list we've been given. 00672 * If it starts with a 'sysUptime.0' varbind, then use that. 00673 * Otherwise, prepend a suitable 'sysUptime.0' varbind. 00674 */ 00675 if (!snmp_oid_compare( vblist->name, vblist->name_length, 00676 sysuptime_oid, sysuptime_oid_len )) { 00677 template_v2pdu->variables = vblist; 00678 trap_vb = vblist->next_variable; 00679 } else { 00680 uptime = netsnmp_get_agent_uptime(); 00681 var = NULL; 00682 snmp_varlist_add_variable( &var, 00683 sysuptime_oid, sysuptime_oid_len, 00684 ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime)); 00685 if (!var) { 00686 snmp_log(LOG_WARNING, 00687 "send_trap: failed to insert sysUptime varbind\n"); 00688 snmp_free_pdu(template_v2pdu); 00689 snmp_free_varbind(vblist); 00690 return -1; 00691 } 00692 template_v2pdu->variables = var; 00693 var->next_variable = vblist; 00694 trap_vb = vblist; 00695 } 00696 00697 /* 00698 * 'trap_vb' should point to the snmpTrapOID.0 varbind, 00699 * identifying the requested trap. If not then bomb out. 00700 * If it's a 'standard' trap, then we need to append an 00701 * snmpEnterprise varbind (if there isn't already one). 00702 */ 00703 if (!trap_vb || 00704 snmp_oid_compare(trap_vb->name, trap_vb->name_length, 00705 snmptrap_oid, snmptrap_oid_len)) { 00706 snmp_log(LOG_WARNING, 00707 "send_trap: no v2 trapOID varbind provided\n"); 00708 snmp_free_pdu(template_v2pdu); 00709 return -1; 00710 } 00711 if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), 00712 trap_prefix, OID_LENGTH(trap_prefix))) { 00713 var = find_varbind_in_list( template_v2pdu->variables, 00714 snmptrapenterprise_oid, 00715 snmptrapenterprise_oid_len); 00716 if (!var && 00717 !snmp_varlist_add_variable( &(template_v2pdu->variables), 00718 snmptrapenterprise_oid, snmptrapenterprise_oid_len, 00719 ASN_OBJECT_ID, 00720 enterprise, enterprise_length*sizeof(oid))) { 00721 snmp_log(LOG_WARNING, 00722 "send_trap: failed to add snmpEnterprise to v2 trap\n"); 00723 snmp_free_pdu(template_v2pdu); 00724 return -1; 00725 } 00726 } 00727 00728 00729 /* 00730 * If everything's OK, convert the v2 template into an SNMPv1 trap PDU. 00731 */ 00732 template_v1pdu = convert_v2pdu_to_v1( template_v2pdu ); 00733 if (!template_v1pdu) { 00734 snmp_log(LOG_WARNING, 00735 "send_trap: failed to convert v2->v1 template PDU\n"); 00736 } 00737 00738 } else { 00739 /* 00740 * Construct the SNMPv1 trap PDU.... 00741 */ 00742 template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP); 00743 if (!template_v1pdu) { 00744 snmp_log(LOG_WARNING, 00745 "send_trap: failed to construct v1 template PDU\n"); 00746 snmp_free_varbind(vblist); 00747 return -1; 00748 } 00749 template_v1pdu->trap_type = trap; 00750 template_v1pdu->specific_type = specific; 00751 template_v1pdu->time = netsnmp_get_agent_uptime(); 00752 00753 if (snmp_clone_mem((void **) &template_v1pdu->enterprise, 00754 enterprise, enterprise_length * sizeof(oid))) { 00755 snmp_log(LOG_WARNING, 00756 "send_trap: failed to set v1 enterprise OID\n"); 00757 snmp_free_varbind(vblist); 00758 snmp_free_pdu(template_v1pdu); 00759 return -1; 00760 } 00761 template_v1pdu->enterprise_length = enterprise_length; 00762 00763 template_v1pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; 00764 template_v1pdu->variables = vblist; 00765 00766 /* 00767 * ... and convert it into an SNMPv2-style notification PDU. 00768 */ 00769 00770 template_v2pdu = convert_v1pdu_to_v2( template_v1pdu ); 00771 if (!template_v2pdu) { 00772 snmp_log(LOG_WARNING, 00773 "send_trap: failed to convert v1->v2 template PDU\n"); 00774 } 00775 } 00776 00777 /* 00778 * Check whether we're ignoring authFail traps 00779 */ 00780 if (template_v1pdu) { 00781 if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL && 00782 snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) { 00783 snmp_free_pdu(template_v1pdu); 00784 snmp_free_pdu(template_v2pdu); 00785 return 0; 00786 } 00787 00788 /* 00789 * Ensure that the v1 trap PDU includes the local IP address 00790 */ 00791 pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr; 00792 v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 00793 NETSNMP_DS_AGENT_TRAP_ADDR); 00794 if (v1trapaddress != NULL) { 00795 /* "v1trapaddress" was specified in config, try to resolve it */ 00796 res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t); 00797 } 00798 if (v1trapaddress == NULL || res < 0) { 00799 /* "v1trapaddress" was not specified in config or the resolution failed, 00800 * try any local address */ 00801 *pdu_in_addr_t = get_myaddr(); 00802 } 00803 00804 } 00805 00806 /* A context name was provided, so copy it and its length to the v2 pdu 00807 * template. */ 00808 if (context != NULL) 00809 { 00810 template_v2pdu->contextName = strdup(context); 00811 template_v2pdu->contextNameLen = strlen(context); 00812 } 00813 00814 /* 00815 * Now loop through the list of trap sinks 00816 * and call the trap callback routines, 00817 * providing an appropriately formatted PDU in each case 00818 */ 00819 for (sink = sinks; sink; sink = sink->next) { 00820 #ifndef NETSNMP_DISABLE_SNMPV1 00821 if (sink->version == SNMP_VERSION_1) { 00822 if (template_v1pdu) { 00823 send_trap_to_sess(sink->sesp, template_v1pdu); 00824 } 00825 } else { 00826 #endif 00827 if (template_v2pdu) { 00828 template_v2pdu->command = sink->pdutype; 00829 send_trap_to_sess(sink->sesp, template_v2pdu); 00830 } 00831 #ifndef NETSNMP_DISABLE_SNMPV1 00832 } 00833 #endif 00834 } 00835 if (template_v1pdu) 00836 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00837 SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu); 00838 if (template_v2pdu) 00839 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00840 SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu); 00841 snmp_free_pdu(template_v1pdu); 00842 snmp_free_pdu(template_v2pdu); 00843 return 0; 00844 } 00845 00846 00847 void 00848 send_enterprise_trap_vars(int trap, 00849 int specific, 00850 const oid * enterprise, int enterprise_length, 00851 netsnmp_variable_list * vars) 00852 { 00853 netsnmp_send_traps(trap, specific, 00854 enterprise, enterprise_length, 00855 vars, NULL, 0); 00856 return; 00857 } 00858 00864 int 00865 handle_inform_response(int op, netsnmp_session * session, 00866 int reqid, netsnmp_pdu *pdu, 00867 void *magic) 00868 { 00869 /* XXX: possibly stats update */ 00870 switch (op) { 00871 00872 case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: 00873 snmp_increment_statistic(STAT_SNMPINPKTS); 00874 DEBUGMSGTL(("trap", "received the inform response for reqid=%d\n", 00875 reqid)); 00876 break; 00877 00878 case NETSNMP_CALLBACK_OP_TIMED_OUT: 00879 DEBUGMSGTL(("trap", 00880 "received a timeout sending an inform for reqid=%d\n", 00881 reqid)); 00882 break; 00883 00884 case NETSNMP_CALLBACK_OP_SEND_FAILED: 00885 DEBUGMSGTL(("trap", 00886 "failed to send an inform for reqid=%d\n", 00887 reqid)); 00888 break; 00889 00890 default: 00891 DEBUGMSGTL(("trap", "received op=%d for reqid=%d when trying to send an inform\n", op, reqid)); 00892 } 00893 00894 return 1; 00895 } 00896 00897 00898 /* 00899 * send_trap_to_sess: sends a trap to a session but assumes that the 00900 * pdu is constructed correctly for the session type. 00901 */ 00902 void 00903 send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu) 00904 { 00905 netsnmp_pdu *pdu; 00906 int result; 00907 00908 if (!sess || !template_pdu) 00909 return; 00910 00911 DEBUGMSGTL(("trap", "sending trap type=%d, version=%ld\n", 00912 template_pdu->command, sess->version)); 00913 00914 #ifndef NETSNMP_DISABLE_SNMPV1 00915 if (sess->version == SNMP_VERSION_1 && 00916 (template_pdu->command != SNMP_MSG_TRAP)) 00917 return; /* Skip v1 sinks for v2 only traps */ 00918 if (sess->version != SNMP_VERSION_1 && 00919 (template_pdu->command == SNMP_MSG_TRAP)) 00920 return; /* Skip v2+ sinks for v1 only traps */ 00921 #endif 00922 template_pdu->version = sess->version; 00923 pdu = snmp_clone_pdu(template_pdu); 00924 pdu->sessid = sess->sessid; /* AgentX only ? */ 00925 00926 if ( template_pdu->command == SNMP_MSG_INFORM 00927 #ifdef USING_AGENTX_PROTOCOL_MODULE 00928 || template_pdu->command == AGENTX_MSG_NOTIFY 00929 #endif 00930 ) { 00931 result = 00932 snmp_async_send(sess, pdu, &handle_inform_response, NULL); 00933 00934 } else { 00935 if ((sess->version == SNMP_VERSION_3) && 00936 (pdu->command == SNMP_MSG_TRAP2) && 00937 (sess->securityEngineIDLen == 0)) { 00938 u_char tmp[SPRINT_MAX_LEN]; 00939 00940 int len = snmpv3_get_engineID(tmp, sizeof(tmp)); 00941 memdup(&pdu->securityEngineID, tmp, len); 00942 pdu->securityEngineIDLen = len; 00943 } 00944 00945 result = snmp_send(sess, pdu); 00946 } 00947 00948 if (result == 0) { 00949 snmp_sess_perror("snmpd: send_trap", sess); 00950 snmp_free_pdu(pdu); 00951 } else { 00952 snmp_increment_statistic(STAT_SNMPOUTTRAPS); 00953 snmp_increment_statistic(STAT_SNMPOUTPKTS); 00954 } 00955 } 00956 00957 void 00958 send_trap_vars(int trap, int specific, netsnmp_variable_list * vars) 00959 { 00960 if (trap == SNMP_TRAP_ENTERPRISESPECIFIC) 00961 send_enterprise_trap_vars(trap, specific, objid_enterprisetrap, 00962 OID_LENGTH(objid_enterprisetrap), vars); 00963 else 00964 send_enterprise_trap_vars(trap, specific, trap_version_id, 00965 OID_LENGTH(trap_version_id), vars); 00966 } 00967 00968 #ifndef NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT 00969 /* Send a trap under a context */ 00970 void send_trap_vars_with_context(int trap, int specific, 00971 netsnmp_variable_list *vars, const char *context) 00972 { 00973 if (trap == SNMP_TRAP_ENTERPRISESPECIFIC) 00974 netsnmp_send_traps(trap, specific, objid_enterprisetrap, 00975 OID_LENGTH(objid_enterprisetrap), vars, 00976 context, 0); 00977 else 00978 netsnmp_send_traps(trap, specific, trap_version_id, 00979 OID_LENGTH(trap_version_id), vars, 00980 context, 0); 00981 00982 } 00983 #endif /* NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT */ 00984 01008 void 01009 send_easy_trap(int trap, int specific) 01010 { 01011 send_trap_vars(trap, specific, NULL); 01012 } 01013 01037 void 01038 send_v2trap(netsnmp_variable_list * vars) 01039 { 01040 send_trap_vars(-1, -1, vars); 01041 } 01042 01055 #ifndef NETSNMP_FEATURE_REMOVE_SEND_V3TRAP 01056 void send_v3trap(netsnmp_variable_list *vars, const char *context) 01057 { 01058 netsnmp_send_traps(-1, -1, 01059 trap_version_id, OID_LENGTH(trap_version_id), 01060 vars, context, 0); 01061 } 01062 #endif /* NETSNMP_FEATURE_REMOVE_SEND_V3TRAP */ 01063 01064 #ifndef NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU 01065 void 01066 send_trap_pdu(netsnmp_pdu *pdu) 01067 { 01068 send_trap_vars(-1, -1, pdu->variables); 01069 } 01070 #endif /* NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU */ 01071 01072 01073 01074 /******************* 01075 * 01076 * Config file handling 01077 * 01078 *******************/ 01079 01080 void 01081 snmpd_parse_config_authtrap(const char *token, char *cptr) 01082 { 01083 int i; 01084 01085 i = atoi(cptr); 01086 if (i == 0) { 01087 if (strcmp(cptr, "enable") == 0) { 01088 i = SNMP_AUTHENTICATED_TRAPS_ENABLED; 01089 } else if (strcmp(cptr, "disable") == 0) { 01090 i = SNMP_AUTHENTICATED_TRAPS_DISABLED; 01091 } 01092 } 01093 if (i < 1 || i > 2) { 01094 config_perror("authtrapenable must be 1 or 2"); 01095 } else { 01096 if (strcmp(token, "pauthtrapenable") == 0) { 01097 if (snmp_enableauthentrapsset < 0) { 01098 /* 01099 * This is bogus (and shouldn't happen anyway) -- the value 01100 * of snmpEnableAuthenTraps.0 is already configured 01101 * read-only. 01102 */ 01103 snmp_log(LOG_WARNING, 01104 "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n"); 01105 return; 01106 } else { 01107 snmp_enableauthentrapsset++; 01108 } 01109 } else { 01110 if (snmp_enableauthentrapsset > 0) { 01111 /* 01112 * This is bogus (and shouldn't happen anyway) -- we already 01113 * read a persistent value of snmpEnableAuthenTraps.0, which 01114 * we should ignore in favour of this one. 01115 */ 01116 snmp_log(LOG_WARNING, 01117 "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n"); 01118 /* 01119 * Fall through and copy in this value. 01120 */ 01121 } 01122 snmp_enableauthentrapsset = -1; 01123 } 01124 snmp_enableauthentraps = i; 01125 } 01126 } 01127 01128 #ifndef NETSNMP_DISABLE_SNMPV1 01129 void 01130 snmpd_parse_config_trapsink(const char *token, char *cptr) 01131 { 01132 char *sp, *cp, *pp = NULL; 01133 char *st; 01134 01135 if (!snmp_trapcommunity) 01136 snmp_trapcommunity = strdup("public"); 01137 sp = strtok_r(cptr, " \t\n", &st); 01138 cp = strtok_r(NULL, " \t\n", &st); 01139 if (cp) 01140 pp = strtok_r(NULL, " \t\n", &st); 01141 if (pp) 01142 config_pwarn("The separate port argument to trapsink is deprecated"); 01143 if (create_v1_trap_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01144 netsnmp_config_error("cannot create trapsink: %s", cptr); 01145 } 01146 } 01147 #endif 01148 01149 #ifndef NETSNMP_DISABLE_SNMPV2C 01150 void 01151 snmpd_parse_config_trap2sink(const char *word, char *cptr) 01152 { 01153 char *st, *sp, *cp, *pp = NULL; 01154 01155 if (!snmp_trapcommunity) 01156 snmp_trapcommunity = strdup("public"); 01157 sp = strtok_r(cptr, " \t\n", &st); 01158 cp = strtok_r(NULL, " \t\n", &st); 01159 if (cp) 01160 pp = strtok_r(NULL, " \t\n", &st); 01161 if (pp) 01162 config_pwarn("The separate port argument to trapsink2 is deprecated"); 01163 if (create_v2_trap_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01164 netsnmp_config_error("cannot create trap2sink: %s", cptr); 01165 } 01166 } 01167 01168 void 01169 snmpd_parse_config_informsink(const char *word, char *cptr) 01170 { 01171 char *st, *sp, *cp, *pp = NULL; 01172 01173 if (!snmp_trapcommunity) 01174 snmp_trapcommunity = strdup("public"); 01175 sp = strtok_r(cptr, " \t\n", &st); 01176 cp = strtok_r(NULL, " \t\n", &st); 01177 if (cp) 01178 pp = strtok_r(NULL, " \t\n", &st); 01179 if (pp) 01180 config_pwarn("The separate port argument to informsink is deprecated"); 01181 if (create_v2_inform_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01182 netsnmp_config_error("cannot create informsink: %s", cptr); 01183 } 01184 } 01185 #endif 01186 01187 /* 01188 * this must be standardized somewhere, right? 01189 */ 01190 #define MAX_ARGS 128 01191 01192 static int traptype; 01193 01194 static void 01195 trapOptProc(int argc, char *const *argv, int opt) 01196 { 01197 switch (opt) { 01198 case 'C': 01199 while (*optarg) { 01200 switch (*optarg++) { 01201 case 'i': 01202 traptype = SNMP_MSG_INFORM; 01203 break; 01204 default: 01205 config_perror("unknown argument passed to -C"); 01206 break; 01207 } 01208 } 01209 break; 01210 } 01211 } 01212 01213 01214 void 01215 snmpd_parse_config_trapsess(const char *word, char *cptr) 01216 { 01217 char *argv[MAX_ARGS], *cp = cptr; 01218 int argn, rc; 01219 netsnmp_session session, *ss; 01220 netsnmp_transport *transport; 01221 size_t len; 01222 01223 /* 01224 * inform or trap? default to trap 01225 */ 01226 traptype = SNMP_MSG_TRAP2; 01227 01228 /* 01229 * create the argv[] like array 01230 */ 01231 argv[0] = strdup("snmpd-trapsess"); /* bogus entry for getopt() */ 01232 for (argn = 1; cp && argn < MAX_ARGS; argn++) { 01233 char tmp[SPRINT_MAX_LEN]; 01234 01235 cp = copy_nword(cp, tmp, SPRINT_MAX_LEN); 01236 argv[argn] = strdup(tmp); 01237 } 01238 01239 netsnmp_parse_args(argn, argv, &session, "C:", trapOptProc, 01240 NETSNMP_PARSE_ARGS_NOLOGGING | 01241 NETSNMP_PARSE_ARGS_NOZERO); 01242 01243 transport = netsnmp_transport_open_client("snmptrap", session.peername); 01244 if ((rc = netsnmp_sess_config_and_open_transport(&session, transport)) 01245 != SNMPERR_SUCCESS) { 01246 session.s_snmp_errno = rc; 01247 session.s_errno = 0; 01248 return; 01249 } 01250 ss = snmp_add(&session, transport, NULL, NULL); 01251 for (; argn > 0; argn--) { 01252 free(argv[argn - 1]); 01253 } 01254 01255 if (!ss) { 01256 config_perror 01257 ("snmpd: failed to parse this line or the remote trap receiver is down. Possible cause:"); 01258 snmp_sess_perror("snmpd: snmpd_parse_config_trapsess()", &session); 01259 return; 01260 } 01261 01262 /* 01263 * If this is an SNMPv3 TRAP session, then the agent is 01264 * the authoritative engine, so set the engineID accordingly 01265 */ 01266 if (ss->version == SNMP_VERSION_3 && 01267 traptype != SNMP_MSG_INFORM && 01268 ss->securityEngineIDLen == 0) { 01269 u_char tmp[SPRINT_MAX_LEN]; 01270 01271 len = snmpv3_get_engineID( tmp, sizeof(tmp)); 01272 memdup(&ss->securityEngineID, tmp, len); 01273 ss->securityEngineIDLen = len; 01274 } 01275 01276 #ifndef NETSNMP_DISABLE_SNMPV1 01277 if (ss->version == SNMP_VERSION_1) 01278 traptype = SNMP_MSG_TRAP; 01279 #endif 01280 add_trap_session(ss, traptype, (traptype == SNMP_MSG_INFORM), ss->version); 01281 } 01282 01283 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01284 void 01285 snmpd_parse_config_trapcommunity(const char *word, char *cptr) 01286 { 01287 if (snmp_trapcommunity != NULL) { 01288 free(snmp_trapcommunity); 01289 } 01290 snmp_trapcommunity = (char *) malloc(strlen(cptr) + 1); 01291 if (snmp_trapcommunity != NULL) { 01292 copy_nword(cptr, snmp_trapcommunity, strlen(cptr) + 1); 01293 } 01294 } 01295 01296 void 01297 snmpd_free_trapcommunity(void) 01298 { 01299 if (snmp_trapcommunity) { 01300 free(snmp_trapcommunity); 01301 snmp_trapcommunity = NULL; 01302 } 01303 } 01304 #endif 01305