http://www.usr.com/support/gpl/USR9107_release1.1.tar.gz
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / ucd-snmp / pass.c
1 #include <net-snmp/net-snmp-config.h>
2
3 #if HAVE_STDLIB_H
4 #include <stdlib.h>
5 #endif
6 #include <stdio.h>
7 #if HAVE_STRING_H
8 #include <string.h>
9 #else
10 #include <strings.h>
11 #endif
12 #if HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 #include <ctype.h>
16 #include <sys/types.h>
17 #if HAVE_NETINET_IN_H
18 #include <netinet/in.h>
19 #endif
20 #if HAVE_SYS_WAIT_H
21 # include <sys/wait.h>
22 #endif
23 #if HAVE_WINSOCK_H
24 #include <winsock.h>
25 #endif
26
27 #if HAVE_DMALLOC_H
28 #include <dmalloc.h>
29 #endif
30
31 #include <net-snmp/net-snmp-includes.h>
32 #include <net-snmp/agent/net-snmp-agent-includes.h>
33
34 #include "struct.h"
35 #include "pass.h"
36 #include "extensible.h"
37 #include "util_funcs.h"
38
39 struct extensible *passthrus = NULL;
40 int             numpassthrus = 0;
41
42 /*
43  * the relocatable extensible commands variables 
44  */
45 struct variable2 extensible_passthru_variables[] = {
46     /*
47      * bogus entry.  Only some of it is actually used. 
48      */
49     {MIBINDEX, ASN_INTEGER, RWRITE, var_extensible_pass, 0, {MIBINDEX}},
50 };
51
52
53
54 /*
55  * lexicographical compare two object identifiers.
56  * * Returns -1 if name1 < name2,
57  * *          0 if name1 = name2,
58  * *          1 if name1 > name2
59  * *
60  * * This method differs from snmp_oid_compare
61  * * in that the comparison stops at the length
62  * * of the smallest object identifier.
63  */
64 int
65 snmp_oid_min_compare(const oid * in_name1,
66                      size_t len1, const oid * in_name2, size_t len2)
67 {
68     register int    len;
69     register const oid *name1 = in_name1;
70     register const oid *name2 = in_name2;
71
72     /*
73      * len = minimum of len1 and len2 
74      */
75     if (len1 < len2)
76         len = len1;
77     else
78         len = len2;
79     /*
80      * find first non-matching OID 
81      */
82     while (len-- > 0) {
83         /*
84          * these must be done in seperate comparisons, since
85          * subtracting them and using that result has problems with
86          * subids > 2^31. 
87          */
88         if (*(name1) < *(name2))
89             return -1;
90         if (*(name1++) > *(name2++))
91             return 1;
92     }
93     /*
94      * both OIDs equal up to length of shorter OID 
95      */
96
97     return 0;
98 }
99
100
101 /*
102  * This is also called from pass_persist.c 
103  */
104 int
105 asc2bin(char *p)
106 {
107     char           *r, *q = p;
108     char            c;
109     int             n = 0;
110
111     for (;;) {
112         c = (char) strtol(q, &r, 16);
113         if (r == q)
114             break;
115         *p++ = c;
116         q = r;
117         n++;
118     }
119     return n;
120 }
121
122 /*
123  * This is also called from pass_persist.c 
124  */
125 int
126 bin2asc(char *p, size_t n)
127 {
128     int             i, flag = 0;
129     char            buffer[SNMP_MAXBUF];
130
131     for (i = 0; i < (int) n; i++) {
132         buffer[i] = p[i];
133         if (!isprint(p[i]))
134             flag = 1;
135     }
136     if (flag == 0) {
137         p[n] = 0;
138         return n;
139     }
140     for (i = 0; i < (int) n; i++) {
141         sprintf(p, "%02x ", (unsigned char) (buffer[i] & 0xff));
142         p += 3;
143     }
144     *--p = 0;
145     return 3 * n - 1;
146 }
147
148
149 void
150 init_pass(void)
151 {
152     snmpd_register_config_handler("pass", pass_parse_config,
153                                   pass_free_config, "miboid command");
154 }
155
156
157 void
158 pass_parse_config(const char *token, char *cptr)
159 {
160     struct extensible **ppass = &passthrus, **etmp, *ptmp;
161     char           *tcptr;
162     int             i;
163
164     if (*cptr == '.')
165         cptr++;
166     if (!isdigit(*cptr)) {
167         config_perror("second token is not a OID");
168         return;
169     }
170     numpassthrus++;
171
172     while (*ppass != NULL)
173         ppass = &((*ppass)->next);
174     (*ppass) = (struct extensible *) malloc(sizeof(struct extensible));
175     if (*ppass == NULL)
176         return;
177     (*ppass)->type = PASSTHRU;
178
179     (*ppass)->miblen = parse_miboid(cptr, (*ppass)->miboid);
180     while (isdigit(*cptr) || *cptr == '.')
181         cptr++;
182     /*
183      * name 
184      */
185     cptr = skip_white(cptr);
186     if (cptr == NULL) {
187         config_perror("No command specified on pass line");
188         (*ppass)->command[0] = 0;
189     } else {
190         for (tcptr = cptr; *tcptr != 0 && *tcptr != '#' && *tcptr != ';';
191              tcptr++);
192         strncpy((*ppass)->command, cptr, tcptr - cptr);
193         (*ppass)->command[tcptr - cptr] = 0;
194     }
195     strncpy((*ppass)->name, (*ppass)->command, sizeof((*ppass)->name));
196     (*ppass)->name[ sizeof((*ppass)->name)-1 ] = 0;
197     (*ppass)->next = NULL;
198
199     register_mib("pass", (struct variable *) extensible_passthru_variables,
200                  sizeof(struct variable2),
201                  1, (*ppass)->miboid, (*ppass)->miblen);
202
203     /*
204      * argggg -- pasthrus must be sorted 
205      */
206     if (numpassthrus > 0) {
207         etmp = (struct extensible **)
208             malloc(((sizeof(struct extensible *)) * numpassthrus));
209         if (etmp == NULL)
210             return;
211
212         for (i = 0, ptmp = (struct extensible *) passthrus;
213              i < numpassthrus && ptmp != 0; i++, ptmp = ptmp->next)
214             etmp[i] = ptmp;
215         qsort(etmp, numpassthrus, sizeof(struct extensible *),
216               pass_compare);
217         passthrus = (struct extensible *) etmp[0];
218         ptmp = (struct extensible *) etmp[0];
219
220         for (i = 0; i < numpassthrus - 1; i++) {
221             ptmp->next = etmp[i + 1];
222             ptmp = ptmp->next;
223         }
224         ptmp->next = NULL;
225         free(etmp);
226     }
227 }
228
229 void
230 pass_free_config(void)
231 {
232     struct extensible *etmp, *etmp2;
233
234     for (etmp = passthrus; etmp != NULL;) {
235         etmp2 = etmp;
236         etmp = etmp->next;
237         unregister_mib(etmp2->miboid, etmp2->miblen);
238         free(etmp2);
239     }
240     passthrus = NULL;
241     numpassthrus = 0;
242 }
243
244 u_char         *
245 var_extensible_pass(struct variable *vp,
246                     oid * name,
247                     size_t * length,
248                     int exact,
249                     size_t * var_len, WriteMethod ** write_method)
250 {
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;
258     FILE           *file;
259
260     long_ret = *length;
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)) {
266             /*
267              * setup args 
268              */
269             if (passthru->miblen >= *length || rtest < 0)
270                 sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
271             else
272                 sprint_mib_oid(buf, name, *length);
273             if (exact)
274                 snprintf(passthru->command, sizeof(passthru->command),
275                          "%s -g %s", passthru->name, buf);
276             else
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",
281                         passthru->command));
282             /*
283              * valid call.  Exec and get output 
284              */
285             if ((fd = get_exec_output(passthru)) != -1) {
286                 file = fdopen(fd, "r");
287                 if (fgets(buf, sizeof(buf), file) == NULL) {
288                     /*
289                      * to enable creation
290                      */
291                     *write_method = setPass;
292                     *var_len = 0;
293                     fclose(file);
294                     wait_on_exec(passthru);
295                     return (NULL);
296                 }
297                 newlen = parse_miboid(buf, newname);
298
299                 /*
300                  * its good, so copy onto name/length 
301                  */
302                 memcpy((char *) name, (char *) newname,
303                        (int) newlen * sizeof(oid));
304                 *length = newlen;
305
306                 /*
307                  * set up return pointer for setable stuff 
308                  */
309                 *write_method = setPass;
310
311                 if (newlen == 0 || fgets(buf, sizeof(buf), file) == NULL
312                     || fgets(buf2, sizeof(buf2), file) == NULL) {
313                     *var_len = 0;
314                     fclose(file);
315                     wait_on_exec(passthru);
316                     return (NULL);
317                 }
318                 fclose(file);
319                 wait_on_exec(passthru);
320
321                 /*
322                  * buf contains the return type, and buf2 contains the data 
323                  */
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);
369                     if (newlen != 4) {
370                         snmp_log(LOG_ERR,
371                                  "invalid ipaddress returned:  %s\n",
372                                  buf2);
373                         *var_len = 0;
374                         return (NULL);
375                     }
376                     long_ret =
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);
383                 }
384             }
385             *var_len = 0;
386             return (NULL);
387         }
388     }
389     if (var_len)
390         *var_len = 0;
391     *write_method = NULL;
392     return (NULL);
393 }
394
395 int
396 setPass(int action,
397         u_char * var_val,
398         u_char var_val_type,
399         size_t var_val_len, u_char * statP, oid * name, size_t name_len)
400 {
401     int             i, rtest;
402     struct extensible *passthru;
403
404     char            buf[SNMP_MAXBUF], buf2[SNMP_MAXBUF];
405     long            tmp;
406     unsigned long   utmp;
407     size_t          itmp;
408
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);
413         if (rtest <= 0) {
414             if (action != COMMIT)
415                 return SNMP_ERR_NOERROR;
416             /*
417              * setup args 
418              */
419             if (passthru->miblen >= name_len || rtest < 0)
420                 sprint_mib_oid(buf, passthru->miboid, passthru->miblen);
421             else
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) {
427             case ASN_INTEGER:
428             case ASN_COUNTER:
429             case ASN_GAUGE:
430             case ASN_TIMETICKS:
431                 tmp = *((long *) var_val);
432                 switch (var_val_type) {
433                 case ASN_INTEGER:
434                     sprintf(buf, "integer %d\n", (int) tmp);
435                     break;
436                 case ASN_COUNTER:
437                     sprintf(buf, "counter %d\n", (int) tmp);
438                     break;
439                 case ASN_GAUGE:
440                     sprintf(buf, "gauge %d\n", (int) tmp);
441                     break;
442                 case ASN_TIMETICKS:
443                     sprintf(buf, "timeticks %d\n", (int) tmp);
444                     break;
445                 }
446                 break;
447             case ASN_IPADDRESS:
448                 utmp = *((u_long *) var_val);
449                 utmp = ntohl(utmp);
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)));
455                 break;
456             case ASN_OCTET_STR:
457                 itmp = sizeof(buf2);
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);
463                 else
464                     snprintf(buf, sizeof(buf), "octet \"%s\"\n", buf2);
465                 buf[ sizeof(buf)-1 ] = 0;
466                 break;
467             case ASN_OBJECT_ID:
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;
471                 break;
472             }
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",
476                         passthru->command));
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;
482             }
483             return SNMP_ERR_NOERROR;
484         }
485     }
486     if (snmp_get_do_debugging()) {
487         sprint_mib_oid(buf2, name, name_len);
488         DEBUGMSGTL(("ucd-snmp/pass", "pass-notfound:  %s\n", buf2));
489     }
490     return SNMP_ERR_NOSUCHNAME;
491 }
492
493 int
494 pass_compare(const void *a, const void *b)
495 {
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,
500                             (*bp)->miblen);
501 }