Coverage Report

Created: 2025-12-14 06:46

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