1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* lib/kadm5/logger.c */ 3 /* 4 * Copyright 1995, 2007 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 /* KADM5 wants non-syslog log files to contain syslog-like entries */ 28 #define VERBOSE_LOGS 29 30 /* 31 * logger.c - Handle logging functions for those who want it. 32 */ 33 #include "k5-int.h" 34 #include "adm_proto.h" 35 #include "com_err.h" 36 #include <stdio.h> 37 #include <ctype.h> 38 #include <syslog.h> 39 #include <stdarg.h> 40 41 #define KRB5_KLOG_MAX_ERRMSG_SIZE 2048 42 #ifndef MAXHOSTNAMELEN 43 #define MAXHOSTNAMELEN 256 44 #endif /* MAXHOSTNAMELEN */ 45 46 /* This is to assure that we have at least one match in the syslog stuff */ 47 #ifndef LOG_AUTH 48 #define LOG_AUTH 0 49 #endif /* LOG_AUTH */ 50 #ifndef LOG_ERR 51 #define LOG_ERR 0 52 #endif /* LOG_ERR */ 53 54 #define lspec_parse_err_1 _("%s: cannot parse <%s>\n") 55 #define lspec_parse_err_2 _("%s: warning - logging entry syntax error\n") 56 #define log_file_err _("%s: error writing to %s\n") 57 #define log_device_err _("%s: error writing to %s device\n") 58 #define log_ufo_string "?\?\?" /* nb: avoid trigraphs */ 59 #define log_emerg_string _("EMERGENCY") 60 #define log_alert_string _("ALERT") 61 #define log_crit_string _("CRITICAL") 62 #define log_err_string _("Error") 63 #define log_warning_string _("Warning") 64 #define log_notice_string _("Notice") 65 #define log_info_string _("info") 66 #define log_debug_string _("debug") 67 68 /* 69 * Output logging. 70 * 71 * Output logging is now controlled by the configuration file. We can specify 72 * the following syntaxes under the [logging]->entity specification. 73 * FILE<opentype><pathname> 74 * SYSLOG[=<severity>[:<facility>]] 75 * STDERR 76 * CONSOLE 77 * DEVICE=<device-spec> 78 * 79 * Where: 80 * <opentype> is ":" for open/append, "=" for open/create. 81 * <pathname> is a valid path name. 82 * <severity> is one of: (default = ERR) 83 * EMERG 84 * ALERT 85 * CRIT 86 * ERR 87 * WARNING 88 * NOTICE 89 * INFO 90 * DEBUG 91 * <facility> is one of: (default = AUTH) 92 * KERN 93 * USER 94 * MAIL 95 * DAEMON 96 * AUTH 97 * LPR 98 * NEWS 99 * UUCP 100 * CRON 101 * LOCAL0..LOCAL7 102 * <device-spec> is a valid device specification. 103 */ 104 struct log_entry { 105 enum log_type { K_LOG_FILE, 106 K_LOG_SYSLOG, 107 K_LOG_STDERR, 108 K_LOG_CONSOLE, 109 K_LOG_DEVICE, 110 K_LOG_NONE } log_type; 111 krb5_pointer log_2free; 112 union log_union { 113 struct log_file { 114 FILE *lf_filep; 115 char *lf_fname; 116 } log_file; 117 struct log_syslog { 118 int ls_facility; 119 } log_syslog; 120 struct log_device { 121 FILE *ld_filep; 122 char *ld_devname; 123 } log_device; 124 } log_union; 125 }; 126 #define lfu_filep log_union.log_file.lf_filep 127 #define lfu_fname log_union.log_file.lf_fname 128 #define lsu_facility log_union.log_syslog.ls_facility 129 #define ldu_filep log_union.log_device.ld_filep 130 #define ldu_devname log_union.log_device.ld_devname 131 132 struct log_control { 133 struct log_entry *log_entries; 134 int log_nentries; 135 char *log_whoami; 136 char *log_hostname; 137 krb5_boolean log_opened; 138 krb5_boolean log_debug; 139 }; 140 141 static struct log_control log_control = { 142 (struct log_entry *) NULL, 143 0, 144 (char *) NULL, 145 (char *) NULL, 146 0 147 }; 148 static struct log_entry def_log_entry; 149 150 /* 151 * These macros define any special processing that needs to happen for 152 * devices. For unix, of course, this is hardly anything. 153 */ 154 #define DEVICE_OPEN(d, m) fopen(d, m) 155 #define CONSOLE_OPEN(m) fopen("/dev/console", m) 156 #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \ 157 (fflush(f), 0) : \ 158 -1) 159 #define DEVICE_CLOSE(d) fclose(d) 160 161 /* 162 * klog_com_err_proc() - Handle com_err(3) messages as specified by the 163 * profile. 164 */ 165 static krb5_context err_context; 166 167 static void 168 klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap) 169 #if !defined(__cplusplus) && (__GNUC__ > 2) 170 __attribute__((__format__(__printf__, 3, 0))) 171 #endif 172 ; 173 174 /* 175 * Write com_err() messages to the configured logging devices. Ignore whoami, 176 * as krb5_klog_init() already received a whoami value. If code is nonzero, 177 * log its error message (retrieved using err_context) and the formatted 178 * message at error severity. If code is zero, log the formatted message at 179 * informational severity. 180 */ 181 static void 182 klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap) 183 { 184 struct k5buf buf; 185 const char *emsg, *msg; 186 187 if (format == NULL) 188 return; 189 190 k5_buf_init_dynamic(&buf); 191 192 if (code) { 193 /* Start with the error message and a separator. */ 194 emsg = krb5_get_error_message(err_context, code); 195 k5_buf_add(&buf, emsg); 196 krb5_free_error_message(err_context, emsg); 197 k5_buf_add(&buf, " - "); 198 } 199 200 /* Add the formatted message. */ 201 k5_buf_add_vfmt(&buf, format, ap); 202 203 msg = k5_buf_cstring(&buf); 204 if (msg != NULL) 205 krb5_klog_syslog(code ? LOG_ERR : LOG_INFO, "%s", msg); 206 207 k5_buf_free(&buf); 208 } 209 210 /* 211 * krb5_klog_init() - Initialize logging. 212 * 213 * This routine parses the syntax described above to specify destinations for 214 * com_err(3) or krb5_klog_syslog() messages generated by the caller. 215 * 216 * Parameters: 217 * kcontext - Kerberos context. 218 * ename - Entity name as it is to appear in the profile. 219 * whoami - Entity name as it is to appear in error output. 220 * do_com_err - Take over com_err(3) processing. 221 * 222 * Implicit inputs: 223 * stderr - This is where STDERR output goes. 224 * 225 * Implicit outputs: 226 * log_nentries - Number of log entries, both valid and invalid. 227 * log_control - List of entries (log_nentries long) which contains 228 * data for klog_com_err_proc() to use to determine 229 * where/how to send output. 230 */ 231 krb5_error_code 232 krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do_com_err) 233 { 234 const char *logging_profent[3]; 235 const char *logging_defent[3]; 236 char **logging_specs; 237 int i, ngood, fd, append; 238 char *cp, *cp2; 239 char savec = '\0'; 240 int error, debug; 241 int do_openlog, log_facility; 242 FILE *f = NULL; 243 244 /* Initialize */ 245 do_openlog = 0; 246 log_facility = 0; 247 248 err_context = kcontext; 249 250 /* Look up [logging]->debug in the profile to see if we should include 251 * debug messages for types other than syslog. Default to false. */ 252 if (!profile_get_boolean(kcontext->profile, KRB5_CONF_LOGGING, 253 KRB5_CONF_DEBUG, NULL, 0, &debug)) 254 log_control.log_debug = debug; 255 256 /* 257 * Look up [logging]-><ename> in the profile. If that doesn't 258 * succeed, then look for [logging]->default. 259 */ 260 logging_profent[0] = KRB5_CONF_LOGGING; 261 logging_profent[1] = ename; 262 logging_profent[2] = (char *) NULL; 263 logging_defent[0] = KRB5_CONF_LOGGING; 264 logging_defent[1] = KRB5_CONF_DEFAULT; 265 logging_defent[2] = (char *) NULL; 266 logging_specs = (char **) NULL; 267 ngood = 0; 268 log_control.log_nentries = 0; 269 if (!profile_get_values(kcontext->profile, 270 logging_profent, 271 &logging_specs) || 272 !profile_get_values(kcontext->profile, 273 logging_defent, 274 &logging_specs)) { 275 /* 276 * We have a match, so we first count the number of elements 277 */ 278 for (log_control.log_nentries = 0; 279 logging_specs[log_control.log_nentries]; 280 log_control.log_nentries++); 281 282 /* 283 * Now allocate our structure. 284 */ 285 log_control.log_entries = (struct log_entry *) 286 malloc(log_control.log_nentries * sizeof(struct log_entry)); 287 if (log_control.log_entries) { 288 /* 289 * Scan through the list. 290 */ 291 for (i=0; i<log_control.log_nentries; i++) { 292 log_control.log_entries[i].log_type = K_LOG_NONE; 293 log_control.log_entries[i].log_2free = logging_specs[i]; 294 /* 295 * The format is: 296 * <whitespace><data><whitespace> 297 * so, trim off the leading and trailing whitespace here. 298 */ 299 for (cp = logging_specs[i]; isspace((int) *cp); cp++); 300 for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1]; 301 isspace((int) *cp2); cp2--); 302 cp2++; 303 *cp2 = '\0'; 304 /* 305 * Is this a file? 306 */ 307 if (!strncasecmp(cp, "FILE", 4)) { 308 /* 309 * Check for append/overwrite, then open the file. 310 */ 311 append = (cp[4] == ':') ? O_APPEND : 0; 312 if (append || cp[4] == '=') { 313 fd = open(&cp[5], O_CREAT | O_WRONLY | append, 314 S_IRUSR | S_IWUSR | S_IRGRP); 315 if (fd != -1) 316 f = fdopen(fd, append ? "a" : "w"); 317 if (fd == -1 || f == NULL) { 318 fprintf(stderr,"Couldn't open log file %s: %s\n", 319 &cp[5], error_message(errno)); 320 continue; 321 } 322 set_cloexec_file(f); 323 log_control.log_entries[i].lfu_filep = f; 324 log_control.log_entries[i].log_type = K_LOG_FILE; 325 log_control.log_entries[i].lfu_fname = &cp[5]; 326 } 327 } 328 /* 329 * Is this a syslog? 330 */ 331 else if (!strncasecmp(cp, "SYSLOG", 6)) { 332 error = 0; 333 log_control.log_entries[i].lsu_facility = LOG_AUTH; 334 /* 335 * Is there a severify (which is now ignored) specified? 336 */ 337 if (cp[6] == ':') { 338 /* 339 * Find the end of the severity. 340 */ 341 cp2 = strchr(&cp[7], ':'); 342 if (cp2) { 343 savec = *cp2; 344 *cp2 = '\0'; 345 cp2++; 346 } 347 348 /* 349 * If there is a facility present, then parse that. 350 */ 351 if (cp2) { 352 static const struct { 353 const char *name; 354 int value; 355 } facilities[] = { 356 { "AUTH", LOG_AUTH }, 357 #ifdef LOG_AUTHPRIV 358 { "AUTHPRIV", LOG_AUTHPRIV }, 359 #endif /* LOG_AUTHPRIV */ 360 #ifdef LOG_KERN 361 { "KERN", LOG_KERN }, 362 #endif /* LOG_KERN */ 363 #ifdef LOG_USER 364 { "USER", LOG_USER }, 365 #endif /* LOG_USER */ 366 #ifdef LOG_MAIL 367 { "MAIL", LOG_MAIL }, 368 #endif /* LOG_MAIL */ 369 #ifdef LOG_DAEMON 370 { "DAEMON", LOG_DAEMON }, 371 #endif /* LOG_DAEMON */ 372 #ifdef LOG_FTP 373 { "FTP", LOG_FTP }, 374 #endif /* LOG_FTP */ 375 #ifdef LOG_LPR 376 { "LPR", LOG_LPR }, 377 #endif /* LOG_LPR */ 378 #ifdef LOG_NEWS 379 { "NEWS", LOG_NEWS }, 380 #endif /* LOG_NEWS */ 381 #ifdef LOG_UUCP 382 { "UUCP", LOG_UUCP }, 383 #endif /* LOG_UUCP */ 384 #ifdef LOG_CRON 385 { "CRON", LOG_CRON }, 386 #endif /* LOG_CRON */ 387 #ifdef LOG_LOCAL0 388 { "LOCAL0", LOG_LOCAL0 }, 389 #endif /* LOG_LOCAL0 */ 390 #ifdef LOG_LOCAL1 391 { "LOCAL1", LOG_LOCAL1 }, 392 #endif /* LOG_LOCAL1 */ 393 #ifdef LOG_LOCAL2 394 { "LOCAL2", LOG_LOCAL2 }, 395 #endif /* LOG_LOCAL2 */ 396 #ifdef LOG_LOCAL3 397 { "LOCAL3", LOG_LOCAL3 }, 398 #endif /* LOG_LOCAL3 */ 399 #ifdef LOG_LOCAL4 400 { "LOCAL4", LOG_LOCAL4 }, 401 #endif /* LOG_LOCAL4 */ 402 #ifdef LOG_LOCAL5 403 { "LOCAL5", LOG_LOCAL5 }, 404 #endif /* LOG_LOCAL5 */ 405 #ifdef LOG_LOCAL6 406 { "LOCAL6", LOG_LOCAL6 }, 407 #endif /* LOG_LOCAL6 */ 408 #ifdef LOG_LOCAL7 409 { "LOCAL7", LOG_LOCAL7 }, 410 #endif /* LOG_LOCAL7 */ 411 }; 412 unsigned int j; 413 414 for (j = 0; j < sizeof(facilities)/sizeof(facilities[0]); j++) 415 if (!strcasecmp(cp2, facilities[j].name)) { 416 log_control.log_entries[i].lsu_facility = facilities[j].value; 417 break; 418 } 419 cp2--; 420 *cp2 = savec; 421 } 422 } 423 if (!error) { 424 log_control.log_entries[i].log_type = K_LOG_SYSLOG; 425 do_openlog = 1; 426 log_facility = log_control.log_entries[i].lsu_facility; 427 } 428 } 429 /* 430 * Is this a standard error specification? 431 */ 432 else if (!strcasecmp(cp, "STDERR")) { 433 log_control.log_entries[i].lfu_filep = 434 fdopen(fileno(stderr), "w"); 435 if (log_control.log_entries[i].lfu_filep) { 436 log_control.log_entries[i].log_type = K_LOG_STDERR; 437 log_control.log_entries[i].lfu_fname = 438 "standard error"; 439 } 440 } 441 /* 442 * Is this a specification of the console? 443 */ 444 else if (!strcasecmp(cp, "CONSOLE")) { 445 log_control.log_entries[i].ldu_filep = 446 CONSOLE_OPEN("a+"); 447 if (log_control.log_entries[i].ldu_filep) { 448 set_cloexec_file(log_control.log_entries[i].ldu_filep); 449 log_control.log_entries[i].log_type = K_LOG_CONSOLE; 450 log_control.log_entries[i].ldu_devname = "console"; 451 } 452 } 453 /* 454 * Is this a specification of a device? 455 */ 456 else if (!strncasecmp(cp, "DEVICE", 6)) { 457 /* 458 * We handle devices very similarly to files. 459 */ 460 if (cp[6] == '=') { 461 log_control.log_entries[i].ldu_filep = 462 DEVICE_OPEN(&cp[7], "w"); 463 if (log_control.log_entries[i].ldu_filep) { 464 set_cloexec_file(log_control.log_entries[i].ldu_filep); 465 log_control.log_entries[i].log_type = K_LOG_DEVICE; 466 log_control.log_entries[i].ldu_devname = &cp[7]; 467 } 468 } 469 } 470 /* 471 * See if we successfully parsed this specification. 472 */ 473 if (log_control.log_entries[i].log_type == K_LOG_NONE) { 474 fprintf(stderr, lspec_parse_err_1, whoami, cp); 475 fprintf(stderr, lspec_parse_err_2, whoami); 476 } 477 else 478 ngood++; 479 } 480 } 481 /* 482 * If we didn't find anything, then free our lists. 483 */ 484 if (ngood == 0) { 485 for (i=0; i<log_control.log_nentries; i++) 486 free(logging_specs[i]); 487 } 488 free(logging_specs); 489 } 490 /* 491 * If we didn't find anything, go for the default which is to log to 492 * the system log. 493 */ 494 if (ngood == 0) { 495 if (log_control.log_entries) 496 free(log_control.log_entries); 497 log_control.log_entries = &def_log_entry; 498 log_control.log_entries->log_type = K_LOG_SYSLOG; 499 log_control.log_entries->log_2free = (krb5_pointer) NULL; 500 log_facility = log_control.log_entries->lsu_facility = LOG_AUTH; 501 do_openlog = 1; 502 log_control.log_nentries = 1; 503 } 504 if (log_control.log_nentries) { 505 log_control.log_whoami = strdup(whoami); 506 log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN + 1); 507 if (log_control.log_hostname) { 508 if (gethostname(log_control.log_hostname, MAXHOSTNAMELEN) == -1) { 509 free(log_control.log_hostname); 510 log_control.log_hostname = NULL; 511 } else 512 log_control.log_hostname[MAXHOSTNAMELEN] = '\0'; 513 } 514 if (do_openlog) { 515 openlog(whoami, LOG_NDELAY|LOG_PID, log_facility); 516 log_control.log_opened = 1; 517 } 518 if (do_com_err) 519 (void) set_com_err_hook(klog_com_err_proc); 520 } 521 return((log_control.log_nentries) ? 0 : ENOENT); 522 } 523 524 /* Reset the context used by the com_err hook to retrieve error messages. */ 525 void 526 krb5_klog_set_context(krb5_context kcontext) 527 { 528 err_context = kcontext; 529 } 530 531 /* 532 * krb5_klog_close() - Close the logging context and free all data. 533 */ 534 void 535 krb5_klog_close(krb5_context kcontext) 536 { 537 int lindex; 538 (void) reset_com_err_hook(); 539 for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 540 switch (log_control.log_entries[lindex].log_type) { 541 case K_LOG_FILE: 542 case K_LOG_STDERR: 543 /* 544 * Files/standard error. 545 */ 546 fclose(log_control.log_entries[lindex].lfu_filep); 547 break; 548 case K_LOG_CONSOLE: 549 case K_LOG_DEVICE: 550 /* 551 * Devices (may need special handling) 552 */ 553 DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep); 554 break; 555 case K_LOG_SYSLOG: 556 /* 557 * System log. 558 */ 559 break; 560 default: 561 break; 562 } 563 if (log_control.log_entries[lindex].log_2free) 564 free(log_control.log_entries[lindex].log_2free); 565 } 566 if (log_control.log_entries != &def_log_entry) 567 free(log_control.log_entries); 568 log_control.log_entries = (struct log_entry *) NULL; 569 log_control.log_nentries = 0; 570 if (log_control.log_whoami) 571 free(log_control.log_whoami); 572 log_control.log_whoami = (char *) NULL; 573 if (log_control.log_hostname) 574 free(log_control.log_hostname); 575 log_control.log_hostname = (char *) NULL; 576 if (log_control.log_opened) 577 closelog(); 578 } 579 580 /* 581 * severity2string() - Convert a severity to a string. 582 */ 583 static const char * 584 severity2string(int severity) 585 { 586 int s; 587 const char *ss; 588 589 s = severity & LOG_PRIMASK; 590 ss = log_ufo_string; 591 switch (s) { 592 case LOG_EMERG: 593 ss = log_emerg_string; 594 break; 595 case LOG_ALERT: 596 ss = log_alert_string; 597 break; 598 case LOG_CRIT: 599 ss = log_crit_string; 600 break; 601 case LOG_ERR: 602 ss = log_err_string; 603 break; 604 case LOG_WARNING: 605 ss = log_warning_string; 606 break; 607 case LOG_NOTICE: 608 ss = log_notice_string; 609 break; 610 case LOG_INFO: 611 ss = log_info_string; 612 break; 613 case LOG_DEBUG: 614 ss = log_debug_string; 615 break; 616 } 617 return(ss); 618 } 619 620 /* 621 * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while 622 * also performing the logging redirection as specified 623 * by krb5_klog_init(). 624 */ 625 static int 626 klog_vsyslog(int priority, const char *format, va_list arglist) 627 #if !defined(__cplusplus) && (__GNUC__ > 2) 628 __attribute__((__format__(__printf__, 2, 0))) 629 #endif 630 ; 631 632 static int 633 klog_vsyslog(int priority, const char *format, va_list arglist) 634 { 635 char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; 636 int lindex; 637 char *syslogp; 638 char *cp; 639 time_t now; 640 size_t soff; 641 struct tm *tm; 642 643 /* 644 * Format a syslog-esque message of the format: 645 * 646 * (verbose form) 647 * <date> <hostname> <id>[<pid>](<priority>): <message> 648 * 649 * (short form) 650 * <date> <message> 651 */ 652 cp = outbuf; 653 (void) time(&now); 654 655 /* 656 * Format the date: mon dd hh:mm:ss 657 */ 658 tm = localtime(&now); 659 if (tm == NULL) 660 return(-1); 661 soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", tm); 662 if (soff > 0) 663 cp += soff; 664 else 665 return(-1); 666 667 #ifdef VERBOSE_LOGS 668 snprintf(cp, sizeof(outbuf) - (cp-outbuf), " %s %s[%ld](%s): ", 669 log_control.log_hostname ? log_control.log_hostname : "", 670 log_control.log_whoami ? log_control.log_whoami : "", 671 (long) getpid(), 672 severity2string(priority)); 673 #else 674 snprintf(cp, sizeof(outbuf) - (cp-outbuf), " "); 675 #endif 676 syslogp = &outbuf[strlen(outbuf)]; 677 678 /* Now format the actual message */ 679 vsnprintf(syslogp, sizeof(outbuf) - (syslogp - outbuf), format, arglist); 680 681 /* 682 * If the user did not use krb5_klog_init() instead of dropping 683 * the request on the floor, syslog it - if it exists 684 */ 685 if (log_control.log_nentries == 0) { 686 /* Log the message with our header trimmed off */ 687 syslog(priority, "%s", syslogp); 688 } 689 690 /* 691 * Now that we have the message formatted, perform the output to each 692 * logging specification. 693 */ 694 for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 695 /* Omit LOG_DEBUG messages for non-syslog outputs unless we are 696 * configured to include them. */ 697 if (priority == LOG_DEBUG && !log_control.log_debug && 698 log_control.log_entries[lindex].log_type != K_LOG_SYSLOG) 699 continue; 700 701 switch (log_control.log_entries[lindex].log_type) { 702 case K_LOG_FILE: 703 case K_LOG_STDERR: 704 /* 705 * Files/standard error. 706 */ 707 if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", 708 outbuf) < 0) { 709 /* Attempt to report error */ 710 fprintf(stderr, log_file_err, log_control.log_whoami, 711 log_control.log_entries[lindex].lfu_fname); 712 } 713 else { 714 fflush(log_control.log_entries[lindex].lfu_filep); 715 } 716 break; 717 case K_LOG_CONSOLE: 718 case K_LOG_DEVICE: 719 /* 720 * Devices (may need special handling) 721 */ 722 if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, 723 outbuf) < 0) { 724 /* Attempt to report error */ 725 fprintf(stderr, log_device_err, log_control.log_whoami, 726 log_control.log_entries[lindex].ldu_devname); 727 } 728 break; 729 case K_LOG_SYSLOG: 730 /* 731 * System log. 732 */ 733 734 /* Log the message with our header trimmed off */ 735 syslog(priority, "%s", syslogp); 736 break; 737 default: 738 break; 739 } 740 } 741 return(0); 742 } 743 744 int 745 krb5_klog_syslog(int priority, const char *format, ...) 746 { 747 int retval; 748 va_list pvar; 749 750 va_start(pvar, format); 751 retval = klog_vsyslog(priority, format, pvar); 752 va_end(pvar); 753 return(retval); 754 } 755 756 /* 757 * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files. 758 * This function is called when a SIGHUP is received 759 * so that external log-archival utilities may 760 * alert the Kerberos daemons that they should get 761 * a new file descriptor for the give filename. 762 */ 763 void 764 krb5_klog_reopen(krb5_context kcontext) 765 { 766 int lindex; 767 FILE *f; 768 769 /* 770 * Only logs which are actually files need to be closed 771 * and reopened in response to a SIGHUP 772 */ 773 for (lindex = 0; lindex < log_control.log_nentries; lindex++) { 774 if (log_control.log_entries[lindex].log_type == K_LOG_FILE) { 775 fclose(log_control.log_entries[lindex].lfu_filep); 776 /* 777 * In case the old logfile did not get moved out of the 778 * way, open for append to prevent squashing the old logs. 779 */ 780 f = fopen(log_control.log_entries[lindex].lfu_fname, "a+"); 781 if (f) { 782 set_cloexec_file(f); 783 log_control.log_entries[lindex].lfu_filep = f; 784 } else { 785 fprintf(stderr, _("Couldn't open log file %s: %s\n"), 786 log_control.log_entries[lindex].lfu_fname, 787 error_message(errno)); 788 } 789 } 790 } 791 } 792