Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/read_config.c
Line
Count
Source
1
/*
2
 * read_config.c
3
 */
4
/* Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 */
8
/*
9
 * Portions of this file are copyrighted by:
10
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
11
 * Use is subject to license terms specified in the COPYING file
12
 * distributed with the Net-SNMP package.
13
 */
14
15
/** @defgroup read_config parsing various configuration files at run time
16
 *  @ingroup library
17
 *
18
 * The read_config related functions are a fairly extensible  system  of
19
 * parsing various configuration files at the run time.
20
 *
21
 * The idea is that the calling application is able to register
22
 * handlers for certain tokens specified in certain types
23
 * of files.  The read_configs function can then be  called
24
 * to  look  for all the files that it has registrations for,
25
 * find the first word on each line, and pass  the  remainder
26
 * to the appropriately registered handler.
27
 *
28
 * For persistent configuration storage you will need to use the
29
 * read_config_read_data, read_config_store, and read_config_store_data
30
 * APIs in conjunction with first registering a
31
 * callback so when the agent shuts down for whatever reason data is written
32
 * to your configuration files.  The following explains in more detail the
33
 * sequence to make this happen.
34
 *
35
 * This is the callback registration API, you need to call this API with
36
 * the appropriate parameters in order to configure persistent storage needs.
37
 *
38
 *        int snmp_register_callback(int major, int minor,
39
 *                                   SNMPCallback *new_callback,
40
 *                                   void *arg);
41
 *
42
 * You will need to set major to SNMP_CALLBACK_LIBRARY, minor to
43
 * SNMP_CALLBACK_STORE_DATA. arg is whatever you want.
44
 *
45
 * Your callback function's prototype is:
46
 * int     (SNMPCallback) (int majorID, int minorID, void *serverarg,
47
 *                        void *clientarg);
48
 *
49
 * The majorID, minorID and clientarg are what you passed in the callback
50
 * registration above.  When the callback is called you have to essentially
51
 * transfer all your state from memory to disk. You do this by generating
52
 * configuration lines into a buffer.  The lines are of the form token
53
 * followed by token parameters.
54
 * 
55
 * Finally storing is done using read_config_store(type, buffer);
56
 * type is the application name this can be obtained from:
57
 *
58
 * netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE);
59
 *
60
 * Now, reading back the data: This is done by registering a config handler
61
 * for your token using the register_config_handler function. Your
62
 * handler will be invoked and you can parse in the data using the
63
 * read_config_read APIs.
64
 *
65
 *  @{
66
 */
67
#include <net-snmp/net-snmp-config.h>
68
#include <net-snmp/net-snmp-features.h>
69
70
#include <stdio.h>
71
#include <ctype.h>
72
#ifdef HAVE_STDLIB_H
73
#include <stdlib.h>
74
#endif
75
#ifdef HAVE_STRING_H
76
#include <string.h>
77
#else
78
#include <strings.h>
79
#endif
80
#ifdef HAVE_UNISTD_H
81
#include <unistd.h>
82
#endif
83
#include <sys/types.h>
84
#ifdef HAVE_SYS_PARAM_H
85
#include <sys/param.h>
86
#endif
87
#ifdef TIME_WITH_SYS_TIME
88
# include <sys/time.h>
89
# include <time.h>
90
#else
91
# ifdef HAVE_SYS_TIME_H
92
#  include <sys/time.h>
93
# else
94
#  include <time.h>
95
# endif
96
#endif
97
#ifdef HAVE_SYS_STAT_H
98
#include <sys/stat.h>
99
#endif
100
#ifdef HAVE_NETINET_IN_H
101
#include <netinet/in.h>
102
#endif
103
#ifdef HAVE_ARPA_INET_H
104
#include <arpa/inet.h>
105
#endif
106
#ifdef HAVE_SYS_SELECT_H
107
#include <sys/select.h>
108
#endif
109
#ifdef HAVE_SYS_SOCKET_H
110
#include <sys/socket.h>
111
#endif
112
#ifdef HAVE_NETDB_H
113
#include <netdb.h>
114
#endif
115
#include <errno.h>
116
#ifdef HAVE_IO_H
117
#include <io.h>
118
#endif
119
120
#ifdef HAVE_DIRENT_H
121
#include <dirent.h>
122
#endif
123
124
#include <net-snmp/types.h>
125
#include <net-snmp/output_api.h>
126
#include <net-snmp/config_api.h>
127
#include <net-snmp/library/read_config.h>       /* for "internal" definitions */
128
#include <net-snmp/utilities.h>
129
130
#include <net-snmp/library/mib.h>
131
#include <net-snmp/library/parse.h>
132
#include <net-snmp/library/snmp_api.h>
133
#include <net-snmp/library/callback.h>
134
135
netsnmp_feature_child_of(read_config_all, libnetsnmp);
136
137
netsnmp_feature_child_of(unregister_app_config_handler, read_config_all);
138
netsnmp_feature_child_of(read_config_register_app_prenetsnmp_mib_handler, netsnmp_unused);
139
140
static int      config_errors;
141
static int      config_warnings;
142
143
struct config_files *config_files = NULL;
144
145
146
static struct config_line *
147
internal_register_config_handler(const char *type_param,
148
         const char *token,
149
         void (*parser1) (const char *, char *),
150
         void (*parser2) (const char *, const char *),
151
         void (*releaser) (void), const char *help,
152
         int when)
153
27.5k
{
154
27.5k
    struct config_files **ctmp = &config_files;
155
27.5k
    struct config_line  **ltmp;
156
27.5k
    const char           *type = type_param;
157
158
27.5k
    if (type == NULL || *type == '\0') {
159
0
        type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
160
0
             NETSNMP_DS_LIB_APPTYPE);
161
0
    }
162
163
    /*
164
     * Handle multiple types (recursively)
165
     */
166
27.5k
    if (strchr(type, ':')) {
167
0
        struct config_line *ltmp2 = NULL;
168
0
        char                buf[STRINGMAX];
169
0
        char               *cptr = buf;
170
171
0
        strlcpy(buf, type, STRINGMAX);
172
0
        while (cptr) {
173
0
            char* c = cptr;
174
0
            cptr = strchr(cptr, ':');
175
0
            if(cptr) {
176
0
                *cptr = '\0';
177
0
                ++cptr;
178
0
            }
179
0
            ltmp2 = internal_register_config_handler(c, token, parser1, parser2,
180
0
                                                     releaser, help, when);
181
0
        }
182
0
        return ltmp2;
183
0
    }
184
    
185
    /*
186
     * Find type in current list  -OR-  create a new file type.
187
     */
188
27.5k
    while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
189
0
        ctmp = &((*ctmp)->next);
190
0
    }
191
192
27.5k
    if (*ctmp == NULL) {
193
1
        *ctmp = (struct config_files *)
194
1
            calloc(1, sizeof(struct config_files));
195
1
        if (!*ctmp) {
196
0
            return NULL;
197
0
        }
198
199
1
        (*ctmp)->fileHeader = strdup(type);
200
1
        if (!(*ctmp)->fileHeader) {
201
0
            free(*ctmp);
202
0
            *ctmp = NULL;
203
0
            return NULL;
204
0
        }
205
1
        DEBUGMSGTL(("9:read_config:type", "new type %s\n", type));
206
1
    }
207
208
27.5k
    DEBUGMSGTL(("9:read_config:register_handler", "registering %s %s\n",
209
27.5k
                type, token));
210
    /*
211
     * Find parser type in current list  -OR-  create a new
212
     * line parser entry.
213
     */
214
27.5k
    ltmp = &((*ctmp)->start);
215
216
316k
    while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) {
217
288k
        ltmp = &((*ltmp)->next);
218
288k
    }
219
220
27.5k
    if (*ltmp == NULL) {
221
22
        *ltmp = (struct config_line *)
222
22
            calloc(1, sizeof(struct config_line));
223
22
        if (!*ltmp) {
224
0
            return NULL;
225
0
        }
226
227
22
        (*ltmp)->config_time = when;
228
22
        (*ltmp)->config_token = strdup(token);
229
22
        if (!(*ltmp)->config_token) {
230
0
            free(*ltmp);
231
0
            *ltmp = NULL;
232
0
            return NULL;
233
0
        }
234
235
22
        if (help != NULL)
236
22
            (*ltmp)->help = strdup(help);
237
22
    }
238
239
    /*
240
     * Add/Replace the parse/free functions for the given line type
241
     * in the given file type.
242
     */
243
27.5k
    (*ltmp)->parse_line1 = parser1;
244
27.5k
    (*ltmp)->parse_line2 = parser2;
245
27.5k
    (*ltmp)->free_func = releaser;
246
247
27.5k
    return (*ltmp);
248
249
27.5k
}                               /* end register_config_handler() */
250
251
struct config_line *
252
register_prenetsnmp_mib_handler(const char *type,
253
                                const char *token,
254
                                void (*parser) (const char *, char *),
255
                                void (*releaser) (void), const char *help)
256
26.2k
{
257
26.2k
    return internal_register_config_handler(type, token, parser, NULL, releaser,
258
26.2k
              help, PREMIB_CONFIG);
259
26.2k
}
260
261
#ifndef NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_APP_PRENETSNMP_MIB_HANDLER
262
struct config_line *
263
register_app_prenetsnmp_mib_handler(const char *token,
264
                                    void (*parser) (const char *, char *),
265
                                    void (*releaser) (void),
266
                                    const char *help)
267
0
{
268
0
    return (register_prenetsnmp_mib_handler
269
0
            (NULL, token, parser, releaser, help));
270
0
}
271
#endif /* NETSNMP_FEATURE_REMOVE_READ_CONFIG_REGISTER_APP_PRENETSNMP_MIB_HANDLER */
272
273
/**
274
 * register_config_handler registers handlers for certain tokens specified in
275
 * certain types of files.
276
 *
277
 * Allows a module writer use/register multiple configuration files based off
278
 * of the type parameter.  A module writer may want to set up multiple
279
 * configuration files to separate out related tasks/variables or just for
280
 * management of where to put tokens as the module or modules get more complex
281
 * in regard to handling token registrations.
282
 *
283
 * @param type     the configuration file used, e.g., if snmp.conf is the
284
 *                 file where the token is located use "snmp" here.
285
 *                 Multiple colon separated tokens might be used.
286
 *                 If NULL or "" then the configuration file used will be
287
 *                 \<application\>.conf.
288
 *
289
 * @param token    the token being parsed from the file.  Must be non-NULL.
290
 *
291
 * @param parser   the handler function pointer that use  the specified
292
 *                 token and the rest of the line to do whatever is required
293
 *                 Should be non-NULL in order to make use of this API.
294
 *
295
 * @param releaser if non-NULL, the function specified is called when
296
 *                 unregistering config handler or when configuration
297
 *                 files are re-read.
298
 *                 This function should free any resources allocated by
299
 *                 the token handler function.
300
 *
301
 * @param help     if non-NULL, used to display help information on the
302
 *                 expected arguments after the token.
303
 *
304
 * @return Pointer to a new config line entry or NULL on error.
305
 */
306
struct config_line *
307
register_config_handler(const char *type,
308
      const char *token,
309
      void (*parser) (const char *, char *),
310
      void (*releaser) (void), const char *help)
311
1.25k
{
312
1.25k
    return internal_register_config_handler(type, token, parser, NULL, releaser,
313
1.25k
              help, NORMAL_CONFIG);
314
1.25k
}
315
316
struct config_line *
317
register_const_config_handler(const char *type,
318
                              const char *token,
319
                              void (*parser) (const char *, const char *),
320
                              void (*releaser) (void), const char *help)
321
0
{
322
0
    return internal_register_config_handler(type, token, NULL, parser, releaser,
323
0
              help, NORMAL_CONFIG);
324
0
}
325
326
struct config_line *
327
register_app_config_handler(const char *token,
328
                            void (*parser) (const char *, char *),
329
                            void (*releaser) (void), const char *help)
330
0
{
331
0
    return register_config_handler(NULL, token, parser, releaser, help);
332
0
}
333
334
struct config_line *
335
register_const_app_config_handler(const char *token,
336
                                  void (*parser) (const char *, const char *),
337
                                  void (*releaser) (void), const char *help)
