syslogd.c revision 335492
1/*
2 * Copyright (c) 1983, 1988, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29/*-
30 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31 *
32 * Copyright (c) 2018 Prodrive Technologies, https://prodrive-technologies.com/
33 * Author: Ed Schouten <ed@FreeBSD.org>
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#ifndef lint
58static const char copyright[] =
59"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
60	The Regents of the University of California.  All rights reserved.\n";
61#endif /* not lint */
62
63#ifndef lint
64#if 0
65static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
66#endif
67#endif /* not lint */
68
69#include <sys/cdefs.h>
70__FBSDID("$FreeBSD: stable/11/usr.sbin/syslogd/syslogd.c 335492 2018-06-21 16:12:30Z ed $");
71
72/*
73 *  syslogd -- log system messages
74 *
75 * This program implements a system log. It takes a series of lines.
76 * Each line may have a priority, signified as "<n>" as
77 * the first characters of the line.  If this is
78 * not present, a default priority is used.
79 *
80 * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
81 * cause it to reread its configuration file.
82 *
83 * Defined Constants:
84 *
85 * MAXLINE -- the maximum line length that can be handled.
86 * DEFUPRI -- the default priority for user messages
87 * DEFSPRI -- the default priority for kernel messages
88 *
89 * Author: Eric Allman
90 * extensive changes by Ralph Campbell
91 * more extensive changes by Eric Allman (again)
92 * Extension to log by program name as well as facility and priority
93 *   by Peter da Silva.
94 * -u and -v by Harlan Stenn.
95 * Priority comparison code by Harlan Stenn.
96 */
97
98/* Maximum number of characters in time of last occurrence */
99#define	MAXLINE		2048		/* maximum line length */
100#define	MAXSVLINE	MAXLINE		/* maximum saved line length */
101#define	DEFUPRI		(LOG_USER|LOG_NOTICE)
102#define	DEFSPRI		(LOG_KERN|LOG_CRIT)
103#define	TIMERINTVL	30		/* interval for checking flush, mark */
104#define	TTYMSGTIME	1		/* timeout passed to ttymsg */
105#define	RCVBUF_MINSIZE	(80 * 1024)	/* minimum size of dgram rcv buffer */
106
107#include <sys/param.h>
108#include <sys/ioctl.h>
109#include <sys/mman.h>
110#include <sys/queue.h>
111#include <sys/resource.h>
112#include <sys/socket.h>
113#include <sys/stat.h>
114#include <sys/syslimits.h>
115#include <sys/time.h>
116#include <sys/uio.h>
117#include <sys/un.h>
118#include <sys/wait.h>
119
120#if defined(INET) || defined(INET6)
121#include <netinet/in.h>
122#include <arpa/inet.h>
123#endif
124
125#include <assert.h>
126#include <ctype.h>
127#include <dirent.h>
128#include <err.h>
129#include <errno.h>
130#include <fcntl.h>
131#include <fnmatch.h>
132#include <libutil.h>
133#include <limits.h>
134#include <netdb.h>
135#include <paths.h>
136#include <signal.h>
137#include <stdbool.h>
138#include <stdio.h>
139#include <stdlib.h>
140#include <string.h>
141#include <sysexits.h>
142#include <unistd.h>
143#include <utmpx.h>
144
145#include "pathnames.h"
146#include "ttymsg.h"
147
148#define SYSLOG_NAMES
149#include <sys/syslog.h>
150
151static const char *ConfFile = _PATH_LOGCONF;
152static const char *PidFile = _PATH_LOGPID;
153static const char ctty[] = _PATH_CONSOLE;
154static const char include_str[] = "include";
155static const char include_ext[] = ".conf";
156
157#define	dprintf		if (Debug) printf
158
159#define	MAXUNAMES	20	/* maximum number of user names */
160
161#define	sstosa(ss)	((struct sockaddr *)(ss))
162#ifdef INET
163#define	sstosin(ss)	((struct sockaddr_in *)(void *)(ss))
164#define	satosin(sa)	((struct sockaddr_in *)(void *)(sa))
165#endif
166#ifdef INET6
167#define	sstosin6(ss)	((struct sockaddr_in6 *)(void *)(ss))
168#define	satosin6(sa)	((struct sockaddr_in6 *)(void *)(sa))
169#define	s6_addr32	__u6_addr.__u6_addr32
170#define	IN6_ARE_MASKED_ADDR_EQUAL(d, a, m)	(	\
171	(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
172	(((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
173	(((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
174	(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
175#endif
176/*
177 * List of peers and sockets for binding.
178 */
179struct peer {
180	const char	*pe_name;
181	const char	*pe_serv;
182	mode_t		pe_mode;
183	STAILQ_ENTRY(peer)	next;
184};
185static STAILQ_HEAD(, peer) pqueue = STAILQ_HEAD_INITIALIZER(pqueue);
186
187struct socklist {
188	struct sockaddr_storage	sl_ss;
189	int			sl_socket;
190	struct peer		*sl_peer;
191	int			(*sl_recv)(struct socklist *);
192	STAILQ_ENTRY(socklist)	next;
193};
194static STAILQ_HEAD(, socklist) shead = STAILQ_HEAD_INITIALIZER(shead);
195
196/*
197 * Flags to logmsg().
198 */
199
200#define	IGN_CONS	0x001	/* don't print on console */
201#define	SYNC_FILE	0x002	/* do fsync on file after printing */
202#define	MARK		0x008	/* this message is a mark */
203
204/* Timestamps of log entries. */
205struct logtime {
206	struct tm	tm;
207	suseconds_t	usec;
208};
209
210/* Traditional syslog timestamp format. */
211#define	RFC3164_DATELEN	15
212#define	RFC3164_DATEFMT	"%b %e %H:%M:%S"
213
214/*
215 * This structure represents the files that will have log
216 * copies printed.
217 * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
218 * or if f_type is F_PIPE and f_pid > 0.
219 */
220
221struct filed {
222	STAILQ_ENTRY(filed)	next;	/* next in linked list */
223	short	f_type;			/* entry type, see below */
224	short	f_file;			/* file descriptor */
225	time_t	f_time;			/* time this was last written */
226	char	*f_host;		/* host from which to recd. */
227	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
228	u_char	f_pcmp[LOG_NFACILITIES+1];	/* compare priority */
229#define PRI_LT	0x1
230#define PRI_EQ	0x2
231#define PRI_GT	0x4
232	char	*f_program;		/* program this applies to */
233	union {
234		char	f_uname[MAXUNAMES][MAXLOGNAME];
235		struct {
236			char	f_hname[MAXHOSTNAMELEN];
237			struct addrinfo *f_addr;
238
239		} f_forw;		/* forwarding address */
240		char	f_fname[MAXPATHLEN];
241		struct {
242			char	f_pname[MAXPATHLEN];
243			pid_t	f_pid;
244		} f_pipe;
245	} f_un;
246#define	fu_uname	f_un.f_uname
247#define	fu_forw_hname	f_un.f_forw.f_hname
248#define	fu_forw_addr	f_un.f_forw.f_addr
249#define	fu_fname	f_un.f_fname
250#define	fu_pipe_pname	f_un.f_pipe.f_pname
251#define	fu_pipe_pid	f_un.f_pipe.f_pid
252	char	f_prevline[MAXSVLINE];		/* last message logged */
253	struct logtime f_lasttime;		/* time of last occurrence */
254	int	f_prevpri;			/* pri of f_prevline */
255	size_t	f_prevlen;			/* length of f_prevline */
256	int	f_prevcount;			/* repetition cnt of prevline */
257	u_int	f_repeatcount;			/* number of "repeated" msgs */
258	int	f_flags;			/* file-specific flags */
259#define	FFLAG_SYNC 0x01
260#define	FFLAG_NEEDSYNC	0x02
261};
262
263/*
264 * Queue of about-to-be dead processes we should watch out for.
265 */
266struct deadq_entry {
267	pid_t				dq_pid;
268	int				dq_timeout;
269	TAILQ_ENTRY(deadq_entry)	dq_entries;
270};
271static TAILQ_HEAD(, deadq_entry) deadq_head =
272    TAILQ_HEAD_INITIALIZER(deadq_head);
273
274/*
275 * The timeout to apply to processes waiting on the dead queue.  Unit
276 * of measure is `mark intervals', i.e. 20 minutes by default.
277 * Processes on the dead queue will be terminated after that time.
278 */
279
280#define	 DQ_TIMO_INIT	2
281
282/*
283 * Struct to hold records of network addresses that are allowed to log
284 * to us.
285 */
286struct allowedpeer {
287	int isnumeric;
288	u_short port;
289	union {
290		struct {
291			struct sockaddr_storage addr;
292			struct sockaddr_storage mask;
293		} numeric;
294		char *name;
295	} u;
296#define a_addr u.numeric.addr
297#define a_mask u.numeric.mask
298#define a_name u.name
299	STAILQ_ENTRY(allowedpeer)	next;
300};
301static STAILQ_HEAD(, allowedpeer) aphead = STAILQ_HEAD_INITIALIZER(aphead);
302
303
304/*
305 * Intervals at which we flush out "message repeated" messages,
306 * in seconds after previous message is logged.  After each flush,
307 * we move to the next interval until we reach the largest.
308 */
309static int repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
310#define	MAXREPEAT	(nitems(repeatinterval) - 1)
311#define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
312#define	BACKOFF(f)	do {						\
313				if (++(f)->f_repeatcount > MAXREPEAT)	\
314					(f)->f_repeatcount = MAXREPEAT;	\
315			} while (0)
316
317/* values for f_type */
318#define F_UNUSED	0		/* unused entry */
319#define F_FILE		1		/* regular file */
320#define F_TTY		2		/* terminal */
321#define F_CONSOLE	3		/* console terminal */
322#define F_FORW		4		/* remote machine */
323#define F_USERS		5		/* list of users */
324#define F_WALL		6		/* everyone logged on */
325#define F_PIPE		7		/* pipe to program */
326
327static const char *TypeNames[] = {
328	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
329	"FORW",		"USERS",	"WALL",		"PIPE"
330};
331
332static STAILQ_HEAD(, filed) fhead =
333    STAILQ_HEAD_INITIALIZER(fhead);	/* Log files that we write to */
334static struct filed consfile;	/* Console */
335
336static int	Debug;		/* debug flag */
337static int	Foreground = 0;	/* Run in foreground, instead of daemonizing */
338static int	resolve = 1;	/* resolve hostname */
339static char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
340static const char *LocalDomain;	/* our local domain name */
341static int	Initialized;	/* set when we have initialized ourselves */
342static int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
343static int	MarkSeq;	/* mark sequence number */
344static int	NoBind;		/* don't bind() as suggested by RFC 3164 */
345static int	SecureMode;	/* when true, receive only unix domain socks */
346#ifdef INET6
347static int	family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
348#else
349static int	family = PF_INET; /* protocol family (IPv4 only) */
350#endif
351static int	mask_C1 = 1;	/* mask characters from 0x80 - 0x9F */
352static int	send_to_all;	/* send message to all IPv4/IPv6 addresses */
353static int	use_bootfile;	/* log entire bootfile for every kern msg */
354static int	no_compress;	/* don't compress messages (1=pipes, 2=all) */
355static int	logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
356
357static char	bootfile[MAXLINE+1]; /* booted kernel file */
358
359static int	RemoteAddDate;	/* Always set the date on remote messages */
360static int	RemoteHostname;	/* Log remote hostname from the message */
361
362static int	UniquePriority;	/* Only log specified priority? */
363static int	LogFacPri;	/* Put facility and priority in log message: */
364				/* 0=no, 1=numeric, 2=names */
365static int	KeepKernFac;	/* Keep remotely logged kernel facility */
366static int	needdofsync = 0; /* Are any file(s) waiting to be fsynced? */
367static struct pidfh *pfh;
368static int	sigpipe[2];	/* Pipe to catch a signal during select(). */
369static bool	RFC3164OutputFormat = true; /* Use legacy format by default. */
370
371static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild;
372
373struct iovlist;
374
375static int	allowaddr(char *);
376static int	addfile(struct filed *);
377static int	addpeer(struct peer *);
378static int	addsock(struct sockaddr *, socklen_t, struct socklist *);
379static struct filed *cfline(const char *, const char *, const char *);
380static const char *cvthname(struct sockaddr *);
381static void	deadq_enter(pid_t, const char *);
382static int	deadq_remove(struct deadq_entry *);
383static int	deadq_removebypid(pid_t);
384static int	decode(const char *, const CODE *);
385static void	die(int) __dead2;
386static void	dodie(int);
387static void	dofsync(void);
388static void	domark(int);
389static void	fprintlog_first(struct filed *, const char *, const char *,
390    const char *, const char *, const char *, const char *, int);
391static void	fprintlog_write(struct filed *, struct iovlist *, int);
392static void	fprintlog_successive(struct filed *, int);
393static void	init(int);
394static void	logerror(const char *);
395static void	logmsg(int, const struct logtime *, const char *, const char *,
396    const char *, const char *, const char *, const char *, int);
397static void	log_deadchild(pid_t, int, const char *);
398static void	markit(void);
399static int	socksetup(struct peer *);
400static int	socklist_recv_file(struct socklist *);
401static int	socklist_recv_sock(struct socklist *);
402static int	socklist_recv_signal(struct socklist *);
403static void	sighandler(int);
404static int	skip_message(const char *, const char *, int);
405static void	parsemsg(const char *, char *);
406static void	printsys(char *);
407static int	p_open(const char *, pid_t *);
408static void	reapchild(int);
409static const char *ttymsg_check(struct iovec *, int, char *, int);
410static void	usage(void);
411static int	validate(struct sockaddr *, const char *);
412static void	unmapped(struct sockaddr *);
413static void	wallmsg(struct filed *, struct iovec *, const int iovlen);
414static int	waitdaemon(int);
415static void	timedout(int);
416static void	increase_rcvbuf(int);
417
418static void
419close_filed(struct filed *f)
420{
421
422	if (f == NULL || f->f_file == -1)
423		return;
424
425	switch (f->f_type) {
426	case F_FORW:
427		if (f->f_un.f_forw.f_addr) {
428			freeaddrinfo(f->f_un.f_forw.f_addr);
429			f->f_un.f_forw.f_addr = NULL;
430		}
431		/* FALLTHROUGH */
432
433	case F_FILE:
434	case F_TTY:
435	case F_CONSOLE:
436		f->f_type = F_UNUSED;
437		break;
438	case F_PIPE:
439		f->fu_pipe_pid = 0;
440		break;
441	}
442	(void)close(f->f_file);
443	f->f_file = -1;
444}
445
446static int
447addfile(struct filed *f0)
448{
449	struct filed *f;
450
451	f = calloc(1, sizeof(*f));
452	if (f == NULL)
453		err(1, "malloc failed");
454	*f = *f0;
455	STAILQ_INSERT_TAIL(&fhead, f, next);
456
457	return (0);
458}
459
460static int
461addpeer(struct peer *pe0)
462{
463	struct peer *pe;
464
465	pe = calloc(1, sizeof(*pe));
466	if (pe == NULL)
467		err(1, "malloc failed");
468	*pe = *pe0;
469	STAILQ_INSERT_TAIL(&pqueue, pe, next);
470
471	return (0);
472}
473
474static int
475addsock(struct sockaddr *sa, socklen_t sa_len, struct socklist *sl0)
476{
477	struct socklist *sl;
478
479	sl = calloc(1, sizeof(*sl));
480	if (sl == NULL)
481		err(1, "malloc failed");
482	*sl = *sl0;
483	if (sa != NULL && sa_len > 0)
484		memcpy(&sl->sl_ss, sa, sa_len);
485	STAILQ_INSERT_TAIL(&shead, sl, next);
486
487	return (0);
488}
489
490int
491main(int argc, char *argv[])
492{
493	int ch, i, s, fdsrmax = 0, bflag = 0, pflag = 0, Sflag = 0;
494	fd_set *fdsr = NULL;
495	struct timeval tv, *tvp;
496	struct peer *pe;
497	struct socklist *sl;
498	pid_t ppid = 1, spid;
499	char *p;
500
501	if (madvise(NULL, 0, MADV_PROTECT) != 0)
502		dprintf("madvise() failed: %s\n", strerror(errno));
503
504	while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:m:nNoO:p:P:sS:Tuv"))
505	    != -1)
506		switch (ch) {
507#ifdef INET
508		case '4':
509			family = PF_INET;
510			break;
511#endif
512#ifdef INET6
513		case '6':
514			family = PF_INET6;
515			break;
516#endif
517		case '8':
518			mask_C1 = 0;
519			break;
520		case 'A':
521			send_to_all++;
522			break;
523		case 'a':		/* allow specific network addresses only */
524			if (allowaddr(optarg) == -1)
525				usage();
526			break;
527		case 'b':
528			bflag = 1;
529			p = strchr(optarg, ']');
530			if (p != NULL)
531				p = strchr(p + 1, ':');
532			else {
533				p = strchr(optarg, ':');
534				if (p != NULL && strchr(p + 1, ':') != NULL)
535					p = NULL; /* backward compatibility */
536			}
537			if (p == NULL) {
538				/* A hostname or filename only. */
539				addpeer(&(struct peer){
540					.pe_name = optarg,
541					.pe_serv = "syslog"
542				});
543			} else {
544				/* The case of "name:service". */
545				*p++ = '\0';
546				addpeer(&(struct peer){
547					.pe_serv = p,
548					.pe_name = (strlen(optarg) == 0) ?
549					    NULL : optarg,
550				});
551			}
552			break;
553		case 'c':
554			no_compress++;
555			break;
556		case 'C':
557			logflags |= O_CREAT;
558			break;
559		case 'd':		/* debug */
560			Debug++;
561			break;
562		case 'f':		/* configuration file */
563			ConfFile = optarg;
564			break;
565		case 'F':		/* run in foreground instead of daemon */
566			Foreground++;
567			break;
568		case 'H':
569			RemoteHostname = 1;
570			break;
571		case 'k':		/* keep remote kern fac */
572			KeepKernFac = 1;
573			break;
574		case 'l':
575		case 'p':
576		case 'S':
577		    {
578			long	perml;
579			mode_t	mode;
580			char	*name, *ep;
581
582			if (ch == 'l')
583				mode = DEFFILEMODE;
584			else if (ch == 'p') {
585				mode = DEFFILEMODE;
586				pflag = 1;
587			} else {
588				mode = S_IRUSR | S_IWUSR;
589				Sflag = 1;
590			}
591			if (optarg[0] == '/')
592				name = optarg;
593			else if ((name = strchr(optarg, ':')) != NULL) {
594				*name++ = '\0';
595				if (name[0] != '/')
596					errx(1, "socket name must be absolute "
597					    "path");
598				if (isdigit(*optarg)) {
599					perml = strtol(optarg, &ep, 8);
600				    if (*ep || perml < 0 ||
601					perml & ~(S_IRWXU|S_IRWXG|S_IRWXO))
602					    errx(1, "invalid mode %s, exiting",
603						optarg);
604				    mode = (mode_t )perml;
605				} else
606					errx(1, "invalid mode %s, exiting",
607					    optarg);
608			} else
609				errx(1, "invalid filename %s, exiting",
610				    optarg);
611			addpeer(&(struct peer){
612				.pe_name = name,
613				.pe_mode = mode
614			});
615			break;
616		   }
617		case 'm':		/* mark interval */
618			MarkInterval = atoi(optarg) * 60;
619			break;
620		case 'N':
621			NoBind = 1;
622			SecureMode = 1;
623			break;
624		case 'n':
625			resolve = 0;
626			break;
627		case 'O':
628			if (strcmp(optarg, "bsd") == 0 ||
629			    strcmp(optarg, "rfc3164") == 0)
630				RFC3164OutputFormat = true;
631			else if (strcmp(optarg, "syslog") == 0 ||
632			    strcmp(optarg, "rfc5424") == 0)
633				RFC3164OutputFormat = false;
634			else
635				usage();
636			break;
637		case 'o':
638			use_bootfile = 1;
639			break;
640		case 'P':		/* path for alt. PID */
641			PidFile = optarg;
642			break;
643		case 's':		/* no network mode */
644			SecureMode++;
645			break;
646		case 'T':
647			RemoteAddDate = 1;
648			break;
649		case 'u':		/* only log specified priority */
650			UniquePriority++;
651			break;
652		case 'v':		/* log facility and priority */
653		  	LogFacPri++;
654			break;
655		default:
656			usage();
657		}
658	if ((argc -= optind) != 0)
659		usage();
660
661	/* Pipe to catch a signal during select(). */
662	s = pipe2(sigpipe, O_CLOEXEC);
663	if (s < 0) {
664		err(1, "cannot open a pipe for signals");
665	} else {
666		addsock(NULL, 0, &(struct socklist){
667		    .sl_socket = sigpipe[0],
668		    .sl_recv = socklist_recv_signal
669		});
670	}
671
672	/* Listen by default: /dev/klog. */
673	s = open(_PATH_KLOG, O_RDONLY | O_NONBLOCK | O_CLOEXEC, 0);
674	if (s < 0) {
675		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
676	} else {
677		addsock(NULL, 0, &(struct socklist){
678			.sl_socket = s,
679			.sl_recv = socklist_recv_file,
680		});
681	}
682	/* Listen by default: *:514 if no -b flag. */
683	if (bflag == 0)
684		addpeer(&(struct peer){
685			.pe_serv = "syslog"
686		});
687	/* Listen by default: /var/run/log if no -p flag. */
688	if (pflag == 0)
689		addpeer(&(struct peer){
690			.pe_name = _PATH_LOG,
691			.pe_mode = DEFFILEMODE,
692		});
693	/* Listen by default: /var/run/logpriv if no -S flag. */
694	if (Sflag == 0)
695		addpeer(&(struct peer){
696			.pe_name = _PATH_LOG_PRIV,
697			.pe_mode = S_IRUSR | S_IWUSR,
698		});
699	STAILQ_FOREACH(pe, &pqueue, next)
700		socksetup(pe);
701
702	pfh = pidfile_open(PidFile, 0600, &spid);
703	if (pfh == NULL) {
704		if (errno == EEXIST)
705			errx(1, "syslogd already running, pid: %d", spid);
706		warn("cannot open pid file");
707	}
708
709	if ((!Foreground) && (!Debug)) {
710		ppid = waitdaemon(30);
711		if (ppid < 0) {
712			warn("could not become daemon");
713			pidfile_remove(pfh);
714			exit(1);
715		}
716	} else if (Debug)
717		setlinebuf(stdout);
718
719	consfile.f_type = F_CONSOLE;
720	(void)strlcpy(consfile.fu_fname, ctty + sizeof _PATH_DEV - 1,
721	    sizeof(consfile.fu_fname));
722	(void)strlcpy(bootfile, getbootfile(), sizeof(bootfile));
723	(void)signal(SIGTERM, dodie);
724	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
725	(void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
726	(void)signal(SIGHUP, sighandler);
727	(void)signal(SIGCHLD, sighandler);
728	(void)signal(SIGALRM, domark);
729	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
730	(void)alarm(TIMERINTVL);
731
732	/* tuck my process id away */
733	pidfile_write(pfh);
734
735	dprintf("off & running....\n");
736
737	tvp = &tv;
738	tv.tv_sec = tv.tv_usec = 0;
739
740	STAILQ_FOREACH(sl, &shead, next) {
741		if (sl->sl_socket > fdsrmax)
742			fdsrmax = sl->sl_socket;
743	}
744	fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
745	    sizeof(*fdsr));
746	if (fdsr == NULL)
747		errx(1, "calloc fd_set");
748
749	for (;;) {
750		if (Initialized == 0)
751			init(0);
752		else if (WantInitialize)
753			init(WantInitialize);
754		if (WantReapchild)
755			reapchild(WantReapchild);
756		if (MarkSet)
757			markit();
758		if (WantDie) {
759			free(fdsr);
760			die(WantDie);
761		}
762
763		bzero(fdsr, howmany(fdsrmax+1, NFDBITS) *
764		    sizeof(*fdsr));
765
766		STAILQ_FOREACH(sl, &shead, next) {
767			if (sl->sl_socket != -1 && sl->sl_recv != NULL)
768				FD_SET(sl->sl_socket, fdsr);
769		}
770		i = select(fdsrmax + 1, fdsr, NULL, NULL,
771		    needdofsync ? &tv : tvp);
772		switch (i) {
773		case 0:
774			dofsync();
775			needdofsync = 0;
776			if (tvp) {
777				tvp = NULL;
778				if (ppid != 1)
779					kill(ppid, SIGALRM);
780			}
781			continue;
782		case -1:
783			if (errno != EINTR)
784				logerror("select");
785			continue;
786		}
787		STAILQ_FOREACH(sl, &shead, next) {
788			if (FD_ISSET(sl->sl_socket, fdsr))
789				(*sl->sl_recv)(sl);
790		}
791	}
792	free(fdsr);
793}
794
795static int
796socklist_recv_signal(struct socklist *sl __unused)
797{
798	ssize_t len;
799	int i, nsig, signo;
800
801	if (ioctl(sigpipe[0], FIONREAD, &i) != 0) {
802		logerror("ioctl(FIONREAD)");
803		err(1, "signal pipe read failed");
804	}
805	nsig = i / sizeof(signo);
806	dprintf("# of received signals = %d\n", nsig);
807	for (i = 0; i < nsig; i++) {
808		len = read(sigpipe[0], &signo, sizeof(signo));
809		if (len != sizeof(signo)) {
810			logerror("signal pipe read failed");
811			err(1, "signal pipe read failed");
812		}
813		dprintf("Received signal: %d from fd=%d\n", signo,
814		    sigpipe[0]);
815		switch (signo) {
816		case SIGHUP:
817			WantInitialize = 1;
818			break;
819		case SIGCHLD:
820			WantReapchild = 1;
821			break;
822		}
823	}
824	return (0);
825}
826
827static int
828socklist_recv_sock(struct socklist *sl)
829{
830	struct sockaddr_storage ss;
831	struct sockaddr *sa = (struct sockaddr *)&ss;
832	socklen_t sslen;
833	const char *hname;
834	char line[MAXLINE + 1];
835	int len;
836
837	sslen = sizeof(ss);
838	len = recvfrom(sl->sl_socket, line, sizeof(line) - 1, 0, sa, &sslen);
839	dprintf("received sa_len = %d\n", sslen);
840	if (len == 0)
841		return (-1);
842	if (len < 0) {
843		if (errno != EINTR)
844			logerror("recvfrom");
845		return (-1);
846	}
847	/* Received valid data. */
848	line[len] = '\0';
849	if (sl->sl_ss.ss_family == AF_LOCAL)
850		hname = LocalHostName;
851	else {
852		hname = cvthname(sa);
853		unmapped(sa);
854		if (validate(sa, hname) == 0) {
855			dprintf("Message from %s was ignored.", hname);
856			return (-1);
857		}
858	}
859	parsemsg(hname, line);
860
861	return (0);
862}
863
864static void
865unmapped(struct sockaddr *sa)
866{
867#if defined(INET) && defined(INET6)
868	struct sockaddr_in6 *sin6;
869	struct sockaddr_in sin;
870
871	if (sa == NULL ||
872	    sa->sa_family != AF_INET6 ||
873	    sa->sa_len != sizeof(*sin6))
874		return;
875	sin6 = satosin6(sa);
876	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
877		return;
878	sin = (struct sockaddr_in){
879		.sin_family = AF_INET,
880		.sin_len = sizeof(sin),
881		.sin_port = sin6->sin6_port
882	};
883	memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
884	    sizeof(sin.sin_addr));
885	memcpy(sa, &sin, sizeof(sin));
886#else
887	if (sa == NULL)
888		return;
889#endif
890}
891
892static void
893usage(void)
894{
895
896	fprintf(stderr,
897		"usage: syslogd [-468ACcdFHknosTuv] [-a allowed_peer]\n"
898		"               [-b bind_address] [-f config_file]\n"
899		"               [-l [mode:]path] [-m mark_interval]\n"
900		"               [-O format] [-P pid_file] [-p log_socket]\n"
901		"               [-S logpriv_socket]\n");
902	exit(1);
903}
904
905/*
906 * Removes characters from log messages that are unsafe to display.
907 * TODO: Permit UTF-8 strings that include a BOM per RFC 5424?
908 */
909static void
910parsemsg_remove_unsafe_characters(const char *in, char *out, size_t outlen)
911{
912	char *q;
913	int c;
914
915	q = out;
916	while ((c = (unsigned char)*in++) != '\0' && q < out + outlen - 4) {
917		if (mask_C1 && (c & 0x80) && c < 0xA0) {
918			c &= 0x7F;
919			*q++ = 'M';
920			*q++ = '-';
921		}
922		if (isascii(c) && iscntrl(c)) {
923			if (c == '\n') {
924				*q++ = ' ';
925			} else if (c == '\t') {
926				*q++ = '\t';
927			} else {
928				*q++ = '^';
929				*q++ = c ^ 0100;
930			}
931		} else {
932			*q++ = c;
933		}
934	}
935	*q = '\0';
936}
937
938/*
939 * Parses a syslog message according to RFC 5424, assuming that PRI and
940 * VERSION (i.e., "<%d>1 ") have already been parsed by parsemsg(). The
941 * parsed result is passed to logmsg().
942 */
943static void
944parsemsg_rfc5424(const char *from, int pri, char *msg)
945{
946	const struct logtime *timestamp;
947	struct logtime timestamp_remote;
948	const char *omsg, *hostname, *app_name, *procid, *msgid,
949	    *structured_data;
950	char line[MAXLINE + 1];
951
952#define	FAIL_IF(field, expr) do {					\
953	if (expr) {							\
954		dprintf("Failed to parse " field " from %s: %s\n",	\
955		    from, omsg);					\
956		return;							\
957	}								\
958} while (0)
959#define	PARSE_CHAR(field, sep) do {					\
960	FAIL_IF(field, *msg != sep);					\
961	++msg;								\
962} while (0)
963#define	IF_NOT_NILVALUE(var)						\
964	if (msg[0] == '-' && msg[1] == ' ') {				\
965		msg += 2;						\
966		var = NULL;						\
967	} else if (msg[0] == '-' && msg[1] == '\0') {			\
968		++msg;							\
969		var = NULL;						\
970	} else
971
972	omsg = msg;
973	IF_NOT_NILVALUE(timestamp) {
974		/* Parse RFC 3339-like timestamp. */
975#define	PARSE_NUMBER(dest, length, min, max) do {			\
976	int i, v;							\
977									\
978	v = 0;								\
979	for (i = 0; i < length; ++i) {					\
980		FAIL_IF("TIMESTAMP", *msg < '0' || *msg > '9');		\
981		v = v * 10 + *msg++ - '0';				\
982	}								\
983	FAIL_IF("TIMESTAMP", v < min || v > max);			\
984	dest = v;							\
985} while (0)
986		/* Date and time. */
987		memset(&timestamp_remote, 0, sizeof(timestamp_remote));
988		PARSE_NUMBER(timestamp_remote.tm.tm_year, 4, 0, 9999);
989		timestamp_remote.tm.tm_year -= 1900;
990		PARSE_CHAR("TIMESTAMP", '-');
991		PARSE_NUMBER(timestamp_remote.tm.tm_mon, 2, 1, 12);
992		--timestamp_remote.tm.tm_mon;
993		PARSE_CHAR("TIMESTAMP", '-');
994		PARSE_NUMBER(timestamp_remote.tm.tm_mday, 2, 1, 31);
995		PARSE_CHAR("TIMESTAMP", 'T');
996		PARSE_NUMBER(timestamp_remote.tm.tm_hour, 2, 0, 23);
997		PARSE_CHAR("TIMESTAMP", ':');
998		PARSE_NUMBER(timestamp_remote.tm.tm_min, 2, 0, 59);
999		PARSE_CHAR("TIMESTAMP", ':');
1000		PARSE_NUMBER(timestamp_remote.tm.tm_sec, 2, 0, 59);
1001		/* Perform normalization. */
1002		timegm(&timestamp_remote.tm);
1003		/* Optional: fractional seconds. */
1004		if (msg[0] == '.' && msg[1] >= '0' && msg[1] <= '9') {
1005			int i;
1006
1007			++msg;
1008			for (i = 100000; i != 0; i /= 10) {
1009				if (*msg < '0' || *msg > '9')
1010					break;
1011				timestamp_remote.usec += (*msg++ - '0') * i;
1012			}
1013		}
1014		/* Timezone. */
1015		if (*msg == 'Z') {
1016			/* UTC. */
1017			++msg;
1018		} else {
1019			int sign, tz_hour, tz_min;
1020
1021			/* Local time zone offset. */
1022			FAIL_IF("TIMESTAMP", *msg != '-' && *msg != '+');
1023			sign = *msg++ == '-' ? -1 : 1;
1024			PARSE_NUMBER(tz_hour, 2, 0, 23);
1025			PARSE_CHAR("TIMESTAMP", ':');
1026			PARSE_NUMBER(tz_min, 2, 0, 59);
1027			timestamp_remote.tm.tm_gmtoff =
1028			    sign * (tz_hour * 3600 + tz_min * 60);
1029		}
1030#undef PARSE_NUMBER
1031		PARSE_CHAR("TIMESTAMP", ' ');
1032		timestamp = RemoteAddDate ? NULL : &timestamp_remote;
1033	}
1034
1035	/* String fields part of the HEADER. */
1036#define	PARSE_STRING(field, var)					\
1037	IF_NOT_NILVALUE(var) {						\
1038		var = msg;						\
1039		while (*msg >= '!' && *msg <= '~')			\
1040			++msg;						\
1041		FAIL_IF(field, var == msg);				\
1042		PARSE_CHAR(field, ' ');					\
1043		msg[-1] = '\0';						\
1044	}
1045	PARSE_STRING("HOSTNAME", hostname);
1046	if (hostname == NULL || !RemoteHostname)
1047		hostname = from;
1048	PARSE_STRING("APP-NAME", app_name);
1049	PARSE_STRING("PROCID", procid);
1050	PARSE_STRING("MSGID", msgid);
1051#undef PARSE_STRING
1052
1053	/* Structured data. */
1054#define	PARSE_SD_NAME() do {						\
1055	const char *start;						\
1056									\
1057	start = msg;							\
1058	while (*msg >= '!' && *msg <= '~' && *msg != '=' &&		\
1059	    *msg != ']' && *msg != '"')					\
1060		++msg;							\
1061	FAIL_IF("STRUCTURED-NAME", start == msg);			\
1062} while (0)
1063	IF_NOT_NILVALUE(structured_data) {
1064		/* SD-ELEMENT. */
1065		while (*msg == '[') {
1066			++msg;
1067			/* SD-ID. */
1068			PARSE_SD_NAME();
1069			/* SD-PARAM. */
1070			while (*msg == ' ') {
1071				++msg;
1072				/* PARAM-NAME. */
1073				PARSE_SD_NAME();
1074				PARSE_CHAR("STRUCTURED-NAME", '=');
1075				PARSE_CHAR("STRUCTURED-NAME", '"');
1076				while (*msg != '"') {
1077					FAIL_IF("STRUCTURED-NAME",
1078					    *msg == '\0');
1079					if (*msg++ == '\\') {
1080						FAIL_IF("STRUCTURED-NAME",
1081						    *msg == '\0');
1082						++msg;
1083					}
1084				}
1085				++msg;
1086			}
1087			PARSE_CHAR("STRUCTURED-NAME", ']');
1088		}
1089		PARSE_CHAR("STRUCTURED-NAME", ' ');
1090		msg[-1] = '\0';
1091	}
1092#undef PARSE_SD_NAME
1093
1094#undef FAIL_IF
1095#undef PARSE_CHAR
1096#undef IF_NOT_NILVALUE
1097
1098	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
1099	logmsg(pri, timestamp, hostname, app_name, procid, msgid,
1100	    structured_data, line, 0);
1101}
1102
1103/*
1104 * Trims the application name ("TAG" in RFC 3164 terminology) and
1105 * process ID from a message if present.
1106 */
1107static void
1108parsemsg_rfc3164_app_name_procid(char **msg, const char **app_name,
1109    const char **procid) {
1110	char *m, *app_name_begin, *procid_begin;
1111	size_t app_name_length, procid_length;
1112
1113	m = *msg;
1114
1115	/* Application name. */
1116	app_name_begin = m;
1117	app_name_length = strspn(m,
1118	    "abcdefghijklmnopqrstuvwxyz"
1119	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1120	    "0123456789"
1121	    "_-");
1122	if (app_name_length == 0)
1123		goto bad;
1124	m += app_name_length;
1125
1126	/* Process identifier (optional). */
1127	if (*m == '[') {
1128		procid_begin = ++m;
1129		procid_length = strspn(m, "0123456789");
1130		if (procid_length == 0)
1131			goto bad;
1132		m += procid_length;
1133		if (*m++ != ']')
1134			goto bad;
1135	} else {
1136		procid_begin = NULL;
1137		procid_length = 0;
1138	}
1139
1140	/* Separator. */
1141	if (m[0] != ':' || m[1] != ' ')
1142		goto bad;
1143
1144	/* Split strings from input. */
1145	app_name_begin[app_name_length] = '\0';
1146	if (procid_begin != 0)
1147		procid_begin[procid_length] = '\0';
1148
1149	*msg = m + 2;
1150	*app_name = app_name_begin;
1151	*procid = procid_begin;
1152	return;
1153bad:
1154	*app_name = NULL;
1155	*procid = NULL;
1156}
1157
1158/*
1159 * Parses a syslog message according to RFC 3164, assuming that PRI
1160 * (i.e., "<%d>") has already been parsed by parsemsg(). The parsed
1161 * result is passed to logmsg().
1162 */
1163static void
1164parsemsg_rfc3164(const char *from, int pri, char *msg)
1165{
1166	struct tm tm_parsed;
1167	const struct logtime *timestamp;
1168	struct logtime timestamp_remote;
1169	const char *app_name, *procid;
1170	size_t i, msglen;
1171	char line[MAXLINE + 1];
1172
1173	/* Parse the timestamp provided by the remote side. */
1174	if (strptime(msg, RFC3164_DATEFMT, &tm_parsed) !=
1175	    msg + RFC3164_DATELEN || msg[RFC3164_DATELEN] != ' ') {
1176		dprintf("Failed to parse TIMESTAMP from %s: %s\n", from, msg);
1177		return;
1178	}
1179	msg += RFC3164_DATELEN + 1;
1180
1181	if (!RemoteAddDate) {
1182		struct tm tm_now;
1183		time_t t_now;
1184		int year;
1185
1186		/*
1187		 * As the timestamp does not contain the year number,
1188		 * daylight saving time information, nor a time zone,
1189		 * attempt to infer it. Due to clock skews, the
1190		 * timestamp may even be part of the next year. Use the
1191		 * last year for which the timestamp is at most one week
1192		 * in the future.
1193		 *
1194		 * This loop can only run for at most three iterations
1195		 * before terminating.
1196		 */
1197		t_now = time(NULL);
1198		localtime_r(&t_now, &tm_now);
1199		for (year = tm_now.tm_year + 1;; --year) {
1200			assert(year >= tm_now.tm_year - 1);
1201			timestamp_remote.tm = tm_parsed;
1202			timestamp_remote.tm.tm_year = year;
1203			timestamp_remote.tm.tm_isdst = -1;
1204			timestamp_remote.usec = 0;
1205			if (mktime(&timestamp_remote.tm) <
1206			    t_now + 7 * 24 * 60 * 60)
1207				break;
1208		}
1209		timestamp = &timestamp_remote;
1210	} else
1211		timestamp = NULL;
1212
1213	/*
1214	 * A single space character MUST also follow the HOSTNAME field.
1215	 */
1216	msglen = strlen(msg);
1217	for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) {
1218		if (msg[i] == ' ') {
1219			if (RemoteHostname) {
1220				msg[i] = '\0';
1221				from = msg;
1222			}
1223			msg += i + 1;
1224			break;
1225		}
1226		/*
1227		 * Support non RFC compliant messages, without hostname.
1228		 */
1229		if (msg[i] == ':')
1230			break;
1231	}
1232	if (i == MIN(MAXHOSTNAMELEN, msglen)) {
1233		dprintf("Invalid HOSTNAME from %s: %s\n", from, msg);
1234		return;
1235	}
1236
1237	/* Remove the TAG, if present. */
1238	parsemsg_rfc3164_app_name_procid(&msg, &app_name, &procid);
1239	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
1240	logmsg(pri, timestamp, from, app_name, procid, NULL, NULL, line, 0);
1241}
1242
1243/*
1244 * Takes a raw input line, extracts PRI and determines whether the
1245 * message is formatted according to RFC 3164 or RFC 5424. Continues
1246 * parsing of addition fields in the message according to those
1247 * standards and prints the message on the appropriate log files.
1248 */
1249static void
1250parsemsg(const char *from, char *msg)
1251{
1252	char *q;
1253	long n;
1254	size_t i;
1255	int pri;
1256
1257	/* Parse PRI. */
1258	if (msg[0] != '<' || !isdigit(msg[1])) {
1259		dprintf("Invalid PRI from %s\n", from);
1260		return;
1261	}
1262	for (i = 2; i <= 4; i++) {
1263		if (msg[i] == '>')
1264			break;
1265		if (!isdigit(msg[i])) {
1266			dprintf("Invalid PRI header from %s\n", from);
1267			return;
1268		}
1269	}
1270	if (msg[i] != '>') {
1271		dprintf("Invalid PRI header from %s\n", from);
1272		return;
1273	}
1274	errno = 0;
1275	n = strtol(msg + 1, &q, 10);
1276	if (errno != 0 || *q != msg[i] || n < 0 || n >= INT_MAX) {
1277		dprintf("Invalid PRI %ld from %s: %s\n",
1278		    n, from, strerror(errno));
1279		return;
1280	}
1281	pri = n;
1282	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1283		pri = DEFUPRI;
1284
1285	/*
1286	 * Don't allow users to log kernel messages.
1287	 * NOTE: since LOG_KERN == 0 this will also match
1288	 *       messages with no facility specified.
1289	 */
1290	if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
1291		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
1292
1293	/* Parse VERSION. */
1294	msg += i + 1;
1295	if (msg[0] == '1' && msg[1] == ' ')
1296		parsemsg_rfc5424(from, pri, msg + 2);
1297	else
1298		parsemsg_rfc3164(from, pri, msg);
1299}
1300
1301/*
1302 * Read /dev/klog while data are available, split into lines.
1303 */
1304static int
1305socklist_recv_file(struct socklist *sl)
1306{
1307	char *p, *q, line[MAXLINE + 1];
1308	int len, i;
1309
1310	len = 0;
1311	for (;;) {
1312		i = read(sl->sl_socket, line + len, MAXLINE - 1 - len);
1313		if (i > 0) {
1314			line[i + len] = '\0';
1315		} else {
1316			if (i < 0 && errno != EINTR && errno != EAGAIN) {
1317				logerror("klog");
1318				close(sl->sl_socket);
1319				sl->sl_socket = -1;
1320			}
1321			break;
1322		}
1323
1324		for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
1325			*q = '\0';
1326			printsys(p);
1327		}
1328		len = strlen(p);
1329		if (len >= MAXLINE - 1) {
1330			printsys(p);
1331			len = 0;
1332		}
1333		if (len > 0)
1334			memmove(line, p, len + 1);
1335	}
1336	if (len > 0)
1337		printsys(line);
1338
1339	return (len);
1340}
1341
1342/*
1343 * Take a raw input line from /dev/klog, format similar to syslog().
1344 */
1345static void
1346printsys(char *msg)
1347{
1348	char *p, *q;
1349	long n;
1350	int flags, isprintf, pri;
1351
1352	flags = SYNC_FILE;	/* fsync after write */
1353	p = msg;
1354	pri = DEFSPRI;
1355	isprintf = 1;
1356	if (*p == '<') {
1357		errno = 0;
1358		n = strtol(p + 1, &q, 10);
1359		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
1360			p = q + 1;
1361			pri = n;
1362			isprintf = 0;
1363		}
1364	}
1365	/*
1366	 * Kernel printf's and LOG_CONSOLE messages have been displayed
1367	 * on the console already.
1368	 */
1369	if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE)
1370		flags |= IGN_CONS;
1371	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1372		pri = DEFSPRI;
1373	logmsg(pri, NULL, LocalHostName, "kernel", NULL, NULL, NULL, p, flags);
1374}
1375
1376static time_t	now;
1377
1378/*
1379 * Match a program or host name against a specification.
1380 * Return a non-0 value if the message must be ignored
1381 * based on the specification.
1382 */
1383static int
1384skip_message(const char *name, const char *spec, int checkcase)
1385{
1386	const char *s;
1387	char prev, next;
1388	int exclude = 0;
1389	/* Behaviour on explicit match */
1390
1391	if (spec == NULL)
1392		return 0;
1393	switch (*spec) {
1394	case '-':
1395		exclude = 1;
1396		/*FALLTHROUGH*/
1397	case '+':
1398		spec++;
1399		break;
1400	default:
1401		break;
1402	}
1403	if (checkcase)
1404		s = strstr (spec, name);
1405	else
1406		s = strcasestr (spec, name);
1407
1408	if (s != NULL) {
1409		prev = (s == spec ? ',' : *(s - 1));
1410		next = *(s + strlen (name));
1411
1412		if (prev == ',' && (next == '\0' || next == ','))
1413			/* Explicit match: skip iff the spec is an
1414			   exclusive one. */
1415			return exclude;
1416	}
1417
1418	/* No explicit match for this name: skip the message iff
1419	   the spec is an inclusive one. */
1420	return !exclude;
1421}
1422
1423/*
1424 * Logs a message to the appropriate log files, users, etc. based on the
1425 * priority. Log messages are always formatted according to RFC 3164,
1426 * even if they were in RFC 5424 format originally, The MSGID and
1427 * STRUCTURED-DATA fields are thus discarded for the time being.
1428 */
1429static void
1430logmsg(int pri, const struct logtime *timestamp, const char *hostname,
1431    const char *app_name, const char *procid, const char *msgid,
1432    const char *structured_data, const char *msg, int flags)
1433{
1434	struct timeval tv;
1435	struct logtime timestamp_now;
1436	struct filed *f;
1437	size_t savedlen;
1438	int fac, prilev;
1439	char saved[MAXSVLINE];
1440
1441	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
1442	    pri, flags, hostname, msg);
1443
1444	(void)gettimeofday(&tv, NULL);
1445	now = tv.tv_sec;
1446	if (timestamp == NULL) {
1447		localtime_r(&now, &timestamp_now.tm);
1448		timestamp_now.usec = tv.tv_usec;
1449		timestamp = &timestamp_now;
1450	}
1451
1452	/* extract facility and priority level */
1453	if (flags & MARK)
1454		fac = LOG_NFACILITIES;
1455	else
1456		fac = LOG_FAC(pri);
1457
1458	/* Check maximum facility number. */
1459	if (fac > LOG_NFACILITIES)
1460		return;
1461
1462	prilev = LOG_PRI(pri);
1463
1464	/* log the message to the particular outputs */
1465	if (!Initialized) {
1466		f = &consfile;
1467		/*
1468		 * Open in non-blocking mode to avoid hangs during open
1469		 * and close(waiting for the port to drain).
1470		 */
1471		f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
1472
1473		if (f->f_file >= 0) {
1474			f->f_lasttime = *timestamp;
1475			fprintlog_first(f, hostname, app_name, procid, msgid,
1476			    structured_data, msg, flags);
1477			close(f->f_file);
1478			f->f_file = -1;
1479		}
1480		return;
1481	}
1482
1483	/*
1484	 * Store all of the fields of the message, except the timestamp,
1485	 * in a single string. This string is used to detect duplicate
1486	 * messages.
1487	 */
1488	assert(hostname != NULL);
1489	assert(msg != NULL);
1490	savedlen = snprintf(saved, sizeof(saved),
1491	    "%d %s %s %s %s %s %s", pri, hostname,
1492	    app_name == NULL ? "-" : app_name, procid == NULL ? "-" : procid,
1493	    msgid == NULL ? "-" : msgid,
1494	    structured_data == NULL ? "-" : structured_data, msg);
1495
1496	STAILQ_FOREACH(f, &fhead, next) {
1497		/* skip messages that are incorrect priority */
1498		if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
1499		     ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
1500		     ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
1501		     )
1502		    || f->f_pmask[fac] == INTERNAL_NOPRI)
1503			continue;
1504
1505		/* skip messages with the incorrect hostname */
1506		if (skip_message(hostname, f->f_host, 0))
1507			continue;
1508
1509		/* skip messages with the incorrect program name */
1510		if (skip_message(app_name == NULL ? "" : app_name,
1511		    f->f_program, 1))
1512			continue;
1513
1514		/* skip message to console if it has already been printed */
1515		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
1516			continue;
1517
1518		/* don't output marks to recently written files */
1519		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
1520			continue;
1521
1522		/*
1523		 * suppress duplicate lines to this file
1524		 */
1525		if (no_compress - (f->f_type != F_PIPE) < 1 &&
1526		    (flags & MARK) == 0 && savedlen == f->f_prevlen &&
1527		    strcmp(saved, f->f_prevline) == 0) {
1528			f->f_lasttime = *timestamp;
1529			f->f_prevcount++;
1530			dprintf("msg repeated %d times, %ld sec of %d\n",
1531			    f->f_prevcount, (long)(now - f->f_time),
1532			    repeatinterval[f->f_repeatcount]);
1533			/*
1534			 * If domark would have logged this by now,
1535			 * flush it now (so we don't hold isolated messages),
1536			 * but back off so we'll flush less often
1537			 * in the future.
1538			 */
1539			if (now > REPEATTIME(f)) {
1540				fprintlog_successive(f, flags);
1541				BACKOFF(f);
1542			}
1543		} else {
1544			/* new line, save it */
1545			if (f->f_prevcount)
1546				fprintlog_successive(f, 0);
1547			f->f_repeatcount = 0;
1548			f->f_prevpri = pri;
1549			f->f_lasttime = *timestamp;
1550			static_assert(sizeof(f->f_prevline) == sizeof(saved),
1551			    "Space to store saved line incorrect");
1552			(void)strcpy(f->f_prevline, saved);
1553			f->f_prevlen = savedlen;
1554			fprintlog_first(f, hostname, app_name, procid, msgid,
1555			    structured_data, msg, flags);
1556		}
1557	}
1558}
1559
1560static void
1561dofsync(void)
1562{
1563	struct filed *f;
1564
1565	STAILQ_FOREACH(f, &fhead, next) {
1566		if ((f->f_type == F_FILE) &&
1567		    (f->f_flags & FFLAG_NEEDSYNC)) {
1568			f->f_flags &= ~FFLAG_NEEDSYNC;
1569			(void)fsync(f->f_file);
1570		}
1571	}
1572}
1573
1574/*
1575 * List of iovecs to which entries can be appended.
1576 * Used for constructing the message to be logged.
1577 */
1578struct iovlist {
1579	struct iovec	iov[TTYMSG_IOV_MAX];
1580	size_t		iovcnt;
1581	size_t		totalsize;
1582};
1583
1584static void
1585iovlist_init(struct iovlist *il)
1586{
1587
1588	il->iovcnt = 0;
1589	il->totalsize = 0;
1590}
1591
1592static void
1593iovlist_append(struct iovlist *il, const char *str)
1594{
1595	size_t size;
1596
1597	/* Discard components if we've run out of iovecs. */
1598	if (il->iovcnt < nitems(il->iov)) {
1599		size = strlen(str);
1600		il->iov[il->iovcnt++] = (struct iovec){
1601			.iov_base	= __DECONST(char *, str),
1602			.iov_len	= size,
1603		};
1604		il->totalsize += size;
1605	}
1606}
1607
1608static void
1609iovlist_truncate(struct iovlist *il, size_t size)
1610{
1611	struct iovec *last;
1612	size_t diff;
1613
1614	while (il->totalsize > size) {
1615		diff = il->totalsize - size;
1616		last = &il->iov[il->iovcnt - 1];
1617		if (diff >= last->iov_len) {
1618			/* Remove the last iovec entirely. */
1619			--il->iovcnt;
1620			il->totalsize -= last->iov_len;
1621		} else {
1622			/* Remove the last iovec partially. */
1623			last->iov_len -= diff;
1624			il->totalsize -= diff;
1625		}
1626	}
1627}
1628
1629static void
1630fprintlog_write(struct filed *f, struct iovlist *il, int flags)
1631{
1632	struct msghdr msghdr;
1633	struct addrinfo *r;
1634	struct socklist *sl;
1635	const char *msgret;
1636	ssize_t lsent;
1637
1638	switch (f->f_type) {
1639	case F_FORW:
1640		/* Truncate messages to RFC 5426 recommended size. */
1641		dprintf(" %s", f->fu_forw_hname);
1642		switch (f->fu_forw_addr->ai_addr->sa_family) {
1643#ifdef INET
1644		case AF_INET:
1645			dprintf(":%d\n",
1646			    ntohs(satosin(f->fu_forw_addr->ai_addr)->sin_port));
1647			iovlist_truncate(il, 480);
1648			break;
1649#endif
1650#ifdef INET6
1651		case AF_INET6:
1652			dprintf(":%d\n",
1653			    ntohs(satosin6(f->fu_forw_addr->ai_addr)->sin6_port));
1654			iovlist_truncate(il, 1180);
1655			break;
1656#endif
1657		default:
1658			dprintf("\n");
1659		}
1660
1661		lsent = 0;
1662		for (r = f->fu_forw_addr; r; r = r->ai_next) {
1663			memset(&msghdr, 0, sizeof(msghdr));
1664			msghdr.msg_name = r->ai_addr;
1665			msghdr.msg_namelen = r->ai_addrlen;
1666			msghdr.msg_iov = il->iov;
1667			msghdr.msg_iovlen = il->iovcnt;
1668			STAILQ_FOREACH(sl, &shead, next) {
1669				if (sl->sl_ss.ss_family == AF_LOCAL ||
1670				    sl->sl_ss.ss_family == AF_UNSPEC ||
1671				    sl->sl_socket < 0)
1672					continue;
1673				lsent = sendmsg(sl->sl_socket, &msghdr, 0);
1674				if (lsent == (ssize_t)il->totalsize)
1675					break;
1676			}
1677			if (lsent == (ssize_t)il->totalsize && !send_to_all)
1678				break;
1679		}
1680		dprintf("lsent/totalsize: %zd/%zu\n", lsent, il->totalsize);
1681		if (lsent != (ssize_t)il->totalsize) {
1682			int e = errno;
1683			logerror("sendto");
1684			errno = e;
1685			switch (errno) {
1686			case ENOBUFS:
1687			case ENETDOWN:
1688			case ENETUNREACH:
1689			case EHOSTUNREACH:
1690			case EHOSTDOWN:
1691			case EADDRNOTAVAIL:
1692				break;
1693			/* case EBADF: */
1694			/* case EACCES: */
1695			/* case ENOTSOCK: */
1696			/* case EFAULT: */
1697			/* case EMSGSIZE: */
1698			/* case EAGAIN: */
1699			/* case ENOBUFS: */
1700			/* case ECONNREFUSED: */
1701			default:
1702				dprintf("removing entry: errno=%d\n", e);
1703				f->f_type = F_UNUSED;
1704				break;
1705			}
1706		}
1707		break;
1708
1709	case F_FILE:
1710		dprintf(" %s\n", f->fu_fname);
1711		iovlist_append(il, "\n");
1712		if (writev(f->f_file, il->iov, il->iovcnt) < 0) {
1713			/*
1714			 * If writev(2) fails for potentially transient errors
1715			 * like the filesystem being full, ignore it.
1716			 * Otherwise remove this logfile from the list.
1717			 */
1718			if (errno != ENOSPC) {
1719				int e = errno;
1720				close_filed(f);
1721				errno = e;
1722				logerror(f->fu_fname);
1723			}
1724		} else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
1725			f->f_flags |= FFLAG_NEEDSYNC;
1726			needdofsync = 1;
1727		}
1728		break;
1729
1730	case F_PIPE:
1731		dprintf(" %s\n", f->fu_pipe_pname);
1732		iovlist_append(il, "\n");
1733		if (f->fu_pipe_pid == 0) {
1734			if ((f->f_file = p_open(f->fu_pipe_pname,
1735						&f->fu_pipe_pid)) < 0) {
1736				logerror(f->fu_pipe_pname);
1737				break;
1738			}
1739		}
1740		if (writev(f->f_file, il->iov, il->iovcnt) < 0) {
1741			int e = errno;
1742
1743			deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname);
1744			close_filed(f);
1745			errno = e;
1746			logerror(f->fu_pipe_pname);
1747		}
1748		break;
1749
1750	case F_CONSOLE:
1751		if (flags & IGN_CONS) {
1752			dprintf(" (ignored)\n");
1753			break;
1754		}
1755		/* FALLTHROUGH */
1756
1757	case F_TTY:
1758		dprintf(" %s%s\n", _PATH_DEV, f->fu_fname);
1759		iovlist_append(il, "\r\n");
1760		errno = 0;	/* ttymsg() only sometimes returns an errno */
1761		if ((msgret = ttymsg(il->iov, il->iovcnt, f->fu_fname, 10))) {
1762			f->f_type = F_UNUSED;
1763			logerror(msgret);
1764		}
1765		break;
1766
1767	case F_USERS:
1768	case F_WALL:
1769		dprintf("\n");
1770		iovlist_append(il, "\r\n");
1771		wallmsg(f, il->iov, il->iovcnt);
1772		break;
1773	}
1774}
1775
1776static void
1777fprintlog_rfc5424(struct filed *f, const char *hostname, const char *app_name,
1778    const char *procid, const char *msgid, const char *structured_data,
1779    const char *msg, int flags)
1780{
1781	struct iovlist il;
1782	suseconds_t usec;
1783	int i;
1784	char timebuf[33], priority_number[5];
1785
1786	iovlist_init(&il);
1787	if (f->f_type == F_WALL)
1788		iovlist_append(&il, "\r\n\aMessage from syslogd ...\r\n");
1789	iovlist_append(&il, "<");
1790	snprintf(priority_number, sizeof(priority_number), "%d", f->f_prevpri);
1791	iovlist_append(&il, priority_number);
1792	iovlist_append(&il, ">1 ");
1793	if (strftime(timebuf, sizeof(timebuf), "%FT%T.______%z",
1794	    &f->f_lasttime.tm) == sizeof(timebuf) - 2) {
1795		/* Add colon to the time zone offset, which %z doesn't do. */
1796		timebuf[32] = '\0';
1797		timebuf[31] = timebuf[30];
1798		timebuf[30] = timebuf[29];
1799		timebuf[29] = ':';
1800
1801		/* Overwrite space for microseconds with actual value. */
1802		usec = f->f_lasttime.usec;
1803		for (i = 25; i >= 20; --i) {
1804			timebuf[i] = usec % 10 + '0';
1805			usec /= 10;
1806		}
1807		iovlist_append(&il, timebuf);
1808	} else
1809		iovlist_append(&il, "-");
1810	iovlist_append(&il, " ");
1811	iovlist_append(&il, hostname);
1812	iovlist_append(&il, " ");
1813	iovlist_append(&il, app_name == NULL ? "-" : app_name);
1814	iovlist_append(&il, " ");
1815	iovlist_append(&il, procid == NULL ? "-" : procid);
1816	iovlist_append(&il, " ");
1817	iovlist_append(&il, msgid == NULL ? "-" : msgid);
1818	iovlist_append(&il, " ");
1819	iovlist_append(&il, structured_data == NULL ? "-" : structured_data);
1820	iovlist_append(&il, " ");
1821	iovlist_append(&il, msg);
1822
1823	fprintlog_write(f, &il, flags);
1824}
1825
1826static void
1827fprintlog_rfc3164(struct filed *f, const char *hostname, const char *app_name,
1828    const char *procid, const char *msg, int flags)
1829{
1830	struct iovlist il;
1831	const CODE *c;
1832	int facility, priority;
1833	char timebuf[RFC3164_DATELEN + 1], facility_number[5],
1834	    priority_number[5];
1835	bool facility_found, priority_found;
1836
1837	if (strftime(timebuf, sizeof(timebuf), RFC3164_DATEFMT,
1838	    &f->f_lasttime.tm) == 0)
1839		timebuf[0] = '\0';
1840
1841	iovlist_init(&il);
1842	switch (f->f_type) {
1843	case F_FORW:
1844		/* Message forwarded over the network. */
1845		iovlist_append(&il, "<");
1846		snprintf(priority_number, sizeof(priority_number), "%d",
1847		    f->f_prevpri);
1848		iovlist_append(&il, priority_number);
1849		iovlist_append(&il, ">");
1850		iovlist_append(&il, timebuf);
1851		if (strcasecmp(hostname, LocalHostName) != 0) {
1852			iovlist_append(&il, " Forwarded from ");
1853			iovlist_append(&il, hostname);
1854			iovlist_append(&il, ":");
1855		}
1856		iovlist_append(&il, " ");
1857		break;
1858
1859	case F_WALL:
1860		/* Message written to terminals. */
1861		iovlist_append(&il, "\r\n\aMessage from syslogd@");
1862		iovlist_append(&il, hostname);
1863		iovlist_append(&il, " at ");
1864		iovlist_append(&il, timebuf);
1865		iovlist_append(&il, " ...\r\n");
1866		break;
1867
1868	default:
1869		/* Message written to files. */
1870		iovlist_append(&il, timebuf);
1871		iovlist_append(&il, " ");
1872		iovlist_append(&il, hostname);
1873		iovlist_append(&il, " ");
1874
1875		if (LogFacPri) {
1876			iovlist_append(&il, "<");
1877
1878			facility = f->f_prevpri & LOG_FACMASK;
1879			facility_found = false;
1880			if (LogFacPri > 1) {
1881				for (c = facilitynames; c->c_name; c++) {
1882					if (c->c_val == facility) {
1883						iovlist_append(&il, c->c_name);
1884						facility_found = true;
1885						break;
1886					}
1887				}
1888			}
1889			if (!facility_found) {
1890				snprintf(facility_number,
1891				    sizeof(facility_number), "%d",
1892				    LOG_FAC(facility));
1893				iovlist_append(&il, facility_number);
1894			}
1895
1896			iovlist_append(&il, ".");
1897
1898			priority = LOG_PRI(f->f_prevpri);
1899			priority_found = false;
1900			if (LogFacPri > 1) {
1901				for (c = prioritynames; c->c_name; c++) {
1902					if (c->c_val == priority) {
1903						iovlist_append(&il, c->c_name);
1904						priority_found = true;
1905						break;
1906					}
1907				}
1908			}
1909			if (!priority_found) {
1910				snprintf(priority_number,
1911				    sizeof(priority_number), "%d", priority);
1912				iovlist_append(&il, priority_number);
1913			}
1914
1915			iovlist_append(&il, "> ");
1916		}
1917		break;
1918	}
1919
1920	/* Message body with application name and process ID prefixed. */
1921	if (app_name != NULL) {
1922		iovlist_append(&il, app_name);
1923		if (procid != NULL) {
1924			iovlist_append(&il, "[");
1925			iovlist_append(&il, procid);
1926			iovlist_append(&il, "]");
1927		}
1928		iovlist_append(&il, ": ");
1929	}
1930	iovlist_append(&il, msg);
1931
1932	fprintlog_write(f, &il, flags);
1933}
1934
1935static void
1936fprintlog_first(struct filed *f, const char *hostname, const char *app_name,
1937    const char *procid, const char *msgid __unused,
1938    const char *structured_data __unused, const char *msg, int flags)
1939{
1940
1941	dprintf("Logging to %s", TypeNames[f->f_type]);
1942	f->f_time = now;
1943	f->f_prevcount = 0;
1944	if (f->f_type == F_UNUSED) {
1945		dprintf("\n");
1946		return;
1947	}
1948
1949	if (RFC3164OutputFormat)
1950		fprintlog_rfc3164(f, hostname, app_name, procid, msg, flags);
1951	else
1952		fprintlog_rfc5424(f, hostname, app_name, procid, msgid,
1953		    structured_data, msg, flags);
1954}
1955
1956/*
1957 * Prints a message to a log file that the previously logged message was
1958 * received multiple times.
1959 */
1960static void
1961fprintlog_successive(struct filed *f, int flags)
1962{
1963	char msg[100];
1964
1965	assert(f->f_prevcount > 0);
1966	snprintf(msg, sizeof(msg), "last message repeated %d times",
1967	    f->f_prevcount);
1968	fprintlog_first(f, LocalHostName, "syslogd", NULL, NULL, NULL, msg,
1969	    flags);
1970}
1971
1972/*
1973 *  WALLMSG -- Write a message to the world at large
1974 *
1975 *	Write the specified message to either the entire
1976 *	world, or a list of approved users.
1977 */
1978static void
1979wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
1980{
1981	static int reenter;			/* avoid calling ourselves */
1982	struct utmpx *ut;
1983	int i;
1984	const char *p;
1985
1986	if (reenter++)
1987		return;
1988	setutxent();
1989	/* NOSTRICT */
1990	while ((ut = getutxent()) != NULL) {
1991		if (ut->ut_type != USER_PROCESS)
1992			continue;
1993		if (f->f_type == F_WALL) {
1994			if ((p = ttymsg(iov, iovlen, ut->ut_line,
1995			    TTYMSGTIME)) != NULL) {
1996				errno = 0;	/* already in msg */
1997				logerror(p);
1998			}
1999			continue;
2000		}
2001		/* should we send the message to this user? */
2002		for (i = 0; i < MAXUNAMES; i++) {
2003			if (!f->fu_uname[i][0])
2004				break;
2005			if (!strcmp(f->fu_uname[i], ut->ut_user)) {
2006				if ((p = ttymsg_check(iov, iovlen, ut->ut_line,
2007				    TTYMSGTIME)) != NULL) {
2008					errno = 0;	/* already in msg */
2009					logerror(p);
2010				}
2011				break;
2012			}
2013		}
2014	}
2015	endutxent();
2016	reenter = 0;
2017}
2018
2019/*
2020 * Wrapper routine for ttymsg() that checks the terminal for messages enabled.
2021 */
2022static const char *
2023ttymsg_check(struct iovec *iov, int iovcnt, char *line, int tmout)
2024{
2025	static char device[1024];
2026	static char errbuf[1024];
2027	struct stat sb;
2028
2029	(void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
2030
2031	if (stat(device, &sb) < 0) {
2032		(void) snprintf(errbuf, sizeof(errbuf),
2033		    "%s: %s", device, strerror(errno));
2034		return (errbuf);
2035	}
2036	if ((sb.st_mode & S_IWGRP) == 0)
2037		/* Messages disabled. */
2038		return (NULL);
2039	return ttymsg(iov, iovcnt, line, tmout);
2040}
2041
2042static void
2043reapchild(int signo __unused)
2044{
2045	int status;
2046	pid_t pid;
2047	struct filed *f;
2048
2049	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
2050		/* First, look if it's a process from the dead queue. */
2051		if (deadq_removebypid(pid))
2052			continue;
2053
2054		/* Now, look in list of active processes. */
2055		STAILQ_FOREACH(f, &fhead, next) {
2056			if (f->f_type == F_PIPE &&
2057			    f->fu_pipe_pid == pid) {
2058				close_filed(f);
2059				log_deadchild(pid, status, f->fu_pipe_pname);
2060				break;
2061			}
2062		}
2063	}
2064	WantReapchild = 0;
2065}
2066
2067/*
2068 * Return a printable representation of a host address.
2069 */
2070static const char *
2071cvthname(struct sockaddr *f)
2072{
2073	int error, hl;
2074	static char hname[NI_MAXHOST], ip[NI_MAXHOST];
2075
2076	dprintf("cvthname(%d) len = %d\n", f->sa_family, f->sa_len);
2077	error = getnameinfo(f, f->sa_len, ip, sizeof(ip), NULL, 0,
2078		    NI_NUMERICHOST);
2079	if (error) {
2080		dprintf("Malformed from address %s\n", gai_strerror(error));
2081		return ("???");
2082	}
2083	dprintf("cvthname(%s)\n", ip);
2084
2085	if (!resolve)
2086		return (ip);
2087
2088	error = getnameinfo(f, f->sa_len, hname, sizeof(hname),
2089		    NULL, 0, NI_NAMEREQD);
2090	if (error) {
2091		dprintf("Host name for your address (%s) unknown\n", ip);
2092		return (ip);
2093	}
2094	hl = strlen(hname);
2095	if (hl > 0 && hname[hl-1] == '.')
2096		hname[--hl] = '\0';
2097	trimdomain(hname, hl);
2098	return (hname);
2099}
2100
2101static void
2102dodie(int signo)
2103{
2104
2105	WantDie = signo;
2106}
2107
2108static void
2109domark(int signo __unused)
2110{
2111
2112	MarkSet = 1;
2113}
2114
2115/*
2116 * Print syslogd errors some place.
2117 */
2118static void
2119logerror(const char *msg)
2120{
2121	char buf[512];
2122	static int recursed = 0;
2123
2124	/* If there's an error while trying to log an error, give up. */
2125	if (recursed)
2126		return;
2127	recursed++;
2128	if (errno != 0) {
2129		(void)snprintf(buf, sizeof(buf), "%s: %s", msg,
2130		    strerror(errno));
2131		msg = buf;
2132	}
2133	errno = 0;
2134	dprintf("%s\n", buf);
2135	logmsg(LOG_SYSLOG|LOG_ERR, NULL, LocalHostName, "syslogd", NULL, NULL,
2136	    NULL, msg, 0);
2137	recursed--;
2138}
2139
2140static void
2141die(int signo)
2142{
2143	struct filed *f;
2144	struct socklist *sl;
2145	char buf[100];
2146
2147	STAILQ_FOREACH(f, &fhead, next) {
2148		/* flush any pending output */
2149		if (f->f_prevcount)
2150			fprintlog_successive(f, 0);
2151		if (f->f_type == F_PIPE && f->fu_pipe_pid > 0)
2152			close_filed(f);
2153	}
2154	if (signo) {
2155		dprintf("syslogd: exiting on signal %d\n", signo);
2156		(void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo);
2157		errno = 0;
2158		logerror(buf);
2159	}
2160	STAILQ_FOREACH(sl, &shead, next) {
2161		if (sl->sl_ss.ss_family == AF_LOCAL)
2162			unlink(sl->sl_peer->pe_name);
2163	}
2164	pidfile_remove(pfh);
2165
2166	exit(1);
2167}
2168
2169static int
2170configfiles(const struct dirent *dp)
2171{
2172	const char *p;
2173	size_t ext_len;
2174
2175	if (dp->d_name[0] == '.')
2176		return (0);
2177
2178	ext_len = sizeof(include_ext) -1;
2179
2180	if (dp->d_namlen <= ext_len)
2181		return (0);
2182
2183	p = &dp->d_name[dp->d_namlen - ext_len];
2184	if (strcmp(p, include_ext) != 0)
2185		return (0);
2186
2187	return (1);
2188}
2189
2190static void
2191readconfigfile(FILE *cf, int allow_includes)
2192{
2193	FILE *cf2;
2194	struct filed *f;
2195	struct dirent **ent;
2196	char cline[LINE_MAX];
2197	char host[MAXHOSTNAMELEN];
2198	char prog[LINE_MAX];
2199	char file[MAXPATHLEN];
2200	char *p, *tmp;
2201	int i, nents;
2202	size_t include_len;
2203
2204	/*
2205	 *  Foreach line in the conf table, open that file.
2206	 */
2207	include_len = sizeof(include_str) -1;
2208	(void)strlcpy(host, "*", sizeof(host));
2209	(void)strlcpy(prog, "*", sizeof(prog));
2210	while (fgets(cline, sizeof(cline), cf) != NULL) {
2211		/*
2212		 * check for end-of-section, comments, strip off trailing
2213		 * spaces and newline character. #!prog is treated specially:
2214		 * following lines apply only to that program.
2215		 */
2216		for (p = cline; isspace(*p); ++p)
2217			continue;
2218		if (*p == 0)
2219			continue;
2220		if (allow_includes &&
2221		    strncmp(p, include_str, include_len) == 0 &&
2222		    isspace(p[include_len])) {
2223			p += include_len;
2224			while (isspace(*p))
2225				p++;
2226			tmp = p;
2227			while (*tmp != '\0' && !isspace(*tmp))
2228				tmp++;
2229			*tmp = '\0';
2230			dprintf("Trying to include files in '%s'\n", p);
2231			nents = scandir(p, &ent, configfiles, alphasort);
2232			if (nents == -1) {
2233				dprintf("Unable to open '%s': %s\n", p,
2234				    strerror(errno));
2235				continue;
2236			}
2237			for (i = 0; i < nents; i++) {
2238				if (snprintf(file, sizeof(file), "%s/%s", p,
2239				    ent[i]->d_name) >= (int)sizeof(file)) {
2240					dprintf("ignoring path too long: "
2241					    "'%s/%s'\n", p, ent[i]->d_name);
2242					free(ent[i]);
2243					continue;
2244				}
2245				free(ent[i]);
2246				cf2 = fopen(file, "r");
2247				if (cf2 == NULL)
2248					continue;
2249				dprintf("reading %s\n", file);
2250				readconfigfile(cf2, 0);
2251				fclose(cf2);
2252			}
2253			free(ent);
2254			continue;
2255		}
2256		if (*p == '#') {
2257			p++;
2258			if (*p != '!' && *p != '+' && *p != '-')
2259				continue;
2260		}
2261		if (*p == '+' || *p == '-') {
2262			host[0] = *p++;
2263			while (isspace(*p))
2264				p++;
2265			if ((!*p) || (*p == '*')) {
2266				(void)strlcpy(host, "*", sizeof(host));
2267				continue;
2268			}
2269			if (*p == '@')
2270				p = LocalHostName;
2271			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
2272				if (!isalnum(*p) && *p != '.' && *p != '-'
2273				    && *p != ',' && *p != ':' && *p != '%')
2274					break;
2275				host[i] = *p++;
2276			}
2277			host[i] = '\0';
2278			continue;
2279		}
2280		if (*p == '!') {
2281			p++;
2282			while (isspace(*p)) p++;
2283			if ((!*p) || (*p == '*')) {
2284				(void)strlcpy(prog, "*", sizeof(prog));
2285				continue;
2286			}
2287			for (i = 0; i < LINE_MAX - 1; i++) {
2288				if (!isprint(p[i]) || isspace(p[i]))
2289					break;
2290				prog[i] = p[i];
2291			}
2292			prog[i] = 0;
2293			continue;
2294		}
2295		for (p = cline + 1; *p != '\0'; p++) {
2296			if (*p != '#')
2297				continue;
2298			if (*(p - 1) == '\\') {
2299				strcpy(p - 1, p);
2300				p--;
2301				continue;
2302			}
2303			*p = '\0';
2304			break;
2305		}
2306		for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
2307			cline[i] = '\0';
2308		f = cfline(cline, prog, host);
2309		if (f != NULL)
2310			addfile(f);
2311		free(f);
2312	}
2313}
2314
2315static void
2316sighandler(int signo)
2317{
2318
2319	/* Send an wake-up signal to the select() loop. */
2320	write(sigpipe[1], &signo, sizeof(signo));
2321}
2322
2323/*
2324 *  INIT -- Initialize syslogd from configuration table
2325 */
2326static void
2327init(int signo)
2328{
2329	int i;
2330	FILE *cf;
2331	struct filed *f;
2332	char *p;
2333	char oldLocalHostName[MAXHOSTNAMELEN];
2334	char hostMsg[2*MAXHOSTNAMELEN+40];
2335	char bootfileMsg[LINE_MAX];
2336
2337	dprintf("init\n");
2338	WantInitialize = 0;
2339
2340	/*
2341	 * Load hostname (may have changed).
2342	 */
2343	if (signo != 0)
2344		(void)strlcpy(oldLocalHostName, LocalHostName,
2345		    sizeof(oldLocalHostName));
2346	if (gethostname(LocalHostName, sizeof(LocalHostName)))
2347		err(EX_OSERR, "gethostname() failed");
2348	if ((p = strchr(LocalHostName, '.')) != NULL) {
2349		/* RFC 5424 prefers logging FQDNs. */
2350		if (RFC3164OutputFormat)
2351			*p = '\0';
2352		LocalDomain = p + 1;
2353	} else {
2354		LocalDomain = "";
2355	}
2356
2357	/*
2358	 * Load / reload timezone data (in case it changed).
2359	 *
2360	 * Just calling tzset() again does not work, the timezone code
2361	 * caches the result.  However, by setting the TZ variable, one
2362	 * can defeat the caching and have the timezone code really
2363	 * reload the timezone data.  Respect any initial setting of
2364	 * TZ, in case the system is configured specially.
2365	 */
2366	dprintf("loading timezone data via tzset()\n");
2367	if (getenv("TZ")) {
2368		tzset();
2369	} else {
2370		setenv("TZ", ":/etc/localtime", 1);
2371		tzset();
2372		unsetenv("TZ");
2373	}
2374
2375	/*
2376	 *  Close all open log files.
2377	 */
2378	Initialized = 0;
2379	STAILQ_FOREACH(f, &fhead, next) {
2380		/* flush any pending output */
2381		if (f->f_prevcount)
2382			fprintlog_successive(f, 0);
2383
2384		switch (f->f_type) {
2385		case F_FILE:
2386		case F_FORW:
2387		case F_CONSOLE:
2388		case F_TTY:
2389			close_filed(f);
2390			break;
2391		case F_PIPE:
2392			deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname);
2393			close_filed(f);
2394			break;
2395		}
2396	}
2397	while(!STAILQ_EMPTY(&fhead)) {
2398		f = STAILQ_FIRST(&fhead);
2399		STAILQ_REMOVE_HEAD(&fhead, next);
2400		free(f->f_program);
2401		free(f->f_host);
2402		free(f);
2403	}
2404
2405	/* open the configuration file */
2406	if ((cf = fopen(ConfFile, "r")) == NULL) {
2407		dprintf("cannot open %s\n", ConfFile);
2408		f = cfline("*.ERR\t/dev/console", "*", "*");
2409		if (f != NULL)
2410			addfile(f);
2411		free(f);
2412		f = cfline("*.PANIC\t*", "*", "*");
2413		if (f != NULL)
2414			addfile(f);
2415		free(f);
2416		Initialized = 1;
2417
2418		return;
2419	}
2420
2421	readconfigfile(cf, 1);
2422
2423	/* close the configuration file */
2424	(void)fclose(cf);
2425
2426	Initialized = 1;
2427
2428	if (Debug) {
2429		int port;
2430		STAILQ_FOREACH(f, &fhead, next) {
2431			for (i = 0; i <= LOG_NFACILITIES; i++)
2432				if (f->f_pmask[i] == INTERNAL_NOPRI)
2433					printf("X ");
2434				else
2435					printf("%d ", f->f_pmask[i]);
2436			printf("%s: ", TypeNames[f->f_type]);
2437			switch (f->f_type) {
2438			case F_FILE:
2439				printf("%s", f->fu_fname);
2440				break;
2441
2442			case F_CONSOLE:
2443			case F_TTY:
2444				printf("%s%s", _PATH_DEV, f->fu_fname);
2445				break;
2446
2447			case F_FORW:
2448				switch (f->fu_forw_addr->ai_addr->sa_family) {
2449#ifdef INET
2450				case AF_INET:
2451					port = ntohs(satosin(f->fu_forw_addr->ai_addr)->sin_port);
2452					break;
2453#endif
2454#ifdef INET6
2455				case AF_INET6:
2456					port = ntohs(satosin6(f->fu_forw_addr->ai_addr)->sin6_port);
2457					break;
2458#endif
2459				default:
2460					port = 0;
2461				}
2462				if (port != 514) {
2463					printf("%s:%d",
2464						f->fu_forw_hname, port);
2465				} else {
2466					printf("%s", f->fu_forw_hname);
2467				}
2468				break;
2469
2470			case F_PIPE:
2471				printf("%s", f->fu_pipe_pname);
2472				break;
2473
2474			case F_USERS:
2475				for (i = 0; i < MAXUNAMES && *f->fu_uname[i]; i++)
2476					printf("%s, ", f->fu_uname[i]);
2477				break;
2478			}
2479			if (f->f_program)
2480				printf(" (%s)", f->f_program);
2481			printf("\n");
2482		}
2483	}
2484
2485	logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd", NULL,
2486	    NULL, NULL, "restart", 0);
2487	dprintf("syslogd: restarted\n");
2488	/*
2489	 * Log a change in hostname, but only on a restart.
2490	 */
2491	if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) {
2492		(void)snprintf(hostMsg, sizeof(hostMsg),
2493		    "hostname changed, \"%s\" to \"%s\"",
2494		    oldLocalHostName, LocalHostName);
2495		logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd",
2496		    NULL, NULL, NULL, hostMsg, 0);
2497		dprintf("%s\n", hostMsg);
2498	}
2499	/*
2500	 * Log the kernel boot file if we aren't going to use it as
2501	 * the prefix, and if this is *not* a restart.
2502	 */
2503	if (signo == 0 && !use_bootfile) {
2504		(void)snprintf(bootfileMsg, sizeof(bootfileMsg),
2505		    "kernel boot file is %s", bootfile);
2506		logmsg(LOG_KERN | LOG_INFO, NULL, LocalHostName, "syslogd",
2507		    NULL, NULL, NULL, bootfileMsg, 0);
2508		dprintf("%s\n", bootfileMsg);
2509	}
2510}
2511
2512/*
2513 * Crack a configuration file line
2514 */
2515static struct filed *
2516cfline(const char *line, const char *prog, const char *host)
2517{
2518	struct filed *f;
2519	struct addrinfo hints, *res;
2520	int error, i, pri, syncfile;
2521	const char *p, *q;
2522	char *bp;
2523	char buf[MAXLINE], ebuf[100];
2524
2525	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
2526
2527	f = calloc(1, sizeof(*f));
2528	if (f == NULL) {
2529		logerror("malloc");
2530		exit(1);
2531	}
2532	errno = 0;	/* keep strerror() stuff out of logerror messages */
2533
2534	for (i = 0; i <= LOG_NFACILITIES; i++)
2535		f->f_pmask[i] = INTERNAL_NOPRI;
2536
2537	/* save hostname if any */
2538	if (host && *host == '*')
2539		host = NULL;
2540	if (host) {
2541		int hl;
2542
2543		f->f_host = strdup(host);
2544		if (f->f_host == NULL) {
2545			logerror("strdup");
2546			exit(1);
2547		}
2548		hl = strlen(f->f_host);
2549		if (hl > 0 && f->f_host[hl-1] == '.')
2550			f->f_host[--hl] = '\0';
2551		trimdomain(f->f_host, hl);
2552	}
2553
2554	/* save program name if any */
2555	if (prog && *prog == '*')
2556		prog = NULL;
2557	if (prog) {
2558		f->f_program = strdup(prog);
2559		if (f->f_program == NULL) {
2560			logerror("strdup");
2561			exit(1);
2562		}
2563	}
2564
2565	/* scan through the list of selectors */
2566	for (p = line; *p && *p != '\t' && *p != ' ';) {
2567		int pri_done;
2568		int pri_cmp;
2569		int pri_invert;
2570
2571		/* find the end of this facility name list */
2572		for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
2573			continue;
2574
2575		/* get the priority comparison */
2576		pri_cmp = 0;
2577		pri_done = 0;
2578		pri_invert = 0;
2579		if (*q == '!') {
2580			pri_invert = 1;
2581			q++;
2582		}
2583		while (!pri_done) {
2584			switch (*q) {
2585			case '<':
2586				pri_cmp |= PRI_LT;
2587				q++;
2588				break;
2589			case '=':
2590				pri_cmp |= PRI_EQ;
2591				q++;
2592				break;
2593			case '>':
2594				pri_cmp |= PRI_GT;
2595				q++;
2596				break;
2597			default:
2598				pri_done++;
2599				break;
2600			}
2601		}
2602
2603		/* collect priority name */
2604		for (bp = buf; *q && !strchr("\t,; ", *q); )
2605			*bp++ = *q++;
2606		*bp = '\0';
2607
2608		/* skip cruft */
2609		while (strchr(",;", *q))
2610			q++;
2611
2612		/* decode priority name */
2613		if (*buf == '*') {
2614			pri = LOG_PRIMASK;
2615			pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
2616		} else {
2617			/* Ignore trailing spaces. */
2618			for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--)
2619				buf[i] = '\0';
2620
2621			pri = decode(buf, prioritynames);
2622			if (pri < 0) {
2623				errno = 0;
2624				(void)snprintf(ebuf, sizeof ebuf,
2625				    "unknown priority name \"%s\"", buf);
2626				logerror(ebuf);
2627				free(f);
2628				return (NULL);
2629			}
2630		}
2631		if (!pri_cmp)
2632			pri_cmp = (UniquePriority)
2633				  ? (PRI_EQ)
2634				  : (PRI_EQ | PRI_GT)
2635				  ;
2636		if (pri_invert)
2637			pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
2638
2639		/* scan facilities */
2640		while (*p && !strchr("\t.; ", *p)) {
2641			for (bp = buf; *p && !strchr("\t,;. ", *p); )
2642				*bp++ = *p++;
2643			*bp = '\0';
2644
2645			if (*buf == '*') {
2646				for (i = 0; i < LOG_NFACILITIES; i++) {
2647					f->f_pmask[i] = pri;
2648					f->f_pcmp[i] = pri_cmp;
2649				}
2650			} else {
2651				i = decode(buf, facilitynames);
2652				if (i < 0) {
2653					errno = 0;
2654					(void)snprintf(ebuf, sizeof ebuf,
2655					    "unknown facility name \"%s\"",
2656					    buf);
2657					logerror(ebuf);
2658					free(f);
2659					return (NULL);
2660				}
2661				f->f_pmask[i >> 3] = pri;
2662				f->f_pcmp[i >> 3] = pri_cmp;
2663			}
2664			while (*p == ',' || *p == ' ')
2665				p++;
2666		}
2667
2668		p = q;
2669	}
2670
2671	/* skip to action part */
2672	while (*p == '\t' || *p == ' ')
2673		p++;
2674
2675	if (*p == '-') {
2676		syncfile = 0;
2677		p++;
2678	} else
2679		syncfile = 1;
2680
2681	switch (*p) {
2682	case '@':
2683		{
2684			char *tp;
2685			char endkey = ':';
2686			/*
2687			 * scan forward to see if there is a port defined.
2688			 * so we can't use strlcpy..
2689			 */
2690			i = sizeof(f->fu_forw_hname);
2691			tp = f->fu_forw_hname;
2692			p++;
2693
2694			/*
2695			 * an ipv6 address should start with a '[' in that case
2696			 * we should scan for a ']'
2697			 */
2698			if (*p == '[') {
2699				p++;
2700				endkey = ']';
2701			}
2702			while (*p && (*p != endkey) && (i-- > 0)) {
2703				*tp++ = *p++;
2704			}
2705			if (endkey == ']' && *p == endkey)
2706				p++;
2707			*tp = '\0';
2708		}
2709		/* See if we copied a domain and have a port */
2710		if (*p == ':')
2711			p++;
2712		else
2713			p = NULL;
2714
2715		hints = (struct addrinfo){
2716			.ai_family = family,
2717			.ai_socktype = SOCK_DGRAM
2718		};
2719		error = getaddrinfo(f->fu_forw_hname,
2720				p ? p : "syslog", &hints, &res);
2721		if (error) {
2722			logerror(gai_strerror(error));
2723			break;
2724		}
2725		f->fu_forw_addr = res;
2726		f->f_type = F_FORW;
2727		break;
2728
2729	case '/':
2730		if ((f->f_file = open(p, logflags, 0600)) < 0) {
2731			f->f_type = F_UNUSED;
2732			logerror(p);
2733			break;
2734		}
2735		if (syncfile)
2736			f->f_flags |= FFLAG_SYNC;
2737		if (isatty(f->f_file)) {
2738			if (strcmp(p, ctty) == 0)
2739				f->f_type = F_CONSOLE;
2740			else
2741				f->f_type = F_TTY;
2742			(void)strlcpy(f->fu_fname, p + sizeof(_PATH_DEV) - 1,
2743			    sizeof(f->fu_fname));
2744		} else {
2745			(void)strlcpy(f->fu_fname, p, sizeof(f->fu_fname));
2746			f->f_type = F_FILE;
2747		}
2748		break;
2749
2750	case '|':
2751		f->fu_pipe_pid = 0;
2752		(void)strlcpy(f->fu_pipe_pname, p + 1,
2753		    sizeof(f->fu_pipe_pname));
2754		f->f_type = F_PIPE;
2755		break;
2756
2757	case '*':
2758		f->f_type = F_WALL;
2759		break;
2760
2761	default:
2762		for (i = 0; i < MAXUNAMES && *p; i++) {
2763			for (q = p; *q && *q != ','; )
2764				q++;
2765			(void)strncpy(f->fu_uname[i], p, MAXLOGNAME - 1);
2766			if ((q - p) >= MAXLOGNAME)
2767				f->fu_uname[i][MAXLOGNAME - 1] = '\0';
2768			else
2769				f->fu_uname[i][q - p] = '\0';
2770			while (*q == ',' || *q == ' ')
2771				q++;
2772			p = q;
2773		}
2774		f->f_type = F_USERS;
2775		break;
2776	}
2777	return (f);
2778}
2779
2780
2781/*
2782 *  Decode a symbolic name to a numeric value
2783 */
2784static int
2785decode(const char *name, const CODE *codetab)
2786{
2787	const CODE *c;
2788	char *p, buf[40];
2789
2790	if (isdigit(*name))
2791		return (atoi(name));
2792
2793	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
2794		if (isupper(*name))
2795			*p = tolower(*name);
2796		else
2797			*p = *name;
2798	}
2799	*p = '\0';
2800	for (c = codetab; c->c_name; c++)
2801		if (!strcmp(buf, c->c_name))
2802			return (c->c_val);
2803
2804	return (-1);
2805}
2806
2807static void
2808markit(void)
2809{
2810	struct filed *f;
2811	struct deadq_entry *dq, *dq0;
2812
2813	now = time((time_t *)NULL);
2814	MarkSeq += TIMERINTVL;
2815	if (MarkSeq >= MarkInterval) {
2816		logmsg(LOG_INFO, NULL, LocalHostName, NULL, NULL, NULL, NULL,
2817		    "-- MARK --", MARK);
2818		MarkSeq = 0;
2819	}
2820
2821	STAILQ_FOREACH(f, &fhead, next) {
2822		if (f->f_prevcount && now >= REPEATTIME(f)) {
2823			dprintf("flush %s: repeated %d times, %d sec.\n",
2824			    TypeNames[f->f_type], f->f_prevcount,
2825			    repeatinterval[f->f_repeatcount]);
2826			fprintlog_successive(f, 0);
2827			BACKOFF(f);
2828		}
2829	}
2830
2831	/* Walk the dead queue, and see if we should signal somebody. */
2832	TAILQ_FOREACH_SAFE(dq, &deadq_head, dq_entries, dq0) {
2833		switch (dq->dq_timeout) {
2834		case 0:
2835			/* Already signalled once, try harder now. */
2836			if (kill(dq->dq_pid, SIGKILL) != 0)
2837				(void)deadq_remove(dq);
2838			break;
2839
2840		case 1:
2841			/*
2842			 * Timed out on dead queue, send terminate
2843			 * signal.  Note that we leave the removal
2844			 * from the dead queue to reapchild(), which
2845			 * will also log the event (unless the process
2846			 * didn't even really exist, in case we simply
2847			 * drop it from the dead queue).
2848			 */
2849			if (kill(dq->dq_pid, SIGTERM) != 0)
2850				(void)deadq_remove(dq);
2851			else
2852				dq->dq_timeout--;
2853			break;
2854		default:
2855			dq->dq_timeout--;
2856		}
2857	}
2858	MarkSet = 0;
2859	(void)alarm(TIMERINTVL);
2860}
2861
2862/*
2863 * fork off and become a daemon, but wait for the child to come online
2864 * before returning to the parent, or we get disk thrashing at boot etc.
2865 * Set a timer so we don't hang forever if it wedges.
2866 */
2867static int
2868waitdaemon(int maxwait)
2869{
2870	int fd;
2871	int status;
2872	pid_t pid, childpid;
2873
2874	switch (childpid = fork()) {
2875	case -1:
2876		return (-1);
2877	case 0:
2878		break;
2879	default:
2880		signal(SIGALRM, timedout);
2881		alarm(maxwait);
2882		while ((pid = wait3(&status, 0, NULL)) != -1) {
2883			if (WIFEXITED(status))
2884				errx(1, "child pid %d exited with return code %d",
2885					pid, WEXITSTATUS(status));
2886			if (WIFSIGNALED(status))
2887				errx(1, "child pid %d exited on signal %d%s",
2888					pid, WTERMSIG(status),
2889					WCOREDUMP(status) ? " (core dumped)" :
2890					"");
2891			if (pid == childpid)	/* it's gone... */
2892				break;
2893		}
2894		exit(0);
2895	}
2896
2897	if (setsid() == -1)
2898		return (-1);
2899
2900	(void)chdir("/");
2901	if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
2902		(void)dup2(fd, STDIN_FILENO);
2903		(void)dup2(fd, STDOUT_FILENO);
2904		(void)dup2(fd, STDERR_FILENO);
2905		if (fd > STDERR_FILENO)
2906			(void)close(fd);
2907	}
2908	return (getppid());
2909}
2910
2911/*
2912 * We get a SIGALRM from the child when it's running and finished doing it's
2913 * fsync()'s or O_SYNC writes for all the boot messages.
2914 *
2915 * We also get a signal from the kernel if the timer expires, so check to
2916 * see what happened.
2917 */
2918static void
2919timedout(int sig __unused)
2920{
2921	int left;
2922	left = alarm(0);
2923	signal(SIGALRM, SIG_DFL);
2924	if (left == 0)
2925		errx(1, "timed out waiting for child");
2926	else
2927		_exit(0);
2928}
2929
2930/*
2931 * Add `s' to the list of allowable peer addresses to accept messages
2932 * from.
2933 *
2934 * `s' is a string in the form:
2935 *
2936 *    [*]domainname[:{servicename|portnumber|*}]
2937 *
2938 * or
2939 *
2940 *    netaddr/maskbits[:{servicename|portnumber|*}]
2941 *
2942 * Returns -1 on error, 0 if the argument was valid.
2943 */
2944static int
2945allowaddr(char *s)
2946{
2947#if defined(INET) || defined(INET6)
2948	char *cp1, *cp2;
2949	struct allowedpeer *ap;
2950	struct servent *se;
2951	int masklen = -1;
2952	struct addrinfo hints, *res = NULL;
2953#ifdef INET
2954	in_addr_t *addrp, *maskp;
2955#endif
2956#ifdef INET6
2957	uint32_t *addr6p, *mask6p;
2958#endif
2959	char ip[NI_MAXHOST];
2960
2961	ap = calloc(1, sizeof(*ap));
2962	if (ap == NULL)
2963		err(1, "malloc failed");
2964
2965#ifdef INET6
2966	if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
2967#endif
2968		cp1 = s;
2969	if ((cp1 = strrchr(cp1, ':'))) {
2970		/* service/port provided */
2971		*cp1++ = '\0';
2972		if (strlen(cp1) == 1 && *cp1 == '*')
2973			/* any port allowed */
2974			ap->port = 0;
2975		else if ((se = getservbyname(cp1, "udp"))) {
2976			ap->port = ntohs(se->s_port);
2977		} else {
2978			ap->port = strtol(cp1, &cp2, 0);
2979			/* port not numeric */
2980			if (*cp2 != '\0')
2981				goto err;
2982		}
2983	} else {
2984		if ((se = getservbyname("syslog", "udp")))
2985			ap->port = ntohs(se->s_port);
2986		else
2987			/* sanity, should not happen */
2988			ap->port = 514;
2989	}
2990
2991	if ((cp1 = strchr(s, '/')) != NULL &&
2992	    strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
2993		*cp1 = '\0';
2994		if ((masklen = atoi(cp1 + 1)) < 0)
2995			goto err;
2996	}
2997#ifdef INET6
2998	if (*s == '[') {
2999		cp2 = s + strlen(s) - 1;
3000		if (*cp2 == ']') {
3001			++s;
3002			*cp2 = '\0';
3003		} else {
3004			cp2 = NULL;
3005		}
3006	} else {
3007		cp2 = NULL;
3008	}
3009#endif
3010	hints = (struct addrinfo){
3011		.ai_family = PF_UNSPEC,
3012		.ai_socktype = SOCK_DGRAM,
3013		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
3014	};
3015	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
3016		ap->isnumeric = 1;
3017		memcpy(&ap->a_addr, res->ai_addr, res->ai_addrlen);
3018		ap->a_mask = (struct sockaddr_storage){
3019			.ss_family = res->ai_family,
3020			.ss_len = res->ai_addrlen
3021		};
3022		switch (res->ai_family) {
3023#ifdef INET
3024		case AF_INET:
3025			maskp = &sstosin(&ap->a_mask)->sin_addr.s_addr;
3026			addrp = &sstosin(&ap->a_addr)->sin_addr.s_addr;
3027			if (masklen < 0) {
3028				/* use default netmask */
3029				if (IN_CLASSA(ntohl(*addrp)))
3030					*maskp = htonl(IN_CLASSA_NET);
3031				else if (IN_CLASSB(ntohl(*addrp)))
3032					*maskp = htonl(IN_CLASSB_NET);
3033				else
3034					*maskp = htonl(IN_CLASSC_NET);
3035			} else if (masklen == 0) {
3036				*maskp = 0;
3037			} else if (masklen <= 32) {
3038				/* convert masklen to netmask */
3039				*maskp = htonl(~((1 << (32 - masklen)) - 1));
3040			} else {
3041				goto err;
3042			}
3043			/* Lose any host bits in the network number. */
3044			*addrp &= *maskp;
3045			break;
3046#endif
3047#ifdef INET6
3048		case AF_INET6:
3049			if (masklen > 128)
3050				goto err;
3051
3052			if (masklen < 0)
3053				masklen = 128;
3054			mask6p = (uint32_t *)&sstosin6(&ap->a_mask)->sin6_addr.s6_addr32[0];
3055			addr6p = (uint32_t *)&sstosin6(&ap->a_addr)->sin6_addr.s6_addr32[0];
3056			/* convert masklen to netmask */
3057			while (masklen > 0) {
3058				if (masklen < 32) {
3059					*mask6p =
3060					    htonl(~(0xffffffff >> masklen));
3061					*addr6p &= *mask6p;
3062					break;
3063				} else {
3064					*mask6p++ = 0xffffffff;
3065					addr6p++;
3066					masklen -= 32;
3067				}
3068			}
3069			break;
3070#endif
3071		default:
3072			goto err;
3073		}
3074		freeaddrinfo(res);
3075	} else {
3076		/* arg `s' is domain name */
3077		ap->isnumeric = 0;
3078		ap->a_name = s;
3079		if (cp1)
3080			*cp1 = '/';
3081#ifdef INET6
3082		if (cp2) {
3083			*cp2 = ']';
3084			--s;
3085		}
3086#endif
3087	}
3088	STAILQ_INSERT_TAIL(&aphead, ap, next);
3089
3090	if (Debug) {
3091		printf("allowaddr: rule ");
3092		if (ap->isnumeric) {
3093			printf("numeric, ");
3094			getnameinfo(sstosa(&ap->a_addr),
3095				    (sstosa(&ap->a_addr))->sa_len,
3096				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
3097			printf("addr = %s, ", ip);
3098			getnameinfo(sstosa(&ap->a_mask),
3099				    (sstosa(&ap->a_mask))->sa_len,
3100				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
3101			printf("mask = %s; ", ip);
3102		} else {
3103			printf("domainname = %s; ", ap->a_name);
3104		}
3105		printf("port = %d\n", ap->port);
3106	}
3107#endif
3108
3109	return (0);
3110err:
3111	if (res != NULL)
3112		freeaddrinfo(res);
3113	free(ap);
3114	return (-1);
3115}
3116
3117/*
3118 * Validate that the remote peer has permission to log to us.
3119 */
3120static int
3121validate(struct sockaddr *sa, const char *hname)
3122{
3123	int i;
3124	char name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
3125	struct allowedpeer *ap;
3126#ifdef INET
3127	struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL;
3128#endif
3129#ifdef INET6
3130	struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
3131#endif
3132	struct addrinfo hints, *res;
3133	u_short sport;
3134	int num = 0;
3135
3136	STAILQ_FOREACH(ap, &aphead, next) {
3137		num++;
3138	}
3139	dprintf("# of validation rule: %d\n", num);
3140	if (num == 0)
3141		/* traditional behaviour, allow everything */
3142		return (1);
3143
3144	(void)strlcpy(name, hname, sizeof(name));
3145	hints = (struct addrinfo){
3146		.ai_family = PF_UNSPEC,
3147		.ai_socktype = SOCK_DGRAM,
3148		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
3149	};
3150	if (getaddrinfo(name, NULL, &hints, &res) == 0)
3151		freeaddrinfo(res);
3152	else if (strchr(name, '.') == NULL) {
3153		strlcat(name, ".", sizeof name);
3154		strlcat(name, LocalDomain, sizeof name);
3155	}
3156	if (getnameinfo(sa, sa->sa_len, ip, sizeof(ip), port, sizeof(port),
3157			NI_NUMERICHOST | NI_NUMERICSERV) != 0)
3158		return (0);	/* for safety, should not occur */
3159	dprintf("validate: dgram from IP %s, port %s, name %s;\n",
3160		ip, port, name);
3161	sport = atoi(port);
3162
3163	/* now, walk down the list */
3164	i = 0;
3165	STAILQ_FOREACH(ap, &aphead, next) {
3166		i++;
3167		if (ap->port != 0 && ap->port != sport) {
3168			dprintf("rejected in rule %d due to port mismatch.\n",
3169			    i);
3170			continue;
3171		}
3172
3173		if (ap->isnumeric) {
3174			if (ap->a_addr.ss_family != sa->sa_family) {
3175				dprintf("rejected in rule %d due to address family mismatch.\n", i);
3176				continue;
3177			}
3178#ifdef INET
3179			else if (ap->a_addr.ss_family == AF_INET) {
3180				sin4 = satosin(sa);
3181				a4p = satosin(&ap->a_addr);
3182				m4p = satosin(&ap->a_mask);
3183				if ((sin4->sin_addr.s_addr & m4p->sin_addr.s_addr)
3184				    != a4p->sin_addr.s_addr) {
3185					dprintf("rejected in rule %d due to IP mismatch.\n", i);
3186					continue;
3187				}
3188			}
3189#endif
3190#ifdef INET6
3191			else if (ap->a_addr.ss_family == AF_INET6) {
3192				sin6 = satosin6(sa);
3193				a6p = satosin6(&ap->a_addr);
3194				m6p = satosin6(&ap->a_mask);
3195				if (a6p->sin6_scope_id != 0 &&
3196				    sin6->sin6_scope_id != a6p->sin6_scope_id) {
3197					dprintf("rejected in rule %d due to scope mismatch.\n", i);
3198					continue;
3199				}
3200				if (IN6_ARE_MASKED_ADDR_EQUAL(&sin6->sin6_addr,
3201				    &a6p->sin6_addr, &m6p->sin6_addr) != 0) {
3202					dprintf("rejected in rule %d due to IP mismatch.\n", i);
3203					continue;
3204				}
3205			}
3206#endif
3207			else
3208				continue;
3209		} else {
3210			if (fnmatch(ap->a_name, name, FNM_NOESCAPE) ==
3211			    FNM_NOMATCH) {
3212				dprintf("rejected in rule %d due to name "
3213				    "mismatch.\n", i);
3214				continue;
3215			}
3216		}
3217		dprintf("accepted in rule %d.\n", i);
3218		return (1);	/* hooray! */
3219	}
3220	return (0);
3221}
3222
3223/*
3224 * Fairly similar to popen(3), but returns an open descriptor, as
3225 * opposed to a FILE *.
3226 */
3227static int
3228p_open(const char *prog, pid_t *rpid)
3229{
3230	int pfd[2], nulldesc;
3231	pid_t pid;
3232	char *argv[4]; /* sh -c cmd NULL */
3233	char errmsg[200];
3234
3235	if (pipe(pfd) == -1)
3236		return (-1);
3237	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
3238		/* we are royally screwed anyway */
3239		return (-1);
3240
3241	switch ((pid = fork())) {
3242	case -1:
3243		close(nulldesc);
3244		return (-1);
3245
3246	case 0:
3247		(void)setsid();	/* Avoid catching SIGHUPs. */
3248		argv[0] = strdup("sh");
3249		argv[1] = strdup("-c");
3250		argv[2] = strdup(prog);
3251		argv[3] = NULL;
3252		if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL) {
3253			logerror("strdup");
3254			exit(1);
3255		}
3256
3257		alarm(0);
3258
3259		/* Restore signals marked as SIG_IGN. */
3260		(void)signal(SIGINT, SIG_DFL);
3261		(void)signal(SIGQUIT, SIG_DFL);
3262		(void)signal(SIGPIPE, SIG_DFL);
3263
3264		dup2(pfd[0], STDIN_FILENO);
3265		dup2(nulldesc, STDOUT_FILENO);
3266		dup2(nulldesc, STDERR_FILENO);
3267		closefrom(STDERR_FILENO + 1);
3268
3269		(void)execvp(_PATH_BSHELL, argv);
3270		_exit(255);
3271	}
3272	close(nulldesc);
3273	close(pfd[0]);
3274	/*
3275	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
3276	 * supposed to get an EWOULDBLOCK on writev(2), which is
3277	 * caught by the logic above anyway, which will in turn close
3278	 * the pipe, and fork a new logging subprocess if necessary.
3279	 * The stale subprocess will be killed some time later unless
3280	 * it terminated itself due to closing its input pipe (so we
3281	 * get rid of really dead puppies).
3282	 */
3283	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
3284		/* This is bad. */
3285		(void)snprintf(errmsg, sizeof errmsg,
3286			       "Warning: cannot change pipe to PID %d to "
3287			       "non-blocking behaviour.",
3288			       (int)pid);
3289		logerror(errmsg);
3290	}
3291	*rpid = pid;
3292	return (pfd[1]);
3293}
3294
3295static void
3296deadq_enter(pid_t pid, const char *name)
3297{
3298	struct deadq_entry *dq;
3299	int status;
3300
3301	if (pid == 0)
3302		return;
3303	/*
3304	 * Be paranoid, if we can't signal the process, don't enter it
3305	 * into the dead queue (perhaps it's already dead).  If possible,
3306	 * we try to fetch and log the child's status.
3307	 */
3308	if (kill(pid, 0) != 0) {
3309		if (waitpid(pid, &status, WNOHANG) > 0)
3310			log_deadchild(pid, status, name);
3311		return;
3312	}
3313
3314	dq = malloc(sizeof(*dq));
3315	if (dq == NULL) {
3316		logerror("malloc");
3317		exit(1);
3318	}
3319	*dq = (struct deadq_entry){
3320		.dq_pid = pid,
3321		.dq_timeout = DQ_TIMO_INIT
3322	};
3323	TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries);
3324}
3325
3326static int
3327deadq_remove(struct deadq_entry *dq)
3328{
3329	if (dq != NULL) {
3330		TAILQ_REMOVE(&deadq_head, dq, dq_entries);
3331		free(dq);
3332		return (1);
3333	}
3334
3335	return (0);
3336}
3337
3338static int
3339deadq_removebypid(pid_t pid)
3340{
3341	struct deadq_entry *dq;
3342
3343	TAILQ_FOREACH(dq, &deadq_head, dq_entries) {
3344		if (dq->dq_pid == pid)
3345			break;
3346	}
3347	return (deadq_remove(dq));
3348}
3349
3350static void
3351log_deadchild(pid_t pid, int status, const char *name)
3352{
3353	int code;
3354	char buf[256];
3355	const char *reason;
3356
3357	errno = 0; /* Keep strerror() stuff out of logerror messages. */
3358	if (WIFSIGNALED(status)) {
3359		reason = "due to signal";
3360		code = WTERMSIG(status);
3361	} else {
3362		reason = "with status";
3363		code = WEXITSTATUS(status);
3364		if (code == 0)
3365			return;
3366	}
3367	(void)snprintf(buf, sizeof buf,
3368		       "Logging subprocess %d (%s) exited %s %d.",
3369		       pid, name, reason, code);
3370	logerror(buf);
3371}
3372
3373static int
3374socksetup(struct peer *pe)
3375{
3376	struct addrinfo hints, *res, *res0;
3377	int error;
3378	char *cp;
3379	int (*sl_recv)(struct socklist *);
3380	/*
3381	 * We have to handle this case for backwards compatibility:
3382	 * If there are two (or more) colons but no '[' and ']',
3383	 * assume this is an inet6 address without a service.
3384	 */
3385	if (pe->pe_name != NULL) {
3386#ifdef INET6
3387		if (pe->pe_name[0] == '[' &&
3388		    (cp = strchr(pe->pe_name + 1, ']')) != NULL) {
3389			pe->pe_name = &pe->pe_name[1];
3390			*cp = '\0';
3391			if (cp[1] == ':' && cp[2] != '\0')
3392				pe->pe_serv = cp + 2;
3393		} else {
3394#endif
3395			cp = strchr(pe->pe_name, ':');
3396			if (cp != NULL && strchr(cp + 1, ':') == NULL) {
3397				*cp = '\0';
3398				if (cp[1] != '\0')
3399					pe->pe_serv = cp + 1;
3400				if (cp == pe->pe_name)
3401					pe->pe_name = NULL;
3402			}
3403#ifdef INET6
3404		}
3405#endif
3406	}
3407	hints = (struct addrinfo){
3408		.ai_family = AF_UNSPEC,
3409		.ai_socktype = SOCK_DGRAM,
3410		.ai_flags = AI_PASSIVE
3411	};
3412	if (pe->pe_name != NULL)
3413		dprintf("Trying peer: %s\n", pe->pe_name);
3414	if (pe->pe_serv == NULL)
3415		pe->pe_serv = "syslog";
3416	error = getaddrinfo(pe->pe_name, pe->pe_serv, &hints, &res0);
3417	if (error) {
3418		char *msgbuf;
3419
3420		asprintf(&msgbuf, "getaddrinfo failed for %s%s: %s",
3421		    pe->pe_name == NULL ? "" : pe->pe_name, pe->pe_serv,
3422		    gai_strerror(error));
3423		errno = 0;
3424		if (msgbuf == NULL)
3425			logerror(gai_strerror(error));
3426		else
3427			logerror(msgbuf);
3428		free(msgbuf);
3429		die(0);
3430	}
3431	for (res = res0; res != NULL; res = res->ai_next) {
3432		int s;
3433
3434		if (res->ai_family != AF_LOCAL &&
3435		    SecureMode > 1) {
3436			/* Only AF_LOCAL in secure mode. */
3437			continue;
3438		}
3439		if (family != AF_UNSPEC &&
3440		    res->ai_family != AF_LOCAL && res->ai_family != family)
3441			continue;
3442
3443		s = socket(res->ai_family, res->ai_socktype,
3444		    res->ai_protocol);
3445		if (s < 0) {
3446			logerror("socket");
3447			error++;
3448			continue;
3449		}
3450#ifdef INET6
3451		if (res->ai_family == AF_INET6) {
3452			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
3453			       &(int){1}, sizeof(int)) < 0) {
3454				logerror("setsockopt(IPV6_V6ONLY)");
3455				close(s);
3456				error++;
3457				continue;
3458			}
3459		}
3460#endif
3461		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
3462		    &(int){1}, sizeof(int)) < 0) {
3463			logerror("setsockopt(SO_REUSEADDR)");
3464			close(s);
3465			error++;
3466			continue;
3467		}
3468
3469		/*
3470		 * Bind INET and UNIX-domain sockets.
3471		 *
3472		 * A UNIX-domain socket is always bound to a pathname
3473		 * regardless of -N flag.
3474		 *
3475		 * For INET sockets, RFC 3164 recommends that client
3476		 * side message should come from the privileged syslogd port.
3477		 *
3478		 * If the system administrator chooses not to obey
3479		 * this, we can skip the bind() step so that the
3480		 * system will choose a port for us.
3481		 */
3482		if (res->ai_family == AF_LOCAL)
3483			unlink(pe->pe_name);
3484		if (res->ai_family == AF_LOCAL ||
3485		    NoBind == 0 || pe->pe_name != NULL) {
3486			if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
3487				logerror("bind");
3488				close(s);
3489				error++;
3490				continue;
3491			}
3492			if (res->ai_family == AF_LOCAL ||
3493			    SecureMode == 0)
3494				increase_rcvbuf(s);
3495		}
3496		if (res->ai_family == AF_LOCAL &&
3497		    chmod(pe->pe_name, pe->pe_mode) < 0) {
3498			dprintf("chmod %s: %s\n", pe->pe_name,
3499			    strerror(errno));
3500			close(s);
3501			error++;
3502			continue;
3503		}
3504		dprintf("new socket fd is %d\n", s);
3505		if (res->ai_socktype != SOCK_DGRAM) {
3506			listen(s, 5);
3507		}
3508		sl_recv = socklist_recv_sock;
3509#if defined(INET) || defined(INET6)
3510		if (SecureMode && (res->ai_family == AF_INET ||
3511		    res->ai_family == AF_INET6)) {
3512			dprintf("shutdown\n");
3513			/* Forbid communication in secure mode. */
3514			if (shutdown(s, SHUT_RD) < 0 &&
3515			    errno != ENOTCONN) {
3516				logerror("shutdown");
3517				if (!Debug)
3518					die(0);
3519			}
3520			sl_recv = NULL;
3521		} else
3522#endif
3523			dprintf("listening on socket\n");
3524		dprintf("sending on socket\n");
3525		addsock(res->ai_addr, res->ai_addrlen,
3526		    &(struct socklist){
3527			.sl_socket = s,
3528			.sl_peer = pe,
3529			.sl_recv = sl_recv
3530		});
3531	}
3532	freeaddrinfo(res0);
3533
3534	return(error);
3535}
3536
3537static void
3538increase_rcvbuf(int fd)
3539{
3540	socklen_t len;
3541
3542	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len,
3543	    &(socklen_t){sizeof(len)}) == 0) {
3544		if (len < RCVBUF_MINSIZE) {
3545			len = RCVBUF_MINSIZE;
3546			setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
3547		}
3548	}
3549}
3550