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

SNMP编程

开发平台:

Unix_Linux

  1. #include <net-snmp/net-snmp-config.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <ctype.h>
  5. #include <errno.h>
  6. #if HAVE_STRING_H
  7. #include <string.h>
  8. #else
  9. #include <strings.h>
  10. #endif
  11. #if HAVE_STDLIB_H
  12. #include <stdlib.h>
  13. #endif
  14. #if HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. #if HAVE_SYS_SOCKET_H
  18. #include <sys/socket.h>
  19. #endif
  20. #if HAVE_SYS_UN_H
  21. #include <sys/un.h>
  22. #endif
  23. #if HAVE_DMALLOC_H
  24. #include <dmalloc.h>
  25. #endif
  26. #include <net-snmp/types.h>
  27. #include <net-snmp/output_api.h>
  28. #include <net-snmp/config_api.h>
  29. #include <net-snmp/library/snmp_transport.h>
  30. #include <net-snmp/library/snmpUnixDomain.h>
  31. #ifndef NETSNMP_STREAM_QUEUE_LEN
  32. #define NETSNMP_STREAM_QUEUE_LEN  5
  33. #endif
  34. #ifndef SUN_LEN
  35. /*
  36.  * Evaluate to actual length of the `sockaddr_un' structure.
  37.  */
  38. #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)         
  39.                       + strlen ((ptr)->sun_path))
  40. #endif
  41. oid netsnmp_UnixDomain[] = { TRANSPORT_DOMAIN_LOCAL };
  42. static netsnmp_tdomain unixDomain;
  43. /*
  44.  * This is the structure we use to hold transport-specific data.
  45.  */
  46. typedef struct _sockaddr_un_pair {
  47.     int             local;
  48.     struct sockaddr_un server;
  49.     struct sockaddr_un client;
  50. } sockaddr_un_pair;
  51. /*
  52.  * Return a string representing the address in data, or else the "far end"
  53.  * address if data is NULL.
  54.  */
  55. static char *
  56. netsnmp_unix_fmtaddr(netsnmp_transport *t, void *data, int len)
  57. {
  58.     struct sockaddr_un *to = NULL;
  59.     if (data != NULL) {
  60.         to = (struct sockaddr_un *) data;
  61.     } else if (t != NULL && t->data != NULL) {
  62.         to = &(((sockaddr_un_pair *) t->data)->server);
  63.         len = SUN_LEN(to);
  64.     }
  65.     if (to == NULL) {
  66.         /*
  67.          * "Local IPC" is the Posix.1g term for Unix domain protocols,
  68.          * according to W. R. Stevens, ``Unix Network Programming Volume I
  69.          * Second Edition'', p. 374.
  70.          */
  71.         return strdup("Local IPC: unknown");
  72.     } else if (to->sun_path[0] == 0) {
  73.         /*
  74.          * This is an abstract name.  We could render it as hex or something
  75.          * but let's not worry about that for now.
  76.          */
  77.         return strdup("Local IPC: abstract");
  78.     } else {
  79.         char           *tmp = (char *) malloc(16 + len);
  80.         if (tmp != NULL) {
  81.             sprintf(tmp, "Local IPC: %s", to->sun_path);
  82.         }
  83.         return tmp;
  84.     }
  85. }
  86. /*
  87.  * You can write something into opaque that will subsequently get passed back
  88.  * to your send function if you like.  For instance, you might want to
  89.  * remember where a PDU came from, so that you can send a reply there...
  90.  */
  91. static int
  92. netsnmp_unix_recv(netsnmp_transport *t, void *buf, int size,
  93.                   void **opaque, int *olength)
  94. {
  95.     int rc = -1;
  96.     socklen_t       tolen = sizeof(struct sockaddr_un);
  97.     struct sockaddr *to;
  98.     if (t != NULL && t->sock >= 0) {
  99.         to = (struct sockaddr *) malloc(sizeof(struct sockaddr_un));
  100.         if (to == NULL) {
  101.             *opaque = NULL;
  102.             *olength = 0;
  103.             return -1;
  104.         } else {
  105.             memset(to, 0, tolen);
  106.         }
  107.         if(getsockname(t->sock, to, &tolen) != 0){
  108.             free(to);
  109.             *opaque = NULL;
  110.             *olength = 0;
  111.             return -1;
  112.         };
  113.         while (rc < 0) {
  114.             rc = recv(t->sock, buf, size, 0);
  115.             if (rc < 0 && errno != EINTR) {
  116.                 DEBUGMSGTL(("netsnmp_unix", "recv fd %d err %d ("%s")n",
  117.                             t->sock, errno, strerror(errno)));
  118.                 return rc;
  119.             }
  120.             *opaque = (void*)to;
  121.             *olength = sizeof(struct sockaddr_un);
  122.         }
  123.         DEBUGMSGTL(("netsnmp_unix", "recv fd %d got %d bytesn", t->sock, rc));
  124.     }
  125.     return rc;
  126. }
  127. static int
  128. netsnmp_unix_send(netsnmp_transport *t, void *buf, int size,
  129.                   void **opaque, int *olength)
  130. {
  131.     int rc = -1;
  132.     if (t != NULL && t->sock >= 0) {
  133.         DEBUGMSGTL(("netsnmp_unix", "send %d bytes to %p on fd %dn",
  134.                     size, buf, t->sock));
  135.         while (rc < 0) {
  136.             rc = send(t->sock, buf, size, 0);
  137.             if (rc < 0 && errno != EINTR) {
  138.                 break;
  139.             }
  140.         }
  141.     }
  142.     return rc;
  143. }
  144. static int
  145. netsnmp_unix_close(netsnmp_transport *t)
  146. {
  147.     int rc = 0;
  148.     sockaddr_un_pair *sup = (sockaddr_un_pair *) t->data;
  149.     if (t->sock >= 0) {
  150. #ifndef HAVE_CLOSESOCKET
  151.         rc = close(t->sock);
  152. #else
  153.         rc = closesocket(t->sock);
  154. #endif
  155.         t->sock = -1;
  156.         if (sup != NULL) {
  157.             if (sup->local) {
  158.                 if (sup->server.sun_path[0] != 0) {
  159.                   DEBUGMSGTL(("netsnmp_unix", "close: server unlink("%s")n",
  160.                               sup->server.sun_path));
  161.                   unlink(sup->server.sun_path);
  162.                 }
  163.             } else {
  164.                 if (sup->client.sun_path[0] != 0) {
  165.                   DEBUGMSGTL(("netsnmp_unix", "close: client unlink("%s")n",
  166.                               sup->client.sun_path));
  167.                   unlink(sup->client.sun_path);
  168.                 }
  169.             }
  170.         }
  171.         return rc;
  172.     } else {
  173.         return -1;
  174.     }
  175. }
  176. static int
  177. netsnmp_unix_accept(netsnmp_transport *t)
  178. {
  179.     struct sockaddr *farend = NULL;
  180.     int             newsock = -1;
  181.     socklen_t       farendlen = sizeof(struct sockaddr_un);
  182.     farend = (struct sockaddr *) malloc(farendlen);
  183.     if (farend == NULL) {
  184.         /*
  185.          * Indicate that the acceptance of this socket failed.
  186.          */
  187.         DEBUGMSGTL(("netsnmp_unix", "accept: malloc failedn"));
  188.         return -1;
  189.     }
  190.     memset(farend, 0, farendlen);
  191.     if (t != NULL && t->sock >= 0) {
  192.         newsock = accept(t->sock, farend, &farendlen);
  193.         if (newsock < 0) {
  194.             DEBUGMSGTL(("netsnmp_unix","accept failed rc %d errno %d "%s"n",
  195.                         newsock, errno, strerror(errno)));
  196.             free(farend);
  197.             return newsock;
  198.         }
  199.         if (t->data != NULL) {
  200.             free(t->data);
  201.         }
  202.         DEBUGMSGTL(("netsnmp_unix", "accept succeeded (farend %p len %d)n",
  203.                     farend, farendlen));
  204.         t->data = farend;
  205.         t->data_length = sizeof(struct sockaddr_un);
  206.         return newsock;
  207.     } else {
  208.         free(farend);
  209.         return -1;
  210.     }
  211. }
  212. /*
  213.  * Open a Unix-domain transport for SNMP.  Local is TRUE if addr is the local
  214.  * address to bind to (i.e. this is a server-type session); otherwise addr is
  215.  * the remote address to send things to (and we make up a temporary name for
  216.  * the local end of the connection).
  217.  */
  218. netsnmp_transport *
  219. netsnmp_unix_transport(struct sockaddr_un *addr, int local)
  220. {
  221.     netsnmp_transport *t = NULL;
  222.     sockaddr_un_pair *sup = NULL;
  223.     int             rc = 0;
  224.     char           *str = NULL;
  225.     if (addr == NULL || addr->sun_family != AF_UNIX) {
  226.         return NULL;
  227.     }
  228.     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
  229.     if (t == NULL) {
  230.         return NULL;
  231.     }
  232.     str = netsnmp_unix_fmtaddr(NULL, (void *)addr,
  233.                                   sizeof(struct sockaddr_un));
  234.     DEBUGMSGTL(("netsnmp_unix", "open %s %sn", local ? "local" : "remote",
  235.                 str));
  236.     free(str);
  237.     memset(t, 0, sizeof(netsnmp_transport));
  238.     t->domain = netsnmp_UnixDomain;
  239.     t->domain_length =
  240.         sizeof(netsnmp_UnixDomain) / sizeof(netsnmp_UnixDomain[0]);
  241.     t->data = malloc(sizeof(sockaddr_un_pair));
  242.     if (t->data == NULL) {
  243.         netsnmp_transport_free(t);
  244.         return NULL;
  245.     }
  246.     memset(t->data, 0, sizeof(sockaddr_un_pair));
  247.     t->data_length = sizeof(sockaddr_un_pair);
  248.     sup = (sockaddr_un_pair *) t->data;
  249.     t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
  250.     if (t->sock < 0) {
  251.         netsnmp_transport_free(t);
  252.         return NULL;
  253.     }
  254.     t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;
  255.     if (local) {
  256.         t->local = malloc(strlen(addr->sun_path));
  257.         if (t->local == NULL) {
  258.             netsnmp_transport_free(t);
  259.             return NULL;
  260.         }
  261.         memcpy(t->local, addr->sun_path, strlen(addr->sun_path));
  262.         t->local_length = strlen(addr->sun_path);
  263.         /*
  264.          * This session is inteneded as a server, so we must bind to the given
  265.          * path (unlinking it first, to avoid errors).
  266.          */
  267.         t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
  268.         unlink(addr->sun_path);
  269.         rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
  270.         if (rc != 0) {
  271.             DEBUGMSGTL(("netsnmp_unix_transport",
  272.                         "couldn't bind "%s", errno %d (%s)n",
  273.                         addr->sun_path, errno, strerror(errno)));
  274.             netsnmp_unix_close(t);
  275.             netsnmp_transport_free(t);
  276.             return NULL;
  277.         }
  278.         /*
  279.          * Save the address in the transport-specific data pointer for later
  280.          * use by netsnmp_unix_close.
  281.          */
  282.         sup->server.sun_family = AF_UNIX;
  283.         strcpy(sup->server.sun_path, addr->sun_path);
  284.         sup->local = 1;
  285.         /*
  286.          * Now sit here and listen for connections to arrive.
  287.          */
  288.         rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
  289.         if (rc != 0) {
  290.             DEBUGMSGTL(("netsnmp_unix_transport",
  291.                         "couldn't listen to "%s", errno %d (%s)n",
  292.                         addr->sun_path, errno, strerror(errno)));
  293.             netsnmp_unix_close(t);
  294.             netsnmp_transport_free(t);
  295.         }
  296.     } else {
  297.         t->remote = malloc(strlen(addr->sun_path));
  298.         if (t->remote == NULL) {
  299.             netsnmp_transport_free(t);
  300.             return NULL;
  301.         }
  302.         memcpy(t->remote, addr->sun_path, strlen(addr->sun_path));
  303.         t->remote_length = strlen(addr->sun_path);
  304.         rc = connect(t->sock, (struct sockaddr *) addr,
  305.                      sizeof(struct sockaddr_un));
  306.         if (rc != 0) {
  307.             DEBUGMSGTL(("netsnmp_unix_transport",
  308.                         "couldn't connect to "%s", errno %d (%s)n",
  309.                         addr->sun_path, errno, strerror(errno)));
  310.             netsnmp_unix_close(t);
  311.             netsnmp_transport_free(t);
  312.             return NULL;
  313.         }
  314.         /*
  315.          * Save the remote address in the transport-specific data pointer for
  316.          * later use by netsnmp_unix_send.
  317.          */
  318.         sup->server.sun_family = AF_UNIX;
  319.         strcpy(sup->server.sun_path, addr->sun_path);
  320.         sup->local = 0;
  321.     }
  322.     /*
  323.      * Message size is not limited by this transport (hence msgMaxSize
  324.      * is equal to the maximum legal size of an SNMP message).
  325.      */
  326.     t->msgMaxSize = 0x7fffffff;
  327.     t->f_recv     = netsnmp_unix_recv;
  328.     t->f_send     = netsnmp_unix_send;
  329.     t->f_close    = netsnmp_unix_close;
  330.     t->f_accept   = netsnmp_unix_accept;
  331.     t->f_fmtaddr  = netsnmp_unix_fmtaddr;
  332.     return t;
  333. }
  334. netsnmp_transport *
  335. netsnmp_unix_create_tstring(const char *str, int local)
  336. {
  337.     struct sockaddr_un addr;
  338.     if ((str != NULL) && (strlen(str) < sizeof(addr.sun_path))) {
  339.         addr.sun_family = AF_UNIX;
  340.         memset(addr.sun_path, 0, sizeof(addr.sun_path));
  341.         strncpy(addr.sun_path, str, sizeof(addr.sun_path) - 1);
  342.         return netsnmp_unix_transport(&addr, local);
  343.     } else {
  344.         if (str != NULL) {
  345.             snmp_log(LOG_ERR, "Path too long for Unix domain transportn");
  346.         }
  347.         return NULL;
  348.     }
  349. }
  350. netsnmp_transport *
  351. netsnmp_unix_create_ostring(const u_char * o, size_t o_len, int local)
  352. {
  353.     struct sockaddr_un addr;
  354.     if (o_len > 0 && o_len < (sizeof(addr.sun_path) - 1)) {
  355.         addr.sun_family = AF_UNIX;
  356.         memset(addr.sun_path, 0, sizeof(addr.sun_path));
  357.         strncpy(addr.sun_path, o, o_len);
  358.         return netsnmp_unix_transport(&addr, local);
  359.     } else {
  360.         if (o_len > 0) {
  361.             snmp_log(LOG_ERR, "Path too long for Unix domain transportn");
  362.         }
  363.     }
  364.     return NULL;
  365. }
  366. void
  367. netsnmp_unix_ctor(void)
  368. {
  369.     unixDomain.name = netsnmp_UnixDomain;
  370.     unixDomain.name_length = sizeof(netsnmp_UnixDomain) / sizeof(oid);
  371.     unixDomain.prefix = calloc(2, sizeof(char *));
  372.     unixDomain.prefix[0] = "unix";
  373.     unixDomain.f_create_from_tstring = netsnmp_unix_create_tstring;
  374.     unixDomain.f_create_from_ostring = netsnmp_unix_create_ostring;
  375.     netsnmp_tdomain_register(&unixDomain);
  376. }
  377. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  378. /* support for SNMPv1 and SNMPv2c on unix domain*/
  379. #define EXAMPLE_COMMUNITY "COMMUNITY"
  380. typedef struct _com2SecUnixEntry {
  381.     char            community[VACMSTRINGLEN];
  382.     char            sockpath[sizeof(struct sockaddr_un)];
  383.     unsigned long   pathlen;
  384.     char            secName[VACMSTRINGLEN];
  385.     char            contextName[VACMSTRINGLEN];
  386.     struct _com2SecUnixEntry *next;
  387. } com2SecUnixEntry;
  388. com2SecUnixEntry   *com2SecUnixList = NULL, *com2SecUnixListLast = NULL;
  389. int
  390. netsnmp_unix_getSecName(void *opaque, int olength,
  391.                         const char *community,
  392.                         size_t community_len,
  393.                         char **secName, char **contextName)
  394. {
  395.     com2SecUnixEntry   *c;
  396.     struct sockaddr_un *to = (struct sockaddr_un *) opaque;
  397.     char           *ztcommunity = NULL;
  398.     if (secName != NULL) {
  399.         *secName = NULL;  /* Haven't found anything yet */
  400.     }
  401.     /*
  402.      * Special case if there are NO entries (as opposed to no MATCHING
  403.      * entries).
  404.      */
  405.     if (com2SecUnixList == NULL) {
  406.         DEBUGMSGTL(("netsnmp_unix_getSecName", "no com2sec entriesn"));
  407.         return 0;
  408.     }
  409.     /*
  410.      * If there is no unix socket path, then there can be no valid security
  411.      * name.
  412.      */
  413.     if (opaque == NULL || olength != sizeof(struct sockaddr_un) ||
  414.         to->sun_family != AF_UNIX) {
  415.         DEBUGMSGTL(("netsnmp_unix_getSecName",
  416.                     "no unix destine address in PDU?n"));
  417.         return 1;
  418.     }
  419.     DEBUGIF("netsnmp_unix_getSecName") {
  420.         ztcommunity = (char *)malloc(community_len + 1);
  421.         if (ztcommunity != NULL) {
  422.             memcpy(ztcommunity, community, community_len);
  423.             ztcommunity[community_len] = '';
  424.         }
  425.         DEBUGMSGTL(("netsnmp_unix_getSecName", "resolve <"%s">n",
  426.                     ztcommunity ? ztcommunity : "<malloc error>"));
  427.     }
  428.     for (c = com2SecUnixList; c != NULL; c = c->next) {
  429.         DEBUGMSGTL(("netsnmp_unix_getSecName","compare <"%s",to socket %s>",
  430.                     c->community, c->sockpath ));
  431.         if ((community_len == strlen(c->community)) &&
  432.             (memcmp(community, c->community, community_len) == 0) &&
  433.             /* compare sockpath, if pathlen == 0, always match */
  434.             (strlen(to->sun_path) == c->pathlen || c->pathlen == 0) &&
  435.             (memcmp(to->sun_path, c->sockpath, c->pathlen) == 0)
  436.             ) {
  437.             DEBUGMSG(("netsnmp_unix_getSecName", "... SUCCESSn"));
  438.             if (secName != NULL) {
  439.                 *secName = c->secName;
  440.                 *contextName = c->contextName;
  441.             }
  442.             break;
  443.         }
  444.         DEBUGMSG(("netsnmp_unix_getSecName", "... nopen"));
  445.     }
  446.     if (ztcommunity != NULL) {
  447.         free(ztcommunity);
  448.     }
  449.     return 1;
  450. }
  451. void
  452. netsnmp_unix_parse_security(const char *token, char *param)
  453. {
  454.     char              secName[VACMSTRINGLEN + 1], community[VACMSTRINGLEN + 1];
  455.     char              contextName[VACMSTRINGLEN + 1];
  456.     char              sockpath[sizeof(struct sockaddr_un) + 1];
  457.     com2SecUnixEntry *e = NULL;
  458.     param = copy_nword(param, secName, VACMSTRINGLEN);
  459.     if (strcmp(secName, "-Cn") == 0) {
  460.         if (!secName) {
  461.             config_perror("missing CONTEXT_NAME parameter");
  462.             return;
  463.         }
  464.         param = copy_nword( param, contextName, sizeof(contextName));
  465.         param = copy_nword( param, secName, sizeof(secName));
  466.     } else {
  467.         contextName[0] = '';
  468.     }
  469.     if (secName[0] == '') {
  470.         config_perror("missing NAME parameter");
  471.         return;
  472.     } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
  473.         config_perror("security name too long");
  474.         return;
  475.     }
  476.         param = copy_nword(param, sockpath, sizeof(struct sockaddr_un) - 1);
  477.     if (sockpath[0] == '') {
  478.         config_perror("missing SOCKPATH parameter");
  479.         return;
  480.     } else if (strlen(sockpath) > (sizeof(struct sockaddr_un) - 1)) {
  481.         config_perror("sockpath too long");
  482.         return;
  483.     }
  484.     /* if sockpath == "default", set pathlen=0*/
  485.     if(strcmp(sockpath, "default") == 0){
  486.         sockpath[0] = 0;
  487.     }
  488.     param = copy_nword(param, community, VACMSTRINGLEN);
  489.     if (community[0] == '') {
  490.         config_perror("missing COMMUNITY parametern");
  491.         return;
  492.     } else if (strncmp
  493.                (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
  494.                == 0) {
  495.         config_perror("example config COMMUNITY not properly configured");
  496.         return;
  497.     } else if (strlen(community) > (VACMSTRINGLEN - 1)) {
  498.         config_perror("community name too long");
  499.         return;
  500.     }
  501.     e = (com2SecUnixEntry *) malloc(sizeof(com2SecUnixEntry));
  502.     if (e == NULL) {
  503.         config_perror("memory error");
  504.         return;
  505.     }
  506.     DEBUGMSGTL(("netsnmp_unix_parse_security",
  507.                 "<"%s"> => "%s"n", community, secName));
  508.     strcpy(e->secName, secName);
  509.     strcpy(e->contextName, contextName);
  510.     strcpy(e->community, community);
  511.     strcpy(e->sockpath, sockpath);
  512.     e->pathlen = strlen(sockpath);
  513.     e->next = NULL;
  514.     if (com2SecUnixListLast != NULL) {
  515.         com2SecUnixListLast->next = e;
  516.         com2SecUnixListLast = e;
  517.     } else {
  518.         com2SecUnixListLast = com2SecUnixList = e;
  519.     }
  520. }
  521. void
  522. netsnmp_unix_com2SecList_free(void)
  523. {
  524.     com2SecUnixEntry   *e = com2SecUnixList;
  525.     while (e != NULL) {
  526.         com2SecUnixEntry   *tmp = e;
  527.         e = e->next;
  528.         free(tmp);
  529.     }
  530.     com2SecUnixList = com2SecUnixListLast = NULL;
  531. }
  532. #endif /* support for community based SNMP */
  533. void
  534. netsnmp_unix_agent_config_tokens_register(void)
  535. {
  536. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  537.     register_app_config_handler("com2secunix", netsnmp_unix_parse_security,
  538.                                 netsnmp_unix_com2SecList_free,
  539.                                 "[-Cn CONTEXT] secName sockpath community");
  540. #endif /* support for community based SNMP */
  541. }