5 #include <net-snmp/net-snmp-config.h>
20 #include <sys/types.h>
22 #include <sys/param.h>
24 #if TIME_WITH_SYS_TIME
26 # include <sys/timeb.h>
28 # include <sys/time.h>
33 # include <sys/time.h>
38 #ifdef HAVE_SYS_STAT_H
42 #include <netinet/in.h>
45 #include <arpa/inet.h>
48 #include <sys/select.h>
54 #include <sys/socket.h>
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>
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>
77 static int config_errors;
79 struct config_files *config_files = NULL;
81 #ifdef BRCM_SNMP_SUPPORT
83 register_prenetsnmp_mib_handler(const char *type,
85 void (*parser) (const char *, char *),
86 void (*releaser) (void), const char *help)
88 struct config_line *ltmp;
89 ltmp = register_config_handler(type, token, parser, releaser, help);
91 ltmp->config_time = PREMIB_CONFIG;
96 register_app_prenetsnmp_mib_handler(const char *token,
97 void (*parser) (const char *, char *),
98 void (*releaser) (void),
101 return (register_prenetsnmp_mib_handler
102 (NULL, token, parser, releaser, help));
104 #endif /* #ifdef BRCM_SNMP_SUPPORT */
106 /*******************************************************************-o-******
107 * register_config_handler
116 * Pointer to a new config line entry -OR- NULL on error.
119 register_config_handler(const char *type_param,
121 void (*parser) (const char *, char *),
122 void (*releaser) (void), const char *help)
124 struct config_files **ctmp = &config_files;
125 struct config_line **ltmp;
126 const char *type = type_param;
129 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
130 NETSNMP_DS_LIB_APPTYPE);
134 * Find type in current list -OR- create a new file type.
136 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
137 ctmp = &((*ctmp)->next);
141 *ctmp = (struct config_files *)
142 calloc(1, sizeof(struct config_files));
147 (*ctmp)->fileHeader = strdup(type);
151 * Find parser type in current list -OR- create a new
154 ltmp = &((*ctmp)->start);
156 while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) {
157 ltmp = &((*ltmp)->next);
161 *ltmp = (struct config_line *)
162 calloc(1, sizeof(struct config_line));
167 (*ltmp)->config_time = NORMAL_CONFIG;
168 (*ltmp)->config_token = strdup(token);
170 (*ltmp)->help = strdup(help);
174 * Add/Replace the parse/free functions for the given line type
175 * in the given file type.
177 (*ltmp)->parse_line = parser;
178 (*ltmp)->free_func = releaser;
182 } /* end register_config_handler() */
185 register_app_config_handler(const char *token,
186 void (*parser) (const char *, char *),
187 void (*releaser) (void), const char *help)
189 return (register_config_handler(NULL, token, parser, releaser, help));
193 unregister_config_handler(const char *type_param, const char *token)
195 struct config_files **ctmp = &config_files;
196 struct config_line **ltmp, *ltmp2;
197 const char *type = type_param;
200 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
201 NETSNMP_DS_LIB_APPTYPE);
205 * find type in current list
207 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
208 ctmp = &((*ctmp)->next);
218 ltmp = &((*ctmp)->start);
225 if (strcmp((*ltmp)->config_token, token) == 0) {
227 * found it at the top of the list
229 ltmp2 = (*ltmp)->next;
230 free((*ltmp)->config_token);
231 SNMP_FREE((*ltmp)->help);
233 (*ctmp)->start = ltmp2;
236 while ((*ltmp)->next != NULL
237 && strcmp((*ltmp)->next->config_token, token)) {
238 ltmp = &((*ltmp)->next);
240 if ((*ltmp)->next != NULL) {
241 free((*ltmp)->next->config_token);
242 SNMP_FREE((*ltmp)->next->help);
243 ltmp2 = (*ltmp)->next->next;
245 (*ltmp)->next = ltmp2;
250 unregister_app_config_handler(const char *token)
252 unregister_config_handler(NULL, token);
256 unregister_all_config_handlers()
258 struct config_files *ctmp, *save;
259 struct config_line *ltmp;
264 * Keep using config_files until there are no more!
266 for (ctmp = config_files; ctmp;) {
267 for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) {
268 unregister_config_handler(ctmp->fileHeader,
271 free(ctmp->fileHeader);
281 print_config_handlers(void)
283 struct config_files *ctmp = config_files;
284 struct config_line *ltmp;
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));
296 const char *curfilename;
299 read_config_get_handlers(const char *type)
301 struct config_files *ctmp = config_files;
302 for (; ctmp != NULL && strcmp(ctmp->fileHeader, type);
310 read_config_with_type(const char *filename, const char *type)
312 struct config_line *ctmp = read_config_get_handlers(type);
314 read_config_snmp(filename, ctmp, EITHER_CONFIG);
316 DEBUGMSGTL(("read_config",
317 "read_config: I have no registrations for type:%s,file:%s\n",
323 read_config_find_handler(struct config_line *line_handlers,
326 struct config_line *lptr;
328 for (lptr = line_handlers; lptr != NULL; lptr = lptr->next) {
329 if (!strcasecmp(token, lptr->config_token)) {
337 * searches a config_line linked list for a match
340 run_config_handler(struct config_line *lptr,
341 const char *token, char *cptr, int when)
343 char tmpbuf[STRINGMAX];
344 lptr = read_config_find_handler(lptr, token);
346 if (when == EITHER_CONFIG || lptr->config_time == when) {
347 DEBUGMSGTL(("read_config",
348 "Found a parser. Calling it: %s / %s\n", token,
350 (*(lptr->parse_line)) (token, cptr);
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;
359 return SNMPERR_SUCCESS;
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.
370 * we allow = delimeters here
372 #define SNMP_CONFIG_DELIMETERS " \t="
375 snmp_config_when(char *line, int when)
377 char *cptr, buf[STRINGMAX], tmpbuf[STRINGMAX];
378 struct config_line *lptr = NULL;
379 struct config_files *ctmp = config_files;
382 config_perror("snmp_config() called with a null string.");
383 return SNMPERR_GENERR;
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;
394 lptr = read_config_get_handlers(cptr + 1);
396 sprintf(tmpbuf, "No handlers regestered for type %s.",
398 config_perror(tmpbuf);
399 return SNMPERR_GENERR;
401 cptr = strtok(NULL, SNMP_CONFIG_DELIMETERS);
402 lptr = read_config_find_handler(lptr, cptr);
405 * we have to find a token
407 for (; ctmp != NULL && lptr == NULL; ctmp = ctmp->next)
408 lptr = read_config_find_handler(ctmp->start, cptr);
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;
418 * use the original string instead since strtok messed up the original
420 line = skip_white(line + (cptr - buf) + strlen(cptr) + 1);
422 return (run_config_handler(lptr, cptr, line, when));
425 netsnmp_config(char *line)
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()
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);
441 netsnmp_config_remember_in_list(char *line,
442 struct read_config_memory **mem)
448 mem = &((*mem)->next);
450 *mem = SNMP_MALLOC_STRUCT(read_config_memory);
452 (*mem)->line = strdup(line);
456 netsnmp_config_remember_free_list(struct read_config_memory **mem)
458 struct read_config_memory *tmpmem;
460 SNMP_FREE((*mem)->line);
461 tmpmem = (*mem)->next;
469 netsnmp_config_process_memory_list(struct read_config_memory **memp,
473 struct read_config_memory *mem;
481 DEBUGMSGTL(("read_config", "processing memory: %s\n", mem->line));
482 snmp_config_when(mem->line, when);
487 netsnmp_config_remember_free_list(memp);
491 * default storage location implementation
493 static struct read_config_memory *memorylist = NULL;
496 netsnmp_config_remember(char *line)
498 netsnmp_config_remember_in_list(line, &memorylist);
502 netsnmp_config_process_memories(void)
504 netsnmp_config_process_memory_list(&memorylist, EITHER_CONFIG, 1);
508 netsnmp_config_process_memories_when(int when, int clear)
510 netsnmp_config_process_memory_list(&memorylist, when, clear);
513 /*******************************************************************-o-******
521 * Read <filename> and process each line in accordance with the list of
522 * <line_handler> functions.
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
529 * For each match, check that <when> is the designated time for the
530 * <line_handler> function to be executed before processing the line.
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.
540 read_config_snmp(const char *filename,
541 struct config_line *line_handler, int when)
545 char line[STRINGMAX], token[STRINGMAX], tmpbuf[STRINGMAX];
548 struct config_line *lptr;
551 curfilename = filename;
553 if ((ifile = fopen(filename, "r")) == NULL) {
555 if (errno == ENOENT) {
556 DEBUGMSGTL(("read_config", "%s: %s\n", filename,
561 if (errno == EACCES) {
562 DEBUGMSGTL(("read_config", "%s: %s\n", filename,
566 #if defined(ENOENT) || defined(EACCES)
568 snmp_log_perror(filename);
570 #else /* defined(ENOENT) || defined(EACCES) */
571 snmp_log_perror(filename);
575 DEBUGMSGTL(("read_config", "Reading configuration %s\n",
579 while (fgets(line, sizeof(line), ifile) != NULL) {
583 i = strlen(line) - 1;
587 * check blank line or # comment
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]);
595 sprintf(tmpbuf, "No handlers regestered for type %s.",
597 config_perror(tmpbuf);
600 DEBUGMSGTL(("read_config",
601 "Switching to new context: %s%s\n",
602 ((cptr) ? "(this line only) " : ""),
606 * change context permanently
612 * the rest of this line only applies.
614 cptr = copy_nword(cptr, token, sizeof(token));
620 sprintf(tmpbuf, "Blank line following %s token.", token);
621 config_perror(tmpbuf);
623 DEBUGMSGTL(("read_config", "%s:%d examining: %s\n",
624 filename, linecount, line));
625 run_config_handler(lptr, token, cptr, when);
632 } /* end read_config() */
639 struct config_files *ctmp = config_files;
640 struct config_line *ltmp;
642 for (; ctmp != NULL; ctmp = ctmp->next)
643 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next)
645 (*(ltmp->free_func)) ();
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);
657 DEBUGMSGTL(("read_config", "reading normal configuration tokens\n"));
659 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
660 NETSNMP_DS_LIB_DONT_READ_CONFIGS)) {
661 read_config_files(NORMAL_CONFIG);
665 * do this even when the normal above wasn't done
667 if (optional_config && type) {
669 if (stat(optional_config, &statbuf)) {
670 DEBUGMSGTL(("read_config",
671 "Optional File \"%s\" does not exist.\n",
673 snmp_log_perror(optional_config);
675 DEBUGMSGTL(("read_config",
676 "Reading optional config file: \"%s\"\n",
678 read_config_with_type(optional_config, type);
682 netsnmp_config_process_memories_when(NORMAL_CONFIG, 1);
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);
690 #ifdef BRCM_SNMP_SUPPORT
692 read_premib_configs(void)
694 DEBUGMSGTL(("read_config", "reading premib configuration tokens\n"));
696 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
697 NETSNMP_DS_LIB_DONT_READ_CONFIGS)) {
698 read_config_files(PREMIB_CONFIG);
701 netsnmp_config_process_memories_when(PREMIB_CONFIG, 0);
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);
708 #endif /* BRCM_SNMP_SUPPORT */
710 /*******************************************************************-o-******
711 * set_configuration_directory
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'.
719 set_configuration_directory(const char *dir)
721 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
722 NETSNMP_DS_LIB_CONFIGURATION_DIR, dir);
725 /*******************************************************************-o-******
726 * get_configuration_directory
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.
735 * We always retrieve it new, since we have to do it anyway if it is just set.
738 get_configuration_directory()
740 char defaultPath[SPRINT_MAX_LEN];
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);
754 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
755 NETSNMP_DS_LIB_CONFIGURATION_DIR));
758 /*******************************************************************-o-******
759 * set_persistent_directory
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)
768 set_persistent_directory(const char *dir)
770 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
771 NETSNMP_DS_LIB_PERSISTENT_DIR, dir);
774 /*******************************************************************-o-******
775 * get_persistent_directory
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.
782 * We always retrieve it new, since we have to do it anyway if it is just set.
785 get_persistent_directory()
787 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
788 NETSNMP_DS_LIB_PERSISTENT_DIR)) {
789 set_persistent_directory(PERSISTENT_DIRECTORY);
791 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
792 NETSNMP_DS_LIB_PERSISTENT_DIR));
796 /*******************************************************************-o-******
800 * when == PREMIB_CONFIG, NORMAL_CONFIG -or- EITHER_CONFIG
803 * Traverse the list of config file types, performing the following actions
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):
810 * SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp
812 * Then, In each of these directories, read config files by the name of:
814 * <dir>/<fileHeader>.conf -AND-
815 * <dir>/<fileHeader>.local.conf
817 * where <fileHeader> is taken from the config file type structure.
820 * PREMIB_CONFIG causes free_config() to be invoked prior to any other action.
823 * EXITs if any 'config_errors' are logged while parsing config file lines.
826 read_config_files(int when)
829 char configfile[300];
831 const char *confpath, *perspath;
833 char defaultPath[SPRINT_MAX_LEN];
835 struct config_files *ctmp = config_files;
836 struct config_line *ltmp;
841 if (when == PREMIB_CONFIG)
844 confpath = get_configuration_directory();
845 perspath = get_persistent_directory();
848 * read all config file types
850 for (; ctmp != NULL; ctmp = ctmp->next) {
855 * read the config files
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;
864 envconfpath = strdup(envconfpath); /* prevent actually writing in env */
865 DEBUGMSGTL(("read_config", "config path used:%s\n", envconfpath));
866 cptr1 = cptr2 = envconfpath;
868 while (i && *cptr2 != 0) {
869 while (*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR)
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
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)) {
888 * limit this to the known storage directory only
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) {
895 * file not there, continue
900 * backup exists, read it
902 DEBUGMSGTL(("read_config_files",
903 "old config file found: %s, parsing\n",
905 read_config_snmp(configfile, ltmp, when);
909 sprintf(configfile, "%s/%s.conf", cptr2, ctmp->fileHeader);
910 read_config_snmp(configfile, ltmp, when);
911 sprintf(configfile, "%s/%s.local.conf", cptr2,
913 read_config_snmp(configfile, ltmp, when);
920 snmp_log(LOG_ERR, "net-snmp: %d error(s) in config file(s)\n",
928 #ifdef BRCM_SNMP_SUPPORT
930 read_config_print_usage(const char *lead)
932 struct config_files *ctmp = config_files;
933 struct config_line *ltmp;
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", "*"));
946 DEBUGMSG(("read_config_usage", " "));
949 snmp_log(LOG_INFO, "%s%s%-15s %s\n", lead, lead,
950 ltmp->config_token, ltmp->help);
952 DEBUGIF("read_config_usage") {
953 snmp_log(LOG_INFO, "%s%s%-15s [NO HELP]\n", lead, lead,
962 read_config_print_usage(const char *lead)
966 #endif /* #ifdef BRCM_SNMP_SUPPORT */
968 /*******************************************************************-o-******
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.
980 * Intended for use by applications to store permenant configuration
981 * information generated by sets or persistent counters.
985 read_config_store(const char *type, const char *line)
987 #ifdef PERSISTENT_DIRECTORY
988 char file[512], *filep;
990 #ifdef PERSISTENT_MASK
995 * store configuration directives in the following order of preference:
996 * 1. ENV variable SNMP_PERSISTENT_FILE
997 * 2. configured <PERSISTENT_DIRECTORY>/<type>.conf
999 if ((filep = getenv("SNMP_PERSISTENT_FILE")) == NULL) {
1000 sprintf(file, "%s/%s.conf", get_persistent_directory(), type);
1003 #ifdef PERSISTENT_MASK
1004 oldmask = umask(PERSISTENT_MASK);
1006 if (mkdirhier(filep, AGENT_DIRECTORY_MODE, 1)) {
1008 "Failed to create the persistent directory for %s\n",
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));
1018 DEBUGMSGTL(("read_config", "open failure"));
1020 #ifdef PERSISTENT_MASK
1025 } /* end read_config_store() */
1028 read_app_config_store(const char *line)
1030 read_config_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1031 NETSNMP_DS_LIB_APPTYPE), line);
1034 /*******************************************************************-o-******
1035 * snmp_save_persistent
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.
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.
1050 * Note: on an rename error, the files are removed rather than saved.
1054 snmp_save_persistent(const char *type)
1056 char file[512], fileold[SPRINT_MAX_LEN];
1057 struct stat statbuf;
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(),
1066 if (stat(fileold, &statbuf) != 0) {
1067 DEBUGMSGTL(("snmp_save_persistent",
1068 " saving old config file: %s -> %s.\n", file,
1070 if (rename(file, fileold)) {
1071 unlink(file); /* moving it failed, try nuking it, as leaving
1072 * it around is very bad. */
1079 * save a warning header to the top of the new file
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",
1084 read_config_store(type, fileold);
1088 /*******************************************************************-o-******
1089 * snmp_clean_persistent
1095 * Unlink all backup files called "<PERSISTENT_DIRECTORY>/<type>.%d.conf".
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.
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.
1106 snmp_clean_persistent(const char *type)
1109 struct stat statbuf;
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(),
1118 if (stat(file, &statbuf) == 0) {
1119 DEBUGMSGTL(("snmp_clean_persistent",
1120 " removing old config file: %s\n", file));
1131 * config_perror: prints a warning string associated with a file and
1132 * line number of a .conf file and increments the error count.
1135 config_perror(const char *string)
1137 snmp_log(LOG_ERR, "%s: line %d: Error: %s\n", curfilename, linecount,
1143 config_pwarn(const char *string)
1145 snmp_log(LOG_WARNING, "%s: line %d: Warning: %s\n", curfilename,
1150 * skip all white spaces and return 1 if found something either end of
1151 * line or a comment character
1154 skip_white(char *ptr)
1158 while (*ptr != 0 && isspace(*ptr))
1160 if (*ptr == 0 || *ptr == '#')
1166 skip_not_white(char *ptr)
1170 while (*ptr != 0 && !isspace(*ptr))
1172 if (*ptr == 0 || *ptr == '#')
1178 skip_token(char *ptr)
1180 ptr = skip_white(ptr);
1181 ptr = skip_not_white(ptr);
1182 ptr = skip_white(ptr);
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.
1201 copy_nword(char *from, char *to, int len)
1204 if ((*from == '\"') || (*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);
1211 *(to - 1) = '\0'; /* null protect the last spot */
1215 if (len > 0) { /* don't copy beyond len bytes */
1218 *(to - 1) = '\0'; /* null protect the last spot */
1224 DEBUGMSGTL(("read_config_copy_word",
1225 "no end quote found in config string\n"));
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);
1234 *(to - 1) = '\0'; /* null protect the last spot */
1238 if (len > 0) { /* don't copy beyond len bytes */
1241 *(to - 1) = '\0'; /* null protect the last spot */
1249 from = skip_white(from);
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.
1265 static int have_warned = 0;
1267 copy_word(char *from, char *to)
1271 "copy_word() called. Use copy_nword() instead.\n");
1274 return copy_nword(from, to, SPRINT_MAX_LEN);
1278 * read_config_save_octet_string(): saves an octet string as a length
1279 * followed by a string of hex
1282 read_config_save_octet_string(char *saveto, u_char * str, size_t len)
1288 * is everything easily printable
1290 for (i = 0, cp = str; i < (int) len && cp &&
1291 (isalpha(*cp) || isdigit(*cp) || *cp == ' '); cp++, i++);
1293 if (len != 0 && i == (int) len) {
1295 memcpy(saveto, str, len);
1301 sprintf(saveto, "0x");
1303 for (i = 0; i < (int) len; i++) {
1304 sprintf(saveto, "%02x", str[i]);
1305 saveto = saveto + 2;
1308 sprintf(saveto, "\"\"");
1316 * read_config_read_octet_string(): reads an octet string that was
1317 * saved by the read_config_save_octet_string() function
1320 read_config_read_octet_string(char *readfrom, u_char ** str, size_t * len)
1322 u_char *cptr = NULL;
1327 if (readfrom == NULL || str == NULL)
1330 if (strncasecmp(readfrom, "0x", 2) == 0) {
1332 * A hex string submitted. How long?
1335 cptr1 = skip_not_white(readfrom);
1337 *len = (cptr1 - readfrom);
1339 *len = strlen(readfrom);
1342 DEBUGMSGTL(("read_config_read_octet_string",
1343 "invalid hex string: wrong length"));
1349 * malloc data space if needed (+1 for good measure)
1352 if ((cptr = (u_char *) malloc(*len + 1)) == NULL) {
1361 * copy validated data
1363 for (i = 0; i < (int) *len; i++) {
1364 if (1 == sscanf(readfrom, "%2x", &tmp))
1365 *cptr++ = (u_char) tmp;
1368 * we may lose memory, but don't know caller's buffer XX free(cptr);
1375 readfrom = skip_white(readfrom);
1382 * malloc string space if needed (including NULL terminator)
1385 char buf[SNMP_MAXBUF];
1386 readfrom = copy_nword(readfrom, buf, sizeof(buf));
1389 if ((cptr = (u_char *) malloc(*len + 1)) == NULL)
1393 memcpy(cptr, buf, *len + 1);
1396 readfrom = copy_nword(readfrom, (char *) *str, *len);
1397 *len = strlen(*str);
1405 * read_config_save_objid(): saves an objid as a numerical string
1408 read_config_save_objid(char *saveto, oid * objid, size_t len)
1413 strcat(saveto, "NULL");
1414 saveto += strlen(saveto);
1419 * in case len=0, this makes it easier to read it back in
1421 for (i = 0; i < (int) len; i++) {
1422 sprintf(saveto, ".%ld", objid[i]);
1423 saveto += strlen(saveto);
1429 * read_config_read_objid(): reads an objid from a format saved by the above
1432 read_config_read_objid(char *readfrom, oid ** objid, size_t * len)
1435 if (objid == NULL || readfrom == NULL)
1438 if (*objid == NULL) {
1440 if ((*objid = (oid *) malloc(MAX_OID_LEN * sizeof(oid))) == NULL)
1445 if (strncmp(readfrom, "NULL", 4) == 0) {
1452 * qualify the string for read_objid
1454 char buf[SPRINT_MAX_LEN];
1455 copy_nword(readfrom, buf, sizeof(buf));
1457 if (!read_objid(buf, *objid, len)) {
1458 DEBUGMSGTL(("read_config_read_objid", "Invalid OID"));
1464 readfrom = skip_token(readfrom);
1467 #ifdef BRCM_SNMP_SUPPORT
1469 * read_config_read_data():
1470 * reads data of a given type from a token(s) on a configuration line.
1472 * Returns: character pointer to the next token in the configuration line.
1473 * NULL if none left.
1474 * NULL if an unknown type.
1476 * dataptr is expected to match a pointer type being read
1477 * (int *, u_int *, char **, oid **)
1480 read_config_read_data(int type, char *readfrom, void *dataptr,
1486 unsigned int *uintp;
1488 if (dataptr && readfrom)
1491 intp = (int *) dataptr;
1492 *intp = atoi(readfrom);
1493 readfrom = skip_token(readfrom);
1497 uintp = (unsigned int *) dataptr;
1498 *uintp = strtoul(readfrom, NULL, 0);
1499 readfrom = skip_token(readfrom);
1504 charpp = (char **) dataptr;
1505 return read_config_read_octet_string(readfrom,
1506 (u_char **) charpp, len);
1509 #ifdef BRCM_SNMP_SUPPORT
1510 oidpp = (oid **) dataptr;
1511 return read_config_read_objid(readfrom, oidpp, len);
1514 DEBUGMSGTL(("read_config_read_data", "Fail: Unknown type: %d",
1522 * read_config_read_memory():
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.
1529 read_config_read_memory(int type, char *readfrom,
1530 char *dataptr, size_t * len)
1533 unsigned int *uintp;
1535 if (!dataptr || !readfrom)
1540 if (*len < sizeof(int))
1542 intp = (int *) dataptr;
1543 *intp = atoi(readfrom);
1545 readfrom = skip_token(readfrom);
1549 if (*len < sizeof(unsigned int))
1551 uintp = (unsigned int *) dataptr;
1552 *uintp = strtoul(readfrom, NULL, 0);
1553 *len = sizeof(unsigned int);
1554 readfrom = skip_token(readfrom);
1559 case ASN_PRIV_IMPLIED_OCTET_STR:
1560 return read_config_read_octet_string(readfrom,
1561 (u_char **) & dataptr, len);
1563 case ASN_PRIV_IMPLIED_OBJECT_ID:
1566 read_config_read_objid(readfrom, (oid **) & dataptr, len);
1567 *len *= sizeof(oid);
1571 DEBUGMSGTL(("read_config_read_memory", "Fail: Unknown type: %d",
1579 * read_config_store_data():
1580 * stores data of a given type to a configuration line.
1582 * Returns: character pointer to the next token in the configuration line.
1583 * NULL if none left.
1584 * NULL if an unknown type.
1587 read_config_store_data(int type, char *storeto, void *dataptr,
1592 unsigned int *uintp;
1595 if (dataptr && storeto)
1598 intp = (int *) dataptr;
1599 sprintf(storeto, " %d", *intp);
1600 return (storeto + strlen(storeto));
1603 uintp = (unsigned int *) dataptr;
1604 sprintf(storeto, " %u", *uintp);
1605 return (storeto + strlen(storeto));
1610 charpp = (u_char **) dataptr;
1611 return read_config_save_octet_string(storeto, *charpp, *len);
1615 oidpp = (oid **) dataptr;
1616 return read_config_save_objid(storeto, *oidpp, *len);
1619 DEBUGMSGTL(("read_config_store_data", "Fail: Unknown type: %d",
1626 #endif /* BRCM_SNMP_SUPPORT */
1630 struct config_files *config_files = NULL;
1632 /* remove later, only for testing purpose */
1634 copy_nword(char *from, char *to, int len)
1640 config_perror(const char *string)
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)
1660 return (register_config_handler(NULL, token, parser, releaser, help));
1664 unregister_config_handler(const char *type_param, const char *token)
1666 struct config_files **ctmp = &config_files;
1667 struct config_line **ltmp, *ltmp2;
1668 const char *type = type_param;
1671 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1672 NETSNMP_DS_LIB_APPTYPE);
1676 * find type in current list
1678 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
1679 ctmp = &((*ctmp)->next);
1682 if (*ctmp == NULL) {
1684 * Not found, return.
1689 ltmp = &((*ctmp)->start);
1690 if (*ltmp == NULL) {
1692 * Not found, return.
1696 if (strcmp((*ltmp)->config_token, token) == 0) {
1698 * found it at the top of the list
1700 ltmp2 = (*ltmp)->next;
1701 free((*ltmp)->config_token);
1702 SNMP_FREE((*ltmp)->help);
1704 (*ctmp)->start = ltmp2;
1707 while ((*ltmp)->next != NULL
1708 && strcmp((*ltmp)->next->config_token, token)) {
1709 ltmp = &((*ltmp)->next);
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;
1721 unregister_app_config_handler(const char *token)
1723 unregister_config_handler(NULL, token);
1727 unregister_all_config_handlers()
1729 struct config_files *ctmp, *save;
1730 struct config_line *ltmp;
1735 * Keep using config_files until there are no more!
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);
1742 free(ctmp->fileHeader);
1746 config_files = save;
1751 read_app_config_store(const char *line)
1756 struct config_line *
1757 register_config_handler(const char *type_param,
1759 void (*parser) (const char *, char *),
1760 void (*releaser) (void), const char *help)
1762 struct config_files **ctmp = &config_files;
1763 struct config_line **ltmp;
1764 const char *type = type_param;
1767 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1768 NETSNMP_DS_LIB_APPTYPE);
1772 * Find type in current list -OR- create a new file type.
1774 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
1775 ctmp = &((*ctmp)->next);
1778 if (*ctmp == NULL) {
1779 *ctmp = (struct config_files *)
1780 calloc(1, sizeof(struct config_files));
1785 (*ctmp)->fileHeader = strdup(type);
1789 * Find parser type in current list -OR- create a new
1790 * line parser entry.
1792 ltmp = &((*ctmp)->start);
1794 while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) {
1795 ltmp = &((*ltmp)->next);
1798 if (*ltmp == NULL) {
1799 *ltmp = (struct config_line *)
1800 calloc(1, sizeof(struct config_line));
1805 (*ltmp)->config_time = NORMAL_CONFIG;
1806 (*ltmp)->config_token = strdup(token);
1808 (*ltmp)->help = strdup(help);
1812 * Add/Replace the parse/free functions for the given line type
1813 * in the given file type.
1815 (*ltmp)->parse_line = parser;
1816 (*ltmp)->free_func = releaser;
1820 } /* end register_config_handler() */
1821 #endif /* ILMI_TEST */
1822 #endif /* BUILD_ILMI */