turn off v4 conversion stuff
[heimdal.git] / lib / krb5 / log.c
blob9f814609732391186aaeb80f532f78f9f3901515
1 /*
2 * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * 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.
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.
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.
34 #include "krb5_locl.h"
35 #include <vis.h>
37 struct facility {
38 int min;
39 int max;
40 krb5_log_log_func_t log_func;
41 krb5_log_close_func_t close_func;
42 void *data;
45 static struct facility*
46 log_realloc(krb5_log_facility *f)
48 struct facility *fp;
49 fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
50 if(fp == NULL)
51 return NULL;
52 f->len++;
53 f->val = fp;
54 fp += f->len - 1;
55 return fp;
58 struct s2i {
59 const char *s;
60 int val;
63 #define L(X) { #X, LOG_ ## X }
65 static struct s2i syslogvals[] = {
66 L(EMERG),
67 L(ALERT),
68 L(CRIT),
69 L(ERR),
70 L(WARNING),
71 L(NOTICE),
72 L(INFO),
73 L(DEBUG),
75 L(AUTH),
76 #ifdef LOG_AUTHPRIV
77 L(AUTHPRIV),
78 #endif
79 #ifdef LOG_CRON
80 L(CRON),
81 #endif
82 L(DAEMON),
83 #ifdef LOG_FTP
84 L(FTP),
85 #endif
86 L(KERN),
87 L(LPR),
88 L(MAIL),
89 #ifdef LOG_NEWS
90 L(NEWS),
91 #endif
92 L(SYSLOG),
93 L(USER),
94 #ifdef LOG_UUCP
95 L(UUCP),
96 #endif
97 L(LOCAL0),
98 L(LOCAL1),
99 L(LOCAL2),
100 L(LOCAL3),
101 L(LOCAL4),
102 L(LOCAL5),
103 L(LOCAL6),
104 L(LOCAL7),
105 { NULL, -1 }
108 static int
109 find_value(const char *s, struct s2i *table)
111 while(table->s && strcasecmp(table->s, s))
112 table++;
113 return table->val;
116 krb5_error_code KRB5_LIB_FUNCTION
117 krb5_initlog(krb5_context context,
118 const char *program,
119 krb5_log_facility **fac)
121 krb5_log_facility *f = calloc(1, sizeof(*f));
122 if(f == NULL) {
123 krb5_set_error_message(context, ENOMEM,
124 N_("malloc: out of memory", ""));
125 return ENOMEM;
127 f->program = strdup(program);
128 if(f->program == NULL){
129 free(f);
130 krb5_set_error_message(context, ENOMEM,
131 N_("malloc: out of memory", ""));
132 return ENOMEM;
134 *fac = f;
135 return 0;
138 krb5_error_code KRB5_LIB_FUNCTION
139 krb5_addlog_func(krb5_context context,
140 krb5_log_facility *fac,
141 int min,
142 int max,
143 krb5_log_log_func_t log_func,
144 krb5_log_close_func_t close_func,
145 void *data)
147 struct facility *fp = log_realloc(fac);
148 if(fp == NULL) {
149 krb5_set_error_message(context, ENOMEM,
150 N_("malloc: out of memory", ""));
151 return ENOMEM;
153 fp->min = min;
154 fp->max = max;
155 fp->log_func = log_func;
156 fp->close_func = close_func;
157 fp->data = data;
158 return 0;
162 struct _heimdal_syslog_data{
163 int priority;
166 static void
167 log_syslog(const char *timestr,
168 const char *msg,
169 void *data)
172 struct _heimdal_syslog_data *s = data;
173 syslog(s->priority, "%s", msg);
176 static void
177 close_syslog(void *data)
179 free(data);
180 closelog();
183 static krb5_error_code
184 open_syslog(krb5_context context,
185 krb5_log_facility *facility, int min, int max,
186 const char *sev, const char *fac)
188 struct _heimdal_syslog_data *sd = malloc(sizeof(*sd));
189 int i;
191 if(sd == NULL) {
192 krb5_set_error_message(context, ENOMEM,
193 N_("malloc: out of memory", ""));
194 return ENOMEM;
196 i = find_value(sev, syslogvals);
197 if(i == -1)
198 i = LOG_ERR;
199 sd->priority = i;
200 i = find_value(fac, syslogvals);
201 if(i == -1)
202 i = LOG_AUTH;
203 sd->priority |= i;
204 roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
205 return krb5_addlog_func(context, facility, min, max,
206 log_syslog, close_syslog, sd);
209 struct file_data{
210 const char *filename;
211 const char *mode;
212 FILE *fd;
213 int keep_open;
216 static void
217 log_file(const char *timestr,
218 const char *msg,
219 void *data)
221 struct file_data *f = data;
222 char *msgclean;
223 size_t len = strlen(msg);
224 if(f->keep_open == 0)
225 f->fd = fopen(f->filename, f->mode);
226 if(f->fd == NULL)
227 return;
228 /* make sure the log doesn't contain special chars */
229 msgclean = malloc((len + 1) * 4);
230 if (msgclean == NULL)
231 goto out;
232 strvisx(msgclean, rk_UNCONST(msg), len, VIS_OCTAL);
233 fprintf(f->fd, "%s %s\n", timestr, msgclean);
234 free(msgclean);
235 out:
236 if(f->keep_open == 0) {
237 fclose(f->fd);
238 f->fd = NULL;
242 static void
243 close_file(void *data)
245 struct file_data *f = data;
246 if(f->keep_open && f->filename)
247 fclose(f->fd);
248 free(data);
251 static krb5_error_code
252 open_file(krb5_context context, krb5_log_facility *fac, int min, int max,
253 const char *filename, const char *mode, FILE *f, int keep_open)
255 struct file_data *fd = malloc(sizeof(*fd));
256 if(fd == NULL) {
257 krb5_set_error_message(context, ENOMEM,
258 N_("malloc: out of memory", ""));
259 return ENOMEM;
261 fd->filename = filename;
262 fd->mode = mode;
263 fd->fd = f;
264 fd->keep_open = keep_open;
266 return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
271 krb5_error_code KRB5_LIB_FUNCTION
272 krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig)
274 krb5_error_code ret = 0;
275 int min = 0, max = -1, n;
276 char c;
277 const char *p = orig;
279 n = sscanf(p, "%d%c%d/", &min, &c, &max);
280 if(n == 2){
281 if(c == '/') {
282 if(min < 0){
283 max = -min;
284 min = 0;
285 }else{
286 max = min;
290 if(n){
291 p = strchr(p, '/');
292 if(p == NULL) {
293 krb5_set_error_message(context, HEIM_ERR_LOG_PARSE,
294 N_("failed to parse \"%s\"", ""), orig);
295 return HEIM_ERR_LOG_PARSE;
297 p++;
299 if(strcmp(p, "STDERR") == 0){
300 ret = open_file(context, f, min, max, NULL, NULL, stderr, 1);
301 }else if(strcmp(p, "CONSOLE") == 0){
302 ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0);
303 }else if(strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')){
304 char *fn;
305 FILE *file = NULL;
306 int keep_open = 0;
307 fn = strdup(p + 5);
308 if(fn == NULL) {
309 krb5_set_error_message(context, ENOMEM,
310 N_("malloc: out of memory", ""));
311 return ENOMEM;
313 if(p[4] == '='){
314 int i = open(fn, O_WRONLY | O_CREAT |
315 O_TRUNC | O_APPEND, 0666);
316 if(i < 0) {
317 ret = errno;
318 krb5_set_error_message(context, ret,
319 N_("open(%s) logile: %s", ""), fn,
320 strerror(ret));
321 free(fn);
322 return ret;
324 rk_cloexec(i);
325 file = fdopen(i, "a");
326 if(file == NULL){
327 ret = errno;
328 close(i);
329 krb5_set_error_message(context, ret,
330 N_("fdopen(%s) logfile: %s", ""),
331 fn, strerror(ret));
332 free(fn);
333 return ret;
335 keep_open = 1;
337 ret = open_file(context, f, min, max, fn, "a", file, keep_open);
338 }else if(strncmp(p, "DEVICE", 6) == 0 && (p[6] == ':' || p[6] == '=')){
339 ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0);
340 }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){
341 char severity[128] = "";
342 char facility[128] = "";
343 p += 6;
344 if(*p != '\0')
345 p++;
346 if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
347 strsep_copy(&p, ":", facility, sizeof(facility));
348 if(*severity == '\0')
349 strlcpy(severity, "ERR", sizeof(severity));
350 if(*facility == '\0')
351 strlcpy(facility, "AUTH", sizeof(facility));
352 ret = open_syslog(context, f, min, max, severity, facility);
353 }else{
354 ret = HEIM_ERR_LOG_PARSE; /* XXX */
355 krb5_set_error_message (context, ret,
356 N_("unknown log type: %s", ""), p);
358 return ret;
362 krb5_error_code KRB5_LIB_FUNCTION
363 krb5_openlog(krb5_context context,
364 const char *program,
365 krb5_log_facility **fac)
367 krb5_error_code ret;
368 char **p, **q;
370 ret = krb5_initlog(context, program, fac);
371 if(ret)
372 return ret;
374 p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
375 if(p == NULL)
376 p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
377 if(p){
378 for(q = p; *q && ret == 0; q++)
379 ret = krb5_addlog_dest(context, *fac, *q);
380 krb5_config_free_strings(p);
381 }else
382 ret = krb5_addlog_dest(context, *fac, "SYSLOG");
383 return ret;
386 krb5_error_code KRB5_LIB_FUNCTION
387 krb5_closelog(krb5_context context,
388 krb5_log_facility *fac)
390 int i;
391 for(i = 0; i < fac->len; i++)
392 (*fac->val[i].close_func)(fac->val[i].data);
393 free(fac->val);
394 free(fac->program);
395 fac->val = NULL;
396 fac->len = 0;
397 fac->program = NULL;
398 free(fac);
399 return 0;
402 #undef __attribute__
403 #define __attribute__(X)
405 krb5_error_code KRB5_LIB_FUNCTION
406 krb5_vlog_msg(krb5_context context,
407 krb5_log_facility *fac,
408 char **reply,
409 int level,
410 const char *fmt,
411 va_list ap)
412 __attribute__((format (printf, 5, 0)))
415 char *msg = NULL;
416 const char *actual = NULL;
417 char buf[64];
418 time_t t = 0;
419 int i;
421 for(i = 0; fac && i < fac->len; i++)
422 if(fac->val[i].min <= level &&
423 (fac->val[i].max < 0 || fac->val[i].max >= level)) {
424 if(t == 0) {
425 t = time(NULL);
426 krb5_format_time(context, t, buf, sizeof(buf), TRUE);
428 if(actual == NULL) {
429 vasprintf(&msg, fmt, ap);
430 if(msg == NULL)
431 actual = fmt;
432 else
433 actual = msg;
435 (*fac->val[i].log_func)(buf, actual, fac->val[i].data);
437 if(reply == NULL)
438 free(msg);
439 else
440 *reply = msg;
441 return 0;
444 krb5_error_code KRB5_LIB_FUNCTION
445 krb5_vlog(krb5_context context,
446 krb5_log_facility *fac,
447 int level,
448 const char *fmt,
449 va_list ap)
450 __attribute__((format (printf, 4, 0)))
452 return krb5_vlog_msg(context, fac, NULL, level, fmt, ap);
455 krb5_error_code KRB5_LIB_FUNCTION
456 krb5_log_msg(krb5_context context,
457 krb5_log_facility *fac,
458 int level,
459 char **reply,
460 const char *fmt,
461 ...)
462 __attribute__((format (printf, 5, 6)))
464 va_list ap;
465 krb5_error_code ret;
467 va_start(ap, fmt);
468 ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
469 va_end(ap);
470 return ret;
474 krb5_error_code KRB5_LIB_FUNCTION
475 krb5_log(krb5_context context,
476 krb5_log_facility *fac,
477 int level,
478 const char *fmt,
479 ...)
480 __attribute__((format (printf, 4, 5)))
482 va_list ap;
483 krb5_error_code ret;
485 va_start(ap, fmt);
486 ret = krb5_vlog(context, fac, level, fmt, ap);
487 va_end(ap);
488 return ret;
491 void KRB5_LIB_FUNCTION
492 _krb5_debug(krb5_context context,
493 int level,
494 const char *fmt,
495 ...)
496 __attribute__((format (printf, 3, 4)))
498 va_list ap;
500 if (context == NULL || context->debug_dest == NULL)
501 return;
503 va_start(ap, fmt);
504 krb5_vlog(context, context->debug_dest, level, fmt, ap);
505 va_end(ap);