338
0
{
339
0
    return register_const_config_handler(NULL, token, parser, releaser, help);
340
0
}
341
342
343
/**
344
 * uregister_config_handler un-registers handlers given a specific type_param
345
 * and token.
346
 *
347
 * @param type_param the configuration file used where the token is located.
348
 *                   Used to lookup the config file entry
349
 * 
350
 * @param token      the token that is being unregistered
351
 *
352
 * @return void
353
 */
354
void
355
unregister_config_handler(const char *type_param, const char *token)
356
0
{
357
0
    struct config_files **ctmp = &config_files;
358
0
    struct config_line  **ltmp;
359
0
    const char           *type = type_param;
360
361
0
    if (type == NULL || *type == '\0') {
362
0
        type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
363
0
             NETSNMP_DS_LIB_APPTYPE);
364
0
    }
365
366
    /*
367
     * Handle multiple types (recursively)
368
     */
369
0
    if (strchr(type, ':')) {
370
0
        char                buf[STRINGMAX];
371
0
        char               *cptr = buf;
372
373
0
        strlcpy(buf, type, STRINGMAX);
374
0
        while (cptr) {
375
0
            char* c = cptr;
376
0
            cptr = strchr(cptr, ':');
377
0
            if(cptr) {
378
0
                *cptr = '\0';
379
0
                ++cptr;
380
0
            }
381
0
            unregister_config_handler(c, token);
382
0
        }
383
0
        return;
384
0
    }
385
    
386
    /*
387
     * find type in current list 
388
     */
389
0
    while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) {
390
0
        ctmp = &((*ctmp)->next);
391
0
    }
392
393
0
    if (*ctmp == NULL) {
394
        /*
395
         * Not found, return. 
396
         */
397
0
        return;
398
0
    }
399
400
0
    ltmp = &((*ctmp)->start);
401
0
    if (*ltmp == NULL) {
402
        /*
403
         * Not found, return. 
404
         */
405
0
        return;
406
0
    }
407
0
    if (strcmp((*ltmp)->config_token, token) == 0) {
408
        /*
409
         * found it at the top of the list 
410
         */
411
0
        struct config_line *ltmp2 = (*ltmp)->next;
412
0
        if ((*ltmp)->free_func)
413
0
            (*ltmp)->free_func();
414
0
        SNMP_FREE((*ltmp)->config_token);
415
0
        SNMP_FREE((*ltmp)->help);
416
0
        SNMP_FREE(*ltmp);
417
0
        (*ctmp)->start = ltmp2;
418
0
        return;
419
0
    }
420
0
    while ((*ltmp)->next != NULL
421
0
           && strcmp((*ltmp)->next->config_token, token)) {
422
0
        ltmp = &((*ltmp)->next);
423
0
    }
424
0
    if ((*ltmp)->next != NULL) {
425
0
        struct config_line *ltmp2 = (*ltmp)->next->next;
426
0
        if ((*ltmp)->next->free_func)
427
0
            (*ltmp)->next->free_func();
428
0
        SNMP_FREE((*ltmp)->next->config_token);
429
0
        SNMP_FREE((*ltmp)->next->help);
430
0
        SNMP_FREE((*ltmp)->next);
431
0
        (*ltmp)->next = ltmp2;
432
0
    }
433
0
}
434
435
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_APP_CONFIG_HANDLER
436
void
437
unregister_app_config_handler(const char *token)
438
0
{
439
0
    unregister_config_handler(NULL, token);
440
0
}
441
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_APP_CONFIG_HANDLER */
442
443
void
444
unregister_all_config_handlers(void)
445
0
{
446
0
    struct config_files *ctmp, *save;
447
0
    struct config_line *ltmp;
448
449
    /*
450
     * Keep using config_files until there are no more! 
451
     */
452
0
    for (ctmp = config_files; ctmp;) {
453
0
        for (ltmp = ctmp->start; ltmp; ltmp = ctmp->start) {
454
0
            unregister_config_handler(ctmp->fileHeader,
455
0
                                      ltmp->config_token);
456
0
        }
457
0
        SNMP_FREE(ctmp->fileHeader);
458
0
        save = ctmp->next;
459
0
        SNMP_FREE(ctmp);
460
0
        ctmp = save;
461
0
        config_files = save;
462
0
    }
463
0
}
464
465
#ifdef TESTING
466
void
467
print_config_handlers(void)
468
{
469
    struct config_files *ctmp = config_files;
470
    struct config_line *ltmp;
471
472
    for (; ctmp != NULL; ctmp = ctmp->next) {
473
        DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader));
474
        for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next)
475
            DEBUGMSGTL(("read_config", "                   %s\n",
476
                        ltmp->config_token));
477
    }
478
}
479
#endif
480
481
static unsigned int  linecount;
482
static const char   *curfilename;
483
484
struct config_line *
485
read_config_get_handlers(const char *type)
486
1.98k
{
487
1.98k
    struct config_files *ctmp = config_files;
488
2.32k
    for (; ctmp != NULL && strcmp(ctmp->fileHeader, type);
489
1.98k
         ctmp = ctmp->next);
490
1.98k
    if (ctmp)
491
1.65k
        return ctmp->start;
492
339
    return NULL;
493
1.98k
}
494
495
int
496
read_config_with_type_when(const char *filename, const char *type, int when)
497
0
{
498
0
    struct config_line *ctmp = read_config_get_handlers(type);
499
0
    if (ctmp)
500
0
        return read_config(filename, ctmp, when);
501
0
    else
502
0
        DEBUGMSGTL(("read_config",
503
0
                    "read_config: I have no registrations for type:%s,file:%s\n",
504
0
                    type, filename));
505
0
    return SNMPERR_GENERR;     /* No config files read */
506
0
}
507
508
int
509
read_config_with_type(const char *filename, const char *type)
510
0
{
511
0
    return read_config_with_type_when(filename, type, EITHER_CONFIG);
512
0
}
513
514
515
struct config_line *
516
read_config_find_handler(struct config_line *line_handlers,
517
                         const char *token)
518
9.38k
{
519
9.38k
    struct config_line *lptr;
520
521
9.38k
    netsnmp_assert(token);
522
523
169k
    for (lptr = line_handlers; lptr != NULL; lptr = lptr->next) {
524
162k
        if (!strcasecmp(token, lptr->config_token)) {
525
2.28k
            return lptr;
526
2.28k
        }
527
162k
    }
528
7.10k
    return NULL;
529
9.38k
}
530
531
532
/*
533
 * searches a config_line linked list for a match 
534
 */
535
static int
536
run_config_handler(struct config_line *lptr,
537
                   const char *token, char *cptr, int when)
538
9.38k
{
539
9.38k
    char           *cp;
540
541
9.38k
    netsnmp_assert(token);
542
543
9.38k
    lptr = read_config_find_handler(lptr, token);
544
9.38k
    if (lptr != NULL) {
545
2.28k
        if (when == EITHER_CONFIG || lptr->config_time == when) {
546
2.02k
            char tmpbuf[1];
547
2.02k
            DEBUGMSGTL(("read_config:parser",
548
2.02k
                        "Found a parser.  Calling it: %s / %s\n", token,
549
2.02k
                        cptr));
550
            /*
551
             * Make sure cptr is non-null
552
             */
553
2.02k
            if (!cptr) {
554
0
                tmpbuf[0] = '\0';
555
0
                cptr = tmpbuf;
556
0
            }
557
558
            /*
559
             * Stomp on any trailing whitespace
560
             */
561
2.02k
            cp = cptr[0] ? &(cptr[strlen(cptr)-1]) : cptr;
562
2.22k
            while ((cp > cptr) && isspace((unsigned char)(*cp))) {
563
203
                *(cp--) = '\0';
564
203
            }
565
2.02k
            if (lptr->parse_line1)
566
2.02k
                lptr->parse_line1(token, cptr);
567
0
            else
568
0
                lptr->parse_line2(token, cptr);
569
2.02k
        }
570
264
        else
571
264
            DEBUGMSGTL(("9:read_config:parser",
572
2.28k
                        "%s handler not registered for this time\n", token));
573
7.10k
    } else if (when != PREMIB_CONFIG && 
574
7.10k
         !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
575
7.10k
               NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) {
576
7.10k
  netsnmp_config_warn("Unknown token: %s.", token);
577
7.10k
        return SNMPERR_GENERR;
578
7.10k
    }
579
2.28k
    return SNMPERR_SUCCESS;
580
9.38k
}
581
582
/*
583
 * takes an arbitrary string and tries to interprets it based on the
584
 * known configuration handlers for all registered types.  May produce
585
 * inconsistent results when multiple tokens of the same name are
586
 * registered under different file types. 
587
 */
588
589
/*
590
 * we allow = delimiters here 
591
 */
592
0
#define SNMP_CONFIG_DELIMETERS " \t="
593
594
static int
595
snmp_config_when(char *line, int when)
596
0
{
597
0
    char           *cptr, buf[STRINGMAX];
598
0
    struct config_line *lptr = NULL;
599
0
    struct config_files *ctmp = config_files;
600
0
    char           *st, *start_from, *end;
601
602
0
    if (line == NULL) {
603
0
        config_perror("snmp_config() called with a null string.");
604
0
        return SNMPERR_GENERR;
605
0
    }
606
607
0
    strlcpy(buf, line, STRINGMAX);
608
0
    cptr = strtok_r(buf, SNMP_CONFIG_DELIMETERS, &st);
609
0
    if (!cptr) {
610
0
        netsnmp_config_warn("Wrong format: %s", line);
611
0
        return SNMPERR_GENERR;
612
0
    }
613
0
    if (cptr[0] == '[') {
614
0
        if (cptr[strlen(cptr) - 1] != ']') {
615
0
      netsnmp_config_error("no matching ']' for type %s.", cptr + 1);
616
0
            return SNMPERR_GENERR;
617
0
        }
618
0
        cptr[strlen(cptr) - 1] = '\0';
619
0
        lptr = read_config_get_handlers(cptr + 1);
620
0
        if (lptr == NULL) {
621
0
      netsnmp_config_error("No handlers registered for type %s.",
622
0
         cptr + 1);
623
0
            return SNMPERR_GENERR;
624
0
        }
625
0
        cptr = strtok_r(NULL, SNMP_CONFIG_DELIMETERS, &st);
626
0
        if (!cptr) {
627
0
            netsnmp_config_error("Invalid configuration line %s", line);
628
0
            return SNMPERR_GENERR;
629
0
        }
630
0
        lptr = read_config_find_handler(lptr, cptr);
631
0
    } else {
632
        /*
633
         * we have to find a token 
634
         */
635
0
        for (; ctmp != NULL && lptr == NULL; ctmp = ctmp->next)
636
0
            lptr = read_config_find_handler(ctmp->start, cptr);
637
0
    }
638
0
    if (lptr == NULL) {
639
0
        if (when != PREMIB_CONFIG &&
640
0
            !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
641
0
                                    NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) {
642
0
            netsnmp_config_warn("Unknown token: %s.", cptr);
643
0
            return SNMPERR_GENERR;
644
0
        }
645
0
        return SNMPERR_SUCCESS;
646
0
    }
647
648
    /*
649
     * use the original string instead since strtok_r messed up the original 
650
     */
651
0
    end = line + strlen(line);
652
0
    start_from = line + (cptr - buf) + strlen(cptr) + 1;
653
0
    if (start_from > end)
654
0
        start_from = end;
655
0
    line = skip_white(start_from);
656
657
0
    return (run_config_handler(lptr, cptr, line, when));
658
0
}
659
660
int
661
netsnmp_config(char *line)
662
0
{
663
0
    int             ret = SNMP_ERR_NOERROR;
664
0
    DEBUGMSGTL(("snmp_config", "remembering line \"%s\"\n", line));
665
0
    netsnmp_config_remember(line);      /* always remember it so it's read
666
                                         * processed after a free_config()
667
                                         * call */
668
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
669
0
             NETSNMP_DS_LIB_HAVE_READ_CONFIG)) {
670
0
        DEBUGMSGTL(("snmp_config", "  ... processing it now\n"));
671
0
        ret = snmp_config_when(line, NORMAL_CONFIG);
672
0
    }
