Coverage Report

Created: 2026-10-19 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmp_logging.c
Line
Count
Source
1
/*
2
 * logging.c - generic logging for snmp-agent
3
 * * Contributed by Ragnar Kjørstad, ucd@ragnark.vestdata.no 1999-06-26 
4
 */
5
/* Portions of this file are subject to the following copyright(s).  See
6
 * the Net-SNMP's COPYING file for more details and other copyrights
7
 * that may apply:
8
 */
9
/*
10
 * Portions of this file are copyrighted by:
11
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
12
 * Use is subject to license terms specified in the COPYING file
13
 * distributed with the Net-SNMP package.
14
 *
15
 * Portions of this file are copyrighted by:
16
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
17
 * Use is subject to license terms specified in the COPYING file
18
 * distributed with the Net-SNMP package.
19
 */
20
/** @defgroup snmp_logging generic logging for net-snmp 
21
 *  @ingroup library
22
 * 
23
 *  @{
24
 */
25
#include <net-snmp/net-snmp-config.h>
26
#include <net-snmp/net-snmp-features.h>
27
#include <stdio.h>
28
#ifdef HAVE_MALLOC_H
29
#include <malloc.h>
30
#endif
31
#ifdef HAVE_STRING_H
32
#include <string.h>
33
#else
34
#include <strings.h>
35
#endif
36
#include <ctype.h>
37
#ifdef HAVE_STDLIB_H
38
#include <stdlib.h>
39
#endif
40
#include <sys/types.h>
41
#include <sys/stat.h>
42
#include <fcntl.h>
43
#include <errno.h>
44
#ifdef HAVE_SYSLOG_H
45
#include <syslog.h>
46
#ifndef LOG_CONS                /* Interesting Ultrix feature */
47
#include <sys/syslog.h>
48
#endif
49
#endif
50
#ifdef TIME_WITH_SYS_TIME
51
# include <sys/time.h>
52
# include <time.h>
53
#else
54
# ifdef HAVE_SYS_TIME_H
55
#  include <sys/time.h>
56
# else
57
#  include <time.h>
58
# endif
59
#endif
60
#ifdef HAVE_NETINET_IN_H
61
#include <netinet/in.h>
62
#endif
63
64
#include <stdarg.h>
65
66
#ifdef HAVE_UNISTD_H
67
#include <unistd.h>
68
#endif
69
70
#include <net-snmp/types.h>
71
#include <net-snmp/output_api.h>
72
#include <net-snmp/library/snmp_logging.h>      /* For this file's "internal" definitions */
73
#include <net-snmp/config_api.h>
74
#include <net-snmp/utilities.h>
75
76
#include <net-snmp/library/callback.h>
77
78
#include "snmp_syslog.h"
79
80
#ifdef va_copy
81
#define NEED_VA_END_AFTER_VA_COPY
82
#else
83
#ifdef __vacopy
84
#define vacopy __vacopy
85
#define NEED_VA_END_AFTER_VA_COPY
86
#else
87
#define va_copy(dest, src) memcpy (&dest, &src, sizeof (va_list))
88
#endif
89
#endif
90
#ifndef HAVE_VSNPRINTF
91
#include "snprintf.h"
92
#endif
93
94
netsnmp_feature_child_of(logging_all, libnetsnmp);
95
96
netsnmp_feature_child_of(logging_outputs, logging_all);
97
netsnmp_feature_child_of(logging_file, logging_outputs);
98
netsnmp_feature_child_of(logging_stdio, logging_outputs);
99
netsnmp_feature_child_of(logging_syslog, logging_outputs);
100
netsnmp_feature_child_of(logging_external, logging_all);
101
102
netsnmp_feature_child_of(enable_stderrlog, logging_all);
103
104
netsnmp_feature_child_of(logging_enable_calllog, netsnmp_unused);
105
netsnmp_feature_child_of(logging_enable_loghandler, netsnmp_unused);
106
107
/* default to the file/stdio/syslog set */
108
netsnmp_feature_want(logging_outputs);
109
110
/*
111
 * logh_head:  A list of all log handlers, in increasing order of priority
112
 * logh_priorities:  'Indexes' into this list, by priority
113
 */
114
static netsnmp_log_handler *logh_head;
115
static netsnmp_log_handler *logh_priorities[LOG_DEBUG+1];
116
static int logh_enabled;
117
118
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
119
static char syslogname[64] = DEFAULT_LOG_ID;
120
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
121
122
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
123
netsnmp_log_handler *
124
netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
125
                                  const char *tok);
126
#endif
127
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
128
netsnmp_log_handler *
129
netsnmp_register_filelog_handler(const char* logfilename, int priority,
130
                                 int priority_max, int dont_zero_log);
131
#endif
132
133
void
134
netsnmp_disable_this_loghandler(netsnmp_log_handler *logh)
135
0
{
136
0
    if (!logh || (0 == logh->enabled))
137
0
        return;
138
0
    logh->enabled = 0;
139
0
    --logh_enabled;
140
0
    netsnmp_assert(logh_enabled >= 0);
141
0
}
142
143
void
144
netsnmp_enable_this_loghandler(netsnmp_log_handler *logh)
145
0
{
146
0
    if (!logh || (0 != logh->enabled))
147
0
        return;
148
0
    logh->enabled = 1;
149
0
    ++logh_enabled;
150
0
}
151
152
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
153
void
154
netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log);
155
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
156
157
void
158
parse_config_logOption(const char *token, char *cptr)
159
0
{
160
0
  int my_argc = 0 ;
161
0
  char **my_argv = NULL;
162
163
0
  snmp_log_options( cptr, my_argc, my_argv );
164
0
}
165
166
void
167
init_snmp_logging(void)
168
0
{
169
0
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp", 
170
0
       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP);
171
0
    register_prenetsnmp_mib_handler("snmp", "logOption",
172
0
                                    parse_config_logOption, NULL, "string");
