Coverage Report

Created: 2023-11-19 06:08

/src/net-snmp/snmplib/snmp_logging.c
Line
Count
Source (jump to first uncovered line)
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
netsnmp_log_handler *logh_head = NULL;
115
netsnmp_log_handler *logh_priorities[LOG_DEBUG+1];
116
static int  logh_enabled = 0;
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
2.63k
{
169
2.63k
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp", 
170
2.63k
       NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP);
171
2.63k
    register_prenetsnmp_mib_handler("snmp", "logOption",
172
2.63k
                                    parse_config_logOption, NULL, "string");
173
174
2.63k
}
175
176
void
177
shutdown_snmp_logging(void)
178
2.63k
{
179
2.63k
   snmp_disable_log();
180
2.63k
   while(NULL != logh_head)
181
0
      netsnmp_remove_loghandler( logh_head );
182
2.63k
}
183
184
/* Set line buffering mode for a stream. */
185
void
186
netsnmp_set_line_buffering(FILE *stream)
187
13
{
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
13
    setvbuf(stream, NULL, _IOLBF, BUFSIZ);
201
13
#endif
202
13
}
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. 0x7 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_DEBUG;
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
    optarg++;
337
0
    if (!*cp)
338
0
        cp = &missing_opt;
339
340
    /*
341
     * Support '... -Lx=value ....' syntax
342
     */
343
0
    if (*optarg == '=') {
344
0
        optarg++;
345
0
    }
346
    /*
347
     * and '.... "-Lx value" ....'  (*with* the quotes)
348
     */
349
0
    while (*optarg && isspace((unsigned char)(*optarg))) {
350
0
        optarg++;
351
0
    }
352
    /*
353
     * Finally, handle ".... -Lx value ...." syntax
354
     *   (*without* surrounding quotes)
355
     */
356
0
    if ((!*optarg) && (NULL != argv)) {
357
        /*
358
         * We've run off the end of the argument
359
         *  so move on to the next.
360
         * But we might not actually need it, so don't
361
   *  increment optind just yet!
362
         */
363
0
        optarg = argv[optind];
364
0
        inc_optind = 1;
365
0
    }
366
367
0
    DEBUGMSGT(("logging:options", "*cp: '%c'\n", *cp));
368
0
    switch (*cp) {
369
370
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
371
    /*
372
     * Log to Standard Error
373
     */
374
0
    case 'E':
375
0
        priority = decode_priority( &optarg, &pri_max );
376
0
        if (priority == -1)  return -1;
377
0
        if (inc_optind)
378
0
            optind++;
379
0
        NETSNMP_FALLTHROUGH;
380
0
    case 'e':
381
0
        logh = netsnmp_register_stdio_loghandler(0, priority, pri_max, "stderr");
382
0
        break;
383
384
    /*
385
     * Log to Standard Output
386
     */
387
0
    case 'O':
388
0
        priority = decode_priority( &optarg, &pri_max );
389
0
        if (priority == -1)  return -1;
390
0
        if (inc_optind)
391
0
            optind++;
392
0
        NETSNMP_FALLTHROUGH;
393
0
    case 'o':
394
0
        logh = netsnmp_register_stdio_loghandler( 1, priority, pri_max, "stdout" );
395
0
        break;
396
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
397
398
    /*
399
     * Log to a named file
400
     */
401
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
402
0
    case 'F':
403
0
        priority = decode_priority( &optarg, &pri_max );
404
0
        if (priority == -1) return -1;
405
0
        while (*optarg == ' ') optarg++;
406
0
        if (!*optarg && !argv) return -1;
407
0
        else if (!*optarg) optarg = argv[++optind];
408
0
        NETSNMP_FALLTHROUGH;
409
0
    case 'f':
410
0
        if (inc_optind)
411
0
            optind++;
412
0
        if (!optarg) {
413
0
            fprintf(stderr, "Missing log file\n");
414
0
            return -1;
415
0
        }
416
0
        DEBUGMSGTL(("logging:options", "%d-%d: '%s'\n", priority, pri_max, optarg));
417
0
        logh = netsnmp_register_filelog_handler(optarg, priority, pri_max,
418
0
                                                   -1);
419
0
        break;
420
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
421
422
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
423
    /*
424
     * Log to syslog
425
     */
426
0
    case 'S':
427
0
        priority = decode_priority( &optarg, &pri_max );
428
0
        if (priority == -1 || !argv)  return -1;
429
0
        if (!optarg[0]) {
430
            /* The command line argument with priority does not contain log
431
             * facility. The facility must be in next argument then. */
432
0
            optind++;
433
0
            if (optind < argc)
434
0
                optarg = argv[optind];
435
0
        }
436
0
        NETSNMP_FALLTHROUGH;
437
0
    case 's':
438
0
        if (inc_optind)
439
0
            optind++;
440
0
        if (!optarg) {
441
0
            fprintf(stderr, "Missing syslog facility\n");
442
0
            return -1;
443
0
        }
444
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, priority);
445
0
        if (logh) {
446
0
            int facility = decode_facility(optarg);
447
0
            if (facility == -1) {
448
0
                netsnmp_remove_loghandler(logh);
449
0
                return -1;
450
0
            }
451
0
            logh->pri_max = pri_max;
452
0
            logh->token   = strdup(snmp_log_syslogname(NULL));
453
0
            logh->magic   = (void *)(intptr_t)facility;
454
0
      snmp_enable_syslog_ident(snmp_log_syslogname(NULL), facility);
455
0
  }