673
0
    return ret;
674
0
}
675
676
void
677
netsnmp_config_remember_in_list(char *line,
678
                                struct read_config_memory **mem)
679
0
{
680
0
    if (mem == NULL)
681
0
        return;
682
683
0
    while (*mem != NULL)
684
0
        mem = &((*mem)->next);
685
686
0
    *mem = SNMP_MALLOC_STRUCT(read_config_memory);
687
0
    if (*mem != NULL) {
688
0
        if (line)
689
0
            (*mem)->line = strdup(line);
690
0
    }
691
0
}
692
693
void
694
netsnmp_config_remember_free_list(struct read_config_memory **mem)
695
0
{
696
0
    struct read_config_memory *tmpmem;
697
0
    while (*mem) {
698
0
        SNMP_FREE((*mem)->line);
699
0
        tmpmem = (*mem)->next;
700
0
        SNMP_FREE(*mem);
701
0
        *mem = tmpmem;
702
0
    }
703
0
}
704
705
void
706
netsnmp_config_process_memory_list(struct read_config_memory **memp,
707
                                   int when, int clear)
708
0
{
709
710
0
    struct read_config_memory *mem;
711
712
0
    if (!memp)
713
0
        return;
714
715
0
    mem = *memp;
716
717
0
    while (mem) {
718
0
        DEBUGMSGTL(("read_config:mem", "processing memory: %s\n", mem->line));
719
0
        snmp_config_when(mem->line, when);
720
0
        mem = mem->next;
721
0
    }
722
723
0
    if (clear)
724
0
        netsnmp_config_remember_free_list(memp);
725
0
}
726
727
/*
728
 * default storage location implementation 
729
 */
730
static struct read_config_memory *memorylist = NULL;
731
732
void
733
netsnmp_config_remember(char *line)
734
0
{
735
0
    netsnmp_config_remember_in_list(line, &memorylist);
736
0
}
737
738
void
739
netsnmp_config_process_memories(void)
740
0
{
741
0
    netsnmp_config_process_memory_list(&memorylist, EITHER_CONFIG, 1);
742
0
}
743
744
void
745
netsnmp_config_process_memories_when(int when, int clear)
746
0
{
747
0
    netsnmp_config_process_memory_list(&memorylist, when, clear);
748
0
}
749
750
/*******************************************************************-o-******
751
 * read_config
752
 *
753
 * Parameters:
754
 *  *filename
755
 *  *line_handler
756
 *   when
757
 *
758
 * Read <filename> and process each line in accordance with the list of
759
 * <line_handler> functions.
760
 *
761
 *
762
 * For each line in <filename>, search the list of <line_handler>'s 
763
 * for an entry that matches the first token on the line.  This comparison is
764
 * case insensitive.
765
 *
766
 * For each match, check that <when> is the designated time for the
767
 * <line_handler> function to be executed before processing the line.
768
 *
769
 * Returns SNMPERR_SUCCESS if the file is processed successfully.
770
 * Returns SNMPERR_GENERR  if it cannot.
771
 *    Note that individual config token errors do not trigger SNMPERR_GENERR
772
 *    It's only if the whole file cannot be processed for some reason.
773
 */
774
int
775
read_config(const char *filename,
776
            struct config_line *line_handler, int when)
777
92.5k
{
778
92.5k
    static int      depth = 0;
779
92.5k
    static int      files = 0;
780
781
92.5k
    const char * const prev_filename = curfilename;
782
92.5k
    const unsigned int prev_linecount = linecount;
783
784
92.5k
    FILE           *ifile;
785
92.5k
    char           *line = NULL;  /* current line buffer */
786
92.5k
    size_t          linesize = 0; /* allocated size of line */
787
788
92.5k
    netsnmp_assert(line_handler);
789
92.5k
    netsnmp_assert(line_handler->config_token);
790
791
    /* reset file counter when recursion depth is 0 */
792
92.5k
    if (depth == 0) {
793
1.25k
        files = 0;
794
1.25k
        config_errors = 0;
795
1.25k
        config_warnings = 0;
796
1.25k
    }
797
798
92.5k
    if ((ifile = fopen(filename, "r")) == NULL) {
799
6.27k
#ifdef ENOENT
800
6.27k
        if (errno == ENOENT) {
801
6.16k
            DEBUGMSGTL(("read_config", "%s: %s\n", filename,
802
6.16k
                        strerror(errno)));
803
6.16k
        } else
804
112
#endif                          /* ENOENT */
805
112
#ifdef EACCES
806
112
        if (errno == EACCES) {
807
0
            DEBUGMSGTL(("read_config", "%s: %s\n", filename,
808
0
                        strerror(errno)));
809
0
        } else
810
112
#endif                          /* EACCES */
811
112
        {
812
112
            snmp_log_perror(filename);
813
112
        }
814
6.27k
        return SNMPERR_GENERR;
815
6.27k
    }
816
817
86.7k
#define CONFIG_MAX_FILES 4096
818
86.3k
    if (files > CONFIG_MAX_FILES) {
819
478
        netsnmp_config_error("maximum conf file count (%d) exceeded\n",
820
478
                             CONFIG_MAX_FILES);
821
478
  fclose(ifile);
822
478
        return SNMPERR_GENERR;
823
478
    }
824
85.8k
#define CONFIG_MAX_RECURSE_DEPTH 16
825
85.8k
    if (depth > CONFIG_MAX_RECURSE_DEPTH) {
826
0
        netsnmp_config_error("nested include depth > %d\n",
827
0
                             CONFIG_MAX_RECURSE_DEPTH);
828
0
  fclose(ifile);
829
0
        return SNMPERR_GENERR;
830
0
    }
831
832
85.8k
    linecount = 0;
833
85.8k
    curfilename = filename;
834
835
85.8k
    ++files;
836
85.8k
    ++depth;
837
838
85.8k
    DEBUGMSGTL(("read_config:file", "Reading configuration %s (%d)\n",
839
85.8k
                filename, when));
840
841
291k
    while (ifile) {
842
205k
        size_t              linelen = 0; /* strlen of the current line */
843
205k
        char               *cptr;
844
205k
        struct config_line *lptr = line_handler;
845
846
205k
        if (config_errors + config_warnings > 500) {
847
32
            snmp_log(LOG_ERR, "Too many config errors/warnings. Aborting parsing of %s.\n", filename);
848
32
            fclose(ifile);
849
32
            ifile = NULL;
850
32
            break;
851
32
        }
852
853
285k
        for (;;) {
854
285k
            if (linesize <= linelen + 1) {
855
143k
                char *tmp = realloc(line, linesize + 256);
856
143k
                if (tmp) {
857
143k
                    line = tmp;
858
143k
                    linesize += 256;
859
143k
                } else {
860
0
                    netsnmp_config_error("Failed to allocate memory\n");
861
0
                    free(line);
862
0
                    fclose(ifile);
863
0
                    linecount = prev_linecount;
864
0
                    curfilename = prev_filename;
865
0
                    --depth;
866
0
                    return SNMPERR_GENERR;
867
0
                }
868
143k
            }
869
285k
            if (fgets(line + linelen, linesize - linelen, ifile) == NULL) {
870
85.8k
                line[linelen] = '\0';
871
85.8k
                fclose (ifile);
872
85.8k
                ifile = NULL;
873
85.8k
                break;
874
85.8k
            }
875
876
200k
            linelen += strlen(line + linelen);
877
878
200k
            if (linelen && line[linelen - 1] == '\n') {
879
119k
              line[linelen - 1] = '\0';
880
119k
              break;
881
119k
            }
882
200k
        }
883
884
205k
        ++linecount;
885
205k
        DEBUGMSGTL(("9:read_config:line", "%s:%d examining: %s\n",
886
205k
                    filename, linecount, line));
887
        /*
888
         * check blank line or # comment 
889
         */
890
205k
        if ((cptr = skip_white(line))) {
891
109k
            char token[STRINGMAX];
892
893
109k
            cptr = copy_nword(cptr, token, sizeof(token));
894
109k
            if (token[0] == '[') {
895
848
                if (token[strlen(token) - 1] != ']') {
896
109
        netsnmp_config_error("no matching ']' for type %s.",
897
109
           &token[1]);
898
109
                    continue;
899
109
                }
900
739
                token[strlen(token) - 1] = '\0';
901
739
                lptr = read_config_get_handlers(&token[1]);
902
739
                if (lptr == NULL) {
903
339
        netsnmp_config_error("No handlers registered for type %s.",
904
339
           &token[1]);
905
339
                    continue;
906
339
                }
907
400
                DEBUGMSGTL(("read_config:context",
908
400
                            "Switching to new context: %s%s\n",
909
400
                            ((cptr) ? "(this line only) " : ""),
910
400
                            &token[1]));
911
400
                if (cptr == NULL) {
912
                    /*
913
                     * change context permanently 
914
                     */
915
194
                    line_handler = lptr;
916
194
                    continue;
917
206
                } else {
918
                    /*
919
                     * the rest of this line only applies. 
920
                     */
921
206
                    cptr = copy_nword(cptr, token, sizeof(token));
922
206
                }
923
108k
            } else if ((token[0] == 'i') && (strncasecmp(token,"include", 7 )==0)) {
924
90.3k
                if ( strcasecmp( token, "include" )==0) {
925
234
                    if (when != PREMIB_CONFIG && 
926
234
                  !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
927
234
                        NETSNMP_DS_LIB_NO_TOKEN_WARNINGS)) {
928
234
                  netsnmp_config_warn("Ambiguous token '%s' - use 'includeSearch' (or 'includeFile') instead.", token);
929
234
                    }
930
234
                    continue;
931
90.0k
                } else if ( strcasecmp( token, "includedir" )==0) {
932
732
                    DIR *d;
933
732
                    struct dirent *entry;
934
732
                    char  fname[SNMP_MAXPATH];
935
732
                    int   len;
936
937
732
                    if (cptr == NULL) {
938
200
                        if (when != PREMIB_CONFIG)
939
200
                netsnmp_config_error("Blank line following %s token.", token);
940
200
                        continue;
941
200
                    }
942
532
                    if ((d=opendir(cptr)) == NULL ) {
943
198
                        if (when != PREMIB_CONFIG)
944
198
                            netsnmp_config_error("Can't open include dir '%s'.", cptr);
945
198
                        continue;
946
198
                    }
947
17.0k
                    while ((entry = readdir( d )) != NULL ) {
948
16.7k
                        if ( entry->d_name[0] != '.') {
949
15.9k
                            len = strlen(entry->d_name);
950
15.9k
                            if ((len > 5) && (strcmp(&(entry->d_name[len-5]),".conf") == 0)) {
951
675
                                snprintf(fname, SNMP_MAXPATH, "%s/%s",
952
675
                                         cptr, entry->d_name);
953
675
                                (void)read_config(fname, line_handler, when);
954
675
                            }
955
15.9k
                        }
956
16.7k
                    }
957
334
                    closedir(d);
958
334
                    continue;
959
89.3k
                } else if ( strcasecmp( token, "includefile" )==0) {
960
86.1k
                    char  fname[SNMP_MAXPATH], *cp;
961
962
86.1k
                    if (cptr == NULL) {
963
198
                        if (when != PREMIB_CONFIG)
964
198
                netsnmp_config_error("Blank line following %s token.", token);
965
198
                        continue;
966
198
                    }
967
85.9k
                    if (strlen(cptr) + 1 >= SNMP_MAXPATH) {
968
217
                        netsnmp_config_error("File name '%s' is too long",
969
217
                                             cptr);
970
217
                        continue;
971
217
                    }
972
85.7k
                    if ( cptr[0] == '/' ) {
973
84.7k
                        strlcpy(fname, cptr, SNMP_MAXPATH);
974
84.7k
                    } else {
975
1.04k
                        strlcpy(fname, filename, SNMP_MAXPATH);
976
1.04k
                        cp = strrchr(fname, '/');
977
1.04k
                        if (!cp)
978
0
                            fname[0] = '\0';
979
1.04k
                        else
980
1.04k
                            *(++cp) = '\0';
981
1.04k
                        strlcat(fname, cptr, SNMP_MAXPATH);
982
1.04k
                    }
983
85.7k
                    if (read_config(fname, line_handler, when) !=
984
85.7k
                        SNMPERR_SUCCESS && when != PREMIB_CONFIG)
985
1.59k
                        netsnmp_config_error("Included file '%s' not found.",
986
1.59k
                                             fname);
987
85.7k
                    continue;
988
85.9k
                } else if ( strcasecmp( token, "includesearch" )==0) {
989
2.65k
                    struct config_files ctmp;
990
2.65k
                    int len, ret;
991
992
2.65k
                    if (cptr == NULL) {
993
195
                        if (when != PREMIB_CONFIG)
994
195
                netsnmp_config_error("Blank line following %s token.", token);
995
195
                        continue;
996
195
                    }
997
2.45k
                    len = strlen(cptr);
998
2.45k
                    ctmp.fileHeader = cptr;
999
2.45k
                    ctmp.start = line_handler;
1000
2.45k
                    ctmp.next = NULL;
1001
2.45k
                    if ((len > 5) && (strcmp(&cptr[len-5],".conf") == 0))
1002
297
                       cptr[len-5] = 0; /* chop off .conf */
1003
2.45k
                    ret = read_config_files_of_type(when,&ctmp);
1004
2.45k
                    if ((len > 5) && (cptr[len-5] == 0))
1005
297
                       cptr[len-5] = '.'; /* restore .conf */
1006
2.45k
                    if (( ret != SNMPERR_SUCCESS ) && (when != PREMIB_CONFIG))
1007
2.45k
            netsnmp_config_error("Included config '%s' not found.", cptr);
1008
2.45k
                    continue;
1009
2.65k
                } else {
1010
518
                    lptr = line_handler;
1011
518
                }
1012
90.3k
            } else {
1013
18.2k
                lptr = line_handler;
1014
18.2k
            }
1015
18.9k
            if (cptr == NULL) {
1016
9.56k
    netsnmp_config_error("Blank line following %s token.", token);
1017
9.56k
            } else {
1018
9.38k
                DEBUGMSGTL(("read_config:line", "%s:%d examining: %s\n",
1019
9.38k
                            filename, linecount, line));
1020
9.38k
                run_config_handler(lptr, token, cptr, when);
1021
9.38k
            }
1022
18.9k
        }
1023
205k
    }