173
174
0
}
175
176
void
177
shutdown_snmp_logging(void)
178
0
{
179
0
   snmp_disable_log();
180
0
   while(NULL != logh_head)
181
0
      netsnmp_remove_loghandler( logh_head );
182
0
}
183
184
/* Set line buffering mode for a stream. */
185
void
186
netsnmp_set_line_buffering(FILE *stream)
187
1
{
188
#if defined(WIN32)
189
    /*
190
     * According to MSDN, the Microsoft Visual Studio C runtime library does
191
     * not support line buffering, so turn off buffering completely.
192
     * See also http://msdn.microsoft.com/en-us/library/86cebhfs(VS.71).aspx.
193
     */
194
    setvbuf(stream, NULL, _IONBF, BUFSIZ);
195
#elif defined(HAVE_SETLINEBUF)
196
    /* setlinefunction() is a function from the BSD Unix API. */
197
    setlinebuf(stream);
198
#else
199
    /* See also the C89 or C99 standard for more information about setvbuf(). */
200
1
    setvbuf(stream, NULL, _IOLBF, BUFSIZ);
201
1
#endif
202
1
}
203
204
/*
205
 * Decodes log priority.
206
 * @param optarg - IN - priority to decode, "0" or "0-7"
207
 *                 OUT - points to last character after the decoded priority
208
 * @param pri_max - OUT - maximum priority (i.e. 0 from "0-7")
209
 */
210
static int
211
decode_priority( char **optarg, int *pri_max )
212
0
{
213
0
    int pri_low = LOG_DEBUG;
214
215
0
    if (*optarg == NULL)
216
0
        return -1;
217
218
0
    switch (**optarg) {
219
0
        case '0': 
220
0
        case '!': 
221
0
            pri_low = LOG_EMERG;
222
0
            break;
223
0
        case '1': 
224
0
        case 'a': 
225
0
        case 'A': 
226
0
            pri_low = LOG_ALERT;
227
0
            break;
228
0
        case '2': 
229
0
        case 'c': 
230
0
        case 'C': 
231
0
            pri_low = LOG_CRIT;
232
0
            break;
233
0
        case '3': 
234
0
        case 'e': 
235
0
        case 'E': 
236
0
            pri_low = LOG_ERR;
237
0
            break;
238
0
        case '4': 
239
0
        case 'w': 
240
0
        case 'W': 
241
0
            pri_low = LOG_WARNING;
242
0
            break;
243
0
        case '5': 
244
0
        case 'n': 
245
0
        case 'N': 
246
0
            pri_low = LOG_NOTICE;
247
0
            break;
248
0
        case '6': 
249
0
        case 'i': 
250
0
        case 'I': 
251
0
            pri_low = LOG_INFO;
252
0
            break;
253
0
        case '7': 
254
0
        case 'd': 
255
0
        case 'D': 
256
0
            pri_low = LOG_DEBUG;
257
0
            break;
258
0
        default: 
259
0
            fprintf(stderr, "invalid priority: %c\n",**optarg);
260
0
            return -1;
261
0
    }
262
0
    *optarg = *optarg+1;
263
264
0
    if (pri_max && **optarg=='-') {
265
0
        *optarg = *optarg + 1; /* skip '-' */
266
0
        *pri_max = decode_priority( optarg, NULL );
267
0
        if (*pri_max == -1) return -1;
268
0
        if (pri_low < *pri_max) { 
269
0
            int tmp = pri_low; 
270
0
            pri_low = *pri_max; 
271
0
            *pri_max = tmp; 
272
0
        }
273
274
0
    }
275
0
    return pri_low;
276
0
}
277
278
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
279
static int
280
decode_facility( char *optarg )
281
0
{
282
0
    if (optarg == NULL)
283
0
        return -1;
284
285
0
    switch (*optarg) {
286
0
    case 'd':
287
0
    case 'D':
288
0
        return LOG_DAEMON;
289
0
    case 'u':
290
0
    case 'U':
291
0
        return LOG_USER;
292
0
    case '0':
293
0
        return LOG_LOCAL0;
294
0
    case '1':
295
0
        return LOG_LOCAL1;
296
0
    case '2':
297
0
        return LOG_LOCAL2;
298
0
    case '3':
299
0
        return LOG_LOCAL3;
300
0
    case '4':
301
0
        return LOG_LOCAL4;
302
0
    case '5':
303
0
        return LOG_LOCAL5;
304
0
    case '6':
305
0
        return LOG_LOCAL6;
306
0
    case '7':
307
0
        return LOG_LOCAL7;
308
0
    default:
309
0
        fprintf(stderr, "invalid syslog facility: %c\n",*optarg);
310
0
        return -1;
311
0
    }
312
0
}
313
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
314
315
int
316
snmp_log_options(char *optarg, int argc, char *const *argv)
317
0
{
318
0
    char           *cp = optarg;
319
        /*
320
   * Hmmm... this doesn't seem to work.
321
   * The main agent 'getopt' handling assumes
322
   *   that the -L option takes an argument,
323
   *   and objects if this is missing.
324
   * Trying to differentiate between
325
   *   new-style "-Lx", and old-style "-L xx"
326
   *   is likely to be a major headache.
327
   */
328
0
    char            missing_opt = 'e';  /* old -L is new -Le */
329
0
    int             priority = LOG_DEBUG;
330
0
    int             pri_max  = LOG_EMERG;
331
0
    int             inc_optind = 0;
332
0
    netsnmp_log_handler *logh;
333
334
0
    DEBUGMSGT(("logging:options", "optarg: '%s', argc %d, argv '%s'\n",
335
0
               optarg, argc, argv ? argv[0] : "NULL"));
336
0
    if (!*cp)
337
0
        cp = &missing_opt;
338
0
    else
339
0
        optarg++;
340
341
    /*
342
     * Support '... -Lx=value ....' syntax
343
     */
344
0
    if (*optarg == '=') {
345
0
        optarg++;
346
0
    }
347
    /*
348
     * and '.... "-Lx value" ....'  (*with* the quotes)
349
     */
350
0
    while (*optarg && isspace((unsigned char)(*optarg))) {
351
0
        optarg++;
352
0
    }
353
    /*
354
     * Finally, handle ".... -Lx value ...." syntax
355
     *   (*without* surrounding quotes)
356
     */
357
0
    if (!*optarg && argv && optind < argc) {
358
        /*
359
         * We've run off the end of the argument
360
         *  so move on to the next.
361
         * But we might not actually need it, so don't
362
   *  increment optind just yet!
363
         */
364
0
        optarg = argv[optind];
365
0
        inc_optind = 1;
366
0
    }
367
368
0
    DEBUGMSGT(("logging:options", "*cp: '%c'\n", *cp));
369
0
    switch (*cp) {
370
371
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
372
    /*
373
     * Log to Standard Error
374
     */
375
0
    case 'E':
376
0
        priority = decode_priority( &optarg, &pri_max );
377
0
        if (priority == -1)  return -1;
378
0
        if (inc_optind)
379
0
            optind++;
380
0
        NETSNMP_FALLTHROUGH;
381
0
    case 'e':
382
0
        logh = netsnmp_register_stdio_loghandler(0, priority, pri_max, "stderr");
383
0
        break;
384
385
    /*
386
     * Log to Standard Output
387
     */
388
0
    case 'O':
389
0
        priority = decode_priority( &optarg, &pri_max );
390
0
        if (priority == -1)  return -1;
391
0
        if (inc_optind)
392
0
            optind++;
393
0
        NETSNMP_FALLTHROUGH;
394
0
    case 'o':
395
0
        logh = netsnmp_register_stdio_loghandler( 1, priority, pri_max, "stdout" );
396
0
        break;
397
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
398
399
    /*
400
     * Log to a named file
401
     */
402
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
403
0
    case 'F':
404
0
        priority = decode_priority( &optarg, &pri_max );
405
0
        if (priority == -1) return -1;
406
0
        while (*optarg == ' ') optarg++;
407
0
        if (!*optarg && !argv)
408
0
            return -1;
409
0
        else if (!*optarg)
410
0
            optarg = optind + 1 < argc ? argv[++optind] : NULL;
411
0
        NETSNMP_FALLTHROUGH;
412
0
    case 'f':
413
0
        if (inc_optind)
414
0
            optind++;
415
0
        if (!optarg) {
416
0
            fprintf(stderr, "Missing log file\n");
417
0
            return -1;
418
0
        }
419
0
        DEBUGMSGTL(("logging:options", "%d-%d: '%s'\n", priority, pri_max, optarg));
420
0
        logh = netsnmp_register_filelog_handler(optarg, priority, pri_max,
421
0
                                                   -1);
422
0
        break;
423
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
424
425
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
426
    /*
427
     * Log to syslog
428
     */
429
0
    case 'S':
430
0
        priority = decode_priority( &optarg, &pri_max );
431
0
        if (priority == -1 || !argv)  return -1;
432
0
        if (!optarg[0]) {
433
            /* The command line argument with priority does not contain log
434
             * facility. The facility must be in next argument then. */
435
0
            optind++;
436
0
            if (optind < argc)
437
0
                optarg = argv[optind];
438
0
            else
439
0
                optarg = NULL;
440
0
        }
441
0
        NETSNMP_FALLTHROUGH;
442
0
    case 's':
443
0
        if (inc_optind)
444
0
            optind++;
445
0
        if (!optarg) {
446
0
            fprintf(stderr, "Missing syslog facility\n");
447
0
            return -1;
448
0
        }
449
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, priority);
450
0
        if (logh) {
451
0
            int facility = decode_facility(optarg);
452
0
            if (facility == -1) {
453
0
                netsnmp_remove_loghandler(logh);
454
0
                return -1;
455
0
            }
456
0
            logh->pri_max = pri_max;
457
0
            logh->token   = strdup(snmp_log_syslogname(NULL));
458
0
            logh->magic   = (void *)(intptr_t)facility;
459
0
      snmp_enable_syslog_ident(snmp_log_syslogname(NULL), facility);
460
0
  }
461
0
        break;
462
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
463
464
    /*
465
     * Don't log 
466
     */
467
0
    case 'N':
468
0
        priority = decode_priority( &optarg, &pri_max );
469
0
        if (priority == -1)  return -1;
470
0
        if (inc_optind)
471
0
            optind++;
472
0
        NETSNMP_FALLTHROUGH;
473
0
    case 'n':
474
        /*
475
         * disable all logs to clean them up (close files, etc),
476
         * remove all log handlers, then register a null handler.
477
         */
478
0
        snmp_disable_log();
479
0
        while(NULL != logh_head)
480
0
            netsnmp_remove_loghandler( logh_head );
481
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, priority);
482
0
        if (logh) {
483
0
            logh->pri_max = pri_max;
484
0
  }
