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