xref: /minix3/usr.sbin/syslogd/syslogd.c (revision 686761dbbce7cc1bcf150ce26b1c3f0eed7d17c6)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: syslogd.c,v 1.122 2015/09/05 20:19:43 dholland Exp $	*/
23e07920fSDavid van Moolenbroek 
33e07920fSDavid van Moolenbroek /*
43e07920fSDavid van Moolenbroek  * Copyright (c) 1983, 1988, 1993, 1994
53e07920fSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
63e07920fSDavid van Moolenbroek  *
73e07920fSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
83e07920fSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
93e07920fSDavid van Moolenbroek  * are met:
103e07920fSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
113e07920fSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
123e07920fSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
133e07920fSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
143e07920fSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
153e07920fSDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
163e07920fSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
173e07920fSDavid van Moolenbroek  *    without specific prior written permission.
183e07920fSDavid van Moolenbroek  *
193e07920fSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
203e07920fSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
213e07920fSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
223e07920fSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
233e07920fSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
243e07920fSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
253e07920fSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
263e07920fSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
273e07920fSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
283e07920fSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
293e07920fSDavid van Moolenbroek  * SUCH DAMAGE.
303e07920fSDavid van Moolenbroek  */
313e07920fSDavid van Moolenbroek 
323e07920fSDavid van Moolenbroek #include <sys/cdefs.h>
333e07920fSDavid van Moolenbroek #ifndef lint
343e07920fSDavid van Moolenbroek __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\
353e07920fSDavid van Moolenbroek 	The Regents of the University of California.  All rights reserved.");
363e07920fSDavid van Moolenbroek #endif /* not lint */
373e07920fSDavid van Moolenbroek 
383e07920fSDavid van Moolenbroek #ifndef lint
393e07920fSDavid van Moolenbroek #if 0
403e07920fSDavid van Moolenbroek static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
413e07920fSDavid van Moolenbroek #else
42*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: syslogd.c,v 1.122 2015/09/05 20:19:43 dholland Exp $");
433e07920fSDavid van Moolenbroek #endif
443e07920fSDavid van Moolenbroek #endif /* not lint */
453e07920fSDavid van Moolenbroek 
463e07920fSDavid van Moolenbroek /*
473e07920fSDavid van Moolenbroek  *  syslogd -- log system messages
483e07920fSDavid van Moolenbroek  *
493e07920fSDavid van Moolenbroek  * This program implements a system log. It takes a series of lines.
503e07920fSDavid van Moolenbroek  * Each line may have a priority, signified as "<n>" as
513e07920fSDavid van Moolenbroek  * the first characters of the line.  If this is
523e07920fSDavid van Moolenbroek  * not present, a default priority is used.
533e07920fSDavid van Moolenbroek  *
543e07920fSDavid van Moolenbroek  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
553e07920fSDavid van Moolenbroek  * cause it to reread its configuration file.
563e07920fSDavid van Moolenbroek  *
573e07920fSDavid van Moolenbroek  * Defined Constants:
583e07920fSDavid van Moolenbroek  *
593e07920fSDavid van Moolenbroek  * MAXLINE -- the maximimum line length that can be handled.
603e07920fSDavid van Moolenbroek  * DEFUPRI -- the default priority for user messages
613e07920fSDavid van Moolenbroek  * DEFSPRI -- the default priority for kernel messages
623e07920fSDavid van Moolenbroek  *
633e07920fSDavid van Moolenbroek  * Author: Eric Allman
643e07920fSDavid van Moolenbroek  * extensive changes by Ralph Campbell
653e07920fSDavid van Moolenbroek  * more extensive changes by Eric Allman (again)
663e07920fSDavid van Moolenbroek  * Extension to log by program name as well as facility and priority
673e07920fSDavid van Moolenbroek  *   by Peter da Silva.
683e07920fSDavid van Moolenbroek  * -U and -v by Harlan Stenn.
693e07920fSDavid van Moolenbroek  * Priority comparison code by Harlan Stenn.
703e07920fSDavid van Moolenbroek  * TLS, syslog-protocol, and syslog-sign code by Martin Schuette.
713e07920fSDavid van Moolenbroek  */
723e07920fSDavid van Moolenbroek #define SYSLOG_NAMES
733e07920fSDavid van Moolenbroek #include <sys/stat.h>
743e07920fSDavid van Moolenbroek #include <poll.h>
753e07920fSDavid van Moolenbroek #include "syslogd.h"
763e07920fSDavid van Moolenbroek #include "extern.h"
773e07920fSDavid van Moolenbroek 
783e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
793e07920fSDavid van Moolenbroek #include "sign.h"
803e07920fSDavid van Moolenbroek struct sign_global_t GlobalSign = {
813e07920fSDavid van Moolenbroek 	.rsid = 0,
823e07920fSDavid van Moolenbroek 	.sig2_delims = STAILQ_HEAD_INITIALIZER(GlobalSign.sig2_delims)
833e07920fSDavid van Moolenbroek };
843e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
853e07920fSDavid van Moolenbroek 
863e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
873e07920fSDavid van Moolenbroek #include "tls.h"
883e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
893e07920fSDavid van Moolenbroek 
903e07920fSDavid van Moolenbroek #ifdef LIBWRAP
913e07920fSDavid van Moolenbroek int allow_severity = LOG_AUTH|LOG_INFO;
923e07920fSDavid van Moolenbroek int deny_severity = LOG_AUTH|LOG_WARNING;
933e07920fSDavid van Moolenbroek #endif
943e07920fSDavid van Moolenbroek 
953e07920fSDavid van Moolenbroek const char	*ConfFile = _PATH_LOGCONF;
963e07920fSDavid van Moolenbroek char	ctty[] = _PATH_CONSOLE;
973e07920fSDavid van Moolenbroek 
983e07920fSDavid van Moolenbroek /*
993e07920fSDavid van Moolenbroek  * Queue of about-to-be-dead processes we should watch out for.
1003e07920fSDavid van Moolenbroek  */
1013e07920fSDavid van Moolenbroek TAILQ_HEAD(, deadq_entry) deadq_head = TAILQ_HEAD_INITIALIZER(deadq_head);
1023e07920fSDavid van Moolenbroek 
1033e07920fSDavid van Moolenbroek typedef struct deadq_entry {
1043e07920fSDavid van Moolenbroek 	pid_t				dq_pid;
1053e07920fSDavid van Moolenbroek 	int				dq_timeout;
1063e07920fSDavid van Moolenbroek 	TAILQ_ENTRY(deadq_entry)	dq_entries;
1073e07920fSDavid van Moolenbroek } *dq_t;
1083e07920fSDavid van Moolenbroek 
1093e07920fSDavid van Moolenbroek /*
1103e07920fSDavid van Moolenbroek  * The timeout to apply to processes waiting on the dead queue.	 Unit
1113e07920fSDavid van Moolenbroek  * of measure is "mark intervals", i.e. 20 minutes by default.
1123e07920fSDavid van Moolenbroek  * Processes on the dead queue will be terminated after that time.
1133e07920fSDavid van Moolenbroek  */
1143e07920fSDavid van Moolenbroek #define DQ_TIMO_INIT	2
1153e07920fSDavid van Moolenbroek 
1163e07920fSDavid van Moolenbroek /*
1173e07920fSDavid van Moolenbroek  * Intervals at which we flush out "message repeated" messages,
1183e07920fSDavid van Moolenbroek  * in seconds after previous message is logged.	 After each flush,
1193e07920fSDavid van Moolenbroek  * we move to the next interval until we reach the largest.
1203e07920fSDavid van Moolenbroek  */
1213e07920fSDavid van Moolenbroek int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
1223e07920fSDavid van Moolenbroek #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
1233e07920fSDavid van Moolenbroek #define REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
1243e07920fSDavid van Moolenbroek #define BACKOFF(f)	{ if ((size_t)(++(f)->f_repeatcount) > MAXREPEAT) \
1253e07920fSDavid van Moolenbroek 				 (f)->f_repeatcount = MAXREPEAT; \
1263e07920fSDavid van Moolenbroek 			}
1273e07920fSDavid van Moolenbroek 
1283e07920fSDavid van Moolenbroek /* values for f_type */
1293e07920fSDavid van Moolenbroek #define F_UNUSED	0		/* unused entry */
1303e07920fSDavid van Moolenbroek #define F_FILE		1		/* regular file */
1313e07920fSDavid van Moolenbroek #define F_TTY		2		/* terminal */
1323e07920fSDavid van Moolenbroek #define F_CONSOLE	3		/* console terminal */
1333e07920fSDavid van Moolenbroek #define F_FORW		4		/* remote machine */
1343e07920fSDavid van Moolenbroek #define F_USERS		5		/* list of users */
1353e07920fSDavid van Moolenbroek #define F_WALL		6		/* everyone logged on */
1363e07920fSDavid van Moolenbroek #define F_PIPE		7		/* pipe to program */
1373e07920fSDavid van Moolenbroek #define F_FIFO		8		/* mkfifo(2) file */
1383e07920fSDavid van Moolenbroek #define F_TLS		9
1393e07920fSDavid van Moolenbroek 
1403e07920fSDavid van Moolenbroek struct TypeInfo {
1413e07920fSDavid van Moolenbroek 	const char *name;
1423e07920fSDavid van Moolenbroek 	char	   *queue_length_string;
1433e07920fSDavid van Moolenbroek 	const char *default_length_string;
1443e07920fSDavid van Moolenbroek 	char	   *queue_size_string;
1453e07920fSDavid van Moolenbroek 	const char *default_size_string;
1463e07920fSDavid van Moolenbroek 	int64_t	    queue_length;
1473e07920fSDavid van Moolenbroek 	int64_t	    queue_size;
1483e07920fSDavid van Moolenbroek 	int   max_msg_length;
1493e07920fSDavid van Moolenbroek } TypeInfo[] = {
1503e07920fSDavid van Moolenbroek 	/* numeric values are set in init()
1513e07920fSDavid van Moolenbroek 	 * -1 in length/size or max_msg_length means infinite */
1523e07920fSDavid van Moolenbroek 	{"UNUSED",  NULL,    "0", NULL,	  "0", 0, 0,	 0},
1533e07920fSDavid van Moolenbroek 	{"FILE",    NULL, "1024", NULL,	 "1M", 0, 0, 16384},
1543e07920fSDavid van Moolenbroek 	{"TTY",	    NULL,    "0", NULL,	  "0", 0, 0,  1024},
1553e07920fSDavid van Moolenbroek 	{"CONSOLE", NULL,    "0", NULL,	  "0", 0, 0,  1024},
1563e07920fSDavid van Moolenbroek 	{"FORW",    NULL,    "0", NULL,	 "1M", 0, 0, 16384},
1573e07920fSDavid van Moolenbroek 	{"USERS",   NULL,    "0", NULL,	  "0", 0, 0,  1024},
1583e07920fSDavid van Moolenbroek 	{"WALL",    NULL,    "0", NULL,	  "0", 0, 0,  1024},
1593e07920fSDavid van Moolenbroek 	{"PIPE",    NULL, "1024", NULL,	 "1M", 0, 0, 16384},
1603e07920fSDavid van Moolenbroek 	{"FIFO",    NULL, "1024", NULL,	 "1M", 0, 0, 16384},
1613e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
1623e07920fSDavid van Moolenbroek 	{"TLS",	    NULL,   "-1", NULL, "16M", 0, 0, 16384}
1633e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
1643e07920fSDavid van Moolenbroek };
1653e07920fSDavid van Moolenbroek 
1663e07920fSDavid van Moolenbroek struct	filed *Files = NULL;
1673e07920fSDavid van Moolenbroek struct	filed consfile;
1683e07920fSDavid van Moolenbroek 
1693e07920fSDavid van Moolenbroek time_t	now;
1703e07920fSDavid van Moolenbroek int	Debug = D_NONE;		/* debug flag */
1713e07920fSDavid van Moolenbroek int	daemonized = 0;		/* we are not daemonized yet */
1723e07920fSDavid van Moolenbroek char	*LocalFQDN = NULL;	       /* our FQDN */
1733e07920fSDavid van Moolenbroek char	*oldLocalFQDN = NULL;	       /* our previous FQDN */
1743e07920fSDavid van Moolenbroek char	LocalHostName[MAXHOSTNAMELEN]; /* our hostname */
1753e07920fSDavid van Moolenbroek struct socketEvent *finet;	/* Internet datagram sockets and events */
1763e07920fSDavid van Moolenbroek int   *funix;			/* Unix domain datagram sockets */
1773e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
1783e07920fSDavid van Moolenbroek struct socketEvent *TLS_Listen_Set; /* TLS/TCP sockets and events */
1793e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
1803e07920fSDavid van Moolenbroek int	Initialized = 0;	/* set when we have initialized ourselves */
1813e07920fSDavid van Moolenbroek int	ShuttingDown;		/* set when we die() */
1823e07920fSDavid van Moolenbroek int	MarkInterval = 20 * 60; /* interval between marks in seconds */
1833e07920fSDavid van Moolenbroek int	MarkSeq = 0;		/* mark sequence number */
1843e07920fSDavid van Moolenbroek int	SecureMode = 0;		/* listen only on unix domain socks */
1853e07920fSDavid van Moolenbroek int	UseNameService = 1;	/* make domain name queries */
1863e07920fSDavid van Moolenbroek int	NumForwards = 0;	/* number of forwarding actions in conf file */
1873e07920fSDavid van Moolenbroek char	**LogPaths;		/* array of pathnames to read messages from */
1883e07920fSDavid van Moolenbroek int	NoRepeat = 0;		/* disable "repeated"; log always */
1893e07920fSDavid van Moolenbroek int	RemoteAddDate = 0;	/* always add date to messages from network */
1903e07920fSDavid van Moolenbroek int	SyncKernel = 0;		/* write kernel messages synchronously */
1913e07920fSDavid van Moolenbroek int	UniquePriority = 0;	/* only log specified priority */
1923e07920fSDavid van Moolenbroek int	LogFacPri = 0;		/* put facility and priority in log messages: */
1933e07920fSDavid van Moolenbroek 				/* 0=no, 1=numeric, 2=names */
1943e07920fSDavid van Moolenbroek bool	BSDOutputFormat = true;	/* if true emit traditional BSD Syslog lines,
1953e07920fSDavid van Moolenbroek 				 * otherwise new syslog-protocol lines
1963e07920fSDavid van Moolenbroek 				 *
1973e07920fSDavid van Moolenbroek 				 * Open Issue: having a global flag is the
1983e07920fSDavid van Moolenbroek 				 * easiest solution. If we get a more detailed
1993e07920fSDavid van Moolenbroek 				 * config file this could/should be changed
2003e07920fSDavid van Moolenbroek 				 * into a destination-specific flag.
2013e07920fSDavid van Moolenbroek 				 * Most output code should be ready to handle
2023e07920fSDavid van Moolenbroek 				 * this, it will only break some syslog-sign
2033e07920fSDavid van Moolenbroek 				 * configurations (e.g. with SG="0").
2043e07920fSDavid van Moolenbroek 				 */
2053e07920fSDavid van Moolenbroek char	appname[]   = "syslogd";/* the APPNAME for own messages */
2063e07920fSDavid van Moolenbroek char   *include_pid = NULL;	/* include PID in own messages */
2073e07920fSDavid van Moolenbroek 
2083e07920fSDavid van Moolenbroek 
2093e07920fSDavid van Moolenbroek /* init and setup */
2103e07920fSDavid van Moolenbroek void		usage(void) __attribute__((__noreturn__));
2113e07920fSDavid van Moolenbroek void		logpath_add(char ***, int *, int *, const char *);
2123e07920fSDavid van Moolenbroek void		logpath_fileadd(char ***, int *, int *, const char *);
2133e07920fSDavid van Moolenbroek void		init(int fd, short event, void *ev);  /* SIGHUP kevent dispatch routine */
2143e07920fSDavid van Moolenbroek struct socketEvent*
2153e07920fSDavid van Moolenbroek 		socksetup(int, const char *);
2163e07920fSDavid van Moolenbroek int		getmsgbufsize(void);
2173e07920fSDavid van Moolenbroek char	       *getLocalFQDN(void);
2183e07920fSDavid van Moolenbroek void		trim_anydomain(char *);
2193e07920fSDavid van Moolenbroek /* pipe & subprocess handling */
2203e07920fSDavid van Moolenbroek int		p_open(char *, pid_t *);
2213e07920fSDavid van Moolenbroek void		deadq_enter(pid_t, const char *);
2223e07920fSDavid van Moolenbroek int		deadq_remove(pid_t);
2233e07920fSDavid van Moolenbroek void		log_deadchild(pid_t, int, const char *);
2243e07920fSDavid van Moolenbroek void		reapchild(int fd, short event, void *ev); /* SIGCHLD kevent dispatch routine */
2253e07920fSDavid van Moolenbroek /* input message parsing & formatting */
2263e07920fSDavid van Moolenbroek const char     *cvthname(struct sockaddr_storage *);
2273e07920fSDavid van Moolenbroek void		printsys(char *);
2283e07920fSDavid van Moolenbroek struct buf_msg *printline_syslogprotocol(const char*, char*, int, int);
2293e07920fSDavid van Moolenbroek struct buf_msg *printline_bsdsyslog(const char*, char*, int, int);
2303e07920fSDavid van Moolenbroek struct buf_msg *printline_kernelprintf(const char*, char*, int, int);
2313e07920fSDavid van Moolenbroek size_t		check_timestamp(unsigned char *, char **, bool, bool);
2323e07920fSDavid van Moolenbroek char	       *copy_utf8_ascii(char*, size_t);
2333e07920fSDavid van Moolenbroek uint_fast32_t	get_utf8_value(const char*);
2343e07920fSDavid van Moolenbroek unsigned	valid_utf8(const char *);
2353e07920fSDavid van Moolenbroek static unsigned check_sd(char*);
2363e07920fSDavid van Moolenbroek static unsigned check_msgid(char *);
2373e07920fSDavid van Moolenbroek /* event handling */
2383e07920fSDavid van Moolenbroek static void	dispatch_read_klog(int fd, short event, void *ev);
2393e07920fSDavid van Moolenbroek static void	dispatch_read_finet(int fd, short event, void *ev);
2403e07920fSDavid van Moolenbroek static void	dispatch_read_funix(int fd, short event, void *ev);
2413e07920fSDavid van Moolenbroek static void	domark(int fd, short event, void *ev); /* timer kevent dispatch routine */
2423e07920fSDavid van Moolenbroek /* log messages */
2433e07920fSDavid van Moolenbroek void		logmsg_async(int, const char *, const char *, int);
2443e07920fSDavid van Moolenbroek void		logmsg(struct buf_msg *);
2453e07920fSDavid van Moolenbroek int		matches_spec(const char *, const char *,
2463e07920fSDavid van Moolenbroek 		char *(*)(const char *, const char *));
2473e07920fSDavid van Moolenbroek void		udp_send(struct filed *, char *, size_t);
2483e07920fSDavid van Moolenbroek void		wallmsg(struct filed *, struct iovec *, size_t);
2493e07920fSDavid van Moolenbroek /* buffer & queue functions */
2503e07920fSDavid van Moolenbroek size_t		message_queue_purge(struct filed *f, size_t, int);
2513e07920fSDavid van Moolenbroek size_t		message_allqueues_check(void);
2523e07920fSDavid van Moolenbroek static struct buf_queue *
2533e07920fSDavid van Moolenbroek 		find_qentry_to_delete(const struct buf_queue_head *, int, bool);
2543e07920fSDavid van Moolenbroek struct buf_queue *
2553e07920fSDavid van Moolenbroek 		message_queue_add(struct filed *, struct buf_msg *);
2563e07920fSDavid van Moolenbroek size_t		buf_queue_obj_size(struct buf_queue*);
2573e07920fSDavid van Moolenbroek /* configuration & parsing */
2583e07920fSDavid van Moolenbroek void		cfline(size_t, const char *, struct filed *, const char *,
2593e07920fSDavid van Moolenbroek     const char *);
2603e07920fSDavid van Moolenbroek void		read_config_file(FILE*, struct filed**);
2613e07920fSDavid van Moolenbroek void		store_sign_delim_sg2(char*);
2623e07920fSDavid van Moolenbroek int		decode(const char *, CODE *);
2633e07920fSDavid van Moolenbroek bool		copy_config_value(const char *, char **, const char **,
2643e07920fSDavid van Moolenbroek     const char *, int);
2653e07920fSDavid van Moolenbroek bool		copy_config_value_word(char **, const char **);
2663e07920fSDavid van Moolenbroek 
2673e07920fSDavid van Moolenbroek /* config parsing */
2683e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
2693e07920fSDavid van Moolenbroek void		free_cred_SLIST(struct peer_cred_head *);
2703e07920fSDavid van Moolenbroek static inline void
2713e07920fSDavid van Moolenbroek 		free_incoming_tls_sockets(void);
2723e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
2733e07920fSDavid van Moolenbroek static int writev1(int, struct iovec *, size_t);
2743e07920fSDavid van Moolenbroek 
2753e07920fSDavid van Moolenbroek /* for make_timestamp() */
276*0a6a1f1dSLionel Sambuc char	timestamp[MAX_TIMESTAMPLEN + 1];
2773e07920fSDavid van Moolenbroek /*
2783e07920fSDavid van Moolenbroek  * Global line buffer.	Since we only process one event at a time,
2793e07920fSDavid van Moolenbroek  * a global one will do.  But for klog, we use own buffer so that
2803e07920fSDavid van Moolenbroek  * partial line at the end of buffer can be deferred.
2813e07920fSDavid van Moolenbroek  */
2823e07920fSDavid van Moolenbroek char *linebuf, *klog_linebuf;
2833e07920fSDavid van Moolenbroek size_t linebufsize, klog_linebufoff;
2843e07920fSDavid van Moolenbroek 
2853e07920fSDavid van Moolenbroek static const char *bindhostname = NULL;
2863e07920fSDavid van Moolenbroek 
2873e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
2883e07920fSDavid van Moolenbroek struct TLS_Incoming TLS_Incoming_Head = \
2893e07920fSDavid van Moolenbroek 	SLIST_HEAD_INITIALIZER(TLS_Incoming_Head);
2903e07920fSDavid van Moolenbroek extern char *SSL_ERRCODE[];
2913e07920fSDavid van Moolenbroek struct tls_global_options_t tls_opt;
2923e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
2933e07920fSDavid van Moolenbroek 
2943e07920fSDavid van Moolenbroek int
main(int argc,char * argv[])2953e07920fSDavid van Moolenbroek main(int argc, char *argv[])
2963e07920fSDavid van Moolenbroek {
2973e07920fSDavid van Moolenbroek 	int ch, j, fklog;
2983e07920fSDavid van Moolenbroek 	int funixsize = 0, funixmaxsize = 0;
2993e07920fSDavid van Moolenbroek 	struct sockaddr_un sunx;
3003e07920fSDavid van Moolenbroek 	char **pp;
3013e07920fSDavid van Moolenbroek 	struct event *ev;
3023e07920fSDavid van Moolenbroek 	uid_t uid = 0;
3033e07920fSDavid van Moolenbroek 	gid_t gid = 0;
3043e07920fSDavid van Moolenbroek 	char *user = NULL;
3053e07920fSDavid van Moolenbroek 	char *group = NULL;
3063e07920fSDavid van Moolenbroek 	const char *root = "/";
3073e07920fSDavid van Moolenbroek 	char *endp;
3083e07920fSDavid van Moolenbroek 	struct group   *gr;
3093e07920fSDavid van Moolenbroek 	struct passwd  *pw;
3103e07920fSDavid van Moolenbroek 	unsigned long l;
3113e07920fSDavid van Moolenbroek 
3123e07920fSDavid van Moolenbroek 	/* should we set LC_TIME="C" to ensure correct timestamps&parsing? */
3133e07920fSDavid van Moolenbroek 	(void)setlocale(LC_ALL, "");
3143e07920fSDavid van Moolenbroek 
3153e07920fSDavid van Moolenbroek 	while ((ch = getopt(argc, argv, "b:dnsSf:m:o:p:P:ru:g:t:TUv")) != -1)
3163e07920fSDavid van Moolenbroek 		switch(ch) {
3173e07920fSDavid van Moolenbroek 		case 'b':
3183e07920fSDavid van Moolenbroek 			bindhostname = optarg;
3193e07920fSDavid van Moolenbroek 			break;
3203e07920fSDavid van Moolenbroek 		case 'd':		/* debug */
3213e07920fSDavid van Moolenbroek 			Debug = D_DEFAULT;
3223e07920fSDavid van Moolenbroek 			/* is there a way to read the integer value
3233e07920fSDavid van Moolenbroek 			 * for Debug as an optional argument? */
3243e07920fSDavid van Moolenbroek 			break;
3253e07920fSDavid van Moolenbroek 		case 'f':		/* configuration file */
3263e07920fSDavid van Moolenbroek 			ConfFile = optarg;
3273e07920fSDavid van Moolenbroek 			break;
3283e07920fSDavid van Moolenbroek 		case 'g':
3293e07920fSDavid van Moolenbroek 			group = optarg;
3303e07920fSDavid van Moolenbroek 			if (*group == '\0')
3313e07920fSDavid van Moolenbroek 				usage();
3323e07920fSDavid van Moolenbroek 			break;
3333e07920fSDavid van Moolenbroek 		case 'm':		/* mark interval */
3343e07920fSDavid van Moolenbroek 			MarkInterval = atoi(optarg) * 60;
3353e07920fSDavid van Moolenbroek 			break;
3363e07920fSDavid van Moolenbroek 		case 'n':		/* turn off DNS queries */
3373e07920fSDavid van Moolenbroek 			UseNameService = 0;
3383e07920fSDavid van Moolenbroek 			break;
3393e07920fSDavid van Moolenbroek 		case 'o':		/* message format */
3403e07920fSDavid van Moolenbroek #define EQ(a)		(strncmp(optarg, # a, sizeof(# a) - 1) == 0)
3413e07920fSDavid van Moolenbroek 			if (EQ(bsd) || EQ(rfc3264))
3423e07920fSDavid van Moolenbroek 				BSDOutputFormat = true;
3433e07920fSDavid van Moolenbroek 			else if (EQ(syslog) || EQ(rfc5424))
3443e07920fSDavid van Moolenbroek 				BSDOutputFormat = false;
3453e07920fSDavid van Moolenbroek 			else
3463e07920fSDavid van Moolenbroek 				usage();
3473e07920fSDavid van Moolenbroek 			/* TODO: implement additional output option "osyslog"
3483e07920fSDavid van Moolenbroek 			 *	 for old syslogd behaviour as introduced after
3493e07920fSDavid van Moolenbroek 			 *	 FreeBSD PR#bin/7055.
3503e07920fSDavid van Moolenbroek 			 */
3513e07920fSDavid van Moolenbroek 			break;
3523e07920fSDavid van Moolenbroek 		case 'p':		/* path */
3533e07920fSDavid van Moolenbroek 			logpath_add(&LogPaths, &funixsize,
3543e07920fSDavid van Moolenbroek 			    &funixmaxsize, optarg);
3553e07920fSDavid van Moolenbroek 			break;
3563e07920fSDavid van Moolenbroek 		case 'P':		/* file of paths */
3573e07920fSDavid van Moolenbroek 			logpath_fileadd(&LogPaths, &funixsize,
3583e07920fSDavid van Moolenbroek 			    &funixmaxsize, optarg);
3593e07920fSDavid van Moolenbroek 			break;
3603e07920fSDavid van Moolenbroek 		case 'r':		/* disable "repeated" compression */
3613e07920fSDavid van Moolenbroek 			NoRepeat++;
3623e07920fSDavid van Moolenbroek 			break;
3633e07920fSDavid van Moolenbroek 		case 's':		/* no network listen mode */
3643e07920fSDavid van Moolenbroek 			SecureMode++;
3653e07920fSDavid van Moolenbroek 			break;
3663e07920fSDavid van Moolenbroek 		case 'S':
3673e07920fSDavid van Moolenbroek 			SyncKernel = 1;
3683e07920fSDavid van Moolenbroek 			break;
3693e07920fSDavid van Moolenbroek 		case 't':
3703e07920fSDavid van Moolenbroek 			root = optarg;
3713e07920fSDavid van Moolenbroek 			if (*root == '\0')
3723e07920fSDavid van Moolenbroek 				usage();
3733e07920fSDavid van Moolenbroek 			break;
3743e07920fSDavid van Moolenbroek 		case 'T':
3753e07920fSDavid van Moolenbroek 			RemoteAddDate = 1;
3763e07920fSDavid van Moolenbroek 			break;
3773e07920fSDavid van Moolenbroek 		case 'u':
3783e07920fSDavid van Moolenbroek 			user = optarg;
3793e07920fSDavid van Moolenbroek 			if (*user == '\0')
3803e07920fSDavid van Moolenbroek 				usage();
3813e07920fSDavid van Moolenbroek 			break;
3823e07920fSDavid van Moolenbroek 		case 'U':		/* only log specified priority */
3833e07920fSDavid van Moolenbroek 			UniquePriority = 1;
3843e07920fSDavid van Moolenbroek 			break;
3853e07920fSDavid van Moolenbroek 		case 'v':		/* log facility and priority */
3863e07920fSDavid van Moolenbroek 			if (LogFacPri < 2)
3873e07920fSDavid van Moolenbroek 				LogFacPri++;
3883e07920fSDavid van Moolenbroek 			break;
3893e07920fSDavid van Moolenbroek 		default:
3903e07920fSDavid van Moolenbroek 			usage();
3913e07920fSDavid van Moolenbroek 		}
3923e07920fSDavid van Moolenbroek 	if ((argc -= optind) != 0)
3933e07920fSDavid van Moolenbroek 		usage();
3943e07920fSDavid van Moolenbroek 
3953e07920fSDavid van Moolenbroek 	setlinebuf(stdout);
3963e07920fSDavid van Moolenbroek 	tzset(); /* init TZ information for localtime. */
3973e07920fSDavid van Moolenbroek 
3983e07920fSDavid van Moolenbroek 	if (user != NULL) {
3993e07920fSDavid van Moolenbroek 		if (isdigit((unsigned char)*user)) {
4003e07920fSDavid van Moolenbroek 			errno = 0;
4013e07920fSDavid van Moolenbroek 			endp = NULL;
4023e07920fSDavid van Moolenbroek 			l = strtoul(user, &endp, 0);
4033e07920fSDavid van Moolenbroek 			if (errno || *endp != '\0')
4043e07920fSDavid van Moolenbroek 				goto getuser;
4053e07920fSDavid van Moolenbroek 			uid = (uid_t)l;
4063e07920fSDavid van Moolenbroek 			if (uid != l) {/* TODO: never executed */
4073e07920fSDavid van Moolenbroek 				errno = 0;
4083e07920fSDavid van Moolenbroek 				logerror("UID out of range");
4093e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
4103e07920fSDavid van Moolenbroek 			}
4113e07920fSDavid van Moolenbroek 		} else {
4123e07920fSDavid van Moolenbroek getuser:
4133e07920fSDavid van Moolenbroek 			if ((pw = getpwnam(user)) != NULL) {
4143e07920fSDavid van Moolenbroek 				uid = pw->pw_uid;
4153e07920fSDavid van Moolenbroek 			} else {
4163e07920fSDavid van Moolenbroek 				errno = 0;
4173e07920fSDavid van Moolenbroek 				logerror("Cannot find user `%s'", user);
4183e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
4193e07920fSDavid van Moolenbroek 			}
4203e07920fSDavid van Moolenbroek 		}
4213e07920fSDavid van Moolenbroek 	}
4223e07920fSDavid van Moolenbroek 
4233e07920fSDavid van Moolenbroek 	if (group != NULL) {
4243e07920fSDavid van Moolenbroek 		if (isdigit((unsigned char)*group)) {
4253e07920fSDavid van Moolenbroek 			errno = 0;
4263e07920fSDavid van Moolenbroek 			endp = NULL;
4273e07920fSDavid van Moolenbroek 			l = strtoul(group, &endp, 0);
4283e07920fSDavid van Moolenbroek 			if (errno || *endp != '\0')
4293e07920fSDavid van Moolenbroek 				goto getgroup;
4303e07920fSDavid van Moolenbroek 			gid = (gid_t)l;
4313e07920fSDavid van Moolenbroek 			if (gid != l) {/* TODO: never executed */
4323e07920fSDavid van Moolenbroek 				errno = 0;
4333e07920fSDavid van Moolenbroek 				logerror("GID out of range");
4343e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
4353e07920fSDavid van Moolenbroek 			}
4363e07920fSDavid van Moolenbroek 		} else {
4373e07920fSDavid van Moolenbroek getgroup:
4383e07920fSDavid van Moolenbroek 			if ((gr = getgrnam(group)) != NULL) {
4393e07920fSDavid van Moolenbroek 				gid = gr->gr_gid;
4403e07920fSDavid van Moolenbroek 			} else {
4413e07920fSDavid van Moolenbroek 				errno = 0;
4423e07920fSDavid van Moolenbroek 				logerror("Cannot find group `%s'", group);
4433e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
4443e07920fSDavid van Moolenbroek 			}
4453e07920fSDavid van Moolenbroek 		}
4463e07920fSDavid van Moolenbroek 	}
4473e07920fSDavid van Moolenbroek 
4483e07920fSDavid van Moolenbroek 	if (access(root, F_OK | R_OK)) {
4493e07920fSDavid van Moolenbroek 		logerror("Cannot access `%s'", root);
4503e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
4513e07920fSDavid van Moolenbroek 	}
4523e07920fSDavid van Moolenbroek 
4533e07920fSDavid van Moolenbroek 	consfile.f_type = F_CONSOLE;
4543e07920fSDavid van Moolenbroek 	(void)strlcpy(consfile.f_un.f_fname, ctty,
4553e07920fSDavid van Moolenbroek 	    sizeof(consfile.f_un.f_fname));
4563e07920fSDavid van Moolenbroek 	linebufsize = getmsgbufsize();
4573e07920fSDavid van Moolenbroek 	if (linebufsize < MAXLINE)
4583e07920fSDavid van Moolenbroek 		linebufsize = MAXLINE;
4593e07920fSDavid van Moolenbroek 	linebufsize++;
4603e07920fSDavid van Moolenbroek 
4613e07920fSDavid van Moolenbroek 	if (!(linebuf = malloc(linebufsize))) {
4623e07920fSDavid van Moolenbroek 		logerror("Couldn't allocate buffer");
4633e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
4643e07920fSDavid van Moolenbroek 	}
4653e07920fSDavid van Moolenbroek 	if (!(klog_linebuf = malloc(linebufsize))) {
4663e07920fSDavid van Moolenbroek 		logerror("Couldn't allocate buffer for klog");
4673e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
4683e07920fSDavid van Moolenbroek 	}
4693e07920fSDavid van Moolenbroek 
4703e07920fSDavid van Moolenbroek 
4713e07920fSDavid van Moolenbroek #ifndef SUN_LEN
4723e07920fSDavid van Moolenbroek #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
4733e07920fSDavid van Moolenbroek #endif
4743e07920fSDavid van Moolenbroek 	if (funixsize == 0)
4753e07920fSDavid van Moolenbroek 		logpath_add(&LogPaths, &funixsize,
4763e07920fSDavid van Moolenbroek 		    &funixmaxsize, _PATH_LOG);
4773e07920fSDavid van Moolenbroek 	funix = malloc(sizeof(*funix) * funixsize);
4783e07920fSDavid van Moolenbroek 	if (funix == NULL) {
4793e07920fSDavid van Moolenbroek 		logerror("Couldn't allocate funix descriptors");
4803e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
4813e07920fSDavid van Moolenbroek 	}
4823e07920fSDavid van Moolenbroek 	for (j = 0, pp = LogPaths; *pp; pp++, j++) {
4833e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "Making unix dgram socket `%s'\n", *pp);
4843e07920fSDavid van Moolenbroek 		unlink(*pp);
4853e07920fSDavid van Moolenbroek 		memset(&sunx, 0, sizeof(sunx));
4863e07920fSDavid van Moolenbroek 		sunx.sun_family = AF_LOCAL;
4873e07920fSDavid van Moolenbroek 		(void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path));
4883e07920fSDavid van Moolenbroek 		funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0);
4893e07920fSDavid van Moolenbroek 		if (funix[j] < 0 || bind(funix[j],
4903e07920fSDavid van Moolenbroek 		    (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
4913e07920fSDavid van Moolenbroek 		    chmod(*pp, 0666) < 0) {
4923e07920fSDavid van Moolenbroek 			logerror("Cannot create `%s'", *pp);
4933e07920fSDavid van Moolenbroek 			die(0, 0, NULL);
4943e07920fSDavid van Moolenbroek 		}
4953e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "Listening on unix dgram socket `%s'\n", *pp);
4963e07920fSDavid van Moolenbroek 	}
4973e07920fSDavid van Moolenbroek 
4983e07920fSDavid van Moolenbroek 	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
4993e07920fSDavid van Moolenbroek 		DPRINTF(D_FILE, "Can't open `%s' (%d)\n", _PATH_KLOG, errno);
5003e07920fSDavid van Moolenbroek 	} else {
5013e07920fSDavid van Moolenbroek 		DPRINTF(D_FILE, "Listening on kernel log `%s' with fd %d\n",
5023e07920fSDavid van Moolenbroek 		    _PATH_KLOG, fklog);
5033e07920fSDavid van Moolenbroek 	}
5043e07920fSDavid van Moolenbroek 
5053e07920fSDavid van Moolenbroek #if (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN))
5063e07920fSDavid van Moolenbroek 	/* basic OpenSSL init */
5073e07920fSDavid van Moolenbroek 	SSL_load_error_strings();
5083e07920fSDavid van Moolenbroek 	(void) SSL_library_init();
5093e07920fSDavid van Moolenbroek 	OpenSSL_add_all_digests();
5103e07920fSDavid van Moolenbroek 	/* OpenSSL PRNG needs /dev/urandom, thus initialize before chroot() */
5113e07920fSDavid van Moolenbroek 	if (!RAND_status()) {
5123e07920fSDavid van Moolenbroek 		errno = 0;
5133e07920fSDavid van Moolenbroek 		logerror("Unable to initialize OpenSSL PRNG");
5143e07920fSDavid van Moolenbroek 	} else {
5153e07920fSDavid van Moolenbroek 		DPRINTF(D_TLS, "Initializing PRNG\n");
5163e07920fSDavid van Moolenbroek 	}
5173e07920fSDavid van Moolenbroek #endif /* (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN)) */
5183e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
5193e07920fSDavid van Moolenbroek 	/* initialize rsid -- we will use that later to determine
5203e07920fSDavid van Moolenbroek 	 * whether sign_global_init() was already called */
5213e07920fSDavid van Moolenbroek 	GlobalSign.rsid = 0;
5223e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
5233e07920fSDavid van Moolenbroek #if (IETF_NUM_PRIVALUES != (LOG_NFACILITIES<<3))
5243e07920fSDavid van Moolenbroek 	logerror("Warning: system defines %d priority values, but "
5253e07920fSDavid van Moolenbroek 	    "syslog-protocol/syslog-sign specify %d values",
5263e07920fSDavid van Moolenbroek 	    LOG_NFACILITIES, SIGN_NUM_PRIVALS);
5273e07920fSDavid van Moolenbroek #endif
5283e07920fSDavid van Moolenbroek 
5293e07920fSDavid van Moolenbroek 	/*
5303e07920fSDavid van Moolenbroek 	 * All files are open, we can drop privileges and chroot
5313e07920fSDavid van Moolenbroek 	 */
5323e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "Attempt to chroot to `%s'\n", root);
5333e07920fSDavid van Moolenbroek 	if (chroot(root) == -1) {
5343e07920fSDavid van Moolenbroek 		logerror("Failed to chroot to `%s'", root);
5353e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
5363e07920fSDavid van Moolenbroek 	}
5373e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "Attempt to set GID/EGID to `%d'\n", gid);
5383e07920fSDavid van Moolenbroek 	if (setgid(gid) || setegid(gid)) {
5393e07920fSDavid van Moolenbroek 		logerror("Failed to set gid to `%d'", gid);
5403e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
5413e07920fSDavid van Moolenbroek 	}
5423e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "Attempt to set UID/EUID to `%d'\n", uid);
5433e07920fSDavid van Moolenbroek 	if (setuid(uid) || seteuid(uid)) {
5443e07920fSDavid van Moolenbroek 		logerror("Failed to set uid to `%d'", uid);
5453e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
5463e07920fSDavid van Moolenbroek 	}
5473e07920fSDavid van Moolenbroek 	/*
5483e07920fSDavid van Moolenbroek 	 * We cannot detach from the terminal before we are sure we won't
5493e07920fSDavid van Moolenbroek 	 * have a fatal error, because error message would not go to the
5503e07920fSDavid van Moolenbroek 	 * terminal and would not be logged because syslogd dies.
5513e07920fSDavid van Moolenbroek 	 * All die() calls are behind us, we can call daemon()
5523e07920fSDavid van Moolenbroek 	 */
5533e07920fSDavid van Moolenbroek 	if (!Debug) {
5543e07920fSDavid van Moolenbroek 		(void)daemon(0, 0);
5553e07920fSDavid van Moolenbroek 		daemonized = 1;
5563e07920fSDavid van Moolenbroek 		/* tuck my process id away, if i'm not in debug mode */
5573e07920fSDavid van Moolenbroek #ifdef __NetBSD_Version__
5583e07920fSDavid van Moolenbroek 		pidfile(NULL);
5593e07920fSDavid van Moolenbroek #endif /* __NetBSD_Version__ */
5603e07920fSDavid van Moolenbroek 	}
5613e07920fSDavid van Moolenbroek 
5623e07920fSDavid van Moolenbroek #define MAX_PID_LEN 5
5633e07920fSDavid van Moolenbroek 	include_pid = malloc(MAX_PID_LEN+1);
5643e07920fSDavid van Moolenbroek 	snprintf(include_pid, MAX_PID_LEN+1, "%d", getpid());
5653e07920fSDavid van Moolenbroek 
5663e07920fSDavid van Moolenbroek 	/*
5673e07920fSDavid van Moolenbroek 	 * Create the global kernel event descriptor.
5683e07920fSDavid van Moolenbroek 	 *
5693e07920fSDavid van Moolenbroek 	 * NOTE: We MUST do this after daemon(), bacause the kqueue()
5703e07920fSDavid van Moolenbroek 	 * API dictates that kqueue descriptors are not inherited
5713e07920fSDavid van Moolenbroek 	 * across forks (lame!).
5723e07920fSDavid van Moolenbroek 	 */
5733e07920fSDavid van Moolenbroek 	(void)event_init();
5743e07920fSDavid van Moolenbroek 
5753e07920fSDavid van Moolenbroek 	/*
5763e07920fSDavid van Moolenbroek 	 * We must read the configuration file for the first time
5773e07920fSDavid van Moolenbroek 	 * after the kqueue descriptor is created, because we install
5783e07920fSDavid van Moolenbroek 	 * events during this process.
5793e07920fSDavid van Moolenbroek 	 */
5803e07920fSDavid van Moolenbroek 	init(0, 0, NULL);
5813e07920fSDavid van Moolenbroek 
5823e07920fSDavid van Moolenbroek 	/*
5833e07920fSDavid van Moolenbroek 	 * Always exit on SIGTERM.  Also exit on SIGINT and SIGQUIT
5843e07920fSDavid van Moolenbroek 	 * if we're debugging.
5853e07920fSDavid van Moolenbroek 	 */
5863e07920fSDavid van Moolenbroek 	(void)signal(SIGTERM, SIG_IGN);
5873e07920fSDavid van Moolenbroek 	(void)signal(SIGINT, SIG_IGN);
5883e07920fSDavid van Moolenbroek 	(void)signal(SIGQUIT, SIG_IGN);
5893e07920fSDavid van Moolenbroek 
5903e07920fSDavid van Moolenbroek 	ev = allocev();
5913e07920fSDavid van Moolenbroek 	signal_set(ev, SIGTERM, die, ev);
5923e07920fSDavid van Moolenbroek 	EVENT_ADD(ev);
5933e07920fSDavid van Moolenbroek 
5943e07920fSDavid van Moolenbroek 	if (Debug) {
5953e07920fSDavid van Moolenbroek 		ev = allocev();
5963e07920fSDavid van Moolenbroek 		signal_set(ev, SIGINT, die, ev);
5973e07920fSDavid van Moolenbroek 		EVENT_ADD(ev);
5983e07920fSDavid van Moolenbroek 		ev = allocev();
5993e07920fSDavid van Moolenbroek 		signal_set(ev, SIGQUIT, die, ev);
6003e07920fSDavid van Moolenbroek 		EVENT_ADD(ev);
6013e07920fSDavid van Moolenbroek 	}
6023e07920fSDavid van Moolenbroek 
6033e07920fSDavid van Moolenbroek 	ev = allocev();
6043e07920fSDavid van Moolenbroek 	signal_set(ev, SIGCHLD, reapchild, ev);
6053e07920fSDavid van Moolenbroek 	EVENT_ADD(ev);
6063e07920fSDavid van Moolenbroek 
6073e07920fSDavid van Moolenbroek 	ev = allocev();
6083e07920fSDavid van Moolenbroek 	schedule_event(&ev,
6093e07920fSDavid van Moolenbroek 		&((struct timeval){TIMERINTVL, 0}),
6103e07920fSDavid van Moolenbroek 		domark, ev);
6113e07920fSDavid van Moolenbroek 
6123e07920fSDavid van Moolenbroek 	(void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */
6133e07920fSDavid van Moolenbroek 
6143e07920fSDavid van Moolenbroek 	/* Re-read configuration on SIGHUP. */
6153e07920fSDavid van Moolenbroek 	(void) signal(SIGHUP, SIG_IGN);
6163e07920fSDavid van Moolenbroek 	ev = allocev();
6173e07920fSDavid van Moolenbroek 	signal_set(ev, SIGHUP, init, ev);
6183e07920fSDavid van Moolenbroek 	EVENT_ADD(ev);
6193e07920fSDavid van Moolenbroek 
6203e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
6213e07920fSDavid van Moolenbroek 	ev = allocev();
6223e07920fSDavid van Moolenbroek 	signal_set(ev, SIGUSR1, dispatch_force_tls_reconnect, ev);
6233e07920fSDavid van Moolenbroek 	EVENT_ADD(ev);
6243e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
6253e07920fSDavid van Moolenbroek 
6263e07920fSDavid van Moolenbroek 	if (fklog >= 0) {
6273e07920fSDavid van Moolenbroek 		ev = allocev();
6283e07920fSDavid van Moolenbroek 		DPRINTF(D_EVENT,
6293e07920fSDavid van Moolenbroek 			"register klog for fd %d with ev@%p\n", fklog, ev);
6303e07920fSDavid van Moolenbroek 		event_set(ev, fklog, EV_READ | EV_PERSIST,
6313e07920fSDavid van Moolenbroek 			dispatch_read_klog, ev);
6323e07920fSDavid van Moolenbroek 		EVENT_ADD(ev);
6333e07920fSDavid van Moolenbroek 	}
6343e07920fSDavid van Moolenbroek 	for (j = 0, pp = LogPaths; *pp; pp++, j++) {
6353e07920fSDavid van Moolenbroek 		ev = allocev();
6363e07920fSDavid van Moolenbroek 		event_set(ev, funix[j], EV_READ | EV_PERSIST,
6373e07920fSDavid van Moolenbroek 			dispatch_read_funix, ev);
6383e07920fSDavid van Moolenbroek 		EVENT_ADD(ev);
6393e07920fSDavid van Moolenbroek 	}
6403e07920fSDavid van Moolenbroek 
6413e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "Off & running....\n");
6423e07920fSDavid van Moolenbroek 
6433e07920fSDavid van Moolenbroek 	j = event_dispatch();
6443e07920fSDavid van Moolenbroek 	/* normal termination via die(), reaching this is an error */
6453e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "event_dispatch() returned %d\n", j);
6463e07920fSDavid van Moolenbroek 	die(0, 0, NULL);
6473e07920fSDavid van Moolenbroek 	/*NOTREACHED*/
6483e07920fSDavid van Moolenbroek 	return 0;
6493e07920fSDavid van Moolenbroek }
6503e07920fSDavid van Moolenbroek 
6513e07920fSDavid van Moolenbroek void
usage(void)6523e07920fSDavid van Moolenbroek usage(void)
6533e07920fSDavid van Moolenbroek {
6543e07920fSDavid van Moolenbroek 
6553e07920fSDavid van Moolenbroek 	(void)fprintf(stderr,
6563e07920fSDavid van Moolenbroek 	    "usage: %s [-dnrSsTUv] [-b bind_address] [-f config_file] [-g group]\n"
6573e07920fSDavid van Moolenbroek 	    "\t[-m mark_interval] [-P file_list] [-p log_socket\n"
6583e07920fSDavid van Moolenbroek 	    "\t[-p log_socket2 ...]] [-t chroot_dir] [-u user]\n",
6593e07920fSDavid van Moolenbroek 	    getprogname());
6603e07920fSDavid van Moolenbroek 	exit(1);
6613e07920fSDavid van Moolenbroek }
6623e07920fSDavid van Moolenbroek 
6633e07920fSDavid van Moolenbroek /*
6643e07920fSDavid van Moolenbroek  * Dispatch routine for reading /dev/klog
6653e07920fSDavid van Moolenbroek  *
6663e07920fSDavid van Moolenbroek  * Note: slightly different semantic in dispatch_read functions:
6673e07920fSDavid van Moolenbroek  *	 - read_klog() might give multiple messages in linebuf and
6683e07920fSDavid van Moolenbroek  *	   leaves the task of splitting them to printsys()
6693e07920fSDavid van Moolenbroek  *	 - all other read functions receive one message and
6703e07920fSDavid van Moolenbroek  *	   then call printline() with one buffer.
6713e07920fSDavid van Moolenbroek  */
6723e07920fSDavid van Moolenbroek static void
dispatch_read_klog(int fd,short event,void * ev)6733e07920fSDavid van Moolenbroek dispatch_read_klog(int fd, short event, void *ev)
6743e07920fSDavid van Moolenbroek {
6753e07920fSDavid van Moolenbroek 	ssize_t rv;
6763e07920fSDavid van Moolenbroek 	size_t resid = linebufsize - klog_linebufoff;
6773e07920fSDavid van Moolenbroek 
6783e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_EVENT), "Kernel log active (%d, %d, %p)"
6793e07920fSDavid van Moolenbroek 		" with linebuf@%p, length %zu)\n", fd, event, ev,
6803e07920fSDavid van Moolenbroek 		klog_linebuf, linebufsize);
6813e07920fSDavid van Moolenbroek 
6823e07920fSDavid van Moolenbroek 	rv = read(fd, &klog_linebuf[klog_linebufoff], resid - 1);
6833e07920fSDavid van Moolenbroek 	if (rv > 0) {
6843e07920fSDavid van Moolenbroek 		klog_linebuf[klog_linebufoff + rv] = '\0';
6853e07920fSDavid van Moolenbroek 		printsys(klog_linebuf);
6863e07920fSDavid van Moolenbroek 	} else if (rv < 0 && errno != EINTR) {
6873e07920fSDavid van Moolenbroek 		/*
6883e07920fSDavid van Moolenbroek 		 * /dev/klog has croaked.  Disable the event
6893e07920fSDavid van Moolenbroek 		 * so it won't bother us again.
6903e07920fSDavid van Moolenbroek 		 */
6913e07920fSDavid van Moolenbroek 		logerror("klog failed");
6923e07920fSDavid van Moolenbroek 		event_del(ev);
6933e07920fSDavid van Moolenbroek 	}
6943e07920fSDavid van Moolenbroek }
6953e07920fSDavid van Moolenbroek 
6963e07920fSDavid van Moolenbroek /*
6973e07920fSDavid van Moolenbroek  * Dispatch routine for reading Unix domain sockets.
6983e07920fSDavid van Moolenbroek  */
6993e07920fSDavid van Moolenbroek static void
dispatch_read_funix(int fd,short event,void * ev)7003e07920fSDavid van Moolenbroek dispatch_read_funix(int fd, short event, void *ev)
7013e07920fSDavid van Moolenbroek {
7023e07920fSDavid van Moolenbroek 	struct sockaddr_un myname, fromunix;
7033e07920fSDavid van Moolenbroek 	ssize_t rv;
7043e07920fSDavid van Moolenbroek 	socklen_t sunlen;
7053e07920fSDavid van Moolenbroek 
7063e07920fSDavid van Moolenbroek 	sunlen = sizeof(myname);
7073e07920fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&myname, &sunlen) != 0) {
7083e07920fSDavid van Moolenbroek 		/*
7093e07920fSDavid van Moolenbroek 		 * This should never happen, so ensure that it doesn't
7103e07920fSDavid van Moolenbroek 		 * happen again.
7113e07920fSDavid van Moolenbroek 		 */
7123e07920fSDavid van Moolenbroek 		logerror("getsockname() unix failed");
7133e07920fSDavid van Moolenbroek 		event_del(ev);
7143e07920fSDavid van Moolenbroek 		return;
7153e07920fSDavid van Moolenbroek 	}
7163e07920fSDavid van Moolenbroek 
717*0a6a1f1dSLionel Sambuc #define SUN_PATHLEN(su) \
718*0a6a1f1dSLionel Sambuc 	((su)->sun_len - (sizeof(*(su)) - sizeof((su)->sun_path)))
719*0a6a1f1dSLionel Sambuc 
7203e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_EVENT|D_NET), "Unix socket (%.*s) active (%d, %d %p)"
721*0a6a1f1dSLionel Sambuc 		" with linebuf@%p, size %zu)\n", (int)SUN_PATHLEN(&myname),
7223e07920fSDavid van Moolenbroek 		myname.sun_path, fd, event, ev, linebuf, linebufsize-1);
7233e07920fSDavid van Moolenbroek 
7243e07920fSDavid van Moolenbroek 	sunlen = sizeof(fromunix);
7253e07920fSDavid van Moolenbroek 	rv = recvfrom(fd, linebuf, linebufsize-1, 0,
7263e07920fSDavid van Moolenbroek 	    (struct sockaddr *)&fromunix, &sunlen);
7273e07920fSDavid van Moolenbroek 	if (rv > 0) {
7283e07920fSDavid van Moolenbroek 		linebuf[rv] = '\0';
7293e07920fSDavid van Moolenbroek 		printline(LocalFQDN, linebuf, 0);
7303e07920fSDavid van Moolenbroek 	} else if (rv < 0 && errno != EINTR) {
7313e07920fSDavid van Moolenbroek 		logerror("recvfrom() unix `%.*s'",
732*0a6a1f1dSLionel Sambuc 			(int)SUN_PATHLEN(&myname), myname.sun_path);
7333e07920fSDavid van Moolenbroek 	}
7343e07920fSDavid van Moolenbroek }
7353e07920fSDavid van Moolenbroek 
7363e07920fSDavid van Moolenbroek /*
7373e07920fSDavid van Moolenbroek  * Dispatch routine for reading Internet sockets.
7383e07920fSDavid van Moolenbroek  */
7393e07920fSDavid van Moolenbroek static void
dispatch_read_finet(int fd,short event,void * ev)7403e07920fSDavid van Moolenbroek dispatch_read_finet(int fd, short event, void *ev)
7413e07920fSDavid van Moolenbroek {
7423e07920fSDavid van Moolenbroek #ifdef LIBWRAP
7433e07920fSDavid van Moolenbroek 	struct request_info req;
7443e07920fSDavid van Moolenbroek #endif
7453e07920fSDavid van Moolenbroek 	struct sockaddr_storage frominet;
7463e07920fSDavid van Moolenbroek 	ssize_t rv;
7473e07920fSDavid van Moolenbroek 	socklen_t len;
7483e07920fSDavid van Moolenbroek 	int reject = 0;
7493e07920fSDavid van Moolenbroek 
7503e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_EVENT|D_NET), "inet socket active (%d, %d %p) "
7513e07920fSDavid van Moolenbroek 		" with linebuf@%p, size %zu)\n",
7523e07920fSDavid van Moolenbroek 		fd, event, ev, linebuf, linebufsize-1);
7533e07920fSDavid van Moolenbroek 
7543e07920fSDavid van Moolenbroek #ifdef LIBWRAP
7553e07920fSDavid van Moolenbroek 	request_init(&req, RQ_DAEMON, appname, RQ_FILE, fd, NULL);
7563e07920fSDavid van Moolenbroek 	fromhost(&req);
7573e07920fSDavid van Moolenbroek 	reject = !hosts_access(&req);
7583e07920fSDavid van Moolenbroek 	if (reject)
7593e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "access denied\n");
7603e07920fSDavid van Moolenbroek #endif
7613e07920fSDavid van Moolenbroek 
7623e07920fSDavid van Moolenbroek 	len = sizeof(frominet);
7633e07920fSDavid van Moolenbroek 	rv = recvfrom(fd, linebuf, linebufsize-1, 0,
7643e07920fSDavid van Moolenbroek 	    (struct sockaddr *)&frominet, &len);
7653e07920fSDavid van Moolenbroek 	if (rv == 0 || (rv < 0 && errno == EINTR))
7663e07920fSDavid van Moolenbroek 		return;
7673e07920fSDavid van Moolenbroek 	else if (rv < 0) {
7683e07920fSDavid van Moolenbroek 		logerror("recvfrom inet");
7693e07920fSDavid van Moolenbroek 		return;
7703e07920fSDavid van Moolenbroek 	}
7713e07920fSDavid van Moolenbroek 
7723e07920fSDavid van Moolenbroek 	linebuf[rv] = '\0';
7733e07920fSDavid van Moolenbroek 	if (!reject)
7743e07920fSDavid van Moolenbroek 		printline(cvthname(&frominet), linebuf,
7753e07920fSDavid van Moolenbroek 		    RemoteAddDate ? ADDDATE : 0);
7763e07920fSDavid van Moolenbroek }
7773e07920fSDavid van Moolenbroek 
7783e07920fSDavid van Moolenbroek /*
7793e07920fSDavid van Moolenbroek  * given a pointer to an array of char *'s, a pointer to its current
7803e07920fSDavid van Moolenbroek  * size and current allocated max size, and a new char * to add, add
7813e07920fSDavid van Moolenbroek  * it, update everything as necessary, possibly allocating a new array
7823e07920fSDavid van Moolenbroek  */
7833e07920fSDavid van Moolenbroek void
logpath_add(char *** lp,int * szp,int * maxszp,const char * new)7843e07920fSDavid van Moolenbroek logpath_add(char ***lp, int *szp, int *maxszp, const char *new)
7853e07920fSDavid van Moolenbroek {
7863e07920fSDavid van Moolenbroek 	char **nlp;
7873e07920fSDavid van Moolenbroek 	int newmaxsz;
7883e07920fSDavid van Moolenbroek 
7893e07920fSDavid van Moolenbroek 	DPRINTF(D_FILE, "Adding `%s' to the %p logpath list\n", new, *lp);
7903e07920fSDavid van Moolenbroek 	if (*szp == *maxszp) {
7913e07920fSDavid van Moolenbroek 		if (*maxszp == 0) {
7923e07920fSDavid van Moolenbroek 			newmaxsz = 4;	/* start of with enough for now */
7933e07920fSDavid van Moolenbroek 			*lp = NULL;
7943e07920fSDavid van Moolenbroek 		} else
7953e07920fSDavid van Moolenbroek 			newmaxsz = *maxszp * 2;
7963e07920fSDavid van Moolenbroek 		nlp = realloc(*lp, sizeof(char *) * (newmaxsz + 1));
7973e07920fSDavid van Moolenbroek 		if (nlp == NULL) {
7983e07920fSDavid van Moolenbroek 			logerror("Couldn't allocate line buffer");
7993e07920fSDavid van Moolenbroek 			die(0, 0, NULL);
8003e07920fSDavid van Moolenbroek 		}
8013e07920fSDavid van Moolenbroek 		*lp = nlp;
8023e07920fSDavid van Moolenbroek 		*maxszp = newmaxsz;
8033e07920fSDavid van Moolenbroek 	}
8043e07920fSDavid van Moolenbroek 	if (((*lp)[(*szp)++] = strdup(new)) == NULL) {
8053e07920fSDavid van Moolenbroek 		logerror("Couldn't allocate logpath");
8063e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
8073e07920fSDavid van Moolenbroek 	}
8083e07920fSDavid van Moolenbroek 	(*lp)[(*szp)] = NULL;		/* always keep it NULL terminated */
8093e07920fSDavid van Moolenbroek }
8103e07920fSDavid van Moolenbroek 
8113e07920fSDavid van Moolenbroek /* do a file of log sockets */
8123e07920fSDavid van Moolenbroek void
logpath_fileadd(char *** lp,int * szp,int * maxszp,const char * file)8133e07920fSDavid van Moolenbroek logpath_fileadd(char ***lp, int *szp, int *maxszp, const char *file)
8143e07920fSDavid van Moolenbroek {
8153e07920fSDavid van Moolenbroek 	FILE *fp;
8163e07920fSDavid van Moolenbroek 	char *line;
8173e07920fSDavid van Moolenbroek 	size_t len;
8183e07920fSDavid van Moolenbroek 
8193e07920fSDavid van Moolenbroek 	fp = fopen(file, "r");
8203e07920fSDavid van Moolenbroek 	if (fp == NULL) {
8213e07920fSDavid van Moolenbroek 		logerror("Could not open socket file list `%s'", file);
8223e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
8233e07920fSDavid van Moolenbroek 	}
8243e07920fSDavid van Moolenbroek 
8253e07920fSDavid van Moolenbroek 	while ((line = fgetln(fp, &len)) != NULL) {
8263e07920fSDavid van Moolenbroek 		line[len - 1] = 0;
8273e07920fSDavid van Moolenbroek 		logpath_add(lp, szp, maxszp, line);
8283e07920fSDavid van Moolenbroek 	}
8293e07920fSDavid van Moolenbroek 	fclose(fp);
8303e07920fSDavid van Moolenbroek }
8313e07920fSDavid van Moolenbroek 
8323e07920fSDavid van Moolenbroek /*
8333e07920fSDavid van Moolenbroek  * checks UTF-8 codepoint
8343e07920fSDavid van Moolenbroek  * returns either its length in bytes or 0 if *input is invalid
8353e07920fSDavid van Moolenbroek */
8363e07920fSDavid van Moolenbroek unsigned
valid_utf8(const char * c)8373e07920fSDavid van Moolenbroek valid_utf8(const char *c) {
8383e07920fSDavid van Moolenbroek 	unsigned rc, nb;
8393e07920fSDavid van Moolenbroek 
8403e07920fSDavid van Moolenbroek 	/* first byte gives sequence length */
8413e07920fSDavid van Moolenbroek 	     if ((*c & 0x80) == 0x00) return 1; /* 0bbbbbbb -- ASCII */
8423e07920fSDavid van Moolenbroek 	else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */
8433e07920fSDavid van Moolenbroek 	else if ((*c & 0xe0) == 0xc0) nb = 2;	/* 110bbbbb */
8443e07920fSDavid van Moolenbroek 	else if ((*c & 0xf0) == 0xe0) nb = 3;	/* 1110bbbb */
8453e07920fSDavid van Moolenbroek 	else if ((*c & 0xf8) == 0xf0) nb = 4;	/* 11110bbb */
8463e07920fSDavid van Moolenbroek 	else return 0; /* UTF-8 allows only up to 4 bytes */
8473e07920fSDavid van Moolenbroek 
8483e07920fSDavid van Moolenbroek 	/* catch overlong encodings */
8493e07920fSDavid van Moolenbroek 	if ((*c & 0xfe) == 0xc0)
8503e07920fSDavid van Moolenbroek 		return 0; /* 1100000b ... */
8513e07920fSDavid van Moolenbroek 	else if (((*c & 0xff) == 0xe0) && ((*(c+1) & 0xe0) == 0x80))
8523e07920fSDavid van Moolenbroek 		return 0; /* 11100000 100bbbbb ... */
8533e07920fSDavid van Moolenbroek 	else if (((*c & 0xff) == 0xf0) && ((*(c+1) & 0xf0) == 0x80))
8543e07920fSDavid van Moolenbroek 		return 0; /* 11110000 1000bbbb ... ... */
8553e07920fSDavid van Moolenbroek 
8563e07920fSDavid van Moolenbroek 	/* and also filter UTF-16 surrogates (=invalid in UTF-8) */
8573e07920fSDavid van Moolenbroek 	if (((*c & 0xff) == 0xed) && ((*(c+1) & 0xe0) == 0xa0))
8583e07920fSDavid van Moolenbroek 		return 0; /* 11101101 101bbbbb ... */
8593e07920fSDavid van Moolenbroek 
8603e07920fSDavid van Moolenbroek 	rc = nb;
8613e07920fSDavid van Moolenbroek 	/* check trailing bytes */
8623e07920fSDavid van Moolenbroek 	switch (nb) {
8633e07920fSDavid van Moolenbroek 	default: return 0;
8643e07920fSDavid van Moolenbroek 	case 4: if ((*(c+3) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
8653e07920fSDavid van Moolenbroek 	case 3: if ((*(c+2) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
8663e07920fSDavid van Moolenbroek 	case 2: if ((*(c+1) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
8673e07920fSDavid van Moolenbroek 	}
8683e07920fSDavid van Moolenbroek 	return rc;
8693e07920fSDavid van Moolenbroek }
8703e07920fSDavid van Moolenbroek #define UTF8CHARMAX 4
8713e07920fSDavid van Moolenbroek 
8723e07920fSDavid van Moolenbroek /*
8733e07920fSDavid van Moolenbroek  * read UTF-8 value
8743e07920fSDavid van Moolenbroek  * returns a the codepoint number
8753e07920fSDavid van Moolenbroek  */
8763e07920fSDavid van Moolenbroek uint_fast32_t
get_utf8_value(const char * c)8773e07920fSDavid van Moolenbroek get_utf8_value(const char *c) {
8783e07920fSDavid van Moolenbroek 	uint_fast32_t sum;
8793e07920fSDavid van Moolenbroek 	unsigned nb, i;
8803e07920fSDavid van Moolenbroek 
8813e07920fSDavid van Moolenbroek 	/* first byte gives sequence length */
8823e07920fSDavid van Moolenbroek 	     if ((*c & 0x80) == 0x00) return *c;/* 0bbbbbbb -- ASCII */
8833e07920fSDavid van Moolenbroek 	else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */
8843e07920fSDavid van Moolenbroek 	else if ((*c & 0xe0) == 0xc0) {		/* 110bbbbb */
8853e07920fSDavid van Moolenbroek 		nb = 2;
8863e07920fSDavid van Moolenbroek 		sum = (*c & ~0xe0) & 0xff;
8873e07920fSDavid van Moolenbroek 	} else if ((*c & 0xf0) == 0xe0) {	/* 1110bbbb */
8883e07920fSDavid van Moolenbroek 		nb = 3;
8893e07920fSDavid van Moolenbroek 		sum = (*c & ~0xf0) & 0xff;
8903e07920fSDavid van Moolenbroek 	} else if ((*c & 0xf8) == 0xf0) {	/* 11110bbb */
8913e07920fSDavid van Moolenbroek 		nb = 4;
8923e07920fSDavid van Moolenbroek 		sum = (*c & ~0xf8) & 0xff;
8933e07920fSDavid van Moolenbroek 	} else return 0; /* UTF-8 allows only up to 4 bytes */
8943e07920fSDavid van Moolenbroek 
8953e07920fSDavid van Moolenbroek 	/* check trailing bytes -- 10bbbbbb */
8963e07920fSDavid van Moolenbroek 	i = 1;
8973e07920fSDavid van Moolenbroek 	while (i < nb) {
8983e07920fSDavid van Moolenbroek 		sum <<= 6;
8993e07920fSDavid van Moolenbroek 		sum |= ((*(c+i) & ~0xc0) & 0xff);
9003e07920fSDavid van Moolenbroek 		i++;
9013e07920fSDavid van Moolenbroek 	}
9023e07920fSDavid van Moolenbroek 	return sum;
9033e07920fSDavid van Moolenbroek }
9043e07920fSDavid van Moolenbroek 
9053e07920fSDavid van Moolenbroek /* note previous versions transscribe
9063e07920fSDavid van Moolenbroek  * control characters, e.g. \007 --> "^G"
9073e07920fSDavid van Moolenbroek  * did anyone rely on that?
9083e07920fSDavid van Moolenbroek  *
9093e07920fSDavid van Moolenbroek  * this new version works on only one buffer and
9103e07920fSDavid van Moolenbroek  * replaces control characters with a space
9113e07920fSDavid van Moolenbroek  */
9123e07920fSDavid van Moolenbroek #define NEXTFIELD(ptr) if (*(p) == ' ') (p)++; /* SP */			\
9133e07920fSDavid van Moolenbroek 		       else {						\
9143e07920fSDavid van Moolenbroek 				DPRINTF(D_DATA, "format error\n");	\
9153e07920fSDavid van Moolenbroek 				if (*(p) == '\0') start = (p);		\
9163e07920fSDavid van Moolenbroek 				goto all_syslog_msg;			\
9173e07920fSDavid van Moolenbroek 		       }
9183e07920fSDavid van Moolenbroek #define FORCE2ASCII(c) ((iscntrl((unsigned char)(c)) && (c) != '\t')	\
9193e07920fSDavid van Moolenbroek 			? ((c) == '\n' ? ' ' : '?')			\
9203e07920fSDavid van Moolenbroek 			: (c) & 0177)
9213e07920fSDavid van Moolenbroek 
9223e07920fSDavid van Moolenbroek /* following syslog-protocol */
9233e07920fSDavid van Moolenbroek #define printusascii(ch) (ch >= 33 && ch <= 126)
9243e07920fSDavid van Moolenbroek #define sdname(ch) (ch != '=' && ch != ' ' \
9253e07920fSDavid van Moolenbroek 		 && ch != ']' && ch != '"' \
9263e07920fSDavid van Moolenbroek 		 && printusascii(ch))
9273e07920fSDavid van Moolenbroek 
9283e07920fSDavid van Moolenbroek /* checks whether the first word of string p can be interpreted as
9293e07920fSDavid van Moolenbroek  * a syslog-protocol MSGID and if so returns its length.
9303e07920fSDavid van Moolenbroek  *
9313e07920fSDavid van Moolenbroek  * otherwise returns 0
9323e07920fSDavid van Moolenbroek  */
9333e07920fSDavid van Moolenbroek static unsigned
check_msgid(char * p)9343e07920fSDavid van Moolenbroek check_msgid(char *p)
9353e07920fSDavid van Moolenbroek {
9363e07920fSDavid van Moolenbroek 	char *q = p;
9373e07920fSDavid van Moolenbroek 
9383e07920fSDavid van Moolenbroek 	/* consider the NILVALUE to be valid */
9393e07920fSDavid van Moolenbroek 	if (*q == '-' && *(q+1) == ' ')
9403e07920fSDavid van Moolenbroek 		return 1;
9413e07920fSDavid van Moolenbroek 
9423e07920fSDavid van Moolenbroek 	for (;;) {
9433e07920fSDavid van Moolenbroek 		if (*q == ' ')
9443e07920fSDavid van Moolenbroek 			return q - p;
9453e07920fSDavid van Moolenbroek 		else if (*q == '\0' || !printusascii(*q) || q - p >= MSGID_MAX)
9463e07920fSDavid van Moolenbroek 			return 0;
9473e07920fSDavid van Moolenbroek 		else
9483e07920fSDavid van Moolenbroek 			q++;
9493e07920fSDavid van Moolenbroek 	}
9503e07920fSDavid van Moolenbroek }
9513e07920fSDavid van Moolenbroek 
9523e07920fSDavid van Moolenbroek /*
9533e07920fSDavid van Moolenbroek  * returns number of chars found in SD at beginning of string p
9543e07920fSDavid van Moolenbroek  * thus returns 0 if no valid SD is found
9553e07920fSDavid van Moolenbroek  *
9563e07920fSDavid van Moolenbroek  * if ascii == true then substitute all non-ASCII chars
9573e07920fSDavid van Moolenbroek  * otherwise use syslog-protocol rules to allow UTF-8 in values
9583e07920fSDavid van Moolenbroek  * note: one pass for filtering and scanning, so a found SD
9593e07920fSDavid van Moolenbroek  * is always filtered, but an invalid one could be partially
9603e07920fSDavid van Moolenbroek  * filtered up to the format error.
9613e07920fSDavid van Moolenbroek  */
9623e07920fSDavid van Moolenbroek static unsigned
check_sd(char * p)9633e07920fSDavid van Moolenbroek check_sd(char* p)
9643e07920fSDavid van Moolenbroek {
9653e07920fSDavid van Moolenbroek 	char *q = p;
9663e07920fSDavid van Moolenbroek 	bool esc = false;
9673e07920fSDavid van Moolenbroek 
9683e07920fSDavid van Moolenbroek 	/* consider the NILVALUE to be valid */
9693e07920fSDavid van Moolenbroek 	if (*q == '-' && (*(q+1) == ' ' || *(q+1) == '\0'))
9703e07920fSDavid van Moolenbroek 		return 1;
9713e07920fSDavid van Moolenbroek 
9723e07920fSDavid van Moolenbroek 	for(;;) { /* SD-ELEMENT */
9733e07920fSDavid van Moolenbroek 		if (*q++ != '[') return 0;
9743e07920fSDavid van Moolenbroek 		/* SD-ID */
9753e07920fSDavid van Moolenbroek 		if (!sdname(*q)) return 0;
9763e07920fSDavid van Moolenbroek 		while (sdname(*q)) {
9773e07920fSDavid van Moolenbroek 			*q = FORCE2ASCII(*q);
9783e07920fSDavid van Moolenbroek 			q++;
9793e07920fSDavid van Moolenbroek 		}
9803e07920fSDavid van Moolenbroek 		for(;;) { /* SD-PARAM */
9813e07920fSDavid van Moolenbroek 			if (*q == ']') {
9823e07920fSDavid van Moolenbroek 				q++;
9833e07920fSDavid van Moolenbroek 				if (*q == ' ' || *q == '\0') return q - p;
9843e07920fSDavid van Moolenbroek 				else if (*q == '[') break;
9853e07920fSDavid van Moolenbroek 			} else if (*q++ != ' ') return 0;
9863e07920fSDavid van Moolenbroek 
9873e07920fSDavid van Moolenbroek 			/* PARAM-NAME */
9883e07920fSDavid van Moolenbroek 			if (!sdname(*q)) return 0;
9893e07920fSDavid van Moolenbroek 			while (sdname(*q)) {
9903e07920fSDavid van Moolenbroek 				*q = FORCE2ASCII(*q);
9913e07920fSDavid van Moolenbroek 				q++;
9923e07920fSDavid van Moolenbroek 			}
9933e07920fSDavid van Moolenbroek 
9943e07920fSDavid van Moolenbroek 			if (*q++ != '=') return 0;
9953e07920fSDavid van Moolenbroek 			if (*q++ != '"') return 0;
9963e07920fSDavid van Moolenbroek 
9973e07920fSDavid van Moolenbroek 			for(;;) { /* PARAM-VALUE */
9983e07920fSDavid van Moolenbroek 				if (esc) {
9993e07920fSDavid van Moolenbroek 					esc = false;
10003e07920fSDavid van Moolenbroek 					if (*q == '\\' || *q == '"' ||
10013e07920fSDavid van Moolenbroek 					    *q == ']') {
10023e07920fSDavid van Moolenbroek 						q++;
10033e07920fSDavid van Moolenbroek 						continue;
10043e07920fSDavid van Moolenbroek 					}
10053e07920fSDavid van Moolenbroek 					/* no else because invalid
10063e07920fSDavid van Moolenbroek 					 * escape sequences are accepted */
10073e07920fSDavid van Moolenbroek 				}
10083e07920fSDavid van Moolenbroek 				else if (*q == '"') break;
10093e07920fSDavid van Moolenbroek 				else if (*q == '\0' || *q == ']') return 0;
10103e07920fSDavid van Moolenbroek 				else if (*q == '\\') esc = true;
10113e07920fSDavid van Moolenbroek 				else {
10123e07920fSDavid van Moolenbroek 					int i;
10133e07920fSDavid van Moolenbroek 					i = valid_utf8(q);
10143e07920fSDavid van Moolenbroek 					if (i == 0)
10153e07920fSDavid van Moolenbroek 						*q = '?';
10163e07920fSDavid van Moolenbroek 					else if (i == 1)
10173e07920fSDavid van Moolenbroek 						*q = FORCE2ASCII(*q);
10183e07920fSDavid van Moolenbroek 					else /* multi byte char */
10193e07920fSDavid van Moolenbroek 						q += (i-1);
10203e07920fSDavid van Moolenbroek 				}
10213e07920fSDavid van Moolenbroek 				q++;
10223e07920fSDavid van Moolenbroek 			}
10233e07920fSDavid van Moolenbroek 			q++;
10243e07920fSDavid van Moolenbroek 		}
10253e07920fSDavid van Moolenbroek 	}
10263e07920fSDavid van Moolenbroek }
10273e07920fSDavid van Moolenbroek 
10283e07920fSDavid van Moolenbroek struct buf_msg *
printline_syslogprotocol(const char * hname,char * msg,int flags,int pri)10293e07920fSDavid van Moolenbroek printline_syslogprotocol(const char *hname, char *msg,
10303e07920fSDavid van Moolenbroek 	int flags, int pri)
10313e07920fSDavid van Moolenbroek {
10323e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
10333e07920fSDavid van Moolenbroek 	char *p, *start;
10343e07920fSDavid van Moolenbroek 	unsigned sdlen = 0, i = 0;
10353e07920fSDavid van Moolenbroek 	bool utf8allowed = false; /* for some fields */
10363e07920fSDavid van Moolenbroek 
10373e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_syslogprotocol("
10383e07920fSDavid van Moolenbroek 	    "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
10393e07920fSDavid van Moolenbroek 
10403e07920fSDavid van Moolenbroek 	buffer = buf_msg_new(0);
10413e07920fSDavid van Moolenbroek 	p = msg;
10423e07920fSDavid van Moolenbroek 	p += check_timestamp((unsigned char*) p,
10433e07920fSDavid van Moolenbroek 		&buffer->timestamp, true, !BSDOutputFormat);
10443e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp);
10453e07920fSDavid van Moolenbroek 
10463e07920fSDavid van Moolenbroek 	if (flags & ADDDATE) {
10473e07920fSDavid van Moolenbroek 		FREEPTR(buffer->timestamp);
1048*0a6a1f1dSLionel Sambuc 		buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
10493e07920fSDavid van Moolenbroek 	}
10503e07920fSDavid van Moolenbroek 
10513e07920fSDavid van Moolenbroek 	start = p;
10523e07920fSDavid van Moolenbroek 	NEXTFIELD(p);
10533e07920fSDavid van Moolenbroek 	/* extract host */
10543e07920fSDavid van Moolenbroek 	for (start = p;; p++) {
10553e07920fSDavid van Moolenbroek 		if ((*p == ' ' || *p == '\0')
10563e07920fSDavid van Moolenbroek 		    && start == p-1 && *(p-1) == '-') {
10573e07920fSDavid van Moolenbroek 			/* NILVALUE */
10583e07920fSDavid van Moolenbroek 			break;
10593e07920fSDavid van Moolenbroek 		} else if ((*p == ' ' || *p == '\0')
10603e07920fSDavid van Moolenbroek 		    && (start != p-1 || *(p-1) != '-')) {
10613e07920fSDavid van Moolenbroek 			buffer->host = strndup(start, p - start);
10623e07920fSDavid van Moolenbroek 			break;
10633e07920fSDavid van Moolenbroek 		} else {
10643e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
10653e07920fSDavid van Moolenbroek 		}
10663e07920fSDavid van Moolenbroek 	}
10673e07920fSDavid van Moolenbroek 	/* p @ SP after host */
10683e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host);
10693e07920fSDavid van Moolenbroek 
10703e07920fSDavid van Moolenbroek 	/* extract app-name */
10713e07920fSDavid van Moolenbroek 	NEXTFIELD(p);
10723e07920fSDavid van Moolenbroek 	for (start = p;; p++) {
10733e07920fSDavid van Moolenbroek 		if ((*p == ' ' || *p == '\0')
10743e07920fSDavid van Moolenbroek 		    && start == p-1 && *(p-1) == '-') {
10753e07920fSDavid van Moolenbroek 			/* NILVALUE */
10763e07920fSDavid van Moolenbroek 			break;
10773e07920fSDavid van Moolenbroek 		} else if ((*p == ' ' || *p == '\0')
10783e07920fSDavid van Moolenbroek 		    && (start != p-1 || *(p-1) != '-')) {
10793e07920fSDavid van Moolenbroek 			buffer->prog = strndup(start, p - start);
10803e07920fSDavid van Moolenbroek 			break;
10813e07920fSDavid van Moolenbroek 		} else {
10823e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
10833e07920fSDavid van Moolenbroek 		}
10843e07920fSDavid van Moolenbroek 	}
10853e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog);
10863e07920fSDavid van Moolenbroek 
10873e07920fSDavid van Moolenbroek 	/* extract procid */
10883e07920fSDavid van Moolenbroek 	NEXTFIELD(p);
10893e07920fSDavid van Moolenbroek 	for (start = p;; p++) {
10903e07920fSDavid van Moolenbroek 		if ((*p == ' ' || *p == '\0')
10913e07920fSDavid van Moolenbroek 		    && start == p-1 && *(p-1) == '-') {
10923e07920fSDavid van Moolenbroek 			/* NILVALUE */
10933e07920fSDavid van Moolenbroek 			break;
10943e07920fSDavid van Moolenbroek 		} else if ((*p == ' ' || *p == '\0')
10953e07920fSDavid van Moolenbroek 		    && (start != p-1 || *(p-1) != '-')) {
10963e07920fSDavid van Moolenbroek 			buffer->pid = strndup(start, p - start);
10973e07920fSDavid van Moolenbroek 			start = p;
10983e07920fSDavid van Moolenbroek 			break;
10993e07920fSDavid van Moolenbroek 		} else {
11003e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
11013e07920fSDavid van Moolenbroek 		}
11023e07920fSDavid van Moolenbroek 	}
11033e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid);
11043e07920fSDavid van Moolenbroek 
11053e07920fSDavid van Moolenbroek 	/* extract msgid */
11063e07920fSDavid van Moolenbroek 	NEXTFIELD(p);
11073e07920fSDavid van Moolenbroek 	for (start = p;; p++) {
11083e07920fSDavid van Moolenbroek 		if ((*p == ' ' || *p == '\0')
11093e07920fSDavid van Moolenbroek 		    && start == p-1 && *(p-1) == '-') {
11103e07920fSDavid van Moolenbroek 			/* NILVALUE */
11113e07920fSDavid van Moolenbroek 			start = p+1;
11123e07920fSDavid van Moolenbroek 			break;
11133e07920fSDavid van Moolenbroek 		} else if ((*p == ' ' || *p == '\0')
11143e07920fSDavid van Moolenbroek 		    && (start != p-1 || *(p-1) != '-')) {
11153e07920fSDavid van Moolenbroek 			buffer->msgid = strndup(start, p - start);
11163e07920fSDavid van Moolenbroek 			start = p+1;
11173e07920fSDavid van Moolenbroek 			break;
11183e07920fSDavid van Moolenbroek 		} else {
11193e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
11203e07920fSDavid van Moolenbroek 		}
11213e07920fSDavid van Moolenbroek 	}
11223e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got msgid \"%s\"\n", buffer->msgid);
11233e07920fSDavid van Moolenbroek 
11243e07920fSDavid van Moolenbroek 	/* extract SD */
11253e07920fSDavid van Moolenbroek 	NEXTFIELD(p);
11263e07920fSDavid van Moolenbroek 	start = p;
11273e07920fSDavid van Moolenbroek 	sdlen = check_sd(p);
11283e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "check_sd(\"%s\") returned %d\n", p, sdlen);
11293e07920fSDavid van Moolenbroek 
11303e07920fSDavid van Moolenbroek 	if (sdlen == 1 && *p == '-') {
11313e07920fSDavid van Moolenbroek 		/* NILVALUE */
11323e07920fSDavid van Moolenbroek 		p++;
11333e07920fSDavid van Moolenbroek 	} else if (sdlen > 1) {
11343e07920fSDavid van Moolenbroek 		buffer->sd = strndup(p, sdlen);
11353e07920fSDavid van Moolenbroek 		p += sdlen;
11363e07920fSDavid van Moolenbroek 	} else {
11373e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "format error\n");
11383e07920fSDavid van Moolenbroek 	}
11393e07920fSDavid van Moolenbroek 	if	(*p == '\0') start = p;
11403e07920fSDavid van Moolenbroek 	else if (*p == ' ')  start = ++p; /* SP */
11413e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
11423e07920fSDavid van Moolenbroek 
11433e07920fSDavid van Moolenbroek 	/* and now the message itself
11443e07920fSDavid van Moolenbroek 	 * note: move back to last start to check for BOM
11453e07920fSDavid van Moolenbroek 	 */
11463e07920fSDavid van Moolenbroek all_syslog_msg:
11473e07920fSDavid van Moolenbroek 	p = start;
11483e07920fSDavid van Moolenbroek 
11493e07920fSDavid van Moolenbroek 	/* check for UTF-8-BOM */
11503e07920fSDavid van Moolenbroek 	if (IS_BOM(p)) {
11513e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "UTF-8 BOM\n");
11523e07920fSDavid van Moolenbroek 		utf8allowed = true;
11533e07920fSDavid van Moolenbroek 		p += 3;
11543e07920fSDavid van Moolenbroek 	}
11553e07920fSDavid van Moolenbroek 
11563e07920fSDavid van Moolenbroek 	if (*p != '\0' && !utf8allowed) {
11573e07920fSDavid van Moolenbroek 		size_t msglen;
11583e07920fSDavid van Moolenbroek 
11593e07920fSDavid van Moolenbroek 		msglen = strlen(p);
11603e07920fSDavid van Moolenbroek 		assert(!buffer->msg);
11613e07920fSDavid van Moolenbroek 		buffer->msg = copy_utf8_ascii(p, msglen);
11623e07920fSDavid van Moolenbroek 		buffer->msgorig = buffer->msg;
11633e07920fSDavid van Moolenbroek 		buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
11643e07920fSDavid van Moolenbroek 	} else if (*p != '\0' && utf8allowed) {
11653e07920fSDavid van Moolenbroek 		while (*p != '\0') {
11663e07920fSDavid van Moolenbroek 			i = valid_utf8(p);
11673e07920fSDavid van Moolenbroek 			if (i == 0)
11683e07920fSDavid van Moolenbroek 				*p++ = '?';
11693e07920fSDavid van Moolenbroek 			else if (i == 1)
11703e07920fSDavid van Moolenbroek 				*p = FORCE2ASCII(*p);
11713e07920fSDavid van Moolenbroek 			p += i;
11723e07920fSDavid van Moolenbroek 		}
11733e07920fSDavid van Moolenbroek 		assert(p != start);
11743e07920fSDavid van Moolenbroek 		assert(!buffer->msg);
11753e07920fSDavid van Moolenbroek 		buffer->msg = strndup(start, p - start);
11763e07920fSDavid van Moolenbroek 		buffer->msgorig = buffer->msg;
11773e07920fSDavid van Moolenbroek 		buffer->msglen = buffer->msgsize = 1 + p - start;
11783e07920fSDavid van Moolenbroek 	}
11793e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
11803e07920fSDavid van Moolenbroek 
11813e07920fSDavid van Moolenbroek 	buffer->recvhost = strdup(hname);
11823e07920fSDavid van Moolenbroek 	buffer->pri = pri;
11833e07920fSDavid van Moolenbroek 	buffer->flags = flags;
11843e07920fSDavid van Moolenbroek 
11853e07920fSDavid van Moolenbroek 	return buffer;
11863e07920fSDavid van Moolenbroek }
11873e07920fSDavid van Moolenbroek 
11883e07920fSDavid van Moolenbroek /* copies an input into a new ASCII buffer
11893e07920fSDavid van Moolenbroek  * ASCII controls are converted to format "^X"
11903e07920fSDavid van Moolenbroek  * multi-byte UTF-8 chars are converted to format "<ab><cd>"
11913e07920fSDavid van Moolenbroek  */
11923e07920fSDavid van Moolenbroek #define INIT_BUFSIZE 512
11933e07920fSDavid van Moolenbroek char *
copy_utf8_ascii(char * p,size_t p_len)11943e07920fSDavid van Moolenbroek copy_utf8_ascii(char *p, size_t p_len)
11953e07920fSDavid van Moolenbroek {
11963e07920fSDavid van Moolenbroek 	size_t idst = 0, isrc = 0, dstsize = INIT_BUFSIZE, i;
11973e07920fSDavid van Moolenbroek 	char *dst, *tmp_dst;
11983e07920fSDavid van Moolenbroek 
11993e07920fSDavid van Moolenbroek 	MALLOC(dst, dstsize);
12003e07920fSDavid van Moolenbroek 	while (isrc < p_len) {
12013e07920fSDavid van Moolenbroek 		if (dstsize < idst + 10) {
12023e07920fSDavid van Moolenbroek 			/* check for enough space for \0 and a UTF-8
12033e07920fSDavid van Moolenbroek 			 * conversion; longest possible is <U+123456> */
12043e07920fSDavid van Moolenbroek 			tmp_dst = realloc(dst, dstsize + INIT_BUFSIZE);
12053e07920fSDavid van Moolenbroek 			if (!tmp_dst)
12063e07920fSDavid van Moolenbroek 				break;
12073e07920fSDavid van Moolenbroek 			dst = tmp_dst;
12083e07920fSDavid van Moolenbroek 			dstsize += INIT_BUFSIZE;
12093e07920fSDavid van Moolenbroek 		}
12103e07920fSDavid van Moolenbroek 
12113e07920fSDavid van Moolenbroek 		i = valid_utf8(&p[isrc]);
12123e07920fSDavid van Moolenbroek 		if (i == 0) { /* invalid encoding */
12133e07920fSDavid van Moolenbroek 			dst[idst++] = '?';
12143e07920fSDavid van Moolenbroek 			isrc++;
12153e07920fSDavid van Moolenbroek 		} else if (i == 1) { /* check printable */
12163e07920fSDavid van Moolenbroek 			if (iscntrl((unsigned char)p[isrc])
12173e07920fSDavid van Moolenbroek 			 && p[isrc] != '\t') {
12183e07920fSDavid van Moolenbroek 				if (p[isrc] == '\n') {
12193e07920fSDavid van Moolenbroek 					dst[idst++] = ' ';
12203e07920fSDavid van Moolenbroek 					isrc++;
12213e07920fSDavid van Moolenbroek 				} else {
12223e07920fSDavid van Moolenbroek 					dst[idst++] = '^';
12233e07920fSDavid van Moolenbroek 					dst[idst++] = p[isrc++] ^ 0100;
12243e07920fSDavid van Moolenbroek 				}
12253e07920fSDavid van Moolenbroek 			} else
12263e07920fSDavid van Moolenbroek 				dst[idst++] = p[isrc++];
12273e07920fSDavid van Moolenbroek 		} else {  /* convert UTF-8 to ASCII */
12283e07920fSDavid van Moolenbroek 			dst[idst++] = '<';
12293e07920fSDavid van Moolenbroek 			idst += snprintf(&dst[idst], dstsize - idst, "U+%x",
12303e07920fSDavid van Moolenbroek 			    get_utf8_value(&p[isrc]));
12313e07920fSDavid van Moolenbroek 			isrc += i;
12323e07920fSDavid van Moolenbroek 			dst[idst++] = '>';
12333e07920fSDavid van Moolenbroek 		}
12343e07920fSDavid van Moolenbroek 	}
12353e07920fSDavid van Moolenbroek 	dst[idst] = '\0';
12363e07920fSDavid van Moolenbroek 
12373e07920fSDavid van Moolenbroek 	/* shrink buffer to right size */
12383e07920fSDavid van Moolenbroek 	tmp_dst = realloc(dst, idst+1);
12393e07920fSDavid van Moolenbroek 	if (tmp_dst)
12403e07920fSDavid van Moolenbroek 		return tmp_dst;
12413e07920fSDavid van Moolenbroek 	else
12423e07920fSDavid van Moolenbroek 		return dst;
12433e07920fSDavid van Moolenbroek }
12443e07920fSDavid van Moolenbroek 
12453e07920fSDavid van Moolenbroek struct buf_msg *
printline_bsdsyslog(const char * hname,char * msg,int flags,int pri)12463e07920fSDavid van Moolenbroek printline_bsdsyslog(const char *hname, char *msg,
12473e07920fSDavid van Moolenbroek 	int flags, int pri)
12483e07920fSDavid van Moolenbroek {
12493e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
12503e07920fSDavid van Moolenbroek 	char *p, *start;
12513e07920fSDavid van Moolenbroek 	unsigned msgidlen = 0, sdlen = 0;
12523e07920fSDavid van Moolenbroek 
12533e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_bsdsyslog("
12543e07920fSDavid van Moolenbroek 		"\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
12553e07920fSDavid van Moolenbroek 
12563e07920fSDavid van Moolenbroek 	buffer = buf_msg_new(0);
12573e07920fSDavid van Moolenbroek 	p = msg;
12583e07920fSDavid van Moolenbroek 	p += check_timestamp((unsigned char*) p,
12593e07920fSDavid van Moolenbroek 		&buffer->timestamp, false, !BSDOutputFormat);
12603e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp);
12613e07920fSDavid van Moolenbroek 
12623e07920fSDavid van Moolenbroek 	if (flags & ADDDATE || !buffer->timestamp) {
12633e07920fSDavid van Moolenbroek 		FREEPTR(buffer->timestamp);
1264*0a6a1f1dSLionel Sambuc 		buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
12653e07920fSDavid van Moolenbroek 	}
12663e07920fSDavid van Moolenbroek 
12673e07920fSDavid van Moolenbroek 	if (*p == ' ') p++; /* SP */
12683e07920fSDavid van Moolenbroek 	else goto all_bsd_msg;
12693e07920fSDavid van Moolenbroek 	/* in any error case we skip header parsing and
12703e07920fSDavid van Moolenbroek 	 * treat all following data as message content */
12713e07920fSDavid van Moolenbroek 
12723e07920fSDavid van Moolenbroek 	/* extract host */
12733e07920fSDavid van Moolenbroek 	for (start = p;; p++) {
12743e07920fSDavid van Moolenbroek 		if (*p == ' ' || *p == '\0') {
12753e07920fSDavid van Moolenbroek 			buffer->host = strndup(start, p - start);
12763e07920fSDavid van Moolenbroek 			break;
12773e07920fSDavid van Moolenbroek 		} else if (*p == '[' || (*p == ':'
12783e07920fSDavid van Moolenbroek 			&& (*(p+1) == ' ' || *(p+1) == '\0'))) {
12793e07920fSDavid van Moolenbroek 			/* no host in message */
12803e07920fSDavid van Moolenbroek 			buffer->host = LocalFQDN;
12813e07920fSDavid van Moolenbroek 			buffer->prog = strndup(start, p - start);
12823e07920fSDavid van Moolenbroek 			break;
12833e07920fSDavid van Moolenbroek 		} else {
12843e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
12853e07920fSDavid van Moolenbroek 		}
12863e07920fSDavid van Moolenbroek 	}
12873e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host);
12883e07920fSDavid van Moolenbroek 	/* p @ SP after host, or @ :/[ after prog */
12893e07920fSDavid van Moolenbroek 
12903e07920fSDavid van Moolenbroek 	/* extract program */
12913e07920fSDavid van Moolenbroek 	if (!buffer->prog) {
12923e07920fSDavid van Moolenbroek 		if (*p == ' ') p++; /* SP */
12933e07920fSDavid van Moolenbroek 		else goto all_bsd_msg;
12943e07920fSDavid van Moolenbroek 
12953e07920fSDavid van Moolenbroek 		for (start = p;; p++) {
12963e07920fSDavid van Moolenbroek 			if (*p == ' ' || *p == '\0') { /* error */
12973e07920fSDavid van Moolenbroek 				goto all_bsd_msg;
12983e07920fSDavid van Moolenbroek 			} else if (*p == '[' || (*p == ':'
12993e07920fSDavid van Moolenbroek 				&& (*(p+1) == ' ' || *(p+1) == '\0'))) {
13003e07920fSDavid van Moolenbroek 				buffer->prog = strndup(start, p - start);
13013e07920fSDavid van Moolenbroek 				break;
13023e07920fSDavid van Moolenbroek 			} else {
13033e07920fSDavid van Moolenbroek 				*p = FORCE2ASCII(*p);
13043e07920fSDavid van Moolenbroek 			}
13053e07920fSDavid van Moolenbroek 		}
13063e07920fSDavid van Moolenbroek 	}
13073e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog);
13083e07920fSDavid van Moolenbroek 	start = p;
13093e07920fSDavid van Moolenbroek 
13103e07920fSDavid van Moolenbroek 	/* p @ :/[ after prog */
13113e07920fSDavid van Moolenbroek 	if (*p == '[') {
13123e07920fSDavid van Moolenbroek 		p++;
13133e07920fSDavid van Moolenbroek 		if (*p == ' ') p++; /* SP */
13143e07920fSDavid van Moolenbroek 		for (start = p;; p++) {
13153e07920fSDavid van Moolenbroek 			if (*p == ' ' || *p == '\0') { /* error */
13163e07920fSDavid van Moolenbroek 				goto all_bsd_msg;
13173e07920fSDavid van Moolenbroek 			} else if (*p == ']') {
13183e07920fSDavid van Moolenbroek 				buffer->pid = strndup(start, p - start);
13193e07920fSDavid van Moolenbroek 				break;
13203e07920fSDavid van Moolenbroek 			} else {
13213e07920fSDavid van Moolenbroek 				*p = FORCE2ASCII(*p);
13223e07920fSDavid van Moolenbroek 			}
13233e07920fSDavid van Moolenbroek 		}
13243e07920fSDavid van Moolenbroek 	}
13253e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid);
13263e07920fSDavid van Moolenbroek 
13273e07920fSDavid van Moolenbroek 	if (*p == ']') p++;
13283e07920fSDavid van Moolenbroek 	if (*p == ':') p++;
13293e07920fSDavid van Moolenbroek 	if (*p == ' ') p++;
13303e07920fSDavid van Moolenbroek 
13313e07920fSDavid van Moolenbroek 	/* p @ msgid, @ opening [ of SD or @ first byte of message
13323e07920fSDavid van Moolenbroek 	 * accept either case and try to detect MSGID and SD fields
13333e07920fSDavid van Moolenbroek 	 *
13343e07920fSDavid van Moolenbroek 	 * only limitation: we do not accept UTF-8 data in
13353e07920fSDavid van Moolenbroek 	 * BSD Syslog messages -- so all SD values are ASCII-filtered
13363e07920fSDavid van Moolenbroek 	 *
13373e07920fSDavid van Moolenbroek 	 * I have found one scenario with 'unexpected' behaviour:
13383e07920fSDavid van Moolenbroek 	 * if there is only a SD intended, but a) it is short enough
13393e07920fSDavid van Moolenbroek 	 * to be a MSGID and b) the first word of the message can also
13403e07920fSDavid van Moolenbroek 	 * be parsed as an SD.
13413e07920fSDavid van Moolenbroek 	 * example:
13423e07920fSDavid van Moolenbroek 	 * "<35>Jul  6 12:39:08 tag[123]: [exampleSDID@0] - hello"
13433e07920fSDavid van Moolenbroek 	 * --> parsed as
13443e07920fSDavid van Moolenbroek 	 *     MSGID = "[exampleSDID@0]"
13453e07920fSDavid van Moolenbroek 	 *     SD    = "-"
13463e07920fSDavid van Moolenbroek 	 *     MSG   = "hello"
13473e07920fSDavid van Moolenbroek 	 */
13483e07920fSDavid van Moolenbroek 	start = p;
13493e07920fSDavid van Moolenbroek 	msgidlen = check_msgid(p);
13503e07920fSDavid van Moolenbroek 	if (msgidlen) /* check for SD in 2nd field */
13513e07920fSDavid van Moolenbroek 		sdlen = check_sd(p+msgidlen+1);
13523e07920fSDavid van Moolenbroek 
13533e07920fSDavid van Moolenbroek 	if (msgidlen && sdlen) {
13543e07920fSDavid van Moolenbroek 		/* MSGID in 1st and SD in 2nd field
13553e07920fSDavid van Moolenbroek 		 * now check for NILVALUEs and copy */
13563e07920fSDavid van Moolenbroek 		if (msgidlen == 1 && *p == '-') {
13573e07920fSDavid van Moolenbroek 			p++; /* - */
13583e07920fSDavid van Moolenbroek 			p++; /* SP */
13593e07920fSDavid van Moolenbroek 			DPRINTF(D_DATA, "Got MSGID \"-\"\n");
13603e07920fSDavid van Moolenbroek 		} else {
13613e07920fSDavid van Moolenbroek 			/* only has ASCII chars after check_msgid() */
13623e07920fSDavid van Moolenbroek 			buffer->msgid = strndup(p, msgidlen);
13633e07920fSDavid van Moolenbroek 			p += msgidlen;
13643e07920fSDavid van Moolenbroek 			p++; /* SP */
13653e07920fSDavid van Moolenbroek 			DPRINTF(D_DATA, "Got MSGID \"%s\"\n",
13663e07920fSDavid van Moolenbroek 				buffer->msgid);
13673e07920fSDavid van Moolenbroek 		}
13683e07920fSDavid van Moolenbroek 	} else {
13693e07920fSDavid van Moolenbroek 		/* either no msgid or no SD in 2nd field
13703e07920fSDavid van Moolenbroek 		 * --> check 1st field for SD */
13713e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "No MSGID\n");
13723e07920fSDavid van Moolenbroek 		sdlen = check_sd(p);
13733e07920fSDavid van Moolenbroek 	}
13743e07920fSDavid van Moolenbroek 
13753e07920fSDavid van Moolenbroek 	if (sdlen == 0) {
13763e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "No SD\n");
13773e07920fSDavid van Moolenbroek 	} else if (sdlen > 1) {
13783e07920fSDavid van Moolenbroek 		buffer->sd = copy_utf8_ascii(p, sdlen);
13793e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
13803e07920fSDavid van Moolenbroek 	} else if (sdlen == 1 && *p == '-') {
13813e07920fSDavid van Moolenbroek 		p++;
13823e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Got SD \"-\"\n");
13833e07920fSDavid van Moolenbroek 	} else {
13843e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Error\n");
13853e07920fSDavid van Moolenbroek 	}
13863e07920fSDavid van Moolenbroek 
13873e07920fSDavid van Moolenbroek 	if (*p == ' ') p++;
13883e07920fSDavid van Moolenbroek 	start = p;
13893e07920fSDavid van Moolenbroek 	/* and now the message itself
13903e07920fSDavid van Moolenbroek 	 * note: do not reset start, because we might come here
13913e07920fSDavid van Moolenbroek 	 * by goto and want to have the incomplete field as part
13923e07920fSDavid van Moolenbroek 	 * of the msg
13933e07920fSDavid van Moolenbroek 	 */
13943e07920fSDavid van Moolenbroek all_bsd_msg:
13953e07920fSDavid van Moolenbroek 	if (*p != '\0') {
13963e07920fSDavid van Moolenbroek 		size_t msglen = strlen(p);
13973e07920fSDavid van Moolenbroek 		buffer->msg = copy_utf8_ascii(p, msglen);
13983e07920fSDavid van Moolenbroek 		buffer->msgorig = buffer->msg;
13993e07920fSDavid van Moolenbroek 		buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
14003e07920fSDavid van Moolenbroek 	}
14013e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
14023e07920fSDavid van Moolenbroek 
14033e07920fSDavid van Moolenbroek 	buffer->recvhost = strdup(hname);
14043e07920fSDavid van Moolenbroek 	buffer->pri = pri;
14053e07920fSDavid van Moolenbroek 	buffer->flags = flags | BSDSYSLOG;
14063e07920fSDavid van Moolenbroek 
14073e07920fSDavid van Moolenbroek 	return buffer;
14083e07920fSDavid van Moolenbroek }
14093e07920fSDavid van Moolenbroek 
14103e07920fSDavid van Moolenbroek struct buf_msg *
printline_kernelprintf(const char * hname,char * msg,int flags,int pri)14113e07920fSDavid van Moolenbroek printline_kernelprintf(const char *hname, char *msg,
14123e07920fSDavid van Moolenbroek 	int flags, int pri)
14133e07920fSDavid van Moolenbroek {
14143e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
14153e07920fSDavid van Moolenbroek 	char *p;
14163e07920fSDavid van Moolenbroek 	unsigned sdlen = 0;
14173e07920fSDavid van Moolenbroek 
14183e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_kernelprintf("
14193e07920fSDavid van Moolenbroek 		"\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
14203e07920fSDavid van Moolenbroek 
14213e07920fSDavid van Moolenbroek 	buffer = buf_msg_new(0);
1422*0a6a1f1dSLionel Sambuc 	buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
14233e07920fSDavid van Moolenbroek 	buffer->pri = pri;
14243e07920fSDavid van Moolenbroek 	buffer->flags = flags;
14253e07920fSDavid van Moolenbroek 
14263e07920fSDavid van Moolenbroek 	/* assume there is no MSGID but there might be SD */
14273e07920fSDavid van Moolenbroek 	p = msg;
14283e07920fSDavid van Moolenbroek 	sdlen = check_sd(p);
14293e07920fSDavid van Moolenbroek 
14303e07920fSDavid van Moolenbroek 	if (sdlen == 0) {
14313e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "No SD\n");
14323e07920fSDavid van Moolenbroek 	} else if (sdlen > 1) {
14333e07920fSDavid van Moolenbroek 		buffer->sd = copy_utf8_ascii(p, sdlen);
14343e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
14353e07920fSDavid van Moolenbroek 	} else if (sdlen == 1 && *p == '-') {
14363e07920fSDavid van Moolenbroek 		p++;
14373e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Got SD \"-\"\n");
14383e07920fSDavid van Moolenbroek 	} else {
14393e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "Error\n");
14403e07920fSDavid van Moolenbroek 	}
14413e07920fSDavid van Moolenbroek 
14423e07920fSDavid van Moolenbroek 	if (*p == ' ') p++;
14433e07920fSDavid van Moolenbroek 	if (*p != '\0') {
14443e07920fSDavid van Moolenbroek 		size_t msglen = strlen(p);
14453e07920fSDavid van Moolenbroek 		buffer->msg = copy_utf8_ascii(p, msglen);
14463e07920fSDavid van Moolenbroek 		buffer->msgorig = buffer->msg;
14473e07920fSDavid van Moolenbroek 		buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
14483e07920fSDavid van Moolenbroek 	}
14493e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
14503e07920fSDavid van Moolenbroek 
14513e07920fSDavid van Moolenbroek 	return buffer;
14523e07920fSDavid van Moolenbroek }
14533e07920fSDavid van Moolenbroek 
14543e07920fSDavid van Moolenbroek /*
14553e07920fSDavid van Moolenbroek  * Take a raw input line, read priority and version, call the
14563e07920fSDavid van Moolenbroek  * right message parsing function, then call logmsg().
14573e07920fSDavid van Moolenbroek  */
14583e07920fSDavid van Moolenbroek void
printline(const char * hname,char * msg,int flags)14593e07920fSDavid van Moolenbroek printline(const char *hname, char *msg, int flags)
14603e07920fSDavid van Moolenbroek {
14613e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
14623e07920fSDavid van Moolenbroek 	int pri;
14633e07920fSDavid van Moolenbroek 	char *p, *q;
14643e07920fSDavid van Moolenbroek 	long n;
14653e07920fSDavid van Moolenbroek 	bool bsdsyslog = true;
14663e07920fSDavid van Moolenbroek 
14673e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER|D_DATA),
14683e07920fSDavid van Moolenbroek 		"printline(\"%s\", \"%s\", %d)\n", hname, msg, flags);
14693e07920fSDavid van Moolenbroek 
14703e07920fSDavid van Moolenbroek 	/* test for special codes */
14713e07920fSDavid van Moolenbroek 	pri = DEFUPRI;
14723e07920fSDavid van Moolenbroek 	p = msg;
14733e07920fSDavid van Moolenbroek 	if (*p == '<') {
14743e07920fSDavid van Moolenbroek 		errno = 0;
14753e07920fSDavid van Moolenbroek 		n = strtol(p + 1, &q, 10);
14763e07920fSDavid van Moolenbroek 		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
14773e07920fSDavid van Moolenbroek 			p = q + 1;
14783e07920fSDavid van Moolenbroek 			pri = (int)n;
14793e07920fSDavid van Moolenbroek 			/* check for syslog-protocol version */
14803e07920fSDavid van Moolenbroek 			if (*p == '1' && p[1] == ' ') {
14813e07920fSDavid van Moolenbroek 				p += 2;	 /* skip version and space */
14823e07920fSDavid van Moolenbroek 				bsdsyslog = false;
14833e07920fSDavid van Moolenbroek 			} else {
14843e07920fSDavid van Moolenbroek 				bsdsyslog = true;
14853e07920fSDavid van Moolenbroek 			}
14863e07920fSDavid van Moolenbroek 		}
14873e07920fSDavid van Moolenbroek 	}
14883e07920fSDavid van Moolenbroek 	if (pri & ~(LOG_FACMASK|LOG_PRIMASK))
14893e07920fSDavid van Moolenbroek 		pri = DEFUPRI;
14903e07920fSDavid van Moolenbroek 
14913e07920fSDavid van Moolenbroek 	/*
14923e07920fSDavid van Moolenbroek 	 * Don't allow users to log kernel messages.
14933e07920fSDavid van Moolenbroek 	 * NOTE: Since LOG_KERN == 0, this will also match
14943e07920fSDavid van Moolenbroek 	 *	 messages with no facility specified.
14953e07920fSDavid van Moolenbroek 	 */
14963e07920fSDavid van Moolenbroek 	if ((pri & LOG_FACMASK) == LOG_KERN)
14973e07920fSDavid van Moolenbroek 		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
14983e07920fSDavid van Moolenbroek 
14993e07920fSDavid van Moolenbroek 	if (bsdsyslog) {
15003e07920fSDavid van Moolenbroek 		buffer = printline_bsdsyslog(hname, p, flags, pri);
15013e07920fSDavid van Moolenbroek 	} else {
15023e07920fSDavid van Moolenbroek 		buffer = printline_syslogprotocol(hname, p, flags, pri);
15033e07920fSDavid van Moolenbroek 	}
15043e07920fSDavid van Moolenbroek 	logmsg(buffer);
15053e07920fSDavid van Moolenbroek 	DELREF(buffer);
15063e07920fSDavid van Moolenbroek }
15073e07920fSDavid van Moolenbroek 
15083e07920fSDavid van Moolenbroek /*
15093e07920fSDavid van Moolenbroek  * Take a raw input line from /dev/klog, split and format similar to syslog().
15103e07920fSDavid van Moolenbroek  */
15113e07920fSDavid van Moolenbroek void
printsys(char * msg)15123e07920fSDavid van Moolenbroek printsys(char *msg)
15133e07920fSDavid van Moolenbroek {
15143e07920fSDavid van Moolenbroek 	int n, is_printf, pri, flags;
15153e07920fSDavid van Moolenbroek 	char *p, *q;
15163e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
15173e07920fSDavid van Moolenbroek 
15183e07920fSDavid van Moolenbroek 	klog_linebufoff = 0;
15193e07920fSDavid van Moolenbroek 	for (p = msg; *p != '\0'; ) {
15203e07920fSDavid van Moolenbroek 		bool bsdsyslog = true;
15213e07920fSDavid van Moolenbroek 
15223e07920fSDavid van Moolenbroek 		is_printf = 1;
15233e07920fSDavid van Moolenbroek 		flags = ISKERNEL | ADDDATE | BSDSYSLOG;
15243e07920fSDavid van Moolenbroek 		if (SyncKernel)
15253e07920fSDavid van Moolenbroek 			flags |= SYNC_FILE;
15263e07920fSDavid van Moolenbroek 		if (is_printf) /* kernel printf's come out on console */
15273e07920fSDavid van Moolenbroek 			flags |= IGN_CONS;
15283e07920fSDavid van Moolenbroek 		pri = DEFSPRI;
15293e07920fSDavid van Moolenbroek 
15303e07920fSDavid van Moolenbroek 		if (*p == '<') {
15313e07920fSDavid van Moolenbroek 			errno = 0;
15323e07920fSDavid van Moolenbroek 			n = (int)strtol(p + 1, &q, 10);
15333e07920fSDavid van Moolenbroek 			if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
15343e07920fSDavid van Moolenbroek 				p = q + 1;
15353e07920fSDavid van Moolenbroek 				is_printf = 0;
15363e07920fSDavid van Moolenbroek 				pri = n;
15373e07920fSDavid van Moolenbroek 				if (*p == '1') { /* syslog-protocol version */
15383e07920fSDavid van Moolenbroek 					p += 2;	 /* skip version and space */
15393e07920fSDavid van Moolenbroek 					bsdsyslog = false;
15403e07920fSDavid van Moolenbroek 				} else {
15413e07920fSDavid van Moolenbroek 					bsdsyslog = true;
15423e07920fSDavid van Moolenbroek 				}
15433e07920fSDavid van Moolenbroek 			}
15443e07920fSDavid van Moolenbroek 		}
15453e07920fSDavid van Moolenbroek 		for (q = p; *q != '\0' && *q != '\n'; q++)
15463e07920fSDavid van Moolenbroek 			/* look for end of line; no further checks.
15473e07920fSDavid van Moolenbroek 			 * trust the kernel to send ASCII only */;
15483e07920fSDavid van Moolenbroek 		if (*q != '\0')
15493e07920fSDavid van Moolenbroek 			*q++ = '\0';
15503e07920fSDavid van Moolenbroek 		else {
15513e07920fSDavid van Moolenbroek 			memcpy(linebuf, p, klog_linebufoff = q - p);
15523e07920fSDavid van Moolenbroek 			break;
15533e07920fSDavid van Moolenbroek 		}
15543e07920fSDavid van Moolenbroek 
15553e07920fSDavid van Moolenbroek 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
15563e07920fSDavid van Moolenbroek 			pri = DEFSPRI;
15573e07920fSDavid van Moolenbroek 
15583e07920fSDavid van Moolenbroek 		/* allow all kinds of input from kernel */
15593e07920fSDavid van Moolenbroek 		if (is_printf)
15603e07920fSDavid van Moolenbroek 			buffer = printline_kernelprintf(
15613e07920fSDavid van Moolenbroek 			    LocalFQDN, p, flags, pri);
15623e07920fSDavid van Moolenbroek 		else {
15633e07920fSDavid van Moolenbroek 			if (bsdsyslog)
15643e07920fSDavid van Moolenbroek 				buffer = printline_bsdsyslog(
15653e07920fSDavid van Moolenbroek 				    LocalFQDN, p, flags, pri);
15663e07920fSDavid van Moolenbroek 			else
15673e07920fSDavid van Moolenbroek 				buffer = printline_syslogprotocol(
15683e07920fSDavid van Moolenbroek 				    LocalFQDN, p, flags, pri);
15693e07920fSDavid van Moolenbroek 		}
15703e07920fSDavid van Moolenbroek 
15713e07920fSDavid van Moolenbroek 		/* set fields left open */
15723e07920fSDavid van Moolenbroek 		if (!buffer->prog)
15733e07920fSDavid van Moolenbroek 			buffer->prog = strdup(_PATH_UNIX);
15743e07920fSDavid van Moolenbroek 		if (!buffer->host)
15753e07920fSDavid van Moolenbroek 			buffer->host = LocalFQDN;
15763e07920fSDavid van Moolenbroek 		if (!buffer->recvhost)
15773e07920fSDavid van Moolenbroek 			buffer->recvhost = LocalFQDN;
15783e07920fSDavid van Moolenbroek 
15793e07920fSDavid van Moolenbroek 		logmsg(buffer);
15803e07920fSDavid van Moolenbroek 		DELREF(buffer);
15813e07920fSDavid van Moolenbroek 		p = q;
15823e07920fSDavid van Moolenbroek 	}
15833e07920fSDavid van Moolenbroek }
15843e07920fSDavid van Moolenbroek 
15853e07920fSDavid van Moolenbroek /*
15863e07920fSDavid van Moolenbroek  * Check to see if `name' matches the provided specification, using the
15873e07920fSDavid van Moolenbroek  * specified strstr function.
15883e07920fSDavid van Moolenbroek  */
15893e07920fSDavid van Moolenbroek int
matches_spec(const char * name,const char * spec,char * (* check)(const char *,const char *))15903e07920fSDavid van Moolenbroek matches_spec(const char *name, const char *spec,
15913e07920fSDavid van Moolenbroek     char *(*check)(const char *, const char *))
15923e07920fSDavid van Moolenbroek {
15933e07920fSDavid van Moolenbroek 	const char *s;
15943e07920fSDavid van Moolenbroek 	const char *cursor;
15953e07920fSDavid van Moolenbroek 	char prev, next;
15963e07920fSDavid van Moolenbroek 	size_t len;
15973e07920fSDavid van Moolenbroek 
15983e07920fSDavid van Moolenbroek 	if (name[0] == '\0')
15993e07920fSDavid van Moolenbroek 		return 0;
16003e07920fSDavid van Moolenbroek 
16013e07920fSDavid van Moolenbroek 	if (strchr(name, ',')) /* sanity */
16023e07920fSDavid van Moolenbroek 		return 0;
16033e07920fSDavid van Moolenbroek 
16043e07920fSDavid van Moolenbroek 	len = strlen(name);
16053e07920fSDavid van Moolenbroek 	cursor = spec;
16063e07920fSDavid van Moolenbroek 	while ((s = (*check)(cursor, name)) != NULL) {
16073e07920fSDavid van Moolenbroek 		prev = s == spec ? ',' : *(s - 1);
16083e07920fSDavid van Moolenbroek 		cursor = s + len;
16093e07920fSDavid van Moolenbroek 		next = *cursor;
16103e07920fSDavid van Moolenbroek 
16113e07920fSDavid van Moolenbroek 		if (prev == ',' && (next == '\0' || next == ','))
16123e07920fSDavid van Moolenbroek 			return 1;
16133e07920fSDavid van Moolenbroek 	}
16143e07920fSDavid van Moolenbroek 
16153e07920fSDavid van Moolenbroek 	return 0;
16163e07920fSDavid van Moolenbroek }
16173e07920fSDavid van Moolenbroek 
16183e07920fSDavid van Moolenbroek /*
16193e07920fSDavid van Moolenbroek  * wrapper with old function signature,
16203e07920fSDavid van Moolenbroek  * keeps calling code shorter and hides buffer allocation
16213e07920fSDavid van Moolenbroek  */
16223e07920fSDavid van Moolenbroek void
logmsg_async(int pri,const char * sd,const char * msg,int flags)16233e07920fSDavid van Moolenbroek logmsg_async(int pri, const char *sd, const char *msg, int flags)
16243e07920fSDavid van Moolenbroek {
16253e07920fSDavid van Moolenbroek 	struct buf_msg *buffer;
16263e07920fSDavid van Moolenbroek 	size_t msglen;
16273e07920fSDavid van Moolenbroek 
16283e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_DATA), "logmsg_async(%d, \"%s\", \"%s\", %d)\n",
16293e07920fSDavid van Moolenbroek 	    pri, sd, msg, flags);
16303e07920fSDavid van Moolenbroek 
16313e07920fSDavid van Moolenbroek 	if (msg) {
16323e07920fSDavid van Moolenbroek 		msglen = strlen(msg);
16333e07920fSDavid van Moolenbroek 		msglen++;		/* adds \0 */
16343e07920fSDavid van Moolenbroek 		buffer = buf_msg_new(msglen);
16353e07920fSDavid van Moolenbroek 		buffer->msglen = strlcpy(buffer->msg, msg, msglen) + 1;
16363e07920fSDavid van Moolenbroek 	} else {
16373e07920fSDavid van Moolenbroek 		buffer = buf_msg_new(0);
16383e07920fSDavid van Moolenbroek 	}
16393e07920fSDavid van Moolenbroek 	if (sd) buffer->sd = strdup(sd);
1640*0a6a1f1dSLionel Sambuc 	buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
16413e07920fSDavid van Moolenbroek 	buffer->prog = appname;
16423e07920fSDavid van Moolenbroek 	buffer->pid = include_pid;
16433e07920fSDavid van Moolenbroek 	buffer->recvhost = buffer->host = LocalFQDN;
16443e07920fSDavid van Moolenbroek 	buffer->pri = pri;
16453e07920fSDavid van Moolenbroek 	buffer->flags = flags;
16463e07920fSDavid van Moolenbroek 
16473e07920fSDavid van Moolenbroek 	logmsg(buffer);
16483e07920fSDavid van Moolenbroek 	DELREF(buffer);
16493e07920fSDavid van Moolenbroek }
16503e07920fSDavid van Moolenbroek 
16513e07920fSDavid van Moolenbroek /* read timestamp in from_buf, convert into a timestamp in to_buf
16523e07920fSDavid van Moolenbroek  *
16533e07920fSDavid van Moolenbroek  * returns length of timestamp found in from_buf (= number of bytes consumed)
16543e07920fSDavid van Moolenbroek  */
16553e07920fSDavid van Moolenbroek size_t
check_timestamp(unsigned char * from_buf,char ** to_buf,bool from_iso,bool to_iso)16563e07920fSDavid van Moolenbroek check_timestamp(unsigned char *from_buf, char **to_buf,
16573e07920fSDavid van Moolenbroek 	bool from_iso, bool to_iso)
16583e07920fSDavid van Moolenbroek {
16593e07920fSDavid van Moolenbroek 	unsigned char *q;
16603e07920fSDavid van Moolenbroek 	int p;
16613e07920fSDavid van Moolenbroek 	bool found_ts = false;
16623e07920fSDavid van Moolenbroek 
16633e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_DATA), "check_timestamp(%p = \"%s\", from_iso=%d, "
16643e07920fSDavid van Moolenbroek 	    "to_iso=%d)\n", from_buf, from_buf, from_iso, to_iso);
16653e07920fSDavid van Moolenbroek 
16663e07920fSDavid van Moolenbroek 	if (!from_buf) return 0;
16673e07920fSDavid van Moolenbroek 	/*
16683e07920fSDavid van Moolenbroek 	 * Check to see if msg looks non-standard.
16693e07920fSDavid van Moolenbroek 	 * looks at every char because we do not have a msg length yet
16703e07920fSDavid van Moolenbroek 	 */
16713e07920fSDavid van Moolenbroek 	/* detailed checking adapted from Albert Mietus' sl_timestamp.c */
16723e07920fSDavid van Moolenbroek 	if (from_iso) {
16733e07920fSDavid van Moolenbroek 		if (from_buf[4] == '-' && from_buf[7] == '-'
16743e07920fSDavid van Moolenbroek 		    && from_buf[10] == 'T' && from_buf[13] == ':'
16753e07920fSDavid van Moolenbroek 		    && from_buf[16] == ':'
16763e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[0]) && isdigit(from_buf[1])
16773e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[2]) && isdigit(from_buf[3])  /* YYYY */
16783e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[5]) && isdigit(from_buf[6])
16793e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[8]) && isdigit(from_buf[9])  /* mm dd */
16803e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[11]) && isdigit(from_buf[12]) /* HH */
16813e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[14]) && isdigit(from_buf[15]) /* MM */
16823e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[17]) && isdigit(from_buf[18]) /* SS */
16833e07920fSDavid van Moolenbroek 		    )  {
16843e07920fSDavid van Moolenbroek 			/* time-secfrac */
16853e07920fSDavid van Moolenbroek 			if (from_buf[19] == '.')
16863e07920fSDavid van Moolenbroek 				for (p=20; isdigit(from_buf[p]); p++) /* NOP*/;
16873e07920fSDavid van Moolenbroek 			else
16883e07920fSDavid van Moolenbroek 				p = 19;
16893e07920fSDavid van Moolenbroek 			/* time-offset */
16903e07920fSDavid van Moolenbroek 			if (from_buf[p] == 'Z'
16913e07920fSDavid van Moolenbroek 			 || ((from_buf[p] == '+' || from_buf[p] == '-')
16923e07920fSDavid van Moolenbroek 			    && from_buf[p+3] == ':'
16933e07920fSDavid van Moolenbroek 			    && isdigit(from_buf[p+1]) && isdigit(from_buf[p+2])
16943e07920fSDavid van Moolenbroek 			    && isdigit(from_buf[p+4]) && isdigit(from_buf[p+5])
16953e07920fSDavid van Moolenbroek 			 ))
16963e07920fSDavid van Moolenbroek 				found_ts = true;
16973e07920fSDavid van Moolenbroek 		}
16983e07920fSDavid van Moolenbroek 	} else {
16993e07920fSDavid van Moolenbroek 		if (from_buf[3] == ' ' && from_buf[6] == ' '
17003e07920fSDavid van Moolenbroek 		    && from_buf[9] == ':' && from_buf[12] == ':'
17013e07920fSDavid van Moolenbroek 		    && (from_buf[4] == ' ' || isdigit(from_buf[4]))
17023e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[5]) /* dd */
17033e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[7])  && isdigit(from_buf[8])   /* HH */
17043e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[10]) && isdigit(from_buf[11])  /* MM */
17053e07920fSDavid van Moolenbroek 		    && isdigit(from_buf[13]) && isdigit(from_buf[14])  /* SS */
17063e07920fSDavid van Moolenbroek 		    && isupper(from_buf[0]) && islower(from_buf[1]) /* month */
17073e07920fSDavid van Moolenbroek 		    && islower(from_buf[2]))
17083e07920fSDavid van Moolenbroek 			found_ts = true;
17093e07920fSDavid van Moolenbroek 	}
17103e07920fSDavid van Moolenbroek 	if (!found_ts) {
17113e07920fSDavid van Moolenbroek 		if (from_buf[0] == '-' && from_buf[1] == ' ') {
17123e07920fSDavid van Moolenbroek 			/* NILVALUE */
17133e07920fSDavid van Moolenbroek 			if (to_iso) {
17143e07920fSDavid van Moolenbroek 				/* with ISO = syslog-protocol output leave
17153e07920fSDavid van Moolenbroek 			 	 * it as is, because it is better to have
17163e07920fSDavid van Moolenbroek 			 	 * no timestamp than a wrong one.
17173e07920fSDavid van Moolenbroek 			 	 */
17183e07920fSDavid van Moolenbroek 				*to_buf = strdup("-");
17193e07920fSDavid van Moolenbroek 			} else {
17203e07920fSDavid van Moolenbroek 				/* with BSD Syslog the field is reqired
17213e07920fSDavid van Moolenbroek 				 * so replace it with current time
17223e07920fSDavid van Moolenbroek 				 */
1723*0a6a1f1dSLionel Sambuc 				*to_buf = make_timestamp(NULL, false, 0);
17243e07920fSDavid van Moolenbroek 			}
17253e07920fSDavid van Moolenbroek 			return 2;
17263e07920fSDavid van Moolenbroek 		}
1727*0a6a1f1dSLionel Sambuc 		*to_buf = make_timestamp(NULL, false, 0);
17283e07920fSDavid van Moolenbroek 		return 0;
17293e07920fSDavid van Moolenbroek 	}
17303e07920fSDavid van Moolenbroek 
17313e07920fSDavid van Moolenbroek 	if (!from_iso && !to_iso) {
17323e07920fSDavid van Moolenbroek 		/* copy BSD timestamp */
17333e07920fSDavid van Moolenbroek 		DPRINTF(D_CALL, "check_timestamp(): copy BSD timestamp\n");
17343e07920fSDavid van Moolenbroek 		*to_buf = strndup((char *)from_buf, BSD_TIMESTAMPLEN);
17353e07920fSDavid van Moolenbroek 		return BSD_TIMESTAMPLEN;
17363e07920fSDavid van Moolenbroek 	} else if (from_iso && to_iso) {
17373e07920fSDavid van Moolenbroek 		/* copy ISO timestamp */
17383e07920fSDavid van Moolenbroek 		DPRINTF(D_CALL, "check_timestamp(): copy ISO timestamp\n");
17393e07920fSDavid van Moolenbroek 		if (!(q = (unsigned char *) strchr((char *)from_buf, ' ')))
17403e07920fSDavid van Moolenbroek 			q = from_buf + strlen((char *)from_buf);
17413e07920fSDavid van Moolenbroek 		*to_buf = strndup((char *)from_buf, q - from_buf);
17423e07920fSDavid van Moolenbroek 		return q - from_buf;
17433e07920fSDavid van Moolenbroek 	} else if (from_iso && !to_iso) {
17443e07920fSDavid van Moolenbroek 		/* convert ISO->BSD */
17453e07920fSDavid van Moolenbroek 		struct tm parsed;
17463e07920fSDavid van Moolenbroek 		time_t timeval;
17473e07920fSDavid van Moolenbroek 		char tsbuf[MAX_TIMESTAMPLEN];
17483e07920fSDavid van Moolenbroek 		int i = 0;
17493e07920fSDavid van Moolenbroek 
17503e07920fSDavid van Moolenbroek 		DPRINTF(D_CALL, "check_timestamp(): convert ISO->BSD\n");
17513e07920fSDavid van Moolenbroek 		for(i = 0; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
17523e07920fSDavid van Moolenbroek 		    && from_buf[i] != '.' && from_buf[i] != ' '; i++)
17533e07920fSDavid van Moolenbroek 			tsbuf[i] = from_buf[i]; /* copy date & time */
17543e07920fSDavid van Moolenbroek 		for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
17553e07920fSDavid van Moolenbroek 		    && from_buf[i] != '+' && from_buf[i] != '-'
17563e07920fSDavid van Moolenbroek 		    && from_buf[i] != 'Z' && from_buf[i] != ' '; i++)
17573e07920fSDavid van Moolenbroek 			;			   /* skip fraction digits */
17583e07920fSDavid van Moolenbroek 		for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
17593e07920fSDavid van Moolenbroek 		    && from_buf[i] != ':' && from_buf[i] != ' ' ; i++)
17603e07920fSDavid van Moolenbroek 			tsbuf[i] = from_buf[i]; /* copy TZ */
17613e07920fSDavid van Moolenbroek 		if (from_buf[i] == ':') i++;	/* skip colon */
17623e07920fSDavid van Moolenbroek 		for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
17633e07920fSDavid van Moolenbroek 		    && from_buf[i] != ' ' ; i++)
17643e07920fSDavid van Moolenbroek 			tsbuf[i] = from_buf[i]; /* copy TZ */
17653e07920fSDavid van Moolenbroek 
17663e07920fSDavid van Moolenbroek 		(void)memset(&parsed, 0, sizeof(parsed));
17673e07920fSDavid van Moolenbroek 		parsed.tm_isdst = -1;
17683e07920fSDavid van Moolenbroek 		(void)strptime(tsbuf, "%FT%T%z", &parsed);
17693e07920fSDavid van Moolenbroek 		timeval = mktime(&parsed);
17703e07920fSDavid van Moolenbroek 
1771*0a6a1f1dSLionel Sambuc 		*to_buf = make_timestamp(&timeval, false, BSD_TIMESTAMPLEN);
17723e07920fSDavid van Moolenbroek 		return i;
17733e07920fSDavid van Moolenbroek 	} else if (!from_iso && to_iso) {
17743e07920fSDavid van Moolenbroek 		/* convert BSD->ISO */
17753e07920fSDavid van Moolenbroek 		struct tm parsed;
17763e07920fSDavid van Moolenbroek 		struct tm *current;
17773e07920fSDavid van Moolenbroek 		time_t timeval;
17783e07920fSDavid van Moolenbroek 
17793e07920fSDavid van Moolenbroek 		(void)memset(&parsed, 0, sizeof(parsed));
17803e07920fSDavid van Moolenbroek 		parsed.tm_isdst = -1;
17813e07920fSDavid van Moolenbroek 		DPRINTF(D_CALL, "check_timestamp(): convert BSD->ISO\n");
1782*0a6a1f1dSLionel Sambuc 		strptime((char *)from_buf, "%b %d %T", &parsed);
17833e07920fSDavid van Moolenbroek 		current = gmtime(&now);
17843e07920fSDavid van Moolenbroek 
17853e07920fSDavid van Moolenbroek 		/* use current year and timezone */
17863e07920fSDavid van Moolenbroek 		parsed.tm_isdst = current->tm_isdst;
17873e07920fSDavid van Moolenbroek 		parsed.tm_gmtoff = current->tm_gmtoff;
17883e07920fSDavid van Moolenbroek 		parsed.tm_year = current->tm_year;
17893e07920fSDavid van Moolenbroek 		if (current->tm_mon == 0 && parsed.tm_mon == 11)
17903e07920fSDavid van Moolenbroek 			parsed.tm_year--;
17913e07920fSDavid van Moolenbroek 
17923e07920fSDavid van Moolenbroek 		timeval = mktime(&parsed);
1793*0a6a1f1dSLionel Sambuc 		*to_buf = make_timestamp(&timeval, true, MAX_TIMESTAMPLEN - 1);
17943e07920fSDavid van Moolenbroek 
17953e07920fSDavid van Moolenbroek 		return BSD_TIMESTAMPLEN;
17963e07920fSDavid van Moolenbroek 	} else {
17973e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC,
17983e07920fSDavid van Moolenbroek 			"Executing unreachable code in check_timestamp()\n");
17993e07920fSDavid van Moolenbroek 		return 0;
18003e07920fSDavid van Moolenbroek 	}
18013e07920fSDavid van Moolenbroek }
18023e07920fSDavid van Moolenbroek 
18033e07920fSDavid van Moolenbroek /*
18043e07920fSDavid van Moolenbroek  * Log a message to the appropriate log files, users, etc. based on
18053e07920fSDavid van Moolenbroek  * the priority.
18063e07920fSDavid van Moolenbroek  */
18073e07920fSDavid van Moolenbroek void
logmsg(struct buf_msg * buffer)18083e07920fSDavid van Moolenbroek logmsg(struct buf_msg *buffer)
18093e07920fSDavid van Moolenbroek {
18103e07920fSDavid van Moolenbroek 	struct filed *f;
18113e07920fSDavid van Moolenbroek 	int fac, omask, prilev;
18123e07920fSDavid van Moolenbroek 
18133e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER), "logmsg: buffer@%p, pri 0%o/%d, flags 0x%x,"
18143e07920fSDavid van Moolenbroek 	    " timestamp \"%s\", from \"%s\", sd \"%s\", msg \"%s\"\n",
18153e07920fSDavid van Moolenbroek 	    buffer, buffer->pri, buffer->pri, buffer->flags,
18163e07920fSDavid van Moolenbroek 	    buffer->timestamp, buffer->recvhost, buffer->sd, buffer->msg);
18173e07920fSDavid van Moolenbroek 
18183e07920fSDavid van Moolenbroek 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
18193e07920fSDavid van Moolenbroek 
18203e07920fSDavid van Moolenbroek 	/* sanity check */
18213e07920fSDavid van Moolenbroek 	assert(buffer->refcount == 1);
18223e07920fSDavid van Moolenbroek 	assert(buffer->msglen <= buffer->msgsize);
18233e07920fSDavid van Moolenbroek 	assert(buffer->msgorig <= buffer->msg);
18243e07920fSDavid van Moolenbroek 	assert((buffer->msg && buffer->msglen == strlen(buffer->msg)+1)
18253e07920fSDavid van Moolenbroek 	      || (!buffer->msg && !buffer->msglen));
18263e07920fSDavid van Moolenbroek 	if (!buffer->msg && !buffer->sd && !buffer->msgid)
18273e07920fSDavid van Moolenbroek 		DPRINTF(D_BUFFER, "Empty message?\n");
18283e07920fSDavid van Moolenbroek 
18293e07920fSDavid van Moolenbroek 	/* extract facility and priority level */
18303e07920fSDavid van Moolenbroek 	if (buffer->flags & MARK)
18313e07920fSDavid van Moolenbroek 		fac = LOG_NFACILITIES;
18323e07920fSDavid van Moolenbroek 	else
18333e07920fSDavid van Moolenbroek 		fac = LOG_FAC(buffer->pri);
18343e07920fSDavid van Moolenbroek 	prilev = LOG_PRI(buffer->pri);
18353e07920fSDavid van Moolenbroek 
18363e07920fSDavid van Moolenbroek 	/* log the message to the particular outputs */
18373e07920fSDavid van Moolenbroek 	if (!Initialized) {
18383e07920fSDavid van Moolenbroek 		f = &consfile;
18393e07920fSDavid van Moolenbroek 		f->f_file = open(ctty, O_WRONLY | O_NDELAY, 0);
18403e07920fSDavid van Moolenbroek 
18413e07920fSDavid van Moolenbroek 		if (f->f_file >= 0) {
18423e07920fSDavid van Moolenbroek 			DELREF(f->f_prevmsg);
18433e07920fSDavid van Moolenbroek 			f->f_prevmsg = NEWREF(buffer);
18443e07920fSDavid van Moolenbroek 			fprintlog(f, NEWREF(buffer), NULL);
18453e07920fSDavid van Moolenbroek 			DELREF(buffer);
18463e07920fSDavid van Moolenbroek 			(void)close(f->f_file);
18473e07920fSDavid van Moolenbroek 		}
18483e07920fSDavid van Moolenbroek 		(void)sigsetmask(omask);
18493e07920fSDavid van Moolenbroek 		return;
18503e07920fSDavid van Moolenbroek 	}
18513e07920fSDavid van Moolenbroek 
18523e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next) {
1853*0a6a1f1dSLionel Sambuc 		char *h;	/* host to use for comparing */
1854*0a6a1f1dSLionel Sambuc 
18553e07920fSDavid van Moolenbroek 		/* skip messages that are incorrect priority */
18563e07920fSDavid van Moolenbroek 		if (!MATCH_PRI(f, fac, prilev)
18573e07920fSDavid van Moolenbroek 		    || f->f_pmask[fac] == INTERNAL_NOPRI)
18583e07920fSDavid van Moolenbroek 			continue;
18593e07920fSDavid van Moolenbroek 
18603e07920fSDavid van Moolenbroek 		/* skip messages with the incorrect host name */
1861*0a6a1f1dSLionel Sambuc 		/* compare with host (which is supposedly more correct), */
1862*0a6a1f1dSLionel Sambuc 		/* but fallback to recvhost if host is NULL */
1863*0a6a1f1dSLionel Sambuc 		h = (buffer->host != NULL) ? buffer->host : buffer->recvhost;
1864*0a6a1f1dSLionel Sambuc 		if (f->f_host != NULL && h != NULL) {
1865*0a6a1f1dSLionel Sambuc 			char shost[MAXHOSTNAMELEN + 1];
1866*0a6a1f1dSLionel Sambuc 
1867*0a6a1f1dSLionel Sambuc 			if (BSDOutputFormat) {
1868*0a6a1f1dSLionel Sambuc 				(void)strlcpy(shost, h, sizeof(shost));
18693e07920fSDavid van Moolenbroek 				trim_anydomain(shost);
18703e07920fSDavid van Moolenbroek 				h = shost;
18713e07920fSDavid van Moolenbroek 			}
18723e07920fSDavid van Moolenbroek 			switch (f->f_host[0]) {
18733e07920fSDavid van Moolenbroek 			case '+':
18743e07920fSDavid van Moolenbroek 				if (! matches_spec(h, f->f_host + 1,
18753e07920fSDavid van Moolenbroek 				    strcasestr))
18763e07920fSDavid van Moolenbroek 					continue;
18773e07920fSDavid van Moolenbroek 				break;
18783e07920fSDavid van Moolenbroek 			case '-':
18793e07920fSDavid van Moolenbroek 				if (matches_spec(h, f->f_host + 1,
18803e07920fSDavid van Moolenbroek 				    strcasestr))
18813e07920fSDavid van Moolenbroek 					continue;
18823e07920fSDavid van Moolenbroek 				break;
18833e07920fSDavid van Moolenbroek 			}
18843e07920fSDavid van Moolenbroek 		}
18853e07920fSDavid van Moolenbroek 
18863e07920fSDavid van Moolenbroek 		/* skip messages with the incorrect program name */
18873e07920fSDavid van Moolenbroek 		if (f->f_program != NULL && buffer->prog != NULL) {
18883e07920fSDavid van Moolenbroek 			switch (f->f_program[0]) {
18893e07920fSDavid van Moolenbroek 			case '+':
18903e07920fSDavid van Moolenbroek 				if (!matches_spec(buffer->prog,
18913e07920fSDavid van Moolenbroek 				    f->f_program + 1, strstr))
18923e07920fSDavid van Moolenbroek 					continue;
18933e07920fSDavid van Moolenbroek 				break;
18943e07920fSDavid van Moolenbroek 			case '-':
18953e07920fSDavid van Moolenbroek 				if (matches_spec(buffer->prog,
18963e07920fSDavid van Moolenbroek 				    f->f_program + 1, strstr))
18973e07920fSDavid van Moolenbroek 					continue;
18983e07920fSDavid van Moolenbroek 				break;
18993e07920fSDavid van Moolenbroek 			default:
19003e07920fSDavid van Moolenbroek 				if (!matches_spec(buffer->prog,
19013e07920fSDavid van Moolenbroek 				    f->f_program, strstr))
19023e07920fSDavid van Moolenbroek 					continue;
19033e07920fSDavid van Moolenbroek 				break;
19043e07920fSDavid van Moolenbroek 			}
19053e07920fSDavid van Moolenbroek 		}
19063e07920fSDavid van Moolenbroek 
19073e07920fSDavid van Moolenbroek 		if (f->f_type == F_CONSOLE && (buffer->flags & IGN_CONS))
19083e07920fSDavid van Moolenbroek 			continue;
19093e07920fSDavid van Moolenbroek 
19103e07920fSDavid van Moolenbroek 		/* don't output marks to recently written files */
19113e07920fSDavid van Moolenbroek 		if ((buffer->flags & MARK)
19123e07920fSDavid van Moolenbroek 		 && (now - f->f_time) < MarkInterval / 2)
19133e07920fSDavid van Moolenbroek 			continue;
19143e07920fSDavid van Moolenbroek 
19153e07920fSDavid van Moolenbroek 		/*
19163e07920fSDavid van Moolenbroek 		 * suppress duplicate lines to this file unless NoRepeat
19173e07920fSDavid van Moolenbroek 		 */
19183e07920fSDavid van Moolenbroek #define MSG_FIELD_EQ(x) ((!buffer->x && !f->f_prevmsg->x) ||	\
19193e07920fSDavid van Moolenbroek     (buffer->x && f->f_prevmsg->x && !strcmp(buffer->x, f->f_prevmsg->x)))
19203e07920fSDavid van Moolenbroek 
19213e07920fSDavid van Moolenbroek 		if ((buffer->flags & MARK) == 0 &&
19223e07920fSDavid van Moolenbroek 		    f->f_prevmsg &&
19233e07920fSDavid van Moolenbroek 		    buffer->msglen == f->f_prevmsg->msglen &&
19243e07920fSDavid van Moolenbroek 		    !NoRepeat &&
19253e07920fSDavid van Moolenbroek 		    MSG_FIELD_EQ(host) &&
19263e07920fSDavid van Moolenbroek 		    MSG_FIELD_EQ(sd) &&
19273e07920fSDavid van Moolenbroek 		    MSG_FIELD_EQ(msg)
19283e07920fSDavid van Moolenbroek 		    ) {
19293e07920fSDavid van Moolenbroek 			f->f_prevcount++;
19303e07920fSDavid van Moolenbroek 			DPRINTF(D_DATA, "Msg repeated %d times, %ld sec of %d\n",
19313e07920fSDavid van Moolenbroek 			    f->f_prevcount, (long)(now - f->f_time),
19323e07920fSDavid van Moolenbroek 			    repeatinterval[f->f_repeatcount]);
19333e07920fSDavid van Moolenbroek 			/*
19343e07920fSDavid van Moolenbroek 			 * If domark would have logged this by now,
19353e07920fSDavid van Moolenbroek 			 * flush it now (so we don't hold isolated messages),
19363e07920fSDavid van Moolenbroek 			 * but back off so we'll flush less often
19373e07920fSDavid van Moolenbroek 			 * in the future.
19383e07920fSDavid van Moolenbroek 			 */
19393e07920fSDavid van Moolenbroek 			if (now > REPEATTIME(f)) {
19403e07920fSDavid van Moolenbroek 				fprintlog(f, NEWREF(buffer), NULL);
19413e07920fSDavid van Moolenbroek 				DELREF(buffer);
19423e07920fSDavid van Moolenbroek 				BACKOFF(f);
19433e07920fSDavid van Moolenbroek 			}
19443e07920fSDavid van Moolenbroek 		} else {
19453e07920fSDavid van Moolenbroek 			/* new line, save it */
19463e07920fSDavid van Moolenbroek 			if (f->f_prevcount)
19473e07920fSDavid van Moolenbroek 				fprintlog(f, NULL, NULL);
19483e07920fSDavid van Moolenbroek 			f->f_repeatcount = 0;
19493e07920fSDavid van Moolenbroek 			DELREF(f->f_prevmsg);
19503e07920fSDavid van Moolenbroek 			f->f_prevmsg = NEWREF(buffer);
19513e07920fSDavid van Moolenbroek 			fprintlog(f, NEWREF(buffer), NULL);
19523e07920fSDavid van Moolenbroek 			DELREF(buffer);
19533e07920fSDavid van Moolenbroek 		}
19543e07920fSDavid van Moolenbroek 	}
19553e07920fSDavid van Moolenbroek 	(void)sigsetmask(omask);
19563e07920fSDavid van Moolenbroek }
19573e07920fSDavid van Moolenbroek 
19583e07920fSDavid van Moolenbroek /*
19593e07920fSDavid van Moolenbroek  * format one buffer into output format given by flag BSDOutputFormat
19603e07920fSDavid van Moolenbroek  * line is allocated and has to be free()d by caller
19613e07920fSDavid van Moolenbroek  * size_t pointers are optional, if not NULL then they will return
19623e07920fSDavid van Moolenbroek  *   different lenghts used for formatting and output
19633e07920fSDavid van Moolenbroek  */
19643e07920fSDavid van Moolenbroek #define OUT(x) ((x)?(x):"-")
19653e07920fSDavid van Moolenbroek bool
format_buffer(struct buf_msg * buffer,char ** line,size_t * ptr_linelen,size_t * ptr_msglen,size_t * ptr_tlsprefixlen,size_t * ptr_prilen)19663e07920fSDavid van Moolenbroek format_buffer(struct buf_msg *buffer, char **line, size_t *ptr_linelen,
19673e07920fSDavid van Moolenbroek 	size_t *ptr_msglen, size_t *ptr_tlsprefixlen, size_t *ptr_prilen)
19683e07920fSDavid van Moolenbroek {
19693e07920fSDavid van Moolenbroek #define FPBUFSIZE 30
19703e07920fSDavid van Moolenbroek 	static char ascii_empty[] = "";
19713e07920fSDavid van Moolenbroek 	char fp_buf[FPBUFSIZE] = "\0";
19723e07920fSDavid van Moolenbroek 	char *hostname, *shorthostname = NULL;
19733e07920fSDavid van Moolenbroek 	char *ascii_sd = ascii_empty;
19743e07920fSDavid van Moolenbroek 	char *ascii_msg = ascii_empty;
19753e07920fSDavid van Moolenbroek 	size_t linelen, msglen, tlsprefixlen, prilen, j;
19763e07920fSDavid van Moolenbroek 
19773e07920fSDavid van Moolenbroek 	DPRINTF(D_CALL, "format_buffer(%p)\n", buffer);
19783e07920fSDavid van Moolenbroek 	if (!buffer) return false;
19793e07920fSDavid van Moolenbroek 
19803e07920fSDavid van Moolenbroek 	/* All buffer fields are set with strdup(). To avoid problems
19813e07920fSDavid van Moolenbroek 	 * on memory exhaustion we allow them to be empty and replace
19823e07920fSDavid van Moolenbroek 	 * the essential fields with already allocated generic values.
19833e07920fSDavid van Moolenbroek 	 */
19843e07920fSDavid van Moolenbroek 	if (!buffer->timestamp)
19853e07920fSDavid van Moolenbroek 		buffer->timestamp = timestamp;
19863e07920fSDavid van Moolenbroek 	if (!buffer->host && !buffer->recvhost)
19873e07920fSDavid van Moolenbroek 		buffer->host = LocalFQDN;
19883e07920fSDavid van Moolenbroek 
19893e07920fSDavid van Moolenbroek 	if (LogFacPri) {
19903e07920fSDavid van Moolenbroek 		const char *f_s = NULL, *p_s = NULL;
19913e07920fSDavid van Moolenbroek 		int fac = buffer->pri & LOG_FACMASK;
19923e07920fSDavid van Moolenbroek 		int pri = LOG_PRI(buffer->pri);
19933e07920fSDavid van Moolenbroek 		char f_n[5], p_n[5];
19943e07920fSDavid van Moolenbroek 
19953e07920fSDavid van Moolenbroek 		if (LogFacPri > 1) {
19963e07920fSDavid van Moolenbroek 			CODE *c;
19973e07920fSDavid van Moolenbroek 
19983e07920fSDavid van Moolenbroek 			for (c = facilitynames; c->c_name != NULL; c++) {
19993e07920fSDavid van Moolenbroek 				if (c->c_val == fac) {
20003e07920fSDavid van Moolenbroek 					f_s = c->c_name;
20013e07920fSDavid van Moolenbroek 					break;
20023e07920fSDavid van Moolenbroek 				}
20033e07920fSDavid van Moolenbroek 			}
20043e07920fSDavid van Moolenbroek 			for (c = prioritynames; c->c_name != NULL; c++) {
20053e07920fSDavid van Moolenbroek 				if (c->c_val == pri) {
20063e07920fSDavid van Moolenbroek 					p_s = c->c_name;
20073e07920fSDavid van Moolenbroek 					break;
20083e07920fSDavid van Moolenbroek 				}
20093e07920fSDavid van Moolenbroek 			}
20103e07920fSDavid van Moolenbroek 		}
20113e07920fSDavid van Moolenbroek 		if (f_s == NULL) {
20123e07920fSDavid van Moolenbroek 			snprintf(f_n, sizeof(f_n), "%d", LOG_FAC(fac));
20133e07920fSDavid van Moolenbroek 			f_s = f_n;
20143e07920fSDavid van Moolenbroek 		}
20153e07920fSDavid van Moolenbroek 		if (p_s == NULL) {
20163e07920fSDavid van Moolenbroek 			snprintf(p_n, sizeof(p_n), "%d", pri);
20173e07920fSDavid van Moolenbroek 			p_s = p_n;
20183e07920fSDavid van Moolenbroek 		}
20193e07920fSDavid van Moolenbroek 		snprintf(fp_buf, sizeof(fp_buf), "<%s.%s>", f_s, p_s);
20203e07920fSDavid van Moolenbroek 	}
20213e07920fSDavid van Moolenbroek 
20223e07920fSDavid van Moolenbroek 	/* hostname or FQDN */
20233e07920fSDavid van Moolenbroek 	hostname = (buffer->host ? buffer->host : buffer->recvhost);
20243e07920fSDavid van Moolenbroek 	if (BSDOutputFormat
20253e07920fSDavid van Moolenbroek 	 && (shorthostname = strdup(hostname))) {
20263e07920fSDavid van Moolenbroek 		/* if the previous BSD output format with "host [recvhost]:"
20273e07920fSDavid van Moolenbroek 		 * gets implemented, this is the right place to distinguish
20283e07920fSDavid van Moolenbroek 		 * between buffer->host and buffer->recvhost
20293e07920fSDavid van Moolenbroek 		 */
20303e07920fSDavid van Moolenbroek 		trim_anydomain(shorthostname);
20313e07920fSDavid van Moolenbroek 		hostname = shorthostname;
20323e07920fSDavid van Moolenbroek 	}
20333e07920fSDavid van Moolenbroek 
20343e07920fSDavid van Moolenbroek 	/* new message formatting:
20353e07920fSDavid van Moolenbroek 	 * instead of using iov always assemble one complete TLS-ready line
20363e07920fSDavid van Moolenbroek 	 * with length and priority (depending on BSDOutputFormat either in
20373e07920fSDavid van Moolenbroek 	 * BSD Syslog or syslog-protocol format)
20383e07920fSDavid van Moolenbroek 	 *
20393e07920fSDavid van Moolenbroek 	 * additionally save the length of the prefixes,
20403e07920fSDavid van Moolenbroek 	 * so UDP destinations can skip the length prefix and
20413e07920fSDavid van Moolenbroek 	 * file/pipe/wall destinations can omit length and priority
20423e07920fSDavid van Moolenbroek 	 */
20433e07920fSDavid van Moolenbroek 	/* first determine required space */
20443e07920fSDavid van Moolenbroek 	if (BSDOutputFormat) {
20453e07920fSDavid van Moolenbroek 		/* only output ASCII chars */
20463e07920fSDavid van Moolenbroek 		if (buffer->sd)
20473e07920fSDavid van Moolenbroek 			ascii_sd = copy_utf8_ascii(buffer->sd,
20483e07920fSDavid van Moolenbroek 				strlen(buffer->sd));
20493e07920fSDavid van Moolenbroek 		if (buffer->msg) {
20503e07920fSDavid van Moolenbroek 			if (IS_BOM(buffer->msg))
20513e07920fSDavid van Moolenbroek 				ascii_msg = copy_utf8_ascii(buffer->msg,
20523e07920fSDavid van Moolenbroek 					buffer->msglen - 1);
20533e07920fSDavid van Moolenbroek 			else /* assume already converted at input */
20543e07920fSDavid van Moolenbroek 				ascii_msg = buffer->msg;
20553e07920fSDavid van Moolenbroek 		}
20563e07920fSDavid van Moolenbroek 		msglen = snprintf(NULL, 0, "<%d>%s%.15s %s %s%s%s%s: %s%s%s",
20573e07920fSDavid van Moolenbroek 			     buffer->pri, fp_buf, buffer->timestamp,
20583e07920fSDavid van Moolenbroek 			     hostname, OUT(buffer->prog),
20593e07920fSDavid van Moolenbroek 			     buffer->pid ? "[" : "",
20603e07920fSDavid van Moolenbroek 			     buffer->pid ? buffer->pid : "",
20613e07920fSDavid van Moolenbroek 			     buffer->pid ? "]" : "", ascii_sd,
20623e07920fSDavid van Moolenbroek 			     (buffer->sd && buffer->msg ? " ": ""), ascii_msg);
20633e07920fSDavid van Moolenbroek 	} else
20643e07920fSDavid van Moolenbroek 		msglen = snprintf(NULL, 0, "<%d>1 %s%s %s %s %s %s %s%s%s",
20653e07920fSDavid van Moolenbroek 			     buffer->pri, fp_buf, buffer->timestamp,
20663e07920fSDavid van Moolenbroek 			     hostname, OUT(buffer->prog), OUT(buffer->pid),
20673e07920fSDavid van Moolenbroek 			     OUT(buffer->msgid), OUT(buffer->sd),
20683e07920fSDavid van Moolenbroek 			     (buffer->msg ? " ": ""),
20693e07920fSDavid van Moolenbroek 			     (buffer->msg ? buffer->msg: ""));
20703e07920fSDavid van Moolenbroek 	/* add space for length prefix */
20713e07920fSDavid van Moolenbroek 	tlsprefixlen = 0;
20723e07920fSDavid van Moolenbroek 	for (j = msglen; j; j /= 10)
20733e07920fSDavid van Moolenbroek 		tlsprefixlen++;
20743e07920fSDavid van Moolenbroek 	/* one more for the space */
20753e07920fSDavid van Moolenbroek 	tlsprefixlen++;
20763e07920fSDavid van Moolenbroek 
20773e07920fSDavid van Moolenbroek 	prilen = snprintf(NULL, 0, "<%d>", buffer->pri);
20783e07920fSDavid van Moolenbroek 	if (!BSDOutputFormat)
20793e07920fSDavid van Moolenbroek 		prilen += 2; /* version char and space */
20803e07920fSDavid van Moolenbroek 	MALLOC(*line, msglen + tlsprefixlen + 1);
20813e07920fSDavid van Moolenbroek 	if (BSDOutputFormat)
20823e07920fSDavid van Moolenbroek 		linelen = snprintf(*line,
20833e07920fSDavid van Moolenbroek 		     msglen + tlsprefixlen + 1,
20843e07920fSDavid van Moolenbroek 		     "%zu <%d>%s%.15s %s %s%s%s%s: %s%s%s",
20853e07920fSDavid van Moolenbroek 		     msglen, buffer->pri, fp_buf, buffer->timestamp,
20863e07920fSDavid van Moolenbroek 		     hostname, OUT(buffer->prog),
20873e07920fSDavid van Moolenbroek 		     (buffer->pid ? "[" : ""),
20883e07920fSDavid van Moolenbroek 		     (buffer->pid ? buffer->pid : ""),
20893e07920fSDavid van Moolenbroek 		     (buffer->pid ? "]" : ""), ascii_sd,
20903e07920fSDavid van Moolenbroek 		     (buffer->sd && buffer->msg ? " ": ""), ascii_msg);
20913e07920fSDavid van Moolenbroek 	else
20923e07920fSDavid van Moolenbroek 		linelen = snprintf(*line,
20933e07920fSDavid van Moolenbroek 		     msglen + tlsprefixlen + 1,
20943e07920fSDavid van Moolenbroek 		     "%zu <%d>1 %s%s %s %s %s %s %s%s%s",
20953e07920fSDavid van Moolenbroek 		     msglen, buffer->pri, fp_buf, buffer->timestamp,
20963e07920fSDavid van Moolenbroek 		     hostname, OUT(buffer->prog), OUT(buffer->pid),
20973e07920fSDavid van Moolenbroek 		     OUT(buffer->msgid), OUT(buffer->sd),
20983e07920fSDavid van Moolenbroek 		     (buffer->msg ? " ": ""),
20993e07920fSDavid van Moolenbroek 		     (buffer->msg ? buffer->msg: ""));
21003e07920fSDavid van Moolenbroek 	DPRINTF(D_DATA, "formatted %zu octets to: '%.*s' (linelen %zu, "
21013e07920fSDavid van Moolenbroek 	    "msglen %zu, tlsprefixlen %zu, prilen %zu)\n", linelen,
21023e07920fSDavid van Moolenbroek 	    (int)linelen, *line, linelen, msglen, tlsprefixlen, prilen);
21033e07920fSDavid van Moolenbroek 
21043e07920fSDavid van Moolenbroek 	FREEPTR(shorthostname);
21053e07920fSDavid van Moolenbroek 	if (ascii_sd != ascii_empty)
21063e07920fSDavid van Moolenbroek 		FREEPTR(ascii_sd);
21073e07920fSDavid van Moolenbroek 	if (ascii_msg != ascii_empty && ascii_msg != buffer->msg)
21083e07920fSDavid van Moolenbroek 		FREEPTR(ascii_msg);
21093e07920fSDavid van Moolenbroek 
21103e07920fSDavid van Moolenbroek 	if (ptr_linelen)      *ptr_linelen	= linelen;
21113e07920fSDavid van Moolenbroek 	if (ptr_msglen)	      *ptr_msglen	= msglen;
21123e07920fSDavid van Moolenbroek 	if (ptr_tlsprefixlen) *ptr_tlsprefixlen = tlsprefixlen;
21133e07920fSDavid van Moolenbroek 	if (ptr_prilen)	      *ptr_prilen	= prilen;
21143e07920fSDavid van Moolenbroek 	return true;
21153e07920fSDavid van Moolenbroek }
21163e07920fSDavid van Moolenbroek 
21173e07920fSDavid van Moolenbroek /*
21183e07920fSDavid van Moolenbroek  * if qentry == NULL: new message, if temporarily undeliverable it will be enqueued
21193e07920fSDavid van Moolenbroek  * if qentry != NULL: a temporarily undeliverable message will not be enqueued,
21203e07920fSDavid van Moolenbroek  *		    but after delivery be removed from the queue
21213e07920fSDavid van Moolenbroek  */
21223e07920fSDavid van Moolenbroek void
fprintlog(struct filed * f,struct buf_msg * passedbuffer,struct buf_queue * qentry)21233e07920fSDavid van Moolenbroek fprintlog(struct filed *f, struct buf_msg *passedbuffer, struct buf_queue *qentry)
21243e07920fSDavid van Moolenbroek {
21253e07920fSDavid van Moolenbroek 	static char crnl[] = "\r\n";
21263e07920fSDavid van Moolenbroek 	struct buf_msg *buffer = passedbuffer;
21273e07920fSDavid van Moolenbroek 	struct iovec iov[4];
21283e07920fSDavid van Moolenbroek 	struct iovec *v = iov;
21293e07920fSDavid van Moolenbroek 	bool error = false;
21303e07920fSDavid van Moolenbroek 	int e = 0, len = 0;
21313e07920fSDavid van Moolenbroek 	size_t msglen, linelen, tlsprefixlen, prilen;
21323e07920fSDavid van Moolenbroek 	char *p, *line = NULL, *lineptr = NULL;
21333e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
21343e07920fSDavid van Moolenbroek 	bool newhash = false;
21353e07920fSDavid van Moolenbroek #endif
21363e07920fSDavid van Moolenbroek #define REPBUFSIZE 80
21373e07920fSDavid van Moolenbroek 	char greetings[200];
21383e07920fSDavid van Moolenbroek #define ADDEV() do { v++; assert((size_t)(v - iov) < A_CNT(iov)); } while(/*CONSTCOND*/0)
21393e07920fSDavid van Moolenbroek 
21403e07920fSDavid van Moolenbroek 	DPRINTF(D_CALL, "fprintlog(%p, %p, %p)\n", f, buffer, qentry);
21413e07920fSDavid van Moolenbroek 
21423e07920fSDavid van Moolenbroek 	f->f_time = now;
21433e07920fSDavid van Moolenbroek 
21443e07920fSDavid van Moolenbroek 	/* increase refcount here and lower again at return.
21453e07920fSDavid van Moolenbroek 	 * this enables the buffer in the else branch to be freed
21463e07920fSDavid van Moolenbroek 	 * --> every branch needs one NEWREF() or buf_msg_new()! */
21473e07920fSDavid van Moolenbroek 	if (buffer) {
21483e07920fSDavid van Moolenbroek 		(void)NEWREF(buffer);
21493e07920fSDavid van Moolenbroek 	} else {
21503e07920fSDavid van Moolenbroek 		if (f->f_prevcount > 1) {
21513e07920fSDavid van Moolenbroek 			/* possible syslog-sign incompatibility:
21523e07920fSDavid van Moolenbroek 			 * assume destinations f1 and f2 share one SG and
21533e07920fSDavid van Moolenbroek 			 * get the same message sequence.
21543e07920fSDavid van Moolenbroek 			 *
21553e07920fSDavid van Moolenbroek 			 * now both f1 and f2 generate "repeated" messages
21563e07920fSDavid van Moolenbroek 			 * "repeated" messages are different due to different
21573e07920fSDavid van Moolenbroek 			 * timestamps
21583e07920fSDavid van Moolenbroek 			 * the SG will get hashes for the two "repeated" messages
21593e07920fSDavid van Moolenbroek 			 *
21603e07920fSDavid van Moolenbroek 			 * now both f1 and f2 are just fine, but a verification
21613e07920fSDavid van Moolenbroek 			 * will report that each 'lost' a message, i.e. the
21623e07920fSDavid van Moolenbroek 			 * other's "repeated" message
21633e07920fSDavid van Moolenbroek 			 *
21643e07920fSDavid van Moolenbroek 			 * conditions for 'safe configurations':
21653e07920fSDavid van Moolenbroek 			 * - use NoRepeat option,
21663e07920fSDavid van Moolenbroek 			 * - use SG 3, or
21673e07920fSDavid van Moolenbroek 			 * - have exactly one destination for every PRI
21683e07920fSDavid van Moolenbroek 			 */
21693e07920fSDavid van Moolenbroek 			buffer = buf_msg_new(REPBUFSIZE);
21703e07920fSDavid van Moolenbroek 			buffer->msglen = snprintf(buffer->msg, REPBUFSIZE,
21713e07920fSDavid van Moolenbroek 			    "last message repeated %d times", f->f_prevcount);
2172*0a6a1f1dSLionel Sambuc 			buffer->timestamp = make_timestamp(NULL,
2173*0a6a1f1dSLionel Sambuc 			    !BSDOutputFormat, 0);
21743e07920fSDavid van Moolenbroek 			buffer->pri = f->f_prevmsg->pri;
21753e07920fSDavid van Moolenbroek 			buffer->host = LocalFQDN;
21763e07920fSDavid van Moolenbroek 			buffer->prog = appname;
21773e07920fSDavid van Moolenbroek 			buffer->pid = include_pid;
21783e07920fSDavid van Moolenbroek 
21793e07920fSDavid van Moolenbroek 		} else {
21803e07920fSDavid van Moolenbroek 			buffer = NEWREF(f->f_prevmsg);
21813e07920fSDavid van Moolenbroek 		}
21823e07920fSDavid van Moolenbroek 	}
21833e07920fSDavid van Moolenbroek 
21843e07920fSDavid van Moolenbroek 	/* no syslog-sign messages to tty/console/... */
21853e07920fSDavid van Moolenbroek 	if ((buffer->flags & SIGN_MSG)
21863e07920fSDavid van Moolenbroek 	    && ((f->f_type == F_UNUSED)
21873e07920fSDavid van Moolenbroek 	    || (f->f_type == F_TTY)
21883e07920fSDavid van Moolenbroek 	    || (f->f_type == F_CONSOLE)
21893e07920fSDavid van Moolenbroek 	    || (f->f_type == F_USERS)
21903e07920fSDavid van Moolenbroek 	    || (f->f_type == F_WALL)
21913e07920fSDavid van Moolenbroek 	    || (f->f_type == F_FIFO))) {
21923e07920fSDavid van Moolenbroek 		DELREF(buffer);
21933e07920fSDavid van Moolenbroek 		return;
21943e07920fSDavid van Moolenbroek 	}
21953e07920fSDavid van Moolenbroek 
21963e07920fSDavid van Moolenbroek 	/* buffering works only for few types */
21973e07920fSDavid van Moolenbroek 	if (qentry
21983e07920fSDavid van Moolenbroek 	    && (f->f_type != F_TLS)
21993e07920fSDavid van Moolenbroek 	    && (f->f_type != F_PIPE)
22003e07920fSDavid van Moolenbroek 	    && (f->f_type != F_FILE)
22013e07920fSDavid van Moolenbroek 	    && (f->f_type != F_FIFO)) {
22023e07920fSDavid van Moolenbroek 		errno = 0;
22033e07920fSDavid van Moolenbroek 		logerror("Warning: unexpected message type %d in buffer",
22043e07920fSDavid van Moolenbroek 		    f->f_type);
22053e07920fSDavid van Moolenbroek 		DELREF(buffer);
22063e07920fSDavid van Moolenbroek 		return;
22073e07920fSDavid van Moolenbroek 	}
22083e07920fSDavid van Moolenbroek 
22093e07920fSDavid van Moolenbroek 	if (!format_buffer(buffer, &line,
22103e07920fSDavid van Moolenbroek 	    &linelen, &msglen, &tlsprefixlen, &prilen)) {
22113e07920fSDavid van Moolenbroek 		DPRINTF(D_CALL, "format_buffer() failed, skip message\n");
22123e07920fSDavid van Moolenbroek 		DELREF(buffer);
22133e07920fSDavid van Moolenbroek 		return;
22143e07920fSDavid van Moolenbroek 	}
22153e07920fSDavid van Moolenbroek 	/* assert maximum message length */
22163e07920fSDavid van Moolenbroek 	if (TypeInfo[f->f_type].max_msg_length != -1
22173e07920fSDavid van Moolenbroek 	    && (size_t)TypeInfo[f->f_type].max_msg_length
22183e07920fSDavid van Moolenbroek 	    < linelen - tlsprefixlen - prilen) {
22193e07920fSDavid van Moolenbroek 		linelen = TypeInfo[f->f_type].max_msg_length
22203e07920fSDavid van Moolenbroek 		    + tlsprefixlen + prilen;
22213e07920fSDavid van Moolenbroek 		DPRINTF(D_DATA, "truncating oversized message to %zu octets\n",
22223e07920fSDavid van Moolenbroek 		    linelen);
22233e07920fSDavid van Moolenbroek 	}
22243e07920fSDavid van Moolenbroek 
22253e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
22263e07920fSDavid van Moolenbroek 	/* keep state between appending the hash (before buffer is sent)
22273e07920fSDavid van Moolenbroek 	 * and possibly sending a SB (after buffer is sent): */
22283e07920fSDavid van Moolenbroek 	/* get hash */
22293e07920fSDavid van Moolenbroek 	if (!(buffer->flags & SIGN_MSG) && !qentry) {
22303e07920fSDavid van Moolenbroek 		char *hash = NULL;
22313e07920fSDavid van Moolenbroek 		struct signature_group_t *sg;
22323e07920fSDavid van Moolenbroek 
22333e07920fSDavid van Moolenbroek 		if ((sg = sign_get_sg(buffer->pri, f)) != NULL) {
22343e07920fSDavid van Moolenbroek 			if (sign_msg_hash(line + tlsprefixlen, &hash))
22353e07920fSDavid van Moolenbroek 				newhash = sign_append_hash(hash, sg);
22363e07920fSDavid van Moolenbroek 			else
22373e07920fSDavid van Moolenbroek 				DPRINTF(D_SIGN,
22383e07920fSDavid van Moolenbroek 					"Unable to hash line \"%s\"\n", line);
22393e07920fSDavid van Moolenbroek 		}
22403e07920fSDavid van Moolenbroek 	}
22413e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
22423e07920fSDavid van Moolenbroek 
22433e07920fSDavid van Moolenbroek 	/* set start and length of buffer and/or fill iovec */
22443e07920fSDavid van Moolenbroek 	switch (f->f_type) {
22453e07920fSDavid van Moolenbroek 	case F_UNUSED:
22463e07920fSDavid van Moolenbroek 		/* nothing */
22473e07920fSDavid van Moolenbroek 		break;
22483e07920fSDavid van Moolenbroek 	case F_TLS:
22493e07920fSDavid van Moolenbroek 		/* nothing, as TLS uses whole buffer to send */
22503e07920fSDavid van Moolenbroek 		lineptr = line;
22513e07920fSDavid van Moolenbroek 		len = linelen;
22523e07920fSDavid van Moolenbroek 		break;
22533e07920fSDavid van Moolenbroek 	case F_FORW:
22543e07920fSDavid van Moolenbroek 		lineptr = line + tlsprefixlen;
22553e07920fSDavid van Moolenbroek 		len = linelen - tlsprefixlen;
22563e07920fSDavid van Moolenbroek 		break;
22573e07920fSDavid van Moolenbroek 	case F_PIPE:
22583e07920fSDavid van Moolenbroek 	case F_FIFO:
22593e07920fSDavid van Moolenbroek 	case F_FILE:  /* fallthrough */
22603e07920fSDavid van Moolenbroek 		if (f->f_flags & FFLAG_FULL) {
22613e07920fSDavid van Moolenbroek 			v->iov_base = line + tlsprefixlen;
22623e07920fSDavid van Moolenbroek 			v->iov_len = linelen - tlsprefixlen;
22633e07920fSDavid van Moolenbroek 		} else {
22643e07920fSDavid van Moolenbroek 			v->iov_base = line + tlsprefixlen + prilen;
22653e07920fSDavid van Moolenbroek 			v->iov_len = linelen - tlsprefixlen - prilen;
22663e07920fSDavid van Moolenbroek 		}
22673e07920fSDavid van Moolenbroek 		ADDEV();
22683e07920fSDavid van Moolenbroek 		v->iov_base = &crnl[1];
22693e07920fSDavid van Moolenbroek 		v->iov_len = 1;
22703e07920fSDavid van Moolenbroek 		ADDEV();
22713e07920fSDavid van Moolenbroek 		break;
22723e07920fSDavid van Moolenbroek 	case F_CONSOLE:
22733e07920fSDavid van Moolenbroek 	case F_TTY:
22743e07920fSDavid van Moolenbroek 		/* filter non-ASCII */
22753e07920fSDavid van Moolenbroek 		p = line;
22763e07920fSDavid van Moolenbroek 		while (*p) {
22773e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
22783e07920fSDavid van Moolenbroek 			p++;
22793e07920fSDavid van Moolenbroek 		}
22803e07920fSDavid van Moolenbroek 		v->iov_base = line + tlsprefixlen + prilen;
22813e07920fSDavid van Moolenbroek 		v->iov_len = linelen - tlsprefixlen - prilen;
22823e07920fSDavid van Moolenbroek 		ADDEV();
22833e07920fSDavid van Moolenbroek 		v->iov_base = crnl;
22843e07920fSDavid van Moolenbroek 		v->iov_len = 2;
22853e07920fSDavid van Moolenbroek 		ADDEV();
22863e07920fSDavid van Moolenbroek 		break;
22873e07920fSDavid van Moolenbroek 	case F_WALL:
22883e07920fSDavid van Moolenbroek 		v->iov_base = greetings;
22893e07920fSDavid van Moolenbroek 		v->iov_len = snprintf(greetings, sizeof(greetings),
22903e07920fSDavid van Moolenbroek 		    "\r\n\7Message from syslogd@%s at %s ...\r\n",
22913e07920fSDavid van Moolenbroek 		    (buffer->host ? buffer->host : buffer->recvhost),
22923e07920fSDavid van Moolenbroek 		    buffer->timestamp);
22933e07920fSDavid van Moolenbroek 		ADDEV();
22943e07920fSDavid van Moolenbroek 	case F_USERS: /* fallthrough */
22953e07920fSDavid van Moolenbroek 		/* filter non-ASCII */
22963e07920fSDavid van Moolenbroek 		p = line;
22973e07920fSDavid van Moolenbroek 		while (*p) {
22983e07920fSDavid van Moolenbroek 			*p = FORCE2ASCII(*p);
22993e07920fSDavid van Moolenbroek 			p++;
23003e07920fSDavid van Moolenbroek 		}
23013e07920fSDavid van Moolenbroek 		v->iov_base = line + tlsprefixlen + prilen;
23023e07920fSDavid van Moolenbroek 		v->iov_len = linelen - tlsprefixlen - prilen;
23033e07920fSDavid van Moolenbroek 		ADDEV();
23043e07920fSDavid van Moolenbroek 		v->iov_base = &crnl[1];
23053e07920fSDavid van Moolenbroek 		v->iov_len = 1;
23063e07920fSDavid van Moolenbroek 		ADDEV();
23073e07920fSDavid van Moolenbroek 		break;
23083e07920fSDavid van Moolenbroek 	}
23093e07920fSDavid van Moolenbroek 
23103e07920fSDavid van Moolenbroek 	/* send */
23113e07920fSDavid van Moolenbroek 	switch (f->f_type) {
23123e07920fSDavid van Moolenbroek 	case F_UNUSED:
23133e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name);
23143e07920fSDavid van Moolenbroek 		break;
23153e07920fSDavid van Moolenbroek 
23163e07920fSDavid van Moolenbroek 	case F_FORW:
23173e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s %s\n",
23183e07920fSDavid van Moolenbroek 		    TypeInfo[f->f_type].name, f->f_un.f_forw.f_hname);
23193e07920fSDavid van Moolenbroek 		udp_send(f, lineptr, len);
23203e07920fSDavid van Moolenbroek 		break;
23213e07920fSDavid van Moolenbroek 
23223e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
23233e07920fSDavid van Moolenbroek 	case F_TLS:
23243e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s %s\n",
23253e07920fSDavid van Moolenbroek 		    TypeInfo[f->f_type].name,
23263e07920fSDavid van Moolenbroek 		    f->f_un.f_tls.tls_conn->hostname);
23273e07920fSDavid van Moolenbroek 		/* make sure every message gets queued once
23283e07920fSDavid van Moolenbroek 		 * it will be removed when sendmsg is sent and free()d */
23293e07920fSDavid van Moolenbroek 		if (!qentry)
23303e07920fSDavid van Moolenbroek 			qentry = message_queue_add(f, NEWREF(buffer));
23313e07920fSDavid van Moolenbroek 		(void)tls_send(f, lineptr, len, qentry);
23323e07920fSDavid van Moolenbroek 		break;
23333e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
23343e07920fSDavid van Moolenbroek 
23353e07920fSDavid van Moolenbroek 	case F_PIPE:
23363e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s %s\n",
23373e07920fSDavid van Moolenbroek 		    TypeInfo[f->f_type].name, f->f_un.f_pipe.f_pname);
23383e07920fSDavid van Moolenbroek 		if (f->f_un.f_pipe.f_pid == 0) {
23393e07920fSDavid van Moolenbroek 			/* (re-)open */
23403e07920fSDavid van Moolenbroek 			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
23413e07920fSDavid van Moolenbroek 			    &f->f_un.f_pipe.f_pid)) < 0) {
23423e07920fSDavid van Moolenbroek 				f->f_type = F_UNUSED;
23433e07920fSDavid van Moolenbroek 				logerror("%s", f->f_un.f_pipe.f_pname);
23443e07920fSDavid van Moolenbroek 				message_queue_freeall(f);
23453e07920fSDavid van Moolenbroek 				break;
23463e07920fSDavid van Moolenbroek 			} else if (!qentry) /* prevent recursion */
23473e07920fSDavid van Moolenbroek 				SEND_QUEUE(f);
23483e07920fSDavid van Moolenbroek 		}
23493e07920fSDavid van Moolenbroek 		if (writev(f->f_file, iov, v - iov) < 0) {
23503e07920fSDavid van Moolenbroek 			e = errno;
23513e07920fSDavid van Moolenbroek 			if (f->f_un.f_pipe.f_pid > 0) {
23523e07920fSDavid van Moolenbroek 				(void) close(f->f_file);
23533e07920fSDavid van Moolenbroek 				deadq_enter(f->f_un.f_pipe.f_pid,
23543e07920fSDavid van Moolenbroek 				    f->f_un.f_pipe.f_pname);
23553e07920fSDavid van Moolenbroek 			}
23563e07920fSDavid van Moolenbroek 			f->f_un.f_pipe.f_pid = 0;
23573e07920fSDavid van Moolenbroek 			/*
23583e07920fSDavid van Moolenbroek 			 * If the error was EPIPE, then what is likely
23593e07920fSDavid van Moolenbroek 			 * has happened is we have a command that is
23603e07920fSDavid van Moolenbroek 			 * designed to take a single message line and
23613e07920fSDavid van Moolenbroek 			 * then exit, but we tried to feed it another
23623e07920fSDavid van Moolenbroek 			 * one before we reaped the child and thus
23633e07920fSDavid van Moolenbroek 			 * reset our state.
23643e07920fSDavid van Moolenbroek 			 *
23653e07920fSDavid van Moolenbroek 			 * Well, now we've reset our state, so try opening
23663e07920fSDavid van Moolenbroek 			 * the pipe and sending the message again if EPIPE
23673e07920fSDavid van Moolenbroek 			 * was the error.
23683e07920fSDavid van Moolenbroek 			 */
23693e07920fSDavid van Moolenbroek 			if (e == EPIPE) {
23703e07920fSDavid van Moolenbroek 				if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
23713e07920fSDavid van Moolenbroek 				     &f->f_un.f_pipe.f_pid)) < 0) {
23723e07920fSDavid van Moolenbroek 					f->f_type = F_UNUSED;
23733e07920fSDavid van Moolenbroek 					logerror("%s", f->f_un.f_pipe.f_pname);
23743e07920fSDavid van Moolenbroek 					message_queue_freeall(f);
23753e07920fSDavid van Moolenbroek 					break;
23763e07920fSDavid van Moolenbroek 				}
23773e07920fSDavid van Moolenbroek 				if (writev(f->f_file, iov, v - iov) < 0) {
23783e07920fSDavid van Moolenbroek 					e = errno;
23793e07920fSDavid van Moolenbroek 					if (f->f_un.f_pipe.f_pid > 0) {
23803e07920fSDavid van Moolenbroek 					    (void) close(f->f_file);
23813e07920fSDavid van Moolenbroek 					    deadq_enter(f->f_un.f_pipe.f_pid,
23823e07920fSDavid van Moolenbroek 						f->f_un.f_pipe.f_pname);
23833e07920fSDavid van Moolenbroek 					}
23843e07920fSDavid van Moolenbroek 					f->f_un.f_pipe.f_pid = 0;
23853e07920fSDavid van Moolenbroek 					error = true;	/* enqueue on return */
23863e07920fSDavid van Moolenbroek 				} else
23873e07920fSDavid van Moolenbroek 					e = 0;
23883e07920fSDavid van Moolenbroek 			}
23893e07920fSDavid van Moolenbroek 			if (e != 0 && !error) {
23903e07920fSDavid van Moolenbroek 				errno = e;
23913e07920fSDavid van Moolenbroek 				logerror("%s", f->f_un.f_pipe.f_pname);
23923e07920fSDavid van Moolenbroek 			}
23933e07920fSDavid van Moolenbroek 		}
23943e07920fSDavid van Moolenbroek 		if (e == 0 && qentry) { /* sent buffered msg */
23953e07920fSDavid van Moolenbroek 			message_queue_remove(f, qentry);
23963e07920fSDavid van Moolenbroek 		}
23973e07920fSDavid van Moolenbroek 		break;
23983e07920fSDavid van Moolenbroek 
23993e07920fSDavid van Moolenbroek 	case F_CONSOLE:
24003e07920fSDavid van Moolenbroek 		if (buffer->flags & IGN_CONS) {
24013e07920fSDavid van Moolenbroek 			DPRINTF(D_MISC, "Logging to %s (ignored)\n",
24023e07920fSDavid van Moolenbroek 				TypeInfo[f->f_type].name);
24033e07920fSDavid van Moolenbroek 			break;
24043e07920fSDavid van Moolenbroek 		}
24053e07920fSDavid van Moolenbroek 		/* FALLTHROUGH */
24063e07920fSDavid van Moolenbroek 
24073e07920fSDavid van Moolenbroek 	case F_TTY:
24083e07920fSDavid van Moolenbroek 	case F_FILE:
24093e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s %s\n",
24103e07920fSDavid van Moolenbroek 			TypeInfo[f->f_type].name, f->f_un.f_fname);
24113e07920fSDavid van Moolenbroek 	again:
24123e07920fSDavid van Moolenbroek 		if ((f->f_type == F_FILE ? writev(f->f_file, iov, v - iov) :
24133e07920fSDavid van Moolenbroek 		    writev1(f->f_file, iov, v - iov)) < 0) {
24143e07920fSDavid van Moolenbroek 			e = errno;
24153e07920fSDavid van Moolenbroek 			if (f->f_type == F_FILE && e == ENOSPC) {
24163e07920fSDavid van Moolenbroek 				int lasterror = f->f_lasterror;
24173e07920fSDavid van Moolenbroek 				f->f_lasterror = e;
24183e07920fSDavid van Moolenbroek 				if (lasterror != e)
24193e07920fSDavid van Moolenbroek 					logerror("%s", f->f_un.f_fname);
24203e07920fSDavid van Moolenbroek 				error = true;	/* enqueue on return */
24213e07920fSDavid van Moolenbroek 			}
24223e07920fSDavid van Moolenbroek 			(void)close(f->f_file);
24233e07920fSDavid van Moolenbroek 			/*
24243e07920fSDavid van Moolenbroek 			 * Check for errors on TTY's due to loss of tty
24253e07920fSDavid van Moolenbroek 			 */
24263e07920fSDavid van Moolenbroek 			if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
24273e07920fSDavid van Moolenbroek 				f->f_file = open(f->f_un.f_fname,
24283e07920fSDavid van Moolenbroek 				    O_WRONLY|O_APPEND|O_NONBLOCK, 0);
24293e07920fSDavid van Moolenbroek 				if (f->f_file < 0) {
24303e07920fSDavid van Moolenbroek 					f->f_type = F_UNUSED;
24313e07920fSDavid van Moolenbroek 					logerror("%s", f->f_un.f_fname);
24323e07920fSDavid van Moolenbroek 					message_queue_freeall(f);
24333e07920fSDavid van Moolenbroek 				} else
24343e07920fSDavid van Moolenbroek 					goto again;
24353e07920fSDavid van Moolenbroek 			} else {
24363e07920fSDavid van Moolenbroek 				f->f_type = F_UNUSED;
24373e07920fSDavid van Moolenbroek 				errno = e;
24383e07920fSDavid van Moolenbroek 				f->f_lasterror = e;
24393e07920fSDavid van Moolenbroek 				logerror("%s", f->f_un.f_fname);
24403e07920fSDavid van Moolenbroek 				message_queue_freeall(f);
24413e07920fSDavid van Moolenbroek 			}
24423e07920fSDavid van Moolenbroek 		} else {
24433e07920fSDavid van Moolenbroek 			f->f_lasterror = 0;
24443e07920fSDavid van Moolenbroek 			if ((buffer->flags & SYNC_FILE)
24453e07920fSDavid van Moolenbroek 			 && (f->f_flags & FFLAG_SYNC))
24463e07920fSDavid van Moolenbroek 				(void)fsync(f->f_file);
24473e07920fSDavid van Moolenbroek 			/* Problem with files: We cannot check beforehand if
24483e07920fSDavid van Moolenbroek 			 * they would be writeable and call send_queue() first.
24493e07920fSDavid van Moolenbroek 			 * So we call send_queue() after a successful write,
24503e07920fSDavid van Moolenbroek 			 * which means the first message will be out of order.
24513e07920fSDavid van Moolenbroek 			 */
24523e07920fSDavid van Moolenbroek 			if (!qentry) /* prevent recursion */
24533e07920fSDavid van Moolenbroek 				SEND_QUEUE(f);
24543e07920fSDavid van Moolenbroek 			else if (qentry) /* sent buffered msg */
24553e07920fSDavid van Moolenbroek 				message_queue_remove(f, qentry);
24563e07920fSDavid van Moolenbroek 		}
24573e07920fSDavid van Moolenbroek 		break;
24583e07920fSDavid van Moolenbroek 
24593e07920fSDavid van Moolenbroek 	case F_FIFO:
24603e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s %s\n",
24613e07920fSDavid van Moolenbroek 			TypeInfo[f->f_type].name, f->f_un.f_fname);
24623e07920fSDavid van Moolenbroek 		if (f->f_file < 0) {
24633e07920fSDavid van Moolenbroek 			f->f_file =
24643e07920fSDavid van Moolenbroek 			  open(f->f_un.f_fname, O_WRONLY|O_NONBLOCK, 0);
24653e07920fSDavid van Moolenbroek 			e = errno;
24663e07920fSDavid van Moolenbroek 			if (f->f_file < 0 && e == ENXIO) {
24673e07920fSDavid van Moolenbroek 				/* Drop messages with no reader */
24683e07920fSDavid van Moolenbroek 				if (qentry)
24693e07920fSDavid van Moolenbroek 					message_queue_remove(f, qentry);
24703e07920fSDavid van Moolenbroek 				break;
24713e07920fSDavid van Moolenbroek 			}
24723e07920fSDavid van Moolenbroek 		}
24733e07920fSDavid van Moolenbroek 
24743e07920fSDavid van Moolenbroek 		if (f->f_file >= 0 && writev(f->f_file, iov, v - iov) < 0) {
24753e07920fSDavid van Moolenbroek 			e = errno;
24763e07920fSDavid van Moolenbroek 
24773e07920fSDavid van Moolenbroek 			/* Enqueue if the fifo buffer is full */
24783e07920fSDavid van Moolenbroek 			if (e == EAGAIN) {
24793e07920fSDavid van Moolenbroek 				if (f->f_lasterror != e)
24803e07920fSDavid van Moolenbroek 					logerror("%s", f->f_un.f_fname);
24813e07920fSDavid van Moolenbroek 				f->f_lasterror = e;
24823e07920fSDavid van Moolenbroek 				error = true;	/* enqueue on return */
24833e07920fSDavid van Moolenbroek 				break;
24843e07920fSDavid van Moolenbroek 			}
24853e07920fSDavid van Moolenbroek 
24863e07920fSDavid van Moolenbroek 			close(f->f_file);
24873e07920fSDavid van Moolenbroek 			f->f_file = -1;
24883e07920fSDavid van Moolenbroek 
24893e07920fSDavid van Moolenbroek 			/* Drop messages with no reader */
24903e07920fSDavid van Moolenbroek 			if (e == EPIPE) {
24913e07920fSDavid van Moolenbroek 				if (qentry)
24923e07920fSDavid van Moolenbroek 					message_queue_remove(f, qentry);
24933e07920fSDavid van Moolenbroek 				break;
24943e07920fSDavid van Moolenbroek 			}
24953e07920fSDavid van Moolenbroek 		}
24963e07920fSDavid van Moolenbroek 
24973e07920fSDavid van Moolenbroek 		if (f->f_file < 0) {
24983e07920fSDavid van Moolenbroek 			f->f_type = F_UNUSED;
24993e07920fSDavid van Moolenbroek 			errno = e;
25003e07920fSDavid van Moolenbroek 			f->f_lasterror = e;
25013e07920fSDavid van Moolenbroek 			logerror("%s", f->f_un.f_fname);
25023e07920fSDavid van Moolenbroek 			message_queue_freeall(f);
25033e07920fSDavid van Moolenbroek 			break;
25043e07920fSDavid van Moolenbroek 		}
25053e07920fSDavid van Moolenbroek 
25063e07920fSDavid van Moolenbroek 		f->f_lasterror = 0;
25073e07920fSDavid van Moolenbroek 		if (!qentry) /* prevent recursion (see comment for F_FILE) */
25083e07920fSDavid van Moolenbroek 			SEND_QUEUE(f);
25093e07920fSDavid van Moolenbroek 		if (qentry) /* sent buffered msg */
25103e07920fSDavid van Moolenbroek 			message_queue_remove(f, qentry);
25113e07920fSDavid van Moolenbroek 		break;
25123e07920fSDavid van Moolenbroek 
25133e07920fSDavid van Moolenbroek 	case F_USERS:
25143e07920fSDavid van Moolenbroek 	case F_WALL:
25153e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name);
25163e07920fSDavid van Moolenbroek 		wallmsg(f, iov, v - iov);
25173e07920fSDavid van Moolenbroek 		break;
25183e07920fSDavid van Moolenbroek 	}
25193e07920fSDavid van Moolenbroek 	f->f_prevcount = 0;
25203e07920fSDavid van Moolenbroek 
25213e07920fSDavid van Moolenbroek 	if (error && !qentry)
25223e07920fSDavid van Moolenbroek 		message_queue_add(f, NEWREF(buffer));
25233e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
25243e07920fSDavid van Moolenbroek 	if (newhash) {
25253e07920fSDavid van Moolenbroek 		struct signature_group_t *sg;
25263e07920fSDavid van Moolenbroek 		sg = sign_get_sg(buffer->pri, f);
25273e07920fSDavid van Moolenbroek 		(void)sign_send_signature_block(sg, false);
25283e07920fSDavid van Moolenbroek 	}
25293e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
25303e07920fSDavid van Moolenbroek 	/* this belongs to the ad-hoc buffer at the first if(buffer) */
25313e07920fSDavid van Moolenbroek 	DELREF(buffer);
25323e07920fSDavid van Moolenbroek 	/* TLS frees on its own */
25333e07920fSDavid van Moolenbroek 	if (f->f_type != F_TLS)
25343e07920fSDavid van Moolenbroek 		FREEPTR(line);
25353e07920fSDavid van Moolenbroek }
25363e07920fSDavid van Moolenbroek 
25373e07920fSDavid van Moolenbroek /* send one line by UDP */
25383e07920fSDavid van Moolenbroek void
udp_send(struct filed * f,char * line,size_t len)25393e07920fSDavid van Moolenbroek udp_send(struct filed *f, char *line, size_t len)
25403e07920fSDavid van Moolenbroek {
25413e07920fSDavid van Moolenbroek 	int lsent, fail, retry, j;
25423e07920fSDavid van Moolenbroek 	struct addrinfo *r;
25433e07920fSDavid van Moolenbroek 
25443e07920fSDavid van Moolenbroek 	DPRINTF((D_NET|D_CALL), "udp_send(f=%p, line=\"%s\", "
25453e07920fSDavid van Moolenbroek 	    "len=%zu) to dest.\n", f, line, len);
25463e07920fSDavid van Moolenbroek 
25473e07920fSDavid van Moolenbroek 	if (!finet)
25483e07920fSDavid van Moolenbroek 		return;
25493e07920fSDavid van Moolenbroek 
25503e07920fSDavid van Moolenbroek 	lsent = -1;
25513e07920fSDavid van Moolenbroek 	fail = 0;
25523e07920fSDavid van Moolenbroek 	assert(f->f_type == F_FORW);
25533e07920fSDavid van Moolenbroek 	for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
25543e07920fSDavid van Moolenbroek 		retry = 0;
25553e07920fSDavid van Moolenbroek 		for (j = 0; j < finet->fd; j++) {
25563e07920fSDavid van Moolenbroek 			if (finet[j+1].af != r->ai_family)
25573e07920fSDavid van Moolenbroek 				continue;
25583e07920fSDavid van Moolenbroek sendagain:
25593e07920fSDavid van Moolenbroek 			lsent = sendto(finet[j+1].fd, line, len, 0,
25603e07920fSDavid van Moolenbroek 			    r->ai_addr, r->ai_addrlen);
25613e07920fSDavid van Moolenbroek 			if (lsent == -1) {
25623e07920fSDavid van Moolenbroek 				switch (errno) {
25633e07920fSDavid van Moolenbroek 				case ENOBUFS:
25643e07920fSDavid van Moolenbroek 					/* wait/retry/drop */
25653e07920fSDavid van Moolenbroek 					if (++retry < 5) {
25663e07920fSDavid van Moolenbroek 						usleep(1000);
25673e07920fSDavid van Moolenbroek 						goto sendagain;
25683e07920fSDavid van Moolenbroek 					}
25693e07920fSDavid van Moolenbroek 					break;
25703e07920fSDavid van Moolenbroek 				case EHOSTDOWN:
25713e07920fSDavid van Moolenbroek 				case EHOSTUNREACH:
25723e07920fSDavid van Moolenbroek 				case ENETDOWN:
25733e07920fSDavid van Moolenbroek 					/* drop */
25743e07920fSDavid van Moolenbroek 					break;
25753e07920fSDavid van Moolenbroek 				default:
25763e07920fSDavid van Moolenbroek 					/* busted */
25773e07920fSDavid van Moolenbroek 					fail++;
25783e07920fSDavid van Moolenbroek 					break;
25793e07920fSDavid van Moolenbroek 				}
25803e07920fSDavid van Moolenbroek 			} else if ((size_t)lsent == len)
25813e07920fSDavid van Moolenbroek 				break;
25823e07920fSDavid van Moolenbroek 		}
25833e07920fSDavid van Moolenbroek 		if ((size_t)lsent != len && fail) {
25843e07920fSDavid van Moolenbroek 			f->f_type = F_UNUSED;
25853e07920fSDavid van Moolenbroek 			logerror("sendto() failed");
25863e07920fSDavid van Moolenbroek 		}
25873e07920fSDavid van Moolenbroek 	}
25883e07920fSDavid van Moolenbroek }
25893e07920fSDavid van Moolenbroek 
25903e07920fSDavid van Moolenbroek /*
25913e07920fSDavid van Moolenbroek  *  WALLMSG -- Write a message to the world at large
25923e07920fSDavid van Moolenbroek  *
25933e07920fSDavid van Moolenbroek  *	Write the specified message to either the entire
25943e07920fSDavid van Moolenbroek  *	world, or a list of approved users.
25953e07920fSDavid van Moolenbroek  */
25963e07920fSDavid van Moolenbroek void
wallmsg(struct filed * f,struct iovec * iov,size_t iovcnt)25973e07920fSDavid van Moolenbroek wallmsg(struct filed *f, struct iovec *iov, size_t iovcnt)
25983e07920fSDavid van Moolenbroek {
25993e07920fSDavid van Moolenbroek #ifdef __NetBSD_Version__
26003e07920fSDavid van Moolenbroek 	static int reenter;			/* avoid calling ourselves */
26013e07920fSDavid van Moolenbroek 	int i;
26023e07920fSDavid van Moolenbroek 	char *p;
26033e07920fSDavid van Moolenbroek 	struct utmpentry *ep;
26043e07920fSDavid van Moolenbroek 
26053e07920fSDavid van Moolenbroek 	if (reenter++)
26063e07920fSDavid van Moolenbroek 		return;
26073e07920fSDavid van Moolenbroek 
26083e07920fSDavid van Moolenbroek 	(void)getutentries(NULL, &ep);
26093e07920fSDavid van Moolenbroek 	/* NOSTRICT */
26103e07920fSDavid van Moolenbroek 	for (; ep; ep = ep->next) {
26113e07920fSDavid van Moolenbroek 		if (f->f_type == F_WALL) {
26123e07920fSDavid van Moolenbroek 			if ((p = ttymsg(iov, iovcnt, ep->line, TTYMSGTIME))
26133e07920fSDavid van Moolenbroek 			    != NULL) {
26143e07920fSDavid van Moolenbroek 				errno = 0;	/* already in msg */
26153e07920fSDavid van Moolenbroek 				logerror("%s", p);
26163e07920fSDavid van Moolenbroek 			}
26173e07920fSDavid van Moolenbroek 			continue;
26183e07920fSDavid van Moolenbroek 		}
26193e07920fSDavid van Moolenbroek 		/* should we send the message to this user? */
26203e07920fSDavid van Moolenbroek 		for (i = 0; i < MAXUNAMES; i++) {
26213e07920fSDavid van Moolenbroek 			if (!f->f_un.f_uname[i][0])
26223e07920fSDavid van Moolenbroek 				break;
26233e07920fSDavid van Moolenbroek 			if (strcmp(f->f_un.f_uname[i], ep->name) == 0) {
26243e07920fSDavid van Moolenbroek 				struct stat st;
26253e07920fSDavid van Moolenbroek 				char tty[MAXPATHLEN];
26263e07920fSDavid van Moolenbroek 				snprintf(tty, sizeof(tty), "%s/%s", _PATH_DEV,
26273e07920fSDavid van Moolenbroek 				    ep->line);
26283e07920fSDavid van Moolenbroek 				if (stat(tty, &st) != -1 &&
26293e07920fSDavid van Moolenbroek 				    (st.st_mode & S_IWGRP) == 0)
26303e07920fSDavid van Moolenbroek 					break;
26313e07920fSDavid van Moolenbroek 
26323e07920fSDavid van Moolenbroek 				if ((p = ttymsg(iov, iovcnt, ep->line,
26333e07920fSDavid van Moolenbroek 				    TTYMSGTIME)) != NULL) {
26343e07920fSDavid van Moolenbroek 					errno = 0;	/* already in msg */
26353e07920fSDavid van Moolenbroek 					logerror("%s", p);
26363e07920fSDavid van Moolenbroek 				}
26373e07920fSDavid van Moolenbroek 				break;
26383e07920fSDavid van Moolenbroek 			}
26393e07920fSDavid van Moolenbroek 		}
26403e07920fSDavid van Moolenbroek 	}
26413e07920fSDavid van Moolenbroek 	reenter = 0;
26423e07920fSDavid van Moolenbroek #endif /* __NetBSD_Version__ */
26433e07920fSDavid van Moolenbroek }
26443e07920fSDavid van Moolenbroek 
26453e07920fSDavid van Moolenbroek void
26463e07920fSDavid van Moolenbroek /*ARGSUSED*/
reapchild(int fd,short event,void * ev)26473e07920fSDavid van Moolenbroek reapchild(int fd, short event, void *ev)
26483e07920fSDavid van Moolenbroek {
26493e07920fSDavid van Moolenbroek 	int status;
26503e07920fSDavid van Moolenbroek 	pid_t pid;
26513e07920fSDavid van Moolenbroek 	struct filed *f;
26523e07920fSDavid van Moolenbroek 
26533e07920fSDavid van Moolenbroek 	while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
26543e07920fSDavid van Moolenbroek 		if (!Initialized || ShuttingDown) {
26553e07920fSDavid van Moolenbroek 			/*
26563e07920fSDavid van Moolenbroek 			 * Be silent while we are initializing or
26573e07920fSDavid van Moolenbroek 			 * shutting down.
26583e07920fSDavid van Moolenbroek 			 */
26593e07920fSDavid van Moolenbroek 			continue;
26603e07920fSDavid van Moolenbroek 		}
26613e07920fSDavid van Moolenbroek 
26623e07920fSDavid van Moolenbroek 		if (deadq_remove(pid))
26633e07920fSDavid van Moolenbroek 			continue;
26643e07920fSDavid van Moolenbroek 
26653e07920fSDavid van Moolenbroek 		/* Now, look in the list of active processes. */
26663e07920fSDavid van Moolenbroek 		for (f = Files; f != NULL; f = f->f_next) {
26673e07920fSDavid van Moolenbroek 			if (f->f_type == F_PIPE &&
26683e07920fSDavid van Moolenbroek 			    f->f_un.f_pipe.f_pid == pid) {
26693e07920fSDavid van Moolenbroek 				(void) close(f->f_file);
26703e07920fSDavid van Moolenbroek 				f->f_un.f_pipe.f_pid = 0;
26713e07920fSDavid van Moolenbroek 				log_deadchild(pid, status,
26723e07920fSDavid van Moolenbroek 				    f->f_un.f_pipe.f_pname);
26733e07920fSDavid van Moolenbroek 				break;
26743e07920fSDavid van Moolenbroek 			}
26753e07920fSDavid van Moolenbroek 		}
26763e07920fSDavid van Moolenbroek 	}
26773e07920fSDavid van Moolenbroek }
26783e07920fSDavid van Moolenbroek 
26793e07920fSDavid van Moolenbroek /*
26803e07920fSDavid van Moolenbroek  * Return a printable representation of a host address (FQDN if available)
26813e07920fSDavid van Moolenbroek  */
26823e07920fSDavid van Moolenbroek const char *
cvthname(struct sockaddr_storage * f)26833e07920fSDavid van Moolenbroek cvthname(struct sockaddr_storage *f)
26843e07920fSDavid van Moolenbroek {
26853e07920fSDavid van Moolenbroek 	int error;
26863e07920fSDavid van Moolenbroek 	int niflag = NI_DGRAM;
26873e07920fSDavid van Moolenbroek 	static char host[NI_MAXHOST], ip[NI_MAXHOST];
26883e07920fSDavid van Moolenbroek 
26893e07920fSDavid van Moolenbroek 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
26903e07920fSDavid van Moolenbroek 	    ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag);
26913e07920fSDavid van Moolenbroek 
26923e07920fSDavid van Moolenbroek 	DPRINTF(D_CALL, "cvthname(%s)\n", ip);
26933e07920fSDavid van Moolenbroek 
26943e07920fSDavid van Moolenbroek 	if (error) {
26953e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "Malformed from address %s\n",
26963e07920fSDavid van Moolenbroek 		    gai_strerror(error));
26973e07920fSDavid van Moolenbroek 		return "???";
26983e07920fSDavid van Moolenbroek 	}
26993e07920fSDavid van Moolenbroek 
27003e07920fSDavid van Moolenbroek 	if (!UseNameService)
27013e07920fSDavid van Moolenbroek 		return ip;
27023e07920fSDavid van Moolenbroek 
27033e07920fSDavid van Moolenbroek 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
27043e07920fSDavid van Moolenbroek 	    host, sizeof host, NULL, 0, niflag);
27053e07920fSDavid van Moolenbroek 	if (error) {
27063e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "Host name for your address (%s) unknown\n", ip);
27073e07920fSDavid van Moolenbroek 		return ip;
27083e07920fSDavid van Moolenbroek 	}
27093e07920fSDavid van Moolenbroek 
27103e07920fSDavid van Moolenbroek 	return host;
27113e07920fSDavid van Moolenbroek }
27123e07920fSDavid van Moolenbroek 
27133e07920fSDavid van Moolenbroek void
trim_anydomain(char * host)27143e07920fSDavid van Moolenbroek trim_anydomain(char *host)
27153e07920fSDavid van Moolenbroek {
27163e07920fSDavid van Moolenbroek 	bool onlydigits = true;
27173e07920fSDavid van Moolenbroek 	int i;
27183e07920fSDavid van Moolenbroek 
27193e07920fSDavid van Moolenbroek 	if (!BSDOutputFormat)
27203e07920fSDavid van Moolenbroek 		return;
27213e07920fSDavid van Moolenbroek 
27223e07920fSDavid van Moolenbroek 	/* if non-digits found, then assume hostname and cut at first dot (this
27233e07920fSDavid van Moolenbroek 	 * case also covers IPv6 addresses which should not contain dots),
27243e07920fSDavid van Moolenbroek 	 * if only digits then assume IPv4 address and do not cut at all */
27253e07920fSDavid van Moolenbroek 	for (i = 0; host[i]; i++) {
27263e07920fSDavid van Moolenbroek 		if (host[i] == '.' && !onlydigits)
27273e07920fSDavid van Moolenbroek 			host[i] = '\0';
27283e07920fSDavid van Moolenbroek 		else if (!isdigit((unsigned char)host[i]) && host[i] != '.')
27293e07920fSDavid van Moolenbroek 			onlydigits = false;
27303e07920fSDavid van Moolenbroek 	}
27313e07920fSDavid van Moolenbroek }
27323e07920fSDavid van Moolenbroek 
27333e07920fSDavid van Moolenbroek static void
27343e07920fSDavid van Moolenbroek /*ARGSUSED*/
domark(int fd,short event,void * ev)27353e07920fSDavid van Moolenbroek domark(int fd, short event, void *ev)
27363e07920fSDavid van Moolenbroek {
27373e07920fSDavid van Moolenbroek 	struct event *ev_pass = (struct event *)ev;
27383e07920fSDavid van Moolenbroek 	struct filed *f;
27393e07920fSDavid van Moolenbroek 	dq_t q, nextq;
27403e07920fSDavid van Moolenbroek 	sigset_t newmask, omask;
27413e07920fSDavid van Moolenbroek 
27423e07920fSDavid van Moolenbroek 	schedule_event(&ev_pass,
27433e07920fSDavid van Moolenbroek 		&((struct timeval){TIMERINTVL, 0}),
27443e07920fSDavid van Moolenbroek 		domark, ev_pass);
27453e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_EVENT), "domark()\n");
27463e07920fSDavid van Moolenbroek 
27473e07920fSDavid van Moolenbroek 	BLOCK_SIGNALS(omask, newmask);
27483e07920fSDavid van Moolenbroek 	now = time(NULL);
27493e07920fSDavid van Moolenbroek 	MarkSeq += TIMERINTVL;
27503e07920fSDavid van Moolenbroek 	if (MarkSeq >= MarkInterval) {
27513e07920fSDavid van Moolenbroek 		logmsg_async(LOG_INFO, NULL, "-- MARK --", ADDDATE|MARK);
27523e07920fSDavid van Moolenbroek 		MarkSeq = 0;
27533e07920fSDavid van Moolenbroek 	}
27543e07920fSDavid van Moolenbroek 
27553e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next) {
27563e07920fSDavid van Moolenbroek 		if (f->f_prevcount && now >= REPEATTIME(f)) {
27573e07920fSDavid van Moolenbroek 			DPRINTF(D_DATA, "Flush %s: repeated %d times, %d sec.\n",
27583e07920fSDavid van Moolenbroek 			    TypeInfo[f->f_type].name, f->f_prevcount,
27593e07920fSDavid van Moolenbroek 			    repeatinterval[f->f_repeatcount]);
27603e07920fSDavid van Moolenbroek 			fprintlog(f, NULL, NULL);
27613e07920fSDavid van Moolenbroek 			BACKOFF(f);
27623e07920fSDavid van Moolenbroek 		}
27633e07920fSDavid van Moolenbroek 	}
27643e07920fSDavid van Moolenbroek 	message_allqueues_check();
27653e07920fSDavid van Moolenbroek 	RESTORE_SIGNALS(omask);
27663e07920fSDavid van Moolenbroek 
27673e07920fSDavid van Moolenbroek 	/* Walk the dead queue, and see if we should signal somebody. */
27683e07920fSDavid van Moolenbroek 	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = nextq) {
27693e07920fSDavid van Moolenbroek 		nextq = TAILQ_NEXT(q, dq_entries);
27703e07920fSDavid van Moolenbroek 		switch (q->dq_timeout) {
27713e07920fSDavid van Moolenbroek 		case 0:
27723e07920fSDavid van Moolenbroek 			/* Already signalled once, try harder now. */
27733e07920fSDavid van Moolenbroek 			if (kill(q->dq_pid, SIGKILL) != 0)
27743e07920fSDavid van Moolenbroek 				(void) deadq_remove(q->dq_pid);
27753e07920fSDavid van Moolenbroek 			break;
27763e07920fSDavid van Moolenbroek 
27773e07920fSDavid van Moolenbroek 		case 1:
27783e07920fSDavid van Moolenbroek 			/*
27793e07920fSDavid van Moolenbroek 			 * Timed out on the dead queue, send terminate
27803e07920fSDavid van Moolenbroek 			 * signal.  Note that we leave the removal from
27813e07920fSDavid van Moolenbroek 			 * the dead queue to reapchild(), which will
27823e07920fSDavid van Moolenbroek 			 * also log the event (unless the process
27833e07920fSDavid van Moolenbroek 			 * didn't even really exist, in case we simply
27843e07920fSDavid van Moolenbroek 			 * drop it from the dead queue).
27853e07920fSDavid van Moolenbroek 			 */
27863e07920fSDavid van Moolenbroek 			if (kill(q->dq_pid, SIGTERM) != 0) {
27873e07920fSDavid van Moolenbroek 				(void) deadq_remove(q->dq_pid);
27883e07920fSDavid van Moolenbroek 				break;
27893e07920fSDavid van Moolenbroek 			}
27903e07920fSDavid van Moolenbroek 			/* FALLTHROUGH */
27913e07920fSDavid van Moolenbroek 
27923e07920fSDavid van Moolenbroek 		default:
27933e07920fSDavid van Moolenbroek 			q->dq_timeout--;
27943e07920fSDavid van Moolenbroek 		}
27953e07920fSDavid van Moolenbroek 	}
27963e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
27973e07920fSDavid van Moolenbroek 	if (GlobalSign.rsid) {	/* check if initialized */
27983e07920fSDavid van Moolenbroek 		struct signature_group_t *sg;
27993e07920fSDavid van Moolenbroek 		STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) {
28003e07920fSDavid van Moolenbroek 			sign_send_certificate_block(sg);
28013e07920fSDavid van Moolenbroek 		}
28023e07920fSDavid van Moolenbroek 	}
28033e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
28043e07920fSDavid van Moolenbroek }
28053e07920fSDavid van Moolenbroek 
28063e07920fSDavid van Moolenbroek /*
28073e07920fSDavid van Moolenbroek  * Print syslogd errors some place.
28083e07920fSDavid van Moolenbroek  */
28093e07920fSDavid van Moolenbroek void
logerror(const char * fmt,...)28103e07920fSDavid van Moolenbroek logerror(const char *fmt, ...)
28113e07920fSDavid van Moolenbroek {
28123e07920fSDavid van Moolenbroek 	static int logerror_running;
28133e07920fSDavid van Moolenbroek 	va_list ap;
28143e07920fSDavid van Moolenbroek 	char tmpbuf[BUFSIZ];
28153e07920fSDavid van Moolenbroek 	char buf[BUFSIZ];
28163e07920fSDavid van Moolenbroek 	char *outbuf;
28173e07920fSDavid van Moolenbroek 
28183e07920fSDavid van Moolenbroek 	/* If there's an error while trying to log an error, give up. */
28193e07920fSDavid van Moolenbroek 	if (logerror_running)
28203e07920fSDavid van Moolenbroek 		return;
28213e07920fSDavid van Moolenbroek 	logerror_running = 1;
28223e07920fSDavid van Moolenbroek 
28233e07920fSDavid van Moolenbroek 	va_start(ap, fmt);
28243e07920fSDavid van Moolenbroek 	(void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
28253e07920fSDavid van Moolenbroek 	va_end(ap);
28263e07920fSDavid van Moolenbroek 
28273e07920fSDavid van Moolenbroek 	if (errno) {
28283e07920fSDavid van Moolenbroek 		(void)snprintf(buf, sizeof(buf), "%s: %s",
28293e07920fSDavid van Moolenbroek 		    tmpbuf, strerror(errno));
28303e07920fSDavid van Moolenbroek 		outbuf = buf;
28313e07920fSDavid van Moolenbroek 	} else {
28323e07920fSDavid van Moolenbroek 		(void)snprintf(buf, sizeof(buf), "%s", tmpbuf);
28333e07920fSDavid van Moolenbroek 		outbuf = tmpbuf;
28343e07920fSDavid van Moolenbroek 	}
28353e07920fSDavid van Moolenbroek 
28363e07920fSDavid van Moolenbroek 	if (daemonized)
28373e07920fSDavid van Moolenbroek 		logmsg_async(LOG_SYSLOG|LOG_ERR, NULL, outbuf, ADDDATE);
28383e07920fSDavid van Moolenbroek 	if (!daemonized && Debug)
28393e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "%s\n", outbuf);
28403e07920fSDavid van Moolenbroek 	if (!daemonized && !Debug)
28413e07920fSDavid van Moolenbroek 		printf("%s\n", outbuf);
28423e07920fSDavid van Moolenbroek 
28433e07920fSDavid van Moolenbroek 	logerror_running = 0;
28443e07920fSDavid van Moolenbroek }
28453e07920fSDavid van Moolenbroek 
28463e07920fSDavid van Moolenbroek /*
28473e07920fSDavid van Moolenbroek  * Print syslogd info some place.
28483e07920fSDavid van Moolenbroek  */
28493e07920fSDavid van Moolenbroek void
loginfo(const char * fmt,...)28503e07920fSDavid van Moolenbroek loginfo(const char *fmt, ...)
28513e07920fSDavid van Moolenbroek {
28523e07920fSDavid van Moolenbroek 	va_list ap;
28533e07920fSDavid van Moolenbroek 	char buf[BUFSIZ];
28543e07920fSDavid van Moolenbroek 
28553e07920fSDavid van Moolenbroek 	va_start(ap, fmt);
28563e07920fSDavid van Moolenbroek 	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
28573e07920fSDavid van Moolenbroek 	va_end(ap);
28583e07920fSDavid van Moolenbroek 
28593e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "%s\n", buf);
28603e07920fSDavid van Moolenbroek 	logmsg_async(LOG_SYSLOG|LOG_INFO, NULL, buf, ADDDATE);
28613e07920fSDavid van Moolenbroek }
28623e07920fSDavid van Moolenbroek 
28633e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
28643e07920fSDavid van Moolenbroek static inline void
free_incoming_tls_sockets(void)28653e07920fSDavid van Moolenbroek free_incoming_tls_sockets(void)
28663e07920fSDavid van Moolenbroek {
28673e07920fSDavid van Moolenbroek 	struct TLS_Incoming_Conn *tls_in;
28683e07920fSDavid van Moolenbroek 	int i;
28693e07920fSDavid van Moolenbroek 
28703e07920fSDavid van Moolenbroek 	/*
28713e07920fSDavid van Moolenbroek 	 * close all listening and connected TLS sockets
28723e07920fSDavid van Moolenbroek 	 */
28733e07920fSDavid van Moolenbroek 	if (TLS_Listen_Set)
28743e07920fSDavid van Moolenbroek 		for (i = 0; i < TLS_Listen_Set->fd; i++) {
28753e07920fSDavid van Moolenbroek 			if (close(TLS_Listen_Set[i+1].fd) == -1)
28763e07920fSDavid van Moolenbroek 				logerror("close() failed");
28773e07920fSDavid van Moolenbroek 			DEL_EVENT(TLS_Listen_Set[i+1].ev);
28783e07920fSDavid van Moolenbroek 			FREEPTR(TLS_Listen_Set[i+1].ev);
28793e07920fSDavid van Moolenbroek 		}
28803e07920fSDavid van Moolenbroek 	FREEPTR(TLS_Listen_Set);
28813e07920fSDavid van Moolenbroek 	/* close/free incoming TLS connections */
28823e07920fSDavid van Moolenbroek 	while (!SLIST_EMPTY(&TLS_Incoming_Head)) {
28833e07920fSDavid van Moolenbroek 		tls_in = SLIST_FIRST(&TLS_Incoming_Head);
28843e07920fSDavid van Moolenbroek 		SLIST_REMOVE_HEAD(&TLS_Incoming_Head, entries);
28853e07920fSDavid van Moolenbroek 		FREEPTR(tls_in->inbuf);
28863e07920fSDavid van Moolenbroek 		free_tls_conn(tls_in->tls_conn);
28873e07920fSDavid van Moolenbroek 		free(tls_in);
28883e07920fSDavid van Moolenbroek 	}
28893e07920fSDavid van Moolenbroek }
28903e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
28913e07920fSDavid van Moolenbroek 
28923e07920fSDavid van Moolenbroek void
28933e07920fSDavid van Moolenbroek /*ARGSUSED*/
die(int fd,short event,void * ev)28943e07920fSDavid van Moolenbroek die(int fd, short event, void *ev)
28953e07920fSDavid van Moolenbroek {
28963e07920fSDavid van Moolenbroek 	struct filed *f, *next;
28973e07920fSDavid van Moolenbroek 	char **p;
28983e07920fSDavid van Moolenbroek 	sigset_t newmask, omask;
28993e07920fSDavid van Moolenbroek 	int i;
29003e07920fSDavid van Moolenbroek 	size_t j;
29013e07920fSDavid van Moolenbroek 
29023e07920fSDavid van Moolenbroek 	ShuttingDown = 1;	/* Don't log SIGCHLDs. */
29033e07920fSDavid van Moolenbroek 	/* prevent recursive signals */
29043e07920fSDavid van Moolenbroek 	BLOCK_SIGNALS(omask, newmask);
29053e07920fSDavid van Moolenbroek 
29063e07920fSDavid van Moolenbroek 	errno = 0;
29073e07920fSDavid van Moolenbroek 	if (ev != NULL)
29083e07920fSDavid van Moolenbroek 		logerror("Exiting on signal %d", fd);
29093e07920fSDavid van Moolenbroek 	else
29103e07920fSDavid van Moolenbroek 		logerror("Fatal error, exiting");
29113e07920fSDavid van Moolenbroek 
29123e07920fSDavid van Moolenbroek 	/*
29133e07920fSDavid van Moolenbroek 	 *  flush any pending output
29143e07920fSDavid van Moolenbroek 	 */
29153e07920fSDavid van Moolenbroek 	for (f = Files; f != NULL; f = f->f_next) {
29163e07920fSDavid van Moolenbroek 		/* flush any pending output */
29173e07920fSDavid van Moolenbroek 		if (f->f_prevcount)
29183e07920fSDavid van Moolenbroek 			fprintlog(f, NULL, NULL);
29193e07920fSDavid van Moolenbroek 		SEND_QUEUE(f);
29203e07920fSDavid van Moolenbroek 	}
29213e07920fSDavid van Moolenbroek 
29223e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
29233e07920fSDavid van Moolenbroek 	free_incoming_tls_sockets();
29243e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
29253e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
29263e07920fSDavid van Moolenbroek 	sign_global_free();
29273e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
29283e07920fSDavid van Moolenbroek 
29293e07920fSDavid van Moolenbroek 	/*
29303e07920fSDavid van Moolenbroek 	 *  Close all open log files.
29313e07920fSDavid van Moolenbroek 	 */
29323e07920fSDavid van Moolenbroek 	for (f = Files; f != NULL; f = next) {
29333e07920fSDavid van Moolenbroek 		message_queue_freeall(f);
29343e07920fSDavid van Moolenbroek 
29353e07920fSDavid van Moolenbroek 		switch (f->f_type) {
29363e07920fSDavid van Moolenbroek 		case F_FILE:
29373e07920fSDavid van Moolenbroek 		case F_TTY:
29383e07920fSDavid van Moolenbroek 		case F_CONSOLE:
29393e07920fSDavid van Moolenbroek 		case F_FIFO:
29403e07920fSDavid van Moolenbroek 			if (f->f_file >= 0)
29413e07920fSDavid van Moolenbroek 				(void)close(f->f_file);
29423e07920fSDavid van Moolenbroek 			break;
29433e07920fSDavid van Moolenbroek 		case F_PIPE:
29443e07920fSDavid van Moolenbroek 			if (f->f_un.f_pipe.f_pid > 0) {
29453e07920fSDavid van Moolenbroek 				(void)close(f->f_file);
29463e07920fSDavid van Moolenbroek 			}
29473e07920fSDavid van Moolenbroek 			f->f_un.f_pipe.f_pid = 0;
29483e07920fSDavid van Moolenbroek 			break;
29493e07920fSDavid van Moolenbroek 		case F_FORW:
29503e07920fSDavid van Moolenbroek 			if (f->f_un.f_forw.f_addr)
29513e07920fSDavid van Moolenbroek 				freeaddrinfo(f->f_un.f_forw.f_addr);
29523e07920fSDavid van Moolenbroek 			break;
29533e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
29543e07920fSDavid van Moolenbroek 		case F_TLS:
29553e07920fSDavid van Moolenbroek 			free_tls_conn(f->f_un.f_tls.tls_conn);
29563e07920fSDavid van Moolenbroek 			break;
29573e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
29583e07920fSDavid van Moolenbroek 		}
29593e07920fSDavid van Moolenbroek 		next = f->f_next;
29603e07920fSDavid van Moolenbroek 		DELREF(f->f_prevmsg);
29613e07920fSDavid van Moolenbroek 		FREEPTR(f->f_program);
29623e07920fSDavid van Moolenbroek 		FREEPTR(f->f_host);
29633e07920fSDavid van Moolenbroek 		DEL_EVENT(f->f_sq_event);
29643e07920fSDavid van Moolenbroek 		free((char *)f);
29653e07920fSDavid van Moolenbroek 	}
29663e07920fSDavid van Moolenbroek 
29673e07920fSDavid van Moolenbroek 	/*
29683e07920fSDavid van Moolenbroek 	 *  Close all open UDP sockets
29693e07920fSDavid van Moolenbroek 	 */
29703e07920fSDavid van Moolenbroek 	if (finet) {
29713e07920fSDavid van Moolenbroek 		for (i = 0; i < finet->fd; i++) {
29723e07920fSDavid van Moolenbroek 			if (close(finet[i+1].fd) < 0) {
29733e07920fSDavid van Moolenbroek 				logerror("close() failed");
29743e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
29753e07920fSDavid van Moolenbroek 			}
29763e07920fSDavid van Moolenbroek 			DEL_EVENT(finet[i+1].ev);
29773e07920fSDavid van Moolenbroek 			FREEPTR(finet[i+1].ev);
29783e07920fSDavid van Moolenbroek 		}
29793e07920fSDavid van Moolenbroek 		FREEPTR(finet);
29803e07920fSDavid van Moolenbroek 	}
29813e07920fSDavid van Moolenbroek 
29823e07920fSDavid van Moolenbroek 	/* free config options */
29833e07920fSDavid van Moolenbroek 	for (j = 0; j < A_CNT(TypeInfo); j++) {
29843e07920fSDavid van Moolenbroek 		FREEPTR(TypeInfo[j].queue_length_string);
29853e07920fSDavid van Moolenbroek 		FREEPTR(TypeInfo[j].queue_size_string);
29863e07920fSDavid van Moolenbroek 	}
29873e07920fSDavid van Moolenbroek 
29883e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
29893e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.CAdir);
29903e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.CAfile);
29913e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.keyfile);
29923e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.certfile);
29933e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.x509verify);
29943e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.bindhost);
29953e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.bindport);
29963e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.server);
29973e07920fSDavid van Moolenbroek 	FREEPTR(tls_opt.gen_cert);
29983e07920fSDavid van Moolenbroek 	free_cred_SLIST(&tls_opt.cert_head);
29993e07920fSDavid van Moolenbroek 	free_cred_SLIST(&tls_opt.fprint_head);
30003e07920fSDavid van Moolenbroek 	FREE_SSL_CTX(tls_opt.global_TLS_CTX);
30013e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
30023e07920fSDavid van Moolenbroek 
30033e07920fSDavid van Moolenbroek 	FREEPTR(funix);
30043e07920fSDavid van Moolenbroek 	for (p = LogPaths; p && *p; p++)
30053e07920fSDavid van Moolenbroek 		unlink(*p);
30063e07920fSDavid van Moolenbroek 	exit(0);
30073e07920fSDavid van Moolenbroek }
30083e07920fSDavid van Moolenbroek 
30093e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
30103e07920fSDavid van Moolenbroek /*
30113e07920fSDavid van Moolenbroek  * get one "sign_delim_sg2" item, convert and store in ordered queue
30123e07920fSDavid van Moolenbroek  */
30133e07920fSDavid van Moolenbroek void
store_sign_delim_sg2(char * tmp_buf)30143e07920fSDavid van Moolenbroek store_sign_delim_sg2(char *tmp_buf)
30153e07920fSDavid van Moolenbroek {
30163e07920fSDavid van Moolenbroek 	struct string_queue *sqentry, *sqe1, *sqe2;
30173e07920fSDavid van Moolenbroek 
30183e07920fSDavid van Moolenbroek 	if(!(sqentry = malloc(sizeof(*sqentry)))) {
30193e07920fSDavid van Moolenbroek 		logerror("Unable to allocate memory");
30203e07920fSDavid van Moolenbroek 		return;
30213e07920fSDavid van Moolenbroek 	}
30223e07920fSDavid van Moolenbroek 	/*LINTED constcond/null effect */
30233e07920fSDavid van Moolenbroek 	assert(sizeof(int64_t) == sizeof(uint_fast64_t));
30243e07920fSDavid van Moolenbroek 	if (dehumanize_number(tmp_buf, (int64_t*) &(sqentry->key)) == -1
30253e07920fSDavid van Moolenbroek 	    || sqentry->key > (LOG_NFACILITIES<<3)) {
30263e07920fSDavid van Moolenbroek 		DPRINTF(D_PARSE, "invalid sign_delim_sg2: %s\n", tmp_buf);
30273e07920fSDavid van Moolenbroek 		free(sqentry);
30283e07920fSDavid van Moolenbroek 		FREEPTR(tmp_buf);
30293e07920fSDavid van Moolenbroek 		return;
30303e07920fSDavid van Moolenbroek 	}
30313e07920fSDavid van Moolenbroek 	sqentry->data = tmp_buf;
30323e07920fSDavid van Moolenbroek 
30333e07920fSDavid van Moolenbroek 	if (STAILQ_EMPTY(&GlobalSign.sig2_delims)) {
30343e07920fSDavid van Moolenbroek 		STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims,
30353e07920fSDavid van Moolenbroek 		    sqentry, entries);
30363e07920fSDavid van Moolenbroek 		return;
30373e07920fSDavid van Moolenbroek 	}
30383e07920fSDavid van Moolenbroek 
30393e07920fSDavid van Moolenbroek 	/* keep delimiters sorted */
30403e07920fSDavid van Moolenbroek 	sqe1 = sqe2 = STAILQ_FIRST(&GlobalSign.sig2_delims);
30413e07920fSDavid van Moolenbroek 	if (sqe1->key > sqentry->key) {
30423e07920fSDavid van Moolenbroek 		STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims,
30433e07920fSDavid van Moolenbroek 		    sqentry, entries);
30443e07920fSDavid van Moolenbroek 		return;
30453e07920fSDavid van Moolenbroek 	}
30463e07920fSDavid van Moolenbroek 
30473e07920fSDavid van Moolenbroek 	while ((sqe1 = sqe2)
30483e07920fSDavid van Moolenbroek 	   && (sqe2 = STAILQ_NEXT(sqe1, entries))) {
30493e07920fSDavid van Moolenbroek 		if (sqe2->key > sqentry->key) {
30503e07920fSDavid van Moolenbroek 			break;
30513e07920fSDavid van Moolenbroek 		} else if (sqe2->key == sqentry->key) {
30523e07920fSDavid van Moolenbroek 			DPRINTF(D_PARSE, "duplicate sign_delim_sg2: %s\n",
30533e07920fSDavid van Moolenbroek 			    tmp_buf);
30543e07920fSDavid van Moolenbroek 			FREEPTR(sqentry);
30553e07920fSDavid van Moolenbroek 			FREEPTR(tmp_buf);
30563e07920fSDavid van Moolenbroek 			return;
30573e07920fSDavid van Moolenbroek 		}
30583e07920fSDavid van Moolenbroek 	}
30593e07920fSDavid van Moolenbroek 	STAILQ_INSERT_AFTER(&GlobalSign.sig2_delims, sqe1, sqentry, entries);
30603e07920fSDavid van Moolenbroek }
30613e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
30623e07920fSDavid van Moolenbroek 
30633e07920fSDavid van Moolenbroek /*
30643e07920fSDavid van Moolenbroek  * read syslog.conf
30653e07920fSDavid van Moolenbroek  */
30663e07920fSDavid van Moolenbroek void
read_config_file(FILE * cf,struct filed ** f_ptr)30673e07920fSDavid van Moolenbroek read_config_file(FILE *cf, struct filed **f_ptr)
30683e07920fSDavid van Moolenbroek {
30693e07920fSDavid van Moolenbroek 	size_t linenum = 0;
30703e07920fSDavid van Moolenbroek 	size_t i;
30713e07920fSDavid van Moolenbroek 	struct filed *f, **nextp;
30723e07920fSDavid van Moolenbroek 	char cline[LINE_MAX];
30733e07920fSDavid van Moolenbroek 	char prog[NAME_MAX + 1];
30743e07920fSDavid van Moolenbroek 	char host[MAXHOSTNAMELEN];
30753e07920fSDavid van Moolenbroek 	const char *p;
30763e07920fSDavid van Moolenbroek 	char *q;
30773e07920fSDavid van Moolenbroek 	bool found_keyword;
30783e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
30793e07920fSDavid van Moolenbroek 	struct peer_cred *cred = NULL;
30803e07920fSDavid van Moolenbroek 	struct peer_cred_head *credhead = NULL;
30813e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
30823e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
30833e07920fSDavid van Moolenbroek 	char *sign_sg_str = NULL;
30843e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
30853e07920fSDavid van Moolenbroek #if (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN))
30863e07920fSDavid van Moolenbroek 	char *tmp_buf = NULL;
30873e07920fSDavid van Moolenbroek #endif /* (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN)) */
30883e07920fSDavid van Moolenbroek 	/* central list of recognized configuration keywords
30893e07920fSDavid van Moolenbroek 	 * and an address for their values as strings */
30903e07920fSDavid van Moolenbroek 	const struct config_keywords {
30913e07920fSDavid van Moolenbroek 		const char *keyword;
30923e07920fSDavid van Moolenbroek 		char **variable;
30933e07920fSDavid van Moolenbroek 	} config_keywords[] = {
30943e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
30953e07920fSDavid van Moolenbroek 		/* TLS settings */
30963e07920fSDavid van Moolenbroek 		{"tls_ca",		  &tls_opt.CAfile},
30973e07920fSDavid van Moolenbroek 		{"tls_cadir",		  &tls_opt.CAdir},
30983e07920fSDavid van Moolenbroek 		{"tls_cert",		  &tls_opt.certfile},
30993e07920fSDavid van Moolenbroek 		{"tls_key",		  &tls_opt.keyfile},
31003e07920fSDavid van Moolenbroek 		{"tls_verify",		  &tls_opt.x509verify},
31013e07920fSDavid van Moolenbroek 		{"tls_bindport",	  &tls_opt.bindport},
31023e07920fSDavid van Moolenbroek 		{"tls_bindhost",	  &tls_opt.bindhost},
31033e07920fSDavid van Moolenbroek 		{"tls_server",		  &tls_opt.server},
31043e07920fSDavid van Moolenbroek 		{"tls_gen_cert",	  &tls_opt.gen_cert},
31053e07920fSDavid van Moolenbroek 		/* special cases in parsing */
31063e07920fSDavid van Moolenbroek 		{"tls_allow_fingerprints",&tmp_buf},
31073e07920fSDavid van Moolenbroek 		{"tls_allow_clientcerts", &tmp_buf},
31083e07920fSDavid van Moolenbroek 		/* buffer settings */
31093e07920fSDavid van Moolenbroek 		{"tls_queue_length",	  &TypeInfo[F_TLS].queue_length_string},
31103e07920fSDavid van Moolenbroek 		{"tls_queue_size",	  &TypeInfo[F_TLS].queue_size_string},
31113e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
31123e07920fSDavid van Moolenbroek 		{"file_queue_length",	  &TypeInfo[F_FILE].queue_length_string},
31133e07920fSDavid van Moolenbroek 		{"pipe_queue_length",	  &TypeInfo[F_PIPE].queue_length_string},
31143e07920fSDavid van Moolenbroek 		{"fifo_queue_length",	  &TypeInfo[F_FIFO].queue_length_string},
31153e07920fSDavid van Moolenbroek 		{"file_queue_size",	  &TypeInfo[F_FILE].queue_size_string},
31163e07920fSDavid van Moolenbroek 		{"pipe_queue_size",	  &TypeInfo[F_PIPE].queue_size_string},
31173e07920fSDavid van Moolenbroek 		{"fifo_queue_size",	  &TypeInfo[F_FIFO].queue_size_string},
31183e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
31193e07920fSDavid van Moolenbroek 		/* syslog-sign setting */
31203e07920fSDavid van Moolenbroek 		{"sign_sg",		  &sign_sg_str},
31213e07920fSDavid van Moolenbroek 		/* also special case in parsing */
31223e07920fSDavid van Moolenbroek 		{"sign_delim_sg2",	  &tmp_buf},
31233e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
31243e07920fSDavid van Moolenbroek 	};
31253e07920fSDavid van Moolenbroek 
31263e07920fSDavid van Moolenbroek 	DPRINTF(D_CALL, "read_config_file()\n");
31273e07920fSDavid van Moolenbroek 
31283e07920fSDavid van Moolenbroek 	/* free all previous config options */
31293e07920fSDavid van Moolenbroek 	for (i = 0; i < A_CNT(TypeInfo); i++) {
31303e07920fSDavid van Moolenbroek 		if (TypeInfo[i].queue_length_string
31313e07920fSDavid van Moolenbroek 		    && TypeInfo[i].queue_length_string
31323e07920fSDavid van Moolenbroek 		    != TypeInfo[i].default_length_string) {
31333e07920fSDavid van Moolenbroek 			FREEPTR(TypeInfo[i].queue_length_string);
31343e07920fSDavid van Moolenbroek 			TypeInfo[i].queue_length_string =
31353e07920fSDavid van Moolenbroek 				strdup(TypeInfo[i].default_length_string);
31363e07920fSDavid van Moolenbroek 		 }
31373e07920fSDavid van Moolenbroek 		if (TypeInfo[i].queue_size_string
31383e07920fSDavid van Moolenbroek 		    && TypeInfo[i].queue_size_string
31393e07920fSDavid van Moolenbroek 		    != TypeInfo[i].default_size_string) {
31403e07920fSDavid van Moolenbroek 			FREEPTR(TypeInfo[i].queue_size_string);
31413e07920fSDavid van Moolenbroek 			TypeInfo[i].queue_size_string =
31423e07920fSDavid van Moolenbroek 				strdup(TypeInfo[i].default_size_string);
31433e07920fSDavid van Moolenbroek 		 }
31443e07920fSDavid van Moolenbroek 	}
31453e07920fSDavid van Moolenbroek 	for (i = 0; i < A_CNT(config_keywords); i++)
31463e07920fSDavid van Moolenbroek 		FREEPTR(*config_keywords[i].variable);
31473e07920fSDavid van Moolenbroek 	/*
31483e07920fSDavid van Moolenbroek 	 * global settings
31493e07920fSDavid van Moolenbroek 	 */
31503e07920fSDavid van Moolenbroek 	while (fgets(cline, sizeof(cline), cf) != NULL) {
31513e07920fSDavid van Moolenbroek 		linenum++;
31523e07920fSDavid van Moolenbroek 		for (p = cline; isspace((unsigned char)*p); ++p)
31533e07920fSDavid van Moolenbroek 			continue;
31543e07920fSDavid van Moolenbroek 		if ((*p == '\0') || (*p == '#'))
31553e07920fSDavid van Moolenbroek 			continue;
31563e07920fSDavid van Moolenbroek 
31573e07920fSDavid van Moolenbroek 		for (i = 0; i < A_CNT(config_keywords); i++) {
31583e07920fSDavid van Moolenbroek 			if (copy_config_value(config_keywords[i].keyword,
31593e07920fSDavid van Moolenbroek 			    config_keywords[i].variable, &p, ConfFile,
31603e07920fSDavid van Moolenbroek 			    linenum)) {
31613e07920fSDavid van Moolenbroek 				DPRINTF((D_PARSE|D_MEM),
31623e07920fSDavid van Moolenbroek 				    "found option %s, saved @%p\n",
31633e07920fSDavid van Moolenbroek 				    config_keywords[i].keyword,
31643e07920fSDavid van Moolenbroek 				    *config_keywords[i].variable);
31653e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
31663e07920fSDavid van Moolenbroek 				if (!strcmp("sign_delim_sg2",
31673e07920fSDavid van Moolenbroek 				    config_keywords[i].keyword))
31683e07920fSDavid van Moolenbroek 					do {
31693e07920fSDavid van Moolenbroek 						store_sign_delim_sg2(tmp_buf);
31703e07920fSDavid van Moolenbroek 					} while (copy_config_value_word(
31713e07920fSDavid van Moolenbroek 					    &tmp_buf, &p));
31723e07920fSDavid van Moolenbroek 
31733e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
31743e07920fSDavid van Moolenbroek 
31753e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
31763e07920fSDavid van Moolenbroek 				/* special cases with multiple parameters */
31773e07920fSDavid van Moolenbroek 				if (!strcmp("tls_allow_fingerprints",
31783e07920fSDavid van Moolenbroek 				    config_keywords[i].keyword))
31793e07920fSDavid van Moolenbroek 					credhead = &tls_opt.fprint_head;
31803e07920fSDavid van Moolenbroek 				else if (!strcmp("tls_allow_clientcerts",
31813e07920fSDavid van Moolenbroek 				    config_keywords[i].keyword))
31823e07920fSDavid van Moolenbroek 					credhead = &tls_opt.cert_head;
31833e07920fSDavid van Moolenbroek 
31843e07920fSDavid van Moolenbroek 				if (credhead) do {
31853e07920fSDavid van Moolenbroek 					if(!(cred = malloc(sizeof(*cred)))) {
31863e07920fSDavid van Moolenbroek 						logerror("Unable to "
31873e07920fSDavid van Moolenbroek 							"allocate memory");
31883e07920fSDavid van Moolenbroek 						break;
31893e07920fSDavid van Moolenbroek 					}
31903e07920fSDavid van Moolenbroek 					cred->data = tmp_buf;
31913e07920fSDavid van Moolenbroek 					tmp_buf = NULL;
31923e07920fSDavid van Moolenbroek 					SLIST_INSERT_HEAD(credhead,
31933e07920fSDavid van Moolenbroek 						cred, entries);
31943e07920fSDavid van Moolenbroek 				} while /* additional values? */
31953e07920fSDavid van Moolenbroek 					(copy_config_value_word(&tmp_buf, &p));
31963e07920fSDavid van Moolenbroek 				credhead = NULL;
31973e07920fSDavid van Moolenbroek 				break;
31983e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
31993e07920fSDavid van Moolenbroek 			}
32003e07920fSDavid van Moolenbroek 		}
32013e07920fSDavid van Moolenbroek 	}
32023e07920fSDavid van Moolenbroek 	/* convert strings to integer values */
32033e07920fSDavid van Moolenbroek 	for (i = 0; i < A_CNT(TypeInfo); i++) {
32043e07920fSDavid van Moolenbroek 		if (!TypeInfo[i].queue_length_string
32053e07920fSDavid van Moolenbroek 		    || dehumanize_number(TypeInfo[i].queue_length_string,
32063e07920fSDavid van Moolenbroek 		    &TypeInfo[i].queue_length) == -1)
32073e07920fSDavid van Moolenbroek 			if (dehumanize_number(TypeInfo[i].default_length_string,
32083e07920fSDavid van Moolenbroek 			    &TypeInfo[i].queue_length) == -1)
32093e07920fSDavid van Moolenbroek 				abort();
32103e07920fSDavid van Moolenbroek 		if (!TypeInfo[i].queue_size_string
32113e07920fSDavid van Moolenbroek 		    || dehumanize_number(TypeInfo[i].queue_size_string,
32123e07920fSDavid van Moolenbroek 		    &TypeInfo[i].queue_size) == -1)
32133e07920fSDavid van Moolenbroek 			if (dehumanize_number(TypeInfo[i].default_size_string,
32143e07920fSDavid van Moolenbroek 			    &TypeInfo[i].queue_size) == -1)
32153e07920fSDavid van Moolenbroek 				abort();
32163e07920fSDavid van Moolenbroek 	}
32173e07920fSDavid van Moolenbroek 
32183e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
32193e07920fSDavid van Moolenbroek 	if (sign_sg_str) {
32203e07920fSDavid van Moolenbroek 		if (sign_sg_str[1] == '\0'
32213e07920fSDavid van Moolenbroek 		    && (sign_sg_str[0] == '0' || sign_sg_str[0] == '1'
32223e07920fSDavid van Moolenbroek 		    || sign_sg_str[0] == '2' || sign_sg_str[0] == '3'))
32233e07920fSDavid van Moolenbroek 			GlobalSign.sg = sign_sg_str[0] - '0';
32243e07920fSDavid van Moolenbroek 		else {
32253e07920fSDavid van Moolenbroek 			GlobalSign.sg = SIGN_SG;
32263e07920fSDavid van Moolenbroek 			DPRINTF(D_MISC, "Invalid sign_sg value `%s', "
32273e07920fSDavid van Moolenbroek 			    "use default value `%d'\n",
32283e07920fSDavid van Moolenbroek 			    sign_sg_str, GlobalSign.sg);
32293e07920fSDavid van Moolenbroek 		}
32303e07920fSDavid van Moolenbroek 	} else	/* disable syslog-sign */
32313e07920fSDavid van Moolenbroek 		GlobalSign.sg = -1;
32323e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
32333e07920fSDavid van Moolenbroek 
32343e07920fSDavid van Moolenbroek 	rewind(cf);
32353e07920fSDavid van Moolenbroek 	linenum = 0;
32363e07920fSDavid van Moolenbroek 	/*
32373e07920fSDavid van Moolenbroek 	 *  Foreach line in the conf table, open that file.
32383e07920fSDavid van Moolenbroek 	 */
32393e07920fSDavid van Moolenbroek 	f = NULL;
32403e07920fSDavid van Moolenbroek 	nextp = &f;
32413e07920fSDavid van Moolenbroek 
32423e07920fSDavid van Moolenbroek 	strcpy(prog, "*");
32433e07920fSDavid van Moolenbroek 	strcpy(host, "*");
32443e07920fSDavid van Moolenbroek 	while (fgets(cline, sizeof(cline), cf) != NULL) {
32453e07920fSDavid van Moolenbroek 		linenum++;
32463e07920fSDavid van Moolenbroek 		found_keyword = false;
32473e07920fSDavid van Moolenbroek 		/*
32483e07920fSDavid van Moolenbroek 		 * check for end-of-section, comments, strip off trailing
32493e07920fSDavid van Moolenbroek 		 * spaces and newline character.  #!prog is treated specially:
32503e07920fSDavid van Moolenbroek 		 * following lines apply only to that program.
32513e07920fSDavid van Moolenbroek 		 */
32523e07920fSDavid van Moolenbroek 		for (p = cline; isspace((unsigned char)*p); ++p)
32533e07920fSDavid van Moolenbroek 			continue;
32543e07920fSDavid van Moolenbroek 		if (*p == '\0')
32553e07920fSDavid van Moolenbroek 			continue;
32563e07920fSDavid van Moolenbroek 		if (*p == '#') {
32573e07920fSDavid van Moolenbroek 			p++;
32583e07920fSDavid van Moolenbroek 			if (*p != '!' && *p != '+' && *p != '-')
32593e07920fSDavid van Moolenbroek 				continue;
32603e07920fSDavid van Moolenbroek 		}
32613e07920fSDavid van Moolenbroek 
32623e07920fSDavid van Moolenbroek 		for (i = 0; i < A_CNT(config_keywords); i++) {
32633e07920fSDavid van Moolenbroek 			if (!strncasecmp(p, config_keywords[i].keyword,
32643e07920fSDavid van Moolenbroek 				strlen(config_keywords[i].keyword))) {
32653e07920fSDavid van Moolenbroek 				DPRINTF(D_PARSE,
32663e07920fSDavid van Moolenbroek 				    "skip cline %zu with keyword %s\n",
32673e07920fSDavid van Moolenbroek 				    linenum, config_keywords[i].keyword);
32683e07920fSDavid van Moolenbroek 				found_keyword = true;
32693e07920fSDavid van Moolenbroek 			}
32703e07920fSDavid van Moolenbroek 		}
32713e07920fSDavid van Moolenbroek 		if (found_keyword)
32723e07920fSDavid van Moolenbroek 			continue;
32733e07920fSDavid van Moolenbroek 
32743e07920fSDavid van Moolenbroek 		if (*p == '+' || *p == '-') {
32753e07920fSDavid van Moolenbroek 			host[0] = *p++;
32763e07920fSDavid van Moolenbroek 			while (isspace((unsigned char)*p))
32773e07920fSDavid van Moolenbroek 				p++;
32783e07920fSDavid van Moolenbroek 			if (*p == '\0' || *p == '*') {
32793e07920fSDavid van Moolenbroek 				strcpy(host, "*");
32803e07920fSDavid van Moolenbroek 				continue;
32813e07920fSDavid van Moolenbroek 			}
32823e07920fSDavid van Moolenbroek 			/* the +hostname expression will continue
32833e07920fSDavid van Moolenbroek 			 * to use the LocalHostName, not the FQDN */
32843e07920fSDavid van Moolenbroek 			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
32853e07920fSDavid van Moolenbroek 				if (*p == '@') {
32863e07920fSDavid van Moolenbroek 					(void)strncpy(&host[i], LocalHostName,
32873e07920fSDavid van Moolenbroek 					    sizeof(host) - 1 - i);
32883e07920fSDavid van Moolenbroek 					host[sizeof(host) - 1] = '\0';
32893e07920fSDavid van Moolenbroek 					i = strlen(host) - 1;
32903e07920fSDavid van Moolenbroek 					p++;
32913e07920fSDavid van Moolenbroek 					continue;
32923e07920fSDavid van Moolenbroek 				}
32933e07920fSDavid van Moolenbroek 				if (!isalnum((unsigned char)*p) &&
32943e07920fSDavid van Moolenbroek 				    *p != '.' && *p != '-' && *p != ',')
32953e07920fSDavid van Moolenbroek 					break;
32963e07920fSDavid van Moolenbroek 				host[i] = *p++;
32973e07920fSDavid van Moolenbroek 			}
32983e07920fSDavid van Moolenbroek 			host[i] = '\0';
32993e07920fSDavid van Moolenbroek 			continue;
33003e07920fSDavid van Moolenbroek 		}
33013e07920fSDavid van Moolenbroek 		if (*p == '!') {
33023e07920fSDavid van Moolenbroek 			p++;
33033e07920fSDavid van Moolenbroek 			while (isspace((unsigned char)*p))
33043e07920fSDavid van Moolenbroek 				p++;
33053e07920fSDavid van Moolenbroek 			if (*p == '\0' || *p == '*') {
33063e07920fSDavid van Moolenbroek 				strcpy(prog, "*");
33073e07920fSDavid van Moolenbroek 				continue;
33083e07920fSDavid van Moolenbroek 			}
33093e07920fSDavid van Moolenbroek 			for (i = 0; i < NAME_MAX; i++) {
33103e07920fSDavid van Moolenbroek 				if (!isprint((unsigned char)p[i]))
33113e07920fSDavid van Moolenbroek 					break;
33123e07920fSDavid van Moolenbroek 				prog[i] = p[i];
33133e07920fSDavid van Moolenbroek 			}
33143e07920fSDavid van Moolenbroek 			prog[i] = '\0';
33153e07920fSDavid van Moolenbroek 			continue;
33163e07920fSDavid van Moolenbroek 		}
33173e07920fSDavid van Moolenbroek 		for (q = strchr(cline, '\0'); isspace((unsigned char)*--q);)
33183e07920fSDavid van Moolenbroek 			continue;
33193e07920fSDavid van Moolenbroek 		*++q = '\0';
33203e07920fSDavid van Moolenbroek 		if ((f = calloc(1, sizeof(*f))) == NULL) {
33213e07920fSDavid van Moolenbroek 			logerror("alloc failed");
33223e07920fSDavid van Moolenbroek 			die(0, 0, NULL);
33233e07920fSDavid van Moolenbroek 		}
33243e07920fSDavid van Moolenbroek 		if (!*f_ptr) *f_ptr = f; /* return first node */
33253e07920fSDavid van Moolenbroek 		*nextp = f;
33263e07920fSDavid van Moolenbroek 		nextp = &f->f_next;
33273e07920fSDavid van Moolenbroek 		cfline(linenum, cline, f, prog, host);
33283e07920fSDavid van Moolenbroek 	}
33293e07920fSDavid van Moolenbroek }
33303e07920fSDavid van Moolenbroek 
33313e07920fSDavid van Moolenbroek /*
33323e07920fSDavid van Moolenbroek  *  INIT -- Initialize syslogd from configuration table
33333e07920fSDavid van Moolenbroek  */
33343e07920fSDavid van Moolenbroek void
33353e07920fSDavid van Moolenbroek /*ARGSUSED*/
init(int fd,short event,void * ev)33363e07920fSDavid van Moolenbroek init(int fd, short event, void *ev)
33373e07920fSDavid van Moolenbroek {
33383e07920fSDavid van Moolenbroek 	FILE *cf;
33393e07920fSDavid van Moolenbroek 	int i;
33403e07920fSDavid van Moolenbroek 	struct filed *f, *newf, **nextp, *f2;
33413e07920fSDavid van Moolenbroek 	char *p;
33423e07920fSDavid van Moolenbroek 	sigset_t newmask, omask;
33433e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
33443e07920fSDavid van Moolenbroek 	char *tls_status_msg = NULL;
33453e07920fSDavid van Moolenbroek 	struct peer_cred *cred = NULL;
33463e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
33473e07920fSDavid van Moolenbroek 
33483e07920fSDavid van Moolenbroek 	/* prevent recursive signals */
33493e07920fSDavid van Moolenbroek 	BLOCK_SIGNALS(omask, newmask);
33503e07920fSDavid van Moolenbroek 
33513e07920fSDavid van Moolenbroek 	DPRINTF((D_EVENT|D_CALL), "init\n");
33523e07920fSDavid van Moolenbroek 
33533e07920fSDavid van Moolenbroek 	/*
33543e07920fSDavid van Moolenbroek 	 * be careful about dependencies and order of actions:
33553e07920fSDavid van Moolenbroek 	 * 1. flush buffer queues
33563e07920fSDavid van Moolenbroek 	 * 2. flush -sign SBs
33573e07920fSDavid van Moolenbroek 	 * 3. flush/delete buffer queue again, in case an SB got there
33583e07920fSDavid van Moolenbroek 	 * 4. close files/connections
33593e07920fSDavid van Moolenbroek 	 */
33603e07920fSDavid van Moolenbroek 
33613e07920fSDavid van Moolenbroek 	/*
33623e07920fSDavid van Moolenbroek 	 *  flush any pending output
33633e07920fSDavid van Moolenbroek 	 */
33643e07920fSDavid van Moolenbroek 	for (f = Files; f != NULL; f = f->f_next) {
33653e07920fSDavid van Moolenbroek 		/* flush any pending output */
33663e07920fSDavid van Moolenbroek 		if (f->f_prevcount)
33673e07920fSDavid van Moolenbroek 			fprintlog(f, NULL, NULL);
33683e07920fSDavid van Moolenbroek 		SEND_QUEUE(f);
33693e07920fSDavid van Moolenbroek 	}
33703e07920fSDavid van Moolenbroek 	/* some actions only on SIGHUP and not on first start */
33713e07920fSDavid van Moolenbroek 	if (Initialized) {
33723e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
33733e07920fSDavid van Moolenbroek 		sign_global_free();
33743e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
33753e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
33763e07920fSDavid van Moolenbroek 		free_incoming_tls_sockets();
33773e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
33783e07920fSDavid van Moolenbroek 		Initialized = 0;
33793e07920fSDavid van Moolenbroek 	}
33803e07920fSDavid van Moolenbroek 	/*
33813e07920fSDavid van Moolenbroek 	 *  Close all open log files.
33823e07920fSDavid van Moolenbroek 	 */
33833e07920fSDavid van Moolenbroek 	for (f = Files; f != NULL; f = f->f_next) {
33843e07920fSDavid van Moolenbroek 		switch (f->f_type) {
33853e07920fSDavid van Moolenbroek 		case F_FILE:
33863e07920fSDavid van Moolenbroek 		case F_TTY:
33873e07920fSDavid van Moolenbroek 		case F_CONSOLE:
33883e07920fSDavid van Moolenbroek 			(void)close(f->f_file);
33893e07920fSDavid van Moolenbroek 			break;
33903e07920fSDavid van Moolenbroek 		case F_PIPE:
33913e07920fSDavid van Moolenbroek 			if (f->f_un.f_pipe.f_pid > 0) {
33923e07920fSDavid van Moolenbroek 				(void)close(f->f_file);
33933e07920fSDavid van Moolenbroek 				deadq_enter(f->f_un.f_pipe.f_pid,
33943e07920fSDavid van Moolenbroek 				    f->f_un.f_pipe.f_pname);
33953e07920fSDavid van Moolenbroek 			}
33963e07920fSDavid van Moolenbroek 			f->f_un.f_pipe.f_pid = 0;
33973e07920fSDavid van Moolenbroek 			break;
33983e07920fSDavid van Moolenbroek 		case F_FORW:
33993e07920fSDavid van Moolenbroek 			if (f->f_un.f_forw.f_addr)
34003e07920fSDavid van Moolenbroek 				freeaddrinfo(f->f_un.f_forw.f_addr);
34013e07920fSDavid van Moolenbroek 			break;
34023e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
34033e07920fSDavid van Moolenbroek 		case F_TLS:
34043e07920fSDavid van Moolenbroek 			free_tls_sslptr(f->f_un.f_tls.tls_conn);
34053e07920fSDavid van Moolenbroek 			break;
34063e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
34073e07920fSDavid van Moolenbroek 		}
34083e07920fSDavid van Moolenbroek 	}
34093e07920fSDavid van Moolenbroek 
34103e07920fSDavid van Moolenbroek 	/*
34113e07920fSDavid van Moolenbroek 	 *  Close all open UDP sockets
34123e07920fSDavid van Moolenbroek 	 */
34133e07920fSDavid van Moolenbroek 	if (finet) {
34143e07920fSDavid van Moolenbroek 		for (i = 0; i < finet->fd; i++) {
34153e07920fSDavid van Moolenbroek 			if (close(finet[i+1].fd) < 0) {
34163e07920fSDavid van Moolenbroek 				logerror("close() failed");
34173e07920fSDavid van Moolenbroek 				die(0, 0, NULL);
34183e07920fSDavid van Moolenbroek 			}
34193e07920fSDavid van Moolenbroek 			DEL_EVENT(finet[i+1].ev);
34203e07920fSDavid van Moolenbroek 			FREEPTR(finet[i+1].ev);
34213e07920fSDavid van Moolenbroek 		}
34223e07920fSDavid van Moolenbroek 		FREEPTR(finet);
34233e07920fSDavid van Moolenbroek 	}
34243e07920fSDavid van Moolenbroek 
34253e07920fSDavid van Moolenbroek 	/* get FQDN and hostname/domain */
34263e07920fSDavid van Moolenbroek 	FREEPTR(oldLocalFQDN);
34273e07920fSDavid van Moolenbroek 	oldLocalFQDN = LocalFQDN;
34283e07920fSDavid van Moolenbroek 	LocalFQDN = getLocalFQDN();
34293e07920fSDavid van Moolenbroek 	if ((p = strchr(LocalFQDN, '.')) != NULL)
34303e07920fSDavid van Moolenbroek 		(void)strlcpy(LocalHostName, LocalFQDN, 1+p-LocalFQDN);
34313e07920fSDavid van Moolenbroek 	else
34323e07920fSDavid van Moolenbroek 		(void)strlcpy(LocalHostName, LocalFQDN, sizeof(LocalHostName));
34333e07920fSDavid van Moolenbroek 
34343e07920fSDavid van Moolenbroek 	/*
34353e07920fSDavid van Moolenbroek 	 *  Reset counter of forwarding actions
34363e07920fSDavid van Moolenbroek 	 */
34373e07920fSDavid van Moolenbroek 
34383e07920fSDavid van Moolenbroek 	NumForwards=0;
34393e07920fSDavid van Moolenbroek 
34403e07920fSDavid van Moolenbroek 	/* new destination list to replace Files */
34413e07920fSDavid van Moolenbroek 	newf = NULL;
34423e07920fSDavid van Moolenbroek 	nextp = &newf;
34433e07920fSDavid van Moolenbroek 
34443e07920fSDavid van Moolenbroek 	/* open the configuration file */
34453e07920fSDavid van Moolenbroek 	if ((cf = fopen(ConfFile, "r")) == NULL) {
34463e07920fSDavid van Moolenbroek 		DPRINTF(D_FILE, "Cannot open `%s'\n", ConfFile);
34473e07920fSDavid van Moolenbroek 		*nextp = (struct filed *)calloc(1, sizeof(*f));
34483e07920fSDavid van Moolenbroek 		cfline(0, "*.ERR\t/dev/console", *nextp, "*", "*");
34493e07920fSDavid van Moolenbroek 		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
34503e07920fSDavid van Moolenbroek 		cfline(0, "*.PANIC\t*", (*nextp)->f_next, "*", "*");
34513e07920fSDavid van Moolenbroek 		Initialized = 1;
34523e07920fSDavid van Moolenbroek 		RESTORE_SIGNALS(omask);
34533e07920fSDavid van Moolenbroek 		return;
34543e07920fSDavid van Moolenbroek 	}
34553e07920fSDavid van Moolenbroek 
34563e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
34573e07920fSDavid van Moolenbroek 	/* init with new TLS_CTX
34583e07920fSDavid van Moolenbroek 	 * as far as I see one cannot change the cert/key of an existing CTX
34593e07920fSDavid van Moolenbroek 	 */
34603e07920fSDavid van Moolenbroek 	FREE_SSL_CTX(tls_opt.global_TLS_CTX);
34613e07920fSDavid van Moolenbroek 
34623e07920fSDavid van Moolenbroek 	free_cred_SLIST(&tls_opt.cert_head);
34633e07920fSDavid van Moolenbroek 	free_cred_SLIST(&tls_opt.fprint_head);
34643e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
34653e07920fSDavid van Moolenbroek 
34663e07920fSDavid van Moolenbroek 	/* read and close configuration file */
34673e07920fSDavid van Moolenbroek 	read_config_file(cf, &newf);
34683e07920fSDavid van Moolenbroek 	newf = *nextp;
34693e07920fSDavid van Moolenbroek 	(void)fclose(cf);
34703e07920fSDavid van Moolenbroek 	DPRINTF(D_MISC, "read_config_file() returned newf=%p\n", newf);
34713e07920fSDavid van Moolenbroek 
34723e07920fSDavid van Moolenbroek #define MOVE_QUEUE(dst, src) do {				\
34733e07920fSDavid van Moolenbroek 	struct buf_queue *buf;					\
34743e07920fSDavid van Moolenbroek 	STAILQ_CONCAT(&dst->f_qhead, &src->f_qhead);		\
34753e07920fSDavid van Moolenbroek 	STAILQ_FOREACH(buf, &dst->f_qhead, entries) {		\
34763e07920fSDavid van Moolenbroek 	      dst->f_qelements++;				\
34773e07920fSDavid van Moolenbroek 	      dst->f_qsize += buf_queue_obj_size(buf);		\
34783e07920fSDavid van Moolenbroek 	}							\
34793e07920fSDavid van Moolenbroek 	src->f_qsize = 0;					\
34803e07920fSDavid van Moolenbroek 	src->f_qelements = 0;					\
34813e07920fSDavid van Moolenbroek } while (/*CONSTCOND*/0)
34823e07920fSDavid van Moolenbroek 
34833e07920fSDavid van Moolenbroek 	/*
34843e07920fSDavid van Moolenbroek 	 *  Free old log files.
34853e07920fSDavid van Moolenbroek 	 */
34863e07920fSDavid van Moolenbroek 	for (f = Files; f != NULL;) {
34873e07920fSDavid van Moolenbroek 		struct filed *ftmp;
34883e07920fSDavid van Moolenbroek 
34893e07920fSDavid van Moolenbroek 		/* check if a new logfile is equal, if so pass the queue */
34903e07920fSDavid van Moolenbroek 		for (f2 = newf; f2 != NULL; f2 = f2->f_next) {
34913e07920fSDavid van Moolenbroek 			if (f->f_type == f2->f_type
34923e07920fSDavid van Moolenbroek 			    && ((f->f_type == F_PIPE
34933e07920fSDavid van Moolenbroek 			    && !strcmp(f->f_un.f_pipe.f_pname,
34943e07920fSDavid van Moolenbroek 			    f2->f_un.f_pipe.f_pname))
34953e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
34963e07920fSDavid van Moolenbroek 			    || (f->f_type == F_TLS
34973e07920fSDavid van Moolenbroek 			    && !strcmp(f->f_un.f_tls.tls_conn->hostname,
34983e07920fSDavid van Moolenbroek 			    f2->f_un.f_tls.tls_conn->hostname)
34993e07920fSDavid van Moolenbroek 			    && !strcmp(f->f_un.f_tls.tls_conn->port,
35003e07920fSDavid van Moolenbroek 			    f2->f_un.f_tls.tls_conn->port))
35013e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
35023e07920fSDavid van Moolenbroek 			    || (f->f_type == F_FORW
35033e07920fSDavid van Moolenbroek 			    && !strcmp(f->f_un.f_forw.f_hname,
35043e07920fSDavid van Moolenbroek 			    f2->f_un.f_forw.f_hname)))) {
35053e07920fSDavid van Moolenbroek 				DPRINTF(D_BUFFER, "move queue from f@%p "
35063e07920fSDavid van Moolenbroek 				    "to f2@%p\n", f, f2);
35073e07920fSDavid van Moolenbroek 				MOVE_QUEUE(f2, f);
35083e07920fSDavid van Moolenbroek 			 }
35093e07920fSDavid van Moolenbroek 		}
35103e07920fSDavid van Moolenbroek 		message_queue_freeall(f);
35113e07920fSDavid van Moolenbroek 		DELREF(f->f_prevmsg);
35123e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
35133e07920fSDavid van Moolenbroek 		if (f->f_type == F_TLS)
35143e07920fSDavid van Moolenbroek 			free_tls_conn(f->f_un.f_tls.tls_conn);
35153e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
35163e07920fSDavid van Moolenbroek 		FREEPTR(f->f_program);
35173e07920fSDavid van Moolenbroek 		FREEPTR(f->f_host);
35183e07920fSDavid van Moolenbroek 		DEL_EVENT(f->f_sq_event);
35193e07920fSDavid van Moolenbroek 
35203e07920fSDavid van Moolenbroek 		ftmp = f->f_next;
35213e07920fSDavid van Moolenbroek 		free((char *)f);
35223e07920fSDavid van Moolenbroek 		f = ftmp;
35233e07920fSDavid van Moolenbroek 	}
35243e07920fSDavid van Moolenbroek 	Files = newf;
35253e07920fSDavid van Moolenbroek 	Initialized = 1;
35263e07920fSDavid van Moolenbroek 
35273e07920fSDavid van Moolenbroek 	if (Debug) {
35283e07920fSDavid van Moolenbroek 		for (f = Files; f; f = f->f_next) {
35293e07920fSDavid van Moolenbroek 			for (i = 0; i <= LOG_NFACILITIES; i++)
35303e07920fSDavid van Moolenbroek 				if (f->f_pmask[i] == INTERNAL_NOPRI)
35313e07920fSDavid van Moolenbroek 					printf("X ");
35323e07920fSDavid van Moolenbroek 				else
35333e07920fSDavid van Moolenbroek 					printf("%d ", f->f_pmask[i]);
35343e07920fSDavid van Moolenbroek 			printf("%s: ", TypeInfo[f->f_type].name);
35353e07920fSDavid van Moolenbroek 			switch (f->f_type) {
35363e07920fSDavid van Moolenbroek 			case F_FILE:
35373e07920fSDavid van Moolenbroek 			case F_TTY:
35383e07920fSDavid van Moolenbroek 			case F_CONSOLE:
35393e07920fSDavid van Moolenbroek 			case F_FIFO:
35403e07920fSDavid van Moolenbroek 				printf("%s", f->f_un.f_fname);
35413e07920fSDavid van Moolenbroek 				break;
35423e07920fSDavid van Moolenbroek 
35433e07920fSDavid van Moolenbroek 			case F_FORW:
35443e07920fSDavid van Moolenbroek 				printf("%s", f->f_un.f_forw.f_hname);
35453e07920fSDavid van Moolenbroek 				break;
35463e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
35473e07920fSDavid van Moolenbroek 			case F_TLS:
35483e07920fSDavid van Moolenbroek 				printf("[%s]", f->f_un.f_tls.tls_conn->hostname);
35493e07920fSDavid van Moolenbroek 				break;
35503e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
35513e07920fSDavid van Moolenbroek 			case F_PIPE:
35523e07920fSDavid van Moolenbroek 				printf("%s", f->f_un.f_pipe.f_pname);
35533e07920fSDavid van Moolenbroek 				break;
35543e07920fSDavid van Moolenbroek 
35553e07920fSDavid van Moolenbroek 			case F_USERS:
35563e07920fSDavid van Moolenbroek 				for (i = 0;
35573e07920fSDavid van Moolenbroek 				    i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
35583e07920fSDavid van Moolenbroek 					printf("%s, ", f->f_un.f_uname[i]);
35593e07920fSDavid van Moolenbroek 				break;
35603e07920fSDavid van Moolenbroek 			}
35613e07920fSDavid van Moolenbroek 			if (f->f_program != NULL)
35623e07920fSDavid van Moolenbroek 				printf(" (%s)", f->f_program);
35633e07920fSDavid van Moolenbroek 			printf("\n");
35643e07920fSDavid van Moolenbroek 		}
35653e07920fSDavid van Moolenbroek 	}
35663e07920fSDavid van Moolenbroek 
35673e07920fSDavid van Moolenbroek 	finet = socksetup(PF_UNSPEC, bindhostname);
35683e07920fSDavid van Moolenbroek 	if (finet) {
35693e07920fSDavid van Moolenbroek 		if (SecureMode) {
35703e07920fSDavid van Moolenbroek 			for (i = 0; i < finet->fd; i++) {
35713e07920fSDavid van Moolenbroek 				if (shutdown(finet[i+1].fd, SHUT_RD) < 0) {
35723e07920fSDavid van Moolenbroek 					logerror("shutdown() failed");
35733e07920fSDavid van Moolenbroek 					die(0, 0, NULL);
35743e07920fSDavid van Moolenbroek 				}
35753e07920fSDavid van Moolenbroek 			}
35763e07920fSDavid van Moolenbroek 		} else
35773e07920fSDavid van Moolenbroek 			DPRINTF(D_NET, "Listening on inet and/or inet6 socket\n");
35783e07920fSDavid van Moolenbroek 		DPRINTF(D_NET, "Sending on inet and/or inet6 socket\n");
35793e07920fSDavid van Moolenbroek 	}
35803e07920fSDavid van Moolenbroek 
35813e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
35823e07920fSDavid van Moolenbroek 	/* TLS setup -- after all local destinations opened  */
35833e07920fSDavid van Moolenbroek 	DPRINTF(D_PARSE, "Parsed options: tls_ca: %s, tls_cadir: %s, "
35843e07920fSDavid van Moolenbroek 	    "tls_cert: %s, tls_key: %s, tls_verify: %s, "
35853e07920fSDavid van Moolenbroek 	    "bind: %s:%s, max. queue_lengths: %"
35863e07920fSDavid van Moolenbroek 	    PRId64 ", %" PRId64 ", %" PRId64 ", "
35873e07920fSDavid van Moolenbroek 	    "max. queue_sizes: %"
35883e07920fSDavid van Moolenbroek 	    PRId64 ", %" PRId64 ", %" PRId64 "\n",
35893e07920fSDavid van Moolenbroek 	    tls_opt.CAfile, tls_opt.CAdir,
35903e07920fSDavid van Moolenbroek 	    tls_opt.certfile, tls_opt.keyfile, tls_opt.x509verify,
35913e07920fSDavid van Moolenbroek 	    tls_opt.bindhost, tls_opt.bindport,
35923e07920fSDavid van Moolenbroek 	    TypeInfo[F_TLS].queue_length, TypeInfo[F_FILE].queue_length,
35933e07920fSDavid van Moolenbroek 	    TypeInfo[F_PIPE].queue_length,
35943e07920fSDavid van Moolenbroek 	    TypeInfo[F_TLS].queue_size, TypeInfo[F_FILE].queue_size,
35953e07920fSDavid van Moolenbroek 	    TypeInfo[F_PIPE].queue_size);
35963e07920fSDavid van Moolenbroek 	SLIST_FOREACH(cred, &tls_opt.cert_head, entries) {
35973e07920fSDavid van Moolenbroek 		DPRINTF(D_PARSE, "Accepting peer certificate "
35983e07920fSDavid van Moolenbroek 		    "from file: \"%s\"\n", cred->data);
35993e07920fSDavid van Moolenbroek 	}
36003e07920fSDavid van Moolenbroek 	SLIST_FOREACH(cred, &tls_opt.fprint_head, entries) {
36013e07920fSDavid van Moolenbroek 		DPRINTF(D_PARSE, "Accepting peer certificate with "
36023e07920fSDavid van Moolenbroek 		    "fingerprint: \"%s\"\n", cred->data);
36033e07920fSDavid van Moolenbroek 	}
36043e07920fSDavid van Moolenbroek 
36053e07920fSDavid van Moolenbroek 	/* Note: The order of initialization is important because syslog-sign
36063e07920fSDavid van Moolenbroek 	 * should use the TLS cert for signing. -- So we check first if TLS
36073e07920fSDavid van Moolenbroek 	 * will be used and initialize it before starting -sign.
36083e07920fSDavid van Moolenbroek 	 *
36093e07920fSDavid van Moolenbroek 	 * This means that if we are a client without TLS destinations TLS
36103e07920fSDavid van Moolenbroek 	 * will not be initialized and syslog-sign will generate a new key.
36113e07920fSDavid van Moolenbroek 	 * -- Even if the user has set a usable tls_cert.
36123e07920fSDavid van Moolenbroek 	 * Is this the expected behaviour? The alternative would be to always
36133e07920fSDavid van Moolenbroek 	 * initialize the TLS structures, even if they will not be needed
36143e07920fSDavid van Moolenbroek 	 * (or only needed to read the DSA key for -sign).
36153e07920fSDavid van Moolenbroek 	 */
36163e07920fSDavid van Moolenbroek 
36173e07920fSDavid van Moolenbroek 	/* Initialize TLS only if used */
36183e07920fSDavid van Moolenbroek 	if (tls_opt.server)
36193e07920fSDavid van Moolenbroek 		tls_status_msg = init_global_TLS_CTX();
36203e07920fSDavid van Moolenbroek 	else
36213e07920fSDavid van Moolenbroek 		for (f = Files; f; f = f->f_next) {
36223e07920fSDavid van Moolenbroek 			if (f->f_type != F_TLS)
36233e07920fSDavid van Moolenbroek 				continue;
36243e07920fSDavid van Moolenbroek 			tls_status_msg = init_global_TLS_CTX();
36253e07920fSDavid van Moolenbroek 			break;
36263e07920fSDavid van Moolenbroek 		}
36273e07920fSDavid van Moolenbroek 
36283e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
36293e07920fSDavid van Moolenbroek 
36303e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
36313e07920fSDavid van Moolenbroek 	/* only initialize -sign if actually used */
36323e07920fSDavid van Moolenbroek 	if (GlobalSign.sg == 0 || GlobalSign.sg == 1 || GlobalSign.sg == 2)
36333e07920fSDavid van Moolenbroek 		(void)sign_global_init(Files);
36343e07920fSDavid van Moolenbroek 	else if (GlobalSign.sg == 3)
36353e07920fSDavid van Moolenbroek 		for (f = Files; f; f = f->f_next)
36363e07920fSDavid van Moolenbroek 			if (f->f_flags & FFLAG_SIGN) {
36373e07920fSDavid van Moolenbroek 				(void)sign_global_init(Files);
36383e07920fSDavid van Moolenbroek 				break;
36393e07920fSDavid van Moolenbroek 			}
36403e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
36413e07920fSDavid van Moolenbroek 
36423e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
36433e07920fSDavid van Moolenbroek 	if (tls_status_msg) {
36443e07920fSDavid van Moolenbroek 		loginfo("%s", tls_status_msg);
36453e07920fSDavid van Moolenbroek 		free(tls_status_msg);
36463e07920fSDavid van Moolenbroek 	}
36473e07920fSDavid van Moolenbroek 	DPRINTF((D_NET|D_TLS), "Preparing sockets for TLS\n");
36483e07920fSDavid van Moolenbroek 	TLS_Listen_Set =
36493e07920fSDavid van Moolenbroek 		socksetup_tls(PF_UNSPEC, tls_opt.bindhost, tls_opt.bindport);
36503e07920fSDavid van Moolenbroek 
36513e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next) {
36523e07920fSDavid van Moolenbroek 		if (f->f_type != F_TLS)
36533e07920fSDavid van Moolenbroek 			continue;
36543e07920fSDavid van Moolenbroek 		if (!tls_connect(f->f_un.f_tls.tls_conn)) {
36553e07920fSDavid van Moolenbroek 			logerror("Unable to connect to TLS server %s",
36563e07920fSDavid van Moolenbroek 			    f->f_un.f_tls.tls_conn->hostname);
36573e07920fSDavid van Moolenbroek 			/* Reconnect after x seconds  */
36583e07920fSDavid van Moolenbroek 			schedule_event(&f->f_un.f_tls.tls_conn->event,
36593e07920fSDavid van Moolenbroek 			    &((struct timeval){TLS_RECONNECT_SEC, 0}),
36603e07920fSDavid van Moolenbroek 			    tls_reconnect, f->f_un.f_tls.tls_conn);
36613e07920fSDavid van Moolenbroek 		}
36623e07920fSDavid van Moolenbroek 	}
36633e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
36643e07920fSDavid van Moolenbroek 
36653e07920fSDavid van Moolenbroek 	loginfo("restart");
36663e07920fSDavid van Moolenbroek 	/*
36673e07920fSDavid van Moolenbroek 	 * Log a change in hostname, but only on a restart (we detect this
36683e07920fSDavid van Moolenbroek 	 * by checking to see if we're passed a kevent).
36693e07920fSDavid van Moolenbroek 	 */
36703e07920fSDavid van Moolenbroek 	if (oldLocalFQDN && strcmp(oldLocalFQDN, LocalFQDN) != 0)
36713e07920fSDavid van Moolenbroek 		loginfo("host name changed, \"%s\" to \"%s\"",
36723e07920fSDavid van Moolenbroek 		    oldLocalFQDN, LocalFQDN);
36733e07920fSDavid van Moolenbroek 
36743e07920fSDavid van Moolenbroek 	RESTORE_SIGNALS(omask);
36753e07920fSDavid van Moolenbroek }
36763e07920fSDavid van Moolenbroek 
36773e07920fSDavid van Moolenbroek /*
36783e07920fSDavid van Moolenbroek  * Crack a configuration file line
36793e07920fSDavid van Moolenbroek  */
36803e07920fSDavid van Moolenbroek void
cfline(size_t linenum,const char * line,struct filed * f,const char * prog,const char * host)36813e07920fSDavid van Moolenbroek cfline(size_t linenum, const char *line, struct filed *f, const char *prog,
36823e07920fSDavid van Moolenbroek     const char *host)
36833e07920fSDavid van Moolenbroek {
36843e07920fSDavid van Moolenbroek 	struct addrinfo hints, *res;
36853e07920fSDavid van Moolenbroek 	int    error, i, pri, syncfile;
36863e07920fSDavid van Moolenbroek 	const char   *p, *q;
36873e07920fSDavid van Moolenbroek 	char *bp;
36883e07920fSDavid van Moolenbroek 	char   buf[MAXLINE];
36893e07920fSDavid van Moolenbroek 	struct stat sb;
36903e07920fSDavid van Moolenbroek 
36913e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_PARSE),
36923e07920fSDavid van Moolenbroek 		"cfline(%zu, \"%s\", f, \"%s\", \"%s\")\n",
36933e07920fSDavid van Moolenbroek 		linenum, line, prog, host);
36943e07920fSDavid van Moolenbroek 
36953e07920fSDavid van Moolenbroek 	errno = 0;	/* keep strerror() stuff out of logerror messages */
36963e07920fSDavid van Moolenbroek 
36973e07920fSDavid van Moolenbroek 	/* clear out file entry */
36983e07920fSDavid van Moolenbroek 	memset(f, 0, sizeof(*f));
36993e07920fSDavid van Moolenbroek 	for (i = 0; i <= LOG_NFACILITIES; i++)
37003e07920fSDavid van Moolenbroek 		f->f_pmask[i] = INTERNAL_NOPRI;
37013e07920fSDavid van Moolenbroek 	STAILQ_INIT(&f->f_qhead);
37023e07920fSDavid van Moolenbroek 
37033e07920fSDavid van Moolenbroek 	/*
37043e07920fSDavid van Moolenbroek 	 * There should not be any space before the log facility.
37053e07920fSDavid van Moolenbroek 	 * Check this is okay, complain and fix if it is not.
37063e07920fSDavid van Moolenbroek 	 */
37073e07920fSDavid van Moolenbroek 	q = line;
37083e07920fSDavid van Moolenbroek 	if (isblank((unsigned char)*line)) {
37093e07920fSDavid van Moolenbroek 		errno = 0;
37103e07920fSDavid van Moolenbroek 		logerror("Warning: `%s' space or tab before the log facility",
37113e07920fSDavid van Moolenbroek 		    line);
37123e07920fSDavid van Moolenbroek 		/* Fix: strip all spaces/tabs before the log facility */
37133e07920fSDavid van Moolenbroek 		while (*q++ && isblank((unsigned char)*q))
37143e07920fSDavid van Moolenbroek 			/* skip blanks */;
37153e07920fSDavid van Moolenbroek 		line = q;
37163e07920fSDavid van Moolenbroek 	}
37173e07920fSDavid van Moolenbroek 
37183e07920fSDavid van Moolenbroek 	/*
37193e07920fSDavid van Moolenbroek 	 * q is now at the first char of the log facility
37203e07920fSDavid van Moolenbroek 	 * There should be at least one tab after the log facility
37213e07920fSDavid van Moolenbroek 	 * Check this is okay, and complain and fix if it is not.
37223e07920fSDavid van Moolenbroek 	 */
37233e07920fSDavid van Moolenbroek 	q = line + strlen(line);
37243e07920fSDavid van Moolenbroek 	while (!isblank((unsigned char)*q) && (q != line))
37253e07920fSDavid van Moolenbroek 		q--;
37263e07920fSDavid van Moolenbroek 	if ((q == line) && strlen(line)) {
37273e07920fSDavid van Moolenbroek 		/* No tabs or space in a non empty line: complain */
37283e07920fSDavid van Moolenbroek 		errno = 0;
37293e07920fSDavid van Moolenbroek 		logerror(
37303e07920fSDavid van Moolenbroek 		    "Error: `%s' log facility or log target missing",
37313e07920fSDavid van Moolenbroek 		    line);
37323e07920fSDavid van Moolenbroek 		return;
37333e07920fSDavid van Moolenbroek 	}
37343e07920fSDavid van Moolenbroek 
37353e07920fSDavid van Moolenbroek 	/* save host name, if any */
37363e07920fSDavid van Moolenbroek 	if (*host == '*')
37373e07920fSDavid van Moolenbroek 		f->f_host = NULL;
37383e07920fSDavid van Moolenbroek 	else {
37393e07920fSDavid van Moolenbroek 		f->f_host = strdup(host);
3740*0a6a1f1dSLionel Sambuc 		trim_anydomain(&f->f_host[1]);	/* skip +/- at beginning */
37413e07920fSDavid van Moolenbroek 	}
37423e07920fSDavid van Moolenbroek 
37433e07920fSDavid van Moolenbroek 	/* save program name, if any */
37443e07920fSDavid van Moolenbroek 	if (*prog == '*')
37453e07920fSDavid van Moolenbroek 		f->f_program = NULL;
37463e07920fSDavid van Moolenbroek 	else
37473e07920fSDavid van Moolenbroek 		f->f_program = strdup(prog);
37483e07920fSDavid van Moolenbroek 
37493e07920fSDavid van Moolenbroek 	/* scan through the list of selectors */
37503e07920fSDavid van Moolenbroek 	for (p = line; *p && !isblank((unsigned char)*p);) {
37513e07920fSDavid van Moolenbroek 		int pri_done, pri_cmp, pri_invert;
37523e07920fSDavid van Moolenbroek 
37533e07920fSDavid van Moolenbroek 		/* find the end of this facility name list */
37543e07920fSDavid van Moolenbroek 		for (q = p; *q && !isblank((unsigned char)*q) && *q++ != '.'; )
37553e07920fSDavid van Moolenbroek 			continue;
37563e07920fSDavid van Moolenbroek 
37573e07920fSDavid van Moolenbroek 		/* get the priority comparison */
37583e07920fSDavid van Moolenbroek 		pri_cmp = 0;
37593e07920fSDavid van Moolenbroek 		pri_done = 0;
37603e07920fSDavid van Moolenbroek 		pri_invert = 0;
37613e07920fSDavid van Moolenbroek 		if (*q == '!') {
37623e07920fSDavid van Moolenbroek 			pri_invert = 1;
37633e07920fSDavid van Moolenbroek 			q++;
37643e07920fSDavid van Moolenbroek 		}
37653e07920fSDavid van Moolenbroek 		while (! pri_done) {
37663e07920fSDavid van Moolenbroek 			switch (*q) {
37673e07920fSDavid van Moolenbroek 			case '<':
37683e07920fSDavid van Moolenbroek 				pri_cmp = PRI_LT;
37693e07920fSDavid van Moolenbroek 				q++;
37703e07920fSDavid van Moolenbroek 				break;
37713e07920fSDavid van Moolenbroek 			case '=':
37723e07920fSDavid van Moolenbroek 				pri_cmp = PRI_EQ;
37733e07920fSDavid van Moolenbroek 				q++;
37743e07920fSDavid van Moolenbroek 				break;
37753e07920fSDavid van Moolenbroek 			case '>':
37763e07920fSDavid van Moolenbroek 				pri_cmp = PRI_GT;
37773e07920fSDavid van Moolenbroek 				q++;
37783e07920fSDavid van Moolenbroek 				break;
37793e07920fSDavid van Moolenbroek 			default:
37803e07920fSDavid van Moolenbroek 				pri_done = 1;
37813e07920fSDavid van Moolenbroek 				break;
37823e07920fSDavid van Moolenbroek 			}
37833e07920fSDavid van Moolenbroek 		}
37843e07920fSDavid van Moolenbroek 
37853e07920fSDavid van Moolenbroek 		/* collect priority name */
37863e07920fSDavid van Moolenbroek 		for (bp = buf; *q && !strchr("\t ,;", *q); )
37873e07920fSDavid van Moolenbroek 			*bp++ = *q++;
37883e07920fSDavid van Moolenbroek 		*bp = '\0';
37893e07920fSDavid van Moolenbroek 
37903e07920fSDavid van Moolenbroek 		/* skip cruft */
37913e07920fSDavid van Moolenbroek 		while (strchr(",;", *q))
37923e07920fSDavid van Moolenbroek 			q++;
37933e07920fSDavid van Moolenbroek 
37943e07920fSDavid van Moolenbroek 		/* decode priority name */
37953e07920fSDavid van Moolenbroek 		if (*buf == '*') {
37963e07920fSDavid van Moolenbroek 			pri = LOG_PRIMASK + 1;
37973e07920fSDavid van Moolenbroek 			pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
37983e07920fSDavid van Moolenbroek 		} else {
37993e07920fSDavid van Moolenbroek 			pri = decode(buf, prioritynames);
38003e07920fSDavid van Moolenbroek 			if (pri < 0) {
38013e07920fSDavid van Moolenbroek 				errno = 0;
38023e07920fSDavid van Moolenbroek 				logerror("Unknown priority name `%s'", buf);
38033e07920fSDavid van Moolenbroek 				return;
38043e07920fSDavid van Moolenbroek 			}
38053e07920fSDavid van Moolenbroek 		}
38063e07920fSDavid van Moolenbroek 		if (pri_cmp == 0)
38073e07920fSDavid van Moolenbroek 			pri_cmp = UniquePriority ? PRI_EQ
38083e07920fSDavid van Moolenbroek 						 : PRI_EQ | PRI_GT;
38093e07920fSDavid van Moolenbroek 		if (pri_invert)
38103e07920fSDavid van Moolenbroek 			pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
38113e07920fSDavid van Moolenbroek 
38123e07920fSDavid van Moolenbroek 		/* scan facilities */
38133e07920fSDavid van Moolenbroek 		while (*p && !strchr("\t .;", *p)) {
38143e07920fSDavid van Moolenbroek 			for (bp = buf; *p && !strchr("\t ,;.", *p); )
38153e07920fSDavid van Moolenbroek 				*bp++ = *p++;
38163e07920fSDavid van Moolenbroek 			*bp = '\0';
38173e07920fSDavid van Moolenbroek 			if (*buf == '*')
38183e07920fSDavid van Moolenbroek 				for (i = 0; i < LOG_NFACILITIES; i++) {
38193e07920fSDavid van Moolenbroek 					f->f_pmask[i] = pri;
38203e07920fSDavid van Moolenbroek 					f->f_pcmp[i] = pri_cmp;
38213e07920fSDavid van Moolenbroek 				}
38223e07920fSDavid van Moolenbroek 			else {
38233e07920fSDavid van Moolenbroek 				i = decode(buf, facilitynames);
38243e07920fSDavid van Moolenbroek 				if (i < 0) {
38253e07920fSDavid van Moolenbroek 					errno = 0;
38263e07920fSDavid van Moolenbroek 					logerror("Unknown facility name `%s'",
38273e07920fSDavid van Moolenbroek 					    buf);
38283e07920fSDavid van Moolenbroek 					return;
38293e07920fSDavid van Moolenbroek 				}
38303e07920fSDavid van Moolenbroek 				f->f_pmask[i >> 3] = pri;
38313e07920fSDavid van Moolenbroek 				f->f_pcmp[i >> 3] = pri_cmp;
38323e07920fSDavid van Moolenbroek 			}
38333e07920fSDavid van Moolenbroek 			while (*p == ',' || *p == ' ')
38343e07920fSDavid van Moolenbroek 				p++;
38353e07920fSDavid van Moolenbroek 		}
38363e07920fSDavid van Moolenbroek 
38373e07920fSDavid van Moolenbroek 		p = q;
38383e07920fSDavid van Moolenbroek 	}
38393e07920fSDavid van Moolenbroek 
38403e07920fSDavid van Moolenbroek 	/* skip to action part */
38413e07920fSDavid van Moolenbroek 	while (isblank((unsigned char)*p))
38423e07920fSDavid van Moolenbroek 		p++;
38433e07920fSDavid van Moolenbroek 
38443e07920fSDavid van Moolenbroek 	/*
38453e07920fSDavid van Moolenbroek 	 * should this be "#ifndef DISABLE_SIGN" or is it a general option?
38463e07920fSDavid van Moolenbroek 	 * '+' before file destination: write with PRI field for later
38473e07920fSDavid van Moolenbroek 	 * verification
38483e07920fSDavid van Moolenbroek 	 */
38493e07920fSDavid van Moolenbroek 	if (*p == '+') {
38503e07920fSDavid van Moolenbroek 		f->f_flags |= FFLAG_FULL;
38513e07920fSDavid van Moolenbroek 		p++;
38523e07920fSDavid van Moolenbroek 	}
38533e07920fSDavid van Moolenbroek 	if (*p == '-') {
38543e07920fSDavid van Moolenbroek 		syncfile = 0;
38553e07920fSDavid van Moolenbroek 		p++;
38563e07920fSDavid van Moolenbroek 	} else
38573e07920fSDavid van Moolenbroek 		syncfile = 1;
38583e07920fSDavid van Moolenbroek 
38593e07920fSDavid van Moolenbroek 	switch (*p) {
38603e07920fSDavid van Moolenbroek 	case '@':
38613e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
38623e07920fSDavid van Moolenbroek 		if (GlobalSign.sg == 3)
38633e07920fSDavid van Moolenbroek 			f->f_flags |= FFLAG_SIGN;
38643e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
38653e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
38663e07920fSDavid van Moolenbroek 		if (*(p+1) == '[') {
38673e07920fSDavid van Moolenbroek 			/* TLS destination */
38683e07920fSDavid van Moolenbroek 			if (!parse_tls_destination(p, f, linenum)) {
38693e07920fSDavid van Moolenbroek 				logerror("Unable to parse action %s", p);
38703e07920fSDavid van Moolenbroek 				break;
38713e07920fSDavid van Moolenbroek 			}
38723e07920fSDavid van Moolenbroek 			f->f_type = F_TLS;
38733e07920fSDavid van Moolenbroek 			break;
38743e07920fSDavid van Moolenbroek 		}
38753e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
38763e07920fSDavid van Moolenbroek 		(void)strlcpy(f->f_un.f_forw.f_hname, ++p,
38773e07920fSDavid van Moolenbroek 		    sizeof(f->f_un.f_forw.f_hname));
38783e07920fSDavid van Moolenbroek 		memset(&hints, 0, sizeof(hints));
38793e07920fSDavid van Moolenbroek 		hints.ai_family = AF_UNSPEC;
38803e07920fSDavid van Moolenbroek 		hints.ai_socktype = SOCK_DGRAM;
38813e07920fSDavid van Moolenbroek 		hints.ai_protocol = 0;
38823e07920fSDavid van Moolenbroek 		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
38833e07920fSDavid van Moolenbroek 		    &res);
38843e07920fSDavid van Moolenbroek 		if (error) {
38853e07920fSDavid van Moolenbroek 			errno = 0;
38863e07920fSDavid van Moolenbroek 			logerror("%s", gai_strerror(error));
38873e07920fSDavid van Moolenbroek 			break;
38883e07920fSDavid van Moolenbroek 		}
38893e07920fSDavid van Moolenbroek 		f->f_un.f_forw.f_addr = res;
38903e07920fSDavid van Moolenbroek 		f->f_type = F_FORW;
38913e07920fSDavid van Moolenbroek 		NumForwards++;
38923e07920fSDavid van Moolenbroek 		break;
38933e07920fSDavid van Moolenbroek 
38943e07920fSDavid van Moolenbroek 	case '/':
38953e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
38963e07920fSDavid van Moolenbroek 		if (GlobalSign.sg == 3)
38973e07920fSDavid van Moolenbroek 			f->f_flags |= FFLAG_SIGN;
38983e07920fSDavid van Moolenbroek #endif /* !DISABLE_SIGN */
38993e07920fSDavid van Moolenbroek 		(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
39003e07920fSDavid van Moolenbroek 		if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NONBLOCK, 0)) < 0)
39013e07920fSDavid van Moolenbroek 		{
39023e07920fSDavid van Moolenbroek 			f->f_type = F_UNUSED;
39033e07920fSDavid van Moolenbroek 			logerror("%s", p);
39043e07920fSDavid van Moolenbroek 			break;
39053e07920fSDavid van Moolenbroek 		}
39063e07920fSDavid van Moolenbroek 		if (!fstat(f->f_file, &sb) && S_ISFIFO(sb.st_mode)) {
39073e07920fSDavid van Moolenbroek 			f->f_file = -1;
39083e07920fSDavid van Moolenbroek 			f->f_type = F_FIFO;
39093e07920fSDavid van Moolenbroek 			break;
39103e07920fSDavid van Moolenbroek 		}
39113e07920fSDavid van Moolenbroek 
39123e07920fSDavid van Moolenbroek 		if (isatty(f->f_file)) {
39133e07920fSDavid van Moolenbroek 			f->f_type = F_TTY;
39143e07920fSDavid van Moolenbroek 			if (strcmp(p, ctty) == 0)
39153e07920fSDavid van Moolenbroek 				f->f_type = F_CONSOLE;
39163e07920fSDavid van Moolenbroek 		} else
39173e07920fSDavid van Moolenbroek 			f->f_type = F_FILE;
39183e07920fSDavid van Moolenbroek 
39193e07920fSDavid van Moolenbroek 		if (syncfile)
39203e07920fSDavid van Moolenbroek 			f->f_flags |= FFLAG_SYNC;
39213e07920fSDavid van Moolenbroek 		break;
39223e07920fSDavid van Moolenbroek 
39233e07920fSDavid van Moolenbroek 	case '|':
39243e07920fSDavid van Moolenbroek #ifndef DISABLE_SIGN
39253e07920fSDavid van Moolenbroek 		if (GlobalSign.sg == 3)
39263e07920fSDavid van Moolenbroek 			f->f_flags |= FFLAG_SIGN;
39273e07920fSDavid van Moolenbroek #endif
39283e07920fSDavid van Moolenbroek 		f->f_un.f_pipe.f_pid = 0;
39293e07920fSDavid van Moolenbroek 		(void) strlcpy(f->f_un.f_pipe.f_pname, p + 1,
39303e07920fSDavid van Moolenbroek 		    sizeof(f->f_un.f_pipe.f_pname));
39313e07920fSDavid van Moolenbroek 		f->f_type = F_PIPE;
39323e07920fSDavid van Moolenbroek 		break;
39333e07920fSDavid van Moolenbroek 
39343e07920fSDavid van Moolenbroek 	case '*':
39353e07920fSDavid van Moolenbroek 		f->f_type = F_WALL;
39363e07920fSDavid van Moolenbroek 		break;
39373e07920fSDavid van Moolenbroek 
39383e07920fSDavid van Moolenbroek 	default:
39393e07920fSDavid van Moolenbroek 		for (i = 0; i < MAXUNAMES && *p; i++) {
39403e07920fSDavid van Moolenbroek 			for (q = p; *q && *q != ','; )
39413e07920fSDavid van Moolenbroek 				q++;
39423e07920fSDavid van Moolenbroek 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
39433e07920fSDavid van Moolenbroek 			if ((q - p) > UT_NAMESIZE)
39443e07920fSDavid van Moolenbroek 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
39453e07920fSDavid van Moolenbroek 			else
39463e07920fSDavid van Moolenbroek 				f->f_un.f_uname[i][q - p] = '\0';
39473e07920fSDavid van Moolenbroek 			while (*q == ',' || *q == ' ')
39483e07920fSDavid van Moolenbroek 				q++;
39493e07920fSDavid van Moolenbroek 			p = q;
39503e07920fSDavid van Moolenbroek 		}
39513e07920fSDavid van Moolenbroek 		f->f_type = F_USERS;
39523e07920fSDavid van Moolenbroek 		break;
39533e07920fSDavid van Moolenbroek 	}
39543e07920fSDavid van Moolenbroek }
39553e07920fSDavid van Moolenbroek 
39563e07920fSDavid van Moolenbroek 
39573e07920fSDavid van Moolenbroek /*
39583e07920fSDavid van Moolenbroek  *  Decode a symbolic name to a numeric value
39593e07920fSDavid van Moolenbroek  */
39603e07920fSDavid van Moolenbroek int
decode(const char * name,CODE * codetab)39613e07920fSDavid van Moolenbroek decode(const char *name, CODE *codetab)
39623e07920fSDavid van Moolenbroek {
39633e07920fSDavid van Moolenbroek 	CODE *c;
39643e07920fSDavid van Moolenbroek 	char *p, buf[40];
39653e07920fSDavid van Moolenbroek 
39663e07920fSDavid van Moolenbroek 	if (isdigit((unsigned char)*name))
39673e07920fSDavid van Moolenbroek 		return atoi(name);
39683e07920fSDavid van Moolenbroek 
39693e07920fSDavid van Moolenbroek 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
39703e07920fSDavid van Moolenbroek 		if (isupper((unsigned char)*name))
39713e07920fSDavid van Moolenbroek 			*p = tolower((unsigned char)*name);
39723e07920fSDavid van Moolenbroek 		else
39733e07920fSDavid van Moolenbroek 			*p = *name;
39743e07920fSDavid van Moolenbroek 	}
39753e07920fSDavid van Moolenbroek 	*p = '\0';
39763e07920fSDavid van Moolenbroek 	for (c = codetab; c->c_name; c++)
39773e07920fSDavid van Moolenbroek 		if (!strcmp(buf, c->c_name))
39783e07920fSDavid van Moolenbroek 			return c->c_val;
39793e07920fSDavid van Moolenbroek 
39803e07920fSDavid van Moolenbroek 	return -1;
39813e07920fSDavid van Moolenbroek }
39823e07920fSDavid van Moolenbroek 
39833e07920fSDavid van Moolenbroek /*
39843e07920fSDavid van Moolenbroek  * Retrieve the size of the kernel message buffer, via sysctl.
39853e07920fSDavid van Moolenbroek  */
39863e07920fSDavid van Moolenbroek int
getmsgbufsize(void)39873e07920fSDavid van Moolenbroek getmsgbufsize(void)
39883e07920fSDavid van Moolenbroek {
39893e07920fSDavid van Moolenbroek #ifdef __NetBSD_Version__
39903e07920fSDavid van Moolenbroek 	int msgbufsize, mib[2];
39913e07920fSDavid van Moolenbroek 	size_t size;
39923e07920fSDavid van Moolenbroek 
39933e07920fSDavid van Moolenbroek 	mib[0] = CTL_KERN;
39943e07920fSDavid van Moolenbroek 	mib[1] = KERN_MSGBUFSIZE;
39953e07920fSDavid van Moolenbroek 	size = sizeof msgbufsize;
39963e07920fSDavid van Moolenbroek 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
39973e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Couldn't get kern.msgbufsize\n");
39983e07920fSDavid van Moolenbroek 		return 0;
39993e07920fSDavid van Moolenbroek 	}
40003e07920fSDavid van Moolenbroek 	return msgbufsize;
40013e07920fSDavid van Moolenbroek #else
40023e07920fSDavid van Moolenbroek 	return MAXLINE;
40033e07920fSDavid van Moolenbroek #endif /* __NetBSD_Version__ */
40043e07920fSDavid van Moolenbroek }
40053e07920fSDavid van Moolenbroek 
40063e07920fSDavid van Moolenbroek /*
40073e07920fSDavid van Moolenbroek  * Retrieve the hostname, via sysctl.
40083e07920fSDavid van Moolenbroek  */
40093e07920fSDavid van Moolenbroek char *
getLocalFQDN(void)40103e07920fSDavid van Moolenbroek getLocalFQDN(void)
40113e07920fSDavid van Moolenbroek {
40123e07920fSDavid van Moolenbroek 	int mib[2];
40133e07920fSDavid van Moolenbroek 	char *hostname;
40143e07920fSDavid van Moolenbroek 	size_t len;
40153e07920fSDavid van Moolenbroek 
40163e07920fSDavid van Moolenbroek 	mib[0] = CTL_KERN;
40173e07920fSDavid van Moolenbroek 	mib[1] = KERN_HOSTNAME;
40183e07920fSDavid van Moolenbroek 	sysctl(mib, 2, NULL, &len, NULL, 0);
40193e07920fSDavid van Moolenbroek 
40203e07920fSDavid van Moolenbroek 	if (!(hostname = malloc(len))) {
40213e07920fSDavid van Moolenbroek 		logerror("Unable to allocate memory");
40223e07920fSDavid van Moolenbroek 		die(0,0,NULL);
40233e07920fSDavid van Moolenbroek 	} else if (sysctl(mib, 2, hostname, &len, NULL, 0) == -1) {
40243e07920fSDavid van Moolenbroek 		DPRINTF(D_MISC, "Couldn't get kern.hostname\n");
4025*0a6a1f1dSLionel Sambuc 		(void)gethostname(hostname, sizeof(len));
40263e07920fSDavid van Moolenbroek 	}
40273e07920fSDavid van Moolenbroek 	return hostname;
40283e07920fSDavid van Moolenbroek }
40293e07920fSDavid van Moolenbroek 
40303e07920fSDavid van Moolenbroek struct socketEvent *
socksetup(int af,const char * hostname)40313e07920fSDavid van Moolenbroek socksetup(int af, const char *hostname)
40323e07920fSDavid van Moolenbroek {
40333e07920fSDavid van Moolenbroek 	struct addrinfo hints, *res, *r;
40343e07920fSDavid van Moolenbroek 	int error, maxs;
40353e07920fSDavid van Moolenbroek #ifdef IPV6_V6ONLY
40363e07920fSDavid van Moolenbroek 	int on = 1;
40373e07920fSDavid van Moolenbroek #endif /* IPV6_V6ONLY */
40383e07920fSDavid van Moolenbroek 	struct socketEvent *s, *socks;
40393e07920fSDavid van Moolenbroek 
40403e07920fSDavid van Moolenbroek 	if(SecureMode && !NumForwards)
40413e07920fSDavid van Moolenbroek 		return NULL;
40423e07920fSDavid van Moolenbroek 
40433e07920fSDavid van Moolenbroek 	memset(&hints, 0, sizeof(hints));
40443e07920fSDavid van Moolenbroek 	hints.ai_flags = AI_PASSIVE;
40453e07920fSDavid van Moolenbroek 	hints.ai_family = af;
40463e07920fSDavid van Moolenbroek 	hints.ai_socktype = SOCK_DGRAM;
40473e07920fSDavid van Moolenbroek 	error = getaddrinfo(hostname, "syslog", &hints, &res);
40483e07920fSDavid van Moolenbroek 	if (error) {
40493e07920fSDavid van Moolenbroek 		errno = 0;
40503e07920fSDavid van Moolenbroek 		logerror("%s", gai_strerror(error));
40513e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
40523e07920fSDavid van Moolenbroek 	}
40533e07920fSDavid van Moolenbroek 
40543e07920fSDavid van Moolenbroek 	/* Count max number of sockets we may open */
40553e07920fSDavid van Moolenbroek 	for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
40563e07920fSDavid van Moolenbroek 		continue;
40573e07920fSDavid van Moolenbroek 	socks = calloc(maxs+1, sizeof(*socks));
40583e07920fSDavid van Moolenbroek 	if (!socks) {
40593e07920fSDavid van Moolenbroek 		logerror("Couldn't allocate memory for sockets");
40603e07920fSDavid van Moolenbroek 		die(0, 0, NULL);
40613e07920fSDavid van Moolenbroek 	}
40623e07920fSDavid van Moolenbroek 
40633e07920fSDavid van Moolenbroek 	socks->fd = 0;	 /* num of sockets counter at start of array */
40643e07920fSDavid van Moolenbroek 	s = socks + 1;
40653e07920fSDavid van Moolenbroek 	for (r = res; r; r = r->ai_next) {
40663e07920fSDavid van Moolenbroek 		s->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
40673e07920fSDavid van Moolenbroek 		if (s->fd < 0) {
40683e07920fSDavid van Moolenbroek 			logerror("socket() failed");
40693e07920fSDavid van Moolenbroek 			continue;
40703e07920fSDavid van Moolenbroek 		}
40713e07920fSDavid van Moolenbroek 		s->af = r->ai_family;
40723e07920fSDavid van Moolenbroek #ifdef IPV6_V6ONLY
40733e07920fSDavid van Moolenbroek 		if (r->ai_family == AF_INET6 && setsockopt(s->fd, IPPROTO_IPV6,
40743e07920fSDavid van Moolenbroek 		    IPV6_V6ONLY, &on, sizeof(on)) < 0) {
40753e07920fSDavid van Moolenbroek 			logerror("setsockopt(IPV6_V6ONLY) failed");
40763e07920fSDavid van Moolenbroek 			close(s->fd);
40773e07920fSDavid van Moolenbroek 			continue;
40783e07920fSDavid van Moolenbroek 		}
40793e07920fSDavid van Moolenbroek #endif /* IPV6_V6ONLY */
40803e07920fSDavid van Moolenbroek 
40813e07920fSDavid van Moolenbroek 		if (!SecureMode) {
40823e07920fSDavid van Moolenbroek 			if (bind(s->fd, r->ai_addr, r->ai_addrlen) < 0) {
40833e07920fSDavid van Moolenbroek 				logerror("bind() failed");
40843e07920fSDavid van Moolenbroek 				close(s->fd);
40853e07920fSDavid van Moolenbroek 				continue;
40863e07920fSDavid van Moolenbroek 			}
40873e07920fSDavid van Moolenbroek 			s->ev = allocev();
40883e07920fSDavid van Moolenbroek 			event_set(s->ev, s->fd, EV_READ | EV_PERSIST,
40893e07920fSDavid van Moolenbroek 				dispatch_read_finet, s->ev);
40903e07920fSDavid van Moolenbroek 			if (event_add(s->ev, NULL) == -1) {
40913e07920fSDavid van Moolenbroek 				DPRINTF((D_EVENT|D_NET),
40923e07920fSDavid van Moolenbroek 				    "Failure in event_add()\n");
40933e07920fSDavid van Moolenbroek 			} else {
40943e07920fSDavid van Moolenbroek 				DPRINTF((D_EVENT|D_NET),
40953e07920fSDavid van Moolenbroek 				    "Listen on UDP port "
40963e07920fSDavid van Moolenbroek 				    "(event@%p)\n", s->ev);
40973e07920fSDavid van Moolenbroek 			}
40983e07920fSDavid van Moolenbroek 		}
40993e07920fSDavid van Moolenbroek 
41003e07920fSDavid van Moolenbroek 		socks->fd++;  /* num counter */
41013e07920fSDavid van Moolenbroek 		s++;
41023e07920fSDavid van Moolenbroek 	}
41033e07920fSDavid van Moolenbroek 
41043e07920fSDavid van Moolenbroek 	if (res)
41053e07920fSDavid van Moolenbroek 		freeaddrinfo(res);
41063e07920fSDavid van Moolenbroek 	if (socks->fd == 0) {
41073e07920fSDavid van Moolenbroek 		free (socks);
41083e07920fSDavid van Moolenbroek 		if(Debug)
41093e07920fSDavid van Moolenbroek 			return NULL;
41103e07920fSDavid van Moolenbroek 		else
41113e07920fSDavid van Moolenbroek 			die(0, 0, NULL);
41123e07920fSDavid van Moolenbroek 	}
41133e07920fSDavid van Moolenbroek 	return socks;
41143e07920fSDavid van Moolenbroek }
41153e07920fSDavid van Moolenbroek 
41163e07920fSDavid van Moolenbroek /*
41173e07920fSDavid van Moolenbroek  * Fairly similar to popen(3), but returns an open descriptor, as opposed
41183e07920fSDavid van Moolenbroek  * to a FILE *.
41193e07920fSDavid van Moolenbroek  */
41203e07920fSDavid van Moolenbroek int
p_open(char * prog,pid_t * rpid)41213e07920fSDavid van Moolenbroek p_open(char *prog, pid_t *rpid)
41223e07920fSDavid van Moolenbroek {
41233e07920fSDavid van Moolenbroek 	static char sh[] = "sh", mc[] = "-c";
41243e07920fSDavid van Moolenbroek 	int pfd[2], nulldesc, i;
41253e07920fSDavid van Moolenbroek 	pid_t pid;
41263e07920fSDavid van Moolenbroek 	char *argv[4];	/* sh -c cmd NULL */
41273e07920fSDavid van Moolenbroek 
41283e07920fSDavid van Moolenbroek 	if (pipe(pfd) == -1)
41293e07920fSDavid van Moolenbroek 		return -1;
41303e07920fSDavid van Moolenbroek 	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) {
41313e07920fSDavid van Moolenbroek 		/* We are royally screwed anyway. */
41323e07920fSDavid van Moolenbroek 		return -1;
41333e07920fSDavid van Moolenbroek 	}
41343e07920fSDavid van Moolenbroek 
41353e07920fSDavid van Moolenbroek 	switch ((pid = fork())) {
41363e07920fSDavid van Moolenbroek 	case -1:
41373e07920fSDavid van Moolenbroek 		(void) close(nulldesc);
41383e07920fSDavid van Moolenbroek 		return -1;
41393e07920fSDavid van Moolenbroek 
41403e07920fSDavid van Moolenbroek 	case 0:
41413e07920fSDavid van Moolenbroek 		argv[0] = sh;
41423e07920fSDavid van Moolenbroek 		argv[1] = mc;
41433e07920fSDavid van Moolenbroek 		argv[2] = prog;
41443e07920fSDavid van Moolenbroek 		argv[3] = NULL;
41453e07920fSDavid van Moolenbroek 
41463e07920fSDavid van Moolenbroek 		(void) setsid();	/* avoid catching SIGHUPs. */
41473e07920fSDavid van Moolenbroek 
41483e07920fSDavid van Moolenbroek 		/*
41493e07920fSDavid van Moolenbroek 		 * Reset ignored signals to their default behavior.
41503e07920fSDavid van Moolenbroek 		 */
41513e07920fSDavid van Moolenbroek 		(void)signal(SIGTERM, SIG_DFL);
41523e07920fSDavid van Moolenbroek 		(void)signal(SIGINT, SIG_DFL);
41533e07920fSDavid van Moolenbroek 		(void)signal(SIGQUIT, SIG_DFL);
41543e07920fSDavid van Moolenbroek 		(void)signal(SIGPIPE, SIG_DFL);
41553e07920fSDavid van Moolenbroek 		(void)signal(SIGHUP, SIG_DFL);
41563e07920fSDavid van Moolenbroek 
41573e07920fSDavid van Moolenbroek 		dup2(pfd[0], STDIN_FILENO);
41583e07920fSDavid van Moolenbroek 		dup2(nulldesc, STDOUT_FILENO);
41593e07920fSDavid van Moolenbroek 		dup2(nulldesc, STDERR_FILENO);
41603e07920fSDavid van Moolenbroek 		for (i = getdtablesize(); i > 2; i--)
41613e07920fSDavid van Moolenbroek 			(void) close(i);
41623e07920fSDavid van Moolenbroek 
41633e07920fSDavid van Moolenbroek 		(void) execvp(_PATH_BSHELL, argv);
41643e07920fSDavid van Moolenbroek 		_exit(255);
41653e07920fSDavid van Moolenbroek 	}
41663e07920fSDavid van Moolenbroek 
41673e07920fSDavid van Moolenbroek 	(void) close(nulldesc);
41683e07920fSDavid van Moolenbroek 	(void) close(pfd[0]);
41693e07920fSDavid van Moolenbroek 
41703e07920fSDavid van Moolenbroek 	/*
41713e07920fSDavid van Moolenbroek 	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
41723e07920fSDavid van Moolenbroek 	 * supposed to get an EWOULDBLOCK on writev(2), which is
41733e07920fSDavid van Moolenbroek 	 * caught by the logic above anyway, which will in turn
41743e07920fSDavid van Moolenbroek 	 * close the pipe, and fork a new logging subprocess if
41753e07920fSDavid van Moolenbroek 	 * necessary.  The stale subprocess will be killed some
41763e07920fSDavid van Moolenbroek 	 * time later unless it terminated itself due to closing
41773e07920fSDavid van Moolenbroek 	 * its input pipe.
41783e07920fSDavid van Moolenbroek 	 */
41793e07920fSDavid van Moolenbroek 	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
41803e07920fSDavid van Moolenbroek 		/* This is bad. */
41813e07920fSDavid van Moolenbroek 		logerror("Warning: cannot change pipe to pid %d to "
41823e07920fSDavid van Moolenbroek 		    "non-blocking.", (int) pid);
41833e07920fSDavid van Moolenbroek 	}
41843e07920fSDavid van Moolenbroek 	*rpid = pid;
41853e07920fSDavid van Moolenbroek 	return pfd[1];
41863e07920fSDavid van Moolenbroek }
41873e07920fSDavid van Moolenbroek 
41883e07920fSDavid van Moolenbroek void
deadq_enter(pid_t pid,const char * name)41893e07920fSDavid van Moolenbroek deadq_enter(pid_t pid, const char *name)
41903e07920fSDavid van Moolenbroek {
41913e07920fSDavid van Moolenbroek 	dq_t p;
41923e07920fSDavid van Moolenbroek 	int status;
41933e07920fSDavid van Moolenbroek 
41943e07920fSDavid van Moolenbroek 	/*
41953e07920fSDavid van Moolenbroek 	 * Be paranoid: if we can't signal the process, don't enter it
41963e07920fSDavid van Moolenbroek 	 * into the dead queue (perhaps it's already dead).  If possible,
41973e07920fSDavid van Moolenbroek 	 * we try to fetch and log the child's status.
41983e07920fSDavid van Moolenbroek 	 */
41993e07920fSDavid van Moolenbroek 	if (kill(pid, 0) != 0) {
42003e07920fSDavid van Moolenbroek 		if (waitpid(pid, &status, WNOHANG) > 0)
42013e07920fSDavid van Moolenbroek 			log_deadchild(pid, status, name);
42023e07920fSDavid van Moolenbroek 		return;
42033e07920fSDavid van Moolenbroek 	}
42043e07920fSDavid van Moolenbroek 
42053e07920fSDavid van Moolenbroek 	p = malloc(sizeof(*p));
42063e07920fSDavid van Moolenbroek 	if (p == NULL) {
42073e07920fSDavid van Moolenbroek 		logerror("panic: out of memory!");
42083e07920fSDavid van Moolenbroek 		exit(1);
42093e07920fSDavid van Moolenbroek 	}
42103e07920fSDavid van Moolenbroek 
42113e07920fSDavid van Moolenbroek 	p->dq_pid = pid;
42123e07920fSDavid van Moolenbroek 	p->dq_timeout = DQ_TIMO_INIT;
42133e07920fSDavid van Moolenbroek 	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
42143e07920fSDavid van Moolenbroek }
42153e07920fSDavid van Moolenbroek 
42163e07920fSDavid van Moolenbroek int
deadq_remove(pid_t pid)42173e07920fSDavid van Moolenbroek deadq_remove(pid_t pid)
42183e07920fSDavid van Moolenbroek {
42193e07920fSDavid van Moolenbroek 	dq_t q;
42203e07920fSDavid van Moolenbroek 
42213e07920fSDavid van Moolenbroek 	for (q = TAILQ_FIRST(&deadq_head); q != NULL;
42223e07920fSDavid van Moolenbroek 	     q = TAILQ_NEXT(q, dq_entries)) {
42233e07920fSDavid van Moolenbroek 		if (q->dq_pid == pid) {
42243e07920fSDavid van Moolenbroek 			TAILQ_REMOVE(&deadq_head, q, dq_entries);
42253e07920fSDavid van Moolenbroek 			free(q);
42263e07920fSDavid van Moolenbroek 			return 1;
42273e07920fSDavid van Moolenbroek 		}
42283e07920fSDavid van Moolenbroek 	}
42293e07920fSDavid van Moolenbroek 	return 0;
42303e07920fSDavid van Moolenbroek }
42313e07920fSDavid van Moolenbroek 
42323e07920fSDavid van Moolenbroek void
log_deadchild(pid_t pid,int status,const char * name)42333e07920fSDavid van Moolenbroek log_deadchild(pid_t pid, int status, const char *name)
42343e07920fSDavid van Moolenbroek {
42353e07920fSDavid van Moolenbroek 	int code;
42363e07920fSDavid van Moolenbroek 	char buf[256];
42373e07920fSDavid van Moolenbroek 	const char *reason;
42383e07920fSDavid van Moolenbroek 
42393e07920fSDavid van Moolenbroek 	/* Keep strerror() struff out of logerror messages. */
42403e07920fSDavid van Moolenbroek 	errno = 0;
42413e07920fSDavid van Moolenbroek 	if (WIFSIGNALED(status)) {
42423e07920fSDavid van Moolenbroek 		reason = "due to signal";
42433e07920fSDavid van Moolenbroek 		code = WTERMSIG(status);
42443e07920fSDavid van Moolenbroek 	} else {
42453e07920fSDavid van Moolenbroek 		reason = "with status";
42463e07920fSDavid van Moolenbroek 		code = WEXITSTATUS(status);
42473e07920fSDavid van Moolenbroek 		if (code == 0)
42483e07920fSDavid van Moolenbroek 			return;
42493e07920fSDavid van Moolenbroek 	}
42503e07920fSDavid van Moolenbroek 	(void) snprintf(buf, sizeof(buf),
42513e07920fSDavid van Moolenbroek 	    "Logging subprocess %d (%s) exited %s %d.",
42523e07920fSDavid van Moolenbroek 	    pid, name, reason, code);
42533e07920fSDavid van Moolenbroek 	logerror("%s", buf);
42543e07920fSDavid van Moolenbroek }
42553e07920fSDavid van Moolenbroek 
42563e07920fSDavid van Moolenbroek struct event *
allocev(void)42573e07920fSDavid van Moolenbroek allocev(void)
42583e07920fSDavid van Moolenbroek {
42593e07920fSDavid van Moolenbroek 	struct event *ev;
42603e07920fSDavid van Moolenbroek 
42613e07920fSDavid van Moolenbroek 	if (!(ev = calloc(1, sizeof(*ev))))
42623e07920fSDavid van Moolenbroek 		logerror("Unable to allocate memory");
42633e07920fSDavid van Moolenbroek 	return ev;
42643e07920fSDavid van Moolenbroek }
42653e07920fSDavid van Moolenbroek 
42663e07920fSDavid van Moolenbroek /* *ev is allocated if necessary */
42673e07920fSDavid van Moolenbroek void
schedule_event(struct event ** ev,struct timeval * tv,void (* cb)(int,short,void *),void * arg)42683e07920fSDavid van Moolenbroek schedule_event(struct event **ev, struct timeval *tv,
42693e07920fSDavid van Moolenbroek 	void (*cb)(int, short, void *), void *arg)
42703e07920fSDavid van Moolenbroek {
42713e07920fSDavid van Moolenbroek 	if (!*ev && !(*ev = allocev())) {
42723e07920fSDavid van Moolenbroek 		return;
42733e07920fSDavid van Moolenbroek 	}
42743e07920fSDavid van Moolenbroek 	event_set(*ev, 0, 0, cb, arg);
42753e07920fSDavid van Moolenbroek 	DPRINTF(D_EVENT, "event_add(%s@%p)\n", "schedule_ev", *ev); \
42763e07920fSDavid van Moolenbroek 	if (event_add(*ev, tv) == -1) {
42773e07920fSDavid van Moolenbroek 		DPRINTF(D_EVENT, "Failure in event_add()\n");
42783e07920fSDavid van Moolenbroek 	}
42793e07920fSDavid van Moolenbroek }
42803e07920fSDavid van Moolenbroek 
42813e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
42823e07920fSDavid van Moolenbroek /* abbreviation for freeing credential lists */
42833e07920fSDavid van Moolenbroek void
free_cred_SLIST(struct peer_cred_head * head)42843e07920fSDavid van Moolenbroek free_cred_SLIST(struct peer_cred_head *head)
42853e07920fSDavid van Moolenbroek {
42863e07920fSDavid van Moolenbroek 	struct peer_cred *cred;
42873e07920fSDavid van Moolenbroek 
42883e07920fSDavid van Moolenbroek 	while (!SLIST_EMPTY(head)) {
42893e07920fSDavid van Moolenbroek 		cred = SLIST_FIRST(head);
42903e07920fSDavid van Moolenbroek 		SLIST_REMOVE_HEAD(head, entries);
42913e07920fSDavid van Moolenbroek 		FREEPTR(cred->data);
42923e07920fSDavid van Moolenbroek 		free(cred);
42933e07920fSDavid van Moolenbroek 	}
42943e07920fSDavid van Moolenbroek }
42953e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
42963e07920fSDavid van Moolenbroek 
42973e07920fSDavid van Moolenbroek /*
42983e07920fSDavid van Moolenbroek  * send message queue after reconnect
42993e07920fSDavid van Moolenbroek  */
43003e07920fSDavid van Moolenbroek /*ARGSUSED*/
43013e07920fSDavid van Moolenbroek void
send_queue(int fd,short event,void * arg)43023e07920fSDavid van Moolenbroek send_queue(int fd, short event, void *arg)
43033e07920fSDavid van Moolenbroek {
43043e07920fSDavid van Moolenbroek 	struct filed *f = (struct filed *) arg;
43053e07920fSDavid van Moolenbroek 	struct buf_queue *qentry;
43063e07920fSDavid van Moolenbroek #define SQ_CHUNK_SIZE 250
43073e07920fSDavid van Moolenbroek 	size_t cnt = 0;
43083e07920fSDavid van Moolenbroek 
43093e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
43103e07920fSDavid van Moolenbroek 	if (f->f_type == F_TLS) {
43113e07920fSDavid van Moolenbroek 		/* use a flag to prevent recursive calls to send_queue() */
43123e07920fSDavid van Moolenbroek 		if (f->f_un.f_tls.tls_conn->send_queue)
43133e07920fSDavid van Moolenbroek 			return;
43143e07920fSDavid van Moolenbroek 		else
43153e07920fSDavid van Moolenbroek 			f->f_un.f_tls.tls_conn->send_queue = true;
43163e07920fSDavid van Moolenbroek 	}
43173e07920fSDavid van Moolenbroek 	DPRINTF((D_DATA|D_CALL), "send_queue(f@%p with %zu msgs, "
43183e07920fSDavid van Moolenbroek 		"cnt@%p = %zu)\n", f, f->f_qelements, &cnt, cnt);
43193e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
43203e07920fSDavid van Moolenbroek 
43213e07920fSDavid van Moolenbroek 	while ((qentry = STAILQ_FIRST(&f->f_qhead))) {
43223e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
43233e07920fSDavid van Moolenbroek 		/* send_queue() might be called with an unconnected destination
43243e07920fSDavid van Moolenbroek 		 * from init() or die() or one message might take longer,
43253e07920fSDavid van Moolenbroek 		 * leaving the connection in state ST_WAITING and thus not
43263e07920fSDavid van Moolenbroek 		 * ready for the next message.
43273e07920fSDavid van Moolenbroek 		 * this check is a shortcut to skip these unnecessary calls */
43283e07920fSDavid van Moolenbroek 		if (f->f_type == F_TLS
43293e07920fSDavid van Moolenbroek 		    && f->f_un.f_tls.tls_conn->state != ST_TLS_EST) {
43303e07920fSDavid van Moolenbroek 			DPRINTF(D_TLS, "abort send_queue(cnt@%p = %zu) "
43313e07920fSDavid van Moolenbroek 			    "on TLS connection in state %d\n",
43323e07920fSDavid van Moolenbroek 			    &cnt, cnt, f->f_un.f_tls.tls_conn->state);
43333e07920fSDavid van Moolenbroek 			return;
43343e07920fSDavid van Moolenbroek 		 }
43353e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
43363e07920fSDavid van Moolenbroek 		fprintlog(f, qentry->msg, qentry);
43373e07920fSDavid van Moolenbroek 
43383e07920fSDavid van Moolenbroek 		/* Sending a long queue can take some time during which
43393e07920fSDavid van Moolenbroek 		 * SIGHUP and SIGALRM are blocked and no events are handled.
43403e07920fSDavid van Moolenbroek 		 * To avoid that we only send SQ_CHUNK_SIZE messages at once
43413e07920fSDavid van Moolenbroek 		 * and then reschedule ourselves to continue. Thus the control
43423e07920fSDavid van Moolenbroek 		 * will return first from all signal-protected functions so a
43433e07920fSDavid van Moolenbroek 		 * possible SIGHUP/SIGALRM is handled and then back to the
43443e07920fSDavid van Moolenbroek 		 * main loop which can handle possible input.
43453e07920fSDavid van Moolenbroek 		 */
43463e07920fSDavid van Moolenbroek 		if (++cnt >= SQ_CHUNK_SIZE) {
43473e07920fSDavid van Moolenbroek 			if (!f->f_sq_event) { /* alloc on demand */
43483e07920fSDavid van Moolenbroek 				f->f_sq_event = allocev();
43493e07920fSDavid van Moolenbroek 				event_set(f->f_sq_event, 0, 0, send_queue, f);
43503e07920fSDavid van Moolenbroek 			}
43513e07920fSDavid van Moolenbroek 			if (event_add(f->f_sq_event, &((struct timeval){0, 1})) == -1) {
43523e07920fSDavid van Moolenbroek 				DPRINTF(D_EVENT, "Failure in event_add()\n");
43533e07920fSDavid van Moolenbroek 			}
43543e07920fSDavid van Moolenbroek 			break;
43553e07920fSDavid van Moolenbroek 		}
43563e07920fSDavid van Moolenbroek 	}
43573e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
43583e07920fSDavid van Moolenbroek 	if (f->f_type == F_TLS)
43593e07920fSDavid van Moolenbroek 		f->f_un.f_tls.tls_conn->send_queue = false;
43603e07920fSDavid van Moolenbroek #endif
43613e07920fSDavid van Moolenbroek 
43623e07920fSDavid van Moolenbroek }
43633e07920fSDavid van Moolenbroek 
43643e07920fSDavid van Moolenbroek /*
43653e07920fSDavid van Moolenbroek  * finds the next queue element to delete
43663e07920fSDavid van Moolenbroek  *
43673e07920fSDavid van Moolenbroek  * has stateful behaviour, before using it call once with reset = true
43683e07920fSDavid van Moolenbroek  * after that every call will return one next queue elemen to delete,
43693e07920fSDavid van Moolenbroek  * depending on strategy either the oldest or the one with the lowest priority
43703e07920fSDavid van Moolenbroek  */
43713e07920fSDavid van Moolenbroek static struct buf_queue *
find_qentry_to_delete(const struct buf_queue_head * head,int strategy,bool reset)43723e07920fSDavid van Moolenbroek find_qentry_to_delete(const struct buf_queue_head *head, int strategy,
43733e07920fSDavid van Moolenbroek     bool reset)
43743e07920fSDavid van Moolenbroek {
43753e07920fSDavid van Moolenbroek 	static int pri;
43763e07920fSDavid van Moolenbroek 	static struct buf_queue *qentry_static;
43773e07920fSDavid van Moolenbroek 
43783e07920fSDavid van Moolenbroek 	struct buf_queue *qentry_tmp;
43793e07920fSDavid van Moolenbroek 
43803e07920fSDavid van Moolenbroek 	if (reset || STAILQ_EMPTY(head)) {
43813e07920fSDavid van Moolenbroek 		pri = LOG_DEBUG;
43823e07920fSDavid van Moolenbroek 		qentry_static = STAILQ_FIRST(head);
43833e07920fSDavid van Moolenbroek 		return NULL;
43843e07920fSDavid van Moolenbroek 	}
43853e07920fSDavid van Moolenbroek 
43863e07920fSDavid van Moolenbroek 	/* find elements to delete */
43873e07920fSDavid van Moolenbroek 	if (strategy == PURGE_BY_PRIORITY) {
43883e07920fSDavid van Moolenbroek 		qentry_tmp = qentry_static;
43893e07920fSDavid van Moolenbroek 		if (!qentry_tmp) return NULL;
43903e07920fSDavid van Moolenbroek 		while ((qentry_tmp = STAILQ_NEXT(qentry_tmp, entries)) != NULL)
43913e07920fSDavid van Moolenbroek 		{
43923e07920fSDavid van Moolenbroek 			if (LOG_PRI(qentry_tmp->msg->pri) == pri) {
43933e07920fSDavid van Moolenbroek 				/* save the successor, because qentry_tmp
43943e07920fSDavid van Moolenbroek 				 * is probably deleted by the caller */
43953e07920fSDavid van Moolenbroek 				qentry_static = STAILQ_NEXT(qentry_tmp, entries);
43963e07920fSDavid van Moolenbroek 				return qentry_tmp;
43973e07920fSDavid van Moolenbroek 			}
43983e07920fSDavid van Moolenbroek 		}
43993e07920fSDavid van Moolenbroek 		/* nothing found in while loop --> next pri */
44003e07920fSDavid van Moolenbroek 		if (--pri)
44013e07920fSDavid van Moolenbroek 			return find_qentry_to_delete(head, strategy, false);
44023e07920fSDavid van Moolenbroek 		else
44033e07920fSDavid van Moolenbroek 			return NULL;
44043e07920fSDavid van Moolenbroek 	} else /* strategy == PURGE_OLDEST or other value */ {
44053e07920fSDavid van Moolenbroek 		qentry_tmp = qentry_static;
44063e07920fSDavid van Moolenbroek 		qentry_static = STAILQ_NEXT(qentry_tmp, entries);
44073e07920fSDavid van Moolenbroek 		return qentry_tmp;  /* is NULL on empty queue */
44083e07920fSDavid van Moolenbroek 	}
44093e07920fSDavid van Moolenbroek }
44103e07920fSDavid van Moolenbroek 
44113e07920fSDavid van Moolenbroek /* note on TAILQ: newest message added at TAIL,
44123e07920fSDavid van Moolenbroek  *		  oldest to be removed is FIRST
44133e07920fSDavid van Moolenbroek  */
44143e07920fSDavid van Moolenbroek /*
44153e07920fSDavid van Moolenbroek  * checks length of a destination's message queue
44163e07920fSDavid van Moolenbroek  * if del_entries == 0 then assert queue length is
44173e07920fSDavid van Moolenbroek  *   less or equal to configured number of queue elements
44183e07920fSDavid van Moolenbroek  * otherwise del_entries tells how many entries to delete
44193e07920fSDavid van Moolenbroek  *
44203e07920fSDavid van Moolenbroek  * returns the number of removed queue elements
44213e07920fSDavid van Moolenbroek  * (which not necessarily means free'd messages)
44223e07920fSDavid van Moolenbroek  *
44233e07920fSDavid van Moolenbroek  * strategy PURGE_OLDEST to delete oldest entry, e.g. after it was resent
44243e07920fSDavid van Moolenbroek  * strategy PURGE_BY_PRIORITY to delete messages with lowest priority first,
44253e07920fSDavid van Moolenbroek  *	this is much slower but might be desirable when unsent messages have
44263e07920fSDavid van Moolenbroek  *	to be deleted, e.g. in call from domark()
44273e07920fSDavid van Moolenbroek  */
44283e07920fSDavid van Moolenbroek size_t
message_queue_purge(struct filed * f,size_t del_entries,int strategy)44293e07920fSDavid van Moolenbroek message_queue_purge(struct filed *f, size_t del_entries, int strategy)
44303e07920fSDavid van Moolenbroek {
44313e07920fSDavid van Moolenbroek 	size_t removed = 0;
44323e07920fSDavid van Moolenbroek 	struct buf_queue *qentry = NULL;
44333e07920fSDavid van Moolenbroek 
44343e07920fSDavid van Moolenbroek 	DPRINTF((D_CALL|D_BUFFER), "purge_message_queue(%p, %zu, %d) with "
44353e07920fSDavid van Moolenbroek 	    "f_qelements=%zu and f_qsize=%zu\n",
44363e07920fSDavid van Moolenbroek 	    f, del_entries, strategy,
44373e07920fSDavid van Moolenbroek 	    f->f_qelements, f->f_qsize);
44383e07920fSDavid van Moolenbroek 
44393e07920fSDavid van Moolenbroek 	/* reset state */
44403e07920fSDavid van Moolenbroek 	(void)find_qentry_to_delete(&f->f_qhead, strategy, true);
44413e07920fSDavid van Moolenbroek 
44423e07920fSDavid van Moolenbroek 	while (removed < del_entries
44433e07920fSDavid van Moolenbroek 	    || (TypeInfo[f->f_type].queue_length != -1
44443e07920fSDavid van Moolenbroek 	    && (size_t)TypeInfo[f->f_type].queue_length <= f->f_qelements)
44453e07920fSDavid van Moolenbroek 	    || (TypeInfo[f->f_type].queue_size != -1
44463e07920fSDavid van Moolenbroek 	    && (size_t)TypeInfo[f->f_type].queue_size <= f->f_qsize)) {
44473e07920fSDavid van Moolenbroek 		qentry = find_qentry_to_delete(&f->f_qhead, strategy, 0);
44483e07920fSDavid van Moolenbroek 		if (message_queue_remove(f, qentry))
44493e07920fSDavid van Moolenbroek 			removed++;
44503e07920fSDavid van Moolenbroek 		else
44513e07920fSDavid van Moolenbroek 			break;
44523e07920fSDavid van Moolenbroek 	}
44533e07920fSDavid van Moolenbroek 	return removed;
44543e07920fSDavid van Moolenbroek }
44553e07920fSDavid van Moolenbroek 
44563e07920fSDavid van Moolenbroek /* run message_queue_purge() for all destinations to free memory */
44573e07920fSDavid van Moolenbroek size_t
message_allqueues_purge(void)44583e07920fSDavid van Moolenbroek message_allqueues_purge(void)
44593e07920fSDavid van Moolenbroek {
44603e07920fSDavid van Moolenbroek 	size_t sum = 0;
44613e07920fSDavid van Moolenbroek 	struct filed *f;
44623e07920fSDavid van Moolenbroek 
44633e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next)
44643e07920fSDavid van Moolenbroek 		sum += message_queue_purge(f,
44653e07920fSDavid van Moolenbroek 		    f->f_qelements/10, PURGE_BY_PRIORITY);
44663e07920fSDavid van Moolenbroek 
44673e07920fSDavid van Moolenbroek 	DPRINTF(D_BUFFER,
44683e07920fSDavid van Moolenbroek 	    "message_allqueues_purge(): removed %zu buffer entries\n", sum);
44693e07920fSDavid van Moolenbroek 	return sum;
44703e07920fSDavid van Moolenbroek }
44713e07920fSDavid van Moolenbroek 
44723e07920fSDavid van Moolenbroek /* run message_queue_purge() for all destinations to check limits */
44733e07920fSDavid van Moolenbroek size_t
message_allqueues_check(void)44743e07920fSDavid van Moolenbroek message_allqueues_check(void)
44753e07920fSDavid van Moolenbroek {
44763e07920fSDavid van Moolenbroek 	size_t sum = 0;
44773e07920fSDavid van Moolenbroek 	struct filed *f;
44783e07920fSDavid van Moolenbroek 
44793e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next)
44803e07920fSDavid van Moolenbroek 		sum += message_queue_purge(f, 0, PURGE_BY_PRIORITY);
44813e07920fSDavid van Moolenbroek 	DPRINTF(D_BUFFER,
44823e07920fSDavid van Moolenbroek 	    "message_allqueues_check(): removed %zu buffer entries\n", sum);
44833e07920fSDavid van Moolenbroek 	return sum;
44843e07920fSDavid van Moolenbroek }
44853e07920fSDavid van Moolenbroek 
44863e07920fSDavid van Moolenbroek struct buf_msg *
buf_msg_new(const size_t len)44873e07920fSDavid van Moolenbroek buf_msg_new(const size_t len)
44883e07920fSDavid van Moolenbroek {
44893e07920fSDavid van Moolenbroek 	struct buf_msg *newbuf;
44903e07920fSDavid van Moolenbroek 
44913e07920fSDavid van Moolenbroek 	CALLOC(newbuf, sizeof(*newbuf));
44923e07920fSDavid van Moolenbroek 
44933e07920fSDavid van Moolenbroek 	if (len) { /* len = 0 is valid */
44943e07920fSDavid van Moolenbroek 		MALLOC(newbuf->msg, len);
44953e07920fSDavid van Moolenbroek 		newbuf->msgorig = newbuf->msg;
44963e07920fSDavid van Moolenbroek 		newbuf->msgsize = len;
44973e07920fSDavid van Moolenbroek 	}
44983e07920fSDavid van Moolenbroek 	return NEWREF(newbuf);
44993e07920fSDavid van Moolenbroek }
45003e07920fSDavid van Moolenbroek 
45013e07920fSDavid van Moolenbroek void
buf_msg_free(struct buf_msg * buf)45023e07920fSDavid van Moolenbroek buf_msg_free(struct buf_msg *buf)
45033e07920fSDavid van Moolenbroek {
45043e07920fSDavid van Moolenbroek 	if (!buf)
45053e07920fSDavid van Moolenbroek 		return;
45063e07920fSDavid van Moolenbroek 
45073e07920fSDavid van Moolenbroek 	buf->refcount--;
45083e07920fSDavid van Moolenbroek 	if (buf->refcount == 0) {
45093e07920fSDavid van Moolenbroek 		FREEPTR(buf->timestamp);
45103e07920fSDavid van Moolenbroek 		/* small optimizations: the host/recvhost may point to the
45113e07920fSDavid van Moolenbroek 		 * global HostName/FQDN. of course this must not be free()d
45123e07920fSDavid van Moolenbroek 		 * same goes for appname and include_pid
45133e07920fSDavid van Moolenbroek 		 */
45143e07920fSDavid van Moolenbroek 		if (buf->recvhost != buf->host
45153e07920fSDavid van Moolenbroek 		    && buf->recvhost != LocalHostName
45163e07920fSDavid van Moolenbroek 		    && buf->recvhost != LocalFQDN
45173e07920fSDavid van Moolenbroek 		    && buf->recvhost != oldLocalFQDN)
45183e07920fSDavid van Moolenbroek 			FREEPTR(buf->recvhost);
45193e07920fSDavid van Moolenbroek 		if (buf->host != LocalHostName
45203e07920fSDavid van Moolenbroek 		    && buf->host != LocalFQDN
45213e07920fSDavid van Moolenbroek 		    && buf->host != oldLocalFQDN)
45223e07920fSDavid van Moolenbroek 			FREEPTR(buf->host);
45233e07920fSDavid van Moolenbroek 		if (buf->prog != appname)
45243e07920fSDavid van Moolenbroek 			FREEPTR(buf->prog);
45253e07920fSDavid van Moolenbroek 		if (buf->pid != include_pid)
45263e07920fSDavid van Moolenbroek 			FREEPTR(buf->pid);
45273e07920fSDavid van Moolenbroek 		FREEPTR(buf->msgid);
45283e07920fSDavid van Moolenbroek 		FREEPTR(buf->sd);
45293e07920fSDavid van Moolenbroek 		FREEPTR(buf->msgorig);	/* instead of msg */
45303e07920fSDavid van Moolenbroek 		FREEPTR(buf);
45313e07920fSDavid van Moolenbroek 	}
45323e07920fSDavid van Moolenbroek }
45333e07920fSDavid van Moolenbroek 
45343e07920fSDavid van Moolenbroek size_t
buf_queue_obj_size(struct buf_queue * qentry)45353e07920fSDavid van Moolenbroek buf_queue_obj_size(struct buf_queue *qentry)
45363e07920fSDavid van Moolenbroek {
45373e07920fSDavid van Moolenbroek 	size_t sum = 0;
45383e07920fSDavid van Moolenbroek 
45393e07920fSDavid van Moolenbroek 	if (!qentry)
45403e07920fSDavid van Moolenbroek 		return 0;
45413e07920fSDavid van Moolenbroek 	sum += sizeof(*qentry)
45423e07920fSDavid van Moolenbroek 	    + sizeof(*qentry->msg)
45433e07920fSDavid van Moolenbroek 	    + qentry->msg->msgsize
45443e07920fSDavid van Moolenbroek 	    + SAFEstrlen(qentry->msg->timestamp)+1
45453e07920fSDavid van Moolenbroek 	    + SAFEstrlen(qentry->msg->msgid)+1;
45463e07920fSDavid van Moolenbroek 	if (qentry->msg->prog
45473e07920fSDavid van Moolenbroek 	    && qentry->msg->prog != include_pid)
45483e07920fSDavid van Moolenbroek 		sum += strlen(qentry->msg->prog)+1;
45493e07920fSDavid van Moolenbroek 	if (qentry->msg->pid
45503e07920fSDavid van Moolenbroek 	    && qentry->msg->pid != appname)
45513e07920fSDavid van Moolenbroek 		sum += strlen(qentry->msg->pid)+1;
45523e07920fSDavid van Moolenbroek 	if (qentry->msg->recvhost
45533e07920fSDavid van Moolenbroek 	    && qentry->msg->recvhost != LocalHostName
45543e07920fSDavid van Moolenbroek 	    && qentry->msg->recvhost != LocalFQDN
45553e07920fSDavid van Moolenbroek 	    && qentry->msg->recvhost != oldLocalFQDN)
45563e07920fSDavid van Moolenbroek 		sum += strlen(qentry->msg->recvhost)+1;
45573e07920fSDavid van Moolenbroek 	if (qentry->msg->host
45583e07920fSDavid van Moolenbroek 	    && qentry->msg->host != LocalHostName
45593e07920fSDavid van Moolenbroek 	    && qentry->msg->host != LocalFQDN
45603e07920fSDavid van Moolenbroek 	    && qentry->msg->host != oldLocalFQDN)
45613e07920fSDavid van Moolenbroek 		sum += strlen(qentry->msg->host)+1;
45623e07920fSDavid van Moolenbroek 
45633e07920fSDavid van Moolenbroek 	return sum;
45643e07920fSDavid van Moolenbroek }
45653e07920fSDavid van Moolenbroek 
45663e07920fSDavid van Moolenbroek bool
message_queue_remove(struct filed * f,struct buf_queue * qentry)45673e07920fSDavid van Moolenbroek message_queue_remove(struct filed *f, struct buf_queue *qentry)
45683e07920fSDavid van Moolenbroek {
45693e07920fSDavid van Moolenbroek 	if (!f || !qentry || !qentry->msg)
45703e07920fSDavid van Moolenbroek 		return false;
45713e07920fSDavid van Moolenbroek 
45723e07920fSDavid van Moolenbroek 	assert(!STAILQ_EMPTY(&f->f_qhead));
45733e07920fSDavid van Moolenbroek 	STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries);
45743e07920fSDavid van Moolenbroek 	f->f_qelements--;
45753e07920fSDavid van Moolenbroek 	f->f_qsize -= buf_queue_obj_size(qentry);
45763e07920fSDavid van Moolenbroek 
45773e07920fSDavid van Moolenbroek 	DPRINTF(D_BUFFER, "msg @%p removed from queue @%p, new qlen = %zu\n",
45783e07920fSDavid van Moolenbroek 	    qentry->msg, f, f->f_qelements);
45793e07920fSDavid van Moolenbroek 	DELREF(qentry->msg);
45803e07920fSDavid van Moolenbroek 	FREEPTR(qentry);
45813e07920fSDavid van Moolenbroek 	return true;
45823e07920fSDavid van Moolenbroek }
45833e07920fSDavid van Moolenbroek 
45843e07920fSDavid van Moolenbroek /*
45853e07920fSDavid van Moolenbroek  * returns *qentry on success and NULL on error
45863e07920fSDavid van Moolenbroek  */
45873e07920fSDavid van Moolenbroek struct buf_queue *
message_queue_add(struct filed * f,struct buf_msg * buffer)45883e07920fSDavid van Moolenbroek message_queue_add(struct filed *f, struct buf_msg *buffer)
45893e07920fSDavid van Moolenbroek {
45903e07920fSDavid van Moolenbroek 	struct buf_queue *qentry;
45913e07920fSDavid van Moolenbroek 
45923e07920fSDavid van Moolenbroek 	/* check on every call or only every n-th time? */
45933e07920fSDavid van Moolenbroek 	message_queue_purge(f, 0, PURGE_BY_PRIORITY);
45943e07920fSDavid van Moolenbroek 
45953e07920fSDavid van Moolenbroek 	while (!(qentry = malloc(sizeof(*qentry)))
45963e07920fSDavid van Moolenbroek 	    && message_queue_purge(f, 1, PURGE_OLDEST))
45973e07920fSDavid van Moolenbroek 		continue;
45983e07920fSDavid van Moolenbroek 	if (!qentry) {
45993e07920fSDavid van Moolenbroek 		logerror("Unable to allocate memory");
46003e07920fSDavid van Moolenbroek 		DPRINTF(D_BUFFER, "queue empty, no memory, msg dropped\n");
46013e07920fSDavid van Moolenbroek 		return NULL;
46023e07920fSDavid van Moolenbroek 	} else {
46033e07920fSDavid van Moolenbroek 		qentry->msg = buffer;
46043e07920fSDavid van Moolenbroek 		f->f_qelements++;
46053e07920fSDavid van Moolenbroek 		f->f_qsize += buf_queue_obj_size(qentry);
46063e07920fSDavid van Moolenbroek 		STAILQ_INSERT_TAIL(&f->f_qhead, qentry, entries);
46073e07920fSDavid van Moolenbroek 
46083e07920fSDavid van Moolenbroek 		DPRINTF(D_BUFFER, "msg @%p queued @%p, qlen = %zu\n",
46093e07920fSDavid van Moolenbroek 		    buffer, f, f->f_qelements);
46103e07920fSDavid van Moolenbroek 		return qentry;
46113e07920fSDavid van Moolenbroek 	}
46123e07920fSDavid van Moolenbroek }
46133e07920fSDavid van Moolenbroek 
46143e07920fSDavid van Moolenbroek void
message_queue_freeall(struct filed * f)46153e07920fSDavid van Moolenbroek message_queue_freeall(struct filed *f)
46163e07920fSDavid van Moolenbroek {
46173e07920fSDavid van Moolenbroek 	struct buf_queue *qentry;
46183e07920fSDavid van Moolenbroek 
46193e07920fSDavid van Moolenbroek 	if (!f) return;
46203e07920fSDavid van Moolenbroek 	DPRINTF(D_MEM, "message_queue_freeall(f@%p) with f_qhead@%p\n", f,
46213e07920fSDavid van Moolenbroek 	    &f->f_qhead);
46223e07920fSDavid van Moolenbroek 
46233e07920fSDavid van Moolenbroek 	while (!STAILQ_EMPTY(&f->f_qhead)) {
46243e07920fSDavid van Moolenbroek 		qentry = STAILQ_FIRST(&f->f_qhead);
46253e07920fSDavid van Moolenbroek 		STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries);
46263e07920fSDavid van Moolenbroek 		DELREF(qentry->msg);
46273e07920fSDavid van Moolenbroek 		FREEPTR(qentry);
46283e07920fSDavid van Moolenbroek 	}
46293e07920fSDavid van Moolenbroek 
46303e07920fSDavid van Moolenbroek 	f->f_qelements = 0;
46313e07920fSDavid van Moolenbroek 	f->f_qsize = 0;
46323e07920fSDavid van Moolenbroek }
46333e07920fSDavid van Moolenbroek 
46343e07920fSDavid van Moolenbroek #ifndef DISABLE_TLS
46353e07920fSDavid van Moolenbroek /* utility function for tls_reconnect() */
46363e07920fSDavid van Moolenbroek struct filed *
get_f_by_conninfo(struct tls_conn_settings * conn_info)46373e07920fSDavid van Moolenbroek get_f_by_conninfo(struct tls_conn_settings *conn_info)
46383e07920fSDavid van Moolenbroek {
46393e07920fSDavid van Moolenbroek 	struct filed *f;
46403e07920fSDavid van Moolenbroek 
46413e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next) {
46423e07920fSDavid van Moolenbroek 		if ((f->f_type == F_TLS) && f->f_un.f_tls.tls_conn == conn_info)
46433e07920fSDavid van Moolenbroek 			return f;
46443e07920fSDavid van Moolenbroek 	}
46453e07920fSDavid van Moolenbroek 	DPRINTF(D_TLS, "get_f_by_conninfo() called on invalid conn_info\n");
46463e07920fSDavid van Moolenbroek 	return NULL;
46473e07920fSDavid van Moolenbroek }
46483e07920fSDavid van Moolenbroek 
46493e07920fSDavid van Moolenbroek /*
46503e07920fSDavid van Moolenbroek  * Called on signal.
46513e07920fSDavid van Moolenbroek  * Lets the admin reconnect without waiting for the reconnect timer expires.
46523e07920fSDavid van Moolenbroek  */
46533e07920fSDavid van Moolenbroek /*ARGSUSED*/
46543e07920fSDavid van Moolenbroek void
dispatch_force_tls_reconnect(int fd,short event,void * ev)46553e07920fSDavid van Moolenbroek dispatch_force_tls_reconnect(int fd, short event, void *ev)
46563e07920fSDavid van Moolenbroek {
46573e07920fSDavid van Moolenbroek 	struct filed *f;
46583e07920fSDavid van Moolenbroek 	DPRINTF((D_TLS|D_CALL|D_EVENT), "dispatch_force_tls_reconnect()\n");
46593e07920fSDavid van Moolenbroek 	for (f = Files; f; f = f->f_next) {
46603e07920fSDavid van Moolenbroek 		if (f->f_type == F_TLS &&
46613e07920fSDavid van Moolenbroek 		    f->f_un.f_tls.tls_conn->state == ST_NONE)
46623e07920fSDavid van Moolenbroek 			tls_reconnect(fd, event, f->f_un.f_tls.tls_conn);
46633e07920fSDavid van Moolenbroek 	}
46643e07920fSDavid van Moolenbroek }
46653e07920fSDavid van Moolenbroek #endif /* !DISABLE_TLS */
46663e07920fSDavid van Moolenbroek 
46673e07920fSDavid van Moolenbroek /*
46683e07920fSDavid van Moolenbroek  * return a timestamp in a static buffer,
46693e07920fSDavid van Moolenbroek  * either format the timestamp given by parameter in_now
46703e07920fSDavid van Moolenbroek  * or use the current time if in_now is NULL.
46713e07920fSDavid van Moolenbroek  */
46723e07920fSDavid van Moolenbroek char *
make_timestamp(time_t * in_now,bool iso,size_t tlen)4673*0a6a1f1dSLionel Sambuc make_timestamp(time_t *in_now, bool iso, size_t tlen)
46743e07920fSDavid van Moolenbroek {
46753e07920fSDavid van Moolenbroek 	int frac_digits = 6;
46763e07920fSDavid van Moolenbroek 	struct timeval tv;
46773e07920fSDavid van Moolenbroek 	time_t mytime;
46783e07920fSDavid van Moolenbroek 	struct tm ltime;
46793e07920fSDavid van Moolenbroek 	int len = 0;
46803e07920fSDavid van Moolenbroek 	int tzlen = 0;
46813e07920fSDavid van Moolenbroek 	/* uses global var: time_t now; */
46823e07920fSDavid van Moolenbroek 
46833e07920fSDavid van Moolenbroek 	if (in_now) {
46843e07920fSDavid van Moolenbroek 		mytime = *in_now;
46853e07920fSDavid van Moolenbroek 	} else {
46863e07920fSDavid van Moolenbroek 		gettimeofday(&tv, NULL);
4687*0a6a1f1dSLionel Sambuc 		mytime = now = tv.tv_sec;
46883e07920fSDavid van Moolenbroek 	}
46893e07920fSDavid van Moolenbroek 
46903e07920fSDavid van Moolenbroek 	if (!iso) {
4691*0a6a1f1dSLionel Sambuc 		strlcpy(timestamp, ctime(&mytime) + 4, sizeof(timestamp));
46923e07920fSDavid van Moolenbroek 		timestamp[BSD_TIMESTAMPLEN] = '\0';
4693*0a6a1f1dSLionel Sambuc 	} else {
46943e07920fSDavid van Moolenbroek 		localtime_r(&mytime, &ltime);
4695*0a6a1f1dSLionel Sambuc 		len += strftime(timestamp, sizeof(timestamp), "%FT%T", &ltime);
4696*0a6a1f1dSLionel Sambuc 		snprintf(&timestamp[len], frac_digits + 2, ".%.*jd",
4697*0a6a1f1dSLionel Sambuc 		    frac_digits, (intmax_t)tv.tv_usec);
46983e07920fSDavid van Moolenbroek 		len += frac_digits + 1;
4699*0a6a1f1dSLionel Sambuc 		tzlen = strftime(&timestamp[len], sizeof(timestamp) - len, "%z",
4700*0a6a1f1dSLionel Sambuc 		    &ltime);
47013e07920fSDavid van Moolenbroek 		len += tzlen;
47023e07920fSDavid van Moolenbroek 
47033e07920fSDavid van Moolenbroek 		if (tzlen == 5) {
47043e07920fSDavid van Moolenbroek 			/* strftime gives "+0200", but we need "+02:00" */
4705*0a6a1f1dSLionel Sambuc 			timestamp[len + 2] = '\0';
47063e07920fSDavid van Moolenbroek 			timestamp[len + 1] = timestamp[len];
47073e07920fSDavid van Moolenbroek 			timestamp[len] = timestamp[len - 1];
47083e07920fSDavid van Moolenbroek 			timestamp[len - 1] = timestamp[len - 2];
47093e07920fSDavid van Moolenbroek 			timestamp[len - 2] = ':';
47103e07920fSDavid van Moolenbroek 		}
4711*0a6a1f1dSLionel Sambuc 	}
4712*0a6a1f1dSLionel Sambuc 
4713*0a6a1f1dSLionel Sambuc 	switch (tlen) {
4714*0a6a1f1dSLionel Sambuc 	case (size_t)-1:
47153e07920fSDavid van Moolenbroek 		return timestamp;
4716*0a6a1f1dSLionel Sambuc 	case 0:
4717*0a6a1f1dSLionel Sambuc 		return strdup(timestamp);
4718*0a6a1f1dSLionel Sambuc 	default:
4719*0a6a1f1dSLionel Sambuc 		return strndup(timestamp, tlen);
4720*0a6a1f1dSLionel Sambuc 	}
47213e07920fSDavid van Moolenbroek }
47223e07920fSDavid van Moolenbroek 
47233e07920fSDavid van Moolenbroek /* auxillary code to allocate memory and copy a string */
47243e07920fSDavid van Moolenbroek bool
copy_string(char ** mem,const char * p,const char * q)47253e07920fSDavid van Moolenbroek copy_string(char **mem, const char *p, const char *q)
47263e07920fSDavid van Moolenbroek {
47273e07920fSDavid van Moolenbroek 	const size_t len = 1 + q - p;
47283e07920fSDavid van Moolenbroek 	if (!(*mem = malloc(len))) {
47293e07920fSDavid van Moolenbroek 		logerror("Unable to allocate memory for config");
47303e07920fSDavid van Moolenbroek 		return false;
47313e07920fSDavid van Moolenbroek 	}
47323e07920fSDavid van Moolenbroek 	strlcpy(*mem, p, len);
47333e07920fSDavid van Moolenbroek 	return true;
47343e07920fSDavid van Moolenbroek }
47353e07920fSDavid van Moolenbroek 
47363e07920fSDavid van Moolenbroek /* keyword has to end with ",  everything until next " is copied */
47373e07920fSDavid van Moolenbroek bool
copy_config_value_quoted(const char * keyword,char ** mem,const char ** p)47383e07920fSDavid van Moolenbroek copy_config_value_quoted(const char *keyword, char **mem, const char **p)
47393e07920fSDavid van Moolenbroek {
47403e07920fSDavid van Moolenbroek 	const char *q;
47413e07920fSDavid van Moolenbroek 	if (strncasecmp(*p, keyword, strlen(keyword)))
47423e07920fSDavid van Moolenbroek 		return false;
47433e07920fSDavid van Moolenbroek 	q = *p += strlen(keyword);
47443e07920fSDavid van Moolenbroek 	if (!(q = strchr(*p, '"'))) {
47453e07920fSDavid van Moolenbroek 		errno = 0;
47463e07920fSDavid van Moolenbroek 		logerror("unterminated \"\n");
47473e07920fSDavid van Moolenbroek 		return false;
47483e07920fSDavid van Moolenbroek 	}
47493e07920fSDavid van Moolenbroek 	if (!(copy_string(mem, *p, q)))
47503e07920fSDavid van Moolenbroek 		return false;
47513e07920fSDavid van Moolenbroek 	*p = ++q;
47523e07920fSDavid van Moolenbroek 	return true;
47533e07920fSDavid van Moolenbroek }
47543e07920fSDavid van Moolenbroek 
47553e07920fSDavid van Moolenbroek /* for config file:
47563e07920fSDavid van Moolenbroek  * following = required but whitespace allowed, quotes optional
47573e07920fSDavid van Moolenbroek  * if numeric, then conversion to integer and no memory allocation
47583e07920fSDavid van Moolenbroek  */
47593e07920fSDavid van Moolenbroek bool
copy_config_value(const char * keyword,char ** mem,const char ** p,const char * file,int line)47603e07920fSDavid van Moolenbroek copy_config_value(const char *keyword, char **mem,
47613e07920fSDavid van Moolenbroek 	const char **p, const char *file, int line)
47623e07920fSDavid van Moolenbroek {
47633e07920fSDavid van Moolenbroek 	if (strncasecmp(*p, keyword, strlen(keyword)))
47643e07920fSDavid van Moolenbroek 		return false;
47653e07920fSDavid van Moolenbroek 	*p += strlen(keyword);
47663e07920fSDavid van Moolenbroek 
47673e07920fSDavid van Moolenbroek 	while (isspace((unsigned char)**p))
47683e07920fSDavid van Moolenbroek 		*p += 1;
47693e07920fSDavid van Moolenbroek 	if (**p != '=') {
47703e07920fSDavid van Moolenbroek 		errno = 0;
47713e07920fSDavid van Moolenbroek 		logerror("expected \"=\" in file %s, line %d", file, line);
47723e07920fSDavid van Moolenbroek 		return false;
47733e07920fSDavid van Moolenbroek 	}
47743e07920fSDavid van Moolenbroek 	*p += 1;
47753e07920fSDavid van Moolenbroek 
47763e07920fSDavid van Moolenbroek 	return copy_config_value_word(mem, p);
47773e07920fSDavid van Moolenbroek }
47783e07920fSDavid van Moolenbroek 
47793e07920fSDavid van Moolenbroek /* copy next parameter from a config line */
47803e07920fSDavid van Moolenbroek bool
copy_config_value_word(char ** mem,const char ** p)47813e07920fSDavid van Moolenbroek copy_config_value_word(char **mem, const char **p)
47823e07920fSDavid van Moolenbroek {
47833e07920fSDavid van Moolenbroek 	const char *q;
47843e07920fSDavid van Moolenbroek 	while (isspace((unsigned char)**p))
47853e07920fSDavid van Moolenbroek 		*p += 1;
47863e07920fSDavid van Moolenbroek 	if (**p == '"')
47873e07920fSDavid van Moolenbroek 		return copy_config_value_quoted("\"", mem, p);
47883e07920fSDavid van Moolenbroek 
47893e07920fSDavid van Moolenbroek 	/* without quotes: find next whitespace or end of line */
47903e07920fSDavid van Moolenbroek 	(void)((q = strchr(*p, ' ')) || (q = strchr(*p, '\t'))
47913e07920fSDavid van Moolenbroek 	     || (q = strchr(*p, '\n')) || (q = strchr(*p, '\0')));
47923e07920fSDavid van Moolenbroek 
47933e07920fSDavid van Moolenbroek 	if (q-*p == 0 || !(copy_string(mem, *p, q)))
47943e07920fSDavid van Moolenbroek 		return false;
47953e07920fSDavid van Moolenbroek 
47963e07920fSDavid van Moolenbroek 	*p = ++q;
47973e07920fSDavid van Moolenbroek 	return true;
47983e07920fSDavid van Moolenbroek }
47993e07920fSDavid van Moolenbroek 
48003e07920fSDavid van Moolenbroek static int
writev1(int fd,struct iovec * iov,size_t count)48013e07920fSDavid van Moolenbroek writev1(int fd, struct iovec *iov, size_t count)
48023e07920fSDavid van Moolenbroek {
48033e07920fSDavid van Moolenbroek 	ssize_t nw = 0, tot = 0;
48043e07920fSDavid van Moolenbroek 	size_t ntries = 5;
48053e07920fSDavid van Moolenbroek 
48063e07920fSDavid van Moolenbroek 	if (count == 0)
48073e07920fSDavid van Moolenbroek 		return 0;
48083e07920fSDavid van Moolenbroek 	while (ntries--) {
48093e07920fSDavid van Moolenbroek 		switch ((nw = writev(fd, iov, count))) {
48103e07920fSDavid van Moolenbroek 		case -1:
48113e07920fSDavid van Moolenbroek 			if (errno == EAGAIN || errno == EWOULDBLOCK) {
48123e07920fSDavid van Moolenbroek 				struct pollfd pfd;
48133e07920fSDavid van Moolenbroek 				pfd.fd = fd;
48143e07920fSDavid van Moolenbroek 				pfd.events = POLLOUT;
48153e07920fSDavid van Moolenbroek 				pfd.revents = 0;
48163e07920fSDavid van Moolenbroek 				(void)poll(&pfd, 1, 500);
48173e07920fSDavid van Moolenbroek 				continue;
48183e07920fSDavid van Moolenbroek 			}
48193e07920fSDavid van Moolenbroek 			return -1;
48203e07920fSDavid van Moolenbroek 		case 0:
48213e07920fSDavid van Moolenbroek 			return 0;
48223e07920fSDavid van Moolenbroek 		default:
48233e07920fSDavid van Moolenbroek 			tot += nw;
48243e07920fSDavid van Moolenbroek 			while (nw > 0) {
48253e07920fSDavid van Moolenbroek 				if (iov->iov_len > (size_t)nw) {
48263e07920fSDavid van Moolenbroek 					iov->iov_len -= nw;
48273e07920fSDavid van Moolenbroek 					iov->iov_base =
48283e07920fSDavid van Moolenbroek 					    (char *)iov->iov_base + nw;
48293e07920fSDavid van Moolenbroek 					break;
48303e07920fSDavid van Moolenbroek 				} else {
48313e07920fSDavid van Moolenbroek 					if (--count == 0)
48323e07920fSDavid van Moolenbroek 						return tot;
48333e07920fSDavid van Moolenbroek 					nw -= iov->iov_len;
48343e07920fSDavid van Moolenbroek 					iov++;
48353e07920fSDavid van Moolenbroek 				}
48363e07920fSDavid van Moolenbroek 			}
48373e07920fSDavid van Moolenbroek 		}
48383e07920fSDavid van Moolenbroek 	}
48393e07920fSDavid van Moolenbroek 	return tot == 0 ? nw : tot;
48403e07920fSDavid van Moolenbroek }
4841*0a6a1f1dSLionel Sambuc 
4842*0a6a1f1dSLionel Sambuc #ifndef NDEBUG
4843*0a6a1f1dSLionel Sambuc void
dbprintf(const char * fname,const char * funname,size_t lnum,const char * fmt,...)4844*0a6a1f1dSLionel Sambuc dbprintf(const char *fname, const char *funname,
4845*0a6a1f1dSLionel Sambuc     size_t lnum, const char *fmt, ...)
4846*0a6a1f1dSLionel Sambuc {
4847*0a6a1f1dSLionel Sambuc 	va_list ap;
4848*0a6a1f1dSLionel Sambuc 	char *ts;
4849*0a6a1f1dSLionel Sambuc 
4850*0a6a1f1dSLionel Sambuc 	ts = make_timestamp(NULL, true, (size_t)-1);
4851*0a6a1f1dSLionel Sambuc 	printf("%s:%s:%s:%.4zu\t", ts, fname, funname, lnum);
4852*0a6a1f1dSLionel Sambuc 
4853*0a6a1f1dSLionel Sambuc 	va_start(ap, fmt);
4854*0a6a1f1dSLionel Sambuc 	vprintf(fmt, ap);
4855*0a6a1f1dSLionel Sambuc 	va_end(ap);
4856*0a6a1f1dSLionel Sambuc }
4857*0a6a1f1dSLionel Sambuc #endif
4858