485
0
        break;
486
487
0
    default:
488
0
        fprintf(stderr, "Unknown logging option passed to -L: %c.\n", *cp);
489
0
        return -1;
490
0
    }
491
0
    return 0;
492
0
}
493
494
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
495
char *
496
snmp_log_syslogname(const char *pstr)
497
0
{
498
0
  if (pstr && pstr != syslogname)
499
0
    strlcpy (syslogname, pstr, sizeof(syslogname));
500
501
0
  return syslogname;
502
0
}
503
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
504
505
void
506
snmp_log_options_usage(const char *lead, FILE * outf)
507
0
{
508
0
    const char *pri1_msg = " for level 'pri' and above";
509
0
    const char *pri2_msg = " for levels 'p1' to 'p2'";
510
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
511
0
    fprintf(outf, "%se:           log to standard error\n", lead);
512
0
    fprintf(outf, "%so:           log to standard output\n", lead);
513
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
514
0
    fprintf(outf, "%sn:           don't log at all\n", lead);
515
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
516
0
    fprintf(outf, "%sf file:      log to the specified file\n", lead);
517
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
518
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
519
0
    fprintf(outf, "%ss facility:  log to syslog (via the specified facility)\n", lead);
520
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
521
0
    fprintf(outf, "\n%s(variants)\n", lead);
522
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
523
0
    fprintf(outf, "%s[EON] pri:   log to standard error, output or /dev/null%s\n", lead, pri1_msg);
524
0
    fprintf(outf, "%s[EON] p1-p2: log to standard error, output or /dev/null%s\n", lead, pri2_msg);
525
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
526
0
    fprintf(outf, "%s[FS] pri token:    log to file/syslog%s\n", lead, pri1_msg);
527
0
    fprintf(outf, "%s[FS] p1-p2 token:  log to file/syslog%s\n", lead, pri2_msg);
528
0
}
529
530
/**
531
 * Is logging done?
532
 *
533
 * @return Returns 0 if logging is off, 1 when it is done.
534
 *
535
 */