1024
85.8k
    free(line);
1025
85.8k
    linecount = prev_linecount;
1026
85.8k
    curfilename = prev_filename;
1027
85.8k
    --depth;
1028
85.8k
    return SNMPERR_SUCCESS;
1029
1030
85.8k
}                               /* end read_config() */
1031
1032
1033
1034
void
1035
free_config(void)
1036
0
{
1037
0
    struct config_files *ctmp = config_files;
1038
0
    struct config_line *ltmp;
1039
1040
0
    for (; ctmp != NULL; ctmp = ctmp->next)
1041
0
        for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next)
1042
0
            if (ltmp->free_func)
1043
0
                (*(ltmp->free_func)) ();
1044
0
}
1045
1046
/*
1047
 * Return SNMPERR_SUCCESS if any config files are processed
1048
 * Return SNMPERR_GENERR if _no_ config files are processed
1049
 *    Whether this is actually an error is left to the application
1050
 */
1051
int
1052
read_configs_optional(const char *optional_config, int when)
1053
0
{
1054
0
    char *newp, *cp, *st = NULL;
1055
0
    int              ret = SNMPERR_GENERR;
1056
0
    char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1057
0
               NETSNMP_DS_LIB_APPTYPE);
1058
1059
0
    if ((NULL == optional_config) || (NULL == type))
1060
0
        return ret;
1061
1062
0
    DEBUGMSGTL(("read_configs_optional",
1063
0
                "reading optional configuration tokens for %s\n", type));
1064
    
1065
0
    newp = strdup(optional_config);      /* strtok_r messes it up */
1066
0
    if (!newp)
1067
0
        return ret;
1068
0
    cp = strtok_r(newp, ",", &st);
1069
0
    while (cp) {
1070
0
        struct stat     statbuf;
1071
0
        if (stat(cp, &statbuf)) {
1072
0
            DEBUGMSGTL(("read_config",
1073
0
                        "Optional File \"%s\" does not exist.\n", cp));
1074
0
            snmp_log_perror(cp);
1075
0
        } else {
1076
0
            DEBUGMSGTL(("read_config:opt",
1077
0
                        "Reading optional config file: \"%s\"\n", cp));
1078
0
            if ( read_config_with_type_when(cp, type, when) == SNMPERR_SUCCESS )
1079
0
                ret = SNMPERR_SUCCESS;
1080
0
        }
1081
0
        cp = strtok_r(NULL, ",", &st);
1082
0
    }
1083
0
    free(newp);
1084
0
    return ret;
1085
0
}
1086
1087
void
1088
read_configs(void)
1089
0
{
1090
0
    char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1091
0
                 NETSNMP_DS_LIB_OPTIONALCONFIG);
1092
1093
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
1094
0
                        SNMP_CALLBACK_PRE_READ_CONFIG, NULL);
1095
1096
0
    DEBUGMSGTL(("read_config", "reading normal configuration tokens\n"));
1097
1098
0
    if ((NULL != optional_config) && (*optional_config == '-')) {
1099
0
        (void)read_configs_optional(++optional_config, NORMAL_CONFIG);
1100
0
        optional_config = NULL; /* clear, so we don't read them twice */
1101
0
    }
1102
1103
0
    (void)read_config_files(NORMAL_CONFIG);
1104
1105
    /*
1106
     * do this even when the normal above wasn't done 
1107
     */
1108
0
    if (NULL != optional_config)
1109
0
        (void)read_configs_optional(optional_config, NORMAL_CONFIG);
1110
1111
0
    netsnmp_config_process_memories_when(NORMAL_CONFIG, 1);
1112
1113
0
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
1114
0
         NETSNMP_DS_LIB_HAVE_READ_CONFIG, 1);
1115
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
1116
0
                        SNMP_CALLBACK_POST_READ_CONFIG, NULL);
1117
0
}
1118
1119
void
1120
read_premib_configs(void)
1121
0
{
1122
0
    char *optional_config = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1123
0
                 NETSNMP_DS_LIB_OPTIONALCONFIG);
1124
1125
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
1126
0
                        SNMP_CALLBACK_PRE_PREMIB_READ_CONFIG, NULL);
1127
1128
0
    DEBUGMSGTL(("read_config", "reading premib configuration tokens\n"));
1129
1130
0
    if ((NULL != optional_config) && (*optional_config == '-')) {
1131
0
        (void)read_configs_optional(++optional_config, PREMIB_CONFIG);
1132
0
        optional_config = NULL; /* clear, so we don't read them twice */
1133
0
    }
1134
1135
0
    (void)read_config_files(PREMIB_CONFIG);
1136
1137
0
    if (NULL != optional_config)
1138
0
        (void)read_configs_optional(optional_config, PREMIB_CONFIG);
1139
1140
0
    netsnmp_config_process_memories_when(PREMIB_CONFIG, 0);
1141
1142
0
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
1143
0
         NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG, 1);
1144
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
1145
0
                        SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, NULL);
1146
0
}
1147
1148
/*******************************************************************-o-******
1149
 * set_configuration_directory
1150
 *
1151
 * Parameters:
1152
 *      char *dir - value of the directory
1153
 * Sets the configuration directory. Multiple directories can be
1154
 * specified, but need to be separated by 'ENV_SEPARATOR_CHAR'.
1155
 */
1156
void
1157
set_configuration_directory(const char *dir)
1158
1
{
1159
1
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
1160
1
        NETSNMP_DS_LIB_CONFIGURATION_DIR, dir);
1161
1
}
1162
1163
/*******************************************************************-o-******
1164
 * get_configuration_directory
1165
 *
1166
 * Parameters: -
1167
 * Retrieve the configuration directory or directories.
1168
 * (For backwards compatibility that is:
1169
 *       SNMPCONFPATH, SNMPSHAREPATH, SNMPLIBPATH, HOME/.snmp
1170
 * First check whether the value is set.
1171
 * If not set give it the default value.
1172
 * Return the value.
1173
 * We always retrieve it new, since we have to do it anyway if it is just set.
1174
 */
1175
const char     *
1176
get_configuration_directory(void)
1177
2.45k
{
1178
2.45k
    char            defaultPath[SPRINT_MAX_LEN];
1179
2.45k
    const char     *homepath;
1180
1181
2.45k
    if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1182
2.45k
              NETSNMP_DS_LIB_CONFIGURATION_DIR)) {
1183
1
        homepath = netsnmp_gethomedir();
1184
1
        snprintf(defaultPath, sizeof(defaultPath), "%s%c%s%c%s%s%s%s",
1185
1
                SNMPCONFPATH, ENV_SEPARATOR_CHAR,
1186
1
                SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH,
1187
1
                ((homepath == NULL) ? "" : ENV_SEPARATOR),
1188
1
                ((homepath == NULL) ? "" : homepath),
1189
1
                ((homepath == NULL) ? "" : "/.snmp"));
1190
1
        defaultPath[ sizeof(defaultPath)-1 ] = 0;
1191
1
        set_configuration_directory(defaultPath);
1192
1
    }
1193
2.45k
    return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1194
2.45k
          NETSNMP_DS_LIB_CONFIGURATION_DIR));
1195
2.45k
}
1196
1197
/*******************************************************************-o-******
1198
 * set_persistent_directory
1199
 *
1200
 * Parameters:
1201
 *      char *dir - value of the directory
1202
 * Sets the configuration directory. 
1203
 * No multiple directories may be specified.
1204
 * (However, this is not checked)
1205
 */
1206
void
1207
set_persistent_directory(const char *dir)
1208
1
{
1209
1
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
1210
1
        NETSNMP_DS_LIB_PERSISTENT_DIR, dir);
1211
1
}
1212
1213
/*******************************************************************-o-******
1214
 * get_persistent_directory
1215
 *
1216
 * Parameters: -
1217
 * Function will retrieve the persistent directory value.
1218
 * First check whether the value is set.
1219
 * If not set give it the default value.
1220
 * Return the value. 
1221
 * We always retrieve it new, since we have to do it anyway if it is just set.
1222
 */
1223
const char     *
1224
get_persistent_directory(void)
1225
4.91k
{
1226
4.91k
    if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1227
4.91k
              NETSNMP_DS_LIB_PERSISTENT_DIR)) {
1228
1
        const char *persdir = netsnmp_getenv("SNMP_PERSISTENT_DIR");
1229
1
        if (NULL == persdir)
1230
1
            persdir = NETSNMP_PERSISTENT_DIRECTORY;
1231
1
        set_persistent_directory(persdir);
1232
1
    }
1233
4.91k
    return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1234
4.91k
          NETSNMP_DS_LIB_PERSISTENT_DIR));
1235
4.91k
}
1236
1237
/*******************************************************************-o-******
1238
 * set_temp_file_pattern
1239
 *
1240
 * Parameters:
1241
 *      char *pattern - value of the file pattern
1242
 * Sets the temp file pattern. 
1243
 * Multiple patterns may not be specified.
1244
 * (However, this is not checked)
1245
 */
1246
void
1247
set_temp_file_pattern(const char *pattern)
1248
0
{
1249
0
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
1250
0
        NETSNMP_DS_LIB_TEMP_FILE_PATTERN, pattern);
1251
0
}
1252
1253
/*******************************************************************-o-******
1254
 * get_temp_file_pattern
1255
 *
1256
 * Parameters: -
1257
 * Function will retrieve the temp file pattern value.
1258
 * First check whether the value is set.
1259
 * If not set give it the default value.
1260
 * Return the value. 
1261
 * We always retrieve it new, since we have to do it anyway if it is just set.
1262
 */
