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>