536
int
537
snmp_get_do_logging(void)
538
0
{
539
0
    return (logh_enabled > 0);
540
0
}
541
542
543
static char    *
544
snprintf_stamp(time_t * now, char *sbuf, size_t sbuf_len)
545
0
{
546
0
    time_t          Now;
547
0
    struct tm      *tm;
548
549
0
    if (now == NULL) {
550
0
        now = &Now;
551
0
        time(now);
552
0
    }
553
0
    tm = localtime(now);
554
0
    if (tm)
555
0
        snprintf(sbuf, sbuf_len, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
556
0
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
557
0
                tm->tm_hour, tm->tm_min, tm->tm_sec);
558
0
    else
559
0
        snprintf(sbuf, sbuf_len, "(unknown)");
560
0
    return sbuf;
561
0
}
562
563
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
564
void
565
snmp_disable_syslog_entry(netsnmp_log_handler *logh)
566
0
{
567
0
    if (!logh || !logh->enabled || logh->type != NETSNMP_LOGHANDLER_SYSLOG)
568
0
        return;
569
570
#ifdef WIN32
571
    if (logh->magic) {
572
        HANDLE eventlog_h = (HANDLE)logh->magic;
573
        CloseEventLog(eventlog_h);
574
        logh->magic = NULL;
575
    }
576
#else
577
0
    closelog();
578
0
    logh->imagic  = 0;
579
0
#endif
580
581
0
    netsnmp_disable_this_loghandler(logh);
582
0
}
583
584
void
585
snmp_disable_syslog(void)
586
0
{
587
0
    netsnmp_log_handler *logh;
588
589
0
    for (logh = logh_head; logh; logh = logh->next)
590
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_SYSLOG)
591
0
            snmp_disable_syslog_entry(logh);
592
0
}
593
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
594
595
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
596
void
597
snmp_disable_filelog_entry(netsnmp_log_handler *logh)
598
0
{
599
0
    if (!logh /* || !logh->enabled */ || logh->type != NETSNMP_LOGHANDLER_FILE)
600
0
        return;
601
602
0
    if (logh->magic) {
603
0
        fputs("\n", (FILE*)logh->magic);  /* XXX - why? */
604
0
        fclose((FILE*)logh->magic);
605
0
        logh->magic   = NULL;
606
0
    }
607
0
    netsnmp_disable_this_loghandler(logh);
608
0
}
609
610
void
611
snmp_disable_filelog(void)
612
0
{
613
0
    netsnmp_log_handler *logh;
614
615
0
    for (logh = logh_head; logh; logh = logh->next)
616
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_FILE)
617
0
            snmp_disable_filelog_entry(logh);
618
0
}
619
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
620
621
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
622
623
netsnmp_log_handler *
624
netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
625
                                  const char *tok)
626
0
{
627
0
    netsnmp_log_handler *logh =
628
0
        netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority);
629
0
    if (NULL == logh) {
630
0
        return NULL;
631
0
    }
632
0
    if (is_stdout) {
633
0
        netsnmp_set_line_buffering(stdout);
634
0
        logh->imagic = 1; /* stdout, not stderr */
635
0
    } else
636
0
        netsnmp_set_line_buffering(stderr);
637
638
0
    logh->pri_max = priority_max;
639
0
    if (tok)
640
0
        logh->token   = strdup(tok);
641
0
    return logh;
642
0
}
643
644
/*
645
 * returns that status of stderr logging
646
 *
647
 * @retval 0 : stderr logging disabled
648
 * @retval 1 : stderr logging enabled
649
 */
650
int
651
snmp_stderrlog_status(void)
652
0
{
653
0
    netsnmp_log_handler *logh;
654
655
0
    for (logh = logh_head; logh; logh = logh->next)
656
0
        if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
657
0
                              logh->type == NETSNMP_LOGHANDLER_STDERR)) {
658
0
            return 1;
659
0
       }
660
661
0
    return 0;
662
0
}
663
664
void
665
snmp_disable_stderrlog(void)
666
0
{
667
0
    netsnmp_log_handler *logh;
668
669
0
    for (logh = logh_head; logh; logh = logh->next)
670
0
        if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
671
0
                              logh->type == NETSNMP_LOGHANDLER_STDERR)) {
672
0
            netsnmp_disable_this_loghandler(logh);
673
0
  }
674
0
}
675
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
676
677
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
678
void
679
snmp_disable_calllog(void)
680
0
{
681
0
    netsnmp_log_handler *logh;
682
683
0
    for (logh = logh_head; logh; logh = logh->next)
684
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
685
0
            netsnmp_disable_this_loghandler(logh);
686
0
  }
687
0
}
688
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
689
690
void
691
snmp_disable_log(void)
692
0
{
693
0
    netsnmp_log_handler *logh;
694
695
0
    for (logh = logh_head; logh; logh = logh->next) {
696
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
697
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG)
698
0
            snmp_disable_syslog_entry(logh);
699
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
700
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
701
0
        if (logh->type == NETSNMP_LOGHANDLER_FILE)
702
0
            snmp_disable_filelog_entry(logh);
703
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
704
0
        netsnmp_disable_this_loghandler(logh);
705
0
    }
706
0
}
707
708
/*
709
 * close and reopen all file based logs, to allow logfile
710
 * rotation.
711
 */
712
void
713
netsnmp_logging_restart(void)
714
0
{
715
0
    netsnmp_log_handler *logh;
716
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
717
0
    int doneone = 0;
718
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
719
720
0
    for (logh = logh_head; logh; logh = logh->next) {
721
0
        if (0 == logh->enabled)
722
0
            continue;
723
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
724
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
725
0
            snmp_disable_syslog_entry(logh);
726
0
            snmp_enable_syslog_ident(logh->token,(int)(intptr_t)logh->magic);
727
0
            doneone = 1;
728
0
        }
729
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
730
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
731
0
        if (logh->type == NETSNMP_LOGHANDLER_FILE && !doneone) {
732
0
            snmp_disable_filelog_entry(logh);
733
            /** hmm, don't zero status isn't saved.. i think it's
734
             * safer not to overwrite, in case a hup is just to
735
             * re-read config files...
736
             */
737
0
            netsnmp_enable_filelog(logh, 1);
738
0
        }
739
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
740
0
    }