1263
const char     *
1264
get_temp_file_pattern(void)
1265
0
{
1266
0
    if (NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1267
0
              NETSNMP_DS_LIB_TEMP_FILE_PATTERN)) {
1268
0
        set_temp_file_pattern(NETSNMP_TEMP_FILE_PATTERN);
1269
0
    }
1270
0
    return (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1271
0
          NETSNMP_DS_LIB_TEMP_FILE_PATTERN));
1272
0
}
1273
1274
/**
1275
 * utility routine for read_config_files
1276
 *
1277
 * Return SNMPERR_SUCCESS if any config files are processed
1278
 * Return SNMPERR_GENERR if _no_ config files are processed
1279
 *    Whether this is actually an error is left to the application
1280
 */
1281
static int
1282
read_config_files_in_path(const char *path, struct config_files *ctmp,
1283
                          int when, const char *perspath, const char *persfile)
1284
4.91k
{
1285
4.91k
    int             done, j;
1286
4.91k
    char            configfile[300];
1287
4.91k
    char           *cptr1, *cptr2, *envconfpath;
1288
4.91k
    struct stat     statbuf;
1289
4.91k
    int             ret = SNMPERR_GENERR;
1290
1291
4.91k
    if ((NULL == path) || (NULL == ctmp))
1292
0
        return SNMPERR_GENERR;
1293
1294
4.91k
    envconfpath = strdup(path);
1295
4.91k
    if (NULL == envconfpath) {
1296
0
        return SNMPERR_GENERR;
1297
0
    }
1298
1299
4.91k
    DEBUGMSGTL(("read_config:path", " config path used for %s:%s (persistent path:%s)\n",
1300
4.91k
                ctmp->fileHeader, envconfpath, perspath));
1301
4.91k
    cptr1 = cptr2 = envconfpath;
1302
4.91k
    done = 0;
1303
14.7k
    while ((!done) && (*cptr2 != 0)) {
1304
333k
        while (*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR)
1305
321k
            cptr1++;
1306
12.2k
        if (*cptr1 == 0)
1307
4.91k
            done = 1;
1308
7.36k
        else
1309
7.36k
            *cptr1 = 0;
1310
1311
12.2k
        DEBUGMSGTL(("read_config:dir", " config dir: %s\n", cptr2 ));
1312
12.2k
        if (stat(cptr2, &statbuf) != 0) {
1313
            /*
1314
             * Directory not there, continue 
1315
             */
1316
9.82k
            DEBUGMSGTL(("read_config:dir", " Directory not present: %s\n", cptr2 ));
1317
9.82k
            cptr2 = ++cptr1;
1318
9.82k
            continue;
1319
9.82k
        }
1320
2.45k
#ifdef S_ISDIR
1321
2.45k
        if (!S_ISDIR(statbuf.st_mode)) {
1322
            /*
1323
             * Not a directory, continue 
1324
             */
1325
0
            DEBUGMSGTL(("read_config:dir", " Not a directory: %s\n", cptr2 ));
1326
0
            cptr2 = ++cptr1;
1327
0
            continue;
1328
0
        }
1329
2.45k
#endif
1330
1331
        /*
1332
         * for proper persistent storage retrieval, we need to read old backup
1333
         * copies of the previous storage files.  If the application in
1334
         * question has died without the proper call to snmp_clean_persistent,
1335
         * then we read all the configuration files we can, starting with
1336
         * the oldest first.
1337
         */
1338
2.45k
        if (strncmp(cptr2, perspath, strlen(perspath)) == 0 ||
1339
0
            (persfile != NULL &&
1340
2.45k
             strncmp(cptr2, persfile, strlen(persfile)) == 0)) {
1341
2.45k
            DEBUGMSGTL(("read_config:persist", " persist dir: %s\n", cptr2 ));
1342
            /*
1343
             * limit this to the known storage directory only 
1344
             */
1345
2.45k
            for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) {
1346
2.45k
                snprintf(configfile, sizeof(configfile),
1347
2.45k
                         "%s/%s.%d.conf", cptr2,
1348
2.45k
                         ctmp->fileHeader, j);
1349
2.45k
                if (stat(configfile, &statbuf) != 0) {
1350
                    /*
1351
                     * file not there, continue 
1352
                     */
1353
2.45k
                    break;
1354
2.45k
                } else {
1355
                    /*
1356
                     * backup exists, read it 
1357
                     */
1358
0
                    DEBUGMSGTL(("read_config_files",
1359
0
                                "old config file found: %s, parsing\n",
1360
0
                                configfile));
1361
0
                    if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS)
1362
0
                        ret = SNMPERR_SUCCESS;
1363
0
                }
1364
2.45k
            }
1365
2.45k
        }
1366
2.45k
        snprintf(configfile, sizeof(configfile),
1367
2.45k
                 "%s/%s.conf", cptr2, ctmp->fileHeader);
1368
2.45k
        if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS)
1369
0
            ret = SNMPERR_SUCCESS;
1370
2.45k
        snprintf(configfile, sizeof(configfile),
1371
2.45k
                 "%s/%s.local.conf", cptr2, ctmp->fileHeader);
1372
2.45k
        if (read_config(configfile, ctmp->start, when) == SNMPERR_SUCCESS)
1373
0
            ret = SNMPERR_SUCCESS;
1374
1375
2.45k
        if(done)
1376
2.45k
            break;
1377
1378
0
        cptr2 = ++cptr1;
1379
0
    }
1380
4.91k
    SNMP_FREE(envconfpath);
1381
4.91k
    return ret;
1382
4.91k
}
1383
1384
/*******************************************************************-o-******
1385
 * read_config_files
1386
 *
1387
 * Parameters:
1388
 *  when  == PREMIB_CONFIG, NORMAL_CONFIG  -or-  EITHER_CONFIG
1389
 *
1390
 *
1391
 * Traverse the list of config file types, performing the following actions
1392
 * for each --
1393
 *
1394
 * First, build a search path for config files.  If the contents of 
1395
 * environment variable SNMPCONFPATH are NULL, then use the following
1396
 * path list (where the last entry exists only if HOME is non-null):
1397
 *
1398
 *  SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp
1399
 *
1400
 * Then, In each of these directories, read config files by the name of:
1401
 *
1402
 *  <dir>/<fileHeader>.conf   -AND-
1403
 *  <dir>/<fileHeader>.local.conf
1404
 *
1405
 * where <fileHeader> is taken from the config file type structure.
1406
 *
1407
 *
1408
 * PREMIB_CONFIG causes free_config() to be invoked prior to any other action.
1409
 *
1410
 *
1411
 * EXITs if any 'config_errors' are logged while parsing config file lines.
1412
 *
1413
 * Return SNMPERR_SUCCESS if any config files are processed
1414
 * Return SNMPERR_GENERR if _no_ config files are processed
1415
 *    Whether this is actually an error is left to the application
1416
 */
1417
int
1418
read_config_files_of_type(int when, struct config_files *ctmp)
1419
2.45k
{
1420
2.45k
    const char     *confpath, *persfile, *envconfpath;
1421
2.45k
    char           *perspath;
1422
2.45k
    int             ret = SNMPERR_GENERR;
1423
1424
2.45k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1425
2.45k
                               NETSNMP_DS_LIB_DONT_PERSIST_STATE)
1426
2.45k
        || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1427
2.45k
                                  NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD)
1428
2.45k
        || (NULL == ctmp)) return ret;
1429
1430
    /*
1431
     * these shouldn't change
1432
     */
1433
2.45k
    confpath = get_configuration_directory();
1434
2.45k
    persfile = netsnmp_getenv("SNMP_PERSISTENT_FILE");
1435
2.45k
    envconfpath = netsnmp_getenv("SNMPCONFPATH");
1436
1437
1438
        /*
1439
         * read the config files. strdup() the result of
1440
         * get_persistent_directory() to avoid that parsing the "persistentDir"
1441
         * keyword transforms the perspath pointer into a dangling pointer.
1442
         */
1443
2.45k
        perspath = strdup(get_persistent_directory());
1444
2.45k
        if (perspath == NULL) {
1445
0
            return SNMPERR_GENERR;
1446
0
        }
1447
2.45k
        if (envconfpath == NULL) {
1448
            /*
1449
             * read just the config files (no persistent stuff), since
1450
             * persistent path can change via conf file. Then get the
1451
             * current persistent directory, and read files there.
1452
             */
1453
2.45k
            if ( read_config_files_in_path(confpath, ctmp, when, perspath,
1454
2.45k
                                      persfile) == SNMPERR_SUCCESS )
1455
0
                ret = SNMPERR_SUCCESS;
1456
2.45k
            free(perspath);
1457
2.45k
            perspath = strdup(get_persistent_directory());
1458
2.45k
            if (perspath == NULL) {
1459
0
                return SNMPERR_GENERR;
1460
0
            }
1461
2.45k
            if ( read_config_files_in_path(perspath, ctmp, when, perspath,
1462
2.45k
                                      persfile) == SNMPERR_SUCCESS )
1463
0
                ret = SNMPERR_SUCCESS;
1464
2.45k
        }
1465
0
        else {
1466
            /*
1467
             * only read path specified by user
1468
             */
1469
0
            if ( read_config_files_in_path(envconfpath, ctmp, when, perspath,
1470
0
                                      persfile) == SNMPERR_SUCCESS )
1471
0
                ret = SNMPERR_SUCCESS;
1472
0
        }
1473
2.45k
        free(perspath);
1474
2.45k
        return ret;
1475
2.45k
}
1476
1477
/*
1478
 * Return SNMPERR_SUCCESS if any config files are processed
1479
 * Return SNMPERR_GENERR if _no_ config files are processed
1480
 *    Whether this is actually an error is left to the application
1481
 */
1482
int
1483
0
read_config_files(int when) {
1484
1485
0
    struct config_files *ctmp = config_files;
1486
0
    int                  ret  = SNMPERR_GENERR;
1487
1488
0
    config_errors = 0;
1489
1490
0
    if (when == PREMIB_CONFIG)
1491
0
        free_config();
1492
1493
    /*
1494
     * read all config file types 
1495
     */
1496
0
    for (; ctmp != NULL; ctmp = ctmp->next) {
1497
0
        if ( read_config_files_of_type(when, ctmp) == SNMPERR_SUCCESS )
1498
0
            ret = SNMPERR_SUCCESS;
1499
0
    }
1500
1501
0
    if (config_errors) {
1502
0
        snmp_log(LOG_ERR, "net-snmp: %d error(s) in config file(s)\n",
1503
0
                 config_errors);
1504
0
    }
1505
0
    return ret;
1506
0
}
1507
1508
void
1509
read_config_print_usage(const char *lead)
1510
0
{
1511
0
    struct config_files *ctmp;
1512
0
    struct config_line *ltmp;
1513
1514
0
    if (lead == NULL)
1515
0
        lead = "";
1516
1517
0
    for (ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) {
1518
0
        snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead,
1519
0
                 ctmp->fileHeader, ctmp->fileHeader);
1520
0
        for (ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) {
1521
0
            DEBUGIF("read_config_usage") {
1522
0
                if (ltmp->config_time == PREMIB_CONFIG)
1523
0
                    DEBUGMSG(("read_config_usage", "*"));
1524
0
                else
1525
0
                    DEBUGMSG(("read_config_usage", " "));
1526
0
            }
1527
0
            if (ltmp->help) {
1528
0
                snmp_log(LOG_INFO, "%s%s%-24s %s\n", lead, lead,
1529
0
                         ltmp->config_token, ltmp->help);
1530
0
            } else {
1531
0
                DEBUGIF("read_config_usage") {
1532
0
                    snmp_log(LOG_INFO, "%s%s%-24s [NO HELP]\n", lead, lead,
1533
0
                             ltmp->config_token);
1534
0
                }
1535
0
            }
1536
0
        }
1537
0
    }