456
0
        break;
457
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
458
459
    /*
460
     * Don't log 
461
     */
462
0
    case 'N':
463
0
        priority = decode_priority( &optarg, &pri_max );
464
0
        if (priority == -1)  return -1;
465
0
        if (inc_optind)
466
0
            optind++;
467
0
        NETSNMP_FALLTHROUGH;
468
0
    case 'n':
469
        /*
470
         * disable all logs to clean them up (close files, etc),
471
         * remove all log handlers, then register a null handler.
472
         */
473
0
        snmp_disable_log();
474
0
        while(NULL != logh_head)
475
0
            netsnmp_remove_loghandler( logh_head );
476
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, priority);
477
0
        if (logh) {
478
0
            logh->pri_max = pri_max;
479
0
  }
480
0
        break;
481
482
0
    default:
483
0
        fprintf(stderr, "Unknown logging option passed to -L: %c.\n", *cp);
484
0
        return -1;
485
0
    }
486
0
    return 0;
487
0
}
488
489
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
490
char *
491
snmp_log_syslogname(const char *pstr)
492
0
{
493
0
  if (pstr)
494
0
    strlcpy (syslogname, pstr, sizeof(syslogname));
495
496
0
  return syslogname;
497
0
}
498
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
499
500
void
501
snmp_log_options_usage(const char *lead, FILE * outf)
502
0
{
503
0
    const char *pri1_msg = " for level 'pri' and above";
504
0
    const char *pri2_msg = " for levels 'p1' to 'p2'";
505
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
506
0
    fprintf(outf, "%se:           log to standard error\n", lead);
507
0
    fprintf(outf, "%so:           log to standard output\n", lead);
508
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
509
0
    fprintf(outf, "%sn:           don't log at all\n", lead);
510
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
511
0
    fprintf(outf, "%sf file:      log to the specified file\n", lead);
512
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
513
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
514
0
    fprintf(outf, "%ss facility:  log to syslog (via the specified facility)\n", lead);
515
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
516
0
    fprintf(outf, "\n%s(variants)\n", lead);
517
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
518
0
    fprintf(outf, "%s[EON] pri:   log to standard error, output or /dev/null%s\n", lead, pri1_msg);
519
0
    fprintf(outf, "%s[EON] p1-p2: log to standard error, output or /dev/null%s\n", lead, pri2_msg);
520
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
521
0
    fprintf(outf, "%s[FS] pri token:    log to file/syslog%s\n", lead, pri1_msg);
522
0
    fprintf(outf, "%s[FS] p1-p2 token:  log to file/syslog%s\n", lead, pri2_msg);
523
0
}
524
525
/**
526
 * Is logging done?
527
 *
528
 * @return Returns 0 if logging is off, 1 when it is done.
529
 *
530
 */
531
int
532
snmp_get_do_logging(void)
533
0
{
534
0
    return (logh_enabled > 0);
535
0
}
536
537
538
static char    *
539
sprintf_stamp(time_t * now, char *sbuf)
540
126
{
541
126
    time_t          Now;
542
126
    struct tm      *tm;
543
544
126
    if (now == NULL) {
545
126
        now = &Now;
546
126
        time(now);
547
126
    }
548
126
    tm = localtime(now);
549
126
    sprintf(sbuf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
550
126
            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
551
126
            tm->tm_hour, tm->tm_min, tm->tm_sec);
552
126
    return sbuf;
553
126
}
554
555
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
556
void
557
snmp_disable_syslog_entry(netsnmp_log_handler *logh)
558
0
{
559
0
    if (!logh || !logh->enabled || logh->type != NETSNMP_LOGHANDLER_SYSLOG)
560
0
        return;
561
562
#ifdef WIN32
563
    if (logh->magic) {
564
        HANDLE eventlog_h = (HANDLE)logh->magic;
565
        CloseEventLog(eventlog_h);
566
        logh->magic = NULL;
567
    }
568
#else
569
0
    closelog();
570
0
    logh->imagic  = 0;
571
0
#endif
572
573
0
    netsnmp_disable_this_loghandler(logh);
574
0
}
575
576
void
577
snmp_disable_syslog(void)
578
0
{
579
0
    netsnmp_log_handler *logh;
580
581
0
    for (logh = logh_head; logh; logh = logh->next)
582
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_SYSLOG)
583
0
            snmp_disable_syslog_entry(logh);
