/** * Authorizes incoming notifications for further processing */ int netsnmp_trapd_auth(netsnmp_pdu *pdu, netsnmp_transport *transport, netsnmp_trapd_handler *handler) { int ret = 0; oid snmptrapoid[] = { 1,3,6,1,6,3,1,1,4,1,0 }; size_t snmptrapoid_len = OID_LENGTH(snmptrapoid); int i; netsnmp_pdu *newpdu = pdu; netsnmp_variable_list *var; /* check to see if authorization was not disabled */ if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NO_AUTHORIZATION)) { DEBUGMSGTL(("snmptrapd:auth", "authorization turned off: not checking\n")); return NETSNMPTRAPD_HANDLER_OK; } /* bail early if called illegally */ if (!pdu || !transport || !handler) return NETSNMPTRAPD_HANDLER_FINISH; /* convert to v2 so we can check it in a consistent manner */ #ifndef NETSNMP_DISABLE_SNMPV1 if (pdu->version == SNMP_VERSION_1) { newpdu = convert_v1pdu_to_v2(pdu); if (!newpdu) { snmp_log(LOG_ERR, "Failed to duplicate incoming PDU. Refusing to authorize.\n"); return NETSNMPTRAPD_HANDLER_FINISH; } } #endif if (!vacm_is_configured()) { #ifndef NETSNMP_DISABLE_SNMPV1 if (newpdu != pdu) snmp_free_pdu(newpdu); #endif snmp_log(LOG_WARNING, "No access configuration - dropping trap.\n"); return NETSNMPTRAPD_HANDLER_FINISH; } /* loop through each variable and find the snmpTrapOID.0 var indicating what the trap is we're staring at. */ for (var = newpdu->variables; var != NULL; var = var->next_variable) { if (netsnmp_oid_equals(var->name, var->name_length, snmptrapoid, snmptrapoid_len) == 0) break; } /* make sure we can continue: we found the snmpTrapOID.0 and its an oid */ if (!var || var->type != ASN_OBJECT_ID) { snmp_log(LOG_ERR, "Can't determine trap identifier; refusing to authorize it\n"); #ifndef NETSNMP_DISABLE_SNMPV1 if (newpdu != pdu) snmp_free_pdu(newpdu); #endif return NETSNMPTRAPD_HANDLER_FINISH; } #ifdef USING_MIBII_VACM_CONF_MODULE /* check the pdu against each typo of VACM access we may want to check up on later. We cache the results for future lookup on each call to netsnmp_trapd_check_auth */ for(i = 0; i < VACM_MAX_VIEWS; i++) { /* pass the PDU to the VACM routine for handling authorization */ DEBUGMSGTL(("snmptrapd:auth", "Calling VACM for checking phase %d:%s\n", i, se_find_label_in_slist(VACM_VIEW_ENUM_NAME, i))); if (vacm_check_view_contents(newpdu, var->val.objid, var->val_len/sizeof(oid), 0, i, VACM_CHECK_VIEW_CONTENTS_DNE_CONTEXT_OK) == VACM_SUCCESS) { DEBUGMSGTL(("snmptrapd:auth", " result: authorized\n")); ret |= 1 << i; } else { DEBUGMSGTL(("snmptrapd:auth", " result: not authorized\n")); } } DEBUGMSGTL(("snmptrapd:auth", "Final bitmask auth: %x\n", ret)); #endif if (ret) { /* we have policy to at least do "something". Remember and continue. */ lastlookup = ret; #ifndef NETSNMP_DISABLE_SNMPV1 if (newpdu != pdu) snmp_free_pdu(newpdu); #endif return NETSNMPTRAPD_HANDLER_OK; } /* No policy was met, so we drop the PDU from further processing */ DEBUGMSGTL(("snmptrapd:auth", "Dropping unauthorized message\n")); #ifndef NETSNMP_DISABLE_SNMPV1 if (newpdu != pdu) snmp_free_pdu(newpdu); #endif return NETSNMPTRAPD_HANDLER_FINISH; }
/** * This function allows you to make a distinction between generic * traps from different classes of equipment. For example, you may want * to handle a SNMP_TRAP_LINKDOWN trap for a particular device in a * different manner to a generic system SNMP_TRAP_LINKDOWN trap. * * * @param trap is the generic trap type. The trap types are: * - SNMP_TRAP_COLDSTART: * cold start * - SNMP_TRAP_WARMSTART: * warm start * - SNMP_TRAP_LINKDOWN: * link down * - SNMP_TRAP_LINKUP: * link up * - SNMP_TRAP_AUTHFAIL: * authentication failure * - SNMP_TRAP_EGPNEIGHBORLOSS: * egp neighbor loss * - SNMP_TRAP_ENTERPRISESPECIFIC: * enterprise specific * * @param specific is the specific trap value. * * @param enterprise is an enterprise oid in which you want to send specifc * traps from. * * @param enterprise_length is the length of the enterprise oid, use macro, * OID_LENGTH, to compute length. * * @param vars is used to supply list of variable bindings to form an SNMPv2 * trap. * * @param context currently unused * * @param flags currently unused * * @return void * * @see send_easy_trap * @see send_v2trap */ int netsnmp_send_traps(int trap, int specific, oid * enterprise, int enterprise_length, netsnmp_variable_list * vars, char * context, int flags) { netsnmp_pdu *template_v1pdu; netsnmp_pdu *template_v2pdu; netsnmp_variable_list *vblist = NULL; netsnmp_variable_list *trap_vb; netsnmp_variable_list *var; in_addr_t *pdu_in_addr_t; u_long uptime; struct trap_sink *sink; DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific)); DEBUGMSGOID(("trap", enterprise, enterprise_length)); DEBUGMSG(( "trap", "\n")); if (vars) { vblist = snmp_clone_varbind( vars ); if (!vblist) { snmp_log(LOG_WARNING, "send_trap: failed to clone varbind list\n"); return -1; } } if ( trap == -1 ) { /* * Construct the SNMPv2-style notification PDU */ if (!vblist) { snmp_log(LOG_WARNING, "send_trap: called with NULL v2 information\n"); return -1; } template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2); if (!template_v2pdu) { snmp_log(LOG_WARNING, "send_trap: failed to construct v2 template PDU\n"); snmp_free_varbind(vblist); return -1; } /* * Check the varbind list we've been given. * If it starts with a 'sysUptime.0' varbind, then use that. * Otherwise, prepend a suitable 'sysUptime.0' varbind. */ if (!snmp_oid_compare( vblist->name, vblist->name_length, sysuptime_oid, sysuptime_oid_len )) { template_v2pdu->variables = vblist; trap_vb = vblist->next_variable; } else { uptime = netsnmp_get_agent_uptime(); var = NULL; snmp_varlist_add_variable( &var, sysuptime_oid, sysuptime_oid_len, ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime)); if (!var) { snmp_log(LOG_WARNING, "send_trap: failed to insert sysUptime varbind\n"); snmp_free_pdu(template_v2pdu); snmp_free_varbind(vblist); return -1; } template_v2pdu->variables = var; var->next_variable = vblist; trap_vb = vblist; } /* * 'trap_vb' should point to the snmpTrapOID.0 varbind, * identifying the requested trap. If not then bomb out. * If it's a 'standard' trap, then we need to append an * snmpEnterprise varbind (if there isn't already one). */ if (!trap_vb || snmp_oid_compare(trap_vb->name, trap_vb->name_length, snmptrap_oid, snmptrap_oid_len)) { snmp_log(LOG_WARNING, "send_trap: no v2 trapOID varbind provided\n"); snmp_free_pdu(template_v2pdu); return -1; } if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), trap_prefix, OID_LENGTH(trap_prefix))) { var = find_varbind_in_list( template_v2pdu->variables, snmptrapenterprise_oid, snmptrapenterprise_oid_len); if (!var && !snmp_varlist_add_variable( &(template_v2pdu->variables), snmptrapenterprise_oid, snmptrapenterprise_oid_len, ASN_OBJECT_ID, (char*)enterprise, enterprise_length*sizeof(oid))) { snmp_log(LOG_WARNING, "send_trap: failed to add snmpEnterprise to v2 trap\n"); snmp_free_pdu(template_v2pdu); return -1; } } /* * If everything's OK, convert the v2 template into an SNMPv1 trap PDU. */ template_v1pdu = convert_v2pdu_to_v1( template_v2pdu ); if (!template_v1pdu) { snmp_log(LOG_WARNING, "send_trap: failed to convert v2->v1 template PDU\n"); } } else { /* * Construct the SNMPv1 trap PDU.... */ template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP); if (!template_v1pdu) { snmp_log(LOG_WARNING, "send_trap: failed to construct v1 template PDU\n"); snmp_free_varbind(vblist); return -1; } template_v1pdu->trap_type = trap; template_v1pdu->specific_type = specific; template_v1pdu->time = netsnmp_get_agent_uptime(); if (snmp_clone_mem((void **) &template_v1pdu->enterprise, enterprise, enterprise_length * sizeof(oid))) { snmp_log(LOG_WARNING, "send_trap: failed to set v1 enterprise OID\n"); snmp_free_varbind(vblist); snmp_free_pdu(template_v1pdu); return -1; } template_v1pdu->enterprise_length = enterprise_length; template_v1pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; template_v1pdu->variables = vblist; /* * ... and convert it into an SNMPv2-style notification PDU. */ template_v2pdu = convert_v1pdu_to_v2( template_v1pdu ); if (!template_v2pdu) { snmp_log(LOG_WARNING, "send_trap: failed to convert v1->v2 template PDU\n"); } } /* * Check whether we're ignoring authFail traps */ if (template_v1pdu) { if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL && snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) { snmp_free_pdu(template_v1pdu); snmp_free_pdu(template_v2pdu); return 0; } /* * Ensure that the v1 trap PDU includes the local IP address */ pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr; *pdu_in_addr_t = get_myaddr(); } /* * Now loop through the list of trap sinks * and call the trap callback routines, * providing an appropriately formatted PDU in each case */ for (sink = sinks; sink; sink = sink->next) { #ifndef NETSNMP_DISABLE_SNMPV1 if (sink->version == SNMP_VERSION_1) { if (template_v1pdu) { send_trap_to_sess(sink->sesp, template_v1pdu); } } else { #endif if (template_v2pdu) { template_v2pdu->command = sink->pdutype; send_trap_to_sess(sink->sesp, template_v2pdu); } #ifndef NETSNMP_DISABLE_SNMPV1 } #endif } if (template_v1pdu) snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu); if (template_v2pdu) snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu); snmp_free_pdu(template_v1pdu); snmp_free_pdu(template_v2pdu); return 0; }
int perl_trapd_handler( netsnmp_pdu *pdu, netsnmp_transport *transport, netsnmp_trapd_handler *handler) { trapd_cb_data *cb_data; SV *pcallback; netsnmp_variable_list *vb; netsnmp_oid *o; SV *arg; SV *rarg; SV **tmparray; int i, c = 0; u_char *outbuf; size_t ob_len = 0, oo_len = 0; AV *varbinds; HV *pduinfo; dSP; ENTER; SAVETMPS; if (!pdu || !handler) return 0; /* nuke v1 PDUs */ if (pdu->command == SNMP_MSG_TRAP) pdu = convert_v1pdu_to_v2(pdu); cb_data = handler->handler_data; if (!cb_data || !cb_data->perl_cb) return 0; pcallback = cb_data->perl_cb; /* get PDU related info */ pduinfo = newHV(); #define STOREPDU(n, v) hv_store(pduinfo, n, strlen(n), v, 0) #define STOREPDUi(n, v) STOREPDU(n, newSViv(v)) #define STOREPDUs(n, v) STOREPDU(n, newSVpv(v, 0)) STOREPDUi("version", pdu->version); STOREPDUs("notificationtype", ((pdu->command == SNMP_MSG_INFORM) ? "INFORM":"TRAP")); STOREPDUi("requestid", pdu->reqid); STOREPDUi("messageid", pdu->msgid); STOREPDUi("transactionid", pdu->transid); STOREPDUi("errorstatus", pdu->errstat); STOREPDUi("errorindex", pdu->errindex); if (pdu->version == 3) { STOREPDUi("securitymodel", pdu->securityModel); STOREPDUi("securitylevel", pdu->securityLevel); STOREPDU("contextName", newSVpv(pdu->contextName, pdu->contextNameLen)); STOREPDU("contextEngineID", newSVpv(pdu->contextEngineID, pdu->contextEngineIDLen)); STOREPDU("securityEngineID", newSVpv(pdu->securityEngineID, pdu->securityEngineIDLen)); STOREPDU("securityName", newSVpv(pdu->securityName, pdu->securityNameLen)); } else { STOREPDU("community", newSVpv(pdu->community, pdu->community_len)); } if (transport && transport->f_fmtaddr) { char *tstr = transport->f_fmtaddr(transport, pdu->transport_data, pdu->transport_data_length); STOREPDUs("receivedfrom", tstr); free(tstr); } /* * collect OID objects in a temp array first */ /* get VARBIND related info */ i = count_varbinds(pdu->variables); tmparray = malloc(sizeof(*tmparray) * i); for(vb = pdu->variables; vb; vb = vb->next_variable) { /* get the oid */ o = SNMP_MALLOC_TYPEDEF(netsnmp_oid); o->name = o->namebuf; o->len = vb->name_length; memcpy(o->name, vb->name, vb->name_length * sizeof(oid)); #undef CALL_EXTERNAL_OID_NEW #ifdef CALL_EXTERNAL_OID_NEW PUSHMARK(sp); rarg = sv_2mortal(newSViv((IV) 0)); arg = sv_2mortal(newSVrv(rarg, "netsnmp_oidPtr")); sv_setiv(arg, (IV) o); XPUSHs(rarg); PUTBACK; i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR); SPAGAIN; if (i != 1) { snmp_log(LOG_ERR, "unhandled OID error.\n"); /* ack XXX */ } /* get the value */ tmparray[c++] = POPs; SvREFCNT_inc(tmparray[c-1]); PUTBACK; #else /* build it and bless ourselves */ { HV *hv = newHV(); SV *rv = newRV_noinc((SV *) hv); SV *rvsub = newRV_noinc((SV *) newSViv((UV) o)); SV *sv; rvsub = sv_bless(rvsub, gv_stashpv("netsnmp_oidPtr", 1)); hv_store(hv, "oidptr", 6, rvsub, 0); rv = sv_bless(rv, gv_stashpv("NetSNMP::OID", 1)); tmparray[c++] = rv; } #endif /* build oid ourselves */ } /* * build the varbind lists */ varbinds = newAV(); for(vb = pdu->variables, i = 0; vb; vb = vb->next_variable, i++) { /* push the oid */ AV *vba; vba = newAV(); /* get the value */ outbuf = NULL; ob_len = 0; oo_len = 0; sprint_realloc_by_type(&outbuf, &ob_len, &oo_len, 1, vb, 0, 0, 0); av_push(vba,tmparray[i]); av_push(vba,newSVpvn(outbuf, oo_len)); free(outbuf); av_push(vba,newSViv(vb->type)); av_push(varbinds, (SV *) newRV_noinc((SV *) vba)); } PUSHMARK(sp); /* store the collected information on the stack */ XPUSHs(sv_2mortal(newRV_noinc((SV*) pduinfo))); XPUSHs(sv_2mortal(newRV_noinc((SV*) varbinds))); /* put the stack back in order */ PUTBACK; /* actually call the callback function */ if (SvTYPE(pcallback) == SVt_PVCV) { perl_call_sv(pcallback, G_DISCARD); /* XXX: it discards the results, which isn't right */ } else if (SvROK(pcallback) && SvTYPE(SvRV(pcallback)) == SVt_PVCV) { /* reference to code */ perl_call_sv(SvRV(pcallback), G_DISCARD); } else { snmp_log(LOG_ERR, " tried to call a perl function but failed to understand its type: (ref = %x, svrok: %lu, SVTYPE: %lu)\n", (uintptr_t)pcallback, SvROK(pcallback), SvTYPE(pcallback)); } #ifdef DUMPIT fprintf(stderr, "DUMPDUMPDUMPDUMPDUMPDUMP\n"); sv_dump(pduinfo); fprintf(stderr, "--------------------\n"); sv_dump(varbinds); #endif /* svREFCNT_dec((SV *) pduinfo); */ #ifdef NOT_THIS { SV *vba; while(vba = av_pop(varbinds)) { av_undef((AV *) vba); } } av_undef(varbinds); #endif free(tmparray); /* Not needed because of the G_DISCARD flag (I think) */ /* SPAGAIN; */ /* PUTBACK; */ #ifndef __x86_64__ FREETMPS; /* FIXME: known to cause a segfault on x86-64 */ #endif LEAVE; return NETSNMPTRAPD_HANDLER_OK; }
/* * Trap handler for invoking a suitable script */ int command_handler( netsnmp_pdu *pdu, netsnmp_transport *transport, netsnmp_trapd_handler *handler) { #ifndef USING_UTILITIES_EXECUTE_MODULE NETSNMP_LOGONCE((LOG_WARNING, "support for run_shell_command not available\n")); return NETSNMPTRAPD_HANDLER_FAIL; #else u_char *rbuf = NULL; size_t r_len = 64, o_len = 0; int oldquick; DEBUGMSGTL(( "snmptrapd", "command_handler\n")); DEBUGMSGTL(( "snmptrapd", "token = '%s'\n", handler->token)); if (handler && handler->token && *handler->token) { netsnmp_pdu *v2_pdu = NULL; if (pdu->command == SNMP_MSG_TRAP) v2_pdu = convert_v1pdu_to_v2(pdu); else v2_pdu = pdu; oldquick = snmp_get_quick_print(); snmp_set_quick_print(1); /* * Format the trap and pass this string to the external command */ if ((rbuf = (u_char *) calloc(r_len, 1)) == NULL) { snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n"); return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */ } /* * If there's a format string registered for this trap, then use it. * Otherwise use the standard execution format setting. */ if (handler && handler->format && *handler->format) { DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format)); realloc_format_trap(&rbuf, &r_len, &o_len, 1, handler->format, v2_pdu, transport); } else { if ( pdu->command == SNMP_MSG_TRAP && exec_format1 ) { DEBUGMSGTL(( "snmptrapd", "exec v1 = '%s'\n", exec_format1)); realloc_format_trap(&rbuf, &r_len, &o_len, 1, exec_format1, pdu, transport); } else if ( pdu->command != SNMP_MSG_TRAP && exec_format2 ) { DEBUGMSGTL(( "snmptrapd", "exec v2/3 = '%s'\n", exec_format2)); realloc_format_trap(&rbuf, &r_len, &o_len, 1, exec_format2, pdu, transport); } else { DEBUGMSGTL(( "snmptrapd", "execute format\n")); realloc_format_trap(&rbuf, &r_len, &o_len, 1, EXECUTE_FORMAT, v2_pdu, transport); } } /* * and pass this formatted string to the command specified */ run_shell_command(handler->token, (char*)rbuf, NULL, NULL); /* Not interested in output */ snmp_set_quick_print(oldquick); if (pdu->command == SNMP_MSG_TRAP) snmp_free_pdu(v2_pdu); free(rbuf); } return NETSNMPTRAPD_HANDLER_OK; #endif /* !def USING_UTILITIES_EXECUTE_MODULE */ }