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