Example #1
0
/*
 * check a session validity for connectivity to the master agent.  If
 * not functioning, close and start attempts to reopen the session
 */
void agentx_check_session (unsigned int clientreg, void *clientarg)
{
    netsnmp_session *ss = (netsnmp_session *) clientarg;

    if (!ss)
    {
        if (clientreg)
            snmp_alarm_unregister (clientreg);
        return;
    }
    DEBUGMSGTL (("agentx/subagent", "checking status of session %p\n", ss));

    if (!agentx_send_ping (ss))
    {
        snmp_log (LOG_WARNING, "AgentX master agent failed to respond to ping.  Attempting to re-register.\n");
        /*
         * master agent disappeared?  Try and re-register.
         * close first, just to be sure .
         */
        agentx_unregister_callbacks (ss);
        agentx_close_session (ss, AGENTX_CLOSE_TIMEOUT);
        snmp_alarm_unregister (clientreg);    /* delete ping alarm timer */
        snmp_call_callbacks (SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_INDEX_STOP, (void *) ss);
        register_mib_detach ();
        if (main_session != NULL)
        {
            remove_trap_session (ss);
            snmp_close (main_session);
            /*
             * We need to remove the callbacks attached to the callback
             * session because they have a magic callback data structure
             * which includes a pointer to the main session
             *    (which is no longer valid).
             *
             * Given that the main session is not responsive anyway.
             * it shoudn't matter if we lose some outstanding requests.
             */
            if (agentx_callback_sess != NULL)
            {
                snmp_close (agentx_callback_sess);
                agentx_callback_sess = NULL;

                subagent_init_callback_session ();
            }
            main_session = NULL;
            agentx_reopen_session (0, NULL);
        }
        else
        {
            snmp_close (main_session);
            main_session = NULL;
        }
    }
    else
    {
        DEBUGMSGTL (("agentx/subagent", "session %p responded to ping\n", ss));
    }
}
static int
subagent_shutdown(int majorID, int minorID, void *serverarg, void *clientarg)
{
    netsnmp_session *thesession = (netsnmp_session *)clientarg;
    DEBUGMSGTL(("agentx/subagent", "shutting down session....\n"));
    if (thesession == NULL) {
	DEBUGMSGTL(("agentx/subagent", "Empty session to shutdown\n"));
	main_session = NULL;
	return 0;
    }
    agentx_close_session(thesession, AGENTX_CLOSE_SHUTDOWN);
    snmp_close(thesession);
    if (main_session != NULL) {
        remove_trap_session(main_session);
        main_session = NULL;
    }
    DEBUGMSGTL(("agentx/subagent", "shut down finished.\n"));

    subagent_init_init = 0;
    return 1;
}
/*
 * check a session validity for connectivity to the master agent.  If
 * not functioning, close and start attempts to reopen the session 
 */