741
0
}
742
743
/* ================================================== */
744
745
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
746
void
747
snmp_enable_syslog(void)
748
0
{
749
0
    snmp_enable_syslog_ident(snmp_log_syslogname(NULL), LOG_DAEMON);
750
0
}
751
752
void
753
snmp_enable_syslog_ident(const char *ident, const int facility)
754
0
{
755
0
    netsnmp_log_handler *logh;
756
0
    int                  found = 0;
757
0
    int                  enable = 1;
758
#ifdef WIN32
759
    HANDLE               eventlog_h;
760
#else
761
0
    void                *eventlog_h = NULL;
762
0
#endif
763
764
0
    snmp_disable_syslog();     /* only one syslog at a time */
765
#ifdef WIN32
766
    eventlog_h = OpenEventLog(NULL, ident);
767
    if (eventlog_h == NULL) {
768
      /*
769
       * Hmmm.....
770
       * Maybe disable this handler, and log the error ?
771
       */
772
        fprintf(stderr, "Could not open event log for %s. Last error: %u\n",
773
                ident, (unsigned int)GetLastError());
774
        enable = 0;
775
    }
776
#else
777
0
    openlog(snmp_log_syslogname(ident), LOG_CONS | LOG_PID, facility);
778
0
#endif
779
780
0
    for (logh = logh_head; logh; logh = logh->next)
781
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
782
0
            logh->magic   = (void*)eventlog_h;
783
0
            logh->imagic  = enable; /* syslog open */
784
0
            if (logh->enabled && (0 == enable))
785
0
                netsnmp_disable_this_loghandler(logh);
786
0
            else if ((0 == logh->enabled) && enable)
787
0
                netsnmp_enable_this_loghandler(logh);
788
0
            found         = 1;
789
0
  }
790
791
0
    if (!found) {
792
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG,
793
0
                                           LOG_DEBUG );
794
0
        if (logh) {
795
0
            logh->magic    = (void*)eventlog_h;
796
0
            logh->token    = strdup(ident);
797
0
            logh->imagic   = enable;  /* syslog open */
798
0
            if (logh->enabled && (0 == enable))
799
0
                netsnmp_disable_this_loghandler(logh);
800
0
            else if ((0 == logh->enabled) && enable)
801
0
                netsnmp_enable_this_loghandler(logh);
802
0
        }
803
0
    }
804
0
}
805
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
806
807
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
808
void
809
netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log)
810
0
{
811
0
    FILE *logfile;
812
813
0
    if (!logh)
814
0
        return;
815
816
0
    if (!logh->magic) {
817
0
        logfile = fopen(logh->token, dont_zero_log ? "a" : "w");
818
0
        if (!logfile) {
819
0
      snmp_log_perror(logh->token);
820
0
            return;
821
0
  }
822
0
        logh->magic = (void*)logfile;
823
0
        netsnmp_set_line_buffering(logfile);
824
0
    }
825
0
    netsnmp_enable_this_loghandler(logh);
826
0
}
827
828
netsnmp_log_handler *
829
netsnmp_register_filelog_handler(const char* logfilename, int priority,
830
                                 int priority_max, int dont_zero_log)
831
0
{
832
0
    netsnmp_log_handler *logh =
833
0
        netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE,
834
0
                                    priority );
835
0
    if (NULL == logh)
836
0
        return NULL;
837
0
    logh->pri_max = priority_max;
838
0
    logh->token = strdup(logfilename);
839
0
    if (-1 == dont_zero_log)
840
0
        dont_zero_log = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
841
0
                                               NETSNMP_DS_LIB_APPEND_LOGFILES);
842
0
    netsnmp_enable_filelog(logh, dont_zero_log);
843
0
    return logh;
844
0
}
845
846
void
847
snmp_enable_filelog(const char *logfilename, int dont_zero_log)
848
0
{
849
0
    netsnmp_log_handler *logh;
850
851
    /*
852
     * don't disable ALL filelogs whenever a new one is enabled.
853
     * this prevents '-Lf file' from working in snmpd, as the
854
     * call to set up /var/log/snmpd.log will disable the previous
855
     * log setup.
856
     * snmp_disable_filelog();
857
     */
858
859
0
    if (logfilename) {
860
0
        logh = netsnmp_find_loghandler( logfilename );
861
0
        if (!logh)
862
0
            logh = netsnmp_register_filelog_handler( logfilename, LOG_DEBUG,
863
0
                                                     0, dont_zero_log );
864
0
        else
865
0
            netsnmp_enable_filelog(logh, dont_zero_log);
866
0
    } else {
867
0
        for (logh = logh_head; logh; logh = logh->next)
868
0
            if (logh->type == NETSNMP_LOGHANDLER_FILE)
869
0
                netsnmp_enable_filelog(logh, dont_zero_log);
870
0
    }
871
0
}
872
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
873
874
875
#ifndef NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG
876
/* used in the perl modules and ip-mib/ipv4InterfaceTable/ipv4InterfaceTable_subagent.c */
877
void
878
snmp_enable_stderrlog(void)
879
0
{
880
0
    netsnmp_log_handler *logh;
881
0
    int                  found = 0;
882
883
0
    for (logh = logh_head; logh; logh = logh->next)
884
0
        if (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
885
0
            logh->type == NETSNMP_LOGHANDLER_STDERR) {
886
0
            netsnmp_enable_this_loghandler(logh);
887
0
            found         = 1;
888
0
        }
889
890
0
    if (!found) {
891
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR,
892
0
                                           LOG_DEBUG );
893
0
        if (logh)
894
0
            logh->token    = strdup("stderr");
895
0
    }
896
0
}
897
#endif /* NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG */
898
899
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
900
void
901
snmp_enable_calllog(void) /* XXX - or take a callback routine ??? */
902
0
{
903
0
    netsnmp_log_handler *logh;
904
0
    int                  found = 0;
905
906
0
    for (logh = logh_head; logh; logh = logh->next)
907
0
        if (logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
908
0
            netsnmp_enable_this_loghandler(logh);
909
0
            found         = 1;
910
0
  }
911
912
0
    if (!found) {
913
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_CALLBACK,
914
0
                                           LOG_DEBUG );
915
0
        if (logh)
916
0
            logh->token    = strdup("callback");
917
0
    }