584
0
}
585
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
586
587
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
588
void
589
snmp_disable_filelog_entry(netsnmp_log_handler *logh)
590
0
{
591
0
    if (!logh /* || !logh->enabled */ || logh->type != NETSNMP_LOGHANDLER_FILE)
592
0
        return;
593
594
0
    if (logh->magic) {
595
0
        fputs("\n", (FILE*)logh->magic);  /* XXX - why? */
596
0
        fclose((FILE*)logh->magic);
597
0
        logh->magic   = NULL;
598
0
    }
599
0
    netsnmp_disable_this_loghandler(logh);
600
0
}
601
602
void
603
snmp_disable_filelog(void)
604
0
{
605
0
    netsnmp_log_handler *logh;
606
607
0
    for (logh = logh_head; logh; logh = logh->next)
608
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_FILE)
609
0
            snmp_disable_filelog_entry(logh);
610
0
}
611
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
612
613
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
614
615
netsnmp_log_handler *
616
netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
617
                                  const char *tok)
618
0
{
619
0
    netsnmp_log_handler *logh =
620
0
        netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority);
621
0
    if (NULL == logh) {
622
0
        return NULL;
623
0
    }
624
0
    if (is_stdout) {
625
0
        netsnmp_set_line_buffering(stdout);
626
0
        logh->imagic = 1; /* stdout, not stderr */
627
0
    } else
628
0
        netsnmp_set_line_buffering(stderr);
629
630
0
    logh->pri_max = priority_max;
631
0
    if (tok)
632
0
        logh->token   = strdup(tok);
633
0
    return logh;
634
0
}
635
636
/*
637
 * returns that status of stderr logging
638
 *
639
 * @retval 0 : stderr logging disabled
640
 * @retval 1 : stderr logging enabled
641
 */
642
int
643
snmp_stderrlog_status(void)
644
0
{
645
0
    netsnmp_log_handler *logh;
646
647
0
    for (logh = logh_head; logh; logh = logh->next)
648
0
        if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
649
0
                              logh->type == NETSNMP_LOGHANDLER_STDERR)) {
650
0
            return 1;
651
0
       }
652
653
0
    return 0;
654
0
}
655
656
void
657
snmp_disable_stderrlog(void)
658
0
{
659
0
    netsnmp_log_handler *logh;
660
661
0
    for (logh = logh_head; logh; logh = logh->next)
662
0
        if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
663
0
                              logh->type == NETSNMP_LOGHANDLER_STDERR)) {
664
0
            netsnmp_disable_this_loghandler(logh);
665
0
  }
666
0
}
667
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
668
669
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
670
void
671
snmp_disable_calllog(void)
672
0
{
673
0
    netsnmp_log_handler *logh;
674
675
0
    for (logh = logh_head; logh; logh = logh->next)
676
0
        if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
677
0
            netsnmp_disable_this_loghandler(logh);
678
0
  }
679
0
}
680
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
681
682
void
683
snmp_disable_log(void)
684
2.63k
{
685
2.63k
    netsnmp_log_handler *logh;
686
687
2.63k
    for (logh = logh_head; logh; logh = logh->next) {
688
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
689
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG)
690
0
            snmp_disable_syslog_entry(logh);
691
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
692
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
693
0
        if (logh->type == NETSNMP_LOGHANDLER_FILE)
694
0
            snmp_disable_filelog_entry(logh);
695
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
696
0
        netsnmp_disable_this_loghandler(logh);
697
0
    }
698
2.63k
}
699
700
/*
701
 * close and reopen all file based logs, to allow logfile
702
 * rotation.
703
 */
704
void
705
netsnmp_logging_restart(void)
706
0
{
707
0
    netsnmp_log_handler *logh;
708
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
709
0
    int doneone = 0;
710
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
711
712
0
    for (logh = logh_head; logh; logh = logh->next) {
713
0
        if (0 == logh->enabled)
714
0
            continue;
715
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
716
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
717
0
            snmp_disable_syslog_entry(logh);
718
0
            snmp_enable_syslog_ident(logh->token,(int)(intptr_t)logh->magic);
719
0
            doneone = 1;
720
0
        }
721
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
722
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
723
0
        if (logh->type == NETSNMP_LOGHANDLER_FILE && !doneone) {
724
0
            snmp_disable_filelog_entry(logh);
725
            /** hmm, don't zero status isn't saved.. i think it's
726
             * safer not to overwrite, in case a hup is just to
727
             * re-read config files...
728
             */
729
0
            netsnmp_enable_filelog(logh, 1);
730
0
        }
731
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
732
0
    }
