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