xref: /freebsd/crypto/heimdal/lib/krb5/log.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 
36 RCSID("$Id: log.c,v 1.21 1999/12/02 17:05:11 joda Exp $");
37 
38 struct facility {
39     int min;
40     int max;
41     krb5_log_log_func_t log;
42     krb5_log_close_func_t close;
43     void *data;
44 };
45 
46 static struct facility*
47 log_realloc(krb5_log_facility *f)
48 {
49     struct facility *fp;
50     f->len++;
51     fp = realloc(f->val, f->len * sizeof(*f->val));
52     if(fp == NULL)
53 	return NULL;
54     f->val = fp;
55     fp += f->len - 1;
56     return fp;
57 }
58 
59 struct s2i{
60     char *s;
61     int val;
62 };
63 
64 #define L(X) { #X, LOG_ ## X }
65 
66 struct s2i syslogvals[] = {
67     L(EMERG),
68     L(ALERT),
69     L(CRIT),
70     L(ERR),
71     L(WARNING),
72     L(NOTICE),
73     L(INFO),
74     L(DEBUG),
75 
76     L(AUTH),
77 #ifdef LOG_AUTHPRIV
78     L(AUTHPRIV),
79 #endif
80 #ifdef LOG_CRON
81     L(CRON),
82 #endif
83     L(DAEMON),
84 #ifdef LOG_FTP
85     L(FTP),
86 #endif
87     L(KERN),
88     L(LPR),
89     L(MAIL),
90 #ifdef LOG_NEWS
91     L(NEWS),
92 #endif
93     L(SYSLOG),
94     L(USER),
95 #ifdef LOG_UUCP
96     L(UUCP),
97 #endif
98     L(LOCAL0),
99     L(LOCAL1),
100     L(LOCAL2),
101     L(LOCAL3),
102     L(LOCAL4),
103     L(LOCAL5),
104     L(LOCAL6),
105     L(LOCAL7),
106     { NULL, -1 }
107 };
108 
109 static int
110 find_value(const char *s, struct s2i *table)
111 {
112     while(table->s && strcasecmp(table->s, s))
113 	table++;
114     return table->val;
115 }
116 
117 krb5_error_code
118 krb5_initlog(krb5_context context,
119 	     const char *program,
120 	     krb5_log_facility **fac)
121 {
122     krb5_log_facility *f = calloc(1, sizeof(*f));
123     if(f == NULL)
124 	return ENOMEM;
125     f->program = strdup(program);
126     if(f->program == NULL){
127 	free(f);
128 	return ENOMEM;
129     }
130     *fac = f;
131     return 0;
132 }
133 
134 krb5_error_code
135 krb5_addlog_func(krb5_context context,
136 		 krb5_log_facility *fac,
137 		 int min,
138 		 int max,
139 		 krb5_log_log_func_t log,
140 		 krb5_log_close_func_t close,
141 		 void *data)
142 {
143     struct facility *fp = log_realloc(fac);
144     if(fp == NULL)
145 	return ENOMEM;
146     fp->min = min;
147     fp->max = max;
148     fp->log = log;
149     fp->close = close;
150     fp->data = data;
151     return 0;
152 }
153 
154 
155 struct syslog_data{
156     int priority;
157 };
158 
159 static void
160 log_syslog(const char *time,
161 	   const char *msg,
162 	   void *data)
163 
164 {
165     struct syslog_data *s = data;
166     syslog(s->priority, "%s", msg);
167 }
168 
169 static void
170 close_syslog(void *data)
171 {
172     free(data);
173     closelog();
174 }
175 
176 static krb5_error_code
177 open_syslog(krb5_context context,
178 	    krb5_log_facility *facility, int min, int max,
179 	    const char *sev, const char *fac)
180 {
181     struct syslog_data *sd = malloc(sizeof(*sd));
182     int i;
183 
184     if(sd == NULL)
185 	return ENOMEM;
186     i = find_value(sev, syslogvals);
187     if(i == -1)
188 	i = LOG_ERR;
189     sd->priority = i;
190     i = find_value(fac, syslogvals);
191     if(i == -1)
192 	i = LOG_AUTH;
193     sd->priority |= i;
194     roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
195     return krb5_addlog_func(context, facility, min, max,
196 			    log_syslog, close_syslog, sd);
197 }
198 
199 struct file_data{
200     char *filename;
201     char *mode;
202     FILE *fd;
203     int keep_open;
204 };
205 
206 static void
207 log_file(const char *time,
208 	 const char *msg,
209 	 void *data)
210 {
211     struct file_data *f = data;
212     if(f->keep_open == 0)
213 	f->fd = fopen(f->filename, f->mode);
214     if(f->fd == NULL)
215 	return;
216     fprintf(f->fd, "%s %s\n", time, msg);
217     if(f->keep_open == 0)
218 	fclose(f->fd);
219 }
220 
221 static void
222 close_file(void *data)
223 {
224     struct file_data *f = data;
225     if(f->keep_open && f->filename)
226 	fclose(f->fd);
227     free(data);
228 }
229 
230 static krb5_error_code
231 open_file(krb5_context context, krb5_log_facility *fac, int min, int max,
232 	  char *filename, char *mode, FILE *f, int keep_open)
233 {
234     struct file_data *fd = malloc(sizeof(*fd));
235     if(fd == NULL)
236 	return ENOMEM;
237     fd->filename = filename;
238     fd->mode = mode;
239     fd->fd = f;
240     fd->keep_open = keep_open;
241 
242     return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
243 }
244 
245 
246 
247 krb5_error_code
248 krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *p)
249 {
250     krb5_error_code ret = 0;
251     int min = 0, max = -1, n;
252     char c;
253     n = sscanf(p, "%d%c%d/", &min, &c, &max);
254     if(n == 2){
255 	if(c == '/') {
256 	    if(min < 0){
257 		max = -min;
258 		min = 0;
259 	    }else{
260 		max = min;
261 	    }
262 	}
263     }
264     if(n){
265 	p = strchr(p, '/');
266 	if(p == NULL) return HEIM_ERR_LOG_PARSE;
267 	p++;
268     }
269     if(strcmp(p, "STDERR") == 0){
270 	ret = open_file(context, f, min, max, NULL, NULL, stderr, 1);
271     }else if(strcmp(p, "CONSOLE") == 0){
272 	ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0);
273     }else if(strncmp(p, "FILE:", 4) == 0 && (p[4] == ':' || p[4] == '=')){
274 	char *fn;
275 	FILE *file = NULL;
276 	int keep_open = 0;
277 	fn = strdup(p + 5);
278 	if(fn == NULL)
279 	    return ENOMEM;
280 	if(p[4] == '='){
281 	    int i = open(fn, O_WRONLY | O_CREAT |
282 			 O_TRUNC | O_APPEND, 0666);
283 	    if(i < 0)
284 		return errno;
285 	    file = fdopen(i, "a");
286 	    if(file == NULL){
287 		close(i);
288 		return errno;
289 	    }
290 	    keep_open = 1;
291 	}
292 	ret = open_file(context, f, min, max, fn, "a", file, keep_open);
293     }else if(strncmp(p, "DEVICE=", 6) == 0){
294 	ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0);
295     }else if(strncmp(p, "SYSLOG", 6) == 0){
296 	char *severity;
297 	char *facility;
298 	severity = strchr(p, ':');
299 	if(severity == NULL)
300 	    severity = "ERR";
301 	facility = strchr(severity, ':');
302 	if(facility == NULL)
303 	    facility = "AUTH";
304 	ret = open_syslog(context, f, min, max, severity, facility);
305     }else{
306 	ret = HEIM_ERR_LOG_PARSE; /* XXX */
307     }
308     return ret;
309 }
310 
311 
312 krb5_error_code
313 krb5_openlog(krb5_context context,
314 	     const char *program,
315 	     krb5_log_facility **fac)
316 {
317     krb5_error_code ret;
318     char **p, **q;
319 
320     ret = krb5_initlog(context, program, fac);
321     if(ret)
322 	return ret;
323 
324     p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
325     if(p == NULL)
326 	p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
327     if(p){
328 	for(q = p; *q; q++)
329 	    ret = krb5_addlog_dest(context, *fac, *q);
330 	krb5_config_free_strings(p);
331     }else
332 	ret = krb5_addlog_dest(context, *fac, "SYSLOG");
333     return 0;
334 }
335 
336 krb5_error_code
337 krb5_closelog(krb5_context context,
338 	      krb5_log_facility *fac)
339 {
340     int i;
341     for(i = 0; i < fac->len; i++)
342 	(*fac->val[i].close)(&fac->val[i].data);
343     return 0;
344 }
345 
346 #undef __attribute__
347 #define __attribute__(X)
348 
349 krb5_error_code
350 krb5_vlog_msg(krb5_context context,
351 	      krb5_log_facility *fac,
352 	      char **reply,
353 	      int level,
354 	      const char *fmt,
355 	      va_list ap)
356      __attribute__((format (printf, 5, 0)))
357 {
358     char *msg;
359     char buf[64];
360     time_t t;
361     int i;
362 
363     vasprintf(&msg, fmt, ap);
364     t = time(NULL);
365     strftime(buf, sizeof(buf), context->time_fmt,
366 	     context->log_utc ? gmtime(&t) : localtime(&t));
367     for(i = 0; i < fac->len; i++)
368 	if(fac->val[i].min <= level &&
369 	   (fac->val[i].max < 0 || fac->val[i].max >= level))
370 	    (*fac->val[i].log)(buf, msg, fac->val[i].data);
371     *reply = msg;
372     return 0;
373 }
374 
375 krb5_error_code
376 krb5_vlog(krb5_context context,
377 	  krb5_log_facility *fac,
378 	  int level,
379 	  const char *fmt,
380 	  va_list ap)
381      __attribute__((format (printf, 4, 0)))
382 {
383     char *msg;
384     krb5_error_code ret;
385 
386     ret = krb5_vlog_msg(context, fac, &msg, level, fmt, ap);
387     free(msg);
388     return ret;
389 }
390 
391 krb5_error_code
392 krb5_log_msg(krb5_context context,
393 	     krb5_log_facility *fac,
394 	     int level,
395 	     char **reply,
396 	     const char *fmt,
397 	     ...)
398      __attribute__((format (printf, 5, 6)))
399 {
400     va_list ap;
401     krb5_error_code ret;
402 
403     va_start(ap, fmt);
404     ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
405     va_end(ap);
406     return ret;
407 }
408 
409 
410 krb5_error_code
411 krb5_log(krb5_context context,
412 	 krb5_log_facility *fac,
413 	 int level,
414 	 const char *fmt,
415 	 ...)
416      __attribute__((format (printf, 4, 5)))
417 {
418     va_list ap;
419     krb5_error_code ret;
420 
421     va_start(ap, fmt);
422     ret = krb5_vlog(context, fac, level, fmt, ap);
423     va_end(ap);
424     return ret;
425 }
426 
427