1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/kadm5/logger.c */
3 /*
4 * Copyright 1995, 2007 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /* KADM5 wants non-syslog log files to contain syslog-like entries */
28 #define VERBOSE_LOGS
29
30 /*
31 * logger.c - Handle logging functions for those who want it.
32 */
33 #include "k5-int.h"
34 #include "adm_proto.h"
35 #include "com_err.h"
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <syslog.h>
39 #include <stdarg.h>
40
41 #define KRB5_KLOG_MAX_ERRMSG_SIZE 2048
42 #ifndef MAXHOSTNAMELEN
43 #define MAXHOSTNAMELEN 256
44 #endif /* MAXHOSTNAMELEN */
45
46 /* This is to assure that we have at least one match in the syslog stuff */
47 #ifndef LOG_AUTH
48 #define LOG_AUTH 0
49 #endif /* LOG_AUTH */
50 #ifndef LOG_ERR
51 #define LOG_ERR 0
52 #endif /* LOG_ERR */
53
54 #define lspec_parse_err_1 _("%s: cannot parse <%s>\n")
55 #define lspec_parse_err_2 _("%s: warning - logging entry syntax error\n")
56 #define log_file_err _("%s: error writing to %s\n")
57 #define log_device_err _("%s: error writing to %s device\n")
58 #define log_ufo_string "?\?\?" /* nb: avoid trigraphs */
59 #define log_emerg_string _("EMERGENCY")
60 #define log_alert_string _("ALERT")
61 #define log_crit_string _("CRITICAL")
62 #define log_err_string _("Error")
63 #define log_warning_string _("Warning")
64 #define log_notice_string _("Notice")
65 #define log_info_string _("info")
66 #define log_debug_string _("debug")
67
68 /*
69 * Output logging.
70 *
71 * Output logging is now controlled by the configuration file. We can specify
72 * the following syntaxes under the [logging]->entity specification.
73 * FILE<opentype><pathname>
74 * SYSLOG[=<severity>[:<facility>]]
75 * STDERR
76 * CONSOLE
77 * DEVICE=<device-spec>
78 *
79 * Where:
80 * <opentype> is ":" for open/append, "=" for open/create.
81 * <pathname> is a valid path name.
82 * <severity> is one of: (default = ERR)
83 * EMERG
84 * ALERT
85 * CRIT
86 * ERR
87 * WARNING
88 * NOTICE
89 * INFO
90 * DEBUG
91 * <facility> is one of: (default = AUTH)
92 * KERN
93 * USER
94 * MAIL
95 * DAEMON
96 * AUTH
97 * LPR
98 * NEWS
99 * UUCP
100 * CRON
101 * LOCAL0..LOCAL7
102 * <device-spec> is a valid device specification.
103 */
104 struct log_entry {
105 enum log_type { K_LOG_FILE,
106 K_LOG_SYSLOG,
107 K_LOG_STDERR,
108 K_LOG_CONSOLE,
109 K_LOG_DEVICE,
110 K_LOG_NONE } log_type;
111 krb5_pointer log_2free;
112 union log_union {
113 struct log_file {
114 FILE *lf_filep;
115 char *lf_fname;
116 } log_file;
117 struct log_syslog {
118 int ls_facility;
119 } log_syslog;
120 struct log_device {
121 FILE *ld_filep;
122 char *ld_devname;
123 } log_device;
124 } log_union;
125 };
126 #define lfu_filep log_union.log_file.lf_filep
127 #define lfu_fname log_union.log_file.lf_fname
128 #define lsu_facility log_union.log_syslog.ls_facility
129 #define ldu_filep log_union.log_device.ld_filep
130 #define ldu_devname log_union.log_device.ld_devname
131
132 struct log_control {
133 struct log_entry *log_entries;
134 int log_nentries;
135 char *log_whoami;
136 char *log_hostname;
137 krb5_boolean log_opened;
138 krb5_boolean log_debug;
139 };
140
141 static struct log_control log_control = {
142 (struct log_entry *) NULL,
143 0,
144 (char *) NULL,
145 (char *) NULL,
146 0
147 };
148 static struct log_entry def_log_entry;
149
150 /*
151 * These macros define any special processing that needs to happen for
152 * devices. For unix, of course, this is hardly anything.
153 */
154 #define DEVICE_OPEN(d, m) fopen(d, m)
155 #define CONSOLE_OPEN(m) fopen("/dev/console", m)
156 #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \
157 (fflush(f), 0) : \
158 -1)
159 #define DEVICE_CLOSE(d) fclose(d)
160
161 /*
162 * klog_com_err_proc() - Handle com_err(3) messages as specified by the
163 * profile.
164 */
165 static krb5_context err_context;
166
167 static void
168 klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap)
169 #if !defined(__cplusplus) && (__GNUC__ > 2)
170 __attribute__((__format__(__printf__, 3, 0)))
171 #endif
172 ;
173
174 /*
175 * Write com_err() messages to the configured logging devices. Ignore whoami,
176 * as krb5_klog_init() already received a whoami value. If code is nonzero,
177 * log its error message (retrieved using err_context) and the formatted
178 * message at error severity. If code is zero, log the formatted message at
179 * informational severity.
180 */
181 static void
klog_com_err_proc(const char * whoami,long int code,const char * format,va_list ap)182 klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap)
183 {
184 struct k5buf buf;
185 const char *emsg, *msg;
186
187 if (format == NULL)
188 return;
189
190 k5_buf_init_dynamic(&buf);
191
192 if (code) {
193 /* Start with the error message and a separator. */
194 emsg = krb5_get_error_message(err_context, code);
195 k5_buf_add(&buf, emsg);
196 krb5_free_error_message(err_context, emsg);
197 k5_buf_add(&buf, " - ");
198 }
199
200 /* Add the formatted message. */
201 k5_buf_add_vfmt(&buf, format, ap);
202
203 msg = k5_buf_cstring(&buf);
204 if (msg != NULL)
205 krb5_klog_syslog(code ? LOG_ERR : LOG_INFO, "%s", msg);
206
207 k5_buf_free(&buf);
208 }
209
210 /*
211 * krb5_klog_init() - Initialize logging.
212 *
213 * This routine parses the syntax described above to specify destinations for
214 * com_err(3) or krb5_klog_syslog() messages generated by the caller.
215 *
216 * Parameters:
217 * kcontext - Kerberos context.
218 * ename - Entity name as it is to appear in the profile.
219 * whoami - Entity name as it is to appear in error output.
220 * do_com_err - Take over com_err(3) processing.
221 *
222 * Implicit inputs:
223 * stderr - This is where STDERR output goes.
224 *
225 * Implicit outputs:
226 * log_nentries - Number of log entries, both valid and invalid.
227 * log_control - List of entries (log_nentries long) which contains
228 * data for klog_com_err_proc() to use to determine
229 * where/how to send output.
230 */
231 krb5_error_code
krb5_klog_init(krb5_context kcontext,char * ename,char * whoami,krb5_boolean do_com_err)232 krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do_com_err)
233 {
234 const char *logging_profent[3];
235 const char *logging_defent[3];
236 char **logging_specs;
237 int i, ngood, fd, append;
238 char *cp, *cp2;
239 char savec = '\0';
240 int error, debug;
241 int do_openlog, log_facility;
242 FILE *f = NULL;
243
244 /* Initialize */
245 do_openlog = 0;
246 log_facility = 0;
247
248 err_context = kcontext;
249
250 /* Look up [logging]->debug in the profile to see if we should include
251 * debug messages for types other than syslog. Default to false. */
252 if (!profile_get_boolean(kcontext->profile, KRB5_CONF_LOGGING,
253 KRB5_CONF_DEBUG, NULL, 0, &debug))
254 log_control.log_debug = debug;
255
256 /*
257 * Look up [logging]-><ename> in the profile. If that doesn't
258 * succeed, then look for [logging]->default.
259 */
260 logging_profent[0] = KRB5_CONF_LOGGING;
261 logging_profent[1] = ename;
262 logging_profent[2] = (char *) NULL;
263 logging_defent[0] = KRB5_CONF_LOGGING;
264 logging_defent[1] = KRB5_CONF_DEFAULT;
265 logging_defent[2] = (char *) NULL;
266 logging_specs = (char **) NULL;
267 ngood = 0;
268 log_control.log_nentries = 0;
269 if (!profile_get_values(kcontext->profile,
270 logging_profent,
271 &logging_specs) ||
272 !profile_get_values(kcontext->profile,
273 logging_defent,
274 &logging_specs)) {
275 /*
276 * We have a match, so we first count the number of elements
277 */
278 for (log_control.log_nentries = 0;
279 logging_specs[log_control.log_nentries];
280 log_control.log_nentries++);
281
282 /*
283 * Now allocate our structure.
284 */
285 log_control.log_entries = (struct log_entry *)
286 malloc(log_control.log_nentries * sizeof(struct log_entry));
287 if (log_control.log_entries) {
288 /*
289 * Scan through the list.
290 */
291 for (i=0; i<log_control.log_nentries; i++) {
292 log_control.log_entries[i].log_type = K_LOG_NONE;
293 log_control.log_entries[i].log_2free = logging_specs[i];
294 /*
295 * The format is:
296 * <whitespace><data><whitespace>
297 * so, trim off the leading and trailing whitespace here.
298 */
299 for (cp = logging_specs[i]; isspace((int) *cp); cp++);
300 for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1];
301 isspace((int) *cp2); cp2--);
302 cp2++;
303 *cp2 = '\0';
304 /*
305 * Is this a file?
306 */
307 if (!strncasecmp(cp, "FILE", 4)) {
308 /*
309 * Check for append/overwrite, then open the file.
310 */
311 append = (cp[4] == ':') ? O_APPEND : 0;
312 if (append || cp[4] == '=') {
313 fd = open(&cp[5], O_CREAT | O_WRONLY | append,
314 S_IRUSR | S_IWUSR | S_IRGRP);
315 if (fd != -1)
316 f = fdopen(fd, append ? "a" : "w");
317 if (fd == -1 || f == NULL) {
318 fprintf(stderr,"Couldn't open log file %s: %s\n",
319 &cp[5], error_message(errno));
320 continue;
321 }
322 set_cloexec_file(f);
323 log_control.log_entries[i].lfu_filep = f;
324 log_control.log_entries[i].log_type = K_LOG_FILE;
325 log_control.log_entries[i].lfu_fname = &cp[5];
326 }
327 }
328 /*
329 * Is this a syslog?
330 */
331 else if (!strncasecmp(cp, "SYSLOG", 6)) {
332 error = 0;
333 log_control.log_entries[i].lsu_facility = LOG_AUTH;
334 /*
335 * Is there a severify (which is now ignored) specified?
336 */
337 if (cp[6] == ':') {
338 /*
339 * Find the end of the severity.
340 */
341 cp2 = strchr(&cp[7], ':');
342 if (cp2) {
343 savec = *cp2;
344 *cp2 = '\0';
345 cp2++;
346 }
347
348 /*
349 * If there is a facility present, then parse that.
350 */
351 if (cp2) {
352 static const struct {
353 const char *name;
354 int value;
355 } facilities[] = {
356 { "AUTH", LOG_AUTH },
357 #ifdef LOG_AUTHPRIV
358 { "AUTHPRIV", LOG_AUTHPRIV },
359 #endif /* LOG_AUTHPRIV */
360 #ifdef LOG_KERN
361 { "KERN", LOG_KERN },
362 #endif /* LOG_KERN */
363 #ifdef LOG_USER
364 { "USER", LOG_USER },
365 #endif /* LOG_USER */
366 #ifdef LOG_MAIL
367 { "MAIL", LOG_MAIL },
368 #endif /* LOG_MAIL */
369 #ifdef LOG_DAEMON
370 { "DAEMON", LOG_DAEMON },
371 #endif /* LOG_DAEMON */
372 #ifdef LOG_FTP
373 { "FTP", LOG_FTP },
374 #endif /* LOG_FTP */
375 #ifdef LOG_LPR
376 { "LPR", LOG_LPR },
377 #endif /* LOG_LPR */
378 #ifdef LOG_NEWS
379 { "NEWS", LOG_NEWS },
380 #endif /* LOG_NEWS */
381 #ifdef LOG_UUCP
382 { "UUCP", LOG_UUCP },
383 #endif /* LOG_UUCP */
384 #ifdef LOG_CRON
385 { "CRON", LOG_CRON },
386 #endif /* LOG_CRON */
387 #ifdef LOG_LOCAL0
388 { "LOCAL0", LOG_LOCAL0 },
389 #endif /* LOG_LOCAL0 */
390 #ifdef LOG_LOCAL1
391 { "LOCAL1", LOG_LOCAL1 },
392 #endif /* LOG_LOCAL1 */
393 #ifdef LOG_LOCAL2
394 { "LOCAL2", LOG_LOCAL2 },
395 #endif /* LOG_LOCAL2 */
396 #ifdef LOG_LOCAL3
397 { "LOCAL3", LOG_LOCAL3 },
398 #endif /* LOG_LOCAL3 */
399 #ifdef LOG_LOCAL4
400 { "LOCAL4", LOG_LOCAL4 },
401 #endif /* LOG_LOCAL4 */
402 #ifdef LOG_LOCAL5
403 { "LOCAL5", LOG_LOCAL5 },
404 #endif /* LOG_LOCAL5 */
405 #ifdef LOG_LOCAL6
406 { "LOCAL6", LOG_LOCAL6 },
407 #endif /* LOG_LOCAL6 */
408 #ifdef LOG_LOCAL7
409 { "LOCAL7", LOG_LOCAL7 },
410 #endif /* LOG_LOCAL7 */
411 };
412 unsigned int j;
413
414 for (j = 0; j < sizeof(facilities)/sizeof(facilities[0]); j++)
415 if (!strcasecmp(cp2, facilities[j].name)) {
416 log_control.log_entries[i].lsu_facility = facilities[j].value;
417 break;
418 }
419 cp2--;
420 *cp2 = savec;
421 }
422 }
423 if (!error) {
424 log_control.log_entries[i].log_type = K_LOG_SYSLOG;
425 do_openlog = 1;
426 log_facility = log_control.log_entries[i].lsu_facility;
427 }
428 }
429 /*
430 * Is this a standard error specification?
431 */
432 else if (!strcasecmp(cp, "STDERR")) {
433 log_control.log_entries[i].lfu_filep =
434 fdopen(fileno(stderr), "w");
435 if (log_control.log_entries[i].lfu_filep) {
436 log_control.log_entries[i].log_type = K_LOG_STDERR;
437 log_control.log_entries[i].lfu_fname =
438 "standard error";
439 }
440 }
441 /*
442 * Is this a specification of the console?
443 */
444 else if (!strcasecmp(cp, "CONSOLE")) {
445 log_control.log_entries[i].ldu_filep =
446 CONSOLE_OPEN("a+");
447 if (log_control.log_entries[i].ldu_filep) {
448 set_cloexec_file(log_control.log_entries[i].ldu_filep);
449 log_control.log_entries[i].log_type = K_LOG_CONSOLE;
450 log_control.log_entries[i].ldu_devname = "console";
451 }
452 }
453 /*
454 * Is this a specification of a device?
455 */
456 else if (!strncasecmp(cp, "DEVICE", 6)) {
457 /*
458 * We handle devices very similarly to files.
459 */
460 if (cp[6] == '=') {
461 log_control.log_entries[i].ldu_filep =
462 DEVICE_OPEN(&cp[7], "w");
463 if (log_control.log_entries[i].ldu_filep) {
464 set_cloexec_file(log_control.log_entries[i].ldu_filep);
465 log_control.log_entries[i].log_type = K_LOG_DEVICE;
466 log_control.log_entries[i].ldu_devname = &cp[7];
467 }
468 }
469 }
470 /*
471 * See if we successfully parsed this specification.
472 */
473 if (log_control.log_entries[i].log_type == K_LOG_NONE) {
474 fprintf(stderr, lspec_parse_err_1, whoami, cp);
475 fprintf(stderr, lspec_parse_err_2, whoami);
476 }
477 else
478 ngood++;
479 }
480 }
481 /*
482 * If we didn't find anything, then free our lists.
483 */
484 if (ngood == 0) {
485 for (i=0; i<log_control.log_nentries; i++)
486 free(logging_specs[i]);
487 }
488 free(logging_specs);
489 }
490 /*
491 * If we didn't find anything, go for the default which is to log to
492 * the system log.
493 */
494 if (ngood == 0) {
495 if (log_control.log_entries)
496 free(log_control.log_entries);
497 log_control.log_entries = &def_log_entry;
498 log_control.log_entries->log_type = K_LOG_SYSLOG;
499 log_control.log_entries->log_2free = (krb5_pointer) NULL;
500 log_facility = log_control.log_entries->lsu_facility = LOG_AUTH;
501 do_openlog = 1;
502 log_control.log_nentries = 1;
503 }
504 if (log_control.log_nentries) {
505 log_control.log_whoami = strdup(whoami);
506 log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN + 1);
507 if (log_control.log_hostname) {
508 if (gethostname(log_control.log_hostname, MAXHOSTNAMELEN) == -1) {
509 free(log_control.log_hostname);
510 log_control.log_hostname = NULL;
511 } else
512 log_control.log_hostname[MAXHOSTNAMELEN] = '\0';
513 }
514 if (do_openlog) {
515 openlog(whoami, LOG_NDELAY|LOG_PID, log_facility);
516 log_control.log_opened = 1;
517 }
518 if (do_com_err)
519 (void) set_com_err_hook(klog_com_err_proc);
520 }
521 return((log_control.log_nentries) ? 0 : ENOENT);
522 }
523
524 /* Reset the context used by the com_err hook to retrieve error messages. */
525 void
krb5_klog_set_context(krb5_context kcontext)526 krb5_klog_set_context(krb5_context kcontext)
527 {
528 err_context = kcontext;
529 }
530
531 /*
532 * krb5_klog_close() - Close the logging context and free all data.
533 */
534 void
krb5_klog_close(krb5_context kcontext)535 krb5_klog_close(krb5_context kcontext)
536 {
537 int lindex;
538 (void) reset_com_err_hook();
539 for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
540 switch (log_control.log_entries[lindex].log_type) {
541 case K_LOG_FILE:
542 case K_LOG_STDERR:
543 /*
544 * Files/standard error.
545 */
546 fclose(log_control.log_entries[lindex].lfu_filep);
547 break;
548 case K_LOG_CONSOLE:
549 case K_LOG_DEVICE:
550 /*
551 * Devices (may need special handling)
552 */
553 DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep);
554 break;
555 case K_LOG_SYSLOG:
556 /*
557 * System log.
558 */
559 break;
560 default:
561 break;
562 }
563 if (log_control.log_entries[lindex].log_2free)
564 free(log_control.log_entries[lindex].log_2free);
565 }
566 if (log_control.log_entries != &def_log_entry)
567 free(log_control.log_entries);
568 log_control.log_entries = (struct log_entry *) NULL;
569 log_control.log_nentries = 0;
570 if (log_control.log_whoami)
571 free(log_control.log_whoami);
572 log_control.log_whoami = (char *) NULL;
573 if (log_control.log_hostname)
574 free(log_control.log_hostname);
575 log_control.log_hostname = (char *) NULL;
576 if (log_control.log_opened)
577 closelog();
578 }
579
580 /*
581 * severity2string() - Convert a severity to a string.
582 */
583 static const char *
severity2string(int severity)584 severity2string(int severity)
585 {
586 int s;
587 const char *ss;
588
589 s = severity & LOG_PRIMASK;
590 ss = log_ufo_string;
591 switch (s) {
592 case LOG_EMERG:
593 ss = log_emerg_string;
594 break;
595 case LOG_ALERT:
596 ss = log_alert_string;
597 break;
598 case LOG_CRIT:
599 ss = log_crit_string;
600 break;
601 case LOG_ERR:
602 ss = log_err_string;
603 break;
604 case LOG_WARNING:
605 ss = log_warning_string;
606 break;
607 case LOG_NOTICE:
608 ss = log_notice_string;
609 break;
610 case LOG_INFO:
611 ss = log_info_string;
612 break;
613 case LOG_DEBUG:
614 ss = log_debug_string;
615 break;
616 }
617 return(ss);
618 }
619
620 /*
621 * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while
622 * also performing the logging redirection as specified
623 * by krb5_klog_init().
624 */
625 static int
626 klog_vsyslog(int priority, const char *format, va_list arglist)
627 #if !defined(__cplusplus) && (__GNUC__ > 2)
628 __attribute__((__format__(__printf__, 2, 0)))
629 #endif
630 ;
631
632 static int
klog_vsyslog(int priority,const char * format,va_list arglist)633 klog_vsyslog(int priority, const char *format, va_list arglist)
634 {
635 char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
636 int lindex;
637 char *syslogp;
638 char *cp;
639 time_t now;
640 size_t soff;
641 struct tm *tm;
642
643 /*
644 * Format a syslog-esque message of the format:
645 *
646 * (verbose form)
647 * <date> <hostname> <id>[<pid>](<priority>): <message>
648 *
649 * (short form)
650 * <date> <message>
651 */
652 cp = outbuf;
653 (void) time(&now);
654
655 /*
656 * Format the date: mon dd hh:mm:ss
657 */
658 tm = localtime(&now);
659 if (tm == NULL)
660 return(-1);
661 soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", tm);
662 if (soff > 0)
663 cp += soff;
664 else
665 return(-1);
666
667 #ifdef VERBOSE_LOGS
668 snprintf(cp, sizeof(outbuf) - (cp-outbuf), " %s %s[%ld](%s): ",
669 log_control.log_hostname ? log_control.log_hostname : "",
670 log_control.log_whoami ? log_control.log_whoami : "",
671 (long) getpid(),
672 severity2string(priority));
673 #else
674 snprintf(cp, sizeof(outbuf) - (cp-outbuf), " ");
675 #endif
676 syslogp = &outbuf[strlen(outbuf)];
677
678 /* Now format the actual message */
679 vsnprintf(syslogp, sizeof(outbuf) - (syslogp - outbuf), format, arglist);
680
681 /*
682 * If the user did not use krb5_klog_init() instead of dropping
683 * the request on the floor, syslog it - if it exists
684 */
685 if (log_control.log_nentries == 0) {
686 /* Log the message with our header trimmed off */
687 syslog(priority, "%s", syslogp);
688 }
689
690 /*
691 * Now that we have the message formatted, perform the output to each
692 * logging specification.
693 */
694 for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
695 /* Omit LOG_DEBUG messages for non-syslog outputs unless we are
696 * configured to include them. */
697 if (priority == LOG_DEBUG && !log_control.log_debug &&
698 log_control.log_entries[lindex].log_type != K_LOG_SYSLOG)
699 continue;
700
701 switch (log_control.log_entries[lindex].log_type) {
702 case K_LOG_FILE:
703 case K_LOG_STDERR:
704 /*
705 * Files/standard error.
706 */
707 if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n",
708 outbuf) < 0) {
709 /* Attempt to report error */
710 fprintf(stderr, log_file_err, log_control.log_whoami,
711 log_control.log_entries[lindex].lfu_fname);
712 }
713 else {
714 fflush(log_control.log_entries[lindex].lfu_filep);
715 }
716 break;
717 case K_LOG_CONSOLE:
718 case K_LOG_DEVICE:
719 /*
720 * Devices (may need special handling)
721 */
722 if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
723 outbuf) < 0) {
724 /* Attempt to report error */
725 fprintf(stderr, log_device_err, log_control.log_whoami,
726 log_control.log_entries[lindex].ldu_devname);
727 }
728 break;
729 case K_LOG_SYSLOG:
730 /*
731 * System log.
732 */
733
734 /* Log the message with our header trimmed off */
735 syslog(priority, "%s", syslogp);
736 break;
737 default:
738 break;
739 }
740 }
741 return(0);
742 }
743
744 int
krb5_klog_syslog(int priority,const char * format,...)745 krb5_klog_syslog(int priority, const char *format, ...)
746 {
747 int retval;
748 va_list pvar;
749
750 va_start(pvar, format);
751 retval = klog_vsyslog(priority, format, pvar);
752 va_end(pvar);
753 return(retval);
754 }
755
756 /*
757 * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files.
758 * This function is called when a SIGHUP is received
759 * so that external log-archival utilities may
760 * alert the Kerberos daemons that they should get
761 * a new file descriptor for the give filename.
762 */
763 void
krb5_klog_reopen(krb5_context kcontext)764 krb5_klog_reopen(krb5_context kcontext)
765 {
766 int lindex;
767 FILE *f;
768
769 /*
770 * Only logs which are actually files need to be closed
771 * and reopened in response to a SIGHUP
772 */
773 for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
774 if (log_control.log_entries[lindex].log_type == K_LOG_FILE) {
775 fclose(log_control.log_entries[lindex].lfu_filep);
776 /*
777 * In case the old logfile did not get moved out of the
778 * way, open for append to prevent squashing the old logs.
779 */
780 f = fopen(log_control.log_entries[lindex].lfu_fname, "a+");
781 if (f) {
782 set_cloexec_file(f);
783 log_control.log_entries[lindex].lfu_filep = f;
784 } else {
785 fprintf(stderr, _("Couldn't open log file %s: %s\n"),
786 log_control.log_entries[lindex].lfu_fname,
787 error_message(errno));
788 }
789 }
790 }
791 }
792