733
0
}
734
735
/* ================================================== */
736
737
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
738
void
739
snmp_enable_syslog(void)
740
0
{
741
0
    snmp_enable_syslog_ident(snmp_log_syslogname(NULL), LOG_DAEMON);
742
0
}
743
744
void
745
snmp_enable_syslog_ident(const char *ident, const int facility)
746
0
{
747
0
    netsnmp_log_handler *logh;
748
0
    int                  found = 0;
749
0
    int                  enable = 1;
750
#ifdef WIN32
751
    HANDLE               eventlog_h;
752
#else
753
0
    void                *eventlog_h = NULL;
754
0
#endif
755
756
0
    snmp_disable_syslog();     /* only one syslog at a time */
757
#ifdef WIN32
758
    eventlog_h = OpenEventLog(NULL, ident);
759
    if (eventlog_h == NULL) {
760
      /*
761
       * Hmmm.....
762
       * Maybe disable this handler, and log the error ?
763
       */
764
        fprintf(stderr, "Could not open event log for %s. Last error: %u\n",
765
                ident, (unsigned int)GetLastError());
766
        enable = 0;
767
    }
768
#else
769
0
    openlog(snmp_log_syslogname(ident), LOG_CONS | LOG_PID, facility);
770
0
#endif
771
772
0
    for (logh = logh_head; logh; logh = logh->next)
773
0
        if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
774
0
            logh->magic   = (void*)eventlog_h;
775
0
            logh->imagic  = enable; /* syslog open */
776
0
            if (logh->enabled && (0 == enable))
777
0
                netsnmp_disable_this_loghandler(logh);
778
0
            else if ((0 == logh->enabled) && enable)
779
0
                netsnmp_enable_this_loghandler(logh);
780
0
            found         = 1;
781
0
  }
782
783
0
    if (!found) {
784
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG,
785
0
                                           LOG_DEBUG );
786
0
        if (logh) {
787
0
            logh->magic    = (void*)eventlog_h;
788
0
            logh->token    = strdup(ident);
789
0
            logh->imagic   = enable;  /* syslog open */
790
0
            if (logh->enabled && (0 == enable))
791
0
                netsnmp_disable_this_loghandler(logh);
792
0
            else if ((0 == logh->enabled) && enable)
793
0
                netsnmp_enable_this_loghandler(logh);
794
0
        }
795
0
    }
796
0
}
797
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
798
799
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
800
void
801
netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log)
802
0
{
803
0
    FILE *logfile;
804
805
0
    if (!logh)
806
0
        return;
807
808
0
    if (!logh->magic) {
809
0
        logfile = fopen(logh->token, dont_zero_log ? "a" : "w");
810
0
        if (!logfile) {
811
0
      snmp_log_perror(logh->token);
812
0
            return;
813
0
  }
814
0
        logh->magic = (void*)logfile;
815
0
        netsnmp_set_line_buffering(logfile);
816
0
    }
817
0
    netsnmp_enable_this_loghandler(logh);
818
0
}
819
820
netsnmp_log_handler *
821
netsnmp_register_filelog_handler(const char* logfilename, int priority,
822
                                 int priority_max, int dont_zero_log)
823
0
{
824
0
    netsnmp_log_handler *logh =
825
0
        netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE,
826
0
                                    priority );
827
0
    if (NULL == logh)
828
0
        return NULL;
829
0
    logh->pri_max = priority_max;
830
0
    logh->token = strdup(logfilename);
831
0
    if (-1 == dont_zero_log)
832
0
        dont_zero_log = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
833
0
                                               NETSNMP_DS_LIB_APPEND_LOGFILES);
834
0
    netsnmp_enable_filelog(logh, dont_zero_log);
835
0
    return logh;
836
0
}
837
838
void
839
snmp_enable_filelog(const char *logfilename, int dont_zero_log)
840
0
{
841
0
    netsnmp_log_handler *logh;
842
843
    /*
844
     * don't disable ALL filelogs whenever a new one is enabled.
845
     * this prevents '-Lf file' from working in snmpd, as the
846
     * call to set up /var/log/snmpd.log will disable the previous
847
     * log setup.
848
     * snmp_disable_filelog();
849
     */
850
851
0
    if (logfilename) {
852
0
        logh = netsnmp_find_loghandler( logfilename );
853
0
        if (!logh)
854
0
            logh = netsnmp_register_filelog_handler( logfilename, LOG_DEBUG,
855
0
                                                     0, dont_zero_log );
856
0
        else
857
0
            netsnmp_enable_filelog(logh, dont_zero_log);
858
0
    } else {
859
0
        for (logh = logh_head; logh; logh = logh->next)
860
0
            if (logh->type == NETSNMP_LOGHANDLER_FILE)
861
0
                netsnmp_enable_filelog(logh, dont_zero_log);
862
0
    }
863
0
}
864
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
865
866
867
#ifndef NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG
868
/* used in the perl modules and ip-mib/ipv4InterfaceTable/ipv4InterfaceTable_subagent.c */
869
void
870
snmp_enable_stderrlog(void)
871
0
{
872
0
    netsnmp_log_handler *logh;
873
0
    int                  found = 0;
874
875
0
    for (logh = logh_head; logh; logh = logh->next)
876
0
        if (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
877
0
            logh->type == NETSNMP_LOGHANDLER_STDERR) {
878
0
            netsnmp_enable_this_loghandler(logh);
879
0
            found         = 1;
880
0
        }
881
882
0
    if (!found) {
883
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR,
884
0
                                           LOG_DEBUG );
885
0
        if (logh)
886
0
            logh->token    = strdup("stderr");
887
0
    }