1538
0
}
1539
1540
/**
1541
 * read_config_store intended for use by applications to store permanent
1542
 * configuration information generated by sets or persistent counters.
1543
 * Appends line to a file named either ENV(SNMP_PERSISTENT_FILE) or
1544
 *   "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf".
1545
 * Adds a trailing newline to the stored file if necessary.
1546
 *
1547
 * @param type is the application name
1548
 * @param line is the configuration line written to the application name's
1549
 * configuration file
1550
 *      
1551
 * @return void
1552
  */
1553
void
1554
read_config_store(const char *type, const char *line)
1555
0
{
1556
0
#ifdef NETSNMP_PERSISTENT_DIRECTORY
1557
0
    char            file[512], *filep;
1558
0
    FILE           *fout;
1559
0
#ifdef NETSNMP_PERSISTENT_MASK
1560
0
    mode_t          oldmask;
1561
0
#endif
1562
1563
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1564
0
                               NETSNMP_DS_LIB_DONT_PERSIST_STATE)
1565
0
     || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1566
0
                               NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD)) return;
1567
1568
    /*
1569
     * store configuration directives in the following order of preference:
1570
     * 1. ENV variable SNMP_PERSISTENT_FILE
1571
     * 2. configured <NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf
1572
     */
1573
0
    if ((filep = netsnmp_getenv("SNMP_PERSISTENT_FILE")) == NULL) {
1574
0
        snprintf(file, sizeof(file),
1575
0
                 "%s/%s.conf", get_persistent_directory(), type);
1576
0
        filep = file;
1577
0
    }
1578
0
#ifdef NETSNMP_PERSISTENT_MASK
1579
0
    oldmask = umask(NETSNMP_PERSISTENT_MASK);
1580
0
#endif
1581
0
    if (mkdirhier(filep, NETSNMP_AGENT_DIRECTORY_MODE, 1)) {
1582
0
        snmp_log(LOG_ERR,
1583
0
                 "Failed to create the persistent directory for %s\n",
1584
0
                 filep);
1585
0
    }
1586
0
    if ((fout = fopen(filep, "a")) != NULL) {
1587
0
        fprintf(fout, "%s", line);
1588
0
        if (line[strlen(line)] != '\n')
1589
0
            fprintf(fout, "\n");
1590
0
        DEBUGMSGTL(("read_config:store", "storing: %s\n", line));
1591
0
        fflush(fout);
1592
0
#if defined(HAVE_FSYNC)
1593
0
        fsync(fileno(fout));
1594
#elif defined(HAVE__GET_OSFHANDLE)
1595
        {
1596
            int fd;
1597
            HANDLE h;
1598
1599
            fd = fileno(fout);
1600
            netsnmp_assert(fd != -1);
1601
            /*
1602
             * Use size_t instead of uintptr_t because not all supported
1603
             * Windows compilers support uintptr_t.
1604
             */
1605
            h = (HANDLE)(size_t)_get_osfhandle(fd);
1606
            netsnmp_assert(h != INVALID_HANDLE_VALUE);
1607
            FlushFileBuffers(h);
1608
        }
1609
#endif
1610
0
        fclose(fout);
1611
0
    } else {
1612
0
        if (strcmp(NETSNMP_APPLICATION_CONFIG_TYPE, type) != 0) {
1613
            /*
1614
             * Ignore this error in client utilities, they can run with random
1615
             * UID/GID and typically cannot write to /var. Error message just
1616
             * confuses people.
1617
             */
1618
0
            snmp_log(LOG_ERR, "read_config_store open failure on %s\n", filep);
1619
0
        }
1620
0
    }
1621
0
#ifdef NETSNMP_PERSISTENT_MASK
1622
0
    umask(oldmask);
1623
0
#endif
1624
1625
0
#endif
1626
0
}                               /* end read_config_store() */
1627
1628
void
1629
read_app_config_store(const char *line)
1630
0
{
1631
0
    read_config_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1632
0
              NETSNMP_DS_LIB_APPTYPE), line);
1633
0
}
1634
1635
1636
1637
1638
/*******************************************************************-o-******
1639
 * snmp_save_persistent
1640
 *
1641
 * Parameters:
1642
 *  *type
1643
 *      
1644
 *
1645
 * Save the file "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy
1646
 * called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an
1647
 * incrementing number on each call, but less than NETSNMP_MAX_PERSISTENT_BACKUPS.
1648
 *
1649
 * Should be called just before all persistent information is supposed to be
1650
 * written to move aside the existing persistent cache.
1651
 * snmp_clean_persistent should then be called afterward all data has been
1652
 * saved to remove these backup files.
1653
 *
1654
 * Note: on an rename error, the files are removed rather than saved.
1655
 *
1656
 */
1657
void
1658
snmp_save_persistent(const char *type)
1659
0
{
1660
0
    char            file[512], fileold[SPRINT_MAX_LEN];
1661
0
    struct stat     statbuf;
1662
0
    int             j;
1663
1664
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1665
0
                               NETSNMP_DS_LIB_DONT_PERSIST_STATE)
1666
0
     || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1667
0
                               NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE)) return;
1668
1669
0
    DEBUGMSGTL(("snmp_save_persistent", "saving %s files...\n", type));
1670
0
    snprintf(file, sizeof(file),
1671
0
             "%s/%s.conf", get_persistent_directory(), type);
1672
0
    if (stat(file, &statbuf) == 0) {
1673
0
        for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) {
1674
0
            snprintf(fileold, sizeof(fileold),
1675
0
                     "%s/%s.%d.conf", get_persistent_directory(), type, j);
1676
0
            if (stat(fileold, &statbuf) != 0) {
1677
0
                DEBUGMSGTL(("snmp_save_persistent",
1678
0
                            " saving old config file: %s -> %s.\n", file,
1679
0
                            fileold));
1680
0
                if (rename(file, fileold)) {
1681
0
                    snmp_log(LOG_ERR, "Cannot rename %s to %s\n", file, fileold);
1682
                     /* moving it failed, try nuking it, as leaving
1683
                      * it around is very bad. */
1684
0
                    if (unlink(file) == -1)
1685
0
                        snmp_log(LOG_ERR, "Cannot unlink %s\n", file);
1686
0
                }
1687
0
                break;
1688
0
            }
1689
0
        }
1690
0
    }
1691
    /*
1692
     * save a warning header to the top of the new file 
1693
     */
1694
0
    snprintf(fileold, sizeof(fileold),
1695
0
            "%s%s# Please save normal configuration tokens for %s in SNMPCONFPATH/%s.conf.\n# Only \"createUser\" tokens should be placed here by %s administrators.\n%s",
1696
0
            "#\n# net-snmp (or ucd-snmp) persistent data file.\n#\n############################################################################\n# STOP STOP STOP STOP STOP STOP STOP STOP STOP \n",
1697
0
            "#\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",
1698
0
            type, type, type,
1699
0
      "# (Did I mention: do not edit this file?)\n#\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
1700
0
    read_config_store(type, fileold);
1701
0
}
1702
1703
1704
/*******************************************************************-o-******
1705
 * snmp_clean_persistent
1706
 *
1707
 * Parameters:
1708
 *  *type
1709
 *      
1710
 *
1711
 * Unlink all backup files called "<NETSNMP_PERSISTENT_DIRECTORY>/<type>.%d.conf".
1712
 *
1713
 * Should be called just after we successfull dumped the last of the
1714
 * persistent data, to remove the backup copies of previous storage dumps.
1715
 *
1716
 * XXX  Worth overwriting with random bytes first?  This would
1717
 *  ensure that the data is destroyed, even a buffer containing the
1718
 *  data persists in memory or swap.  Only important if secrets
1719
 *  will be stored here.
1720
 */
1721
void
1722
snmp_clean_persistent(const char *type)
1723
0
{
1724
0
    char            file[512];
1725
0
    struct stat     statbuf;
1726
0
    int             j;
1727
1728
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1729
0
                               NETSNMP_DS_LIB_DONT_PERSIST_STATE)
1730
0
     || netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1731
0
                               NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE)) return;
1732
1733
0
    DEBUGMSGTL(("snmp_clean_persistent", "cleaning %s files...\n", type));
1734
0
    snprintf(file, sizeof(file),
1735
0
             "%s/%s.conf", get_persistent_directory(), type);
1736
0
    if (stat(file, &statbuf) == 0) {
1737
0
        for (j = 0; j <= NETSNMP_MAX_PERSISTENT_BACKUPS; j++) {
1738
0
            snprintf(file, sizeof(file),
1739
0
                     "%s/%s.%d.conf", get_persistent_directory(), type, j);
1740
0
            if (stat(file, &statbuf) == 0) {
1741
0
                DEBUGMSGTL(("snmp_clean_persistent",
1742
0
                            " removing old config file: %s\n", file));
1743
0
                if (unlink(file) == -1)
1744
0
                    snmp_log(LOG_ERR, "Cannot unlink %s\n", file);
1745
0
            }
1746
0
        }
1747
0
    }
1748
0
}
1749
1750
1751
1752
1753
/*
1754
 * config_perror: prints a warning string associated with a file and
1755
 * line number of a .conf file and increments the error count. 
1756
 */
1757
static void
1758
config_vlog(int level, const char *levelmsg, const char *str, va_list args)
1759
22.8k
{
1760
22.8k
    char *msg = NULL;
1761
1762
22.8k
    if (vasprintf(&msg, str, args) < 0)
1763
0
        return;
1764
22.8k
    snmp_log(level, "%s: line %d: %s: %s\n",
1765
22.8k
             curfilename, linecount, levelmsg, msg);
1766
22.8k
    free(msg);
1767
22.8k
}
1768
1769
void
1770
netsnmp_config_error(const char *str, ...)
1771
15.5k
{
1772
15.5k
    va_list args;
1773
15.5k
    va_start(args, str);
1774
15.5k
    config_vlog(LOG_ERR, "Error", str, args);
1775
15.5k
    va_end(args);
1776
15.5k
    config_errors++;
1777
15.5k
}
1778
1779
void
1780
netsnmp_config_warn(const char *str, ...)
1781
7.33k
{
1782
7.33k
    va_list args;
1783
7.33k
    va_start(args, str);
1784
7.33k
    config_vlog(LOG_WARNING, "Warning", str, args);
1785
7.33k
    va_end(args);
1786
7.33k
    config_warnings++;
1787
7.33k
}
1788
1789
void
1790
config_perror(const char *str)
1791
0
{
1792
0
    netsnmp_config_error("%s", str);
1793
0
}
1794
1795
void
1796
config_pwarn(const char *str)
1797
0
{
1798
0
    netsnmp_config_warn("%s", str);
1799
0
}
1800
1801
/*
1802
 * skip all white spaces and return 1 if found something either end of
1803
 * line or a comment character 
1804
 */
1805
char           *
1806
skip_white(char *ptr)
1807
205k
{
1808
205k
    return NETSNMP_REMOVE_CONST(char *, skip_white_const(ptr));
1809
205k
}
1810
1811
const char     *
1812
skip_white_const(const char *ptr)
1813
314k
{
1814
314k
    if (ptr == NULL)
1815
0
        return (NULL);
1816
426k
    while (*ptr != 0 && isspace((unsigned char)*ptr))
1817
112k
        ptr++;
1818
314k
    if (*ptr == 0 || *ptr == '#')
1819
106k
        return (NULL);
1820
207k
    return (ptr);
1821
314k
}
1822
1823
char           *
1824
skip_not_white(char *ptr)
1825
0
{
1826
0
    return NETSNMP_REMOVE_CONST(char *, skip_not_white_const(ptr));
1827
0
}
1828
1829
const char     *
1830
skip_not_white_const(const char *ptr)
1831
0
{
1832
0
    if (ptr == NULL)
1833
0
        return (NULL);
1834
0
    while (*ptr != 0 && !isspace((unsigned char)*ptr))
1835
0
        ptr++;
1836
0
    if (*ptr == 0 || *ptr == '#')
1837
0
        return (NULL);
1838
0
    return (ptr);
1839
0
}
1840
1841
char           *
1842
skip_token(char *ptr)
1843
0
{
1844
0
    return NETSNMP_REMOVE_CONST(char *, skip_token_const(ptr));
1845
0
}
1846
1847
const char     *
1848
skip_token_const(const char *ptr)
1849
0
{
1850
0
    ptr = skip_white_const(ptr);
1851
0
    ptr = skip_not_white_const(ptr);
1852
0
    ptr = skip_white_const(ptr);
1853
0
    return (ptr);
1854
0
}
1855
1856
/*
1857
 * copy_word
1858
 * copies the next 'token' from 'from' into 'to', maximum len-1 characters.
1859
 * currently a token is anything separate by white space
1860
 * or within quotes (double or single) (i.e. "the red rose" 
1861
 * is one token, \"the red rose\" is three tokens)
1862
 * a '\' character will allow a quote character to be treated
1863
 * as a regular character 
1864
 * It returns a pointer to first non-white space after the end of the token
1865
 * being copied or to 0 if we reach the end.
1866
 * Note: Partially copied words (greater than len) still returns a !NULL ptr
1867
 * Note: partially copied words are, however, null terminated.
1868
 */
