Esempio n. 1
0
/*
 * send_trap_to_sess: sends a trap to a session but assumes that the
 * pdu is constructed correctly for the session type. 
 */
void
send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
{
    netsnmp_pdu    *pdu;

    if (!sess || !template_pdu)
        return;

    DEBUGMSGTL(("trap", "sending trap type=%d, version=%d\n",
                template_pdu->command, sess->version));

    if (sess->version == SNMP_VERSION_1 &&
        (template_pdu->command == SNMP_MSG_TRAP2 ||
         template_pdu->command == SNMP_MSG_INFORM))
        return;                 /* Skip v1 sinks for v2 only traps */
    template_pdu->version = sess->version;
    pdu = snmp_clone_pdu(template_pdu);
    pdu->sessid = sess->sessid; /* AgentX only ? */
    if (snmp_send(sess, pdu) == 0) {
        snmp_sess_perror("snmpd: send_trap", sess);
        snmp_free_pdu(pdu);
    } else {
        snmp_increment_statistic(STAT_SNMPOUTTRAPS);
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
    }
}
Esempio n. 2
0
void
send_trap_pdu(struct snmp_pdu *pdu)
{
  struct snmp_pdu *mypdu;
  
  struct trap_sink *sink = sinks;

  if ((snmp_enableauthentraps == 1) && sink != NULL) {
    DEBUGMSGTL(("snmpd", "sending v2 trap pdu...\n"));
    while (sink) {
      if (sink->ses.version == SNMP_VERSION_2c) {
        DEBUGMSGTL(("snmpd", " found v2 session...\n"));
        mypdu = snmp_clone_pdu(pdu);
        if (snmp_send(sink->sesp, mypdu) == 0) {
          snmp_perror ("snmpd: send_trap_pdu");
        }
#ifdef USING_MIBII_SNMP_MIB_MODULE       
        snmp_outtraps++;
#endif
      }
      sink = sink->next;
    }
    DEBUGMSGTL(("snmpd", "  done\n"));
  }
}
Esempio n. 3
0
v8::Handle<v8::Value> Session::sendNativePdu(const v8::Arguments& args) {
    UNWRAP(Session, wrap, args.This());
    SwapScope scope(wrap, args);
    if(0 == wrap->session_) {
        return ThrowError("Session hasn't opened.");
    }

    if(2 != args.Length()) {
        return ThrowError("Must pass pdu and cb arguments to sendNativePdu.");
    }

    v8::Handle<v8::Object> cb = args[1]->ToObject();
    if (!cb->IsCallable()) {
        return ThrowError("Must pass pdu and cb arguments to sendNativePdu.");
    }

    UNWRAP(Pdu, pdu, args[0]->ToObject());

	std::auto_ptr<netsnmp_pdu> copy(pdu->is_owner()? pdu->release() : snmp_clone_pdu(pdu->native()));
    std::auto_ptr<Callable> callable(new Callable(cb, args[0], copy.get()));
    if(0 == snmp_sess_async_send(wrap->session_, copy.get(),
                                 Callable::OnEvent, callable.get())) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }
    callable.release();
    copy.release();

    if(scope.hasException()) {
        return scope.getException();
    }
    return v8::Undefined();
}
/*
 * send_trap_to_sess: sends a trap to a session but assumes that the
 * pdu is constructed correctly for the session type. 
 */
