log.c revision 1.15
1/*	$OpenBSD: log.c,v 1.15 2001/01/26 12:12:52 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_PID | 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	      && 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
146		  : syslog_level, "%s", buffer);
147	}
148    }
149  else
150    syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer);
151}
152
153#ifdef USE_DEBUG
154void
155#ifdef __STDC__
156log_debug (int cls, int level, const char *fmt, ...)
157#else
158log_debug (cls, level, fmt, va_alist)
159     int cls;
160     int level;
161     const char *fmt;
162     va_dcl
163#endif
164{
165  va_list ap;
166
167  /*
168   * If we are not debugging this class, or the level is too low, just return.
169   */
170  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
171    return;
172#ifdef __STDC__
173  va_start (ap, fmt);
174#else
175  va_start (ap);
176  fmt = va_arg (ap, const char *);
177#endif
178  _log_print (0, LOG_DEBUG, fmt, ap, cls, level);
179  va_end (ap);
180}
181
182void
183log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf,
184	       size_t sz)
185{
186  char s[73];
187  int i, j;
188
189  /*
190   * If we are not debugging this class, or the level is too low, just return.
191   */
192  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
193    return;
194
195  log_debug (cls, level, "%s:", header);
196  for (i = j = 0; i < sz;)
197    {
198      sprintf (s + j, "%02x", buf[i++]);
199      j += 2;
200      if (i % 4 == 0)
201	{
202	  if (i % 32 == 0)
203	    {
204	      s[j] = '\0';
205	      log_debug (cls, level, "%s", s);
206	      j = 0;
207	    }
208	  else
209	    s[j++] = ' ';
210	}
211    }
212  if (j)
213    {
214      s[j] = '\0';
215      log_debug (cls, level, "%s", s);
216    }
217}
218
219void
220log_debug_cmd (int cls, int level)
221{
222  if (cls < 0 || cls >= LOG_ENDCLASS)
223    {
224      log_print ("log_debug_cmd: invalid debugging class %d", cls);
225      return;
226    }
227
228  if (level < 0)
229    {
230      log_print ("log_debug_cmd: invalid debugging level %d for class %d",
231		 level, cls);
232      return;
233    }
234
235  if (level == log_level[cls])
236    log_print ("log_debug_cmd: log level unchanged for class %d", cls);
237  else
238    {
239      log_print ("log_debug_cmd: log level changed from %d to %d for class %d",
240		 log_level[cls], level, cls);
241      log_level[cls] = level;
242    }
243}
244#endif /* USE_DEBUG */
245
246void
247#ifdef __STDC__
248log_print (const char *fmt, ...)
249#else
250log_print (fmt, va_alist)
251     const char *fmt;
252     va_dcl
253#endif
254{
255  va_list ap;
256
257#ifdef __STDC__
258  va_start (ap, fmt);
259#else
260  va_start (ap);
261  fmt = va_arg (ap, const char *);
262#endif
263  _log_print (0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
264  va_end (ap);
265}
266
267void
268#ifdef __STDC__
269log_error (const char *fmt, ...)
270#else
271log_error (fmt, va_alist)
272     const char *fmt;
273     va_dcl
274#endif
275{
276  va_list ap;
277
278#ifdef __STDC__
279  va_start (ap, fmt);
280#else
281  va_start (ap);
282  fmt = va_arg (ap, const char *);
283#endif
284  _log_print (1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
285  va_end (ap);
286}
287
288void
289#ifdef __STDC__
290log_fatal (const char *fmt, ...)
291#else
292log_fatal (fmt, va_alist)
293     const char *fmt;
294     va_dcl
295#endif
296{
297  va_list ap;
298
299#ifdef __STDC__
300  va_start (ap, fmt);
301#else
302  va_start (ap);
303  fmt = va_arg (ap, const char *);
304#endif
305  _log_print (1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
306  va_end (ap);
307  exit (1);
308}
309