added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / ucd-snmp / extensible.c
1 #include <net-snmp/net-snmp-config.h>
2
3 #if HAVE_STDLIB_H
4 #include <stdlib.h>
5 #endif
6 #if HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9 #if HAVE_FCNTL_H
10 #include <fcntl.h>
11 #endif
12 #if TIME_WITH_SYS_TIME
13 # ifdef WIN32
14 #  include <sys/timeb.h>
15 # else
16 #  include <sys/time.h>
17 # endif
18 # include <time.h>
19 #else
20 # if HAVE_SYS_TIME_H
21 #  include <sys/time.h>
22 # else
23 #  include <time.h>
24 # endif
25 #endif
26 #include <signal.h>
27 #if HAVE_MACHINE_PARAM_H
28 #include <machine/param.h>
29 #endif
30 #if HAVE_SYS_PARAM_H
31 #include <sys/param.h>
32 #endif
33 #if HAVE_SYS_VMMETER_H
34 #if !(defined(bsdi2) || defined(netbsd1))
35 #include <sys/vmmeter.h>
36 #endif
37 #endif
38 #if HAVE_SYS_CONF_H
39 #include <sys/conf.h>
40 #endif
41 #if HAVE_ASM_PAGE_H
42 #include <asm/page.h>
43 #endif
44 #if HAVE_SYS_SWAP_H
45 #include <sys/swap.h>
46 #endif
47 #if HAVE_SYS_FS_H
48 #include <sys/fs.h>
49 #else
50 #if HAVE_UFS_FS_H
51 #include <ufs/fs.h>
52 #else
53 #if HAVE_UFS_UFS_DINODE_H
54 #include <ufs/ufs/dinode.h>
55 #endif
56 #if HAVE_UFS_FFS_FS_H
57 #include <ufs/ffs/fs.h>
58 #endif
59 #endif
60 #endif
61 #if HAVE_MTAB_H
62 #include <mtab.h>
63 #endif
64 #include <sys/stat.h>
65 #include <errno.h>
66 #if HAVE_FSTAB_H
67 #include <fstab.h>
68 #endif
69 #if HAVE_SYS_STATFS_H
70 #include <sys/statfs.h>
71 #endif
72 #if HAVE_SYS_STATVFS_H
73 #include <sys/statvfs.h>
74 #endif
75 #if HAVE_SYS_VFS_H
76 #include <sys/vfs.h>
77 #endif
78 #if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS)
79 #if HAVE_SYS_MOUNT_H
80 #include <sys/mount.h>
81 #endif
82 #if HAVE_SYS_SYSCTL_H
83 #include <sys/sysctl.h>
84 #endif
85 #define statvfs statfs
86 #endif
87 #if HAVE_VM_VM_H
88 #include <vm/vm.h>
89 #endif
90 #if HAVE_VM_SWAP_PAGER_H
91 #include <vm/swap_pager.h>
92 #endif
93 #if HAVE_SYS_FIXPOINT_H
94 #include <sys/fixpoint.h>
95 #endif
96 #if HAVE_MALLOC_H
97 #include <malloc.h>
98 #endif
99 #if HAVE_STRING_H
100 #include <string.h>
101 #endif
102 #include <ctype.h>
103 #if HAVE_WINSOCK_H
104 #include <winsock.h>
105 #endif
106 #ifndef HAVE_STRNCASECMP
107 int             strncasecmp(const char *s1, const char *s2, size_t n);
108 #endif
109
110 #if HAVE_DMALLOC_H
111 #include <dmalloc.h>
112 #endif
113
114 #include <net-snmp/net-snmp-includes.h>
115 #include <net-snmp/agent/net-snmp-agent-includes.h>
116 #include <net-snmp/agent/auto_nlist.h>
117
118 #include "struct.h"
119 #include "extensible.h"
120 #include "util_funcs.h"
121
122 extern struct myproc *procwatch;        /* moved to proc.c */
123 extern int      numprocs;       /* ditto */
124 extern struct extensible *extens;       /* In exec.c */
125 extern struct extensible *relocs;       /* In exec.c */
126 extern int      numextens;      /* ditto */
127 extern int      numrelocs;      /* ditto */
128 extern struct extensible *passthrus;    /* In pass.c */
129 extern int      numpassthrus;   /* ditto */
130 extern char     sysName[];
131 extern netsnmp_subtree *subtrees;
132 extern struct variable2 extensible_relocatable_variables[];
133 extern struct variable2 extensible_passthru_variables[];
134
135 void
136 init_extensible(void)
137 {
138
139     struct variable2 extensible_extensible_variables[] = {
140         {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_shell, 1,
141          {MIBINDEX}},
142         {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_shell, 1,
143          {ERRORNAME}},
144         {SHELLCOMMAND, ASN_OCTET_STR, RONLY, var_extensible_shell, 1,
145          {SHELLCOMMAND}},
146         {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_shell, 1,
147          {ERRORFLAG}},
148         {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_shell, 1,
149          {ERRORMSG}},
150         {ERRORFIX, ASN_INTEGER, RWRITE, var_extensible_shell, 1,
151          {ERRORFIX}},
152         {ERRORFIXCMD, ASN_OCTET_STR, RONLY, var_extensible_shell, 1,
153          {ERRORFIXCMD}}
154     };
155
156     /*
157      * Define the OID pointer to the top of the mib tree that we're
158      * registering underneath 
159      */
160     oid             extensible_variables_oid[] =
161         { UCDAVIS_MIB, SHELLMIBNUM, 1 };
162
163     /*
164      * register ourselves with the agent to handle our mib tree 
165      */
166     REGISTER_MIB("ucd-snmp/extensible", extensible_extensible_variables,
167                  variable2, extensible_variables_oid);
168
169     snmpd_register_config_handler("exec", extensible_parse_config,
170                                   extensible_free_config,
171                                   "[miboid] name program arguments");
172     snmpd_register_config_handler("sh", extensible_parse_config,
173                                   extensible_free_config,
174                                   "[miboid] name program-or-script arguments");
175     snmpd_register_config_handler("execfix", execfix_parse_config, NULL,
176                                   "exec-or-sh-name program [arguments...]");
177 }
178
179 void
180 extensible_parse_config(const char *token, char *cptr)
181 {
182     struct extensible *ptmp, **pp;
183     char           *tcptr;
184
185     /*
186      * allocate and clear memory structure 
187      */
188     ptmp = (struct extensible *) calloc(1, sizeof(struct extensible));
189     if (ptmp == NULL)
190         return;                 /* XXX memory alloc error */
191
192     if (*cptr == '.')
193         cptr++;
194     if (isdigit(*cptr)) {
195         /*
196          * its a relocatable extensible mib 
197          */
198         for (pp = &relocs, numrelocs++; *pp; pp = &((*pp)->next));
199         (*pp) = ptmp;
200     } else {
201         /*
202          * it goes in with the general extensible table 
203          */
204         for (pp = &extens, numextens++; *pp; pp = &((*pp)->next));
205         (*pp) = ptmp;
206     }
207
208     /*
209      * the rest is pretty much handled the same 
210      */
211     if (!strncasecmp(token, "sh", 2))
212         ptmp->type = SHPROC;
213     else
214         ptmp->type = EXECPROC;
215     if (isdigit(*cptr)) {
216         ptmp->miblen = parse_miboid(cptr, ptmp->miboid);
217         while (isdigit(*cptr) || *cptr == '.')
218             cptr++;
219     }
220
221     /*
222      * name 
223      */
224     cptr = skip_white(cptr);
225     copy_nword(cptr, ptmp->name, sizeof(ptmp->name));
226     cptr = skip_not_white(cptr);
227     cptr = skip_white(cptr);
228     /*
229      * command 
230      */
231     if (cptr == NULL) {
232         config_perror("No command specified on line");
233     } else {
234         for (tcptr = cptr; *tcptr != 0 && *tcptr != '#' && *tcptr != ';';
235              tcptr++);
236         strncpy(ptmp->command, cptr, tcptr - cptr);
237         ptmp->command[tcptr - cptr] = 0;
238     }
239 #ifdef EXECFIXCMD
240     sprintf(ptmp->fixcmd, EXECFIXCMD, ptmp->name);
241 #endif
242     if (ptmp->miblen > 0) {
243         register_mib(token,
244                      (struct variable *) extensible_relocatable_variables,
245                      sizeof(struct variable2), 6, ptmp->miboid,
246                      ptmp->miblen);
247     }
248 }
249
250 void
251 extensible_free_config(void)
252 {
253     struct extensible *etmp, *etmp2;
254
255     for (etmp = extens; etmp != NULL;) {
256         etmp2 = etmp;
257         etmp = etmp->next;
258         free(etmp2);
259     }
260
261     for (etmp = relocs; etmp != NULL;) {
262         etmp2 = etmp;
263         etmp = etmp->next;
264         unregister_mib(etmp2->miboid, etmp2->miblen);
265         free(etmp2);
266     }
267
268     relocs = NULL;
269     extens = NULL;
270     numextens = 0;
271     numrelocs = 0;
272 }
273
274
275 struct extensible *
276 get_exten_instance(struct extensible *exten, size_t inst)
277 {
278     int             i;
279
280     if (exten == NULL)
281         return (NULL);
282     for (i = 1; i != (int) inst && exten != NULL; i++)
283         exten = exten->next;
284     return (exten);
285 }
286
287 #define MAXMSGLINES 1000
288
289 struct extensible *extens = NULL;       /* In exec.c */
290 struct extensible *relocs = NULL;       /* In exec.c */
291 int             numextens = 0, numrelocs = 0;   /* ditto */
292
293
294 /*
295  * var_extensible_shell(...
296  * Arguments:
297  * vp     IN      - pointer to variable entry that points here
298  * name    IN/OUT  - IN/name requested, OUT/name found
299  * length  IN/OUT  - length of IN/OUT oid's 
300  * exact   IN      - TRUE if an exact match was requested
301  * var_len OUT     - length of variable or 0 if function returned
302  * write_method
303  * 
304  */
305
306 /*
307  * find a give entry in the linked list associated with a proc name 
308  */
309 struct extensible *
310 get_exec_by_name(char *name)
311 {
312     struct extensible *etmp;
313
314     if (name == NULL)
315         return NULL;
316
317     for (etmp = extens; etmp != NULL && strcmp(etmp->name, name) != 0;
318          etmp = etmp->next);
319     return etmp;
320 }
321
322 void
323 execfix_parse_config(const char *token, char *cptr)
324 {
325     char            tmpname[STRMAX];
326     struct extensible *execp;
327
328     /*
329      * don't allow two entries with the same name 
330      */
331     cptr = copy_nword(cptr, tmpname, sizeof(tmpname));
332     if ((execp = get_exec_by_name(tmpname)) == NULL) {
333         config_perror("No exec entry registered for this exec name yet.");
334         return;
335     }
336
337     if (strlen(cptr) > sizeof(execp->fixcmd)) {
338         config_perror("fix command too long.");
339         return;
340     }
341
342     strncpy(execp->fixcmd, cptr, sizeof(execp->fixcmd));
343     execp->fixcmd[ sizeof(execp->fixcmd)-1 ] = 0;
344 }
345
346 u_char         *
347 var_extensible_shell(struct variable * vp,
348                      oid * name,
349                      size_t * length,
350                      int exact,
351                      size_t * var_len, WriteMethod ** write_method)
352 {
353
354     static struct extensible *exten = 0;
355     static long     long_ret;
356
357     if (header_simple_table
358         (vp, name, length, exact, var_len, write_method, numextens))
359         return (NULL);
360
361     if ((exten = get_exten_instance(extens, name[*length - 1]))) {
362         switch (vp->magic) {
363         case MIBINDEX:
364             long_ret = name[*length - 1];
365             return ((u_char *) (&long_ret));
366         case ERRORNAME:        /* name defined in config file */
367             *var_len = strlen(exten->name);
368             return ((u_char *) (exten->name));
369         case SHELLCOMMAND:
370             *var_len = strlen(exten->command);
371             return ((u_char *) (exten->command));
372         case ERRORFLAG:        /* return code from the process */
373             if (exten->type == EXECPROC)
374                 exec_command(exten);
375             else
376                 shell_command(exten);
377             long_ret = exten->result;
378             return ((u_char *) (&long_ret));
379         case ERRORMSG:         /* first line of text returned from the process */
380             if (exten->type == EXECPROC)
381                 exec_command(exten);
382             else
383                 shell_command(exten);
384             *var_len = strlen(exten->output);
385             if (exten->output[*var_len - 1] == '\n')
386                 exten->output[--(*var_len)] = '\0';
387             return ((u_char *) (exten->output));
388         case ERRORFIX:
389             *write_method = fixExecError;
390             long_return = 0;
391             return ((u_char *) & long_return);
392
393         case ERRORFIXCMD:
394             *var_len = strlen(exten->fixcmd);
395             return ((u_char *) exten->fixcmd);
396         }
397         return NULL;
398     }
399     return NULL;
400 }
401
402 int
403 fixExecError(int action,
404              u_char * var_val,
405              u_char var_val_type,
406              size_t var_val_len,
407              u_char * statP, oid * name, size_t name_len)
408 {
409
410     struct extensible *exten;
411     long            tmp = 0;
412     int             fd;
413     static struct extensible ex;
414     FILE           *file;
415
416     if ((exten = get_exten_instance(extens, name[10]))) {
417         if (var_val_type != ASN_INTEGER) {
418             snmp_log(LOG_ERR, "Wrong type != int\n");
419             return SNMP_ERR_WRONGTYPE;
420         }
421         tmp = *((long *) var_val);
422         if ((tmp == 1) && (action == COMMIT) && (exten->fixcmd[0] != 0)) {
423             sprintf(ex.command, exten->fixcmd);
424             if ((fd = get_exec_output(&ex)) != -1) {
425                 file = fdopen(fd, "r");
426                 while (fgets(ex.output, sizeof(ex.output), file) != NULL);
427                 fclose(file);
428                 wait_on_exec(&ex);
429             }
430         }
431         return SNMP_ERR_NOERROR;
432     }
433     return SNMP_ERR_WRONGTYPE;
434 }
435
436 /*
437  * the relocatable extensible commands variables 
438  */
439 struct variable2 extensible_relocatable_variables[] = {
440     {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_relocatable, 1,
441      {MIBINDEX}},
442     {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_relocatable, 1,
443      {ERRORNAME}},
444     {SHELLCOMMAND, ASN_OCTET_STR, RONLY, var_extensible_relocatable, 1,
445      {SHELLCOMMAND}},
446     {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_relocatable, 1,
447      {ERRORFLAG}},
448     {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_relocatable, 1,
449      {ERRORMSG}},
450     {ERRORFIX, ASN_INTEGER, RWRITE, var_extensible_relocatable, 1,
451      {ERRORFIX}}
452 };
453
454 u_char         *
455 var_extensible_relocatable(struct variable *vp,
456                            oid * name,
457                            size_t * length,
458                            int exact,
459                            size_t * var_len, WriteMethod ** write_method)
460 {
461
462     int             fd;
463     int             i;
464     FILE           *file;
465     struct extensible *exten = 0;
466     static long     long_ret;
467     static char     errmsg[STRMAX];
468     struct variable myvp;
469     oid             tname[MAX_OID_LEN];
470
471     memcpy(&myvp, vp, sizeof(struct variable));
472
473     long_ret = *length;
474     for (i = 1; i <= (int) numrelocs; i++) {
475         exten = get_exten_instance(relocs, i);
476         if ((int) exten->miblen == (int) vp->namelen - 1) {
477             memcpy(myvp.name, exten->miboid, exten->miblen * sizeof(oid));
478             myvp.namelen = exten->miblen;
479             *length = vp->namelen;
480             memcpy(tname, vp->name, vp->namelen * sizeof(oid));
481             if (!header_simple_table
482                 (&myvp, tname, length, -1, var_len, write_method, -1))
483                 break;
484             else
485                 exten = NULL;
486         }
487     }
488     if (i > (int) numrelocs || exten == NULL) {
489         *length = long_ret;
490         *var_len = 0;
491         *write_method = NULL;
492         return (NULL);
493     }
494
495     *length = long_ret;
496     if (header_simple_table(vp, name, length, exact, var_len, write_method,
497                             ((vp->magic == ERRORMSG) ? MAXMSGLINES : 1)))
498         return (NULL);
499
500     switch (vp->magic) {
501     case MIBINDEX:
502         long_ret = name[*length - 1];
503         return ((u_char *) (&long_ret));
504     case ERRORNAME:            /* name defined in config file */
505         *var_len = strlen(exten->name);
506         return ((u_char *) (exten->name));
507     case SHELLCOMMAND:
508         *var_len = strlen(exten->command);
509         return ((u_char *) (exten->command));
510     case ERRORFLAG:            /* return code from the process */
511         if (exten->type == EXECPROC)
512             exec_command(exten);
513         else
514             shell_command(exten);
515         long_ret = exten->result;
516         return ((u_char *) (&long_ret));
517     case ERRORMSG:             /* first line of text returned from the process */
518         if (exten->type == EXECPROC) {
519             if ((fd = get_exec_output(exten)) != -1) {
520                 file = fdopen(fd, "r");
521                 for (i = 0; i != (int) name[*length - 1]; i++) {
522                     if (fgets(errmsg, sizeof(errmsg), file) == NULL) {
523                         *var_len = 0;
524                         fclose(file);
525                         wait_on_exec(exten);
526                         return (NULL);
527                     }
528                 }
529                 fclose(file);
530                 wait_on_exec(exten);
531             } else
532                 errmsg[0] = 0;
533         } else {
534             if (*length > 1) {
535                 *var_len = 0;
536                 return (NULL);
537             }
538             shell_command(exten);
539             strncpy(errmsg, exten->output, sizeof(errmsg));
540             errmsg[ sizeof(errmsg)-1 ] = 0;
541         }
542         *var_len = strlen(errmsg);
543         if (errmsg[*var_len - 1] == '\n')
544             errmsg[--(*var_len)] = '\0';
545         return ((u_char *) (errmsg));
546     case ERRORFIX:
547         *write_method = fixExecError;
548         long_return = 0;
549         return ((u_char *) & long_return);
550     }
551     return NULL;
552 }
553
554 netsnmp_subtree *
555 find_extensible(netsnmp_subtree *tp, oid *tname, size_t tnamelen, int exact)
556 {
557     size_t          tmp;
558     int             i;
559     struct extensible *exten = 0;
560     struct variable myvp;
561     oid             name[MAX_OID_LEN];
562     static netsnmp_subtree mysubtree[2] =
563         { { NULL, 0, NULL, 0, NULL, 0, NULL, 0, 0, NULL, NULL, 0, 0, 0,
564             NULL, NULL, NULL, 0, 0, NULL, 0, 0 },
565           { NULL, 0, NULL, 0, NULL, 0, NULL, 0, 0, NULL, NULL, 0, 0, 0,
566             NULL, NULL, NULL, 0, 0, NULL, 0, 0 } };
567
568     for (i = 1; i <= (int) numrelocs; i++) {
569         exten = get_exten_instance(relocs, i);
570         if (exten->miblen != 0) {
571             memcpy(myvp.name, exten->miboid, exten->miblen * sizeof(oid));
572             memcpy(name, tname, tnamelen * sizeof(oid));
573             myvp.name[exten->miblen] = name[exten->miblen];
574             myvp.namelen = exten->miblen + 1;
575             tmp = exten->miblen + 1;
576             if (!header_simple_table(&myvp, name, &tmp, -1, 
577                                      NULL, NULL, numrelocs)) {
578                 break;
579             }
580         }
581     }
582     if (i > (int)numrelocs || exten == NULL) {
583         return (tp);
584     }
585
586     if (mysubtree[0].name_a != NULL) {
587         free(mysubtree[0].name_a);
588         mysubtree[0].name_a = NULL;
589     }
590     mysubtree[0].name_a  = snmp_duplicate_objid(exten->miboid, exten->miblen);
591     mysubtree[0].namelen = exten->miblen;
592     mysubtree[0].variables = (struct variable *)extensible_relocatable_variables;
593     mysubtree[0].variables_len = sizeof(extensible_relocatable_variables) /
594         sizeof(*extensible_relocatable_variables);
595     mysubtree[0].variables_width = sizeof(*extensible_relocatable_variables);
596     mysubtree[1].namelen = 0;
597     return (mysubtree);
598 }