/* * save varbind info from incoming trap * * return 0 on success, anything else is an error */ static int _sql_save_varbind_info(sql_buf *sqlb, netsnmp_pdu *pdu) { netsnmp_variable_list *var; sql_vb_buf *sqlvb; size_t tmp_size, buf_oid_len_t; int oid_overflow, rc; #ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT size_t buf_val_len_t; #endif if ((NULL == sqlb) || (NULL == pdu)) return -1; var = pdu->variables; while(var) { sqlvb = SNMP_MALLOC_TYPEDEF(sql_vb_buf); if (NULL == sqlvb) break; /** OID */ tmp_size = 0; buf_oid_len_t = oid_overflow = 0; netsnmp_sprint_realloc_objid_tree((u_char**)&sqlvb->oid, &tmp_size, &buf_oid_len_t, 1, &oid_overflow, var->name, var->name_length); sqlvb->oid_len = buf_oid_len_t; if (oid_overflow) snmp_log(LOG_WARNING,"OID truncated in sql insert\n"); /** type */ if (var->type > ASN_OBJECT_ID) /** convert application types to sql enum */ sqlvb->type = ASN_OBJECT_ID + 1 + (var->type & ~ASN_APPLICATION); else sqlvb->type = var->type; /** value */ #ifdef NETSNMP_MYSQL_TRAP_VALUE_TEXT tmp_size = 0; buf_val_len_t = 0; sprint_realloc_by_type((u_char**)&sqlvb->val, &tmp_size, &buf_val_len_t, 1, var, 0, 0, 0); sqlvb->val_len = buf_val_len_t; #else memdup(&sqlvb->val, var->val.string, var->val_len); sqlvb->val_len = var->val_len; #endif var = var->next_variable; /** insert into container */ rc = CONTAINER_INSERT(sqlb->varbinds,sqlvb); if(rc) snmp_log(LOG_ERR, "couldn't insert varbind into trap container\n"); } 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; }