/**
 * 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;
}
Beispiel #2
0
/**
 * 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 */
}