void
send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
{
    netsnmp_pdu    *pdu;
    int            result;
    int            len;


    if (!sess || !template_pdu)
        return;

    DEBUGMSGTL(("trap", "sending trap type=%d, version=%ld\n",
                template_pdu->command, sess->version));

#ifndef NETSNMP_DISABLE_SNMPV1
    if (sess->version == SNMP_VERSION_1 &&
        (template_pdu->command != SNMP_MSG_TRAP))
        return;                 /* Skip v1 sinks for v2 only traps */
    if (sess->version != SNMP_VERSION_1 &&
        (template_pdu->command == SNMP_MSG_TRAP))
        return;                 /* Skip v2+ sinks for v1 only traps */
#endif
    template_pdu->version = sess->version;
    pdu = snmp_clone_pdu(template_pdu);
    pdu->sessid = sess->sessid; /* AgentX only ? */

    if ( template_pdu->command == SNMP_MSG_INFORM
#ifdef USING_AGENTX_PROTOCOL_MODULE
         || template_pdu->command == AGENTX_MSG_NOTIFY
#endif
       ) {
        result =
            snmp_async_send(sess, pdu, &handle_inform_response, NULL);
        
    } else {
        if ((sess->version == SNMP_VERSION_3) &&
                (pdu->command == SNMP_MSG_TRAP2) &&
                (sess->securityEngineIDLen == 0)) {
            u_char          tmp[SPRINT_MAX_LEN];

            len = snmpv3_get_engineID(tmp, sizeof(tmp));
            memdup(&pdu->securityEngineID, tmp, len);
            pdu->securityEngineIDLen = len;
        }

        result = snmp_send(sess, pdu);
    }

    if (result == 0) {
        snmp_sess_perror("snmpd: send_trap", sess);
        snmp_free_pdu(pdu);
    } else {
        snmp_increment_statistic(STAT_SNMPOUTTRAPS);
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
    }
}
int
handle_subagent_set_response(int op, netsnmp_session * session, int reqid,
                             netsnmp_pdu *pdu, void *magic)
{
    netsnmp_session *retsess;
    struct agent_netsnmp_set_info *asi;

    if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE || magic == NULL) {
        return 1;
    }

    DEBUGMSGTL(("agentx/subagent",
                "handling agentx subagent set response (mode=%d,req=0x%x,"
                "trans=0x%x,sess=0x%x)\n",
                pdu->command, pdu->reqid,pdu->transid, pdu->sessid));
    pdu = snmp_clone_pdu(pdu);

    asi = (struct agent_netsnmp_set_info *) magic;
    retsess = asi->sess;
    asi->errstat = pdu->errstat;

    if (asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE1) {
        /*
         * reloop for RESERVE2 mode, an internal only agent mode 
         */
        /*
         * XXX: check exception statuses of reserve1 first 
         */
        if (!pdu->errstat) {
            asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_RESERVE2;
            snmp_async_send(agentx_callback_sess, pdu,
                            handle_subagent_set_response, asi);
            DEBUGMSGTL(("agentx/subagent",
                        "  going from RESERVE1 -> RESERVE2\n"));
            return 1;
        }
    } else {
        if (asi->mode == SNMP_MSG_INTERNAL_SET_FREE ||
            asi->mode == SNMP_MSG_INTERNAL_SET_UNDO ||
            asi->mode == SNMP_MSG_INTERNAL_SET_COMMIT) {
            free_set_vars(retsess, pdu);
        }
        snmp_free_varbind(pdu->variables);
        pdu->variables = NULL;  /* the variables were added by us */
    }

    netsnmp_assert(retsess != NULL);
    pdu->command = AGENTX_MSG_RESPONSE;
    pdu->version = retsess->version;

    if (!snmp_send(retsess, pdu)) {
        snmp_free_pdu(pdu);
    }
    DEBUGMSGTL(("agentx/subagent", "  FINISHED\n"));
    return 1;
}
Esempio n. 6
0
u_char         *
cmu_snmp_parse(netsnmp_session * session,
               netsnmp_pdu *pdu, u_char * data, size_t length)
{
    u_char         *bufp = NULL;

    snmp_sess_init(session);    /* gimme a break! */

    switch (pdu->version) {
    case SNMP_VERSION_1:
    case SNMP_VERSION_2c:
    case SNMP_DEFAULT_VERSION:
        break;
    default:
        return NULL;
    }
#ifndef NO_INTERNAL_VARLIST
    if (snmp_parse(0, session, pdu, data, length) != SNMP_ERR_NOERROR) {
        return NULL;
    }
#else
    /*
     * while there are two versions of variable_list:
     * use an internal variable list for snmp_parse;
     * clone the result.
     */
    if (1) {
        netsnmp_pdu    *snmp_clone_pdu(netsnmp_pdu *);
        netsnmp_pdu    *snmp_2clone_pdu(netsnmp_pdu *from_pdu,
                                        netsnmp_pdu *to_pdu);

        netsnmp_pdu    *ipdu;
        ipdu = snmp_clone_pdu(pdu);
        if (snmp_parse(0, session, ipdu, data, length) != SNMP_ERR_NOERROR) {
            snmp_free_internal_pdu(ipdu);
            return NULL;
        }
        pdu = snmp_2clone_pdu(ipdu, pdu);
        snmp_free_internal_pdu(ipdu);
    }
#endif                          /* NO_INTERNAL_VAR_LIST */

    /*
     * Add a null to meet the caller's expectations. 
     */

    bufp = (u_char *) malloc(1 + pdu->community_len);
    if (bufp && pdu->community_len) {
        memcpy(bufp, pdu->community, pdu->community_len);
        bufp[pdu->community_len] = '\0';
    }
    return (bufp);
}
Esempio n. 7
0
static void
NotifyingEntry(UNUSED tState self)
{
    netsnmp_pdu* act = snmp_clone_pdu(pdu);
    if(act) {
        act->sessid = session;
        act->transid = 0;
        act->reqid = ++packetid;
        if(snmp_sess_send(sessp, act) == 0)
            snmp_free_pdu(act);
    }
}
Esempio n. 8
0
static void send_agentx_error (netsnmp_session * session, netsnmp_pdu * pdu, int errstat, int errindex)
{
    pdu = snmp_clone_pdu (pdu);
    pdu->command = AGENTX_MSG_RESPONSE;
    pdu->version = session->version;
    pdu->errstat = errstat;
    pdu->errindex = errindex;
    snmp_free_varbind (pdu->variables);
    pdu->variables = NULL;

    DEBUGMSGTL (("agentx/subagent", "Sending AgentX response error stat %d idx %d\n", errstat, errindex));
    if (!snmp_send (session, pdu))
    {
        snmp_free_pdu (pdu);
    }
}
Esempio n. 9
0
void mux_poller::poll()
{
   static const char *funcname {"snmp::mux_poller::poll"};
   if (0 == tasks.size()) return;

   int fds, block;
   fd_set fdset;
   timeval timeout;
   taskdata::iterator it = tasks.begin();

   for (unsigned active_hosts;;)
   {
      active_hosts = sessions.size();
      if (active_hosts < max_hosts)
      {
         if (0 == active_hosts and it == tasks.end()) return;
         unsigned delta = max_hosts - active_hosts;
         void *sessp;

         for (unsigned i = 0; it != tasks.end() and i < delta; ++i, ++it)
         {
            polltask &task = it->second;
            sessp = init_snmp_session(it->first.c_str(), task.community.c_str(),
                  task.version, callback_wrap, static_cast<void *>(&task));

            sessions.emplace_front(sessp);
            task.pdata = &(sessions.front());

            try { async_send(sessp, snmp_clone_pdu(task.request)); }
            catch (snmprun_error &error) { 
               throw snmprun_error {errtype::runtime, funcname, "poll failed: %s", error.what()}; }
         }
      }

      fds = block = 0;
      FD_ZERO(&fdset);
      
      for (auto &sess : sessions) snmp_sess_select_info(sess.sessp, &fds, &fdset, &timeout, &block);
      if (0 > (fds = select(fds, &fdset, nullptr, nullptr, &timeout)))
         throw snmprun_error {errtype::runtime, funcname, "select() failed: %s", strerror(errno)};

      if (fds) { for (auto &sess : sessions) snmp_sess_read(sess.sessp, &fdset); }
      else     { for (auto &sess : sessions) snmp_sess_timeout(sess.sessp);      }

      sessions.remove_if([](const polldata &p) { return (pollstate::finished == p.state); });
   }
}
Esempio n. 10
0
static int
snmp_synch_input(int op,
                 netsnmp_session * session,
                 int reqid, netsnmp_pdu *pdu, void *magic)
{
    struct synch_state *state = (struct synch_state *) magic;
    int             rpt_type;

    if (reqid != state->reqid && pdu && pdu->command != SNMP_MSG_REPORT) {
        return 0;
    }

    state->waiting = 0;

    if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
        if (pdu->command == SNMP_MSG_REPORT) {
            rpt_type = snmpv3_get_report_type(pdu);
            if (SNMPV3_IGNORE_UNAUTH_REPORTS ||
                rpt_type == SNMPERR_NOT_IN_TIME_WINDOW) {
                state->waiting = 1;
            }
            state->pdu = NULL;
            state->status = STAT_ERROR;
            session->s_snmp_errno = rpt_type;
            SET_SNMP_ERROR(rpt_type);
        } else if (pdu->command == SNMP_MSG_RESPONSE) {
            /*
             * clone the pdu to return to snmp_synch_response 
             */
            state->pdu = snmp_clone_pdu(pdu);
            state->status = STAT_SUCCESS;
            session->s_snmp_errno = SNMPERR_SUCCESS;
        }
    } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
        state->pdu = NULL;
        state->status = STAT_TIMEOUT;
        session->s_snmp_errno = SNMPERR_TIMEOUT;
        SET_SNMP_ERROR(SNMPERR_TIMEOUT);
    } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) {
        state->pdu = NULL;
        state->status = STAT_ERROR;
        session->s_snmp_errno = SNMPERR_ABORT;
        SET_SNMP_ERROR(SNMPERR_ABORT);
    }

    return 1;
}
int
agentx_synch_input(int op,
                   netsnmp_session * session,
                   int reqid, netsnmp_pdu *pdu, void *magic)
{
    struct synch_state *state = (struct synch_state *) magic;
    struct timeval  now, diff;

    if (reqid != state->reqid) {
        return handle_agentx_packet(op, session, reqid, pdu, magic);
    }

    DEBUGMSGTL(("agentx/subagent", "synching input, op 0x%02x\n", op));
    state->waiting = 0;
    if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
        if (pdu->command == AGENTX_MSG_RESPONSE) {
            state->pdu = snmp_clone_pdu(pdu);
            state->status = STAT_SUCCESS;
            session->s_snmp_errno = SNMPERR_SUCCESS;

            /*
             * Synchronise sysUpTime with the master agent
             */
            gettimeofday(&now, NULL);
            now.tv_sec--;
            now.tv_usec += 1000000L;
            diff.tv_sec = pdu->time / 100;
            diff.tv_usec = (pdu->time - (diff.tv_sec * 100)) * 10000;
            starttime.tv_sec = now.tv_sec - diff.tv_sec;
            starttime.tv_usec = now.tv_usec - diff.tv_usec;
            if (starttime.tv_usec > 1000000L) {
                starttime.tv_usec -= 1000000L;
                starttime.tv_sec++;
            }
        }
    } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
        state->pdu = NULL;
        state->status = STAT_TIMEOUT;
        session->s_snmp_errno = SNMPERR_TIMEOUT;
    } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) {
        return handle_agentx_packet(op, session, reqid, pdu, magic);
    }

    return 1;
}
Esempio n. 12
0
/*
 * send_trap_to_sess: sends a trap to a session but assumes that the
 * pdu is constructed correctly for the session type. 
 */
