1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*0Sstevel@tonic-gate /* 8*0Sstevel@tonic-gate * lib/kadm/logger.c 9*0Sstevel@tonic-gate * 10*0Sstevel@tonic-gate * Copyright 1995 by the Massachusetts Institute of Technology. 11*0Sstevel@tonic-gate * All Rights Reserved. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * Export of this software from the United States of America may 14*0Sstevel@tonic-gate * require a specific license from the United States Government. 15*0Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 16*0Sstevel@tonic-gate * export to obtain such a license before exporting. 17*0Sstevel@tonic-gate * 18*0Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19*0Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 20*0Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 21*0Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 22*0Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 23*0Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 24*0Sstevel@tonic-gate * to distribution of the software without specific, written prior 25*0Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 26*0Sstevel@tonic-gate * your software as modified software and not distribute it in such a 27*0Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 28*0Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 29*0Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 30*0Sstevel@tonic-gate * or implied warranty. 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate /* KADM5 wants non-syslog log files to contain syslog-like entries */ 36*0Sstevel@tonic-gate #define VERBOSE_LOGS 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* 39*0Sstevel@tonic-gate * logger.c - Handle logging functions for those who want it. 40*0Sstevel@tonic-gate */ 41*0Sstevel@tonic-gate #include "k5-int.h" 42*0Sstevel@tonic-gate #include "adm_proto.h" 43*0Sstevel@tonic-gate #include "com_err.h" 44*0Sstevel@tonic-gate #include <stdio.h> 45*0Sstevel@tonic-gate #include <ctype.h> 46*0Sstevel@tonic-gate #include <ctype.h> 47*0Sstevel@tonic-gate #include <syslog.h> 48*0Sstevel@tonic-gate #include <stdarg.h> 49*0Sstevel@tonic-gate #include <libintl.h> 50*0Sstevel@tonic-gate #include <sys/types.h> 51*0Sstevel@tonic-gate #include <sys/stat.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #define KRB5_KLOG_MAX_ERRMSG_SIZE 1024 54*0Sstevel@tonic-gate #ifndef MAXHOSTNAMELEN 55*0Sstevel@tonic-gate #define MAXHOSTNAMELEN 256 56*0Sstevel@tonic-gate #endif /* MAXHOSTNAMELEN */ 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #define LSPEC_PARSE_ERR_1 1 59*0Sstevel@tonic-gate #define LSPEC_PARSE_ERR_2 2 60*0Sstevel@tonic-gate #define LOG_FILE_ERR 3 61*0Sstevel@tonic-gate #define LOG_DEVICE_ERR 4 62*0Sstevel@tonic-gate #define LOG_UFO_STRING 5 63*0Sstevel@tonic-gate #define LOG_EMERG_STRING 6 64*0Sstevel@tonic-gate #define LOG_ALERT_STRING 7 65*0Sstevel@tonic-gate #define LOG_CRIT_STRING 8 66*0Sstevel@tonic-gate #define LOG_ERR_STRING 9 67*0Sstevel@tonic-gate #define LOG_WARNING_STRING 10 68*0Sstevel@tonic-gate #define LOG_NOTICE_STRING 11 69*0Sstevel@tonic-gate #define LOG_INFO_STRING 12 70*0Sstevel@tonic-gate #define LOG_DEBUG_STRING 13 71*0Sstevel@tonic-gate /* This is to assure that we have at least one match in the syslog stuff */ 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate static const char LSPEC_PARSE_ERR_1[] = "%s: cannot parse <%s>\n"; 74*0Sstevel@tonic-gate static const char LSPEC_PARSE_ERR_2[] = "%s: warning - logging entry syntax error\n"; 75*0Sstevel@tonic-gate static const char LOG_FILE_ERR[] = "%s: error writing to %s\n"; 76*0Sstevel@tonic-gate static const char LOG_DEVICE_ERR[] = "%s: error writing to %s device\n"; 77*0Sstevel@tonic-gate static const char LOG_UFO_STRING[] = "???"; 78*0Sstevel@tonic-gate static const char LOG_EMERG_STRING[] = "EMERGENCY"; 79*0Sstevel@tonic-gate static const char LOG_ALERT_STRING[] = "ALERT"; 80*0Sstevel@tonic-gate static const char LOG_CRIT_STRING[] = "CRITICAL"; 81*0Sstevel@tonic-gate static const char LOG_ERR_STRING[] = "Error"; 82*0Sstevel@tonic-gate static const char LOG_WARNING_STRING[] = "Warning"; 83*0Sstevel@tonic-gate static const char LOG_NOTICE_STRING[] = "Notice"; 84*0Sstevel@tonic-gate static const char LOG_INFO_STRING[] = "info"; 85*0Sstevel@tonic-gate static const char LOG_DEBUG_STRING[] = "debug"; 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate const char * 90*0Sstevel@tonic-gate krb5_log_error_table(long errorno) { 91*0Sstevel@tonic-gate switch (errorno) { 92*0Sstevel@tonic-gate case LSPEC_PARSE_ERR_1: 93*0Sstevel@tonic-gate return(gettext("%s: cannot parse <%s>\n")); 94*0Sstevel@tonic-gate case LSPEC_PARSE_ERR_2: 95*0Sstevel@tonic-gate return(gettext("%s: warning - logging entry syntax error\n")); 96*0Sstevel@tonic-gate case LOG_FILE_ERR: 97*0Sstevel@tonic-gate return(gettext("%s: error writing to %s\n")); 98*0Sstevel@tonic-gate case LOG_DEVICE_ERR: 99*0Sstevel@tonic-gate return(gettext("%s: error writing to %s device\n")); 100*0Sstevel@tonic-gate case LOG_UFO_STRING: 101*0Sstevel@tonic-gate return(gettext("???")); 102*0Sstevel@tonic-gate case LOG_EMERG_STRING: 103*0Sstevel@tonic-gate return(gettext("EMERGENCY")); 104*0Sstevel@tonic-gate case LOG_ALERT_STRING: 105*0Sstevel@tonic-gate return(gettext("ALERT")); 106*0Sstevel@tonic-gate case LOG_CRIT_STRING: 107*0Sstevel@tonic-gate return(gettext("CRITICAL")); 108*0Sstevel@tonic-gate case LOG_ERR_STRING: 109*0Sstevel@tonic-gate return(gettext("Error")); 110*0Sstevel@tonic-gate case LOG_WARNING_STRING: 111*0Sstevel@tonic-gate return(gettext("Warning")); 112*0Sstevel@tonic-gate case LOG_NOTICE_STRING: 113*0Sstevel@tonic-gate return(gettext("Notice")); 114*0Sstevel@tonic-gate case LOG_INFO_STRING: 115*0Sstevel@tonic-gate return(gettext("info")); 116*0Sstevel@tonic-gate case LOG_DEBUG_STRING: 117*0Sstevel@tonic-gate return(gettext("info")); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * Output logging. 123*0Sstevel@tonic-gate * 124*0Sstevel@tonic-gate * Output logging is now controlled by the configuration file. We can specify 125*0Sstevel@tonic-gate * the following syntaxes under the [logging]->entity specification. 126*0Sstevel@tonic-gate * FILE<opentype><pathname> 127*0Sstevel@tonic-gate * SYSLOG[=<severity>[:<facility>]] 128*0Sstevel@tonic-gate * STDERR 129*0Sstevel@tonic-gate * CONSOLE 130*0Sstevel@tonic-gate * DEVICE=<device-spec> 131*0Sstevel@tonic-gate * 132*0Sstevel@tonic-gate * Where: 133*0Sstevel@tonic-gate * <opentype> is ":" for open/append, "=" for open/create. 134*0Sstevel@tonic-gate * <pathname> is a valid path name. 135*0Sstevel@tonic-gate * <severity> is one of: (default = ERR) 136*0Sstevel@tonic-gate * EMERG 137*0Sstevel@tonic-gate * ALERT 138*0Sstevel@tonic-gate * CRIT 139*0Sstevel@tonic-gate * ERR 140*0Sstevel@tonic-gate * WARNING 141*0Sstevel@tonic-gate * NOTICE 142*0Sstevel@tonic-gate * INFO 143*0Sstevel@tonic-gate * DEBUG 144*0Sstevel@tonic-gate * <facility> is one of: (default = AUTH) 145*0Sstevel@tonic-gate * KERN 146*0Sstevel@tonic-gate * USER 147*0Sstevel@tonic-gate * MAIL 148*0Sstevel@tonic-gate * DAEMON 149*0Sstevel@tonic-gate * AUTH 150*0Sstevel@tonic-gate * LPR 151*0Sstevel@tonic-gate * NEWS 152*0Sstevel@tonic-gate * UUCP 153*0Sstevel@tonic-gate * CRON 154*0Sstevel@tonic-gate * LOCAL0..LOCAL7 155*0Sstevel@tonic-gate * <device-spec> is a valid device specification. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate struct log_entry { 158*0Sstevel@tonic-gate enum log_type { K_LOG_FILE, 159*0Sstevel@tonic-gate K_LOG_SYSLOG, 160*0Sstevel@tonic-gate K_LOG_STDERR, 161*0Sstevel@tonic-gate K_LOG_CONSOLE, 162*0Sstevel@tonic-gate K_LOG_DEVICE, 163*0Sstevel@tonic-gate K_LOG_NONE } log_type; 164*0Sstevel@tonic-gate krb5_pointer log_2free; 165*0Sstevel@tonic-gate union log_union { 166*0Sstevel@tonic-gate struct log_file { 167*0Sstevel@tonic-gate FILE *lf_filep; 168*0Sstevel@tonic-gate char *lf_fname; 169*0Sstevel@tonic-gate char *lf_fopen_mode; /* "a+" or "w" */ 170*0Sstevel@tonic-gate #define K_LOG_DEF_FILE_ROTATE_PERIOD -1 /* never */ 171*0Sstevel@tonic-gate #define K_LOG_DEF_FILE_ROTATE_VERSIONS 0 /* no versions */ 172*0Sstevel@tonic-gate time_t lf_rotate_period; 173*0Sstevel@tonic-gate time_t lf_last_rotated; 174*0Sstevel@tonic-gate int lf_rotate_versions; 175*0Sstevel@tonic-gate } log_file; 176*0Sstevel@tonic-gate struct log_syslog { 177*0Sstevel@tonic-gate int ls_facility; 178*0Sstevel@tonic-gate int ls_severity; 179*0Sstevel@tonic-gate } log_syslog; 180*0Sstevel@tonic-gate struct log_device { 181*0Sstevel@tonic-gate FILE *ld_filep; 182*0Sstevel@tonic-gate char *ld_devname; 183*0Sstevel@tonic-gate } log_device; 184*0Sstevel@tonic-gate } log_union; 185*0Sstevel@tonic-gate }; 186*0Sstevel@tonic-gate #define lfu_filep log_union.log_file.lf_filep 187*0Sstevel@tonic-gate #define lfu_fname log_union.log_file.lf_fname 188*0Sstevel@tonic-gate #define lfu_fopen_mode log_union.log_file.lf_fopen_mode 189*0Sstevel@tonic-gate #define lfu_rotate_period log_union.log_file.lf_rotate_period 190*0Sstevel@tonic-gate #define lfu_last_rotated log_union.log_file.lf_last_rotated 191*0Sstevel@tonic-gate #define lfu_rotate_versions log_union.log_file.lf_rotate_versions 192*0Sstevel@tonic-gate #define lsu_facility log_union.log_syslog.ls_facility 193*0Sstevel@tonic-gate #define lsu_severity log_union.log_syslog.ls_severity 194*0Sstevel@tonic-gate #define ldu_filep log_union.log_device.ld_filep 195*0Sstevel@tonic-gate #define ldu_devname log_union.log_device.ld_devname 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate struct log_control { 198*0Sstevel@tonic-gate struct log_entry *log_entries; 199*0Sstevel@tonic-gate int log_nentries; 200*0Sstevel@tonic-gate char *log_whoami; 201*0Sstevel@tonic-gate char *log_hostname; 202*0Sstevel@tonic-gate krb5_boolean log_opened; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate }; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate static struct log_control log_control = { 207*0Sstevel@tonic-gate (struct log_entry *) NULL, 208*0Sstevel@tonic-gate 0, 209*0Sstevel@tonic-gate (char *) NULL, 210*0Sstevel@tonic-gate (char *) NULL, 211*0Sstevel@tonic-gate 0 212*0Sstevel@tonic-gate }; 213*0Sstevel@tonic-gate static struct log_entry def_log_entry; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate /* 216*0Sstevel@tonic-gate * These macros define any special processing that needs to happen for 217*0Sstevel@tonic-gate * devices. For unix, of course, this is hardly anything. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate #define DEVICE_OPEN(d, m) fopen(d, m) 220*0Sstevel@tonic-gate #define CONSOLE_OPEN(m) fopen("/dev/console", m) 221*0Sstevel@tonic-gate #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \ 222*0Sstevel@tonic-gate (fflush(f), 0) : \ 223*0Sstevel@tonic-gate -1) 224*0Sstevel@tonic-gate #define DEVICE_CLOSE(d) fclose(d) 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* 228*0Sstevel@tonic-gate * klog_rotate() - roate a log file if we have specified rotation 229*0Sstevel@tonic-gate * parameters in krb5.conf. 230*0Sstevel@tonic-gate */ 231*0Sstevel@tonic-gate static void 232*0Sstevel@tonic-gate klog_rotate(struct log_entry *le) 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate time_t t; 235*0Sstevel@tonic-gate int i; 236*0Sstevel@tonic-gate char *name_buf1; 237*0Sstevel@tonic-gate char *name_buf2; 238*0Sstevel@tonic-gate char *old_name; 239*0Sstevel@tonic-gate char *new_name; 240*0Sstevel@tonic-gate char *tmp; 241*0Sstevel@tonic-gate FILE *fp; 242*0Sstevel@tonic-gate int num_vers; 243*0Sstevel@tonic-gate mode_t old_umask; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * By default we don't rotate. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate if (le->lfu_rotate_period == K_LOG_DEF_FILE_ROTATE_PERIOD) 250*0Sstevel@tonic-gate return; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate t = time(0); 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate if (t >= le->lfu_last_rotated + le->lfu_rotate_period) { 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * The N log file versions will be renamed X.N-1 X.N-2, ... X.0. 257*0Sstevel@tonic-gate * So the allocate file name buffers that can the version 258*0Sstevel@tonic-gate * number extensions. 259*0Sstevel@tonic-gate * 32 extra bytes is plenty. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate name_buf1 = malloc(strlen(le->lfu_fname) + 32); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate if (name_buf1 == NULL) 264*0Sstevel@tonic-gate return; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate name_buf2 = malloc(strlen(le->lfu_fname) + 32); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (name_buf2 == NULL) { 269*0Sstevel@tonic-gate free(name_buf1); 270*0Sstevel@tonic-gate return; 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate old_name = name_buf1; 274*0Sstevel@tonic-gate new_name = name_buf2; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * If there N versions, then the first one has file extension 278*0Sstevel@tonic-gate * of N-1. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate (void) sprintf(new_name, "%s.%d", le->lfu_fname, 281*0Sstevel@tonic-gate le->lfu_rotate_versions - 1); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* 284*0Sstevel@tonic-gate * Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ... 285*0Sstevel@tonic-gate * file.0 to file.1 286*0Sstevel@tonic-gate */ 287*0Sstevel@tonic-gate for (i = le->lfu_rotate_versions - 1; i > 0; i--) { 288*0Sstevel@tonic-gate (void) sprintf(old_name, "%s.%d", le->lfu_fname, i - 1); 289*0Sstevel@tonic-gate (void) rename(old_name, new_name); 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * swap old name and new name. This way, 293*0Sstevel@tonic-gate * on the next iteration, new_name.X 294*0Sstevel@tonic-gate * becomes new_name.X-1. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate tmp = old_name; 297*0Sstevel@tonic-gate old_name = new_name; 298*0Sstevel@tonic-gate new_name = tmp; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate old_name = le->lfu_fname; 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate (void) rename(old_name, new_name); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Even though we don't know yet if the fopen() 306*0Sstevel@tonic-gate * of the log file will succeed, we mark the log 307*0Sstevel@tonic-gate * as rotated. This is so we don't repeatably 308*0Sstevel@tonic-gate * rotate file.N-2 to file.N-1 ... etc without 309*0Sstevel@tonic-gate * waiting for the rotate period to elapse. 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate le->lfu_last_rotated = t; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate /* 314*0Sstevel@tonic-gate * Default log file creation mode should be read-only 315*0Sstevel@tonic-gate * by owner(root), but the admin can override with 316*0Sstevel@tonic-gate * chmod(1) if desired. 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate old_umask = umask(077); 320*0Sstevel@tonic-gate fp = fopen(old_name, le->lfu_fopen_mode); 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate umask(old_umask); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (fp != NULL) { 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate (void) fclose(le->lfu_filep); 327*0Sstevel@tonic-gate le->lfu_filep = fp; 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate /* 330*0Sstevel@tonic-gate * If the version parameter in krb5.conf was 331*0Sstevel@tonic-gate * 0, then we take this to mean that rotating the 332*0Sstevel@tonic-gate * log file will cause us to dispose of the 333*0Sstevel@tonic-gate * old one, and created a new one. We have just 334*0Sstevel@tonic-gate * renamed the old one to file.-1, so remove it. 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate if (le->lfu_rotate_versions <= 0) 337*0Sstevel@tonic-gate (void) unlink(new_name); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate } else { 340*0Sstevel@tonic-gate fprintf(stderr, 341*0Sstevel@tonic-gate gettext("During rotate, couldn't open log file %s: %s\n"), 342*0Sstevel@tonic-gate old_name, error_message(errno)); 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * Put it back. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate (void) rename(new_name, old_name); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate free(name_buf1); 349*0Sstevel@tonic-gate free(name_buf2); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * klog_com_err_proc() - Handle com_err(3) messages as specified by the 355*0Sstevel@tonic-gate * profile. 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate static void 358*0Sstevel@tonic-gate klog_com_err_proc(whoami, code, format, ap) 359*0Sstevel@tonic-gate const char *whoami; 360*0Sstevel@tonic-gate long code; 361*0Sstevel@tonic-gate const char *format; 362*0Sstevel@tonic-gate va_list ap; 363*0Sstevel@tonic-gate { 364*0Sstevel@tonic-gate char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; 365*0Sstevel@tonic-gate int lindex; 366*0Sstevel@tonic-gate char *actual_format; 367*0Sstevel@tonic-gate int log_pri = -1; 368*0Sstevel@tonic-gate char *cp; 369*0Sstevel@tonic-gate char *syslogp; 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate /* Make the header */ 372*0Sstevel@tonic-gate sprintf(outbuf, "%s: ", whoami); 373*0Sstevel@tonic-gate /* 374*0Sstevel@tonic-gate * Squirrel away address after header for syslog since syslog makes 375*0Sstevel@tonic-gate * a header 376*0Sstevel@tonic-gate */ 377*0Sstevel@tonic-gate syslogp = &outbuf[strlen(outbuf)]; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* If reporting an error message, separate it. */ 380*0Sstevel@tonic-gate if (code) { 381*0Sstevel@tonic-gate outbuf[sizeof(outbuf) - 1] = '\0'; 382*0Sstevel@tonic-gate strncat(outbuf, error_message(code), sizeof(outbuf) - 1 - strlen(outbuf)); 383*0Sstevel@tonic-gate strncat(outbuf, " - ", sizeof(outbuf) - 1 - strlen(outbuf)); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate cp = &outbuf[strlen(outbuf)]; 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate actual_format = (char *) format; 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * This is an unpleasant hack. If the first character is less than 390*0Sstevel@tonic-gate * 8, then we assume that it is a priority. 391*0Sstevel@tonic-gate * 392*0Sstevel@tonic-gate * Since it is not guaranteed that there is a direct mapping between 393*0Sstevel@tonic-gate * syslog priorities (e.g. Ultrix and old BSD), we resort to this 394*0Sstevel@tonic-gate * intermediate representation. 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) { 397*0Sstevel@tonic-gate actual_format = (char *) (format + 1); 398*0Sstevel@tonic-gate switch ((unsigned char) *format) { 399*0Sstevel@tonic-gate case 1: 400*0Sstevel@tonic-gate log_pri = LOG_EMERG; 401*0Sstevel@tonic-gate break; 402*0Sstevel@tonic-gate case 2: 403*0Sstevel@tonic-gate log_pri = LOG_ALERT; 404*0Sstevel@tonic-gate break; 405*0Sstevel@tonic-gate case 3: 406*0Sstevel@tonic-gate log_pri = LOG_CRIT; 407*0Sstevel@tonic-gate break; 408*0Sstevel@tonic-gate default: 409*0Sstevel@tonic-gate case 4: 410*0Sstevel@tonic-gate log_pri = LOG_ERR; 411*0Sstevel@tonic-gate break; 412*0Sstevel@tonic-gate case 5: 413*0Sstevel@tonic-gate log_pri = LOG_WARNING; 414*0Sstevel@tonic-gate break; 415*0Sstevel@tonic-gate case 6: 416*0Sstevel@tonic-gate log_pri = LOG_NOTICE; 417*0Sstevel@tonic-gate break; 418*0Sstevel@tonic-gate case 7: 419*0Sstevel@tonic-gate log_pri = LOG_INFO; 420*0Sstevel@tonic-gate break; 421*0Sstevel@tonic-gate case 8: 422*0Sstevel@tonic-gate log_pri = LOG_DEBUG; 423*0Sstevel@tonic-gate break; 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate /* Now format the actual message */ 428*0Sstevel@tonic-gate vsprintf(cp, actual_format, ap); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * Now that we have the message formatted, perform the output to each 432*0Sstevel@tonic-gate * logging specification. 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 435*0Sstevel@tonic-gate switch (log_control.log_entries[lindex].log_type) { 436*0Sstevel@tonic-gate case K_LOG_FILE: 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate klog_rotate(&log_control.log_entries[lindex]); 439*0Sstevel@tonic-gate /*FALLTHRU*/ 440*0Sstevel@tonic-gate case K_LOG_STDERR: 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Files/standard error. 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", 445*0Sstevel@tonic-gate outbuf) < 0) { 446*0Sstevel@tonic-gate /* Attempt to report error */ 447*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), whoami, 448*0Sstevel@tonic-gate log_control.log_entries[lindex].lfu_fname); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate else { 451*0Sstevel@tonic-gate fflush(log_control.log_entries[lindex].lfu_filep); 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate break; 454*0Sstevel@tonic-gate case K_LOG_CONSOLE: 455*0Sstevel@tonic-gate case K_LOG_DEVICE: 456*0Sstevel@tonic-gate /* 457*0Sstevel@tonic-gate * Devices (may need special handling) 458*0Sstevel@tonic-gate */ 459*0Sstevel@tonic-gate if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, 460*0Sstevel@tonic-gate outbuf) < 0) { 461*0Sstevel@tonic-gate /* Attempt to report error */ 462*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), whoami, 463*0Sstevel@tonic-gate log_control.log_entries[lindex].ldu_devname); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate break; 466*0Sstevel@tonic-gate case K_LOG_SYSLOG: 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * System log. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * If we have specified a priority through our hackery, then 472*0Sstevel@tonic-gate * use it, otherwise use the default. 473*0Sstevel@tonic-gate */ 474*0Sstevel@tonic-gate if (log_pri >= 0) 475*0Sstevel@tonic-gate log_pri |= log_control.log_entries[lindex].lsu_facility; 476*0Sstevel@tonic-gate else 477*0Sstevel@tonic-gate log_pri = log_control.log_entries[lindex].lsu_facility | 478*0Sstevel@tonic-gate log_control.log_entries[lindex].lsu_severity; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate /* Log the message with our header trimmed off */ 481*0Sstevel@tonic-gate syslog(log_pri, "%s", syslogp); 482*0Sstevel@tonic-gate break; 483*0Sstevel@tonic-gate default: 484*0Sstevel@tonic-gate break; 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * krb5_klog_init() - Initialize logging. 491*0Sstevel@tonic-gate * 492*0Sstevel@tonic-gate * This routine parses the syntax described above to specify destinations for 493*0Sstevel@tonic-gate * com_err(3) or krb5_klog_syslog() messages generated by the caller. 494*0Sstevel@tonic-gate * 495*0Sstevel@tonic-gate * Parameters: 496*0Sstevel@tonic-gate * kcontext - Kerberos context. 497*0Sstevel@tonic-gate * ename - Entity name as it is to appear in the profile. 498*0Sstevel@tonic-gate * whoami - Entity name as it is to appear in error output. 499*0Sstevel@tonic-gate * do_com_err - Take over com_err(3) processing. 500*0Sstevel@tonic-gate * 501*0Sstevel@tonic-gate * Implicit inputs: 502*0Sstevel@tonic-gate * stderr - This is where STDERR output goes. 503*0Sstevel@tonic-gate * 504*0Sstevel@tonic-gate * Implicit outputs: 505*0Sstevel@tonic-gate * log_nentries - Number of log entries, both valid and invalid. 506*0Sstevel@tonic-gate * log_control - List of entries (log_nentries long) which contains 507*0Sstevel@tonic-gate * data for klog_com_err_proc() to use to determine 508*0Sstevel@tonic-gate * where/how to send output. 509*0Sstevel@tonic-gate */ 510*0Sstevel@tonic-gate krb5_error_code 511*0Sstevel@tonic-gate krb5_klog_init(kcontext, ename, whoami, do_com_err) 512*0Sstevel@tonic-gate krb5_context kcontext; 513*0Sstevel@tonic-gate char *ename; 514*0Sstevel@tonic-gate char *whoami; 515*0Sstevel@tonic-gate krb5_boolean do_com_err; 516*0Sstevel@tonic-gate { 517*0Sstevel@tonic-gate const char *logging_profent[3]; 518*0Sstevel@tonic-gate const char *logging_defent[3]; 519*0Sstevel@tonic-gate char **logging_specs; 520*0Sstevel@tonic-gate int i, ngood; 521*0Sstevel@tonic-gate char *cp, *cp2; 522*0Sstevel@tonic-gate char savec; 523*0Sstevel@tonic-gate int error; 524*0Sstevel@tonic-gate int do_openlog, log_facility; 525*0Sstevel@tonic-gate FILE *f; 526*0Sstevel@tonic-gate mode_t old_umask; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate /* Initialize */ 529*0Sstevel@tonic-gate do_openlog = 0; 530*0Sstevel@tonic-gate log_facility = 0; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate /* 533*0Sstevel@tonic-gate * Look up [logging]-><ename> in the profile. If that doesn't 534*0Sstevel@tonic-gate * succeed, then look for [logging]->default. 535*0Sstevel@tonic-gate */ 536*0Sstevel@tonic-gate logging_profent[0] = "logging"; 537*0Sstevel@tonic-gate logging_profent[1] = ename; 538*0Sstevel@tonic-gate logging_profent[2] = (char *) NULL; 539*0Sstevel@tonic-gate logging_defent[0] = "logging"; 540*0Sstevel@tonic-gate logging_defent[1] = "default"; 541*0Sstevel@tonic-gate logging_defent[2] = (char *) NULL; 542*0Sstevel@tonic-gate logging_specs = (char **) NULL; 543*0Sstevel@tonic-gate ngood = 0; 544*0Sstevel@tonic-gate log_control.log_nentries = 0; 545*0Sstevel@tonic-gate if (!profile_get_values(kcontext->profile, 546*0Sstevel@tonic-gate logging_profent, 547*0Sstevel@tonic-gate &logging_specs) || 548*0Sstevel@tonic-gate !profile_get_values(kcontext->profile, 549*0Sstevel@tonic-gate logging_defent, 550*0Sstevel@tonic-gate &logging_specs)) { 551*0Sstevel@tonic-gate /* 552*0Sstevel@tonic-gate * We have a match, so we first count the number of elements 553*0Sstevel@tonic-gate */ 554*0Sstevel@tonic-gate for (log_control.log_nentries = 0; 555*0Sstevel@tonic-gate logging_specs[log_control.log_nentries]; 556*0Sstevel@tonic-gate log_control.log_nentries++); 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate /* 559*0Sstevel@tonic-gate * Now allocate our structure. 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate log_control.log_entries = (struct log_entry *) 562*0Sstevel@tonic-gate malloc(log_control.log_nentries * sizeof(struct log_entry)); 563*0Sstevel@tonic-gate if (log_control.log_entries) { 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * Scan through the list. 566*0Sstevel@tonic-gate */ 567*0Sstevel@tonic-gate for (i=0; i<log_control.log_nentries; i++) { 568*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_NONE; 569*0Sstevel@tonic-gate log_control.log_entries[i].log_2free = logging_specs[i]; 570*0Sstevel@tonic-gate /* 571*0Sstevel@tonic-gate * The format is: 572*0Sstevel@tonic-gate * <whitespace><data><whitespace> 573*0Sstevel@tonic-gate * so, trim off the leading and trailing whitespace here. 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate for (cp = logging_specs[i]; isspace(*cp); cp++); 576*0Sstevel@tonic-gate for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1]; 577*0Sstevel@tonic-gate isspace(*cp2); cp2--); 578*0Sstevel@tonic-gate cp2++; 579*0Sstevel@tonic-gate *cp2 = '\0'; 580*0Sstevel@tonic-gate /* 581*0Sstevel@tonic-gate * Is this a file? 582*0Sstevel@tonic-gate */ 583*0Sstevel@tonic-gate if (!strncasecmp(cp, "FILE", 4)) { 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * Check for append/overwrite, then open the file. 586*0Sstevel@tonic-gate */ 587*0Sstevel@tonic-gate if (cp[4] == ':' || cp[4] == '=') { 588*0Sstevel@tonic-gate log_control.log_entries[i].lfu_fopen_mode = 589*0Sstevel@tonic-gate (cp[4] == ':') ? "a+" : "w"; 590*0Sstevel@tonic-gate old_umask = umask(077); 591*0Sstevel@tonic-gate f = fopen(&cp[5], 592*0Sstevel@tonic-gate log_control.log_entries[i].lfu_fopen_mode); 593*0Sstevel@tonic-gate umask(old_umask); 594*0Sstevel@tonic-gate if (f) { 595*0Sstevel@tonic-gate char rotate_kw[128]; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate log_control.log_entries[i].lfu_filep = f; 598*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_FILE; 599*0Sstevel@tonic-gate log_control.log_entries[i].lfu_fname = &cp[5]; 600*0Sstevel@tonic-gate log_control.log_entries[i].lfu_rotate_period = 601*0Sstevel@tonic-gate K_LOG_DEF_FILE_ROTATE_PERIOD; 602*0Sstevel@tonic-gate log_control.log_entries[i].lfu_rotate_versions = 603*0Sstevel@tonic-gate K_LOG_DEF_FILE_ROTATE_VERSIONS; 604*0Sstevel@tonic-gate log_control.log_entries[i].lfu_last_rotated = 605*0Sstevel@tonic-gate time(0); 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate /* 608*0Sstevel@tonic-gate * Now parse for ename_"rotate" = { 609*0Sstevel@tonic-gate * period = XXX 610*0Sstevel@tonic-gate * versions = 10 611*0Sstevel@tonic-gate * } 612*0Sstevel@tonic-gate */ 613*0Sstevel@tonic-gate if (strlen(ename) + strlen("_rotate") < 614*0Sstevel@tonic-gate sizeof (rotate_kw)) { 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate char *time; 617*0Sstevel@tonic-gate krb5_deltat dt; 618*0Sstevel@tonic-gate int vers; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate strcpy(rotate_kw, ename); 621*0Sstevel@tonic-gate strcat(rotate_kw, "_rotate"); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate if (!profile_get_string(kcontext->profile, 624*0Sstevel@tonic-gate "logging", rotate_kw, "period", 625*0Sstevel@tonic-gate NULL, &time)) { 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate if (time != NULL) { 628*0Sstevel@tonic-gate if (!krb5_string_to_deltat(time, 629*0Sstevel@tonic-gate &dt)) { 630*0Sstevel@tonic-gate log_control.log_entries[i].lfu_rotate_period = 631*0Sstevel@tonic-gate (time_t) dt; 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate free(time); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate if (!profile_get_integer( 638*0Sstevel@tonic-gate kcontext->profile, "logging", 639*0Sstevel@tonic-gate rotate_kw, "versions", 640*0Sstevel@tonic-gate K_LOG_DEF_FILE_ROTATE_VERSIONS, 641*0Sstevel@tonic-gate &vers)) { 642*0Sstevel@tonic-gate log_control.log_entries[i].lfu_rotate_versions = vers; 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate } else { 647*0Sstevel@tonic-gate fprintf(stderr,gettext("Couldn't open log file %s: %s\n"), 648*0Sstevel@tonic-gate &cp[5], error_message(errno)); 649*0Sstevel@tonic-gate continue; 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate /* 654*0Sstevel@tonic-gate * Is this a syslog? 655*0Sstevel@tonic-gate */ 656*0Sstevel@tonic-gate else if (!strncasecmp(cp, "SYSLOG", 6)) { 657*0Sstevel@tonic-gate error = 0; 658*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_AUTH; 659*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = LOG_ERR; 660*0Sstevel@tonic-gate /* 661*0Sstevel@tonic-gate * Is there a severify specified? 662*0Sstevel@tonic-gate */ 663*0Sstevel@tonic-gate if (cp[6] == ':') { 664*0Sstevel@tonic-gate /* 665*0Sstevel@tonic-gate * Find the end of the severity. 666*0Sstevel@tonic-gate */ 667*0Sstevel@tonic-gate if (cp2 = strchr(&cp[7], ':')) { 668*0Sstevel@tonic-gate savec = *cp2; 669*0Sstevel@tonic-gate *cp2 = '\0'; 670*0Sstevel@tonic-gate cp2++; 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate /* 674*0Sstevel@tonic-gate * Match a severity. 675*0Sstevel@tonic-gate */ 676*0Sstevel@tonic-gate if (!strcasecmp(&cp[7], "ERR")) { 677*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = LOG_ERR; 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "EMERG")) { 680*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = 681*0Sstevel@tonic-gate LOG_EMERG; 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "ALERT")) { 684*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = 685*0Sstevel@tonic-gate LOG_ALERT; 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "CRIT")) { 688*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = LOG_CRIT; 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "WARNING")) { 691*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = 692*0Sstevel@tonic-gate LOG_WARNING; 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "NOTICE")) { 695*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = 696*0Sstevel@tonic-gate LOG_NOTICE; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "INFO")) { 699*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = LOG_INFO; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate else if (!strcasecmp(&cp[7], "DEBUG")) { 702*0Sstevel@tonic-gate log_control.log_entries[i].lsu_severity = 703*0Sstevel@tonic-gate LOG_DEBUG; 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate else 706*0Sstevel@tonic-gate error = 1; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * If there is a facility present, then parse that. 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate if (cp2) { 712*0Sstevel@tonic-gate if (!strcasecmp(cp2, "AUTH")) { 713*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_AUTH; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "KERN")) { 716*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_KERN; 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "USER")) { 719*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_USER; 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "MAIL")) { 722*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_MAIL; 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "DAEMON")) { 725*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_DAEMON; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LPR")) { 728*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LPR; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "NEWS")) { 731*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_NEWS; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "UUCP")) { 734*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_UUCP; 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "CRON")) { 737*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_CRON; 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL0")) { 740*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL0; 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL1")) { 743*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL1; 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL2")) { 746*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL2; 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL3")) { 749*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL3; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL4")) { 752*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL4; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL5")) { 755*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL5; 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL6")) { 758*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL6; 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate else if (!strcasecmp(cp2, "LOCAL7")) { 761*0Sstevel@tonic-gate log_control.log_entries[i].lsu_facility = LOG_LOCAL7; 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate cp2--; 764*0Sstevel@tonic-gate *cp2 = savec; 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate if (!error) { 768*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_SYSLOG; 769*0Sstevel@tonic-gate do_openlog = 1; 770*0Sstevel@tonic-gate log_facility = log_control.log_entries[i].lsu_facility; 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate /* 774*0Sstevel@tonic-gate * Is this a standard error specification? 775*0Sstevel@tonic-gate */ 776*0Sstevel@tonic-gate else if (!strcasecmp(cp, "STDERR")) { 777*0Sstevel@tonic-gate if (log_control.log_entries[i].lfu_filep = 778*0Sstevel@tonic-gate fdopen(fileno(stderr), "a+")) { 779*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_STDERR; 780*0Sstevel@tonic-gate log_control.log_entries[i].lfu_fname = 781*0Sstevel@tonic-gate "standard error"; 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate /* 785*0Sstevel@tonic-gate * Is this a specification of the console? 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate else if (!strcasecmp(cp, "CONSOLE")) { 788*0Sstevel@tonic-gate if (log_control.log_entries[i].ldu_filep = 789*0Sstevel@tonic-gate CONSOLE_OPEN("a+")) { 790*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_CONSOLE; 791*0Sstevel@tonic-gate log_control.log_entries[i].ldu_devname = "console"; 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate } 794*0Sstevel@tonic-gate /* 795*0Sstevel@tonic-gate * Is this a specification of a device? 796*0Sstevel@tonic-gate */ 797*0Sstevel@tonic-gate else if (!strncasecmp(cp, "DEVICE", 6)) { 798*0Sstevel@tonic-gate /* 799*0Sstevel@tonic-gate * We handle devices very similarly to files. 800*0Sstevel@tonic-gate */ 801*0Sstevel@tonic-gate if (cp[6] == '=') { 802*0Sstevel@tonic-gate if (log_control.log_entries[i].ldu_filep = 803*0Sstevel@tonic-gate DEVICE_OPEN(&cp[7], "w")) { 804*0Sstevel@tonic-gate log_control.log_entries[i].log_type = K_LOG_DEVICE; 805*0Sstevel@tonic-gate log_control.log_entries[i].ldu_devname = &cp[7]; 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate /* 810*0Sstevel@tonic-gate * See if we successfully parsed this specification. 811*0Sstevel@tonic-gate */ 812*0Sstevel@tonic-gate if (log_control.log_entries[i].log_type == K_LOG_NONE) { 813*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_1), whoami, cp); 814*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_2), whoami); 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate else 817*0Sstevel@tonic-gate ngood++; 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate /* 821*0Sstevel@tonic-gate * If we didn't find anything, then free our lists. 822*0Sstevel@tonic-gate */ 823*0Sstevel@tonic-gate if (ngood == 0) { 824*0Sstevel@tonic-gate for (i=0; i<log_control.log_nentries; i++) 825*0Sstevel@tonic-gate free(logging_specs[i]); 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate free(logging_specs); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate /* 830*0Sstevel@tonic-gate * If we didn't find anything, go for the default which is to log to 831*0Sstevel@tonic-gate * the system log. 832*0Sstevel@tonic-gate */ 833*0Sstevel@tonic-gate if (ngood == 0) { 834*0Sstevel@tonic-gate if (log_control.log_entries) 835*0Sstevel@tonic-gate free(log_control.log_entries); 836*0Sstevel@tonic-gate log_control.log_entries = &def_log_entry; 837*0Sstevel@tonic-gate log_control.log_entries->log_type = K_LOG_SYSLOG; 838*0Sstevel@tonic-gate log_control.log_entries->log_2free = (krb5_pointer) NULL; 839*0Sstevel@tonic-gate log_facility = log_control.log_entries->lsu_facility = LOG_AUTH; 840*0Sstevel@tonic-gate log_control.log_entries->lsu_severity = LOG_ERR; 841*0Sstevel@tonic-gate do_openlog = 1; 842*0Sstevel@tonic-gate log_control.log_nentries = 1; 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate if (log_control.log_nentries) { 845*0Sstevel@tonic-gate if (log_control.log_whoami = (char *) malloc(strlen(whoami)+1)) 846*0Sstevel@tonic-gate strcpy(log_control.log_whoami, whoami); 847*0Sstevel@tonic-gate if (log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN)) 848*0Sstevel@tonic-gate gethostname(log_control.log_hostname, MAXHOSTNAMELEN); 849*0Sstevel@tonic-gate if (do_openlog) { 850*0Sstevel@tonic-gate openlog(whoami, LOG_NDELAY|LOG_PID, log_facility); 851*0Sstevel@tonic-gate log_control.log_opened = 1; 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate if (do_com_err) 854*0Sstevel@tonic-gate (void) set_com_err_hook(klog_com_err_proc); 855*0Sstevel@tonic-gate } 856*0Sstevel@tonic-gate return((log_control.log_nentries) ? 0 : ENOENT); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate /* 860*0Sstevel@tonic-gate * krb5_klog_close() - Close the logging context and free all data. 861*0Sstevel@tonic-gate */ 862*0Sstevel@tonic-gate void 863*0Sstevel@tonic-gate krb5_klog_close(kcontext) 864*0Sstevel@tonic-gate krb5_context kcontext; 865*0Sstevel@tonic-gate { 866*0Sstevel@tonic-gate int lindex; 867*0Sstevel@tonic-gate (void) reset_com_err_hook(); 868*0Sstevel@tonic-gate for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 869*0Sstevel@tonic-gate switch (log_control.log_entries[lindex].log_type) { 870*0Sstevel@tonic-gate case K_LOG_FILE: 871*0Sstevel@tonic-gate case K_LOG_STDERR: 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * Files/standard error. 874*0Sstevel@tonic-gate */ 875*0Sstevel@tonic-gate fclose(log_control.log_entries[lindex].lfu_filep); 876*0Sstevel@tonic-gate break; 877*0Sstevel@tonic-gate case K_LOG_CONSOLE: 878*0Sstevel@tonic-gate case K_LOG_DEVICE: 879*0Sstevel@tonic-gate /* 880*0Sstevel@tonic-gate * Devices (may need special handling) 881*0Sstevel@tonic-gate */ 882*0Sstevel@tonic-gate DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep); 883*0Sstevel@tonic-gate break; 884*0Sstevel@tonic-gate case K_LOG_SYSLOG: 885*0Sstevel@tonic-gate /* 886*0Sstevel@tonic-gate * System log. 887*0Sstevel@tonic-gate */ 888*0Sstevel@tonic-gate break; 889*0Sstevel@tonic-gate default: 890*0Sstevel@tonic-gate break; 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate if (log_control.log_entries[lindex].log_2free) 893*0Sstevel@tonic-gate free(log_control.log_entries[lindex].log_2free); 894*0Sstevel@tonic-gate } 895*0Sstevel@tonic-gate if (log_control.log_entries != &def_log_entry) 896*0Sstevel@tonic-gate free(log_control.log_entries); 897*0Sstevel@tonic-gate log_control.log_entries = (struct log_entry *) NULL; 898*0Sstevel@tonic-gate log_control.log_nentries = 0; 899*0Sstevel@tonic-gate if (log_control.log_whoami) 900*0Sstevel@tonic-gate free(log_control.log_whoami); 901*0Sstevel@tonic-gate log_control.log_whoami = (char *) NULL; 902*0Sstevel@tonic-gate if (log_control.log_hostname) 903*0Sstevel@tonic-gate free(log_control.log_hostname); 904*0Sstevel@tonic-gate log_control.log_hostname = (char *) NULL; 905*0Sstevel@tonic-gate if (log_control.log_opened) 906*0Sstevel@tonic-gate closelog(); 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * severity2string() - Convert a severity to a string. 911*0Sstevel@tonic-gate */ 912*0Sstevel@tonic-gate static char * 913*0Sstevel@tonic-gate severity2string(severity) 914*0Sstevel@tonic-gate int severity; 915*0Sstevel@tonic-gate { 916*0Sstevel@tonic-gate int s; 917*0Sstevel@tonic-gate const char *ss; 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate s = severity & LOG_PRIMASK; 920*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_UFO_STRING); 921*0Sstevel@tonic-gate switch (s) { 922*0Sstevel@tonic-gate case LOG_EMERG: 923*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_EMERG_STRING); 924*0Sstevel@tonic-gate break; 925*0Sstevel@tonic-gate case LOG_ALERT: 926*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_ALERT_STRING); 927*0Sstevel@tonic-gate break; 928*0Sstevel@tonic-gate case LOG_CRIT: 929*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_CRIT_STRING); 930*0Sstevel@tonic-gate break; 931*0Sstevel@tonic-gate case LOG_ERR: 932*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_ERR_STRING); 933*0Sstevel@tonic-gate break; 934*0Sstevel@tonic-gate case LOG_WARNING: 935*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_WARNING_STRING); 936*0Sstevel@tonic-gate break; 937*0Sstevel@tonic-gate case LOG_NOTICE: 938*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_NOTICE_STRING); 939*0Sstevel@tonic-gate break; 940*0Sstevel@tonic-gate case LOG_INFO: 941*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_INFO_STRING); 942*0Sstevel@tonic-gate break; 943*0Sstevel@tonic-gate case LOG_DEBUG: 944*0Sstevel@tonic-gate ss = krb5_log_error_table(LOG_DEBUG_STRING); 945*0Sstevel@tonic-gate break; 946*0Sstevel@tonic-gate } 947*0Sstevel@tonic-gate return((char *) ss); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate /* 951*0Sstevel@tonic-gate * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while 952*0Sstevel@tonic-gate * also performing the logging redirection as specified 953*0Sstevel@tonic-gate * by krb5_klog_init(). 954*0Sstevel@tonic-gate */ 955*0Sstevel@tonic-gate static int 956*0Sstevel@tonic-gate klog_vsyslog(priority, format, arglist) 957*0Sstevel@tonic-gate int priority; 958*0Sstevel@tonic-gate const char *format; 959*0Sstevel@tonic-gate va_list arglist; 960*0Sstevel@tonic-gate { 961*0Sstevel@tonic-gate char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; 962*0Sstevel@tonic-gate int lindex; 963*0Sstevel@tonic-gate char *syslogp; 964*0Sstevel@tonic-gate char *cp; 965*0Sstevel@tonic-gate time_t now; 966*0Sstevel@tonic-gate size_t soff; 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate /* 969*0Sstevel@tonic-gate * Format a syslog-esque message of the format: 970*0Sstevel@tonic-gate * 971*0Sstevel@tonic-gate * (verbose form) 972*0Sstevel@tonic-gate * <date> <hostname> <id>[<pid>](<priority>): <message> 973*0Sstevel@tonic-gate * 974*0Sstevel@tonic-gate * (short form) 975*0Sstevel@tonic-gate * <date> <message> 976*0Sstevel@tonic-gate */ 977*0Sstevel@tonic-gate cp = outbuf; 978*0Sstevel@tonic-gate (void) time(&now); 979*0Sstevel@tonic-gate /* 980*0Sstevel@tonic-gate * Format the date: mon dd hh:mm:ss 981*0Sstevel@tonic-gate */ 982*0Sstevel@tonic-gate soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now)); 983*0Sstevel@tonic-gate if (soff > 0) 984*0Sstevel@tonic-gate cp += soff; 985*0Sstevel@tonic-gate else 986*0Sstevel@tonic-gate return(-1); 987*0Sstevel@tonic-gate #ifdef VERBOSE_LOGS 988*0Sstevel@tonic-gate sprintf(cp, " %s %s[%ld](%s): ", 989*0Sstevel@tonic-gate log_control.log_hostname, log_control.log_whoami, (long) getpid(), 990*0Sstevel@tonic-gate severity2string(priority)); 991*0Sstevel@tonic-gate #else 992*0Sstevel@tonic-gate sprintf(cp, " "); 993*0Sstevel@tonic-gate #endif 994*0Sstevel@tonic-gate syslogp = &outbuf[strlen(outbuf)]; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate /* Now format the actual message */ 997*0Sstevel@tonic-gate vsprintf(syslogp, format, arglist); 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate /* 1000*0Sstevel@tonic-gate * Now that we have the message formatted, perform the output to each 1001*0Sstevel@tonic-gate * logging specification. 1002*0Sstevel@tonic-gate */ 1003*0Sstevel@tonic-gate for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 1004*0Sstevel@tonic-gate switch (log_control.log_entries[lindex].log_type) { 1005*0Sstevel@tonic-gate case K_LOG_FILE: 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate klog_rotate(&log_control.log_entries[lindex]); 1008*0Sstevel@tonic-gate /*FALLTHRU*/ 1009*0Sstevel@tonic-gate case K_LOG_STDERR: 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Files/standard error. 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", 1014*0Sstevel@tonic-gate outbuf) < 0) { 1015*0Sstevel@tonic-gate /* Attempt to report error */ 1016*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), 1017*0Sstevel@tonic-gate log_control.log_whoami, 1018*0Sstevel@tonic-gate log_control.log_entries[lindex].lfu_fname); 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate else { 1021*0Sstevel@tonic-gate fflush(log_control.log_entries[lindex].lfu_filep); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate break; 1024*0Sstevel@tonic-gate case K_LOG_CONSOLE: 1025*0Sstevel@tonic-gate case K_LOG_DEVICE: 1026*0Sstevel@tonic-gate /* 1027*0Sstevel@tonic-gate * Devices (may need special handling) 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, 1030*0Sstevel@tonic-gate outbuf) < 0) { 1031*0Sstevel@tonic-gate /* Attempt to report error */ 1032*0Sstevel@tonic-gate fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), 1033*0Sstevel@tonic-gate log_control.log_whoami, 1034*0Sstevel@tonic-gate log_control.log_entries[lindex].ldu_devname); 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate break; 1037*0Sstevel@tonic-gate case K_LOG_SYSLOG: 1038*0Sstevel@tonic-gate /* 1039*0Sstevel@tonic-gate * System log. 1040*0Sstevel@tonic-gate */ 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate /* Log the message with our header trimmed off */ 1043*0Sstevel@tonic-gate syslog(priority, "%s", syslogp); 1044*0Sstevel@tonic-gate break; 1045*0Sstevel@tonic-gate default: 1046*0Sstevel@tonic-gate break; 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate } 1049*0Sstevel@tonic-gate return(0); 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate int 1053*0Sstevel@tonic-gate krb5_klog_syslog(int priority, const char *format, ...) 1054*0Sstevel@tonic-gate { 1055*0Sstevel@tonic-gate int retval; 1056*0Sstevel@tonic-gate va_list pvar; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate va_start(pvar, format); 1059*0Sstevel@tonic-gate retval = klog_vsyslog(priority, format, pvar); 1060*0Sstevel@tonic-gate va_end(pvar); 1061*0Sstevel@tonic-gate return(retval); 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate /* 1065*0Sstevel@tonic-gate * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files. 1066*0Sstevel@tonic-gate * This function is called when a SIGHUP is received 1067*0Sstevel@tonic-gate * so that external log-archival utilities may 1068*0Sstevel@tonic-gate * alert the Kerberos daemons that they should get 1069*0Sstevel@tonic-gate * a new file descriptor for the give filename. 1070*0Sstevel@tonic-gate */ 1071*0Sstevel@tonic-gate void 1072*0Sstevel@tonic-gate krb5_klog_reopen(kcontext) 1073*0Sstevel@tonic-gate krb5_context kcontext; 1074*0Sstevel@tonic-gate { 1075*0Sstevel@tonic-gate int lindex; 1076*0Sstevel@tonic-gate FILE *f; 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate /* 1079*0Sstevel@tonic-gate * Only logs which are actually files need to be closed 1080*0Sstevel@tonic-gate * and reopened in response to a SIGHUP 1081*0Sstevel@tonic-gate */ 1082*0Sstevel@tonic-gate for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 1083*0Sstevel@tonic-gate if (log_control.log_entries[lindex].log_type == K_LOG_FILE) { 1084*0Sstevel@tonic-gate fclose(log_control.log_entries[lindex].lfu_filep); 1085*0Sstevel@tonic-gate /* 1086*0Sstevel@tonic-gate * In case the old logfile did not get moved out of the 1087*0Sstevel@tonic-gate * way, open for append to prevent squashing the old logs. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate f = fopen(log_control.log_entries[lindex].lfu_fname, "a+"); 1090*0Sstevel@tonic-gate if (f) { 1091*0Sstevel@tonic-gate log_control.log_entries[lindex].lfu_filep = f; 1092*0Sstevel@tonic-gate } else { 1093*0Sstevel@tonic-gate fprintf(stderr, "Couldn't open log file %s: %s\n", 1094*0Sstevel@tonic-gate log_control.log_entries[lindex].lfu_fname, 1095*0Sstevel@tonic-gate error_message(errno)); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate } 1100