xref: /onnv-gate/usr/src/lib/krb5/kadm5/srv/logger.c (revision 3998)
10Sstevel@tonic-gate /*
2*3998Ssemery  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate  * lib/kadm/logger.c
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * Copyright 1995 by the Massachusetts Institute of Technology.
110Sstevel@tonic-gate  * All Rights Reserved.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * Export of this software from the United States of America may
140Sstevel@tonic-gate  *   require a specific license from the United States Government.
150Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
160Sstevel@tonic-gate  *   export to obtain such a license before exporting.
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
190Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
200Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
210Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
220Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
230Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
240Sstevel@tonic-gate  * to distribution of the software without specific, written prior
250Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
260Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
270Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
280Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
290Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
300Sstevel@tonic-gate  * or implied warranty.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /* KADM5 wants non-syslog log files to contain syslog-like entries */
360Sstevel@tonic-gate #define VERBOSE_LOGS
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * logger.c	- Handle logging functions for those who want it.
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate #include "k5-int.h"
420Sstevel@tonic-gate #include "adm_proto.h"
430Sstevel@tonic-gate #include "com_err.h"
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <ctype.h>
460Sstevel@tonic-gate #include <ctype.h>
470Sstevel@tonic-gate #include <syslog.h>
480Sstevel@tonic-gate #include <stdarg.h>
490Sstevel@tonic-gate #include <libintl.h>
500Sstevel@tonic-gate #include <sys/types.h>
510Sstevel@tonic-gate #include <sys/stat.h>
520Sstevel@tonic-gate 
53*3998Ssemery #define	KRB5_KLOG_MAX_ERRMSG_SIZE	2048
540Sstevel@tonic-gate #ifndef	MAXHOSTNAMELEN
550Sstevel@tonic-gate #define	MAXHOSTNAMELEN	256
560Sstevel@tonic-gate #endif	/* MAXHOSTNAMELEN */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define LSPEC_PARSE_ERR_1 	1
590Sstevel@tonic-gate #define LSPEC_PARSE_ERR_2	2
600Sstevel@tonic-gate #define LOG_FILE_ERR		3
610Sstevel@tonic-gate #define LOG_DEVICE_ERR		4
620Sstevel@tonic-gate #define LOG_UFO_STRING		5
630Sstevel@tonic-gate #define LOG_EMERG_STRING	6
640Sstevel@tonic-gate #define LOG_ALERT_STRING	7
650Sstevel@tonic-gate #define LOG_CRIT_STRING		8
660Sstevel@tonic-gate #define LOG_ERR_STRING		9
670Sstevel@tonic-gate #define LOG_WARNING_STRING	10
680Sstevel@tonic-gate #define LOG_NOTICE_STRING	11
690Sstevel@tonic-gate #define LOG_INFO_STRING	12
700Sstevel@tonic-gate #define LOG_DEBUG_STRING	13
710Sstevel@tonic-gate /* This is to assure that we have at least one match in the syslog stuff */
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate static const char LSPEC_PARSE_ERR_1[] =	"%s: cannot parse <%s>\n";
740Sstevel@tonic-gate static const char LSPEC_PARSE_ERR_2[] =	"%s: warning - logging entry syntax error\n";
750Sstevel@tonic-gate static const char LOG_FILE_ERR[] =	"%s: error writing to %s\n";
760Sstevel@tonic-gate static const char LOG_DEVICE_ERR[] =	"%s: error writing to %s device\n";
770Sstevel@tonic-gate static const char LOG_UFO_STRING[] =	"???";
780Sstevel@tonic-gate static const char LOG_EMERG_STRING[] =	"EMERGENCY";
790Sstevel@tonic-gate static const char LOG_ALERT_STRING[] =	"ALERT";
800Sstevel@tonic-gate static const char LOG_CRIT_STRING[] =	"CRITICAL";
810Sstevel@tonic-gate static const char LOG_ERR_STRING[] =	"Error";
820Sstevel@tonic-gate static const char LOG_WARNING_STRING[] =	"Warning";
830Sstevel@tonic-gate static const char LOG_NOTICE_STRING[] =	"Notice";
840Sstevel@tonic-gate static const char LOG_INFO_STRING[] =	"info";
850Sstevel@tonic-gate static const char LOG_DEBUG_STRING[] =	"debug";
860Sstevel@tonic-gate */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 
890Sstevel@tonic-gate const char *
900Sstevel@tonic-gate krb5_log_error_table(long errorno) {
910Sstevel@tonic-gate switch (errorno) {
920Sstevel@tonic-gate 	case LSPEC_PARSE_ERR_1:
930Sstevel@tonic-gate 		return(gettext("%s: cannot parse <%s>\n"));
940Sstevel@tonic-gate 	case LSPEC_PARSE_ERR_2:
950Sstevel@tonic-gate 		return(gettext("%s: warning - logging entry syntax error\n"));
960Sstevel@tonic-gate 	case LOG_FILE_ERR:
970Sstevel@tonic-gate 		return(gettext("%s: error writing to %s\n"));
980Sstevel@tonic-gate 	case LOG_DEVICE_ERR:
990Sstevel@tonic-gate 		return(gettext("%s: error writing to %s device\n"));
1000Sstevel@tonic-gate 	case LOG_UFO_STRING:
101358Sgtb         default:
1020Sstevel@tonic-gate 		return(gettext("???"));
1030Sstevel@tonic-gate 	case LOG_EMERG_STRING:
1040Sstevel@tonic-gate 		return(gettext("EMERGENCY"));
1050Sstevel@tonic-gate 	case LOG_ALERT_STRING:
1060Sstevel@tonic-gate 		return(gettext("ALERT"));
1070Sstevel@tonic-gate 	case LOG_CRIT_STRING:
1080Sstevel@tonic-gate 		return(gettext("CRITICAL"));
1090Sstevel@tonic-gate 	case LOG_ERR_STRING:
1100Sstevel@tonic-gate 		return(gettext("Error"));
1110Sstevel@tonic-gate 	case LOG_WARNING_STRING:
1120Sstevel@tonic-gate 		return(gettext("Warning"));
1130Sstevel@tonic-gate 	case LOG_NOTICE_STRING:
1140Sstevel@tonic-gate 		return(gettext("Notice"));
1150Sstevel@tonic-gate 	case LOG_INFO_STRING:
1160Sstevel@tonic-gate 		return(gettext("info"));
1170Sstevel@tonic-gate 	case LOG_DEBUG_STRING:
1180Sstevel@tonic-gate 		return(gettext("info"));
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * Output logging.
1240Sstevel@tonic-gate  *
1250Sstevel@tonic-gate  * Output logging is now controlled by the configuration file.  We can specify
1260Sstevel@tonic-gate  * the following syntaxes under the [logging]->entity specification.
1270Sstevel@tonic-gate  *	FILE<opentype><pathname>
1280Sstevel@tonic-gate  *	SYSLOG[=<severity>[:<facility>]]
1290Sstevel@tonic-gate  *	STDERR
1300Sstevel@tonic-gate  *	CONSOLE
1310Sstevel@tonic-gate  *	DEVICE=<device-spec>
1320Sstevel@tonic-gate  *
1330Sstevel@tonic-gate  * Where:
1340Sstevel@tonic-gate  *	<opentype> is ":" for open/append, "=" for open/create.
1350Sstevel@tonic-gate  *	<pathname> is a valid path name.
1360Sstevel@tonic-gate  *	<severity> is one of: (default = ERR)
1370Sstevel@tonic-gate  *		EMERG
1380Sstevel@tonic-gate  *		ALERT
1390Sstevel@tonic-gate  *		CRIT
1400Sstevel@tonic-gate  *		ERR
1410Sstevel@tonic-gate  *		WARNING
1420Sstevel@tonic-gate  *		NOTICE
1430Sstevel@tonic-gate  *		INFO
1440Sstevel@tonic-gate  *		DEBUG
1450Sstevel@tonic-gate  *	<facility> is one of: (default = AUTH)
1460Sstevel@tonic-gate  *		KERN
1470Sstevel@tonic-gate  *		USER
1480Sstevel@tonic-gate  *		MAIL
1490Sstevel@tonic-gate  *		DAEMON
1500Sstevel@tonic-gate  *		AUTH
1510Sstevel@tonic-gate  *		LPR
1520Sstevel@tonic-gate  *		NEWS
1530Sstevel@tonic-gate  *		UUCP
1540Sstevel@tonic-gate  *		CRON
1550Sstevel@tonic-gate  *		LOCAL0..LOCAL7
1560Sstevel@tonic-gate  *	<device-spec> is a valid device specification.
1570Sstevel@tonic-gate  */
1580Sstevel@tonic-gate struct log_entry {
1590Sstevel@tonic-gate     enum log_type { K_LOG_FILE,
1600Sstevel@tonic-gate 			K_LOG_SYSLOG,
1610Sstevel@tonic-gate 			K_LOG_STDERR,
1620Sstevel@tonic-gate 			K_LOG_CONSOLE,
1630Sstevel@tonic-gate 			K_LOG_DEVICE,
1640Sstevel@tonic-gate 			K_LOG_NONE } log_type;
1650Sstevel@tonic-gate     krb5_pointer log_2free;
1660Sstevel@tonic-gate     union log_union {
1670Sstevel@tonic-gate 	struct log_file {
1680Sstevel@tonic-gate 	    FILE	*lf_filep;
1690Sstevel@tonic-gate 	    char	*lf_fname;
1700Sstevel@tonic-gate 	    char	*lf_fopen_mode; /* "a+" or "w" */
1710Sstevel@tonic-gate #define	K_LOG_DEF_FILE_ROTATE_PERIOD	-1	/* never */
1720Sstevel@tonic-gate #define	K_LOG_DEF_FILE_ROTATE_VERSIONS	0	/* no versions */
1730Sstevel@tonic-gate 	    time_t	lf_rotate_period;
1740Sstevel@tonic-gate 	    time_t	lf_last_rotated;
1750Sstevel@tonic-gate 	    int		lf_rotate_versions;
1760Sstevel@tonic-gate 	} log_file;
1770Sstevel@tonic-gate 	struct log_syslog {
1780Sstevel@tonic-gate 	    int		ls_facility;
1790Sstevel@tonic-gate 	    int		ls_severity;
1800Sstevel@tonic-gate 	} log_syslog;
1810Sstevel@tonic-gate 	struct log_device {
1820Sstevel@tonic-gate 	    FILE	*ld_filep;
1830Sstevel@tonic-gate 	    char	*ld_devname;
1840Sstevel@tonic-gate 	} log_device;
1850Sstevel@tonic-gate     } log_union;
1860Sstevel@tonic-gate };
1870Sstevel@tonic-gate #define	lfu_filep	log_union.log_file.lf_filep
1880Sstevel@tonic-gate #define	lfu_fname	log_union.log_file.lf_fname
1890Sstevel@tonic-gate #define	lfu_fopen_mode	log_union.log_file.lf_fopen_mode
1900Sstevel@tonic-gate #define	lfu_rotate_period	log_union.log_file.lf_rotate_period
1910Sstevel@tonic-gate #define	lfu_last_rotated	log_union.log_file.lf_last_rotated
1920Sstevel@tonic-gate #define	lfu_rotate_versions	log_union.log_file.lf_rotate_versions
1930Sstevel@tonic-gate #define	lsu_facility	log_union.log_syslog.ls_facility
1940Sstevel@tonic-gate #define	lsu_severity	log_union.log_syslog.ls_severity
1950Sstevel@tonic-gate #define	ldu_filep	log_union.log_device.ld_filep
1960Sstevel@tonic-gate #define	ldu_devname	log_union.log_device.ld_devname
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate struct log_control {
1990Sstevel@tonic-gate     struct log_entry	*log_entries;
2000Sstevel@tonic-gate     int			log_nentries;
2010Sstevel@tonic-gate     char		*log_whoami;
2020Sstevel@tonic-gate     char		*log_hostname;
2030Sstevel@tonic-gate     krb5_boolean	log_opened;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate };
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate static struct log_control log_control = {
2080Sstevel@tonic-gate     (struct log_entry *) NULL,
2090Sstevel@tonic-gate     0,
2100Sstevel@tonic-gate     (char *) NULL,
2110Sstevel@tonic-gate     (char *) NULL,
2120Sstevel@tonic-gate     0
2130Sstevel@tonic-gate };
2140Sstevel@tonic-gate static struct log_entry	def_log_entry;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  * These macros define any special processing that needs to happen for
2180Sstevel@tonic-gate  * devices.  For unix, of course, this is hardly anything.
2190Sstevel@tonic-gate  */
2200Sstevel@tonic-gate #define	DEVICE_OPEN(d, m)	fopen(d, m)
2210Sstevel@tonic-gate #define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
2220Sstevel@tonic-gate #define	DEVICE_PRINT(f, m)	((fprintf(f, "%s\r\n", m) >= 0) ? 	\
2230Sstevel@tonic-gate 				 (fflush(f), 0) :			\
2240Sstevel@tonic-gate 				 -1)
2250Sstevel@tonic-gate #define	DEVICE_CLOSE(d)		fclose(d)
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * klog_rotate() - roate a log file if we have specified rotation
2300Sstevel@tonic-gate  * parameters in krb5.conf.
2310Sstevel@tonic-gate  */
2320Sstevel@tonic-gate static void
2330Sstevel@tonic-gate klog_rotate(struct log_entry *le)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	time_t t;
2360Sstevel@tonic-gate 	int i;
2370Sstevel@tonic-gate 	char *name_buf1;
2380Sstevel@tonic-gate 	char *name_buf2;
2390Sstevel@tonic-gate 	char *old_name;
2400Sstevel@tonic-gate 	char *new_name;
2410Sstevel@tonic-gate 	char *tmp;
2420Sstevel@tonic-gate 	FILE *fp;
2430Sstevel@tonic-gate 	int num_vers;
2440Sstevel@tonic-gate 	mode_t old_umask;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * By default we don't rotate.
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	if (le->lfu_rotate_period == K_LOG_DEF_FILE_ROTATE_PERIOD)
2510Sstevel@tonic-gate 		return;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	t = time(0);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	if (t >= le->lfu_last_rotated + le->lfu_rotate_period) {
2560Sstevel@tonic-gate 		/*
2570Sstevel@tonic-gate 		 * The N log file versions will be renamed X.N-1 X.N-2, ... X.0.
2580Sstevel@tonic-gate 		 * So the allocate file name buffers that can the version
2590Sstevel@tonic-gate 		 * number extensions.
2600Sstevel@tonic-gate 		 * 32 extra bytes is plenty.
2610Sstevel@tonic-gate 		 */
2620Sstevel@tonic-gate 		name_buf1 = malloc(strlen(le->lfu_fname) + 32);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (name_buf1 == NULL)
2650Sstevel@tonic-gate 			return;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		name_buf2 = malloc(strlen(le->lfu_fname) + 32);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 		if (name_buf2 == NULL) {
2700Sstevel@tonic-gate 			free(name_buf1);
2710Sstevel@tonic-gate 			return;
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		old_name = name_buf1;
2750Sstevel@tonic-gate 		new_name = name_buf2;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		/*
2780Sstevel@tonic-gate 		 * If there N versions, then the first one has file extension
2790Sstevel@tonic-gate 		 * of N-1.
2800Sstevel@tonic-gate 		 */
2810Sstevel@tonic-gate 		(void) sprintf(new_name, "%s.%d", le->lfu_fname,
2820Sstevel@tonic-gate 			le->lfu_rotate_versions - 1);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		/*
2850Sstevel@tonic-gate 		 * Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ...
2860Sstevel@tonic-gate 		 * file.0 to file.1
2870Sstevel@tonic-gate 		 */
2880Sstevel@tonic-gate 		for (i = le->lfu_rotate_versions - 1; i > 0; i--) {
2890Sstevel@tonic-gate 			(void) sprintf(old_name, "%s.%d", le->lfu_fname, i - 1);
2900Sstevel@tonic-gate 			(void) rename(old_name, new_name);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 			/*
2930Sstevel@tonic-gate 			 * swap old name and new name. This way,
2940Sstevel@tonic-gate 			 * on the next iteration, new_name.X
2950Sstevel@tonic-gate 			 * becomes new_name.X-1.
2960Sstevel@tonic-gate 			 */
2970Sstevel@tonic-gate 			tmp = old_name;
2980Sstevel@tonic-gate 			old_name = new_name;
2990Sstevel@tonic-gate 			new_name = tmp;
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 		old_name = le->lfu_fname;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		(void) rename(old_name, new_name);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		/*
3060Sstevel@tonic-gate 		 * Even though we don't know yet if the fopen()
3070Sstevel@tonic-gate 		 * of the log file will succeed, we mark the log
3080Sstevel@tonic-gate 		 * as rotated. This is so we don't repeatably
3090Sstevel@tonic-gate 		 * rotate file.N-2 to file.N-1 ... etc without
3100Sstevel@tonic-gate 		 * waiting for the rotate period to elapse.
3110Sstevel@tonic-gate 		 */
3120Sstevel@tonic-gate 		le->lfu_last_rotated = t;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		/*
3150Sstevel@tonic-gate 		 * Default log file creation mode should be read-only
3160Sstevel@tonic-gate 		 * by owner(root), but the admin can override with
3170Sstevel@tonic-gate 		 * chmod(1) if desired.
3180Sstevel@tonic-gate 		 */
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		old_umask = umask(077);
3210Sstevel@tonic-gate 		fp = fopen(old_name, le->lfu_fopen_mode);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		umask(old_umask);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		if (fp != NULL) {
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 			(void) fclose(le->lfu_filep);
3280Sstevel@tonic-gate 			le->lfu_filep = fp;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 			/*
3310Sstevel@tonic-gate 			 * If the version parameter in krb5.conf was
3320Sstevel@tonic-gate 			 * 0, then we take this to mean that rotating the
3330Sstevel@tonic-gate 			 * log file will cause us to dispose of the
3340Sstevel@tonic-gate 			 * old one, and created a new one. We have just
3350Sstevel@tonic-gate 			 * renamed the old one to file.-1, so remove it.
3360Sstevel@tonic-gate 			 */
3370Sstevel@tonic-gate 			if (le->lfu_rotate_versions <= 0)
3380Sstevel@tonic-gate 				(void) unlink(new_name);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 		} else {
3410Sstevel@tonic-gate 			fprintf(stderr,
3420Sstevel@tonic-gate 		gettext("During rotate, couldn't open log file %s: %s\n"),
3430Sstevel@tonic-gate 				old_name, error_message(errno));
3440Sstevel@tonic-gate 			/*
3450Sstevel@tonic-gate 			 * Put it back.
3460Sstevel@tonic-gate 			 */
3470Sstevel@tonic-gate 			(void) rename(new_name, old_name);
3480Sstevel@tonic-gate 		}
3490Sstevel@tonic-gate 		free(name_buf1);
3500Sstevel@tonic-gate 		free(name_buf2);
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * klog_com_err_proc()	- Handle com_err(3) messages as specified by the
3560Sstevel@tonic-gate  *			  profile.
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate static void
3590Sstevel@tonic-gate klog_com_err_proc(whoami, code, format, ap)
3600Sstevel@tonic-gate     const char	*whoami;
3610Sstevel@tonic-gate     long	code;
3620Sstevel@tonic-gate     const char	*format;
3630Sstevel@tonic-gate     va_list	ap;
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate     char	outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
3660Sstevel@tonic-gate     int		lindex;
3670Sstevel@tonic-gate     char	*actual_format;
3680Sstevel@tonic-gate     int		log_pri = -1;
3690Sstevel@tonic-gate     char	*cp;
3700Sstevel@tonic-gate     char	*syslogp;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate     /* Make the header */
3730Sstevel@tonic-gate     sprintf(outbuf, "%s: ", whoami);
3740Sstevel@tonic-gate     /*
3750Sstevel@tonic-gate      * Squirrel away address after header for syslog since syslog makes
3760Sstevel@tonic-gate      * a header
3770Sstevel@tonic-gate      */
3780Sstevel@tonic-gate     syslogp = &outbuf[strlen(outbuf)];
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate     /* If reporting an error message, separate it. */
3810Sstevel@tonic-gate     if (code) {
3820Sstevel@tonic-gate         outbuf[sizeof(outbuf) - 1] = '\0';
383*3998Ssemery 
384*3998Ssemery 	strncat(outbuf, error_message(code),
385*3998Ssemery 		sizeof(outbuf) - 1 - strlen(outbuf));
3860Sstevel@tonic-gate 	strncat(outbuf, " - ", sizeof(outbuf) - 1 - strlen(outbuf));
3870Sstevel@tonic-gate     }
3880Sstevel@tonic-gate     cp = &outbuf[strlen(outbuf)];
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate     actual_format = (char *) format;
3910Sstevel@tonic-gate     /*
3920Sstevel@tonic-gate      * This is an unpleasant hack.  If the first character is less than
3930Sstevel@tonic-gate      * 8, then we assume that it is a priority.
3940Sstevel@tonic-gate      *
3950Sstevel@tonic-gate      * Since it is not guaranteed that there is a direct mapping between
3960Sstevel@tonic-gate      * syslog priorities (e.g. Ultrix and old BSD), we resort to this
3970Sstevel@tonic-gate      * intermediate representation.
3980Sstevel@tonic-gate      */
3990Sstevel@tonic-gate     if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) {
4000Sstevel@tonic-gate 	actual_format = (char *) (format + 1);
4010Sstevel@tonic-gate 	switch ((unsigned char) *format) {
4020Sstevel@tonic-gate 	case 1:
4030Sstevel@tonic-gate 	    log_pri = LOG_EMERG;
4040Sstevel@tonic-gate 	    break;
4050Sstevel@tonic-gate 	case 2:
4060Sstevel@tonic-gate 	    log_pri = LOG_ALERT;
4070Sstevel@tonic-gate 	    break;
4080Sstevel@tonic-gate 	case 3:
4090Sstevel@tonic-gate 	    log_pri = LOG_CRIT;
4100Sstevel@tonic-gate 	    break;
4110Sstevel@tonic-gate 	default:
4120Sstevel@tonic-gate 	case 4:
4130Sstevel@tonic-gate 	    log_pri = LOG_ERR;
4140Sstevel@tonic-gate 	    break;
4150Sstevel@tonic-gate 	case 5:
4160Sstevel@tonic-gate 	    log_pri = LOG_WARNING;
4170Sstevel@tonic-gate 	    break;
4180Sstevel@tonic-gate 	case 6:
4190Sstevel@tonic-gate 	    log_pri = LOG_NOTICE;
4200Sstevel@tonic-gate 	    break;
4210Sstevel@tonic-gate 	case 7:
4220Sstevel@tonic-gate 	    log_pri = LOG_INFO;
4230Sstevel@tonic-gate 	    break;
4240Sstevel@tonic-gate 	case 8:
4250Sstevel@tonic-gate 	    log_pri = LOG_DEBUG;
4260Sstevel@tonic-gate 	    break;
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate     }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate     /* Now format the actual message */
431*3998Ssemery     vsnprintf(cp, sizeof (outbuf) - (cp - outbuf), actual_format, ap);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate     /*
4340Sstevel@tonic-gate      * Now that we have the message formatted, perform the output to each
4350Sstevel@tonic-gate      * logging specification.
4360Sstevel@tonic-gate      */
4370Sstevel@tonic-gate     for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
4380Sstevel@tonic-gate 	switch (log_control.log_entries[lindex].log_type) {
4390Sstevel@tonic-gate 	case K_LOG_FILE:
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	    klog_rotate(&log_control.log_entries[lindex]);
4420Sstevel@tonic-gate 	    /*FALLTHRU*/
4430Sstevel@tonic-gate 	case K_LOG_STDERR:
4440Sstevel@tonic-gate 	    /*
4450Sstevel@tonic-gate 	     * Files/standard error.
4460Sstevel@tonic-gate 	     */
4470Sstevel@tonic-gate 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n",
4480Sstevel@tonic-gate 			outbuf) < 0) {
4490Sstevel@tonic-gate 		/* Attempt to report error */
4500Sstevel@tonic-gate 		fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), whoami,
4510Sstevel@tonic-gate 			log_control.log_entries[lindex].lfu_fname);
4520Sstevel@tonic-gate 	    }
4530Sstevel@tonic-gate 	    else {
4540Sstevel@tonic-gate 		fflush(log_control.log_entries[lindex].lfu_filep);
4550Sstevel@tonic-gate 	    }
4560Sstevel@tonic-gate 	    break;
4570Sstevel@tonic-gate 	case K_LOG_CONSOLE:
4580Sstevel@tonic-gate 	case K_LOG_DEVICE:
4590Sstevel@tonic-gate 	    /*
4600Sstevel@tonic-gate 	     * Devices (may need special handling)
4610Sstevel@tonic-gate 	     */
4620Sstevel@tonic-gate 	    if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
4630Sstevel@tonic-gate 			     outbuf) < 0) {
4640Sstevel@tonic-gate 		/* Attempt to report error */
4650Sstevel@tonic-gate 		fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), whoami,
4660Sstevel@tonic-gate 			log_control.log_entries[lindex].ldu_devname);
4670Sstevel@tonic-gate 	    }
4680Sstevel@tonic-gate 	    break;
4690Sstevel@tonic-gate 	case K_LOG_SYSLOG:
4700Sstevel@tonic-gate 	    /*
4710Sstevel@tonic-gate 	     * System log.
4720Sstevel@tonic-gate 	     */
4730Sstevel@tonic-gate 	    /*
4740Sstevel@tonic-gate 	     * If we have specified a priority through our hackery, then
4750Sstevel@tonic-gate 	     * use it, otherwise use the default.
4760Sstevel@tonic-gate 	     */
4770Sstevel@tonic-gate 	    if (log_pri >= 0)
4780Sstevel@tonic-gate 		log_pri |= log_control.log_entries[lindex].lsu_facility;
4790Sstevel@tonic-gate 	    else
4800Sstevel@tonic-gate 		log_pri = log_control.log_entries[lindex].lsu_facility |
4810Sstevel@tonic-gate 		    log_control.log_entries[lindex].lsu_severity;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	    /* Log the message with our header trimmed off */
4840Sstevel@tonic-gate 	    syslog(log_pri, "%s", syslogp);
4850Sstevel@tonic-gate 	    break;
4860Sstevel@tonic-gate 	default:
4870Sstevel@tonic-gate 	    break;
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate     }
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate /*
4930Sstevel@tonic-gate  * krb5_klog_init()	- Initialize logging.
4940Sstevel@tonic-gate  *
4950Sstevel@tonic-gate  * This routine parses the syntax described above to specify destinations for
4960Sstevel@tonic-gate  * com_err(3) or krb5_klog_syslog() messages generated by the caller.
4970Sstevel@tonic-gate  *
4980Sstevel@tonic-gate  * Parameters:
4990Sstevel@tonic-gate  *	kcontext	- Kerberos context.
5000Sstevel@tonic-gate  *	ename		- Entity name as it is to appear in the profile.
5010Sstevel@tonic-gate  *	whoami		- Entity name as it is to appear in error output.
5020Sstevel@tonic-gate  *	do_com_err	- Take over com_err(3) processing.
5030Sstevel@tonic-gate  *
5040Sstevel@tonic-gate  * Implicit inputs:
5050Sstevel@tonic-gate  *	stderr		- This is where STDERR output goes.
5060Sstevel@tonic-gate  *
5070Sstevel@tonic-gate  * Implicit outputs:
5080Sstevel@tonic-gate  *	log_nentries	- Number of log entries, both valid and invalid.
5090Sstevel@tonic-gate  *	log_control	- List of entries (log_nentries long) which contains
5100Sstevel@tonic-gate  *			  data for klog_com_err_proc() to use to determine
5110Sstevel@tonic-gate  *			  where/how to send output.
5120Sstevel@tonic-gate  */
5130Sstevel@tonic-gate krb5_error_code
5140Sstevel@tonic-gate krb5_klog_init(kcontext, ename, whoami, do_com_err)
5150Sstevel@tonic-gate     krb5_context	kcontext;
5160Sstevel@tonic-gate     char		*ename;
5170Sstevel@tonic-gate     char		*whoami;
5180Sstevel@tonic-gate     krb5_boolean	do_com_err;
5190Sstevel@tonic-gate {
5200Sstevel@tonic-gate     const char	*logging_profent[3];
5210Sstevel@tonic-gate     const char	*logging_defent[3];
5220Sstevel@tonic-gate     char	**logging_specs;
5230Sstevel@tonic-gate     int		i, ngood;
5240Sstevel@tonic-gate     char	*cp, *cp2;
5250Sstevel@tonic-gate     char	savec;
5260Sstevel@tonic-gate     int		error;
5270Sstevel@tonic-gate     int		do_openlog, log_facility;
5280Sstevel@tonic-gate     FILE	*f;
5290Sstevel@tonic-gate     mode_t      old_umask;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate     /* Initialize */
5320Sstevel@tonic-gate     do_openlog = 0;
5330Sstevel@tonic-gate     log_facility = 0;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate     /*
5360Sstevel@tonic-gate      * Look up [logging]-><ename> in the profile.  If that doesn't
5370Sstevel@tonic-gate      * succeed, then look for [logging]->default.
5380Sstevel@tonic-gate      */
5390Sstevel@tonic-gate     logging_profent[0] = "logging";
5400Sstevel@tonic-gate     logging_profent[1] = ename;
5410Sstevel@tonic-gate     logging_profent[2] = (char *) NULL;
5420Sstevel@tonic-gate     logging_defent[0] = "logging";
5430Sstevel@tonic-gate     logging_defent[1] = "default";
5440Sstevel@tonic-gate     logging_defent[2] = (char *) NULL;
5450Sstevel@tonic-gate     logging_specs = (char **) NULL;
5460Sstevel@tonic-gate     ngood = 0;
5470Sstevel@tonic-gate     log_control.log_nentries = 0;
5480Sstevel@tonic-gate     if (!profile_get_values(kcontext->profile,
5490Sstevel@tonic-gate 			    logging_profent,
5500Sstevel@tonic-gate 			    &logging_specs) ||
5510Sstevel@tonic-gate 	!profile_get_values(kcontext->profile,
5520Sstevel@tonic-gate 			    logging_defent,
5530Sstevel@tonic-gate 			    &logging_specs)) {
5540Sstevel@tonic-gate 	/*
5550Sstevel@tonic-gate 	 * We have a match, so we first count the number of elements
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 	for (log_control.log_nentries = 0;
5580Sstevel@tonic-gate 	     logging_specs[log_control.log_nentries];
5590Sstevel@tonic-gate 	     log_control.log_nentries++);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	/*
5620Sstevel@tonic-gate 	 * Now allocate our structure.
5630Sstevel@tonic-gate 	 */
5640Sstevel@tonic-gate 	log_control.log_entries = (struct log_entry *)
5650Sstevel@tonic-gate 	    malloc(log_control.log_nentries * sizeof(struct log_entry));
5660Sstevel@tonic-gate 	if (log_control.log_entries) {
5670Sstevel@tonic-gate 	    /*
5680Sstevel@tonic-gate 	     * Scan through the list.
5690Sstevel@tonic-gate 	     */
5700Sstevel@tonic-gate 	    for (i=0; i<log_control.log_nentries; i++) {
5710Sstevel@tonic-gate 		log_control.log_entries[i].log_type = K_LOG_NONE;
5720Sstevel@tonic-gate 		log_control.log_entries[i].log_2free = logging_specs[i];
5730Sstevel@tonic-gate 		/*
5740Sstevel@tonic-gate 		 * The format is:
5750Sstevel@tonic-gate 		 *	<whitespace><data><whitespace>
5760Sstevel@tonic-gate 		 * so, trim off the leading and trailing whitespace here.
5770Sstevel@tonic-gate 		 */
5780Sstevel@tonic-gate 		for (cp = logging_specs[i]; isspace(*cp); cp++);
5790Sstevel@tonic-gate 		for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1];
5800Sstevel@tonic-gate 		     isspace(*cp2); cp2--);
5810Sstevel@tonic-gate 		cp2++;
5820Sstevel@tonic-gate 		*cp2 = '\0';
5830Sstevel@tonic-gate 		/*
5840Sstevel@tonic-gate 		 * Is this a file?
5850Sstevel@tonic-gate 		 */
5860Sstevel@tonic-gate 		if (!strncasecmp(cp, "FILE", 4)) {
5870Sstevel@tonic-gate 		    /*
5880Sstevel@tonic-gate 		     * Check for append/overwrite, then open the file.
5890Sstevel@tonic-gate 		     */
5900Sstevel@tonic-gate 		    if (cp[4] == ':' || cp[4] == '=') {
5910Sstevel@tonic-gate 			log_control.log_entries[i].lfu_fopen_mode =
5921914Scasper 				(cp[4] == ':') ? "a+F" : "wF";
5930Sstevel@tonic-gate 			old_umask = umask(077);
5940Sstevel@tonic-gate 			f = fopen(&cp[5],
5950Sstevel@tonic-gate 				log_control.log_entries[i].lfu_fopen_mode);
5960Sstevel@tonic-gate 			umask(old_umask);
5970Sstevel@tonic-gate 			if (f) {
5980Sstevel@tonic-gate                             char rotate_kw[128];
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 			    log_control.log_entries[i].lfu_filep = f;
6010Sstevel@tonic-gate 			    log_control.log_entries[i].log_type = K_LOG_FILE;
6020Sstevel@tonic-gate 			    log_control.log_entries[i].lfu_fname = &cp[5];
6030Sstevel@tonic-gate 			    log_control.log_entries[i].lfu_rotate_period =
6040Sstevel@tonic-gate 				K_LOG_DEF_FILE_ROTATE_PERIOD;
6050Sstevel@tonic-gate 			    log_control.log_entries[i].lfu_rotate_versions =
6060Sstevel@tonic-gate 				K_LOG_DEF_FILE_ROTATE_VERSIONS;
6070Sstevel@tonic-gate 			    log_control.log_entries[i].lfu_last_rotated =
6080Sstevel@tonic-gate 				time(0);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 			/*
6110Sstevel@tonic-gate 			 * Now parse for ename_"rotate" = {
6120Sstevel@tonic-gate 			 *	period = XXX
6130Sstevel@tonic-gate 			 * 	versions = 10
6140Sstevel@tonic-gate 			 * }
6150Sstevel@tonic-gate 			 */
6160Sstevel@tonic-gate 			    if (strlen(ename) + strlen("_rotate") <
6170Sstevel@tonic-gate 				sizeof (rotate_kw)) {
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 				    char *time;
6200Sstevel@tonic-gate 				    krb5_deltat	dt;
6210Sstevel@tonic-gate 				    int vers;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 				    strcpy(rotate_kw, ename);
6240Sstevel@tonic-gate 				    strcat(rotate_kw, "_rotate");
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 				    if (!profile_get_string(kcontext->profile,
6270Sstevel@tonic-gate 				        "logging", rotate_kw, "period",
6280Sstevel@tonic-gate 					NULL, &time)) {
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 					if (time != NULL) {
6310Sstevel@tonic-gate 					    if (!krb5_string_to_deltat(time,
6320Sstevel@tonic-gate 						&dt)) {
6330Sstevel@tonic-gate 			log_control.log_entries[i].lfu_rotate_period =
6340Sstevel@tonic-gate 							(time_t) dt;
6350Sstevel@tonic-gate 					    }
6360Sstevel@tonic-gate 					    free(time);
6370Sstevel@tonic-gate 					}
6380Sstevel@tonic-gate 				    }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 				    if (!profile_get_integer(
6410Sstevel@tonic-gate 					kcontext->profile, "logging",
6420Sstevel@tonic-gate 					rotate_kw, "versions",
6430Sstevel@tonic-gate 					K_LOG_DEF_FILE_ROTATE_VERSIONS,
6440Sstevel@tonic-gate 					&vers)) {
6450Sstevel@tonic-gate 			log_control.log_entries[i].lfu_rotate_versions = vers;
6460Sstevel@tonic-gate 				    }
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 			   }
6490Sstevel@tonic-gate 			} else {
6500Sstevel@tonic-gate 			    fprintf(stderr,gettext("Couldn't open log file %s: %s\n"),
6510Sstevel@tonic-gate 				    &cp[5], error_message(errno));
6520Sstevel@tonic-gate 			    continue;
6530Sstevel@tonic-gate 			}
6540Sstevel@tonic-gate 		    }
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 		/*
6570Sstevel@tonic-gate 		 * Is this a syslog?
6580Sstevel@tonic-gate 		 */
6590Sstevel@tonic-gate 		else if (!strncasecmp(cp, "SYSLOG", 6)) {
6600Sstevel@tonic-gate 		    error = 0;
6610Sstevel@tonic-gate 		    log_control.log_entries[i].lsu_facility = LOG_AUTH;
6620Sstevel@tonic-gate 		    log_control.log_entries[i].lsu_severity = LOG_ERR;
6630Sstevel@tonic-gate 		    /*
6640Sstevel@tonic-gate 		     * Is there a severify specified?
6650Sstevel@tonic-gate 		     */
6660Sstevel@tonic-gate 		    if (cp[6] == ':') {
6670Sstevel@tonic-gate 			/*
6680Sstevel@tonic-gate 			 * Find the end of the severity.
6690Sstevel@tonic-gate 			 */
6700Sstevel@tonic-gate 			if (cp2 = strchr(&cp[7], ':')) {
6710Sstevel@tonic-gate 			    savec = *cp2;
6720Sstevel@tonic-gate 			    *cp2 = '\0';
6730Sstevel@tonic-gate 			    cp2++;
6740Sstevel@tonic-gate 			}
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 			/*
6770Sstevel@tonic-gate 			 * Match a severity.
6780Sstevel@tonic-gate 			 */
6790Sstevel@tonic-gate 			if (!strcasecmp(&cp[7], "ERR")) {
6800Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity = LOG_ERR;
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "EMERG")) {
6830Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity =
6840Sstevel@tonic-gate 				LOG_EMERG;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "ALERT")) {
6870Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity =
6880Sstevel@tonic-gate 				LOG_ALERT;
6890Sstevel@tonic-gate 			}
6900Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "CRIT")) {
6910Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity = LOG_CRIT;
6920Sstevel@tonic-gate 			}
6930Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "WARNING")) {
6940Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity =
6950Sstevel@tonic-gate 				LOG_WARNING;
6960Sstevel@tonic-gate 			}
6970Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "NOTICE")) {
6980Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity =
6990Sstevel@tonic-gate 				LOG_NOTICE;
7000Sstevel@tonic-gate 			}
7010Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "INFO")) {
7020Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity = LOG_INFO;
7030Sstevel@tonic-gate 			}
7040Sstevel@tonic-gate 			else if (!strcasecmp(&cp[7], "DEBUG")) {
7050Sstevel@tonic-gate 			    log_control.log_entries[i].lsu_severity =
7060Sstevel@tonic-gate 				LOG_DEBUG;
7070Sstevel@tonic-gate 			}
7080Sstevel@tonic-gate 			else
7090Sstevel@tonic-gate 			    error = 1;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 			/*
7120Sstevel@tonic-gate 			 * If there is a facility present, then parse that.
7130Sstevel@tonic-gate 			 */
7140Sstevel@tonic-gate 			if (cp2) {
7150Sstevel@tonic-gate 			    if (!strcasecmp(cp2, "AUTH")) {
7160Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_AUTH;
7170Sstevel@tonic-gate 			    }
7180Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "KERN")) {
7190Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_KERN;
7200Sstevel@tonic-gate 			    }
7210Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "USER")) {
7220Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_USER;
7230Sstevel@tonic-gate 			    }
7240Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "MAIL")) {
7250Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_MAIL;
7260Sstevel@tonic-gate 			    }
7270Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "DAEMON")) {
7280Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_DAEMON;
7290Sstevel@tonic-gate 			    }
7300Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LPR")) {
7310Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LPR;
7320Sstevel@tonic-gate 			    }
7330Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "NEWS")) {
7340Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_NEWS;
7350Sstevel@tonic-gate 			    }
7360Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "UUCP")) {
7370Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_UUCP;
7380Sstevel@tonic-gate 			    }
7390Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "CRON")) {
7400Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_CRON;
7410Sstevel@tonic-gate 			    }
7420Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL0")) {
7430Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL0;
7440Sstevel@tonic-gate 			    }
7450Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL1")) {
7460Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL1;
7470Sstevel@tonic-gate 			    }
7480Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL2")) {
7490Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL2;
7500Sstevel@tonic-gate 			    }
7510Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL3")) {
7520Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL3;
7530Sstevel@tonic-gate 			    }
7540Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL4")) {
7550Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL4;
7560Sstevel@tonic-gate 			    }
7570Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL5")) {
7580Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL5;
7590Sstevel@tonic-gate 			    }
7600Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL6")) {
7610Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL6;
7620Sstevel@tonic-gate 			    }
7630Sstevel@tonic-gate 			    else if (!strcasecmp(cp2, "LOCAL7")) {
7640Sstevel@tonic-gate 				log_control.log_entries[i].lsu_facility = LOG_LOCAL7;
7650Sstevel@tonic-gate 			    }
7660Sstevel@tonic-gate 			    cp2--;
7670Sstevel@tonic-gate 			    *cp2 = savec;
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 		    }
7700Sstevel@tonic-gate 		    if (!error) {
7710Sstevel@tonic-gate 			log_control.log_entries[i].log_type = K_LOG_SYSLOG;
7720Sstevel@tonic-gate 			do_openlog = 1;
7730Sstevel@tonic-gate 			log_facility = log_control.log_entries[i].lsu_facility;
7740Sstevel@tonic-gate 		    }
7750Sstevel@tonic-gate 		}
7760Sstevel@tonic-gate 		/*
7770Sstevel@tonic-gate 		 * Is this a standard error specification?
7780Sstevel@tonic-gate 		 */
7790Sstevel@tonic-gate 		else if (!strcasecmp(cp, "STDERR")) {
7800Sstevel@tonic-gate 		    if (log_control.log_entries[i].lfu_filep =
7811914Scasper 			fdopen(fileno(stderr), "a+F")) {
7820Sstevel@tonic-gate 			log_control.log_entries[i].log_type = K_LOG_STDERR;
7830Sstevel@tonic-gate 			log_control.log_entries[i].lfu_fname =
7840Sstevel@tonic-gate 			    "standard error";
7850Sstevel@tonic-gate 		    }
7860Sstevel@tonic-gate 		}
7870Sstevel@tonic-gate 		/*
7880Sstevel@tonic-gate 		 * Is this a specification of the console?
7890Sstevel@tonic-gate 		 */
7900Sstevel@tonic-gate 		else if (!strcasecmp(cp, "CONSOLE")) {
7910Sstevel@tonic-gate 		    if (log_control.log_entries[i].ldu_filep =
7921914Scasper 			CONSOLE_OPEN("a+F")) {
7930Sstevel@tonic-gate 			log_control.log_entries[i].log_type = K_LOG_CONSOLE;
7940Sstevel@tonic-gate 			log_control.log_entries[i].ldu_devname = "console";
7950Sstevel@tonic-gate 		    }
7960Sstevel@tonic-gate 		}
7970Sstevel@tonic-gate 		/*
7980Sstevel@tonic-gate 		 * Is this a specification of a device?
7990Sstevel@tonic-gate 		 */
8000Sstevel@tonic-gate 		else if (!strncasecmp(cp, "DEVICE", 6)) {
8010Sstevel@tonic-gate 		    /*
8020Sstevel@tonic-gate 		     * We handle devices very similarly to files.
8030Sstevel@tonic-gate 		     */
8040Sstevel@tonic-gate 		    if (cp[6] == '=') {
8050Sstevel@tonic-gate 			if (log_control.log_entries[i].ldu_filep =
8061914Scasper 			    DEVICE_OPEN(&cp[7], "wF")) {
8070Sstevel@tonic-gate 			    log_control.log_entries[i].log_type = K_LOG_DEVICE;
8080Sstevel@tonic-gate 			    log_control.log_entries[i].ldu_devname = &cp[7];
8090Sstevel@tonic-gate 			}
8100Sstevel@tonic-gate 		    }
8110Sstevel@tonic-gate 		}
8120Sstevel@tonic-gate 		/*
8130Sstevel@tonic-gate 		 * See if we successfully parsed this specification.
8140Sstevel@tonic-gate 		 */
8150Sstevel@tonic-gate 		if (log_control.log_entries[i].log_type == K_LOG_NONE) {
8160Sstevel@tonic-gate 		    fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_1), whoami, cp);
8170Sstevel@tonic-gate 		    fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_2), whoami);
8180Sstevel@tonic-gate 		}
8190Sstevel@tonic-gate 		else
8200Sstevel@tonic-gate 		    ngood++;
8210Sstevel@tonic-gate 	    }
8220Sstevel@tonic-gate 	}
8230Sstevel@tonic-gate 	/*
8240Sstevel@tonic-gate 	 * If we didn't find anything, then free our lists.
8250Sstevel@tonic-gate 	 */
8260Sstevel@tonic-gate 	if (ngood == 0) {
8270Sstevel@tonic-gate 	    for (i=0; i<log_control.log_nentries; i++)
8280Sstevel@tonic-gate 		free(logging_specs[i]);
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 	free(logging_specs);
8310Sstevel@tonic-gate     }
8320Sstevel@tonic-gate     /*
8330Sstevel@tonic-gate      * If we didn't find anything, go for the default which is to log to
8340Sstevel@tonic-gate      * the system log.
8350Sstevel@tonic-gate      */
8360Sstevel@tonic-gate     if (ngood == 0) {
8370Sstevel@tonic-gate 	if (log_control.log_entries)
8380Sstevel@tonic-gate 	    free(log_control.log_entries);
8390Sstevel@tonic-gate 	log_control.log_entries = &def_log_entry;
8400Sstevel@tonic-gate 	log_control.log_entries->log_type = K_LOG_SYSLOG;
8410Sstevel@tonic-gate 	log_control.log_entries->log_2free = (krb5_pointer) NULL;
8420Sstevel@tonic-gate 	log_facility = log_control.log_entries->lsu_facility = LOG_AUTH;
8430Sstevel@tonic-gate 	log_control.log_entries->lsu_severity = LOG_ERR;
8440Sstevel@tonic-gate 	do_openlog = 1;
8450Sstevel@tonic-gate 	log_control.log_nentries = 1;
8460Sstevel@tonic-gate     }
8470Sstevel@tonic-gate     if (log_control.log_nentries) {
8480Sstevel@tonic-gate 	if (log_control.log_whoami = (char *) malloc(strlen(whoami)+1))
8490Sstevel@tonic-gate 	    strcpy(log_control.log_whoami, whoami);
8500Sstevel@tonic-gate 	if (log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN))
8510Sstevel@tonic-gate 	    gethostname(log_control.log_hostname, MAXHOSTNAMELEN);
8520Sstevel@tonic-gate 	if (do_openlog) {
8530Sstevel@tonic-gate 	    openlog(whoami, LOG_NDELAY|LOG_PID, log_facility);
8540Sstevel@tonic-gate 	    log_control.log_opened = 1;
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 	if (do_com_err)
8570Sstevel@tonic-gate 	    (void) set_com_err_hook(klog_com_err_proc);
8580Sstevel@tonic-gate     }
8590Sstevel@tonic-gate     return((log_control.log_nentries) ? 0 : ENOENT);
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * krb5_klog_close()	- Close the logging context and free all data.
8640Sstevel@tonic-gate  */
8650Sstevel@tonic-gate void
8660Sstevel@tonic-gate krb5_klog_close(kcontext)
8670Sstevel@tonic-gate     krb5_context	kcontext;
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate     int lindex;
8700Sstevel@tonic-gate     (void) reset_com_err_hook();
8710Sstevel@tonic-gate     for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
8720Sstevel@tonic-gate 	switch (log_control.log_entries[lindex].log_type) {
8730Sstevel@tonic-gate 	case K_LOG_FILE:
8740Sstevel@tonic-gate 	case K_LOG_STDERR:
8750Sstevel@tonic-gate 	    /*
8760Sstevel@tonic-gate 	     * Files/standard error.
8770Sstevel@tonic-gate 	     */
8780Sstevel@tonic-gate 	    fclose(log_control.log_entries[lindex].lfu_filep);
8790Sstevel@tonic-gate 	    break;
8800Sstevel@tonic-gate 	case K_LOG_CONSOLE:
8810Sstevel@tonic-gate 	case K_LOG_DEVICE:
8820Sstevel@tonic-gate 	    /*
8830Sstevel@tonic-gate 	     * Devices (may need special handling)
8840Sstevel@tonic-gate 	     */
8850Sstevel@tonic-gate 	    DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep);
8860Sstevel@tonic-gate 	    break;
8870Sstevel@tonic-gate 	case K_LOG_SYSLOG:
8880Sstevel@tonic-gate 	    /*
8890Sstevel@tonic-gate 	     * System log.
8900Sstevel@tonic-gate 	     */
8910Sstevel@tonic-gate 	    break;
8920Sstevel@tonic-gate 	default:
8930Sstevel@tonic-gate 	    break;
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 	if (log_control.log_entries[lindex].log_2free)
8960Sstevel@tonic-gate 	    free(log_control.log_entries[lindex].log_2free);
8970Sstevel@tonic-gate     }
8980Sstevel@tonic-gate     if (log_control.log_entries != &def_log_entry)
8990Sstevel@tonic-gate 	free(log_control.log_entries);
9000Sstevel@tonic-gate     log_control.log_entries = (struct log_entry *) NULL;
9010Sstevel@tonic-gate     log_control.log_nentries = 0;
9020Sstevel@tonic-gate     if (log_control.log_whoami)
9030Sstevel@tonic-gate 	free(log_control.log_whoami);
9040Sstevel@tonic-gate     log_control.log_whoami = (char *) NULL;
9050Sstevel@tonic-gate     if (log_control.log_hostname)
9060Sstevel@tonic-gate 	free(log_control.log_hostname);
9070Sstevel@tonic-gate     log_control.log_hostname = (char *) NULL;
9080Sstevel@tonic-gate     if (log_control.log_opened)
9090Sstevel@tonic-gate 	closelog();
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate  * severity2string()	- Convert a severity to a string.
9140Sstevel@tonic-gate  */
9150Sstevel@tonic-gate static char *
9160Sstevel@tonic-gate severity2string(severity)
9170Sstevel@tonic-gate     int	severity;
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate     int s;
9200Sstevel@tonic-gate     const char *ss;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate     s = severity & LOG_PRIMASK;
9230Sstevel@tonic-gate     ss = krb5_log_error_table(LOG_UFO_STRING);
9240Sstevel@tonic-gate     switch (s) {
9250Sstevel@tonic-gate     case LOG_EMERG:
9260Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_EMERG_STRING);
9270Sstevel@tonic-gate 	break;
9280Sstevel@tonic-gate     case LOG_ALERT:
9290Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_ALERT_STRING);
9300Sstevel@tonic-gate 	break;
9310Sstevel@tonic-gate     case LOG_CRIT:
9320Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_CRIT_STRING);
9330Sstevel@tonic-gate 	break;
9340Sstevel@tonic-gate     case LOG_ERR:
9350Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_ERR_STRING);
9360Sstevel@tonic-gate 	break;
9370Sstevel@tonic-gate     case LOG_WARNING:
9380Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_WARNING_STRING);
9390Sstevel@tonic-gate 	break;
9400Sstevel@tonic-gate     case LOG_NOTICE:
9410Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_NOTICE_STRING);
9420Sstevel@tonic-gate 	break;
9430Sstevel@tonic-gate     case LOG_INFO:
9440Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_INFO_STRING);
9450Sstevel@tonic-gate 	break;
9460Sstevel@tonic-gate     case LOG_DEBUG:
9470Sstevel@tonic-gate 	ss = krb5_log_error_table(LOG_DEBUG_STRING);
9480Sstevel@tonic-gate 	break;
9490Sstevel@tonic-gate     }
9500Sstevel@tonic-gate     return((char *) ss);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate  * krb5_klog_syslog()	- Simulate the calling sequence of syslog(3), while
9550Sstevel@tonic-gate  *			  also performing the logging redirection as specified
9560Sstevel@tonic-gate  *			  by krb5_klog_init().
9570Sstevel@tonic-gate  */
9580Sstevel@tonic-gate static int
9590Sstevel@tonic-gate klog_vsyslog(priority, format, arglist)
9600Sstevel@tonic-gate     int		priority;
9610Sstevel@tonic-gate     const char	*format;
9620Sstevel@tonic-gate     va_list	arglist;
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate     char	outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
9650Sstevel@tonic-gate     int		lindex;
9660Sstevel@tonic-gate     char	*syslogp;
9670Sstevel@tonic-gate     char	*cp;
9680Sstevel@tonic-gate     time_t	now;
9690Sstevel@tonic-gate     size_t	soff;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate     /*
9720Sstevel@tonic-gate      * Format a syslog-esque message of the format:
9730Sstevel@tonic-gate      *
9740Sstevel@tonic-gate      * (verbose form)
9750Sstevel@tonic-gate      * 		<date> <hostname> <id>[<pid>](<priority>): <message>
9760Sstevel@tonic-gate      *
9770Sstevel@tonic-gate      * (short form)
9780Sstevel@tonic-gate      *		<date> <message>
9790Sstevel@tonic-gate      */
9800Sstevel@tonic-gate     cp = outbuf;
9810Sstevel@tonic-gate     (void) time(&now);
9820Sstevel@tonic-gate     /*
9830Sstevel@tonic-gate      * Format the date: mon dd hh:mm:ss
9840Sstevel@tonic-gate      */
9850Sstevel@tonic-gate     soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now));
9860Sstevel@tonic-gate     if (soff > 0)
9870Sstevel@tonic-gate 	cp += soff;
9880Sstevel@tonic-gate     else
9890Sstevel@tonic-gate 	return(-1);
9900Sstevel@tonic-gate #ifdef VERBOSE_LOGS
9910Sstevel@tonic-gate     sprintf(cp, " %s %s[%ld](%s): ",
9920Sstevel@tonic-gate 	    log_control.log_hostname, log_control.log_whoami, (long) getpid(),
9930Sstevel@tonic-gate 	    severity2string(priority));
9940Sstevel@tonic-gate #else
9950Sstevel@tonic-gate     sprintf(cp, " ");
9960Sstevel@tonic-gate #endif
9970Sstevel@tonic-gate     syslogp = &outbuf[strlen(outbuf)];
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate     /* Now format the actual message */
1000*3998Ssemery     vsnprintf(syslogp, sizeof (outbuf) - (syslogp - outbuf), format, arglist);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate     /*
10030Sstevel@tonic-gate      * Now that we have the message formatted, perform the output to each
10040Sstevel@tonic-gate      * logging specification.
10050Sstevel@tonic-gate      */
10060Sstevel@tonic-gate     for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
10070Sstevel@tonic-gate 	switch (log_control.log_entries[lindex].log_type) {
10080Sstevel@tonic-gate 	case K_LOG_FILE:
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	    klog_rotate(&log_control.log_entries[lindex]);
10110Sstevel@tonic-gate 	    /*FALLTHRU*/
10120Sstevel@tonic-gate 	case K_LOG_STDERR:
10130Sstevel@tonic-gate 	    /*
10140Sstevel@tonic-gate 	     * Files/standard error.
10150Sstevel@tonic-gate 	     */
10160Sstevel@tonic-gate 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n",
10170Sstevel@tonic-gate 			outbuf) < 0) {
10180Sstevel@tonic-gate 		/* Attempt to report error */
10190Sstevel@tonic-gate 		fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR),
10200Sstevel@tonic-gate 			log_control.log_whoami,
10210Sstevel@tonic-gate 			log_control.log_entries[lindex].lfu_fname);
10220Sstevel@tonic-gate 	    }
10230Sstevel@tonic-gate 	    else {
10240Sstevel@tonic-gate 		fflush(log_control.log_entries[lindex].lfu_filep);
10250Sstevel@tonic-gate 	    }
10260Sstevel@tonic-gate 	    break;
10270Sstevel@tonic-gate 	case K_LOG_CONSOLE:
10280Sstevel@tonic-gate 	case K_LOG_DEVICE:
10290Sstevel@tonic-gate 	    /*
10300Sstevel@tonic-gate 	     * Devices (may need special handling)
10310Sstevel@tonic-gate 	     */
10320Sstevel@tonic-gate 	    if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
10330Sstevel@tonic-gate 			     outbuf) < 0) {
10340Sstevel@tonic-gate 		/* Attempt to report error */
10350Sstevel@tonic-gate 		fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR),
10360Sstevel@tonic-gate 			log_control.log_whoami,
10370Sstevel@tonic-gate 			log_control.log_entries[lindex].ldu_devname);
10380Sstevel@tonic-gate 	    }
10390Sstevel@tonic-gate 	    break;
10400Sstevel@tonic-gate 	case K_LOG_SYSLOG:
10410Sstevel@tonic-gate 	    /*
10420Sstevel@tonic-gate 	     * System log.
10430Sstevel@tonic-gate 	     */
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	    /* Log the message with our header trimmed off */
10460Sstevel@tonic-gate 	    syslog(priority, "%s", syslogp);
10470Sstevel@tonic-gate 	    break;
10480Sstevel@tonic-gate 	default:
10490Sstevel@tonic-gate 	    break;
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate     }
10520Sstevel@tonic-gate     return(0);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate int
10560Sstevel@tonic-gate krb5_klog_syslog(int priority, const char *format, ...)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate     int		retval;
10590Sstevel@tonic-gate     va_list	pvar;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate     va_start(pvar, format);
10620Sstevel@tonic-gate     retval = klog_vsyslog(priority, format, pvar);
10630Sstevel@tonic-gate     va_end(pvar);
10640Sstevel@tonic-gate     return(retval);
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate /*
10680Sstevel@tonic-gate  * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files.
10690Sstevel@tonic-gate  *                      This function is called when a SIGHUP is received
10700Sstevel@tonic-gate  *                      so that external log-archival utilities may
10710Sstevel@tonic-gate  *                      alert the Kerberos daemons that they should get
10720Sstevel@tonic-gate  *                      a new file descriptor for the give filename.
10730Sstevel@tonic-gate  */
10740Sstevel@tonic-gate void
10750Sstevel@tonic-gate krb5_klog_reopen(kcontext)
10760Sstevel@tonic-gate krb5_context kcontext;
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate     int lindex;
10790Sstevel@tonic-gate     FILE *f;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate     /*
10820Sstevel@tonic-gate      * Only logs which are actually files need to be closed
10830Sstevel@tonic-gate      * and reopened in response to a SIGHUP
10840Sstevel@tonic-gate      */
10850Sstevel@tonic-gate     for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
10860Sstevel@tonic-gate 	if (log_control.log_entries[lindex].log_type == K_LOG_FILE) {
10870Sstevel@tonic-gate 	    fclose(log_control.log_entries[lindex].lfu_filep);
10880Sstevel@tonic-gate 	    /*
10890Sstevel@tonic-gate 	     * In case the old logfile did not get moved out of the
10900Sstevel@tonic-gate 	     * way, open for append to prevent squashing the old logs.
10910Sstevel@tonic-gate 	     */
10921914Scasper 	    f = fopen(log_control.log_entries[lindex].lfu_fname, "a+F");
10930Sstevel@tonic-gate 	    if (f) {
10940Sstevel@tonic-gate 		log_control.log_entries[lindex].lfu_filep = f;
10950Sstevel@tonic-gate 	    } else {
10960Sstevel@tonic-gate 		fprintf(stderr, "Couldn't open log file %s: %s\n",
10970Sstevel@tonic-gate 			log_control.log_entries[lindex].lfu_fname,
10980Sstevel@tonic-gate 			error_message(errno));
10990Sstevel@tonic-gate 	    }
11000Sstevel@tonic-gate 	}
11010Sstevel@tonic-gate     }
11020Sstevel@tonic-gate }
1103