pass_persist.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:22k
- #include <net-snmp/net-snmp-config.h>
- #if HAVE_IO_H
- #include <io.h>
- #endif
- #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 <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
- #if HAVE_WINSOCK_H
- #include <winsock.h>
- #endif
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- #include <signal.h>
- #include <errno.h>
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include "struct.h"
- #include "pass_persist.h"
- #include "extensible.h"
- #include "util_funcs.h"
- struct extensible *persistpassthrus = NULL;
- int numpersistpassthrus = 0;
- struct persist_pipe_type {
- FILE *fIn, *fOut;
- int fdIn, fdOut;
- int pid;
- } *persist_pipes = (struct persist_pipe_type *) NULL;
- static int init_persist_pipes(void);
- static void close_persist_pipe(int iindex);
- static int open_persist_pipe(int iindex, char *command);
- static void destruct_persist_pipes(void);
- static int write_persist_pipe(int iindex, const char *data);
- /*
- * These are defined in pass.c
- */
- extern int asc2bin(char *p);
- extern int bin2asc(char *p, size_t n);
- extern int snmp_oid_min_compare(const oid *, size_t, const oid *,
- size_t);
- /*
- * the relocatable extensible commands variables
- */
- struct variable2 extensible_persist_passthru_variables[] = {
- /*
- * bogus entry. Only some of it is actually used.
- */
- {MIBINDEX, ASN_INTEGER, RWRITE, var_extensible_pass_persist, 0,
- {MIBINDEX}},
- };
- void
- init_pass_persist(void)
- {
- snmpd_register_config_handler("pass_persist",
- pass_persist_parse_config,
- pass_persist_free_config,
- "miboid program");
- }
- void
- pass_persist_parse_config(const char *token, char *cptr)
- {
- struct extensible **ppass = &persistpassthrus, **etmp, *ptmp;
- char *tcptr;
- int i;
- if (*cptr == '.')
- cptr++;
- if (!isdigit(*cptr)) {
- config_perror("second token is not a OID");
- return;
- }
- numpersistpassthrus++;
- while (*ppass != NULL)
- ppass = &((*ppass)->next);
- (*ppass) = (struct extensible *) malloc(sizeof(struct extensible));
- if (*ppass == NULL)
- return;
- (*ppass)->type = PASSTHRU_PERSIST;
- (*ppass)->miblen = parse_miboid(cptr, (*ppass)->miboid);
- while (isdigit(*cptr) || *cptr == '.')
- cptr++;
- /*
- * name
- */
- cptr = skip_white(cptr);
- if (cptr == NULL) {
- config_perror("No command specified on pass_persist 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("pass_persist",
- (struct variable *) extensible_persist_passthru_variables,
- sizeof(struct variable2), 1, (*ppass)->miboid,
- (*ppass)->miblen);
- /*
- * argggg -- pasthrus must be sorted
- */
- if (numpersistpassthrus > 1) {
- etmp = (struct extensible **)
- malloc(((sizeof(struct extensible *)) * numpersistpassthrus));
- if (etmp == NULL)
- return;
- for (i = 0, ptmp = (struct extensible *) persistpassthrus;
- i < numpersistpassthrus && ptmp != 0; i++, ptmp = ptmp->next)
- etmp[i] = ptmp;
- qsort(etmp, numpersistpassthrus, sizeof(struct extensible *),
- pass_persist_compare);
- persistpassthrus = (struct extensible *) etmp[0];
- ptmp = (struct extensible *) etmp[0];
- for (i = 0; i < numpersistpassthrus - 1; i++) {
- ptmp->next = etmp[i + 1];
- ptmp = ptmp->next;
- }
- ptmp->next = NULL;
- free(etmp);
- }
- }
- void
- pass_persist_free_config(void)
- {
- struct extensible *etmp, *etmp2;
- /*
- * Close any open pipes to any programs
- */
- destruct_persist_pipes();
- for (etmp = persistpassthrus; etmp != NULL;) {
- etmp2 = etmp;
- etmp = etmp->next;
- unregister_mib(etmp2->miboid, etmp2->miblen);
- free(etmp2);
- }
- persistpassthrus = NULL;
- numpersistpassthrus = 0;
- }
- u_char *
- var_extensible_pass_persist(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, newlen;
- static long long_ret;
- char buf[SNMP_MAXBUF];
- static char buf2[SNMP_MAXBUF];
- static oid objid[MAX_OID_LEN];
- struct extensible *persistpassthru;
- FILE *file;
- /*
- * Make sure that our basic pipe structure is malloced
- */
- init_persist_pipes();
- long_ret = *length;
- for (i = 1; i <= numpersistpassthrus; i++) {
- persistpassthru = get_exten_instance(persistpassthrus, i);
- rtest = snmp_oid_min_compare(name, *length,
- persistpassthru->miboid,
- persistpassthru->miblen);
- if ((exact && rtest == 0) || (!exact && rtest <= 0)) {
- /*
- * setup args
- */
- if (persistpassthru->miblen >= *length || rtest < 0)
- sprint_mib_oid(buf, persistpassthru->miboid,
- persistpassthru->miblen);
- else
- sprint_mib_oid(buf, name, *length);
- /*
- * Open our pipe if necessary
- */
- if (!open_persist_pipe(i, persistpassthru->name)) {
- return (NULL);
- }
- if (exact)
- snprintf(persistpassthru->command,
- sizeof(persistpassthru->command), "getn%sn", buf);
- else
- snprintf(persistpassthru->command,
- sizeof(persistpassthru->command), "getnextn%sn", buf);
- persistpassthru->command[ sizeof(persistpassthru->command)-1 ] = 0;
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "persistpass-sending:n%s",
- persistpassthru->command));
- if (!write_persist_pipe(i, persistpassthru->command)) {
- *var_len = 0;
- /*
- * close_persist_pipes is called in write_persist_pipe
- */
- return (NULL);
- }
- /*
- * valid call. Exec and get output
- */
- if ((file = persist_pipes[i].fIn)) {
- if (fgets(buf, sizeof(buf), file) == NULL) {
- *var_len = 0;
- close_persist_pipe(i);
- return (NULL);
- }
- /*
- * persistant scripts return "NONEn" on invalid items
- */
- if (!strncmp(buf, "NONE", 4)) {
- if (exact) {
- *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 = setPassPersist;
- if (newlen == 0 || fgets(buf, sizeof(buf), file) == NULL
- || fgets(buf2, sizeof(buf2), file) == NULL) {
- *var_len = 0;
- close_persist_pipe(i);
- return (NULL);
- }
- /*
- * 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: %sn",
- buf2);
- *var_len = 0;
- return (NULL);
- }
- long_ret =
- (objid[0] << (8 * 3)) + (objid[1] << (8 * 2)) +
- (objid[2] << 8) + objid[3];
- long_ret = htonl(long_ret);
- *var_len = sizeof(long_ret);
- vp->type = ASN_IPADDRESS;
- return ((unsigned char *) &long_ret);
- }
- }
- *var_len = 0;
- return (NULL);
- }
- }
- if (var_len)
- *var_len = 0;
- *write_method = NULL;
- return (NULL);
- }
- int
- setPassPersist(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 *persistpassthru;
- char buf[SNMP_MAXBUF], buf2[SNMP_MAXBUF];
- long tmp;
- unsigned long utmp;
- /*
- * Make sure that our basic pipe structure is malloced
- */
- init_persist_pipes();
- for (i = 1; i <= numpersistpassthrus; i++) {
- persistpassthru = get_exten_instance(persistpassthrus, i);
- rtest = snmp_oid_min_compare(name, name_len,
- persistpassthru->miboid,
- persistpassthru->miblen);
- if (rtest <= 0) {
- if (action != ACTION)
- return SNMP_ERR_NOERROR;
- /*
- * setup args
- */
- if (persistpassthru->miblen >= name_len || rtest < 0)
- sprint_mib_oid(buf, persistpassthru->miboid,
- persistpassthru->miblen);
- else
- sprint_mib_oid(buf, name, name_len);
- snprintf(persistpassthru->command,
- sizeof(persistpassthru->command), "setn%sn", buf);
- persistpassthru->command[ sizeof(persistpassthru->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 %dn", (int) tmp);
- break;
- case ASN_COUNTER:
- sprintf(buf, "counter %dn", (int) tmp);
- break;
- case ASN_GAUGE:
- sprintf(buf, "gauge %dn", (int) tmp);
- break;
- case ASN_TIMETICKS:
- sprintf(buf, "timeticks %dn", (int) tmp);
- break;
- }
- break;
- case ASN_IPADDRESS:
- utmp = *((u_long *) var_val);
- utmp = ntohl(utmp);
- sprintf(buf, "ipaddress %d.%d.%d.%dn",
- (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);
- snprintf(buf, sizeof(buf), "objectid "%s"n", buf2);
- buf[ sizeof(buf)-1 ] = 0;
- break;
- }
- strncat(persistpassthru->command, buf,
- sizeof(persistpassthru->command) -
- strlen(persistpassthru->command) - 2);
- persistpassthru->command[ sizeof(persistpassthru->command)-2 ] = 'n';
- persistpassthru->command[ sizeof(persistpassthru->command)-1 ] = 0;
- if (!open_persist_pipe(i, persistpassthru->name)) {
- return SNMP_ERR_NOTWRITABLE;
- }
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "persistpass-writing: %sn",
- persistpassthru->command));
- if (!write_persist_pipe(i, persistpassthru->command)) {
- close_persist_pipe(i);
- return SNMP_ERR_NOTWRITABLE;
- }
- if (fgets(buf, sizeof(buf), persist_pipes[i].fIn) == NULL) {
- close_persist_pipe(i);
- return SNMP_ERR_NOTWRITABLE;
- }
- if (!strncasecmp(buf, "not-writable", 12)) {
- return SNMP_ERR_NOTWRITABLE;
- } else if (!strncasecmp(buf, "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_persist", "persistpass-notfound: %sn",
- buf2));
- }
- return SNMP_ERR_NOSUCHNAME;
- }
- int
- pass_persist_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);
- }
- /*
- * Initialize our persistant pipes
- * - Returns 1 on success, 0 on failure.
- * - Initializes all FILE pointers to NULL to indicate "closed"
- */
- static int
- init_persist_pipes(void)
- {
- int i;
- /*
- * if we are already taken care of, just return
- */
- if (persist_pipes) {
- return persist_pipes ? 1 : 0;
- }
- /*
- * Otherwise malloc and initialize
- */
- persist_pipes = (struct persist_pipe_type *)
- malloc(sizeof(struct persist_pipe_type) *
- (numpersistpassthrus + 1));
- if (persist_pipes) {
- for (i = 0; i <= numpersistpassthrus; i++) {
- persist_pipes[i].fIn = persist_pipes[i].fOut = (FILE *) 0;
- persist_pipes[i].fdIn = persist_pipes[i].fdOut = -1;
- persist_pipes[i].pid = -1;
- }
- }
- return persist_pipes ? 1 : 0;
- }
- /*
- * Destruct our persistant pipes
- *
- */
- static void
- destruct_persist_pipes(void)
- {
- int i;
- /*
- * Return if there are no pipes
- */
- if (!persist_pipes) {
- return;
- }
- for (i = 0; i <= numpersistpassthrus; i++) {
- close_persist_pipe(i);
- }
- free(persist_pipes);
- persist_pipes = (struct persist_pipe_type *) 0;
- }
- /*
- * returns 0 on failure, 1 on success
- */
- static int
- open_persist_pipe(int iindex, char *command)
- {
- static int recurse = 0; /* used to allow one level of recursion */
- DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe(%d,'%s')n",
- iindex, command));
- /*
- * Open if it's not already open
- */
- if (persist_pipes[iindex].pid == -1) {
- int fdIn, fdOut, pid;
- /*
- * Did we fail?
- */
- if ((0 == get_exec_pipes(command, &fdIn, &fdOut, &pid)) ||
- (pid == -1)) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "open_persist_pipe: pid == -1n"));
- recurse = 0;
- return 0;
- }
- /*
- * If not, fill out our structure
- */
- persist_pipes[iindex].pid = pid;
- persist_pipes[iindex].fdIn = fdIn;
- persist_pipes[iindex].fdOut = fdOut;
- persist_pipes[iindex].fIn = fdopen(fdIn, "r");
- persist_pipes[iindex].fOut = fdopen(fdOut, "w");
- /*
- * Setup our -non-buffered-io-
- */
- setbuf(persist_pipes[iindex].fOut, (char *) 0);
- }
- /*
- * Send test packet always so we can self-catch
- */
- {
- char buf[SNMP_MAXBUF];
- /*
- * Should catch SIGPIPE around this call!
- */
- if (!write_persist_pipe(iindex, "PINGn")) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "open_persist_pipe: Error writing PINGn"));
- close_persist_pipe(iindex);
- /*
- * Recurse one time if we get a SIGPIPE
- */
- if (!recurse) {
- recurse = 1;
- return open_persist_pipe(iindex, command);
- }
- recurse = 0;
- return 0;
- }
- if (fgets(buf, sizeof(buf), persist_pipes[iindex].fIn) == NULL) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "open_persist_pipe: Error reading for PONGn"));
- close_persist_pipe(iindex);
- recurse = 0;
- return 0;
- }
- if (strncmp(buf, "PONG", 4)) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "open_persist_pipe: PONG not received!n"));
- close_persist_pipe(iindex);
- recurse = 0;
- return 0;
- }
- }
- recurse = 0;
- return 1;
- }
- #if STRUCT_SIGACTION_HAS_SA_SIGACTION
- /*
- * Generic handler
- */
- void
- sigpipe_handler(int sig, siginfo_t * sip, void *uap)
- {
- return;
- }
- #endif
- static int
- write_persist_pipe(int iindex, const char *data)
- {
- #if HAVE_SIGNAL
- struct sigaction sa, osa;
- int wret = 0, werrno = 0;
- /*
- * Don't write to a non-existant process
- */
- if (persist_pipes[iindex].pid == -1) {
- return 0;
- }
- /*
- * Setup our signal action to catch SIGPIPEs
- */
- sa.sa_handler = NULL;
- #if STRUCT_SIGACTION_HAS_SA_SIGACTION
- sa.sa_sigaction = &sigpipe_handler;
- #endif
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGPIPE, &sa, &osa)) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "write_persist_pipe: sigaction failed: %d", errno));
- }
- /*
- * Do the write
- */
- wret = write(persist_pipes[iindex].fdOut, data, strlen(data));
- werrno = errno;
- /*
- * Reset the signal handler
- */
- sigaction(SIGPIPE, &osa, (struct sigaction *) 0);
- if (wret < 0) {
- if (werrno != EINTR) {
- DEBUGMSGTL(("ucd-snmp/pass_persist",
- "write_persist_pipe: write returned unknown error %dn",
- errno));
- }
- close_persist_pipe(iindex);
- return 0;
- }
- #endif /* HAVE_SIGNAL */
- return 1;
- }
- static void
- close_persist_pipe(int iindex)
- {
- /*
- * Check and nix every item
- */
- if (persist_pipes[iindex].fOut) {
- fclose(persist_pipes[iindex].fOut);
- persist_pipes[iindex].fOut = (FILE *) 0;
- }
- if (persist_pipes[iindex].fdOut != -1) {
- close(persist_pipes[iindex].fdOut);
- persist_pipes[iindex].fdOut = -1;
- }
- if (persist_pipes[iindex].fIn) {
- fclose(persist_pipes[iindex].fIn);
- persist_pipes[iindex].fIn = (FILE *) 0;
- }
- if (persist_pipes[iindex].fdIn != -1) {
- close(persist_pipes[iindex].fdIn);
- persist_pipes[iindex].fdIn = -1;
- }
- if (persist_pipes[iindex].pid != -1) {
- #if HAVE_SYS_WAIT_H
- waitpid(persist_pipes[iindex].pid, 0, 0);
- #endif
- persist_pipes[iindex].pid = -1;
- }
- }