1869
1870
char           *
1871
copy_nword(char *from, char *to, int len)
1872
109k
{
1873
109k
    return NETSNMP_REMOVE_CONST(char *, copy_nword_const(from, to, len));
1874
109k
}
1875
1876
const char           *
1877
copy_nword_const(const char *from, char *to, int len)
1878
109k
{
1879
109k
    char            quote;
1880
109k
    if (!from || !to)
1881
0
        return NULL;
1882
109k
    if ((*from == '\"') || (*from == '\'')) {
1883
1.54k
        quote = *(from++);
1884
571k
        while ((*from != quote) && (*from != 0)) {
1885
569k
            if ((*from == '\\') && (*(from + 1) != 0)) {
1886
900
                if (len > 0) {  /* don't copy beyond len bytes */
1887
697
                    *to++ = *(from + 1);
1888
697
                    if (--len == 0)
1889
321
                        *(to - 1) = '\0';       /* null protect the last spot */
1890
697
                }
1891
900
                from = from + 2;
1892
568k
            } else {
1893
568k
                if (len > 0) {  /* don't copy beyond len bytes */
1894
564k
                    *to++ = *from++;
1895
564k
                    if (--len == 0)
1896
212
                        *(to - 1) = '\0';       /* null protect the last spot */
1897
564k
                } else
1898
4.64k
                    from++;
1899
568k
            }
1900
569k
        }
1901
1.54k
        if (*from == 0) {
1902
1.31k
            DEBUGMSGTL(("read_config_copy_word",
1903
1.31k
                        "no end quote found in config string\n"));
1904
1.31k
        } else
1905
226
            from++;
1906
108k
    } else {
1907
4.85M
        while (*from != 0 && !isspace((unsigned char)(*from))) {
1908
4.74M
            if ((*from == '\\') && (*(from + 1) != 0)) {
1909
16.9k
                if (len > 0) {  /* don't copy beyond len bytes */
1910
13.9k
                    *to++ = *(from + 1);
1911
13.9k
                    if (--len == 0)
1912
194
                        *(to - 1) = '\0';       /* null protect the last spot */
1913
13.9k
                }
1914
16.9k
                from = from + 2;
1915
4.73M
            } else {
1916
4.73M
                if (len > 0) {  /* don't copy beyond len bytes */
1917
1.75M
                    *to++ = *from++;
1918
1.75M
                    if (--len == 0)
1919
248
                        *(to - 1) = '\0';       /* null protect the last spot */
1920
1.75M
                } else
1921
2.97M
                    from++;
1922
4.73M
            }
1923
4.74M
        }
1924
108k
    }
1925
109k
    if (len > 0)
1926
108k
        *to = 0;
1927
109k
    from = skip_white_const(from);
1928
109k
    return (from);
1929
109k
}                               /* copy_nword */
1930
1931
/*
1932
 * copy_word
1933
 * copies the next 'token' from 'from' into 'to'.
1934
 * currently a token is anything separate by white space
1935
 * or within quotes (double or single) (i.e. "the red rose" 
1936
 * is one token, \"the red rose\" is three tokens)
1937
 * a '\' character will allow a quote character to be treated
1938
 * as a regular character 
1939
 * It returns a pointer to first non-white space after the end of the token
1940
 * being copied or to 0 if we reach the end.
1941
 */
1942
1943
static int      have_warned = 0;
1944
char           *
1945
copy_word(char *from, char *to)
1946
0
{
1947
0
    if (!have_warned) {
1948
0
        snmp_log(LOG_INFO,
1949
0
                 "copy_word() called.  Use copy_nword() instead.\n");
1950
0
        have_warned = 1;
1951
0
    }
1952
0
    return copy_nword(from, to, SPRINT_MAX_LEN);
1953
0
}                               /* copy_word */
1954
1955
/**
1956
 * Stores an quoted version of the first len bytes from str into saveto.
1957
 *
1958
 * If all octets in str are in the set [[:alnum:] ] then the quotation
1959
 * is to enclose the string in quotation marks ("str") otherwise the
1960
 * quotation is to prepend the string 0x and then add the hex representation
1961
 * of all characters from str (0x737472)
1962
 *
1963
 * @param[in] saveto pointer to output stream, is assumed to be big enough.
1964
 * @param[in] str pointer of the data that is to be stored.
1965
 * @param[in] len length of the data that is to be stored.
1966
 * @return A pointer to saveto after str is added to it.
1967
 */
1968
char           *
1969
read_config_save_octet_string(char *saveto, const u_char * str, size_t len)
1970
0
{
1971
0
    size_t          i;
1972
0
    const u_char   *cp;
1973
1974
    /*
1975
     * is everything easily printable
1976
     */
1977
0
    for (i = 0, cp = str; i < len && cp &&
1978
0
         (isalpha(*cp) || isdigit(*cp) || *cp == ' '); cp++, i++);
1979
1980
0
    if (len != 0 && i == len) {
1981
0
        *saveto++ = '"';
1982
0
        memcpy(saveto, str, len);
1983
0
        saveto += len;
1984
0
        *saveto++ = '"';
1985
0
        *saveto = '\0';
1986
0
    } else {
1987
0
        if (str != NULL) {
1988
0
            sprintf(saveto, "0x");
1989
0
            saveto += 2;
1990
0
            for (i = 0; i < len; i++) {
1991
0
                sprintf(saveto, "%02x", str[i]);
1992
0
                saveto = saveto + 2;
1993
0
            }
1994
0
        } else {
1995
0
            sprintf(saveto, "\"\"");
1996
0
            saveto += 2;
1997
0
        }
1998
0
    }
1999
0
    return saveto;
2000
0
}
2001
2002
/**
2003
 * Reads an octet string that was saved by the
2004
 * read_config_save_octet_string() function.
2005
 *
2006
 * @param[in]     readfrom Pointer to the input data to be parsed.
2007
 * @param[in,out] str      Pointer to the output buffer pointer. The data
2008
 *   written to the output buffer will be '\0'-terminated. If *str == NULL,
2009
 *   an output buffer will be allocated that is one byte larger than the
2010
 *   data stored.
2011
 * @param[in,out] len      If str != NULL, *len is the size of the buffer *str
2012
 *   points at. If str == NULL, the value passed via *len is ignored.
2013
 *   Before this function returns the number of bytes read will be stored
2014
 *   in *len. If a buffer overflow occurs or if a parsing failure occurs, *len
2015
 *   will be set to 0.
2016
 *
2017
 * @return A pointer to the next character in the input to be parsed if
2018
 *   parsing succeeded; NULL when the end of the input string has been reached
2019
 *   or if an error occurred.
2020
 */
2021
char           *
2022
read_config_read_octet_string(const char *readfrom, u_char ** str,
2023
                              size_t * len)
2024
0
{
2025
0
    return NETSNMP_REMOVE_CONST(char *,
2026
0
               read_config_read_octet_string_const(readfrom, str, len));
2027
0
}
2028
2029
const char     *
2030
read_config_read_octet_string_const(const char *readfrom, u_char ** str,
2031
                                    size_t * len)
2032
0
{
2033
0
    u_char         *cptr;
2034
0
    const char     *cptr1;
2035
0
    u_int           tmp;
2036
0
    size_t          i, ilen;
2037
0
    int             allocated = 0;
2038
2039
0
    if (len == NULL)
2040
0
        return NULL;
2041
2042
0
    if (readfrom == NULL || str == NULL)
2043
0
        goto err;
2044
2045
0
    if (strncasecmp(readfrom, "0x", 2) == 0) {
2046
        /*
2047
         * A hex string submitted. How long? 
2048
         */
2049
0
        readfrom += 2;
2050
0
        cptr1 = skip_not_white_const(readfrom);
2051
0
        if (cptr1)
2052
0
            ilen = (cptr1 - readfrom);
2053
0
        else
2054
0
            ilen = strlen(readfrom);
2055
2056
0
        if (ilen % 2) {
2057
0
            snmp_log(LOG_WARNING,"invalid hex string: wrong length\n");
2058
0
            DEBUGMSGTL(("read_config_read_octet_string",
2059
0
                        "invalid hex string: wrong length\n"));
2060
0
            goto err;
2061
0
        }
2062
0
        ilen = ilen / 2;
2063
2064
        /*
2065
         * malloc data space if needed (+1 for good measure) 
2066
         */
2067
0
        if (*str == NULL) {
2068
0
            *str = malloc(ilen + 1);
2069
0
            if (!*str)
2070
0
                goto err;
2071
0
            allocated = 1;
2072
0
        } else {
2073
            /*
2074
             * require caller to have +1, and bail if not enough space.
2075
             */
2076
0
            if (ilen >= *len) {
2077
0
                snmp_log(LOG_WARNING,"buffer too small to read octet string (%lu < %lu)\n",
2078
0
                         (unsigned long)*len, (unsigned long)ilen);
2079
0
                DEBUGMSGTL(("read_config_read_octet_string",
2080
0
                            "buffer too small (%lu < %lu)\n", (unsigned long)*len, (unsigned long)ilen));
2081
0
                *len = 0;
2082
0
                cptr1 = skip_not_white_const(readfrom);
2083
0
                return skip_white_const(cptr1);
2084
0
            }
2085
0
        }
2086
2087
        /*
2088
         * copy validated data 
2089
         */
2090
0
        *len = ilen;
2091
0
        cptr = *str;
2092
0
        for (i = 0; i < ilen; i++) {
2093
0
            if (1 == sscanf(readfrom, "%2x", &tmp))
2094
0
                *cptr++ = (u_char) tmp;
2095
0
            else {
2096
0
                goto err;
2097
0
            }
2098
0
            readfrom += 2;
2099
0
        }
2100
        /*
2101
         * Terminate the output buffer.
2102
         */
2103
0
        *cptr++ = '\0';
2104
0
        readfrom = skip_white_const(readfrom);
2105
0
    } else {
2106
        /*
2107
         * Normal string 
2108
         */
2109
2110
        /*
2111
         * malloc string space if needed (including NULL terminator) 
2112
         */
2113
0
        if (*str == NULL) {
2114
0
            char            buf[SNMP_MAXBUF];
2115
0
            readfrom = copy_nword_const(readfrom, buf, sizeof(buf));
2116
2117
0
            *len = strlen(buf);
2118
0
            *str = malloc(*len + 1);
2119
0
            if (*str == NULL)
2120
0
                goto err;
2121
0
            memcpy(*str, buf, *len + 1);
2122
0
        } else {
2123
0
            readfrom = copy_nword_const(readfrom, (char *) *str, *len);
2124
0
            if (*len)
2125
0
                *len = strlen((char *) *str);
2126
0
        }
2127
0
    }
2128
2129
0
    return readfrom;
2130
2131
0
err:
2132
0
    if (allocated)
2133
0
        SNMP_FREE(*str);
2134
0
    *len = 0;
2135
0
    return NULL;
2136
0
}
2137
2138
/*
2139
 * read_config_save_objid(): saves an objid as a numerical string 
2140
 */