888
0
}
889
#endif /* NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG */
890
891
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
892
void
893
snmp_enable_calllog(void) /* XXX - or take a callback routine ??? */
894
0
{
895
0
    netsnmp_log_handler *logh;
896
0
    int                  found = 0;
897
898
0
    for (logh = logh_head; logh; logh = logh->next)
899
0
        if (logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
900
0
            netsnmp_enable_this_loghandler(logh);
901
0
            found         = 1;
902
0
  }
903
904
0
    if (!found) {
905
0
        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_CALLBACK,
906
0
                                           LOG_DEBUG );
907
0
        if (logh)
908
0
            logh->token    = strdup("callback");
909
0
    }
910
0
}
911
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
912
913
914
/* ==================================================== */
915
916
917
netsnmp_log_handler *
918
netsnmp_find_loghandler( const char *token )
919
0
{
920
0
    netsnmp_log_handler *logh;
921
0
    if (!token)
922
0
        return NULL;
923
924
0
    for (logh = logh_head; logh; logh = logh->next)
925
0
        if (logh->token && !strcmp( token, logh->token ))
926
0
            break;
927
928
0
    return logh;
929
0
}
930
931
int
932
netsnmp_add_loghandler( netsnmp_log_handler *logh )
933
0
{
934
0
    int i;
935
0
    netsnmp_log_handler *logh2;
936
937
0
    if (!logh)
938
0
        return 0;
939
940
    /*
941
     * Find the appropriate point for the new entry...
942
     *   (logh2 will point to the entry immediately following)
943
     */
944
0
    for (logh2 = logh_head; logh2; logh2 = logh2->next)
945
0
        if ( logh2->priority >= logh->priority )
946
0
            break;
947
948
    /*
949
     * ... and link it into the main list.
950
     */
951
0
    if (logh2) {
952
0
        if (logh2->prev)
953
0
            logh2->prev->next = logh;
954
0
        else
955
0
            logh_head = logh;
956
0
        logh->next  = logh2;
957
0
        logh2->prev = logh;
958
0
    } else if (logh_head ) {
959
        /*
960
         * If logh2 is NULL, we're tagging on to the end
961
         */
962
0
        for (logh2 = logh_head; logh2->next; logh2 = logh2->next)
963
0
            ;
964
0
        logh2->next = logh;
965
0
    } else {
966
0
        logh_head = logh;
967
0
    }
968
969
    /*
970
     * Also tweak the relevant priority-'index' array.
971
     */
972
0
    for (i=LOG_EMERG; i<=logh->priority; i++)
973
0
        if (!logh_priorities[i] ||
974
0
             logh_priorities[i]->priority >= logh->priority)
975
0
             logh_priorities[i] = logh;
976
977
0
    return 1;
978
0
}
979
980
netsnmp_log_handler *
981
netsnmp_register_loghandler( int type, int priority )
982
0
{
983
0
    netsnmp_log_handler *logh;
984
985
0
    logh = SNMP_MALLOC_TYPEDEF(netsnmp_log_handler);
986
0
    if (!logh)
987
0
        return NULL;
988
989
0
    DEBUGMSGT(("logging:register", "registering log type %d with pri %d\n",
990
0
               type, priority));
991
0
    if (priority > LOG_DEBUG) {
992
0
        DEBUGMSGT(("logging:register", "  limiting pri %d to %d\n", priority,
993
0
                   LOG_DEBUG));
994
0
        priority = LOG_DEBUG;
995
0
    }
996
997
0
    logh->type     = type;
998
0
    switch ( type ) {
999
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1000
0
    case NETSNMP_LOGHANDLER_STDOUT:
1001
0
        logh->imagic  = 1;
1002
0
        logh->handler = log_handler_stdouterr;
1003
0
        break;
1004
0
    case NETSNMP_LOGHANDLER_STDERR:
1005
0
        logh->handler = log_handler_stdouterr;
1006
0
        break;
1007
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1008
1009
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1010
0
    case NETSNMP_LOGHANDLER_FILE:
1011
0
        logh->handler = log_handler_file;
1012
0
        logh->imagic  = 1;
1013
0
        break;
1014
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1015
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1016
0
    case NETSNMP_LOGHANDLER_SYSLOG:
1017
0
        logh->handler = log_handler_syslog;
1018
0
        break;
1019
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1020
0
    case NETSNMP_LOGHANDLER_CALLBACK:
1021
0
        logh->handler = log_handler_callback;
1022
0
        break;
1023
0
    case NETSNMP_LOGHANDLER_NONE:
1024
0
        logh->handler = log_handler_null;
1025
0
        break;
1026
0
    default:
1027
0
        free(logh);
1028
0
        return NULL;
1029
0
    }
1030
0
    logh->priority = priority;
1031
0
    netsnmp_enable_this_loghandler(logh);
1032
0
    netsnmp_add_loghandler( logh );
1033
0
    return logh;
1034
0
}
1035
1036
1037
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER
1038
int
1039
netsnmp_enable_loghandler( const char *token )
1040
0
{
1041
0
    netsnmp_log_handler *logh;
1042
1043
0
    logh = netsnmp_find_loghandler( token );
1044
0
    if (!logh)
1045
0
        return 0;
1046
0
    netsnmp_enable_this_loghandler(logh);
1047
0
    return 1;
1048
0
}
1049
1050
1051
int
1052
netsnmp_disable_loghandler( const char *token )
1053
0
{
1054
0
    netsnmp_log_handler *logh;
1055
1056
0
    logh = netsnmp_find_loghandler( token );
1057
0
    if (!logh)
1058
0
        return 0;
1059
0
    netsnmp_disable_this_loghandler(logh);
1060
0
    return 1;
1061
0
}
1062
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER */
1063
1064
int
1065
netsnmp_remove_loghandler( netsnmp_log_handler *logh )
1066
0
{
1067
0
    int i;
1068
0
    if (!logh)
1069
0
        return 0;
1070
1071
0
    if (logh->prev)
1072
0
        logh->prev->next = logh->next;
1073
0
    else
1074
0
        logh_head = logh->next;
1075
1076
0
    if (logh->next)
1077
0
        logh->next->prev = logh->prev;
1078
1079
0
    for (i=LOG_EMERG; i<=logh->priority; i++)
1080
0
        if (logh == logh_priorities[i])
1081
0
            logh_priorities[i] = logh->next;
1082
0
    free(NETSNMP_REMOVE_CONST(char*, logh->token));
1083
0
    SNMP_FREE(logh);
1084
1085
0
    return 1;
1086
0
}
1087
1088
/* ==================================================== */
1089
1090
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1091
int
1092
log_handler_stdouterr(  netsnmp_log_handler* logh, int pri, const char *str)
1093
6.52M
{
1094
6.52M
    static int      newline = 1;   /* MTCRITICAL_RESOURCE */
1095
6.52M
    const char     *newline_ptr;
1096
6.52M
    char            sbuf[40];
1097
1098
6.52M
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1099
6.52M
                               NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) {
1100
126
        sprintf_stamp(NULL, sbuf);
1101
6.52M
    } else {
1102
6.52M
        strcpy(sbuf, "");
1103
6.52M
    }