918
0
}
919
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
920
921
922
/* ==================================================== */
923
924
925
netsnmp_log_handler *
926
netsnmp_find_loghandler( const char *token )
927
0
{
928
0
    netsnmp_log_handler *logh;
929
0
    if (!token)
930
0
        return NULL;
931
932
0
    for (logh = logh_head; logh; logh = logh->next)
933
0
        if (logh->token && !strcmp( token, logh->token ))
934
0
            break;
935
936
0
    return logh;
937
0
}
938
939
int
940
netsnmp_add_loghandler( netsnmp_log_handler *logh )
941
0
{
942
0
    int i;
943
0
    netsnmp_log_handler *logh2;
944
945
0
    if (!logh)
946
0
        return 0;
947
948
    /*
949
     * Find the appropriate point for the new entry...
950
     *   (logh2 will point to the entry immediately following)
951
     */
952
0
    for (logh2 = logh_head; logh2; logh2 = logh2->next)
953
0
        if ( logh2->priority >= logh->priority )
954
0
            break;
955
956
    /*
957
     * ... and link it into the main list.
958
     */
959
0
    if (logh2) {
960
0
        if (logh2->prev)
961
0
            logh2->prev->next = logh;
962
0
        else
963
0
            logh_head = logh;
964
0
        logh->prev = logh2->prev;
965
0
        logh->next  = logh2;
966
0
        logh2->prev = logh;
967
0
    } else if (logh_head ) {
968
        /*
969
         * If logh2 is NULL, we're tagging on to the end
970
         */
971
0
        for (logh2 = logh_head; logh2->next; logh2 = logh2->next)
972
0
            ;
973
0
        logh2->next = logh;
974
0
        logh->prev = logh2;
975
0
    } else {
976
0
        logh_head = logh;
977
0
    }
978
979
    /*
980
     * Also tweak the relevant priority-'index' array.
981
     */
982
0
    for (i=LOG_EMERG; i<=logh->priority && i<=LOG_DEBUG; i++)
983
0
        if (!logh_priorities[i] ||
984
0
             logh_priorities[i]->priority >= logh->priority)
985
0
             logh_priorities[i] = logh;
986
987
0
    return 1;
988
0
}
989
990
netsnmp_log_handler *
991
netsnmp_register_loghandler( int type, int priority )
992
0
{
993
0
    netsnmp_log_handler *logh;
994
995
0
    logh = SNMP_MALLOC_TYPEDEF(netsnmp_log_handler);
996
0
    if (!logh)
997
0
        return NULL;
998
999
0
    DEBUGMSGT(("logging:register", "registering log type %d with pri %d\n",
1000
0
               type, priority));
1001
0
    if (priority > LOG_DEBUG) {
1002
0
        DEBUGMSGT(("logging:register", "  limiting pri %d to %d\n", priority,
1003
0
                   LOG_DEBUG));
1004
0
        priority = LOG_DEBUG;
1005
0
    }
1006
1007
0
    logh->type     = type;
1008
0
    switch ( type ) {
1009
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1010
0
    case NETSNMP_LOGHANDLER_STDOUT:
1011
0
        logh->imagic  = 1;
1012
0
        logh->handler = log_handler_stdouterr;
1013
0
        break;
1014
0
    case NETSNMP_LOGHANDLER_STDERR:
1015
0
        logh->handler = log_handler_stdouterr;
1016
0
        break;
1017
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1018
1019
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1020
0
    case NETSNMP_LOGHANDLER_FILE:
1021
0
        logh->handler = log_handler_file;
1022
0
        logh->imagic  = 1;
1023
0
        break;
1024
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1025
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1026
0
    case NETSNMP_LOGHANDLER_SYSLOG:
1027
0
        logh->handler = log_handler_syslog;
1028
0
        break;
1029
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1030
0
    case NETSNMP_LOGHANDLER_CALLBACK:
1031
0
        logh->handler = log_handler_callback;
1032
0
        break;
1033
0
    case NETSNMP_LOGHANDLER_NONE:
1034
0
        logh->handler = log_handler_null;
1035
0
        break;
1036
0
    default:
1037
0
        free(logh);
1038
0
        return NULL;
1039
0
    }
1040
0
    logh->priority = priority;
1041
0
    netsnmp_enable_this_loghandler(logh);
1042
0
    netsnmp_add_loghandler( logh );
1043
0
    return logh;
1044
0
}
1045
1046
1047
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER
1048
int
1049
netsnmp_enable_loghandler( const char *token )
1050
0
{
1051
0
    netsnmp_log_handler *logh;
1052
1053
0
    logh = netsnmp_find_loghandler( token );
1054
0
    if (!logh)
1055
0
        return 0;
1056
0
    netsnmp_enable_this_loghandler(logh);
1057
0
    return 1;
1058
0
}
1059
1060
1061
int
1062
netsnmp_disable_loghandler( const char *token )
1063
0
{
1064
0
    netsnmp_log_handler *logh;
1065
1066
0
    logh = netsnmp_find_loghandler( token );
1067
0
    if (!logh)
1068
0
        return 0;
1069
0
    netsnmp_disable_this_loghandler(logh);
1070
0
    return 1;
1071
0
}
1072
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER */
1073
1074
int
1075
netsnmp_remove_loghandler( netsnmp_log_handler *logh )
1076
0
{
1077
0
    int i;
1078
0
    if (!logh)
1079
0
        return 0;
1080
1081
0
    if (logh->prev)
1082
0
        logh->prev->next = logh->next;
1083
0
    else
1084
0
        logh_head = logh->next;
1085
1086
0
    if (logh->next)
1087
0
        logh->next->prev = logh->prev;
1088
1089
0
    for (i=LOG_EMERG; i<=logh->priority && i<=LOG_DEBUG; i++)
1090
0
        if (logh == logh_priorities[i])
1091
0
            logh_priorities[i] = logh->next;
1092
0
    free(NETSNMP_REMOVE_CONST(char*, logh->token));
1093
0
    SNMP_FREE(logh);
1094
1095
0
    return 1;
1096
0
}
1097
1098
/* ==================================================== */
1099
1100
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1101
int
1102
log_handler_stdouterr(  netsnmp_log_handler* logh, int pri, const char *str)
1103
22.9k
{
1104
22.9k
    static int      newline = 1;   /* MTCRITICAL_RESOURCE */
1105
22.9k
    const char     *newline_ptr;
1106
22.9k
    char            sbuf[40];
1107
1108
22.9k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1109
22.9k
                               NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) {
1110
0
        snprintf_stamp(NULL, sbuf, sizeof(sbuf));
1111
22.9k
    } else {
1112
22.9k
        strcpy(sbuf, "");
1113
22.9k
    }