void
send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
{
    netsnmp_pdu    *pdu;
    int            result;

    if (!sess || !template_pdu)
        return;

    DEBUGMSGTL(("trap", "sending trap type=%d, version=%d\n",
                template_pdu->command, sess->version));

#ifndef DISABLE_SNMPV1
    if (sess->version == SNMP_VERSION_1 &&
        (template_pdu->command != SNMP_MSG_TRAP))
        return;                 /* Skip v1 sinks for v2 only traps */
#endif
    template_pdu->version = sess->version;
    pdu = snmp_clone_pdu(template_pdu);
    pdu->sessid = sess->sessid; /* AgentX only ? */

    if ( template_pdu->command == SNMP_MSG_INFORM
#ifdef USING_AGENTX_PROTOCOL_MODULE
         || template_pdu->command == AGENTX_MSG_NOTIFY
#endif
       ) {
        result =
            snmp_async_send(sess, pdu, &handle_inform_response, NULL);
        
    } else {
        result = snmp_send(sess, pdu);
    }

    if (result == 0) {
        snmp_sess_perror("snmpd: send_trap", sess);
        snmp_free_pdu(pdu);
    } else {
        snmp_increment_statistic(STAT_SNMPOUTTRAPS);
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
    }
}
Esempio n. 13
0
/*
 *  Trap handler for forwarding to another destination
 */
int   forward_handler( netsnmp_pdu           *pdu,
                       netsnmp_transport     *transport,
                       netsnmp_trapd_handler *handler)
{
    netsnmp_session session, *ss;
    netsnmp_pdu *pdu2;
    char buf[BUFSIZ], *cp;

    DEBUGMSGTL(( "snmptrapd", "forward_handler (%s)\n", handler->token));

    snmp_sess_init( &session );
    if (strchr( handler->token, ':') == NULL) {
        snprintf( buf, BUFSIZ, "%s:%d", handler->token, SNMP_TRAP_PORT);
        cp = buf;
    } else {
        cp = handler->token;
    }
    session.peername = cp;
    session.version  = pdu->version;
    ss = snmp_open( &session );
    if (!ss)
        return NETSNMPTRAPD_HANDLER_FAIL;

    /* XXX: wjh we should be caching sessions here and not always
       reopening a session.  It's very ineffecient, especially with v3
       INFORMS which may require engineID probing */

    pdu2 = snmp_clone_pdu(pdu);
    if (pdu2->transport_data) {
        free(pdu2->transport_data);
        pdu2->transport_data        = NULL;
        pdu2->transport_data_length = 0;
    }
    if (!snmp_send( ss, pdu2 )) {
	snmp_sess_perror("Forward failed", ss);
	snmp_free_pdu(pdu2);
    }
    snmp_close( ss );
    return NETSNMPTRAPD_HANDLER_OK;
}
Esempio n. 14
0
int
handle_next_pass(struct agent_snmp_session  *asp)
{
    int status;
    struct snmp_pdu *pdu = asp->pdu;
    struct request_list *req_p, *next_req;


        if ( asp->outstanding_requests != NULL )
	    return SNMP_ERR_NOERROR;
	status = handle_var_list( asp );
        if ( asp->outstanding_requests != NULL ) {
	    if ( status == SNMP_ERR_NOERROR ) {
		/* Send out any subagent requests */
		for ( req_p = asp->outstanding_requests ;
			req_p != NULL ; req_p = req_p->next_request ) {

		    snmp_async_send( req_p->session,  req_p->pdu,
				      req_p->callback, req_p->cb_data );
		}
		asp->pdu = snmp_clone_pdu( pdu );
		asp->pdu->variables = pdu->variables;
		pdu->variables = NULL;
	    }
	    else {
	    	/* discard outstanding requests */
		for ( req_p = asp->outstanding_requests ;
			req_p != NULL ; req_p = next_req ) {
			
			next_req = req_p->next_request;
			free( req_p );
		}
		asp->outstanding_requests = NULL;
	    }
	}
	return status;
}
Esempio n. 15
0
int
handle_snmp_packet(int operation, struct snmp_session *session, int reqid,
                   struct snmp_pdu *pdu, void *magic)
{
    struct agent_snmp_session  *asp;
    int status, allDone, i;
    struct variable_list *var_ptr, *var_ptr2;

    if ( magic == NULL ) {
	asp = init_agent_snmp_session( session, snmp_clone_pdu(pdu) );
	status = SNMP_ERR_NOERROR;
    }
    else {
	asp = (struct agent_snmp_session *)magic;
        status =   asp->status;
    }

    if (asp->outstanding_requests != NULL)
	return 1;

    if ( check_access(pdu) != 0) {
        /* access control setup is incorrect */
	send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
        if (asp->pdu->version != SNMP_VERSION_1 && asp->pdu->version != SNMP_VERSION_2c) {
            asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
            asp->pdu->command = SNMP_MSG_RESPONSE;
            snmp_increment_statistic(STAT_SNMPOUTPKTS);
            snmp_send( asp->session, asp->pdu );
            free( asp );
            return 1;
        } else {
            /* drop the request */
            free( asp );
            return 0;
        }
    }