1104
    /*
1105
     * Remember whether or not the current line ends with a newline for the
1106
     * next call of log_handler_stdouterr().
1107
     */
1108
6.52M
    newline_ptr = strrchr(str, '\n');
1109
6.52M
    newline = newline_ptr && newline_ptr[1] == 0;
1110
1111
6.52M
    if (logh->imagic)
1112
0
       printf(         "%s%s", sbuf, str);
1113
6.52M
    else
1114
6.52M
       fprintf(stderr, "%s%s", sbuf, str);
1115
1116
6.52M
    return 1;
1117
6.52M
}
1118
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1119
1120
1121
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1122
#ifdef WIN32
1123
int
1124
log_handler_syslog(  netsnmp_log_handler* logh, int pri, const char *str)
1125
{
1126
    WORD            etype;
1127
    LPCTSTR         event_msg[2];
1128
    HANDLE          eventlog_h = logh->magic;
1129
1130
        /*
1131
         **  EVENT TYPES:
1132
         **
1133
         **  Information (EVENTLOG_INFORMATION_TYPE)
1134
         **      Information events indicate infrequent but significant
1135
         **      successful operations.
1136
         **  Warning (EVENTLOG_WARNING_TYPE)
1137
         **      Warning events indicate problems that are not immediately
1138
         **      significant, but that may indicate conditions that could
1139
         **      cause future problems. Resource consumption is a good
1140
         **      candidate for a warning event.
1141
         **  Error (EVENTLOG_ERROR_TYPE)
1142
         **      Error events indicate significant problems that the user
1143
         **      should know about. Error events usually indicate a loss of
1144
         **      functionality or data.
1145
         */
1146
    switch (pri) {
1147
        case LOG_EMERG:
1148
        case LOG_ALERT:
1149
        case LOG_CRIT:
1150
        case LOG_ERR:
1151
            etype = EVENTLOG_ERROR_TYPE;
1152
            break;
1153
        case LOG_WARNING:
1154
            etype = EVENTLOG_WARNING_TYPE;
1155
            break;
1156
        case LOG_NOTICE:
1157
        case LOG_INFO:
1158
        case LOG_DEBUG:
1159
            etype = EVENTLOG_INFORMATION_TYPE;
1160
            break;
1161
        default:
1162
            etype = EVENTLOG_INFORMATION_TYPE;
1163
            break;
1164
    }
1165
    event_msg[0] = str;
1166
    event_msg[1] = NULL;
1167
    /* NOTE: 4th parameter must match winservice.mc:MessageId value */
1168
    if (!ReportEvent(eventlog_h, etype, 0, 100, NULL, 1, 0, event_msg, NULL)) {
1169
      /*
1170
       * Hmmm.....
1171
       * Maybe disable this handler, and log the error ?
1172
       */
1173
        fprintf(stderr, "Could not report event.  Last error: %u\n",
1174
                (unsigned int)GetLastError());
1175
        return 0;
1176
    }
1177
    return 1;
1178
}
1179
#else
1180
int
1181
log_handler_syslog(  netsnmp_log_handler* logh, int pri, const char *str)
1182
0
{
1183
  /*
1184
   * XXX
1185
   * We've got three items of information to work with:
1186
   *     Is the syslog currently open?
1187
   *     What ident string to use?
1188
   *     What facility to log to?
1189
   *
1190
   * We've got two "magic" locations (imagic & magic) plus the token
1191
   */
1192
0
    if (!(logh->imagic)) {
1193
0
        const char *ident    = logh->token;
1194
0
        int   facility = (int)(intptr_t)logh->magic;
1195
0
        if (!ident)
1196
0
            ident = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1197
0
                                          NETSNMP_DS_LIB_APPTYPE);
1198
0
        openlog(ident, LOG_CONS | LOG_PID, facility);
1199
0
        logh->imagic = 1;
1200
0
    }
