log.c revision 1.7
1/*	$OpenBSD: log.c,v 1.7 1999/07/07 22:11:14 niklas Exp $	*/
2/*	$EOM: log.c,v 1.24 1999/06/26 23:26:56 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 = stderr;
55static int log_level[LOG_ENDCLASS];
56
57void
58log_to (FILE *f)
59{
60  if (!log_output && f)
61    closelog ();
62  log_output = f;
63  if (!f)
64    openlog ("isakmpd", LOG_CONS, LOG_DAEMON);
65}
66
67FILE *
68log_current (void)
69{
70  return log_output;
71}
72
73static char *
74_log_get_class (int error_class)
75{
76  /* XXX For test purposes. To be removed later on?  */
77  static char *class_text[] = LOG_CLASSES_TEXT;
78
79  if (error_class < 0)
80    return "Dflt";
81  else if (error_class >= LOG_ENDCLASS)
82    return "Unkn";
83  else
84    return class_text[error_class];
85}
86
87static void
88_log_print (int error, int syslog_level, const char *fmt, va_list ap,
89	    int class, int level)
90{
91  char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
92  static const char fallback_msg[] =
93    "write to log file failed (errno %d), redirecting output to syslog";
94  int len;
95  struct tm *tm;
96  struct timeval now;
97  time_t t;
98
99  len = vsnprintf (buffer, LOG_SIZE, fmt, ap);
100  if (len < LOG_SIZE - 1 && error)
101    snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno));
102  if (log_output)
103    {
104      gettimeofday (&now, 0);
105      t = now.tv_sec;
106      tm = localtime (&t);
107      if (class >= 0)
108	sprintf (nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour,
109		 tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class (class),
110		 level);
111      else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
112	sprintf (nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour,
113		 tm->tm_min, tm->tm_sec, now.tv_usec,
114		 class == LOG_PRINT ? "Default" : "Report>");
115      strcat (nbuf, buffer);
116      strcat (nbuf, "\n");
117
118      if (fwrite (nbuf, strlen (nbuf), 1, log_output) == 0)
119	{
120	  /* Report fallback.  */
121	  syslog (LOG_ALERT, fallback_msg, errno);
122	  fprintf (log_output, fallback_msg, errno);
123
124	  /*
125	   * Close log_output to prevent isakmpd from locking the file.
126	   * We may need to explicitly close stdout to do this properly.
127	   * XXX - Figure out how to match two FILE *'s and rewrite.
128	   */
129	  if (log_output->_file != -1)
130	    if (stdout->_file == log_output->_file)
131	      fclose (stdout);
132	  fclose (log_output);
133
134	  /* Fallback to syslog.  */
135	  log_to (0);
136
137	  /* (Re)send current message to syslog(). */
138	  syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, buffer);
139	}
140    }
141  else
142    syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, buffer);
143}
144
145void
146#ifdef __STDC__
147log_debug (int cls, int level, const char *fmt, ...)
148#else
149log_debug (cls, level, fmt, va_alist)
150     int cls;
151     int level;
152     const char *fmt;
153     va_dcl
154#endif
155{
156  va_list ap;
157
158  /*
159   * If we are not debugging this class, or the level is too low, just return.
160   */
161  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
162    return;
163#ifdef __STDC__
164  va_start (ap, fmt);
165#else
166  va_start (ap);
167  fmt = va_arg (ap, const char *);
168#endif
169  _log_print (0, LOG_DEBUG, fmt, ap, cls, level);
170  va_end (ap);
171}
172
173void
174log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf,
175	       size_t sz)
176{
177  char s[73];
178  int i, j;
179
180  /*
181   * If we are not debugging this class, or the level is too low, just return.
182   */
183  if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
184    return;
185
186  log_debug (cls, level, "%s:", header);
187  for (i = j = 0; i < sz;)
188    {
189      sprintf (s + j, "%02x", buf[i++]);
190      j += 2;
191      if (i % 4 == 0)
192	{
193	  if (i % 32 == 0)
194	    {
195	      s[j] = '\0';
196	      log_debug (cls, level, "%s", s);
197	      j = 0;
198	    }
199	  else
200	    s[j++] = ' ';
201	}
202    }
203  if (j)
204    {
205      s[j] = '\0';
206      log_debug (cls, level, "%s", s);
207    }
208}
209
210void
211#ifdef __STDC__
212log_print (const char *fmt, ...)
213#else
214log_print (fmt, va_alist)
215     const char *fmt;
216     va_dcl
217#endif
218{
219  va_list ap;
220
221#ifdef __STDC__
222  va_start (ap, fmt);
223#else
224  va_start (ap);
225  fmt = va_arg (ap, const char *);
226#endif
227  _log_print (0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
228  va_end (ap);
229}
230
231void
232#ifdef __STDC__
233log_error (const char *fmt, ...)
234#else
235log_error (fmt, va_alist)
236     const char *fmt;
237     va_dcl
238#endif
239{
240  va_list ap;
241
242#ifdef __STDC__
243  va_start (ap, fmt);
244#else
245  va_start (ap);
246  fmt = va_arg (ap, const char *);
247#endif
248  _log_print (1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
249  va_end (ap);
250}
251
252void
253#ifdef __STDC__
254log_fatal (const char *fmt, ...)
255#else
256log_fatal (fmt, va_alist)
257     const char *fmt;
258     va_dcl
259#endif
260{
261  va_list ap;
262
263#ifdef __STDC__
264  va_start (ap, fmt);
265#else
266  va_start (ap);
267  fmt = va_arg (ap, const char *);
268#endif
269  _log_print (1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
270  va_end (ap);
271  exit (1);
272}
273
274void
275log_debug_cmd (int cls, int level)
276{
277  if (cls < 0 || cls >= LOG_ENDCLASS)
278    {
279      log_print ("log_debug_cmd: invalid debugging class %d", cls);
280      return;
281    }
282
283  if (level < 0)
284    {
285      log_print ("log_debug_cmd: invalid debugging level %d for class %d",
286		 level, cls);
287      return;
288    }
289
290  if (level == log_level[cls])
291    log_print ("log_debug_cmd: log level unchanged for class %d", cls);
292  else
293    {
294      log_print ("log_debug_cmd: log level changed from %d to %d for class %d",
295		 log_level[cls], level, cls);
296      log_level[cls] = level;
297    }
298}
299