diff options
Diffstat (limited to 'agent/mibgroup/agentx/client.c')
-rw-r--r-- | agent/mibgroup/agentx/client.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/agent/mibgroup/agentx/client.c b/agent/mibgroup/agentx/client.c new file mode 100644 index 0000000..d36fe2d --- /dev/null +++ b/agent/mibgroup/agentx/client.c @@ -0,0 +1,492 @@ +/* + * AgentX utility routines + */ + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-features.h> + +#include <stdio.h> +#include <errno.h> +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/types.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> +#include <net-snmp/agent/agent_index.h> + +#include "agentx/protocol.h" +#include "agentx/client.h" +#include "agentx/subagent.h" + +netsnmp_feature_require(set_agent_uptime) + + /* + * AgentX handling utility routines + * + * Mostly wrappers round, or re-writes of + * the SNMP equivalents + */ + +int +agentx_synch_input(int op, + netsnmp_session * session, + int reqid, netsnmp_pdu *pdu, void *magic) +{ + struct synch_state *state = (struct synch_state *) magic; + + if (!state || 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 + */ + netsnmp_set_agent_uptime(pdu->time); + } + } 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; +} + + + +int +agentx_synch_response(netsnmp_session * ss, netsnmp_pdu *pdu, + netsnmp_pdu **response) +{ + return snmp_synch_response_cb(ss, pdu, response, agentx_synch_input); +} + + + /* + * AgentX PofE convenience functions + */ + +int +agentx_open_session(netsnmp_session * ss) +{ + netsnmp_pdu *pdu, *response; + extern oid version_sysoid[]; + extern int version_sysoid_len; + u_long timeout; + + DEBUGMSGTL(("agentx/subagent", "opening session \n")); + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_OPEN); + if (pdu == NULL) + return 0; + timeout = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_AGENTX_TIMEOUT); + if (timeout < 0) + pdu->time = 0; + else + /* for master TIMEOUT is usec, but Agentx Open specifies sec */ + pdu->time = timeout/ONE_SEC; + + snmp_add_var(pdu, version_sysoid, version_sysoid_len, + 's', "Net-SNMP AgentX sub-agent"); + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return 0; + + if (!response) + return 0; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return 0; + } + + ss->sessid = response->sessid; + snmp_free_pdu(response); + + DEBUGMSGTL(("agentx/subagent", "open \n")); + return 1; +} + +int +agentx_close_session(netsnmp_session * ss, int why) +{ + netsnmp_pdu *pdu, *response; + DEBUGMSGTL(("agentx/subagent", "closing session\n")); + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_CLOSE); + if (pdu == NULL) + return 0; + pdu->time = 0; + pdu->errstat = why; + pdu->sessid = ss->sessid; + + if (agentx_synch_response(ss, pdu, &response) == STAT_SUCCESS) + snmp_free_pdu(response); + DEBUGMSGTL(("agentx/subagent", "closed\n")); + + return 1; +} + +int +agentx_register(netsnmp_session * ss, oid start[], size_t startlen, + int priority, int range_subid, oid range_ubound, + int timeout, u_char flags, const char *contextName) +{ + netsnmp_pdu *pdu, *response; + + DEBUGMSGTL(("agentx/subagent", "registering: ")); + DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid, + range_ubound)); + DEBUGMSG(("agentx/subagent", "\n")); + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_REGISTER); + if (pdu == NULL) { + return 0; + } + pdu->time = timeout; + pdu->priority = priority; + pdu->sessid = ss->sessid; + pdu->range_subid = range_subid; + if (contextName) { + pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT; + pdu->community = (u_char *) strdup(contextName); + pdu->community_len = strlen(contextName); + } + + if (flags & FULLY_QUALIFIED_INSTANCE) { + pdu->flags |= AGENTX_MSG_FLAG_INSTANCE_REGISTER; + } + + if (range_subid) { + snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID, + (u_char *) start, startlen * sizeof(oid)); + pdu->variables->val.objid[range_subid - 1] = range_ubound; + } else { + snmp_add_null_var(pdu, start, startlen); + } + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) { + DEBUGMSGTL(("agentx/subagent", "registering failed!\n")); + return 0; + } + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_log(LOG_ERR,"registering pdu failed: %ld!\n", response->errstat); + snmp_free_pdu(response); + return 0; + } + + snmp_free_pdu(response); + DEBUGMSGTL(("agentx/subagent", "registered\n")); + return 1; +} + +int +agentx_unregister(netsnmp_session * ss, oid start[], size_t startlen, + int priority, int range_subid, oid range_ubound, + const char *contextName) +{ + netsnmp_pdu *pdu, *response; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + DEBUGMSGTL(("agentx/subagent", "unregistering: ")); + DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid, + range_ubound)); + DEBUGMSG(("agentx/subagent", "\n")); + pdu = snmp_pdu_create(AGENTX_MSG_UNREGISTER); + if (pdu == NULL) { + return 0; + } + pdu->time = 0; + pdu->priority = priority; + pdu->sessid = ss->sessid; + pdu->range_subid = range_subid; + if (contextName) { + pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT; + pdu->community = (u_char *) strdup(contextName); + pdu->community_len = strlen(contextName); + } + + if (range_subid) { + snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID, + (u_char *) start, startlen * sizeof(oid)); + pdu->variables->val.objid[range_subid - 1] = range_ubound; + } else { + snmp_add_null_var(pdu, start, startlen); + } + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return 0; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return 0; + } + + snmp_free_pdu(response); + DEBUGMSGTL(("agentx/subagent", "unregistered\n")); + return 1; +} + +netsnmp_variable_list * +agentx_register_index(netsnmp_session * ss, + netsnmp_variable_list * varbind, int flags) +{ + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *varbind2; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return NULL; + } + + /* + * Make a copy of the index request varbind + * for the AgentX request PDU + * (since the pdu structure will be freed) + */ + varbind2 = + (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); + if (varbind2 == NULL) + return NULL; + if (snmp_clone_var(varbind, varbind2)) { + snmp_free_varbind(varbind2); + return NULL; + } + if (varbind2->val.string == NULL) + varbind2->val.string = varbind2->buf; /* ensure it points somewhere */ + + pdu = snmp_pdu_create(AGENTX_MSG_INDEX_ALLOCATE); + if (pdu == NULL) { + snmp_free_varbind(varbind2); + return NULL; + } + pdu->time = 0; + pdu->sessid = ss->sessid; + if (flags == ALLOCATE_ANY_INDEX) + pdu->flags |= AGENTX_MSG_FLAG_ANY_INSTANCE; + if (flags == ALLOCATE_NEW_INDEX) + pdu->flags |= AGENTX_MSG_FLAG_NEW_INSTANCE; + + /* + * Just send a single index request varbind. + * Although the AgentX protocol supports + * multiple index allocations in a single + * request, the model used in the net-snmp agent + * doesn't currently take advantage of this. + * I believe this is our prerogative - just as + * long as the master side Index request handler + * can cope with multiple index requests. + */ + pdu->variables = varbind2; + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return NULL; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return NULL; + } + + /* + * Unlink the (single) response varbind to return + * to the main driving index request routine. + * + * This is a memory leak, as nothing will ever + * release this varbind. If this becomes a problem, + * we'll need to keep a list of these here, and + * free the memory in the "index release" routine. + * But the master side never frees these either (by + * design, since it still needs them), so expecting + * the subagent to is discrimination, pure & simple :-) + */ + varbind2 = response->variables; + response->variables = NULL; + snmp_free_pdu(response); + return varbind2; +} + +int +agentx_unregister_index(netsnmp_session * ss, + netsnmp_variable_list * varbind) +{ + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *varbind2; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return -1; + } + + /* + * Make a copy of the index request varbind + * for the AgentX request PDU + * (since the pdu structure will be freed) + */ + varbind2 = + (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); + if (varbind2 == NULL) + return -1; + if (snmp_clone_var(varbind, varbind2)) { + snmp_free_varbind(varbind2); + return -1; + } + + pdu = snmp_pdu_create(AGENTX_MSG_INDEX_DEALLOCATE); + if (pdu == NULL) { + snmp_free_varbind(varbind2); + return -1; + } + pdu->time = 0; + pdu->sessid = ss->sessid; + + /* + * Just send a single index release varbind. + * (as above) + */ + pdu->variables = varbind2; + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return -1; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return -1; /* XXX - say why */ + } + + snmp_free_pdu(response); + return SNMP_ERR_NOERROR; +} + +int +agentx_add_agentcaps(netsnmp_session * ss, + const oid * agent_cap, size_t agent_caplen, + const char *descr) +{ + netsnmp_pdu *pdu, *response; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_ADD_AGENT_CAPS); + if (pdu == NULL) + return 0; + pdu->time = 0; + pdu->sessid = ss->sessid; + snmp_add_var(pdu, agent_cap, agent_caplen, 's', descr); + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return 0; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return 0; + } + + snmp_free_pdu(response); + return 1; +} + +int +agentx_remove_agentcaps(netsnmp_session * ss, + const oid * agent_cap, size_t agent_caplen) +{ + netsnmp_pdu *pdu, *response; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_REMOVE_AGENT_CAPS); + if (pdu == NULL) + return 0; + pdu->time = 0; + pdu->sessid = ss->sessid; + snmp_add_null_var(pdu, agent_cap, agent_caplen); + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return 0; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return 0; + } + + snmp_free_pdu(response); + return 1; +} + +int +agentx_send_ping(netsnmp_session * ss) +{ + netsnmp_pdu *pdu, *response; + + if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { + return 0; + } + + pdu = snmp_pdu_create(AGENTX_MSG_PING); + if (pdu == NULL) + return 0; + pdu->time = 0; + pdu->sessid = ss->sessid; + + if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) + return 0; + + if (response->errstat != SNMP_ERR_NOERROR) { + snmp_free_pdu(response); + return 0; + } + + snmp_free_pdu(response); + return 1; +} |