/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* Copyright 1995 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*/
/* KADM5 wants non-syslog log files to contain syslog-like entries */
#define VERBOSE_LOGS
/*
* logger.c - Handle logging functions for those who want it.
*/
#include "k5-int.h"
#include "adm_proto.h"
#include "com_err.h"
#include <stdio.h>
#include <ctype.h>
#include <ctype.h>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif /* HAVE_SYSLOG_H */
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#else /* HAVE_STDARG_H */
#include <varargs.h>
#endif /* HAVE_STDARG_H */
#include <libintl.h>
#ifndef MAXHOSTNAMELEN
#endif /* MAXHOSTNAMELEN */
/* This is to assure that we have at least one match in the syslog stuff */
/*
static const char LSPEC_PARSE_ERR_1[] = "%s: cannot parse <%s>\n";
static const char LSPEC_PARSE_ERR_2[] = "%s: warning - logging entry syntax error\n";
static const char LOG_FILE_ERR[] = "%s: error writing to %s\n";
static const char LOG_DEVICE_ERR[] = "%s: error writing to %s device\n";
static const char LOG_UFO_STRING[] = "???";
static const char LOG_EMERG_STRING[] = "EMERGENCY";
static const char LOG_ALERT_STRING[] = "ALERT";
static const char LOG_CRIT_STRING[] = "CRITICAL";
static const char LOG_ERR_STRING[] = "Error";
static const char LOG_WARNING_STRING[] = "Warning";
static const char LOG_NOTICE_STRING[] = "Notice";
static const char LOG_INFO_STRING[] = "info";
static const char LOG_DEBUG_STRING[] = "debug";
*/
const char *
switch (errorno) {
case LSPEC_PARSE_ERR_1:
return(gettext("%s: cannot parse <%s>\n"));
case LSPEC_PARSE_ERR_2:
return(gettext("%s: warning - logging entry syntax error\n"));
case LOG_FILE_ERR:
return(gettext("%s: error writing to %s\n"));
case LOG_DEVICE_ERR:
return(gettext("%s: error writing to %s device\n"));
case LOG_UFO_STRING:
default:
return(gettext("???"));
case LOG_EMERG_STRING:
return(gettext("EMERGENCY"));
case LOG_ALERT_STRING:
return(gettext("ALERT"));
case LOG_CRIT_STRING:
return(gettext("CRITICAL"));
case LOG_ERR_STRING:
return(gettext("Error"));
case LOG_WARNING_STRING:
return(gettext("Warning"));
case LOG_NOTICE_STRING:
return(gettext("Notice"));
case LOG_INFO_STRING:
return(gettext("info"));
case LOG_DEBUG_STRING:
return(gettext("info"));
}
}
/*
* Output logging.
*
* Output logging is now controlled by the configuration file. We can specify
* the following syntaxes under the [logging]->entity specification.
* FILE<opentype><pathname>
* SYSLOG[=<severity>[:<facility>]]
* STDERR
* CONSOLE
* DEVICE=<device-spec>
*
* Where:
* <pathname> is a valid path name.
* <severity> is one of: (default = ERR)
* EMERG
* ALERT
* CRIT
* ERR
* WARNING
* NOTICE
* INFO
* DEBUG
* <facility> is one of: (default = AUTH)
* KERN
* USER
* MAIL
* DAEMON
* AUTH
* LPR
* NEWS
* UUCP
* CRON
* LOCAL0..LOCAL7
* <device-spec> is a valid device specification.
*/
struct log_entry {
union log_union {
struct log_file {
char *lf_fname;
int lf_rotate_versions;
} log_file;
struct log_syslog {
int ls_facility;
int ls_severity;
} log_syslog;
struct log_device {
char *ld_devname;
} log_device;
} log_union;
};
struct log_control {
int log_nentries;
char *log_whoami;
char *log_hostname;
};
0,
(char *) NULL,
(char *) NULL,
0
};
/*
* These macros define any special processing that needs to happen for
* devices. For unix, of course, this is hardly anything.
*/
(fflush(f), 0) : \
-1)
/*
* klog_rotate() - roate a log file if we have specified rotation
* parameters in krb5.conf.
*/
static void
{
time_t t;
int i;
char *name_buf1;
char *name_buf2;
char *old_name;
char *new_name;
char *tmp;
int num_vers;
/*
* By default we don't rotate.
*/
return;
t = time(0);
/*
* The N log file versions will be renamed X.N-1 X.N-2, ... X.0.
* So the allocate file name buffers that can the version
* number extensions.
* 32 extra bytes is plenty.
*/
return;
return;
}
/*
* If there N versions, then the first one has file extension
* of N-1.
*/
/*
* Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ...
* file.0 to file.1
*/
/*
* swap old name and new name. This way,
* on the next iteration, new_name.X
* becomes new_name.X-1.
*/
}
/*
* Even though we don't know yet if the fopen()
* of the log file will succeed, we mark the log
* as rotated. This is so we don't repeatably
* rotate file.N-2 to file.N-1 ... etc without
* waiting for the rotate period to elapse.
*/
le->lfu_last_rotated = t;
/*
* Default log file creation mode should be read-only
* by owner(root), but the admin can override with
* chmod(1) if desired.
*/
/*
* If the version parameter in krb5.conf was
* 0, then we take this to mean that rotating the
* log file will cause us to dispose of the
* old one, and created a new one. We have just
* renamed the old one to file.-1, so remove it.
*/
if (le->lfu_rotate_versions <= 0)
} else {
gettext("During rotate, couldn't open log file %s: %s\n"),
/*
* Put it back.
*/
}
}
}
/*
* klog_com_err_proc() - Handle com_err(3) messages as specified by the
* profile.
*/
static void
{
int lindex;
const char *actual_format;
#ifdef HAVE_SYSLOG
#endif /* HAVE_SYSLOG */
char *cp;
char *syslogp;
/* Make the header */
/*
* Squirrel away address after header for syslog since syslog makes
* a header
*/
/* If reporting an error message, separate it. */
if (code) {
/* Solaris Kerberos */
const char *emsg;
}
#ifdef HAVE_SYSLOG
/*
* This is an unpleasant hack. If the first character is less than
* 8, then we assume that it is a priority.
*
* Since it is not guaranteed that there is a direct mapping between
* syslog priorities (e.g. Ultrix and old BSD), we resort to this
* intermediate representation.
*/
switch ((unsigned char) *format) {
#ifdef LOG_EMERG
case 1:
break;
#endif /* LOG_EMERG */
#ifdef LOG_ALERT
case 2:
break;
#endif /* LOG_ALERT */
#ifdef LOG_CRIT
case 3:
break;
#endif /* LOG_CRIT */
default:
case 4:
break;
#ifdef LOG_WARNING
case 5:
break;
#endif /* LOG_WARNING */
#ifdef LOG_NOTICE
case 6:
break;
#endif /* LOG_NOTICE */
#ifdef LOG_INFO
case 7:
break;
#endif /* LOG_INFO */
#ifdef LOG_DEBUG
case 8:
break;
#endif /* LOG_DEBUG */
}
}
#endif /* HAVE_SYSLOG */
/* Now format the actual message */
#if HAVE_VSNPRINTF
#else /* HAVE_VSPRINTF */
#endif /* HAVE_VSPRINTF */
/*
* Now that we have the message formatted, perform the output to each
* logging specification.
*/
case K_LOG_FILE:
/*FALLTHRU*/
case K_LOG_STDERR:
/*
*/
outbuf) < 0) {
/* Attempt to report error */
}
else {
}
break;
case K_LOG_CONSOLE:
case K_LOG_DEVICE:
/*
* Devices (may need special handling)
*/
outbuf) < 0) {
/* Attempt to report error */
}
break;
#ifdef HAVE_SYSLOG
case K_LOG_SYSLOG:
/*
* System log.
*/
/*
* If we have specified a priority through our hackery, then
* use it, otherwise use the default.
*/
if (log_pri >= 0)
else
/* Log the message with our header trimmed off */
break;
#endif /* HAVE_SYSLOG */
default:
break;
}
}
}
/*
* krb5_klog_init() - Initialize logging.
*
* This routine parses the syntax described above to specify destinations for
* com_err(3) or krb5_klog_syslog() messages generated by the caller.
*
* Parameters:
* kcontext - Kerberos context.
* ename - Entity name as it is to appear in the profile.
* whoami - Entity name as it is to appear in error output.
* do_com_err - Take over com_err(3) processing.
*
* Implicit inputs:
* stderr - This is where STDERR output goes.
*
* Implicit outputs:
* log_nentries - Number of log entries, both valid and invalid.
* log_control - List of entries (log_nentries long) which contains
* data for klog_com_err_proc() to use to determine
*/
{
char **logging_specs;
int i, ngood;
int error;
FILE *f;
/* Initialize */
do_openlog = 0;
log_facility = 0;
/*
* Look up [logging]-><ename> in the profile. If that doesn't
* succeed, then look for [logging]->default.
*/
logging_profent[0] = "logging";
logging_defent[0] = "logging";
logging_specs = (char **) NULL;
ngood = 0;
log_control.log_nentries = 0;
&logging_specs) ||
&logging_specs)) {
/*
* We have a match, so we first count the number of elements
*/
for (log_control.log_nentries = 0;
/*
* Now allocate our structure.
*/
if (log_control.log_entries) {
/*
* Scan through the list.
*/
for (i=0; i<log_control.log_nentries; i++) {
/*
* The format is:
* <whitespace><data><whitespace>
* so, trim off the leading and trailing whitespace here.
*/
cp2++;
*cp2 = '\0';
/*
* Is this a file?
*/
/*
*/
if (f) {
time(0);
/*
* Now parse for ename_"rotate" = {
* period = XXX
* versions = 10
* }
*/
sizeof (rotate_kw)) {
char *time;
int vers;
if (!krb5_string_to_deltat(time,
&dt)) {
}
}
}
if (!profile_get_integer(
rotate_kw, "versions",
&vers)) {
}
}
} else {
continue;
}
}
}
#ifdef HAVE_SYSLOG
/*
* Is this a syslog?
*/
error = 0;
/*
* Is there a severify specified?
*/
/*
* Find the end of the severity.
*/
if (cp2) {
*cp2 = '\0';
cp2++;
}
/*
* Match a severity.
*/
}
#ifdef LOG_EMERG
}
#endif /* LOG_EMERG */
#ifdef LOG_ALERT
}
#endif /* LOG_ALERT */
#ifdef LOG_CRIT
}
#endif /* LOG_CRIT */
#ifdef LOG_WARNING
}
#endif /* LOG_WARNING */
#ifdef LOG_NOTICE
}
#endif /* LOG_NOTICE */
#ifdef LOG_INFO
}
#endif /* LOG_INFO */
#ifdef LOG_DEBUG
}
#endif /* LOG_DEBUG */
else
error = 1;
/*
* If there is a facility present, then parse that.
*/
if (cp2) {
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
cp2--;
}
}
if (!error) {
do_openlog = 1;
}
}
#endif /* HAVE_SYSLOG */
/*
* Is this a standard error specification?
*/
"standard error";
}
}
/*
* Is this a specification of the console?
*/
CONSOLE_OPEN("a+F");
}
}
/*
* Is this a specification of a device?
*/
/*
* We handle devices very similarly to files.
*/
}
}
}
/*
* See if we successfully parsed this specification.
*/
}
else
ngood++;
}
}
/*
* If we didn't find anything, then free our lists.
*/
if (ngood == 0) {
for (i=0; i<log_control.log_nentries; i++)
free(logging_specs[i]);
}
}
/*
* If we didn't find anything, go for the default which is to log to
* the system log.
*/
if (ngood == 0) {
if (log_control.log_entries)
do_openlog = 1;
}
if (log_control.log_nentries) {
if (log_control.log_whoami)
if (log_control.log_hostname) {
}
#ifdef HAVE_OPENLOG
if (do_openlog) {
}
#endif /* HAVE_OPENLOG */
if (do_com_err)
(void) set_com_err_hook(klog_com_err_proc);
}
}
/*
* krb5_klog_close() - Close the logging context and free all data.
*/
void
{
int lindex;
(void) reset_com_err_hook();
case K_LOG_FILE:
case K_LOG_STDERR:
/*
*/
break;
case K_LOG_CONSOLE:
case K_LOG_DEVICE:
/*
* Devices (may need special handling)
*/
break;
#ifdef HAVE_SYSLOG
case K_LOG_SYSLOG:
/*
* System log.
*/
break;
#endif /* HAVE_SYSLOG */
default:
break;
}
}
log_control.log_nentries = 0;
if (log_control.log_whoami)
if (log_control.log_hostname)
#ifdef HAVE_CLOSELOG
if (log_control.log_opened)
closelog();
#endif /* HAVE_CLOSELOG */
}
/*
* severity2string() - Convert a severity to a string.
*/
static const char *
{
int s;
const char *ss;
s = severity & LOG_PRIMASK;
switch (s) {
#ifdef LOG_EMERG
case LOG_EMERG:
break;
#endif /* LOG_EMERG */
#ifdef LOG_ALERT
case LOG_ALERT:
break;
#endif /* LOG_ALERT */
#ifdef LOG_CRIT
case LOG_CRIT:
break;
#endif /* LOG_CRIT */
case LOG_ERR:
break;
#ifdef LOG_WARNING
case LOG_WARNING:
break;
#endif /* LOG_WARNING */
#ifdef LOG_NOTICE
case LOG_NOTICE:
break;
#endif /* LOG_NOTICE */
#ifdef LOG_INFO
case LOG_INFO:
break;
#endif /* LOG_INFO */
#ifdef LOG_DEBUG
case LOG_DEBUG:
break;
#endif /* LOG_DEBUG */
}
return((char *) ss);
}
/*
* krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while
* also performing the logging redirection as specified
* by krb5_klog_init().
*/
static int
{
int lindex;
char *syslogp;
char *cp;
#ifdef HAVE_STRFTIME
#endif /* HAVE_STRFTIME */
/*
* Format a syslog-esque message of the format:
*
* (verbose form)
* <date> <hostname> <id>[<pid>](<priority>): <message>
*
* (short form)
* <date> <message>
*/
#ifdef HAVE_STRFTIME
/*
* Format the date: mon dd hh:mm:ss
*/
if (soff > 0)
else
return(-1);
#else /* HAVE_STRFTIME */
/*
* Format the date:
* We ASSUME here that the output of ctime is of the format:
* dow mon dd hh:mm:ss tzs yyyy\n
* 012345678901234567890123456789
*/
cp += 15;
#endif /* HAVE_STRFTIME */
#ifdef VERBOSE_LOGS
#else
#endif
/* Now format the actual message */
#ifdef HAVE_VSNPRINTF
#else /* HAVE_VSPRINTF */
#endif /* HAVE_VSPRINTF */
/*
* If the user did not use krb5_klog_init() instead of dropping
* the request on the floor, syslog it - if it exists
*/
#ifdef HAVE_SYSLOG
if (log_control.log_nentries == 0) {
/* Log the message with our header trimmed off */
}
#endif
/*
* Now that we have the message formatted, perform the output to each
* logging specification.
*/
case K_LOG_FILE:
/*FALLTHRU*/
case K_LOG_STDERR:
/*
*/
outbuf) < 0) {
/* Attempt to report error */
}
else {
}
break;
case K_LOG_CONSOLE:
case K_LOG_DEVICE:
/*
* Devices (may need special handling)
*/
outbuf) < 0) {
/* Attempt to report error */
}
break;
#ifdef HAVE_SYSLOG
case K_LOG_SYSLOG:
/*
* System log.
*/
/* Log the message with our header trimmed off */
break;
#endif /* HAVE_SYSLOG */
default:
break;
}
}
return(0);
}
int
{
int retval;
return(retval);
}
/*
* krb5_klog_reopen() - Close and reopen any open (non-syslog) log files.
* This function is called when a SIGHUP is received
* so that external log-archival utilities may
* alert the Kerberos daemons that they should get
* a new file descriptor for the give filename.
*/
void
{
int lindex;
FILE *f;
/*
* Only logs which are actually files need to be closed
* and reopened in response to a SIGHUP
*/
/*
* In case the old logfile did not get moved out of the
* way, open for append to prevent squashing the old logs.
*/
if (f) {
} else {
}
}
}
}
/*
* Solaris Kerberos:
* Switch the current context to the one supplied
*/
}
/*
* Solaris Kerberos:
* Return a string representation of "facility"
*/
switch (facility) {
case (LOG_AUTH):
return ("AUTH");
case (LOG_KERN):
return ("KERN");
case (LOG_USER):
return ("USER");
case (LOG_MAIL):
return ("MAIL");
case (LOG_DAEMON):
return ("DAEMON");
case (LOG_LPR):
return ("LPR");
case (LOG_NEWS):
return ("NEWS");
case (LOG_UUCP):
return ("UUCP");
case (LOG_CRON):
return ("CRON");
case (LOG_LOCAL0):
return ("LOCAL0");
case (LOG_LOCAL1):
return ("LOCAL1");
case (LOG_LOCAL2):
return ("LOCAL2");
case (LOG_LOCAL3):
return ("LOCAL3");
case (LOG_LOCAL4):
return ("LOCAL4");
case (LOG_LOCAL5):
return ("LOCAL6");
case (LOG_LOCAL7):
return ("LOCAL7");
}
return ("UNKNOWN");
}
/*
* Solaris Kerberos:
* Print to stderr where logging is being done
*/
int lindex;
case K_LOG_FILE:
break;
case K_LOG_STDERR:
break;
case K_LOG_CONSOLE:
break;
case K_LOG_DEVICE:
break;
case K_LOG_SYSLOG:
break;
case K_LOG_NONE:
break;
default: /* Should never get here */
return (-1);
}
}
return (0);
}
/*
* Solaris Kerberos:
* Add logging to stderr.
*/
int i;
return (ENOMEM);
}
} else {
return (ENOMEM);
}
sizeof(struct log_entry));
}
i = log_control.log_nentries;
} else {
/* Free the alloc'ed extra entry */
return (err);
}
return (0);
}
/*
* Solaris Kerberos
* Remove logging to stderr.
*/
void krb5_klog_remove_stderr() {
int i;
/* Find the entry (if it exists) */
for (i = 0; i < log_control.log_nentries; i++) {
break;
}
}
if ( i < log_control.log_nentries) {
log_control.log_entries[i] =
sizeof(struct log_entry));
else
} else {
}
}
}
/* Solaris Kerberos: Indicate if currently logging to stderr */
int i;
/* Find the entry (if it exists) */
for (i = 0; i < log_control.log_nentries; i++) {
return (TRUE);
}
}
return (FALSE);
}