summaryrefslogtreecommitdiff
path: root/agent/mibgroup/ucd-snmp/pass.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/ucd-snmp/pass.c')
-rw-r--r--agent/mibgroup/ucd-snmp/pass.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/pass.c b/agent/mibgroup/ucd-snmp/pass.c
new file mode 100644
index 0000000..27350ba
--- /dev/null
+++ b/agent/mibgroup/ucd-snmp/pass.c
@@ -0,0 +1,541 @@
+#include <net-snmp/net-snmp-config.h>
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#if HAVE_WINSOCK_H
+#include <winsock.h>
+#endif
+#ifdef WIN32
+#include <limits.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "struct.h"
+#include "pass.h"
+#include "extensible.h"
+#include "util_funcs.h"
+
+struct extensible *passthrus = NULL;
+int numpassthrus = 0;
+
+/*
+ * the relocatable extensible commands variables
+ */
+struct variable2 extensible_passthru_variables[] = {
+ /*
+ * bogus entry. Only some of it is actually used.
+ */
+ {MIBINDEX, ASN_INTEGER, RWRITE, var_extensible_pass, 0, {MIBINDEX}},
+};
+
+
+
+/*
+ * lexicographical compare two object identifiers.
+ * * Returns -1 if name1 < name2,
+ * * 0 if name1 = name2,
+ * * 1 if name1 > name2
+ * *
+ * * This method differs from snmp_oid_compare
+ * * in that the comparison stops at the length
+ * * of the smallest object identifier.
+ */
+int
+snmp_oid_min_compare(const oid * in_name1,
+ size_t len1, const oid * in_name2, size_t len2)
+{
+ register int len;
+ register const oid *name1 = in_name1;
+ register const oid *name2 = in_name2;
+
+ /*
+ * len = minimum of len1 and len2
+ */
+ if (len1 < len2)
+ len = len1;
+ else
+ len = len2;
+ /*
+ * find first non-matching OID
+ */
+ while (len-- > 0) {
+ /*
+ * these must be done in seperate comparisons, since
+ * subtracting them and using that result has problems with
+ * subids > 2^31.
+ */
+ if (*(name1) < *(name2))
+ return -1;
+ if (*(name1++) > *(name2++))
+ return 1;
+ }
+ /*
+ * both OIDs equal up to length of shorter OID
+ */
+
+ return 0;
+}
+
+
+/*
+ * This is also called from pass_persist.c
+ */
+int
+asc2bin(char *p)
+{
+ char *r, *q = p;
+ char c;
+ int n = 0;
+
+ for (;;) {
+ c = (char) strtol(q, &r, 16);
+ if (r == q)
+ break;
+ *p++ = c;
+ q = r;
+ n++;
+ }
+ return n;
+}
+
+/*
+ * This is also called from pass_persist.c
+ */
+int
+bin2asc(char *p, size_t n)
+{
+ int i, flag = 0;
+ char buffer[SNMP_MAXBUF];
+
+ /* prevent buffer overflow */
+ if ((int)n > (sizeof(buffer) - 1))
+ n = sizeof(buffer) - 1;
+
+ for (i = 0; i < (int) n; i++) {
+ buffer[i] = p[i];
+ if (!isprint(p[i]))
+ flag = 1;
+ }
+ if (flag == 0) {
+ p[n] = 0;
+ return n;
+ }
+ for (i = 0; i < (int) n; i++) {
+ sprintf(p, "%02x ", (unsigned char) (buffer[i] & 0xff));
+ p += 3;
+ }
+ *--p = 0;
+ return 3 * n - 1;
+}
+
+void
+init_pass(void)
+{
+ snmpd_register_config_handler("pass", pass_parse_config,
+ pass_free_config, "miboid command");
+}
+
+void
+pass_parse_config(const char *token, char *cptr)
+{
+ struct extensible **ppass = &passthrus, **etmp, *ptmp;
+ char *tcptr, *endopt;
+ int i, priority;
+
+ /*
+ * options
+ */
+ priority = DEFAULT_MIB_PRIORITY;
+ while (*cptr == '-') {
+ cptr++;
+ switch (*cptr) {
+ case 'p':
+ /* change priority level */
+ cptr++;
+ cptr = skip_white(cptr);
+ if (! isdigit(*cptr)) {
+ config_perror("priority must be an integer");
+ return;
+ }
+ priority = strtol((const char*) cptr, &endopt, 0);
+ if ((priority == LONG_MIN) || (priority == LONG_MAX)) {
+ config_perror("priority under/overflow");
+ return;
+ }
+ cptr = endopt;
+ cptr = skip_white(cptr);
+ break;
+ default:
+ config_perror("unknown option for pass directive");
+ return;
+ }
+ }
+
+ /*
+ * MIB
+ */
+ if (*cptr == '.')
+ cptr++;
+ if (!isdigit(*cptr)) {
+ config_perror("second token is not a OID");
+ return;
+ }
+ numpassthrus++;
+
+ while (*ppass != NULL)
+ ppass = &((*ppass)->next);
+ (*ppass) = (struct extensible *) malloc(sizeof(struct extensible));
+ if (*ppass == NULL)
+ return;
+ (*ppass)->type = PASSTHRU;
+
+ (*ppass)->miblen = parse_miboid(cptr, (*ppass)->miboid);
+ while (isdigit(*cptr) || *cptr == '.')
+ cptr++;
+ /*
+ * path
+ */
+ cptr = skip_white(cptr);
+ if (cptr == NULL) {
+ config_perror("No command specified on pass line");
+ (*ppass)->command[0] = 0;
+ } else {
+ for (tcptr = cptr; *tcptr != 0 && *tcptr != '#' && *tcptr != ';';
+ tcptr++);
+ strncpy((*ppass)->command, cptr, tcptr - cptr);
+ (*ppass)->command[tcptr - cptr] = 0;
+ }
+ strncpy((*ppass)->name, (*ppass)->command, sizeof((*ppass)->name));
+ (*ppass)->name[ sizeof((*ppass)->name)-1 ] = 0;
+ (*ppass)->next = NULL;
+
+ register_mib_priority("pass", (struct variable *) extensible_passthru_variables,
+ sizeof(struct variable2),
+ 1, (*ppass)->miboid, (*ppass)->miblen, priority);
+
+ /*
+ * argggg -- pasthrus must be sorted
+ */
+ if (numpassthrus > 1) {
+ etmp = (struct extensible **)
+ malloc(((sizeof(struct extensible *)) * numpassthrus));
+ if (etmp == NULL)
+ return;
+
+ for (i = 0, ptmp = (struct extensible *) passthrus;
+ i < numpassthrus && ptmp != 0; i++, ptmp = ptmp->next)
+ etmp[i] = ptmp;
+ qsort(etmp, numpassthrus, sizeof(struct extensible *),
+ pass_compare);
+ passthrus = (struct extensible *) etmp[0];
+ ptmp = (struct extensible *) etmp[0];
+
+ for (i = 0; i < numpassthrus - 1; i++) {
+ ptmp->next = etmp[i + 1];
+ ptmp = ptmp->next;
+ }
+ ptmp->next = NULL;
+ free(etmp);
+ }
+}
+
+void
+pass_free_config(void)
+{
+ struct extensible *etmp, *etmp2;
+
+ for (etmp = passthrus; etmp != NULL;) {
+ etmp2 = etmp;
+ etmp = etmp->next;
+ unregister_mib(etmp2->miboid, etmp2->miblen);
+ free(etmp2);
+ }
+ passthrus = NULL;
+ numpassthrus = 0;
+}
+
+u_char *
+var_extensible_pass(struct variable *vp,
+ oid * name,
+ size_t * length,
+ int exact,
+ size_t * var_len, WriteMethod ** write_method)
+{
+ oid newname[MAX_OID_LEN];
+ int i, rtest, fd, newlen;
+ static long long_ret;
+ static in_addr_t addr_ret;
+ char buf[SNMP_MAXBUF];
+ static char buf2[SNMP_MAXBUF];
+ static oid objid[MAX_OID_LEN];
+ struct extensible *passthru;
+ FILE *file;
+
+ long_ret = *length;
+ for (i = 1; i <= numpassthrus; i++) {
+ passthru = get_exten_instance(passthrus, i);
+ rtest = snmp_oid_min_compare(name, *length,
+ passthru->miboid, passthru->miblen);
+ if ((exact && rtest == 0) || (!exact && rtest <= 0)) {
+ /*
+ * setup args
+ */
+ if (passthru->miblen >= *length || rtest < 0)
+ sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
+ else
+ sprint_mib_oid(buf, name, *length);
+ if (exact)
+ snprintf(passthru->command, sizeof(passthru->command),
+ "%s -g %s", passthru->name, buf);
+ else
+ snprintf(passthru->command, sizeof(passthru->command),
+ "%s -n %s", passthru->name, buf);
+ passthru->command[ sizeof(passthru->command)-1 ] = 0;
+ DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s\n",
+ passthru->command));
+ /*
+ * valid call. Exec and get output
+ */
+ if ((fd = get_exec_output(passthru)) != -1) {
+ file = fdopen(fd, "r");
+ if (fgets(buf, sizeof(buf), file) == NULL) {
+ fclose(file);
+ wait_on_exec(passthru);
+ if (exact) {
+ /*
+ * to enable creation
+ */
+ *write_method = setPass;
+ *var_len = 0;
+ return (NULL);
+ }
+ continue;
+ }
+ newlen = parse_miboid(buf, newname);
+
+ /*
+ * its good, so copy onto name/length
+ */
+ memcpy((char *) name, (char *) newname,
+ (int) newlen * sizeof(oid));
+ *length = newlen;
+
+ /*
+ * set up return pointer for setable stuff
+ */
+ *write_method = setPass;
+
+ if (newlen == 0 || fgets(buf, sizeof(buf), file) == NULL
+ || fgets(buf2, sizeof(buf2), file) == NULL) {
+ *var_len = 0;
+ fclose(file);
+ wait_on_exec(passthru);
+ return (NULL);
+ }
+ fclose(file);
+ wait_on_exec(passthru);
+
+ /*
+ * buf contains the return type, and buf2 contains the data
+ */
+ if (!strncasecmp(buf, "string", 6)) {
+ buf2[strlen(buf2) - 1] = 0; /* zap the linefeed */
+ *var_len = strlen(buf2);
+ vp->type = ASN_OCTET_STR;
+ return ((unsigned char *) buf2);
+ } else if (!strncasecmp(buf, "integer", 7)) {
+ *var_len = sizeof(long_ret);
+ long_ret = strtol(buf2, NULL, 10);
+ vp->type = ASN_INTEGER;
+ return ((unsigned char *) &long_ret);
+ } else if (!strncasecmp(buf, "unsigned", 8)) {
+ *var_len = sizeof(long_ret);
+ long_ret = strtoul(buf2, NULL, 10);
+ vp->type = ASN_UNSIGNED;
+ return ((unsigned char *) &long_ret);
+ } else if (!strncasecmp(buf, "counter", 7)) {
+ *var_len = sizeof(long_ret);
+ long_ret = strtoul(buf2, NULL, 10);
+ vp->type = ASN_COUNTER;
+ return ((unsigned char *) &long_ret);
+ } else if (!strncasecmp(buf, "octet", 5)) {
+ *var_len = asc2bin(buf2);
+ vp->type = ASN_OCTET_STR;
+ return ((unsigned char *) buf2);
+ } else if (!strncasecmp(buf, "opaque", 6)) {
+ *var_len = asc2bin(buf2);
+ vp->type = ASN_OPAQUE;
+ return ((unsigned char *) buf2);
+ } else if (!strncasecmp(buf, "gauge", 5)) {
+ *var_len = sizeof(long_ret);
+ long_ret = strtoul(buf2, NULL, 10);
+ vp->type = ASN_GAUGE;
+ return ((unsigned char *) &long_ret);
+ } else if (!strncasecmp(buf, "objectid", 8)) {
+ newlen = parse_miboid(buf2, objid);
+ *var_len = newlen * sizeof(oid);
+ vp->type = ASN_OBJECT_ID;
+ return ((unsigned char *) objid);
+ } else if (!strncasecmp(buf, "timetick", 8)) {
+ *var_len = sizeof(long_ret);
+ long_ret = strtoul(buf2, NULL, 10);
+ vp->type = ASN_TIMETICKS;
+ return ((unsigned char *) &long_ret);
+ } else if (!strncasecmp(buf, "ipaddress", 9)) {
+ newlen = parse_miboid(buf2, objid);
+ if (newlen != 4) {
+ snmp_log(LOG_ERR,
+ "invalid ipaddress returned: %s\n",
+ buf2);
+ *var_len = 0;
+ return (NULL);
+ }
+ addr_ret =
+ (objid[0] << (8 * 3)) + (objid[1] << (8 * 2)) +
+ (objid[2] << 8) + objid[3];
+ addr_ret = htonl(addr_ret);
+ *var_len = sizeof(addr_ret);
+ vp->type = ASN_IPADDRESS;
+ return ((unsigned char *) &addr_ret);
+ }
+ }
+ *var_len = 0;
+ return (NULL);
+ }
+ }
+ if (var_len)
+ *var_len = 0;
+ *write_method = NULL;
+ return (NULL);
+}
+
+int
+setPass(int action,
+ u_char * var_val,
+ u_char var_val_type,
+ size_t var_val_len, u_char * statP, oid * name, size_t name_len)
+{
+ int i, rtest;
+ struct extensible *passthru;
+
+ char buf[SNMP_MAXBUF], buf2[SNMP_MAXBUF];
+ long tmp;
+ unsigned long utmp;
+
+ for (i = 1; i <= numpassthrus; i++) {
+ passthru = get_exten_instance(passthrus, i);
+ rtest = snmp_oid_min_compare(name, name_len,
+ passthru->miboid, passthru->miblen);
+ if (rtest <= 0) {
+ if (action != ACTION)
+ return SNMP_ERR_NOERROR;
+ /*
+ * setup args
+ */
+ if (passthru->miblen >= name_len || rtest < 0)
+ sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
+ else
+ sprint_mib_oid(buf, name, name_len);
+ snprintf(passthru->command, sizeof(passthru->command),
+ "%s -s %s ", passthru->name, buf);
+ passthru->command[ sizeof(passthru->command)-1 ] = 0;
+ switch (var_val_type) {
+ case ASN_INTEGER:
+ case ASN_COUNTER:
+ case ASN_GAUGE:
+ case ASN_TIMETICKS:
+ tmp = *((long *) var_val);
+ switch (var_val_type) {
+ case ASN_INTEGER:
+ sprintf(buf, "integer %d\n", (int) tmp);
+ break;
+ case ASN_COUNTER:
+ sprintf(buf, "counter %d\n", (int) tmp);
+ break;
+ case ASN_GAUGE:
+ sprintf(buf, "gauge %d\n", (int) tmp);
+ break;
+ case ASN_TIMETICKS:
+ sprintf(buf, "timeticks %d\n", (int) tmp);
+ break;
+ }
+ break;
+ case ASN_IPADDRESS:
+ utmp = *((u_long *) var_val);
+ utmp = ntohl(utmp);
+ sprintf(buf, "ipaddress %d.%d.%d.%d\n",
+ (int) ((utmp & 0xff000000) >> (8 * 3)),
+ (int) ((utmp & 0xff0000) >> (8 * 2)),
+ (int) ((utmp & 0xff00) >> (8)),
+ (int) ((utmp & 0xff)));
+ break;
+ case ASN_OCTET_STR:
+ memcpy(buf2, var_val, var_val_len);
+ if (var_val_len == 0)
+ sprintf(buf, "string \"\"\n");
+ else if (bin2asc(buf2, var_val_len) == (int) var_val_len)
+ snprintf(buf, sizeof(buf), "string \"%s\"\n", buf2);
+ else
+ snprintf(buf, sizeof(buf), "octet \"%s\"\n", buf2);
+ buf[ sizeof(buf)-1 ] = 0;
+ break;
+ case ASN_OBJECT_ID:
+ sprint_mib_oid(buf2, (oid *) var_val, var_val_len/sizeof(oid));
+ snprintf(buf, sizeof(buf), "objectid \"%s\"\n", buf2);
+ buf[ sizeof(buf)-1 ] = 0;
+ break;
+ }
+ strncat(passthru->command, buf, sizeof(passthru->command)-strlen(passthru->command)-1);
+ passthru->command[ sizeof(passthru->command)-1 ] = 0;
+ DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s",
+ passthru->command));
+ exec_command(passthru);
+ DEBUGMSGTL(("ucd-snmp/pass", "pass-running returned: %s",
+ passthru->output));
+ if (!strncasecmp(passthru->output, "not-writable", 12)) {
+ return SNMP_ERR_NOTWRITABLE;
+ } else if (!strncasecmp(passthru->output, "wrong-type", 10)) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ return SNMP_ERR_NOERROR;
+ }
+ }
+ if (snmp_get_do_debugging()) {
+ sprint_mib_oid(buf2, name, name_len);
+ DEBUGMSGTL(("ucd-snmp/pass", "pass-notfound: %s\n", buf2));
+ }
+ return SNMP_ERR_NOSUCHNAME;
+}
+
+int
+pass_compare(const void *a, const void *b)
+{
+ const struct extensible *const *ap, *const *bp;
+ ap = (const struct extensible * const *) a;
+ bp = (const struct extensible * const *) b;
+ return snmp_oid_compare((*ap)->miboid, (*ap)->miblen, (*bp)->miboid,
+ (*bp)->miblen);
+}