Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

read_config.c

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 }

Generated on Fri Dec 30 13:47:46 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


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.