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