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"));
105 return(gettext("???"));
106 case LOG_EMERG_STRING
:
107 return(gettext("EMERGENCY"));
108 case LOG_ALERT_STRING
:
109 return(gettext("ALERT"));
110 case LOG_CRIT_STRING
:
111 return(gettext("CRITICAL"));
113 return(gettext("Error"));
114 case LOG_WARNING_STRING
:
115 return(gettext("Warning"));
116 case LOG_NOTICE_STRING
:
117 return(gettext("Notice"));
118 case LOG_INFO_STRING
:
119 case LOG_DEBUG_STRING
:
121 return(gettext("info"));
128 * Output logging is now controlled by the configuration file. We can specify
129 * the following syntaxes under the [logging]->entity specification.
130 * FILE<opentype><pathname>
131 * SYSLOG[=<severity>[:<facility>]]
134 * DEVICE=<device-spec>
137 * <opentype> is ":" for open/append, "=" for open/create.
138 * <pathname> is a valid path name.
139 * <severity> is one of: (default = ERR)
148 * <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. */
385 outbuf
[sizeof(outbuf
) - 1] = '\0';
387 emsg
= krb5_get_error_message (err_context
, code
);
388 strncat(outbuf
, emsg
, sizeof(outbuf
) - 1 - strlen(outbuf
));
389 strncat(outbuf
, " - ", sizeof(outbuf
) - 1 - strlen(outbuf
));
390 krb5_free_error_message(err_context
, emsg
);
392 cp
= &outbuf
[strlen(outbuf
)];
394 actual_format
= format
;
397 * This is an unpleasant hack. If the first character is less than
398 * 8, then we assume that it is a priority.
400 * Since it is not guaranteed that there is a direct mapping between
401 * syslog priorities (e.g. Ultrix and old BSD), we resort to this
402 * intermediate representation.
404 if ((((unsigned char) *format
) > 0) && (((unsigned char) *format
) <= 8)) {
405 actual_format
= (format
+ 1);
406 switch ((unsigned char) *format
) {
411 #endif /* LOG_EMERG */
416 #endif /* LOG_ALERT */
421 #endif /* LOG_CRIT */
428 log_pri
= LOG_WARNING
;
430 #endif /* LOG_WARNING */
433 log_pri
= LOG_NOTICE
;
435 #endif /* LOG_NOTICE */
440 #endif /* LOG_INFO */
445 #endif /* LOG_DEBUG */
448 #endif /* HAVE_SYSLOG */
450 /* Now format the actual message */
452 vsnprintf(cp
, sizeof(outbuf
) - (cp
- outbuf
), actual_format
, ap
);
454 vsprintf(cp
, actual_format
, ap
);
455 #else /* HAVE_VSPRINTF */
456 sprintf(cp
, actual_format
, ((int *) ap
)[0], ((int *) ap
)[1],
457 ((int *) ap
)[2], ((int *) ap
)[3],
458 ((int *) ap
)[4], ((int *) ap
)[5]);
459 #endif /* HAVE_VSPRINTF */
462 * Now that we have the message formatted, perform the output to each
463 * logging specification.
465 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
466 switch (log_control
.log_entries
[lindex
].log_type
) {
469 klog_rotate(&log_control
.log_entries
[lindex
]);
473 * Files/standard error.
475 if (fprintf(log_control
.log_entries
[lindex
].lfu_filep
, "%s\n",
477 /* Attempt to report error */
478 fprintf(stderr
, krb5_log_error_table(LOG_FILE_ERR
), whoami
,
479 log_control
.log_entries
[lindex
].lfu_fname
);
482 fflush(log_control
.log_entries
[lindex
].lfu_filep
);
488 * Devices (may need special handling)
490 if (DEVICE_PRINT(log_control
.log_entries
[lindex
].ldu_filep
,
492 /* Attempt to report error */
493 fprintf(stderr
, krb5_log_error_table(LOG_DEVICE_ERR
), whoami
,
494 log_control
.log_entries
[lindex
].ldu_devname
);
503 * If we have specified a priority through our hackery, then
504 * use it, otherwise use the default.
507 log_pri
|= log_control
.log_entries
[lindex
].lsu_facility
;
509 log_pri
= log_control
.log_entries
[lindex
].lsu_facility
|
510 log_control
.log_entries
[lindex
].lsu_severity
;
512 /* Log the message with our header trimmed off */
513 syslog(log_pri
, syslogp
);
515 #endif /* HAVE_SYSLOG */
523 * krb5_klog_init() - Initialize logging.
525 * This routine parses the syntax described above to specify destinations for
526 * com_err(3) or krb5_klog_syslog() messages generated by the caller.
529 * kcontext - Kerberos context.
530 * ename - Entity name as it is to appear in the profile.
531 * whoami - Entity name as it is to appear in error output.
532 * do_com_err - Take over com_err(3) processing.
535 * stderr - This is where STDERR output goes.
538 * log_nentries - Number of log entries, both valid and invalid.
539 * log_control - List of entries (log_nentries long) which contains
540 * data for klog_com_err_proc() to use to determine
541 * where/how to send output.
544 krb5_klog_init(krb5_context kcontext
, char *ename
, char *whoami
, krb5_boolean do_com_err
)
546 const char *logging_profent
[3];
547 const char *logging_defent
[3];
548 char **logging_specs
;
553 int do_openlog
, log_facility
;
561 err_context
= kcontext
;
564 * Look up [logging]-><ename> in the profile. If that doesn't
565 * succeed, then look for [logging]->default.
567 logging_profent
[0] = "logging";
568 logging_profent
[1] = ename
;
569 logging_profent
[2] = (char *) NULL
;
570 logging_defent
[0] = "logging";
571 logging_defent
[1] = "default";
572 logging_defent
[2] = (char *) NULL
;
573 logging_specs
= (char **) NULL
;
575 log_control
.log_nentries
= 0;
576 if (!profile_get_values(kcontext
->profile
,
579 !profile_get_values(kcontext
->profile
,
583 * We have a match, so we first count the number of elements
585 for (log_control
.log_nentries
= 0;
586 logging_specs
[log_control
.log_nentries
];
587 log_control
.log_nentries
++);
590 * Now allocate our structure.
592 log_control
.log_entries
= (struct log_entry
*)
593 malloc(log_control
.log_nentries
* sizeof(struct log_entry
));
594 if (log_control
.log_entries
) {
596 * Scan through the list.
598 for (i
=0; i
<log_control
.log_nentries
; i
++) {
599 log_control
.log_entries
[i
].log_type
= K_LOG_NONE
;
600 log_control
.log_entries
[i
].log_2free
= logging_specs
[i
];
603 * <whitespace><data><whitespace>
604 * so, trim off the leading and trailing whitespace here.
606 for (cp
= logging_specs
[i
]; isspace((int) *cp
); cp
++);
607 for (cp2
= &logging_specs
[i
][strlen(logging_specs
[i
])-1];
608 isspace((int) *cp2
); cp2
--);
614 if (!strncasecmp(cp
, "FILE", 4)) {
616 * Check for append/overwrite, then open the file.
618 if (cp
[4] == ':' || cp
[4] == '=') {
619 log_control
.log_entries
[i
].lfu_fopen_mode
=
620 (cp
[4] == ':') ? "a+F" : "wF";
621 old_umask
= umask(077);
623 log_control
.log_entries
[i
].lfu_fopen_mode
);
628 log_control
.log_entries
[i
].lfu_filep
= f
;
629 log_control
.log_entries
[i
].log_type
= K_LOG_FILE
;
630 log_control
.log_entries
[i
].lfu_fname
= &cp
[5];
631 log_control
.log_entries
[i
].lfu_rotate_period
=
632 K_LOG_DEF_FILE_ROTATE_PERIOD
;
633 log_control
.log_entries
[i
].lfu_rotate_versions
=
634 K_LOG_DEF_FILE_ROTATE_VERSIONS
;
635 log_control
.log_entries
[i
].lfu_last_rotated
=
639 * Now parse for ename_"rotate" = {
644 if (strlen(ename
) + strlen("_rotate") <
645 sizeof (rotate_kw
)) {
651 strcpy(rotate_kw
, ename
);
652 strcat(rotate_kw
, "_rotate");
654 if (!profile_get_string(kcontext
->profile
,
655 "logging", rotate_kw
, "period",
659 if (!krb5_string_to_deltat(time
,
661 log_control
.log_entries
[i
].lfu_rotate_period
=
668 if (!profile_get_integer(
669 kcontext
->profile
, "logging",
670 rotate_kw
, "versions",
671 K_LOG_DEF_FILE_ROTATE_VERSIONS
,
673 log_control
.log_entries
[i
].lfu_rotate_versions
= vers
;
678 fprintf(stderr
, gettext("Couldn't open log file %s: %s\n"),
679 &cp
[5], error_message(errno
));
688 else if (!strncasecmp(cp
, "SYSLOG", 6)) {
690 log_control
.log_entries
[i
].lsu_facility
= LOG_AUTH
;
691 log_control
.log_entries
[i
].lsu_severity
= LOG_ERR
;
693 * Is there a severify specified?
697 * Find the end of the severity.
699 cp2
= strchr(&cp
[7], ':');
709 if (!strcasecmp(&cp
[7], "ERR")) {
710 log_control
.log_entries
[i
].lsu_severity
= LOG_ERR
;
713 else if (!strcasecmp(&cp
[7], "EMERG")) {
714 log_control
.log_entries
[i
].lsu_severity
=
717 #endif /* LOG_EMERG */
719 else if (!strcasecmp(&cp
[7], "ALERT")) {
720 log_control
.log_entries
[i
].lsu_severity
=
723 #endif /* LOG_ALERT */
725 else if (!strcasecmp(&cp
[7], "CRIT")) {
726 log_control
.log_entries
[i
].lsu_severity
= LOG_CRIT
;
728 #endif /* LOG_CRIT */
730 else if (!strcasecmp(&cp
[7], "WARNING")) {
731 log_control
.log_entries
[i
].lsu_severity
=
734 #endif /* LOG_WARNING */
736 else if (!strcasecmp(&cp
[7], "NOTICE")) {
737 log_control
.log_entries
[i
].lsu_severity
=
740 #endif /* LOG_NOTICE */
742 else if (!strcasecmp(&cp
[7], "INFO")) {
743 log_control
.log_entries
[i
].lsu_severity
= LOG_INFO
;
745 #endif /* LOG_INFO */
747 else if (!strcasecmp(&cp
[7], "DEBUG")) {
748 log_control
.log_entries
[i
].lsu_severity
=
751 #endif /* LOG_DEBUG */
756 * If there is a facility present, then parse that.
759 if (!strcasecmp(cp2
, "AUTH")) {
760 log_control
.log_entries
[i
].lsu_facility
= LOG_AUTH
;
762 else if (!strcasecmp(cp2
, "KERN")) {
763 log_control
.log_entries
[i
].lsu_facility
= LOG_KERN
;
765 else if (!strcasecmp(cp2
, "USER")) {
766 log_control
.log_entries
[i
].lsu_facility
= LOG_USER
;
768 else if (!strcasecmp(cp2
, "MAIL")) {
769 log_control
.log_entries
[i
].lsu_facility
= LOG_MAIL
;
771 else if (!strcasecmp(cp2
, "DAEMON")) {
772 log_control
.log_entries
[i
].lsu_facility
= LOG_DAEMON
;
774 else if (!strcasecmp(cp2
, "LPR")) {
775 log_control
.log_entries
[i
].lsu_facility
= LOG_LPR
;
777 else if (!strcasecmp(cp2
, "NEWS")) {
778 log_control
.log_entries
[i
].lsu_facility
= LOG_NEWS
;
780 else if (!strcasecmp(cp2
, "UUCP")) {
781 log_control
.log_entries
[i
].lsu_facility
= LOG_UUCP
;
783 else if (!strcasecmp(cp2
, "CRON")) {
784 log_control
.log_entries
[i
].lsu_facility
= LOG_CRON
;
786 else if (!strcasecmp(cp2
, "AUDIT")) {
787 log_control
.log_entries
[i
].lsu_facility
= LOG_AUDIT
;
789 else if (!strcasecmp(cp2
, "LOCAL0")) {
790 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL0
;
792 else if (!strcasecmp(cp2
, "LOCAL1")) {
793 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL1
;
795 else if (!strcasecmp(cp2
, "LOCAL2")) {
796 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL2
;
798 else if (!strcasecmp(cp2
, "LOCAL3")) {
799 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL3
;
801 else if (!strcasecmp(cp2
, "LOCAL4")) {
802 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL4
;
804 else if (!strcasecmp(cp2
, "LOCAL5")) {
805 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL5
;
807 else if (!strcasecmp(cp2
, "LOCAL6")) {
808 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL6
;
810 else if (!strcasecmp(cp2
, "LOCAL7")) {
811 log_control
.log_entries
[i
].lsu_facility
= LOG_LOCAL7
;
818 log_control
.log_entries
[i
].log_type
= K_LOG_SYSLOG
;
820 log_facility
= log_control
.log_entries
[i
].lsu_facility
;
823 #endif /* HAVE_SYSLOG */
825 * Is this a standard error specification?
827 else if (!strcasecmp(cp
, "STDERR")) {
828 log_control
.log_entries
[i
].lfu_filep
=
829 fdopen(fileno(stderr
), "a+F");
830 if (log_control
.log_entries
[i
].lfu_filep
) {
831 log_control
.log_entries
[i
].log_type
= K_LOG_STDERR
;
832 log_control
.log_entries
[i
].lfu_fname
=
837 * Is this a specification of the console?
839 else if (!strcasecmp(cp
, "CONSOLE")) {
840 log_control
.log_entries
[i
].ldu_filep
=
842 if (log_control
.log_entries
[i
].ldu_filep
) {
843 log_control
.log_entries
[i
].log_type
= K_LOG_CONSOLE
;
844 log_control
.log_entries
[i
].ldu_devname
= "console";
848 * Is this a specification of a device?
850 else if (!strncasecmp(cp
, "DEVICE", 6)) {
852 * We handle devices very similarly to files.
855 log_control
.log_entries
[i
].ldu_filep
=
856 DEVICE_OPEN(&cp
[7], "wF");
857 if (log_control
.log_entries
[i
].ldu_filep
) {
858 log_control
.log_entries
[i
].log_type
= K_LOG_DEVICE
;
859 log_control
.log_entries
[i
].ldu_devname
= &cp
[7];
864 * See if we successfully parsed this specification.
866 if (log_control
.log_entries
[i
].log_type
== K_LOG_NONE
) {
867 fprintf(stderr
, krb5_log_error_table(LSPEC_PARSE_ERR_1
), whoami
, cp
);
868 fprintf(stderr
, krb5_log_error_table(LSPEC_PARSE_ERR_2
), whoami
);
875 * If we didn't find anything, then free our lists.
878 for (i
=0; i
<log_control
.log_nentries
; i
++)
879 free(logging_specs
[i
]);
884 * If we didn't find anything, go for the default which is to log to
888 free(log_control
.log_entries
);
889 log_control
.log_entries
= &def_log_entry
;
890 log_control
.log_entries
->log_type
= K_LOG_SYSLOG
;
891 log_control
.log_entries
->log_2free
= (krb5_pointer
) NULL
;
892 log_facility
= log_control
.log_entries
->lsu_facility
= LOG_AUTH
;
893 log_control
.log_entries
->lsu_severity
= LOG_ERR
;
895 log_control
.log_nentries
= 1;
897 if (log_control
.log_nentries
) {
898 log_control
.log_whoami
= (char *) malloc(strlen(whoami
)+1);
899 if (log_control
.log_whoami
)
900 strcpy(log_control
.log_whoami
, whoami
);
902 log_control
.log_hostname
= (char *) malloc(MAXHOSTNAMELEN
+ 1);
903 if (log_control
.log_hostname
) {
904 gethostname(log_control
.log_hostname
, MAXHOSTNAMELEN
);
905 log_control
.log_hostname
[MAXHOSTNAMELEN
] = '\0';
909 openlog(whoami
, LOG_NDELAY
|LOG_PID
, log_facility
);
910 log_control
.log_opened
= 1;
912 #endif /* HAVE_OPENLOG */
914 (void) set_com_err_hook(klog_com_err_proc
);
916 return((log_control
.log_nentries
) ? 0 : ENOENT
);
920 * krb5_klog_close() - Close the logging context and free all data.
923 krb5_klog_close(krb5_context kcontext
)
926 (void) reset_com_err_hook();
927 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
928 switch (log_control
.log_entries
[lindex
].log_type
) {
932 * Files/standard error.
934 fclose(log_control
.log_entries
[lindex
].lfu_filep
);
939 * Devices (may need special handling)
941 DEVICE_CLOSE(log_control
.log_entries
[lindex
].ldu_filep
);
949 #endif /* HAVE_SYSLOG */
953 free(log_control
.log_entries
[lindex
].log_2free
);
955 if (log_control
.log_entries
!= &def_log_entry
)
956 free(log_control
.log_entries
);
957 log_control
.log_entries
= NULL
;
958 log_control
.log_nentries
= 0;
959 free(log_control
.log_whoami
);
960 log_control
.log_whoami
= (char *) NULL
;
961 free(log_control
.log_hostname
);
962 log_control
.log_hostname
= (char *) NULL
;
964 if (log_control
.log_opened
)
966 #endif /* HAVE_CLOSELOG */
970 * severity2string() - Convert a severity to a string.
973 severity2string(int severity
)
978 s
= severity
& LOG_PRIMASK
;
979 ss
= krb5_log_error_table(LOG_UFO_STRING
);
983 ss
= krb5_log_error_table(LOG_EMERG_STRING
);
985 #endif /* LOG_EMERG */
988 ss
= krb5_log_error_table(LOG_ALERT_STRING
);
990 #endif /* LOG_ALERT */
993 ss
= krb5_log_error_table(LOG_CRIT_STRING
);
995 #endif /* LOG_CRIT */
997 ss
= krb5_log_error_table(LOG_ERR_STRING
);
1001 ss
= krb5_log_error_table(LOG_WARNING_STRING
);
1003 #endif /* LOG_WARNING */
1006 ss
= krb5_log_error_table(LOG_NOTICE_STRING
);
1008 #endif /* LOG_NOTICE */
1011 ss
= krb5_log_error_table(LOG_INFO_STRING
);
1013 #endif /* LOG_INFO */
1016 ss
= krb5_log_error_table(LOG_DEBUG_STRING
);
1018 #endif /* LOG_DEBUG */
1020 return((char *) ss
);
1024 * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while
1025 * also performing the logging redirection as specified
1026 * by krb5_klog_init().
1029 klog_vsyslog(int priority
, const char *format
, va_list arglist
)
1031 char outbuf
[KRB5_KLOG_MAX_ERRMSG_SIZE
];
1036 #ifdef HAVE_STRFTIME
1038 #endif /* HAVE_STRFTIME */
1041 * Format a syslog-esque message of the format:
1044 * <date> <hostname> <id>[<pid>](<priority>): <message>
1051 #ifdef HAVE_STRFTIME
1053 * Format the date: mon dd hh:mm:ss
1055 soff
= strftime(outbuf
, sizeof(outbuf
), "%b %d %H:%M:%S", localtime(&now
));
1060 #else /* HAVE_STRFTIME */
1063 * We ASSUME here that the output of ctime is of the format:
1064 * dow mon dd hh:mm:ss tzs yyyy\n
1065 * 012345678901234567890123456789
1067 strncpy(outbuf
, ctime(&now
) + 4, 15);
1069 #endif /* HAVE_STRFTIME */
1071 sprintf(cp
, " %s %s[%ld](%s): ",
1072 log_control
.log_hostname
, log_control
.log_whoami
, (long) getpid(),
1073 severity2string(priority
));
1077 syslogp
= &outbuf
[strlen(outbuf
)];
1079 /* Now format the actual message */
1080 #ifdef HAVE_VSNPRINTF
1081 vsnprintf(syslogp
, sizeof(outbuf
) - (syslogp
- outbuf
), format
, arglist
);
1083 vsprintf(syslogp
, format
, arglist
);
1084 #else /* HAVE_VSPRINTF */
1085 sprintf(syslogp
, format
, ((int *) arglist
)[0], ((int *) arglist
)[1],
1086 ((int *) arglist
)[2], ((int *) arglist
)[3],
1087 ((int *) arglist
)[4], ((int *) arglist
)[5]);
1088 #endif /* HAVE_VSPRINTF */
1091 * If the user did not use krb5_klog_init() instead of dropping
1092 * the request on the floor, syslog it - if it exists
1095 if (log_control
.log_nentries
== 0) {
1096 /* Log the message with our header trimmed off */
1097 syslog(priority
, "%s", syslogp
);
1102 * Now that we have the message formatted, perform the output to each
1103 * logging specification.
1105 for (lindex
= 0; lindex
< log_control
.log_nentries
; lindex
++) {
1106 switch (log_control
.log_entries
[lindex
].log_type
) {
1109 klog_rotate(&log_control
.log_entries
[lindex
]);
1113 * Files/standard error.
1115 if (fprintf(log_control
.log_entries
[lindex
].lfu_filep
, "%s\n",
1117 /* Attempt to report error */
1118 fprintf(stderr
, krb5_log_error_table(LOG_FILE_ERR
),
1119 log_control
.log_whoami
,
1120 log_control
.log_entries
[lindex
].lfu_fname
);
1123 fflush(log_control
.log_entries
[lindex
].lfu_filep
);
1129 * Devices (may need special handling)
1131 if (DEVICE_PRINT(log_control
.log_entries
[lindex
].ldu_filep
,
1133 /* Attempt to report error */
1134 fprintf(stderr
, krb5_log_error_table(LOG_DEVICE_ERR
),
1135 log_control
.log_whoami
,
1136 log_control
.log_entries
[lindex
].ldu_devname
);
1145 /* Log the message with our header trimmed off */
1146 syslog(priority
, "%s", syslogp
);
1148 #endif /* HAVE_SYSLOG */
1157 krb5_klog_syslog(int priority
, const char *format
, ...)
1162 va_start(pvar
, format
);
1163 retval
= klog_vsyslog(priority
, format
, pvar
);