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 #if HAVE_MALLOC_H
29 #include <malloc.h>
30 #endif
31 #if HAVE_STRING_H
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36 #include <ctype.h>
37 #if 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 #if HAVE_SYSLOG_H
45 #include <syslog.h>
46 #ifndef LOG_CONS                /* Interesting Ultrix feature */
47 #include <sys/syslog.h>
48 #endif
49 #endif
50 #if TIME_WITH_SYS_TIME
51 # include <sys/time.h>
52 # include <time.h>
53 #else
54 # if HAVE_SYS_TIME_H
55 #  include <sys/time.h>
56 # else
57 #  include <time.h>
58 # endif
59 #endif
60 #if HAVE_NETINET_IN_H
61 #include <netinet/in.h>
62 #endif
63 
64 #include <stdarg.h>
65 
66 #if 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
netsnmp_disable_this_loghandler(netsnmp_log_handler * logh)134 netsnmp_disable_this_loghandler(netsnmp_log_handler *logh)
135 {
136     if (!logh || (0 == logh->enabled))
137         return;
138     logh->enabled = 0;
139     --logh_enabled;
140     netsnmp_assert(logh_enabled >= 0);
141 }
142 
143 void
netsnmp_enable_this_loghandler(netsnmp_log_handler * logh)144 netsnmp_enable_this_loghandler(netsnmp_log_handler *logh)
145 {
146     if (!logh || (0 != logh->enabled))
147         return;
148     logh->enabled = 1;
149     ++logh_enabled;
150 }
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
parse_config_logOption(const char * token,char * cptr)158 parse_config_logOption(const char *token, char *cptr)
159 {
160   int my_argc = 0 ;
161   char **my_argv = NULL;
162 
163   snmp_log_options( cptr, my_argc, my_argv );
164 }
165 
166 void
init_snmp_logging(void)167 init_snmp_logging(void)
168 {
169     netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp",
170 			 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP);
171     register_prenetsnmp_mib_handler("snmp", "logOption",
172                                     parse_config_logOption, NULL, "string");
173 
174 }
175 
176 void
shutdown_snmp_logging(void)177 shutdown_snmp_logging(void)
178 {
179    snmp_disable_log();
180    while(NULL != logh_head)
181       netsnmp_remove_loghandler( logh_head );
182 }
183 
184 /* Set line buffering mode for a stream. */
185 void
netsnmp_set_line_buffering(FILE * stream)186 netsnmp_set_line_buffering(FILE *stream)
187 {
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     setvbuf(stream, NULL, _IOLBF, BUFSIZ);
201 #endif
202 }
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
decode_priority(char ** optarg,int * pri_max)211 decode_priority( char **optarg, int *pri_max )
212 {
213     int pri_low = LOG_DEBUG;
214 
215     if (*optarg == NULL)
216         return -1;
217 
218     switch (**optarg) {
219         case '0':
220         case '!':
221             pri_low = LOG_EMERG;
222             break;
223         case '1':
224         case 'a':
225         case 'A':
226             pri_low = LOG_ALERT;
227             break;
228         case '2':
229         case 'c':
230         case 'C':
231             pri_low = LOG_CRIT;
232             break;
233         case '3':
234         case 'e':
235         case 'E':
236             pri_low = LOG_ERR;
237             break;
238         case '4':
239         case 'w':
240         case 'W':
241             pri_low = LOG_WARNING;
242             break;
243         case '5':
244         case 'n':
245         case 'N':
246             pri_low = LOG_NOTICE;
247             break;
248         case '6':
249         case 'i':
250         case 'I':
251             pri_low = LOG_INFO;
252             break;
253         case '7':
254         case 'd':
255         case 'D':
256             pri_low = LOG_DEBUG;
257             break;
258         default:
259             fprintf(stderr, "invalid priority: %c\n",**optarg);
260             return -1;
261     }
262     *optarg = *optarg+1;
263 
264     if (pri_max && **optarg=='-') {
265         *optarg = *optarg + 1; /* skip '-' */
266         *pri_max = decode_priority( optarg, NULL );
267         if (*pri_max == -1) return -1;
268         if (pri_low < *pri_max) {
269             int tmp = pri_low;
270             pri_low = *pri_max;
271             *pri_max = tmp;
272         }
273 
274     }
275     return pri_low;
276 }
277 
278 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
279 static int
decode_facility(char * optarg)280 decode_facility( char *optarg )
281 {
282     if (optarg == NULL)
283         return -1;
284 
285     switch (*optarg) {
286     case 'd':
287     case 'D':
288         return LOG_DAEMON;
289     case 'u':
290     case 'U':
291         return LOG_USER;
292     case '0':
293         return LOG_LOCAL0;
294     case '1':
295         return LOG_LOCAL1;
296     case '2':
297         return LOG_LOCAL2;
298     case '3':
299         return LOG_LOCAL3;
300     case '4':
301         return LOG_LOCAL4;
302     case '5':
303         return LOG_LOCAL5;
304     case '6':
305         return LOG_LOCAL6;
306     case '7':
307         return LOG_LOCAL7;
308     default:
309         fprintf(stderr, "invalid syslog facility: %c\n",*optarg);
310         return -1;
311     }
312 }
313 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
314 
315 int
snmp_log_options(char * optarg,int argc,char * const * argv)316 snmp_log_options(char *optarg, int argc, char *const *argv)
317 {
318     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     char            missing_opt = 'e';	/* old -L is new -Le */
329     int             priority = LOG_DEBUG;
330     int             pri_max  = LOG_EMERG;
331     int             inc_optind = 0;
332     netsnmp_log_handler *logh;
333 
334     DEBUGMSGT(("logging:options", "optarg: '%s', argc %d, argv '%s'\n",
335                optarg, argc, argv ? argv[0] : "NULL"));
336     optarg++;
337     if (!*cp)
338         cp = &missing_opt;
339 
340     /*
341      * Support '... -Lx=value ....' syntax
342      */
343     if (*optarg == '=') {
344         optarg++;
345     }
346     /*
347      * and '.... "-Lx value" ....'  (*with* the quotes)
348      */
349     while (*optarg && isspace((unsigned char)(*optarg))) {
350         optarg++;
351     }
352     /*
353      * Finally, handle ".... -Lx value ...." syntax
354      *   (*without* surrounding quotes)
355      */
356     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         optarg = argv[optind];
364         inc_optind = 1;
365     }
366 
367     DEBUGMSGT(("logging:options", "*cp: '%c'\n", *cp));
368     switch (*cp) {
369 
370 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
371     /*
372      * Log to Standard Error
373      */
374     case 'E':
375         priority = decode_priority( &optarg, &pri_max );
376         if (priority == -1)  return -1;
377         if (inc_optind)
378             optind++;
379         /* Fallthrough */
380     case 'e':
381         logh = netsnmp_register_stdio_loghandler(0, priority, pri_max, "stderr");
382         break;
383 
384     /*
385      * Log to Standard Output
386      */
387     case 'O':
388         priority = decode_priority( &optarg, &pri_max );
389         if (priority == -1)  return -1;
390         if (inc_optind)
391             optind++;
392         /* Fallthrough */
393     case 'o':
394         logh = netsnmp_register_stdio_loghandler( 1, priority, pri_max, "stdout" );
395         break;
396 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
397 
398     /*
399      * Log to a named file
400      */
401 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
402     case 'F':
403         priority = decode_priority( &optarg, &pri_max );
404         if (priority == -1) return -1;
405         while (*optarg == ' ') optarg++;
406         if (!*optarg && !argv) return -1;
407         else if (!*optarg) optarg = argv[++optind];
408         /* FALL THROUGH */
409     case 'f':
410         if (inc_optind)
411             optind++;
412         if (!optarg) {
413             fprintf(stderr, "Missing log file\n");
414             return -1;
415         }
416         DEBUGMSGTL(("logging:options", "%d-%d: '%s'\n", priority, pri_max, optarg));
417         logh = netsnmp_register_filelog_handler(optarg, priority, pri_max,
418                                                    -1);
419         break;
420 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
421 
422 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
423     /*
424      * Log to syslog
425      */
426     case 'S':
427         priority = decode_priority( &optarg, &pri_max );
428         if (priority == -1 || !argv)  return -1;
429         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             optind++;
433             if (optind < argc)
434                 optarg = argv[optind];
435         }
436         /* Fallthrough */
437     case 's':
438         if (inc_optind)
439             optind++;
440         if (!optarg) {
441             fprintf(stderr, "Missing syslog facility\n");
442             return -1;
443         }
444         logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, priority);
445         if (logh) {
446             int facility = decode_facility(optarg);
447             if (facility == -1) {
448                 netsnmp_remove_loghandler(logh);
449                 return -1;
450             }
451             logh->pri_max = pri_max;
452             logh->token   = strdup(snmp_log_syslogname(NULL));
453             logh->magic   = (void *)(intptr_t)facility;
454 	    snmp_enable_syslog_ident(snmp_log_syslogname(NULL), facility);
455 	}
456         break;
457 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
458 
459     /*
460      * Don't log
461      */
462     case 'N':
463         priority = decode_priority( &optarg, &pri_max );
464         if (priority == -1)  return -1;
465         if (inc_optind)
466             optind++;
467         /* Fallthrough */
468     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         snmp_disable_log();
474         while(NULL != logh_head)
475             netsnmp_remove_loghandler( logh_head );
476         logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, priority);
477         if (logh) {
478             logh->pri_max = pri_max;
479 	}
480         break;
481 
482     default:
483         fprintf(stderr, "Unknown logging option passed to -L: %c.\n", *cp);
484         return -1;
485     }
486     return 0;
487 }
488 
489 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
490 char *
snmp_log_syslogname(const char * pstr)491 snmp_log_syslogname(const char *pstr)
492 {
493   if (pstr)
494     strlcpy (syslogname, pstr, sizeof(syslogname));
495 
496   return syslogname;
497 }
498 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
499 
500 void
snmp_log_options_usage(const char * lead,FILE * outf)501 snmp_log_options_usage(const char *lead, FILE * outf)
502 {
503     const char *pri1_msg = " for level 'pri' and above";
504     const char *pri2_msg = " for levels 'p1' to 'p2'";
505 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
506     fprintf(outf, "%se:           log to standard error\n", lead);
507     fprintf(outf, "%so:           log to standard output\n", lead);
508 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
509     fprintf(outf, "%sn:           don't log at all\n", lead);
510 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
511     fprintf(outf, "%sf file:      log to the specified file\n", lead);
512 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
513 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
514     fprintf(outf, "%ss facility:  log to syslog (via the specified facility)\n", lead);
515 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
516     fprintf(outf, "\n%s(variants)\n", lead);
517 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
518     fprintf(outf, "%s[EON] pri:   log to standard error, output or /dev/null%s\n", lead, pri1_msg);
519     fprintf(outf, "%s[EON] p1-p2: log to standard error, output or /dev/null%s\n", lead, pri2_msg);
520 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
521     fprintf(outf, "%s[FS] pri token:    log to file/syslog%s\n", lead, pri1_msg);
522     fprintf(outf, "%s[FS] p1-p2 token:  log to file/syslog%s\n", lead, pri2_msg);
523 }
524 
525 /**
526  * Is logging done?
527  *
528  * @return Returns 0 if logging is off, 1 when it is done.
529  *
530  */
531 int
snmp_get_do_logging(void)532 snmp_get_do_logging(void)
533 {
534     return (logh_enabled > 0);
535 }
536 
537 
538 static char    *
sprintf_stamp(time_t * now,char * sbuf)539 sprintf_stamp(time_t * now, char *sbuf)
540 {
541     time_t          Now;
542     struct tm      *tm;
543 
544     if (now == NULL) {
545         now = &Now;
546         time(now);
547     }
548     tm = localtime(now);
549     sprintf(sbuf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
550             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
551             tm->tm_hour, tm->tm_min, tm->tm_sec);
552     return sbuf;
553 }
554 
555 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
556 void
snmp_disable_syslog_entry(netsnmp_log_handler * logh)557 snmp_disable_syslog_entry(netsnmp_log_handler *logh)
558 {
559     if (!logh || !logh->enabled || logh->type != NETSNMP_LOGHANDLER_SYSLOG)
560         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     closelog();
570     logh->imagic  = 0;
571 #endif
572 
573     netsnmp_disable_this_loghandler(logh);
574 }
575 
576 void
snmp_disable_syslog(void)577 snmp_disable_syslog(void)
578 {
579     netsnmp_log_handler *logh;
580 
581     for (logh = logh_head; logh; logh = logh->next)
582         if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_SYSLOG)
583             snmp_disable_syslog_entry(logh);
584 }
585 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
586 
587 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
588 void
snmp_disable_filelog_entry(netsnmp_log_handler * logh)589 snmp_disable_filelog_entry(netsnmp_log_handler *logh)
590 {
591     if (!logh /* || !logh->enabled */ || logh->type != NETSNMP_LOGHANDLER_FILE)
592         return;
593 
594     if (logh->magic) {
595         fputs("\n", (FILE*)logh->magic);	/* XXX - why? */
596         fclose((FILE*)logh->magic);
597         logh->magic   = NULL;
598     }
599     netsnmp_disable_this_loghandler(logh);
600 }
601 
602 void
snmp_disable_filelog(void)603 snmp_disable_filelog(void)
604 {
605     netsnmp_log_handler *logh;
606 
607     for (logh = logh_head; logh; logh = logh->next)
608         if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_FILE)
609             snmp_disable_filelog_entry(logh);
610 }
611 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
612 
613 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
614 
615 netsnmp_log_handler *
netsnmp_register_stdio_loghandler(int is_stdout,int priority,int priority_max,const char * tok)616 netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
617                                   const char *tok)
618 {
619     netsnmp_log_handler *logh =
620         netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority);
621     if (NULL == logh) {
622         return NULL;
623     }
624     if (is_stdout) {
625         netsnmp_set_line_buffering(stdout);
626         logh->imagic = 1; /* stdout, not stderr */
627     } else
628         netsnmp_set_line_buffering(stderr);
629 
630     logh->pri_max = priority_max;
631     if (tok)
632         logh->token   = strdup(tok);
633     return logh;
634 }
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
snmp_stderrlog_status(void)643 snmp_stderrlog_status(void)
644 {
645     netsnmp_log_handler *logh;
646 
647     for (logh = logh_head; logh; logh = logh->next)
648         if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
649                               logh->type == NETSNMP_LOGHANDLER_STDERR)) {
650             return 1;
651        }
652 
653     return 0;
654 }
655 
656 void
snmp_disable_stderrlog(void)657 snmp_disable_stderrlog(void)
658 {
659     netsnmp_log_handler *logh;
660 
661     for (logh = logh_head; logh; logh = logh->next)
662         if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
663                               logh->type == NETSNMP_LOGHANDLER_STDERR)) {
664             netsnmp_disable_this_loghandler(logh);
665 	}
666 }
667 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
668 
669 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
670 void
snmp_disable_calllog(void)671 snmp_disable_calllog(void)
672 {
673     netsnmp_log_handler *logh;
674 
675     for (logh = logh_head; logh; logh = logh->next)
676         if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
677             netsnmp_disable_this_loghandler(logh);
678 	}
679 }
680 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
681 
682 void
snmp_disable_log(void)683 snmp_disable_log(void)
684 {
685     netsnmp_log_handler *logh;
686 
687     for (logh = logh_head; logh; logh = logh->next) {
688 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
689         if (logh->type == NETSNMP_LOGHANDLER_SYSLOG)
690             snmp_disable_syslog_entry(logh);
691 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
692 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
693         if (logh->type == NETSNMP_LOGHANDLER_FILE)
694             snmp_disable_filelog_entry(logh);
695 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
696         netsnmp_disable_this_loghandler(logh);
697     }
698 }
699 
700 /*
701  * close and reopen all file based logs, to allow logfile
702  * rotation.
703  */
704 void
netsnmp_logging_restart(void)705 netsnmp_logging_restart(void)
706 {
707     netsnmp_log_handler *logh;
708 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
709     int doneone = 0;
710 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
711 
712     for (logh = logh_head; logh; logh = logh->next) {
713         if (0 == logh->enabled)
714             continue;
715 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
716         if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
717             snmp_disable_syslog_entry(logh);
718             snmp_enable_syslog_ident(logh->token,(int)(intptr_t)logh->magic);
719             doneone = 1;
720         }
721 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
722 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
723         if (logh->type == NETSNMP_LOGHANDLER_FILE && !doneone) {
724             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             netsnmp_enable_filelog(logh, 1);
730         }
731 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
732     }
733 }
734 
735 /* ================================================== */
736 
737 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
738 void
snmp_enable_syslog(void)739 snmp_enable_syslog(void)
740 {
741     snmp_enable_syslog_ident(snmp_log_syslogname(NULL), LOG_DAEMON);
742 }
743 
744 void
snmp_enable_syslog_ident(const char * ident,const int facility)745 snmp_enable_syslog_ident(const char *ident, const int facility)
746 {
747     netsnmp_log_handler *logh;
748     int                  found = 0;
749     int                  enable = 1;
750 #ifdef WIN32
751     HANDLE               eventlog_h;
752 #else
753     void                *eventlog_h = NULL;
754 #endif
755 
756     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     openlog(snmp_log_syslogname(ident), LOG_CONS | LOG_PID, facility);
770 #endif
771 
772     for (logh = logh_head; logh; logh = logh->next)
773         if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
774             logh->magic   = (void*)eventlog_h;
775             logh->imagic  = enable;	/* syslog open */
776             if (logh->enabled && (0 == enable))
777                 netsnmp_disable_this_loghandler(logh);
778             else if ((0 == logh->enabled) && enable)
779                 netsnmp_enable_this_loghandler(logh);
780             found         = 1;
781 	}
782 
783     if (!found) {
784         logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG,
785                                            LOG_DEBUG );
786         if (logh) {
787             logh->magic    = (void*)eventlog_h;
788             logh->token    = strdup(ident);
789             logh->imagic   = enable;	/* syslog open */
790             if (logh->enabled && (0 == enable))
791                 netsnmp_disable_this_loghandler(logh);
792             else if ((0 == logh->enabled) && enable)
793                 netsnmp_enable_this_loghandler(logh);
794         }
795     }
796 }
797 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
798 
799 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
800 void
netsnmp_enable_filelog(netsnmp_log_handler * logh,int dont_zero_log)801 netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log)
802 {
803     FILE *logfile;
804 
805     if (!logh)
806         return;
807 
808     if (!logh->magic) {
809         logfile = fopen(logh->token, dont_zero_log ? "a" : "w");
810         if (!logfile) {
811 	    snmp_log_perror(logh->token);
812             return;
813 	}
814         logh->magic = (void*)logfile;
815         netsnmp_set_line_buffering(logfile);
816     }
817     netsnmp_enable_this_loghandler(logh);
818 }
819 
820 netsnmp_log_handler *
netsnmp_register_filelog_handler(const char * logfilename,int priority,int priority_max,int dont_zero_log)821 netsnmp_register_filelog_handler(const char* logfilename, int priority,
822                                  int priority_max, int dont_zero_log)
823 {
824     netsnmp_log_handler *logh =
825         netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE,
826                                     priority );
827     if (NULL == logh)
828         return NULL;
829     logh->pri_max = priority_max;
830     logh->token = strdup(logfilename);
831     if (-1 == dont_zero_log)
832         dont_zero_log = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
833                                                NETSNMP_DS_LIB_APPEND_LOGFILES);
834     netsnmp_enable_filelog(logh, dont_zero_log);
835     return logh;
836 }
837 
838 void
snmp_enable_filelog(const char * logfilename,int dont_zero_log)839 snmp_enable_filelog(const char *logfilename, int dont_zero_log)
840 {
841     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     if (logfilename) {
852         logh = netsnmp_find_loghandler( logfilename );
853         if (!logh)
854             logh = netsnmp_register_filelog_handler( logfilename, LOG_DEBUG,
855                                                      0, dont_zero_log );
856         else
857             netsnmp_enable_filelog(logh, dont_zero_log);
858     } else {
859         for (logh = logh_head; logh; logh = logh->next)
860             if (logh->type == NETSNMP_LOGHANDLER_FILE)
861                 netsnmp_enable_filelog(logh, dont_zero_log);
862     }
863 }
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
snmp_enable_stderrlog(void)870 snmp_enable_stderrlog(void)
871 {
872     netsnmp_log_handler *logh;
873     int                  found = 0;
874 
875     for (logh = logh_head; logh; logh = logh->next)
876         if (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
877             logh->type == NETSNMP_LOGHANDLER_STDERR) {
878             netsnmp_enable_this_loghandler(logh);
879             found         = 1;
880         }
881 
882     if (!found) {
883         logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR,
884                                            LOG_DEBUG );
885         if (logh)
886             logh->token    = strdup("stderr");
887     }
888 }
889 #endif /* NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG */
890 
891 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
892 void
snmp_enable_calllog(void)893 snmp_enable_calllog(void)	/* XXX - or take a callback routine ??? */
894 {
895     netsnmp_log_handler *logh;
896     int                  found = 0;
897 
898     for (logh = logh_head; logh; logh = logh->next)
899         if (logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
900             netsnmp_enable_this_loghandler(logh);
901             found         = 1;
902 	}
903 
904     if (!found) {
905         logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_CALLBACK,
906                                            LOG_DEBUG );
907         if (logh)
908             logh->token    = strdup("callback");
909     }
910 }
911 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
912 
913 
914 /* ==================================================== */
915 
916 
917 netsnmp_log_handler *
netsnmp_find_loghandler(const char * token)918 netsnmp_find_loghandler( const char *token )
919 {
920     netsnmp_log_handler *logh;
921     if (!token)
922         return NULL;
923 
924     for (logh = logh_head; logh; logh = logh->next)
925         if (logh->token && !strcmp( token, logh->token ))
926             break;
927 
928     return logh;
929 }
930 
931 int
netsnmp_add_loghandler(netsnmp_log_handler * logh)932 netsnmp_add_loghandler( netsnmp_log_handler *logh )
933 {
934     int i;
935     netsnmp_log_handler *logh2;
936 
937     if (!logh)
938         return 0;
939 
940     /*
941      * Find the appropriate point for the new entry...
942      *   (logh2 will point to the entry immediately following)
943      */
944     for (logh2 = logh_head; logh2; logh2 = logh2->next)
945         if ( logh2->priority >= logh->priority )
946             break;
947 
948     /*
949      * ... and link it into the main list.
950      */
951     if (logh2) {
952         if (logh2->prev)
953             logh2->prev->next = logh;
954         else
955             logh_head = logh;
956         logh->next  = logh2;
957         logh2->prev = logh;
958     } else if (logh_head ) {
959         /*
960          * If logh2 is NULL, we're tagging on to the end
961          */
962         for (logh2 = logh_head; logh2->next; logh2 = logh2->next)
963             ;
964         logh2->next = logh;
965     } else {
966         logh_head = logh;
967     }
968 
969     /*
970      * Also tweak the relevant priority-'index' array.
971      */
972     for (i=LOG_EMERG; i<=logh->priority; i++)
973         if (!logh_priorities[i] ||
974              logh_priorities[i]->priority >= logh->priority)
975              logh_priorities[i] = logh;
976 
977     return 1;
978 }
979 
980 netsnmp_log_handler *
netsnmp_register_loghandler(int type,int priority)981 netsnmp_register_loghandler( int type, int priority )
982 {
983     netsnmp_log_handler *logh;
984 
985     logh = SNMP_MALLOC_TYPEDEF(netsnmp_log_handler);
986     if (!logh)
987         return NULL;
988 
989     DEBUGMSGT(("logging:register", "registering log type %d with pri %d\n",
990                type, priority));
991     if (priority > LOG_DEBUG) {
992         DEBUGMSGT(("logging:register", "  limiting pri %d to %d\n", priority,
993                    LOG_DEBUG));
994         priority = LOG_DEBUG;
995     }
996 
997     logh->type     = type;
998     switch ( type ) {
999     case NETSNMP_LOGHANDLER_STDOUT:
1000         logh->imagic  = 1;
1001         logh->handler = log_handler_stdouterr;
1002         break;
1003 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1004     case NETSNMP_LOGHANDLER_STDERR:
1005         logh->handler = log_handler_stdouterr;
1006         break;
1007 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1008 
1009 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1010     case NETSNMP_LOGHANDLER_FILE:
1011         logh->handler = log_handler_file;
1012         logh->imagic  = 1;
1013         break;
1014 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1015 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1016     case NETSNMP_LOGHANDLER_SYSLOG:
1017         logh->handler = log_handler_syslog;
1018         break;
1019 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1020     case NETSNMP_LOGHANDLER_CALLBACK:
1021         logh->handler = log_handler_callback;
1022         break;
1023     case NETSNMP_LOGHANDLER_NONE:
1024         logh->handler = log_handler_null;
1025         break;
1026     default:
1027         free(logh);
1028         return NULL;
1029     }
1030     logh->priority = priority;
1031     netsnmp_enable_this_loghandler(logh);
1032     netsnmp_add_loghandler( logh );
1033     return logh;
1034 }
1035 
1036 
1037 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER
1038 int
netsnmp_enable_loghandler(const char * token)1039 netsnmp_enable_loghandler( const char *token )
1040 {
1041     netsnmp_log_handler *logh;
1042 
1043     logh = netsnmp_find_loghandler( token );
1044     if (!logh)
1045         return 0;
1046     netsnmp_enable_this_loghandler(logh);
1047     return 1;
1048 }
1049 
1050 
1051 int
netsnmp_disable_loghandler(const char * token)1052 netsnmp_disable_loghandler( const char *token )
1053 {
1054     netsnmp_log_handler *logh;
1055 
1056     logh = netsnmp_find_loghandler( token );
1057     if (!logh)
1058         return 0;
1059     netsnmp_disable_this_loghandler(logh);
1060     return 1;
1061 }
1062 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER */
1063 
1064 int
netsnmp_remove_loghandler(netsnmp_log_handler * logh)1065 netsnmp_remove_loghandler( netsnmp_log_handler *logh )
1066 {
1067     int i;
1068     if (!logh)
1069         return 0;
1070 
1071     if (logh->prev)
1072         logh->prev->next = logh->next;
1073     else
1074         logh_head = logh->next;
1075 
1076     if (logh->next)
1077         logh->next->prev = logh->prev;
1078 
1079     for (i=LOG_EMERG; i<=logh->priority; i++)
1080         if (logh == logh_priorities[i])
1081             logh_priorities[i] = logh->next;
1082     free(NETSNMP_REMOVE_CONST(char*, logh->token));
1083     SNMP_FREE(logh);
1084 
1085     return 1;
1086 }
1087 
1088 /* ==================================================== */
1089 
1090 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1091 int
log_handler_stdouterr(netsnmp_log_handler * logh,int pri,const char * str)1092 log_handler_stdouterr(  netsnmp_log_handler* logh, int pri, const char *str)
1093 {
1094     static int      newline = 1;	 /* MTCRITICAL_RESOURCE */
1095     const char     *newline_ptr;
1096     char            sbuf[40];
1097 
1098     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1099                                NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) {
1100         sprintf_stamp(NULL, sbuf);
1101     } else {
1102         strcpy(sbuf, "");
1103     }
1104     /*
1105      * Remember whether or not the current line ends with a newline for the
1106      * next call of log_handler_stdouterr().
1107      */
1108     newline_ptr = strrchr(str, '\n');
1109     newline = newline_ptr && newline_ptr[1] == 0;
1110 
1111     if (logh->imagic)
1112        printf(         "%s%s", sbuf, str);
1113     else
1114        fprintf(stderr, "%s%s", sbuf, str);
1115 
1116     return 1;
1117 }
1118 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1119 
1120 
1121 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1122 #ifdef WIN32
1123 int
log_handler_syslog(netsnmp_log_handler * logh,int pri,const char * str)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
log_handler_syslog(netsnmp_log_handler * logh,int pri,const char * str)1181 log_handler_syslog(  netsnmp_log_handler* logh, int pri, const char *str)
1182 {
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     if (!(logh->imagic)) {
1193         const char *ident    = logh->token;
1194         int   facility = (int)(intptr_t)logh->magic;
1195         if (!ident)
1196             ident = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1197                                           NETSNMP_DS_LIB_APPTYPE);
1198         openlog(ident, LOG_CONS | LOG_PID, facility);
1199         logh->imagic = 1;
1200     }
1201     syslog( pri, "%s", str );
1202     return 1;
1203 }
1204 #endif /* !WIN32 */
1205 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1206 
1207 
1208 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1209 int
log_handler_file(netsnmp_log_handler * logh,int pri,const char * str)1210 log_handler_file(    netsnmp_log_handler* logh, int pri, const char *str)
1211 {
1212     FILE           *fhandle;
1213     char            sbuf[40];
1214     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     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1221                                NETSNMP_DS_LIB_LOG_TIMESTAMP) && logh->imagic) {
1222         sprintf_stamp(NULL, sbuf);
1223     } else {
1224         strcpy(sbuf, "");
1225     }
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     fhandle = (FILE*)logh->magic;
1235     if (!logh->magic) {
1236         fhandle = fopen(logh->token, "a+");
1237         if (!fhandle)
1238             return 0;
1239         logh->magic = (void*)fhandle;
1240     }
1241     fprintf(fhandle, "%s%s", sbuf, str);
1242     fflush(fhandle);
1243     if (len > 0) {
1244         logh->imagic = str[len - 1] == '\n';
1245     } else {
1246         logh->imagic = 0;
1247     }
1248     return 1;
1249 }
1250 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1251 
1252 int
log_handler_callback(netsnmp_log_handler * logh,int pri,const char * str)1253 log_handler_callback(netsnmp_log_handler* logh, int pri, const char *str)
1254 {
1255 	/*
1256 	 * XXX - perhaps replace 'snmp_call_callbacks' processing
1257 	 *       with individual callback log_handlers ??
1258 	 */
1259     struct snmp_log_message slm;
1260     int             dodebug = snmp_get_do_debugging();
1261 
1262     slm.priority = pri;
1263     slm.msg = str;
1264     if (dodebug)            /* turn off debugging inside the callbacks else will loop */
1265         snmp_set_do_debugging(0);
1266     snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm);
1267     if (dodebug)
1268         snmp_set_do_debugging(dodebug);
1269     return 1;
1270 }
1271 
1272 int
log_handler_null(netsnmp_log_handler * logh,int pri,const char * str)1273 log_handler_null(    netsnmp_log_handler* logh, int pri, const char *str)
1274 {
1275     /*
1276      * Dummy log handler - just throw away the error completely
1277      * You probably don't really want to do this!
1278      */
1279     return 1;
1280 }
1281 
1282 void
snmp_log_string(int priority,const char * str)1283 snmp_log_string(int priority, const char *str)
1284 {
1285 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1286     static int stderr_enabled = 0;
1287     static netsnmp_log_handler lh = { 1, 0, 0, 0, "stderr",
1288                                       log_handler_stdouterr, 0, NULL,  NULL,
1289                                       NULL };
1290 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1291     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     if (0 == logh_enabled) {
1298 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1299         if (!stderr_enabled) {
1300             ++stderr_enabled;
1301             netsnmp_set_line_buffering(stderr);
1302         }
1303         log_handler_stdouterr( &lh, priority, str );
1304 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1305 
1306         return;
1307     }
1308 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1309     else if (stderr_enabled) {
1310         stderr_enabled = 0;
1311         log_handler_stdouterr( &lh, LOG_INFO,
1312                                "Log handling defined - disabling stderr\n" );
1313     }
1314 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1315 
1316 
1317     /*
1318      * Start at the given priority, and work "upwards"....
1319      */
1320     if (priority > LOG_DEBUG)
1321         priority = LOG_DEBUG;
1322     logh = logh_priorities[priority];
1323     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         if (logh->enabled && (priority >= logh->pri_max))
1331             logh->handler( logh, priority, str );
1332     }
1333 }
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 messgae is written to the logfile.
1366  *
1367  * @see snmp_log
1368  */
1369 int
snmp_vlog(int priority,const char * format,va_list ap)1370 snmp_vlog(int priority, const char *format, va_list ap)
1371 {
1372     char           *buffer = NULL;
1373     int             length;
1374 
1375     length = vasprintf(&buffer, format, ap);
1376     if (length < 0) {
1377         snmp_log_string(LOG_ERR, "Could not format log-string\n");
1378         return -1;
1379     }
1380 
1381     snmp_log_string(priority, buffer);
1382     free(buffer);
1383     return 0;
1384 }
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
snmp_log(int priority,const char * format,...)1394 snmp_log(int priority, const char *format, ...)
1395 {
1396     va_list         ap;
1397     int             ret;
1398     va_start(ap, format);
1399     ret = snmp_vlog(priority, format, ap);
1400     va_end(ap);
1401     return (ret);
1402 }
1403 
1404 /*
1405  * log a critical error.
1406  */
1407 void
snmp_log_perror(const char * s)1408 snmp_log_perror(const char *s)
1409 {
1410     char           *error = strerror(errno);
1411     if (s) {
1412         if (error)
1413             snmp_log(LOG_ERR, "%s: %s\n", s, error);
1414         else
1415             snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno);
1416     } else {
1417         if (error)
1418             snmp_log(LOG_ERR, "%s\n", error);
1419         else
1420             snmp_log(LOG_ERR, "Error %d out-of-range\n", errno);
1421     }
1422 }
1423 
1424 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL
1425 /* external access to logh_head variable */
1426 netsnmp_log_handler  *
get_logh_head(void)1427 get_logh_head(void)
1428 {
1429 	return logh_head;
1430 }
1431 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL */
1432 
1433 /**  @} */
1434