2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
9 * Copyright 1995 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
33 /* KADM5 wants non-syslog log files to contain syslog-like entries */
37 * logger.c - Handle logging functions for those who want it.
40 #include "adm_proto.h"
47 #endif /* HAVE_SYSLOG_H */
50 #else /* HAVE_STDARG_H */
52 #endif /* HAVE_STDARG_H */
54 #include <sys/types.h>
57 #define KRB5_KLOG_MAX_ERRMSG_SIZE 2048
58 #ifndef MAXHOSTNAMELEN
59 #define MAXHOSTNAMELEN 256
60 #endif /* MAXHOSTNAMELEN */
62 #define LSPEC_PARSE_ERR_1 1
63 #define LSPEC_PARSE_ERR_2 2
64 #define LOG_FILE_ERR 3
65 #define LOG_DEVICE_ERR 4
66 #define LOG_UFO_STRING 5
67 #define LOG_EMERG_STRING 6
68 #define LOG_ALERT_STRING 7
69 #define LOG_CRIT_STRING 8
70 #define LOG_ERR_STRING 9
71 #define LOG_WARNING_STRING 10
72 #define LOG_NOTICE_STRING 11
73 #define LOG_INFO_STRING 12
74 #define LOG_DEBUG_STRING 13
75 /* This is to assure that we have at least one match in the syslog stuff */
77 static const char LSPEC_PARSE_ERR_1[] = "%s: cannot parse <%s>\n";
78 static const char LSPEC_PARSE_ERR_2[] = "%s: warning - logging entry syntax error\n";
79 static const char LOG_FILE_ERR[] = "%s: error writing to %s\n";
80 static const char LOG_DEVICE_ERR[] = "%s: error writing to %s device\n";
81 static const char LOG_UFO_STRING[] = "???";
82 static const char LOG_EMERG_STRING[] = "EMERGENCY";
83 static const char LOG_ALERT_STRING[] = "ALERT";
84 static const char LOG_CRIT_STRING[] = "CRITICAL";
85 static const char LOG_ERR_STRING[] = "Error";
86 static const char LOG_WARNING_STRING[] = "Warning";
87 static const char LOG_NOTICE_STRING[] = "Notice";
88 static const char LOG_INFO_STRING[] = "info";
89 static const char LOG_DEBUG_STRING[] = "debug";
94 krb5_log_error_table(long errorno
) {
96 case LSPEC_PARSE_ERR_1
:
97 return(gettext("%s: cannot parse <%s>\n"));
98 case LSPEC_PARSE_ERR_2
:
99 return(gettext("%s: warning - logging entry syntax error\n"));
101 return(gettext("%s: error writing to %s\n"));
103 return(gettext("%s: error writing to %s device\n"));
106 return(gettext("???"));
107 case LOG_EMERG_STRING
:
108 return(gettext("EMERGENCY"));
109 case LOG_ALERT_STRING
:
110 return(gettext("ALERT"));
111 case LOG_CRIT_STRING
:
112 return(gettext("CRITICAL"));
114 return(gettext("Error"));
115 case LOG_WARNING_STRING
:
116 return(gettext("Warning"));
117 case LOG_NOTICE_STRING
:
118 return(gettext("Notice"));
119 case LOG_INFO_STRING
:
120 return(gettext("info"));
121 case LOG_DEBUG_STRING
:
122 return(gettext("info"));
129 * Output logging is now controlled by the configuration file. We can specify
130 * the following syntaxes under the [logging]->entity specification.
131 * FILE<opentype><pathname>
132 * SYSLOG[=<severity>[:<facility>]]
135 * DEVICE=<device-spec>
138 * <opentype> is ":" for open/append, "=" for open/create.
139 * <pathname> is a valid path name.
140 * <severity> is one of: (default = ERR)
149 * <facility> is one of: (default = AUTH)
160 * <device-spec> is a valid device specification.
163 enum log_type
{ K_LOG_FILE
,
168 K_LOG_NONE
} log_type
;
169 krb5_pointer log_2free
;
174 char *lf_fopen_mode
; /* "a+" or "w" */
175 #define K_LOG_DEF_FILE_ROTATE_PERIOD -1 /* never */
176 #define K_LOG_DEF_FILE_ROTATE_VERSIONS 0 /* no versions */
177 time_t lf_rotate_period
;
178 time_t lf_last_rotated
;
179 int lf_rotate_versions
;
191 #define lfu_filep log_union.log_file.lf_filep
192 #define lfu_fname log_union.log_file.lf_fname
193 #define lfu_fopen_mode log_union.log_file.lf_fopen_mode
194 #define lfu_rotate_period log_union.log_file.lf_rotate_period
195 #define lfu_last_rotated log_union.log_file.lf_last_rotated
196 #define lfu_rotate_versions log_union.log_file.lf_rotate_versions
197 #define lsu_facility log_union.log_syslog.ls_facility
198 #define lsu_severity log_union.log_syslog.ls_severity
199 #define ldu_filep log_union.log_device.ld_filep
200 #define ldu_devname log_union.log_device.ld_devname
203 struct log_entry
*log_entries
;
207 krb5_boolean log_opened
;
210 static struct log_control log_control
= {
217 static struct log_entry def_log_entry
;
220 * These macros define any special processing that needs to happen for
221 * devices. For unix, of course, this is hardly anything.
223 #define DEVICE_OPEN(d, m) fopen(d, m)
224 #define CONSOLE_OPEN(m) fopen("/dev/console", m)
225 #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \
228 #define DEVICE_CLOSE(d) fclose(d)
232 * klog_rotate() - roate a log file if we have specified rotation
233 * parameters in krb5.conf.
236 klog_rotate(struct log_entry
*le
)
251 * By default we don't rotate.
253 if (le
->lfu_rotate_period
== K_LOG_DEF_FILE_ROTATE_PERIOD
)
258 if (t
>= le
->lfu_last_rotated
+ le
->lfu_rotate_period
) {
260 * The N log file versions will be renamed X.N-1 X.N-2, ... X.0.
261 * So the allocate file name buffers that can the version
263 * 32 extra bytes is plenty.
265 name_buf1
= malloc(strlen(le
->lfu_fname
) + 32);
267 if (name_buf1
== NULL
)
270 name_buf2
= malloc(strlen(le
->lfu_fname
) + 32);
272 if (name_buf2
== NULL
) {
277 old_name
= name_buf1
;
278 new_name
= name_buf2
;
281 * If there N versions, then the first one has file extension
284 (void) sprintf(new_name
, "%s.%d", le
->lfu_fname
,
285 le
->lfu_rotate_versions
- 1);
288 * Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ...
291 for (i
= le
->lfu_rotate_versions
- 1; i
> 0; i
--) {
292 (void) sprintf(old_name
, "%s.%d", le
->lfu_fname
, i
- 1);
293 (void) rename(old_name
, new_name
);
296 * swap old name and new name. This way,
297 * on the next iteration, new_name.X
298 * becomes new_name.X-1.
304 old_name
= le
->lfu_fname
;
306 (void) rename(old_name
, new_name
);
309 * Even though we don't know yet if the fopen()
310 * of the log file will succeed, we mark the log
311 * as rotated. This is so we don't repeatably
312 * rotate file.N-2 to file.N-1 ... etc without
313 * waiting for the rotate period to elapse.
315 le
->lfu_last_rotated
= t
;
318 * Default log file creation mode should be read-only
319 * by owner(root), but the admin can override with
320 * chmod(1) if desired.
323 old_umask
= umask(077);
324 fp
= fopen(old_name
, le
->lfu_fopen_mode
);
330 (void) fclose(le
->lfu_filep
);
334 * If the version parameter in krb5.conf was
335 * 0, then we take this to mean that rotating the
336 * log file will cause us to dispose of the
337 * old one, and created a new one. We have just
338 * renamed the old one to file.-1, so remove it.
340 if (le
->lfu_rotate_versions
<= 0)
341 (void) unlink(new_name
);
345 gettext("During rotate, couldn't open log file %s: %s\n"),
346 old_name
, error_message(errno
));
350 (void) rename(new_name
, old_name
);
358 * klog_com_err_proc() - Handle com_err(3) messages as specified by the
361 static krb5_context err_context
;
363 klog_com_err_proc(const char *whoami
, long code
, const char *format
, va_list ap
)
365 char outbuf
[KRB5_KLOG_MAX_ERRMSG_SIZE
];
367 const char *actual_format
;
370 #endif /* HAVE_SYSLOG */
374 /* Make the header */
375 sprintf(outbuf
, "%s: ", whoami
);
377 * Squirrel away address after header for syslog since syslog makes
380 syslogp
= &outbuf
[strlen(outbuf
)];
382 /* If reporting an error message, separate it. */
384 /* Solaris Kerberos */
386 outbuf
[sizeof(outbuf
) - 1] = '\0';
388 emsg
= krb5_get_error_message (err_context
, code
);
389 strncat(outbuf
, emsg
, sizeof(outbuf
) - 1 - strlen(outbuf
));
390 strncat(outbuf
, " - ", sizeof(outbuf
) - 1 - strlen(outbuf
));
391 krb5_free_error_message(err_context
, emsg
);
393 cp
= &outbuf
[strlen(outbuf
)];
395 actual_format
= format
;
398 * This is an unpleasant hack. If the first character is less than
399 * 8, then we assume that it is a priority.
401 * Since it is not guaranteed that there is a direct mapping between
402 * syslog priorities (e.g. Ultrix and old BSD), we resort to this
403 * intermediate representation.
405 if ((((unsigned char) *format
) > 0) && (((unsigned char) *format
) <= 8)) {
406 actual_format
= (format
+ 1);
407 switch ((unsigned char) *format
) {
412 #endif /* LOG_EMERG */
417 #endif /* LOG_ALERT */
422 #endif /* LOG_CRIT */
429 log_pri
= LOG_WARNING
;
431 #endif /* LOG_WARNING */
434 log_pri
= LOG_NOTICE
;
436 #endif /* LOG_NOTICE */
441 #endif /* LOG_INFO */
446 #endif /* LOG_DEBUG */
449 #endif /* HAVE_SYSLOG */
451 /* Now format the actual message */
453 vsnprintf(cp
, sizeof(outbuf
) - (cp
- outbuf
), actual_format
, ap
);
455 vsprintf(cp
, actual_format
, ap
);
456 #else /* HAVE_VSPRINTF */
457 sprintf(cp
, actual_format
, ((int *) ap
)[0], ((int *) ap
)[1],
458 ((int *) ap
)[2], ((int *) ap
)[3],
459 ((int *) ap
)[4], ((int *) ap
)[5]);
460 #endif /* HAVE_VSPRINTF */
463 * Now that we have the message formatted, perform the output to each
464 * logging specification.
466 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
467 switch (log_control
.log_entries
[lindex
].log_type
) {
470 klog_rotate(&log_control
.log_entries
[lindex
]);
474 * Files/standard error.
476 if (fprintf(log_control
.log_entries
[lindex
].lfu_filep
, "%s\n",
478 /* Attempt to report error */
479 fprintf(stderr
, krb5_log_error_table(LOG_FILE_ERR
), whoami
,
480 log_control
.log_entries
[lindex
].lfu_fname
);
483 fflush(log_control
.log_entries
[lindex
].lfu_filep
);
489 * Devices (may need special handling)
491 if (DEVICE_PRINT(log_control
.log_entries
[lindex
].ldu_filep
,
493 /* Attempt to report error */
494 fprintf(stderr
, krb5_log_error_table(LOG_DEVICE_ERR
), whoami
,
495 log_control
.log_entries
[lindex
].ldu_devname
);
504 * If we have specified a priority through our hackery, then
505 * use it, otherwise use the default.
508 log_pri
|= log_control
.log_entries
[lindex
].lsu_facility
;
510 log_pri
= log_control
.log_entries
[lindex
].lsu_facility
|
511 log_control
.log_entries
[lindex
].lsu_severity
;
513 /* Log the message with our header trimmed off */
514 syslog(log_pri
, "%s", syslogp
);
516 #endif /* HAVE_SYSLOG */
524 * krb5_klog_init() - Initialize logging.
526 * This routine parses the syntax described above to specify destinations for
527 * com_err(3) or krb5_klog_syslog() messages generated by the caller.
530 * kcontext - Kerberos context.
531 * ename - Entity name as it is to appear in the profile.
532 * whoami - Entity name as it is to appear in error output.
533 * do_com_err - Take over com_err(3) processing.
536 * stderr - This is where STDERR output goes.
539 * log_nentries - Number of log entries, both valid and invalid.
540 * log_control - List of entries (log_nentries long) which contains
541 * data for klog_com_err_proc() to use to determine
542 * where/how to send output.
545 krb5_klog_init(krb5_context kcontext
, char *ename
, char *whoami
, krb5_boolean do_com_err
)
547 const char *logging_profent
[3];
548 const char *logging_defent
[3];
549 char **logging_specs
;
554 int do_openlog
, log_facility
;
562 err_context
= kcontext
;
565 * Look up [logging]-><ename> in the profile. If that doesn't
566 * succeed, then look for [logging]->default.
568 logging_profent
[0] = "logging";
569 logging_profent
[1] = ename
;
570 logging_profent
[2] = (char *) NULL
;
571 logging_defent
[0] = "logging";
572 logging_defent
[1] = "default";
573 logging_defent
[2] = (char *) NULL
;
574 logging_specs
= (char **) NULL
;
576 log_control
.log_nentries
= 0;
577 if (!profile_get_values(kcontext
->profile
,
580 !profile_get_values(kcontext
->profile
,
584 * We have a match, so we first count the number of elements
586 for (log_control
.log_nentries
= 0;
587 logging_specs
[log_control
.log_nentries
];
588 log_control
.log_nentries
++);
591 * Now allocate our structure.
593 log_control
.log_entries
= (struct log_entry
*)
594 malloc(log_control
.log_nentries
* sizeof(struct log_entry
));
595 if (log_control
.log_entries
) {
597 * Scan through the list.
599 for (i
=0; i
<log_control
.log_nentries
; i
++) {
600 log_control
.log_entries
[i
].log_type
= K_LOG_NONE
;
601 log_control
.log_entries
[i
].log_2free
= logging_specs
[i
];
604 * <whitespace><data><whitespace>
605 * so, trim off the leading and trailing whitespace here.
607 for (cp
= logging_specs
[i
]; isspace((int) *cp
); cp
++);
608 for (cp2
= &logging_specs
[i
][strlen(logging_specs
[i
])-1];
609 isspace((int) *cp2
); cp2
--);
615 if (!strncasecmp(cp
, "FILE", 4)) {
617 * Check for append/overwrite, then open the file.
619 if (cp
[4] == ':' || cp
[4] == '=') {
620 log_control
.log_entries
[i
].lfu_fopen_mode
=
621 (cp
[4] == ':') ? "a+F" : "wF";
622 old_umask
= umask(077);
624 log_control
.log_entries
[i
].lfu_fopen_mode
);
629 log_control
.log_entries
[i
].lfu_filep
= f
;
630 log_control
.log_entries
[i
].log_type
= K_LOG_FILE
;
631 log_control
.log_entries
[i
].lfu_fname
= &cp
[5];
632 log_control
.log_entries
[i
].lfu_rotate_period
=
633 K_LOG_DEF_FILE_ROTATE_PERIOD
;
634 log_control
.log_entries
[i
].lfu_rotate_versions
=
635 K_LOG_DEF_FILE_ROTATE_VERSIONS
;
636 log_control
.log_entries
[i
].lfu_last_rotated
=
640 * Now parse for ename_"rotate" = {
645 if (strlen(ename
) + strlen("_rotate") <
646 sizeof (rotate_kw
)) {
652 strcpy(rotate_kw
, ename
);
653 strcat(rotate_kw
, "_rotate");
655 if (!profile_get_string(kcontext
->profile
,
656 "logging", rotate_kw
, "period",
660 if (!krb5_string_to_deltat(time
,
662 log_control
.log_entries
[i
].lfu_rotate_period
=
669 if (!profile_get_integer(
670 kcontext
->profile
, "logging",
671 rotate_kw
, "versions",
672 K_LOG_DEF_FILE_ROTATE_VERSIONS
,
674 log_control
.log_entries
[i
].lfu_rotate_versions
= vers
;
679 fprintf(stderr
, gettext("Couldn't open log file %s: %s\n"),
680 &cp
[5], error_message(errno
));
689 else if (!strncasecmp(cp
, "SYSLOG", 6)) {
691 log_control
.log_entries
[i
].lsu_facility
= LOG_AUTH
;
692 log_control
.log_entries
[i
].lsu_severity
= LOG_ERR
;
694 * Is there a severify specified?
698 * Find the end of the severity.
700 cp2
= strchr(&cp
[7], ':');
710 if (!strcasecmp(&cp
[7], "ERR")) {
711 log_control
.log_entries
[i
].lsu_severity
= LOG_ERR
;
714 else if (!strcasecmp(&cp
[7], "EMERG")) {
715 log_control
.log_entries
[i
].lsu_severity
=
718 #endif /* LOG_EMERG */
720 else if (!strcasecmp(&cp
[7], "ALERT")) {
721 log_control
.log_entries
[i
].lsu_severity
=
724 #endif /* LOG_ALERT */
726 else if (!strcasecmp(&cp
[7], "CRIT")) {
727 log_control
.log_entries
[i
].lsu_severity
= LOG_CRIT
;
729 #endif /* LOG_CRIT */
731 else if (!strcasecmp(&cp
[7], "WARNING")) {
732 log_control
.log_entries
[i
].lsu_severity
=
735 #endif /* LOG_WARNING */
737 else if (!strcasecmp(&cp
[7], "NOTICE")) {
738 log_control
.log_entries
[i
].lsu_severity
=
741 #endif /* LOG_NOTICE */
743 else if (!strcasecmp(&cp
[7], "INFO")) {
744 log_control
.log_entries
[i
].lsu_severity
= LOG_INFO
;
746 #endif /* LOG_INFO */
748 else if (!strcasecmp(&cp
[7], "DEBUG")) {
749 log_control
.log_entries
[i
].lsu_severity
=
752 #endif /* LOG_DEBUG */
757 * If there is a facility present, then parse that.
760 if (!strcasecmp(cp2
, "AUTH")) {
761 log_control
.log_entries
[i
].lsu_facility
= LOG_AUTH
;
763 else if (!strcasecmp(cp2
, "KERN")) {
764 log_control
.log_entries
[i
].lsu_facility
= LOG_KERN
;
766 else if (!strcasecmp(cp2
, "USER")) {
767 log_control
.log_entries
[i
].lsu_facility
= LOG_USER
;
769 else if (!strcasecmp(cp2
, "MAIL")) {
770 log_control
.log_entries
[i
].lsu_facility
= LOG_MAIL
;
772 else if (!strcasecmp(cp2
, "DAEMON")) {
773 log_control
.log_entries
[i
].lsu_facility
= LOG_DAEMON
;
775 else if (!strcasecmp(cp2
, "LPR")) {
776 log_control
.log_entries
[i
].lsu_facility
= LOG_LPR
;
778 else if (!strcasecmp(cp2
, "NEWS")) {
779 log_control
.log_entries
[i
].lsu_facility
= LOG_NEWS
;
781 else if (!strcasecmp(cp2
, "UUCP")) {
782 log_control
.log_entries
[i
].lsu_facility
= LOG_UUCP
;
784 else if (!strcasecmp(cp2
, "CRON")) {
785 log_control
.log_entries
[i
].lsu_facility
= LOG_CRON
;
787 else if (!strcasecmp(cp2
, "LOCAL0")) {
788 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL0
;
790 else if (!strcasecmp(cp2
, "LOCAL1")) {
791 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL1
;
793 else if (!strcasecmp(cp2
, "LOCAL2")) {
794 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL2
;
796 else if (!strcasecmp(cp2
, "LOCAL3")) {
797 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL3
;
799 else if (!strcasecmp(cp2
, "LOCAL4")) {
800 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL4
;
802 else if (!strcasecmp(cp2
, "LOCAL5")) {
803 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL5
;
805 else if (!strcasecmp(cp2
, "LOCAL6")) {
806 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL6
;
808 else if (!strcasecmp(cp2
, "LOCAL7")) {
809 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL7
;
816 log_control
.log_entries
[i
].log_type
= K_LOG_SYSLOG
;
818 log_facility
= log_control
.log_entries
[i
].lsu_facility
;
821 #endif /* HAVE_SYSLOG */
823 * Is this a standard error specification?
825 else if (!strcasecmp(cp
, "STDERR")) {
826 log_control
.log_entries
[i
].lfu_filep
=
827 fdopen(fileno(stderr
), "a+F");
828 if (log_control
.log_entries
[i
].lfu_filep
) {
829 log_control
.log_entries
[i
].log_type
= K_LOG_STDERR
;
830 log_control
.log_entries
[i
].lfu_fname
=
835 * Is this a specification of the console?
837 else if (!strcasecmp(cp
, "CONSOLE")) {
838 log_control
.log_entries
[i
].ldu_filep
=
840 if (log_control
.log_entries
[i
].ldu_filep
) {
841 log_control
.log_entries
[i
].log_type
= K_LOG_CONSOLE
;
842 log_control
.log_entries
[i
].ldu_devname
= "console";
846 * Is this a specification of a device?
848 else if (!strncasecmp(cp
, "DEVICE", 6)) {
850 * We handle devices very similarly to files.
853 log_control
.log_entries
[i
].ldu_filep
=
854 DEVICE_OPEN(&cp
[7], "wF");
855 if (log_control
.log_entries
[i
].ldu_filep
) {
856 log_control
.log_entries
[i
].log_type
= K_LOG_DEVICE
;
857 log_control
.log_entries
[i
].ldu_devname
= &cp
[7];
862 * See if we successfully parsed this specification.
864 if (log_control
.log_entries
[i
].log_type
== K_LOG_NONE
) {
865 fprintf(stderr
, krb5_log_error_table(LSPEC_PARSE_ERR_1
), whoami
, cp
);
866 fprintf(stderr
, krb5_log_error_table(LSPEC_PARSE_ERR_2
), whoami
);
873 * If we didn't find anything, then free our lists.
876 for (i
=0; i
<log_control
.log_nentries
; i
++)
877 free(logging_specs
[i
]);
882 * If we didn't find anything, go for the default which is to log to
886 free(log_control
.log_entries
);
887 log_control
.log_entries
= &def_log_entry
;
888 log_control
.log_entries
->log_type
= K_LOG_SYSLOG
;
889 log_control
.log_entries
->log_2free
= (krb5_pointer
) NULL
;
890 log_facility
= log_control
.log_entries
->lsu_facility
= LOG_AUTH
;
891 log_control
.log_entries
->lsu_severity
= LOG_ERR
;
893 log_control
.log_nentries
= 1;
895 if (log_control
.log_nentries
) {
896 log_control
.log_whoami
= (char *) malloc(strlen(whoami
)+1);
897 if (log_control
.log_whoami
)
898 strcpy(log_control
.log_whoami
, whoami
);
900 log_control
.log_hostname
= (char *) malloc(MAXHOSTNAMELEN
+ 1);
901 if (log_control
.log_hostname
) {
902 gethostname(log_control
.log_hostname
, MAXHOSTNAMELEN
);
903 log_control
.log_hostname
[MAXHOSTNAMELEN
] = '\0';
907 openlog(whoami
, LOG_NDELAY
|LOG_PID
, log_facility
);
908 log_control
.log_opened
= 1;
910 #endif /* HAVE_OPENLOG */
912 (void) set_com_err_hook(klog_com_err_proc
);
914 return((log_control
.log_nentries
) ? 0 : ENOENT
);
918 * krb5_klog_close() - Close the logging context and free all data.
921 krb5_klog_close(krb5_context kcontext
)
924 (void) reset_com_err_hook();
925 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
926 switch (log_control
.log_entries
[lindex
].log_type
) {
930 * Files/standard error.
932 fclose(log_control
.log_entries
[lindex
].lfu_filep
);
937 * Devices (may need special handling)
939 DEVICE_CLOSE(log_control
.log_entries
[lindex
].ldu_filep
);
947 #endif /* HAVE_SYSLOG */
951 free(log_control
.log_entries
[lindex
].log_2free
);
953 if (log_control
.log_entries
!= &def_log_entry
)
954 free(log_control
.log_entries
);
955 log_control
.log_entries
= NULL
;
956 log_control
.log_nentries
= 0;
957 free(log_control
.log_whoami
);
958 log_control
.log_whoami
= (char *) NULL
;
959 free(log_control
.log_hostname
);
960 log_control
.log_hostname
= (char *) NULL
;
962 if (log_control
.log_opened
)
964 #endif /* HAVE_CLOSELOG */
968 * severity2string() - Convert a severity to a string.
971 severity2string(int severity
)
976 s
= severity
& LOG_PRIMASK
;
977 ss
= krb5_log_error_table(LOG_UFO_STRING
);
981 ss
= krb5_log_error_table(LOG_EMERG_STRING
);
983 #endif /* LOG_EMERG */
986 ss
= krb5_log_error_table(LOG_ALERT_STRING
);
988 #endif /* LOG_ALERT */
991 ss
= krb5_log_error_table(LOG_CRIT_STRING
);
993 #endif /* LOG_CRIT */
995 ss
= krb5_log_error_table(LOG_ERR_STRING
);
999 ss
= krb5_log_error_table(LOG_WARNING_STRING
);
1001 #endif /* LOG_WARNING */
1004 ss
= krb5_log_error_table(LOG_NOTICE_STRING
);
1006 #endif /* LOG_NOTICE */
1009 ss
= krb5_log_error_table(LOG_INFO_STRING
);
1011 #endif /* LOG_INFO */
1014 ss
= krb5_log_error_table(LOG_DEBUG_STRING
);
1016 #endif /* LOG_DEBUG */
1018 return((char *) ss
);
1022 * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while
1023 * also performing the logging redirection as specified
1024 * by krb5_klog_init().
1027 klog_vsyslog(int priority
, const char *format
, va_list arglist
)
1029 char outbuf
[KRB5_KLOG_MAX_ERRMSG_SIZE
];
1034 #ifdef HAVE_STRFTIME
1036 #endif /* HAVE_STRFTIME */
1039 * Format a syslog-esque message of the format:
1042 * <date> <hostname> <id>[<pid>](<priority>): <message>
1049 #ifdef HAVE_STRFTIME
1051 * Format the date: mon dd hh:mm:ss
1053 soff
= strftime(outbuf
, sizeof(outbuf
), "%b %d %H:%M:%S", localtime(&now
));
1058 #else /* HAVE_STRFTIME */
1061 * We ASSUME here that the output of ctime is of the format:
1062 * dow mon dd hh:mm:ss tzs yyyy\n
1063 * 012345678901234567890123456789
1065 strncpy(outbuf
, ctime(&now
) + 4, 15);
1067 #endif /* HAVE_STRFTIME */
1069 sprintf(cp
, " %s %s[%ld](%s): ",
1070 log_control
.log_hostname
, log_control
.log_whoami
, (long) getpid(),
1071 severity2string(priority
));
1075 syslogp
= &outbuf
[strlen(outbuf
)];
1077 /* Now format the actual message */
1078 #ifdef HAVE_VSNPRINTF
1079 vsnprintf(syslogp
, sizeof(outbuf
) - (syslogp
- outbuf
), format
, arglist
);
1081 vsprintf(syslogp
, format
, arglist
);
1082 #else /* HAVE_VSPRINTF */
1083 sprintf(syslogp
, format
, ((int *) arglist
)[0], ((int *) arglist
)[1],
1084 ((int *) arglist
)[2], ((int *) arglist
)[3],
1085 ((int *) arglist
)[4], ((int *) arglist
)[5]);
1086 #endif /* HAVE_VSPRINTF */
1089 * If the user did not use krb5_klog_init() instead of dropping
1090 * the request on the floor, syslog it - if it exists
1093 if (log_control
.log_nentries
== 0) {
1094 /* Log the message with our header trimmed off */
1095 syslog(priority
, "%s", syslogp
);
1100 * Now that we have the message formatted, perform the output to each
1101 * logging specification.
1103 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
1104 switch (log_control
.log_entries
[lindex
].log_type
) {
1107 klog_rotate(&log_control
.log_entries
[lindex
]);
1111 * Files/standard error.
1113 if (fprintf(log_control
.log_entries
[lindex
].lfu_filep
, "%s\n",
1115 /* Attempt to report error */
1116 fprintf(stderr
, krb5_log_error_table(LOG_FILE_ERR
),
1117 log_control
.log_whoami
,
1118 log_control
.log_entries
[lindex
].lfu_fname
);
1121 fflush(log_control
.log_entries
[lindex
].lfu_filep
);
1127 * Devices (may need special handling)
1129 if (DEVICE_PRINT(log_control
.log_entries
[lindex
].ldu_filep
,
1131 /* Attempt to report error */
1132 fprintf(stderr
, krb5_log_error_table(LOG_DEVICE_ERR
),
1133 log_control
.log_whoami
,
1134 log_control
.log_entries
[lindex
].ldu_devname
);
1143 /* Log the message with our header trimmed off */
1144 syslog(priority
, "%s", syslogp
);
1146 #endif /* HAVE_SYSLOG */
1155 krb5_klog_syslog(int priority
, const char *format
, ...)
1160 va_start(pvar
, format
);
1161 retval
= klog_vsyslog(priority
, format
, pvar
);
1167 * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files.
1168 * This function is called when a SIGHUP is received
1169 * so that external log-archival utilities may
1170 * alert the Kerberos daemons that they should get
1171 * a new file descriptor for the give filename.
1174 krb5_klog_reopen(krb5_context kcontext
)
1180 * Only logs which are actually files need to be closed
1181 * and reopened in response to a SIGHUP
1183 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
1184 if (log_control
.log_entries
[lindex
].log_type
== K_LOG_FILE
) {
1185 fclose(log_control
.log_entries
[lindex
].lfu_filep
);
1187 * In case the old logfile did not get moved out of the
1188 * way, open for append to prevent squashing the old logs.
1190 f
= fopen(log_control
.log_entries
[lindex
].lfu_fname
, "a+F");
1192 log_control
.log_entries
[lindex
].lfu_filep
= f
;
1194 fprintf(stderr
, "Couldn't open log file %s: %s\n",
1195 log_control
.log_entries
[lindex
].lfu_fname
,
1196 error_message(errno
));
1204 * Switch the current context to the one supplied
1206 void krb5_klog_set_context(krb5_context context
) {
1207 err_context
= context
;
1212 * Return a string representation of "facility"
1214 static const char * facility2string(int facility
) {
1254 * Print to stderr where logging is being done
1256 krb5_error_code
krb5_klog_list_logs(const char *whoami
) {
1259 fprintf(stderr
, gettext("%s: logging to "), whoami
);
1260 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
1261 if (lindex
!= 0 && log_control
.log_entries
[lindex
].log_type
!= K_LOG_NONE
)
1262 fprintf(stderr
, ", ");
1263 switch (log_control
.log_entries
[lindex
].log_type
) {
1265 fprintf(stderr
, "FILE=%s", log_control
.log_entries
[lindex
].lfu_fname
);
1268 fprintf(stderr
, "STDERR");
1271 fprintf(stderr
, "CONSOLE");
1274 fprintf(stderr
, "DEVICE=%s", log_control
.log_entries
[lindex
].ldu_devname
);
1277 fprintf(stderr
, "SYSLOG=%s:%s",
1278 severity2string(log_control
.log_entries
[lindex
].lsu_severity
),
1279 facility2string(log_control
.log_entries
[lindex
].lsu_facility
));
1283 default: /* Should never get here */
1287 fprintf(stderr
, "\n");
1293 * Add logging to stderr.
1295 krb5_error_code
krb5_klog_add_stderr() {
1297 struct log_entry
*tmp_log_entries
= log_control
.log_entries
;
1300 if (log_control
.log_entries
!= &def_log_entry
) {
1301 log_control
.log_entries
= reallocarray(log_control
.log_entries
,
1302 (log_control
.log_nentries
+ 1),
1303 sizeof(struct log_entry
));
1304 if (log_control
.log_entries
== NULL
) {
1305 log_control
.log_entries
= tmp_log_entries
;
1309 log_control
.log_entries
= malloc(2 * sizeof(struct log_entry
));
1310 if (log_control
.log_entries
== NULL
) {
1311 log_control
.log_entries
= &def_log_entry
;
1314 (void) memcpy(&log_control
.log_entries
[0], &def_log_entry
,
1315 sizeof(struct log_entry
));
1318 i
= log_control
.log_nentries
;
1319 if (log_control
.log_entries
[i
].lfu_filep
=
1320 fdopen(fileno(stderr
), "a+F")) {
1321 log_control
.log_entries
[i
].log_type
= K_LOG_STDERR
;
1322 log_control
.log_entries
[i
].log_2free
= NULL
;
1323 log_control
.log_entries
[i
].lfu_fname
= "standard error";
1324 log_control
.log_nentries
++;
1326 /* Free the alloc'ed extra entry */
1328 tmp_log_entries
= log_control
.log_entries
;
1329 log_control
.log_entries
= reallocarray(log_control
.log_entries
,
1330 (log_control
.log_nentries
),
1331 sizeof(struct log_entry
));
1332 if (log_control
.log_entries
== NULL
)
1333 log_control
.log_entries
= tmp_log_entries
;
1342 * Remove logging to stderr.
1344 void krb5_klog_remove_stderr() {
1346 struct log_entry
*tmp_log_entries
= log_control
.log_entries
;
1349 /* Find the entry (if it exists) */
1350 for (i
= 0; i
< log_control
.log_nentries
; i
++) {
1351 if (log_control
.log_entries
[i
].log_type
== K_LOG_STDERR
) {
1356 if ( i
< log_control
.log_nentries
) {
1357 for (; i
< log_control
.log_nentries
- 1; i
++)
1358 log_control
.log_entries
[i
] =
1359 log_control
.log_entries
[i
+ 1];
1361 if (log_control
.log_nentries
> 1) {
1362 log_control
.log_entries
=
1363 reallocarray(log_control
.log_entries
,
1364 (log_control
.log_nentries
+ 1),
1365 sizeof(struct log_entry
));
1366 if (log_control
.log_entries
!= NULL
)
1367 log_control
.log_nentries
--;
1369 log_control
.log_entries
= tmp_log_entries
;
1371 free(log_control
.log_entries
);
1376 /* Solaris Kerberos: Indicate if currently logging to stderr */
1377 krb5_boolean
krb5_klog_logging_to_stderr() {
1380 /* Find the entry (if it exists) */
1381 for (i
= 0; i
< log_control
.log_nentries
; i
++) {
1382 if (log_control
.log_entries
[i
].log_type
== K_LOG_STDERR
) {