    switch (pdu->command) {
    case SNMP_MSG_GET:
	if ( asp->mode != RESERVE1 )
	    break;			/* Single pass */
        snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
	status = handle_next_pass( asp );
	asp->mode = RESERVE2;
	break;

    case SNMP_MSG_GETNEXT:
	if ( asp->mode != RESERVE1 )
	    break;			/* Single pass */
        snmp_increment_statistic(STAT_SNMPINGETNEXTS);
	asp->exact   = FALSE;
	status = handle_next_pass( asp );
	asp->mode = RESERVE2;
	break;

    case SNMP_MSG_GETBULK:
	    /*
	     * GETBULKS require multiple passes. The first pass handles the
	     * explicitly requested varbinds, and subsequent passes append
	     * to the existing var_op_list.  Each pass (after the first)
	     * uses the results of the preceeding pass as the input list
	     * (delimited by the start & end pointers.
	     * Processing is terminated if all entries in a pass are
	     * EndOfMib, or the maximum number of repetitions are made.
	     */
	if ( asp->mode == RESERVE1 ) {
            snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
	    asp->exact   = FALSE;
		    /*
		     * Limit max repetitions to something reasonable
		     *	XXX: We should figure out what will fit somehow...
		     */
	    if ( asp->pdu->errindex > 100 )
	        asp->pdu->errindex = 100;
    
	    status = handle_next_pass( asp );	/* First pass */
	    asp->mode = RESERVE2;
	    if ( status != SNMP_ERR_NOERROR )
	        break;
    
	    while ( asp->pdu->errstat-- > 0 )	/* Skip non-repeaters */
	        asp->start = asp->start->next_variable;
	    asp->pdu->errindex--;           /* Handled first repetition */

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	while ( asp->pdu->errindex-- > 0 ) {	/* Process repeaters */
		/*
		 * Add new variable structures for the
		 * repeating elements, ready for the next pass.
		 * Also check that these are not all EndOfMib
		 */
	    allDone = TRUE;		/* Check for some content */
	    for ( var_ptr = asp->start;
		  var_ptr != asp->end->next_variable;
		  var_ptr = var_ptr->next_variable ) {
				/* XXX: we don't know the size of the next
					OID, so assume the maximum length */
		if ( var_ptr->type != SNMP_ENDOFMIBVIEW )
		{
		var_ptr2 = snmp_add_null_var(asp->pdu, var_ptr->name, MAX_OID_LEN);
		for ( i=var_ptr->name_length ; i<MAX_OID_LEN ; i++)
		    var_ptr2->name[i] = 0;
		var_ptr2->name_length = var_ptr->name_length;

		    allDone = FALSE;
		}
	    }
	    if ( allDone )
		break;

	    asp->start = asp->end->next_variable;
	    while ( asp->end->next_variable != NULL )
		asp->end = asp->end->next_variable;
	    
	    status = handle_next_pass( asp );
	    if ( status != SNMP_ERR_NOERROR )
		break;
	    if ( asp->outstanding_requests != NULL )
		return 1;
	}
	break;

    case SNMP_MSG_SET:
    	    /*
	     * SETS require 3-4 passes through the var_op_list.  The first two
	     * passes verify that all types, lengths, and values are valid
	     * and may reserve resources and the third does the set and a
	     * fourth executes any actions.  Then the identical GET RESPONSE
	     * packet is returned.
	     * If either of the first two passes returns an error, another
	     * pass is made so that any reserved resources can be freed.
	     * If the third pass returns an error, another pass is made so that
	     * any changes can be reversed.
	     * If the fourth pass (or any of the error handling passes)
	     * return an error, we'd rather not know about it!
	     */
	if ( asp->mode == RESERVE1 ) {
            snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
	    asp->rw      = WRITE;

	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = FREE;
	    else
	        asp->mode = RESERVE2;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == RESERVE2 ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = FREE;
	    else
	        asp->mode = ACTION;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == ACTION ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = UNDO;
	    else
	        asp->mode = COMMIT;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == COMMIT ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR ) {
		status    = SNMP_ERR_COMMITFAILED;
	        asp->mode = FINISHED_FAILURE;
	    }
	    else
	        asp->mode = FINISHED_SUCCESS;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == UNDO ) {
	    if (handle_next_pass( asp ) != SNMP_ERR_NOERROR )
		status = SNMP_ERR_UNDOFAILED;

	    asp->mode = FINISHED_FAILURE;
	    break;
	}

	if ( asp->mode == FREE ) {
	    (void) handle_next_pass( asp );
	    break;
	}

	break;

    case SNMP_MSG_RESPONSE:
        snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
	free( asp );
	return 0;
    case SNMP_MSG_TRAP:
    case SNMP_MSG_TRAP2:
        snmp_increment_statistic(STAT_SNMPINTRAPS);
	free( asp );
	return 0;
    default:
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
	free( asp );
	return 0;
    }

    if ( asp->outstanding_requests != NULL ) {
	asp->status = status;
	asp->next = agent_session_list;
	agent_session_list = asp;
    }
    else {
		/*
		 * May need to "dumb down" a SET error status for a
		 *  v1 query.  See RFC2576 - section 4.3
		 */
	if (( asp->pdu->command == SNMP_MSG_SET ) &&
	    ( asp->pdu->version == SNMP_VERSION_1 )) {
	    switch ( status ) {
		case SNMP_ERR_WRONGVALUE:
		case SNMP_ERR_WRONGENCODING:
		case SNMP_ERR_WRONGTYPE:
		case SNMP_ERR_WRONGLENGTH:
		case SNMP_ERR_INCONSISTENTVALUE:
			status = SNMP_ERR_BADVALUE;
			break;
		case SNMP_ERR_NOACCESS:
		case SNMP_ERR_NOTWRITABLE:
		case SNMP_ERR_NOCREATION:
		case SNMP_ERR_INCONSISTENTNAME:
		case SNMP_ERR_AUTHORIZATIONERROR:
			status = SNMP_ERR_NOSUCHNAME;
			break;
		case SNMP_ERR_RESOURCEUNAVAILABLE:
		case SNMP_ERR_COMMITFAILED:
		case SNMP_ERR_UNDOFAILED:
			status = SNMP_ERR_GENERR;
			break;
	    }
	}
		/*
		 * Similarly we may need to "dumb down" v2 exception
		 *  types to throw an error for a v1 query.
		 *  See RFC2576 - section 4.1.2.3
		 */
	if (( asp->pdu->command != SNMP_MSG_SET ) &&
	    ( asp->pdu->version == SNMP_VERSION_1 )) {
		for ( var_ptr = asp->pdu->variables, i=0 ;
			var_ptr != NULL ;
			var_ptr = var_ptr->next_variable, i++ ) {
		    switch ( var_ptr->type ) {
			case SNMP_NOSUCHOBJECT:
			case SNMP_NOSUCHINSTANCE:
			case SNMP_ENDOFMIBVIEW:
			case ASN_COUNTER64:
				status = SNMP_ERR_NOSUCHNAME;
				asp->pdu->errindex=i;
				break;
		    }
		}
	}
	if ( status == SNMP_ERR_NOERROR ) {
	    snmp_increment_statistic_by(
		(asp->pdu->command == SNMP_MSG_SET ?
			STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS ),
	    	count_varbinds( asp->pdu ));
	}
	else {
		/*
		 * Use a copy of the original request
		 *   to report failures.
		 */
	    i = asp->pdu->errindex;
	    snmp_free_pdu( asp->pdu );
	    asp->pdu = snmp_clone_pdu( pdu );
	    asp->pdu->errindex = i;
	}
	asp->pdu->command = SNMP_MSG_RESPONSE;
	asp->pdu->errstat = status;
	snmp_send( asp->session, asp->pdu );
	snmp_increment_statistic(STAT_SNMPOUTPKTS);
	snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
	free( asp );
    }