1201
0
    syslog( pri, "%s", str );
1202
0
    return 1;
1203
0
}
1204
#endif /* !WIN32 */
1205
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1206
1207
1208
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1209
int
1210
log_handler_file(    netsnmp_log_handler* logh, int pri, const char *str)
1211
0
{
1212
0
    FILE           *fhandle;
1213
0
    char            sbuf[40];
1214
0
    int             len = strlen( str );
1215
1216
    /*
1217
     * We use imagic to save information about whether the next output
1218
     * will start a new line, and thus might need a timestamp
1219
     */
1220
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1221
0
                               NETSNMP_DS_LIB_LOG_TIMESTAMP) && logh->imagic) {
1222
0
        sprintf_stamp(NULL, sbuf);
1223
0
    } else {
1224
0
        strcpy(sbuf, "");
1225
0
    }
1226
1227
    /*
1228
     * If we haven't already opened the file, then do so.
1229
     * Save the filehandle pointer for next time.
1230
     *
1231
     * Note that this should still work, even if the file
1232
     * is closed in the meantime (e.g. a regular "cleanup" sweep)
1233
     */
1234
0
    fhandle = (FILE*)logh->magic;
1235
0
    if (!logh->magic) {
1236
0
        fhandle = fopen(logh->token, "a+");
1237
0
        if (!fhandle)
1238
0
            return 0;
1239
0
        logh->magic = (void*)fhandle;
1240
0
    }
1241
0
    fprintf(fhandle, "%s%s", sbuf, str);
1242
0
    fflush(fhandle);
1243
0
    if (len > 0) {
1244
0
        logh->imagic = str[len - 1] == '\n';
1245
0
    } else {
1246
0
        logh->imagic = 0;
1247
0
    }
1248
0
    return 1;
1249
0
}
1250
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1251
1252
int
1253
log_handler_callback(netsnmp_log_handler* logh, int pri, const char *str)
1254
0
{
1255
  /*
1256
   * XXX - perhaps replace 'snmp_call_callbacks' processing
1257
   *       with individual callback log_handlers ??
1258
   */
1259
0
    struct snmp_log_message slm;
1260
0
    int             dodebug = snmp_get_do_debugging();
1261
1262
0
    slm.priority = pri;
1263
0
    slm.msg = str;
1264
0
    if (dodebug)            /* turn off debugging inside the callbacks else will loop */
1265
0
        snmp_set_do_debugging(0);
1266
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm);
1267
0
    if (dodebug)
1268
0
        snmp_set_do_debugging(dodebug);
1269
0
    return 1;