1114
    /*
1115
     * Remember whether or not the current line ends with a newline for the
1116
     * next call of log_handler_stdouterr().
1117
     */
1118
22.9k
    newline_ptr = strrchr(str, '\n');
1119
22.9k
    newline = newline_ptr && newline_ptr[1] == 0;
1120
1121
22.9k
    if (logh->imagic)
1122
0
       printf(         "%s%s", sbuf, str);
1123
22.9k
    else
1124
22.9k
       fprintf(stderr, "%s%s", sbuf, str);
1125
1126
22.9k
    return 1;
1127
22.9k
}
1128
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1129
1130
1131
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1132
#ifdef WIN32
1133
int
1134
log_handler_syslog(  netsnmp_log_handler* logh, int pri, const char *str)
1135
{
1136
    WORD            etype;
1137
    LPCTSTR         event_msg[2];
1138
    HANDLE          eventlog_h = logh->magic;
1139
1140
        /*
1141
         **  EVENT TYPES:
1142
         **
1143
         **  Information (EVENTLOG_INFORMATION_TYPE)
1144
         **      Information events indicate infrequent but significant
1145
         **      successful operations.
1146
         **  Warning (EVENTLOG_WARNING_TYPE)
1147
         **      Warning events indicate problems that are not immediately
1148
         **      significant, but that may indicate conditions that could
1149
         **      cause future problems. Resource consumption is a good
1150
         **      candidate for a warning event.
1151
         **  Error (EVENTLOG_ERROR_TYPE)
1152
         **      Error events indicate significant problems that the user
1153
         **      should know about. Error events usually indicate a loss of
1154
         **      functionality or data.
1155
         */
1156
    switch (pri) {
1157
        case LOG_EMERG:
1158
        case LOG_ALERT:
1159
        case LOG_CRIT:
1160
        case LOG_ERR:
1161
            etype = EVENTLOG_ERROR_TYPE;
1162
            break;
1163
        case LOG_WARNING:
1164
            etype = EVENTLOG_WARNING_TYPE;
1165
            break;
1166
        case LOG_NOTICE:
1167
        case LOG_INFO:
1168
        case LOG_DEBUG:
1169
            etype = EVENTLOG_INFORMATION_TYPE;
1170
            break;
1171
        default:
1172
            etype = EVENTLOG_INFORMATION_TYPE;
1173
            break;
1174
    }
1175
    event_msg[0] = str;
1176
    event_msg[1] = NULL;
1177
    /* NOTE: 4th parameter must match winservice.mc:MessageId value */
1178
    if (!ReportEvent(eventlog_h, etype, 0, 100, NULL, 1, 0, event_msg, NULL)) {
1179
      /*
1180
       * Hmmm.....
1181
       * Maybe disable this handler, and log the error ?
1182
       */
1183
        fprintf(stderr, "Could not report event.  Last error: %u\n",
1184
                (unsigned int)GetLastError());
1185
        return 0;
1186
    }
1187
    return 1;
1188
}
1189
#else
1190
int
1191
log_handler_syslog(  netsnmp_log_handler* logh, int pri, const char *str)
1192
0
{
1193
  /*
1194
   * XXX
1195
   * We've got three items of information to work with:
1196
   *     Is the syslog currently open?
1197
   *     What ident string to use?
1198
   *     What facility to log to?
1199
   *
1200
   * We've got two "magic" locations (imagic & magic) plus the token
1201
   */
1202
0
    if (!(logh->imagic)) {
1203
0
        const char *ident    = logh->token;
1204
0
        int   facility = (int)(intptr_t)logh->magic;
1205
0
        if (!ident)
1206
0
            ident = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1207
0
                                          NETSNMP_DS_LIB_APPTYPE);
1208
0
        openlog(ident, LOG_CONS | LOG_PID, facility);
1209
0
        logh->imagic = 1;
1210
0
    }
1211
0
    syslog( pri, "%s", str );
1212
0
    return 1;
1213
0
}
1214
#endif /* !WIN32 */
1215
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1216
1217
1218
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1219
int
1220
log_handler_file(    netsnmp_log_handler* logh, int pri, const char *str)
1221
0
{
1222
0
    FILE           *fhandle;
1223
0
    char            sbuf[40];
1224
0
    int             len = strlen( str );
1225
1226
    /*
1227
     * We use imagic to save information about whether the next output
1228
     * will start a new line, and thus might need a timestamp
1229
     */
1230
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1231
0
                               NETSNMP_DS_LIB_LOG_TIMESTAMP) && logh->imagic) {
1232
0
        snprintf_stamp(NULL, sbuf, sizeof(sbuf));
1233
0
    } else {
1234
0
        strcpy(sbuf, "");
1235
0
    }
1236
1237
    /*
1238
     * If we haven't already opened the file, then do so.
1239
     * Save the filehandle pointer for next time.
1240
     *
1241
     * Note that this should still work, even if the file
1242
     * is closed in the meantime (e.g. a regular "cleanup" sweep)
1243
     */
1244
0
    fhandle = (FILE*)logh->magic;
1245
0
    if (!logh->magic) {
1246
0
        fhandle = fopen(logh->token, "a+");
1247
0
        if (!fhandle)
1248
0
            return 0;
1249
0
        logh->magic = (void*)fhandle;
1250
0
    }
1251
0
    fprintf(fhandle, "%s%s", sbuf, str);
1252
0
    fflush(fhandle);
1253
0
    if (len > 0) {
1254
0
        logh->imagic = str[len - 1] == '\n';
1255
0
    } else {
1256
0
        logh->imagic = 0;
1257
0
    }
1258
0
    return 1;
1259
0
}
1260
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1261
1262
int
1263
log_handler_callback(netsnmp_log_handler* logh, int pri, const char *str)
1264
0
{
1265
  /*
1266
   * XXX - perhaps replace 'snmp_call_callbacks' processing
1267
   *       with individual callback log_handlers ??
1268
   */
1269
0
    struct snmp_log_message slm;
1270
0
    int             dodebug = snmp_get_do_debugging();
1271
1272
0
    slm.priority = pri;
1273
0
    slm.msg = str;
1274
0
    if (dodebug)            /* turn off debugging inside the callbacks else will loop */
1275
0
        snmp_set_do_debugging(0);
1276
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm);
1277
0
    if (dodebug)
