1 /* $NetBSD: syslogd.c,v 1.72 2004/11/19 18:48:18 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 41 #else 42 __RCSID("$NetBSD: syslogd.c,v 1.72 2004/11/19 18:48:18 wiz Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * syslogd -- log system messages 48 * 49 * This program implements a system log. It takes a series of lines. 50 * Each line may have a priority, signified as "<n>" as 51 * the first characters of the line. If this is 52 * not present, a default priority is used. 53 * 54 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 55 * cause it to reread its configuration file. 56 * 57 * Defined Constants: 58 * 59 * MAXLINE -- the maximimum line length that can be handled. 60 * DEFUPRI -- the default priority for user messages 61 * DEFSPRI -- the default priority for kernel messages 62 * 63 * Author: Eric Allman 64 * extensive changes by Ralph Campbell 65 * more extensive changes by Eric Allman (again) 66 * Extension to log by program name as well as facility and priority 67 * by Peter da Silva. 68 * -U and -v by Harlan Stenn. 69 * Priority comparison code by Harlan Stenn. 70 */ 71 72 #define MAXLINE 1024 /* maximum line length */ 73 #define MAXSVLINE 120 /* maximum saved line length */ 74 #define DEFUPRI (LOG_USER|LOG_NOTICE) 75 #define DEFSPRI (LOG_KERN|LOG_NOTICE) 76 #define TIMERINTVL 30 /* interval for checking flush, mark */ 77 #define TTYMSGTIME 1 /* timeout passed to ttymsg */ 78 79 #include <sys/param.h> 80 #include <sys/socket.h> 81 #include <sys/sysctl.h> 82 #include <sys/types.h> 83 #include <sys/un.h> 84 #include <sys/wait.h> 85 #include <sys/queue.h> 86 #include <sys/event.h> 87 88 #include <netinet/in.h> 89 90 #include <ctype.h> 91 #include <errno.h> 92 #include <fcntl.h> 93 #include <grp.h> 94 #include <locale.h> 95 #include <netdb.h> 96 #include <pwd.h> 97 #include <signal.h> 98 #include <stdarg.h> 99 #include <stdio.h> 100 #include <stdlib.h> 101 #include <string.h> 102 #include <unistd.h> 103 #include <util.h> 104 105 #include "utmpentry.h" 106 #include "pathnames.h" 107 108 #define SYSLOG_NAMES 109 #include <sys/syslog.h> 110 111 #ifdef LIBWRAP 112 #include <tcpd.h> 113 114 int allow_severity = LOG_AUTH|LOG_INFO; 115 int deny_severity = LOG_AUTH|LOG_WARNING; 116 #endif 117 118 char *ConfFile = _PATH_LOGCONF; 119 char ctty[] = _PATH_CONSOLE; 120 121 #define FDMASK(fd) (1 << (fd)) 122 123 #define dprintf if (Debug) printf 124 125 #define MAXUNAMES 20 /* maximum number of user names */ 126 127 /* 128 * Flags to logmsg(). 129 */ 130 131 #define IGN_CONS 0x001 /* don't print on console */ 132 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 133 #define ADDDATE 0x004 /* add a date to the message */ 134 #define MARK 0x008 /* this message is a mark */ 135 #define ISKERNEL 0x010 /* kernel generated message */ 136 137 /* 138 * This structure represents the files that will have log 139 * copies printed. 140 * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY, 141 * or if f_type is F_PIPE and f_pid > 0. 142 */ 143 144 struct filed { 145 struct filed *f_next; /* next in linked list */ 146 short f_type; /* entry type, see below */ 147 short f_file; /* file descriptor */ 148 time_t f_time; /* time this was last written */ 149 char *f_host; /* host from which to record */ 150 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 151 u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ 152 #define PRI_LT 0x1 153 #define PRI_EQ 0x2 154 #define PRI_GT 0x4 155 char *f_program; /* program this applies to */ 156 union { 157 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 158 struct { 159 char f_hname[MAXHOSTNAMELEN]; 160 struct addrinfo *f_addr; 161 } f_forw; /* forwarding address */ 162 char f_fname[MAXPATHLEN]; 163 struct { 164 char f_pname[MAXPATHLEN]; 165 pid_t f_pid; 166 } f_pipe; 167 } f_un; 168 char f_prevline[MAXSVLINE]; /* last message logged */ 169 char f_lasttime[16]; /* time of last occurrence */ 170 char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */ 171 int f_prevpri; /* pri of f_prevline */ 172 int f_prevlen; /* length of f_prevline */ 173 int f_prevcount; /* repetition cnt of prevline */ 174 int f_repeatcount; /* number of "repeated" msgs */ 175 int f_flags; /* file-specific flags */ 176 #define FFLAG_SYNC 0x01 177 }; 178 179 /* 180 * Queue of about-to-be-dead processes we should watch out for. 181 */ 182 TAILQ_HEAD(, deadq_entry) deadq_head = TAILQ_HEAD_INITIALIZER(deadq_head); 183 184 typedef struct deadq_entry { 185 pid_t dq_pid; 186 int dq_timeout; 187 TAILQ_ENTRY(deadq_entry) dq_entries; 188 } *dq_t; 189 190 /* 191 * The timeout to apply to processes waiting on the dead queue. Unit 192 * of measure is "mark intervals", i.e. 20 minutes by default. 193 * Processes on the dead queue will be terminated after that time. 194 */ 195 #define DQ_TIMO_INIT 2 196 197 /* 198 * Intervals at which we flush out "message repeated" messages, 199 * in seconds after previous message is logged. After each flush, 200 * we move to the next interval until we reach the largest. 201 */ 202 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 203 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 204 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 205 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 206 (f)->f_repeatcount = MAXREPEAT; \ 207 } 208 209 /* values for f_type */ 210 #define F_UNUSED 0 /* unused entry */ 211 #define F_FILE 1 /* regular file */ 212 #define F_TTY 2 /* terminal */ 213 #define F_CONSOLE 3 /* console terminal */ 214 #define F_FORW 4 /* remote machine */ 215 #define F_USERS 5 /* list of users */ 216 #define F_WALL 6 /* everyone logged on */ 217 #define F_PIPE 7 /* pipe to program */ 218 219 char *TypeNames[8] = { 220 "UNUSED", "FILE", "TTY", "CONSOLE", 221 "FORW", "USERS", "WALL", "PIPE" 222 }; 223 224 struct filed *Files; 225 struct filed consfile; 226 227 int Debug; /* debug flag */ 228 int daemonized = 0; /* we are not daemonized yet */ 229 char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 230 char oldLocalHostName[MAXHOSTNAMELEN];/* previous hostname */ 231 char *LocalDomain; /* our local domain name */ 232 size_t LocalDomainLen; /* length of LocalDomain */ 233 int *finet = NULL; /* Internet datagram sockets */ 234 int Initialized; /* set when we have initialized ourselves */ 235 int ShuttingDown; /* set when we die() */ 236 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 237 int MarkSeq = 0; /* mark sequence number */ 238 int SecureMode = 0; /* listen only on unix domain socks */ 239 int UseNameService = 1; /* make domain name queries */ 240 int NumForwards = 0; /* number of forwarding actions in conf file */ 241 char **LogPaths; /* array of pathnames to read messages from */ 242 int NoRepeat = 0; /* disable "repeated"; log always */ 243 int SyncKernel = 0; /* write kernel messages synchronously */ 244 int UniquePriority = 0; /* only log specified priority */ 245 int LogFacPri = 0; /* put facility and priority in log messages: */ 246 /* 0=no, 1=numeric, 2=names */ 247 248 void cfline(char *, struct filed *, char *, char *); 249 char *cvthname(struct sockaddr_storage *); 250 void deadq_enter(pid_t, const char *); 251 int deadq_remove(pid_t); 252 int decode(const char *, CODE *); 253 void die(struct kevent *); /* SIGTERM kevent dispatch routine */ 254 void domark(struct kevent *);/* timer kevent dispatch routine */ 255 void fprintlog(struct filed *, int, char *); 256 int getmsgbufsize(void); 257 int* socksetup(int); 258 void init(struct kevent *); /* SIGHUP kevent dispatch routine */ 259 void logerror(const char *, ...); 260 void logmsg(int, char *, char *, int); 261 void log_deadchild(pid_t, int, const char *); 262 int matches_spec(const char *, const char *, 263 char *(*)(const char *, const char *)); 264 void printline(char *, char *); 265 void printsys(char *); 266 int p_open(char *, pid_t *); 267 void trim_localdomain(char *); 268 void reapchild(struct kevent *); /* SIGCHLD kevent dispatch routine */ 269 void usage(void); 270 void wallmsg(struct filed *, struct iovec *); 271 int main(int, char *[]); 272 void logpath_add(char ***, int *, int *, char *); 273 void logpath_fileadd(char ***, int *, int *, char *); 274 275 static int fkq; 276 277 static struct kevent *allocevchange(void); 278 static int wait_for_events(struct kevent *, size_t); 279 280 static void dispatch_read_klog(struct kevent *); 281 static void dispatch_read_finet(struct kevent *); 282 static void dispatch_read_funix(struct kevent *); 283 284 /* 285 * Global line buffer. Since we only process one event at a time, 286 * a global one will do. 287 */ 288 static char *linebuf; 289 static size_t linebufsize; 290 291 #define A_CNT(x) (sizeof((x)) / sizeof((x)[0])) 292 293 int 294 main(int argc, char *argv[]) 295 { 296 int ch, *funix, j, fklog; 297 int funixsize = 0, funixmaxsize = 0; 298 struct kevent events[16]; 299 struct sockaddr_un sunx; 300 char **pp; 301 struct kevent *ev; 302 uid_t uid = 0; 303 gid_t gid = 0; 304 char *user = NULL; 305 char *group = NULL; 306 char *root = "/"; 307 char *endp; 308 struct group *gr; 309 struct passwd *pw; 310 unsigned long l; 311 312 (void)setlocale(LC_ALL, ""); 313 314 while ((ch = getopt(argc, argv, "dnsSf:m:p:P:ru:g:t:Uv")) != -1) 315 switch(ch) { 316 case 'd': /* debug */ 317 Debug++; 318 break; 319 case 'f': /* configuration file */ 320 ConfFile = optarg; 321 break; 322 case 'g': 323 group = optarg; 324 if (*group == '\0') 325 usage(); 326 break; 327 case 'm': /* mark interval */ 328 MarkInterval = atoi(optarg) * 60; 329 break; 330 case 'n': /* turn off DNS queries */ 331 UseNameService = 0; 332 break; 333 case 'p': /* path */ 334 logpath_add(&LogPaths, &funixsize, 335 &funixmaxsize, optarg); 336 break; 337 case 'P': /* file of paths */ 338 logpath_fileadd(&LogPaths, &funixsize, 339 &funixmaxsize, optarg); 340 break; 341 case 'r': /* disable "repeated" compression */ 342 NoRepeat++; 343 break; 344 case 's': /* no network listen mode */ 345 SecureMode++; 346 break; 347 case 'S': 348 SyncKernel = 1; 349 break; 350 case 't': 351 root = optarg; 352 if (*root == '\0') 353 usage(); 354 break; 355 case 'u': 356 user = optarg; 357 if (*user == '\0') 358 usage(); 359 break; 360 case 'U': /* only log specified priority */ 361 UniquePriority = 1; 362 break; 363 case 'v': /* log facility and priority */ 364 if (LogFacPri < 2) 365 LogFacPri++; 366 break; 367 default: 368 usage(); 369 } 370 if ((argc -= optind) != 0) 371 usage(); 372 373 setlinebuf(stdout); 374 375 if (user != NULL) { 376 if (isdigit((unsigned char)*user)) { 377 errno = 0; 378 endp = NULL; 379 l = strtoul(user, &endp, 0); 380 if (errno || *endp != '\0') 381 goto getuser; 382 uid = (uid_t)l; 383 if (uid != l) { 384 errno = 0; 385 logerror("UID out of range"); 386 die(NULL); 387 } 388 } else { 389 getuser: 390 if ((pw = getpwnam(user)) != NULL) { 391 uid = pw->pw_uid; 392 } else { 393 errno = 0; 394 logerror("Cannot find user `%s'", user); 395 die(NULL); 396 } 397 } 398 } 399 400 if (group != NULL) { 401 if (isdigit((unsigned char)*group)) { 402 errno = 0; 403 endp = NULL; 404 l = strtoul(group, &endp, 0); 405 if (errno || *endp != '\0') 406 goto getgroup; 407 gid = (gid_t)l; 408 if (gid != l) { 409 errno = 0; 410 logerror("GID out of range"); 411 die(NULL); 412 } 413 } else { 414 getgroup: 415 if ((gr = getgrnam(group)) != NULL) { 416 gid = gr->gr_gid; 417 } else { 418 errno = 0; 419 logerror("Cannot find group `%s'", group); 420 die(NULL); 421 } 422 } 423 } 424 425 if (access(root, F_OK | R_OK)) { 426 logerror("Cannot access `%s'", root); 427 die(NULL); 428 } 429 430 consfile.f_type = F_CONSOLE; 431 (void)strlcpy(consfile.f_un.f_fname, ctty, 432 sizeof(consfile.f_un.f_fname)); 433 linebufsize = getmsgbufsize(); 434 if (linebufsize < MAXLINE) 435 linebufsize = MAXLINE; 436 linebufsize++; 437 linebuf = malloc(linebufsize); 438 if (linebuf == NULL) { 439 logerror("Couldn't allocate line buffer"); 440 die(NULL); 441 } 442 443 #ifndef SUN_LEN 444 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 445 #endif 446 if (funixsize == 0) 447 logpath_add(&LogPaths, &funixsize, 448 &funixmaxsize, _PATH_LOG); 449 funix = (int *)malloc(sizeof(int) * funixsize); 450 if (funix == NULL) { 451 logerror("Couldn't allocate funix descriptors"); 452 die(NULL); 453 } 454 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 455 dprintf("Making unix dgram socket `%s'\n", *pp); 456 unlink(*pp); 457 memset(&sunx, 0, sizeof(sunx)); 458 sunx.sun_family = AF_LOCAL; 459 (void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path)); 460 funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0); 461 if (funix[j] < 0 || bind(funix[j], 462 (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 463 chmod(*pp, 0666) < 0) { 464 logerror("Cannot create `%s'", *pp); 465 die(NULL); 466 } 467 dprintf("Listening on unix dgram socket `%s'\n", *pp); 468 } 469 470 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) { 471 dprintf("Can't open `%s' (%d)\n", _PATH_KLOG, errno); 472 } else { 473 dprintf("Listening on kernel log `%s'\n", _PATH_KLOG); 474 } 475 476 /* 477 * All files are open, we can drop privileges and chroot 478 */ 479 dprintf("Attempt to chroot to `%s'\n", root); 480 if (chroot(root)) { 481 logerror("Failed to chroot to `%s'", root); 482 die(NULL); 483 } 484 dprintf("Attempt to set GID/EGID to `%d'\n", gid); 485 if (setgid(gid) || setegid(gid)) { 486 logerror("Failed to set gid to `%d'", gid); 487 die(NULL); 488 } 489 dprintf("Attempt to set UID/EUID to `%d'\n", uid); 490 if (setuid(uid) || seteuid(uid)) { 491 logerror("Failed to set uid to `%d'", uid); 492 die(NULL); 493 } 494 495 /* 496 * We cannot detach from the terminal before we are sure we won't 497 * have a fatal error, because error message would not go to the 498 * terminal and would not be logged because syslogd dies. 499 * All die() calls are behind us, we can call daemon() 500 */ 501 if (!Debug) { 502 (void)daemon(0, 0); 503 daemonized = 1; 504 505 /* tuck my process id away, if i'm not in debug mode */ 506 pidfile(NULL); 507 } 508 509 /* 510 * Create the global kernel event descriptor. 511 * 512 * NOTE: We MUST do this after daemon(), bacause the kqueue() 513 * API dictates that kqueue descriptors are not inherited 514 * across forks (lame!). 515 */ 516 if ((fkq = kqueue()) < 0) { 517 logerror("Cannot create event queue"); 518 die(NULL); /* XXX This error is lost! */ 519 } 520 521 /* 522 * We must read the configuration file for the first time 523 * after the kqueue descriptor is created, because we install 524 * events during this process. 525 */ 526 init(NULL); 527 528 /* 529 * Always exit on SIGTERM. Also exit on SIGINT and SIGQUIT 530 * if we're debugging. 531 */ 532 (void)signal(SIGTERM, SIG_IGN); 533 (void)signal(SIGINT, SIG_IGN); 534 (void)signal(SIGQUIT, SIG_IGN); 535 ev = allocevchange(); 536 EV_SET(ev, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 537 (intptr_t) die); 538 if (Debug) { 539 ev = allocevchange(); 540 EV_SET(ev, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 541 (intptr_t) die); 542 543 ev = allocevchange(); 544 EV_SET(ev, SIGQUIT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 545 (intptr_t) die); 546 } 547 548 ev = allocevchange(); 549 EV_SET(ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 550 (intptr_t) reapchild); 551 552 ev = allocevchange(); 553 EV_SET(ev, 0, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 554 TIMERINTVL * 1000 /* seconds -> ms */, (intptr_t) domark); 555 556 (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ 557 558 /* Re-read configuration on SIGHUP. */ 559 (void) signal(SIGHUP, SIG_IGN); 560 ev = allocevchange(); 561 EV_SET(ev, SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 562 (intptr_t) init); 563 564 if (fklog >= 0) { 565 ev = allocevchange(); 566 EV_SET(ev, fklog, EVFILT_READ, EV_ADD | EV_ENABLE, 567 0, 0, (intptr_t) dispatch_read_klog); 568 } 569 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 570 ev = allocevchange(); 571 EV_SET(ev, funix[j], EVFILT_READ, EV_ADD | EV_ENABLE, 572 0, 0, (intptr_t) dispatch_read_funix); 573 } 574 575 dprintf("Off & running....\n"); 576 577 for (;;) { 578 void (*handler)(struct kevent *); 579 int i, rv; 580 581 rv = wait_for_events(events, A_CNT(events)); 582 if (rv == 0) 583 continue; 584 if (rv < 0) { 585 if (errno != EINTR) 586 logerror("kevent() failed"); 587 continue; 588 } 589 dprintf("Got an event (%d)\n", rv); 590 for (i = 0; i < rv; i++) { 591 handler = (void *) events[i].udata; 592 (*handler)(&events[i]); 593 } 594 } 595 } 596 597 void 598 usage(void) 599 { 600 601 (void)fprintf(stderr, 602 "usage: %s [-dnrSsUv] [-f config_file] [-g group] [-m mark_interval]\n" 603 "\t[-P file_list] [-p log_socket [-p log_socket2 ...]]\n" 604 "\t[-t chroot_dir] [-u user]\n", getprogname()); 605 exit(1); 606 } 607 608 /* 609 * Dispatch routine for reading /dev/klog 610 */ 611 static void 612 dispatch_read_klog(struct kevent *ev) 613 { 614 ssize_t rv; 615 int fd = ev->ident; 616 617 dprintf("Kernel log active\n"); 618 619 rv = read(fd, linebuf, linebufsize - 1); 620 if (rv > 0) { 621 linebuf[rv] = '\0'; 622 printsys(linebuf); 623 } else if (rv < 0 && errno != EINTR) { 624 /* 625 * /dev/klog has croaked. Disable the event 626 * so it won't bother us again. 627 */ 628 struct kevent *cev = allocevchange(); 629 logerror("klog failed"); 630 EV_SET(cev, fd, EVFILT_READ, EV_DISABLE, 631 0, 0, (intptr_t) dispatch_read_klog); 632 } 633 } 634 635 /* 636 * Dispatch routine for reading Unix domain sockets. 637 */ 638 static void 639 dispatch_read_funix(struct kevent *ev) 640 { 641 struct sockaddr_un myname, fromunix; 642 ssize_t rv; 643 socklen_t sunlen; 644 int fd = ev->ident; 645 646 sunlen = sizeof(myname); 647 if (getsockname(fd, (struct sockaddr *)&myname, &sunlen) != 0) { 648 /* 649 * This should never happen, so ensure that it doesn't 650 * happen again. 651 */ 652 struct kevent *cev = allocevchange(); 653 logerror("getsockname() unix failed"); 654 EV_SET(cev, fd, EVFILT_READ, EV_DISABLE, 655 0, 0, (intptr_t) dispatch_read_funix); 656 return; 657 } 658 659 dprintf("Unix socket (%s) active\n", myname.sun_path); 660 661 sunlen = sizeof(fromunix); 662 rv = recvfrom(fd, linebuf, MAXLINE, 0, 663 (struct sockaddr *)&fromunix, &sunlen); 664 if (rv > 0) { 665 linebuf[rv] = '\0'; 666 printline(LocalHostName, linebuf); 667 } else if (rv < 0 && errno != EINTR) { 668 logerror("recvfrom() unix `%s'", myname.sun_path); 669 } 670 } 671 672 /* 673 * Dispatch routine for reading Internet sockets. 674 */ 675 static void 676 dispatch_read_finet(struct kevent *ev) 677 { 678 #ifdef LIBWRAP 679 struct request_info req; 680 #endif 681 struct sockaddr_storage frominet; 682 ssize_t rv; 683 socklen_t len; 684 int fd = ev->ident; 685 int reject = 0; 686 687 dprintf("inet socket active\n"); 688 689 #ifdef LIBWRAP 690 request_init(&req, RQ_DAEMON, "syslogd", RQ_FILE, fd, NULL); 691 fromhost(&req); 692 reject = !hosts_access(&req); 693 if (reject) 694 dprintf("access denied\n"); 695 #endif 696 697 len = sizeof(frominet); 698 rv = recvfrom(fd, linebuf, MAXLINE, 0, 699 (struct sockaddr *)&frominet, &len); 700 if (rv == 0 || (rv < 0 && errno == EINTR)) 701 return; 702 else if (rv < 0) { 703 logerror("recvfrom inet"); 704 return; 705 } 706 707 linebuf[rv] = '\0'; 708 if (!reject) 709 printline(cvthname(&frominet), linebuf); 710 } 711 712 /* 713 * given a pointer to an array of char *'s, a pointer to it's current 714 * size and current allocated max size, and a new char * to add, add 715 * it, update everything as necessary, possibly allocating a new array 716 */ 717 void 718 logpath_add(char ***lp, int *szp, int *maxszp, char *new) 719 { 720 char **nlp; 721 int newmaxsz; 722 723 dprintf("Adding `%s' to the %p logpath list\n", new, *lp); 724 if (*szp == *maxszp) { 725 if (*maxszp == 0) { 726 newmaxsz = 4; /* start of with enough for now */ 727 *lp = NULL; 728 } else 729 newmaxsz = *maxszp * 2; 730 nlp = realloc(*lp, sizeof(char *) * (newmaxsz + 1)); 731 if (nlp == NULL) { 732 logerror("Couldn't allocate line buffer"); 733 die(NULL); 734 } 735 *lp = nlp; 736 *maxszp = newmaxsz; 737 } 738 if (((*lp)[(*szp)++] = strdup(new)) == NULL) { 739 logerror("Couldn't allocate logpath"); 740 die(NULL); 741 } 742 (*lp)[(*szp)] = NULL; /* always keep it NULL terminated */ 743 } 744 745 /* do a file of log sockets */ 746 void 747 logpath_fileadd(char ***lp, int *szp, int *maxszp, char *file) 748 { 749 FILE *fp; 750 char *line; 751 size_t len; 752 753 fp = fopen(file, "r"); 754 if (fp == NULL) { 755 logerror("Could not open socket file list `%s'", file); 756 die(NULL); 757 } 758 759 while ((line = fgetln(fp, &len))) { 760 line[len - 1] = 0; 761 logpath_add(lp, szp, maxszp, line); 762 } 763 fclose(fp); 764 } 765 766 /* 767 * Take a raw input line, decode the message, and print the message 768 * on the appropriate log files. 769 */ 770 void 771 printline(char *hname, char *msg) 772 { 773 int c, pri; 774 char *p, *q, line[MAXLINE + 1]; 775 long n; 776 777 /* test for special codes */ 778 pri = DEFUPRI; 779 p = msg; 780 if (*p == '<') { 781 errno = 0; 782 n = strtol(p + 1, &q, 10); 783 if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 784 p = q + 1; 785 pri = (int)n; 786 } 787 } 788 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 789 pri = DEFUPRI; 790 791 /* 792 * Don't allow users to log kernel messages. 793 * NOTE: Since LOG_KERN == 0, this will also match 794 * messages with no facility specified. 795 */ 796 if ((pri & LOG_FACMASK) == LOG_KERN) 797 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 798 799 q = line; 800 801 while ((c = *p++) != '\0' && 802 q < &line[sizeof(line) - 2]) { 803 c &= 0177; 804 if (iscntrl(c)) 805 if (c == '\n') 806 *q++ = ' '; 807 else if (c == '\t') 808 *q++ = '\t'; 809 else { 810 *q++ = '^'; 811 *q++ = c ^ 0100; 812 } 813 else 814 *q++ = c; 815 } 816 *q = '\0'; 817 818 logmsg(pri, line, hname, 0); 819 } 820 821 /* 822 * Take a raw input line from /dev/klog, split and format similar to syslog(). 823 */ 824 void 825 printsys(char *msg) 826 { 827 int n, pri, flags, is_printf; 828 char *p, *q; 829 830 for (p = msg; *p != '\0'; ) { 831 flags = ISKERNEL | ADDDATE; 832 if (SyncKernel) 833 flags |= SYNC_FILE; 834 pri = DEFSPRI; 835 is_printf = 1; 836 if (*p == '<') { 837 errno = 0; 838 n = (int)strtol(p + 1, &q, 10); 839 if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 840 p = q + 1; 841 pri = n; 842 is_printf = 0; 843 } 844 } 845 if (is_printf) { 846 /* kernel printf's come out on console */ 847 flags |= IGN_CONS; 848 } 849 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 850 pri = DEFSPRI; 851 for (q = p; *q != '\0' && *q != '\n'; q++) 852 /* look for end of line */; 853 if (*q != '\0') 854 *q++ = '\0'; 855 logmsg(pri, p, LocalHostName, flags); 856 p = q; 857 } 858 } 859 860 time_t now; 861 862 /* 863 * Check to see if `name' matches the provided specification, using the 864 * specified strstr function. 865 */ 866 int 867 matches_spec(const char *name, const char *spec, 868 char *(*check)(const char *, const char *)) 869 { 870 const char *s; 871 char prev, next; 872 873 if ((s = (*check)(spec, name)) != NULL) { 874 prev = s == spec ? ',' : *(s - 1); 875 next = *(s + strlen(name)); 876 877 if (prev == ',' && (next == '\0' || next == ',')) 878 return (1); 879 } 880 881 return (0); 882 } 883 884 /* 885 * Log a message to the appropriate log files, users, etc. based on 886 * the priority. 887 */ 888 void 889 logmsg(int pri, char *msg, char *from, int flags) 890 { 891 struct filed *f; 892 int fac, msglen, omask, prilev, i; 893 char *timestamp; 894 char prog[NAME_MAX + 1]; 895 char buf[MAXLINE + 1]; 896 897 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 898 pri, flags, from, msg); 899 900 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 901 902 /* 903 * Check to see if msg looks non-standard. 904 */ 905 msglen = strlen(msg); 906 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 907 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 908 flags |= ADDDATE; 909 910 (void)time(&now); 911 if (flags & ADDDATE) 912 timestamp = ctime(&now) + 4; 913 else { 914 timestamp = msg; 915 msg += 16; 916 msglen -= 16; 917 } 918 919 /* skip leading whitespace */ 920 while (isspace((unsigned char)*msg)) { 921 msg++; 922 msglen--; 923 } 924 925 /* extract facility and priority level */ 926 if (flags & MARK) 927 fac = LOG_NFACILITIES; 928 else 929 fac = LOG_FAC(pri); 930 prilev = LOG_PRI(pri); 931 932 /* extract program name */ 933 for (i = 0; i < NAME_MAX; i++) { 934 if (!isprint((unsigned char)msg[i]) || 935 msg[i] == ':' || msg[i] == '[') 936 break; 937 prog[i] = msg[i]; 938 } 939 prog[i] = '\0'; 940 941 /* add kernel prefix for kernel messages */ 942 if (flags & ISKERNEL) { 943 snprintf(buf, sizeof(buf), "%s: %s", 944 _PATH_UNIX, msg); 945 msg = buf; 946 msglen = strlen(buf); 947 } 948 949 /* log the message to the particular outputs */ 950 if (!Initialized) { 951 f = &consfile; 952 f->f_file = open(ctty, O_WRONLY, 0); 953 954 if (f->f_file >= 0) { 955 (void)strncpy(f->f_lasttime, timestamp, 15); 956 fprintlog(f, flags, msg); 957 (void)close(f->f_file); 958 } 959 (void)sigsetmask(omask); 960 return; 961 } 962 for (f = Files; f; f = f->f_next) { 963 /* skip messages that are incorrect priority */ 964 if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev)) 965 ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev)) 966 ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev)) 967 ) 968 || f->f_pmask[fac] == INTERNAL_NOPRI) 969 continue; 970 971 /* skip messages with the incorrect host name */ 972 if (f->f_host != NULL) { 973 switch (f->f_host[0]) { 974 case '+': 975 if (! matches_spec(from, f->f_host + 1, 976 strcasestr)) 977 continue; 978 break; 979 case '-': 980 if (matches_spec(from, f->f_host + 1, 981 strcasestr)) 982 continue; 983 break; 984 } 985 } 986 987 /* skip messages with the incorrect program name */ 988 if (f->f_program != NULL) { 989 switch (f->f_program[0]) { 990 case '+': 991 if (! matches_spec(prog, f->f_program + 1, 992 strstr)) 993 continue; 994 break; 995 case '-': 996 if (matches_spec(prog, f->f_program + 1, 997 strstr)) 998 continue; 999 break; 1000 default: 1001 if (! matches_spec(prog, f->f_program, 1002 strstr)) 1003 continue; 1004 break; 1005 } 1006 } 1007 1008 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 1009 continue; 1010 1011 /* don't output marks to recently written files */ 1012 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 1013 continue; 1014 1015 /* 1016 * suppress duplicate lines to this file unless NoRepeat 1017 */ 1018 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 1019 !NoRepeat && 1020 !strcmp(msg, f->f_prevline) && 1021 !strcasecmp(from, f->f_prevhost)) { 1022 (void)strncpy(f->f_lasttime, timestamp, 15); 1023 f->f_prevcount++; 1024 dprintf("Msg repeated %d times, %ld sec of %d\n", 1025 f->f_prevcount, (long)(now - f->f_time), 1026 repeatinterval[f->f_repeatcount]); 1027 /* 1028 * If domark would have logged this by now, 1029 * flush it now (so we don't hold isolated messages), 1030 * but back off so we'll flush less often 1031 * in the future. 1032 */ 1033 if (now > REPEATTIME(f)) { 1034 fprintlog(f, flags, (char *)NULL); 1035 BACKOFF(f); 1036 } 1037 } else { 1038 /* new line, save it */ 1039 if (f->f_prevcount) 1040 fprintlog(f, 0, (char *)NULL); 1041 f->f_repeatcount = 0; 1042 f->f_prevpri = pri; 1043 (void)strncpy(f->f_lasttime, timestamp, 15); 1044 (void)strncpy(f->f_prevhost, from, 1045 sizeof(f->f_prevhost)); 1046 if (msglen < MAXSVLINE) { 1047 f->f_prevlen = msglen; 1048 (void)strlcpy(f->f_prevline, msg, 1049 sizeof(f->f_prevline)); 1050 fprintlog(f, flags, (char *)NULL); 1051 } else { 1052 f->f_prevline[0] = 0; 1053 f->f_prevlen = 0; 1054 fprintlog(f, flags, msg); 1055 } 1056 } 1057 } 1058 (void)sigsetmask(omask); 1059 } 1060 1061 void 1062 fprintlog(struct filed *f, int flags, char *msg) 1063 { 1064 struct iovec iov[7]; 1065 struct iovec *v; 1066 struct addrinfo *r; 1067 int j, l, lsent; 1068 char line[MAXLINE + 1], repbuf[80], greetings[200]; 1069 1070 v = iov; 1071 if (f->f_type == F_WALL) { 1072 v->iov_base = greetings; 1073 v->iov_len = snprintf(greetings, sizeof greetings, 1074 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 1075 f->f_prevhost, ctime(&now)); 1076 v++; 1077 v->iov_base = ""; 1078 v->iov_len = 0; 1079 v++; 1080 } else { 1081 v->iov_base = f->f_lasttime; 1082 v->iov_len = 15; 1083 v++; 1084 v->iov_base = " "; 1085 v->iov_len = 1; 1086 v++; 1087 } 1088 1089 if (LogFacPri) { 1090 static char fp_buf[30]; 1091 const char *f_s = NULL, *p_s = NULL; 1092 int fac = f->f_prevpri & LOG_FACMASK; 1093 int pri = LOG_PRI(f->f_prevpri); 1094 char f_n[5], p_n[5]; 1095 1096 if (LogFacPri > 1) { 1097 CODE *c; 1098 1099 for (c = facilitynames; c->c_name != NULL; c++) { 1100 if (c->c_val == fac) { 1101 f_s = c->c_name; 1102 break; 1103 } 1104 } 1105 for (c = prioritynames; c->c_name != NULL; c++) { 1106 if (c->c_val == pri) { 1107 p_s = c->c_name; 1108 break; 1109 } 1110 } 1111 } 1112 if (f_s == NULL) { 1113 snprintf(f_n, sizeof(f_n), "%d", LOG_FAC(fac)); 1114 f_s = f_n; 1115 } 1116 if (p_s == NULL) { 1117 snprintf(p_n, sizeof(p_n), "%d", pri); 1118 p_s = p_n; 1119 } 1120 snprintf(fp_buf, sizeof(fp_buf), "<%s.%s>", f_s, p_s); 1121 v->iov_base = fp_buf; 1122 v->iov_len = strlen(fp_buf); 1123 } else { 1124 v->iov_base = ""; 1125 v->iov_len = 0; 1126 } 1127 v++; 1128 1129 v->iov_base = f->f_prevhost; 1130 v->iov_len = strlen(v->iov_base); 1131 v++; 1132 v->iov_base = " "; 1133 v->iov_len = 1; 1134 v++; 1135 1136 if (msg) { 1137 v->iov_base = msg; 1138 v->iov_len = strlen(msg); 1139 } else if (f->f_prevcount > 1) { 1140 v->iov_base = repbuf; 1141 v->iov_len = snprintf(repbuf, sizeof repbuf, 1142 "last message repeated %d times", f->f_prevcount); 1143 } else { 1144 v->iov_base = f->f_prevline; 1145 v->iov_len = f->f_prevlen; 1146 } 1147 v++; 1148 1149 dprintf("Logging to %s", TypeNames[f->f_type]); 1150 f->f_time = now; 1151 1152 switch (f->f_type) { 1153 case F_UNUSED: 1154 dprintf("\n"); 1155 break; 1156 1157 case F_FORW: 1158 dprintf(" %s\n", f->f_un.f_forw.f_hname); 1159 /* 1160 * check for local vs remote messages 1161 * (from FreeBSD PR#bin/7055) 1162 */ 1163 if (strcasecmp(f->f_prevhost, LocalHostName)) { 1164 l = snprintf(line, sizeof(line) - 1, 1165 "<%d>%.15s [%s]: %s", 1166 f->f_prevpri, (char *) iov[0].iov_base, 1167 f->f_prevhost, (char *) iov[5].iov_base); 1168 } else { 1169 l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s", 1170 f->f_prevpri, (char *) iov[0].iov_base, 1171 (char *) iov[5].iov_base); 1172 } 1173 if (l > MAXLINE) 1174 l = MAXLINE; 1175 if (finet) { 1176 for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 1177 for (j = 0; j < *finet; j++) { 1178 #if 0 1179 /* 1180 * should we check AF first, or just 1181 * trial and error? FWD 1182 */ 1183 if (r->ai_family == 1184 address_family_of(finet[j+1])) 1185 #endif 1186 lsent = sendto(finet[j+1], line, l, 0, 1187 r->ai_addr, r->ai_addrlen); 1188 if (lsent == l) 1189 break; 1190 } 1191 } 1192 if (lsent != l) { 1193 f->f_type = F_UNUSED; 1194 logerror("sendto() failed"); 1195 } 1196 } 1197 break; 1198 1199 case F_PIPE: 1200 dprintf(" %s\n", f->f_un.f_pipe.f_pname); 1201 v->iov_base = "\n"; 1202 v->iov_len = 1; 1203 if (f->f_un.f_pipe.f_pid == 0) { 1204 if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 1205 &f->f_un.f_pipe.f_pid)) < 0) { 1206 f->f_type = F_UNUSED; 1207 logerror(f->f_un.f_pipe.f_pname); 1208 break; 1209 } 1210 } 1211 if (writev(f->f_file, iov, 7) < 0) { 1212 int e = errno; 1213 if (f->f_un.f_pipe.f_pid > 0) { 1214 (void) close(f->f_file); 1215 deadq_enter(f->f_un.f_pipe.f_pid, 1216 f->f_un.f_pipe.f_pname); 1217 } 1218 f->f_un.f_pipe.f_pid = 0; 1219 /* 1220 * If the error was EPIPE, then what is likely 1221 * has happened is we have a command that is 1222 * designed to take a single message line and 1223 * then exit, but we tried to feed it another 1224 * one before we reaped the child and thus 1225 * reset our state. 1226 * 1227 * Well, now we've reset our state, so try opening 1228 * the pipe and sending the message again if EPIPE 1229 * was the error. 1230 */ 1231 if (e == EPIPE) { 1232 if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 1233 &f->f_un.f_pipe.f_pid)) < 0) { 1234 f->f_type = F_UNUSED; 1235 logerror(f->f_un.f_pipe.f_pname); 1236 break; 1237 } 1238 if (writev(f->f_file, iov, 7) < 0) { 1239 e = errno; 1240 if (f->f_un.f_pipe.f_pid > 0) { 1241 (void) close(f->f_file); 1242 deadq_enter(f->f_un.f_pipe.f_pid, 1243 f->f_un.f_pipe.f_pname); 1244 } 1245 f->f_un.f_pipe.f_pid = 0; 1246 } else 1247 e = 0; 1248 } 1249 if (e != 0) { 1250 errno = e; 1251 logerror(f->f_un.f_pipe.f_pname); 1252 } 1253 } 1254 break; 1255 1256 case F_CONSOLE: 1257 if (flags & IGN_CONS) { 1258 dprintf(" (ignored)\n"); 1259 break; 1260 } 1261 /* FALLTHROUGH */ 1262 1263 case F_TTY: 1264 case F_FILE: 1265 dprintf(" %s\n", f->f_un.f_fname); 1266 if (f->f_type != F_FILE) { 1267 v->iov_base = "\r\n"; 1268 v->iov_len = 2; 1269 } else { 1270 v->iov_base = "\n"; 1271 v->iov_len = 1; 1272 } 1273 again: 1274 if (writev(f->f_file, iov, 7) < 0) { 1275 int e = errno; 1276 (void)close(f->f_file); 1277 /* 1278 * Check for errors on TTY's due to loss of tty 1279 */ 1280 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 1281 f->f_file = open(f->f_un.f_fname, 1282 O_WRONLY|O_APPEND, 0); 1283 if (f->f_file < 0) { 1284 f->f_type = F_UNUSED; 1285 logerror(f->f_un.f_fname); 1286 } else 1287 goto again; 1288 } else { 1289 f->f_type = F_UNUSED; 1290 errno = e; 1291 logerror(f->f_un.f_fname); 1292 } 1293 } else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) 1294 (void)fsync(f->f_file); 1295 break; 1296 1297 case F_USERS: 1298 case F_WALL: 1299 dprintf("\n"); 1300 v->iov_base = "\r\n"; 1301 v->iov_len = 2; 1302 wallmsg(f, iov); 1303 break; 1304 } 1305 f->f_prevcount = 0; 1306 } 1307 1308 /* 1309 * WALLMSG -- Write a message to the world at large 1310 * 1311 * Write the specified message to either the entire 1312 * world, or a list of approved users. 1313 */ 1314 void 1315 wallmsg(struct filed *f, struct iovec *iov) 1316 { 1317 static int reenter; /* avoid calling ourselves */ 1318 int i; 1319 char *p; 1320 static struct utmpentry *ohead = NULL; 1321 struct utmpentry *ep; 1322 1323 if (reenter++) 1324 return; 1325 1326 (void)getutentries(NULL, &ep); 1327 if (ep != ohead) { 1328 freeutentries(ohead); 1329 ohead = ep; 1330 } 1331 /* NOSTRICT */ 1332 for (; ep; ep = ep->next) { 1333 if (f->f_type == F_WALL) { 1334 if ((p = ttymsg(iov, 7, ep->line, TTYMSGTIME)) 1335 != NULL) { 1336 errno = 0; /* already in msg */ 1337 logerror(p); 1338 } 1339 continue; 1340 } 1341 /* should we send the message to this user? */ 1342 for (i = 0; i < MAXUNAMES; i++) { 1343 if (!f->f_un.f_uname[i][0]) 1344 break; 1345 if (strcmp(f->f_un.f_uname[i], ep->name) == 0) { 1346 if ((p = ttymsg(iov, 7, ep->line, TTYMSGTIME)) 1347 != NULL) { 1348 errno = 0; /* already in msg */ 1349 logerror(p); 1350 } 1351 break; 1352 } 1353 } 1354 } 1355 reenter = 0; 1356 } 1357 1358 void 1359 reapchild(struct kevent *ev) 1360 { 1361 int status; 1362 pid_t pid; 1363 struct filed *f; 1364 1365 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { 1366 if (!Initialized || ShuttingDown) { 1367 /* 1368 * Be silent while we are initializing or 1369 * shutting down. 1370 */ 1371 continue; 1372 } 1373 1374 if (deadq_remove(pid)) 1375 continue; 1376 1377 /* Now, look in the list of active processes. */ 1378 for (f = Files; f != NULL; f = f->f_next) { 1379 if (f->f_type == F_PIPE && 1380 f->f_un.f_pipe.f_pid == pid) { 1381 (void) close(f->f_file); 1382 f->f_un.f_pipe.f_pid = 0; 1383 log_deadchild(pid, status, 1384 f->f_un.f_pipe.f_pname); 1385 break; 1386 } 1387 } 1388 } 1389 } 1390 1391 /* 1392 * Return a printable representation of a host address. 1393 */ 1394 char * 1395 cvthname(struct sockaddr_storage *f) 1396 { 1397 int error; 1398 const int niflag = NI_DGRAM; 1399 static char host[NI_MAXHOST], ip[NI_MAXHOST]; 1400 1401 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1402 ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag); 1403 1404 dprintf("cvthname(%s)\n", ip); 1405 1406 if (error) { 1407 dprintf("Malformed from address %s\n", gai_strerror(error)); 1408 return ("???"); 1409 } 1410 1411 if (!UseNameService) 1412 return (ip); 1413 1414 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1415 host, sizeof host, NULL, 0, niflag); 1416 if (error) { 1417 dprintf("Host name for your address (%s) unknown\n", ip); 1418 return (ip); 1419 } 1420 1421 trim_localdomain(host); 1422 1423 return (host); 1424 } 1425 1426 void 1427 trim_localdomain(char *host) 1428 { 1429 size_t hl; 1430 1431 hl = strlen(host); 1432 if (hl > 0 && host[hl - 1] == '.') 1433 host[--hl] = '\0'; 1434 1435 if (hl > LocalDomainLen && host[hl - LocalDomainLen - 1] == '.' && 1436 strcasecmp(&host[hl - LocalDomainLen], LocalDomain) == 0) 1437 host[hl - LocalDomainLen - 1] = '\0'; 1438 } 1439 1440 void 1441 domark(struct kevent *ev) 1442 { 1443 struct filed *f; 1444 dq_t q, nextq; 1445 1446 /* 1447 * XXX Should we bother to adjust for the # of times the timer 1448 * has expired (i.e. in case we miss one?). This information is 1449 * returned to us in ev->data. 1450 */ 1451 1452 now = time((time_t *)NULL); 1453 MarkSeq += TIMERINTVL; 1454 if (MarkSeq >= MarkInterval) { 1455 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 1456 MarkSeq = 0; 1457 } 1458 1459 for (f = Files; f; f = f->f_next) { 1460 if (f->f_prevcount && now >= REPEATTIME(f)) { 1461 dprintf("Flush %s: repeated %d times, %d sec.\n", 1462 TypeNames[f->f_type], f->f_prevcount, 1463 repeatinterval[f->f_repeatcount]); 1464 fprintlog(f, 0, (char *)NULL); 1465 BACKOFF(f); 1466 } 1467 } 1468 1469 /* Walk the dead queue, and see if we should signal somebody. */ 1470 for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = nextq) { 1471 nextq = TAILQ_NEXT(q, dq_entries); 1472 switch (q->dq_timeout) { 1473 case 0: 1474 /* Already signalled once, try harder now. */ 1475 if (kill(q->dq_pid, SIGKILL) != 0) 1476 (void) deadq_remove(q->dq_pid); 1477 break; 1478 1479 case 1: 1480 /* 1481 * Timed out on the dead queue, send terminate 1482 * signal. Note that we leave the removal from 1483 * the dead queue to reapchild(), which will 1484 * also log the event (unless the process 1485 * didn't even really exist, in case we simply 1486 * drop it from the dead queue). 1487 */ 1488 if (kill(q->dq_pid, SIGTERM) != 0) { 1489 (void) deadq_remove(q->dq_pid); 1490 break; 1491 } 1492 /* FALLTHROUGH */ 1493 1494 default: 1495 q->dq_timeout--; 1496 } 1497 } 1498 } 1499 1500 /* 1501 * Print syslogd errors some place. 1502 */ 1503 void 1504 logerror(const char *fmt, ...) 1505 { 1506 static int logerror_running; 1507 va_list ap; 1508 char tmpbuf[BUFSIZ]; 1509 char buf[BUFSIZ]; 1510 1511 /* If there's an error while trying to log an error, give up. */ 1512 if (logerror_running) 1513 return; 1514 logerror_running = 1; 1515 1516 va_start(ap, fmt); 1517 1518 (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap); 1519 1520 va_end(ap); 1521 1522 if (errno) 1523 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1524 tmpbuf, strerror(errno)); 1525 else 1526 (void)snprintf(buf, sizeof(buf), "syslogd: %s", tmpbuf); 1527 1528 if (daemonized) 1529 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1530 if (!daemonized && Debug) 1531 dprintf("%s\n", buf); 1532 if (!daemonized && !Debug) 1533 printf("%s\n", buf); 1534 1535 logerror_running = 0; 1536 } 1537 1538 void 1539 die(struct kevent *ev) 1540 { 1541 struct filed *f; 1542 char **p; 1543 1544 ShuttingDown = 1; /* Don't log SIGCHLDs. */ 1545 for (f = Files; f != NULL; f = f->f_next) { 1546 /* flush any pending output */ 1547 if (f->f_prevcount) 1548 fprintlog(f, 0, (char *)NULL); 1549 if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) { 1550 (void) close(f->f_file); 1551 f->f_un.f_pipe.f_pid = 0; 1552 } 1553 } 1554 errno = 0; 1555 if (ev != NULL) 1556 logerror("Exiting on signal %d", (int) ev->ident); 1557 else 1558 logerror("Fatal error, exiting"); 1559 for (p = LogPaths; p && *p; p++) 1560 unlink(*p); 1561 exit(0); 1562 } 1563 1564 /* 1565 * INIT -- Initialize syslogd from configuration table 1566 */ 1567 void 1568 init(struct kevent *ev) 1569 { 1570 int i; 1571 FILE *cf; 1572 struct filed *f, *next, **nextp; 1573 char *p; 1574 char cline[LINE_MAX]; 1575 char prog[NAME_MAX + 1]; 1576 char host[MAXHOSTNAMELEN]; 1577 char hostMsg[2*MAXHOSTNAMELEN + 40]; 1578 1579 dprintf("init\n"); 1580 1581 (void)strlcpy(oldLocalHostName, LocalHostName, 1582 sizeof(oldLocalHostName)); 1583 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 1584 if ((p = strchr(LocalHostName, '.')) != NULL) { 1585 *p++ = '\0'; 1586 LocalDomain = p; 1587 } else 1588 LocalDomain = ""; 1589 LocalDomainLen = strlen(LocalDomain); 1590 1591 /* 1592 * Close all open log files. 1593 */ 1594 Initialized = 0; 1595 for (f = Files; f != NULL; f = next) { 1596 /* flush any pending output */ 1597 if (f->f_prevcount) 1598 fprintlog(f, 0, (char *)NULL); 1599 1600 switch (f->f_type) { 1601 case F_FILE: 1602 case F_TTY: 1603 case F_CONSOLE: 1604 (void)close(f->f_file); 1605 break; 1606 case F_PIPE: 1607 if (f->f_un.f_pipe.f_pid > 0) { 1608 (void)close(f->f_file); 1609 deadq_enter(f->f_un.f_pipe.f_pid, 1610 f->f_un.f_pipe.f_pname); 1611 } 1612 f->f_un.f_pipe.f_pid = 0; 1613 break; 1614 case F_FORW: 1615 if (f->f_un.f_forw.f_addr) 1616 freeaddrinfo(f->f_un.f_forw.f_addr); 1617 break; 1618 } 1619 next = f->f_next; 1620 if (f->f_program != NULL) 1621 free(f->f_program); 1622 if (f->f_host != NULL) 1623 free(f->f_host); 1624 free((char *)f); 1625 } 1626 Files = NULL; 1627 nextp = &Files; 1628 1629 /* 1630 * Close all open sockets 1631 */ 1632 1633 if (finet) { 1634 for (i = 0; i < *finet; i++) { 1635 if (close(finet[i+1]) < 0) { 1636 logerror("close() failed"); 1637 die(NULL); 1638 } 1639 } 1640 } 1641 1642 /* 1643 * Reset counter of forwarding actions 1644 */ 1645 1646 NumForwards=0; 1647 1648 /* open the configuration file */ 1649 if ((cf = fopen(ConfFile, "r")) == NULL) { 1650 dprintf("Cannot open `%s'\n", ConfFile); 1651 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1652 cfline("*.ERR\t/dev/console", *nextp, "*", "*"); 1653 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1654 cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*"); 1655 Initialized = 1; 1656 return; 1657 } 1658 1659 /* 1660 * Foreach line in the conf table, open that file. 1661 */ 1662 f = NULL; 1663 strcpy(prog, "*"); 1664 strcpy(host, "*"); 1665 while (fgets(cline, sizeof(cline), cf) != NULL) { 1666 /* 1667 * check for end-of-section, comments, strip off trailing 1668 * spaces and newline character. #!prog is treated specially: 1669 * following lines apply only to that program. 1670 */ 1671 for (p = cline; isspace((unsigned char)*p); ++p) 1672 continue; 1673 if (*p == '\0') 1674 continue; 1675 if (*p == '#') { 1676 p++; 1677 if (*p != '!' && *p != '+' && *p != '-') 1678 continue; 1679 } 1680 if (*p == '+' || *p == '-') { 1681 host[0] = *p++; 1682 while (isspace((unsigned char)*p)) 1683 p++; 1684 if (*p == '\0' || *p == '*') { 1685 strcpy(host, "*"); 1686 continue; 1687 } 1688 if (*p == '@') 1689 p = LocalHostName; 1690 for (i = 1; i < MAXHOSTNAMELEN - 1; i++) { 1691 if (!isalnum((unsigned char)*p) && 1692 *p != '.' && *p != '-' && *p != ',') 1693 break; 1694 host[i] = *p++; 1695 } 1696 host[i] = '\0'; 1697 continue; 1698 } 1699 if (*p == '!') { 1700 p++; 1701 while (isspace((unsigned char)*p)) 1702 p++; 1703 if (*p == '\0' || *p == '*') { 1704 strcpy(prog, "*"); 1705 continue; 1706 } 1707 for (i = 0; i < NAME_MAX; i++) { 1708 if (!isprint((unsigned char)p[i])) 1709 break; 1710 prog[i] = p[i]; 1711 } 1712 prog[i] = '\0'; 1713 continue; 1714 } 1715 for (p = strchr(cline, '\0'); isspace((unsigned char)*--p);) 1716 continue; 1717 *++p = '\0'; 1718 f = (struct filed *)calloc(1, sizeof(*f)); 1719 *nextp = f; 1720 nextp = &f->f_next; 1721 cfline(cline, f, prog, host); 1722 } 1723 1724 /* close the configuration file */ 1725 (void)fclose(cf); 1726 1727 Initialized = 1; 1728 1729 if (Debug) { 1730 for (f = Files; f; f = f->f_next) { 1731 for (i = 0; i <= LOG_NFACILITIES; i++) 1732 if (f->f_pmask[i] == INTERNAL_NOPRI) 1733 printf("X "); 1734 else 1735 printf("%d ", f->f_pmask[i]); 1736 printf("%s: ", TypeNames[f->f_type]); 1737 switch (f->f_type) { 1738 case F_FILE: 1739 case F_TTY: 1740 case F_CONSOLE: 1741 printf("%s", f->f_un.f_fname); 1742 break; 1743 1744 case F_FORW: 1745 printf("%s", f->f_un.f_forw.f_hname); 1746 break; 1747 1748 case F_PIPE: 1749 printf("%s", f->f_un.f_pipe.f_pname); 1750 break; 1751 1752 case F_USERS: 1753 for (i = 0; 1754 i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1755 printf("%s, ", f->f_un.f_uname[i]); 1756 break; 1757 } 1758 if (f->f_program != NULL) 1759 printf(" (%s)", f->f_program); 1760 printf("\n"); 1761 } 1762 } 1763 1764 finet = socksetup(PF_UNSPEC); 1765 if (finet) { 1766 if (SecureMode) { 1767 for (i = 0; i < *finet; i++) { 1768 if (shutdown(finet[i+1], SHUT_RD) < 0) { 1769 logerror("shutdown() failed"); 1770 die(NULL); 1771 } 1772 } 1773 } else 1774 dprintf("Listening on inet and/or inet6 socket\n"); 1775 dprintf("Sending on inet and/or inet6 socket\n"); 1776 } 1777 1778 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 1779 dprintf("syslogd: restarted\n"); 1780 /* 1781 * Log a change in hostname, but only on a restart (we detect this 1782 * by checking to see if we're passed a kevent). 1783 */ 1784 if (ev != NULL && strcmp(oldLocalHostName, LocalHostName) != 0) { 1785 (void)snprintf(hostMsg, sizeof(hostMsg), 1786 "syslogd: host name changed, \"%s\" to \"%s\"", 1787 oldLocalHostName, LocalHostName); 1788 logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE); 1789 dprintf("%s\n", hostMsg); 1790 } 1791 } 1792 1793 /* 1794 * Crack a configuration file line 1795 */ 1796 void 1797 cfline(char *line, struct filed *f, char *prog, char *host) 1798 { 1799 struct addrinfo hints, *res; 1800 int error, i, pri, syncfile; 1801 char *bp, *p, *q; 1802 char buf[MAXLINE]; 1803 1804 dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host); 1805 1806 errno = 0; /* keep strerror() stuff out of logerror messages */ 1807 1808 /* clear out file entry */ 1809 memset(f, 0, sizeof(*f)); 1810 for (i = 0; i <= LOG_NFACILITIES; i++) 1811 f->f_pmask[i] = INTERNAL_NOPRI; 1812 1813 /* 1814 * There should not be any space before the log facility. 1815 * Check this is okay, complain and fix if it is not. 1816 */ 1817 q = line; 1818 if (isblank((unsigned char)*line)) { 1819 errno = 0; 1820 logerror( 1821 "Warning: `%s' space or tab before the log facility", 1822 line); 1823 /* Fix: strip all spaces/tabs before the log facility */ 1824 while (*q++ && isblank((unsigned char)*q)) 1825 /* skip blanks */; 1826 line = q; 1827 } 1828 1829 /* 1830 * q is now at the first char of the log facility 1831 * There should be at least one tab after the log facility 1832 * Check this is okay, and complain and fix if it is not. 1833 */ 1834 q = line + strlen(line); 1835 while (!isblank((unsigned char)*q) && (q != line)) 1836 q--; 1837 if ((q == line) && strlen(line)) { 1838 /* No tabs or space in a non empty line: complain */ 1839 errno = 0; 1840 logerror( 1841 "Error: `%s' log facility or log target missing", 1842 line); 1843 return; 1844 } 1845 1846 /* save host name, if any */ 1847 if (*host == '*') 1848 f->f_host = NULL; 1849 else { 1850 f->f_host = strdup(host); 1851 trim_localdomain(f->f_host); 1852 } 1853 1854 /* save program name, if any */ 1855 if (*prog == '*') 1856 f->f_program = NULL; 1857 else 1858 f->f_program = strdup(prog); 1859 1860 /* scan through the list of selectors */ 1861 for (p = line; *p && !isblank((unsigned char)*p);) { 1862 int pri_done, pri_cmp, pri_invert; 1863 1864 /* find the end of this facility name list */ 1865 for (q = p; *q && !isblank((unsigned char)*q) && *q++ != '.'; ) 1866 continue; 1867 1868 /* get the priority comparison */ 1869 pri_cmp = 0; 1870 pri_done = 0; 1871 pri_invert = 0; 1872 if (*q == '!') { 1873 pri_invert = 1; 1874 q++; 1875 } 1876 while (! pri_done) { 1877 switch (*q) { 1878 case '<': 1879 pri_cmp = PRI_LT; 1880 q++; 1881 break; 1882 case '=': 1883 pri_cmp = PRI_EQ; 1884 q++; 1885 break; 1886 case '>': 1887 pri_cmp = PRI_GT; 1888 q++; 1889 break; 1890 default: 1891 pri_done = 1; 1892 break; 1893 } 1894 } 1895 1896 /* collect priority name */ 1897 for (bp = buf; *q && !strchr("\t ,;", *q); ) 1898 *bp++ = *q++; 1899 *bp = '\0'; 1900 1901 /* skip cruft */ 1902 while (strchr(",;", *q)) 1903 q++; 1904 1905 /* decode priority name */ 1906 if (*buf == '*') { 1907 pri = LOG_PRIMASK + 1; 1908 pri_cmp = PRI_LT | PRI_EQ | PRI_GT; 1909 } else { 1910 pri = decode(buf, prioritynames); 1911 if (pri < 0) { 1912 errno = 0; 1913 logerror("Unknown priority name `%s'", buf); 1914 return; 1915 } 1916 } 1917 if (pri_cmp == 0) 1918 pri_cmp = UniquePriority ? PRI_EQ 1919 : PRI_EQ | PRI_GT; 1920 if (pri_invert) 1921 pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT; 1922 1923 /* scan facilities */ 1924 while (*p && !strchr("\t .;", *p)) { 1925 for (bp = buf; *p && !strchr("\t ,;.", *p); ) 1926 *bp++ = *p++; 1927 *bp = '\0'; 1928 if (*buf == '*') 1929 for (i = 0; i < LOG_NFACILITIES; i++) { 1930 f->f_pmask[i] = pri; 1931 f->f_pcmp[i] = pri_cmp; 1932 } 1933 else { 1934 i = decode(buf, facilitynames); 1935 if (i < 0) { 1936 errno = 0; 1937 logerror("Unknown facility name `%s'", 1938 buf); 1939 return; 1940 } 1941 f->f_pmask[i >> 3] = pri; 1942 f->f_pmask[i >> 3] = pri_cmp; 1943 } 1944 while (*p == ',' || *p == ' ') 1945 p++; 1946 } 1947 1948 p = q; 1949 } 1950 1951 /* skip to action part */ 1952 while (isblank((unsigned char)*p)) 1953 p++; 1954 1955 if (*p == '-') { 1956 syncfile = 0; 1957 p++; 1958 } else 1959 syncfile = 1; 1960 1961 switch (*p) { 1962 case '@': 1963 (void)strlcpy(f->f_un.f_forw.f_hname, ++p, 1964 sizeof(f->f_un.f_forw.f_hname)); 1965 memset(&hints, 0, sizeof(hints)); 1966 hints.ai_family = AF_UNSPEC; 1967 hints.ai_socktype = SOCK_DGRAM; 1968 hints.ai_protocol = 0; 1969 error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, 1970 &res); 1971 if (error) { 1972 logerror(gai_strerror(error)); 1973 break; 1974 } 1975 f->f_un.f_forw.f_addr = res; 1976 f->f_type = F_FORW; 1977 NumForwards++; 1978 break; 1979 1980 case '/': 1981 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1982 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1983 f->f_type = F_UNUSED; 1984 logerror(p); 1985 break; 1986 } 1987 if (syncfile) 1988 f->f_flags |= FFLAG_SYNC; 1989 if (isatty(f->f_file)) 1990 f->f_type = F_TTY; 1991 else 1992 f->f_type = F_FILE; 1993 if (strcmp(p, ctty) == 0) 1994 f->f_type = F_CONSOLE; 1995 break; 1996 1997 case '|': 1998 f->f_un.f_pipe.f_pid = 0; 1999 (void) strlcpy(f->f_un.f_pipe.f_pname, p + 1, 2000 sizeof(f->f_un.f_pipe.f_pname)); 2001 f->f_type = F_PIPE; 2002 break; 2003 2004 case '*': 2005 f->f_type = F_WALL; 2006 break; 2007 2008 default: 2009 for (i = 0; i < MAXUNAMES && *p; i++) { 2010 for (q = p; *q && *q != ','; ) 2011 q++; 2012 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 2013 if ((q - p) > UT_NAMESIZE) 2014 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 2015 else 2016 f->f_un.f_uname[i][q - p] = '\0'; 2017 while (*q == ',' || *q == ' ') 2018 q++; 2019 p = q; 2020 } 2021 f->f_type = F_USERS; 2022 break; 2023 } 2024 } 2025 2026 2027 /* 2028 * Decode a symbolic name to a numeric value 2029 */ 2030 int 2031 decode(const char *name, CODE *codetab) 2032 { 2033 CODE *c; 2034 char *p, buf[40]; 2035 2036 if (isdigit((unsigned char)*name)) 2037 return (atoi(name)); 2038 2039 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 2040 if (isupper((unsigned char)*name)) 2041 *p = tolower((unsigned char)*name); 2042 else 2043 *p = *name; 2044 } 2045 *p = '\0'; 2046 for (c = codetab; c->c_name; c++) 2047 if (!strcmp(buf, c->c_name)) 2048 return (c->c_val); 2049 2050 return (-1); 2051 } 2052 2053 /* 2054 * Retrieve the size of the kernel message buffer, via sysctl. 2055 */ 2056 int 2057 getmsgbufsize(void) 2058 { 2059 int msgbufsize, mib[2]; 2060 size_t size; 2061 2062 mib[0] = CTL_KERN; 2063 mib[1] = KERN_MSGBUFSIZE; 2064 size = sizeof msgbufsize; 2065 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 2066 dprintf("Couldn't get kern.msgbufsize\n"); 2067 return (0); 2068 } 2069 return (msgbufsize); 2070 } 2071 2072 int * 2073 socksetup(int af) 2074 { 2075 struct addrinfo hints, *res, *r; 2076 struct kevent *ev; 2077 int error, maxs, *s, *socks; 2078 const int on = 1; 2079 2080 if(SecureMode && !NumForwards) 2081 return(NULL); 2082 2083 memset(&hints, 0, sizeof(hints)); 2084 hints.ai_flags = AI_PASSIVE; 2085 hints.ai_family = af; 2086 hints.ai_socktype = SOCK_DGRAM; 2087 error = getaddrinfo(NULL, "syslog", &hints, &res); 2088 if (error) { 2089 logerror(gai_strerror(error)); 2090 errno = 0; 2091 die(NULL); 2092 } 2093 2094 /* Count max number of sockets we may open */ 2095 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 2096 continue; 2097 socks = malloc((maxs+1) * sizeof(int)); 2098 if (!socks) { 2099 logerror("Couldn't allocate memory for sockets"); 2100 die(NULL); 2101 } 2102 2103 *socks = 0; /* num of sockets counter at start of array */ 2104 s = socks + 1; 2105 for (r = res; r; r = r->ai_next) { 2106 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 2107 if (*s < 0) { 2108 logerror("socket() failed"); 2109 continue; 2110 } 2111 if (r->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6, 2112 IPV6_V6ONLY, &on, sizeof(on)) < 0) { 2113 logerror("setsockopt(IPV6_V6ONLY) failed"); 2114 close(*s); 2115 continue; 2116 } 2117 2118 if (!SecureMode) { 2119 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 2120 logerror("bind() failed"); 2121 close(*s); 2122 continue; 2123 } 2124 ev = allocevchange(); 2125 EV_SET(ev, *s, EVFILT_READ, EV_ADD | EV_ENABLE, 2126 0, 0, (intptr_t) dispatch_read_finet); 2127 } 2128 2129 *socks = *socks + 1; 2130 s++; 2131 } 2132 2133 if (*socks == 0) { 2134 free (socks); 2135 if(Debug) 2136 return(NULL); 2137 else 2138 die(NULL); 2139 } 2140 if (res) 2141 freeaddrinfo(res); 2142 2143 return(socks); 2144 } 2145 2146 /* 2147 * Fairly similar to popen(3), but returns an open descriptor, as opposed 2148 * to a FILE *. 2149 */ 2150 int 2151 p_open(char *prog, pid_t *rpid) 2152 { 2153 int pfd[2], nulldesc, i; 2154 pid_t pid; 2155 char *argv[4]; /* sh -c cmd NULL */ 2156 char errmsg[200]; 2157 2158 if (pipe(pfd) == -1) 2159 return (-1); 2160 if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2161 /* We are royally screwed anyway. */ 2162 return (-1); 2163 } 2164 2165 switch ((pid = fork())) { 2166 case -1: 2167 (void) close(nulldesc); 2168 return (-1); 2169 2170 case 0: 2171 argv[0] = "sh"; 2172 argv[1] = "-c"; 2173 argv[2] = prog; 2174 argv[3] = NULL; 2175 2176 (void) setsid(); /* avoid catching SIGHUPs. */ 2177 2178 /* 2179 * Reset ignored signals to their default behavior. 2180 */ 2181 (void)signal(SIGTERM, SIG_DFL); 2182 (void)signal(SIGINT, SIG_DFL); 2183 (void)signal(SIGQUIT, SIG_DFL); 2184 (void)signal(SIGPIPE, SIG_DFL); 2185 (void)signal(SIGHUP, SIG_DFL); 2186 2187 dup2(pfd[0], STDIN_FILENO); 2188 dup2(nulldesc, STDOUT_FILENO); 2189 dup2(nulldesc, STDERR_FILENO); 2190 for (i = getdtablesize(); i > 2; i--) 2191 (void) close(i); 2192 2193 (void) execvp(_PATH_BSHELL, argv); 2194 _exit(255); 2195 } 2196 2197 (void) close(nulldesc); 2198 (void) close(pfd[0]); 2199 2200 /* 2201 * Avoid blocking on a hung pipe. With O_NONBLOCK, we are 2202 * supposed to get an EWOULDBLOCK on writev(2), which is 2203 * caught by the logic above anyway, which will in turn 2204 * close the pipe, and fork a new logging subprocess if 2205 * necessary. The stale subprocess will be killed some 2206 * time later unless it terminated itself due to closing 2207 * its input pipe. 2208 */ 2209 if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) { 2210 /* This is bad. */ 2211 (void) snprintf(errmsg, sizeof(errmsg), 2212 "Warning: cannot change pipe to pid %d to " 2213 "non-blocking.", (int) pid); 2214 logerror(errmsg); 2215 } 2216 *rpid = pid; 2217 return (pfd[1]); 2218 } 2219 2220 void 2221 deadq_enter(pid_t pid, const char *name) 2222 { 2223 dq_t p; 2224 int status; 2225 2226 /* 2227 * Be paranoid: if we can't signal the process, don't enter it 2228 * into the dead queue (perhaps it's already dead). If possible, 2229 * we try to fetch and log the child's status. 2230 */ 2231 if (kill(pid, 0) != 0) { 2232 if (waitpid(pid, &status, WNOHANG) > 0) 2233 log_deadchild(pid, status, name); 2234 return; 2235 } 2236 2237 p = malloc(sizeof(*p)); 2238 if (p == NULL) { 2239 errno = 0; 2240 logerror("panic: out of memory!"); 2241 exit(1); 2242 } 2243 2244 p->dq_pid = pid; 2245 p->dq_timeout = DQ_TIMO_INIT; 2246 TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries); 2247 } 2248 2249 int 2250 deadq_remove(pid_t pid) 2251 { 2252 dq_t q; 2253 2254 for (q = TAILQ_FIRST(&deadq_head); q != NULL; 2255 q = TAILQ_NEXT(q, dq_entries)) { 2256 if (q->dq_pid == pid) { 2257 TAILQ_REMOVE(&deadq_head, q, dq_entries); 2258 free(q); 2259 return (1); 2260 } 2261 } 2262 return (0); 2263 } 2264 2265 void 2266 log_deadchild(pid_t pid, int status, const char *name) 2267 { 2268 int code; 2269 char buf[256]; 2270 const char *reason; 2271 2272 /* Keep strerror() struff out of logerror messages. */ 2273 errno = 0; 2274 if (WIFSIGNALED(status)) { 2275 reason = "due to signal"; 2276 code = WTERMSIG(status); 2277 } else { 2278 reason = "with status"; 2279 code = WEXITSTATUS(status); 2280 if (code == 0) 2281 return; 2282 } 2283 (void) snprintf(buf, sizeof(buf), 2284 "Logging subprocess %d (%s) exited %s %d.", 2285 pid, name, reason, code); 2286 logerror(buf); 2287 } 2288 2289 static struct kevent changebuf[8]; 2290 static int nchanges; 2291 2292 static struct kevent * 2293 allocevchange(void) 2294 { 2295 2296 if (nchanges == A_CNT(changebuf)) { 2297 /* XXX Error handling could be improved. */ 2298 (void) wait_for_events(NULL, 0); 2299 } 2300 2301 return (&changebuf[nchanges++]); 2302 } 2303 2304 static int 2305 wait_for_events(struct kevent *events, size_t nevents) 2306 { 2307 int rv; 2308 2309 rv = kevent(fkq, nchanges ? changebuf : NULL, nchanges, 2310 events, nevents, NULL); 2311 nchanges = 0; 2312 return (rv); 2313 } 2314