1270
0
}
1271
1272
int
1273
log_handler_null(    netsnmp_log_handler* logh, int pri, const char *str)
1274
0
{
1275
    /*
1276
     * Dummy log handler - just throw away the error completely
1277
     * You probably don't really want to do this!
1278
     */
1279
0
    return 1;
1280
0
}
1281
1282
void
1283
snmp_log_string(int priority, const char *str)
1284
6.52M
{
1285
6.52M
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1286
6.52M
    static int stderr_enabled = 0;
1287
6.52M
    static netsnmp_log_handler lh = { 1, 0, 0, 0, "stderr",
1288
6.52M
                                      log_handler_stdouterr, 0, NULL,  NULL,
1289
6.52M
                                      NULL };
1290
6.52M
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1291
6.52M
    netsnmp_log_handler *logh;
1292
1293
    /*
1294
     * We've got to be able to log messages *somewhere*!
1295
     * If you don't want stderr logging, then enable something else.
1296
     */
1297
6.52M
    if (0 == logh_enabled) {
1298
6.52M
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1299
6.52M
        if (!stderr_enabled) {
1300
13
            ++stderr_enabled;
1301
13
            netsnmp_set_line_buffering(stderr);
1302
13
        }
1303
6.52M
        log_handler_stdouterr( &lh, priority, str );
1304
6.52M
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1305
1306
6.52M
        return;
1307
6.52M
    }
1308
0
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1309
0
    else if (stderr_enabled) {
1310
0
        stderr_enabled = 0;
1311
0
        log_handler_stdouterr( &lh, LOG_INFO,
1312
0
                               "Log handling defined - disabling stderr\n" );
1313
0
    }
1314
0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1315
        
1316
1317
    /*
1318
     * Start at the given priority, and work "upwards"....
1319
     */
1320
0
    if (priority > LOG_DEBUG)
1321
0
        priority = LOG_DEBUG;
1322
0
    logh = logh_priorities[priority];
1323
0
    for ( ; logh; logh = logh->next ) {
1324
        /*
1325
         * ... but skipping any handlers with a "maximum priority"
1326
         *     that we have already exceeded. And don't forget to
1327
         *     ensure this logging is turned on (see snmp_disable_stderrlog
1328
         *     and its cohorts).
1329
         */
1330
0
        if (logh->enabled && priority <= logh->pri_max)
1331
0
            logh->handler( logh, priority, str );
1332
0
    }
1333
0
}
1334
1335
/* ==================================================== */
1336
1337
1338
/**
1339
 * This snmp logging function allows variable argument list given the
1340
 * specified priority, format and a populated va_list structure.
1341
 * The default logfile this function writes to is /var/log/snmpd.log.
1342
 *
1343
 * @param priority is an integer representing the type of message to be written
1344
 *  to the snmp log file.  The types are errors, warning, and information.
1345
 *      - The error types are:
1346
 *        - LOG_EMERG       system is unusable 
1347
 *        - LOG_ALERT       action must be taken immediately 
1348
 *        - LOG_CRIT        critical conditions 
1349
 *        - LOG_ERR         error conditions
1350
 *      - The warning type is:
1351
 *        - LOG_WARNING     warning conditions 
1352
 *      - The information types are:
1353
 *        - LOG_NOTICE      normal but significant condition
1354
 *        - LOG_INFO        informational
1355
 *        - LOG_DEBUG       debug-level messages
1356
 *
1357
 * @param format is a pointer to a char representing the variable argument list
1358
 *  format used.
1359
 *
1360
 * @param ap is a va_list type used to traverse the list of arguments.
1361
 *
1362
 * @return Returns 0 on success, -1 when the code could not format the log-
1363
 *         string, -2 when dynamic memory could not be allocated if the length
1364
 *         of the log buffer is greater then 1024 bytes.  For each of these
1365
 *         errors a LOG_ERR message is written to the logfile.
1366
 *
1367
 * @see snmp_log
1368
 */
1369
int
1370
snmp_vlog(int priority, const char *format, va_list ap)
1371
6.52M
{
1372
6.52M
    char           *buffer = NULL;
1373
6.52M
    int             length;
1374
1375
6.52M
    length = vasprintf(&buffer, format, ap);
1376
6.52M
    if (length < 0) {
1377
0
        snmp_log_string(LOG_ERR, "Could not format log-string\n");
1378
0
        return -1;
1379
0
    }
1380
1381
6.52M
    snmp_log_string(priority, buffer);
1382
6.52M
    free(buffer);
1383
6.52M
    return 0;
1384
6.52M
}
1385
1386
/**
1387
 * This snmp logging function allows variable argument list given the
1388
 * specified format and priority.  Calls the snmp_vlog function.
1389
 * The default logfile this function writes to is /var/log/snmpd.log.
1390
 *
1391
 * @see snmp_vlog
1392
 */
1393
int
1394
snmp_log(int priority, const char *format, ...)
1395
272k
{
1396
272k
    va_list         ap;
1397
272k
    int             ret;
1398
272k
    va_start(ap, format);
1399
272k
    ret = snmp_vlog(priority, format, ap);
1400
272k
    va_end(ap);
1401
272k
    return (ret);
1402
272k
}
1403
1404
/*
1405
 * log a critical error.
1406
 */
1407
void
1408
snmp_log_perror(const char *s)
1409
774
{
1410
774
    char           *error = strerror(errno);
1411
774
    if (s) {
1412
774
        if (error)
1413
774
            snmp_log(LOG_ERR, "%s: %s\n", s, error);
1414
0
        else
1415
0
            snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno);
1416
774
    } else {
1417
0
        if (error)
1418
0
            snmp_log(LOG_ERR, "%s\n", error);
1419
0
        else
1420
0
            snmp_log(LOG_ERR, "Error %d out-of-range\n", errno);
1421
0
    }
1422
774
}
1423
1424
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL
1425
/* external access to logh_head variable */
1426
netsnmp_log_handler  *
1427
get_logh_head(void)
1428
0
{
1429
0
  return logh_head;
1430
0
}
1431
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL */
1432
1433
/**  @} */