1278
0
        snmp_set_do_debugging(dodebug);
1279
0
    return 1;
1280
0
}
1281
1282
int
1283
log_handler_null(    netsnmp_log_handler* logh, int pri, const char *str)
1284
0
{
1285
    /*
1286
     * Dummy log handler - just throw away the error completely
1287
     * You probably don't really want to do this!
1288
     */
1289
0
    return 1;
1290
0
}
1291
1292
void
1293
snmp_log_string(int priority, const char *str)
1294
22.9k
{
1295
22.9k
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1296
22.9k
    static int stderr_enabled = 0;
1297
22.9k
    static netsnmp_log_handler lh = { 1, 0, 0, 0, "stderr",
1298
22.9k
                                      log_handler_stdouterr, 0, NULL,  NULL,
1299
22.9k
                                      NULL };
1300
22.9k
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1301
22.9k
    netsnmp_log_handler *logh;
1302
1303
    /*
1304
     * We've got to be able to log messages *somewhere*!
1305
     * If you don't want stderr logging, then enable something else.
1306
     */
1307
22.9k
    if (0 == logh_enabled) {
1308
22.9k
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1309
22.9k
        if (!stderr_enabled) {
1310
1
            ++stderr_enabled;
1311
1
            netsnmp_set_line_buffering(stderr);
1312
1
        }
1313
22.9k
        log_handler_stdouterr( &lh, priority, str );
1314
22.9k
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1315
1316
22.9k
        return;
1317
22.9k
    }
1318
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1319
0
    else if (stderr_enabled) {
1320
0
        stderr_enabled = 0;
1321
0
        log_handler_stdouterr( &lh, LOG_INFO,
1322
0
                               "Log handling defined - disabling stderr\n" );
1323
0
    }
1324
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1325
        
1326
1327
    /*
1328
     * Start at the given priority, and work "upwards"....
1329
     */
1330
0
    if (priority < LOG_EMERG)
1331
0
        priority = LOG_EMERG;
1332
0
    else if (priority > LOG_DEBUG)
1333
0
        priority = LOG_DEBUG;
1334
0
    logh = logh_priorities[priority];
1335
0
    for ( ; logh; logh = logh->next ) {
1336
        /*
1337
         * ... but skipping any handlers with a "maximum priority"
1338
         *     that we have already exceeded. And don't forget to
1339
         *     ensure this logging is turned on (see snmp_disable_stderrlog
1340
         *     and its cohorts).
1341
         */
1342
0
        if (logh->enabled && priority >= logh->pri_max)
1343
0
            logh->handler( logh, priority, str );
1344
0
    }
1345
0
}
1346
1347
/* ==================================================== */
1348
1349
1350
/**
1351
 * This snmp logging function allows variable argument list given the
1352
 * specified priority, format and a populated va_list structure.
1353
 * The default logfile this function writes to is /var/log/snmpd.log.
1354
 *
1355
 * @param priority is an integer representing the type of message to be written
1356
 *  to the snmp log file.  The types are errors, warning, and information.
1357
 *      - The error types are:
1358
 *        - LOG_EMERG       system is unusable 
1359
 *        - LOG_ALERT       action must be taken immediately 
1360
 *        - LOG_CRIT        critical conditions 
1361
 *        - LOG_ERR         error conditions
1362
 *      - The warning type is:
1363
 *        - LOG_WARNING     warning conditions 
1364
 *      - The information types are:
1365
 *        - LOG_NOTICE      normal but significant condition
1366
 *        - LOG_INFO        informational
1367
 *        - LOG_DEBUG       debug-level messages
1368
 *
1369
 * @param format is a pointer to a char representing the variable argument list
1370
 *  format used.
1371
 *
1372
 * @param ap is a va_list type used to traverse the list of arguments.
1373
 *
1374
 * @return Returns 0 on success, -1 when the code could not format the log-
1375
 *         string, -2 when dynamic memory could not be allocated if the length
1376
 *         of the log buffer is greater then 1024 bytes.  For each of these
1377
 *         errors a LOG_ERR message is written to the logfile.
1378
 *
1379
 * @see snmp_log
1380
 */
1381
int
1382
snmp_vlog(int priority, const char *format, va_list ap)
1383
22.9k
{
1384
22.9k
    char           *buffer = NULL;
1385
22.9k
    int             length;
1386
1387
22.9k
    length = vasprintf(&buffer, format, ap);
1388
22.9k
    if (length < 0) {
1389
0
        snmp_log_string(LOG_ERR, "Could not format log-string\n");
1390
0
        return -1;
1391
0
    }
1392
1393
22.9k
    snmp_log_string(priority, buffer);
1394
22.9k
    free(buffer);
1395
22.9k
    return 0;
1396
22.9k
}
1397
1398
/**
1399
 * This snmp logging function allows variable argument list given the
1400
 * specified format and priority.  Calls the snmp_vlog function.
1401
 * The default logfile this function writes to is /var/log/snmpd.log.
1402
 *
1403
 * @see snmp_vlog
1404
 */
1405
int
1406
snmp_log(int priority, const char *format, ...)
1407
22.9k
{
1408
22.9k
    va_list         ap;
1409
22.9k
    int             ret;
1410
22.9k
    va_start(ap, format);
1411
22.9k
    ret = snmp_vlog(priority, format, ap);
1412
22.9k
    va_end(ap);
1413
22.9k
    return (ret);
1414
22.9k
}
1415
1416
/*
1417
 * log a critical error.
1418
 */
1419
void
1420
snmp_log_perror(const char *s)
1421
380
{
1422
380
    char           *error = strerror(errno);
1423
380
    if (s) {
1424
380
        if (error)
1425
380
            snmp_log(LOG_ERR, "%s: %s\n", s, error);
1426
0
        else
1427
0
            snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno);
1428
380
    } else {
1429
0
        if (error)
1430
0
            snmp_log(LOG_ERR, "%s\n", error);
1431
0
        else
1432
0
            snmp_log(LOG_ERR, "Error %d out-of-range\n", errno);
1433
0
    }
1434
380
}
1435
1436
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL
1437
/* external access to logh_head variable */
1438
netsnmp_log_handler  *
1439
get_logh_head(void)
1440
0
{
1441
0
  return logh_head;
1442
0
}
1443
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL */
1444
1445
/**  @} */