master_admin.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:17k
- /*
- * AgentX Administrative request handling
- */
- #include <net-snmp/net-snmp-config.h>
- #include <sys/types.h>
- #ifdef HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if TIME_WITH_SYS_TIME
- # ifdef WIN32
- # include <sys/timeb.h>
- # else
- # include <sys/time.h>
- # endif
- # 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
- #if HAVE_WINSOCK_H
- #include <winsock.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include "agentx/protocol.h"
- #include "agentx/client.h"
- #include <net-snmp/agent/agent_index.h>
- #include <net-snmp/agent/agent_trap.h>
- #include <net-snmp/agent/agent_callbacks.h>
- #include "mibII/sysORTable.h"
- #include "master.h"
- extern struct timeval starttime;
- netsnmp_session *
- find_agentx_session(netsnmp_session * session, int sessid)
- {
- netsnmp_session *sp;
- for (sp = session->subsession; sp != NULL; sp = sp->next) {
- if (sp->sessid == sessid)
- return sp;
- }
- return NULL;
- }
- int
- open_agentx_session(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- struct timeval now;
- DEBUGMSGTL(("agentx/master", "open %08pn", session));
- sp = (netsnmp_session *) malloc(sizeof(netsnmp_session));
- if (sp == NULL) {
- session->s_snmp_errno = AGENTX_ERR_OPEN_FAILED;
- return -1;
- }
- memcpy(sp, session, sizeof(netsnmp_session));
- sp->sessid = snmp_get_next_sessid();
- sp->version = pdu->version;
- sp->timeout = pdu->time;
- /*
- * Be careful with fields: if these aren't zeroed, they will get free()d
- * more than once when the session is closed -- once in the main session,
- * and once in each subsession. Basically, if it's not being used for
- * some AgentX-specific purpose, it ought to be zeroed here.
- */
- sp->community = NULL;
- sp->peername = NULL;
- sp->contextEngineID = NULL;
- sp->contextName = NULL;
- sp->securityEngineID = NULL;
- sp->securityPrivProto = NULL;
- /*
- * This next bit utilises unused SNMPv3 fields
- * to store the subagent OID and description.
- * This really ought to use AgentX-specific fields,
- * but it hardly seems worth it for a one-off use.
- *
- * But I'm willing to be persuaded otherwise.... */
- sp->securityAuthProto = snmp_duplicate_objid(pdu->variables->name,
- pdu->variables->
- name_length);
- sp->securityAuthProtoLen = pdu->variables->name_length;
- sp->securityName = strdup((char *) pdu->variables->val.string);
- gettimeofday(&now, NULL);
- sp->engineTime = calculate_time_diff(&now, &starttime);
- sp->subsession = session; /* link back to head */
- sp->flags |= SNMP_FLAGS_SUBSESSION;
- sp->flags &= ~AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER;
- sp->flags |= (pdu->flags & AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER);
- sp->next = session->subsession;
- session->subsession = sp;
- DEBUGMSGTL(("agentx/master", "opened %08p = %d with flags = %02xn",
- sp, sp->sessid, sp->flags & AGENTX_MSG_FLAGS_MASK));
- return sp->sessid;
- }
- int
- close_agentx_session(netsnmp_session * session, int sessid)
- {
- netsnmp_session *sp, **prevNext;
- DEBUGMSGTL(("agentx/master", "close %08p, %dn", session, sessid));
- if (session != NULL && sessid == -1) {
- unregister_mibs_by_session(session);
- unregister_index_by_session(session);
- snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
- SNMPD_CALLBACK_REQ_UNREG_SYSOR_SESS,
- (void*)session);
- if (session->myvoid != NULL) {
- free(session->myvoid);
- }
- /*
- * The following is necessary to avoid locking up the agent when
- * a sugagent dies during a set request. We must clean up the
- * requests, so that the delegated request will be completed and
- * further requests can be processed
- */
- netsnmp_remove_delegated_requests_for_session(session);
- if (session->subsession != NULL) {
- netsnmp_session *subsession = session->subsession;
- for(; subsession; subsession = subsession->next) {
- netsnmp_remove_delegated_requests_for_session(subsession);
- }
- }
-
- return AGENTX_ERR_NOERROR;
- }
- prevNext = &(session->subsession);
- for (sp = session->subsession; sp != NULL; sp = sp->next) {
- if (sp->sessid == sessid) {
- unregister_mibs_by_session(sp);
- unregister_index_by_session(sp);
- snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
- SNMPD_CALLBACK_REQ_UNREG_SYSOR_SESS,
- (void*)sp);
- *prevNext = sp->next;
- if (sp->securityAuthProto != NULL) {
- free(sp->securityAuthProto);
- }
- if (sp->securityName != NULL) {
- free(sp->securityName);
- }
- free(sp);
- sp = NULL;
- DEBUGMSGTL(("agentx/master", "closed %08p, %d okayn",
- session, sessid));
- return AGENTX_ERR_NOERROR;
- }
- prevNext = &(sp->next);
- }
- DEBUGMSGTL(("agentx/master", "sessid %d not foundn", sessid));
- return AGENTX_ERR_NOT_OPEN;
- }
- int
- register_agentx_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- char buf[128];
- oid ubound = 0;
- u_long flags = 0;
- netsnmp_handler_registration *reg;
- int rc = 0;
- int cacheid;
- DEBUGMSGTL(("agentx/master", "in register_agentx_listn"));
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- sprintf(buf, "AgentX subagent %ld, session %8p, subsession %8p",
- sp->sessid, session, sp);
- /*
- * * TODO: registration timeout
- * * registration context
- */
- if (pdu->range_subid) {
- ubound = pdu->variables->val.objid[pdu->range_subid - 1];
- }
- if (pdu->flags & AGENTX_MSG_FLAG_INSTANCE_REGISTER) {
- flags = FULLY_QUALIFIED_INSTANCE;
- }
- reg = netsnmp_create_handler_registration(buf, agentx_master_handler, pdu->variables->name, pdu->variables->name_length, HANDLER_CAN_RWRITE | HANDLER_CAN_GETBULK); /* fake it */
- if (!session->myvoid) {
- session->myvoid = malloc(sizeof(cacheid));
- cacheid = netsnmp_allocate_globalcacheid();
- *((int *) session->myvoid) = cacheid;
- } else {
- cacheid = *((int *) session->myvoid);
- }
- reg->handler->myvoid = session;
- reg->global_cacheid = cacheid;
- if (NULL != pdu->community)
- reg->contextName = strdup(pdu->community);
- /*
- * register mib. Note that for failure cases, the registration info
- * (reg) will be freed, and thus is no longer a valid pointer.
- */
- switch (netsnmp_register_mib(buf, NULL, 0, 1,
- pdu->variables->name,
- pdu->variables->name_length,
- pdu->priority, pdu->range_subid, ubound,
- sp, (char *) pdu->community, pdu->time,
- flags, reg, 1)) {
- case MIB_REGISTERED_OK:
- DEBUGMSGTL(("agentx/master", "registered okn"));
- return AGENTX_ERR_NOERROR;
- case MIB_DUPLICATE_REGISTRATION:
- DEBUGMSGTL(("agentx/master", "duplicate registrationn"));
- rc = AGENTX_ERR_DUPLICATE_REGISTRATION;
- break;
- case MIB_REGISTRATION_FAILED:
- default:
- rc = AGENTX_ERR_REQUEST_DENIED;
- DEBUGMSGTL(("agentx/master", "failed registrationn"));
- }
- return rc;
- }
- int
- unregister_agentx_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- int rc = 0;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL) {
- return AGENTX_ERR_NOT_OPEN;
- }
- if (pdu->range_subid != 0) {
- oid ubound =
- pdu->variables->val.objid[pdu->range_subid - 1];
- rc = netsnmp_unregister_mib_table_row(pdu->variables->name,
- pdu->variables->name_length,
- pdu->priority,
- pdu->range_subid, ubound,
- (char *) pdu->community);
- } else {
- rc = unregister_mib_context(pdu->variables->name,
- pdu->variables->name_length,
- pdu->priority, 0, 0,
- (char *) pdu->community);
- }
- switch (rc) {
- case MIB_UNREGISTERED_OK:
- return AGENTX_ERR_NOERROR;
- case MIB_NO_SUCH_REGISTRATION:
- return AGENTX_ERR_UNKNOWN_REGISTRATION;
- case MIB_UNREGISTRATION_FAILED:
- default:
- return AGENTX_ERR_REQUEST_DENIED;
- }
- }
- int
- allocate_idx_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- netsnmp_variable_list *vp, *vp2, *next, *res;
- int flags = 0;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- if (pdu->flags & AGENTX_MSG_FLAG_ANY_INSTANCE)
- flags |= ALLOCATE_ANY_INDEX;
- if (pdu->flags & AGENTX_MSG_FLAG_NEW_INSTANCE)
- flags |= ALLOCATE_NEW_INDEX;
- /*
- * XXX - what about errors?
- *
- * If any allocations fail, then we need to
- * *fully* release the earlier ones.
- * (i.e. remove them completely from the index registry,
- * not simply mark them as available for re-use)
- *
- * For now - assume they all succeed.
- */
- for (vp = pdu->variables; vp != NULL; vp = next) {
- next = vp->next_variable;
- res = register_index(vp, flags, session);
- if (res == NULL) {
- /*
- * If any allocations fail, we need to *fully* release
- * all previous ones (i.e. remove them completely
- * from the index registry)
- */
- for (vp2 = pdu->variables; vp2 != vp; vp2 = vp2->next_variable) {
- remove_index(vp2, session);
- }
- return AGENTX_ERR_INDEX_NONE_AVAILABLE; /* XXX */
- } else {
- (void) snmp_clone_var(res, vp);
- free(res);
- }
- vp->next_variable = next;
- }
- return AGENTX_ERR_NOERROR;
- }
- int
- release_idx_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- netsnmp_variable_list *vp, *vp2, *rv = NULL;
- int res;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
- res = unregister_index(vp, TRUE, session);
- /*
- * If any releases fail,
- * we need to reinstate all previous ones.
- */
- if (res != SNMP_ERR_NOERROR) {
- for (vp2 = pdu->variables; vp2 != vp; vp2 = vp2->next_variable) {
- rv = register_index(vp2, ALLOCATE_THIS_INDEX, session);
- free(rv);
- }
- return AGENTX_ERR_INDEX_NOT_ALLOCATED; /* Probably */
- }
- }
- return AGENTX_ERR_NOERROR;
- }
- int
- add_agent_caps_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- struct sysORTable parms;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- parms.OR_oid = pdu->variables->name;
- parms.OR_oidlen = pdu->variables->name_length;
- parms.OR_descr = (char *) pdu->variables->val.string;
- parms.OR_sess = sp;
- snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
- SNMPD_CALLBACK_REQ_REG_SYSOR, (void*)&parms);
- return AGENTX_ERR_NOERROR;
- }
- int
- remove_agent_caps_list(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- struct sysORTable parms;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- parms.OR_oid = pdu->variables->name;
- parms.OR_oidlen = pdu->variables->name_length;
- parms.OR_sess = sp;
- snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
- SNMPD_CALLBACK_REQ_UNREG_SYSOR, (void*)&parms);
- /*
- * no easy way to get an error code...
- * if (rc < 0)
- * return AGENTX_ERR_UNKNOWN_AGENTCAPS;
- */
- return AGENTX_ERR_NOERROR;
- }
- int
- agentx_notify(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- netsnmp_variable_list *var;
- int got_sysuptime = 0;
- extern oid sysuptime_oid[], snmptrap_oid[];
- extern size_t sysuptime_oid_len, snmptrap_oid_len;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- var = pdu->variables;
- if (!var)
- return AGENTX_ERR_PROCESSING_ERROR;
- if (snmp_oid_compare(var->name, var->name_length,
- sysuptime_oid, sysuptime_oid_len) == 0) {
- got_sysuptime = 1;
- var = var->next_variable;
- }
- if (!var || snmp_oid_compare(var->name, var->name_length,
- snmptrap_oid, snmptrap_oid_len) != 0)
- return AGENTX_ERR_PROCESSING_ERROR;
- /*
- * If sysUptime isn't the first varbind, don't worry.
- * send_trap_vars() will add it if necessary.
- *
- * Note that if this behaviour is altered, it will
- * be necessary to add sysUptime here,
- * as this is valid AgentX syntax.
- */
- send_trap_vars(-1, -1, pdu->variables);
- return AGENTX_ERR_NOERROR;
- }
- int
- agentx_ping_response(netsnmp_session * session, netsnmp_pdu *pdu)
- {
- netsnmp_session *sp;
- sp = find_agentx_session(session, pdu->sessid);
- if (sp == NULL)
- return AGENTX_ERR_NOT_OPEN;
- else
- return AGENTX_ERR_NOERROR;
- }
- int
- handle_master_agentx_packet(int operation,
- netsnmp_session * session,
- int reqid, netsnmp_pdu *pdu, void *magic)
- {
- netsnmp_agent_session *asp;
- struct timeval now;
- if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
- DEBUGMSGTL(("agentx/master",
- "transport disconnect on session %08pn", session));
- /*
- * Shut this session down gracefully.
- */
- close_agentx_session(session, -1);
- return 1;
- } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
- DEBUGMSGTL(("agentx/master", "unexpected callback op %dn",
- 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%x,trans=0x%x,sess=0x%x)n",
- pdu->reqid,pdu->transid, 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;
- }
- gettimeofday(&now, NULL);
- asp->pdu->time = calculate_time_diff(&now, &starttime);
- asp->pdu->command = AGENTX_MSG_RESPONSE;
- asp->pdu->errstat = asp->status;
- DEBUGMSGTL(("agentx/master", "send response, stat %d (req=0x%x,trans="
- "0x%x,sess=0x%x)n",
- asp->status, pdu->reqid,pdu->transid, 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 %sn", pe, pse, eb));
- free(eb);
- }
- asp->pdu = NULL;
- free_agent_snmp_session(asp);
- return 1;
- }