2141
char           *
2142
read_config_save_objid(char *saveto, const oid *objid, size_t len)
2143
0
{
2144
0
    int             i;
2145
2146
0
    if (len == 0) {
2147
0
        strcat(saveto, "NULL");
2148
0
        saveto += strlen(saveto);
2149
0
        return saveto;
2150
0
    }
2151
2152
    /*
2153
     * in case len=0, this makes it easier to read it back in 
2154
     */
2155
0
    for (i = 0; i < len; i++)
2156
0
        saveto += sprintf(saveto, ".%" NETSNMP_PRIo "d", objid[i]);
2157
2158
0
    return saveto;
2159
0
}
2160
2161
/*
2162
 * read_config_read_objid(): reads an objid from a format saved by the above 
2163
 */
2164
char           *
2165
read_config_read_objid(char *readfrom, oid ** objid, size_t * len)
2166
0
{
2167
0
    return NETSNMP_REMOVE_CONST(char *,
2168
0
             read_config_read_objid_const(readfrom, objid, len));
2169
0
}
2170
2171
const char     *
2172
read_config_read_objid_const(const char *readfrom, oid ** objid, size_t * len)
2173
0
{
2174
0
    int             allocated = 0;
2175
2176
0
    if (objid == NULL || readfrom == NULL || len == NULL)
2177
0
        return NULL;
2178
2179
0
    if (*objid == NULL) {
2180
0
        *len = 0;
2181
0
        if ((*objid = (oid *) malloc(MAX_OID_LEN * sizeof(oid))) == NULL)
2182
0
            return NULL;
2183
0
        *len = MAX_OID_LEN;
2184
0
        allocated = 1;
2185
0
    }
2186
2187
0
    if (strncmp(readfrom, "NULL", 4) == 0) {
2188
        /*
2189
         * null length oid 
2190
         */
2191
0
        *len = 0;
2192
0
    } else {
2193
        /*
2194
         * qualify the string for read_objid 
2195
         */
2196
0
        char            buf[SPRINT_MAX_LEN];
2197
0
        copy_nword_const(readfrom, buf, sizeof(buf));
2198
2199
0
        if (!read_objid(buf, *objid, len)) {
2200
0
            DEBUGMSGTL(("read_config_read_objid", "Invalid OID\n"));
2201
0
            if (allocated)
2202
0
                SNMP_FREE(*objid);
2203
0
            *len = 0;
2204
0
            return NULL;
2205
0
        }
2206
0
    }
2207
2208
0
    readfrom = skip_token_const(readfrom);
2209
0
    return readfrom;
2210
0
}
2211
2212
/**
2213
 * read_config_read_data reads data of a given type from a token(s) on a
2214
 * configuration line.  The supported types are:
2215
 *
2216
 *    - ASN_INTEGER
2217
 *    - ASN_TIMETICKS
2218
 *    - ASN_UNSIGNED
2219
 *    - ASN_OCTET_STR
2220
 *    - ASN_BIT_STR
2221
 *    - ASN_OBJECT_ID
2222
 *
2223
 * @param type the asn data type to be read in.
2224
 *
2225
 * @param readfrom the configuration line data to be read.
2226
 *
2227
 * @param dataptr an allocated pointer expected to match the type being read
2228
 *        (int *, u_int *, char **, oid **)
2229
 *
2230
 * @param len is the length of an asn oid or octet/bit string, not required
2231
 *            for the asn integer, unsigned integer, and timeticks types
2232
 *
2233
 * @return the next token in the configuration line.  NULL if none left or
2234
 * if an unknown type.
2235
 * 
2236
 */
2237
char           *
2238
read_config_read_data(int type, char *readfrom, void *dataptr,
2239
                      size_t * len)
2240
0
{
2241
0
    int            *intp;
2242
0
    char          **charpp;
2243
0
    oid           **oidpp;
2244
0
    unsigned int   *uintp;
2245
2246
0
    if (dataptr && readfrom)
2247
0
        switch (type) {
2248
0
        case ASN_INTEGER:
2249
0
            intp = (int *) dataptr;
2250
0
            *intp = atoi(readfrom);
2251
0
            readfrom = skip_token(readfrom);
2252
0
            return readfrom;
2253
2254
0
        case ASN_TIMETICKS:
2255
0
        case ASN_UNSIGNED:
2256
0
            uintp = (unsigned int *) dataptr;
2257
0
            *uintp = strtoul(readfrom, NULL, 0);
2258
0
            readfrom = skip_token(readfrom);
2259
0
            return readfrom;
2260
2261
0
        case ASN_IPADDRESS:
2262
0
            intp = (int *) dataptr;
2263
0
            *intp = inet_addr(readfrom);
2264
0
            if ((*intp == -1) &&
2265
0
                (strncmp(readfrom, "255.255.255.255", 15) != 0))
2266
0
                return NULL;
2267
0
            readfrom = skip_token(readfrom);
2268
0
            return readfrom;
2269
2270
0
        case ASN_OCTET_STR:
2271
0
        case ASN_BIT_STR:
2272
0
            charpp = (char **) dataptr;
2273
0
            return read_config_read_octet_string(readfrom,
2274
0
                                                 (u_char **) charpp, len);
2275
2276
0
        case ASN_OBJECT_ID:
2277
0
            oidpp = (oid **) dataptr;
2278
0
            return read_config_read_objid(readfrom, oidpp, len);
2279
2280
0
        default:
2281
0
            DEBUGMSGTL(("read_config_read_data", "Fail: Unknown type: %d\n",
2282
0
                        type));
2283
0
            return NULL;
2284
0
        }
2285
0
    return NULL;
2286
0
}
2287
2288
/*
2289
 * read_config_read_memory():
2290
 * 
2291
 * similar to read_config_read_data, but expects a generic memory
2292
 * pointer rather than a specific type of pointer.  Len is expected to
2293
 * be the amount of available memory.
2294
 */
2295
char           *
2296
read_config_read_memory(int type, char *readfrom,
2297
                        char *dataptr, size_t * len)
2298
0
{
2299
0
    int            *intp;
2300
0
    unsigned int   *uintp;
2301
0
    char            buf[SPRINT_MAX_LEN];
2302
2303
0
    if (!dataptr || !readfrom)
2304
0
        return NULL;
2305
2306
0
    switch (type) {
2307
0
    case ASN_INTEGER:
2308
0
        if (*len < sizeof(int))
2309
0
            return NULL;
2310
0
        intp = (int *) dataptr;
2311
0
        readfrom = copy_nword(readfrom, buf, sizeof(buf));
2312
0
        *intp = atoi(buf);
2313
0
        *len = sizeof(int);
2314
0
        return readfrom;
2315
2316
0
    case ASN_COUNTER:
2317
0
    case ASN_TIMETICKS:
2318
0
    case ASN_UNSIGNED:
2319
0
        if (*len < sizeof(unsigned int))
2320
0
            return NULL;
2321
0
        uintp = (unsigned int *) dataptr;
2322
0
        readfrom = copy_nword(readfrom, buf, sizeof(buf));
2323
0
        *uintp = strtoul(buf, NULL, 0);
2324
0
        *len = sizeof(unsigned int);
2325
0
        return readfrom;
2326
2327
0
    case ASN_IPADDRESS:
2328
0
        if (*len < sizeof(int))
2329
0
            return NULL;
2330
0
        intp = (int *) dataptr;
2331
0
        readfrom = copy_nword(readfrom, buf, sizeof(buf));
2332
0
        *intp = inet_addr(buf);
2333
0
        if ((*intp == -1) && (strcmp(buf, "255.255.255.255") != 0))
2334
0
            return NULL;
2335
0
        *len = sizeof(int);
2336
0
        return readfrom;
2337
2338
0
    case ASN_OCTET_STR:
2339
0
    case ASN_BIT_STR:
2340
0
    case ASN_PRIV_IMPLIED_OCTET_STR:
2341
0
        return read_config_read_octet_string(readfrom,
2342
0
                                             (u_char **) & dataptr, len);
2343
2344
0
    case ASN_PRIV_IMPLIED_OBJECT_ID:
2345
0
    case ASN_OBJECT_ID:
2346
0
        *len /= sizeof(oid);
2347
0
        readfrom =
2348
0
            read_config_read_objid(readfrom, (oid **) & dataptr, len);
2349
0
        *len *= sizeof(oid);
2350
0
        return readfrom;
2351
2352
0
    case ASN_COUNTER64:
2353
0
        if (*len < sizeof(struct counter64))
2354
0
            return NULL;
2355
0
        *len = sizeof(struct counter64);
2356
0
        read64((struct counter64 *) dataptr, readfrom);
2357
0
        readfrom = skip_token(readfrom);
2358
0
        return readfrom;
2359
0
    }
2360
2361
0
    DEBUGMSGTL(("read_config_read_memory", "Fail: Unknown type: %d\n", type));
2362
0
    return NULL;
2363
0
}
2364
2365
/**
2366
 * read_config_store_data stores data of a given type to a configuration line
2367
 * into the storeto buffer.
2368
 * Calls read_config_store_data_prefix with the prefix parameter set to a char
2369
 * space.  The supported types are:
2370
 *
2371
 *    - ASN_INTEGER
2372
 *    - ASN_TIMETICKS
2373
 *    - ASN_UNSIGNED
2374
 *    - ASN_OCTET_STR
2375
 *    - ASN_BIT_STR
2376
 *    - ASN_OBJECT_ID
2377
 *
2378
 * @param type    the asn data type to be stored
2379
 *
2380
 * @param storeto a pre-allocated char buffer which will contain the data
2381
 *                to be stored
2382
 *
2383
 * @param dataptr contains the value to be stored, the supported pointers:
2384
 *                (int *, u_int *, char **, oid **)
2385
 *
2386
 * @param len     is the length of the value to be stored
2387
 *                (not required for the asn integer, unsigned integer,
2388
 *                 and timeticks types)
2389
 *
2390
 * @return character pointer to the end of the line. NULL if an unknown type.
2391
 */
2392
char           *
2393
read_config_store_data(int type, char *storeto, void *dataptr, size_t * len)
2394
0
{
2395
0
    return read_config_store_data_prefix(' ', type, storeto, dataptr,
2396
0
                                                         (len ? *len : 0));
2397
0
}
2398
2399
char           *
2400
read_config_store_data_prefix(char prefix, int type, char *storeto,
2401
                              void *dataptr, size_t len)
2402
0
{
2403
0
    int            *intp;
2404
0
    u_char        **charpp;
2405
0
    unsigned int   *uintp;
2406
0
    struct in_addr  in;
2407
0
    oid           **oidpp;
2408
2409
0
    if (dataptr && storeto)
2410
0
        switch (type) {
2411
0
        case ASN_INTEGER:
2412
0
            intp = (int *) dataptr;
2413
0
            sprintf(storeto, "%c%d", prefix, *intp);
2414
0
            return (storeto + strlen(storeto));
2415
2416
0
        case ASN_TIMETICKS:
2417
0
        case ASN_UNSIGNED:
2418
0
            uintp = (unsigned int *) dataptr;
2419
0
            sprintf(storeto, "%c%u", prefix, *uintp);
2420
0
            return (storeto + strlen(storeto));
2421
2422
0
        case ASN_IPADDRESS:
2423
0
            in.s_addr = *(unsigned int *) dataptr; 
2424
0
            sprintf(storeto, "%c%s", prefix, inet_ntoa(in));
2425
0
            return (storeto + strlen(storeto));
2426
2427
0
        case ASN_OCTET_STR:
2428
0
        case ASN_BIT_STR:
2429
0
            *storeto++ = prefix;
2430
0
            charpp = (u_char **) dataptr;
2431
0
            return read_config_save_octet_string(storeto, *charpp, len);
2432
2433
0
        case ASN_OBJECT_ID:
2434
0
            *storeto++ = prefix;
2435
0
            oidpp = (oid **) dataptr;
2436
0
            return read_config_save_objid(storeto, *oidpp, len);
2437
2438
0
        default:
2439
0
            DEBUGMSGTL(("read_config_store_data_prefix",
2440
0
                        "Fail: Unknown type: %d\n", type));
2441
0
            return NULL;
2442
0
        }
2443
0
    return NULL;
2444
0
}
2445
2446
/** @} */