void
agentx_check_session(unsigned int clientreg, void *clientarg)
{
    netsnmp_session *ss = (netsnmp_session *) clientarg;
    if (!ss) {
        if (clientreg)
            snmp_alarm_unregister(clientreg);
        return;
    }
    DEBUGMSGTL(("agentx/subagent", "checking status of session %p\n", ss));

    if (!agentx_send_ping(ss)) {
        snmp_log(LOG_WARNING,
                 "AgentX master agent failed to respond to ping.  Attempting to re-register.\n");
        /*
         * master agent disappeared?  Try and re-register.
         * close first, just to be sure .
         */
        agentx_unregister_callbacks(ss);
        agentx_close_session(ss, AGENTX_CLOSE_TIMEOUT);
        snmp_alarm_unregister(clientreg);       /* delete ping alarm timer */
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
                            SNMPD_CALLBACK_INDEX_STOP, (void *) ss);
        register_mib_detach();
        if (main_session != NULL) {
            remove_trap_session(ss);
        snmp_close(main_session);
        main_session = NULL;
        agentx_reopen_session(0, NULL);
        }
        else {
            snmp_close(main_session);
            main_session = NULL;
        }
    } else {
        DEBUGMSGTL(("agentx/subagent", "session %p responded to ping\n",
                    ss));
    }
}
int
handle_agentx_packet(int operation, netsnmp_session * session, int reqid,
                     netsnmp_pdu *pdu, void *magic)
{
    struct agent_netsnmp_set_info *asi = NULL;
    snmp_callback   mycallback;
    netsnmp_pdu    *internal_pdu = NULL;
    void           *retmagic = NULL;
    ns_subagent_magic *smagic = NULL;

    if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
        struct synch_state *state = (struct synch_state *) magic;
        int             period =
            netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
                               NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL);
        DEBUGMSGTL(("agentx/subagent",
                    "transport disconnect indication\n"));

        /*
         * deal with existing session. This happend if agentx sends
         * a message to the master, but the master goes away before
         * a response is sent. agentx will spin in snmp_synch_response_cb,
         * waiting for a response. At the very least, the waiting
         * flag must be set to break that loop. The rest is copied
         * from disconnect handling in snmp_sync_input.
         */
        if(state) {
            state->waiting = 0;
            state->pdu = NULL;
            state->status = STAT_ERROR;
            session->s_snmp_errno = SNMPERR_ABORT;
            SET_SNMP_ERROR(SNMPERR_ABORT);
        }

        /*
         * Deregister the ping alarm, if any, and invalidate all other
         * references to this session.  
         */
        if (session->securityModel != SNMP_DEFAULT_SECMODEL) {
            snmp_alarm_unregister(session->securityModel);
        }
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
                            SNMPD_CALLBACK_INDEX_STOP, (void *) session);
        agentx_unregister_callbacks(session);
        remove_trap_session(session);
        register_mib_detach();
        main_session = NULL;
        if (period != 0) {
            /*
             * Pings are enabled, so periodically attempt to re-establish contact 
             * with the master agent.  Don't worry about the handle,
             * agentx_reopen_session unregisters itself if it succeeds in talking 
             * to the master agent.  
             */
            snmp_alarm_register(period, SA_REPEAT, agentx_reopen_session,
                                NULL);
        }
        return 0;
    } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
        DEBUGMSGTL(("agentx/subagent", "unexpected callback op %d\n",
                    operation));
        return 1;
    }

    /*
     * ok, we have a pdu from the net. Modify as needed 
     */

    DEBUGMSGTL(("agentx/subagent", "handling agentx request (req=0x%x,trans="
                "0x%x,sess=0x%x)\n", pdu->reqid,pdu->transid, pdu->sessid));
    pdu->version = AGENTX_VERSION_1;
    pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW;

    if (pdu->command == AGENTX_MSG_GET
        || pdu->command == AGENTX_MSG_GETNEXT
        || pdu->command == AGENTX_MSG_GETBULK) {
        smagic =
            (ns_subagent_magic *) calloc(1, sizeof(ns_subagent_magic));
        if (smagic == NULL) {
            DEBUGMSGTL(("agentx/subagent", "couldn't malloc() smagic\n"));
            return 1;
        }
        smagic->original_command = pdu->command;
        smagic->session = session;
        smagic->ovars = NULL;
        retmagic = (void *) smagic;
    }

    switch (pdu->command) {
    case AGENTX_MSG_GET:
        DEBUGMSGTL(("agentx/subagent", "  -> get\n"));
        pdu->command = SNMP_MSG_GET;
        mycallback = handle_subagent_response;
        break;

    case AGENTX_MSG_GETNEXT:
        DEBUGMSGTL(("agentx/subagent", "  -> getnext\n"));
        pdu->command = SNMP_MSG_GETNEXT;

        /*
         * We have to save a copy of the original variable list here because
         * if the master agent has requested scoping for some of the varbinds
         * that information is stored there.  
         */

        smagic->ovars = snmp_clone_varbind(pdu->variables);
        DEBUGMSGTL(("agentx/subagent", "saved variables\n"));
        mycallback = handle_subagent_response;
        break;

    case AGENTX_MSG_GETBULK:
        /*
         * WWWXXX 
         */
        DEBUGMSGTL(("agentx/subagent", "  -> getbulk\n"));
        pdu->command = SNMP_MSG_GETBULK;

        /*
         * We have to save a copy of the original variable list here because
         * if the master agent has requested scoping for some of the varbinds
         * that information is stored there.  
         */

        smagic->ovars = snmp_clone_varbind(pdu->variables);
        DEBUGMSGTL(("agentx/subagent", "saved variables at %p\n",
                    smagic->ovars));
        mycallback = handle_subagent_response;
        break;

    case AGENTX_MSG_RESPONSE:
        SNMP_FREE(smagic);
        DEBUGMSGTL(("agentx/subagent", "  -> response\n"));
        return 1;

    case AGENTX_MSG_TESTSET:
        /*
         * XXXWWW we have to map this twice to both RESERVE1 and RESERVE2 
         */
        DEBUGMSGTL(("agentx/subagent", "  -> testset\n"));
        asi = save_set_vars(session, pdu);
        if (asi == NULL) {
            SNMP_FREE(smagic);
            snmp_log(LOG_WARNING, "save_set_vars() failed\n");
            return 1;
        }
        asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_RESERVE1;
        mycallback = handle_subagent_set_response;
        retmagic = asi;
        break;

    case AGENTX_MSG_COMMITSET:
        DEBUGMSGTL(("agentx/subagent", "  -> commitset\n"));
        asi = restore_set_vars(session, pdu);
        if (asi == NULL) {
            SNMP_FREE(smagic);
            snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
            return 1;
        }
        if (asi->mode != SNMP_MSG_INTERNAL_SET_RESERVE2) {
            SNMP_FREE(smagic);
            snmp_log(LOG_WARNING,
                     "dropping bad AgentX request (wrong mode %d)\n",
                     asi->mode);
            return 1;
        }
        asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_ACTION;
        mycallback = handle_subagent_set_response;
        retmagic = asi;
        break;

    case AGENTX_MSG_CLEANUPSET:
        DEBUGMSGTL(("agentx/subagent", "  -> cleanupset\n"));
        asi = restore_set_vars(session, pdu);
        if (asi == NULL) {
            SNMP_FREE(smagic);
            snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
            return 1;
        }
        if (asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE1 ||
            asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE2) {
            asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_FREE;
        } else if (asi->mode == SNMP_MSG_INTERNAL_SET_ACTION) {
            asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_COMMIT;
        } else {
            snmp_log(LOG_WARNING,
                     "dropping bad AgentX request (wrong mode %d)\n",
                     asi->mode);
            SNMP_FREE(retmagic);
            return 1;
        }
        mycallback = handle_subagent_set_response;
        retmagic = asi;
        break;

    case AGENTX_MSG_UNDOSET:
        DEBUGMSGTL(("agentx/subagent", "  -> undoset\n"));
        asi = restore_set_vars(session, pdu);
        if (asi == NULL) {
            SNMP_FREE(smagic);
            snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
            return 1;
        }
        asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_UNDO;
        mycallback = handle_subagent_set_response;
        retmagic = asi;
        break;

    default:
        SNMP_FREE(smagic);
        DEBUGMSGTL(("agentx/subagent", "  -> unknown command %d (%02x)\n",
                    pdu->command, pdu->command));
        return 0;
    }

    /*
     * submit the pdu to the internal handler 
     */

    /*
     * We have to clone the PDU here, because when we return from this
     * callback, sess_process_packet will free(pdu), but this call also
     * free()s its argument PDU.  
     */

    internal_pdu = snmp_clone_pdu(pdu);
    internal_pdu->contextName = internal_pdu->community;
    internal_pdu->contextNameLen = internal_pdu->community_len;
    internal_pdu->community = NULL;
    internal_pdu->community_len = 0;
    snmp_async_send(agentx_callback_sess, internal_pdu, mycallback,
                    retmagic);
    return 1;
}