# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / read_config.c
1 /*
2  * read_config.c
3  */
4
5 #include <net-snmp/net-snmp-config.h>
6
7 #include <stdio.h>
8 #include <ctype.h>
9 #if HAVE_STDLIB_H
10 #include <stdlib.h>
11 #endif
12 #if HAVE_STRING_H
13 #include <string.h>
14 #else
15 #include <strings.h>
16 #endif
17 #if HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #include <sys/types.h>
21 #if HAVE_SYS_PARAM_H
22 #include <sys/param.h>
23 #endif
24 #if TIME_WITH_SYS_TIME
25 # ifdef WIN32
26 #  include <sys/timeb.h>
27 # else
28 #  include <sys/time.h>
29 # endif
30 # include <time.h>
31 #else
32 # if HAVE_SYS_TIME_H
33 #  include <sys/time.h>
34 # else
35 #  include <time.h>
36 # endif
37 #endif
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41 #if HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #if HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
46 #endif
47 #if HAVE_SYS_SELECT_H
48 #include <sys/select.h>
49 #endif
50 #if HAVE_WINSOCK_H
51 #include <winsock.h>
52 #endif
53 #if HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
55 #endif
56 #if HAVE_NETDB_H
57 #include <netdb.h>
58 #endif
59 #include <errno.h>
60
61 #if HAVE_DMALLOC_H
62 #include <dmalloc.h>
63 #endif
64
65 #include <net-snmp/types.h>
66 #include <net-snmp/output_api.h>
67 #include <net-snmp/config_api.h>
68 #include <net-snmp/library/read_config.h>       /* for "internal" definitions */
69 #include <net-snmp/utilities.h>
70
71 #include <net-snmp/library/mib.h>
72 #include <net-snmp/library/parse.h>
73 #include <net-snmp/library/snmp_api.h>
74 #include <net-snmp/library/callback.h>
75
76 #ifndef BUILD_ILMI
77 static int      config_errors;
78
79 struct config_files *config_files = NULL;
80
81 #ifdef BRCM_SNMP_SUPPORT
82 struct config_line *
83 register_prenetsnmp_mib_handler(const char *type,
84                                 const char *token,
85                                 void (*parser) (const char *, char *),
86                                 void (*releaser) (void), const char *help)
87 {
88     struct config_line *ltmp;
89     ltmp = register_config_handler(type, token, parser, releaser, help);
90     if (ltmp != NULL)
91         ltmp->config_time = PREMIB_CONFIG;
92     return (ltmp);
93 }
94
95 struct config_line *
96 register_app_prenetsnmp_mib_handler(const char *token,
97                                     void (*parser) (const char *, char *),
98                                     void (*releaser) (void),
99                                     const char *help)
100 {
101     return (register_prenetsnmp_mib_handler
102             (NULL, token, parser, releaser, help));
103 }
104 #endif /* #ifdef BRCM_SNMP_SUPPORT */
105
106 /*******************************************************************-o-******
107  * register_config_handler
108  *
109  * Parameters:
110  *      *type
111  *      *token
112  *      *parser
113  *      *releaser
114  *      
115  * Returns:
116  *      Pointer to a new config line entry  -OR-  NULL on error.
117  */
118 struct config_line *
119 register_config_handler(const char *type_param,
120                         const char *token,
121                         void (*parser) (const char *, char *),
122                         void (*releaser) (void), const char *help)
123 {
124     struct config_files **ctmp = &config_files;
125     struct config_line **ltmp;
126     const char     *type = type_param;
127
128     if (type == NULL) {
129         type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
130                                      NETSNMP_DS_LIB_APPTYPE);
131     }
132
133     /*
134      * Find type in current list  -OR-  create a new file type.
135      */
136     while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
137         ctmp = &((*ctmp)->next);
138     }
139
140     if (*ctmp == NULL) {
141         *ctmp = (struct config_files *)
142             calloc(1, sizeof(struct config_files));
143         if (!*ctmp) {
144             return NULL;
145         }
146
147         (*ctmp)->fileHeader = strdup(type);
148     }
149
150     /*
151      * Find parser type in current list  -OR-  create a new
152      * line parser entry.
153      */
154     ltmp = &((*ctmp)->start);
155
156     while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) {
157         ltmp = &((*ltmp)->next);
158     }
159
160     if (*ltmp == NULL) {
161         *ltmp = (struct config_line *)
162             calloc(1, sizeof(struct config_line));
163         if (!*ltmp) {
164             return NULL;
165         }
166
167         (*ltmp)->config_time = NORMAL_CONFIG;
168         (*ltmp)->config_token = strdup(token);
169         if (help != NULL)
170             (*ltmp)->help = strdup(help);
171     }
172
173     /*
174      * Add/Replace the parse/free functions for the given line type
175      * in the given file type.
176      */
177     (*ltmp)->parse_line = parser;
178     (*ltmp)->free_func = releaser;
179
180     return (*ltmp);
181
182 }                               /* end register_config_handler() */
183
184 struct config_line *
185 register_app_config_handler(const char *token,
186                             void (*parser) (const char *, char *),
187                             void (*releaser) (void), const char *help)
188 {
189     return (register_config_handler(NULL, token, parser, releaser, help));
190 }
191
192 void
193 unregister_config_handler(const char *type_param, const char *token)
194 {
195     struct config_files **ctmp = &config_files;
196     struct config_line **ltmp, *ltmp2;
197     const char     *type = type_param;
198
199     if (type == NULL) {
200         type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
201                                      NETSNMP_DS_LIB_APPTYPE);
202     }
203
204     /*
205      * find type in current list 
206      */
207     while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
208         ctmp = &((*ctmp)->next);
209     }
210
211     if (*ctmp == NULL) {
212         /*
213          * Not found, return. 
214          */
215         return;
216     }
217
218     ltmp = &((*ctmp)->start);
219     if (*ltmp == NULL) {
220         /*
221          * Not found, return. 
222          */
223         return;
224     }
225     if (strcmp((*ltmp)->config_token, token) == 0) {
226         /*
227          * found it at the top of the list 
228          */
229         ltmp2 = (*ltmp)->next;
230         free((*ltmp)->config_token);
231         SNMP_FREE((*ltmp)->help);
232         free(*ltmp);
233         (*ctmp)->start = ltmp2;
234         return;
235     }
236     while ((*ltmp)->next != NULL
237            && strcmp((*ltmp)->next->config_token, token)) {
238         ltmp = &((*ltmp)->next);
239     }
240     if ((*ltmp)->next != NULL) {
241         free((*ltmp)->next->config_token);
242         SNMP_FREE((*ltmp)->next->help);
243         ltmp2 = (*ltmp)->next->next;
244         free((*ltmp)->next);
245         (*ltmp)->next = ltmp2;
246     }
247 }
248
249 void
250 unregister_app_config_handler(const char *token)
251 {
252     unregister_config_handler(NULL, token);
253 }
254
255 void
256 unregister_all_config_handlers()
257 {
258     struct config_files *ctmp, *save;
259     struct config_line *ltmp;
260
261     free_config();
262
263     /*
264      * Keep using config_files until there are no more! 
265      */
266     for (ctmp = config_files; ctmp;) {
267         for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) {
268             unregister_config_handler(ctmp->fileHeader,
269                                       ltmp->config_token);
270         }
271         free(ctmp->fileHeader);
272         save = ctmp->next;
273         free(ctmp);
274         ctmp = save;
275         config_files = save;
276     }
277 }
278
279 #ifdef TESTING
280 void
281 print_config_handlers(void)
282 {
283     struct config_files *ctmp = config_files;
284     struct config_line *ltmp;
285
286     for (; ctmp != NULL; ctmp = ctmp->next) {
287         DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader));
288         for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next)
289             DEBUGMSGTL(("read_config", "                   %s\n",
290                         ltmp->config_token));
291     }
292 }
293 #endif
294
295 int             linecount;
296 const char     *curfilename;
297
298 struct config_line *
299 read_config_get_handlers(const char *type)
300 {
301     struct config_files *ctmp = config_files;
302     for (; ctmp != NULL && strcmp(ctmp->fileHeader, type);
303          ctmp = ctmp->next);
304     if (ctmp)
305         return ctmp->start;
306     return NULL;
307 }
308
309 void
310 read_config_with_type(const char *filename, const char *type)
311 {
312     struct config_line *ctmp = read_config_get_handlers(type);
313     if (ctmp)
314         read_config_snmp(filename, ctmp, EITHER_CONFIG);
315     else
316         DEBUGMSGTL(("read_config",
317                     "read_config: I have no registrations for type:%s,file:%s\n",
318                     type, filename));
319 }
320
321
322 struct config_line *
323 read_config_find_handler(struct config_line *line_handlers,
324                          const char *token)
325 {
326     struct config_line *lptr;
327
328     for (lptr = line_handlers; lptr != NULL; lptr = lptr->next) {
329         if (!strcasecmp(token, lptr->config_token)) {
330             return lptr;
331         }
332     }
333     return NULL;
334 }
335
336 /*
337  * searches a config_line linked list for a match 
338  */
339 int
340 run_config_handler(struct config_line *lptr,
341                    const char *token, char *cptr, int when)
342 {
343     char            tmpbuf[STRINGMAX];
344     lptr = read_config_find_handler(lptr, token);
345     if (lptr != NULL) {
346         if (when == EITHER_CONFIG || lptr->config_time == when) {
347             DEBUGMSGTL(("read_config",
348                         "Found a parser.  Calling it: %s / %s\n", token,
349                         cptr));
350             (*(lptr->parse_line)) (token, cptr);
351         }
352     } else if (when != PREMIB_CONFIG && 
353                !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
354                                        NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) {
355         sprintf(tmpbuf, "Unknown token: %s.", token);
356         config_pwarn(tmpbuf);
357         return SNMPERR_GENERR;
358     }
359     return SNMPERR_SUCCESS;
360 }
361
362 /*
363  * takens an arbitrary string and tries to intepret it based on the
364  * known configruation handlers for all registered types.  May produce
365  * inconsistent results when multiple tokens of the same name are
366  * registered under different file types. 
367  */
368
369 /*
370  * we allow = delimeters here 
371  */
372 #define SNMP_CONFIG_DELIMETERS " \t="
373
374 int
375 snmp_config_when(char *line, int when)
376 {
377     char           *cptr, buf[STRINGMAX], tmpbuf[STRINGMAX];
378     struct config_line *lptr = NULL;
379     struct config_files *ctmp = config_files;
380
381     if (line == NULL) {
382         config_perror("snmp_config() called with a null string.");
383         return SNMPERR_GENERR;
384     }
385
386     strncpy(buf, line, STRINGMAX);
387     buf[STRINGMAX - 1] = '\0';
388     cptr = strtok(buf, SNMP_CONFIG_DELIMETERS);
389     if (cptr && cptr[0] == '[') {
390         if (cptr[strlen(cptr) - 1] != ']') {
391             config_perror("no matching ']'");
392             return SNMPERR_GENERR;
393         }
394         lptr = read_config_get_handlers(cptr + 1);
395         if (lptr == NULL) {
396             sprintf(tmpbuf, "No handlers regestered for type %s.",
397                     cptr + 1);
398             config_perror(tmpbuf);
399             return SNMPERR_GENERR;
400         }
401         cptr = strtok(NULL, SNMP_CONFIG_DELIMETERS);
402         lptr = read_config_find_handler(lptr, cptr);
403     } else {
404         /*
405          * we have to find a token 
406          */
407         for (; ctmp != NULL && lptr == NULL; ctmp = ctmp->next)
408             lptr = read_config_find_handler(ctmp->start, cptr);
409     }
410     if (lptr == NULL && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
411                                           NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) {
412         sprintf(tmpbuf, "Unknown token: %s.", cptr);
413         config_pwarn(tmpbuf);
414         return SNMPERR_GENERR;
415     }
416
417     /*
418      * use the original string instead since strtok messed up the original 
419      */
420     line = skip_white(line + (cptr - buf) + strlen(cptr) + 1);
421
422     return (run_config_handler(lptr, cptr, line, when));
423 }
424 int
425 netsnmp_config(char *line)
426 {
427     int             ret = SNMP_ERR_NOERROR;
428     DEBUGMSGTL(("snmp_config", "remembering line \"%s\"\n", line));
429     netsnmp_config_remember(line);      /* always remember it so it's read
430                                          * processed after a free_config()
431                                          * call */
432     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
433                                NETSNMP_DS_LIB_HAVE_READ_CONFIG)) {
434         DEBUGMSGTL(("snmp_config", "  ... processing it now\n"));
435         ret = snmp_config_when(line, NORMAL_CONFIG);
436     }
437     return ret;
438 }
439
440 void
441 netsnmp_config_remember_in_list(char *line,
442                                 struct read_config_memory **mem)
443 {
444     if (mem == NULL)
445         return;
446
447     while (*mem != NULL)
448         mem = &((*mem)->next);
449
450     *mem = SNMP_MALLOC_STRUCT(read_config_memory);
451     if (line)
452         (*mem)->line = strdup(line);
453 }
454
455 void
456 netsnmp_config_remember_free_list(struct read_config_memory **mem)
457 {
458     struct read_config_memory *tmpmem;
459     while (*mem) {
460         SNMP_FREE((*mem)->line);
461         tmpmem = (*mem)->next;
462         free(*mem);
463         *mem = NULL;
464         mem = &tmpmem;
465     }
466 }
467
468 void
469 netsnmp_config_process_memory_list(struct read_config_memory **memp,
470                                    int when, int clear)
471 {
472
473     struct read_config_memory *mem;
474
475     if (!memp)
476         return;
477
478     mem = *memp;
479
480     while (mem) {
481         DEBUGMSGTL(("read_config", "processing memory: %s\n", mem->line));
482         snmp_config_when(mem->line, when);
483         mem = mem->next;
484     }
485
486     if (clear)
487         netsnmp_config_remember_free_list(memp);
488 }
489
490 /*
491  * default storage location implementation 
492  */
493 static struct read_config_memory *memorylist = NULL;
494
495 void
496 netsnmp_config_remember(char *line)
497 {
498     netsnmp_config_remember_in_list(line, &memorylist);
499 }
500
501 void
502 netsnmp_config_process_memories(void)
503 {
504     netsnmp_config_process_memory_list(&memorylist, EITHER_CONFIG, 1);
505 }
506
507 void
508 netsnmp_config_process_memories_when(int when, int clear)
509 {
510     netsnmp_config_process_memory_list(&memorylist, when, clear);
511 }
512
513 /*******************************************************************-o-******
514  * read_config
515  *
516  * Parameters:
517  *      *filename
518  *      *line_handler
519  *       when
520  *
521  * Read <filename> and process each line in accordance with the list of
522  * <line_handler> functions.
523  *
524  *
525  * For each line in <filename>, search the list of <line_handler>'s 
526  * for an entry that matches the first token on the line.  This comparison is
527  * case insensitive.
528  *
529  * For each match, check that <when> is the designated time for the
530  * <line_handler> function to be executed before processing the line.
531
532 Renamed to read_config_snmp to resolve linket error:
533  read_config is redefined in /CommEngine/user96345/src/udhcp-0.9.6/udhcp.a
534  See also "/net-snmp-5.0.3/include/net-snmp/library/read_config.h" 
535  Anothe way to fix the problem is declare the function "static". It is used only in this file.
536  --YD
537
538  */
539 void
540 read_config_snmp(const char *filename,
541             struct config_line *line_handler, int when)
542 {
543
544     FILE           *ifile;
545     char            line[STRINGMAX], token[STRINGMAX], tmpbuf[STRINGMAX];
546     char           *cptr;
547     int             i;
548     struct config_line *lptr;
549
550     linecount = 0;
551     curfilename = filename;
552
553     if ((ifile = fopen(filename, "r")) == NULL) {
554 #ifdef ENOENT
555         if (errno == ENOENT) {
556             DEBUGMSGTL(("read_config", "%s: %s\n", filename,
557                         strerror(errno)));
558         } else
559 #endif                          /* ENOENT */
560 #ifdef EACCES
561         if (errno == EACCES) {
562             DEBUGMSGTL(("read_config", "%s: %s\n", filename,
563                         strerror(errno)));
564         } else
565 #endif                          /* EACCES */
566 #if defined(ENOENT) || defined(EACCES)
567         {
568             snmp_log_perror(filename);
569         }
570 #else                           /* defined(ENOENT) || defined(EACCES) */
571             snmp_log_perror(filename);
572 #endif                          /* ENOENT */
573         return;
574     } else {
575         DEBUGMSGTL(("read_config", "Reading configuration %s\n",
576                     filename));
577     }
578
579     while (fgets(line, sizeof(line), ifile) != NULL) {
580         lptr = line_handler;
581         linecount++;
582         cptr = line;
583         i = strlen(line) - 1;
584         if (line[i] == '\n')
585             line[i] = 0;
586         /*
587          * check blank line or # comment 
588          */
589         if ((cptr = skip_white(cptr))) {
590             cptr = copy_nword(cptr, token, sizeof(token));
591             if (token[0] == '[') {
592                 token[strlen(token) - 1] = '\0';
593                 lptr = read_config_get_handlers(&token[1]);
594                 if (lptr == NULL) {
595                     sprintf(tmpbuf, "No handlers regestered for type %s.",
596                             &token[1]);
597                     config_perror(tmpbuf);
598                     continue;
599                 }
600                 DEBUGMSGTL(("read_config",
601                             "Switching to new context: %s%s\n",
602                             ((cptr) ? "(this line only) " : ""),
603                             &token[1]));
604                 if (cptr == NULL) {
605                     /*
606                      * change context permanently 
607                      */
608                     line_handler = lptr;
609                     continue;
610                 } else {
611                     /*
612                      * the rest of this line only applies. 
613                      */
614                     cptr = copy_nword(cptr, token, sizeof(token));
615                 }
616             } else {
617                 lptr = line_handler;
618             }
619             if (cptr == NULL) {
620                 sprintf(tmpbuf, "Blank line following %s token.", token);
621                 config_perror(tmpbuf);
622             } else {
623                 DEBUGMSGTL(("read_config", "%s:%d examining: %s\n",
624                             filename, linecount, line));
625                 run_config_handler(lptr, token, cptr, when);
626             }
627         }
628     }
629     fclose(ifile);
630     return;
631
632 }                               /* end read_config() */
633
634
635
636 void
637 free_config(void)
638 {
639     struct config_files *ctmp = config_files;
640     struct config_line *ltmp;
641
642     for (; ctmp != NULL; ctmp = ctmp->next)
643         for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next)
644             if (ltmp->free_func)
645                 (*(ltmp->free_func)) ();
646 }
647
648 void
649 read_configs(void)
650 {
651
652     char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
653                                                NETSNMP_DS_LIB_OPTIONALCONFIG);
654     char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
655                                        NETSNMP_DS_LIB_APPTYPE);
656
657     DEBUGMSGTL(("read_config", "reading normal configuration tokens\n"));
658
659     if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
660                                 NETSNMP_DS_LIB_DONT_READ_CONFIGS)) {
661         read_config_files(NORMAL_CONFIG);
662     }
663
664     /*
665      * do this even when the normal above wasn't done 
666      */
667     if (optional_config && type) {
668         struct stat     statbuf;
669         if (stat(optional_config, &statbuf)) {
670             DEBUGMSGTL(("read_config",
671                         "Optional File \"%s\" does not exist.\n",
672                         optional_config));
673             snmp_log_perror(optional_config);
674         } else {
675             DEBUGMSGTL(("read_config",
676                         "Reading optional config file: \"%s\"\n",
677                         optional_config));
678             read_config_with_type(optional_config, type);
679         }
680     }
681
682     netsnmp_config_process_memories_when(NORMAL_CONFIG, 1);
683
684     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
685                            NETSNMP_DS_LIB_HAVE_READ_CONFIG, 1);
686     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
687                         SNMP_CALLBACK_POST_READ_CONFIG, NULL);
688 }
689
690 #ifdef BRCM_SNMP_SUPPORT
691 void
692 read_premib_configs(void)
693 {
694     DEBUGMSGTL(("read_config", "reading premib configuration tokens\n"));
695
696     if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
697                                 NETSNMP_DS_LIB_DONT_READ_CONFIGS)) {
698         read_config_files(PREMIB_CONFIG);
699     }
700
701     netsnmp_config_process_memories_when(PREMIB_CONFIG, 0);
702
703     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
704                            NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG, 1);
705     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
706                         SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, NULL);
707 }
708 #endif /* BRCM_SNMP_SUPPORT */
709
710 /*******************************************************************-o-******
711  * set_configuration_directory
712  *
713  * Parameters:
714  *      char *dir - value of the directory
715  * Sets the configuration directory. Multiple directories can be
716  * specified, but need to be seperated by 'ENV_SEPARATOR_CHAR'.
717  */
718 void
719 set_configuration_directory(const char *dir)
720 {
721     netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
722                           NETSNMP_DS_LIB_CONFIGURATION_DIR, dir);
723 }
724
725 /*******************************************************************-o-******
726  * get_configuration_directory
727  *
728  * Parameters: -
729  * Retrieve the configuration directory or directories.
730  * (For backwards compatibility that is:
731  *       SNMPCONFPATH, SNMPSHAREPATH, SNMPLIBPATH, HOME/.snmp
732  * First check whether the value is set.
733  * If not set give it the default value.
734  * Return the value.
735  * We always retrieve it new, since we have to do it anyway if it is just set.
736  */
737 const char     *
738 get_configuration_directory()
739 {
740     char            defaultPath[SPRINT_MAX_LEN];
741     char           *homepath;
742
743     if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
744                                       NETSNMP_DS_LIB_CONFIGURATION_DIR)) {
745         homepath = getenv("HOME");
746         sprintf(defaultPath, "%s%c%s%c%s%s%s%s",
747                 SNMPCONFPATH, ENV_SEPARATOR_CHAR,
748                 SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH,
749                 ((homepath == NULL) ? "" : ENV_SEPARATOR),
750                 ((homepath == NULL) ? "" : homepath),
751                 ((homepath == NULL) ? "" : "/.snmp"));
752         set_configuration_directory(defaultPath);
753     }
754     return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
755                                   NETSNMP_DS_LIB_CONFIGURATION_DIR));
756 }
757
758 /*******************************************************************-o-******
759  * set_persistent_directory
760  *
761  * Parameters:
762  *      char *dir - value of the directory
763  * Sets the configuration directory. 
764  * No multiple directories may be specified.
765  * (However, this is not checked)
766  */
767 void
768 set_persistent_directory(const char *dir)
769 {
770     netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
771                           NETSNMP_DS_LIB_PERSISTENT_DIR, dir);
772 }
773
774 /*******************************************************************-o-******
775  * get_persistent_directory
776  *
777  * Parameters: -
778  * Function will retrieve the persisten directory value.
779  * First check whether the value is set.
780  * If not set give it the default value.
781  * Return the value. 
782  * We always retrieve it new, since we have to do it anyway if it is just set.
783  */
784 const char     *
785 get_persistent_directory()
786 {
787     if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
788                                       NETSNMP_DS_LIB_PERSISTENT_DIR)) {
789         set_persistent_directory(PERSISTENT_DIRECTORY);
790     }
791     return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
792                                   NETSNMP_DS_LIB_PERSISTENT_DIR));
793 }
794
795
796 /*******************************************************************-o-******
797  * read_config_files
798  *
799  * Parameters:
800  *      when    == PREMIB_CONFIG, NORMAL_CONFIG  -or-  EITHER_CONFIG
801  *
802  *
803  * Traverse the list of config file types, performing the following actions
804  * for each --
805  *
806  * First, build a search path for config files.  If the contents of 
807  * environment variable SNMPCONFPATH are NULL, then use the following
808  * path list (where the last entry exists only if HOME is non-null):
809  *
810  *      SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp
811  *
812  * Then, In each of these directories, read config files by the name of:
813  *
814  *      <dir>/<fileHeader>.conf         -AND-
815  *      <dir>/<fileHeader>.local.conf
816  *
817  * where <fileHeader> is taken from the config file type structure.
818  *
819  *
820  * PREMIB_CONFIG causes free_config() to be invoked prior to any other action.
821  *
822  *
823  * EXITs if any 'config_errors' are logged while parsing config file lines.
824  */
825 void
826 read_config_files(int when)
827 {
828     int             i, j;
829     char            configfile[300];
830     char           *envconfpath;
831     const char     *confpath, *perspath;
832     char           *cptr1, *cptr2;
833     char            defaultPath[SPRINT_MAX_LEN];
834
835     struct config_files *ctmp = config_files;
836     struct config_line *ltmp;
837     struct stat     statbuf;
838
839     config_errors = 0;
840
841     if (when == PREMIB_CONFIG)
842         free_config();
843
844     confpath = get_configuration_directory();
845     perspath = get_persistent_directory();
846
847     /*
848      * read all config file types 
849      */
850     for (; ctmp != NULL; ctmp = ctmp->next) {
851
852         ltmp = ctmp->start;
853
854         /*
855          * read the config files 
856          */
857         if ((envconfpath = getenv("SNMPCONFPATH")) == NULL) {
858             sprintf(defaultPath, "%s%s%s",
859                     ((confpath == NULL) ? "" : confpath),
860                     ((perspath == NULL) ? "" : ENV_SEPARATOR),
861                     ((perspath == NULL) ? "" : perspath));
862             envconfpath = defaultPath;
863         }
864         envconfpath = strdup(envconfpath);      /* prevent actually writing in env */
865         DEBUGMSGTL(("read_config", "config path used:%s\n", envconfpath));
866         cptr1 = cptr2 = envconfpath;
867         i = 1;
868         while (i && *cptr2 != 0) {
869             while (*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR)
870                 cptr1++;
871             if (*cptr1 == 0)
872                 i = 0;
873             else
874                 *cptr1 = 0;
875             /*
876              * for proper persistent storage retrival, we need to read old backup
877              * copies of the previous storage files.  If the application in
878              * question has died without the proper call to snmp_clean_persistent,
879              * then we read all the configuration files we can, starting with
880              * the oldest first.
881              */
882             if (strncmp(cptr2, perspath,
883                         strlen(perspath)) == 0 ||
884                 (getenv("SNMP_PERSISTENT_FILE") != NULL &&
885                  strncmp(cptr2, getenv("SNMP_PERSISTENT_FILE"),
886                          strlen(getenv("SNMP_PERSISTENT_FILE"))) == 0)) {
887                 /*
888                  * limit this to the known storage directory only 
889                  */
890                 for (j = 0; j <= MAX_PERSISTENT_BACKUPS; j++) {
891                     sprintf(configfile, "%s/%s.%d.conf", cptr2,
892                             ctmp->fileHeader, j);
893                     if (stat(configfile, &statbuf) != 0) {
894                         /*
895                          * file not there, continue 
896                          */
897                         break;
898                     } else {
899                         /*
900                          * backup exists, read it 
901                          */
902                         DEBUGMSGTL(("read_config_files",
903                                     "old config file found: %s, parsing\n",
904                                     configfile));
905                         read_config_snmp(configfile, ltmp, when);
906                     }
907                 }
908             }
909             sprintf(configfile, "%s/%s.conf", cptr2, ctmp->fileHeader);
910             read_config_snmp(configfile, ltmp, when);
911             sprintf(configfile, "%s/%s.local.conf", cptr2,
912                     ctmp->fileHeader);
913             read_config_snmp(configfile, ltmp, when);
914             cptr2 = ++cptr1;
915         }
916         free(envconfpath);
917     }
918
919     if (config_errors) {
920         snmp_log(LOG_ERR, "net-snmp: %d error(s) in config file(s)\n",
921                  config_errors);
922         /*
923          * exit(1); 
924          */
925     }
926 }
927
928 #ifdef BRCM_SNMP_SUPPORT
929 void
930 read_config_print_usage(const char *lead)
931 {
932     struct config_files *ctmp = config_files;
933     struct config_line *ltmp;
934
935     if (lead == NULL)
936         lead = "";
937
938     for (ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) {
939         snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead,
940                  ctmp->fileHeader, ctmp->fileHeader);
941         for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) {
942             DEBUGIF("read_config_usage") {
943                 if (ltmp->config_time == PREMIB_CONFIG)
944                     DEBUGMSG(("read_config_usage", "*"));
945                 else
946                     DEBUGMSG(("read_config_usage", " "));
947             }
948             if (ltmp->help) {
949                 snmp_log(LOG_INFO, "%s%s%-15s %s\n", lead, lead,
950                          ltmp->config_token, ltmp->help);
951             } else {
952                 DEBUGIF("read_config_usage") {
953                     snmp_log(LOG_INFO, "%s%s%-15s [NO HELP]\n", lead, lead,
954                              ltmp->config_token);
955                 }
956             }
957         }
958     }
959 }
960 #else
961 void
962 read_config_print_usage(const char *lead)
963 {
964   return NULL;
965 }
966 #endif /* #ifdef BRCM_SNMP_SUPPORT */
967
968 /*******************************************************************-o-******
969  * read_config_store
970  *
971  * Parameters:
972  *      *type
973  *      *line
974  *      
975  * 
976  * Append line to a file named either ENV(SNMP_PERSISTENT_FILE) or
977  *   "<PERSISTENT_DIRECTORY>/<type>.conf".
978  * Add a trailing newline to the stored file if necessary.
979  *
980  * Intended for use by applications to store permenant configuration 
981  * information generated by sets or persistent counters.
982  *
983  */
984 void
985 read_config_store(const char *type, const char *line)
986 {
987 #ifdef PERSISTENT_DIRECTORY
988     char            file[512], *filep;
989     FILE           *fout;
990 #ifdef PERSISTENT_MASK
991     mode_t          oldmask;
992 #endif
993
994     /*
995      * store configuration directives in the following order of preference:
996      * 1. ENV variable SNMP_PERSISTENT_FILE
997      * 2. configured <PERSISTENT_DIRECTORY>/<type>.conf
998      */
999     if ((filep = getenv("SNMP_PERSISTENT_FILE")) == NULL) {
1000         sprintf(file, "%s/%s.conf", get_persistent_directory(), type);
1001         filep = file;
1002     }
1003 #ifdef PERSISTENT_MASK
1004     oldmask = umask(PERSISTENT_MASK);
1005 #endif
1006     if (mkdirhier(filep, AGENT_DIRECTORY_MODE, 1)) {
1007         snmp_log(LOG_ERR,
1008                  "Failed to create the persistent directory for %s\n",
1009                  file);
1010     }
1011     if ((fout = fopen(filep, "a")) != NULL) {
1012         fprintf(fout, "%s", line);
1013         if (line[strlen(line)] != '\n')
1014             fprintf(fout, "\n");
1015         DEBUGMSGTL(("read_config", "storing: %s\n", line));
1016         fclose(fout);
1017     } else {
1018         DEBUGMSGTL(("read_config", "open failure"));
1019     }
1020 #ifdef PERSISTENT_MASK
1021     umask(oldmask);
1022 #endif
1023
1024 #endif
1025 }                               /* end read_config_store() */
1026
1027 void
1028 read_app_config_store(const char *line)
1029 {
1030     read_config_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1031                                             NETSNMP_DS_LIB_APPTYPE), line);
1032 }
1033
1034 /*******************************************************************-o-******
1035  * snmp_save_persistent
1036  *
1037  * Parameters:
1038  *      *type
1039  *      
1040  *
1041  * Save the file "<PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy
1042  * called "<PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an
1043  * incrementing number on each call, but less than MAX_PERSISTENT_BACKUPS.
1044  *
1045  * Should be called just before all persistent information is supposed to be
1046  * written to move aside the existing persistent cache.
1047  * snmp_clean_persistent should then be called afterward all data has been
1048  * saved to remove these backup files.
1049  *
1050  * Note: on an rename error, the files are removed rather than saved.
1051  *
1052  */
1053 void
1054 snmp_save_persistent(const char *type)
1055 {
1056     char            file[512], fileold[SPRINT_MAX_LEN];
1057     struct stat     statbuf;
1058     int             j;
1059
1060     DEBUGMSGTL(("snmp_save_persistent", "saving %s files...\n", type));
1061     sprintf(file, "%s/%s.conf", get_persistent_directory(), type);
1062     if (stat(file, &statbuf) == 0) {
1063         for (j = 0; j <= MAX_PERSISTENT_BACKUPS; j++) {
1064             sprintf(fileold, "%s/%s.%d.conf", get_persistent_directory(),
1065                     type, j);
1066             if (stat(fileold, &statbuf) != 0) {
1067                 DEBUGMSGTL(("snmp_save_persistent",
1068                             " saving old config file: %s -> %s.\n", file,
1069                             fileold));
1070                 if (rename(file, fileold)) {
1071                     unlink(file);       /* moving it failed, try nuking it, as leaving
1072                                          * it around is very bad. */
1073                 }
1074                 break;
1075             }
1076         }
1077     }
1078     /*
1079      * save a warning header to the top of the new file 
1080      */
1081     sprintf(fileold,
1082             "#\n# net-snmp (or ucd-snmp) persistent data file.\n#\n# DO NOT STORE CONFIGURATION ENTRIES HERE.\n# Please save normal configuration tokens for %s in SNMPCONFPATH/%s.conf.\n# Only \"createUser\" tokens should be placed here by %s administrators.\n#\n",
1083             type, type, type);
1084     read_config_store(type, fileold);
1085 }
1086
1087
1088 /*******************************************************************-o-******
1089  * snmp_clean_persistent
1090  *
1091  * Parameters:
1092  *      *type
1093  *      
1094  *
1095  * Unlink all backup files called "<PERSISTENT_DIRECTORY>/<type>.%d.conf".
1096  *
1097  * Should be called just after we successfull dumped the last of the
1098  * persistent data, to remove the backup copies of previous storage dumps.
1099  *
1100  * XXX  Worth overwriting with random bytes first?  This would
1101  *      ensure that the data is destroyed, even a buffer containing the
1102  *      data persists in memory or swap.  Only important if secrets
1103  *      will be stored here.
1104  */
1105 void
1106 snmp_clean_persistent(const char *type)
1107 {
1108     char            file[512];
1109     struct stat     statbuf;
1110     int             j;
1111
1112     DEBUGMSGTL(("snmp_clean_persistent", "cleaning %s files...\n", type));
1113     sprintf(file, "%s/%s.conf", get_persistent_directory(), type);
1114     if (stat(file, &statbuf) == 0) {
1115         for (j = 0; j <= MAX_PERSISTENT_BACKUPS; j++) {
1116             sprintf(file, "%s/%s.%d.conf", get_persistent_directory(),
1117                     type, j);
1118             if (stat(file, &statbuf) == 0) {
1119                 DEBUGMSGTL(("snmp_clean_persistent",
1120                             " removing old config file: %s\n", file));
1121                 unlink(file);
1122             }
1123         }
1124     }
1125 }
1126
1127
1128
1129
1130 /*
1131  * config_perror: prints a warning string associated with a file and
1132  * line number of a .conf file and increments the error count. 
1133  */
1134 void
1135 config_perror(const char *string)
1136 {
1137     snmp_log(LOG_ERR, "%s: line %d: Error: %s\n", curfilename, linecount,
1138              string);
1139     config_errors++;
1140 }
1141
1142 void
1143 config_pwarn(const char *string)
1144 {
1145     snmp_log(LOG_WARNING, "%s: line %d: Warning: %s\n", curfilename,
1146              linecount, string);
1147 }
1148
1149 /*
1150  * skip all white spaces and return 1 if found something either end of
1151  * line or a comment character 
1152  */
1153 char           *
1154 skip_white(char *ptr)
1155 {
1156     if (ptr == NULL)
1157         return (NULL);
1158     while (*ptr != 0 && isspace(*ptr))
1159         ptr++;
1160     if (*ptr == 0 || *ptr == '#')
1161         return (NULL);
1162     return (ptr);
1163 }
1164
1165 char           *
1166 skip_not_white(char *ptr)
1167 {
1168     if (ptr == NULL)
1169         return (NULL);
1170     while (*ptr != 0 && !isspace(*ptr))
1171         ptr++;
1172     if (*ptr == 0 || *ptr == '#')
1173         return (NULL);
1174     return (ptr);
1175 }
1176
1177 char           *
1178 skip_token(char *ptr)
1179 {
1180     ptr = skip_white(ptr);
1181     ptr = skip_not_white(ptr);
1182     ptr = skip_white(ptr);
1183     return (ptr);
1184 }
1185
1186 /*
1187  * copy_word
1188  * copies the next 'token' from 'from' into 'to', maximum len-1 characters.
1189  * currently a token is anything seperate by white space
1190  * or within quotes (double or single) (i.e. "the red rose" 
1191  * is one token, \"the red rose\" is three tokens)
1192  * a '\' character will allow a quote character to be treated
1193  * as a regular character 
1194  * It returns a pointer to first non-white space after the end of the token
1195  * being copied or to 0 if we reach the end.
1196  * Note: Partially copied words (greater than len) still returns a !NULL ptr
1197  * Note: partially copied words are, however, null terminated.
1198  */
1199
1200 char           *
1201 copy_nword(char *from, char *to, int len)
1202 {
1203     char            quote;
1204     if ((*from == '\"') || (*from == '\'')) {
1205         quote = *(from++);
1206         while ((*from != quote) && (*from != 0)) {
1207             if ((*from == '\\') && (*(from + 1) != 0)) {
1208                 if (len > 0) {  /* don't copy beyond len bytes */
1209                     *to++ = *(from + 1);
1210                     if (--len == 0)
1211                         *(to - 1) = '\0';       /* null protect the last spot */
1212                 }
1213                 from = from + 2;
1214             } else {
1215                 if (len > 0) {  /* don't copy beyond len bytes */
1216                     *to++ = *from++;
1217                     if (--len == 0)
1218                         *(to - 1) = '\0';       /* null protect the last spot */
1219                 } else
1220                     from++;
1221             }
1222         }
1223         if (*from == 0) {
1224             DEBUGMSGTL(("read_config_copy_word",
1225                         "no end quote found in config string\n"));
1226         } else
1227             from++;
1228     } else {
1229         while (*from != 0 && !isspace(*from)) {
1230             if ((*from == '\\') && (*(from + 1) != 0)) {
1231                 if (len > 0) {  /* don't copy beyond len bytes */
1232                     *to++ = *(from + 1);
1233                     if (--len == 0)
1234                         *(to - 1) = '\0';       /* null protect the last spot */
1235                 }
1236                 from = from + 2;
1237             } else {
1238                 if (len > 0) {  /* don't copy beyond len bytes */
1239                     *to++ = *from++;
1240                     if (--len == 0)
1241                         *(to - 1) = '\0';       /* null protect the last spot */
1242                 } else
1243                     from++;
1244             }
1245         }
1246     }
1247     if (len > 0)
1248         *to = 0;
1249     from = skip_white(from);
1250     return (from);
1251 }                               /* copy_word */
1252
1253 /*
1254  * copy_word
1255  * copies the next 'token' from 'from' into 'to'.
1256  * currently a token is anything seperate by white space
1257  * or within quotes (double or single) (i.e. "the red rose" 
1258  * is one token, \"the red rose\" is three tokens)
1259  * a '\' character will allow a quote character to be treated
1260  * as a regular character 
1261  * It returns a pointer to first non-white space after the end of the token
1262  * being copied or to 0 if we reach the end.
1263  */
1264
1265 static int      have_warned = 0;
1266 char           *
1267 copy_word(char *from, char *to)
1268 {
1269     if (!have_warned) {
1270         snmp_log(LOG_INFO,
1271                  "copy_word() called.  Use copy_nword() instead.\n");
1272         have_warned = 1;
1273     }
1274     return copy_nword(from, to, SPRINT_MAX_LEN);
1275 }                               /* copy_word */
1276
1277 /*
1278  * read_config_save_octet_string(): saves an octet string as a length
1279  * followed by a string of hex 
1280  */
1281 char           *
1282 read_config_save_octet_string(char *saveto, u_char * str, size_t len)
1283 {
1284     int             i;
1285     u_char         *cp;
1286
1287     /*
1288      * is everything easily printable 
1289      */
1290     for (i = 0, cp = str; i < (int) len && cp &&
1291          (isalpha(*cp) || isdigit(*cp) || *cp == ' '); cp++, i++);
1292
1293     if (len != 0 && i == (int) len) {
1294         *saveto++ = '"';
1295         memcpy(saveto, str, len);
1296         saveto += len;
1297         *saveto++ = '"';
1298         *saveto = '\0';
1299     } else {
1300         if (str != NULL) {
1301             sprintf(saveto, "0x");
1302             saveto += 2;
1303             for (i = 0; i < (int) len; i++) {
1304                 sprintf(saveto, "%02x", str[i]);
1305                 saveto = saveto + 2;
1306             }
1307         } else {
1308             sprintf(saveto, "\"\"");
1309             saveto += 2;
1310         }
1311     }
1312     return saveto;
1313 }
1314
1315 /*
1316  * read_config_read_octet_string(): reads an octet string that was
1317  * saved by the read_config_save_octet_string() function 
1318  */
1319 char           *
1320 read_config_read_octet_string(char *readfrom, u_char ** str, size_t * len)
1321 {
1322     u_char         *cptr = NULL;
1323     char           *cptr1;
1324     u_int           tmp;
1325     int             i;
1326
1327     if (readfrom == NULL || str == NULL)
1328         return NULL;
1329
1330     if (strncasecmp(readfrom, "0x", 2) == 0) {
1331         /*
1332          * A hex string submitted. How long? 
1333          */
1334         readfrom += 2;
1335         cptr1 = skip_not_white(readfrom);
1336         if (cptr1)
1337             *len = (cptr1 - readfrom);
1338         else
1339             *len = strlen(readfrom);
1340
1341         if (*len % 2) {
1342             DEBUGMSGTL(("read_config_read_octet_string",
1343                         "invalid hex string: wrong length"));
1344             return NULL;
1345         }
1346         *len = *len / 2;
1347
1348         /*
1349          * malloc data space if needed (+1 for good measure) 
1350          */
1351         if (*str == NULL) {
1352             if ((cptr = (u_char *) malloc(*len + 1)) == NULL) {
1353                 return NULL;
1354             }
1355             *str = cptr;
1356         } else {
1357             cptr = *str;
1358         }
1359
1360         /*
1361          * copy validated data 
1362          */
1363         for (i = 0; i < (int) *len; i++) {
1364             if (1 == sscanf(readfrom, "%2x", &tmp))
1365                 *cptr++ = (u_char) tmp;
1366             else {
1367                 /*
1368                  * we may lose memory, but don't know caller's buffer XX free(cptr); 
1369                  */
1370                 return (NULL);
1371             }
1372             readfrom += 2;
1373         }
1374         *cptr++ = '\0';
1375         readfrom = skip_white(readfrom);
1376     } else {
1377         /*
1378          * Normal string 
1379          */
1380
1381         /*
1382          * malloc string space if needed (including NULL terminator) 
1383          */
1384         if (*str == NULL) {
1385             char            buf[SNMP_MAXBUF];
1386             readfrom = copy_nword(readfrom, buf, sizeof(buf));
1387
1388             *len = strlen(buf);
1389             if ((cptr = (u_char *) malloc(*len + 1)) == NULL)
1390                 return NULL;
1391             *str = cptr;
1392             if (cptr) {
1393                 memcpy(cptr, buf, *len + 1);
1394             }
1395         } else {
1396             readfrom = copy_nword(readfrom, (char *) *str, *len);
1397             *len = strlen(*str);
1398         }
1399     }
1400
1401     return readfrom;
1402 }
1403
1404 /*
1405  * read_config_save_objid(): saves an objid as a numerical string 
1406  */
1407 char           *
1408 read_config_save_objid(char *saveto, oid * objid, size_t len)
1409 {
1410     int             i;
1411
1412     if (len == 0) {
1413         strcat(saveto, "NULL");
1414         saveto += strlen(saveto);
1415         return saveto;
1416     }
1417
1418     /*
1419      * in case len=0, this makes it easier to read it back in 
1420      */
1421     for (i = 0; i < (int) len; i++) {
1422         sprintf(saveto, ".%ld", objid[i]);
1423         saveto += strlen(saveto);
1424     }
1425     return saveto;
1426 }
1427
1428 /*
1429  * read_config_read_objid(): reads an objid from a format saved by the above 
1430  */
1431 char           *
1432 read_config_read_objid(char *readfrom, oid ** objid, size_t * len)
1433 {
1434
1435     if (objid == NULL || readfrom == NULL)
1436         return NULL;
1437
1438     if (*objid == NULL) {
1439         *len = 0;
1440         if ((*objid = (oid *) malloc(MAX_OID_LEN * sizeof(oid))) == NULL)
1441             return NULL;
1442         *len = MAX_OID_LEN;
1443     }
1444
1445     if (strncmp(readfrom, "NULL", 4) == 0) {
1446         /*
1447          * null length oid 
1448          */
1449         *len = 0;
1450     } else {
1451         /*
1452          * qualify the string for read_objid 
1453          */
1454         char            buf[SPRINT_MAX_LEN];
1455         copy_nword(readfrom, buf, sizeof(buf));
1456
1457         if (!read_objid(buf, *objid, len)) {
1458             DEBUGMSGTL(("read_config_read_objid", "Invalid OID"));
1459             *len = 0;
1460             return NULL;
1461         }
1462     }
1463
1464     readfrom = skip_token(readfrom);
1465     return readfrom;
1466 }
1467 #ifdef BRCM_SNMP_SUPPORT
1468 /*
1469  * read_config_read_data():
1470  * reads data of a given type from a token(s) on a configuration line.
1471  * 
1472  * Returns: character pointer to the next token in the configuration line.
1473  * NULL if none left.
1474  * NULL if an unknown type.
1475  * 
1476  * dataptr is expected to match a pointer type being read
1477  * (int *, u_int *, char **, oid **)
1478  */
1479 char           *
1480 read_config_read_data(int type, char *readfrom, void *dataptr,
1481                       size_t * len)
1482 {
1483     int            *intp;
1484     char          **charpp;
1485     oid           **oidpp;
1486     unsigned int   *uintp;
1487
1488     if (dataptr && readfrom)
1489         switch (type) {
1490         case ASN_INTEGER:
1491             intp = (int *) dataptr;
1492             *intp = atoi(readfrom);
1493             readfrom = skip_token(readfrom);
1494             return readfrom;
1495
1496         case ASN_UNSIGNED:
1497             uintp = (unsigned int *) dataptr;
1498             *uintp = strtoul(readfrom, NULL, 0);
1499             readfrom = skip_token(readfrom);
1500             return readfrom;
1501
1502         case ASN_OCTET_STR:
1503         case ASN_BIT_STR:
1504             charpp = (char **) dataptr;
1505             return read_config_read_octet_string(readfrom,
1506                                                  (u_char **) charpp, len);
1507
1508         case ASN_OBJECT_ID:
1509 #ifdef BRCM_SNMP_SUPPORT
1510             oidpp = (oid **) dataptr;
1511             return read_config_read_objid(readfrom, oidpp, len);
1512 #endif
1513         default:
1514             DEBUGMSGTL(("read_config_read_data", "Fail: Unknown type: %d",
1515                         type));
1516             return NULL;
1517         }
1518     return NULL;
1519 }
1520
1521 /*
1522  * read_config_read_memory():
1523  * 
1524  * similar to read_config_read_data, but expects a generic memory
1525  * pointer rather than a specific type of pointer.  Len is expected to
1526  * be the amount of available memory.
1527  */
1528 char           *
1529 read_config_read_memory(int type, char *readfrom,
1530                         char *dataptr, size_t * len)
1531 {
1532     int            *intp;
1533     unsigned int   *uintp;
1534
1535     if (!dataptr || !readfrom)
1536         return NULL;
1537
1538     switch (type) {
1539     case ASN_INTEGER:
1540         if (*len < sizeof(int))
1541             return NULL;
1542         intp = (int *) dataptr;
1543         *intp = atoi(readfrom);
1544         *len = sizeof(int);
1545         readfrom = skip_token(readfrom);
1546         return readfrom;
1547
1548     case ASN_UNSIGNED:
1549         if (*len < sizeof(unsigned int))
1550             return NULL;
1551         uintp = (unsigned int *) dataptr;
1552         *uintp = strtoul(readfrom, NULL, 0);
1553         *len = sizeof(unsigned int);
1554         readfrom = skip_token(readfrom);
1555         return readfrom;
1556
1557     case ASN_OCTET_STR:
1558     case ASN_BIT_STR:
1559     case ASN_PRIV_IMPLIED_OCTET_STR:
1560         return read_config_read_octet_string(readfrom,
1561                                              (u_char **) & dataptr, len);
1562
1563     case ASN_PRIV_IMPLIED_OBJECT_ID:
1564     case ASN_OBJECT_ID:
1565         readfrom =
1566             read_config_read_objid(readfrom, (oid **) & dataptr, len);
1567         *len *= sizeof(oid);
1568         return readfrom;
1569
1570     default:
1571         DEBUGMSGTL(("read_config_read_memory", "Fail: Unknown type: %d",
1572                     type));
1573         return NULL;
1574     }
1575     return NULL;
1576 }
1577
1578 /*
1579  * read_config_store_data():
1580  * stores data of a given type to a configuration line.
1581  * 
1582  * Returns: character pointer to the next token in the configuration line.
1583  * NULL if none left.
1584  * NULL if an unknown type.
1585  */
1586 char           *
1587 read_config_store_data(int type, char *storeto, void *dataptr,
1588                        size_t * len)
1589 {
1590     int            *intp;
1591     u_char        **charpp;
1592     unsigned int   *uintp;
1593     oid           **oidpp;
1594
1595     if (dataptr && storeto)
1596         switch (type) {
1597         case ASN_INTEGER:
1598             intp = (int *) dataptr;
1599             sprintf(storeto, " %d", *intp);
1600             return (storeto + strlen(storeto));
1601
1602         case ASN_UNSIGNED:
1603             uintp = (unsigned int *) dataptr;
1604             sprintf(storeto, " %u", *uintp);
1605             return (storeto + strlen(storeto));
1606
1607         case ASN_OCTET_STR:
1608         case ASN_BIT_STR:
1609             *storeto++ = ' ';
1610             charpp = (u_char **) dataptr;
1611             return read_config_save_octet_string(storeto, *charpp, *len);
1612
1613         case ASN_OBJECT_ID:
1614             *storeto++ = ' ';
1615             oidpp = (oid **) dataptr;
1616             return read_config_save_objid(storeto, *oidpp, *len);
1617
1618         default:
1619             DEBUGMSGTL(("read_config_store_data", "Fail: Unknown type: %d",
1620                         type));
1621             return NULL;
1622         }
1623     return NULL;
1624 }
1625
1626 #endif /* BRCM_SNMP_SUPPORT */
1627
1628 #else
1629 #ifdef ILMI_TEST
1630 struct config_files *config_files = NULL;
1631
1632 /* remove later, only for testing purpose */
1633 char           *
1634 copy_nword(char *from, char *to, int len)
1635 {
1636   return NULL;
1637 }
1638
1639 void
1640 config_perror(const char *string)
1641 {
1642   return;
1643 }
1644
1645 void
1646 free_config(void)
1647 {
1648   return;
1649 }
1650 void
1651 read_configs(void)
1652 {
1653   return;
1654 }
1655 struct config_line *
1656 register_app_config_handler(const char *token,
1657                             void (*parser) (const char *, char *),
1658                             void (*releaser) (void), const char *help)
1659 {
1660     return (register_config_handler(NULL, token, parser, releaser, help));
1661 }
1662
1663 void
1664 unregister_config_handler(const char *type_param, const char *token)
1665 {
1666     struct config_files **ctmp = &config_files;
1667     struct config_line **ltmp, *ltmp2;
1668     const char     *type = type_param;
1669
1670     if (type == NULL) {
1671         type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1672                                      NETSNMP_DS_LIB_APPTYPE);
1673     }
1674
1675     /*
1676      * find type in current list 
1677      */
1678     while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
1679         ctmp = &((*ctmp)->next);
1680     }
1681
1682     if (*ctmp == NULL) {
1683         /*
1684          * Not found, return. 
1685          */
1686         return;
1687     }
1688
1689     ltmp = &((*ctmp)->start);
1690     if (*ltmp == NULL) {
1691         /*
1692          * Not found, return. 
1693          */
1694         return;
1695     }
1696     if (strcmp((*ltmp)->config_token, token) == 0) {
1697         /*
1698          * found it at the top of the list 
1699          */
1700         ltmp2 = (*ltmp)->next;
1701         free((*ltmp)->config_token);
1702         SNMP_FREE((*ltmp)->help);
1703         free(*ltmp);
1704         (*ctmp)->start = ltmp2;
1705         return;
1706     }
1707     while ((*ltmp)->next != NULL
1708            && strcmp((*ltmp)->next->config_token, token)) {
1709         ltmp = &((*ltmp)->next);
1710     }
1711     if ((*ltmp)->next != NULL) {
1712         free((*ltmp)->next->config_token);
1713         SNMP_FREE((*ltmp)->next->help);
1714         ltmp2 = (*ltmp)->next->next;
1715         free((*ltmp)->next);
1716         (*ltmp)->next = ltmp2;
1717     }
1718 }
1719
1720 void
1721 unregister_app_config_handler(const char *token)
1722 {
1723     unregister_config_handler(NULL, token);
1724 }
1725
1726 void
1727 unregister_all_config_handlers()
1728 {
1729     struct config_files *ctmp, *save;
1730     struct config_line *ltmp;
1731
1732     free_config();
1733
1734     /*
1735      * Keep using config_files until there are no more! 
1736      */
1737     for (ctmp = config_files; ctmp;) {
1738         for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) {
1739             unregister_config_handler(ctmp->fileHeader,
1740                                       ltmp->config_token);
1741         }
1742         free(ctmp->fileHeader);
1743         save = ctmp->next;
1744         free(ctmp);
1745         ctmp = save;
1746         config_files = save;
1747     }
1748 }
1749
1750 void
1751 read_app_config_store(const char *line)
1752 {
1753   return;
1754 }
1755
1756 struct config_line *
1757 register_config_handler(const char *type_param,
1758                         const char *token,
1759                         void (*parser) (const char *, char *),
1760                         void (*releaser) (void), const char *help)
1761 {
1762     struct config_files **ctmp = &config_files;
1763     struct config_line **ltmp;
1764     const char     *type = type_param;
1765
1766     if (type == NULL) {
1767         type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1768                                      NETSNMP_DS_LIB_APPTYPE);
1769     }
1770
1771     /*
1772      * Find type in current list  -OR-  create a new file type.
1773      */
1774     while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
1775         ctmp = &((*ctmp)->next);
1776     }
1777
1778     if (*ctmp == NULL) {
1779         *ctmp = (struct config_files *)
1780             calloc(1, sizeof(struct config_files));
1781         if (!*ctmp) {
1782             return NULL;
1783         }
1784
1785         (*ctmp)->fileHeader = strdup(type);
1786     }
1787
1788     /*
1789      * Find parser type in current list  -OR-  create a new
1790      * line parser entry.
1791      */
1792     ltmp = &((*ctmp)->start);
1793
1794     while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) {
1795         ltmp = &((*ltmp)->next);
1796     }
1797
1798     if (*ltmp == NULL) {
1799         *ltmp = (struct config_line *)
1800             calloc(1, sizeof(struct config_line));
1801         if (!*ltmp) {
1802             return NULL;
1803         }
1804
1805         (*ltmp)->config_time = NORMAL_CONFIG;
1806         (*ltmp)->config_token = strdup(token);
1807         if (help != NULL)
1808             (*ltmp)->help = strdup(help);
1809     }
1810
1811     /*
1812      * Add/Replace the parse/free functions for the given line type
1813      * in the given file type.
1814      */
1815     (*ltmp)->parse_line = parser;
1816     (*ltmp)->free_func = releaser;
1817
1818     return (*ltmp);
1819
1820 }                               /* end register_config_handler() */
1821 #endif /* ILMI_TEST */
1822 #endif /* BUILD_ILMI */