master_admin.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:17k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  *  AgentX Administrative request handling
  3.  */
  4. #include <net-snmp/net-snmp-config.h>
  5. #include <sys/types.h>
  6. #ifdef HAVE_STRING_H
  7. #include <string.h>
  8. #else
  9. #include <strings.h>
  10. #endif
  11. #ifdef HAVE_STDLIB_H
  12. #include <stdlib.h>
  13. #endif
  14. #if TIME_WITH_SYS_TIME
  15. # ifdef WIN32
  16. #  include <sys/timeb.h>
  17. # else
  18. #  include <sys/time.h>
  19. # endif
  20. # include <time.h>
  21. #else
  22. # if HAVE_SYS_TIME_H
  23. #  include <sys/time.h>
  24. # else
  25. #  include <time.h>
  26. # endif
  27. #endif
  28. #if HAVE_NETINET_IN_H
  29. #include <netinet/in.h>
  30. #endif
  31. #if HAVE_WINSOCK_H
  32. #include <winsock.h>
  33. #endif
  34. #if HAVE_SYS_SOCKET_H
  35. #include <sys/socket.h>
  36. #endif
  37. #if HAVE_DMALLOC_H
  38. #include <dmalloc.h>
  39. #endif
  40. #include <net-snmp/net-snmp-includes.h>
  41. #include <net-snmp/agent/net-snmp-agent-includes.h>
  42. #include "agentx/protocol.h"
  43. #include "agentx/client.h"
  44. #include <net-snmp/agent/agent_index.h>
  45. #include <net-snmp/agent/agent_trap.h>
  46. #include <net-snmp/agent/agent_callbacks.h>
  47. #include "mibII/sysORTable.h"
  48. #include "master.h"
  49. extern struct timeval starttime;
  50. netsnmp_session *
  51. find_agentx_session(netsnmp_session * session, int sessid)
  52. {
  53.     netsnmp_session *sp;
  54.     for (sp = session->subsession; sp != NULL; sp = sp->next) {
  55.         if (sp->sessid == sessid)
  56.             return sp;
  57.     }
  58.     return NULL;
  59. }
  60. int
  61. open_agentx_session(netsnmp_session * session, netsnmp_pdu *pdu)
  62. {
  63.     netsnmp_session *sp;
  64.     struct timeval  now;
  65.     DEBUGMSGTL(("agentx/master", "open %08pn", session));
  66.     sp = (netsnmp_session *) malloc(sizeof(netsnmp_session));
  67.     if (sp == NULL) {
  68.         session->s_snmp_errno = AGENTX_ERR_OPEN_FAILED;
  69.         return -1;
  70.     }
  71.     memcpy(sp, session, sizeof(netsnmp_session));
  72.     sp->sessid = snmp_get_next_sessid();
  73.     sp->version = pdu->version;
  74.     sp->timeout = pdu->time;
  75.     /*
  76.      * Be careful with fields: if these aren't zeroed, they will get free()d
  77.      * more than once when the session is closed -- once in the main session,
  78.      * and once in each subsession.  Basically, if it's not being used for
  79.      * some AgentX-specific purpose, it ought to be zeroed here. 
  80.      */
  81.     sp->community = NULL;
  82.     sp->peername = NULL;
  83.     sp->contextEngineID = NULL;
  84.     sp->contextName = NULL;
  85.     sp->securityEngineID = NULL;
  86.     sp->securityPrivProto = NULL;
  87.     /*
  88.      * This next bit utilises unused SNMPv3 fields
  89.      *   to store the subagent OID and description.
  90.      * This really ought to use AgentX-specific fields,
  91.      *   but it hardly seems worth it for a one-off use.
  92.      *
  93.      * But I'm willing to be persuaded otherwise....  */
  94.     sp->securityAuthProto = snmp_duplicate_objid(pdu->variables->name,
  95.                                                  pdu->variables->
  96.                                                  name_length);
  97.     sp->securityAuthProtoLen = pdu->variables->name_length;
  98.     sp->securityName = strdup((char *) pdu->variables->val.string);
  99.     gettimeofday(&now, NULL);
  100.     sp->engineTime = calculate_time_diff(&now, &starttime);
  101.     sp->subsession = session;   /* link back to head */
  102.     sp->flags |= SNMP_FLAGS_SUBSESSION;
  103.     sp->flags &= ~AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER;
  104.     sp->flags |= (pdu->flags & AGENTX_MSG_FLAG_NETWORK_BYTE_ORDER);
  105.     sp->next = session->subsession;
  106.     session->subsession = sp;
  107.     DEBUGMSGTL(("agentx/master", "opened %08p = %d with flags = %02xn",
  108.                 sp, sp->sessid, sp->flags & AGENTX_MSG_FLAGS_MASK));
  109.     return sp->sessid;
  110. }
  111. int
  112. close_agentx_session(netsnmp_session * session, int sessid)
  113. {
  114.     netsnmp_session *sp, **prevNext;
  115.     DEBUGMSGTL(("agentx/master", "close %08p, %dn", session, sessid));
  116.     if (session != NULL && sessid == -1) {
  117.         unregister_mibs_by_session(session);
  118.         unregister_index_by_session(session);
  119.         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
  120.                             SNMPD_CALLBACK_REQ_UNREG_SYSOR_SESS,
  121.                             (void*)session);
  122. if (session->myvoid != NULL) {
  123.   free(session->myvoid);
  124. }
  125.         /*
  126.          * The following is necessary to avoid locking up the agent when
  127.          * a sugagent dies during a set request. We must clean up the
  128.          * requests, so that the delegated request will be completed and
  129.          * further requests can be processed
  130.          */
  131.         netsnmp_remove_delegated_requests_for_session(session);
  132.         if (session->subsession != NULL) {
  133.             netsnmp_session *subsession = session->subsession;
  134.             for(; subsession; subsession = subsession->next) {
  135.                 netsnmp_remove_delegated_requests_for_session(subsession);
  136.             }
  137.         }
  138.                 
  139.         return AGENTX_ERR_NOERROR;
  140.     }
  141.     prevNext = &(session->subsession);
  142.     for (sp = session->subsession; sp != NULL; sp = sp->next) {
  143.         if (sp->sessid == sessid) {
  144.             unregister_mibs_by_session(sp);
  145.             unregister_index_by_session(sp);
  146.             snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
  147.                                 SNMPD_CALLBACK_REQ_UNREG_SYSOR_SESS,
  148.                                 (void*)sp);
  149.             *prevNext = sp->next;
  150.             if (sp->securityAuthProto != NULL) {
  151.                 free(sp->securityAuthProto);
  152.             }
  153.             if (sp->securityName != NULL) {
  154.                 free(sp->securityName);
  155.             }
  156.             free(sp);
  157.             sp = NULL;
  158.             DEBUGMSGTL(("agentx/master", "closed %08p, %d okayn",
  159.                         session, sessid));
  160.             return AGENTX_ERR_NOERROR;
  161.         }
  162.         prevNext = &(sp->next);
  163.     }
  164.     DEBUGMSGTL(("agentx/master", "sessid %d not foundn", sessid));
  165.     return AGENTX_ERR_NOT_OPEN;
  166. }
  167. int
  168. register_agentx_list(netsnmp_session * session, netsnmp_pdu *pdu)
  169. {
  170.     netsnmp_session *sp;
  171.     char            buf[128];
  172.     oid             ubound = 0;
  173.     u_long          flags = 0;
  174.     netsnmp_handler_registration *reg;
  175.     int             rc = 0;
  176.     int             cacheid;
  177.     DEBUGMSGTL(("agentx/master", "in register_agentx_listn"));
  178.     sp = find_agentx_session(session, pdu->sessid);
  179.     if (sp == NULL)
  180.         return AGENTX_ERR_NOT_OPEN;
  181.     sprintf(buf, "AgentX subagent %ld, session %8p, subsession %8p",
  182.             sp->sessid, session, sp);
  183.     /*
  184.      * * TODO: registration timeout
  185.      * *   registration context
  186.      */
  187.     if (pdu->range_subid) {
  188.         ubound = pdu->variables->val.objid[pdu->range_subid - 1];
  189.     }
  190.     if (pdu->flags & AGENTX_MSG_FLAG_INSTANCE_REGISTER) {
  191.         flags = FULLY_QUALIFIED_INSTANCE;
  192.     }
  193.     reg = netsnmp_create_handler_registration(buf, agentx_master_handler, pdu->variables->name, pdu->variables->name_length, HANDLER_CAN_RWRITE | HANDLER_CAN_GETBULK); /* fake it */
  194.     if (!session->myvoid) {
  195.         session->myvoid = malloc(sizeof(cacheid));
  196.         cacheid = netsnmp_allocate_globalcacheid();
  197.         *((int *) session->myvoid) = cacheid;
  198.     } else {
  199.         cacheid = *((int *) session->myvoid);
  200.     }
  201.     reg->handler->myvoid = session;
  202.     reg->global_cacheid = cacheid;
  203.     if (NULL != pdu->community)
  204.         reg->contextName = strdup(pdu->community);
  205.     /*
  206.      * register mib. Note that for failure cases, the registration info
  207.      * (reg) will be freed, and thus is no longer a valid pointer.
  208.      */
  209.     switch (netsnmp_register_mib(buf, NULL, 0, 1,
  210.                                  pdu->variables->name,
  211.                                  pdu->variables->name_length,
  212.                                  pdu->priority, pdu->range_subid, ubound,
  213.                                  sp, (char *) pdu->community, pdu->time,
  214.                                  flags, reg, 1)) {
  215.     case MIB_REGISTERED_OK:
  216.         DEBUGMSGTL(("agentx/master", "registered okn"));
  217.         return AGENTX_ERR_NOERROR;
  218.     case MIB_DUPLICATE_REGISTRATION:
  219.         DEBUGMSGTL(("agentx/master", "duplicate registrationn"));
  220.         rc = AGENTX_ERR_DUPLICATE_REGISTRATION;
  221.         break;
  222.     case MIB_REGISTRATION_FAILED:
  223.     default:
  224.         rc = AGENTX_ERR_REQUEST_DENIED;
  225.         DEBUGMSGTL(("agentx/master", "failed registrationn"));
  226.     }
  227.     return rc;
  228. }
  229. int
  230. unregister_agentx_list(netsnmp_session * session, netsnmp_pdu *pdu)
  231. {
  232.     netsnmp_session *sp;
  233.     int             rc = 0;
  234.     sp = find_agentx_session(session, pdu->sessid);
  235.     if (sp == NULL) {
  236.         return AGENTX_ERR_NOT_OPEN;
  237.     }
  238.     if (pdu->range_subid != 0) {
  239.         oid             ubound =
  240.             pdu->variables->val.objid[pdu->range_subid - 1];
  241.         rc = netsnmp_unregister_mib_table_row(pdu->variables->name,
  242.                                               pdu->variables->name_length,
  243.                                               pdu->priority,
  244.                                               pdu->range_subid, ubound,
  245.                                               (char *) pdu->community);
  246.     } else {
  247.         rc = unregister_mib_context(pdu->variables->name,
  248.                                     pdu->variables->name_length,
  249.                                     pdu->priority, 0, 0,
  250.                                     (char *) pdu->community);
  251.     }
  252.     switch (rc) {
  253.     case MIB_UNREGISTERED_OK:
  254.         return AGENTX_ERR_NOERROR;
  255.     case MIB_NO_SUCH_REGISTRATION:
  256.         return AGENTX_ERR_UNKNOWN_REGISTRATION;
  257.     case MIB_UNREGISTRATION_FAILED:
  258.     default:
  259.         return AGENTX_ERR_REQUEST_DENIED;
  260.     }
  261. }
  262. int
  263. allocate_idx_list(netsnmp_session * session, netsnmp_pdu *pdu)
  264. {
  265.     netsnmp_session *sp;
  266.     netsnmp_variable_list *vp, *vp2, *next, *res;
  267.     int             flags = 0;
  268.     sp = find_agentx_session(session, pdu->sessid);
  269.     if (sp == NULL)
  270.         return AGENTX_ERR_NOT_OPEN;
  271.     if (pdu->flags & AGENTX_MSG_FLAG_ANY_INSTANCE)
  272.         flags |= ALLOCATE_ANY_INDEX;
  273.     if (pdu->flags & AGENTX_MSG_FLAG_NEW_INSTANCE)
  274.         flags |= ALLOCATE_NEW_INDEX;
  275.     /*
  276.      * XXX - what about errors?
  277.      *
  278.      *  If any allocations fail, then we need to
  279.      *    *fully* release the earlier ones.
  280.      *  (i.e. remove them completely from the index registry,
  281.      *    not simply mark them as available for re-use)
  282.      *
  283.      * For now - assume they all succeed.
  284.      */
  285.     for (vp = pdu->variables; vp != NULL; vp = next) {
  286.         next = vp->next_variable;
  287.         res = register_index(vp, flags, session);
  288.         if (res == NULL) {
  289.             /*
  290.              *  If any allocations fail, we need to *fully* release
  291.              *      all previous ones (i.e. remove them completely
  292.              *      from the index registry)
  293.              */
  294.             for (vp2 = pdu->variables; vp2 != vp; vp2 = vp2->next_variable) {
  295.                 remove_index(vp2, session);
  296.             }
  297.             return AGENTX_ERR_INDEX_NONE_AVAILABLE;     /* XXX */
  298.         } else {
  299.             (void) snmp_clone_var(res, vp);
  300.             free(res);
  301.         }
  302.         vp->next_variable = next;
  303.     }
  304.     return AGENTX_ERR_NOERROR;
  305. }
  306. int
  307. release_idx_list(netsnmp_session * session, netsnmp_pdu *pdu)
  308. {
  309.     netsnmp_session *sp;
  310.     netsnmp_variable_list *vp, *vp2, *rv = NULL;
  311.     int             res;
  312.     sp = find_agentx_session(session, pdu->sessid);
  313.     if (sp == NULL)
  314.         return AGENTX_ERR_NOT_OPEN;
  315.     for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
  316.         res = unregister_index(vp, TRUE, session);
  317.         /*
  318.          *  If any releases fail,
  319.          *      we need to reinstate all previous ones.
  320.          */
  321.         if (res != SNMP_ERR_NOERROR) {
  322.             for (vp2 = pdu->variables; vp2 != vp; vp2 = vp2->next_variable) {
  323.                 rv = register_index(vp2, ALLOCATE_THIS_INDEX, session);
  324.                 free(rv);
  325.             }
  326.             return AGENTX_ERR_INDEX_NOT_ALLOCATED;      /* Probably */
  327.         }
  328.     }
  329.     return AGENTX_ERR_NOERROR;
  330. }
  331. int
  332. add_agent_caps_list(netsnmp_session * session, netsnmp_pdu *pdu)
  333. {
  334.     netsnmp_session *sp;
  335.     struct sysORTable parms;
  336.     sp = find_agentx_session(session, pdu->sessid);
  337.     if (sp == NULL)
  338.         return AGENTX_ERR_NOT_OPEN;
  339.     parms.OR_oid = pdu->variables->name;
  340.     parms.OR_oidlen = pdu->variables->name_length;
  341.     parms.OR_descr = (char *) pdu->variables->val.string;
  342.     parms.OR_sess = sp;
  343.     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
  344.                         SNMPD_CALLBACK_REQ_REG_SYSOR, (void*)&parms);
  345.     return AGENTX_ERR_NOERROR;
  346. }
  347. int
  348. remove_agent_caps_list(netsnmp_session * session, netsnmp_pdu *pdu)
  349. {
  350.     netsnmp_session *sp;
  351.     struct sysORTable parms;
  352.     sp = find_agentx_session(session, pdu->sessid);
  353.     if (sp == NULL)
  354.         return AGENTX_ERR_NOT_OPEN;
  355.     parms.OR_oid = pdu->variables->name;
  356.     parms.OR_oidlen = pdu->variables->name_length;
  357.     parms.OR_sess = sp;
  358.     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
  359.                         SNMPD_CALLBACK_REQ_UNREG_SYSOR, (void*)&parms);
  360.     /*
  361.      * no easy way to get an error code...
  362.      * if (rc < 0)
  363.      *   return AGENTX_ERR_UNKNOWN_AGENTCAPS;
  364.      */
  365.     return AGENTX_ERR_NOERROR;
  366. }
  367. int
  368. agentx_notify(netsnmp_session * session, netsnmp_pdu *pdu)
  369. {
  370.     netsnmp_session *sp;
  371.     netsnmp_variable_list *var;
  372.     int             got_sysuptime = 0;
  373.     extern oid      sysuptime_oid[], snmptrap_oid[];
  374.     extern size_t   sysuptime_oid_len, snmptrap_oid_len;
  375.     sp = find_agentx_session(session, pdu->sessid);
  376.     if (sp == NULL)
  377.         return AGENTX_ERR_NOT_OPEN;
  378.     var = pdu->variables;
  379.     if (!var)
  380.         return AGENTX_ERR_PROCESSING_ERROR;
  381.     if (snmp_oid_compare(var->name, var->name_length,
  382.                          sysuptime_oid, sysuptime_oid_len) == 0) {
  383.         got_sysuptime = 1;
  384.         var = var->next_variable;
  385.     }
  386.     if (!var || snmp_oid_compare(var->name, var->name_length,
  387.                                  snmptrap_oid, snmptrap_oid_len) != 0)
  388.         return AGENTX_ERR_PROCESSING_ERROR;
  389.     /*
  390.      *  If sysUptime isn't the first varbind, don't worry.  
  391.      *     send_trap_vars() will add it if necessary.
  392.      *
  393.      *  Note that if this behaviour is altered, it will
  394.      *     be necessary to add sysUptime here,
  395.      *     as this is valid AgentX syntax.
  396.      */
  397.     send_trap_vars(-1, -1, pdu->variables);
  398.     return AGENTX_ERR_NOERROR;
  399. }
  400. int
  401. agentx_ping_response(netsnmp_session * session, netsnmp_pdu *pdu)
  402. {
  403.     netsnmp_session *sp;
  404.     sp = find_agentx_session(session, pdu->sessid);
  405.     if (sp == NULL)
  406.         return AGENTX_ERR_NOT_OPEN;
  407.     else
  408.         return AGENTX_ERR_NOERROR;
  409. }
  410. int
  411. handle_master_agentx_packet(int operation,
  412.                             netsnmp_session * session,
  413.                             int reqid, netsnmp_pdu *pdu, void *magic)
  414. {
  415.     netsnmp_agent_session *asp;
  416.     struct timeval  now;
  417.     if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
  418.         DEBUGMSGTL(("agentx/master",
  419.                     "transport disconnect on session %08pn", session));
  420.         /*
  421.          * Shut this session down gracefully.  
  422.          */
  423.         close_agentx_session(session, -1);
  424.         return 1;
  425.     } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
  426.         DEBUGMSGTL(("agentx/master", "unexpected callback op %dn",
  427.                     operation));
  428.         return 1;
  429.     }
  430.     /*
  431.      * Okay, it's a NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE op.  
  432.      */
  433.     if (magic) {
  434.         asp = (netsnmp_agent_session *) magic;
  435.     } else {
  436.         asp = init_agent_snmp_session(session, pdu);
  437.     }
  438.     DEBUGMSGTL(("agentx/master", "handle pdu (req=0x%x,trans=0x%x,sess=0x%x)n",
  439.                 pdu->reqid,pdu->transid, pdu->sessid));
  440.     
  441.     switch (pdu->command) {
  442.     case AGENTX_MSG_OPEN:
  443.         asp->pdu->sessid = open_agentx_session(session, pdu);
  444.         if (asp->pdu->sessid == -1)
  445.             asp->status = session->s_snmp_errno;
  446.         break;
  447.     case AGENTX_MSG_CLOSE:
  448.         asp->status = close_agentx_session(session, pdu->sessid);
  449.         break;
  450.     case AGENTX_MSG_REGISTER:
  451.         asp->status = register_agentx_list(session, pdu);
  452.         break;
  453.     case AGENTX_MSG_UNREGISTER:
  454.         asp->status = unregister_agentx_list(session, pdu);
  455.         break;
  456.     case AGENTX_MSG_INDEX_ALLOCATE:
  457.         asp->status = allocate_idx_list(session, asp->pdu);
  458.         if (asp->status != AGENTX_ERR_NOERROR) {
  459.             snmp_free_pdu(asp->pdu);
  460.             asp->pdu = snmp_clone_pdu(pdu);
  461.         }
  462.         break;
  463.     case AGENTX_MSG_INDEX_DEALLOCATE:
  464.         asp->status = release_idx_list(session, pdu);
  465.         break;
  466.     case AGENTX_MSG_ADD_AGENT_CAPS:
  467.         asp->status = add_agent_caps_list(session, pdu);
  468.         break;
  469.     case AGENTX_MSG_REMOVE_AGENT_CAPS:
  470.         asp->status = remove_agent_caps_list(session, pdu);
  471.         break;
  472.     case AGENTX_MSG_NOTIFY:
  473.         asp->status = agentx_notify(session, pdu);
  474.         break;
  475.     case AGENTX_MSG_PING:
  476.         asp->status = agentx_ping_response(session, pdu);
  477.         break;
  478.         /*
  479.          * TODO: Other admin packets 
  480.          */
  481.     case AGENTX_MSG_GET:
  482.     case AGENTX_MSG_GETNEXT:
  483.     case AGENTX_MSG_GETBULK:
  484.     case AGENTX_MSG_TESTSET:
  485.     case AGENTX_MSG_COMMITSET:
  486.     case AGENTX_MSG_UNDOSET:
  487.     case AGENTX_MSG_CLEANUPSET:
  488.     case AGENTX_MSG_RESPONSE:
  489.         /*
  490.          * Shouldn't be handled here 
  491.          */
  492.         break;
  493.     default:
  494.         asp->status = AGENTX_ERR_PARSE_FAILED;
  495.         break;
  496.     }
  497.     gettimeofday(&now, NULL);
  498.     asp->pdu->time = calculate_time_diff(&now, &starttime);
  499.     asp->pdu->command = AGENTX_MSG_RESPONSE;
  500.     asp->pdu->errstat = asp->status;
  501.     DEBUGMSGTL(("agentx/master", "send response, stat %d (req=0x%x,trans="
  502.                 "0x%x,sess=0x%x)n",
  503.                 asp->status, pdu->reqid,pdu->transid, pdu->sessid));
  504.     if (!snmp_send(asp->session, asp->pdu)) {
  505.         char           *eb = NULL;
  506.         int             pe, pse;
  507.         snmp_error(asp->session, &pe, &pse, &eb);
  508.         snmp_free_pdu(asp->pdu);
  509.         DEBUGMSGTL(("agentx/master", "FAILED %d %d %sn", pe, pse, eb));
  510.         free(eb);
  511.     }
  512.     asp->pdu = NULL;
  513.     free_agent_snmp_session(asp);
  514.     return 1;
  515. }