log.c revision 1.11
1/*	$OpenBSD: log.c,v 1.11 2000/06/29 00:01:14 deraadt Exp $	*/
2/*	$EOM: log.c,v 1.27 2000/03/30 14:27:03 ho Exp $	*/
3
4/*
5 * Copyright (c) 1998, 1999 Niklas Hallqvist.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Ericsson Radio Systems.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * This code was written under funding by Ericsson Radio Systems.
35 */
36
37#include <sys/time.h>
38#include <errno.h>
39#include <stdio.h>
40#include <string.h>
41#include <syslog.h>
42#ifdef __STDC__
43#include <stdarg.h>
44#else
45#include <varargs.h>
46#endif
47
48#include "sysdep.h"
49
50#include "log.h"
51
52static void _log_print (int, int, const char *, va_list, int, int);
53
54static FILE *log_output;
55#ifdef USE_DEBUG
56static int log_level[LOG_ENDCLASS];
57#endif
58
59void
60log_init (void)
61{
62  log_output = stderr;
63}
64
65void
66log_to (FILE *f)
67{
68  if (!log_output && f)
69    closelog ();
70  log_output = f;
71  if (!f)
72    openlog ("isakmpd", LOG_CONS, LOG_DAEMON);
73}
74
75FILE *
76log_current (void)
77{
78  return log_output;
79}
80
81static char *
82_log_get_class (int error_class)
83{
84  /* XXX For test purposes. To be removed later on?  */
85  static char *class_text[] = LOG_CLASSES_TEXT;
86
87  if (error_class < 0)
88    return "Dflt";
89  else if (error_class >= LOG_ENDCLASS)
90    return "Unkn";
91  else
92    return class_text[error_class];
93}
94
95static void
96_log_print (int error, int syslog_level, const char *fmt, va_list ap,
97	    int class, int level)
98{
99  char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
100  static const char fallback_msg[] =
101    "write to log file failed (errno %d), redirecting output to syslog";
102  int len;
103  struct tm *tm;
104  struct timeval now;
105  time_t t;
106
107  len = vsnprintf (buffer, LOG_SIZE, fmt, ap);
108  if (len < LOG_SIZE - 1 && error)
109    snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno));
110  if (log_output)
111    {
112      gettimeofday (&now, 0);
113      t = now.tv_sec;
114      tm = localtime (&t);
115      if (class >= 0)
116	sprintf (nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour,
117		 tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class (class),
118		 level);
119      else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
120	sprintf (nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour,
121		 tm->tm_min, tm->tm_sec, now.tv_usec,
122		 class == LOG_PRINT ? "Default" : "Report>");
123      strcat (nbuf, buffer);
124      strcat (nbuf, "\n");
125
126      if (fwrite (nbuf, strlen (nbuf), 1, log_output) == 0)
127	{
128	  /* Report fallback.  */
129	  syslog (LOG_ALERT, fallback_msg, errno);
130	  fprintf (log_output, fallback_msg, errno);
131
132	  /*
133	   * Close log_output to prevent isakmpd from locking the file.
134	   * We may need to explicitly close stdout to do this properly.
135	   * XXX - Figure out how to match two FILE *'s and rewrite.
136	   */
137	  if (fileno (log_output) != -1)
138	    if (fileno (stdout) == fileno (log_output))
139	      fclose (stdout);
140	  fclose (log_output);
141
142	  /* Fallback to syslog.  */
143	  log_to (0);
144
145	  /* (Re)send current message to syslog(). */
146	  syslog (class == LOG_REPORT ? LOG_ALERT : 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