    return 1;
}
Esempio n. 16
0
int
handle_master_agentx_packet(int operation,
                            netsnmp_session * session,
                            int reqid, netsnmp_pdu *pdu, void *magic)
{
    netsnmp_agent_session *asp;

    if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
        DEBUGMSGTL(("agentx/master",
                    "transport disconnect on session %8p\n", session));
        /*
         * Shut this session down gracefully.  
         */
        close_agentx_session(session, -1);
        return 1;
    } else if (operation == NETSNMP_CALLBACK_OP_CONNECT) {
        DEBUGMSGTL(("agentx/master",
                    "transport connect on session %8p\n", session));
        return 1;
    } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
        DEBUGMSGTL(("agentx/master", "unexpected callback op %d\n",
                    operation));
        return 1;
    }

    /*
     * Okay, it's a NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE op.  
     */

    if (magic) {
        asp = (netsnmp_agent_session *) magic;
    } else {
        asp = init_agent_snmp_session(session, pdu);
    }

    DEBUGMSGTL(("agentx/master", "handle pdu (req=0x%lx,trans=0x%lx,sess=0x%lx)\n",
                (unsigned long)pdu->reqid, (unsigned long)pdu->transid,
		(unsigned long)pdu->sessid));
    
    switch (pdu->command) {
    case AGENTX_MSG_OPEN:
        asp->pdu->sessid = open_agentx_session(session, pdu);
        if (asp->pdu->sessid == -1)
            asp->status = session->s_snmp_errno;
        break;

    case AGENTX_MSG_CLOSE:
        asp->status = close_agentx_session(session, pdu->sessid);
        break;

    case AGENTX_MSG_REGISTER:
        asp->status = register_agentx_list(session, pdu);
        break;

    case AGENTX_MSG_UNREGISTER:
        asp->status = unregister_agentx_list(session, pdu);
        break;

    case AGENTX_MSG_INDEX_ALLOCATE:
        asp->status = allocate_idx_list(session, asp->pdu);
        if (asp->status != AGENTX_ERR_NOERROR) {
            snmp_free_pdu(asp->pdu);
            asp->pdu = snmp_clone_pdu(pdu);
        }
        break;

    case AGENTX_MSG_INDEX_DEALLOCATE:
        asp->status = release_idx_list(session, pdu);
        break;

    case AGENTX_MSG_ADD_AGENT_CAPS:
        asp->status = add_agent_caps_list(session, pdu);
        break;

    case AGENTX_MSG_REMOVE_AGENT_CAPS:
        asp->status = remove_agent_caps_list(session, pdu);
        break;

    case AGENTX_MSG_NOTIFY:
        asp->status = agentx_notify(session, pdu);
        break;

    case AGENTX_MSG_PING:
        asp->status = agentx_ping_response(session, pdu);
        break;

        /*
         * TODO: Other admin packets 
         */

    case AGENTX_MSG_GET:
    case AGENTX_MSG_GETNEXT:
    case AGENTX_MSG_GETBULK:
    case AGENTX_MSG_TESTSET:
    case AGENTX_MSG_COMMITSET:
    case AGENTX_MSG_UNDOSET:
    case AGENTX_MSG_CLEANUPSET:
    case AGENTX_MSG_RESPONSE:
        /*
         * Shouldn't be handled here 
         */
        break;

    default:
        asp->status = AGENTX_ERR_PARSE_FAILED;
        break;
    }

    asp->pdu->time = netsnmp_get_agent_uptime();
    asp->pdu->command = AGENTX_MSG_RESPONSE;
    asp->pdu->errstat = asp->status;
    DEBUGMSGTL(("agentx/master", "send response, stat %d (req=0x%lx,trans="
                "0x%lx,sess=0x%lx)\n",
                asp->status, (unsigned long)pdu->reqid,
		(unsigned long)pdu->transid, (unsigned long)pdu->sessid));
    if (!snmp_send(asp->session, asp->pdu)) {
        char           *eb = NULL;
        int             pe, pse;
        snmp_error(asp->session, &pe, &pse, &eb);
        snmp_free_pdu(asp->pdu);
        DEBUGMSGTL(("agentx/master", "FAILED %d %d %s\n", pe, pse, eb));
        free(eb);
    }
    asp->pdu = NULL;
    free_agent_snmp_session(asp);

    return 1;
}
Esempio n. 17
0
void send_enterprise_trap_vars (int trap, 
		     int specific,
		     oid *enterprise, int enterprise_length,
		     struct variable_list *vars)
{
    struct variable_list uptime_var, snmptrap_var, enterprise_var;
    struct variable_list *v2_vars, *last_var=NULL;
    struct snmp_pdu	*template_pdu, *pdu;
    struct timeval	 now;
    long uptime;
    struct sockaddr_in *pduIp;
    struct trap_sink *sink;
    oid temp_oid[MAX_OID_LEN];
    
		/*
		 * Initialise SNMPv2 required variables
		 */
    gettimeofday(&now, NULL);
    uptime = calculate_time_diff(&now, &starttime);
    memset (&uptime_var, 0, sizeof (struct variable_list));
    snmp_set_var_objid( &uptime_var, sysuptime_oid, OID_LENGTH(sysuptime_oid));
    snmp_set_var_value( &uptime_var, (u_char *)&uptime, sizeof(uptime) );
    uptime_var.type           = ASN_TIMETICKS;
    uptime_var.next_variable  = &snmptrap_var;

    memset (&snmptrap_var, 0, sizeof (struct variable_list));
    snmp_set_var_objid( &snmptrap_var, snmptrap_oid, OID_LENGTH(snmptrap_oid));
	/* value set later .... */
    snmptrap_var.type           = ASN_OBJECT_ID;
    if ( vars )
	snmptrap_var.next_variable  = vars;
    else
	snmptrap_var.next_variable  = &enterprise_var;

			/* find end of provided varbind list,
			   ready to append the enterprise info if necessary */
    last_var = vars;
    while ( last_var && last_var->next_variable )
	last_var = last_var->next_variable;

    memset (&enterprise_var, 0, sizeof (struct variable_list));
    snmp_set_var_objid( &enterprise_var,
		 snmptrapenterprise_oid, OID_LENGTH(snmptrapenterprise_oid));
    snmp_set_var_value( &enterprise_var, (u_char *)enterprise, enterprise_length*sizeof(oid));
    enterprise_var.type           = ASN_OBJECT_ID;
    enterprise_var.next_variable  = NULL;

    v2_vars = &uptime_var;

		/*
		 *  Create a template PDU, ready for sending
		 */
    template_pdu = snmp_pdu_create( SNMP_MSG_TRAP );
    if ( template_pdu == NULL ) {
		/* Free memory if value stored dynamically */
	snmp_set_var_value( &enterprise_var, NULL, 0);
	return;
    }
    template_pdu->trap_type     = trap;
    template_pdu->specific_type = specific;
    if ( snmp_clone_mem((void **)&template_pdu->enterprise,
				enterprise, enterprise_length*sizeof(oid))) {
	snmp_free_pdu( template_pdu );
	snmp_set_var_value( &enterprise_var, NULL, 0);
	return;
    }
    template_pdu->enterprise_length = enterprise_length;
    template_pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
    pduIp = (struct sockaddr_in *)&template_pdu->agent_addr;
    pduIp->sin_family		 = AF_INET;
    pduIp->sin_len               = sizeof(*pduIp);
    pduIp->sin_addr.s_addr	 = get_myaddr();
    template_pdu->time		 	 = uptime;

