1 #include <net-snmp/net-snmp-config.h>
16 #include <sys/types.h>
18 #include <netinet/in.h>
21 # include <sys/wait.h>
31 #include <net-snmp/net-snmp-includes.h>
32 #include <net-snmp/agent/net-snmp-agent-includes.h>
36 #include "extensible.h"
37 #include "util_funcs.h"
39 struct extensible *passthrus = NULL;
43 * the relocatable extensible commands variables
45 struct variable2 extensible_passthru_variables[] = {
47 * bogus entry. Only some of it is actually used.
49 {MIBINDEX, ASN_INTEGER, RWRITE, var_extensible_pass, 0, {MIBINDEX}},
55 * lexicographical compare two object identifiers.
56 * * Returns -1 if name1 < name2,
57 * * 0 if name1 = name2,
58 * * 1 if name1 > name2
60 * * This method differs from snmp_oid_compare
61 * * in that the comparison stops at the length
62 * * of the smallest object identifier.
65 snmp_oid_min_compare(const oid * in_name1,
66 size_t len1, const oid * in_name2, size_t len2)
69 register const oid *name1 = in_name1;
70 register const oid *name2 = in_name2;
73 * len = minimum of len1 and len2
80 * find first non-matching OID
84 * these must be done in seperate comparisons, since
85 * subtracting them and using that result has problems with
88 if (*(name1) < *(name2))
90 if (*(name1++) > *(name2++))
94 * both OIDs equal up to length of shorter OID
102 * This is also called from pass_persist.c
112 c = (char) strtol(q, &r, 16);
123 * This is also called from pass_persist.c
126 bin2asc(char *p, size_t n)
129 char buffer[SNMP_MAXBUF];
131 for (i = 0; i < (int) n; i++) {
140 for (i = 0; i < (int) n; i++) {
141 sprintf(p, "%02x ", (unsigned char) (buffer[i] & 0xff));
152 snmpd_register_config_handler("pass", pass_parse_config,
153 pass_free_config, "miboid command");
158 pass_parse_config(const char *token, char *cptr)
160 struct extensible **ppass = &passthrus, **etmp, *ptmp;
166 if (!isdigit(*cptr)) {
167 config_perror("second token is not a OID");
172 while (*ppass != NULL)
173 ppass = &((*ppass)->next);
174 (*ppass) = (struct extensible *) malloc(sizeof(struct extensible));
177 (*ppass)->type = PASSTHRU;
179 (*ppass)->miblen = parse_miboid(cptr, (*ppass)->miboid);
180 while (isdigit(*cptr) || *cptr == '.')
185 cptr = skip_white(cptr);
187 config_perror("No command specified on pass line");
188 (*ppass)->command[0] = 0;
190 for (tcptr = cptr; *tcptr != 0 && *tcptr != '#' && *tcptr != ';';
192 strncpy((*ppass)->command, cptr, tcptr - cptr);
193 (*ppass)->command[tcptr - cptr] = 0;
195 strncpy((*ppass)->name, (*ppass)->command, sizeof((*ppass)->name));
196 (*ppass)->name[ sizeof((*ppass)->name)-1 ] = 0;
197 (*ppass)->next = NULL;
199 register_mib("pass", (struct variable *) extensible_passthru_variables,
200 sizeof(struct variable2),
201 1, (*ppass)->miboid, (*ppass)->miblen);
204 * argggg -- pasthrus must be sorted
206 if (numpassthrus > 0) {
207 etmp = (struct extensible **)
208 malloc(((sizeof(struct extensible *)) * numpassthrus));
212 for (i = 0, ptmp = (struct extensible *) passthrus;
213 i < numpassthrus && ptmp != 0; i++, ptmp = ptmp->next)
215 qsort(etmp, numpassthrus, sizeof(struct extensible *),
217 passthrus = (struct extensible *) etmp[0];
218 ptmp = (struct extensible *) etmp[0];
220 for (i = 0; i < numpassthrus - 1; i++) {
221 ptmp->next = etmp[i + 1];
230 pass_free_config(void)
232 struct extensible *etmp, *etmp2;
234 for (etmp = passthrus; etmp != NULL;) {
237 unregister_mib(etmp2->miboid, etmp2->miblen);
245 var_extensible_pass(struct variable *vp,
249 size_t * var_len, WriteMethod ** write_method)
251 oid newname[MAX_OID_LEN];
252 int i, rtest, fd, newlen;
253 static long long_ret;
254 char buf[SNMP_MAXBUF];
255 static char buf2[SNMP_MAXBUF];
256 static oid objid[MAX_OID_LEN];
257 struct extensible *passthru;
261 for (i = 1; i <= numpassthrus; i++) {
262 passthru = get_exten_instance(passthrus, i);
263 rtest = snmp_oid_min_compare(name, *length,
264 passthru->miboid, passthru->miblen);
265 if ((exact && rtest == 0) || (!exact && rtest <= 0)) {
269 if (passthru->miblen >= *length || rtest < 0)
270 sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
272 sprint_mib_oid(buf, name, *length);
274 snprintf(passthru->command, sizeof(passthru->command),
275 "%s -g %s", passthru->name, buf);
277 snprintf(passthru->command, sizeof(passthru->command),
278 "%s -n %s", passthru->name, buf);
279 passthru->command[ sizeof(passthru->command)-1 ] = 0;
280 DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s\n",
283 * valid call. Exec and get output
285 if ((fd = get_exec_output(passthru)) != -1) {
286 file = fdopen(fd, "r");
287 if (fgets(buf, sizeof(buf), file) == NULL) {
291 *write_method = setPass;
294 wait_on_exec(passthru);
297 newlen = parse_miboid(buf, newname);
300 * its good, so copy onto name/length
302 memcpy((char *) name, (char *) newname,
303 (int) newlen * sizeof(oid));
307 * set up return pointer for setable stuff
309 *write_method = setPass;
311 if (newlen == 0 || fgets(buf, sizeof(buf), file) == NULL
312 || fgets(buf2, sizeof(buf2), file) == NULL) {
315 wait_on_exec(passthru);
319 wait_on_exec(passthru);
322 * buf contains the return type, and buf2 contains the data
324 if (!strncasecmp(buf, "string", 6)) {
325 buf2[strlen(buf2) - 1] = 0; /* zap the linefeed */
326 *var_len = strlen(buf2);
327 vp->type = ASN_OCTET_STR;
328 return ((unsigned char *) buf2);
329 } else if (!strncasecmp(buf, "opaque", 6)) {
330 *var_len = asc2bin(buf2);
331 vp->type = ASN_OPAQUE;
332 return ((unsigned char *) buf2);
333 } else if (!strncasecmp(buf, "integer", 7)) {
334 *var_len = sizeof(long_ret);
335 long_ret = strtol(buf2, NULL, 10);
336 vp->type = ASN_INTEGER;
337 return ((unsigned char *) &long_ret);
338 } else if (!strncasecmp(buf, "unsigned", 7)) {
339 *var_len = sizeof(long_ret);
340 long_ret = strtoul(buf2, NULL, 10);
341 vp->type = ASN_UNSIGNED;
342 return ((unsigned char *) &long_ret);
343 } else if (!strncasecmp(buf, "counter", 7)) {
344 *var_len = sizeof(long_ret);
345 long_ret = strtoul(buf2, NULL, 10);
346 vp->type = ASN_COUNTER;
347 return ((unsigned char *) &long_ret);
348 } else if (!strncasecmp(buf, "octet", 5)) {
349 *var_len = asc2bin(buf2);
350 vp->type = ASN_OCTET_STR;
351 return ((unsigned char *) buf2);
352 } else if (!strncasecmp(buf, "gauge", 5)) {
353 *var_len = sizeof(long_ret);
354 long_ret = strtoul(buf2, NULL, 10);
355 vp->type = ASN_GAUGE;
356 return ((unsigned char *) &long_ret);
357 } else if (!strncasecmp(buf, "objectid", 8)) {
358 newlen = parse_miboid(buf2, objid);
359 *var_len = newlen * sizeof(oid);
360 vp->type = ASN_OBJECT_ID;
361 return ((unsigned char *) objid);
362 } else if (!strncasecmp(buf, "timetick", 8)) {
363 *var_len = sizeof(long_ret);
364 long_ret = strtoul(buf2, NULL, 10);
365 vp->type = ASN_TIMETICKS;
366 return ((unsigned char *) &long_ret);
367 } else if (!strncasecmp(buf, "ipaddress", 9)) {
368 newlen = parse_miboid(buf2, objid);
371 "invalid ipaddress returned: %s\n",
377 (objid[0] << (8 * 3)) + (objid[1] << (8 * 2)) +
378 (objid[2] << 8) + objid[3];
379 long_ret = htonl(long_ret);
380 *var_len = sizeof(long_ret);
381 vp->type = ASN_IPADDRESS;
382 return ((unsigned char *) &long_ret);
391 *write_method = NULL;
399 size_t var_val_len, u_char * statP, oid * name, size_t name_len)
402 struct extensible *passthru;
404 char buf[SNMP_MAXBUF], buf2[SNMP_MAXBUF];
409 for (i = 1; i <= numpassthrus; i++) {
410 passthru = get_exten_instance(passthrus, i);
411 rtest = snmp_oid_min_compare(name, name_len,
412 passthru->miboid, passthru->miblen);
414 if (action != COMMIT)
415 return SNMP_ERR_NOERROR;
419 if (passthru->miblen >= name_len || rtest < 0)
420 sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
422 sprint_mib_oid(buf, name, name_len);
423 snprintf(passthru->command, sizeof(passthru->command),
424 "%s -s %s", passthru->name, buf);
425 passthru->command[ sizeof(passthru->command)-1 ] = 0;
426 switch (var_val_type) {
431 tmp = *((long *) var_val);
432 switch (var_val_type) {
434 sprintf(buf, "integer %d\n", (int) tmp);
437 sprintf(buf, "counter %d\n", (int) tmp);
440 sprintf(buf, "gauge %d\n", (int) tmp);
443 sprintf(buf, "timeticks %d\n", (int) tmp);
448 utmp = *((u_long *) var_val);
450 sprintf(buf, "ipaddress %d.%d.%d.%d\n",
451 (int) ((utmp & 0xff000000) >> (8 * 3)),
452 (int) ((utmp & 0xff0000) >> (8 * 2)),
453 (int) ((utmp & 0xff00) >> (8)),
454 (int) ((utmp & 0xff)));
458 memcpy(buf2, var_val, var_val_len);
459 if (var_val_len == 0)
460 sprintf(buf, "string \"\"\n");
461 else if (bin2asc(buf2, var_val_len) == (int) var_val_len)
462 snprintf(buf, sizeof(buf), "string \"%s\"\n", buf2);
464 snprintf(buf, sizeof(buf), "octet \"%s\"\n", buf2);
465 buf[ sizeof(buf)-1 ] = 0;
468 sprint_mib_oid(buf2, (oid *) var_val, var_val_len);
469 snprintf(buf, sizeof(buf), "objectid \"%s\"\n", buf2);
470 buf[ sizeof(buf)-1 ] = 0;
473 strncat(passthru->command, buf, sizeof(passthru->command));
474 passthru->command[ sizeof(passthru->command)-1 ] = 0;
475 DEBUGMSGTL(("ucd-snmp/pass", "pass-running: %s\n",
477 exec_command(passthru);
478 if (!strncasecmp(passthru->output, "not-writable", 11)) {
479 return SNMP_ERR_NOTWRITABLE;
480 } else if (!strncasecmp(passthru->output, "wrong-type", 9)) {
481 return SNMP_ERR_WRONGTYPE;
483 return SNMP_ERR_NOERROR;
486 if (snmp_get_do_debugging()) {
487 sprint_mib_oid(buf2, name, name_len);
488 DEBUGMSGTL(("ucd-snmp/pass", "pass-notfound: %s\n", buf2));
490 return SNMP_ERR_NOSUCHNAME;
494 pass_compare(const void *a, const void *b)
496 const struct extensible *const *ap, *const *bp;
497 ap = (const struct extensible * const *) a;
498 bp = (const struct extensible * const *) b;
499 return snmp_oid_compare((*ap)->miboid, (*ap)->miblen, (*bp)->miboid,