net-snmp 5.7
|
00001 /* 00002 * read_config.c 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 00013 */ 00014 00067 #include <net-snmp/net-snmp-config.h> 00068 #include <net-snmp/net-snmp-features.h> 00069 00070 #include <stdio.h> 00071 #include <ctype.h> 00072 #if HAVE_STDLIB_H 00073 #include <stdlib.h> 00074 #endif 00075 #if HAVE_STRING_H 00076 #include <string.h> 00077 #else 00078 #include <strings.h> 00079 #endif 00080 #if HAVE_UNISTD_H 00081 #include <unistd.h> 00082 #endif 00083 #include <sys/types.h> 00084 #if HAVE_SYS_PARAM_H 00085 #include <sys/param.h> 00086 #endif 00087 #if TIME_WITH_SYS_TIME 00088 # include <sys/time.h> 00089 # include <time.h> 00090 #else 00091 # if HAVE_SYS_TIME_H 00092 # include <sys/time.h> 00093 # else 00094 # include <time.h> 00095 # endif 00096 #endif 00097 #ifdef HAVE_SYS_STAT_H 00098 #include <sys/stat.h> 00099 #endif 00100 #if HAVE_NETINET_IN_H 00101 #include <netinet/in.h> 00102 #endif 00103 #if HAVE_ARPA_INET_H 00104 #include <arpa/inet.h> 00105 #endif 00106 #if HAVE_SYS_SELECT_H 00107 #include <sys/select.h> 00108 #endif 00109 #if HAVE_SYS_SOCKET_H 00110 #include <sys/socket.h> 00111 #endif 00112 #if HAVE_NETDB_H 00113 #include <netdb.h> 00114 #endif 00115 #include <errno.h> 00116 00117 #if HAVE_DIRENT_H 00118 # include <dirent.h> 00119 # define NAMLEN(dirent) strlen((dirent)->d_name) 00120 #else 00121 # define dirent direct 00122 # define NAMLEN(dirent) (dirent)->d_namlen 00123 # if HAVE_SYS_NDIR_H 00124 # include <sys/ndir.h> 00125 # endif 00126 # if HAVE_SYS_DIR_H 00127 # include <sys/dir.h> 00128 # endif 00129 # if HAVE_NDIR_H 00130 # include <ndir.h> 00131 # endif 00132 #endif 00133 00134 #if HAVE_DMALLOC_H 00135 #include <dmalloc.h> 00136 #endif 00137 00138 #include <net-snmp/types.h> 00139 #include <net-snmp/output_api.h> 00140 #include <net-snmp/config_api.h> 00141 #include <net-snmp/library/read_config.h> /* for "internal" definitions */ 00142 #include <net-snmp/utilities.h> 00143 00144 #include <net-snmp/library/mib.h> 00145 #include <net-snmp/library/parse.h> 00146 #include <net-snmp/library/snmp_api.h> 00147 #include <net-snmp/library/callback.h> 00148 00149 netsnmp_feature_child_of(read_config_all, libnetsnmp) 00150 00151 netsnmp_feature_child_of(unregister_app_config_handler, read_config_all) 00152 netsnmp_feature_child_of(read_config_register_app_prenetsnmp_mib_handler, netsnmp_unused) 00153 netsnmp_feature_child_of(read_config_register_const_config_handler, netsnmp_unused) 00154 00155 static int config_errors; 00156 00157 struct config_files *config_files = NULL; 00158 00159 00160 static struct config_line * 00161 internal_register_config_handler(const char *type_param, 00162 const char *token, 00163 void (*parser) (const char *, char *), 00164 void (*releaser) (void), const char *help, 00165 int when) 00166 { 00167 struct config_files **ctmp = &config_files; 00168 struct config_line **ltmp; 00169 const char *type = type_param; 00170 00171 if (type == NULL || *type == '\0') { 00172 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00173 NETSNMP_DS_LIB_APPTYPE); 00174 } 00175 00176 /* 00177 * Handle multiple types (recursively) 00178 */ 00179 if (strchr(type, ':')) { 00180 struct config_line *ltmp2 = NULL; 00181 char buf[STRINGMAX]; 00182 char *cptr = buf; 00183 strncpy(buf, type, STRINGMAX - 1); 00184 buf[STRINGMAX - 1] = '\0'; 00185 while (cptr) { 00186 char* c = cptr; 00187 cptr = strchr(cptr, ':'); 00188 if(cptr) { 00189 *cptr = '\0'; 00190 ++cptr; 00191 } 00192 ltmp2 = internal_register_config_handler(c, token, parser, 00193 releaser, help, when); 00194 } 00195 return ltmp2; 00196 } 00197 00198 /* 00199 * Find type in current list -OR- create a new file type. 00200 */ 00201 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { 00202 ctmp = &((*ctmp)->next); 00203 } 00204 00205 if (*ctmp == NULL) { 00206 *ctmp = (struct config_files *) 00207 calloc(1, sizeof(struct config_files)); 00208 if (!*ctmp) { 00209 return NULL; 00210 } 00211 00212 (*ctmp)->fileHeader = strdup(type); 00213 DEBUGMSGTL(("9:read_config:type", "new type %s\n", type)); 00214 } 00215 00216 DEBUGMSGTL(("9:read_config:register_handler", "registering %s %s\n", 00217 type, token)); 00218 /* 00219 * Find parser type in current list -OR- create a new 00220 * line parser entry. 00221 */ 00222 ltmp = &((*ctmp)->start); 00223 00224 while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) { 00225 ltmp = &((*ltmp)->next); 00226 } 00227 00228 if (*ltmp == NULL) { 00229 *ltmp = (struct config_line *) 00230 calloc(1, sizeof(struct config_line)); 00231 if (!*ltmp) { 00232 return NULL; 00233 } 00234 00235 (*ltmp)->config_time = when; 00236 (*ltmp)->config_token = strdup(token); 00237 if (help != NULL) 00238 (*ltmp)->help = strdup(help); 00239 } 00240 00241 /* 00242 * Add/Replace the parse/free functions for the given line type 00243 * in the given file type. 00244 */ 00245 (*ltmp)->parse_line = parser; 00246 (*ltmp)->free_func = releaser; 00247 00248 return (*ltmp); 00249 00250 } /* end register_config_handler() */ 00251 00252 struct config_line * 00253 register_prenetsnmp_mib_handler(const char *type, 00254 const char *token, 00255 void (*parser) (const char *, char *), 00256 void (*releaser) (void), const char *help) 00257 { 00258 return internal_register_config_handler(type, token, parser, releaser, 00259 help, PREMIB_CONFIG); 00260 } 00261 00262 #ifndef NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_APP_PRENETSNMP_MIB_HANDLER 00263 struct config_line * 00264 register_app_prenetsnmp_mib_handler(const char *token, 00265 void (*parser) (const char *, char *), 00266 void (*releaser) (void), 00267 const char *help) 00268 { 00269 return (register_prenetsnmp_mib_handler 00270 (NULL, token, parser, releaser, help)); 00271 } 00272 #endif /* NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_APP_PRENETSNMP_MIB_HANDLER */ 00273 00306 struct config_line * 00307 register_config_handler(const char *type, 00308 const char *token, 00309 void (*parser) (const char *, char *), 00310 void (*releaser) (void), const char *help) 00311 { 00312 return internal_register_config_handler(type, token, parser, releaser, 00313 help, NORMAL_CONFIG); 00314 } 00315 00316 #ifndef NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_CONST_CONFIG_HANDLER 00317 struct config_line * 00318 register_const_config_handler(const char *type, 00319 const char *token, 00320 void (*parser) (const char *, const char *), 00321 void (*releaser) (void), const char *help) 00322 { 00323 return internal_register_config_handler(type, token, 00324 (void(*)(const char *, char *)) 00325 parser, releaser, 00326 help, NORMAL_CONFIG); 00327 } 00328 #endif /* NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_CONST_CONFIG_HANDLER */ 00329 00330 struct config_line * 00331 register_app_config_handler(const char *token, 00332 void (*parser) (const char *, char *), 00333 void (*releaser) (void), const char *help) 00334 { 00335 return (register_config_handler(NULL, token, parser, releaser, help)); 00336 } 00337 00338 00339 00351 void 00352 unregister_config_handler(const char *type_param, const char *token) 00353 { 00354 struct config_files **ctmp = &config_files; 00355 struct config_line **ltmp; 00356 const char *type = type_param; 00357 00358 if (type == NULL || *type == '\0') { 00359 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00360 NETSNMP_DS_LIB_APPTYPE); 00361 } 00362 00363 /* 00364 * Handle multiple types (recursively) 00365 */ 00366 if (strchr(type, ':')) { 00367 char buf[STRINGMAX]; 00368 char *cptr = buf; 00369 strncpy(buf, type, STRINGMAX - 1); 00370 buf[STRINGMAX - 1] = '\0'; 00371 while (cptr) { 00372 char* c = cptr; 00373 cptr = strchr(cptr, ':'); 00374 if(cptr) { 00375 *cptr = '\0'; 00376 ++cptr; 00377 } 00378 unregister_config_handler(c, token); 00379 } 00380 return; 00381 } 00382 00383 /* 00384 * find type in current list 00385 */ 00386 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { 00387 ctmp = &((*ctmp)->next); 00388 } 00389 00390 if (*ctmp == NULL) { 00391 /* 00392 * Not found, return. 00393 */ 00394 return; 00395 } 00396 00397 ltmp = &((*ctmp)->start); 00398 if (*ltmp == NULL) { 00399 /* 00400 * Not found, return. 00401 */ 00402 return; 00403 } 00404 if (strcmp((*ltmp)->config_token, token) == 0) { 00405 /* 00406 * found it at the top of the list 00407 */ 00408 struct config_line *ltmp2 = (*ltmp)->next; 00409 SNMP_FREE((*ltmp)->config_token); 00410 SNMP_FREE((*ltmp)->help); 00411 SNMP_FREE(*ltmp); 00412 (*ctmp)->start = ltmp2; 00413 return; 00414 } 00415 while ((*ltmp)->next != NULL 00416 && strcmp((*ltmp)->next->config_token, token)) { 00417 ltmp = &((*ltmp)->next); 00418 } 00419 if ((*ltmp)->next != NULL) { 00420 struct config_line *ltmp2 = (*ltmp)->next->next; 00421 SNMP_FREE((*ltmp)->next->config_token); 00422 SNMP_FREE((*ltmp)->next->help); 00423 SNMP_FREE((*ltmp)->next); 00424 (*ltmp)->next = ltmp2; 00425 } 00426 } 00427 00428 #ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_APP_CONFIG_HANDLER 00429 void 00430 unregister_app_config_handler(const char *token) 00431 { 00432 unregister_config_handler(NULL, token); 00433 } 00434 #endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_APP_CONFIG_HANDLER */ 00435 00436 void 00437 unregister_all_config_handlers(void) 00438 { 00439 struct config_files *ctmp, *save; 00440 struct config_line *ltmp; 00441 00442 free_config(); 00443 00444 /* 00445 * Keep using config_files until there are no more! 00446 */ 00447 for (ctmp = config_files; ctmp;) { 00448 for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) { 00449 unregister_config_handler(ctmp->fileHeader, 00450 ltmp->config_token); 00451 } 00452 SNMP_FREE(ctmp->fileHeader); 00453 save = ctmp->next; 00454 SNMP_FREE(ctmp); 00455 ctmp = save; 00456 config_files = save; 00457 } 00458 } 00459 00460 #ifdef TESTING 00461 void 00462 print_config_handlers(void) 00463 { 00464 struct config_files *ctmp = config_files; 00465 struct config_line *ltmp; 00466 00467 for (; ctmp != NULL; ctmp = ctmp->next) { 00468 DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader)); 00469 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) 00470 DEBUGMSGTL(("read_config", " %s\n", 00471 ltmp->config_token)); 00472 } 00473 } 00474 #endif 00475 00476 int linecount, prev_linecount; 00477 const char *curfilename, *prev_filename; 00478 00479 struct config_line * 00480 read_config_get_handlers(const char *type) 00481 { 00482 struct config_files *ctmp = config_files; 00483 for (; ctmp != NULL && strcmp(ctmp->fileHeader, type); 00484 ctmp = ctmp->next); 00485 if (ctmp) 00486 return ctmp->start; 00487 return NULL; 00488 } 00489 00490 int 00491 read_config_with_type_when(const char *filename, const char *type, int when) 00492 { 00493 struct config_line *ctmp = read_config_get_handlers(type); 00494 if (ctmp) 00495 return read_config(filename, ctmp, when); 00496 else 00497 DEBUGMSGTL(("read_config", 00498 "read_config: I have no registrations for type:%s,file:%s\n", 00499 type, filename)); 00500 return SNMPERR_GENERR; /* No config files read */ 00501 } 00502 00503 int 00504 read_config_with_type(const char *filename, const char *type) 00505 { 00506 return read_config_with_type_when(filename, type, EITHER_CONFIG); 00507 } 00508 00509 00510 struct config_line * 00511 read_config_find_handler(struct config_line *line_handlers, 00512 const char *token) 00513 { 00514 struct config_line *lptr; 00515 00516 for (lptr = line_handlers; lptr != NULL; lptr = lptr->next) { 00517 if (!strcasecmp(token, lptr->config_token)) { 00518 return lptr; 00519 } 00520 } 00521 return NULL; 00522 } 00523 00524 00525 /* 00526 * searches a config_line linked list for a match 00527 */ 00528 int 00529 run_config_handler(struct config_line *lptr, 00530 const char *token, char *cptr, int when) 00531 { 00532 char *cp; 00533 lptr = read_config_find_handler(lptr, token); 00534 if (lptr != NULL) { 00535 if (when == EITHER_CONFIG || lptr->config_time == when) { 00536 DEBUGMSGTL(("read_config:parser", 00537 "Found a parser. Calling it: %s / %s\n", token, 00538 cptr)); 00539 /* 00540 * Stomp on any trailing whitespace 00541 */ 00542 cp = &(cptr[strlen(cptr)-1]); 00543 while ((cp > cptr) && isspace((unsigned char)(*cp))) { 00544 *(cp--) = '\0'; 00545 } 00546 (*(lptr->parse_line)) (token, cptr); 00547 } 00548 else 00549 DEBUGMSGTL(("9:read_config:parser", 00550 "%s handler not registered for this time\n", token)); 00551 } else if (when != PREMIB_CONFIG && 00552 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00553 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) { 00554 netsnmp_config_warn("Unknown token: %s.", token); 00555 return SNMPERR_GENERR; 00556 } 00557 return SNMPERR_SUCCESS; 00558 } 00559 00560 /* 00561 * takens an arbitrary string and tries to intepret it based on the 00562 * known configuration handlers for all registered types. May produce 00563 * inconsistent results when multiple tokens of the same name are 00564 * registered under different file types. 00565 */ 00566 00567 /* 00568 * we allow = delimeters here 00569 */ 00570 #define SNMP_CONFIG_DELIMETERS " \t=" 00571 00572 int 00573 snmp_config_when(char *line, int when) 00574 { 00575 char *cptr, buf[STRINGMAX]; 00576 struct config_line *lptr = NULL; 00577 struct config_files *ctmp = config_files; 00578 char *st; 00579 00580 if (line == NULL) { 00581 config_perror("snmp_config() called with a null string."); 00582 return SNMPERR_GENERR; 00583 } 00584 00585 strncpy(buf, line, STRINGMAX); 00586 buf[STRINGMAX - 1] = '\0'; 00587 cptr = strtok_r(buf, SNMP_CONFIG_DELIMETERS, &st); 00588 if (cptr && cptr[0] == '[') { 00589 if (cptr[strlen(cptr) - 1] != ']') { 00590 netsnmp_config_error("no matching ']' for type %s.", cptr + 1); 00591 return SNMPERR_GENERR; 00592 } 00593 cptr[strlen(cptr) - 1] = '\0'; 00594 lptr = read_config_get_handlers(cptr + 1); 00595 if (lptr == NULL) { 00596 netsnmp_config_error("No handlers regestered for type %s.", 00597 cptr + 1); 00598 return SNMPERR_GENERR; 00599 } 00600 cptr = strtok_r(NULL, SNMP_CONFIG_DELIMETERS, &st); 00601 lptr = read_config_find_handler(lptr, cptr); 00602 } else { 00603 /* 00604 * we have to find a token 00605 */ 00606 for (; ctmp != NULL && lptr == NULL; ctmp = ctmp->next) 00607 lptr = read_config_find_handler(ctmp->start, cptr); 00608 } 00609 if (lptr == NULL && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00610 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) { 00611 netsnmp_config_warn("Unknown token: %s.", cptr); 00612 return SNMPERR_GENERR; 00613 } 00614 00615 /* 00616 * use the original string instead since strtok_r messed up the original 00617 */ 00618 line = skip_white(line + (cptr - buf) + strlen(cptr) + 1); 00619 00620 return (run_config_handler(lptr, cptr, line, when)); 00621 } 00622 00623 int 00624 netsnmp_config(char *line) 00625 { 00626 int ret = SNMP_ERR_NOERROR; 00627 DEBUGMSGTL(("snmp_config", "remembering line \"%s\"\n", line)); 00628 netsnmp_config_remember(line); /* always remember it so it's read 00629 * processed after a free_config() 00630 * call */ 00631 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00632 NETSNMP_DS_LIB_HAVE_READ_CONFIG)) { 00633 DEBUGMSGTL(("snmp_config", " ... processing it now\n")); 00634 ret = snmp_config_when(line, NORMAL_CONFIG); 00635 } 00636 return ret; 00637 } 00638 00639 void 00640 netsnmp_config_remember_in_list(char *line, 00641 struct read_config_memory **mem) 00642 { 00643 if (mem == NULL) 00644 return; 00645 00646 while (*mem != NULL) 00647 mem = &((*mem)->next); 00648 00649 *mem = SNMP_MALLOC_STRUCT(read_config_memory); 00650 if (*mem != NULL) { 00651 if (line) 00652 (*mem)->line = strdup(line); 00653 } 00654 } 00655 00656 void 00657 netsnmp_config_remember_free_list(struct read_config_memory **mem) 00658 { 00659 struct read_config_memory *tmpmem; 00660 while (*mem) { 00661 SNMP_FREE((*mem)->line); 00662 tmpmem = (*mem)->next; 00663 SNMP_FREE(*mem); 00664 *mem = tmpmem; 00665 } 00666 } 00667 00668 void 00669 netsnmp_config_process_memory_list(struct read_config_memory **memp, 00670 int when, int clear) 00671 { 00672 00673 struct read_config_memory *mem; 00674 00675 if (!memp) 00676 return; 00677 00678 mem = *memp; 00679 00680 while (mem) { 00681 DEBUGMSGTL(("read_config:mem", "processing memory: %s\n", mem->line)); 00682 snmp_config_when(mem->line, when); 00683 mem = mem->next; 00684 } 00685 00686 if (clear) 00687 netsnmp_config_remember_free_list(memp); 00688 } 00689 00690 /* 00691 * default storage location implementation 00692 */ 00693 static struct read_config_memory *memorylist = NULL; 00694 00695 void 00696 netsnmp_config_remember(char *line) 00697 { 00698 netsnmp_config_remember_in_list(line, &memorylist); 00699 } 00700 00701 void 00702 netsnmp_config_process_memories(void) 00703 { 00704 netsnmp_config_process_memory_list(&memorylist, EITHER_CONFIG, 1); 00705 } 00706 00707 void 00708 netsnmp_config_process_memories_when(int when, int clear) 00709 { 00710 netsnmp_config_process_memory_list(&memorylist, when, clear); 00711 } 00712 00713 /*******************************************************************-o-****** 00714 * read_config 00715 * 00716 * Parameters: 00717 * *filename 00718 * *line_handler 00719 * when 00720 * 00721 * Read <filename> and process each line in accordance with the list of 00722 * <line_handler> functions. 00723 * 00724 * 00725 * For each line in <filename>, search the list of <line_handler>'s 00726 * for an entry that matches the first token on the line. This comparison is 00727 * case insensitive. 00728 * 00729 * For each match, check that <when> is the designated time for the 00730 * <line_handler> function to be executed before processing the line. 00731 * 00732 * Returns SNMPERR_SUCCESS if the file is processed successfully. 00733 * Returns SNMPERR_GENERR if it cannot. 00734 * Note that individual config token errors do not trigger SNMPERR_GENERR 00735 * It's only if the whole file cannot be processed for some reason. 00736 */ 00737 int 00738 read_config(const char *filename, 00739 struct config_line *line_handler, int when) 00740 { 00741 static int depth = 0; 00742 static int files = 0; 00743 FILE *ifile; 00744 char line[STRINGMAX], token[STRINGMAX]; 00745 char *cptr; 00746 int i, ret; 00747 struct config_line *lptr; 00748 00749 linecount = 0; 00750 curfilename = filename; 00751 00752 if ((ifile = fopen(filename, "r")) == NULL) { 00753 #ifdef ENOENT 00754 if (errno == ENOENT) { 00755 DEBUGMSGTL(("read_config", "%s: %s\n", filename, 00756 strerror(errno))); 00757 } else 00758 #endif /* ENOENT */ 00759 #ifdef EACCES 00760 if (errno == EACCES) { 00761 DEBUGMSGTL(("read_config", "%s: %s\n", filename, 00762 strerror(errno))); 00763 } else 00764 #endif /* EACCES */ 00765 #if defined(ENOENT) || defined(EACCES) 00766 { 00767 snmp_log_perror(filename); 00768 } 00769 #else /* defined(ENOENT) || defined(EACCES) */ 00770 snmp_log_perror(filename); 00771 #endif /* ENOENT */ 00772 return SNMPERR_GENERR; 00773 } 00774 00775 #define CONFIG_MAX_FILES 4096 00776 if (files > CONFIG_MAX_FILES) { 00777 netsnmp_config_error("maximum conf file count (%d) exceeded\n", 00778 CONFIG_MAX_FILES); 00779 return SNMPERR_GENERR; 00780 } 00781 #define CONFIG_MAX_RECURSE_DEPTH 16 00782 if (depth > CONFIG_MAX_RECURSE_DEPTH) { 00783 netsnmp_config_error("nested include depth > %d\n", 00784 CONFIG_MAX_RECURSE_DEPTH); 00785 return SNMPERR_GENERR; 00786 } 00787 ++files; 00788 ++depth; 00789 00790 DEBUGMSGTL(("read_config:file", "Reading configuration %s (%d)\n", 00791 filename, when)); 00792 00793 while (fgets(line, sizeof(line), ifile) != NULL) { 00794 lptr = line_handler; 00795 linecount++; 00796 cptr = line; 00797 i = strlen(line) - 1; 00798 if (line[i] == '\n') 00799 line[i] = 0; 00800 DEBUGMSGTL(("9:read_config:line", "%s:%d examining: %s\n", 00801 filename, linecount, line)); 00802 /* 00803 * check blank line or # comment 00804 */ 00805 if ((cptr = skip_white(cptr))) { 00806 cptr = copy_nword(cptr, token, sizeof(token)); 00807 if (token[0] == '[') { 00808 if (token[strlen(token) - 1] != ']') { 00809 netsnmp_config_error("no matching ']' for type %s.", 00810 &token[1]); 00811 continue; 00812 } 00813 token[strlen(token) - 1] = '\0'; 00814 lptr = read_config_get_handlers(&token[1]); 00815 if (lptr == NULL) { 00816 netsnmp_config_error("No handlers regestered for type %s.", 00817 &token[1]); 00818 continue; 00819 } 00820 DEBUGMSGTL(("read_config:context", 00821 "Switching to new context: %s%s\n", 00822 ((cptr) ? "(this line only) " : ""), 00823 &token[1])); 00824 if (cptr == NULL) { 00825 /* 00826 * change context permanently 00827 */ 00828 line_handler = lptr; 00829 continue; 00830 } else { 00831 /* 00832 * the rest of this line only applies. 00833 */ 00834 cptr = copy_nword(cptr, token, sizeof(token)); 00835 } 00836 } else if ((token[0] == 'i') && (strncasecmp(token,"include", 7 )==0)) { 00837 if ( strcasecmp( token, "include" )==0) { 00838 if (when != PREMIB_CONFIG && 00839 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00840 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) { 00841 netsnmp_config_warn("Ambiguous token '%s' - use 'includeSearch' (or 'includeFile') instead.", token); 00842 } 00843 continue; 00844 } else if ( strcasecmp( token, "includedir" )==0) { 00845 DIR *d; 00846 struct dirent *entry; 00847 char fname[SNMP_MAXPATH]; 00848 int len; 00849 00850 if (cptr == NULL) { 00851 if (when != PREMIB_CONFIG) 00852 netsnmp_config_error("Blank line following %s token.", token); 00853 continue; 00854 } 00855 if ((d=opendir(cptr)) == NULL ) { 00856 if (when != PREMIB_CONFIG) 00857 netsnmp_config_error("Can't open include dir '%s'.", cptr); 00858 continue; 00859 } 00860 prev_filename = curfilename; 00861 prev_linecount = linecount; 00862 while ((entry = readdir( d )) != NULL ) { 00863 if ( entry->d_name && entry->d_name[0] != '.') { 00864 len = NAMLEN(entry); 00865 if ((len > 5) && (strcmp(&(entry->d_name[len-5]),".conf") == 0)) { 00866 snprintf(fname, SNMP_MAXPATH, "%s/%s", 00867 cptr, entry->d_name); 00868 (void)read_config(fname, line_handler, when); 00869 } 00870 } 00871 } 00872 closedir(d); 00873 curfilename = prev_filename; 00874 linecount = prev_linecount; 00875 continue; 00876 } else if ( strcasecmp( token, "includefile" )==0) { 00877 char fname[SNMP_MAXPATH], *cp; 00878 00879 if (cptr == NULL) { 00880 if (when != PREMIB_CONFIG) 00881 netsnmp_config_error("Blank line following %s token.", token); 00882 continue; 00883 } 00884 if ( cptr[0] == '/' ) { 00885 strncpy(fname, cptr, SNMP_MAXPATH); 00886 fname[SNMP_MAXPATH-1]='\0'; 00887 } else { 00888 strncpy(fname, filename, SNMP_MAXPATH); 00889 fname[SNMP_MAXPATH-1]='\0'; 00890 cp = strrchr(fname, '/'); 00891 *(++cp) = '\0'; 00892 strncat(fname, cptr, SNMP_MAXPATH-strlen(fname)); 00893 fname[SNMP_MAXPATH-1]='\0'; 00894 } 00895 prev_filename = curfilename; 00896 prev_linecount = linecount; 00897 ret = read_config(fname, line_handler, when); 00898 curfilename = prev_filename; 00899 linecount = prev_linecount; 00900 if ((ret != SNMPERR_SUCCESS) && (when != PREMIB_CONFIG)) 00901 netsnmp_config_error("Included file '%s' not found.", fname); 00902 continue; 00903 } else if ( strcasecmp( token, "includesearch" )==0) { 00904 struct config_files ctmp; 00905 int len; 00906 00907 if (cptr == NULL) { 00908 if (when != PREMIB_CONFIG) 00909 netsnmp_config_error("Blank line following %s token.", token); 00910 continue; 00911 } 00912 len = strlen(cptr); 00913 ctmp.fileHeader = cptr; 00914 ctmp.start = line_handler; 00915 ctmp.next = NULL; 00916 if ((len > 5) && (strcmp(&cptr[len-5],".conf") == 0)) 00917 cptr[len-5] = 0; /* chop off .conf */ 00918 prev_filename = curfilename; 00919 prev_linecount = linecount; 00920 ret = read_config_files_of_type(when,&ctmp); 00921 curfilename = prev_filename; 00922 linecount = prev_linecount; 00923 if ((len > 5) && (cptr[len-5] == 0)) 00924 cptr[len-5] = '.'; /* restore .conf */ 00925 if (( ret != SNMPERR_SUCCESS ) && (when != PREMIB_CONFIG)) 00926 netsnmp_config_error("Included config '%s' not found.", cptr); 00927 continue; 00928 } else { 00929 lptr = line_handler; 00930 } 00931 } else { 00932 lptr = line_handler; 00933 } 00934 if (cptr == NULL) { 00935 netsnmp_config_error("Blank line following %s token.", token); 00936 } else { 00937 DEBUGMSGTL(("read_config:line", "%s:%d examining: %s\n", 00938 filename, linecount, line)); 00939 run_config_handler(lptr, token, cptr, when); 00940 } 00941 } 00942 } 00943 fclose(ifile); 00944 --depth; 00945 return SNMPERR_SUCCESS; 00946 00947 } /* end read_config() */ 00948 00949 00950 00951 void 00952 free_config(void) 00953 { 00954 struct config_files *ctmp = config_files; 00955 struct config_line *ltmp; 00956 00957 for (; ctmp != NULL; ctmp = ctmp->next) 00958 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) 00959 if (ltmp->free_func) 00960 (*(ltmp->free_func)) (); 00961 } 00962 00963 /* 00964 * Return SNMPERR_SUCCESS if any config files are processed 00965 * Return SNMPERR_GENERR if _no_ config files are processed 00966 * Whether this is actually an error is left to the application 00967 */ 00968 int 00969 read_configs_optional(const char *optional_config, int when) 00970 { 00971 char *newp, *cp, *st = NULL; 00972 int ret = SNMPERR_GENERR; 00973 char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00974 NETSNMP_DS_LIB_APPTYPE); 00975 00976 if ((NULL == optional_config) || (NULL == type)) 00977 return ret; 00978 00979 DEBUGMSGTL(("read_configs_optional", 00980 "reading optional configuration tokens for %s\n", type)); 00981 00982 newp = strdup(optional_config); /* strtok_r messes it up */ 00983 cp = strtok_r(newp, ",", &st); 00984 while (cp) { 00985 struct stat statbuf; 00986 if (stat(cp, &statbuf)) { 00987 DEBUGMSGTL(("read_config", 00988 "Optional File \"%s\" does not exist.\n", cp)); 00989 snmp_log_perror(cp); 00990 } else { 00991 DEBUGMSGTL(("read_config:opt", 00992 "Reading optional config file: \"%s\"\n", cp)); 00993 if ( read_config_with_type_when(cp, type, when) == SNMPERR_SUCCESS ) 00994 ret = SNMPERR_SUCCESS; 00995 } 00996 cp = strtok_r(NULL, ",", &st); 00997 } 00998 free(newp); 00999 return ret; 01000 } 01001 01002 void 01003 read_configs(void) 01004 { 01005 char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01006 NETSNMP_DS_LIB_OPTIONALCONFIG); 01007 01008 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 01009 SNMP_CALLBACK_PRE_READ_CONFIG, NULL); 01010 01011 DEBUGMSGTL(("read_config", "reading normal configuration tokens\n")); 01012 01013 if ((NULL != optional_config) && (*optional_config == '-')) { 01014 (void)read_configs_optional(++optional_config, NORMAL_CONFIG); 01015 optional_config = NULL; /* clear, so we don't read them twice */ 01016 } 01017 01018 (void)read_config_files(NORMAL_CONFIG); 01019 01020 /* 01021 * do this even when the normal above wasn't done 01022 */ 01023 if (NULL != optional_config) 01024 (void)read_configs_optional(optional_config, NORMAL_CONFIG); 01025 01026 netsnmp_config_process_memories_when(NORMAL_CONFIG, 1); 01027 01028 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 01029 NETSNMP_DS_LIB_HAVE_READ_CONFIG, 1); 01030 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 01031 SNMP_CALLBACK_POST_READ_CONFIG, NULL); 01032 } 01033 01034 void 01035 read_premib_configs(void) 01036 { 01037 char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01038 NETSNMP_DS_LIB_OPTIONALCONFIG); 01039 01040 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 01041 SNMP_CALLBACK_PRE_PREMIB_READ_CONFIG, NULL); 01042 01043 DEBUGMSGTL(("read_config", "reading premib configuration tokens\n")); 01044 01045 if ((NULL != optional_config) && (*optional_config == '-')) { 01046 (void)read_configs_optional(++optional_config, PREMIB_CONFIG); 01047 optional_config = NULL; /* clear, so we don't read them twice */ 01048 } 01049 01050 (void)read_config_files(PREMIB_CONFIG); 01051 01052 if (NULL != optional_config) 01053 (void)read_configs_optional(optional_config, PREMIB_CONFIG); 01054 01055 netsnmp_config_process_memories_when(PREMIB_CONFIG, 0); 01056 01057 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 01058 NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG, 1); 01059 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 01060 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, NULL); 01061 } 01062 01063 /*******************************************************************-o-****** 01064 * set_configuration_directory 01065 * 01066 * Parameters: 01067 * char *dir - value of the directory 01068 * Sets the configuration directory. Multiple directories can be 01069 * specified, but need to be seperated by 'ENV_SEPARATOR_CHAR'. 01070 */ 01071 void 01072 set_configuration_directory(const char *dir) 01073 { 01074 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 01075 NETSNMP_DS_LIB_CONFIGURATION_DIR, dir); 01076 } 01077 01078 /*******************************************************************-o-****** 01079 * get_configuration_directory 01080 * 01081 * Parameters: - 01082 * Retrieve the configuration directory or directories. 01083 * (For backwards compatibility that is: 01084 * SNMPCONFPATH, SNMPSHAREPATH, SNMPLIBPATH, HOME/.snmp 01085 * First check whether the value is set. 01086 * If not set give it the default value. 01087 * Return the value. 01088 * We always retrieve it new, since we have to do it anyway if it is just set. 01089 */ 01090 const char * 01091 get_configuration_directory(void) 01092 { 01093 char defaultPath[SPRINT_MAX_LEN]; 01094 char *homepath; 01095 01096 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01097 NETSNMP_DS_LIB_CONFIGURATION_DIR)) { 01098 homepath = netsnmp_getenv("HOME"); 01099 snprintf(defaultPath, sizeof(defaultPath), "%s%c%s%c%s%s%s%s", 01100 SNMPCONFPATH, ENV_SEPARATOR_CHAR, 01101 SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH, 01102 ((homepath == NULL) ? "" : ENV_SEPARATOR), 01103 ((homepath == NULL) ? "" : homepath), 01104 ((homepath == NULL) ? "" : "/.snmp")); 01105 defaultPath[ sizeof(defaultPath)-1 ] = 0; 01106 set_configuration_directory(defaultPath); 01107 } 01108 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01109 NETSNMP_DS_LIB_CONFIGURATION_DIR)); 01110 } 01111 01112 /*******************************************************************-o-****** 01113 * set_persistent_directory 01114 * 01115 * Parameters: 01116 * char *dir - value of the directory 01117 * Sets the configuration directory. 01118 * No multiple directories may be specified. 01119 * (However, this is not checked) 01120 */ 01121 void 01122 set_persistent_directory(const char *dir) 01123 { 01124 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 01125 NETSNMP_DS_LIB_PERSISTENT_DIR, dir); 01126 } 01127 01128 /*******************************************************************-o-****** 01129 * get_persistent_directory 01130 * 01131 * Parameters: - 01132 * Function will retrieve the persisten directory value. 01133 * First check whether the value is set. 01134 * If not set give it the default value. 01135 * Return the value. 01136 * We always retrieve it new, since we have to do it anyway if it is just set. 01137 */ 01138 const char * 01139 get_persistent_directory(void) 01140 { 01141 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01142 NETSNMP_DS_LIB_PERSISTENT_DIR)) { 01143 const char *persdir = netsnmp_getenv("SNMP_PERSISTENT_DIR"); 01144 if (NULL == persdir) 01145 persdir = NETSNMP_PERSISTENT_DIRECTORY; 01146 set_persistent_directory(persdir); 01147 } 01148 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01149 NETSNMP_DS_LIB_PERSISTENT_DIR)); 01150 } 01151 01152 /*******************************************************************-o-****** 01153 * set_temp_file_pattern 01154 * 01155 * Parameters: 01156 * char *pattern - value of the file pattern 01157 * Sets the temp file pattern. 01158 * Multiple patterns may not be specified. 01159 * (However, this is not checked) 01160 */ 01161 void 01162 set_temp_file_pattern(const char *pattern) 01163 { 01164 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 01165 NETSNMP_DS_LIB_TEMP_FILE_PATTERN, pattern); 01166 } 01167 01168 /*******************************************************************-o-****** 01169 * get_temp_file_pattern 01170 * 01171 * Parameters: - 01172 * Function will retrieve the temp file pattern value. 01173 * First check whether the value is set. 01174 * If not set give it the default value. 01175 * Return the value. 01176 * We always retrieve it new, since we have to do it anyway if it is just set. 01177 */ 01178 const char * 01179 get_temp_file_pattern(void) 01180 { 01181 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01182 NETSNMP_DS_LIB_TEMP_FILE_PATTERN)) { 01183 set_temp_file_pattern(NETSNMP_TEMP_FILE_PATTERN); 01184 } 01185 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01186 NETSNMP_DS_LIB_TEMP_FILE_PATTERN)); 01187 } 01188 01196 static int 01197 read_config_files_in_path(const char *path, struct config_files *ctmp, 01198 int when, const char *perspath, const char *persfile) 01199 { 01200 int done, j; 01201 char configfile[300]; 01202 char *cptr1, *cptr2, *envconfpath; 01203 struct stat statbuf; 01204 int ret = SNMPERR_GENERR; 01205 01206 if ((NULL == path) || (NULL == ctmp)) 01207 return SNMPERR_GENERR; 01208 01209 envconfpath = strdup(path); 01210 01211 DEBUGMSGTL(("read_config:path", " config path used for %s:%s (persistent path:%s)\n", 01212 ctmp->fileHeader, envconfpath, perspath)); 01213 cptr1 = cptr2 = envconfpath; 01214 done = 0; 01215 while ((!done) && (*cptr2 != 0)) { 01216 while (*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR) 01217 cptr1++; 01218 if (*cptr1 == 0) 01219 done = 1; 01220 else 01221 *cptr1 = 0; 01222 01223 DEBUGMSGTL(("read_config:dir", " config dir: %s\n", cptr2 )); 01224 if (stat(cptr2, &statbuf) != 0) { 01225 /* 01226 * Directory not there, continue 01227 */ 01228 DEBUGMSGTL(("read_config:dir", " Directory not present: %s\n", cptr2 )); 01229 cptr2 = ++cptr1; 01230 continue; 01231 } 01232 #ifdef S_ISDIR 01233 if (!S_ISDIR(statbuf.st_mode)) { 01234 /* 01235 * Not a directory, continue 01236 */ 01237 DEBUGMSGTL(("read_config:dir", " Not a directory: %s\n", cptr2 )); 01238 cptr2 = ++cptr1; 01239 continue; 01240 } 01241 #endif 01242 01243 /* 01244 * for proper persistent storage retrieval, we need to read old backup 01245 * copies of the previous storage files. If the application in 01246 * question has died without the proper call to snmp_clean_persistent, 01247 * then we read all the configuration files we can, starting with 01248 * the oldest first. 01249 */ 01250 if (strncmp(cptr2, perspath, strlen(perspath)) == 0 || 01251 (persfile != NULL && 01252 strncmp(cptr2, persfile, strlen(persfile)) == 0)) { 01253 DEBUGMSGTL(("read_config:persist", " persist dir: %s\n", cptr2 )); 01254 /* 01255 * limit this to the known storage directory only 01256 */ 01257 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01258 snprintf(configfile, sizeof(configfile), 01259 "%s/%s.%d.conf", cptr2, 01260 ctmp->fileHeader, j); 01261 configfile[ sizeof(configfile)-1 ] = 0; 01262 if (stat(configfile, &statbuf) != 0) { 01263 /* 01264 * file not there, continue 01265 */ 01266 break; 01267 } else { 01268 /* 01269 * backup exists, read it 01270 */ 01271 DEBUGMSGTL(("read_config_files", 01272 "old config file found: %s, parsing\n", 01273 configfile)); 01274 if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS) 01275 ret = SNMPERR_SUCCESS; 01276 } 01277 } 01278 } 01279 snprintf(configfile, sizeof(configfile), 01280 "%s/%s.conf", cptr2, ctmp->fileHeader); 01281 configfile[ sizeof(configfile)-1 ] = 0; 01282 if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS) 01283 ret = SNMPERR_SUCCESS; 01284 snprintf(configfile, sizeof(configfile), 01285 "%s/%s.local.conf", cptr2, ctmp->fileHeader); 01286 configfile[ sizeof(configfile)-1 ] = 0; 01287 if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS) 01288 ret = SNMPERR_SUCCESS; 01289 01290 if(done) 01291 break; 01292 01293 cptr2 = ++cptr1; 01294 } 01295 SNMP_FREE(envconfpath); 01296 return ret; 01297 } 01298 01299 /*******************************************************************-o-****** 01300 * read_config_files 01301 * 01302 * Parameters: 01303 * when == PREMIB_CONFIG, NORMAL_CONFIG -or- EITHER_CONFIG 01304 * 01305 * 01306 * Traverse the list of config file types, performing the following actions 01307 * for each -- 01308 * 01309 * First, build a search path for config files. If the contents of 01310 * environment variable SNMPCONFPATH are NULL, then use the following 01311 * path list (where the last entry exists only if HOME is non-null): 01312 * 01313 * SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp 01314 * 01315 * Then, In each of these directories, read config files by the name of: 01316 * 01317 * <dir>/<fileHeader>.conf -AND- 01318 * <dir>/<fileHeader>.local.conf 01319 * 01320 * where <fileHeader> is taken from the config file type structure. 01321 * 01322 * 01323 * PREMIB_CONFIG causes free_config() to be invoked prior to any other action. 01324 * 01325 * 01326 * EXITs if any 'config_errors' are logged while parsing config file lines. 01327 * 01328 * Return SNMPERR_SUCCESS if any config files are processed 01329 * Return SNMPERR_GENERR if _no_ config files are processed 01330 * Whether this is actually an error is left to the application 01331 */ 01332 int 01333 read_config_files_of_type(int when, struct config_files *ctmp) 01334 { 01335 const char *confpath, *persfile, *envconfpath; 01336 char *perspath; 01337 int ret = SNMPERR_GENERR; 01338 01339 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01340 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01341 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01342 NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD) 01343 || (NULL == ctmp)) return ret; 01344 01345 /* 01346 * these shouldn't change 01347 */ 01348 confpath = get_configuration_directory(); 01349 persfile = netsnmp_getenv("SNMP_PERSISTENT_FILE"); 01350 envconfpath = netsnmp_getenv("SNMPCONFPATH"); 01351 01352 01353 /* 01354 * read the config files. strdup() the result of 01355 * get_persistent_directory() to avoid that parsing the "persistentDir" 01356 * keyword transforms the perspath pointer into a dangling pointer. 01357 */ 01358 perspath = strdup(get_persistent_directory()); 01359 if (envconfpath == NULL) { 01360 /* 01361 * read just the config files (no persistent stuff), since 01362 * persistent path can change via conf file. Then get the 01363 * current persistent directory, and read files there. 01364 */ 01365 if ( read_config_files_in_path(confpath, ctmp, when, perspath, 01366 persfile) == SNMPERR_SUCCESS ) 01367 ret = SNMPERR_SUCCESS; 01368 free(perspath); 01369 perspath = strdup(get_persistent_directory()); 01370 if ( read_config_files_in_path(perspath, ctmp, when, perspath, 01371 persfile) == SNMPERR_SUCCESS ) 01372 ret = SNMPERR_SUCCESS; 01373 } 01374 else { 01375 /* 01376 * only read path specified by user 01377 */ 01378 if ( read_config_files_in_path(envconfpath, ctmp, when, perspath, 01379 persfile) == SNMPERR_SUCCESS ) 01380 ret = SNMPERR_SUCCESS; 01381 } 01382 free(perspath); 01383 return ret; 01384 } 01385 01386 /* 01387 * Return SNMPERR_SUCCESS if any config files are processed 01388 * Return SNMPERR_GENERR if _no_ config files are processed 01389 * Whether this is actually an error is left to the application 01390 */ 01391 int 01392 read_config_files(int when) { 01393 01394 struct config_files *ctmp = config_files; 01395 int ret = SNMPERR_GENERR; 01396 01397 config_errors = 0; 01398 01399 if (when == PREMIB_CONFIG) 01400 free_config(); 01401 01402 /* 01403 * read all config file types 01404 */ 01405 for (; ctmp != NULL; ctmp = ctmp->next) { 01406 if ( read_config_files_of_type(when, ctmp) == SNMPERR_SUCCESS ) 01407 ret = SNMPERR_SUCCESS; 01408 } 01409 01410 if (config_errors) { 01411 snmp_log(LOG_ERR, "net-snmp: %d error(s) in config file(s)\n", 01412 config_errors); 01413 } 01414 return ret; 01415 } 01416 01417 void 01418 read_config_print_usage(const char *lead) 01419 { 01420 struct config_files *ctmp = config_files; 01421 struct config_line *ltmp; 01422 01423 if (lead == NULL) 01424 lead = ""; 01425 01426 for (ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) { 01427 snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead, 01428 ctmp->fileHeader, ctmp->fileHeader); 01429 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) { 01430 DEBUGIF("read_config_usage") { 01431 if (ltmp->config_time == PREMIB_CONFIG) 01432 DEBUGMSG(("read_config_usage", "*")); 01433 else 01434 DEBUGMSG(("read_config_usage", " ")); 01435 } 01436 if (ltmp->help) { 01437 snmp_log(LOG_INFO, "%s%s%-24s %s\n", lead, lead, 01438 ltmp->config_token, ltmp->help); 01439 } else { 01440 DEBUGIF("read_config_usage") { 01441 snmp_log(LOG_INFO, "%s%s%-24s [NO HELP]\n", lead, lead, 01442 ltmp->config_token); 01443 } 01444 } 01445 } 01446 } 01447 } 01448 01462 void 01463 read_config_store(const char *type, const char *line) 01464 { 01465 #ifdef NETSNMP_PERSISTENT_DIRECTORY 01466 char file[512], *filep; 01467 FILE *fout; 01468 #ifdef NETSNMP_PERSISTENT_MASK 01469 mode_t oldmask; 01470 #endif 01471 01472 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01473 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01474 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01475 NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD)) return; 01476 01477 /* 01478 * store configuration directives in the following order of preference: 01479 * 1. ENV variable SNMP_PERSISTENT_FILE 01480 * 2. configured <NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf 01481 */ 01482 if ((filep = netsnmp_getenv("SNMP_PERSISTENT_FILE")) == NULL) { 01483 snprintf(file, sizeof(file), 01484 "%s/%s.conf", get_persistent_directory(), type); 01485 file[ sizeof(file)-1 ] = 0; 01486 filep = file; 01487 } 01488 #ifdef NETSNMP_PERSISTENT_MASK 01489 oldmask = umask(NETSNMP_PERSISTENT_MASK); 01490 #endif 01491 if (mkdirhier(filep, NETSNMP_AGENT_DIRECTORY_MODE, 1)) { 01492 snmp_log(LOG_ERR, 01493 "Failed to create the persistent directory for %s\n", 01494 file); 01495 } 01496 if ((fout = fopen(filep, "a")) != NULL) { 01497 fprintf(fout, "%s", line); 01498 if (line[strlen(line)] != '\n') 01499 fprintf(fout, "\n"); 01500 DEBUGMSGTL(("read_config:store", "storing: %s\n", line)); 01501 fclose(fout); 01502 } else { 01503 snmp_log(LOG_ERR, "read_config_store open failure on %s\n", filep); 01504 } 01505 #ifdef NETSNMP_PERSISTENT_MASK 01506 umask(oldmask); 01507 #endif 01508 01509 #endif 01510 } /* end read_config_store() */ 01511 01512 void 01513 read_app_config_store(const char *line) 01514 { 01515 read_config_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01516 NETSNMP_DS_LIB_APPTYPE), line); 01517 } 01518 01519 01520 01521 01522 /*******************************************************************-o-****** 01523 * snmp_save_persistent 01524 * 01525 * Parameters: 01526 * *type 01527 * 01528 * 01529 * Save the file "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy 01530 * called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an 01531 * incrementing number on each call, but less than NETSNMP_MAX_PERSISTENT_BACKUPS. 01532 * 01533 * Should be called just before all persistent information is supposed to be 01534 * written to move aside the existing persistent cache. 01535 * snmp_clean_persistent should then be called afterward all data has been 01536 * saved to remove these backup files. 01537 * 01538 * Note: on an rename error, the files are removed rather than saved. 01539 * 01540 */ 01541 void 01542 snmp_save_persistent(const char *type) 01543 { 01544 char file[512], fileold[SPRINT_MAX_LEN]; 01545 struct stat statbuf; 01546 int j; 01547 01548 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01549 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01550 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01551 NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE)) return; 01552 01553 DEBUGMSGTL(("snmp_save_persistent", "saving %s files...\n", type)); 01554 snprintf(file, sizeof(file), 01555 "%s/%s.conf", get_persistent_directory(), type); 01556 file[ sizeof(file)-1 ] = 0; 01557 if (stat(file, &statbuf) == 0) { 01558 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01559 snprintf(fileold, sizeof(fileold), 01560 "%s/%s.%d.conf", get_persistent_directory(), type, j); 01561 fileold[ sizeof(fileold)-1 ] = 0; 01562 if (stat(fileold, &statbuf) != 0) { 01563 DEBUGMSGTL(("snmp_save_persistent", 01564 " saving old config file: %s -> %s.\n", file, 01565 fileold)); 01566 if (rename(file, fileold)) { 01567 snmp_log(LOG_ERR, "Cannot rename %s to %s\n", file, fileold); 01568 /* moving it failed, try nuking it, as leaving 01569 * it around is very bad. */ 01570 if (unlink(file) == -1) 01571 snmp_log(LOG_ERR, "Cannot unlink %s\n", file); 01572 } 01573 break; 01574 } 01575 } 01576 } 01577 /* 01578 * save a warning header to the top of the new file 01579 */ 01580 snprintf(fileold, sizeof(fileold), 01581 "%s%s# Please save normal configuration tokens for %s in SNMPCONFPATH/%s.conf.\n# Only \"createUser\" tokens should be placed here by %s administrators.\n%s", 01582 "#\n# net-snmp (or ucd-snmp) persistent data file.\n#\n############################################################################\n# STOP STOP STOP STOP STOP STOP STOP STOP STOP \n", 01583 "#\n# **** DO NOT EDIT THIS FILE ****\n#\n# STOP STOP STOP STOP STOP STOP STOP STOP STOP \n############################################################################\n#\n# DO NOT STORE CONFIGURATION ENTRIES HERE.\n", 01584 type, type, type, 01585 "# (Did I mention: do not edit this file?)\n#\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 01586 fileold[ sizeof(fileold)-1 ] = 0; 01587 read_config_store(type, fileold); 01588 } 01589 01590 01591 /*******************************************************************-o-****** 01592 * snmp_clean_persistent 01593 * 01594 * Parameters: 01595 * *type 01596 * 01597 * 01598 * Unlink all backup files called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf". 01599 * 01600 * Should be called just after we successfull dumped the last of the 01601 * persistent data, to remove the backup copies of previous storage dumps. 01602 * 01603 * XXX Worth overwriting with random bytes first? This would 01604 * ensure that the data is destroyed, even a buffer containing the 01605 * data persists in memory or swap. Only important if secrets 01606 * will be stored here. 01607 */ 01608 void 01609 snmp_clean_persistent(const char *type) 01610 { 01611 char file[512]; 01612 struct stat statbuf; 01613 int j; 01614 01615 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01616 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01617 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01618 NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE)) return; 01619 01620 DEBUGMSGTL(("snmp_clean_persistent", "cleaning %s files...\n", type)); 01621 snprintf(file, sizeof(file), 01622 "%s/%s.conf", get_persistent_directory(), type); 01623 file[ sizeof(file)-1 ] = 0; 01624 if (stat(file, &statbuf) == 0) { 01625 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01626 snprintf(file, sizeof(file), 01627 "%s/%s.%d.conf", get_persistent_directory(), type, j); 01628 file[ sizeof(file)-1 ] = 0; 01629 if (stat(file, &statbuf) == 0) { 01630 DEBUGMSGTL(("snmp_clean_persistent", 01631 " removing old config file: %s\n", file)); 01632 if (unlink(file) == -1) 01633 snmp_log(LOG_ERR, "Cannot unlink %s\n", file); 01634 } 01635 } 01636 } 01637 } 01638 01639 01640 01641 01642 /* 01643 * config_perror: prints a warning string associated with a file and 01644 * line number of a .conf file and increments the error count. 01645 */ 01646 static void 01647 config_vlog(int level, const char *levelmsg, const char *str, va_list args) 01648 { 01649 char tmpbuf[256]; 01650 char* buf = tmpbuf; 01651 int len = snprintf(tmpbuf, sizeof(tmpbuf), "%s: line %d: %s: %s\n", 01652 curfilename, linecount, levelmsg, str); 01653 if (len >= (int)sizeof(tmpbuf)) { 01654 buf = (char*)malloc(len + 1); 01655 sprintf(buf, "%s: line %d: %s: %s\n", 01656 curfilename, linecount, levelmsg, str); 01657 } 01658 snmp_vlog(level, buf, args); 01659 if (buf != tmpbuf) 01660 free(buf); 01661 } 01662 01663 void 01664 netsnmp_config_error(const char *str, ...) 01665 { 01666 va_list args; 01667 va_start(args, str); 01668 config_vlog(LOG_ERR, "Error", str, args); 01669 va_end(args); 01670 config_errors++; 01671 } 01672 01673 void 01674 netsnmp_config_warn(const char *str, ...) 01675 { 01676 va_list args; 01677 va_start(args, str); 01678 config_vlog(LOG_WARNING, "Warning", str, args); 01679 va_end(args); 01680 } 01681 01682 void 01683 config_perror(const char *str) 01684 { 01685 netsnmp_config_error("%s", str); 01686 } 01687 01688 void 01689 config_pwarn(const char *str) 01690 { 01691 netsnmp_config_warn("%s", str); 01692 } 01693 01694 /* 01695 * skip all white spaces and return 1 if found something either end of 01696 * line or a comment character 01697 */ 01698 char * 01699 skip_white(char *ptr) 01700 { 01701 return NETSNMP_REMOVE_CONST(char *, skip_white_const(ptr)); 01702 } 01703 01704 const char * 01705 skip_white_const(const char *ptr) 01706 { 01707 if (ptr == NULL) 01708 return (NULL); 01709 while (*ptr != 0 && isspace((unsigned char)*ptr)) 01710 ptr++; 01711 if (*ptr == 0 || *ptr == '#') 01712 return (NULL); 01713 return (ptr); 01714 } 01715 01716 char * 01717 skip_not_white(char *ptr) 01718 { 01719 return NETSNMP_REMOVE_CONST(char *, skip_not_white_const(ptr)); 01720 } 01721 01722 const char * 01723 skip_not_white_const(const char *ptr) 01724 { 01725 if (ptr == NULL) 01726 return (NULL); 01727 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 01728 ptr++; 01729 if (*ptr == 0 || *ptr == '#') 01730 return (NULL); 01731 return (ptr); 01732 } 01733 01734 char * 01735 skip_token(char *ptr) 01736 { 01737 return NETSNMP_REMOVE_CONST(char *, skip_token_const(ptr)); 01738 } 01739 01740 const char * 01741 skip_token_const(const char *ptr) 01742 { 01743 ptr = skip_white_const(ptr); 01744 ptr = skip_not_white_const(ptr); 01745 ptr = skip_white_const(ptr); 01746 return (ptr); 01747 } 01748 01749 /* 01750 * copy_word 01751 * copies the next 'token' from 'from' into 'to', maximum len-1 characters. 01752 * currently a token is anything seperate by white space 01753 * or within quotes (double or single) (i.e. "the red rose" 01754 * is one token, \"the red rose\" is three tokens) 01755 * a '\' character will allow a quote character to be treated 01756 * as a regular character 01757 * It returns a pointer to first non-white space after the end of the token 01758 * being copied or to 0 if we reach the end. 01759 * Note: Partially copied words (greater than len) still returns a !NULL ptr 01760 * Note: partially copied words are, however, null terminated. 01761 */ 01762 01763 char * 01764 copy_nword(char *from, char *to, int len) 01765 { 01766 return NETSNMP_REMOVE_CONST(char *, copy_nword_const(from, to, len)); 01767 } 01768 01769 const char * 01770 copy_nword_const(const char *from, char *to, int len) 01771 { 01772 char quote; 01773 if (!from || !to) 01774 return NULL; 01775 if ((*from == '\"') || (*from == '\'')) { 01776 quote = *(from++); 01777 while ((*from != quote) && (*from != 0)) { 01778 if ((*from == '\\') && (*(from + 1) != 0)) { 01779 if (len > 0) { /* don't copy beyond len bytes */ 01780 *to++ = *(from + 1); 01781 if (--len == 0) 01782 *(to - 1) = '\0'; /* null protect the last spot */ 01783 } 01784 from = from + 2; 01785 } else { 01786 if (len > 0) { /* don't copy beyond len bytes */ 01787 *to++ = *from++; 01788 if (--len == 0) 01789 *(to - 1) = '\0'; /* null protect the last spot */ 01790 } else 01791 from++; 01792 } 01793 } 01794 if (*from == 0) { 01795 DEBUGMSGTL(("read_config_copy_word", 01796 "no end quote found in config string\n")); 01797 } else 01798 from++; 01799 } else { 01800 while (*from != 0 && !isspace((unsigned char)(*from))) { 01801 if ((*from == '\\') && (*(from + 1) != 0)) { 01802 if (len > 0) { /* don't copy beyond len bytes */ 01803 *to++ = *(from + 1); 01804 if (--len == 0) 01805 *(to - 1) = '\0'; /* null protect the last spot */ 01806 } 01807 from = from + 2; 01808 } else { 01809 if (len > 0) { /* don't copy beyond len bytes */ 01810 *to++ = *from++; 01811 if (--len == 0) 01812 *(to - 1) = '\0'; /* null protect the last spot */ 01813 } else 01814 from++; 01815 } 01816 } 01817 } 01818 if (len > 0) 01819 *to = 0; 01820 from = skip_white_const(from); 01821 return (from); 01822 } /* copy_nword */ 01823 01824 /* 01825 * copy_word 01826 * copies the next 'token' from 'from' into 'to'. 01827 * currently a token is anything seperate by white space 01828 * or within quotes (double or single) (i.e. "the red rose" 01829 * is one token, \"the red rose\" is three tokens) 01830 * a '\' character will allow a quote character to be treated 01831 * as a regular character 01832 * It returns a pointer to first non-white space after the end of the token 01833 * being copied or to 0 if we reach the end. 01834 */ 01835 01836 static int have_warned = 0; 01837 char * 01838 copy_word(char *from, char *to) 01839 { 01840 if (!have_warned) { 01841 snmp_log(LOG_INFO, 01842 "copy_word() called. Use copy_nword() instead.\n"); 01843 have_warned = 1; 01844 } 01845 return copy_nword(from, to, SPRINT_MAX_LEN); 01846 } /* copy_word */ 01847 01848 /* 01849 * read_config_save_octet_string(): saves an octet string as a length 01850 * followed by a string of hex 01851 */ 01852 char * 01853 read_config_save_octet_string(char *saveto, u_char * str, size_t len) 01854 { 01855 int i; 01856 u_char *cp; 01857 01858 /* 01859 * is everything easily printable 01860 */ 01861 for (i = 0, cp = str; i < (int) len && cp && 01862 (isalpha(*cp) || isdigit(*cp) || *cp == ' '); cp++, i++); 01863 01864 if (len != 0 && i == (int) len) { 01865 *saveto++ = '"'; 01866 memcpy(saveto, str, len); 01867 saveto += len; 01868 *saveto++ = '"'; 01869 *saveto = '\0'; 01870 } else { 01871 if (str != NULL) { 01872 sprintf(saveto, "0x"); 01873 saveto += 2; 01874 for (i = 0; i < (int) len; i++) { 01875 sprintf(saveto, "%02x", str[i]); 01876 saveto = saveto + 2; 01877 } 01878 } else { 01879 sprintf(saveto, "\"\""); 01880 saveto += 2; 01881 } 01882 } 01883 return saveto; 01884 } 01885 01904 char * 01905 read_config_read_octet_string(const char *readfrom, u_char ** str, 01906 size_t * len) 01907 { 01908 return NETSNMP_REMOVE_CONST(char *, 01909 read_config_read_octet_string_const(readfrom, str, len)); 01910 } 01911 01912 const char * 01913 read_config_read_octet_string_const(const char *readfrom, u_char ** str, 01914 size_t * len) 01915 { 01916 u_char *cptr; 01917 const char *cptr1; 01918 u_int tmp; 01919 size_t i, ilen; 01920 01921 if (readfrom == NULL || str == NULL || len == NULL) 01922 return NULL; 01923 01924 if (strncasecmp(readfrom, "0x", 2) == 0) { 01925 /* 01926 * A hex string submitted. How long? 01927 */ 01928 readfrom += 2; 01929 cptr1 = skip_not_white_const(readfrom); 01930 if (cptr1) 01931 ilen = (cptr1 - readfrom); 01932 else 01933 ilen = strlen(readfrom); 01934 01935 if (ilen % 2) { 01936 snmp_log(LOG_WARNING,"invalid hex string: wrong length\n"); 01937 DEBUGMSGTL(("read_config_read_octet_string", 01938 "invalid hex string: wrong length")); 01939 return NULL; 01940 } 01941 ilen = ilen / 2; 01942 01943 /* 01944 * malloc data space if needed (+1 for good measure) 01945 */ 01946 if (*str == NULL) { 01947 *str = (u_char *) malloc(ilen + 1); 01948 if (!*str) 01949 return NULL; 01950 } else { 01951 /* 01952 * require caller to have +1, and bail if not enough space. 01953 */ 01954 if (ilen >= *len) { 01955 snmp_log(LOG_WARNING,"buffer too small to read octet string (%lu < %lu)\n", 01956 (unsigned long)*len, (unsigned long)ilen); 01957 DEBUGMSGTL(("read_config_read_octet_string", 01958 "buffer too small (%lu < %lu)", (unsigned long)*len, (unsigned long)ilen)); 01959 *len = 0; 01960 cptr1 = skip_not_white_const(readfrom); 01961 return skip_white_const(cptr1); 01962 } 01963 } 01964 01965 /* 01966 * copy validated data 01967 */ 01968 cptr = *str; 01969 for (i = 0; i < ilen; i++) { 01970 if (1 == sscanf(readfrom, "%2x", &tmp)) 01971 *cptr++ = (u_char) tmp; 01972 else { 01973 /* 01974 * we may lose memory, but don't know caller's buffer XX free(cptr); 01975 */ 01976 return (NULL); 01977 } 01978 readfrom += 2; 01979 } 01980 /* 01981 * Terminate the output buffer. 01982 */ 01983 *cptr++ = '\0'; 01984 *len = ilen; 01985 readfrom = skip_white_const(readfrom); 01986 } else { 01987 /* 01988 * Normal string 01989 */ 01990 01991 /* 01992 * malloc string space if needed (including NULL terminator) 01993 */ 01994 if (*str == NULL) { 01995 char buf[SNMP_MAXBUF]; 01996 readfrom = copy_nword_const(readfrom, buf, sizeof(buf)); 01997 01998 *len = strlen(buf); 01999 *str = (u_char *) malloc(*len + 1); 02000 if (*str == NULL) 02001 return NULL; 02002 memcpy(*str, buf, *len + 1); 02003 } else { 02004 readfrom = copy_nword_const(readfrom, (char *) *str, *len); 02005 if (*len) 02006 *len = strlen((char *) *str); 02007 } 02008 } 02009 02010 return readfrom; 02011 } 02012 02013 /* 02014 * read_config_save_objid(): saves an objid as a numerical string 02015 */ 02016 char * 02017 read_config_save_objid(char *saveto, oid * objid, size_t len) 02018 { 02019 int i; 02020 02021 if (len == 0) { 02022 strcat(saveto, "NULL"); 02023 saveto += strlen(saveto); 02024 return saveto; 02025 } 02026 02027 /* 02028 * in case len=0, this makes it easier to read it back in 02029 */ 02030 for (i = 0; i < (int) len; i++) { 02031 sprintf(saveto, ".%" NETSNMP_PRIo "d", objid[i]); 02032 saveto += strlen(saveto); 02033 } 02034 return saveto; 02035 } 02036 02037 /* 02038 * read_config_read_objid(): reads an objid from a format saved by the above 02039 */ 02040 char * 02041 read_config_read_objid(char *readfrom, oid ** objid, size_t * len) 02042 { 02043 return NETSNMP_REMOVE_CONST(char *, 02044 read_config_read_objid_const(readfrom, objid, len)); 02045 } 02046 02047 const char * 02048 read_config_read_objid_const(const char *readfrom, oid ** objid, size_t * len) 02049 { 02050 02051 if (objid == NULL || readfrom == NULL || len == NULL) 02052 return NULL; 02053 02054 if (*objid == NULL) { 02055 *len = 0; 02056 if ((*objid = (oid *) malloc(MAX_OID_LEN * sizeof(oid))) == NULL) 02057 return NULL; 02058 *len = MAX_OID_LEN; 02059 } 02060 02061 if (strncmp(readfrom, "NULL", 4) == 0) { 02062 /* 02063 * null length oid 02064 */ 02065 *len = 0; 02066 } else { 02067 /* 02068 * qualify the string for read_objid 02069 */ 02070 char buf[SPRINT_MAX_LEN]; 02071 copy_nword_const(readfrom, buf, sizeof(buf)); 02072 02073 if (!read_objid(buf, *objid, len)) { 02074 DEBUGMSGTL(("read_config_read_objid", "Invalid OID")); 02075 *len = 0; 02076 return NULL; 02077 } 02078 } 02079 02080 readfrom = skip_token_const(readfrom); 02081 return readfrom; 02082 } 02083 02109 char * 02110 read_config_read_data(int type, char *readfrom, void *dataptr, 02111 size_t * len) 02112 { 02113 int *intp; 02114 char **charpp; 02115 oid **oidpp; 02116 unsigned int *uintp; 02117 02118 if (dataptr && readfrom) 02119 switch (type) { 02120 case ASN_INTEGER: 02121 intp = (int *) dataptr; 02122 *intp = atoi(readfrom); 02123 readfrom = skip_token(readfrom); 02124 return readfrom; 02125 02126 case ASN_TIMETICKS: 02127 case ASN_UNSIGNED: 02128 uintp = (unsigned int *) dataptr; 02129 *uintp = strtoul(readfrom, NULL, 0); 02130 readfrom = skip_token(readfrom); 02131 return readfrom; 02132 02133 case ASN_IPADDRESS: 02134 intp = (int *) dataptr; 02135 *intp = inet_addr(readfrom); 02136 if ((*intp == -1) && 02137 (strncmp(readfrom, "255.255.255.255", 15) != 0)) 02138 return NULL; 02139 readfrom = skip_token(readfrom); 02140 return readfrom; 02141 02142 case ASN_OCTET_STR: 02143 case ASN_BIT_STR: 02144 charpp = (char **) dataptr; 02145 return read_config_read_octet_string(readfrom, 02146 (u_char **) charpp, len); 02147 02148 case ASN_OBJECT_ID: 02149 oidpp = (oid **) dataptr; 02150 return read_config_read_objid(readfrom, oidpp, len); 02151 02152 default: 02153 DEBUGMSGTL(("read_config_read_data", "Fail: Unknown type: %d", 02154 type)); 02155 return NULL; 02156 } 02157 return NULL; 02158 } 02159 02160 /* 02161 * read_config_read_memory(): 02162 * 02163 * similar to read_config_read_data, but expects a generic memory 02164 * pointer rather than a specific type of pointer. Len is expected to 02165 * be the amount of available memory. 02166 */ 02167 char * 02168 read_config_read_memory(int type, char *readfrom, 02169 char *dataptr, size_t * len) 02170 { 02171 int *intp; 02172 unsigned int *uintp; 02173 char buf[SPRINT_MAX_LEN]; 02174 02175 if (!dataptr || !readfrom) 02176 return NULL; 02177 02178 switch (type) { 02179 case ASN_INTEGER: 02180 if (*len < sizeof(int)) 02181 return NULL; 02182 intp = (int *) dataptr; 02183 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 02184 *intp = atoi(buf); 02185 *len = sizeof(int); 02186 return readfrom; 02187 02188 case ASN_COUNTER: 02189 case ASN_TIMETICKS: 02190 case ASN_UNSIGNED: 02191 if (*len < sizeof(unsigned int)) 02192 return NULL; 02193 uintp = (unsigned int *) dataptr; 02194 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 02195 *uintp = strtoul(buf, NULL, 0); 02196 *len = sizeof(unsigned int); 02197 return readfrom; 02198 02199 case ASN_IPADDRESS: 02200 if (*len < sizeof(int)) 02201 return NULL; 02202 intp = (int *) dataptr; 02203 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 02204 *intp = inet_addr(buf); 02205 if ((*intp == -1) && (strcmp(buf, "255.255.255.255") != 0)) 02206 return NULL; 02207 *len = sizeof(int); 02208 return readfrom; 02209 02210 case ASN_OCTET_STR: 02211 case ASN_BIT_STR: 02212 case ASN_PRIV_IMPLIED_OCTET_STR: 02213 return read_config_read_octet_string(readfrom, 02214 (u_char **) & dataptr, len); 02215 02216 case ASN_PRIV_IMPLIED_OBJECT_ID: 02217 case ASN_OBJECT_ID: 02218 readfrom = 02219 read_config_read_objid(readfrom, (oid **) & dataptr, len); 02220 *len *= sizeof(oid); 02221 return readfrom; 02222 02223 case ASN_COUNTER64: 02224 if (*len < sizeof(U64)) 02225 return NULL; 02226 *len = sizeof(U64); 02227 read64((U64 *) dataptr, readfrom); 02228 readfrom = skip_token(readfrom); 02229 return readfrom; 02230 } 02231 02232 DEBUGMSGTL(("read_config_read_memory", "Fail: Unknown type: %d", type)); 02233 return NULL; 02234 } 02235 02263 char * 02264 read_config_store_data(int type, char *storeto, void *dataptr, size_t * len) 02265 { 02266 return read_config_store_data_prefix(' ', type, storeto, dataptr, 02267 (len ? *len : 0)); 02268 } 02269 02270 char * 02271 read_config_store_data_prefix(char prefix, int type, char *storeto, 02272 void *dataptr, size_t len) 02273 { 02274 int *intp; 02275 u_char **charpp; 02276 unsigned int *uintp; 02277 struct in_addr in; 02278 oid **oidpp; 02279 02280 if (dataptr && storeto) 02281 switch (type) { 02282 case ASN_INTEGER: 02283 intp = (int *) dataptr; 02284 sprintf(storeto, "%c%d", prefix, *intp); 02285 return (storeto + strlen(storeto)); 02286 02287 case ASN_TIMETICKS: 02288 case ASN_UNSIGNED: 02289 uintp = (unsigned int *) dataptr; 02290 sprintf(storeto, "%c%u", prefix, *uintp); 02291 return (storeto + strlen(storeto)); 02292 02293 case ASN_IPADDRESS: 02294 in.s_addr = *(unsigned int *) dataptr; 02295 sprintf(storeto, "%c%s", prefix, inet_ntoa(in)); 02296 return (storeto + strlen(storeto)); 02297 02298 case ASN_OCTET_STR: 02299 case ASN_BIT_STR: 02300 *storeto++ = prefix; 02301 charpp = (u_char **) dataptr; 02302 return read_config_save_octet_string(storeto, *charpp, len); 02303 02304 case ASN_OBJECT_ID: 02305 *storeto++ = prefix; 02306 oidpp = (oid **) dataptr; 02307 return read_config_save_objid(storeto, *oidpp, len); 02308 02309 default: 02310 DEBUGMSGTL(("read_config_store_data_prefix", 02311 "Fail: Unknown type: %d", type)); 02312 return NULL; 02313 } 02314 return NULL; 02315 } 02316 02319 #ifdef READ_CONFIG_UNIT_TEST 02320 02321 #define NETSNMP_USE_ASSERT 1 02322 #include <net-snmp/libary/snmp_assert.h> 02323 02324 int 02325 read64(U64 * i64, const char *str) 02326 { 02327 netsnmp_assert(0); 02328 } 02329 02330 int 02331 snmp_get_do_debugging(void) 02332 { 02333 return 0; 02334 } 02335 02336 int 02337 debug_is_token_registered(const char *token) 02338 { 02339 netsnmp_assert(0); 02340 } 02341 02342 void 02343 debugmsg(const char *token, const char *format, ...) 02344 { 02345 netsnmp_assert(0); 02346 } 02347 02348 void 02349 debugmsgtoken(const char *token, const char *format, ...) 02350 { 02351 netsnmp_assert(0); 02352 } 02353 02354 int 02355 snmp_log(int priority, const char *format, ...) 02356 { 02357 #if 0 02358 va_list ap; 02359 02360 va_start(ap, format); 02361 vprintf(format, ap); 02362 va_end(ap); 02363 #endif 02364 return 0; 02365 } 02366 02367 void 02368 snmp_log_perror(const char *s) 02369 { 02370 netsnmp_assert(0); 02371 } 02372 02373 int 02374 snmp_vlog(int priority, const char *format, va_list ap) 02375 { 02376 netsnmp_assert(0); 02377 } 02378 02379 int 02380 netsnmp_ds_set_boolean(int storeid, int which, int value) 02381 { 02382 netsnmp_assert(0); 02383 } 02384 02385 int 02386 netsnmp_ds_get_boolean(int storeid, int which) 02387 { 02388 netsnmp_assert(0); 02389 } 02390 02391 int 02392 netsnmp_ds_set_string(int storeid, int which, const char *value) 02393 { 02394 netsnmp_assert(0); 02395 } 02396 02397 char * 02398 netsnmp_ds_get_string(int storeid, int which) 02399 { 02400 netsnmp_assert(0); 02401 } 02402 02403 char * 02404 netsnmp_getenv(const char *name) 02405 { 02406 netsnmp_assert(0); 02407 } 02408 02409 int 02410 snmp_call_callbacks(int major, int minor, void *caller_arg) 02411 { 02412 netsnmp_assert(0); 02413 } 02414 02415 int 02416 mkdirhier(const char *pathname, mode_t mode, int skiplast) 02417 { 02418 netsnmp_assert(0); 02419 } 02420 02421 int 02422 read_objid(const char *input, oid * output, size_t * out_len) 02423 { 02424 netsnmp_assert(0); 02425 } 02426 02427 struct read_config_testcase { 02428 /* 02429 * inputs 02430 */ 02431 const char *(*pf) (const char * readfrom, u_char ** str, 02432 size_t * len); 02433 const char *readfrom; 02434 size_t obuf_len; 02435 02436 /* 02437 * expected outputs 02438 */ 02439 size_t expected_offset; 02440 const u_char *expected_output; 02441 size_t expected_len; 02442 }; 02443 02444 static const u_char obuf1[] = { 1, 0, 2 }; 02445 static const u_char obuf2[] = { 'a', 'b', 'c', 0 }; 02446 static const u_char obuf3[] = { 1, 3, 2 }; 02447 02448 static const struct read_config_testcase test_input[] = { 02449 { &read_config_read_octet_string_const, "", 1, -1, NULL, 0 }, 02450 { &read_config_read_octet_string_const, "0x0", 1, -1, NULL, 1 }, 02451 { &read_config_read_octet_string_const, "0x0 0", 1, -1, NULL, 1 }, 02452 02453 { &read_config_read_octet_string_const, "0x010002", 1, -1, NULL, 0 }, 02454 { &read_config_read_octet_string_const, "0x010002", 2, -1, NULL, 0 }, 02455 { &read_config_read_octet_string_const, "0x010002", 3, -1, obuf1, 0 }, 02456 { &read_config_read_octet_string_const, "0x010002", 4, -1, obuf1, 3 }, 02457 { &read_config_read_octet_string_const, "0x010002 0", 4, 9, obuf1, 3 }, 02458 { &read_config_read_octet_string_const, "0x010002", 0, -1, obuf1, 3 }, 02459 02460 { &read_config_read_octet_string_const, "abc", 1, -1, NULL, 0 }, 02461 { &read_config_read_octet_string_const, "abc z", 1, 4, NULL, 0 }, 02462 { &read_config_read_octet_string_const, "abc", 2, -1, NULL, 1 }, 02463 { &read_config_read_octet_string_const, "abc", 3, -1, obuf2, 2 }, 02464 { &read_config_read_octet_string_const, "abc", 4, -1, obuf2, 3 }, 02465 { &read_config_read_octet_string_const, "abc z", 4, 4, obuf2, 3 }, 02466 { &read_config_read_octet_string_const, "abc", 0, -1, obuf2, 3 }, 02467 }; 02468 02469 int 02470 main(int argc, char **argv) 02471 { 02472 int failure_count = 0; 02473 unsigned int i, j; 02474 02475 printf("Start of unit test.\n"); 02476 for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) { 02477 const struct read_config_testcase *const p = &test_input[i]; 02478 size_t len = p->obuf_len; 02479 u_char *str = len > 0 ? malloc(len) : NULL; 02480 const char *result; 02481 size_t offset; 02482 02483 printf("Test %d ...\n", i); 02484 fflush(stdout); 02485 result = (p->pf) (p->readfrom, &str, &len); 02486 offset = result ? result - p->readfrom : -1; 02487 if (offset != p->expected_offset) { 02488 failure_count++; 02489 printf("test %d: expected offset %zd, got offset %" NETSNMP_PRIz "d\n", 02490 i, p->expected_offset, offset); 02491 } else if (len != p->expected_len) { 02492 failure_count++; 02493 printf("test %d: expected length %d, got length %d\n", 02494 i, p->expected_len, len); 02495 } else if (len >= 0 && p->expected_output 02496 && memcmp(str, p->expected_output, len) != 0 02497 && p->expected_output[len] == 0) { 02498 failure_count++; 02499 printf("test %d: output buffer mismatch\n", i); 02500 printf("Expected: "); 02501 for (j = 0; j < p->expected_len; ++j) 02502 printf("%02x ", p->expected_output[j]); 02503 printf("\nActual: "); 02504 for (j = 0; j < len; ++j) 02505 printf("%02x ", str[j]); 02506 printf("\n"); 02507 } 02508 02509 if (str) 02510 free(str); 02511 } 02512 if (failure_count == 0) 02513 printf("All %d tests passed.\n", i); 02514 return 0; 02515 } 02516 #endif /* READ_CONFIG_UNIT_TEST */ 02517 02518 /* 02519 * Local variables: 02520 * c-basic-offset: 4 02521 * indent-tabs-mode: nil 02522 * compile-command: "gcc -Wall -Werror -DREAD_CONFIG_UNIT_TEST=1 -O1 -I../include -g -o read_config-unit-test read_config.c && ./read_config-unit-test && valgrind --leak-check=full ./read_config-unit-test" 02523 * End: 02524 */