blob: 9dce749a268340fb2aba1b0ebe65ce4536aa12da [file] [log] [blame]
#include <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 TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#if HAVE_DMALLOC_H
#include <dmalloc.h>
#endif
#include "mibincl.h"
#include "struct.h"
#include "pass.h"
#include "extensible.h"
#include "util_funcs.h"
#include "read_config.h"
#include "agent_read_config.h"
#include "system.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}},
};
#define BUFMAX 4096
int asc2bin(char *p)
{
char *r, *q = p;
char c;
int n = 0;
for (;;) {
c = strtol(q, &r, 16);
if (r == q) break;
*p++ = c;
q = r;
n++;
}
return n;
}
int bin2asc(char *p, size_t n)
{
int i, flag = 0;
char buffer[BUFMAX];
for (i = 0; i < n; i++) {
buffer[i] = p[i];
if (!isprint(p[i])) flag = 1;
}
if (flag == 0) return n;
for (i = 0; i < 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(char *token, char* cptr)
{
struct extensible **ppass = &passthrus, **etmp, *ptmp;
char *tcptr;
int i;
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));
(*ppass)->type = PASSTHRU;
(*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 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;
}
strcpy((*ppass)->name, (*ppass)->command);
(*ppass)->next = NULL;
register_mib("pass", (struct variable *) extensible_passthru_variables,
sizeof(struct variable2),
1, (*ppass)->miboid, (*ppass)->miblen);
/* argggg -- pasthrus must be sorted */
if (numpassthrus > 0) {
etmp = (struct extensible **)
malloc(((sizeof(struct extensible *)) * numpassthrus));
for(i=0,ptmp = (struct extensible *) passthrus;
i < numpassthrus && ptmp != 0;
i++, ptmp = ptmp->next)
etmp[i] = ptmp;
qsort(etmp, numpassthrus, sizeof(struct extensible *),
#ifdef __STDC__
(int (*)(const void *, const void *)) pass_compare
#else
pass_compare
#endif
);
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, j, rtest=0, fd, newlen, last;
static long long_ret;
static char buf[BUFMAX], buf2[BUFMAX];
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);
last = passthru->miblen;
if (passthru->miblen > *length)
last = *length;
for(j=0,rtest=0; j < last && !rtest; j++) {
if (name[j] != passthru->miboid[j]) {
if (name[j] < passthru->miboid[j])
rtest = -1;
else
rtest = 1;
}
}
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)
sprintf(passthru->command,"%s -g %s",passthru->name,buf);
else
sprintf(passthru->command,"%s -n %s",passthru->name,buf);
DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s\n",passthru->command));
/* valid call. Exec and get output */
if ((fd = get_exec_output(passthru))) {
file = fdopen(fd,"r");
if (fgets(buf,sizeof(buf),file) == NULL) {
*var_len = 0;
fclose(file);
wait_on_exec(passthru);
return(NULL);
}
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",7)) {
*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,"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);
}
long_ret = (objid[0] << (8*3)) + (objid[1] << (8*2)) +
(objid[2] << 8) + objid[3];
long_ret = ntohl(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
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, j, rtest, last;
struct extensible *passthru;
static char buf[BUFMAX], buf2[BUFMAX];
static long tmp;
static unsigned long utmp;
static size_t itmp;
static oid objid[MAX_OID_LEN];
for(i=1; i<= numpassthrus; i++) {
passthru = get_exten_instance(passthrus,i);
last = passthru->miblen;
if (passthru->miblen > name_len)
last = name_len;
for(j=0,rtest=0; j < last && !rtest; j++) {
if (name[j] != passthru->miboid[j]) {
if (name[j] < passthru->miboid[j])
rtest = -1;
else
rtest = 1;
}
}
if (rtest <= 0) {
if (action != COMMIT)
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);
sprintf(passthru->command,"%s -s %s ",passthru->name,buf);
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",(int) tmp);
break;
case ASN_COUNTER:
sprintf(buf,"counter %d",(int) tmp);
break;
case ASN_GAUGE:
sprintf(buf,"gauge %d",(int) tmp);
break;
case ASN_TIMETICKS:
sprintf(buf,"timeticks %d",(int) tmp);
break;
}
break;
case ASN_IPADDRESS:
utmp = *((u_long *) var_val);
sprintf(buf,"ipaddress %d.%d.%d.%d",
(int) ((utmp & 0xff000000) >> (8*3)),
(int) ((utmp & 0xff0000) >> (8*2)),
(int) ((utmp & 0xff00) >> (8)),
(int) ((utmp & 0xff)));
break;
case ASN_OCTET_STR:
itmp = sizeof(buf);
memset(buf2,(0),itmp);
memcpy(buf2, var_val, var_val_len);
buf2[var_val_len] = 0;
if (bin2asc(buf2, itmp) == itmp)
sprintf(buf,"string %s",buf2);
else
sprintf(buf,"octet %s",buf2);
break;
case ASN_OBJECT_ID:
itmp = var_val_len/sizeof(oid);
memcpy(objid, var_val, var_val_len);
sprint_mib_oid(buf2, objid, itmp);
sprintf(buf,"objectid \"%s\"",buf2);
break;
}
strcat(passthru->command,buf);
DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s\n",passthru->command));
exec_command(passthru);
if (!strncasecmp(passthru->output,"not-writable",11)) {
return SNMP_ERR_NOTWRITABLE;
} else if (!strncasecmp(passthru->output,"wrong-type",9)) {
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(void *a, void *b)
{
struct extensible **ap, **bp;
ap = (struct extensible **) a;
bp = (struct extensible **) b;
return snmp_oid_compare((*ap)->miboid,(*ap)->miblen,(*bp)->miboid,(*bp)->miblen);
}