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 00069 #include <stdio.h> 00070 #include <ctype.h> 00071 #if HAVE_STDLIB_H 00072 #include <stdlib.h> 00073 #endif 00074 #if HAVE_STRING_H 00075 #include <string.h> 00076 #else 00077 #include <strings.h> 00078 #endif 00079 #if HAVE_UNISTD_H 00080 #include <unistd.h> 00081 #endif 00082 #include <sys/types.h> 00083 #if HAVE_SYS_PARAM_H 00084 #include <sys/param.h> 00085 #endif 00086 #if TIME_WITH_SYS_TIME 00087 # ifdef WIN32 00088 # include <sys/timeb.h> 00089 # else 00090 # include <sys/time.h> 00091 # endif 00092 # include <time.h> 00093 #else 00094 # if HAVE_SYS_TIME_H 00095 # include <sys/time.h> 00096 # else 00097 # include <time.h> 00098 # endif 00099 #endif 00100 #ifdef HAVE_SYS_STAT_H 00101 #include <sys/stat.h> 00102 #endif 00103 #if HAVE_NETINET_IN_H 00104 #include <netinet/in.h> 00105 #endif 00106 #if HAVE_ARPA_INET_H 00107 #include <arpa/inet.h> 00108 #endif 00109 #if HAVE_SYS_SELECT_H 00110 #include <sys/select.h> 00111 #endif 00112 #if HAVE_WINSOCK_H 00113 #include <winsock.h> 00114 #endif 00115 #if HAVE_SYS_SOCKET_H 00116 #include <sys/socket.h> 00117 #endif 00118 #if HAVE_NETDB_H 00119 #include <netdb.h> 00120 #endif 00121 #include <errno.h> 00122 00123 #if HAVE_DMALLOC_H 00124 #include <dmalloc.h> 00125 #endif 00126 00127 #include <net-snmp/types.h> 00128 #include <net-snmp/output_api.h> 00129 #include <net-snmp/config_api.h> 00130 #include <net-snmp/library/read_config.h> /* for "internal" definitions */ 00131 #include <net-snmp/utilities.h> 00132 00133 #include <net-snmp/library/mib.h> 00134 #include <net-snmp/library/parse.h> 00135 #include <net-snmp/library/snmp_api.h> 00136 #include <net-snmp/library/callback.h> 00137 00138 static int config_errors; 00139 00140 struct config_files *config_files = NULL; 00141 00142 static struct config_line * 00143 internal_register_config_handler(const char *type_param, 00144 const char *token, 00145 void (*parser) (const char *, char *), 00146 void (*releaser) (void), const char *help, 00147 int when) 00148 { 00149 struct config_files **ctmp = &config_files; 00150 struct config_line **ltmp; 00151 const char *type = type_param; 00152 00153 if (type == NULL || *type == '\0') { 00154 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00155 NETSNMP_DS_LIB_APPTYPE); 00156 } 00157 00158 /* 00159 * Handle multiple types (recursively) 00160 */ 00161 if (strchr(type, ':')) { 00162 struct config_line *ltmp2 = NULL; 00163 char buf[STRINGMAX]; 00164 char *cptr = buf; 00165 strncpy(buf, type, STRINGMAX - 1); 00166 buf[STRINGMAX - 1] = '\0'; 00167 while (cptr) { 00168 char* c = cptr; 00169 cptr = strchr(cptr, ':'); 00170 if(cptr) { 00171 *cptr = '\0'; 00172 ++cptr; 00173 } 00174 ltmp2 = internal_register_config_handler(c, token, parser, 00175 releaser, help, when); 00176 } 00177 return ltmp2; 00178 } 00179 00180 /* 00181 * Find type in current list -OR- create a new file type. 00182 */ 00183 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { 00184 ctmp = &((*ctmp)->next); 00185 } 00186 00187 if (*ctmp == NULL) { 00188 *ctmp = (struct config_files *) 00189 calloc(1, sizeof(struct config_files)); 00190 if (!*ctmp) { 00191 return NULL; 00192 } 00193 00194 (*ctmp)->fileHeader = strdup(type); 00195 } 00196 00197 /* 00198 * Find parser type in current list -OR- create a new 00199 * line parser entry. 00200 */ 00201 ltmp = &((*ctmp)->start); 00202 00203 while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) { 00204 ltmp = &((*ltmp)->next); 00205 } 00206 00207 if (*ltmp == NULL) { 00208 *ltmp = (struct config_line *) 00209 calloc(1, sizeof(struct config_line)); 00210 if (!*ltmp) { 00211 return NULL; 00212 } 00213 00214 (*ltmp)->config_time = when; 00215 (*ltmp)->config_token = strdup(token); 00216 if (help != NULL) 00217 (*ltmp)->help = strdup(help); 00218 } 00219 00220 /* 00221 * Add/Replace the parse/free functions for the given line type 00222 * in the given file type. 00223 */ 00224 (*ltmp)->parse_line = parser; 00225 (*ltmp)->free_func = releaser; 00226 00227 return (*ltmp); 00228 00229 } /* end register_config_handler() */ 00230 00231 struct config_line * 00232 register_prenetsnmp_mib_handler(const char *type, 00233 const char *token, 00234 void (*parser) (const char *, char *), 00235 void (*releaser) (void), const char *help) 00236 { 00237 return internal_register_config_handler(type, token, parser, releaser, 00238 help, PREMIB_CONFIG); 00239 } 00240 00241 struct config_line * 00242 register_app_prenetsnmp_mib_handler(const char *token, 00243 void (*parser) (const char *, char *), 00244 void (*releaser) (void), 00245 const char *help) 00246 { 00247 return (register_prenetsnmp_mib_handler 00248 (NULL, token, parser, releaser, help)); 00249 } 00250 00283 struct config_line * 00284 register_config_handler(const char *type, 00285 const char *token, 00286 void (*parser) (const char *, char *), 00287 void (*releaser) (void), const char *help) 00288 { 00289 return internal_register_config_handler(type, token, parser, releaser, 00290 help, NORMAL_CONFIG); 00291 } 00292 00293 struct config_line * 00294 register_app_config_handler(const char *token, 00295 void (*parser) (const char *, char *), 00296 void (*releaser) (void), const char *help) 00297 { 00298 return (register_config_handler(NULL, token, parser, releaser, help)); 00299 } 00300 00301 00302 00314 void 00315 unregister_config_handler(const char *type_param, const char *token) 00316 { 00317 struct config_files **ctmp = &config_files; 00318 struct config_line **ltmp; 00319 const char *type = type_param; 00320 00321 if (type == NULL || *type == '\0') { 00322 type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00323 NETSNMP_DS_LIB_APPTYPE); 00324 } 00325 00326 /* 00327 * Handle multiple types (recursively) 00328 */ 00329 if (strchr(type, ':')) { 00330 char buf[STRINGMAX]; 00331 char *cptr = buf; 00332 strncpy(buf, type, STRINGMAX - 1); 00333 buf[STRINGMAX - 1] = '\0'; 00334 while (cptr) { 00335 char* c = cptr; 00336 cptr = strchr(cptr, ':'); 00337 if(cptr) { 00338 *cptr = '\0'; 00339 ++cptr; 00340 } 00341 unregister_config_handler(c, token); 00342 } 00343 return; 00344 } 00345 00346 /* 00347 * find type in current list 00348 */ 00349 while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { 00350 ctmp = &((*ctmp)->next); 00351 } 00352 00353 if (*ctmp == NULL) { 00354 /* 00355 * Not found, return. 00356 */ 00357 return; 00358 } 00359 00360 ltmp = &((*ctmp)->start); 00361 if (*ltmp == NULL) { 00362 /* 00363 * Not found, return. 00364 */ 00365 return; 00366 } 00367 if (strcmp((*ltmp)->config_token, token) == 0) { 00368 /* 00369 * found it at the top of the list 00370 */ 00371 struct config_line *ltmp2 = (*ltmp)->next; 00372 SNMP_FREE((*ltmp)->config_token); 00373 SNMP_FREE((*ltmp)->help); 00374 SNMP_FREE(*ltmp); 00375 (*ctmp)->start = ltmp2; 00376 return; 00377 } 00378 while ((*ltmp)->next != NULL 00379 && strcmp((*ltmp)->next->config_token, token)) { 00380 ltmp = &((*ltmp)->next); 00381 } 00382 if ((*ltmp)->next != NULL) { 00383 struct config_line *ltmp2 = (*ltmp)->next->next; 00384 SNMP_FREE((*ltmp)->next->config_token); 00385 SNMP_FREE((*ltmp)->next->help); 00386 SNMP_FREE((*ltmp)->next); 00387 (*ltmp)->next = ltmp2; 00388 } 00389 } 00390 00391 void 00392 unregister_app_config_handler(const char *token) 00393 { 00394 unregister_config_handler(NULL, token); 00395 } 00396 00397 void 00398 unregister_all_config_handlers(void) 00399 { 00400 struct config_files *ctmp, *save; 00401 struct config_line *ltmp; 00402 00403 free_config(); 00404 00405 /* 00406 * Keep using config_files until there are no more! 00407 */ 00408 for (ctmp = config_files; ctmp;) { 00409 for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) { 00410 unregister_config_handler(ctmp->fileHeader, 00411 ltmp->config_token); 00412 } 00413 SNMP_FREE(ctmp->fileHeader); 00414 save = ctmp->next; 00415 SNMP_FREE(ctmp); 00416 ctmp = save; 00417 config_files = save; 00418 } 00419 } 00420 00421 #ifdef TESTING 00422 void 00423 print_config_handlers(void) 00424 { 00425 struct config_files *ctmp = config_files; 00426 struct config_line *ltmp; 00427 00428 for (; ctmp != NULL; ctmp = ctmp->next) { 00429 DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader)); 00430 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) 00431 DEBUGMSGTL(("read_config", " %s\n", 00432 ltmp->config_token)); 00433 } 00434 } 00435 #endif 00436 00437 int linecount; 00438 const char *curfilename; 00439 00440 struct config_line * 00441 read_config_get_handlers(const char *type) 00442 { 00443 struct config_files *ctmp = config_files; 00444 for (; ctmp != NULL && strcmp(ctmp->fileHeader, type); 00445 ctmp = ctmp->next); 00446 if (ctmp) 00447 return ctmp->start; 00448 return NULL; 00449 } 00450 00451 void 00452 read_config_with_type_when(const char *filename, const char *type, int when) 00453 { 00454 struct config_line *ctmp = read_config_get_handlers(type); 00455 if (ctmp) 00456 read_config(filename, ctmp, when); 00457 else 00458 DEBUGMSGTL(("read_config", 00459 "read_config: I have no registrations for type:%s,file:%s\n", 00460 type, filename)); 00461 } 00462 00463 void 00464 read_config_with_type(const char *filename, const char *type) 00465 { 00466 read_config_with_type_when(filename, type, EITHER_CONFIG); 00467 } 00468 00469 00470 struct config_line * 00471 read_config_find_handler(struct config_line *line_handlers, 00472 const char *token) 00473 { 00474 struct config_line *lptr; 00475 00476 for (lptr = line_handlers; lptr != NULL; lptr = lptr->next) { 00477 if (!strcasecmp(token, lptr->config_token)) { 00478 return lptr; 00479 } 00480 } 00481 return NULL; 00482 } 00483 00484 00485 /* 00486 * searches a config_line linked list for a match 00487 */ 00488 int 00489 run_config_handler(struct config_line *lptr, 00490 const char *token, char *cptr, int when) 00491 { 00492 char *cp; 00493 lptr = read_config_find_handler(lptr, token); 00494 if (lptr != NULL) { 00495 if (when == EITHER_CONFIG || lptr->config_time == when) { 00496 DEBUGMSGTL(("read_config", 00497 "Found a parser. Calling it: %s / %s\n", token, 00498 cptr)); 00499 /* 00500 * Stomp on any trailing whitespace 00501 */ 00502 cp = &(cptr[strlen(cptr)-1]); 00503 while (isspace(*cp)) { 00504 *(cp--) = '\0'; 00505 } 00506 (*(lptr->parse_line)) (token, cptr); 00507 } 00508 } else if (when != PREMIB_CONFIG && 00509 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00510 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) { 00511 netsnmp_config_warn("Unknown token: %s.", token); 00512 return SNMPERR_GENERR; 00513 } 00514 return SNMPERR_SUCCESS; 00515 } 00516 00517 /* 00518 * takens an arbitrary string and tries to intepret it based on the 00519 * known configuration handlers for all registered types. May produce 00520 * inconsistent results when multiple tokens of the same name are 00521 * registered under different file types. 00522 */ 00523 00524 /* 00525 * we allow = delimeters here 00526 */ 00527 #define SNMP_CONFIG_DELIMETERS " \t=" 00528 00529 int 00530 snmp_config_when(char *line, int when) 00531 { 00532 char *cptr, buf[STRINGMAX]; 00533 struct config_line *lptr = NULL; 00534 struct config_files *ctmp = config_files; 00535 char *st; 00536 00537 if (line == NULL) { 00538 config_perror("snmp_config() called with a null string."); 00539 return SNMPERR_GENERR; 00540 } 00541 00542 strncpy(buf, line, STRINGMAX); 00543 buf[STRINGMAX - 1] = '\0'; 00544 cptr = strtok_r(buf, SNMP_CONFIG_DELIMETERS, &st); 00545 if (cptr && cptr[0] == '[') { 00546 if (cptr[strlen(cptr) - 1] != ']') { 00547 netsnmp_config_error("no matching ']' for type %s.", cptr + 1); 00548 return SNMPERR_GENERR; 00549 } 00550 cptr[strlen(cptr) - 1] = '\0'; 00551 lptr = read_config_get_handlers(cptr + 1); 00552 if (lptr == NULL) { 00553 netsnmp_config_error("No handlers regestered for type %s.", 00554 cptr + 1); 00555 return SNMPERR_GENERR; 00556 } 00557 cptr = strtok_r(NULL, SNMP_CONFIG_DELIMETERS, &st); 00558 lptr = read_config_find_handler(lptr, cptr); 00559 } else { 00560 /* 00561 * we have to find a token 00562 */ 00563 for (; ctmp != NULL && lptr == NULL; ctmp = ctmp->next) 00564 lptr = read_config_find_handler(ctmp->start, cptr); 00565 } 00566 if (lptr == NULL && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00567 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) { 00568 netsnmp_config_warn("Unknown token: %s.", cptr); 00569 return SNMPERR_GENERR; 00570 } 00571 00572 /* 00573 * use the original string instead since strtok_r messed up the original 00574 */ 00575 line = skip_white(line + (cptr - buf) + strlen(cptr) + 1); 00576 00577 return (run_config_handler(lptr, cptr, line, when)); 00578 } 00579 00580 int 00581 netsnmp_config(char *line) 00582 { 00583 int ret = SNMP_ERR_NOERROR; 00584 DEBUGMSGTL(("snmp_config", "remembering line \"%s\"\n", line)); 00585 netsnmp_config_remember(line); /* always remember it so it's read 00586 * processed after a free_config() 00587 * call */ 00588 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00589 NETSNMP_DS_LIB_HAVE_READ_CONFIG)) { 00590 DEBUGMSGTL(("snmp_config", " ... processing it now\n")); 00591 ret = snmp_config_when(line, NORMAL_CONFIG); 00592 } 00593 return ret; 00594 } 00595 00596 void 00597 netsnmp_config_remember_in_list(char *line, 00598 struct read_config_memory **mem) 00599 { 00600 if (mem == NULL) 00601 return; 00602 00603 while (*mem != NULL) 00604 mem = &((*mem)->next); 00605 00606 *mem = SNMP_MALLOC_STRUCT(read_config_memory); 00607 if (*mem != NULL) { 00608 if (line) 00609 (*mem)->line = strdup(line); 00610 } 00611 } 00612 00613 void 00614 netsnmp_config_remember_free_list(struct read_config_memory **mem) 00615 { 00616 struct read_config_memory *tmpmem; 00617 while (*mem) { 00618 SNMP_FREE((*mem)->line); 00619 tmpmem = (*mem)->next; 00620 SNMP_FREE(*mem); 00621 *mem = tmpmem; 00622 } 00623 } 00624 00625 void 00626 netsnmp_config_process_memory_list(struct read_config_memory **memp, 00627 int when, int clear) 00628 { 00629 00630 struct read_config_memory *mem; 00631 00632 if (!memp) 00633 return; 00634 00635 mem = *memp; 00636 00637 while (mem) { 00638 DEBUGMSGTL(("read_config", "processing memory: %s\n", mem->line)); 00639 snmp_config_when(mem->line, when); 00640 mem = mem->next; 00641 } 00642 00643 if (clear) 00644 netsnmp_config_remember_free_list(memp); 00645 } 00646 00647 /* 00648 * default storage location implementation 00649 */ 00650 static struct read_config_memory *memorylist = NULL; 00651 00652 void 00653 netsnmp_config_remember(char *line) 00654 { 00655 netsnmp_config_remember_in_list(line, &memorylist); 00656 } 00657 00658 void 00659 netsnmp_config_process_memories(void) 00660 { 00661 netsnmp_config_process_memory_list(&memorylist, EITHER_CONFIG, 1); 00662 } 00663 00664 void 00665 netsnmp_config_process_memories_when(int when, int clear) 00666 { 00667 netsnmp_config_process_memory_list(&memorylist, when, clear); 00668 } 00669 00670 /*******************************************************************-o-****** 00671 * read_config 00672 * 00673 * Parameters: 00674 * *filename 00675 * *line_handler 00676 * when 00677 * 00678 * Read <filename> and process each line in accordance with the list of 00679 * <line_handler> functions. 00680 * 00681 * 00682 * For each line in <filename>, search the list of <line_handler>'s 00683 * for an entry that matches the first token on the line. This comparison is 00684 * case insensitive. 00685 * 00686 * For each match, check that <when> is the designated time for the 00687 * <line_handler> function to be executed before processing the line. 00688 */ 00689 void 00690 read_config(const char *filename, 00691 struct config_line *line_handler, int when) 00692 { 00693 00694 FILE *ifile; 00695 char line[STRINGMAX], token[STRINGMAX]; 00696 char *cptr; 00697 int i; 00698 struct config_line *lptr; 00699 00700 linecount = 0; 00701 curfilename = filename; 00702 00703 if ((ifile = fopen(filename, "r")) == NULL) { 00704 #ifdef ENOENT 00705 if (errno == ENOENT) { 00706 DEBUGMSGTL(("read_config", "%s: %s\n", filename, 00707 strerror(errno))); 00708 } else 00709 #endif /* ENOENT */ 00710 #ifdef EACCES 00711 if (errno == EACCES) { 00712 DEBUGMSGTL(("read_config", "%s: %s\n", filename, 00713 strerror(errno))); 00714 } else 00715 #endif /* EACCES */ 00716 #if defined(ENOENT) || defined(EACCES) 00717 { 00718 snmp_log_perror(filename); 00719 } 00720 #else /* defined(ENOENT) || defined(EACCES) */ 00721 snmp_log_perror(filename); 00722 #endif /* ENOENT */ 00723 return; 00724 } else { 00725 DEBUGMSGTL(("read_config", "Reading configuration %s\n", 00726 filename)); 00727 } 00728 00729 while (fgets(line, sizeof(line), ifile) != NULL) { 00730 lptr = line_handler; 00731 linecount++; 00732 cptr = line; 00733 i = strlen(line) - 1; 00734 if (line[i] == '\n') 00735 line[i] = 0; 00736 /* 00737 * check blank line or # comment 00738 */ 00739 if ((cptr = skip_white(cptr))) { 00740 cptr = copy_nword(cptr, token, sizeof(token)); 00741 if (token[0] == '[') { 00742 if (token[strlen(token) - 1] != ']') { 00743 netsnmp_config_error("no matching ']' for type %s.", 00744 &token[1]); 00745 continue; 00746 } 00747 token[strlen(token) - 1] = '\0'; 00748 lptr = read_config_get_handlers(&token[1]); 00749 if (lptr == NULL) { 00750 netsnmp_config_error("No handlers regestered for type %s.", 00751 &token[1]); 00752 continue; 00753 } 00754 DEBUGMSGTL(("read_config", 00755 "Switching to new context: %s%s\n", 00756 ((cptr) ? "(this line only) " : ""), 00757 &token[1])); 00758 if (cptr == NULL) { 00759 /* 00760 * change context permanently 00761 */ 00762 line_handler = lptr; 00763 continue; 00764 } else { 00765 /* 00766 * the rest of this line only applies. 00767 */ 00768 cptr = copy_nword(cptr, token, sizeof(token)); 00769 } 00770 } else { 00771 lptr = line_handler; 00772 } 00773 if (cptr == NULL) { 00774 netsnmp_config_error("Blank line following %s token.", token); 00775 } else { 00776 DEBUGMSGTL(("read_config", "%s:%d examining: %s\n", 00777 filename, linecount, line)); 00778 run_config_handler(lptr, token, cptr, when); 00779 } 00780 } 00781 } 00782 fclose(ifile); 00783 return; 00784 00785 } /* end read_config() */ 00786 00787 00788 00789 void 00790 free_config(void) 00791 { 00792 struct config_files *ctmp = config_files; 00793 struct config_line *ltmp; 00794 00795 for (; ctmp != NULL; ctmp = ctmp->next) 00796 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) 00797 if (ltmp->free_func) 00798 (*(ltmp->free_func)) (); 00799 } 00800 00801 void 00802 read_configs_optional(const char *optional_config, int when) 00803 { 00804 char *newp, *cp, *st = NULL; 00805 char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00806 NETSNMP_DS_LIB_APPTYPE); 00807 00808 if ((NULL == optional_config) || (NULL == type)) 00809 return; 00810 00811 DEBUGMSGTL(("read_configs_optional", 00812 "reading optional configuration tokens for %s\n", type)); 00813 00814 newp = strdup(optional_config); /* strtok_r messes it up */ 00815 cp = strtok_r(newp, ",", &st); 00816 while (cp) { 00817 struct stat statbuf; 00818 if (stat(cp, &statbuf)) { 00819 DEBUGMSGTL(("read_config", 00820 "Optional File \"%s\" does not exist.\n", cp)); 00821 snmp_log_perror(cp); 00822 } else { 00823 DEBUGMSGTL(("read_config", 00824 "Reading optional config file: \"%s\"\n", cp)); 00825 read_config_with_type_when(cp, type, when); 00826 } 00827 cp = strtok_r(NULL, ",", &st); 00828 } 00829 free(newp); 00830 00831 } 00832 00833 void 00834 read_configs(void) 00835 { 00836 char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00837 NETSNMP_DS_LIB_OPTIONALCONFIG); 00838 00839 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 00840 SNMP_CALLBACK_PRE_READ_CONFIG, NULL); 00841 00842 DEBUGMSGTL(("read_config", "reading normal configuration tokens\n")); 00843 00844 if ((NULL != optional_config) && (*optional_config == '-')) { 00845 read_configs_optional(++optional_config, NORMAL_CONFIG); 00846 optional_config = NULL; /* clear, so we don't read them twice */ 00847 } 00848 00849 read_config_files(NORMAL_CONFIG); 00850 00851 /* 00852 * do this even when the normal above wasn't done 00853 */ 00854 if (NULL != optional_config) 00855 read_configs_optional(optional_config, NORMAL_CONFIG); 00856 00857 netsnmp_config_process_memories_when(NORMAL_CONFIG, 1); 00858 00859 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 00860 NETSNMP_DS_LIB_HAVE_READ_CONFIG, 1); 00861 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 00862 SNMP_CALLBACK_POST_READ_CONFIG, NULL); 00863 } 00864 00865 void 00866 read_premib_configs(void) 00867 { 00868 char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00869 NETSNMP_DS_LIB_OPTIONALCONFIG); 00870 00871 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 00872 SNMP_CALLBACK_PRE_PREMIB_READ_CONFIG, NULL); 00873 00874 DEBUGMSGTL(("read_config", "reading premib configuration tokens\n")); 00875 00876 if ((NULL != optional_config) && (*optional_config == '-')) { 00877 read_configs_optional(++optional_config, PREMIB_CONFIG); 00878 optional_config = NULL; /* clear, so we don't read them twice */ 00879 } 00880 00881 read_config_files(PREMIB_CONFIG); 00882 00883 if (NULL != optional_config) 00884 read_configs_optional(optional_config, PREMIB_CONFIG); 00885 00886 netsnmp_config_process_memories_when(PREMIB_CONFIG, 0); 00887 00888 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 00889 NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG, 1); 00890 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, 00891 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, NULL); 00892 } 00893 00894 /*******************************************************************-o-****** 00895 * set_configuration_directory 00896 * 00897 * Parameters: 00898 * char *dir - value of the directory 00899 * Sets the configuration directory. Multiple directories can be 00900 * specified, but need to be seperated by 'ENV_SEPARATOR_CHAR'. 00901 */ 00902 void 00903 set_configuration_directory(const char *dir) 00904 { 00905 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 00906 NETSNMP_DS_LIB_CONFIGURATION_DIR, dir); 00907 } 00908 00909 /*******************************************************************-o-****** 00910 * get_configuration_directory 00911 * 00912 * Parameters: - 00913 * Retrieve the configuration directory or directories. 00914 * (For backwards compatibility that is: 00915 * SNMPCONFPATH, SNMPSHAREPATH, SNMPLIBPATH, HOME/.snmp 00916 * First check whether the value is set. 00917 * If not set give it the default value. 00918 * Return the value. 00919 * We always retrieve it new, since we have to do it anyway if it is just set. 00920 */ 00921 const char * 00922 get_configuration_directory(void) 00923 { 00924 char defaultPath[SPRINT_MAX_LEN]; 00925 char *homepath; 00926 00927 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00928 NETSNMP_DS_LIB_CONFIGURATION_DIR)) { 00929 homepath = netsnmp_getenv("HOME"); 00930 snprintf(defaultPath, sizeof(defaultPath), "%s%c%s%c%s%s%s%s", 00931 SNMPCONFPATH, ENV_SEPARATOR_CHAR, 00932 SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH, 00933 ((homepath == NULL) ? "" : ENV_SEPARATOR), 00934 ((homepath == NULL) ? "" : homepath), 00935 ((homepath == NULL) ? "" : "/.snmp")); 00936 defaultPath[ sizeof(defaultPath)-1 ] = 0; 00937 set_configuration_directory(defaultPath); 00938 } 00939 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00940 NETSNMP_DS_LIB_CONFIGURATION_DIR)); 00941 } 00942 00943 /*******************************************************************-o-****** 00944 * set_persistent_directory 00945 * 00946 * Parameters: 00947 * char *dir - value of the directory 00948 * Sets the configuration directory. 00949 * No multiple directories may be specified. 00950 * (However, this is not checked) 00951 */ 00952 void 00953 set_persistent_directory(const char *dir) 00954 { 00955 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 00956 NETSNMP_DS_LIB_PERSISTENT_DIR, dir); 00957 } 00958 00959 /*******************************************************************-o-****** 00960 * get_persistent_directory 00961 * 00962 * Parameters: - 00963 * Function will retrieve the persisten directory value. 00964 * First check whether the value is set. 00965 * If not set give it the default value. 00966 * Return the value. 00967 * We always retrieve it new, since we have to do it anyway if it is just set. 00968 */ 00969 const char * 00970 get_persistent_directory(void) 00971 { 00972 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00973 NETSNMP_DS_LIB_PERSISTENT_DIR)) { 00974 const char *persdir = netsnmp_getenv("SNMP_PERSISTENT_DIR"); 00975 if (NULL == persdir) 00976 persdir = NETSNMP_PERSISTENT_DIRECTORY; 00977 set_persistent_directory(persdir); 00978 } 00979 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00980 NETSNMP_DS_LIB_PERSISTENT_DIR)); 00981 } 00982 00983 /*******************************************************************-o-****** 00984 * set_temp_file_pattern 00985 * 00986 * Parameters: 00987 * char *pattern - value of the file pattern 00988 * Sets the temp file pattern. 00989 * Multiple patterns may not be specified. 00990 * (However, this is not checked) 00991 */ 00992 void 00993 set_temp_file_pattern(const char *pattern) 00994 { 00995 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 00996 NETSNMP_DS_LIB_TEMP_FILE_PATTERN, pattern); 00997 } 00998 00999 /*******************************************************************-o-****** 01000 * get_temp_file_pattern 01001 * 01002 * Parameters: - 01003 * Function will retrieve the temp file pattern value. 01004 * First check whether the value is set. 01005 * If not set give it the default value. 01006 * Return the value. 01007 * We always retrieve it new, since we have to do it anyway if it is just set. 01008 */ 01009 const char * 01010 get_temp_file_pattern(void) 01011 { 01012 if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01013 NETSNMP_DS_LIB_TEMP_FILE_PATTERN)) { 01014 set_temp_file_pattern(NETSNMP_TEMP_FILE_PATTERN); 01015 } 01016 return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01017 NETSNMP_DS_LIB_TEMP_FILE_PATTERN)); 01018 } 01019 01023 static void 01024 read_config_files_in_path(const char *path, struct config_files *ctmp, 01025 int when, const char *perspath, const char *persfile) 01026 { 01027 int done, j; 01028 char configfile[300]; 01029 char *cptr1, *cptr2, *envconfpath; 01030 struct stat statbuf; 01031 01032 if ((NULL == path) || (NULL == ctmp)) 01033 return; 01034 01035 envconfpath = strdup(path); 01036 01037 DEBUGMSGTL(("read_config", " config path used for %s:%s (persistent path:%s)\n", 01038 ctmp->fileHeader, envconfpath, perspath)); 01039 cptr1 = cptr2 = envconfpath; 01040 done = 0; 01041 while ((!done) && (*cptr2 != 0)) { 01042 while (*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR) 01043 cptr1++; 01044 if (*cptr1 == 0) 01045 done = 1; 01046 else 01047 *cptr1 = 0; 01048 01049 DEBUGMSGTL(("read_config", " config dir: %s\n", cptr2 )); 01050 if (stat(cptr2, &statbuf) != 0) { 01051 /* 01052 * Directory not there, continue 01053 */ 01054 DEBUGMSGTL(("read_config", " Directory not present: %s\n", cptr2 )); 01055 cptr2 = ++cptr1; 01056 continue; 01057 } 01058 #ifdef S_ISDIR 01059 if (!S_ISDIR(statbuf.st_mode)) { 01060 /* 01061 * Not a directory, continue 01062 */ 01063 DEBUGMSGTL(("read_config", " Not a directory: %s\n", cptr2 )); 01064 cptr2 = ++cptr1; 01065 continue; 01066 } 01067 #endif 01068 01069 /* 01070 * for proper persistent storage retrival, we need to read old backup 01071 * copies of the previous storage files. If the application in 01072 * question has died without the proper call to snmp_clean_persistent, 01073 * then we read all the configuration files we can, starting with 01074 * the oldest first. 01075 */ 01076 if (strncmp(cptr2, perspath, strlen(perspath)) == 0 || 01077 (persfile != NULL && 01078 strncmp(cptr2, persfile, strlen(persfile)) == 0)) { 01079 /* 01080 * limit this to the known storage directory only 01081 */ 01082 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01083 snprintf(configfile, sizeof(configfile), 01084 "%s/%s.%d.conf", cptr2, 01085 ctmp->fileHeader, j); 01086 configfile[ sizeof(configfile)-1 ] = 0; 01087 if (stat(configfile, &statbuf) != 0) { 01088 /* 01089 * file not there, continue 01090 */ 01091 break; 01092 } else { 01093 /* 01094 * backup exists, read it 01095 */ 01096 DEBUGMSGTL(("read_config_files", 01097 "old config file found: %s, parsing\n", 01098 configfile)); 01099 read_config(configfile, ctmp->start, when); 01100 } 01101 } 01102 } 01103 snprintf(configfile, sizeof(configfile), 01104 "%s/%s.conf", cptr2, ctmp->fileHeader); 01105 configfile[ sizeof(configfile)-1 ] = 0; 01106 read_config(configfile, ctmp->start, when); 01107 snprintf(configfile, sizeof(configfile), 01108 "%s/%s.local.conf", cptr2, ctmp->fileHeader); 01109 configfile[ sizeof(configfile)-1 ] = 0; 01110 read_config(configfile, ctmp->start, when); 01111 01112 if(done) 01113 break; 01114 01115 cptr2 = ++cptr1; 01116 } 01117 SNMP_FREE(envconfpath); 01118 } 01119 01120 /*******************************************************************-o-****** 01121 * read_config_files 01122 * 01123 * Parameters: 01124 * when == PREMIB_CONFIG, NORMAL_CONFIG -or- EITHER_CONFIG 01125 * 01126 * 01127 * Traverse the list of config file types, performing the following actions 01128 * for each -- 01129 * 01130 * First, build a search path for config files. If the contents of 01131 * environment variable SNMPCONFPATH are NULL, then use the following 01132 * path list (where the last entry exists only if HOME is non-null): 01133 * 01134 * SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp 01135 * 01136 * Then, In each of these directories, read config files by the name of: 01137 * 01138 * <dir>/<fileHeader>.conf -AND- 01139 * <dir>/<fileHeader>.local.conf 01140 * 01141 * where <fileHeader> is taken from the config file type structure. 01142 * 01143 * 01144 * PREMIB_CONFIG causes free_config() to be invoked prior to any other action. 01145 * 01146 * 01147 * EXITs if any 'config_errors' are logged while parsing config file lines. 01148 */ 01149 void 01150 read_config_files(int when) 01151 { 01152 const char *confpath, *perspath, *persfile, *envconfpath; 01153 struct config_files *ctmp = config_files; 01154 01155 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01156 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01157 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01158 NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD)) return; 01159 01160 config_errors = 0; 01161 01162 if (when == PREMIB_CONFIG) 01163 free_config(); 01164 01165 /* 01166 * these shouldn't change 01167 */ 01168 confpath = get_configuration_directory(); 01169 persfile = netsnmp_getenv("SNMP_PERSISTENT_FILE"); 01170 envconfpath = netsnmp_getenv("SNMPCONFPATH"); 01171 01172 /* 01173 * read all config file types 01174 */ 01175 for (; ctmp != NULL; ctmp = ctmp->next) { 01176 01177 /* 01178 * read the config files 01179 */ 01180 perspath = get_persistent_directory(); 01181 if (envconfpath == NULL) { 01182 /* 01183 * read just the config files (no persistent stuff), since 01184 * persistent path can change via conf file. Then get the 01185 * current persistent directory, and read files there. 01186 */ 01187 read_config_files_in_path(confpath, ctmp, when, perspath, 01188 persfile); 01189 perspath = get_persistent_directory(); 01190 read_config_files_in_path(perspath, ctmp, when, perspath, 01191 persfile); 01192 } 01193 else { 01194 /* 01195 * only read path specified by user 01196 */ 01197 read_config_files_in_path(envconfpath, ctmp, when, perspath, 01198 persfile); 01199 } 01200 } 01201 01202 if (config_errors) { 01203 snmp_log(LOG_ERR, "net-snmp: %d error(s) in config file(s)\n", 01204 config_errors); 01205 } 01206 } 01207 01208 void 01209 read_config_print_usage(const char *lead) 01210 { 01211 struct config_files *ctmp = config_files; 01212 struct config_line *ltmp; 01213 01214 if (lead == NULL) 01215 lead = ""; 01216 01217 for (ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) { 01218 snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead, 01219 ctmp->fileHeader, ctmp->fileHeader); 01220 for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) { 01221 DEBUGIF("read_config_usage") { 01222 if (ltmp->config_time == PREMIB_CONFIG) 01223 DEBUGMSG(("read_config_usage", "*")); 01224 else 01225 DEBUGMSG(("read_config_usage", " ")); 01226 } 01227 if (ltmp->help) { 01228 snmp_log(LOG_INFO, "%s%s%-24s %s\n", lead, lead, 01229 ltmp->config_token, ltmp->help); 01230 } else { 01231 DEBUGIF("read_config_usage") { 01232 snmp_log(LOG_INFO, "%s%s%-24s [NO HELP]\n", lead, lead, 01233 ltmp->config_token); 01234 } 01235 } 01236 } 01237 } 01238 } 01239 01253 void 01254 read_config_store(const char *type, const char *line) 01255 { 01256 #ifdef NETSNMP_PERSISTENT_DIRECTORY 01257 char file[512], *filep; 01258 FILE *fout; 01259 #ifdef NETSNMP_PERSISTENT_MASK 01260 mode_t oldmask; 01261 #endif 01262 01263 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01264 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01265 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01266 NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD)) return; 01267 01268 /* 01269 * store configuration directives in the following order of preference: 01270 * 1. ENV variable SNMP_PERSISTENT_FILE 01271 * 2. configured <NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf 01272 */ 01273 if ((filep = netsnmp_getenv("SNMP_PERSISTENT_FILE")) == NULL) { 01274 snprintf(file, sizeof(file), 01275 "%s/%s.conf", get_persistent_directory(), type); 01276 file[ sizeof(file)-1 ] = 0; 01277 filep = file; 01278 } 01279 #ifdef NETSNMP_PERSISTENT_MASK 01280 oldmask = umask(NETSNMP_PERSISTENT_MASK); 01281 #endif 01282 if (mkdirhier(filep, NETSNMP_AGENT_DIRECTORY_MODE, 1)) { 01283 snmp_log(LOG_ERR, 01284 "Failed to create the persistent directory for %s\n", 01285 file); 01286 } 01287 if ((fout = fopen(filep, "a")) != NULL) { 01288 fprintf(fout, "%s", line); 01289 if (line[strlen(line)] != '\n') 01290 fprintf(fout, "\n"); 01291 DEBUGMSGTL(("read_config", "storing: %s\n", line)); 01292 fclose(fout); 01293 } else { 01294 snmp_log(LOG_ERR, "read_config_store open failure on %s\n", filep); 01295 } 01296 #ifdef NETSNMP_PERSISTENT_MASK 01297 umask(oldmask); 01298 #endif 01299 01300 #endif 01301 } /* end read_config_store() */ 01302 01303 void 01304 read_app_config_store(const char *line) 01305 { 01306 read_config_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01307 NETSNMP_DS_LIB_APPTYPE), line); 01308 } 01309 01310 01311 01312 01313 /*******************************************************************-o-****** 01314 * snmp_save_persistent 01315 * 01316 * Parameters: 01317 * *type 01318 * 01319 * 01320 * Save the file "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy 01321 * called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an 01322 * incrementing number on each call, but less than NETSNMP_MAX_PERSISTENT_BACKUPS. 01323 * 01324 * Should be called just before all persistent information is supposed to be 01325 * written to move aside the existing persistent cache. 01326 * snmp_clean_persistent should then be called afterward all data has been 01327 * saved to remove these backup files. 01328 * 01329 * Note: on an rename error, the files are removed rather than saved. 01330 * 01331 */ 01332 void 01333 snmp_save_persistent(const char *type) 01334 { 01335 char file[512], fileold[SPRINT_MAX_LEN]; 01336 struct stat statbuf; 01337 int j; 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_PERSISTENT_SAVE)) return; 01343 01344 DEBUGMSGTL(("snmp_save_persistent", "saving %s files...\n", type)); 01345 snprintf(file, sizeof(file), 01346 "%s/%s.conf", get_persistent_directory(), type); 01347 file[ sizeof(file)-1 ] = 0; 01348 if (stat(file, &statbuf) == 0) { 01349 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01350 snprintf(fileold, sizeof(fileold), 01351 "%s/%s.%d.conf", get_persistent_directory(), type, j); 01352 fileold[ sizeof(fileold)-1 ] = 0; 01353 if (stat(fileold, &statbuf) != 0) { 01354 DEBUGMSGTL(("snmp_save_persistent", 01355 " saving old config file: %s -> %s.\n", file, 01356 fileold)); 01357 if (rename(file, fileold)) { 01358 snmp_log(LOG_ERR, "Cannot rename %s to %s\n", file, fileold); 01359 /* moving it failed, try nuking it, as leaving 01360 * it around is very bad. */ 01361 if (unlink(file) == -1) 01362 snmp_log(LOG_ERR, "Cannot unlink %s\n", file); 01363 } 01364 break; 01365 } 01366 } 01367 } 01368 /* 01369 * save a warning header to the top of the new file 01370 */ 01371 snprintf(fileold, sizeof(fileold), 01372 "#\n# net-snmp (or ucd-snmp) persistent data file.\n#\n############################################################################\n# STOP STOP STOP STOP STOP STOP STOP STOP STOP \n#\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# Please save normal configuration tokens for %s in SNMPCONFPATH/%s.conf.\n# Only \"createUser\" tokens should be placed here by %s administrators.\n# (Did I mention: do not edit this file?)\n#\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", 01373 type, type, type); 01374 fileold[ sizeof(fileold)-1 ] = 0; 01375 read_config_store(type, fileold); 01376 } 01377 01378 01379 /*******************************************************************-o-****** 01380 * snmp_clean_persistent 01381 * 01382 * Parameters: 01383 * *type 01384 * 01385 * 01386 * Unlink all backup files called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf". 01387 * 01388 * Should be called just after we successfull dumped the last of the 01389 * persistent data, to remove the backup copies of previous storage dumps. 01390 * 01391 * XXX Worth overwriting with random bytes first? This would 01392 * ensure that the data is destroyed, even a buffer containing the 01393 * data persists in memory or swap. Only important if secrets 01394 * will be stored here. 01395 */ 01396 void 01397 snmp_clean_persistent(const char *type) 01398 { 01399 char file[512]; 01400 struct stat statbuf; 01401 int j; 01402 01403 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01404 NETSNMP_DS_LIB_DONT_PERSIST_STATE) 01405 || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01406 NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE)) return; 01407 01408 DEBUGMSGTL(("snmp_clean_persistent", "cleaning %s files...\n", type)); 01409 snprintf(file, sizeof(file), 01410 "%s/%s.conf", get_persistent_directory(), type); 01411 file[ sizeof(file)-1 ] = 0; 01412 if (stat(file, &statbuf) == 0) { 01413 for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) { 01414 snprintf(file, sizeof(file), 01415 "%s/%s.%d.conf", get_persistent_directory(), type, j); 01416 file[ sizeof(file)-1 ] = 0; 01417 if (stat(file, &statbuf) == 0) { 01418 DEBUGMSGTL(("snmp_clean_persistent", 01419 " removing old config file: %s\n", file)); 01420 if (unlink(file) == -1) 01421 snmp_log(LOG_ERR, "Cannot unlink %s\n", file); 01422 } 01423 } 01424 } 01425 } 01426 01427 01428 01429 01430 /* 01431 * config_perror: prints a warning string associated with a file and 01432 * line number of a .conf file and increments the error count. 01433 */ 01434 static void 01435 config_vlog(int level, const char *levelmsg, const char *str, va_list args) 01436 { 01437 char tmpbuf[256]; 01438 char* buf = tmpbuf; 01439 int len = snprintf(tmpbuf, sizeof(tmpbuf), "%s: line %d: %s: %s\n", 01440 curfilename, linecount, levelmsg, str); 01441 if (len >= sizeof(tmpbuf)) { 01442 buf = (char*)malloc(len + 1); 01443 sprintf(buf, "%s: line %d: %s: %s\n", 01444 curfilename, linecount, levelmsg, str); 01445 } 01446 snmp_vlog(level, buf, args); 01447 if (buf != tmpbuf) 01448 free(buf); 01449 } 01450 01451 void 01452 netsnmp_config_error(const char *str, ...) 01453 { 01454 va_list args; 01455 va_start(args, str); 01456 config_vlog(LOG_ERR, "Error", str, args); 01457 va_end(args); 01458 config_errors++; 01459 } 01460 01461 void 01462 netsnmp_config_warn(const char *str, ...) 01463 { 01464 va_list args; 01465 va_start(args, str); 01466 config_vlog(LOG_WARNING, "Warning", str, args); 01467 va_end(args); 01468 } 01469 01470 void 01471 config_perror(const char *str) 01472 { 01473 netsnmp_config_error("%s", str); 01474 } 01475 01476 void 01477 config_pwarn(const char *str) 01478 { 01479 netsnmp_config_warn("%s", str); 01480 } 01481 01482 /* 01483 * skip all white spaces and return 1 if found something either end of 01484 * line or a comment character 01485 */ 01486 char * 01487 skip_white(char *ptr) 01488 { 01489 if (ptr == NULL) 01490 return (NULL); 01491 while (*ptr != 0 && isspace((unsigned char)*ptr)) 01492 ptr++; 01493 if (*ptr == 0 || *ptr == '#') 01494 return (NULL); 01495 return (ptr); 01496 } 01497 01498 char * 01499 skip_not_white(char *ptr) 01500 { 01501 if (ptr == NULL) 01502 return (NULL); 01503 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 01504 ptr++; 01505 if (*ptr == 0 || *ptr == '#') 01506 return (NULL); 01507 return (ptr); 01508 } 01509 01510 char * 01511 skip_token(char *ptr) 01512 { 01513 ptr = skip_white(ptr); 01514 ptr = skip_not_white(ptr); 01515 ptr = skip_white(ptr); 01516 return (ptr); 01517 } 01518 01519 /* 01520 * copy_word 01521 * copies the next 'token' from 'from' into 'to', maximum len-1 characters. 01522 * currently a token is anything seperate by white space 01523 * or within quotes (double or single) (i.e. "the red rose" 01524 * is one token, \"the red rose\" is three tokens) 01525 * a '\' character will allow a quote character to be treated 01526 * as a regular character 01527 * It returns a pointer to first non-white space after the end of the token 01528 * being copied or to 0 if we reach the end. 01529 * Note: Partially copied words (greater than len) still returns a !NULL ptr 01530 * Note: partially copied words are, however, null terminated. 01531 */ 01532 01533 char * 01534 copy_nword(char *from, char *to, int len) 01535 { 01536 char quote; 01537 if (!from || !to) 01538 return NULL; 01539 if ((*from == '\"') || (*from == '\'')) { 01540 quote = *(from++); 01541 while ((*from != quote) && (*from != 0)) { 01542 if ((*from == '\\') && (*(from + 1) != 0)) { 01543 if (len > 0) { /* don't copy beyond len bytes */ 01544 *to++ = *(from + 1); 01545 if (--len == 0) 01546 *(to - 1) = '\0'; /* null protect the last spot */ 01547 } 01548 from = from + 2; 01549 } else { 01550 if (len > 0) { /* don't copy beyond len bytes */ 01551 *to++ = *from++; 01552 if (--len == 0) 01553 *(to - 1) = '\0'; /* null protect the last spot */ 01554 } else 01555 from++; 01556 } 01557 } 01558 if (*from == 0) { 01559 DEBUGMSGTL(("read_config_copy_word", 01560 "no end quote found in config string\n")); 01561 } else 01562 from++; 01563 } else { 01564 while (*from != 0 && !isspace(*from)) { 01565 if ((*from == '\\') && (*(from + 1) != 0)) { 01566 if (len > 0) { /* don't copy beyond len bytes */ 01567 *to++ = *(from + 1); 01568 if (--len == 0) 01569 *(to - 1) = '\0'; /* null protect the last spot */ 01570 } 01571 from = from + 2; 01572 } else { 01573 if (len > 0) { /* don't copy beyond len bytes */ 01574 *to++ = *from++; 01575 if (--len == 0) 01576 *(to - 1) = '\0'; /* null protect the last spot */ 01577 } else 01578 from++; 01579 } 01580 } 01581 } 01582 if (len > 0) 01583 *to = 0; 01584 from = skip_white(from); 01585 return (from); 01586 } /* copy_word */ 01587 01588 /* 01589 * copy_word 01590 * copies the next 'token' from 'from' into 'to'. 01591 * currently a token is anything seperate by white space 01592 * or within quotes (double or single) (i.e. "the red rose" 01593 * is one token, \"the red rose\" is three tokens) 01594 * a '\' character will allow a quote character to be treated 01595 * as a regular character 01596 * It returns a pointer to first non-white space after the end of the token 01597 * being copied or to 0 if we reach the end. 01598 */ 01599 01600 static int have_warned = 0; 01601 char * 01602 copy_word(char *from, char *to) 01603 { 01604 if (!have_warned) { 01605 snmp_log(LOG_INFO, 01606 "copy_word() called. Use copy_nword() instead.\n"); 01607 have_warned = 1; 01608 } 01609 return copy_nword(from, to, SPRINT_MAX_LEN); 01610 } /* copy_word */ 01611 01612 /* 01613 * read_config_save_octet_string(): saves an octet string as a length 01614 * followed by a string of hex 01615 */ 01616 char * 01617 read_config_save_octet_string(char *saveto, u_char * str, size_t len) 01618 { 01619 int i; 01620 u_char *cp; 01621 01622 /* 01623 * is everything easily printable 01624 */ 01625 for (i = 0, cp = str; i < (int) len && cp && 01626 (isalpha(*cp) || isdigit(*cp) || *cp == ' '); cp++, i++); 01627 01628 if (len != 0 && i == (int) len) { 01629 *saveto++ = '"'; 01630 memcpy(saveto, str, len); 01631 saveto += len; 01632 *saveto++ = '"'; 01633 *saveto = '\0'; 01634 } else { 01635 if (str != NULL) { 01636 sprintf(saveto, "0x"); 01637 saveto += 2; 01638 for (i = 0; i < (int) len; i++) { 01639 sprintf(saveto, "%02x", str[i]); 01640 saveto = saveto + 2; 01641 } 01642 } else { 01643 sprintf(saveto, "\"\""); 01644 saveto += 2; 01645 } 01646 } 01647 return saveto; 01648 } 01649 01650 /* 01651 * read_config_read_octet_string(): reads an octet string that was 01652 * saved by the read_config_save_octet_string() function 01653 */ 01654 char * 01655 read_config_read_octet_string(char *readfrom, u_char ** str, size_t * len) 01656 { 01657 u_char *cptr = NULL; 01658 char *cptr1; 01659 u_int tmp; 01660 int i; 01661 size_t ilen; 01662 01663 if (readfrom == NULL || str == NULL) 01664 return NULL; 01665 01666 if (strncasecmp(readfrom, "0x", 2) == 0) { 01667 /* 01668 * A hex string submitted. How long? 01669 */ 01670 readfrom += 2; 01671 cptr1 = skip_not_white(readfrom); 01672 if (cptr1) 01673 ilen = (cptr1 - readfrom); 01674 else 01675 ilen = strlen(readfrom); 01676 01677 if (ilen % 2) { 01678 snmp_log(LOG_WARNING,"invalid hex string: wrong length\n"); 01679 DEBUGMSGTL(("read_config_read_octet_string", 01680 "invalid hex string: wrong length")); 01681 return NULL; 01682 } 01683 ilen = ilen / 2; 01684 01685 /* 01686 * malloc data space if needed (+1 for good measure) 01687 */ 01688 if (*str == NULL) { 01689 if ((cptr = (u_char *) malloc(ilen + 1)) == NULL) { 01690 return NULL; 01691 } 01692 *str = cptr; 01693 } else { 01694 /* 01695 * don't require caller to have +1 for good measure, and 01696 * bail if not enough space. 01697 */ 01698 if (ilen > *len) { 01699 snmp_log(LOG_WARNING,"buffer too small to read octet string (%lu < %lu)\n", 01700 (unsigned long)*len, (unsigned long)ilen); 01701 DEBUGMSGTL(("read_config_read_octet_string", 01702 "buffer too small (%lu < %lu)", (unsigned long)*len, (unsigned long)ilen)); 01703 cptr1 = skip_not_white(readfrom); 01704 return skip_white(cptr1); 01705 } 01706 cptr = *str; 01707 } 01708 *len = ilen; 01709 01710 /* 01711 * copy validated data 01712 */ 01713 for (i = 0; i < (int) *len; i++) { 01714 if (1 == sscanf(readfrom, "%2x", &tmp)) 01715 *cptr++ = (u_char) tmp; 01716 else { 01717 /* 01718 * we may lose memory, but don't know caller's buffer XX free(cptr); 01719 */ 01720 return (NULL); 01721 } 01722 readfrom += 2; 01723 } 01724 /* 01725 * only null terminate if we have the space 01726 */ 01727 if (ilen > *len) { 01728 ilen = *len-1; 01729 *cptr++ = '\0'; 01730 } 01731 readfrom = skip_white(readfrom); 01732 } else { 01733 /* 01734 * Normal string 01735 */ 01736 01737 /* 01738 * malloc string space if needed (including NULL terminator) 01739 */ 01740 if (*str == NULL) { 01741 char buf[SNMP_MAXBUF]; 01742 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 01743 01744 *len = strlen(buf); 01745 if ((cptr = (u_char *) malloc(*len + 1)) == NULL) 01746 return NULL; 01747 *str = cptr; 01748 if (cptr) { 01749 memcpy(cptr, buf, *len + 1); 01750 } 01751 } else { 01752 readfrom = copy_nword(readfrom, (char *) *str, *len); 01753 *len = strlen((char *) *str); 01754 } 01755 } 01756 01757 return readfrom; 01758 } 01759 01760 01761 /* 01762 * read_config_save_objid(): saves an objid as a numerical string 01763 */ 01764 char * 01765 read_config_save_objid(char *saveto, oid * objid, size_t len) 01766 { 01767 int i; 01768 01769 if (len == 0) { 01770 strcat(saveto, "NULL"); 01771 saveto += strlen(saveto); 01772 return saveto; 01773 } 01774 01775 /* 01776 * in case len=0, this makes it easier to read it back in 01777 */ 01778 for (i = 0; i < (int) len; i++) { 01779 sprintf(saveto, ".%ld", objid[i]); 01780 saveto += strlen(saveto); 01781 } 01782 return saveto; 01783 } 01784 01785 /* 01786 * read_config_read_objid(): reads an objid from a format saved by the above 01787 */ 01788 char * 01789 read_config_read_objid(char *readfrom, oid ** objid, size_t * len) 01790 { 01791 01792 if (objid == NULL || readfrom == NULL || len == NULL) 01793 return NULL; 01794 01795 if (*objid == NULL) { 01796 *len = 0; 01797 if ((*objid = (oid *) malloc(MAX_OID_LEN * sizeof(oid))) == NULL) 01798 return NULL; 01799 *len = MAX_OID_LEN; 01800 } 01801 01802 if (strncmp(readfrom, "NULL", 4) == 0) { 01803 /* 01804 * null length oid 01805 */ 01806 *len = 0; 01807 } else { 01808 /* 01809 * qualify the string for read_objid 01810 */ 01811 char buf[SPRINT_MAX_LEN]; 01812 copy_nword(readfrom, buf, sizeof(buf)); 01813 01814 if (!read_objid(buf, *objid, len)) { 01815 DEBUGMSGTL(("read_config_read_objid", "Invalid OID")); 01816 *len = 0; 01817 return NULL; 01818 } 01819 } 01820 01821 readfrom = skip_token(readfrom); 01822 return readfrom; 01823 } 01824 01850 char * 01851 read_config_read_data(int type, char *readfrom, void *dataptr, 01852 size_t * len) 01853 { 01854 int *intp; 01855 char **charpp; 01856 oid **oidpp; 01857 unsigned int *uintp; 01858 01859 if (dataptr && readfrom) 01860 switch (type) { 01861 case ASN_INTEGER: 01862 intp = (int *) dataptr; 01863 *intp = atoi(readfrom); 01864 readfrom = skip_token(readfrom); 01865 return readfrom; 01866 01867 case ASN_TIMETICKS: 01868 case ASN_UNSIGNED: 01869 uintp = (unsigned int *) dataptr; 01870 *uintp = strtoul(readfrom, NULL, 0); 01871 readfrom = skip_token(readfrom); 01872 return readfrom; 01873 01874 case ASN_IPADDRESS: 01875 intp = (int *) dataptr; 01876 *intp = inet_addr(readfrom); 01877 if ((*intp == -1) && 01878 (strncmp(readfrom, "255.255.255.255", 15) != 0)) 01879 return NULL; 01880 readfrom = skip_token(readfrom); 01881 return readfrom; 01882 01883 case ASN_OCTET_STR: 01884 case ASN_BIT_STR: 01885 charpp = (char **) dataptr; 01886 return read_config_read_octet_string(readfrom, 01887 (u_char **) charpp, len); 01888 01889 case ASN_OBJECT_ID: 01890 oidpp = (oid **) dataptr; 01891 return read_config_read_objid(readfrom, oidpp, len); 01892 01893 default: 01894 DEBUGMSGTL(("read_config_read_data", "Fail: Unknown type: %d", 01895 type)); 01896 return NULL; 01897 } 01898 return NULL; 01899 } 01900 01901 /* 01902 * read_config_read_memory(): 01903 * 01904 * similar to read_config_read_data, but expects a generic memory 01905 * pointer rather than a specific type of pointer. Len is expected to 01906 * be the amount of available memory. 01907 */ 01908 char * 01909 read_config_read_memory(int type, char *readfrom, 01910 char *dataptr, size_t * len) 01911 { 01912 int *intp; 01913 unsigned int *uintp; 01914 char buf[SPRINT_MAX_LEN]; 01915 01916 if (!dataptr || !readfrom) 01917 return NULL; 01918 01919 switch (type) { 01920 case ASN_INTEGER: 01921 if (*len < sizeof(int)) 01922 return NULL; 01923 intp = (int *) dataptr; 01924 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 01925 *intp = atoi(buf); 01926 *len = sizeof(int); 01927 return readfrom; 01928 01929 case ASN_COUNTER: 01930 case ASN_TIMETICKS: 01931 case ASN_UNSIGNED: 01932 if (*len < sizeof(unsigned int)) 01933 return NULL; 01934 uintp = (unsigned int *) dataptr; 01935 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 01936 *uintp = strtoul(buf, NULL, 0); 01937 *len = sizeof(unsigned int); 01938 return readfrom; 01939 01940 case ASN_IPADDRESS: 01941 if (*len < sizeof(int)) 01942 return NULL; 01943 intp = (int *) dataptr; 01944 readfrom = copy_nword(readfrom, buf, sizeof(buf)); 01945 *intp = inet_addr(buf); 01946 if ((*intp == -1) && (strcmp(buf, "255.255.255.255") != 0)) 01947 return NULL; 01948 *len = sizeof(int); 01949 return readfrom; 01950 01951 case ASN_OCTET_STR: 01952 case ASN_BIT_STR: 01953 case ASN_PRIV_IMPLIED_OCTET_STR: 01954 return read_config_read_octet_string(readfrom, 01955 (u_char **) & dataptr, len); 01956 01957 case ASN_PRIV_IMPLIED_OBJECT_ID: 01958 case ASN_OBJECT_ID: 01959 readfrom = 01960 read_config_read_objid(readfrom, (oid **) & dataptr, len); 01961 *len *= sizeof(oid); 01962 return readfrom; 01963 01964 case ASN_COUNTER64: 01965 if (*len < sizeof(U64)) 01966 return NULL; 01967 *len = sizeof(U64); 01968 read64((U64 *) dataptr, readfrom); 01969 readfrom = skip_token(readfrom); 01970 return readfrom; 01971 } 01972 01973 DEBUGMSGTL(("read_config_read_memory", "Fail: Unknown type: %d", type)); 01974 return NULL; 01975 } 01976 02004 char * 02005 read_config_store_data(int type, char *storeto, void *dataptr, size_t * len) 02006 { 02007 return read_config_store_data_prefix(' ', type, storeto, dataptr, 02008 (len ? *len : 0)); 02009 } 02010 02011 char * 02012 read_config_store_data_prefix(char prefix, int type, char *storeto, 02013 void *dataptr, size_t len) 02014 { 02015 int *intp; 02016 u_char **charpp; 02017 unsigned int *uintp; 02018 struct in_addr in; 02019 oid **oidpp; 02020 02021 if (dataptr && storeto) 02022 switch (type) { 02023 case ASN_INTEGER: 02024 intp = (int *) dataptr; 02025 sprintf(storeto, "%c%d", prefix, *intp); 02026 return (storeto + strlen(storeto)); 02027 02028 case ASN_TIMETICKS: 02029 case ASN_UNSIGNED: 02030 uintp = (unsigned int *) dataptr; 02031 sprintf(storeto, "%c%u", prefix, *uintp); 02032 return (storeto + strlen(storeto)); 02033 02034 case ASN_IPADDRESS: 02035 in.s_addr = *(unsigned int *) dataptr; 02036 sprintf(storeto, "%c%s", prefix, inet_ntoa(in)); 02037 return (storeto + strlen(storeto)); 02038 02039 case ASN_OCTET_STR: 02040 case ASN_BIT_STR: 02041 *storeto++ = prefix; 02042 charpp = (u_char **) dataptr; 02043 return read_config_save_octet_string(storeto, *charpp, len); 02044 02045 case ASN_OBJECT_ID: 02046 *storeto++ = prefix; 02047 oidpp = (oid **) dataptr; 02048 return read_config_save_objid(storeto, *oidpp, len); 02049 02050 default: 02051 DEBUGMSGTL(("read_config_store_data_prefix", 02052 "Fail: Unknown type: %d", type)); 02053 return NULL; 02054 } 02055 return NULL; 02056 }
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.