/* * 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); } }
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")); } }
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; }
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); }
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); } }
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); } }
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); }); } }
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; }
/* * 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); } }
/* * 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; }
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; }
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; }
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; }
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 ); }
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; }
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; }
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; }