11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1988, 1993, 1994
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
301553Srgrimes#ifndef lint
3111448Swollmanstatic const char copyright[] =
321553Srgrimes"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
331553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
3430603Scharnier#endif /* not lint */
3530603Scharnier
3630603Scharnier#ifndef lint
3730603Scharnier#if 0
381553Srgrimesstatic char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
3930603Scharnier#endif
401553Srgrimes#endif /* not lint */
411553Srgrimes
4293078Sdes#include <sys/cdefs.h>
4393078Sdes__FBSDID("$FreeBSD$");
4493078Sdes
451553Srgrimes/*
461553Srgrimes *  syslogd -- log system messages
471553Srgrimes *
481553Srgrimes * This program implements a system log. It takes a series of lines.
491553Srgrimes * Each line may have a priority, signified as "<n>" as
501553Srgrimes * the first characters of the line.  If this is
511553Srgrimes * not present, a default priority is used.
521553Srgrimes *
531553Srgrimes * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
541553Srgrimes * cause it to reread its configuration file.
551553Srgrimes *
561553Srgrimes * Defined Constants:
571553Srgrimes *
58129851Sdwmalone * MAXLINE -- the maximum line length that can be handled.
591553Srgrimes * DEFUPRI -- the default priority for user messages
601553Srgrimes * DEFSPRI -- the default priority for kernel messages
611553Srgrimes *
621553Srgrimes * Author: Eric Allman
631553Srgrimes * extensive changes by Ralph Campbell
641553Srgrimes * more extensive changes by Eric Allman (again)
655278Swollman * Extension to log by program name as well as facility and priority
665278Swollman *   by Peter da Silva.
6737820Sphk * -u and -v by Harlan Stenn.
6837820Sphk * Priority comparison code by Harlan Stenn.
691553Srgrimes */
701553Srgrimes
711553Srgrimes#define	MAXLINE		1024		/* maximum line length */
721553Srgrimes#define	MAXSVLINE	120		/* maximum saved line length */
73174316Sobrien#define	DEFUPRI		(LOG_USER|LOG_NOTICE)
74174316Sobrien#define	DEFSPRI		(LOG_KERN|LOG_CRIT)
75174316Sobrien#define	TIMERINTVL	30		/* interval for checking flush, mark */
76174316Sobrien#define	TTYMSGTIME	1		/* timeout passed to ttymsg */
771553Srgrimes
781553Srgrimes#include <sys/param.h>
791553Srgrimes#include <sys/ioctl.h>
80199804Sattilio#include <sys/mman.h>
811553Srgrimes#include <sys/stat.h>
821553Srgrimes#include <sys/wait.h>
831553Srgrimes#include <sys/socket.h>
8422984Sjoerg#include <sys/queue.h>
851553Srgrimes#include <sys/uio.h>
861553Srgrimes#include <sys/un.h>
871553Srgrimes#include <sys/time.h>
881553Srgrimes#include <sys/resource.h>
895278Swollman#include <sys/syslimits.h>
90115108Sgshapiro#include <sys/types.h>
911553Srgrimes
921553Srgrimes#include <netinet/in.h>
931553Srgrimes#include <netdb.h>
941553Srgrimes#include <arpa/inet.h>
951553Srgrimes
961553Srgrimes#include <ctype.h>
9730603Scharnier#include <err.h>
981553Srgrimes#include <errno.h>
991553Srgrimes#include <fcntl.h>
100115108Sgshapiro#include <libutil.h>
101106054Swollman#include <limits.h>
10293078Sdes#include <paths.h>
1031553Srgrimes#include <signal.h>
1041553Srgrimes#include <stdio.h>
1051553Srgrimes#include <stdlib.h>
1061553Srgrimes#include <string.h>
10725437Sjoerg#include <sysexits.h>
1081553Srgrimes#include <unistd.h>
109202206Sed#include <utmpx.h>
11083243Sdd
1111553Srgrimes#include "pathnames.h"
11283243Sdd#include "ttymsg.h"
1131553Srgrimes
1141553Srgrimes#define SYSLOG_NAMES
1151553Srgrimes#include <sys/syslog.h>
11619224Sjoerg
11711448Swollmanconst char	*ConfFile = _PATH_LOGCONF;
11811448Swollmanconst char	*PidFile = _PATH_LOGPID;
11911448Swollmanconst char	ctty[] = _PATH_CONSOLE;
1201553Srgrimes
1211553Srgrimes#define	dprintf		if (Debug) printf
1221553Srgrimes
123174316Sobrien#define	MAXUNAMES	20	/* maximum number of user names */
1241553Srgrimes
125137232Sglebius/*
126137232Sglebius * Unix sockets.
127137233Sglebius * We have two default sockets, one with 666 permissions,
128137857Skeramida * and one for privileged programs.
129137232Sglebius */
130137232Sglebiusstruct funix {
131137232Sglebius	int			s;
132186331Sdelphij	const char		*name;
133137232Sglebius	mode_t			mode;
134137232Sglebius	STAILQ_ENTRY(funix)	next;
135137232Sglebius};
136137233Sglebiusstruct funix funix_secure =	{ -1, _PATH_LOG_PRIV, S_IRUSR | S_IWUSR,
137137233Sglebius				{ NULL } };
138137232Sglebiusstruct funix funix_default =	{ -1, _PATH_LOG, DEFFILEMODE,
139137233Sglebius				{ &funix_secure } };
14037156Sguido
141137232SglebiusSTAILQ_HEAD(, funix) funixes =	{ &funix_default,
142137233Sglebius				&(funix_secure.next.stqe_next) };
14337156Sguido
1441553Srgrimes/*
1451553Srgrimes * Flags to logmsg().
1461553Srgrimes */
1471553Srgrimes
148174316Sobrien#define	IGN_CONS	0x001	/* don't print on console */
149174316Sobrien#define	SYNC_FILE	0x002	/* do fsync on file after printing */
150174316Sobrien#define	ADDDATE		0x004	/* add a date to the message */
151174316Sobrien#define	MARK		0x008	/* this message is a mark */
152174316Sobrien#define	ISKERNEL	0x010	/* kernel generated message */
1531553Srgrimes
1541553Srgrimes/*
1551553Srgrimes * This structure represents the files that will have log
1561553Srgrimes * copies printed.
157129855Sdwmalone * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
158129855Sdwmalone * or if f_type if F_PIPE and f_pid > 0.
1591553Srgrimes */
1601553Srgrimes
1611553Srgrimesstruct filed {
1621553Srgrimes	struct	filed *f_next;		/* next in linked list */
1631553Srgrimes	short	f_type;			/* entry type, see below */
1641553Srgrimes	short	f_file;			/* file descriptor */
1651553Srgrimes	time_t	f_time;			/* time this was last written */
16663795Sdwmalone	char	*f_host;		/* host from which to recd. */
1671553Srgrimes	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
16837820Sphk	u_char	f_pcmp[LOG_NFACILITIES+1];	/* compare priority */
16937820Sphk#define PRI_LT	0x1
17037820Sphk#define PRI_EQ	0x2
17137820Sphk#define PRI_GT	0x4
1725278Swollman	char	*f_program;		/* program this applies to */
1731553Srgrimes	union {
174200954Sed		char	f_uname[MAXUNAMES][MAXLOGNAME];
1751553Srgrimes		struct {
17674053Sbrian			char	f_hname[MAXHOSTNAMELEN];
17770099Sume			struct addrinfo *f_addr;
17870099Sume
1791553Srgrimes		} f_forw;		/* forwarding address */
1801553Srgrimes		char	f_fname[MAXPATHLEN];
18122984Sjoerg		struct {
18222984Sjoerg			char	f_pname[MAXPATHLEN];
18322984Sjoerg			pid_t	f_pid;
18422984Sjoerg		} f_pipe;
1851553Srgrimes	} f_un;
1861553Srgrimes	char	f_prevline[MAXSVLINE];		/* last message logged */
1871553Srgrimes	char	f_lasttime[16];			/* time of last occurrence */
18874053Sbrian	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
1891553Srgrimes	int	f_prevpri;			/* pri of f_prevline */
1901553Srgrimes	int	f_prevlen;			/* length of f_prevline */
1911553Srgrimes	int	f_prevcount;			/* repetition cnt of prevline */
19283243Sdd	u_int	f_repeatcount;			/* number of "repeated" msgs */
193129865Sdwmalone	int	f_flags;			/* file-specific flags */
194174316Sobrien#define	FFLAG_SYNC 0x01
195174316Sobrien#define	FFLAG_NEEDSYNC	0x02
1961553Srgrimes};
1971553Srgrimes
1981553Srgrimes/*
19922984Sjoerg * Queue of about-to-be dead processes we should watch out for.
20022984Sjoerg */
20122984Sjoerg
20260938SjakeTAILQ_HEAD(stailhead, deadq_entry) deadq_head;
20322984Sjoergstruct stailhead *deadq_headp;
20422984Sjoerg
20522984Sjoergstruct deadq_entry {
20622984Sjoerg	pid_t				dq_pid;
20722984Sjoerg	int				dq_timeout;
20860938Sjake	TAILQ_ENTRY(deadq_entry)	dq_entries;
20922984Sjoerg};
21022984Sjoerg
21122984Sjoerg/*
21222984Sjoerg * The timeout to apply to processes waiting on the dead queue.  Unit
21322984Sjoerg * of measure is `mark intervals', i.e. 20 minutes by default.
21422984Sjoerg * Processes on the dead queue will be terminated after that time.
21522984Sjoerg */
21622984Sjoerg
217174316Sobrien#define	 DQ_TIMO_INIT	2
21822984Sjoerg
21922984Sjoergtypedef struct deadq_entry *dq_t;
22022984Sjoerg
22122984Sjoerg
22222984Sjoerg/*
22325437Sjoerg * Struct to hold records of network addresses that are allowed to log
22425437Sjoerg * to us.
22525437Sjoerg */
22625437Sjoergstruct allowedpeer {
22725437Sjoerg	int isnumeric;
22825437Sjoerg	u_short port;
22925437Sjoerg	union {
23025437Sjoerg		struct {
23170099Sume			struct sockaddr_storage addr;
23270099Sume			struct sockaddr_storage mask;
23325437Sjoerg		} numeric;
23425437Sjoerg		char *name;
23525437Sjoerg	} u;
23625437Sjoerg#define a_addr u.numeric.addr
23725437Sjoerg#define a_mask u.numeric.mask
23825437Sjoerg#define a_name u.name
23925437Sjoerg};
24025437Sjoerg
24125437Sjoerg
24225437Sjoerg/*
2431553Srgrimes * Intervals at which we flush out "message repeated" messages,
2441553Srgrimes * in seconds after previous message is logged.  After each flush,
2451553Srgrimes * we move to the next interval until we reach the largest.
2461553Srgrimes */
2471553Srgrimesint	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
2481553Srgrimes#define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
2491553Srgrimes#define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
2501553Srgrimes#define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
2511553Srgrimes				 (f)->f_repeatcount = MAXREPEAT; \
2521553Srgrimes			}
2531553Srgrimes
2541553Srgrimes/* values for f_type */
2551553Srgrimes#define F_UNUSED	0		/* unused entry */
2561553Srgrimes#define F_FILE		1		/* regular file */
2571553Srgrimes#define F_TTY		2		/* terminal */
2581553Srgrimes#define F_CONSOLE	3		/* console terminal */
2591553Srgrimes#define F_FORW		4		/* remote machine */
2601553Srgrimes#define F_USERS		5		/* list of users */
2611553Srgrimes#define F_WALL		6		/* everyone logged on */
26222984Sjoerg#define F_PIPE		7		/* pipe to program */
2631553Srgrimes
26483243Sddconst char *TypeNames[8] = {
2651553Srgrimes	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
26622984Sjoerg	"FORW",		"USERS",	"WALL",		"PIPE"
2671553Srgrimes};
2681553Srgrimes
26993078Sdesstatic struct filed *Files;	/* Log files that we write to */
27093078Sdesstatic struct filed consfile;	/* Console */
2711553Srgrimes
27293078Sdesstatic int	Debug;		/* debug flag */
27393078Sdesstatic int	resolve = 1;	/* resolve hostname */
27493078Sdesstatic char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
275129756Sdwmalonestatic const char *LocalDomain;	/* our local domain name */
27693078Sdesstatic int	*finet;		/* Internet datagram socket */
27793078Sdesstatic int	fklog = -1;	/* /dev/klog */
27893078Sdesstatic int	Initialized;	/* set when we have initialized ourselves */
27993078Sdesstatic int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
28093078Sdesstatic int	MarkSeq;	/* mark sequence number */
281224002Sdelphijstatic int	NoBind;		/* don't bind() as suggested by RFC 3164 */
28293078Sdesstatic int	SecureMode;	/* when true, receive only unix domain socks */
28370099Sume#ifdef INET6
28493078Sdesstatic int	family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
28570099Sume#else
28693078Sdesstatic int	family = PF_INET; /* protocol family (IPv4 only) */
28770099Sume#endif
288178986Sbrianstatic int	mask_C1 = 1;	/* mask characters from 0x80 - 0x9F */
28993078Sdesstatic int	send_to_all;	/* send message to all IPv4/IPv6 addresses */
29093078Sdesstatic int	use_bootfile;	/* log entire bootfile for every kern msg */
29193078Sdesstatic int	no_compress;	/* don't compress messages (1=pipes, 2=all) */
292156339Spjdstatic int	logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
29317245Spst
29493078Sdesstatic char	bootfile[MAXLINE+1]; /* booted kernel file */
2951553Srgrimes
29693078Sdesstruct allowedpeer *AllowedPeers; /* List of allowed peers */
29793078Sdesstatic int	NumAllowed;	/* Number of entries in AllowedPeers */
298183347Sdwmalonestatic int	RemoteAddDate;	/* Always set the date on remote messages */
29925437Sjoerg
30093078Sdesstatic int	UniquePriority;	/* Only log specified priority? */
30193078Sdesstatic int	LogFacPri;	/* Put facility and priority in log message: */
30237820Sphk				/* 0=no, 1=numeric, 2=names */
30393078Sdesstatic int	KeepKernFac;	/* Keep remotely logged kernel facility */
304131589Scpercivastatic int	needdofsync = 0; /* Are any file(s) waiting to be fsynced? */
305149425Spjdstatic struct pidfh *pfh;
30637820Sphk
30782724Skrisvolatile sig_atomic_t MarkSet, WantDie;
30882724Skris
30993078Sdesstatic int	allowaddr(char *);
31093078Sdesstatic void	cfline(const char *, struct filed *,
31193078Sdes		    const char *, const char *);
31293078Sdesstatic const char *cvthname(struct sockaddr *);
31393078Sdesstatic void	deadq_enter(pid_t, const char *);
31493078Sdesstatic int	deadq_remove(pid_t);
31593078Sdesstatic int	decode(const char *, CODE *);
31693078Sdesstatic void	die(int);
31793078Sdesstatic void	dodie(int);
318131591Scpercivastatic void	dofsync(void);
31993078Sdesstatic void	domark(int);
32093078Sdesstatic void	fprintlog(struct filed *, int, const char *);
321211023Sollistatic int	*socksetup(int, char *);
32293078Sdesstatic void	init(int);
32393078Sdesstatic void	logerror(const char *);
32493078Sdesstatic void	logmsg(int, const char *, const char *, int);
32593078Sdesstatic void	log_deadchild(pid_t, int, const char *);
32693078Sdesstatic void	markit(void);
327114676Sgshapirostatic int	skip_message(const char *, const char *, int);
328183347Sdwmalonestatic void	printline(const char *, char *, int);
32993078Sdesstatic void	printsys(char *);
33093078Sdesstatic int	p_open(const char *, pid_t *);
33193078Sdesstatic void	readklog(void);
33293078Sdesstatic void	reapchild(int);
33393077Sdesstatic void	usage(void);
33493078Sdesstatic int	validate(struct sockaddr *, const char *);
33593077Sdesstatic void	unmapped(struct sockaddr *);
336186234Sobrienstatic void	wallmsg(struct filed *, struct iovec *, const int iovlen);
33793078Sdesstatic int	waitdaemon(int, int, int);
33893078Sdesstatic void	timedout(int);
339137568Sglebiusstatic void	double_rbuf(int);
3401553Srgrimes
3411553Srgrimesint
34293078Sdesmain(int argc, char *argv[])
3431553Srgrimes{
34482724Skris	int ch, i, fdsrmax = 0, l;
3451553Srgrimes	struct sockaddr_un sunx, fromunix;
34670099Sume	struct sockaddr_storage frominet;
34782724Skris	fd_set *fdsr = NULL;
34883243Sdd	char line[MAXLINE + 1];
349211023Solli	char *bindhostname;
350211023Solli	const char *hname;
35118710Speter	struct timeval tv, *tvp;
35257558Sjoerg	struct sigaction sact;
353137232Sglebius	struct funix *fx, *fx1;
35457558Sjoerg	sigset_t mask;
355149425Spjd	pid_t ppid = 1, spid;
35655971Sdes	socklen_t len;
3571553Srgrimes
358199804Sattilio	if (madvise(NULL, 0, MADV_PROTECT) != 0)
359199804Sattilio		dprintf("madvise() failed: %s\n", strerror(errno));
360199804Sattilio
36182728Sdd	bindhostname = NULL;
362224002Sdelphij	while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nNop:P:sS:Tuv"))
363183347Sdwmalone	    != -1)
36464195Sdwmalone		switch (ch) {
36570099Sume		case '4':
36670099Sume			family = PF_INET;
36770099Sume			break;
36870099Sume#ifdef INET6
36970099Sume		case '6':
37070099Sume			family = PF_INET6;
37170099Sume			break;
37270099Sume#endif
373178986Sbrian		case '8':
374178986Sbrian			mask_C1 = 0;
375178986Sbrian			break;
37670099Sume		case 'A':
37770099Sume			send_to_all++;
37870099Sume			break;
37925437Sjoerg		case 'a':		/* allow specific network addresses only */
38025437Sjoerg			if (allowaddr(optarg) == -1)
38125437Sjoerg				usage();
38225437Sjoerg			break;
38382728Sdd		case 'b':
38482728Sdd			bindhostname = optarg;
38582728Sdd			break;
38688897Sarchie		case 'c':
38788897Sarchie			no_compress++;
38888897Sarchie			break;
389156339Spjd		case 'C':
390156339Spjd			logflags |= O_CREAT;
391156339Spjd			break;
39264195Sdwmalone		case 'd':		/* debug */
39364195Sdwmalone			Debug++;
39464195Sdwmalone			break;
3951553Srgrimes		case 'f':		/* configuration file */
3961553Srgrimes			ConfFile = optarg;
3971553Srgrimes			break;
39867249Sdwmalone		case 'k':		/* keep remote kern fac */
39967249Sdwmalone			KeepKernFac = 1;
40067249Sdwmalone			break;
40164195Sdwmalone		case 'l':
402137232Sglebius		    {
403137232Sglebius			long	perml;
404137232Sglebius			mode_t	mode;
405137232Sglebius			char	*name, *ep;
406137232Sglebius
407137232Sglebius			if (optarg[0] == '/') {
408137232Sglebius				mode = DEFFILEMODE;
409137232Sglebius				name = optarg;
410137232Sglebius			} else if ((name = strchr(optarg, ':')) != NULL) {
411137232Sglebius				*name++ = '\0';
412137232Sglebius				if (name[0] != '/')
413137232Sglebius					errx(1, "socket name must be absolute "
414137232Sglebius					    "path");
415137232Sglebius				if (isdigit(*optarg)) {
416137232Sglebius					perml = strtol(optarg, &ep, 8);
417137232Sglebius				    if (*ep || perml < 0 ||
418137232Sglebius					perml & ~(S_IRWXU|S_IRWXG|S_IRWXO))
419137232Sglebius					    errx(1, "invalid mode %s, exiting",
420137232Sglebius						optarg);
421137232Sglebius				    mode = (mode_t )perml;
422137232Sglebius				} else
423137232Sglebius					errx(1, "invalid mode %s, exiting",
424137232Sglebius					    optarg);
425137232Sglebius			} else	/* doesn't begin with '/', and no ':' */
426137232Sglebius				errx(1, "can't parse path %s", optarg);
427137232Sglebius
428137232Sglebius			if (strlen(name) >= sizeof(sunx.sun_path))
429137232Sglebius				errx(1, "%s path too long, exiting", name);
430137232Sglebius			if ((fx = malloc(sizeof(struct funix))) == NULL)
431137232Sglebius				errx(1, "malloc failed");
432137232Sglebius			fx->s = -1;
433137232Sglebius			fx->name = name;
434137232Sglebius			fx->mode = mode;
435137232Sglebius			STAILQ_INSERT_TAIL(&funixes, fx, next);
43664195Sdwmalone			break;
437137232Sglebius		   }
4381553Srgrimes		case 'm':		/* mark interval */
4391553Srgrimes			MarkInterval = atoi(optarg) * 60;
4401553Srgrimes			break;
441224002Sdelphij		case 'N':
442224002Sdelphij			NoBind = 1;
443224002Sdelphij			SecureMode = 1;
444224002Sdelphij			break;
44563997Sps		case 'n':
44663997Sps			resolve = 0;
44763997Sps			break;
44887000Sdd		case 'o':
44987000Sdd			use_bootfile = 1;
45087000Sdd			break;
4511553Srgrimes		case 'p':		/* path */
452129853Sdwmalone			if (strlen(optarg) >= sizeof(sunx.sun_path))
453129853Sdwmalone				errx(1, "%s path too long, exiting", optarg);
454137232Sglebius			funix_default.name = optarg;
4551553Srgrimes			break;
45676431Sdwmalone		case 'P':		/* path for alt. PID */
45776431Sdwmalone			PidFile = optarg;
45876431Sdwmalone			break;
45917245Spst		case 's':		/* no network mode */
46017245Spst			SecureMode++;
46117245Spst			break;
462144984Shrs		case 'S':		/* path for privileged originator */
463144984Shrs			if (strlen(optarg) >= sizeof(sunx.sun_path))
464144984Shrs				errx(1, "%s path too long, exiting", optarg);
465144984Shrs			funix_secure.name = optarg;
466144984Shrs			break;
467183347Sdwmalone		case 'T':
468183347Sdwmalone			RemoteAddDate = 1;
469183347Sdwmalone			break;
47037820Sphk		case 'u':		/* only log specified priority */
471137569Sglebius			UniquePriority++;
47237820Sphk			break;
47337820Sphk		case 'v':		/* log facility and priority */
47437820Sphk		  	LogFacPri++;
47537820Sphk			break;
4761553Srgrimes		default:
4771553Srgrimes			usage();
4781553Srgrimes		}
4791553Srgrimes	if ((argc -= optind) != 0)
4801553Srgrimes		usage();
4811553Srgrimes
482149425Spjd	pfh = pidfile_open(PidFile, 0600, &spid);
483149425Spjd	if (pfh == NULL) {
484149425Spjd		if (errno == EEXIST)
485149425Spjd			errx(1, "syslogd already running, pid: %d", spid);
486149425Spjd		warn("cannot open pid file");
487149425Spjd	}
488149425Spjd
48918710Speter	if (!Debug) {
49018710Speter		ppid = waitdaemon(0, 0, 30);
491149425Spjd		if (ppid < 0) {
492149425Spjd			warn("could not become daemon");
493149425Spjd			pidfile_remove(pfh);
494149425Spjd			exit(1);
495149425Spjd		}
49693080Sdes	} else {
4971553Srgrimes		setlinebuf(stdout);
49893080Sdes	}
4991553Srgrimes
50025437Sjoerg	if (NumAllowed)
50125437Sjoerg		endservent();
50225437Sjoerg
5031553Srgrimes	consfile.f_type = F_CONSOLE;
50482724Skris	(void)strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1,
50582724Skris	    sizeof(consfile.f_un.f_fname));
50682724Skris	(void)strlcpy(bootfile, getbootfile(), sizeof(bootfile));
50782724Skris	(void)signal(SIGTERM, dodie);
50882724Skris	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
50982724Skris	(void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
51057558Sjoerg	/*
51157558Sjoerg	 * We don't want the SIGCHLD and SIGHUP handlers to interfere
51257558Sjoerg	 * with each other; they are likely candidates for being called
51357558Sjoerg	 * simultaneously (SIGHUP closes pipe descriptor, process dies,
51457558Sjoerg	 * SIGCHLD happens).
51557558Sjoerg	 */
51657558Sjoerg	sigemptyset(&mask);
51757558Sjoerg	sigaddset(&mask, SIGHUP);
51857558Sjoerg	sact.sa_handler = reapchild;
51957558Sjoerg	sact.sa_mask = mask;
52057609Sjoerg	sact.sa_flags = SA_RESTART;
52157558Sjoerg	(void)sigaction(SIGCHLD, &sact, NULL);
5221553Srgrimes	(void)signal(SIGALRM, domark);
52322984Sjoerg	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
5241553Srgrimes	(void)alarm(TIMERINTVL);
5251553Srgrimes
52625154Spst	TAILQ_INIT(&deadq_head);
52725154Spst
5281553Srgrimes#ifndef SUN_LEN
5291553Srgrimes#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
5301553Srgrimes#endif
531137232Sglebius	STAILQ_FOREACH_SAFE(fx, &funixes, next, fx1) {
532137232Sglebius		(void)unlink(fx->name);
53337156Sguido		memset(&sunx, 0, sizeof(sunx));
534176427Sdwmalone		sunx.sun_family = AF_LOCAL;
535137232Sglebius		(void)strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path));
536176427Sdwmalone		fx->s = socket(PF_LOCAL, SOCK_DGRAM, 0);
537137232Sglebius		if (fx->s < 0 ||
538137232Sglebius		    bind(fx->s, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
539137232Sglebius		    chmod(fx->name, fx->mode) < 0) {
54093080Sdes			(void)snprintf(line, sizeof line,
541137232Sglebius					"cannot create %s", fx->name);
54237156Sguido			logerror(line);
543137232Sglebius			dprintf("cannot create %s (%d)\n", fx->name, errno);
544137233Sglebius			if (fx == &funix_default || fx == &funix_secure)
54537156Sguido				die(0);
546137568Sglebius			else {
547137232Sglebius				STAILQ_REMOVE(&funixes, fx, funix, next);
548137568Sglebius				continue;
549137568Sglebius			}
550137568Sglebius			double_rbuf(fx->s);
55137156Sguido		}
55237156Sguido	}
55346428Sdes	if (SecureMode <= 1)
55482728Sdd		finet = socksetup(family, bindhostname);
5551553Srgrimes
55670099Sume	if (finet) {
55770099Sume		if (SecureMode) {
55870099Sume			for (i = 0; i < *finet; i++) {
55970099Sume				if (shutdown(finet[i+1], SHUT_RD) < 0) {
56070099Sume					logerror("shutdown");
56170099Sume					if (!Debug)
56270099Sume						die(0);
56370099Sume				}
56470099Sume			}
56593080Sdes		} else {
56670099Sume			dprintf("listening on inet and/or inet6 socket\n");
56793080Sdes		}
56870099Sume		dprintf("sending on inet and/or inet6 socket\n");
5691553Srgrimes	}
57035428Sphk
57146299Sdt	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
57246299Sdt		if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0)
57346299Sdt			fklog = -1;
57446299Sdt	if (fklog < 0)
5751553Srgrimes		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
5761553Srgrimes
5771553Srgrimes	/* tuck my process id away */
578149425Spjd	pidfile_write(pfh);
5791553Srgrimes
5801553Srgrimes	dprintf("off & running....\n");
5811553Srgrimes
5821553Srgrimes	init(0);
58357558Sjoerg	/* prevent SIGHUP and SIGCHLD handlers from running in parallel */
58457558Sjoerg	sigemptyset(&mask);
58557558Sjoerg	sigaddset(&mask, SIGCHLD);
58657558Sjoerg	sact.sa_handler = init;
58757558Sjoerg	sact.sa_mask = mask;
58857609Sjoerg	sact.sa_flags = SA_RESTART;
58957558Sjoerg	(void)sigaction(SIGHUP, &sact, NULL);
5901553Srgrimes
59118710Speter	tvp = &tv;
59218710Speter	tv.tv_sec = tv.tv_usec = 0;
59318710Speter
59482724Skris	if (fklog != -1 && fklog > fdsrmax)
59582724Skris		fdsrmax = fklog;
59682724Skris	if (finet && !SecureMode) {
59782724Skris		for (i = 0; i < *finet; i++) {
59882724Skris		    if (finet[i+1] != -1 && finet[i+1] > fdsrmax)
59982724Skris			fdsrmax = finet[i+1];
60082724Skris		}
60182724Skris	}
602137232Sglebius	STAILQ_FOREACH(fx, &funixes, next)
603137232Sglebius		if (fx->s > fdsrmax)
604137232Sglebius			fdsrmax = fx->s;
60582724Skris
60682724Skris	fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
60782724Skris	    sizeof(fd_mask));
60882724Skris	if (fdsr == NULL)
60982724Skris		errx(1, "calloc fd_set");
61082724Skris
6111553Srgrimes	for (;;) {
61282724Skris		if (MarkSet)
61382724Skris			markit();
61482724Skris		if (WantDie)
61582724Skris			die(WantDie);
6161553Srgrimes
61782724Skris		bzero(fdsr, howmany(fdsrmax+1, NFDBITS) *
61882724Skris		    sizeof(fd_mask));
61982724Skris
62082724Skris		if (fklog != -1)
62182724Skris			FD_SET(fklog, fdsr);
62270099Sume		if (finet && !SecureMode) {
62370099Sume			for (i = 0; i < *finet; i++) {
62482724Skris				if (finet[i+1] != -1)
62582724Skris					FD_SET(finet[i+1], fdsr);
62670099Sume			}
62737156Sguido		}
628137232Sglebius		STAILQ_FOREACH(fx, &funixes, next)
629137232Sglebius			FD_SET(fx->s, fdsr);
63037156Sguido
631131589Scperciva		i = select(fdsrmax+1, fdsr, NULL, NULL,
632131589Scperciva		    needdofsync ? &tv : tvp);
63382724Skris		switch (i) {
63482724Skris		case 0:
635131589Scperciva			dofsync();
636131589Scperciva			needdofsync = 0;
63718710Speter			if (tvp) {
63818710Speter				tvp = NULL;
63918710Speter				if (ppid != 1)
64018710Speter					kill(ppid, SIGALRM);
64118710Speter			}
6421553Srgrimes			continue;
64382724Skris		case -1:
6441553Srgrimes			if (errno != EINTR)
6451553Srgrimes				logerror("select");
6461553Srgrimes			continue;
6471553Srgrimes		}
64882724Skris		if (fklog != -1 && FD_ISSET(fklog, fdsr))
64946299Sdt			readklog();
65070099Sume		if (finet && !SecureMode) {
65170099Sume			for (i = 0; i < *finet; i++) {
65282724Skris				if (FD_ISSET(finet[i+1], fdsr)) {
65370099Sume					len = sizeof(frominet);
65470099Sume					l = recvfrom(finet[i+1], line, MAXLINE,
65570099Sume					     0, (struct sockaddr *)&frominet,
65670099Sume					     &len);
65770099Sume					if (l > 0) {
65870099Sume						line[l] = '\0';
65970099Sume						hname = cvthname((struct sockaddr *)&frominet);
66070099Sume						unmapped((struct sockaddr *)&frominet);
66170099Sume						if (validate((struct sockaddr *)&frominet, hname))
662183347Sdwmalone							printline(hname, line, RemoteAddDate ? ADDDATE : 0);
66370099Sume					} else if (l < 0 && errno != EINTR)
66470099Sume						logerror("recvfrom inet");
66570099Sume				}
66670099Sume			}
6678857Srgrimes		}
668137232Sglebius		STAILQ_FOREACH(fx, &funixes, next) {
669137232Sglebius			if (FD_ISSET(fx->s, fdsr)) {
67037156Sguido				len = sizeof(fromunix);
671137232Sglebius				l = recvfrom(fx->s, line, MAXLINE, 0,
67237156Sguido				    (struct sockaddr *)&fromunix, &len);
67337156Sguido				if (l > 0) {
67437156Sguido					line[l] = '\0';
675183347Sdwmalone					printline(LocalHostName, line, 0);
67637156Sguido				} else if (l < 0 && errno != EINTR)
67737156Sguido					logerror("recvfrom unix");
67837156Sguido			}
67937156Sguido		}
6801553Srgrimes	}
68182724Skris	if (fdsr)
68282724Skris		free(fdsr);
6831553Srgrimes}
6841553Srgrimes
68530603Scharnierstatic void
68693078Sdesunmapped(struct sockaddr *sa)
68770099Sume{
68870099Sume	struct sockaddr_in6 *sin6;
68983243Sdd	struct sockaddr_in sin4;
69070099Sume
69170099Sume	if (sa->sa_family != AF_INET6)
69270099Sume		return;
69370099Sume	if (sa->sa_len != sizeof(struct sockaddr_in6) ||
69483243Sdd	    sizeof(sin4) > sa->sa_len)
69570099Sume		return;
69670099Sume	sin6 = (struct sockaddr_in6 *)sa;
69770099Sume	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
69870099Sume		return;
69970099Sume
70083243Sdd	memset(&sin4, 0, sizeof(sin4));
70183243Sdd	sin4.sin_family = AF_INET;
70283243Sdd	sin4.sin_len = sizeof(struct sockaddr_in);
70383243Sdd	memcpy(&sin4.sin_addr, &sin6->sin6_addr.s6_addr[12],
70483243Sdd	       sizeof(sin4.sin_addr));
70583243Sdd	sin4.sin_port = sin6->sin6_port;
70670099Sume
70783243Sdd	memcpy(sa, &sin4, sin4.sin_len);
70870099Sume}
70970099Sume
71070099Sumestatic void
71193078Sdesusage(void)
7121553Srgrimes{
7131553Srgrimes
714105393Stjr	fprintf(stderr, "%s\n%s\n%s\n%s\n",
715183347Sdwmalone		"usage: syslogd [-468ACcdknosTuv] [-a allowed_peer]",
716162805Sru		"               [-b bind_address] [-f config_file]",
717162805Sru		"               [-l [mode:]path] [-m mark_interval]",
718137580Sru		"               [-P pid_file] [-p log_socket]");
7191553Srgrimes	exit(1);
7201553Srgrimes}
7211553Srgrimes
7221553Srgrimes/*
7231553Srgrimes * Take a raw input line, decode the message, and print the message
7241553Srgrimes * on the appropriate log files.
7251553Srgrimes */
72693078Sdesstatic void
727183347Sdwmaloneprintline(const char *hname, char *msg, int flags)
7281553Srgrimes{
729125271Siedowse	char *p, *q;
730125271Siedowse	long n;
7311553Srgrimes	int c, pri;
732125271Siedowse	char line[MAXLINE + 1];
7331553Srgrimes
7341553Srgrimes	/* test for special codes */
735125271Siedowse	p = msg;
7361553Srgrimes	pri = DEFUPRI;
7371553Srgrimes	if (*p == '<') {
738125271Siedowse		errno = 0;
739125271Siedowse		n = strtol(p + 1, &q, 10);
740125271Siedowse		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
741125271Siedowse			p = q + 1;
742125271Siedowse			pri = n;
743125271Siedowse		}
7441553Srgrimes	}
7451553Srgrimes	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
7461553Srgrimes		pri = DEFUPRI;
7471553Srgrimes
748129852Sdwmalone	/*
749129852Sdwmalone	 * Don't allow users to log kernel messages.
750129852Sdwmalone	 * NOTE: since LOG_KERN == 0 this will also match
751129852Sdwmalone	 *       messages with no facility specified.
752129852Sdwmalone	 */
753129852Sdwmalone	if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
7541553Srgrimes		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
7551553Srgrimes
7561553Srgrimes	q = line;
7571553Srgrimes
75859341Sache	while ((c = (unsigned char)*p++) != '\0' &&
75966080Simp	    q < &line[sizeof(line) - 4]) {
760178986Sbrian		if (mask_C1 && (c & 0x80) && c < 0xA0) {
76159341Sache			c &= 0x7F;
76259341Sache			*q++ = 'M';
76359341Sache			*q++ = '-';
76459341Sache		}
76559341Sache		if (isascii(c) && iscntrl(c)) {
76693080Sdes			if (c == '\n') {
7671553Srgrimes				*q++ = ' ';
76893080Sdes			} else if (c == '\t') {
7691553Srgrimes				*q++ = '\t';
77093080Sdes			} else {
7711553Srgrimes				*q++ = '^';
7721553Srgrimes				*q++ = c ^ 0100;
7731553Srgrimes			}
77493080Sdes		} else {
7751553Srgrimes			*q++ = c;
77693080Sdes		}
77759341Sache	}
7781553Srgrimes	*q = '\0';
7791553Srgrimes
780183347Sdwmalone	logmsg(pri, line, hname, flags);
7811553Srgrimes}
7821553Srgrimes
7831553Srgrimes/*
78446299Sdt * Read /dev/klog while data are available, split into lines.
7851553Srgrimes */
78693078Sdesstatic void
78793078Sdesreadklog(void)
7881553Srgrimes{
78946299Sdt	char *p, *q, line[MAXLINE + 1];
79046559Sdt	int len, i;
7911553Srgrimes
79246559Sdt	len = 0;
79346299Sdt	for (;;) {
79446559Sdt		i = read(fklog, line + len, MAXLINE - 1 - len);
79593080Sdes		if (i > 0) {
79646559Sdt			line[i + len] = '\0';
79793080Sdes		} else {
79893080Sdes			if (i < 0 && errno != EINTR && errno != EAGAIN) {
79993080Sdes				logerror("klog");
80093080Sdes				fklog = -1;
80193080Sdes			}
80246299Sdt			break;
80393080Sdes		}
80446299Sdt
80546299Sdt		for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
80646299Sdt			*q = '\0';
80746299Sdt			printsys(p);
8081553Srgrimes		}
80946559Sdt		len = strlen(p);
81046559Sdt		if (len >= MAXLINE - 1) {
81146299Sdt			printsys(p);
81246559Sdt			len = 0;
81346299Sdt		}
814137569Sglebius		if (len > 0)
81546559Sdt			memmove(line, p, len + 1);
8161553Srgrimes	}
81746559Sdt	if (len > 0)
81846299Sdt		printsys(line);
8191553Srgrimes}
8201553Srgrimes
82146299Sdt/*
82246299Sdt * Take a raw input line from /dev/klog, format similar to syslog().
82346299Sdt */
82493078Sdesstatic void
825124992Siedowseprintsys(char *msg)
82646299Sdt{
827125271Siedowse	char *p, *q;
828125271Siedowse	long n;
829125271Siedowse	int flags, isprintf, pri;
83046299Sdt
83146299Sdt	flags = ISKERNEL | SYNC_FILE | ADDDATE;	/* fsync after write */
832125271Siedowse	p = msg;
83346299Sdt	pri = DEFSPRI;
834124992Siedowse	isprintf = 1;
83546299Sdt	if (*p == '<') {
836125271Siedowse		errno = 0;
837125271Siedowse		n = strtol(p + 1, &q, 10);
838125271Siedowse		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
839125271Siedowse			p = q + 1;
840124992Siedowse			pri = n;
841124992Siedowse			isprintf = 0;
842124992Siedowse		}
843124992Siedowse	}
844124992Siedowse	/*
845124992Siedowse	 * Kernel printf's and LOG_CONSOLE messages have been displayed
846124992Siedowse	 * on the console already.
847124992Siedowse	 */
848124992Siedowse	if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE)
84946299Sdt		flags |= IGN_CONS;
85046299Sdt	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
85146299Sdt		pri = DEFSPRI;
85246299Sdt	logmsg(pri, p, LocalHostName, flags);
85346299Sdt}
85446299Sdt
85593078Sdesstatic time_t	now;
8561553Srgrimes
8571553Srgrimes/*
858106571Sthomas * Match a program or host name against a specification.
859106571Sthomas * Return a non-0 value if the message must be ignored
860106571Sthomas * based on the specification.
861106571Sthomas */
862106571Sthomasstatic int
863151420Simpskip_message(const char *name, const char *spec, int checkcase)
864151420Simp{
865110776Sthomas	const char *s;
866110776Sthomas	char prev, next;
867110776Sthomas	int exclude = 0;
868110776Sthomas	/* Behaviour on explicit match */
869110776Sthomas
870106571Sthomas	if (spec == NULL)
871106571Sthomas		return 0;
872110776Sthomas	switch (*spec) {
873110776Sthomas	case '-':
874110776Sthomas		exclude = 1;
875110776Sthomas		/*FALLTHROUGH*/
876106571Sthomas	case '+':
877110776Sthomas		spec++;
878110776Sthomas		break;
879106571Sthomas	default:
880110776Sthomas		break;
881106571Sthomas	}
882114676Sgshapiro	if (checkcase)
883114676Sgshapiro		s = strstr (spec, name);
884114676Sgshapiro	else
885114676Sgshapiro		s = strcasestr (spec, name);
886110776Sthomas
887110776Sthomas	if (s != NULL) {
888110776Sthomas		prev = (s == spec ? ',' : *(s - 1));
889110776Sthomas		next = *(s + strlen (name));
890110776Sthomas
891110776Sthomas		if (prev == ',' && (next == '\0' || next == ','))
892110776Sthomas			/* Explicit match: skip iff the spec is an
893110776Sthomas			   exclusive one. */
894110776Sthomas			return exclude;
895110776Sthomas	}
896110776Sthomas
897110776Sthomas	/* No explicit match for this name: skip the message iff
898110776Sthomas	   the spec is an inclusive one. */
899110776Sthomas	return !exclude;
900106571Sthomas}
901106571Sthomas
902106571Sthomas/*
9031553Srgrimes * Log a message to the appropriate log files, users, etc. based on
9041553Srgrimes * the priority.
9051553Srgrimes */
90693078Sdesstatic void
90793078Sdeslogmsg(int pri, const char *msg, const char *from, int flags)
9081553Srgrimes{
9091553Srgrimes	struct filed *f;
91037145Sjulian	int i, fac, msglen, omask, prilev;
91183243Sdd	const char *timestamp;
9125278Swollman 	char prog[NAME_MAX+1];
91337145Sjulian	char buf[MAXLINE+1];
9141553Srgrimes
9151553Srgrimes	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
9161553Srgrimes	    pri, flags, from, msg);
9171553Srgrimes
9181553Srgrimes	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
9191553Srgrimes
9201553Srgrimes	/*
9211553Srgrimes	 * Check to see if msg looks non-standard.
9221553Srgrimes	 */
9231553Srgrimes	msglen = strlen(msg);
9241553Srgrimes	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
9251553Srgrimes	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
9261553Srgrimes		flags |= ADDDATE;
9271553Srgrimes
9281553Srgrimes	(void)time(&now);
92993080Sdes	if (flags & ADDDATE) {
9301553Srgrimes		timestamp = ctime(&now) + 4;
93193080Sdes	} else {
9321553Srgrimes		timestamp = msg;
9331553Srgrimes		msg += 16;
9341553Srgrimes		msglen -= 16;
9351553Srgrimes	}
9361553Srgrimes
9375278Swollman	/* skip leading blanks */
93864195Sdwmalone	while (isspace(*msg)) {
9395278Swollman		msg++;
9405278Swollman		msglen--;
9415278Swollman	}
9425278Swollman
9431553Srgrimes	/* extract facility and priority level */
9441553Srgrimes	if (flags & MARK)
9451553Srgrimes		fac = LOG_NFACILITIES;
9461553Srgrimes	else
9471553Srgrimes		fac = LOG_FAC(pri);
948144218Sglebius
949144218Sglebius	/* Check maximum facility number. */
950144218Sglebius	if (fac > LOG_NFACILITIES) {
951144218Sglebius		(void)sigsetmask(omask);
952144218Sglebius		return;
953144218Sglebius	}
954144218Sglebius
9551553Srgrimes	prilev = LOG_PRI(pri);
9561553Srgrimes
9575278Swollman	/* extract program name */
95864195Sdwmalone	for (i = 0; i < NAME_MAX; i++) {
959129867Sdwmalone		if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
960139381Sdwmalone		    msg[i] == '/' || isspace(msg[i]))
9615278Swollman			break;
9625278Swollman		prog[i] = msg[i];
9635278Swollman	}
9645278Swollman	prog[i] = 0;
9655278Swollman
96637145Sjulian	/* add kernel prefix for kernel messages */
96737145Sjulian	if (flags & ISKERNEL) {
96887000Sdd		snprintf(buf, sizeof(buf), "%s: %s",
96987000Sdd		    use_bootfile ? bootfile : "kernel", msg);
97037145Sjulian		msg = buf;
97137145Sjulian		msglen = strlen(buf);
97237145Sjulian	}
97337145Sjulian
9741553Srgrimes	/* log the message to the particular outputs */
9751553Srgrimes	if (!Initialized) {
9761553Srgrimes		f = &consfile;
977174533Sobrien		/*
978174533Sobrien		 * Open in non-blocking mode to avoid hangs during open
979174533Sobrien		 * and close(waiting for the port to drain).
980174533Sobrien		 */
981174533Sobrien		f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
9821553Srgrimes
9831553Srgrimes		if (f->f_file >= 0) {
984115109Sgshapiro			(void)strlcpy(f->f_lasttime, timestamp,
985115109Sgshapiro				sizeof(f->f_lasttime));
9861553Srgrimes			fprintlog(f, flags, msg);
9871553Srgrimes			(void)close(f->f_file);
9881553Srgrimes		}
9891553Srgrimes		(void)sigsetmask(omask);
9901553Srgrimes		return;
9911553Srgrimes	}
9921553Srgrimes	for (f = Files; f; f = f->f_next) {
9931553Srgrimes		/* skip messages that are incorrect priority */
99437820Sphk		if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
99537820Sphk		     ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
99637820Sphk		     ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
99737820Sphk		     )
99837820Sphk		    || f->f_pmask[fac] == INTERNAL_NOPRI)
9991553Srgrimes			continue;
1000106571Sthomas
100163795Sdwmalone		/* skip messages with the incorrect hostname */
1002114676Sgshapiro		if (skip_message(from, f->f_host, 0))
1003106571Sthomas			continue;
100463795Sdwmalone
10055278Swollman		/* skip messages with the incorrect program name */
1006114676Sgshapiro		if (skip_message(prog, f->f_program, 1))
1007106571Sthomas			continue;
10081553Srgrimes
1009106571Sthomas		/* skip message to console if it has already been printed */
10101553Srgrimes		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
10111553Srgrimes			continue;
10121553Srgrimes
10131553Srgrimes		/* don't output marks to recently written files */
10141553Srgrimes		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
10151553Srgrimes			continue;
10161553Srgrimes
10171553Srgrimes		/*
10181553Srgrimes		 * suppress duplicate lines to this file
10191553Srgrimes		 */
102088897Sarchie		if (no_compress - (f->f_type != F_PIPE) < 1 &&
102188897Sarchie		    (flags & MARK) == 0 && msglen == f->f_prevlen &&
1022174533Sobrien		    f->f_prevline && !strcmp(msg, f->f_prevline) &&
102349940Sbrian		    !strcasecmp(from, f->f_prevhost)) {
1024115109Sgshapiro			(void)strlcpy(f->f_lasttime, timestamp,
1025115109Sgshapiro				sizeof(f->f_lasttime));
10261553Srgrimes			f->f_prevcount++;
10271553Srgrimes			dprintf("msg repeated %d times, %ld sec of %d\n",
102837450Sbde			    f->f_prevcount, (long)(now - f->f_time),
10291553Srgrimes			    repeatinterval[f->f_repeatcount]);
10301553Srgrimes			/*
10311553Srgrimes			 * If domark would have logged this by now,
10321553Srgrimes			 * flush it now (so we don't hold isolated messages),
10331553Srgrimes			 * but back off so we'll flush less often
10341553Srgrimes			 * in the future.
10351553Srgrimes			 */
10361553Srgrimes			if (now > REPEATTIME(f)) {
10371553Srgrimes				fprintlog(f, flags, (char *)NULL);
10381553Srgrimes				BACKOFF(f);
10391553Srgrimes			}
10401553Srgrimes		} else {
10411553Srgrimes			/* new line, save it */
10421553Srgrimes			if (f->f_prevcount)
10431553Srgrimes				fprintlog(f, 0, (char *)NULL);
10441553Srgrimes			f->f_repeatcount = 0;
104517245Spst			f->f_prevpri = pri;
1046115109Sgshapiro			(void)strlcpy(f->f_lasttime, timestamp,
1047115109Sgshapiro				sizeof(f->f_lasttime));
104882724Skris			(void)strlcpy(f->f_prevhost, from,
104982724Skris			    sizeof(f->f_prevhost));
10501553Srgrimes			if (msglen < MAXSVLINE) {
10511553Srgrimes				f->f_prevlen = msglen;
105282724Skris				(void)strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
10531553Srgrimes				fprintlog(f, flags, (char *)NULL);
10541553Srgrimes			} else {
10551553Srgrimes				f->f_prevline[0] = 0;
10561553Srgrimes				f->f_prevlen = 0;
10571553Srgrimes				fprintlog(f, flags, msg);
10581553Srgrimes			}
10591553Srgrimes		}
10601553Srgrimes	}
10611553Srgrimes	(void)sigsetmask(omask);
10621553Srgrimes}
10631553Srgrimes
106493078Sdesstatic void
1065131589Scpercivadofsync(void)
1066131589Scperciva{
1067131589Scperciva	struct filed *f;
1068131589Scperciva
1069131589Scperciva	for (f = Files; f; f = f->f_next) {
1070131589Scperciva		if ((f->f_type == F_FILE) &&
1071131589Scperciva		    (f->f_flags & FFLAG_NEEDSYNC)) {
1072131589Scperciva			f->f_flags &= ~FFLAG_NEEDSYNC;
1073131589Scperciva			(void)fsync(f->f_file);
1074131589Scperciva		}
1075131589Scperciva	}
1076131589Scperciva}
1077131589Scperciva
1078186234Sobrien#define IOV_SIZE 7
1079131589Scpercivastatic void
108093078Sdesfprintlog(struct filed *f, int flags, const char *msg)
10811553Srgrimes{
1082186234Sobrien	struct iovec iov[IOV_SIZE];
10831553Srgrimes	struct iovec *v;
108470099Sume	struct addrinfo *r;
108570099Sume	int i, l, lsent = 0;
108689162Sdeischen	char line[MAXLINE + 1], repbuf[80], greetings[200], *wmsg = NULL;
1087129756Sdwmalone	char nul[] = "", space[] = " ", lf[] = "\n", crlf[] = "\r\n";
108883243Sdd	const char *msgret;
10891553Srgrimes
10901553Srgrimes	v = iov;
10911553Srgrimes	if (f->f_type == F_WALL) {
10921553Srgrimes		v->iov_base = greetings;
1093174533Sobrien		/* The time displayed is not synchornized with the other log
1094174533Sobrien		 * destinations (like messages).  Following fragment was using
1095174533Sobrien		 * ctime(&now), which was updating the time every 30 sec.
1096174533Sobrien		 * With f_lasttime, time is synchronized correctly.
1097174533Sobrien		 */
109829623Sbrian		v->iov_len = snprintf(greetings, sizeof greetings,
10991553Srgrimes		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
1100174533Sobrien		    f->f_prevhost, f->f_lasttime);
1101217589Sdwmalone		if (v->iov_len >= sizeof greetings)
1102217589Sdwmalone			v->iov_len = sizeof greetings - 1;
1103217589Sdwmalone		v++;
1104129756Sdwmalone		v->iov_base = nul;
11051553Srgrimes		v->iov_len = 0;
11061553Srgrimes		v++;
11071553Srgrimes	} else {
11081553Srgrimes		v->iov_base = f->f_lasttime;
1109174533Sobrien		v->iov_len = strlen(f->f_lasttime);
11101553Srgrimes		v++;
1111129756Sdwmalone		v->iov_base = space;
11121553Srgrimes		v->iov_len = 1;
11131553Srgrimes		v++;
11141553Srgrimes	}
111537820Sphk
111637820Sphk	if (LogFacPri) {
111737820Sphk	  	static char fp_buf[30];	/* Hollow laugh */
111837820Sphk		int fac = f->f_prevpri & LOG_FACMASK;
111937820Sphk		int pri = LOG_PRI(f->f_prevpri);
112076944Sdwmalone		const char *f_s = NULL;
112137820Sphk		char f_n[5];	/* Hollow laugh */
112276944Sdwmalone		const char *p_s = NULL;
112337820Sphk		char p_n[5];	/* Hollow laugh */
112437820Sphk
112537820Sphk		if (LogFacPri > 1) {
112637820Sphk		  CODE *c;
112737820Sphk
112855906Sru		  for (c = facilitynames; c->c_name; c++) {
112937820Sphk		    if (c->c_val == fac) {
113037820Sphk		      f_s = c->c_name;
113137820Sphk		      break;
113237820Sphk		    }
113337820Sphk		  }
113455906Sru		  for (c = prioritynames; c->c_name; c++) {
113537820Sphk		    if (c->c_val == pri) {
113637820Sphk		      p_s = c->c_name;
113737820Sphk		      break;
113837820Sphk		    }
113937820Sphk		  }
114037820Sphk		}
114137820Sphk		if (!f_s) {
114237820Sphk		  snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
114337820Sphk		  f_s = f_n;
114437820Sphk		}
114537820Sphk		if (!p_s) {
114637820Sphk		  snprintf(p_n, sizeof p_n, "%d", pri);
114737820Sphk		  p_s = p_n;
114837820Sphk		}
114937820Sphk		snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
115037820Sphk		v->iov_base = fp_buf;
115137820Sphk		v->iov_len = strlen(fp_buf);
115237820Sphk	} else {
1153137569Sglebius		v->iov_base = nul;
115437820Sphk		v->iov_len = 0;
115537820Sphk	}
115637820Sphk	v++;
115737820Sphk
11581553Srgrimes	v->iov_base = f->f_prevhost;
11591553Srgrimes	v->iov_len = strlen(v->iov_base);
11601553Srgrimes	v++;
1161129756Sdwmalone	v->iov_base = space;
11621553Srgrimes	v->iov_len = 1;
11631553Srgrimes	v++;
11641553Srgrimes
11651553Srgrimes	if (msg) {
116683243Sdd		wmsg = strdup(msg); /* XXX iov_base needs a `const' sibling. */
116784168Sdes		if (wmsg == NULL) {
116884168Sdes			logerror("strdup");
116984168Sdes			exit(1);
117084168Sdes		}
117183243Sdd		v->iov_base = wmsg;
11721553Srgrimes		v->iov_len = strlen(msg);
11731553Srgrimes	} else if (f->f_prevcount > 1) {
11741553Srgrimes		v->iov_base = repbuf;
117582724Skris		v->iov_len = snprintf(repbuf, sizeof repbuf,
117682724Skris		    "last message repeated %d times", f->f_prevcount);
1177174533Sobrien	} else if (f->f_prevline) {
11781553Srgrimes		v->iov_base = f->f_prevline;
11791553Srgrimes		v->iov_len = f->f_prevlen;
1180174533Sobrien	} else {
1181174533Sobrien		return;
11821553Srgrimes	}
11831553Srgrimes	v++;
11841553Srgrimes
11851553Srgrimes	dprintf("Logging to %s", TypeNames[f->f_type]);
11861553Srgrimes	f->f_time = now;
11871553Srgrimes
11881553Srgrimes	switch (f->f_type) {
1189157821Sjulian		int port;
11901553Srgrimes	case F_UNUSED:
11911553Srgrimes		dprintf("\n");
11921553Srgrimes		break;
11931553Srgrimes
11941553Srgrimes	case F_FORW:
1195157821Sjulian		port = (int)ntohs(((struct sockaddr_in *)
1196157821Sjulian			    (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
1197157821Sjulian		if (port != 514) {
1198157821Sjulian			dprintf(" %s:%d\n", f->f_un.f_forw.f_hname, port);
1199157821Sjulian		} else {
1200157821Sjulian			dprintf(" %s\n", f->f_un.f_forw.f_hname);
1201157821Sjulian		}
120237209Ssteve		/* check for local vs remote messages */
120349940Sbrian		if (strcasecmp(f->f_prevhost, LocalHostName))
120437209Ssteve			l = snprintf(line, sizeof line - 1,
120537209Ssteve			    "<%d>%.15s Forwarded from %s: %s",
1206129756Sdwmalone			    f->f_prevpri, (char *)iov[0].iov_base,
1207129756Sdwmalone			    f->f_prevhost, (char *)iov[5].iov_base);
120837209Ssteve		else
120937209Ssteve			l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
1210129756Sdwmalone			     f->f_prevpri, (char *)iov[0].iov_base,
1211129756Sdwmalone			    (char *)iov[5].iov_base);
121281977Sbrian		if (l < 0)
121381977Sbrian			l = 0;
121481977Sbrian		else if (l > MAXLINE)
12151553Srgrimes			l = MAXLINE;
121670099Sume
121770099Sume		if (finet) {
121870099Sume			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
121970099Sume				for (i = 0; i < *finet; i++) {
1220137569Sglebius#if 0
122170099Sume					/*
122270099Sume					 * should we check AF first, or just
122370099Sume					 * trial and error? FWD
122470099Sume					 */
122570099Sume					if (r->ai_family ==
1226137569Sglebius					    address_family_of(finet[i+1]))
122770099Sume#endif
122870099Sume					lsent = sendto(finet[i+1], line, l, 0,
122970099Sume					    r->ai_addr, r->ai_addrlen);
1230137569Sglebius					if (lsent == l)
123170099Sume						break;
123270099Sume				}
1233137569Sglebius				if (lsent == l && !send_to_all)
123470099Sume					break;
123570099Sume			}
1236102401Scjc			dprintf("lsent/l: %d/%d\n", lsent, l);
123770099Sume			if (lsent != l) {
123870099Sume				int e = errno;
1239102401Scjc				logerror("sendto");
124070099Sume				errno = e;
1241102401Scjc				switch (errno) {
1242146414Scsjp				case ENOBUFS:
1243146414Scsjp				case ENETDOWN:
1244102401Scjc				case EHOSTUNREACH:
1245102401Scjc				case EHOSTDOWN:
1246102401Scjc					break;
1247102401Scjc				/* case EBADF: */
1248102401Scjc				/* case EACCES: */
1249102401Scjc				/* case ENOTSOCK: */
1250102401Scjc				/* case EFAULT: */
1251102401Scjc				/* case EMSGSIZE: */
1252102401Scjc				/* case EAGAIN: */
1253102401Scjc				/* case ENOBUFS: */
1254102401Scjc				/* case ECONNREFUSED: */
1255102401Scjc				default:
1256122814Sdwmalone					dprintf("removing entry\n");
1257102401Scjc					f->f_type = F_UNUSED;
1258102401Scjc					break;
1259102401Scjc				}
126070099Sume			}
12611553Srgrimes		}
12621553Srgrimes		break;
12631553Srgrimes
12641553Srgrimes	case F_FILE:
12651553Srgrimes		dprintf(" %s\n", f->f_un.f_fname);
1266129756Sdwmalone		v->iov_base = lf;
126719854Speter		v->iov_len = 1;
1268186234Sobrien		if (writev(f->f_file, iov, IOV_SIZE) < 0) {
1269157311Scsjp			/*
1270157311Scsjp			 * If writev(2) fails for potentially transient errors
1271174533Sobrien			 * like the filesystem being full, ignore it.
1272174533Sobrien			 * Otherwise remove this logfile from the list.
1273157311Scsjp			 */
1274157311Scsjp			if (errno != ENOSPC) {
1275157311Scsjp				int e = errno;
1276157311Scsjp				(void)close(f->f_file);
1277157311Scsjp				f->f_type = F_UNUSED;
1278157311Scsjp				errno = e;
1279157311Scsjp				logerror(f->f_un.f_fname);
1280157311Scsjp			}
1281131589Scperciva		} else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
1282131589Scperciva			f->f_flags |= FFLAG_NEEDSYNC;
1283131589Scperciva			needdofsync = 1;
1284131589Scperciva		}
12851553Srgrimes		break;
12861553Srgrimes
128722984Sjoerg	case F_PIPE:
128822984Sjoerg		dprintf(" %s\n", f->f_un.f_pipe.f_pname);
1289129756Sdwmalone		v->iov_base = lf;
129022984Sjoerg		v->iov_len = 1;
129122984Sjoerg		if (f->f_un.f_pipe.f_pid == 0) {
129222984Sjoerg			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
129322984Sjoerg						&f->f_un.f_pipe.f_pid)) < 0) {
129422984Sjoerg				f->f_type = F_UNUSED;
129522984Sjoerg				logerror(f->f_un.f_pipe.f_pname);
129622984Sjoerg				break;
129722984Sjoerg			}
129822984Sjoerg		}
1299186234Sobrien		if (writev(f->f_file, iov, IOV_SIZE) < 0) {
130022984Sjoerg			int e = errno;
130122984Sjoerg			(void)close(f->f_file);
130222984Sjoerg			if (f->f_un.f_pipe.f_pid > 0)
130357558Sjoerg				deadq_enter(f->f_un.f_pipe.f_pid,
130457558Sjoerg					    f->f_un.f_pipe.f_pname);
130522984Sjoerg			f->f_un.f_pipe.f_pid = 0;
130622984Sjoerg			errno = e;
130722984Sjoerg			logerror(f->f_un.f_pipe.f_pname);
130822984Sjoerg		}
130922984Sjoerg		break;
131022984Sjoerg
131119962Speter	case F_CONSOLE:
131219962Speter		if (flags & IGN_CONS) {
131319962Speter			dprintf(" (ignored)\n");
131419962Speter			break;
131519962Speter		}
131619962Speter		/* FALLTHROUGH */
131719962Speter
131819854Speter	case F_TTY:
131919962Speter		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
1320129756Sdwmalone		v->iov_base = crlf;
132119854Speter		v->iov_len = 2;
132219854Speter
132319854Speter		errno = 0;	/* ttymsg() only sometimes returns an errno */
1324186234Sobrien		if ((msgret = ttymsg(iov, IOV_SIZE, f->f_un.f_fname, 10))) {
132519854Speter			f->f_type = F_UNUSED;
132619854Speter			logerror(msgret);
132719854Speter		}
132819854Speter		break;
132919854Speter
13301553Srgrimes	case F_USERS:
13311553Srgrimes	case F_WALL:
13321553Srgrimes		dprintf("\n");
1333129756Sdwmalone		v->iov_base = crlf;
13341553Srgrimes		v->iov_len = 2;
1335186234Sobrien		wallmsg(f, iov, IOV_SIZE);
13361553Srgrimes		break;
13371553Srgrimes	}
13381553Srgrimes	f->f_prevcount = 0;
1339182605Sobrien	free(wmsg);
13401553Srgrimes}
13411553Srgrimes
13421553Srgrimes/*
13431553Srgrimes *  WALLMSG -- Write a message to the world at large
13441553Srgrimes *
13451553Srgrimes *	Write the specified message to either the entire
13461553Srgrimes *	world, or a list of approved users.
13471553Srgrimes */
134893078Sdesstatic void
1349186234Sobrienwallmsg(struct filed *f, struct iovec *iov, const int iovlen)
13501553Srgrimes{
13511553Srgrimes	static int reenter;			/* avoid calling ourselves */
1352200954Sed	struct utmpx *ut;
13531553Srgrimes	int i;
135483243Sdd	const char *p;
13551553Srgrimes
13561553Srgrimes	if (reenter++)
13571553Srgrimes		return;
1358200954Sed	setutxent();
13591553Srgrimes	/* NOSTRICT */
1360200954Sed	while ((ut = getutxent()) != NULL) {
1361200954Sed		if (ut->ut_type != USER_PROCESS)
13621553Srgrimes			continue;
13631553Srgrimes		if (f->f_type == F_WALL) {
1364200954Sed			if ((p = ttymsg(iov, iovlen, ut->ut_line,
1365200954Sed			    TTYMSGTIME)) != NULL) {
13661553Srgrimes				errno = 0;	/* already in msg */
13671553Srgrimes				logerror(p);
13681553Srgrimes			}
13691553Srgrimes			continue;
13701553Srgrimes		}
13711553Srgrimes		/* should we send the message to this user? */
13721553Srgrimes		for (i = 0; i < MAXUNAMES; i++) {
13731553Srgrimes			if (!f->f_un.f_uname[i][0])
13741553Srgrimes				break;
1375200954Sed			if (!strcmp(f->f_un.f_uname[i], ut->ut_user)) {
1376200954Sed				if ((p = ttymsg(iov, iovlen, ut->ut_line,
1377200954Sed				    TTYMSGTIME)) != NULL) {
13781553Srgrimes					errno = 0;	/* already in msg */
13791553Srgrimes					logerror(p);
13801553Srgrimes				}
13811553Srgrimes				break;
13821553Srgrimes			}
13831553Srgrimes		}
13841553Srgrimes	}
1385200954Sed	endutxent();
13861553Srgrimes	reenter = 0;
13871553Srgrimes}
13881553Srgrimes
138993078Sdesstatic void
139093078Sdesreapchild(int signo __unused)
13911553Srgrimes{
139257558Sjoerg	int status;
139322984Sjoerg	pid_t pid;
139422984Sjoerg	struct filed *f;
13951553Srgrimes
139622984Sjoerg	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
139722984Sjoerg		if (!Initialized)
139822984Sjoerg			/* Don't tell while we are initting. */
139922984Sjoerg			continue;
140022984Sjoerg
140122984Sjoerg		/* First, look if it's a process from the dead queue. */
140257558Sjoerg		if (deadq_remove(pid))
140357558Sjoerg			goto oncemore;
140422984Sjoerg
140522984Sjoerg		/* Now, look in list of active processes. */
140622984Sjoerg		for (f = Files; f; f = f->f_next)
140722984Sjoerg			if (f->f_type == F_PIPE &&
140822984Sjoerg			    f->f_un.f_pipe.f_pid == pid) {
140922984Sjoerg				(void)close(f->f_file);
141022984Sjoerg				f->f_un.f_pipe.f_pid = 0;
141157558Sjoerg				log_deadchild(pid, status,
141257558Sjoerg					      f->f_un.f_pipe.f_pname);
141322984Sjoerg				break;
141422984Sjoerg			}
141522984Sjoerg	  oncemore:
141655971Sdes		continue;
141722984Sjoerg	}
14181553Srgrimes}
14191553Srgrimes
14201553Srgrimes/*
14211553Srgrimes * Return a printable representation of a host address.
14221553Srgrimes */
142393078Sdesstatic const char *
142493078Sdescvthname(struct sockaddr *f)
14251553Srgrimes{
1426114676Sgshapiro	int error, hl;
142742114Scwt	sigset_t omask, nmask;
142870099Sume	static char hname[NI_MAXHOST], ip[NI_MAXHOST];
14291553Srgrimes
143070099Sume	error = getnameinfo((struct sockaddr *)f,
143170099Sume			    ((struct sockaddr *)f)->sa_len,
1432146187Sume			    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
143370099Sume	dprintf("cvthname(%s)\n", ip);
14341553Srgrimes
143570099Sume	if (error) {
143670099Sume		dprintf("Malformed from address %s\n", gai_strerror(error));
14371553Srgrimes		return ("???");
14381553Srgrimes	}
143970099Sume	if (!resolve)
144070099Sume		return (ip);
144170099Sume
144242114Scwt	sigemptyset(&nmask);
144342114Scwt	sigaddset(&nmask, SIGHUP);
144442114Scwt	sigprocmask(SIG_BLOCK, &nmask, &omask);
144570099Sume	error = getnameinfo((struct sockaddr *)f,
144670099Sume			    ((struct sockaddr *)f)->sa_len,
1447146187Sume			    hname, sizeof hname, NULL, 0, NI_NAMEREQD);
144842114Scwt	sigprocmask(SIG_SETMASK, &omask, NULL);
144970099Sume	if (error) {
145070099Sume		dprintf("Host name for your address (%s) unknown\n", ip);
145170099Sume		return (ip);
14521553Srgrimes	}
1453114676Sgshapiro	hl = strlen(hname);
1454114676Sgshapiro	if (hl > 0 && hname[hl-1] == '.')
1455114676Sgshapiro		hname[--hl] = '\0';
1456115108Sgshapiro	trimdomain(hname, hl);
145770099Sume	return (hname);
14581553Srgrimes}
14591553Srgrimes
146093078Sdesstatic void
146193078Sdesdodie(int signo)
14621553Srgrimes{
14631553Srgrimes
146482724Skris	WantDie = signo;
146582724Skris}
14661553Srgrimes
146793078Sdesstatic void
146893078Sdesdomark(int signo __unused)
146982724Skris{
147022984Sjoerg
147182724Skris	MarkSet = 1;
14721553Srgrimes}
14731553Srgrimes
14741553Srgrimes/*
14751553Srgrimes * Print syslogd errors some place.
14761553Srgrimes */
147793078Sdesstatic void
147893078Sdeslogerror(const char *type)
14791553Srgrimes{
148022984Sjoerg	char buf[512];
1481122815Sdwmalone	static int recursed = 0;
14821553Srgrimes
1483122815Sdwmalone	/* If there's an error while trying to log an error, give up. */
1484122815Sdwmalone	if (recursed)
1485122815Sdwmalone		return;
1486122815Sdwmalone	recursed++;
14871553Srgrimes	if (errno)
14881553Srgrimes		(void)snprintf(buf,
148929623Sbrian		    sizeof buf, "syslogd: %s: %s", type, strerror(errno));
14901553Srgrimes	else
149129623Sbrian		(void)snprintf(buf, sizeof buf, "syslogd: %s", type);
14921553Srgrimes	errno = 0;
14931553Srgrimes	dprintf("%s\n", buf);
14941553Srgrimes	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1495122815Sdwmalone	recursed--;
14961553Srgrimes}
14971553Srgrimes
149893078Sdesstatic void
149993078Sdesdie(int signo)
15001553Srgrimes{
15011553Srgrimes	struct filed *f;
1502137232Sglebius	struct funix *fx;
150323868Sjoerg	int was_initialized;
15041553Srgrimes	char buf[100];
15051553Srgrimes
150623868Sjoerg	was_initialized = Initialized;
150722984Sjoerg	Initialized = 0;	/* Don't log SIGCHLDs. */
15081553Srgrimes	for (f = Files; f != NULL; f = f->f_next) {
15091553Srgrimes		/* flush any pending output */
15101553Srgrimes		if (f->f_prevcount)
15111553Srgrimes			fprintlog(f, 0, (char *)NULL);
1512129855Sdwmalone		if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) {
151322984Sjoerg			(void)close(f->f_file);
1514129855Sdwmalone			f->f_un.f_pipe.f_pid = 0;
1515129855Sdwmalone		}
15161553Srgrimes	}
151723868Sjoerg	Initialized = was_initialized;
15181553Srgrimes	if (signo) {
15191553Srgrimes		dprintf("syslogd: exiting on signal %d\n", signo);
152082724Skris		(void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo);
15211553Srgrimes		errno = 0;
15221553Srgrimes		logerror(buf);
15231553Srgrimes	}
1524137232Sglebius	STAILQ_FOREACH(fx, &funixes, next)
1525137232Sglebius		(void)unlink(fx->name);
1526149425Spjd	pidfile_remove(pfh);
1527137232Sglebius
152819854Speter	exit(1);
15291553Srgrimes}
15301553Srgrimes
15311553Srgrimes/*
15321553Srgrimes *  INIT -- Initialize syslogd from configuration table
15331553Srgrimes */
153493078Sdesstatic void
153593078Sdesinit(int signo)
15361553Srgrimes{
15371553Srgrimes	int i;
15381553Srgrimes	FILE *cf;
15391553Srgrimes	struct filed *f, *next, **nextp;
15401553Srgrimes	char *p;
15411553Srgrimes	char cline[LINE_MAX];
15425278Swollman 	char prog[NAME_MAX+1];
154374053Sbrian	char host[MAXHOSTNAMELEN];
154482442Scjc	char oldLocalHostName[MAXHOSTNAMELEN];
154582442Scjc	char hostMsg[2*MAXHOSTNAMELEN+40];
154687000Sdd	char bootfileMsg[LINE_MAX];
15471553Srgrimes
15481553Srgrimes	dprintf("init\n");
15491553Srgrimes
15501553Srgrimes	/*
155182442Scjc	 * Load hostname (may have changed).
155282442Scjc	 */
155382442Scjc	if (signo != 0)
155482442Scjc		(void)strlcpy(oldLocalHostName, LocalHostName,
155582442Scjc		    sizeof(oldLocalHostName));
155682442Scjc	if (gethostname(LocalHostName, sizeof(LocalHostName)))
155782442Scjc		err(EX_OSERR, "gethostname() failed");
155882442Scjc	if ((p = strchr(LocalHostName, '.')) != NULL) {
155982442Scjc		*p++ = '\0';
156082442Scjc		LocalDomain = p;
156193080Sdes	} else {
156282442Scjc		LocalDomain = "";
156393080Sdes	}
156482442Scjc
156582442Scjc	/*
15661553Srgrimes	 *  Close all open log files.
15671553Srgrimes	 */
15681553Srgrimes	Initialized = 0;
15691553Srgrimes	for (f = Files; f != NULL; f = next) {
15701553Srgrimes		/* flush any pending output */
15711553Srgrimes		if (f->f_prevcount)
15721553Srgrimes			fprintlog(f, 0, (char *)NULL);
15731553Srgrimes
15741553Srgrimes		switch (f->f_type) {
15751553Srgrimes		case F_FILE:
15761553Srgrimes		case F_FORW:
157719962Speter		case F_CONSOLE:
157819962Speter		case F_TTY:
157920290Speter			(void)close(f->f_file);
158019962Speter			break;
158122984Sjoerg		case F_PIPE:
1582129855Sdwmalone			if (f->f_un.f_pipe.f_pid > 0) {
1583129855Sdwmalone				(void)close(f->f_file);
158457558Sjoerg				deadq_enter(f->f_un.f_pipe.f_pid,
158557558Sjoerg					    f->f_un.f_pipe.f_pname);
1586129855Sdwmalone			}
158722984Sjoerg			f->f_un.f_pipe.f_pid = 0;
158822984Sjoerg			break;
15891553Srgrimes		}
15901553Srgrimes		next = f->f_next;
159164195Sdwmalone		if (f->f_program) free(f->f_program);
159263795Sdwmalone		if (f->f_host) free(f->f_host);
15931553Srgrimes		free((char *)f);
15941553Srgrimes	}
15951553Srgrimes	Files = NULL;
15961553Srgrimes	nextp = &Files;
15971553Srgrimes
15981553Srgrimes	/* open the configuration file */
15991553Srgrimes	if ((cf = fopen(ConfFile, "r")) == NULL) {
16001553Srgrimes		dprintf("cannot open %s\n", ConfFile);
16011553Srgrimes		*nextp = (struct filed *)calloc(1, sizeof(*f));
160284168Sdes		if (*nextp == NULL) {
160384168Sdes			logerror("calloc");
160484168Sdes			exit(1);
160584168Sdes		}
160663795Sdwmalone		cfline("*.ERR\t/dev/console", *nextp, "*", "*");
16071553Srgrimes		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
160884168Sdes		if ((*nextp)->f_next == NULL) {
160984168Sdes			logerror("calloc");
161084168Sdes			exit(1);
161184168Sdes		}
161263795Sdwmalone		cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
16131553Srgrimes		Initialized = 1;
16141553Srgrimes		return;
16151553Srgrimes	}
16161553Srgrimes
16171553Srgrimes	/*
16181553Srgrimes	 *  Foreach line in the conf table, open that file.
16191553Srgrimes	 */
16201553Srgrimes	f = NULL;
162182724Skris	(void)strlcpy(host, "*", sizeof(host));
162282724Skris	(void)strlcpy(prog, "*", sizeof(prog));
16231553Srgrimes	while (fgets(cline, sizeof(cline), cf) != NULL) {
16241553Srgrimes		/*
16251553Srgrimes		 * check for end-of-section, comments, strip off trailing
16265278Swollman		 * spaces and newline character. #!prog is treated specially:
16275278Swollman		 * following lines apply only to that program.
16281553Srgrimes		 */
16291553Srgrimes		for (p = cline; isspace(*p); ++p)
16301553Srgrimes			continue;
16315278Swollman		if (*p == 0)
16321553Srgrimes			continue;
163364195Sdwmalone		if (*p == '#') {
16345278Swollman			p++;
163563795Sdwmalone			if (*p != '!' && *p != '+' && *p != '-')
16365278Swollman				continue;
16375278Swollman		}
163863795Sdwmalone		if (*p == '+' || *p == '-') {
163983392Sdes			host[0] = *p++;
164083388Sdes			while (isspace(*p))
164183388Sdes				p++;
164263795Sdwmalone			if ((!*p) || (*p == '*')) {
164382724Skris				(void)strlcpy(host, "*", sizeof(host));
164463795Sdwmalone				continue;
164563795Sdwmalone			}
164663795Sdwmalone			if (*p == '@')
164763795Sdwmalone				p = LocalHostName;
164874053Sbrian			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
1649111221Sthomas				if (!isalnum(*p) && *p != '.' && *p != '-'
1650139384Sdwmalone				    && *p != ',' && *p != ':' && *p != '%')
165163795Sdwmalone					break;
165263795Sdwmalone				host[i] = *p++;
165363795Sdwmalone			}
165463795Sdwmalone			host[i] = '\0';
165563795Sdwmalone			continue;
165663795Sdwmalone		}
165764195Sdwmalone		if (*p == '!') {
16585278Swollman			p++;
165964195Sdwmalone			while (isspace(*p)) p++;
166064195Sdwmalone			if ((!*p) || (*p == '*')) {
166182724Skris				(void)strlcpy(prog, "*", sizeof(prog));
16625278Swollman				continue;
16635278Swollman			}
166464195Sdwmalone			for (i = 0; i < NAME_MAX; i++) {
1665139381Sdwmalone				if (!isprint(p[i]) || isspace(p[i]))
16665278Swollman					break;
16675278Swollman				prog[i] = p[i];
16685278Swollman			}
16695278Swollman			prog[i] = 0;
16705278Swollman			continue;
16715278Swollman		}
1672180380Ssobomax		for (p = cline + 1; *p != '\0'; p++) {
1673180380Ssobomax			if (*p != '#')
1674180380Ssobomax				continue;
1675180380Ssobomax			if (*(p - 1) == '\\') {
1676180380Ssobomax				strcpy(p - 1, p);
1677180380Ssobomax				p--;
1678180380Ssobomax				continue;
1679180380Ssobomax			}
1680180380Ssobomax			*p = '\0';
1681180380Ssobomax			break;
1682180380Ssobomax		}
1683129854Sdwmalone		for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
1684129854Sdwmalone			cline[i] = '\0';
16851553Srgrimes		f = (struct filed *)calloc(1, sizeof(*f));
168684168Sdes		if (f == NULL) {
168784168Sdes			logerror("calloc");
168884168Sdes			exit(1);
168984168Sdes		}
16901553Srgrimes		*nextp = f;
16911553Srgrimes		nextp = &f->f_next;
169263795Sdwmalone		cfline(cline, f, prog, host);
16931553Srgrimes	}
16941553Srgrimes
16951553Srgrimes	/* close the configuration file */
16961553Srgrimes	(void)fclose(cf);
16971553Srgrimes
16981553Srgrimes	Initialized = 1;
16991553Srgrimes
17001553Srgrimes	if (Debug) {
1701157821Sjulian		int port;
17021553Srgrimes		for (f = Files; f; f = f->f_next) {
17031553Srgrimes			for (i = 0; i <= LOG_NFACILITIES; i++)
17041553Srgrimes				if (f->f_pmask[i] == INTERNAL_NOPRI)
17051553Srgrimes					printf("X ");
17061553Srgrimes				else
17071553Srgrimes					printf("%d ", f->f_pmask[i]);
17081553Srgrimes			printf("%s: ", TypeNames[f->f_type]);
17091553Srgrimes			switch (f->f_type) {
17101553Srgrimes			case F_FILE:
17111553Srgrimes				printf("%s", f->f_un.f_fname);
17121553Srgrimes				break;
17131553Srgrimes
171419962Speter			case F_CONSOLE:
171519962Speter			case F_TTY:
171619962Speter				printf("%s%s", _PATH_DEV, f->f_un.f_fname);
171719962Speter				break;
171819962Speter
17191553Srgrimes			case F_FORW:
1720157821Sjulian				port = (int)ntohs(((struct sockaddr_in *)
1721157821Sjulian				    (f->f_un.f_forw.f_addr->ai_addr))->sin_port);
1722157821Sjulian				if (port != 514) {
1723157821Sjulian					printf("%s:%d",
1724157821Sjulian						f->f_un.f_forw.f_hname, port);
1725157821Sjulian				} else {
1726157821Sjulian					printf("%s", f->f_un.f_forw.f_hname);
1727157821Sjulian				}
17281553Srgrimes				break;
17291553Srgrimes
173022984Sjoerg			case F_PIPE:
173122984Sjoerg				printf("%s", f->f_un.f_pipe.f_pname);
173222984Sjoerg				break;
173322984Sjoerg
17341553Srgrimes			case F_USERS:
17351553Srgrimes				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
17361553Srgrimes					printf("%s, ", f->f_un.f_uname[i]);
17371553Srgrimes				break;
17381553Srgrimes			}
173964195Sdwmalone			if (f->f_program)
17405278Swollman				printf(" (%s)", f->f_program);
17411553Srgrimes			printf("\n");
17421553Srgrimes		}
17431553Srgrimes	}
17441553Srgrimes
17451553Srgrimes	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
17461553Srgrimes	dprintf("syslogd: restarted\n");
174782442Scjc	/*
174882442Scjc	 * Log a change in hostname, but only on a restart.
174982442Scjc	 */
175082442Scjc	if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) {
175182442Scjc		(void)snprintf(hostMsg, sizeof(hostMsg),
175282442Scjc		    "syslogd: hostname changed, \"%s\" to \"%s\"",
175382442Scjc		    oldLocalHostName, LocalHostName);
175482442Scjc		logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE);
175582442Scjc		dprintf("%s\n", hostMsg);
175682442Scjc	}
175787000Sdd	/*
175887000Sdd	 * Log the kernel boot file if we aren't going to use it as
175987000Sdd	 * the prefix, and if this is *not* a restart.
176087000Sdd	 */
176187000Sdd	if (signo == 0 && !use_bootfile) {
176287000Sdd		(void)snprintf(bootfileMsg, sizeof(bootfileMsg),
176387000Sdd		    "syslogd: kernel boot file is %s", bootfile);
176487000Sdd		logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE);
176587000Sdd		dprintf("%s\n", bootfileMsg);
176687000Sdd	}
17671553Srgrimes}
17681553Srgrimes
17691553Srgrimes/*
17701553Srgrimes * Crack a configuration file line
17711553Srgrimes */
177293078Sdesstatic void
177393078Sdescfline(const char *line, struct filed *f, const char *prog, const char *host)
17741553Srgrimes{
177570099Sume	struct addrinfo hints, *res;
1776129865Sdwmalone	int error, i, pri, syncfile;
177783243Sdd	const char *p, *q;
177883243Sdd	char *bp;
17791553Srgrimes	char buf[MAXLINE], ebuf[100];
17801553Srgrimes
178163795Sdwmalone	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
17821553Srgrimes
17831553Srgrimes	errno = 0;	/* keep strerror() stuff out of logerror messages */
17841553Srgrimes
17851553Srgrimes	/* clear out file entry */
17861553Srgrimes	memset(f, 0, sizeof(*f));
17871553Srgrimes	for (i = 0; i <= LOG_NFACILITIES; i++)
17881553Srgrimes		f->f_pmask[i] = INTERNAL_NOPRI;
17891553Srgrimes
179063795Sdwmalone	/* save hostname if any */
179164195Sdwmalone	if (host && *host == '*')
179264195Sdwmalone		host = NULL;
179383392Sdes	if (host) {
1794114676Sgshapiro		int hl;
179583392Sdes
179664194Sdwmalone		f->f_host = strdup(host);
179784168Sdes		if (f->f_host == NULL) {
179884168Sdes			logerror("strdup");
179984168Sdes			exit(1);
180084168Sdes		}
180183392Sdes		hl = strlen(f->f_host);
1802114676Sgshapiro		if (hl > 0 && f->f_host[hl-1] == '.')
180383392Sdes			f->f_host[--hl] = '\0';
1804115108Sgshapiro		trimdomain(f->f_host, hl);
180583392Sdes	}
180663795Sdwmalone
18075278Swollman	/* save program name if any */
180864195Sdwmalone	if (prog && *prog == '*')
180964195Sdwmalone		prog = NULL;
181084168Sdes	if (prog) {
181164195Sdwmalone		f->f_program = strdup(prog);
181284168Sdes		if (f->f_program == NULL) {
181384168Sdes			logerror("strdup");
181484168Sdes			exit(1);
181584168Sdes		}
181684168Sdes	}
18175278Swollman
18181553Srgrimes	/* scan through the list of selectors */
181941498Sjkh	for (p = line; *p && *p != '\t' && *p != ' ';) {
182037820Sphk		int pri_done;
182137820Sphk		int pri_cmp;
1822102940Sdwmalone		int pri_invert;
18231553Srgrimes
18241553Srgrimes		/* find the end of this facility name list */
182541498Sjkh		for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
18261553Srgrimes			continue;
18271553Srgrimes
182837820Sphk		/* get the priority comparison */
182937820Sphk		pri_cmp = 0;
183037820Sphk		pri_done = 0;
1831102940Sdwmalone		pri_invert = 0;
1832102940Sdwmalone		if (*q == '!') {
1833102940Sdwmalone			pri_invert = 1;
1834102940Sdwmalone			q++;
1835102940Sdwmalone		}
183637820Sphk		while (!pri_done) {
183737820Sphk			switch (*q) {
183837820Sphk			case '<':
183937820Sphk				pri_cmp |= PRI_LT;
184037820Sphk				q++;
184137820Sphk				break;
184237820Sphk			case '=':
184337820Sphk				pri_cmp |= PRI_EQ;
184437820Sphk				q++;
184537820Sphk				break;
184637820Sphk			case '>':
184737820Sphk				pri_cmp |= PRI_GT;
184837820Sphk				q++;
184937820Sphk				break;
185037820Sphk			default:
185137820Sphk				pri_done++;
185237820Sphk				break;
185337820Sphk			}
185437820Sphk		}
185537820Sphk
18561553Srgrimes		/* collect priority name */
185741498Sjkh		for (bp = buf; *q && !strchr("\t,; ", *q); )
18581553Srgrimes			*bp++ = *q++;
18591553Srgrimes		*bp = '\0';
18601553Srgrimes
18611553Srgrimes		/* skip cruft */
186241498Sjkh		while (strchr(",;", *q))
18631553Srgrimes			q++;
18641553Srgrimes
18651553Srgrimes		/* decode priority name */
186693080Sdes		if (*buf == '*') {
1867174533Sobrien			pri = LOG_PRIMASK;
1868102940Sdwmalone			pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
186993080Sdes		} else {
1870129854Sdwmalone			/* Ignore trailing spaces. */
1871129854Sdwmalone			for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--)
1872129854Sdwmalone				buf[i] = '\0';
1873129854Sdwmalone
18741553Srgrimes			pri = decode(buf, prioritynames);
18751553Srgrimes			if (pri < 0) {
1876244881Smarkj				errno = 0;
187729623Sbrian				(void)snprintf(ebuf, sizeof ebuf,
18781553Srgrimes				    "unknown priority name \"%s\"", buf);
18791553Srgrimes				logerror(ebuf);
18801553Srgrimes				return;
18811553Srgrimes			}
18821553Srgrimes		}
1883102940Sdwmalone		if (!pri_cmp)
1884102940Sdwmalone			pri_cmp = (UniquePriority)
1885102940Sdwmalone				  ? (PRI_EQ)
1886102940Sdwmalone				  : (PRI_EQ | PRI_GT)
1887102940Sdwmalone				  ;
1888102940Sdwmalone		if (pri_invert)
1889102940Sdwmalone			pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
18901553Srgrimes
18911553Srgrimes		/* scan facilities */
189241498Sjkh		while (*p && !strchr("\t.; ", *p)) {
189341498Sjkh			for (bp = buf; *p && !strchr("\t,;. ", *p); )
18941553Srgrimes				*bp++ = *p++;
18951553Srgrimes			*bp = '\0';
189637820Sphk
189793080Sdes			if (*buf == '*') {
189837820Sphk				for (i = 0; i < LOG_NFACILITIES; i++) {
18991553Srgrimes					f->f_pmask[i] = pri;
190037820Sphk					f->f_pcmp[i] = pri_cmp;
190137820Sphk				}
190293080Sdes			} else {
19031553Srgrimes				i = decode(buf, facilitynames);
19041553Srgrimes				if (i < 0) {
1905244881Smarkj					errno = 0;
190629623Sbrian					(void)snprintf(ebuf, sizeof ebuf,
19071553Srgrimes					    "unknown facility name \"%s\"",
19081553Srgrimes					    buf);
19091553Srgrimes					logerror(ebuf);
19101553Srgrimes					return;
19111553Srgrimes				}
19121553Srgrimes				f->f_pmask[i >> 3] = pri;
191337820Sphk				f->f_pcmp[i >> 3] = pri_cmp;
19141553Srgrimes			}
19151553Srgrimes			while (*p == ',' || *p == ' ')
19161553Srgrimes				p++;
19171553Srgrimes		}
19181553Srgrimes
19191553Srgrimes		p = q;
19201553Srgrimes	}
19211553Srgrimes
19221553Srgrimes	/* skip to action part */
192341498Sjkh	while (*p == '\t' || *p == ' ')
19241553Srgrimes		p++;
19251553Srgrimes
1926129865Sdwmalone	if (*p == '-') {
1927129865Sdwmalone		syncfile = 0;
1928129865Sdwmalone		p++;
1929129865Sdwmalone	} else
1930129865Sdwmalone		syncfile = 1;
1931129865Sdwmalone
193293079Sdes	switch (*p) {
19331553Srgrimes	case '@':
1934157821Sjulian		{
1935157821Sjulian			char *tp;
1936241473Seadler			char endkey = ':';
1937157821Sjulian			/*
1938157821Sjulian			 * scan forward to see if there is a port defined.
1939157821Sjulian			 * so we can't use strlcpy..
1940157821Sjulian			 */
1941157821Sjulian			i = sizeof(f->f_un.f_forw.f_hname);
1942157821Sjulian			tp = f->f_un.f_forw.f_hname;
1943157821Sjulian			p++;
1944157821Sjulian
1945241473Seadler			/*
1946241473Seadler			 * an ipv6 address should start with a '[' in that case
1947241473Seadler			 * we should scan for a ']'
1948241473Seadler			 */
1949241473Seadler			if (*p == '[') {
1950241473Seadler				p++;
1951241473Seadler				endkey = ']';
1952241473Seadler			}
1953241473Seadler			while (*p && (*p != endkey) && (i-- > 0)) {
1954157821Sjulian				*tp++ = *p++;
1955157821Sjulian			}
1956241473Seadler			if (endkey == ']' && *p == endkey)
1957241473Seadler				p++;
1958157821Sjulian			*tp = '\0';
1959157821Sjulian		}
1960157821Sjulian		/* See if we copied a domain and have a port */
1961157821Sjulian		if (*p == ':')
1962157821Sjulian			p++;
1963157821Sjulian		else
1964157821Sjulian			p = NULL;
1965174316Sobrien
196670099Sume		memset(&hints, 0, sizeof(hints));
196770099Sume		hints.ai_family = family;
196870099Sume		hints.ai_socktype = SOCK_DGRAM;
1969157821Sjulian		error = getaddrinfo(f->f_un.f_forw.f_hname,
1970174316Sobrien				p ? p : "syslog", &hints, &res);
197170099Sume		if (error) {
197270099Sume			logerror(gai_strerror(error));
19731553Srgrimes			break;
19741553Srgrimes		}
197570099Sume		f->f_un.f_forw.f_addr = res;
19761553Srgrimes		f->f_type = F_FORW;
19771553Srgrimes		break;
19781553Srgrimes
19791553Srgrimes	case '/':
1980156339Spjd		if ((f->f_file = open(p, logflags, 0600)) < 0) {
198120290Speter			f->f_type = F_UNUSED;
19821553Srgrimes			logerror(p);
19831553Srgrimes			break;
19841553Srgrimes		}
1985129865Sdwmalone		if (syncfile)
1986129865Sdwmalone			f->f_flags |= FFLAG_SYNC;
198719962Speter		if (isatty(f->f_file)) {
198819962Speter			if (strcmp(p, ctty) == 0)
198919962Speter				f->f_type = F_CONSOLE;
199019962Speter			else
199119962Speter				f->f_type = F_TTY;
199283054Skris			(void)strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1,
199382724Skris			    sizeof(f->f_un.f_fname));
199419962Speter		} else {
199582724Skris			(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
19961553Srgrimes			f->f_type = F_FILE;
199719962Speter		}
19981553Srgrimes		break;
19991553Srgrimes
200022984Sjoerg	case '|':
200122984Sjoerg		f->f_un.f_pipe.f_pid = 0;
2002176427Sdwmalone		(void)strlcpy(f->f_un.f_pipe.f_pname, p + 1,
2003176427Sdwmalone		    sizeof(f->f_un.f_pipe.f_pname));
200422984Sjoerg		f->f_type = F_PIPE;
200522984Sjoerg		break;
200622984Sjoerg
20071553Srgrimes	case '*':
20081553Srgrimes		f->f_type = F_WALL;
20091553Srgrimes		break;
20101553Srgrimes
20111553Srgrimes	default:
20121553Srgrimes		for (i = 0; i < MAXUNAMES && *p; i++) {
20131553Srgrimes			for (q = p; *q && *q != ','; )
20141553Srgrimes				q++;
2015200954Sed			(void)strncpy(f->f_un.f_uname[i], p, MAXLOGNAME - 1);
2016200954Sed			if ((q - p) >= MAXLOGNAME)
2017200954Sed				f->f_un.f_uname[i][MAXLOGNAME - 1] = '\0';
20181553Srgrimes			else
20191553Srgrimes				f->f_un.f_uname[i][q - p] = '\0';
20201553Srgrimes			while (*q == ',' || *q == ' ')
20211553Srgrimes				q++;
20221553Srgrimes			p = q;
20231553Srgrimes		}
20241553Srgrimes		f->f_type = F_USERS;
20251553Srgrimes		break;
20261553Srgrimes	}
20271553Srgrimes}
20281553Srgrimes
20291553Srgrimes
20301553Srgrimes/*
20311553Srgrimes *  Decode a symbolic name to a numeric value
20321553Srgrimes */
203393078Sdesstatic int
203493078Sdesdecode(const char *name, CODE *codetab)
20351553Srgrimes{
20361553Srgrimes	CODE *c;
20371553Srgrimes	char *p, buf[40];
20381553Srgrimes
20391553Srgrimes	if (isdigit(*name))
20401553Srgrimes		return (atoi(name));
20411553Srgrimes
20421553Srgrimes	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
20431553Srgrimes		if (isupper(*name))
20441553Srgrimes			*p = tolower(*name);
20451553Srgrimes		else
20461553Srgrimes			*p = *name;
20471553Srgrimes	}
20481553Srgrimes	*p = '\0';
20491553Srgrimes	for (c = codetab; c->c_name; c++)
20501553Srgrimes		if (!strcmp(buf, c->c_name))
20511553Srgrimes			return (c->c_val);
20521553Srgrimes
20531553Srgrimes	return (-1);
20541553Srgrimes}
205518710Speter
205693078Sdesstatic void
205782724Skrismarkit(void)
205882724Skris{
205982724Skris	struct filed *f;
2060104573Sdes	dq_t q, next;
206182724Skris
206282724Skris	now = time((time_t *)NULL);
206382724Skris	MarkSeq += TIMERINTVL;
206482724Skris	if (MarkSeq >= MarkInterval) {
206582724Skris		logmsg(LOG_INFO, "-- MARK --",
206682724Skris		    LocalHostName, ADDDATE|MARK);
206782724Skris		MarkSeq = 0;
206882724Skris	}
206982724Skris
207082724Skris	for (f = Files; f; f = f->f_next) {
207182724Skris		if (f->f_prevcount && now >= REPEATTIME(f)) {
207282724Skris			dprintf("flush %s: repeated %d times, %d sec.\n",
207382724Skris			    TypeNames[f->f_type], f->f_prevcount,
207482724Skris			    repeatinterval[f->f_repeatcount]);
207582724Skris			fprintlog(f, 0, (char *)NULL);
207682724Skris			BACKOFF(f);
207782724Skris		}
207882724Skris	}
207982724Skris
208082724Skris	/* Walk the dead queue, and see if we should signal somebody. */
2081104573Sdes	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = next) {
2082104573Sdes		next = TAILQ_NEXT(q, dq_entries);
2083104573Sdes
208482724Skris		switch (q->dq_timeout) {
208582724Skris		case 0:
208682724Skris			/* Already signalled once, try harder now. */
208782724Skris			if (kill(q->dq_pid, SIGKILL) != 0)
208882724Skris				(void)deadq_remove(q->dq_pid);
208982724Skris			break;
209082724Skris
209182724Skris		case 1:
209282724Skris			/*
209382724Skris			 * Timed out on dead queue, send terminate
209482724Skris			 * signal.  Note that we leave the removal
209582724Skris			 * from the dead queue to reapchild(), which
209682724Skris			 * will also log the event (unless the process
209782724Skris			 * didn't even really exist, in case we simply
209882724Skris			 * drop it from the dead queue).
209982724Skris			 */
210082724Skris			if (kill(q->dq_pid, SIGTERM) != 0)
210182724Skris				(void)deadq_remove(q->dq_pid);
210282724Skris			/* FALLTHROUGH */
210382724Skris
210482724Skris		default:
210582724Skris			q->dq_timeout--;
210682724Skris		}
210793080Sdes	}
210882724Skris	MarkSet = 0;
210982724Skris	(void)alarm(TIMERINTVL);
211082724Skris}
211182724Skris
211219854Speter/*
211319854Speter * fork off and become a daemon, but wait for the child to come online
211419854Speter * before returing to the parent, or we get disk thrashing at boot etc.
211519854Speter * Set a timer so we don't hang forever if it wedges.
211619854Speter */
211793078Sdesstatic int
211893078Sdeswaitdaemon(int nochdir, int noclose, int maxwait)
211918710Speter{
212018710Speter	int fd;
212119854Speter	int status;
212219854Speter	pid_t pid, childpid;
212318710Speter
212419854Speter	switch (childpid = fork()) {
212518710Speter	case -1:
212618710Speter		return (-1);
212718710Speter	case 0:
212818710Speter		break;
212918710Speter	default:
213019854Speter		signal(SIGALRM, timedout);
213118710Speter		alarm(maxwait);
213219854Speter		while ((pid = wait3(&status, 0, NULL)) != -1) {
213319854Speter			if (WIFEXITED(status))
213419854Speter				errx(1, "child pid %d exited with return code %d",
213519854Speter					pid, WEXITSTATUS(status));
213619854Speter			if (WIFSIGNALED(status))
213719854Speter				errx(1, "child pid %d exited on signal %d%s",
213819854Speter					pid, WTERMSIG(status),
213919854Speter					WCOREDUMP(status) ? " (core dumped)" :
214019854Speter					"");
214119854Speter			if (pid == childpid)	/* it's gone... */
214219854Speter				break;
214319854Speter		}
214419854Speter		exit(0);
214518710Speter	}
214618710Speter
214718710Speter	if (setsid() == -1)
214818710Speter		return (-1);
214918710Speter
215018710Speter	if (!nochdir)
215118710Speter		(void)chdir("/");
215218710Speter
215318710Speter	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
215418710Speter		(void)dup2(fd, STDIN_FILENO);
215518710Speter		(void)dup2(fd, STDOUT_FILENO);
215618710Speter		(void)dup2(fd, STDERR_FILENO);
215718710Speter		if (fd > 2)
215818710Speter			(void)close (fd);
215918710Speter	}
216018710Speter	return (getppid());
216118710Speter}
216219854Speter
216319854Speter/*
216419854Speter * We get a SIGALRM from the child when it's running and finished doing it's
216519854Speter * fsync()'s or O_SYNC writes for all the boot messages.
216619854Speter *
216719854Speter * We also get a signal from the kernel if the timer expires, so check to
216819854Speter * see what happened.
216919854Speter */
217093078Sdesstatic void
217193078Sdestimedout(int sig __unused)
217219854Speter{
217319854Speter	int left;
217419854Speter	left = alarm(0);
217519854Speter	signal(SIGALRM, SIG_DFL);
217619854Speter	if (left == 0)
217719854Speter		errx(1, "timed out waiting for child");
217819854Speter	else
217982724Skris		_exit(0);
218019854Speter}
218122984Sjoerg
218222984Sjoerg/*
218325437Sjoerg * Add `s' to the list of allowable peer addresses to accept messages
218425437Sjoerg * from.
218525437Sjoerg *
218625437Sjoerg * `s' is a string in the form:
218725437Sjoerg *
218825437Sjoerg *    [*]domainname[:{servicename|portnumber|*}]
218925437Sjoerg *
219025437Sjoerg * or
219125437Sjoerg *
219225437Sjoerg *    netaddr/maskbits[:{servicename|portnumber|*}]
219325437Sjoerg *
219425437Sjoerg * Returns -1 on error, 0 if the argument was valid.
219525437Sjoerg */
219693078Sdesstatic int
219793078Sdesallowaddr(char *s)
219825437Sjoerg{
219925437Sjoerg	char *cp1, *cp2;
220025437Sjoerg	struct allowedpeer ap;
220125437Sjoerg	struct servent *se;
2202186263Savatar	int masklen = -1;
220370099Sume	struct addrinfo hints, *res;
220470099Sume	struct in_addr *addrp, *maskp;
2205186263Savatar#ifdef INET6
2206186263Savatar	int i;
220780011Sume	u_int32_t *addr6p, *mask6p;
2208186263Savatar#endif
220970099Sume	char ip[NI_MAXHOST];
221025437Sjoerg
221170099Sume#ifdef INET6
221270099Sume	if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
221370099Sume#endif
221470099Sume		cp1 = s;
221570099Sume	if ((cp1 = strrchr(cp1, ':'))) {
221625437Sjoerg		/* service/port provided */
221725437Sjoerg		*cp1++ = '\0';
221825437Sjoerg		if (strlen(cp1) == 1 && *cp1 == '*')
221925437Sjoerg			/* any port allowed */
222070099Sume			ap.port = 0;
222193080Sdes		else if ((se = getservbyname(cp1, "udp"))) {
222270099Sume			ap.port = ntohs(se->s_port);
222393080Sdes		} else {
222470099Sume			ap.port = strtol(cp1, &cp2, 0);
222525437Sjoerg			if (*cp2 != '\0')
222693079Sdes				return (-1); /* port not numeric */
222725437Sjoerg		}
222825437Sjoerg	} else {
222925437Sjoerg		if ((se = getservbyname("syslog", "udp")))
223070099Sume			ap.port = ntohs(se->s_port);
223125437Sjoerg		else
223225437Sjoerg			/* sanity, should not happen */
223370099Sume			ap.port = 514;
223425437Sjoerg	}
223525437Sjoerg
223670099Sume	if ((cp1 = strchr(s, '/')) != NULL &&
223770099Sume	    strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
223870099Sume		*cp1 = '\0';
223970099Sume		if ((masklen = atoi(cp1 + 1)) < 0)
224093079Sdes			return (-1);
224170099Sume	}
224270099Sume#ifdef INET6
224370099Sume	if (*s == '[') {
224470099Sume		cp2 = s + strlen(s) - 1;
224570099Sume		if (*cp2 == ']') {
224670099Sume			++s;
224770099Sume			*cp2 = '\0';
224893080Sdes		} else {
224970099Sume			cp2 = NULL;
225093080Sdes		}
225193080Sdes	} else {
225270099Sume		cp2 = NULL;
225393080Sdes	}
225470099Sume#endif
225570099Sume	memset(&hints, 0, sizeof(hints));
225670099Sume	hints.ai_family = PF_UNSPEC;
225770099Sume	hints.ai_socktype = SOCK_DGRAM;
225870099Sume	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
225970099Sume	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
226025437Sjoerg		ap.isnumeric = 1;
226170099Sume		memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
226270099Sume		memset(&ap.a_mask, 0, sizeof(ap.a_mask));
226370099Sume		ap.a_mask.ss_family = res->ai_family;
226470099Sume		if (res->ai_family == AF_INET) {
226570099Sume			ap.a_mask.ss_len = sizeof(struct sockaddr_in);
226670099Sume			maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
226779089Scjc			addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
226870099Sume			if (masklen < 0) {
226970099Sume				/* use default netmask */
227070099Sume				if (IN_CLASSA(ntohl(addrp->s_addr)))
227170099Sume					maskp->s_addr = htonl(IN_CLASSA_NET);
227270099Sume				else if (IN_CLASSB(ntohl(addrp->s_addr)))
227370099Sume					maskp->s_addr = htonl(IN_CLASSB_NET);
227470099Sume				else
227570099Sume					maskp->s_addr = htonl(IN_CLASSC_NET);
227670099Sume			} else if (masklen <= 32) {
227770099Sume				/* convert masklen to netmask */
227886343Sps				if (masklen == 0)
227986343Sps					maskp->s_addr = 0;
228086343Sps				else
228186343Sps					maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
228270099Sume			} else {
228370099Sume				freeaddrinfo(res);
228493079Sdes				return (-1);
228570099Sume			}
228679089Scjc			/* Lose any host bits in the network number. */
228779089Scjc			addrp->s_addr &= maskp->s_addr;
228870099Sume		}
228970099Sume#ifdef INET6
229070099Sume		else if (res->ai_family == AF_INET6 && masklen <= 128) {
229170099Sume			ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
229270099Sume			if (masklen < 0)
229370099Sume				masklen = 128;
229470099Sume			mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
229525437Sjoerg			/* convert masklen to netmask */
229670099Sume			while (masklen > 0) {
229770099Sume				if (masklen < 32) {
229870099Sume					*mask6p = htonl(~(0xffffffff >> masklen));
229970099Sume					break;
230070099Sume				}
230170099Sume				*mask6p++ = 0xffffffff;
230270099Sume				masklen -= 32;
230370099Sume			}
230480011Sume			/* Lose any host bits in the network number. */
230580011Sume			mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
230680011Sume			addr6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_addr)->sin6_addr;
230780011Sume			for (i = 0; i < 4; i++)
230880011Sume				addr6p[i] &= mask6p[i];
230925437Sjoerg		}
231070099Sume#endif
231170099Sume		else {
231270099Sume			freeaddrinfo(res);
231393079Sdes			return (-1);
231425437Sjoerg		}
231570099Sume		freeaddrinfo(res);
231625437Sjoerg	} else {
231725437Sjoerg		/* arg `s' is domain name */
231825437Sjoerg		ap.isnumeric = 0;
231925437Sjoerg		ap.a_name = s;
232070099Sume		if (cp1)
232170099Sume			*cp1 = '/';
232270099Sume#ifdef INET6
232370099Sume		if (cp2) {
232470099Sume			*cp2 = ']';
232570099Sume			--s;
232670099Sume		}
232770099Sume#endif
232825437Sjoerg	}
232925437Sjoerg
233025437Sjoerg	if (Debug) {
233125437Sjoerg		printf("allowaddr: rule %d: ", NumAllowed);
233225437Sjoerg		if (ap.isnumeric) {
233325437Sjoerg			printf("numeric, ");
233470099Sume			getnameinfo((struct sockaddr *)&ap.a_addr,
233570099Sume				    ((struct sockaddr *)&ap.a_addr)->sa_len,
2336146187Sume				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
233770099Sume			printf("addr = %s, ", ip);
233870099Sume			getnameinfo((struct sockaddr *)&ap.a_mask,
233970099Sume				    ((struct sockaddr *)&ap.a_mask)->sa_len,
2340146187Sume				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
234170099Sume			printf("mask = %s; ", ip);
234293080Sdes		} else {
234325437Sjoerg			printf("domainname = %s; ", ap.a_name);
234493080Sdes		}
234570099Sume		printf("port = %d\n", ap.port);
234625437Sjoerg	}
234725437Sjoerg
234825437Sjoerg	if ((AllowedPeers = realloc(AllowedPeers,
234925437Sjoerg				    ++NumAllowed * sizeof(struct allowedpeer)))
235025437Sjoerg	    == NULL) {
235184168Sdes		logerror("realloc");
235284168Sdes		exit(1);
235325437Sjoerg	}
235425437Sjoerg	memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
235593079Sdes	return (0);
235625437Sjoerg}
235725437Sjoerg
235825437Sjoerg/*
235925437Sjoerg * Validate that the remote peer has permission to log to us.
236025437Sjoerg */
236193078Sdesstatic int
236293078Sdesvalidate(struct sockaddr *sa, const char *hname)
236325437Sjoerg{
2364186263Savatar	int i;
236525437Sjoerg	size_t l1, l2;
236670099Sume	char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
236725437Sjoerg	struct allowedpeer *ap;
236883243Sdd	struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL;
2369186263Savatar#ifdef INET6
2370186263Savatar	int j, reject;
237170099Sume	struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
2372186263Savatar#endif
237370099Sume	struct addrinfo hints, *res;
237470099Sume	u_short sport;
237525437Sjoerg
237625437Sjoerg	if (NumAllowed == 0)
237725437Sjoerg		/* traditional behaviour, allow everything */
237893079Sdes		return (1);
237925437Sjoerg
238082724Skris	(void)strlcpy(name, hname, sizeof(name));
238170099Sume	memset(&hints, 0, sizeof(hints));
238270099Sume	hints.ai_family = PF_UNSPEC;
238370099Sume	hints.ai_socktype = SOCK_DGRAM;
238470099Sume	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
238570099Sume	if (getaddrinfo(name, NULL, &hints, &res) == 0)
238670099Sume		freeaddrinfo(res);
238770099Sume	else if (strchr(name, '.') == NULL) {
238861384Skris		strlcat(name, ".", sizeof name);
238961384Skris		strlcat(name, LocalDomain, sizeof name);
239025437Sjoerg	}
239170099Sume	if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
2392146187Sume			NI_NUMERICHOST | NI_NUMERICSERV) != 0)
239393079Sdes		return (0);	/* for safety, should not occur */
239470099Sume	dprintf("validate: dgram from IP %s, port %s, name %s;\n",
239570099Sume		ip, port, name);
239670099Sume	sport = atoi(port);
239725437Sjoerg
239825437Sjoerg	/* now, walk down the list */
239925437Sjoerg	for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
240070099Sume		if (ap->port != 0 && ap->port != sport) {
240125437Sjoerg			dprintf("rejected in rule %d due to port mismatch.\n", i);
240225437Sjoerg			continue;
240325437Sjoerg		}
240425437Sjoerg
240525437Sjoerg		if (ap->isnumeric) {
240670099Sume			if (ap->a_addr.ss_family != sa->sa_family) {
240770099Sume				dprintf("rejected in rule %d due to address family mismatch.\n", i);
240825437Sjoerg				continue;
240925437Sjoerg			}
241070099Sume			if (ap->a_addr.ss_family == AF_INET) {
241183243Sdd				sin4 = (struct sockaddr_in *)sa;
241270099Sume				a4p = (struct sockaddr_in *)&ap->a_addr;
241370099Sume				m4p = (struct sockaddr_in *)&ap->a_mask;
241483243Sdd				if ((sin4->sin_addr.s_addr & m4p->sin_addr.s_addr)
241570099Sume				    != a4p->sin_addr.s_addr) {
241670099Sume					dprintf("rejected in rule %d due to IP mismatch.\n", i);
241770099Sume					continue;
241870099Sume				}
241970099Sume			}
242070099Sume#ifdef INET6
242170099Sume			else if (ap->a_addr.ss_family == AF_INET6) {
242270099Sume				sin6 = (struct sockaddr_in6 *)sa;
242370099Sume				a6p = (struct sockaddr_in6 *)&ap->a_addr;
242470099Sume				m6p = (struct sockaddr_in6 *)&ap->a_mask;
242570099Sume				if (a6p->sin6_scope_id != 0 &&
242670099Sume				    sin6->sin6_scope_id != a6p->sin6_scope_id) {
242770099Sume					dprintf("rejected in rule %d due to scope mismatch.\n", i);
242870099Sume					continue;
242970099Sume				}
243070099Sume				reject = 0;
243170099Sume				for (j = 0; j < 16; j += 4) {
243280011Sume					if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j])
243380011Sume					    != *(u_int32_t *)&a6p->sin6_addr.s6_addr[j]) {
243470099Sume						++reject;
243570099Sume						break;
243670099Sume					}
243770099Sume				}
243870099Sume				if (reject) {
243970099Sume					dprintf("rejected in rule %d due to IP mismatch.\n", i);
244070099Sume					continue;
244170099Sume				}
244270099Sume			}
244370099Sume#endif
244470099Sume			else
244570099Sume				continue;
244625437Sjoerg		} else {
244725437Sjoerg			cp = ap->a_name;
244825437Sjoerg			l1 = strlen(name);
244925437Sjoerg			if (*cp == '*') {
245025437Sjoerg				/* allow wildmatch */
245125437Sjoerg				cp++;
245225437Sjoerg				l2 = strlen(cp);
245325437Sjoerg				if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
245425437Sjoerg					dprintf("rejected in rule %d due to name mismatch.\n", i);
245525437Sjoerg					continue;
245625437Sjoerg				}
245725437Sjoerg			} else {
245825437Sjoerg				/* exact match */
245925437Sjoerg				l2 = strlen(cp);
246025437Sjoerg				if (l2 != l1 || memcmp(cp, name, l1) != 0) {
246125437Sjoerg					dprintf("rejected in rule %d due to name mismatch.\n", i);
246225437Sjoerg					continue;
246325437Sjoerg				}
246425437Sjoerg			}
246525437Sjoerg		}
246625437Sjoerg		dprintf("accepted in rule %d.\n", i);
246793079Sdes		return (1);	/* hooray! */
246825437Sjoerg	}
246993079Sdes	return (0);
247025437Sjoerg}
247125437Sjoerg
247225437Sjoerg/*
247322984Sjoerg * Fairly similar to popen(3), but returns an open descriptor, as
247422984Sjoerg * opposed to a FILE *.
247522984Sjoerg */
247693078Sdesstatic int
2477129855Sdwmalonep_open(const char *prog, pid_t *rpid)
247822984Sjoerg{
2479250232Sjilles	int pfd[2], nulldesc;
2480129855Sdwmalone	pid_t pid;
248122984Sjoerg	sigset_t omask, mask;
248222984Sjoerg	char *argv[4]; /* sh -c cmd NULL */
248322984Sjoerg	char errmsg[200];
248422984Sjoerg
248522984Sjoerg	if (pipe(pfd) == -1)
248693079Sdes		return (-1);
248722984Sjoerg	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
248822984Sjoerg		/* we are royally screwed anyway */
248993079Sdes		return (-1);
249022984Sjoerg
249133921Sjraynard	sigemptyset(&mask);
249233921Sjraynard	sigaddset(&mask, SIGALRM);
249333921Sjraynard	sigaddset(&mask, SIGHUP);
249433921Sjraynard	sigprocmask(SIG_BLOCK, &mask, &omask);
2495129855Sdwmalone	switch ((pid = fork())) {
249622984Sjoerg	case -1:
249733921Sjraynard		sigprocmask(SIG_SETMASK, &omask, 0);
249822984Sjoerg		close(nulldesc);
249993079Sdes		return (-1);
250022984Sjoerg
250122984Sjoerg	case 0:
250283243Sdd		argv[0] = strdup("sh");
250383243Sdd		argv[1] = strdup("-c");
250483243Sdd		argv[2] = strdup(prog);
250522984Sjoerg		argv[3] = NULL;
250684168Sdes		if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL) {
250784168Sdes			logerror("strdup");
250884168Sdes			exit(1);
250984168Sdes		}
251022984Sjoerg
251122984Sjoerg		alarm(0);
251222984Sjoerg		(void)setsid();	/* Avoid catching SIGHUPs. */
251322984Sjoerg
251422984Sjoerg		/*
251522984Sjoerg		 * Throw away pending signals, and reset signal
251622984Sjoerg		 * behaviour to standard values.
251722984Sjoerg		 */
251822984Sjoerg		signal(SIGALRM, SIG_IGN);
251922984Sjoerg		signal(SIGHUP, SIG_IGN);
252033921Sjraynard		sigprocmask(SIG_SETMASK, &omask, 0);
252122984Sjoerg		signal(SIGPIPE, SIG_DFL);
252222984Sjoerg		signal(SIGQUIT, SIG_DFL);
252322984Sjoerg		signal(SIGALRM, SIG_DFL);
252422984Sjoerg		signal(SIGHUP, SIG_DFL);
252522984Sjoerg
252622984Sjoerg		dup2(pfd[0], STDIN_FILENO);
252722984Sjoerg		dup2(nulldesc, STDOUT_FILENO);
252822984Sjoerg		dup2(nulldesc, STDERR_FILENO);
2529250232Sjilles		closefrom(3);
253022984Sjoerg
253193080Sdes		(void)execvp(_PATH_BSHELL, argv);
253222984Sjoerg		_exit(255);
253322984Sjoerg	}
253422984Sjoerg
253533921Sjraynard	sigprocmask(SIG_SETMASK, &omask, 0);
253622984Sjoerg	close(nulldesc);
253722984Sjoerg	close(pfd[0]);
253822984Sjoerg	/*
253922984Sjoerg	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
254022984Sjoerg	 * supposed to get an EWOULDBLOCK on writev(2), which is
254122984Sjoerg	 * caught by the logic above anyway, which will in turn close
254222984Sjoerg	 * the pipe, and fork a new logging subprocess if necessary.
254322984Sjoerg	 * The stale subprocess will be killed some time later unless
254422984Sjoerg	 * it terminated itself due to closing its input pipe (so we
254522984Sjoerg	 * get rid of really dead puppies).
254622984Sjoerg	 */
254722984Sjoerg	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
254822984Sjoerg		/* This is bad. */
254922984Sjoerg		(void)snprintf(errmsg, sizeof errmsg,
255022984Sjoerg			       "Warning: cannot change pipe to PID %d to "
255122984Sjoerg			       "non-blocking behaviour.",
2552129855Sdwmalone			       (int)pid);
255322984Sjoerg		logerror(errmsg);
255422984Sjoerg	}
2555129855Sdwmalone	*rpid = pid;
255693079Sdes	return (pfd[1]);
255722984Sjoerg}
255822984Sjoerg
255993078Sdesstatic void
256093078Sdesdeadq_enter(pid_t pid, const char *name)
256122984Sjoerg{
256222984Sjoerg	dq_t p;
256357558Sjoerg	int status;
256422984Sjoerg
256557558Sjoerg	/*
256657558Sjoerg	 * Be paranoid, if we can't signal the process, don't enter it
256757558Sjoerg	 * into the dead queue (perhaps it's already dead).  If possible,
256857558Sjoerg	 * we try to fetch and log the child's status.
256957558Sjoerg	 */
257057558Sjoerg	if (kill(pid, 0) != 0) {
257157558Sjoerg		if (waitpid(pid, &status, WNOHANG) > 0)
257257558Sjoerg			log_deadchild(pid, status, name);
257357558Sjoerg		return;
257457558Sjoerg	}
257557558Sjoerg
257622984Sjoerg	p = malloc(sizeof(struct deadq_entry));
257783392Sdes	if (p == NULL) {
257884168Sdes		logerror("malloc");
257922984Sjoerg		exit(1);
258022984Sjoerg	}
258122984Sjoerg
258222984Sjoerg	p->dq_pid = pid;
258322984Sjoerg	p->dq_timeout = DQ_TIMO_INIT;
258422984Sjoerg	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
258522984Sjoerg}
258657558Sjoerg
258793078Sdesstatic int
258893078Sdesdeadq_remove(pid_t pid)
258957558Sjoerg{
259057558Sjoerg	dq_t q;
259157558Sjoerg
259293080Sdes	TAILQ_FOREACH(q, &deadq_head, dq_entries) {
259357558Sjoerg		if (q->dq_pid == pid) {
259457558Sjoerg			TAILQ_REMOVE(&deadq_head, q, dq_entries);
259557558Sjoerg				free(q);
259693079Sdes				return (1);
259757558Sjoerg		}
259893080Sdes	}
259957558Sjoerg
260093079Sdes	return (0);
260157558Sjoerg}
260257558Sjoerg
260393078Sdesstatic void
260493078Sdeslog_deadchild(pid_t pid, int status, const char *name)
260557558Sjoerg{
260657558Sjoerg	int code;
260757558Sjoerg	char buf[256];
260857558Sjoerg	const char *reason;
260957558Sjoerg
261057558Sjoerg	errno = 0; /* Keep strerror() stuff out of logerror messages. */
261157558Sjoerg	if (WIFSIGNALED(status)) {
261257558Sjoerg		reason = "due to signal";
261357558Sjoerg		code = WTERMSIG(status);
261457558Sjoerg	} else {
261557558Sjoerg		reason = "with status";
261657558Sjoerg		code = WEXITSTATUS(status);
261757558Sjoerg		if (code == 0)
261857558Sjoerg			return;
261957558Sjoerg	}
262057558Sjoerg	(void)snprintf(buf, sizeof buf,
262157558Sjoerg		       "Logging subprocess %d (%s) exited %s %d.",
262257558Sjoerg		       pid, name, reason, code);
262357558Sjoerg	logerror(buf);
262457558Sjoerg}
262570099Sume
262693078Sdesstatic int *
2627211023Sollisocksetup(int af, char *bindhostname)
262870099Sume{
262970099Sume	struct addrinfo hints, *res, *r;
2630211023Solli	const char *bindservice;
2631211023Solli	char *cp;
263270099Sume	int error, maxs, *s, *socks;
263370099Sume
2634211023Solli	/*
2635211023Solli	 * We have to handle this case for backwards compatibility:
2636211023Solli	 * If there are two (or more) colons but no '[' and ']',
2637211023Solli	 * assume this is an inet6 address without a service.
2638211023Solli	 */
2639211023Solli	bindservice = "syslog";
2640211023Solli	if (bindhostname != NULL) {
2641211023Solli#ifdef INET6
2642211023Solli		if (*bindhostname == '[' &&
2643211023Solli		    (cp = strchr(bindhostname + 1, ']')) != NULL) {
2644211023Solli			++bindhostname;
2645211023Solli			*cp = '\0';
2646211023Solli			if (cp[1] == ':' && cp[2] != '\0')
2647211023Solli				bindservice = cp + 2;
2648211023Solli		} else {
2649211023Solli#endif
2650211023Solli			cp = strchr(bindhostname, ':');
2651211023Solli			if (cp != NULL && strchr(cp + 1, ':') == NULL) {
2652211023Solli				*cp = '\0';
2653211023Solli				if (cp[1] != '\0')
2654211023Solli					bindservice = cp + 1;
2655211023Solli				if (cp == bindhostname)
2656211023Solli					bindhostname = NULL;
2657211023Solli			}
2658211023Solli#ifdef INET6
2659211023Solli		}
2660211023Solli#endif
2661211023Solli	}
2662211023Solli
266370099Sume	memset(&hints, 0, sizeof(hints));
266470099Sume	hints.ai_flags = AI_PASSIVE;
266570099Sume	hints.ai_family = af;
266670099Sume	hints.ai_socktype = SOCK_DGRAM;
2667211023Solli	error = getaddrinfo(bindhostname, bindservice, &hints, &res);
266870099Sume	if (error) {
266970099Sume		logerror(gai_strerror(error));
267070099Sume		errno = 0;
267170099Sume		die(0);
267270099Sume	}
267370099Sume
267470099Sume	/* Count max number of sockets we may open */
267570099Sume	for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
267670099Sume	socks = malloc((maxs+1) * sizeof(int));
267783392Sdes	if (socks == NULL) {
267870099Sume		logerror("couldn't allocate memory for sockets");
267970099Sume		die(0);
268070099Sume	}
268170099Sume
268270099Sume	*socks = 0;   /* num of sockets counter at start of array */
268370099Sume	s = socks + 1;
268470099Sume	for (r = res; r; r = r->ai_next) {
2685150689Scognet		int on = 1;
268670099Sume		*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
268770099Sume		if (*s < 0) {
268870099Sume			logerror("socket");
268970099Sume			continue;
269070099Sume		}
2691244881Smarkj#ifdef INET6
269270099Sume		if (r->ai_family == AF_INET6) {
2693100505Sume			if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
269470099Sume				       (char *)&on, sizeof (on)) < 0) {
269570099Sume				logerror("setsockopt");
269670099Sume				close(*s);
269770099Sume				continue;
269870099Sume			}
269970099Sume		}
2700244881Smarkj#endif
2701150689Scognet		if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
2702150690Scognet			       (char *)&on, sizeof (on)) < 0) {
2703150689Scognet			logerror("setsockopt");
2704150689Scognet			close(*s);
2705150689Scognet			continue;
2706150689Scognet		}
2707224002Sdelphij		/*
2708224002Sdelphij		 * RFC 3164 recommends that client side message
2709224002Sdelphij		 * should come from the privileged syslogd port.
2710224002Sdelphij		 *
2711224002Sdelphij		 * If the system administrator choose not to obey
2712224002Sdelphij		 * this, we can skip the bind() step so that the
2713224002Sdelphij		 * system will choose a port for us.
2714224002Sdelphij		 */
2715224002Sdelphij		if (!NoBind) {
2716224002Sdelphij			if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
2717244881Smarkj				logerror("bind");
2718224002Sdelphij				close(*s);
2719224002Sdelphij				continue;
2720224002Sdelphij			}
2721224002Sdelphij
2722224002Sdelphij			if (!SecureMode)
2723224002Sdelphij				double_rbuf(*s);
272470099Sume		}
272570099Sume
272670099Sume		(*socks)++;
272770099Sume		s++;
272870099Sume	}
272970099Sume
273070099Sume	if (*socks == 0) {
273170099Sume		free(socks);
273270099Sume		if (Debug)
273393079Sdes			return (NULL);
273470099Sume		else
273570099Sume			die(0);
273670099Sume	}
273770099Sume	if (res)
273870099Sume		freeaddrinfo(res);
273970099Sume
274093079Sdes	return (socks);
274170099Sume}
2742137568Sglebius
2743137568Sglebiusstatic void
2744137568Sglebiusdouble_rbuf(int fd)
2745137568Sglebius{
2746137568Sglebius	socklen_t slen, len;
2747137568Sglebius
2748137568Sglebius	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) {
2749137568Sglebius		len *= 2;
2750137568Sglebius		setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen);
2751137568Sglebius	}
2752137568Sglebius}
2753