Annotation of embedtools/src/syslogd.c, revision 1.1.2.1
1.1.2.1 ! misho 1: /*
! 2: * Copyright (c) 1983, 1988, 1993, 1994
! 3: * The Regents of the University of California. All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 4. Neither the name of the University nor the names of its contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: #ifndef lint
! 31: static const char copyright[] =
! 32: "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
! 33: The Regents of the University of California. All rights reserved.\n";
! 34: #endif /* not lint */
! 35:
! 36: #ifndef lint
! 37: #if 0
! 38: static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94";
! 39: #endif
! 40: #endif /* not lint */
! 41:
! 42: #include <sys/cdefs.h>
! 43: __FBSDID("$FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.167 2010/08/07 16:20:12 olli Exp $");
! 44:
! 45: /*
! 46: * syslogd -- log system messages
! 47: *
! 48: * This program implements a system log. It takes a series of lines.
! 49: * Each line may have a priority, signified as "<n>" as
! 50: * the first characters of the line. If this is
! 51: * not present, a default priority is used.
! 52: *
! 53: * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
! 54: * cause it to reread its configuration file.
! 55: *
! 56: * Defined Constants:
! 57: *
! 58: * MAXLINE -- the maximum line length that can be handled.
! 59: * DEFUPRI -- the default priority for user messages
! 60: * DEFSPRI -- the default priority for kernel messages
! 61: *
! 62: * Author: Eric Allman
! 63: * extensive changes by Ralph Campbell
! 64: * more extensive changes by Eric Allman (again)
! 65: * Extension to log by program name as well as facility and priority
! 66: * by Peter da Silva.
! 67: * -u and -v by Harlan Stenn.
! 68: * Priority comparison code by Harlan Stenn.
! 69: */
! 70:
! 71: #define MAXLINE 1024 /* maximum line length */
! 72: #define MAXSVLINE 120 /* maximum saved line length */
! 73: #define DEFUPRI (LOG_USER|LOG_NOTICE)
! 74: #define DEFSPRI (LOG_KERN|LOG_CRIT)
! 75: #define TIMERINTVL 30 /* interval for checking flush, mark */
! 76: #define TTYMSGTIME 1 /* timeout passed to ttymsg */
! 77:
! 78: #include <sys/param.h>
! 79: #include <sys/ioctl.h>
! 80: #include <sys/mman.h>
! 81: #include <sys/stat.h>
! 82: #include <sys/wait.h>
! 83: #include <sys/socket.h>
! 84: #include <sys/queue.h>
! 85: #include <sys/uio.h>
! 86: #include <sys/un.h>
! 87: #include <sys/time.h>
! 88: #include <sys/resource.h>
! 89: #include <sys/syslimits.h>
! 90: #include <sys/types.h>
! 91:
! 92: #include <netinet/in.h>
! 93: #include <netdb.h>
! 94: #include <arpa/inet.h>
! 95:
! 96: #include <ctype.h>
! 97: #include <err.h>
! 98: #include <errno.h>
! 99: #include <fcntl.h>
! 100: #include <libutil.h>
! 101: #include <limits.h>
! 102: #include <paths.h>
! 103: #include <signal.h>
! 104: #include <stdio.h>
! 105: #include <stdlib.h>
! 106: #include <string.h>
! 107: #include <sysexits.h>
! 108: #include <unistd.h>
! 109: #include <utmpx.h>
! 110:
! 111: #include "pathnames.h"
! 112: #include "ttymsg.h"
! 113:
! 114: #define SYSLOG_NAMES
! 115: #include <sys/syslog.h>
! 116:
! 117: const char *ConfFile = _PATH_LOGCONF;
! 118: const char *PidFile = _PATH_LOGPID;
! 119: const char ctty[] = _PATH_CONSOLE;
! 120:
! 121: #define dprintf if (Debug) printf
! 122:
! 123: #define MAXUNAMES 20 /* maximum number of user names */
! 124:
! 125: /*
! 126: * Unix sockets.
! 127: * We have two default sockets, one with 666 permissions,
! 128: * and one for privileged programs.
! 129: */
! 130: struct funix {
! 131: int s;
! 132: const char *name;
! 133: mode_t mode;
! 134: STAILQ_ENTRY(funix) next;
! 135: };
! 136: struct funix funix_secure = { -1, _PATH_LOG_PRIV, S_IRUSR | S_IWUSR,
! 137: { NULL } };
! 138: struct funix funix_default = { -1, _PATH_LOG, DEFFILEMODE,
! 139: { &funix_secure } };
! 140:
! 141: STAILQ_HEAD(, funix) funixes = { &funix_default,
! 142: &(funix_secure.next.stqe_next) };
! 143:
! 144: /*
! 145: * Flags to logmsg().
! 146: */
! 147:
! 148: #define IGN_CONS 0x001 /* don't print on console */
! 149: #define SYNC_FILE 0x002 /* do fsync on file after printing */
! 150: #define ADDDATE 0x004 /* add a date to the message */
! 151: #define MARK 0x008 /* this message is a mark */
! 152: #define ISKERNEL 0x010 /* kernel generated message */
! 153:
! 154: /*
! 155: * This structure represents the files that will have log
! 156: * copies printed.
! 157: * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
! 158: * or if f_type if F_PIPE and f_pid > 0.
! 159: */
! 160:
! 161: struct filed {
! 162: struct filed *f_next; /* next in linked list */
! 163: short f_type; /* entry type, see below */
! 164: short f_file; /* file descriptor */
! 165: time_t f_time; /* time this was last written */
! 166: char *f_host; /* host from which to recd. */
! 167: u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
! 168: u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */
! 169: #define PRI_LT 0x1
! 170: #define PRI_EQ 0x2
! 171: #define PRI_GT 0x4
! 172: char *f_program; /* program this applies to */
! 173: union {
! 174: char f_uname[MAXUNAMES][MAXLOGNAME];
! 175: struct {
! 176: char f_hname[MAXHOSTNAMELEN];
! 177: struct addrinfo *f_addr;
! 178:
! 179: } f_forw; /* forwarding address */
! 180: char f_fname[MAXPATHLEN];
! 181: struct {
! 182: char f_pname[MAXPATHLEN];
! 183: pid_t f_pid;
! 184: } f_pipe;
! 185: } f_un;
! 186: char f_prevline[MAXSVLINE]; /* last message logged */
! 187: char f_lasttime[16]; /* time of last occurrence */
! 188: char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */
! 189: int f_prevpri; /* pri of f_prevline */
! 190: int f_prevlen; /* length of f_prevline */
! 191: int f_prevcount; /* repetition cnt of prevline */
! 192: u_int f_repeatcount; /* number of "repeated" msgs */
! 193: int f_flags; /* file-specific flags */
! 194: #define FFLAG_SYNC 0x01
! 195: #define FFLAG_NEEDSYNC 0x02
! 196: };
! 197:
! 198: /*
! 199: * Queue of about-to-be dead processes we should watch out for.
! 200: */
! 201:
! 202: TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
! 203: struct stailhead *deadq_headp;
! 204:
! 205: struct deadq_entry {
! 206: pid_t dq_pid;
! 207: int dq_timeout;
! 208: TAILQ_ENTRY(deadq_entry) dq_entries;
! 209: };
! 210:
! 211: /*
! 212: * The timeout to apply to processes waiting on the dead queue. Unit
! 213: * of measure is `mark intervals', i.e. 20 minutes by default.
! 214: * Processes on the dead queue will be terminated after that time.
! 215: */
! 216:
! 217: #define DQ_TIMO_INIT 2
! 218:
! 219: typedef struct deadq_entry *dq_t;
! 220:
! 221:
! 222: /*
! 223: * Struct to hold records of network addresses that are allowed to log
! 224: * to us.
! 225: */
! 226: struct allowedpeer {
! 227: int isnumeric;
! 228: u_short port;
! 229: union {
! 230: struct {
! 231: struct sockaddr_storage addr;
! 232: struct sockaddr_storage mask;
! 233: } numeric;
! 234: char *name;
! 235: } u;
! 236: #define a_addr u.numeric.addr
! 237: #define a_mask u.numeric.mask
! 238: #define a_name u.name
! 239: };
! 240:
! 241:
! 242: /*
! 243: * Intervals at which we flush out "message repeated" messages,
! 244: * in seconds after previous message is logged. After each flush,
! 245: * we move to the next interval until we reach the largest.
! 246: */
! 247: int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */
! 248: #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
! 249: #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
! 250: #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
! 251: (f)->f_repeatcount = MAXREPEAT; \
! 252: }
! 253:
! 254: /* values for f_type */
! 255: #define F_UNUSED 0 /* unused entry */
! 256: #define F_FILE 1 /* regular file */
! 257: #define F_TTY 2 /* terminal */
! 258: #define F_CONSOLE 3 /* console terminal */
! 259: #define F_FORW 4 /* remote machine */
! 260: #define F_USERS 5 /* list of users */
! 261: #define F_WALL 6 /* everyone logged on */
! 262: #define F_PIPE 7 /* pipe to program */
! 263:
! 264: const char *TypeNames[8] = {
! 265: "UNUSED", "FILE", "TTY", "CONSOLE",
! 266: "FORW", "USERS", "WALL", "PIPE"
! 267: };
! 268:
! 269: static struct filed *Files; /* Log files that we write to */
! 270: static struct filed consfile; /* Console */
! 271:
! 272: static int Debug; /* debug flag */
! 273: static int resolve = 1; /* resolve hostname */
! 274: static char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */
! 275: static const char *LocalDomain; /* our local domain name */
! 276: static int *finet; /* Internet datagram socket */
! 277: static int fklog = -1; /* /dev/klog */
! 278: static int Initialized; /* set when we have initialized ourselves */
! 279: static int MarkInterval = 20 * 60; /* interval between marks in seconds */
! 280: static int MarkSeq; /* mark sequence number */
! 281: static int SecureMode; /* when true, receive only unix domain socks */
! 282: #ifdef INET6
! 283: static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
! 284: #else
! 285: static int family = PF_INET; /* protocol family (IPv4 only) */
! 286: #endif
! 287: static int mask_C1 = 1; /* mask characters from 0x80 - 0x9F */
! 288: static int send_to_all; /* send message to all IPv4/IPv6 addresses */
! 289: static int use_bootfile; /* log entire bootfile for every kern msg */
! 290: static int no_compress; /* don't compress messages (1=pipes, 2=all) */
! 291: static int logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
! 292:
! 293: static char bootfile[MAXLINE+1]; /* booted kernel file */
! 294:
! 295: struct allowedpeer *AllowedPeers; /* List of allowed peers */
! 296: static int NumAllowed; /* Number of entries in AllowedPeers */
! 297: static int RemoteAddDate; /* Always set the date on remote messages */
! 298:
! 299: static int UniquePriority; /* Only log specified priority? */
! 300: static int LogFacPri; /* Put facility and priority in log message: */
! 301: /* 0=no, 1=numeric, 2=names */
! 302: static int KeepKernFac; /* Keep remotely logged kernel facility */
! 303: static int needdofsync = 0; /* Are any file(s) waiting to be fsynced? */
! 304: static struct pidfh *pfh;
! 305:
! 306: volatile sig_atomic_t MarkSet, WantDie;
! 307:
! 308: static int allowaddr(char *);
! 309: static void cfline(const char *, struct filed *,
! 310: const char *, const char *);
! 311: static const char *cvthname(struct sockaddr *);
! 312: static void deadq_enter(pid_t, const char *);
! 313: static int deadq_remove(pid_t);
! 314: static int decode(const char *, CODE *);
! 315: static void die(int);
! 316: static void dodie(int);
! 317: static void dofsync(void);
! 318: static void domark(int);
! 319: static void fprintlog(struct filed *, int, const char *);
! 320: static int *socksetup(int, char *);
! 321: static void init(int);
! 322: static void logerror(const char *);
! 323: static void logmsg(int, const char *, const char *, int);
! 324: static void log_deadchild(pid_t, int, const char *);
! 325: static void markit(void);
! 326: static int skip_message(const char *, const char *, int);
! 327: static void printline(const char *, char *, int);
! 328: static void printsys(char *);
! 329: static int p_open(const char *, pid_t *);
! 330: static void readklog(void);
! 331: static void reapchild(int);
! 332: static void usage(void);
! 333: static int validate(struct sockaddr *, const char *);
! 334: static void unmapped(struct sockaddr *);
! 335: static void wallmsg(struct filed *, struct iovec *, const int iovlen);
! 336: static int waitdaemon(int, int, int);
! 337: static void timedout(int);
! 338: static void double_rbuf(int);
! 339:
! 340: int
! 341: main(int argc, char *argv[])
! 342: {
! 343: int ch, i, fdsrmax = 0, l;
! 344: struct sockaddr_un sunx, fromunix;
! 345: struct sockaddr_storage frominet;
! 346: fd_set *fdsr = NULL;
! 347: char line[MAXLINE + 1];
! 348: char *bindhostname;
! 349: const char *hname;
! 350: struct timeval tv, *tvp;
! 351: struct sigaction sact;
! 352: struct funix *fx, *fx1;
! 353: sigset_t mask;
! 354: pid_t ppid = 1, spid;
! 355: socklen_t len;
! 356:
! 357: if (madvise(NULL, 0, MADV_PROTECT) != 0)
! 358: dprintf("madvise() failed: %s\n", strerror(errno));
! 359:
! 360: bindhostname = NULL;
! 361: while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nop:P:sS:Tuv"))
! 362: != -1)
! 363: switch (ch) {
! 364: case '4':
! 365: family = PF_INET;
! 366: break;
! 367: #ifdef INET6
! 368: case '6':
! 369: family = PF_INET6;
! 370: break;
! 371: #endif
! 372: case '8':
! 373: mask_C1 = 0;
! 374: break;
! 375: case 'A':
! 376: send_to_all++;
! 377: break;
! 378: case 'a': /* allow specific network addresses only */
! 379: if (allowaddr(optarg) == -1)
! 380: usage();
! 381: break;
! 382: case 'b':
! 383: bindhostname = optarg;
! 384: break;
! 385: case 'c':
! 386: no_compress++;
! 387: break;
! 388: case 'C':
! 389: logflags |= O_CREAT;
! 390: break;
! 391: case 'd': /* debug */
! 392: Debug++;
! 393: break;
! 394: case 'f': /* configuration file */
! 395: ConfFile = optarg;
! 396: break;
! 397: case 'k': /* keep remote kern fac */
! 398: KeepKernFac = 1;
! 399: break;
! 400: case 'l':
! 401: {
! 402: long perml;
! 403: mode_t mode;
! 404: char *name, *ep;
! 405:
! 406: if (optarg[0] == '/') {
! 407: mode = DEFFILEMODE;
! 408: name = optarg;
! 409: } else if ((name = strchr(optarg, ':')) != NULL) {
! 410: *name++ = '\0';
! 411: if (name[0] != '/')
! 412: errx(1, "socket name must be absolute "
! 413: "path");
! 414: if (isdigit(*optarg)) {
! 415: perml = strtol(optarg, &ep, 8);
! 416: if (*ep || perml < 0 ||
! 417: perml & ~(S_IRWXU|S_IRWXG|S_IRWXO))
! 418: errx(1, "invalid mode %s, exiting",
! 419: optarg);
! 420: mode = (mode_t )perml;
! 421: } else
! 422: errx(1, "invalid mode %s, exiting",
! 423: optarg);
! 424: } else /* doesn't begin with '/', and no ':' */
! 425: errx(1, "can't parse path %s", optarg);
! 426:
! 427: if (strlen(name) >= sizeof(sunx.sun_path))
! 428: errx(1, "%s path too long, exiting", name);
! 429: if ((fx = malloc(sizeof(struct funix))) == NULL)
! 430: errx(1, "malloc failed");
! 431: fx->s = -1;
! 432: fx->name = name;
! 433: fx->mode = mode;
! 434: STAILQ_INSERT_TAIL(&funixes, fx, next);
! 435: break;
! 436: }
! 437: case 'm': /* mark interval */
! 438: MarkInterval = atoi(optarg) * 60;
! 439: break;
! 440: case 'n':
! 441: resolve = 0;
! 442: break;
! 443: case 'o':
! 444: use_bootfile = 1;
! 445: break;
! 446: case 'p': /* path */
! 447: if (strlen(optarg) >= sizeof(sunx.sun_path))
! 448: errx(1, "%s path too long, exiting", optarg);
! 449: funix_default.name = optarg;
! 450: break;
! 451: case 'P': /* path for alt. PID */
! 452: PidFile = optarg;
! 453: break;
! 454: case 's': /* no network mode */
! 455: SecureMode++;
! 456: break;
! 457: case 'S': /* path for privileged originator */
! 458: if (strlen(optarg) >= sizeof(sunx.sun_path))
! 459: errx(1, "%s path too long, exiting", optarg);
! 460: funix_secure.name = optarg;
! 461: break;
! 462: case 'T':
! 463: RemoteAddDate = 1;
! 464: break;
! 465: case 'u': /* only log specified priority */
! 466: UniquePriority++;
! 467: break;
! 468: case 'v': /* log facility and priority */
! 469: LogFacPri++;
! 470: break;
! 471: default:
! 472: usage();
! 473: }
! 474: if ((argc -= optind) != 0)
! 475: usage();
! 476:
! 477: pfh = pidfile_open(PidFile, 0600, &spid);
! 478: if (pfh == NULL) {
! 479: if (errno == EEXIST)
! 480: errx(1, "syslogd already running, pid: %d", spid);
! 481: warn("cannot open pid file");
! 482: }
! 483:
! 484: if (!Debug) {
! 485: ppid = waitdaemon(0, 0, 30);
! 486: if (ppid < 0) {
! 487: warn("could not become daemon");
! 488: pidfile_remove(pfh);
! 489: exit(1);
! 490: }
! 491: } else {
! 492: setlinebuf(stdout);
! 493: }
! 494:
! 495: if (NumAllowed)
! 496: endservent();
! 497:
! 498: consfile.f_type = F_CONSOLE;
! 499: (void)strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1,
! 500: sizeof(consfile.f_un.f_fname));
! 501: (void)strlcpy(bootfile, getbootfile(), sizeof(bootfile));
! 502: (void)signal(SIGTERM, dodie);
! 503: (void)signal(SIGINT, Debug ? dodie : SIG_IGN);
! 504: (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
! 505: /*
! 506: * We don't want the SIGCHLD and SIGHUP handlers to interfere
! 507: * with each other; they are likely candidates for being called
! 508: * simultaneously (SIGHUP closes pipe descriptor, process dies,
! 509: * SIGCHLD happens).
! 510: */
! 511: sigemptyset(&mask);
! 512: sigaddset(&mask, SIGHUP);
! 513: sact.sa_handler = reapchild;
! 514: sact.sa_mask = mask;
! 515: sact.sa_flags = SA_RESTART;
! 516: (void)sigaction(SIGCHLD, &sact, NULL);
! 517: (void)signal(SIGALRM, domark);
! 518: (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */
! 519: (void)alarm(TIMERINTVL);
! 520:
! 521: TAILQ_INIT(&deadq_head);
! 522:
! 523: #ifndef SUN_LEN
! 524: #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
! 525: #endif
! 526: STAILQ_FOREACH_SAFE(fx, &funixes, next, fx1) {
! 527: (void)unlink(fx->name);
! 528: memset(&sunx, 0, sizeof(sunx));
! 529: sunx.sun_family = AF_LOCAL;
! 530: (void)strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path));
! 531: fx->s = socket(PF_LOCAL, SOCK_DGRAM, 0);
! 532: if (fx->s < 0 ||
! 533: bind(fx->s, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
! 534: chmod(fx->name, fx->mode) < 0) {
! 535: (void)snprintf(line, sizeof line,
! 536: "cannot create %s", fx->name);
! 537: logerror(line);
! 538: dprintf("cannot create %s (%d)\n", fx->name, errno);
! 539: if (fx == &funix_default || fx == &funix_secure)
! 540: die(0);
! 541: else {
! 542: STAILQ_REMOVE(&funixes, fx, funix, next);
! 543: continue;
! 544: }
! 545: double_rbuf(fx->s);
! 546: }
! 547: }
! 548: if (SecureMode <= 1)
! 549: finet = socksetup(family, bindhostname);
! 550:
! 551: if (finet) {
! 552: if (SecureMode) {
! 553: for (i = 0; i < *finet; i++) {
! 554: if (shutdown(finet[i+1], SHUT_RD) < 0) {
! 555: logerror("shutdown");
! 556: if (!Debug)
! 557: die(0);
! 558: }
! 559: }
! 560: } else {
! 561: dprintf("listening on inet and/or inet6 socket\n");
! 562: }
! 563: dprintf("sending on inet and/or inet6 socket\n");
! 564: }
! 565:
! 566: if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
! 567: if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0)
! 568: fklog = -1;
! 569: if (fklog < 0)
! 570: dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
! 571:
! 572: /* tuck my process id away */
! 573: pidfile_write(pfh);
! 574:
! 575: dprintf("off & running....\n");
! 576:
! 577: init(0);
! 578: /* prevent SIGHUP and SIGCHLD handlers from running in parallel */
! 579: sigemptyset(&mask);
! 580: sigaddset(&mask, SIGCHLD);
! 581: sact.sa_handler = init;
! 582: sact.sa_mask = mask;
! 583: sact.sa_flags = SA_RESTART;
! 584: (void)sigaction(SIGHUP, &sact, NULL);
! 585:
! 586: tvp = &tv;
! 587: tv.tv_sec = tv.tv_usec = 0;
! 588:
! 589: if (fklog != -1 && fklog > fdsrmax)
! 590: fdsrmax = fklog;
! 591: if (finet && !SecureMode) {
! 592: for (i = 0; i < *finet; i++) {
! 593: if (finet[i+1] != -1 && finet[i+1] > fdsrmax)
! 594: fdsrmax = finet[i+1];
! 595: }
! 596: }
! 597: STAILQ_FOREACH(fx, &funixes, next)
! 598: if (fx->s > fdsrmax)
! 599: fdsrmax = fx->s;
! 600:
! 601: fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
! 602: sizeof(fd_mask));
! 603: if (fdsr == NULL)
! 604: errx(1, "calloc fd_set");
! 605:
! 606: for (;;) {
! 607: if (MarkSet)
! 608: markit();
! 609: if (WantDie)
! 610: die(WantDie);
! 611:
! 612: bzero(fdsr, howmany(fdsrmax+1, NFDBITS) *
! 613: sizeof(fd_mask));
! 614:
! 615: if (fklog != -1)
! 616: FD_SET(fklog, fdsr);
! 617: if (finet && !SecureMode) {
! 618: for (i = 0; i < *finet; i++) {
! 619: if (finet[i+1] != -1)
! 620: FD_SET(finet[i+1], fdsr);
! 621: }
! 622: }
! 623: STAILQ_FOREACH(fx, &funixes, next)
! 624: FD_SET(fx->s, fdsr);
! 625:
! 626: i = select(fdsrmax+1, fdsr, NULL, NULL,
! 627: needdofsync ? &tv : tvp);
! 628: switch (i) {
! 629: case 0:
! 630: dofsync();
! 631: needdofsync = 0;
! 632: if (tvp) {
! 633: tvp = NULL;
! 634: if (ppid != 1)
! 635: kill(ppid, SIGALRM);
! 636: }
! 637: continue;
! 638: case -1:
! 639: if (errno != EINTR)
! 640: logerror("select");
! 641: continue;
! 642: }
! 643: if (fklog != -1 && FD_ISSET(fklog, fdsr))
! 644: readklog();
! 645: if (finet && !SecureMode) {
! 646: for (i = 0; i < *finet; i++) {
! 647: if (FD_ISSET(finet[i+1], fdsr)) {
! 648: len = sizeof(frominet);
! 649: l = recvfrom(finet[i+1], line, MAXLINE,
! 650: 0, (struct sockaddr *)&frominet,
! 651: &len);
! 652: if (l > 0) {
! 653: line[l] = '\0';
! 654: hname = cvthname((struct sockaddr *)&frominet);
! 655: unmapped((struct sockaddr *)&frominet);
! 656: if (validate((struct sockaddr *)&frominet, hname))
! 657: printline(hname, line, RemoteAddDate ? ADDDATE : 0);
! 658: } else if (l < 0 && errno != EINTR)
! 659: logerror("recvfrom inet");
! 660: }
! 661: }
! 662: }
! 663: STAILQ_FOREACH(fx, &funixes, next) {
! 664: if (FD_ISSET(fx->s, fdsr)) {
! 665: len = sizeof(fromunix);
! 666: l = recvfrom(fx->s, line, MAXLINE, 0,
! 667: (struct sockaddr *)&fromunix, &len);
! 668: if (l > 0) {
! 669: line[l] = '\0';
! 670: printline(LocalHostName, line, 0);
! 671: } else if (l < 0 && errno != EINTR)
! 672: logerror("recvfrom unix");
! 673: }
! 674: }
! 675: }
! 676: if (fdsr)
! 677: free(fdsr);
! 678: }
! 679:
! 680: static void
! 681: unmapped(struct sockaddr *sa)
! 682: {
! 683: struct sockaddr_in6 *sin6;
! 684: struct sockaddr_in sin4;
! 685:
! 686: if (sa->sa_family != AF_INET6)
! 687: return;
! 688: if (sa->sa_len != sizeof(struct sockaddr_in6) ||
! 689: sizeof(sin4) > sa->sa_len)
! 690: return;
! 691: sin6 = (struct sockaddr_in6 *)sa;
! 692: if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
! 693: return;
! 694:
! 695: memset(&sin4, 0, sizeof(sin4));
! 696: sin4.sin_family = AF_INET;
! 697: sin4.sin_len = sizeof(struct sockaddr_in);
! 698: memcpy(&sin4.sin_addr, &sin6->sin6_addr.s6_addr[12],
! 699: sizeof(sin4.sin_addr));
! 700: sin4.sin_port = sin6->sin6_port;
! 701:
! 702: memcpy(sa, &sin4, sin4.sin_len);
! 703: }
! 704:
! 705: static void
! 706: usage(void)
! 707: {
! 708:
! 709: fprintf(stderr, "%s\n%s\n%s\n%s\n",
! 710: "usage: syslogd [-468ACcdknosTuv] [-a allowed_peer]",
! 711: " [-b bind_address] [-f config_file]",
! 712: " [-l [mode:]path] [-m mark_interval]",
! 713: " [-P pid_file] [-p log_socket]");
! 714: exit(1);
! 715: }
! 716:
! 717: /*
! 718: * Take a raw input line, decode the message, and print the message
! 719: * on the appropriate log files.
! 720: */
! 721: static void
! 722: printline(const char *hname, char *msg, int flags)
! 723: {
! 724: char *p, *q;
! 725: long n;
! 726: int c, pri;
! 727: char line[MAXLINE + 1];
! 728:
! 729: /* test for special codes */
! 730: p = msg;
! 731: pri = DEFUPRI;
! 732: if (*p == '<') {
! 733: errno = 0;
! 734: n = strtol(p + 1, &q, 10);
! 735: if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
! 736: p = q + 1;
! 737: pri = n;
! 738: }
! 739: }
! 740: if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
! 741: pri = DEFUPRI;
! 742:
! 743: /*
! 744: * Don't allow users to log kernel messages.
! 745: * NOTE: since LOG_KERN == 0 this will also match
! 746: * messages with no facility specified.
! 747: */
! 748: if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
! 749: pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
! 750:
! 751: q = line;
! 752:
! 753: while ((c = (unsigned char)*p++) != '\0' &&
! 754: q < &line[sizeof(line) - 4]) {
! 755: if (mask_C1 && (c & 0x80) && c < 0xA0) {
! 756: c &= 0x7F;
! 757: *q++ = 'M';
! 758: *q++ = '-';
! 759: }
! 760: if (isascii(c) && iscntrl(c)) {
! 761: if (c == '\n') {
! 762: *q++ = ' ';
! 763: } else if (c == '\t') {
! 764: *q++ = '\t';
! 765: } else {
! 766: *q++ = '^';
! 767: *q++ = c ^ 0100;
! 768: }
! 769: } else {
! 770: *q++ = c;
! 771: }
! 772: }
! 773: *q = '\0';
! 774:
! 775: logmsg(pri, line, hname, flags);
! 776: }
! 777:
! 778: /*
! 779: * Read /dev/klog while data are available, split into lines.
! 780: */
! 781: static void
! 782: readklog(void)
! 783: {
! 784: char *p, *q, line[MAXLINE + 1];
! 785: int len, i;
! 786:
! 787: len = 0;
! 788: for (;;) {
! 789: i = read(fklog, line + len, MAXLINE - 1 - len);
! 790: if (i > 0) {
! 791: line[i + len] = '\0';
! 792: } else {
! 793: if (i < 0 && errno != EINTR && errno != EAGAIN) {
! 794: logerror("klog");
! 795: fklog = -1;
! 796: }
! 797: break;
! 798: }
! 799:
! 800: for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
! 801: *q = '\0';
! 802: printsys(p);
! 803: }
! 804: len = strlen(p);
! 805: if (len >= MAXLINE - 1) {
! 806: printsys(p);
! 807: len = 0;
! 808: }
! 809: if (len > 0)
! 810: memmove(line, p, len + 1);
! 811: }
! 812: if (len > 0)
! 813: printsys(line);
! 814: }
! 815:
! 816: /*
! 817: * Take a raw input line from /dev/klog, format similar to syslog().
! 818: */
! 819: static void
! 820: printsys(char *msg)
! 821: {
! 822: char *p, *q;
! 823: long n;
! 824: int flags, isprintf, pri;
! 825:
! 826: flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */
! 827: p = msg;
! 828: pri = DEFSPRI;
! 829: isprintf = 1;
! 830: if (*p == '<') {
! 831: errno = 0;
! 832: n = strtol(p + 1, &q, 10);
! 833: if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
! 834: p = q + 1;
! 835: pri = n;
! 836: isprintf = 0;
! 837: }
! 838: }
! 839: /*
! 840: * Kernel printf's and LOG_CONSOLE messages have been displayed
! 841: * on the console already.
! 842: */
! 843: if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE)
! 844: flags |= IGN_CONS;
! 845: if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
! 846: pri = DEFSPRI;
! 847: logmsg(pri, p, LocalHostName, flags);
! 848: }
! 849:
! 850: static time_t now;
! 851:
! 852: /*
! 853: * Match a program or host name against a specification.
! 854: * Return a non-0 value if the message must be ignored
! 855: * based on the specification.
! 856: */
! 857: static int
! 858: skip_message(const char *name, const char *spec, int checkcase)
! 859: {
! 860: const char *s;
! 861: char prev, next;
! 862: int exclude = 0;
! 863: /* Behaviour on explicit match */
! 864:
! 865: if (spec == NULL)
! 866: return 0;
! 867: switch (*spec) {
! 868: case '-':
! 869: exclude = 1;
! 870: /*FALLTHROUGH*/
! 871: case '+':
! 872: spec++;
! 873: break;
! 874: default:
! 875: break;
! 876: }
! 877: if (checkcase)
! 878: s = strstr (spec, name);
! 879: else
! 880: s = strcasestr (spec, name);
! 881:
! 882: if (s != NULL) {
! 883: prev = (s == spec ? ',' : *(s - 1));
! 884: next = *(s + strlen (name));
! 885:
! 886: if (prev == ',' && (next == '\0' || next == ','))
! 887: /* Explicit match: skip iff the spec is an
! 888: exclusive one. */
! 889: return exclude;
! 890: }
! 891:
! 892: /* No explicit match for this name: skip the message iff
! 893: the spec is an inclusive one. */
! 894: return !exclude;
! 895: }
! 896:
! 897: /*
! 898: * Log a message to the appropriate log files, users, etc. based on
! 899: * the priority.
! 900: */
! 901: static void
! 902: logmsg(int pri, const char *msg, const char *from, int flags)
! 903: {
! 904: struct filed *f;
! 905: int i, fac, msglen, omask, prilev;
! 906: const char *timestamp;
! 907: char prog[NAME_MAX+1];
! 908: char buf[MAXLINE+1];
! 909:
! 910: dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
! 911: pri, flags, from, msg);
! 912:
! 913: omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
! 914:
! 915: /*
! 916: * Check to see if msg looks non-standard.
! 917: */
! 918: msglen = strlen(msg);
! 919: if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
! 920: msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
! 921: flags |= ADDDATE;
! 922:
! 923: (void)time(&now);
! 924: if (flags & ADDDATE) {
! 925: timestamp = ctime(&now) + 4;
! 926: } else {
! 927: timestamp = msg;
! 928: msg += 16;
! 929: msglen -= 16;
! 930: }
! 931:
! 932: /* skip leading blanks */
! 933: while (isspace(*msg)) {
! 934: msg++;
! 935: msglen--;
! 936: }
! 937:
! 938: /* extract facility and priority level */
! 939: if (flags & MARK)
! 940: fac = LOG_NFACILITIES;
! 941: else
! 942: fac = LOG_FAC(pri);
! 943:
! 944: /* Check maximum facility number. */
! 945: if (fac > LOG_NFACILITIES) {
! 946: (void)sigsetmask(omask);
! 947: return;
! 948: }
! 949:
! 950: prilev = LOG_PRI(pri);
! 951:
! 952: /* extract program name */
! 953: for (i = 0; i < NAME_MAX; i++) {
! 954: if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
! 955: msg[i] == '/' || isspace(msg[i]))
! 956: break;
! 957: prog[i] = msg[i];
! 958: }
! 959: prog[i] = 0;
! 960:
! 961: /* add kernel prefix for kernel messages */
! 962: if (flags & ISKERNEL) {
! 963: snprintf(buf, sizeof(buf), "%s: %s",
! 964: use_bootfile ? bootfile : "kernel", msg);
! 965: msg = buf;
! 966: msglen = strlen(buf);
! 967: }
! 968:
! 969: /* log the message to the particular outputs */
! 970: if (!Initialized) {
! 971: f = &consfile;
! 972: /*
! 973: * Open in non-blocking mode to avoid hangs during open
! 974: * and close(waiting for the port to drain).
! 975: */
! 976: f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
! 977:
! 978: if (f->f_file >= 0) {
! 979: (void)strlcpy(f->f_lasttime, timestamp,
! 980: sizeof(f->f_lasttime));
! 981: fprintlog(f, flags, msg);
! 982: (void)close(f->f_file);
! 983: }
! 984: (void)sigsetmask(omask);
! 985: return;
! 986: }
! 987: for (f = Files; f; f = f->f_next) {
! 988: /* skip messages that are incorrect priority */
! 989: if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
! 990: ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
! 991: ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
! 992: )
! 993: || f->f_pmask[fac] == INTERNAL_NOPRI)
! 994: continue;
! 995:
! 996: /* skip messages with the incorrect hostname */
! 997: if (skip_message(from, f->f_host, 0))
! 998: continue;
! 999:
! 1000: /* skip messages with the incorrect program name */
! 1001: if (skip_message(prog, f->f_program, 1))
! 1002: continue;
! 1003:
! 1004: /* skip message to console if it has already been printed */
! 1005: if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
! 1006: continue;
! 1007:
! 1008: /* don't output marks to recently written files */
! 1009: if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
! 1010: continue;
! 1011:
! 1012: /*
! 1013: * suppress duplicate lines to this file
! 1014: */
! 1015: if (no_compress - (f->f_type != F_PIPE) < 1 &&
! 1016: (flags & MARK) == 0 && msglen == f->f_prevlen &&
! 1017: f->f_prevline && !strcmp(msg, f->f_prevline) &&
! 1018: !strcasecmp(from, f->f_prevhost)) {
! 1019: (void)strlcpy(f->f_lasttime, timestamp,
! 1020: sizeof(f->f_lasttime));
! 1021: f->f_prevcount++;
! 1022: dprintf("msg repeated %d times, %ld sec of %d\n",
! 1023: f->f_prevcount, (long)(now - f->f_time),
! 1024: repeatinterval[f->f_repeatcount]);
! 1025: /*
! 1026: * If domark would have logged this by now,
! 1027: * flush it now (so we don't hold isolated messages),
! 1028: * but back off so we'll flush less often
! 1029: * in the future.
! 1030: */
! 1031: if (now > REPEATTIME(f)) {
! 1032: fprintlog(f, flags, (char *)NULL);
! 1033: BACKOFF(f);
! 1034: }
! 1035: } else {
! 1036: /* new line, save it */
! 1037: if (f->f_prevcount)
! 1038: fprintlog(f, 0, (char *)NULL);
! 1039: f->f_repeatcount = 0;
! 1040: f->f_prevpri = pri;
! 1041: (void)strlcpy(f->f_lasttime, timestamp,
! 1042: sizeof(f->f_lasttime));
! 1043: (void)strlcpy(f->f_prevhost, from,
! 1044: sizeof(f->f_prevhost));
! 1045: if (msglen < MAXSVLINE) {
! 1046: f->f_prevlen = msglen;
! 1047: (void)strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
! 1048: fprintlog(f, flags, (char *)NULL);
! 1049: } else {
! 1050: f->f_prevline[0] = 0;
! 1051: f->f_prevlen = 0;
! 1052: fprintlog(f, flags, msg);
! 1053: }
! 1054: }
! 1055: }
! 1056: (void)sigsetmask(omask);
! 1057: }
! 1058:
! 1059: static void
! 1060: dofsync(void)
! 1061: {
! 1062: struct filed *f;
! 1063:
! 1064: for (f = Files; f; f = f->f_next) {
! 1065: if ((f->f_type == F_FILE) &&
! 1066: (f->f_flags & FFLAG_NEEDSYNC)) {
! 1067: f->f_flags &= ~FFLAG_NEEDSYNC;
! 1068: (void)fsync(f->f_file);
! 1069: }
! 1070: }
! 1071: }
! 1072:
! 1073: #define IOV_SIZE 7
! 1074: static void
! 1075: fprintlog(struct filed *f, int flags, const char *msg)
! 1076: {
! 1077: struct iovec iov[IOV_SIZE];
! 1078: struct iovec *v;
! 1079: struct addrinfo *r;
! 1080: int i, l, lsent = 0;
! 1081: char line[MAXLINE + 1], repbuf[80], greetings[200], *wmsg = NULL;
! 1082: char nul[] = "", space[] = " ", lf[] = "\n", crlf[] = "\r\n";
! 1083: const char *msgret;
! 1084:
! 1085: v = iov;
! 1086: if (f->f_type == F_WALL) {
! 1087: v->iov_base = greetings;
! 1088: /* The time displayed is not synchornized with the other log
! 1089: * destinations (like messages). Following fragment was using
! 1090: * ctime(&now), which was updating the time every 30 sec.
! 1091: * With f_lasttime, time is synchronized correctly.
! 1092: */
! 1093: v->iov_len = snprintf(greetings, sizeof greetings,
! 1094: "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
! 1095: f->f_prevhost, f->f_lasttime);
! 1096: if (v->iov_len > 0)
! 1097: v++;
! 1098: v->iov_base = nul;
! 1099: v->iov_len = 0;
! 1100: v++;
! 1101: } else {
! 1102: v->iov_base = f->f_lasttime;
! 1103: v->iov_len = strlen(f->f_lasttime);
! 1104: v++;
! 1105: v->iov_base = space;
! 1106: v->iov_len = 1;
! 1107: v++;
! 1108: }
! 1109:
! 1110: if (LogFacPri) {
! 1111: static char fp_buf[30]; /* Hollow laugh */
! 1112: int fac = f->f_prevpri & LOG_FACMASK;
! 1113: int pri = LOG_PRI(f->f_prevpri);
! 1114: const char *f_s = NULL;
! 1115: char f_n[5]; /* Hollow laugh */
! 1116: const char *p_s = NULL;
! 1117: char p_n[5]; /* Hollow laugh */
! 1118:
! 1119: if (LogFacPri > 1) {
! 1120: CODE *c;
! 1121:
! 1122: for (c = facilitynames; c->c_name; c++) {
! 1123: if (c->c_val == fac) {
! 1124: f_s = c->c_name;
! 1125: break;
! 1126: }
! 1127: }
! 1128: for (c = prioritynames; c->c_name; c++) {
! 1129: if (c->c_val == pri) {
! 1130: p_s = c->c_name;
! 1131: break;
! 1132: }
! 1133: }
! 1134: }
! 1135: if (!f_s) {
! 1136: snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
! 1137: f_s = f_n;
! 1138: }
! 1139: if (!p_s) {
! 1140: snprintf(p_n, sizeof p_n, "%d", pri);
! 1141: p_s = p_n;
! 1142: }
! 1143: snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
! 1144: v->iov_base = fp_buf;
! 1145: v->iov_len = strlen(fp_buf);
! 1146: } else {
! 1147: v->iov_base = nul;
! 1148: v->iov_len = 0;
! 1149: }
! 1150: v++;
! 1151:
! 1152: v->iov_base = f->f_prevhost;
! 1153: v->iov_len = strlen(v->iov_base);
! 1154: v++;
! 1155: v->iov_base = space;
! 1156: v->iov_len = 1;
! 1157: v++;
! 1158:
! 1159: if (msg) {
! 1160: wmsg = strdup(msg); /* XXX iov_base needs a `const' sibling. */
! 1161: if (wmsg == NULL) {
! 1162: logerror("strdup");
! 1163: exit(1);
! 1164: }
! 1165: v->iov_base = wmsg;
! 1166: v->iov_len = strlen(msg);
! 1167: } else if (f->f_prevcount > 1) {
! 1168: v->iov_base = repbuf;
! 1169: v->iov_len = snprintf(repbuf, sizeof repbuf,
! 1170: "last message repeated %d times", f->f_prevcount);
! 1171: } else if (f->f_prevline) {
! 1172: v->iov_base = f->f_prevline;
! 1173: v->iov_len = f->f_prevlen;
! 1174: } else {
! 1175: return;
! 1176: }
! 1177: v++;
! 1178:
! 1179: dprintf("Logging to %s", TypeNames[f->f_type]);
! 1180: f->f_time = now;
! 1181:
! 1182: switch (f->f_type) {
! 1183: int port;
! 1184: case F_UNUSED:
! 1185: dprintf("\n");
! 1186: break;
! 1187:
! 1188: case F_FORW:
! 1189: port = (int)ntohs(((struct sockaddr_in *)
! 1190: (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
! 1191: if (port != 514) {
! 1192: dprintf(" %s:%d\n", f->f_un.f_forw.f_hname, port);
! 1193: } else {
! 1194: dprintf(" %s\n", f->f_un.f_forw.f_hname);
! 1195: }
! 1196: /* check for local vs remote messages */
! 1197: if (strcasecmp(f->f_prevhost, LocalHostName))
! 1198: l = snprintf(line, sizeof line - 1,
! 1199: "<%d>%.15s Forwarded from %s: %s",
! 1200: f->f_prevpri, (char *)iov[0].iov_base,
! 1201: f->f_prevhost, (char *)iov[5].iov_base);
! 1202: else
! 1203: l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
! 1204: f->f_prevpri, (char *)iov[0].iov_base,
! 1205: (char *)iov[5].iov_base);
! 1206: if (l < 0)
! 1207: l = 0;
! 1208: else if (l > MAXLINE)
! 1209: l = MAXLINE;
! 1210:
! 1211: if (finet) {
! 1212: for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
! 1213: for (i = 0; i < *finet; i++) {
! 1214: #if 0
! 1215: /*
! 1216: * should we check AF first, or just
! 1217: * trial and error? FWD
! 1218: */
! 1219: if (r->ai_family ==
! 1220: address_family_of(finet[i+1]))
! 1221: #endif
! 1222: lsent = sendto(finet[i+1], line, l, 0,
! 1223: r->ai_addr, r->ai_addrlen);
! 1224: if (lsent == l)
! 1225: break;
! 1226: }
! 1227: if (lsent == l && !send_to_all)
! 1228: break;
! 1229: }
! 1230: dprintf("lsent/l: %d/%d\n", lsent, l);
! 1231: if (lsent != l) {
! 1232: int e = errno;
! 1233: logerror("sendto");
! 1234: errno = e;
! 1235: switch (errno) {
! 1236: case ENOBUFS:
! 1237: case ENETDOWN:
! 1238: case EHOSTUNREACH:
! 1239: case EHOSTDOWN:
! 1240: break;
! 1241: /* case EBADF: */
! 1242: /* case EACCES: */
! 1243: /* case ENOTSOCK: */
! 1244: /* case EFAULT: */
! 1245: /* case EMSGSIZE: */
! 1246: /* case EAGAIN: */
! 1247: /* case ENOBUFS: */
! 1248: /* case ECONNREFUSED: */
! 1249: default:
! 1250: dprintf("removing entry\n");
! 1251: f->f_type = F_UNUSED;
! 1252: break;
! 1253: }
! 1254: }
! 1255: }
! 1256: break;
! 1257:
! 1258: case F_FILE:
! 1259: dprintf(" %s\n", f->f_un.f_fname);
! 1260: v->iov_base = lf;
! 1261: v->iov_len = 1;
! 1262: if (writev(f->f_file, iov, IOV_SIZE) < 0) {
! 1263: /*
! 1264: * If writev(2) fails for potentially transient errors
! 1265: * like the filesystem being full, ignore it.
! 1266: * Otherwise remove this logfile from the list.
! 1267: */
! 1268: if (errno != ENOSPC) {
! 1269: int e = errno;
! 1270: (void)close(f->f_file);
! 1271: f->f_type = F_UNUSED;
! 1272: errno = e;
! 1273: logerror(f->f_un.f_fname);
! 1274: }
! 1275: } else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
! 1276: f->f_flags |= FFLAG_NEEDSYNC;
! 1277: needdofsync = 1;
! 1278: }
! 1279: break;
! 1280:
! 1281: case F_PIPE:
! 1282: dprintf(" %s\n", f->f_un.f_pipe.f_pname);
! 1283: v->iov_base = lf;
! 1284: v->iov_len = 1;
! 1285: if (f->f_un.f_pipe.f_pid == 0) {
! 1286: if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
! 1287: &f->f_un.f_pipe.f_pid)) < 0) {
! 1288: f->f_type = F_UNUSED;
! 1289: logerror(f->f_un.f_pipe.f_pname);
! 1290: break;
! 1291: }
! 1292: }
! 1293: if (writev(f->f_file, iov, IOV_SIZE) < 0) {
! 1294: int e = errno;
! 1295: (void)close(f->f_file);
! 1296: if (f->f_un.f_pipe.f_pid > 0)
! 1297: deadq_enter(f->f_un.f_pipe.f_pid,
! 1298: f->f_un.f_pipe.f_pname);
! 1299: f->f_un.f_pipe.f_pid = 0;
! 1300: errno = e;
! 1301: logerror(f->f_un.f_pipe.f_pname);
! 1302: }
! 1303: break;
! 1304:
! 1305: case F_CONSOLE:
! 1306: if (flags & IGN_CONS) {
! 1307: dprintf(" (ignored)\n");
! 1308: break;
! 1309: }
! 1310: /* FALLTHROUGH */
! 1311:
! 1312: case F_TTY:
! 1313: dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
! 1314: v->iov_base = crlf;
! 1315: v->iov_len = 2;
! 1316:
! 1317: errno = 0; /* ttymsg() only sometimes returns an errno */
! 1318: if ((msgret = ttymsg(iov, IOV_SIZE, f->f_un.f_fname, 10))) {
! 1319: f->f_type = F_UNUSED;
! 1320: logerror(msgret);
! 1321: }
! 1322: break;
! 1323:
! 1324: case F_USERS:
! 1325: case F_WALL:
! 1326: dprintf("\n");
! 1327: v->iov_base = crlf;
! 1328: v->iov_len = 2;
! 1329: wallmsg(f, iov, IOV_SIZE);
! 1330: break;
! 1331: }
! 1332: f->f_prevcount = 0;
! 1333: free(wmsg);
! 1334: }
! 1335:
! 1336: /*
! 1337: * WALLMSG -- Write a message to the world at large
! 1338: *
! 1339: * Write the specified message to either the entire
! 1340: * world, or a list of approved users.
! 1341: */
! 1342: static void
! 1343: wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
! 1344: {
! 1345: static int reenter; /* avoid calling ourselves */
! 1346: struct utmpx *ut;
! 1347: int i;
! 1348: const char *p;
! 1349:
! 1350: if (reenter++)
! 1351: return;
! 1352: setutxent();
! 1353: /* NOSTRICT */
! 1354: while ((ut = getutxent()) != NULL) {
! 1355: if (ut->ut_type != USER_PROCESS)
! 1356: continue;
! 1357: if (f->f_type == F_WALL) {
! 1358: if ((p = ttymsg(iov, iovlen, ut->ut_line,
! 1359: TTYMSGTIME)) != NULL) {
! 1360: errno = 0; /* already in msg */
! 1361: logerror(p);
! 1362: }
! 1363: continue;
! 1364: }
! 1365: /* should we send the message to this user? */
! 1366: for (i = 0; i < MAXUNAMES; i++) {
! 1367: if (!f->f_un.f_uname[i][0])
! 1368: break;
! 1369: if (!strcmp(f->f_un.f_uname[i], ut->ut_user)) {
! 1370: if ((p = ttymsg(iov, iovlen, ut->ut_line,
! 1371: TTYMSGTIME)) != NULL) {
! 1372: errno = 0; /* already in msg */
! 1373: logerror(p);
! 1374: }
! 1375: break;
! 1376: }
! 1377: }
! 1378: }
! 1379: endutxent();
! 1380: reenter = 0;
! 1381: }
! 1382:
! 1383: static void
! 1384: reapchild(int signo __unused)
! 1385: {
! 1386: int status;
! 1387: pid_t pid;
! 1388: struct filed *f;
! 1389:
! 1390: while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
! 1391: if (!Initialized)
! 1392: /* Don't tell while we are initting. */
! 1393: continue;
! 1394:
! 1395: /* First, look if it's a process from the dead queue. */
! 1396: if (deadq_remove(pid))
! 1397: goto oncemore;
! 1398:
! 1399: /* Now, look in list of active processes. */
! 1400: for (f = Files; f; f = f->f_next)
! 1401: if (f->f_type == F_PIPE &&
! 1402: f->f_un.f_pipe.f_pid == pid) {
! 1403: (void)close(f->f_file);
! 1404: f->f_un.f_pipe.f_pid = 0;
! 1405: log_deadchild(pid, status,
! 1406: f->f_un.f_pipe.f_pname);
! 1407: break;
! 1408: }
! 1409: oncemore:
! 1410: continue;
! 1411: }
! 1412: }
! 1413:
! 1414: /*
! 1415: * Return a printable representation of a host address.
! 1416: */
! 1417: static const char *
! 1418: cvthname(struct sockaddr *f)
! 1419: {
! 1420: int error, hl;
! 1421: sigset_t omask, nmask;
! 1422: static char hname[NI_MAXHOST], ip[NI_MAXHOST];
! 1423:
! 1424: error = getnameinfo((struct sockaddr *)f,
! 1425: ((struct sockaddr *)f)->sa_len,
! 1426: ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
! 1427: dprintf("cvthname(%s)\n", ip);
! 1428:
! 1429: if (error) {
! 1430: dprintf("Malformed from address %s\n", gai_strerror(error));
! 1431: return ("???");
! 1432: }
! 1433: if (!resolve)
! 1434: return (ip);
! 1435:
! 1436: sigemptyset(&nmask);
! 1437: sigaddset(&nmask, SIGHUP);
! 1438: sigprocmask(SIG_BLOCK, &nmask, &omask);
! 1439: error = getnameinfo((struct sockaddr *)f,
! 1440: ((struct sockaddr *)f)->sa_len,
! 1441: hname, sizeof hname, NULL, 0, NI_NAMEREQD);
! 1442: sigprocmask(SIG_SETMASK, &omask, NULL);
! 1443: if (error) {
! 1444: dprintf("Host name for your address (%s) unknown\n", ip);
! 1445: return (ip);
! 1446: }
! 1447: hl = strlen(hname);
! 1448: if (hl > 0 && hname[hl-1] == '.')
! 1449: hname[--hl] = '\0';
! 1450: trimdomain(hname, hl);
! 1451: return (hname);
! 1452: }
! 1453:
! 1454: static void
! 1455: dodie(int signo)
! 1456: {
! 1457:
! 1458: WantDie = signo;
! 1459: }
! 1460:
! 1461: static void
! 1462: domark(int signo __unused)
! 1463: {
! 1464:
! 1465: MarkSet = 1;
! 1466: }
! 1467:
! 1468: /*
! 1469: * Print syslogd errors some place.
! 1470: */
! 1471: static void
! 1472: logerror(const char *type)
! 1473: {
! 1474: char buf[512];
! 1475: static int recursed = 0;
! 1476:
! 1477: /* If there's an error while trying to log an error, give up. */
! 1478: if (recursed)
! 1479: return;
! 1480: recursed++;
! 1481: if (errno)
! 1482: (void)snprintf(buf,
! 1483: sizeof buf, "syslogd: %s: %s", type, strerror(errno));
! 1484: else
! 1485: (void)snprintf(buf, sizeof buf, "syslogd: %s", type);
! 1486: errno = 0;
! 1487: dprintf("%s\n", buf);
! 1488: logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
! 1489: recursed--;
! 1490: }
! 1491:
! 1492: static void
! 1493: die(int signo)
! 1494: {
! 1495: struct filed *f;
! 1496: struct funix *fx;
! 1497: int was_initialized;
! 1498: char buf[100];
! 1499:
! 1500: was_initialized = Initialized;
! 1501: Initialized = 0; /* Don't log SIGCHLDs. */
! 1502: for (f = Files; f != NULL; f = f->f_next) {
! 1503: /* flush any pending output */
! 1504: if (f->f_prevcount)
! 1505: fprintlog(f, 0, (char *)NULL);
! 1506: if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) {
! 1507: (void)close(f->f_file);
! 1508: f->f_un.f_pipe.f_pid = 0;
! 1509: }
! 1510: }
! 1511: Initialized = was_initialized;
! 1512: if (signo) {
! 1513: dprintf("syslogd: exiting on signal %d\n", signo);
! 1514: (void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo);
! 1515: errno = 0;
! 1516: logerror(buf);
! 1517: }
! 1518: STAILQ_FOREACH(fx, &funixes, next)
! 1519: (void)unlink(fx->name);
! 1520: pidfile_remove(pfh);
! 1521:
! 1522: exit(1);
! 1523: }
! 1524:
! 1525: /*
! 1526: * INIT -- Initialize syslogd from configuration table
! 1527: */
! 1528: static void
! 1529: init(int signo)
! 1530: {
! 1531: int i;
! 1532: FILE *cf;
! 1533: struct filed *f, *next, **nextp;
! 1534: char *p;
! 1535: char cline[LINE_MAX];
! 1536: char prog[NAME_MAX+1];
! 1537: char host[MAXHOSTNAMELEN];
! 1538: char oldLocalHostName[MAXHOSTNAMELEN];
! 1539: char hostMsg[2*MAXHOSTNAMELEN+40];
! 1540: char bootfileMsg[LINE_MAX];
! 1541:
! 1542: dprintf("init\n");
! 1543:
! 1544: /*
! 1545: * Load hostname (may have changed).
! 1546: */
! 1547: if (signo != 0)
! 1548: (void)strlcpy(oldLocalHostName, LocalHostName,
! 1549: sizeof(oldLocalHostName));
! 1550: if (gethostname(LocalHostName, sizeof(LocalHostName)))
! 1551: err(EX_OSERR, "gethostname() failed");
! 1552: if ((p = strchr(LocalHostName, '.')) != NULL) {
! 1553: *p++ = '\0';
! 1554: LocalDomain = p;
! 1555: } else {
! 1556: LocalDomain = "";
! 1557: }
! 1558:
! 1559: /*
! 1560: * Close all open log files.
! 1561: */
! 1562: Initialized = 0;
! 1563: for (f = Files; f != NULL; f = next) {
! 1564: /* flush any pending output */
! 1565: if (f->f_prevcount)
! 1566: fprintlog(f, 0, (char *)NULL);
! 1567:
! 1568: switch (f->f_type) {
! 1569: case F_FILE:
! 1570: case F_FORW:
! 1571: case F_CONSOLE:
! 1572: case F_TTY:
! 1573: (void)close(f->f_file);
! 1574: break;
! 1575: case F_PIPE:
! 1576: if (f->f_un.f_pipe.f_pid > 0) {
! 1577: (void)close(f->f_file);
! 1578: deadq_enter(f->f_un.f_pipe.f_pid,
! 1579: f->f_un.f_pipe.f_pname);
! 1580: }
! 1581: f->f_un.f_pipe.f_pid = 0;
! 1582: break;
! 1583: }
! 1584: next = f->f_next;
! 1585: if (f->f_program) free(f->f_program);
! 1586: if (f->f_host) free(f->f_host);
! 1587: free((char *)f);
! 1588: }
! 1589: Files = NULL;
! 1590: nextp = &Files;
! 1591:
! 1592: /* open the configuration file */
! 1593: if ((cf = fopen(ConfFile, "r")) == NULL) {
! 1594: dprintf("cannot open %s\n", ConfFile);
! 1595: *nextp = (struct filed *)calloc(1, sizeof(*f));
! 1596: if (*nextp == NULL) {
! 1597: logerror("calloc");
! 1598: exit(1);
! 1599: }
! 1600: cfline("*.ERR\t/dev/console", *nextp, "*", "*");
! 1601: (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
! 1602: if ((*nextp)->f_next == NULL) {
! 1603: logerror("calloc");
! 1604: exit(1);
! 1605: }
! 1606: cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
! 1607: Initialized = 1;
! 1608: return;
! 1609: }
! 1610:
! 1611: /*
! 1612: * Foreach line in the conf table, open that file.
! 1613: */
! 1614: f = NULL;
! 1615: (void)strlcpy(host, "*", sizeof(host));
! 1616: (void)strlcpy(prog, "*", sizeof(prog));
! 1617: while (fgets(cline, sizeof(cline), cf) != NULL) {
! 1618: /*
! 1619: * check for end-of-section, comments, strip off trailing
! 1620: * spaces and newline character. #!prog is treated specially:
! 1621: * following lines apply only to that program.
! 1622: */
! 1623: for (p = cline; isspace(*p); ++p)
! 1624: continue;
! 1625: if (*p == 0)
! 1626: continue;
! 1627: if (*p == '#') {
! 1628: p++;
! 1629: if (*p != '!' && *p != '+' && *p != '-')
! 1630: continue;
! 1631: }
! 1632: if (*p == '+' || *p == '-') {
! 1633: host[0] = *p++;
! 1634: while (isspace(*p))
! 1635: p++;
! 1636: if ((!*p) || (*p == '*')) {
! 1637: (void)strlcpy(host, "*", sizeof(host));
! 1638: continue;
! 1639: }
! 1640: if (*p == '@')
! 1641: p = LocalHostName;
! 1642: for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
! 1643: if (!isalnum(*p) && *p != '.' && *p != '-'
! 1644: && *p != ',' && *p != ':' && *p != '%')
! 1645: break;
! 1646: host[i] = *p++;
! 1647: }
! 1648: host[i] = '\0';
! 1649: continue;
! 1650: }
! 1651: if (*p == '!') {
! 1652: p++;
! 1653: while (isspace(*p)) p++;
! 1654: if ((!*p) || (*p == '*')) {
! 1655: (void)strlcpy(prog, "*", sizeof(prog));
! 1656: continue;
! 1657: }
! 1658: for (i = 0; i < NAME_MAX; i++) {
! 1659: if (!isprint(p[i]) || isspace(p[i]))
! 1660: break;
! 1661: prog[i] = p[i];
! 1662: }
! 1663: prog[i] = 0;
! 1664: continue;
! 1665: }
! 1666: for (p = cline + 1; *p != '\0'; p++) {
! 1667: if (*p != '#')
! 1668: continue;
! 1669: if (*(p - 1) == '\\') {
! 1670: strcpy(p - 1, p);
! 1671: p--;
! 1672: continue;
! 1673: }
! 1674: *p = '\0';
! 1675: break;
! 1676: }
! 1677: for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
! 1678: cline[i] = '\0';
! 1679: f = (struct filed *)calloc(1, sizeof(*f));
! 1680: if (f == NULL) {
! 1681: logerror("calloc");
! 1682: exit(1);
! 1683: }
! 1684: *nextp = f;
! 1685: nextp = &f->f_next;
! 1686: cfline(cline, f, prog, host);
! 1687: }
! 1688:
! 1689: /* close the configuration file */
! 1690: (void)fclose(cf);
! 1691:
! 1692: Initialized = 1;
! 1693:
! 1694: if (Debug) {
! 1695: int port;
! 1696: for (f = Files; f; f = f->f_next) {
! 1697: for (i = 0; i <= LOG_NFACILITIES; i++)
! 1698: if (f->f_pmask[i] == INTERNAL_NOPRI)
! 1699: printf("X ");
! 1700: else
! 1701: printf("%d ", f->f_pmask[i]);
! 1702: printf("%s: ", TypeNames[f->f_type]);
! 1703: switch (f->f_type) {
! 1704: case F_FILE:
! 1705: printf("%s", f->f_un.f_fname);
! 1706: break;
! 1707:
! 1708: case F_CONSOLE:
! 1709: case F_TTY:
! 1710: printf("%s%s", _PATH_DEV, f->f_un.f_fname);
! 1711: break;
! 1712:
! 1713: case F_FORW:
! 1714: port = (int)ntohs(((struct sockaddr_in *)
! 1715: (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
! 1716: if (port != 514) {
! 1717: printf("%s:%d",
! 1718: f->f_un.f_forw.f_hname, port);
! 1719: } else {
! 1720: printf("%s", f->f_un.f_forw.f_hname);
! 1721: }
! 1722: break;
! 1723:
! 1724: case F_PIPE:
! 1725: printf("%s", f->f_un.f_pipe.f_pname);
! 1726: break;
! 1727:
! 1728: case F_USERS:
! 1729: for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
! 1730: printf("%s, ", f->f_un.f_uname[i]);
! 1731: break;
! 1732: }
! 1733: if (f->f_program)
! 1734: printf(" (%s)", f->f_program);
! 1735: printf("\n");
! 1736: }
! 1737: }
! 1738:
! 1739: logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
! 1740: dprintf("syslogd: restarted\n");
! 1741: /*
! 1742: * Log a change in hostname, but only on a restart.
! 1743: */
! 1744: if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) {
! 1745: (void)snprintf(hostMsg, sizeof(hostMsg),
! 1746: "syslogd: hostname changed, \"%s\" to \"%s\"",
! 1747: oldLocalHostName, LocalHostName);
! 1748: logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE);
! 1749: dprintf("%s\n", hostMsg);
! 1750: }
! 1751: /*
! 1752: * Log the kernel boot file if we aren't going to use it as
! 1753: * the prefix, and if this is *not* a restart.
! 1754: */
! 1755: if (signo == 0 && !use_bootfile) {
! 1756: (void)snprintf(bootfileMsg, sizeof(bootfileMsg),
! 1757: "syslogd: kernel boot file is %s", bootfile);
! 1758: logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE);
! 1759: dprintf("%s\n", bootfileMsg);
! 1760: }
! 1761: }
! 1762:
! 1763: /*
! 1764: * Crack a configuration file line
! 1765: */
! 1766: static void
! 1767: cfline(const char *line, struct filed *f, const char *prog, const char *host)
! 1768: {
! 1769: struct addrinfo hints, *res;
! 1770: int error, i, pri, syncfile;
! 1771: const char *p, *q;
! 1772: char *bp;
! 1773: char buf[MAXLINE], ebuf[100];
! 1774:
! 1775: dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
! 1776:
! 1777: errno = 0; /* keep strerror() stuff out of logerror messages */
! 1778:
! 1779: /* clear out file entry */
! 1780: memset(f, 0, sizeof(*f));
! 1781: for (i = 0; i <= LOG_NFACILITIES; i++)
! 1782: f->f_pmask[i] = INTERNAL_NOPRI;
! 1783:
! 1784: /* save hostname if any */
! 1785: if (host && *host == '*')
! 1786: host = NULL;
! 1787: if (host) {
! 1788: int hl;
! 1789:
! 1790: f->f_host = strdup(host);
! 1791: if (f->f_host == NULL) {
! 1792: logerror("strdup");
! 1793: exit(1);
! 1794: }
! 1795: hl = strlen(f->f_host);
! 1796: if (hl > 0 && f->f_host[hl-1] == '.')
! 1797: f->f_host[--hl] = '\0';
! 1798: trimdomain(f->f_host, hl);
! 1799: }
! 1800:
! 1801: /* save program name if any */
! 1802: if (prog && *prog == '*')
! 1803: prog = NULL;
! 1804: if (prog) {
! 1805: f->f_program = strdup(prog);
! 1806: if (f->f_program == NULL) {
! 1807: logerror("strdup");
! 1808: exit(1);
! 1809: }
! 1810: }
! 1811:
! 1812: /* scan through the list of selectors */
! 1813: for (p = line; *p && *p != '\t' && *p != ' ';) {
! 1814: int pri_done;
! 1815: int pri_cmp;
! 1816: int pri_invert;
! 1817:
! 1818: /* find the end of this facility name list */
! 1819: for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
! 1820: continue;
! 1821:
! 1822: /* get the priority comparison */
! 1823: pri_cmp = 0;
! 1824: pri_done = 0;
! 1825: pri_invert = 0;
! 1826: if (*q == '!') {
! 1827: pri_invert = 1;
! 1828: q++;
! 1829: }
! 1830: while (!pri_done) {
! 1831: switch (*q) {
! 1832: case '<':
! 1833: pri_cmp |= PRI_LT;
! 1834: q++;
! 1835: break;
! 1836: case '=':
! 1837: pri_cmp |= PRI_EQ;
! 1838: q++;
! 1839: break;
! 1840: case '>':
! 1841: pri_cmp |= PRI_GT;
! 1842: q++;
! 1843: break;
! 1844: default:
! 1845: pri_done++;
! 1846: break;
! 1847: }
! 1848: }
! 1849:
! 1850: /* collect priority name */
! 1851: for (bp = buf; *q && !strchr("\t,; ", *q); )
! 1852: *bp++ = *q++;
! 1853: *bp = '\0';
! 1854:
! 1855: /* skip cruft */
! 1856: while (strchr(",;", *q))
! 1857: q++;
! 1858:
! 1859: /* decode priority name */
! 1860: if (*buf == '*') {
! 1861: pri = LOG_PRIMASK;
! 1862: pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
! 1863: } else {
! 1864: /* Ignore trailing spaces. */
! 1865: for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--)
! 1866: buf[i] = '\0';
! 1867:
! 1868: pri = decode(buf, prioritynames);
! 1869: if (pri < 0) {
! 1870: (void)snprintf(ebuf, sizeof ebuf,
! 1871: "unknown priority name \"%s\"", buf);
! 1872: logerror(ebuf);
! 1873: return;
! 1874: }
! 1875: }
! 1876: if (!pri_cmp)
! 1877: pri_cmp = (UniquePriority)
! 1878: ? (PRI_EQ)
! 1879: : (PRI_EQ | PRI_GT)
! 1880: ;
! 1881: if (pri_invert)
! 1882: pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
! 1883:
! 1884: /* scan facilities */
! 1885: while (*p && !strchr("\t.; ", *p)) {
! 1886: for (bp = buf; *p && !strchr("\t,;. ", *p); )
! 1887: *bp++ = *p++;
! 1888: *bp = '\0';
! 1889:
! 1890: if (*buf == '*') {
! 1891: for (i = 0; i < LOG_NFACILITIES; i++) {
! 1892: f->f_pmask[i] = pri;
! 1893: f->f_pcmp[i] = pri_cmp;
! 1894: }
! 1895: } else {
! 1896: i = decode(buf, facilitynames);
! 1897: if (i < 0) {
! 1898: (void)snprintf(ebuf, sizeof ebuf,
! 1899: "unknown facility name \"%s\"",
! 1900: buf);
! 1901: logerror(ebuf);
! 1902: return;
! 1903: }
! 1904: f->f_pmask[i >> 3] = pri;
! 1905: f->f_pcmp[i >> 3] = pri_cmp;
! 1906: }
! 1907: while (*p == ',' || *p == ' ')
! 1908: p++;
! 1909: }
! 1910:
! 1911: p = q;
! 1912: }
! 1913:
! 1914: /* skip to action part */
! 1915: while (*p == '\t' || *p == ' ')
! 1916: p++;
! 1917:
! 1918: if (*p == '-') {
! 1919: syncfile = 0;
! 1920: p++;
! 1921: } else
! 1922: syncfile = 1;
! 1923:
! 1924: switch (*p) {
! 1925: case '@':
! 1926: {
! 1927: char *tp;
! 1928: /*
! 1929: * scan forward to see if there is a port defined.
! 1930: * so we can't use strlcpy..
! 1931: */
! 1932: i = sizeof(f->f_un.f_forw.f_hname);
! 1933: tp = f->f_un.f_forw.f_hname;
! 1934: p++;
! 1935:
! 1936: while (*p && (*p != ':') && (i-- > 0)) {
! 1937: *tp++ = *p++;
! 1938: }
! 1939: *tp = '\0';
! 1940: }
! 1941: /* See if we copied a domain and have a port */
! 1942: if (*p == ':')
! 1943: p++;
! 1944: else
! 1945: p = NULL;
! 1946:
! 1947: memset(&hints, 0, sizeof(hints));
! 1948: hints.ai_family = family;
! 1949: hints.ai_socktype = SOCK_DGRAM;
! 1950: error = getaddrinfo(f->f_un.f_forw.f_hname,
! 1951: p ? p : "syslog", &hints, &res);
! 1952: if (error) {
! 1953: logerror(gai_strerror(error));
! 1954: break;
! 1955: }
! 1956: f->f_un.f_forw.f_addr = res;
! 1957: f->f_type = F_FORW;
! 1958: break;
! 1959:
! 1960: case '/':
! 1961: if ((f->f_file = open(p, logflags, 0600)) < 0) {
! 1962: f->f_type = F_UNUSED;
! 1963: logerror(p);
! 1964: break;
! 1965: }
! 1966: if (syncfile)
! 1967: f->f_flags |= FFLAG_SYNC;
! 1968: if (isatty(f->f_file)) {
! 1969: if (strcmp(p, ctty) == 0)
! 1970: f->f_type = F_CONSOLE;
! 1971: else
! 1972: f->f_type = F_TTY;
! 1973: (void)strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1,
! 1974: sizeof(f->f_un.f_fname));
! 1975: } else {
! 1976: (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
! 1977: f->f_type = F_FILE;
! 1978: }
! 1979: break;
! 1980:
! 1981: case '|':
! 1982: f->f_un.f_pipe.f_pid = 0;
! 1983: (void)strlcpy(f->f_un.f_pipe.f_pname, p + 1,
! 1984: sizeof(f->f_un.f_pipe.f_pname));
! 1985: f->f_type = F_PIPE;
! 1986: break;
! 1987:
! 1988: case '*':
! 1989: f->f_type = F_WALL;
! 1990: break;
! 1991:
! 1992: default:
! 1993: for (i = 0; i < MAXUNAMES && *p; i++) {
! 1994: for (q = p; *q && *q != ','; )
! 1995: q++;
! 1996: (void)strncpy(f->f_un.f_uname[i], p, MAXLOGNAME - 1);
! 1997: if ((q - p) >= MAXLOGNAME)
! 1998: f->f_un.f_uname[i][MAXLOGNAME - 1] = '\0';
! 1999: else
! 2000: f->f_un.f_uname[i][q - p] = '\0';
! 2001: while (*q == ',' || *q == ' ')
! 2002: q++;
! 2003: p = q;
! 2004: }
! 2005: f->f_type = F_USERS;
! 2006: break;
! 2007: }
! 2008: }
! 2009:
! 2010:
! 2011: /*
! 2012: * Decode a symbolic name to a numeric value
! 2013: */
! 2014: static int
! 2015: decode(const char *name, CODE *codetab)
! 2016: {
! 2017: CODE *c;
! 2018: char *p, buf[40];
! 2019:
! 2020: if (isdigit(*name))
! 2021: return (atoi(name));
! 2022:
! 2023: for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
! 2024: if (isupper(*name))
! 2025: *p = tolower(*name);
! 2026: else
! 2027: *p = *name;
! 2028: }
! 2029: *p = '\0';
! 2030: for (c = codetab; c->c_name; c++)
! 2031: if (!strcmp(buf, c->c_name))
! 2032: return (c->c_val);
! 2033:
! 2034: return (-1);
! 2035: }
! 2036:
! 2037: static void
! 2038: markit(void)
! 2039: {
! 2040: struct filed *f;
! 2041: dq_t q, next;
! 2042:
! 2043: now = time((time_t *)NULL);
! 2044: MarkSeq += TIMERINTVL;
! 2045: if (MarkSeq >= MarkInterval) {
! 2046: logmsg(LOG_INFO, "-- MARK --",
! 2047: LocalHostName, ADDDATE|MARK);
! 2048: MarkSeq = 0;
! 2049: }
! 2050:
! 2051: for (f = Files; f; f = f->f_next) {
! 2052: if (f->f_prevcount && now >= REPEATTIME(f)) {
! 2053: dprintf("flush %s: repeated %d times, %d sec.\n",
! 2054: TypeNames[f->f_type], f->f_prevcount,
! 2055: repeatinterval[f->f_repeatcount]);
! 2056: fprintlog(f, 0, (char *)NULL);
! 2057: BACKOFF(f);
! 2058: }
! 2059: }
! 2060:
! 2061: /* Walk the dead queue, and see if we should signal somebody. */
! 2062: for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = next) {
! 2063: next = TAILQ_NEXT(q, dq_entries);
! 2064:
! 2065: switch (q->dq_timeout) {
! 2066: case 0:
! 2067: /* Already signalled once, try harder now. */
! 2068: if (kill(q->dq_pid, SIGKILL) != 0)
! 2069: (void)deadq_remove(q->dq_pid);
! 2070: break;
! 2071:
! 2072: case 1:
! 2073: /*
! 2074: * Timed out on dead queue, send terminate
! 2075: * signal. Note that we leave the removal
! 2076: * from the dead queue to reapchild(), which
! 2077: * will also log the event (unless the process
! 2078: * didn't even really exist, in case we simply
! 2079: * drop it from the dead queue).
! 2080: */
! 2081: if (kill(q->dq_pid, SIGTERM) != 0)
! 2082: (void)deadq_remove(q->dq_pid);
! 2083: /* FALLTHROUGH */
! 2084:
! 2085: default:
! 2086: q->dq_timeout--;
! 2087: }
! 2088: }
! 2089: MarkSet = 0;
! 2090: (void)alarm(TIMERINTVL);
! 2091: }
! 2092:
! 2093: /*
! 2094: * fork off and become a daemon, but wait for the child to come online
! 2095: * before returing to the parent, or we get disk thrashing at boot etc.
! 2096: * Set a timer so we don't hang forever if it wedges.
! 2097: */
! 2098: static int
! 2099: waitdaemon(int nochdir, int noclose, int maxwait)
! 2100: {
! 2101: int fd;
! 2102: int status;
! 2103: pid_t pid, childpid;
! 2104:
! 2105: switch (childpid = fork()) {
! 2106: case -1:
! 2107: return (-1);
! 2108: case 0:
! 2109: break;
! 2110: default:
! 2111: signal(SIGALRM, timedout);
! 2112: alarm(maxwait);
! 2113: while ((pid = wait3(&status, 0, NULL)) != -1) {
! 2114: if (WIFEXITED(status))
! 2115: errx(1, "child pid %d exited with return code %d",
! 2116: pid, WEXITSTATUS(status));
! 2117: if (WIFSIGNALED(status))
! 2118: errx(1, "child pid %d exited on signal %d%s",
! 2119: pid, WTERMSIG(status),
! 2120: WCOREDUMP(status) ? " (core dumped)" :
! 2121: "");
! 2122: if (pid == childpid) /* it's gone... */
! 2123: break;
! 2124: }
! 2125: exit(0);
! 2126: }
! 2127:
! 2128: if (setsid() == -1)
! 2129: return (-1);
! 2130:
! 2131: if (!nochdir)
! 2132: (void)chdir("/");
! 2133:
! 2134: if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
! 2135: (void)dup2(fd, STDIN_FILENO);
! 2136: (void)dup2(fd, STDOUT_FILENO);
! 2137: (void)dup2(fd, STDERR_FILENO);
! 2138: if (fd > 2)
! 2139: (void)close (fd);
! 2140: }
! 2141: return (getppid());
! 2142: }
! 2143:
! 2144: /*
! 2145: * We get a SIGALRM from the child when it's running and finished doing it's
! 2146: * fsync()'s or O_SYNC writes for all the boot messages.
! 2147: *
! 2148: * We also get a signal from the kernel if the timer expires, so check to
! 2149: * see what happened.
! 2150: */
! 2151: static void
! 2152: timedout(int sig __unused)
! 2153: {
! 2154: int left;
! 2155: left = alarm(0);
! 2156: signal(SIGALRM, SIG_DFL);
! 2157: if (left == 0)
! 2158: errx(1, "timed out waiting for child");
! 2159: else
! 2160: _exit(0);
! 2161: }
! 2162:
! 2163: /*
! 2164: * Add `s' to the list of allowable peer addresses to accept messages
! 2165: * from.
! 2166: *
! 2167: * `s' is a string in the form:
! 2168: *
! 2169: * [*]domainname[:{servicename|portnumber|*}]
! 2170: *
! 2171: * or
! 2172: *
! 2173: * netaddr/maskbits[:{servicename|portnumber|*}]
! 2174: *
! 2175: * Returns -1 on error, 0 if the argument was valid.
! 2176: */
! 2177: static int
! 2178: allowaddr(char *s)
! 2179: {
! 2180: char *cp1, *cp2;
! 2181: struct allowedpeer ap;
! 2182: struct servent *se;
! 2183: int masklen = -1;
! 2184: struct addrinfo hints, *res;
! 2185: struct in_addr *addrp, *maskp;
! 2186: #ifdef INET6
! 2187: int i;
! 2188: u_int32_t *addr6p, *mask6p;
! 2189: #endif
! 2190: char ip[NI_MAXHOST];
! 2191:
! 2192: #ifdef INET6
! 2193: if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
! 2194: #endif
! 2195: cp1 = s;
! 2196: if ((cp1 = strrchr(cp1, ':'))) {
! 2197: /* service/port provided */
! 2198: *cp1++ = '\0';
! 2199: if (strlen(cp1) == 1 && *cp1 == '*')
! 2200: /* any port allowed */
! 2201: ap.port = 0;
! 2202: else if ((se = getservbyname(cp1, "udp"))) {
! 2203: ap.port = ntohs(se->s_port);
! 2204: } else {
! 2205: ap.port = strtol(cp1, &cp2, 0);
! 2206: if (*cp2 != '\0')
! 2207: return (-1); /* port not numeric */
! 2208: }
! 2209: } else {
! 2210: if ((se = getservbyname("syslog", "udp")))
! 2211: ap.port = ntohs(se->s_port);
! 2212: else
! 2213: /* sanity, should not happen */
! 2214: ap.port = 514;
! 2215: }
! 2216:
! 2217: if ((cp1 = strchr(s, '/')) != NULL &&
! 2218: strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
! 2219: *cp1 = '\0';
! 2220: if ((masklen = atoi(cp1 + 1)) < 0)
! 2221: return (-1);
! 2222: }
! 2223: #ifdef INET6
! 2224: if (*s == '[') {
! 2225: cp2 = s + strlen(s) - 1;
! 2226: if (*cp2 == ']') {
! 2227: ++s;
! 2228: *cp2 = '\0';
! 2229: } else {
! 2230: cp2 = NULL;
! 2231: }
! 2232: } else {
! 2233: cp2 = NULL;
! 2234: }
! 2235: #endif
! 2236: memset(&hints, 0, sizeof(hints));
! 2237: hints.ai_family = PF_UNSPEC;
! 2238: hints.ai_socktype = SOCK_DGRAM;
! 2239: hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
! 2240: if (getaddrinfo(s, NULL, &hints, &res) == 0) {
! 2241: ap.isnumeric = 1;
! 2242: memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
! 2243: memset(&ap.a_mask, 0, sizeof(ap.a_mask));
! 2244: ap.a_mask.ss_family = res->ai_family;
! 2245: if (res->ai_family == AF_INET) {
! 2246: ap.a_mask.ss_len = sizeof(struct sockaddr_in);
! 2247: maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
! 2248: addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
! 2249: if (masklen < 0) {
! 2250: /* use default netmask */
! 2251: if (IN_CLASSA(ntohl(addrp->s_addr)))
! 2252: maskp->s_addr = htonl(IN_CLASSA_NET);
! 2253: else if (IN_CLASSB(ntohl(addrp->s_addr)))
! 2254: maskp->s_addr = htonl(IN_CLASSB_NET);
! 2255: else
! 2256: maskp->s_addr = htonl(IN_CLASSC_NET);
! 2257: } else if (masklen <= 32) {
! 2258: /* convert masklen to netmask */
! 2259: if (masklen == 0)
! 2260: maskp->s_addr = 0;
! 2261: else
! 2262: maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
! 2263: } else {
! 2264: freeaddrinfo(res);
! 2265: return (-1);
! 2266: }
! 2267: /* Lose any host bits in the network number. */
! 2268: addrp->s_addr &= maskp->s_addr;
! 2269: }
! 2270: #ifdef INET6
! 2271: else if (res->ai_family == AF_INET6 && masklen <= 128) {
! 2272: ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
! 2273: if (masklen < 0)
! 2274: masklen = 128;
! 2275: mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
! 2276: /* convert masklen to netmask */
! 2277: while (masklen > 0) {
! 2278: if (masklen < 32) {
! 2279: *mask6p = htonl(~(0xffffffff >> masklen));
! 2280: break;
! 2281: }
! 2282: *mask6p++ = 0xffffffff;
! 2283: masklen -= 32;
! 2284: }
! 2285: /* Lose any host bits in the network number. */
! 2286: mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
! 2287: addr6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_addr)->sin6_addr;
! 2288: for (i = 0; i < 4; i++)
! 2289: addr6p[i] &= mask6p[i];
! 2290: }
! 2291: #endif
! 2292: else {
! 2293: freeaddrinfo(res);
! 2294: return (-1);
! 2295: }
! 2296: freeaddrinfo(res);
! 2297: } else {
! 2298: /* arg `s' is domain name */
! 2299: ap.isnumeric = 0;
! 2300: ap.a_name = s;
! 2301: if (cp1)
! 2302: *cp1 = '/';
! 2303: #ifdef INET6
! 2304: if (cp2) {
! 2305: *cp2 = ']';
! 2306: --s;
! 2307: }
! 2308: #endif
! 2309: }
! 2310:
! 2311: if (Debug) {
! 2312: printf("allowaddr: rule %d: ", NumAllowed);
! 2313: if (ap.isnumeric) {
! 2314: printf("numeric, ");
! 2315: getnameinfo((struct sockaddr *)&ap.a_addr,
! 2316: ((struct sockaddr *)&ap.a_addr)->sa_len,
! 2317: ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
! 2318: printf("addr = %s, ", ip);
! 2319: getnameinfo((struct sockaddr *)&ap.a_mask,
! 2320: ((struct sockaddr *)&ap.a_mask)->sa_len,
! 2321: ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
! 2322: printf("mask = %s; ", ip);
! 2323: } else {
! 2324: printf("domainname = %s; ", ap.a_name);
! 2325: }
! 2326: printf("port = %d\n", ap.port);
! 2327: }
! 2328:
! 2329: if ((AllowedPeers = realloc(AllowedPeers,
! 2330: ++NumAllowed * sizeof(struct allowedpeer)))
! 2331: == NULL) {
! 2332: logerror("realloc");
! 2333: exit(1);
! 2334: }
! 2335: memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
! 2336: return (0);
! 2337: }
! 2338:
! 2339: /*
! 2340: * Validate that the remote peer has permission to log to us.
! 2341: */
! 2342: static int
! 2343: validate(struct sockaddr *sa, const char *hname)
! 2344: {
! 2345: int i;
! 2346: size_t l1, l2;
! 2347: char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
! 2348: struct allowedpeer *ap;
! 2349: struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL;
! 2350: #ifdef INET6
! 2351: int j, reject;
! 2352: struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
! 2353: #endif
! 2354: struct addrinfo hints, *res;
! 2355: u_short sport;
! 2356:
! 2357: if (NumAllowed == 0)
! 2358: /* traditional behaviour, allow everything */
! 2359: return (1);
! 2360:
! 2361: (void)strlcpy(name, hname, sizeof(name));
! 2362: memset(&hints, 0, sizeof(hints));
! 2363: hints.ai_family = PF_UNSPEC;
! 2364: hints.ai_socktype = SOCK_DGRAM;
! 2365: hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
! 2366: if (getaddrinfo(name, NULL, &hints, &res) == 0)
! 2367: freeaddrinfo(res);
! 2368: else if (strchr(name, '.') == NULL) {
! 2369: strlcat(name, ".", sizeof name);
! 2370: strlcat(name, LocalDomain, sizeof name);
! 2371: }
! 2372: if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
! 2373: NI_NUMERICHOST | NI_NUMERICSERV) != 0)
! 2374: return (0); /* for safety, should not occur */
! 2375: dprintf("validate: dgram from IP %s, port %s, name %s;\n",
! 2376: ip, port, name);
! 2377: sport = atoi(port);
! 2378:
! 2379: /* now, walk down the list */
! 2380: for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
! 2381: if (ap->port != 0 && ap->port != sport) {
! 2382: dprintf("rejected in rule %d due to port mismatch.\n", i);
! 2383: continue;
! 2384: }
! 2385:
! 2386: if (ap->isnumeric) {
! 2387: if (ap->a_addr.ss_family != sa->sa_family) {
! 2388: dprintf("rejected in rule %d due to address family mismatch.\n", i);
! 2389: continue;
! 2390: }
! 2391: if (ap->a_addr.ss_family == AF_INET) {
! 2392: sin4 = (struct sockaddr_in *)sa;
! 2393: a4p = (struct sockaddr_in *)&ap->a_addr;
! 2394: m4p = (struct sockaddr_in *)&ap->a_mask;
! 2395: if ((sin4->sin_addr.s_addr & m4p->sin_addr.s_addr)
! 2396: != a4p->sin_addr.s_addr) {
! 2397: dprintf("rejected in rule %d due to IP mismatch.\n", i);
! 2398: continue;
! 2399: }
! 2400: }
! 2401: #ifdef INET6
! 2402: else if (ap->a_addr.ss_family == AF_INET6) {
! 2403: sin6 = (struct sockaddr_in6 *)sa;
! 2404: a6p = (struct sockaddr_in6 *)&ap->a_addr;
! 2405: m6p = (struct sockaddr_in6 *)&ap->a_mask;
! 2406: if (a6p->sin6_scope_id != 0 &&
! 2407: sin6->sin6_scope_id != a6p->sin6_scope_id) {
! 2408: dprintf("rejected in rule %d due to scope mismatch.\n", i);
! 2409: continue;
! 2410: }
! 2411: reject = 0;
! 2412: for (j = 0; j < 16; j += 4) {
! 2413: if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j])
! 2414: != *(u_int32_t *)&a6p->sin6_addr.s6_addr[j]) {
! 2415: ++reject;
! 2416: break;
! 2417: }
! 2418: }
! 2419: if (reject) {
! 2420: dprintf("rejected in rule %d due to IP mismatch.\n", i);
! 2421: continue;
! 2422: }
! 2423: }
! 2424: #endif
! 2425: else
! 2426: continue;
! 2427: } else {
! 2428: cp = ap->a_name;
! 2429: l1 = strlen(name);
! 2430: if (*cp == '*') {
! 2431: /* allow wildmatch */
! 2432: cp++;
! 2433: l2 = strlen(cp);
! 2434: if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
! 2435: dprintf("rejected in rule %d due to name mismatch.\n", i);
! 2436: continue;
! 2437: }
! 2438: } else {
! 2439: /* exact match */
! 2440: l2 = strlen(cp);
! 2441: if (l2 != l1 || memcmp(cp, name, l1) != 0) {
! 2442: dprintf("rejected in rule %d due to name mismatch.\n", i);
! 2443: continue;
! 2444: }
! 2445: }
! 2446: }
! 2447: dprintf("accepted in rule %d.\n", i);
! 2448: return (1); /* hooray! */
! 2449: }
! 2450: return (0);
! 2451: }
! 2452:
! 2453: /*
! 2454: * Fairly similar to popen(3), but returns an open descriptor, as
! 2455: * opposed to a FILE *.
! 2456: */
! 2457: static int
! 2458: p_open(const char *prog, pid_t *rpid)
! 2459: {
! 2460: int pfd[2], nulldesc, i;
! 2461: pid_t pid;
! 2462: sigset_t omask, mask;
! 2463: char *argv[4]; /* sh -c cmd NULL */
! 2464: char errmsg[200];
! 2465:
! 2466: if (pipe(pfd) == -1)
! 2467: return (-1);
! 2468: if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
! 2469: /* we are royally screwed anyway */
! 2470: return (-1);
! 2471:
! 2472: sigemptyset(&mask);
! 2473: sigaddset(&mask, SIGALRM);
! 2474: sigaddset(&mask, SIGHUP);
! 2475: sigprocmask(SIG_BLOCK, &mask, &omask);
! 2476: switch ((pid = fork())) {
! 2477: case -1:
! 2478: sigprocmask(SIG_SETMASK, &omask, 0);
! 2479: close(nulldesc);
! 2480: return (-1);
! 2481:
! 2482: case 0:
! 2483: argv[0] = strdup("sh");
! 2484: argv[1] = strdup("-c");
! 2485: argv[2] = strdup(prog);
! 2486: argv[3] = NULL;
! 2487: if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL) {
! 2488: logerror("strdup");
! 2489: exit(1);
! 2490: }
! 2491:
! 2492: alarm(0);
! 2493: (void)setsid(); /* Avoid catching SIGHUPs. */
! 2494:
! 2495: /*
! 2496: * Throw away pending signals, and reset signal
! 2497: * behaviour to standard values.
! 2498: */
! 2499: signal(SIGALRM, SIG_IGN);
! 2500: signal(SIGHUP, SIG_IGN);
! 2501: sigprocmask(SIG_SETMASK, &omask, 0);
! 2502: signal(SIGPIPE, SIG_DFL);
! 2503: signal(SIGQUIT, SIG_DFL);
! 2504: signal(SIGALRM, SIG_DFL);
! 2505: signal(SIGHUP, SIG_DFL);
! 2506:
! 2507: dup2(pfd[0], STDIN_FILENO);
! 2508: dup2(nulldesc, STDOUT_FILENO);
! 2509: dup2(nulldesc, STDERR_FILENO);
! 2510: for (i = getdtablesize(); i > 2; i--)
! 2511: (void)close(i);
! 2512:
! 2513: (void)execvp(_PATH_BSHELL, argv);
! 2514: _exit(255);
! 2515: }
! 2516:
! 2517: sigprocmask(SIG_SETMASK, &omask, 0);
! 2518: close(nulldesc);
! 2519: close(pfd[0]);
! 2520: /*
! 2521: * Avoid blocking on a hung pipe. With O_NONBLOCK, we are
! 2522: * supposed to get an EWOULDBLOCK on writev(2), which is
! 2523: * caught by the logic above anyway, which will in turn close
! 2524: * the pipe, and fork a new logging subprocess if necessary.
! 2525: * The stale subprocess will be killed some time later unless
! 2526: * it terminated itself due to closing its input pipe (so we
! 2527: * get rid of really dead puppies).
! 2528: */
! 2529: if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
! 2530: /* This is bad. */
! 2531: (void)snprintf(errmsg, sizeof errmsg,
! 2532: "Warning: cannot change pipe to PID %d to "
! 2533: "non-blocking behaviour.",
! 2534: (int)pid);
! 2535: logerror(errmsg);
! 2536: }
! 2537: *rpid = pid;
! 2538: return (pfd[1]);
! 2539: }
! 2540:
! 2541: static void
! 2542: deadq_enter(pid_t pid, const char *name)
! 2543: {
! 2544: dq_t p;
! 2545: int status;
! 2546:
! 2547: /*
! 2548: * Be paranoid, if we can't signal the process, don't enter it
! 2549: * into the dead queue (perhaps it's already dead). If possible,
! 2550: * we try to fetch and log the child's status.
! 2551: */
! 2552: if (kill(pid, 0) != 0) {
! 2553: if (waitpid(pid, &status, WNOHANG) > 0)
! 2554: log_deadchild(pid, status, name);
! 2555: return;
! 2556: }
! 2557:
! 2558: p = malloc(sizeof(struct deadq_entry));
! 2559: if (p == NULL) {
! 2560: logerror("malloc");
! 2561: exit(1);
! 2562: }
! 2563:
! 2564: p->dq_pid = pid;
! 2565: p->dq_timeout = DQ_TIMO_INIT;
! 2566: TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
! 2567: }
! 2568:
! 2569: static int
! 2570: deadq_remove(pid_t pid)
! 2571: {
! 2572: dq_t q;
! 2573:
! 2574: TAILQ_FOREACH(q, &deadq_head, dq_entries) {
! 2575: if (q->dq_pid == pid) {
! 2576: TAILQ_REMOVE(&deadq_head, q, dq_entries);
! 2577: free(q);
! 2578: return (1);
! 2579: }
! 2580: }
! 2581:
! 2582: return (0);
! 2583: }
! 2584:
! 2585: static void
! 2586: log_deadchild(pid_t pid, int status, const char *name)
! 2587: {
! 2588: int code;
! 2589: char buf[256];
! 2590: const char *reason;
! 2591:
! 2592: errno = 0; /* Keep strerror() stuff out of logerror messages. */
! 2593: if (WIFSIGNALED(status)) {
! 2594: reason = "due to signal";
! 2595: code = WTERMSIG(status);
! 2596: } else {
! 2597: reason = "with status";
! 2598: code = WEXITSTATUS(status);
! 2599: if (code == 0)
! 2600: return;
! 2601: }
! 2602: (void)snprintf(buf, sizeof buf,
! 2603: "Logging subprocess %d (%s) exited %s %d.",
! 2604: pid, name, reason, code);
! 2605: logerror(buf);
! 2606: }
! 2607:
! 2608: static int *
! 2609: socksetup(int af, char *bindhostname)
! 2610: {
! 2611: struct addrinfo hints, *res, *r;
! 2612: const char *bindservice;
! 2613: char *cp;
! 2614: int error, maxs, *s, *socks;
! 2615:
! 2616: /*
! 2617: * We have to handle this case for backwards compatibility:
! 2618: * If there are two (or more) colons but no '[' and ']',
! 2619: * assume this is an inet6 address without a service.
! 2620: */
! 2621: bindservice = "syslog";
! 2622: if (bindhostname != NULL) {
! 2623: #ifdef INET6
! 2624: if (*bindhostname == '[' &&
! 2625: (cp = strchr(bindhostname + 1, ']')) != NULL) {
! 2626: ++bindhostname;
! 2627: *cp = '\0';
! 2628: if (cp[1] == ':' && cp[2] != '\0')
! 2629: bindservice = cp + 2;
! 2630: } else {
! 2631: #endif
! 2632: cp = strchr(bindhostname, ':');
! 2633: if (cp != NULL && strchr(cp + 1, ':') == NULL) {
! 2634: *cp = '\0';
! 2635: if (cp[1] != '\0')
! 2636: bindservice = cp + 1;
! 2637: if (cp == bindhostname)
! 2638: bindhostname = NULL;
! 2639: }
! 2640: #ifdef INET6
! 2641: }
! 2642: #endif
! 2643: }
! 2644:
! 2645: memset(&hints, 0, sizeof(hints));
! 2646: hints.ai_flags = AI_PASSIVE;
! 2647: hints.ai_family = af;
! 2648: hints.ai_socktype = SOCK_DGRAM;
! 2649: error = getaddrinfo(bindhostname, bindservice, &hints, &res);
! 2650: if (error) {
! 2651: logerror(gai_strerror(error));
! 2652: errno = 0;
! 2653: die(0);
! 2654: }
! 2655:
! 2656: /* Count max number of sockets we may open */
! 2657: for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
! 2658: socks = malloc((maxs+1) * sizeof(int));
! 2659: if (socks == NULL) {
! 2660: logerror("couldn't allocate memory for sockets");
! 2661: die(0);
! 2662: }
! 2663:
! 2664: *socks = 0; /* num of sockets counter at start of array */
! 2665: s = socks + 1;
! 2666: for (r = res; r; r = r->ai_next) {
! 2667: int on = 1;
! 2668: *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
! 2669: if (*s < 0) {
! 2670: logerror("socket");
! 2671: continue;
! 2672: }
! 2673: if (r->ai_family == AF_INET6) {
! 2674: if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
! 2675: (char *)&on, sizeof (on)) < 0) {
! 2676: logerror("setsockopt");
! 2677: close(*s);
! 2678: continue;
! 2679: }
! 2680: }
! 2681: if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
! 2682: (char *)&on, sizeof (on)) < 0) {
! 2683: logerror("setsockopt");
! 2684: close(*s);
! 2685: continue;
! 2686: }
! 2687: if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
! 2688: close(*s);
! 2689: logerror("bind");
! 2690: continue;
! 2691: }
! 2692:
! 2693: double_rbuf(*s);
! 2694:
! 2695: (*socks)++;
! 2696: s++;
! 2697: }
! 2698:
! 2699: if (*socks == 0) {
! 2700: free(socks);
! 2701: if (Debug)
! 2702: return (NULL);
! 2703: else
! 2704: die(0);
! 2705: }
! 2706: if (res)
! 2707: freeaddrinfo(res);
! 2708:
! 2709: return (socks);
! 2710: }
! 2711:
! 2712: static void
! 2713: double_rbuf(int fd)
! 2714: {
! 2715: socklen_t slen, len;
! 2716:
! 2717: if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) {
! 2718: len *= 2;
! 2719: setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen);
! 2720: }
! 2721: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>