		/*
		 *  Now use the parameters to determine
		 *    which v2 variables are needed,
		 *    and what values they should take.
		 */
    switch ( trap ) {
	case -1:	/*
			 *	SNMPv2 only
			 *  Check to see whether the variables provided
			 *    are sufficient for SNMPv2 notifications
			 */
		if (vars && snmp_oid_compare(vars->name, vars->name_length,
				sysuptime_oid, OID_LENGTH(sysuptime_oid)) == 0 )
			v2_vars = vars;
		else
		if (vars && snmp_oid_compare(vars->name, vars->name_length,
				snmptrap_oid, OID_LENGTH(snmptrap_oid)) == 0 )
			uptime_var.next_variable = vars;
		else {
			/* Hmmm... we don't seem to have a value - oops! */
			snmptrap_var.next_variable = vars;
		}
		last_var = NULL;	/* Don't need enterprise info */
		break;

			/* "Standard" SNMPv1 traps */

	case SNMP_TRAP_COLDSTART:
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)cold_start_oid,
				    sizeof(cold_start_oid));
		break;
	case SNMP_TRAP_WARMSTART:
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)warm_start_oid,
				    sizeof(warm_start_oid));
		break;
	case SNMP_TRAP_LINKDOWN:
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)link_down_oid,
				    sizeof(link_down_oid));
		break;
	case SNMP_TRAP_LINKUP:
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)link_up_oid,
				    sizeof(link_up_oid));
		break;
	case SNMP_TRAP_AUTHFAIL:
                if (snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) {
                    snmp_free_pdu( template_pdu );
		    snmp_set_var_value( &enterprise_var, NULL, 0);
		    return;
                }
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)auth_fail_oid,
				    sizeof(auth_fail_oid));
		break;
	case SNMP_TRAP_EGPNEIGHBORLOSS:
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)egp_xxx_oid,
				    sizeof(egp_xxx_oid));
		break;

	case SNMP_TRAP_ENTERPRISESPECIFIC:
		memcpy( &temp_oid,
				    (char *)enterprise,
				    (enterprise_length)*sizeof(oid));
		temp_oid[ enterprise_length   ] = 0;
		temp_oid[ enterprise_length+1 ] = specific;
		snmp_set_var_value( &snmptrap_var,
				    (u_char *)&temp_oid,
				    (enterprise_length+2)*sizeof(oid));
		snmptrap_var.next_variable  = vars;
		last_var = NULL;	/* Don't need version info */
		break;
    }
    

		/*
		 *  Now loop through the list of trap sinks,
		 *   sending an appropriately formatted PDU to each
		 */
    for ( sink = sinks ; sink ; sink=sink->next ) {
	if ( sink->version == SNMP_VERSION_1 && trap == -1 )
		continue;	/* Skip v1 sinks for v2 only traps */
	template_pdu->version = sink->version;
	template_pdu->command = sink->pdutype;
	if ( sink->version != SNMP_VERSION_1 ) {
	    template_pdu->variables = v2_vars;
	    if ( last_var )
		last_var->next_variable = &enterprise_var;
	}
	else
	    template_pdu->variables = vars;

	pdu = snmp_clone_pdu( template_pdu );
	pdu->sessid = sink->sesp->sessid;	/* AgentX only ? */
	if ( snmp_send( sink->sesp, pdu) == 0 ) {
            snmp_sess_perror ("snmpd: send_trap", sink->sesp);
	    snmp_free_pdu( pdu );
	}
	else {
	    snmp_increment_statistic(STAT_SNMPOUTTRAPS);
	    snmp_increment_statistic(STAT_SNMPOUTPKTS);
	}
		
	if ( sink->version != SNMP_VERSION_1 && last_var )
	    last_var->next_variable = NULL;
    }

		/* Free memory if values stored dynamically */
    snmp_set_var_value( &enterprise_var, NULL, 0);
    snmp_set_var_value( &snmptrap_var, NULL, 0);
	/* Ensure we don't free anything we shouldn't */
    if ( last_var )
	last_var->next_variable = NULL;
    template_pdu->variables = NULL;
    snmp_free_pdu( template_pdu );
}
Esempio n. 18
0
int
snmp_input(int op, netsnmp_session *session,
           int reqid, netsnmp_pdu *pdu, void *magic)
{
    oid stdTrapOidRoot[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
    oid snmpTrapOid[]    = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
    oid trapOid[MAX_OID_LEN+2] = {0};
    int trapOidLen;
    netsnmp_variable_list *vars;
    netsnmp_trapd_handler *traph;
    netsnmp_transport *transport = (netsnmp_transport *) magic;
    int ret, idx;

    switch (op) {
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
        /*
         * Drops packets with reception problems
         */
        if (session->s_snmp_errno) {
            /* drop problem packets */
            return 1;
        }

        /*
	 * Determine the OID that identifies the trap being handled
	 */
        DEBUGMSGTL(("snmptrapd", "input: %x\n", pdu->command));
        switch (pdu->command) {
        case SNMP_MSG_TRAP:
            /*
	     * Convert v1 traps into a v2-style trap OID
	     *    (following RFC 2576)
	     */
            if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
                trapOidLen = pdu->enterprise_length;
                memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen);
                if (trapOid[trapOidLen - 1] != 0) {
                    trapOid[trapOidLen++] = 0;
                }
                trapOid[trapOidLen++] = pdu->specific_type;
            } else {
                memcpy(trapOid, stdTrapOidRoot, sizeof(stdTrapOidRoot));
                trapOidLen = OID_LENGTH(stdTrapOidRoot);  /* 9 */
                trapOid[trapOidLen++] = pdu->trap_type+1;
            }
            break;

        case SNMP_MSG_TRAP2:
        case SNMP_MSG_INFORM:
            /*
	     * v2c/v3 notifications *should* have snmpTrapOID as the
	     *    second varbind, so we can go straight there.
	     *    But check, just to make sure
	     */
            vars = pdu->variables;
            if (vars)
                vars = vars->next_variable;
            if (!vars || snmp_oid_compare(vars->name, vars->name_length,
                                          snmpTrapOid, OID_LENGTH(snmpTrapOid))) {
	        /*
		 * Didn't find it!
		 * Let's look through the full list....
		 */
		for ( vars = pdu->variables; vars; vars=vars->next_variable) {
                    if (!snmp_oid_compare(vars->name, vars->name_length,
                                          snmpTrapOid, OID_LENGTH(snmpTrapOid)))
                        break;
                }
                if (!vars) {
	            /*
		     * Still can't find it!  Give up.
		     */
		    snmp_log(LOG_ERR, "Cannot find TrapOID in TRAP2 PDU\n");
		    return 1;		/* ??? */
		}
	    }
            memcpy(trapOid, vars->val.objid, vars->val_len);
            trapOidLen = vars->val_len /sizeof(oid);
            break;

        default:
            /* SHOULDN'T HAPPEN! */
            return 1;	/* ??? */
	}
        DEBUGMSGTL(( "snmptrapd", "Trap OID: "));
        DEBUGMSGOID(("snmptrapd", trapOid, trapOidLen));
        DEBUGMSG(( "snmptrapd", "\n"));


        /*
	 *  OK - We've found the Trap OID used to identify this trap.
         *  Call each of the various lists of handlers:
         *     a) authentication-related handlers,
         *     b) other handlers to be applied to all traps
         *		(*before* trap-specific handlers)
         *     c) the handler(s) specific to this trap
t        *     d) any other global handlers
         *
	 *  In each case, a particular trap handler can abort further
         *     processing - either just for that particular list,
         *     or for the trap completely.
         *
	 *  This is particularly designed for authentication-related
	 *     handlers, but can also be used elsewhere.
         *
         *  OK - Enough waffling, let's get to work.....
	 */

        for( idx = 0; handlers[idx].descr; ++idx ) {
            DEBUGMSGTL(("snmptrapd", "Running %s handlers\n",
                        handlers[idx].descr));
            if (NULL == handlers[idx].handler) /* specific */
                traph = netsnmp_get_traphandler(trapOid, trapOidLen);
            else
                traph = *handlers[idx].handler;

            for( ; traph; traph = traph->nexth) {
                if (!netsnmp_trapd_check_auth(traph->authtypes))
                    continue; /* we continue on and skip this one */

                ret = (*(traph->handler))(pdu, transport, traph);
                if(NETSNMPTRAPD_HANDLER_FINISH == ret)
                    return 1;
                if (ret == NETSNMPTRAPD_HANDLER_BREAK)
                    break; /* move on to next type */
            } /* traph */
        } /* handlers */


	if (pdu->command == SNMP_MSG_INFORM) {
	    netsnmp_pdu *reply = snmp_clone_pdu(pdu);
	    if (!reply) {
		snmp_log(LOG_ERR, "couldn't clone PDU for INFORM response\n");
	    } else {
		reply->command = SNMP_MSG_RESPONSE;
		reply->errstat = 0;
		reply->errindex = 0;
		if (!snmp_send(session, reply)) {
		    snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
                                    session);
		    snmp_free_pdu(reply);
		}
	    }
	}

        break;

    case NETSNMP_CALLBACK_OP_TIMED_OUT:
        snmp_log(LOG_ERR, "Timeout: This shouldn't happen!\n");
        break;

    case NETSNMP_CALLBACK_OP_SEND_FAILED:
        snmp_log(LOG_ERR, "Send Failed: This shouldn't happen either!\n");
        break;

    case NETSNMP_CALLBACK_OP_CONNECT:
    case NETSNMP_CALLBACK_OP_DISCONNECT:
        /* Ignore silently */
        break;

    default:
        snmp_log(LOG_ERR, "Unknown operation (%d): This shouldn't happen!\n", op);
        break;
    }
    return 0;
}
Esempio n. 19
0
netsnmp_pdu*
convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu )
{
    netsnmp_pdu           *template_v2pdu;
    netsnmp_variable_list *first_vb;
    netsnmp_variable_list *var;
    oid                    enterprise[MAX_OID_LEN];
    size_t                 enterprise_len;

    /*
     * Make a copy of the v1 Trap PDU
     *   before starting to convert this
     *   into a v2 Trap PDU.
     */
    template_v2pdu = snmp_clone_pdu( template_v1pdu);
    if (!template_v2pdu) {
        snmp_log(LOG_WARNING,
                 "send_trap: failed to copy v2 template PDU\n");
        return NULL;
    }
    template_v2pdu->command = SNMP_MSG_TRAP2;
    first_vb = template_v2pdu->variables;

    /*
     * Insert an snmpTrapOID varbind before the original v1 varbind list
     *   either using one of the standard defined trap OIDs,
     *   or constructing this from the PDU enterprise & specific trap fields
     */
    if (template_v1pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
        memcpy(enterprise, template_v1pdu->enterprise,
                           template_v1pdu->enterprise_length*sizeof(oid));
        enterprise_len               = template_v1pdu->enterprise_length;
        enterprise[enterprise_len++] = 0;
        enterprise[enterprise_len++] = template_v1pdu->specific_type;
    } else {
        memcpy(enterprise, cold_start_oid, sizeof(cold_start_oid));
	enterprise[9]  = template_v1pdu->trap_type+1;
        enterprise_len = sizeof(cold_start_oid)/sizeof(oid);
    }

    var = NULL;
    if (!snmp_varlist_add_variable( &var,
             snmptrap_oid, snmptrap_oid_len,
             ASN_OBJECT_ID,
             (u_char*)enterprise, enterprise_len*sizeof(oid))) {
        snmp_log(LOG_WARNING,
                 "send_trap: failed to insert copied snmpTrapOID varbind\n");
        snmp_free_pdu(template_v2pdu);
        return NULL;
    }
    var->next_variable        = template_v2pdu->variables;
    template_v2pdu->variables = var;

    /*
     * Insert a sysUptime varbind at the head of the v2 varbind list
     */
    var = NULL;
    if (!snmp_varlist_add_variable( &var,
             sysuptime_oid, sysuptime_oid_len,
             ASN_TIMETICKS,
             (u_char*)&(template_v1pdu->time), 
             sizeof(template_v1pdu->time))) {
        snmp_log(LOG_WARNING,
                 "send_trap: failed to insert copied sysUptime varbind\n");
        snmp_free_pdu(template_v2pdu);
        return NULL;
    }
    var->next_variable        = template_v2pdu->variables;
    template_v2pdu->variables = var;

    /*
     * Append the other three conversion varbinds,
     *  (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise)
     *  if they're not already present.
     *  But don't bomb out completely if there are problems.
     */
    var = find_varbind_in_list( template_v2pdu->variables,
                                agentaddr_oid, agentaddr_oid_len);
    if (!var && (template_v1pdu->agent_addr[0]
              || template_v1pdu->agent_addr[1]
              || template_v1pdu->agent_addr[2]
              || template_v1pdu->agent_addr[3])) {
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
                 agentaddr_oid, agentaddr_oid_len,
                 ASN_IPADDRESS,
                 (u_char*)&(template_v1pdu->agent_addr), 
                 sizeof(template_v1pdu->agent_addr)))
            snmp_log(LOG_WARNING,
                 "send_trap: failed to append snmpTrapAddr varbind\n");
    }
    var = find_varbind_in_list( template_v2pdu->variables,
                                community_oid, community_oid_len);
    if (!var && template_v1pdu->community) {
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
                 community_oid, community_oid_len,
                 ASN_OCTET_STR,
                 template_v1pdu->community, 
                 template_v1pdu->community_len))
            snmp_log(LOG_WARNING,
                 "send_trap: failed to append snmpTrapCommunity varbind\n");
    }
    var = find_varbind_in_list( template_v2pdu->variables,
                                snmptrapenterprise_oid,
                                snmptrapenterprise_oid_len);
    if (!var) {
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
                 snmptrapenterprise_oid, snmptrapenterprise_oid_len,
                 ASN_OBJECT_ID,
                 (u_char*)template_v1pdu->enterprise, 
                 template_v1pdu->enterprise_length*sizeof(oid)))
            snmp_log(LOG_WARNING,
                 "send_trap: failed to append snmpEnterprise varbind\n");
    }
    return template_v2pdu;
}
Esempio n. 20
0
netsnmp_pdu*
convert_v2pdu_to_v1( netsnmp_pdu* template_v2pdu )
{
    netsnmp_pdu           *template_v1pdu;
    netsnmp_variable_list *first_vb, *vblist;
    netsnmp_variable_list *var;
    size_t                 len;

    /*
     * Make a copy of the v2 Trap PDU
     *   before starting to convert this
     *   into a v1 Trap PDU.
     */
    template_v1pdu = snmp_clone_pdu( template_v2pdu);
    if (!template_v1pdu) {
        snmp_log(LOG_WARNING,
                 "send_trap: failed to copy v1 template PDU\n");
        return NULL;
    }
    template_v1pdu->command = SNMP_MSG_TRAP;
    first_vb = template_v1pdu->variables;
    vblist   = template_v1pdu->variables;

    /*
     * The first varbind should be the system uptime.
     */
    if (!vblist ||
        snmp_oid_compare(vblist->name,  vblist->name_length,
                         sysuptime_oid, sysuptime_oid_len)) {
        snmp_log(LOG_WARNING,
                 "send_trap: no v2 sysUptime varbind to set from\n");
        snmp_free_pdu(template_v1pdu);
        return NULL;
    }
    template_v1pdu->time = *vblist->val.integer;
    vblist = vblist->next_variable;
            
    /*
     * The second varbind should be the snmpTrapOID.
     */
    if (!vblist ||
        snmp_oid_compare(vblist->name, vblist->name_length,
                         snmptrap_oid, snmptrap_oid_len)) {
        snmp_log(LOG_WARNING,
                 "send_trap: no v2 trapOID varbind to set from\n");
        snmp_free_pdu(template_v1pdu);
        return NULL;
    }

    /*
     * Check the v2 varbind list for any varbinds
     *  that are not valid in an SNMPv1 trap.
     *  This basically means Counter64 values.
     *
     * RFC 2089 said to omit such varbinds from the list.
     * RFC 2576/3584 say to drop the trap completely.
     */
    for (var = vblist->next_variable; var; var = var->next_variable) {
        if ( var->type == ASN_COUNTER64 ) {
            snmp_log(LOG_WARNING,
                     "send_trap: v1 traps can't carry Counter64 varbinds\n");
            snmp_free_pdu(template_v1pdu);
            return NULL;
        }
    }

    /*
     * Set the generic & specific trap types,
     *    and the enterprise field from the v2 varbind list.
     * If there's an agentIPAddress varbind, set the agent_addr too
     */
    if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix),
                          trap_prefix,       OID_LENGTH(trap_prefix))) {
        /*
         * For 'standard' traps, extract the generic trap type
         *   from the snmpTrapOID value, and take the enterprise
         *   value from the 'snmpEnterprise' varbind.
         */
        template_v1pdu->trap_type =
            vblist->val.objid[OID_LENGTH(trap_prefix)] - 1;
        template_v1pdu->specific_type = 0;

        var = find_varbind_in_list( vblist,
                             snmptrapenterprise_oid,
                             snmptrapenterprise_oid_len);
        if (var) {
            memdup((u_char**)&template_v1pdu->enterprise,
                   (const u_char*)var->val.objid, var->val_len);
            template_v1pdu->enterprise_length = var->val_len/sizeof(oid);
        } else {
            template_v1pdu->enterprise        = NULL;
            template_v1pdu->enterprise_length = 0;		/* XXX ??? */
        }
    } else {
        /*
         * For enterprise-specific traps, split the snmpTrapOID value
         *   into enterprise and specific trap
         */
        len = vblist->val_len / sizeof(oid);
        if ( len <= 2 ) {
            snmp_log(LOG_WARNING,
                     "send_trap: v2 trapOID too short (%d)\n", len);
            snmp_free_pdu(template_v1pdu);
            return NULL;
        }
        template_v1pdu->trap_type     = SNMP_TRAP_ENTERPRISESPECIFIC;
        template_v1pdu->specific_type = vblist->val.objid[len - 1];
        len--;
        if (vblist->val.objid[len-1] == 0)
            len--;
        SNMP_FREE(template_v1pdu->enterprise);
        memdup((u_char**)&template_v1pdu->enterprise,
               (u_char *)vblist->val.objid, len*sizeof(oid));
        template_v1pdu->enterprise_length = len;
    }
    var = find_varbind_in_list( vblist, agentaddr_oid,
                                        agentaddr_oid_len);
    if (var) {
        memcpy(template_v1pdu->agent_addr,
               var->val.string, 4);
    }

    /*
     * The remainder of the v2 varbind list is kept
     * as the v2 varbind list.  Update the PDU and
     * free the two redundant varbinds.
     */
    template_v1pdu->variables = vblist->next_variable;
    vblist->next_variable = NULL;
    snmp_free_varbind( first_vb );
            
    return template_v1pdu;
}
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;
}
int
handle_subagent_response(int op, netsnmp_session * session, int reqid,
                         netsnmp_pdu *pdu, void *magic)
{
    ns_subagent_magic *smagic = (ns_subagent_magic *) magic;
    netsnmp_variable_list *u = NULL, *v = NULL;
    int             rc = 0;

    if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE || magic == NULL) {
        return 1;
    }

    pdu = snmp_clone_pdu(pdu);
    DEBUGMSGTL(("agentx/subagent",
                "handling AgentX response (cmd 0x%02x orig_cmd 0x%02x)\n",
                pdu->command, smagic->original_command));

    if (pdu->command == SNMP_MSG_INTERNAL_SET_FREE ||
        pdu->command == SNMP_MSG_INTERNAL_SET_UNDO ||
        pdu->command == SNMP_MSG_INTERNAL_SET_COMMIT) {
        free_set_vars(smagic->session, pdu);
    }

    if (smagic->original_command == AGENTX_MSG_GETNEXT) {
        DEBUGMSGTL(("agentx/subagent",
                    "do getNext scope processing %p %p\n", smagic->ovars,
                    pdu->variables));
        for (u = smagic->ovars, v = pdu->variables; u != NULL && v != NULL;
             u = u->next_variable, v = v->next_variable) {
            if (snmp_oid_compare
                (u->val.objid, u->val_len / sizeof(oid), nullOid,
                 nullOidLen) != 0) {
                /*
                 * The master agent requested scoping for this variable.  
                 */
                rc = snmp_oid_compare(v->name, v->name_length,
                                      u->val.objid,
                                      u->val_len / sizeof(oid));
                DEBUGMSGTL(("agentx/subagent", "result "));
                DEBUGMSGOID(("agentx/subagent", v->name, v->name_length));
                DEBUGMSG(("agentx/subagent", " scope to "));
                DEBUGMSGOID(("agentx/subagent",
                             u->val.objid, u->val_len / sizeof(oid)));
                DEBUGMSG(("agentx/subagent", " result %d\n", rc));

                if (rc >= 0) {
                    /*
                     * The varbind is out of scope.  From RFC2741, p. 66: "If
                     * the subagent cannot locate an appropriate variable,
                     * v.name is set to the starting OID, and the VarBind is
                     * set to `endOfMibView'".  
                     */
                    snmp_set_var_objid(v, u->name, u->name_length);
                    snmp_set_var_typed_value(v, SNMP_ENDOFMIBVIEW, 0, 0);
                    DEBUGMSGTL(("agentx/subagent",
                                "scope violation -- return endOfMibView\n"));
                }
            } else {
                DEBUGMSGTL(("agentx/subagent", "unscoped var\n"));
            }
        }
    }

    /*
     * XXXJBPN: similar for GETBULK but the varbinds can get re-ordered I
     * think which makes it er more difficult.  
     */

    if (smagic->ovars != NULL) {
        snmp_free_varbind(smagic->ovars);
    }

    pdu->command = AGENTX_MSG_RESPONSE;
    pdu->version = smagic->session->version;

    if (!snmp_send(smagic->session, pdu)) {
        snmp_free_pdu(pdu);
    }
    DEBUGMSGTL(("agentx/subagent", "  FINISHED\n"));
    free(smagic);
    return 1;
}