log.c revision 1.13
1/*	$OpenBSD: log.c,v 1.13 2000/10/07 06:58:29 niklas Exp $	*/
2/*	$EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $	*/
3
4/*
5 * Copyright (c) 1998, 1999 Niklas Hallqvist.  All rights reserved.
6 * Copyright (c) 1999, 2000 H�kan Olsson.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by Ericsson Radio Systems.
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * This code was written under funding by Ericsson Radio Systems.
36 */
37
38#include <sys/time.h>
39#include <errno.h>
40#include <stdio.h>
41#include <string.h>
42#include <syslog.h>
43#ifdef __STDC__
44#include <stdarg.h>
45#else
46#include <varargs.h>
47#endif
48
49#include "log.h"
50
51static void _log_print (int, int, const char *, va_list, int, int);
52
53static FILE *log_output;
54#ifdef USE_DEBUG
55static int log_level[LOG_ENDCLASS];
56#endif
57
58void
59log_init (void)
60{
61  log_output = stderr;
62}
63
64void
65log_to (FILE *f)
66{
67  if (!log_output && f)
68    closelog ();
69  log_output = f;
70  if (!f)
71    openlog ("isakmpd", LOG_CONS, LOG_DAEMON);
72}
73
74FILE *
75log_current (void)
76{
77  return log_output;
78}
79
80static char *
81_log_get_class (int error_class)
82{
83  /* XXX For test purposes. To be removed later on?  */
84  static char *class_text[] = LOG_CLASSES_TEXT;
85
86  if (error_class < 0)
87    return "Dflt";
88  else if (error_class >= LOG_ENDCLASS)
89    return "Unkn";
90  else
91    return class_text[error_class];
92}
93
94static void
95_log_print (int error, int syslog_level, const char *fmt, va_list ap,
96	    int class, int level)
97{
98  char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
99  static const char fallback_msg[] =
100    "write to log file failed (errno %d), redirecting output to syslog";
101  int len;
102  struct tm *tm;
103  struct timeval now;
104  time_t t;
105
106  len = vsnprintf (buffer, LOG_SIZE, fmt, ap);
107  if (len < LOG_SIZE - 1 && error)
108    snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno));
109  if (log_output)
110    {
111      gettimeofday (&now, 0);
112      t = now.tv_sec;
113      tm = localtime (&t);
114      if (class >= 0)
115	sprintf (nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour,
116		 tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class (class),
117		 level);
118      else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
119	sprintf (nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour,
120		 tm->tm_min, tm->tm_sec, now.tv_usec,
121		 class == LOG_PRINT ? "Default" : "Report>");
122      strcat (nbuf, buffer);
123      strcat (nbuf, "\n");
124
125      if (fwrite (nbuf, strlen (nbuf), 1, log_output) == 0)
126	{
127	  /* Report fallback.  */
128	  syslog (LOG_ALERT, fallback_msg, errno);
129	  fprintf (log_output, fallback_msg, errno);
130
131	  /*
132	   * Close log_output to prevent isakmpd from locking the file.
133	   * We may need to explicitly close stdout to do this properly.
134	   * XXX - Figure out how to match two FILE *'s and rewrite.
135	   */
136	  if (fileno (log_output) != -1)
137	    if (fileno (stdout) == fileno (log_output))
138	      fclose (stdout);
139	  fclose (log_output);
140
141	  /* Fallback to syslog.  */
142	  log_to (0);
143
144	  /* (Re)send current message to syslog(). */
145	  syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer);
146	}
147    }
148  else
149    syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer);
150}
151
152#ifdef USE_DEBUG
153void
154#ifdef __STDC__
155log_debug (int cls, int level, const char *fmt, ...)
156#else
157log_debug (cls, level, fmt, va_alist)
158     int cls;
159     int level;
160     const char *fmt;
161     va_dcl
162#endif
163{
164  va_list ap;
165
166  /*
167   * If we are not debugging this class, or the level is too low, just return.
168   */
169  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
170    return;
171#ifdef __STDC__
172  va_start (ap, fmt);
173#else
174  va_start (ap);
175  fmt = va_arg (ap, const char *);
176#endif
177  _log_print (0, LOG_DEBUG, fmt, ap, cls, level);
178  va_end (ap);
179}
180
181void
182log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf,
183	       size_t sz)
184{
185  char s[73];
186  int i, j;
187
188  /*
189   * If we are not debugging this class, or the level is too low, just return.
190   */
191  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
192    return;
193
194  log_debug (cls, level, "%s:", header);
195  for (i = j = 0; i < sz;)
196    {
197      sprintf (s + j, "%02x", buf[i++]);
198      j += 2;
199      if (i % 4 == 0)
200	{
201	  if (i % 32 == 0)
202	    {
203	      s[j] = '\0';
204	      log_debug (cls, level, "%s", s);
205	      j = 0;
206	    }
207	  else
208	    s[j++] = ' ';
209	}
210    }
211  if (j)
212    {
213      s[j] = '\0';
214      log_debug (cls, level, "%s", s);
215    }
216}
217
218void
219log_debug_cmd (int cls, int level)
220{
221  if (cls < 0 || cls >= LOG_ENDCLASS)
222    {
223      log_print ("log_debug_cmd: invalid debugging class %d", cls);
224      return;
225    }
226
227  if (level < 0)
228    {
229      log_print ("log_debug_cmd: invalid debugging level %d for class %d",
230		 level, cls);
231      return;
232    }
233
234  if (level == log_level[cls])
235    log_print ("log_debug_cmd: log level unchanged for class %d", cls);
236  else
237    {
238      log_print ("log_debug_cmd: log level changed from %d to %d for class %d",
239		 log_level[cls], level, cls);
240      log_level[cls] = level;
241    }
242}
243#endif /* USE_DEBUG */
244
245void
246#ifdef __STDC__
247log_print (const char *fmt, ...)
248#else
249log_print (fmt, va_alist)
250     const char *fmt;
251     va_dcl
252#endif
253{
254  va_list ap;
255
256#ifdef __STDC__
257  va_start (ap, fmt);
258#else
259  va_start (ap);
260  fmt = va_arg (ap, const char *);
261#endif
262  _log_print (0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
263  va_end (ap);
264}
265
266void
267#ifdef __STDC__
268log_error (const char *fmt, ...)
269#else
270log_error (fmt, va_alist)
271     const char *fmt;
272     va_dcl
273#endif
274{
275  va_list ap;
276
277#ifdef __STDC__
278  va_start (ap, fmt);
279#else
280  va_start (ap);
281  fmt = va_arg (ap, const char *);
282#endif
283  _log_print (1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
284  va_end (ap);
285}
286
287void
288#ifdef __STDC__
289log_fatal (const char *fmt, ...)
290#else
291log_fatal (fmt, va_alist)
292     const char *fmt;
293     va_dcl
294#endif
295{
296  va_list ap;
297
298#ifdef __STDC__
299  va_start (ap, fmt);
300#else
301  va_start (ap);
302  fmt = va_arg (ap, const char *);
303#endif
304  _log_print (1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
305  va_end (ap);
306  exit (1);
307}
308