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