xref: /netbsd-src/usr.sbin/syslogd/syslogd.c (revision 17306b8fd0952c7489f93f0230818481e5a1e2c9)
1 /*	$NetBSD: syslogd.c,v 1.45 2001/06/08 04:16:28 mrg Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
45 #else
46 __RCSID("$NetBSD: syslogd.c,v 1.45 2001/06/08 04:16:28 mrg Exp $");
47 #endif
48 #endif /* not lint */
49 
50 /*
51  *  syslogd -- log system messages
52  *
53  * This program implements a system log. It takes a series of lines.
54  * Each line may have a priority, signified as "<n>" as
55  * the first characters of the line.  If this is
56  * not present, a default priority is used.
57  *
58  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
59  * cause it to reread its configuration file.
60  *
61  * Defined Constants:
62  *
63  * MAXLINE -- the maximimum line length that can be handled.
64  * DEFUPRI -- the default priority for user messages
65  * DEFSPRI -- the default priority for kernel messages
66  *
67  * Author: Eric Allman
68  * extensive changes by Ralph Campbell
69  * more extensive changes by Eric Allman (again)
70  */
71 
72 #define	MAXLINE		1024		/* maximum line length */
73 #define	MAXSVLINE	120		/* maximum saved line length */
74 #define DEFUPRI		(LOG_USER|LOG_NOTICE)
75 #define DEFSPRI		(LOG_KERN|LOG_CRIT)
76 #define TIMERINTVL	30		/* interval for checking flush, mark */
77 #define TTYMSGTIME	1		/* timeout passed to ttymsg */
78 
79 #include <sys/param.h>
80 #include <sys/ioctl.h>
81 #include <sys/stat.h>
82 #include <sys/wait.h>
83 #include <sys/socket.h>
84 #include <sys/msgbuf.h>
85 #include <sys/uio.h>
86 #include <sys/poll.h>
87 #include <sys/un.h>
88 #include <sys/time.h>
89 #include <sys/resource.h>
90 #include <sys/sysctl.h>
91 
92 #include <netinet/in.h>
93 #include <netdb.h>
94 #include <arpa/inet.h>
95 
96 #include <ctype.h>
97 #include <errno.h>
98 #include <fcntl.h>
99 #include <locale.h>
100 #include <setjmp.h>
101 #include <signal.h>
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include <unistd.h>
106 #include <utmp.h>
107 #include <util.h>
108 #include "pathnames.h"
109 
110 #define SYSLOG_NAMES
111 #include <sys/syslog.h>
112 
113 char	*ConfFile = _PATH_LOGCONF;
114 char	ctty[] = _PATH_CONSOLE;
115 
116 #define FDMASK(fd)	(1 << (fd))
117 
118 #define	dprintf		if (Debug) printf
119 
120 #define MAXUNAMES	20	/* maximum number of user names */
121 
122 /*
123  * Flags to logmsg().
124  */
125 
126 #define IGN_CONS	0x001	/* don't print on console */
127 #define SYNC_FILE	0x002	/* do fsync on file after printing */
128 #define ADDDATE		0x004	/* add a date to the message */
129 #define MARK		0x008	/* this message is a mark */
130 
131 /*
132  * This structure represents the files that will have log
133  * copies printed.
134  */
135 
136 struct filed {
137 	struct	filed *f_next;		/* next in linked list */
138 	short	f_type;			/* entry type, see below */
139 	short	f_file;			/* file descriptor */
140 	time_t	f_time;			/* time this was last written */
141 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
142 	union {
143 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
144 		struct {
145 			char	f_hname[MAXHOSTNAMELEN+1];
146 			struct	addrinfo *f_addr;
147 		} f_forw;		/* forwarding address */
148 		char	f_fname[MAXPATHLEN];
149 	} f_un;
150 	char	f_prevline[MAXSVLINE];		/* last message logged */
151 	char	f_lasttime[16];			/* time of last occurrence */
152 	char	f_prevhost[MAXHOSTNAMELEN+1];	/* host from which recd. */
153 	int	f_prevpri;			/* pri of f_prevline */
154 	int	f_prevlen;			/* length of f_prevline */
155 	int	f_prevcount;			/* repetition cnt of prevline */
156 	int	f_repeatcount;			/* number of "repeated" msgs */
157 };
158 
159 /*
160  * Intervals at which we flush out "message repeated" messages,
161  * in seconds after previous message is logged.  After each flush,
162  * we move to the next interval until we reach the largest.
163  */
164 int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
165 #define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
166 #define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
167 #define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
168 				 (f)->f_repeatcount = MAXREPEAT; \
169 			}
170 
171 /* values for f_type */
172 #define F_UNUSED	0		/* unused entry */
173 #define F_FILE		1		/* regular file */
174 #define F_TTY		2		/* terminal */
175 #define F_CONSOLE	3		/* console terminal */
176 #define F_FORW		4		/* remote machine */
177 #define F_USERS		5		/* list of users */
178 #define F_WALL		6		/* everyone logged on */
179 
180 char	*TypeNames[7] = {
181 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
182 	"FORW",		"USERS",	"WALL"
183 };
184 
185 struct	filed *Files;
186 struct	filed consfile;
187 
188 int	Debug;			/* debug flag */
189 char	LocalHostName[MAXHOSTNAMELEN+1];	/* our hostname */
190 char	*LocalDomain;		/* our local domain name */
191 int	*finet = NULL;			/* Internet datagram sockets */
192 int	Initialized = 0;	/* set when we have initialized ourselves */
193 int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
194 int	MarkSeq = 0;		/* mark sequence number */
195 int	SecureMode = 0;		/* listen only on unix domain socks */
196 int	UseNameService = 1;	/* make domain name queries */
197 int	NumForwards = 0;	/* number of forwarding actions in conf file */
198 char	**LogPaths;		/* array of pathnames to read messages from */
199 
200 void	cfline __P((char *, struct filed *));
201 char   *cvthname __P((struct sockaddr_storage *));
202 int	decode __P((const char *, CODE *));
203 void	die __P((int));
204 void	domark __P((int));
205 void	fprintlog __P((struct filed *, int, char *));
206 int	getmsgbufsize __P((void));
207 int*	socksetup __P((int));
208 void	init __P((int));
209 void	logerror __P((char *));
210 void	logmsg __P((int, char *, char *, int));
211 void	printline __P((char *, char *));
212 void	printsys __P((char *));
213 void	reapchild __P((int));
214 void	usage __P((void));
215 void	wallmsg __P((struct filed *, struct iovec *));
216 int	main __P((int, char *[]));
217 void	logpath_add __P((char ***, int *, int *, char *));
218 void	logpath_fileadd __P((char ***, int *, int *, char *));
219 
220 int
221 main(argc, argv)
222 	int argc;
223 	char *argv[];
224 {
225 	int ch, *funix, i, j, fklog, len, linesize;
226 	int *nfinetix, nfklogix, nfunixbaseix, nfds;
227 	int funixsize = 0, funixmaxsize = 0;
228 	struct sockaddr_un sunx, fromunix;
229 	struct sockaddr_storage frominet;
230 	char *p, *line, **pp;
231 	struct pollfd *readfds;
232 
233 	(void)setlocale(LC_ALL, "");
234 
235 	while ((ch = getopt(argc, argv, "dnsf:m:p:P:")) != -1)
236 		switch(ch) {
237 		case 'd':		/* debug */
238 			Debug++;
239 			break;
240 		case 'f':		/* configuration file */
241 			ConfFile = optarg;
242 			break;
243 		case 'm':		/* mark interval */
244 			MarkInterval = atoi(optarg) * 60;
245 			break;
246 		case 'n':		/* turn off DNS queries */
247 			UseNameService = 0;
248 			break;
249 		case 'p':		/* path */
250 			logpath_add(&LogPaths, &funixsize,
251 			    &funixmaxsize, optarg);
252 			break;
253 		case 'P':		/* file of paths */
254 			logpath_fileadd(&LogPaths, &funixsize,
255 			    &funixmaxsize, optarg);
256 			break;
257 		case 's':		/* no network listen mode */
258 			SecureMode++;
259 			break;
260 		case '?':
261 		default:
262 			usage();
263 		}
264 	if ((argc -= optind) != 0)
265 		usage();
266 
267 	if (!Debug)
268 		(void)daemon(0, 0);
269 	else
270 		setlinebuf(stdout);
271 
272 	consfile.f_type = F_CONSOLE;
273 	(void)strcpy(consfile.f_un.f_fname, ctty);
274 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
275 	LocalHostName[sizeof(LocalHostName) - 1] = '\0';
276 	if ((p = strchr(LocalHostName, '.')) != NULL) {
277 		*p++ = '\0';
278 		LocalDomain = p;
279 	} else
280 		LocalDomain = "";
281 	linesize = getmsgbufsize();
282 	if (linesize < MAXLINE)
283 		linesize = MAXLINE;
284 	linesize++;
285 	line = malloc(linesize);
286 	if (line == NULL) {
287 		logerror("couldn't allocate line buffer");
288 		die(0);
289 	}
290 	(void)signal(SIGTERM, die);
291 	(void)signal(SIGINT, Debug ? die : SIG_IGN);
292 	(void)signal(SIGQUIT, Debug ? die : SIG_IGN);
293 	(void)signal(SIGCHLD, reapchild);
294 	(void)signal(SIGALRM, domark);
295 	(void)alarm(TIMERINTVL);
296 
297 #ifndef SUN_LEN
298 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
299 #endif
300 	if (funixsize == 0)
301 		logpath_add(&LogPaths, &funixsize,
302 		    &funixmaxsize, _PATH_LOG);
303 	funix = (int *)malloc(sizeof(int) * funixsize);
304 	if (funix == NULL) {
305 		logerror("couldn't allocate funix descriptors");
306 		die(0);
307 	}
308 	for (j = 0, pp = LogPaths; *pp; pp++, j++) {
309 		dprintf("making unix dgram socket %s\n", *pp);
310 		unlink(*pp);
311 		memset(&sunx, 0, sizeof(sunx));
312 		sunx.sun_family = AF_LOCAL;
313 		(void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path));
314 		funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0);
315 		if (funix[j] < 0 || bind(funix[j],
316 		    (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
317 		    chmod(*pp, 0666) < 0) {
318 			int serrno = errno;
319 			(void)snprintf(line, sizeof line,
320 			    "cannot create %s", *pp);
321 			errno = serrno;
322 			logerror(line);
323 			errno = serrno;
324 			dprintf("cannot create %s (%d)\n", *pp, errno);
325 			die(0);
326 		}
327 		dprintf("listening on unix dgram socket %s\n", *pp);
328 	}
329 
330 	init(0);
331 
332 	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
333 		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
334 	} else {
335 		dprintf("listening on kernel log %s\n", _PATH_KLOG);
336 	}
337 
338 	/* tuck my process id away, if i'm not in debug mode */
339 	if (Debug == 0)
340 		pidfile(NULL);
341 
342 	dprintf("off & running....\n");
343 
344 	(void)signal(SIGHUP, init);
345 
346 	/* setup pollfd set. */
347 	readfds = (struct pollfd *)malloc(sizeof(struct pollfd) *
348 			(funixsize + (finet ? *finet : 0) + 1));
349 	if (readfds == NULL) {
350 		logerror("couldn't allocate pollfds");
351 		die(0);
352 	}
353 	nfds = 0;
354 	if (fklog >= 0) {
355 		nfklogix = nfds++;
356 		readfds[nfklogix].fd = fklog;
357 		readfds[nfklogix].events = POLLIN | POLLPRI;
358 	}
359 	if (finet && !SecureMode) {
360 		nfinetix = malloc(*finet * sizeof(*nfinetix));
361 		for (j = 0; j < *finet; j++) {
362 			nfinetix[j] = nfds++;
363 			readfds[nfinetix[j]].fd = finet[j+1];
364 			readfds[nfinetix[j]].events = POLLIN | POLLPRI;
365 		}
366 	}
367 	nfunixbaseix = nfds;
368 	for (j = 0, pp = LogPaths; *pp; pp++) {
369 		readfds[nfds].fd = funix[j++];
370 		readfds[nfds++].events = POLLIN | POLLPRI;
371 	}
372 
373 	for (;;) {
374 		int rv;
375 
376 		rv = poll(readfds, nfds, INFTIM);
377 		if (rv == 0)
378 			continue;
379 		if (rv < 0) {
380 			if (errno != EINTR)
381 				logerror("poll");
382 			continue;
383 		}
384 		dprintf("got a message (%d)\n", rv);
385 		if (fklog >= 0 &&
386 		    (readfds[nfklogix].revents & (POLLIN | POLLPRI))) {
387 			dprintf("kernel log active\n");
388 			i = read(fklog, line, linesize - 1);
389 			if (i > 0) {
390 				line[i] = '\0';
391 				printsys(line);
392 			} else if (i < 0 && errno != EINTR) {
393 				logerror("klog");
394 				fklog = -1;
395 			}
396 		}
397 		for (j = 0, pp = LogPaths; *pp; pp++, j++) {
398 			if ((readfds[nfunixbaseix + j].revents &
399 			    (POLLIN | POLLPRI)) == 0)
400 				continue;
401 
402 			dprintf("unix socket (%s) active\n", *pp);
403 			len = sizeof(fromunix);
404 			i = recvfrom(funix[j], line, MAXLINE, 0,
405 			    (struct sockaddr *)&fromunix, &len);
406 			if (i > 0) {
407 				line[i] = '\0';
408 				printline(LocalHostName, line);
409 			} else if (i < 0 && errno != EINTR) {
410 				char buf[MAXPATHLEN];
411 				int serrno = errno;
412 
413 				(void)snprintf(buf, sizeof buf,
414 				    "recvfrom unix %s", *pp);
415 				errno = serrno;
416 				logerror(buf);
417 			}
418 		}
419 		if (finet && !SecureMode) {
420 			for (j = 0; j < *finet; j++) {
421 		    		if (readfds[nfinetix[j]].revents &
422 				    (POLLIN | POLLPRI)) {
423 					dprintf("inet socket active\n");
424 					len = sizeof(frominet);
425 					i = recvfrom(finet[j+1], line, MAXLINE,
426 					    0, (struct sockaddr *)&frominet,
427 					    &len);
428 					if (i > 0) {
429 						line[i] = '\0';
430 						printline(cvthname(&frominet),
431 						    line);
432 					} else if (i < 0 && errno != EINTR)
433 						logerror("recvfrom inet");
434 				}
435 			}
436 		}
437 	}
438 }
439 
440 void
441 usage()
442 {
443 
444 	(void)fprintf(stderr,
445 "usage: %s [-ds] [-f conffile] [-m markinterval] [-P logpathfile] [-p logpath1] [-p logpath2 ..]\n",
446 	    getprogname());
447 	exit(1);
448 }
449 
450 /*
451  * given a pointer to an array of char *'s, a pointer to it's current
452  * size and current allocated max size, and a new char * to add, add
453  * it, update everything as necessary, possibly allocating a new array
454  */
455 void
456 logpath_add(lp, szp, maxszp, new)
457 	char ***lp;
458 	int *szp;
459 	int *maxszp;
460 	char *new;
461 {
462 
463 	dprintf("adding %s to the %p logpath list\n", new, *lp);
464 	if (*szp == *maxszp) {
465 		if (*maxszp == 0) {
466 			*maxszp = 4;	/* start of with enough for now */
467 			*lp = NULL;
468 		}
469 		else
470 			*maxszp *= 2;
471 		*lp = realloc(*lp, sizeof(char *) * (*maxszp + 1));
472 		if (*lp == NULL) {
473 			logerror("couldn't allocate line buffer");
474 			die(0);
475 		}
476 	}
477 	(*lp)[(*szp)++] = new;
478 	(*lp)[(*szp)] = NULL;		/* always keep it NULL terminated */
479 }
480 
481 /* do a file of log sockets */
482 void
483 logpath_fileadd(lp, szp, maxszp, file)
484 	char ***lp;
485 	int *szp;
486 	int *maxszp;
487 	char *file;
488 {
489 	FILE *fp;
490 	char *line;
491 	size_t len;
492 
493 	fp = fopen(file, "r");
494 	if (fp == NULL) {
495 		int serrno = errno;
496 
497 		dprintf("can't open %s (%d)\n", file, errno);
498 		errno = serrno;
499 		logerror("could not open socket file list");
500 		die(0);
501 	}
502 
503 	while ((line = fgetln(fp, &len))) {
504 		line[len - 1] = 0;
505 		logpath_add(lp, szp, maxszp, line);
506 	}
507 	fclose(fp);
508 }
509 
510 /*
511  * Take a raw input line, decode the message, and print the message
512  * on the appropriate log files.
513  */
514 void
515 printline(hname, msg)
516 	char *hname;
517 	char *msg;
518 {
519 	int c, pri;
520 	char *p, *q, line[MAXLINE + 1];
521 
522 	/* test for special codes */
523 	pri = DEFUPRI;
524 	p = msg;
525 	if (*p == '<') {
526 		pri = 0;
527 		while (isdigit(*++p))
528 			pri = 10 * pri + (*p - '0');
529 		if (*p == '>')
530 			++p;
531 	}
532 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
533 		pri = DEFUPRI;
534 
535 	/* don't allow users to log kernel messages */
536 	if (LOG_FAC(pri) == LOG_KERN)
537 		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
538 
539 	q = line;
540 
541 	while ((c = *p++) != '\0' &&
542 	    q < &line[sizeof(line) - 2]) {
543 		c &= 0177;
544 		if (iscntrl(c))
545 			if (c == '\n')
546 				*q++ = ' ';
547 			else if (c == '\t')
548 				*q++ = '\t';
549 			else {
550 				*q++ = '^';
551 				*q++ = c ^ 0100;
552 			}
553 		else
554 			*q++ = c;
555 	}
556 	*q = '\0';
557 
558 	logmsg(pri, line, hname, 0);
559 }
560 
561 /*
562  * Take a raw input line from /dev/klog, split and format similar to syslog().
563  */
564 void
565 printsys(msg)
566 	char *msg;
567 {
568 	int c, pri, flags;
569 	char *lp, *p, *q, line[MAXLINE + 1];
570 
571 	(void)strcpy(line, _PATH_UNIX);
572 	(void)strcat(line, ": ");
573 	lp = line + strlen(line);
574 	for (p = msg; *p != '\0'; ) {
575 		flags = SYNC_FILE | ADDDATE;	/* fsync file after write */
576 		pri = DEFSPRI;
577 		if (*p == '<') {
578 			pri = 0;
579 			while (isdigit(*++p))
580 				pri = 10 * pri + (*p - '0');
581 			if (*p == '>')
582 				++p;
583 		} else {
584 			/* kernel printf's come out on console */
585 			flags |= IGN_CONS;
586 		}
587 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
588 			pri = DEFSPRI;
589 		q = lp;
590 		while (*p != '\0' && (c = *p++) != '\n' &&
591 		    q < &line[MAXLINE])
592 			*q++ = c;
593 		*q = '\0';
594 		logmsg(pri, line, LocalHostName, flags);
595 	}
596 }
597 
598 time_t	now;
599 
600 /*
601  * Log a message to the appropriate log files, users, etc. based on
602  * the priority.
603  */
604 void
605 logmsg(pri, msg, from, flags)
606 	int pri;
607 	char *msg, *from;
608 	int flags;
609 {
610 	struct filed *f;
611 	int fac, msglen, omask, prilev;
612 	char *timestamp;
613 
614 	dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n",
615 	    pri, flags, from, msg);
616 
617 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
618 
619 	/*
620 	 * Check to see if msg looks non-standard.
621 	 */
622 	msglen = strlen(msg);
623 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
624 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
625 		flags |= ADDDATE;
626 
627 	(void)time(&now);
628 	if (flags & ADDDATE)
629 		timestamp = ctime(&now) + 4;
630 	else {
631 		timestamp = msg;
632 		msg += 16;
633 		msglen -= 16;
634 	}
635 
636 	/* extract facility and priority level */
637 	if (flags & MARK)
638 		fac = LOG_NFACILITIES;
639 	else
640 		fac = LOG_FAC(pri);
641 	prilev = LOG_PRI(pri);
642 
643 	/* log the message to the particular outputs */
644 	if (!Initialized) {
645 		f = &consfile;
646 		f->f_file = open(ctty, O_WRONLY, 0);
647 
648 		if (f->f_file >= 0) {
649 			fprintlog(f, flags, msg);
650 			(void)close(f->f_file);
651 		}
652 		(void)sigsetmask(omask);
653 		return;
654 	}
655 	for (f = Files; f; f = f->f_next) {
656 		/* skip messages that are incorrect priority */
657 		if (f->f_pmask[fac] < prilev ||
658 		    f->f_pmask[fac] == INTERNAL_NOPRI)
659 			continue;
660 
661 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
662 			continue;
663 
664 		/* don't output marks to recently written files */
665 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
666 			continue;
667 
668 		/*
669 		 * suppress duplicate lines to this file
670 		 */
671 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
672 		    !strcmp(msg, f->f_prevline) &&
673 		    !strcmp(from, f->f_prevhost)) {
674 			(void)strncpy(f->f_lasttime, timestamp, 15);
675 			f->f_prevcount++;
676 			dprintf("msg repeated %d times, %ld sec of %d\n",
677 			    f->f_prevcount, (long)(now - f->f_time),
678 			    repeatinterval[f->f_repeatcount]);
679 			/*
680 			 * If domark would have logged this by now,
681 			 * flush it now (so we don't hold isolated messages),
682 			 * but back off so we'll flush less often
683 			 * in the future.
684 			 */
685 			if (now > REPEATTIME(f)) {
686 				fprintlog(f, flags, (char *)NULL);
687 				BACKOFF(f);
688 			}
689 		} else {
690 			/* new line, save it */
691 			if (f->f_prevcount)
692 				fprintlog(f, 0, (char *)NULL);
693 			f->f_repeatcount = 0;
694 			f->f_prevpri = pri;
695 			(void)strncpy(f->f_lasttime, timestamp, 15);
696 			(void)strncpy(f->f_prevhost, from,
697 					sizeof(f->f_prevhost));
698 			if (msglen < MAXSVLINE) {
699 				f->f_prevlen = msglen;
700 				(void)strcpy(f->f_prevline, msg);
701 				fprintlog(f, flags, (char *)NULL);
702 			} else {
703 				f->f_prevline[0] = 0;
704 				f->f_prevlen = 0;
705 				fprintlog(f, flags, msg);
706 			}
707 		}
708 	}
709 	(void)sigsetmask(omask);
710 }
711 
712 void
713 fprintlog(f, flags, msg)
714 	struct filed *f;
715 	int flags;
716 	char *msg;
717 {
718 	struct iovec iov[6];
719 	struct iovec *v;
720 	struct addrinfo *r;
721 	int j, l, lsent;
722 	char line[MAXLINE + 1], repbuf[80], greetings[200];
723 
724 	v = iov;
725 	if (f->f_type == F_WALL) {
726 		v->iov_base = greetings;
727 		v->iov_len = snprintf(greetings, sizeof greetings,
728 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
729 		    f->f_prevhost, ctime(&now));
730 		v++;
731 		v->iov_base = "";
732 		v->iov_len = 0;
733 		v++;
734 	} else {
735 		v->iov_base = f->f_lasttime;
736 		v->iov_len = 15;
737 		v++;
738 		v->iov_base = " ";
739 		v->iov_len = 1;
740 		v++;
741 	}
742 	v->iov_base = f->f_prevhost;
743 	v->iov_len = strlen(v->iov_base);
744 	v++;
745 	v->iov_base = " ";
746 	v->iov_len = 1;
747 	v++;
748 
749 	if (msg) {
750 		v->iov_base = msg;
751 		v->iov_len = strlen(msg);
752 	} else if (f->f_prevcount > 1) {
753 		v->iov_base = repbuf;
754 		v->iov_len = snprintf(repbuf, sizeof repbuf,
755 		    "last message repeated %d times", f->f_prevcount);
756 	} else {
757 		v->iov_base = f->f_prevline;
758 		v->iov_len = f->f_prevlen;
759 	}
760 	v++;
761 
762 	dprintf("Logging to %s", TypeNames[f->f_type]);
763 	f->f_time = now;
764 
765 	switch (f->f_type) {
766 	case F_UNUSED:
767 		dprintf("\n");
768 		break;
769 
770 	case F_FORW:
771 		dprintf(" %s\n", f->f_un.f_forw.f_hname);
772 			/*
773 			 * check for local vs remote messages
774 			 * (from FreeBSD PR#bin/7055)
775 			 */
776 		if (strcmp(f->f_prevhost, LocalHostName)) {
777 			l = snprintf(line, sizeof(line) - 1,
778 				     "<%d>%.15s [%s]: %s",
779 				     f->f_prevpri, (char *) iov[0].iov_base,
780 				     f->f_prevhost, (char *) iov[4].iov_base);
781 		} else {
782 			l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s",
783 				     f->f_prevpri, (char *) iov[0].iov_base,
784 				     (char *) iov[4].iov_base);
785 		}
786 		if (l > MAXLINE)
787 			l = MAXLINE;
788 		if (finet) {
789 			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
790 				for (j = 0; j < *finet; j++) {
791 #if 0
792 					/*
793 					 * should we check AF first, or just
794 					 * trial and error? FWD
795 					 */
796 					if (r->ai_family ==
797 					    address_family_of(finet[j+1]))
798 #endif
799 					lsent = sendto(finet[j+1], line, l, 0,
800 					    r->ai_addr, r->ai_addrlen);
801 					if (lsent == l)
802 						break;
803 				}
804 			}
805 			if (lsent != l) {
806 				f->f_type = F_UNUSED;
807 				logerror("sendto");
808 			}
809 		}
810 		break;
811 
812 	case F_CONSOLE:
813 		if (flags & IGN_CONS) {
814 			dprintf(" (ignored)\n");
815 			break;
816 		}
817 		/* FALLTHROUGH */
818 
819 	case F_TTY:
820 	case F_FILE:
821 		dprintf(" %s\n", f->f_un.f_fname);
822 		if (f->f_type != F_FILE) {
823 			v->iov_base = "\r\n";
824 			v->iov_len = 2;
825 		} else {
826 			v->iov_base = "\n";
827 			v->iov_len = 1;
828 		}
829 	again:
830 		if (writev(f->f_file, iov, 6) < 0) {
831 			int e = errno;
832 			(void)close(f->f_file);
833 			/*
834 			 * Check for errors on TTY's due to loss of tty
835 			 */
836 			if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
837 				f->f_file = open(f->f_un.f_fname,
838 				    O_WRONLY|O_APPEND, 0);
839 				if (f->f_file < 0) {
840 					f->f_type = F_UNUSED;
841 					logerror(f->f_un.f_fname);
842 				} else
843 					goto again;
844 			} else {
845 				f->f_type = F_UNUSED;
846 				errno = e;
847 				logerror(f->f_un.f_fname);
848 			}
849 		} else if (flags & SYNC_FILE)
850 			(void)fsync(f->f_file);
851 		break;
852 
853 	case F_USERS:
854 	case F_WALL:
855 		dprintf("\n");
856 		v->iov_base = "\r\n";
857 		v->iov_len = 2;
858 		wallmsg(f, iov);
859 		break;
860 	}
861 	f->f_prevcount = 0;
862 }
863 
864 /*
865  *  WALLMSG -- Write a message to the world at large
866  *
867  *	Write the specified message to either the entire
868  *	world, or a list of approved users.
869  */
870 void
871 wallmsg(f, iov)
872 	struct filed *f;
873 	struct iovec *iov;
874 {
875 	static int reenter;			/* avoid calling ourselves */
876 	FILE *uf;
877 	struct utmp ut;
878 	int i;
879 	char *p;
880 	char line[sizeof(ut.ut_line) + 1];
881 
882 	if (reenter++)
883 		return;
884 	if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
885 		logerror(_PATH_UTMP);
886 		reenter = 0;
887 		return;
888 	}
889 	/* NOSTRICT */
890 	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
891 		if (ut.ut_name[0] == '\0')
892 			continue;
893 		strncpy(line, ut.ut_line, sizeof(ut.ut_line));
894 		line[sizeof(ut.ut_line)] = '\0';
895 		if (f->f_type == F_WALL) {
896 			if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
897 				errno = 0;	/* already in msg */
898 				logerror(p);
899 			}
900 			continue;
901 		}
902 		/* should we send the message to this user? */
903 		for (i = 0; i < MAXUNAMES; i++) {
904 			if (!f->f_un.f_uname[i][0])
905 				break;
906 			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
907 			    UT_NAMESIZE)) {
908 				if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
909 								!= NULL) {
910 					errno = 0;	/* already in msg */
911 					logerror(p);
912 				}
913 				break;
914 			}
915 		}
916 	}
917 	(void)fclose(uf);
918 	reenter = 0;
919 }
920 
921 void
922 reapchild(signo)
923 	int signo;
924 {
925 	union wait status;
926 
927 	while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0)
928 		;
929 }
930 
931 /*
932  * Return a printable representation of a host address.
933  */
934 char *
935 cvthname(f)
936 	struct sockaddr_storage *f;
937 {
938 	int error;
939 	char *p;
940 #ifdef KAME_SCOPEID
941 	const int niflag = NI_DGRAM | NI_WITHSCOPEID;
942 #else
943 	const int niflag = NI_DGRAM;
944 #endif
945 	static char host[NI_MAXHOST], ip[NI_MAXHOST];
946 
947 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
948 			ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag);
949 
950 	dprintf("cvthname(%s)\n", ip);
951 
952 	if (error) {
953 		dprintf("Malformed from address %s\n", gai_strerror(error));
954 		return ("???");
955 	}
956 
957 	if (!UseNameService)
958 		return (ip);
959 
960 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
961 			host, sizeof host, NULL, 0, niflag);
962 	if (error) {
963 		dprintf("Host name for your address (%s) unknown\n", ip);
964 		return (ip);
965 	}
966 	if ((p = strchr(host, '.')) && strcmp(p + 1, LocalDomain) == 0)
967 		*p = '\0';
968 	return (host);
969 }
970 
971 void
972 domark(signo)
973 	int signo;
974 {
975 	struct filed *f;
976 
977 	now = time((time_t *)NULL);
978 	MarkSeq += TIMERINTVL;
979 	if (MarkSeq >= MarkInterval) {
980 		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
981 		MarkSeq = 0;
982 	}
983 
984 	for (f = Files; f; f = f->f_next) {
985 		if (f->f_prevcount && now >= REPEATTIME(f)) {
986 			dprintf("flush %s: repeated %d times, %d sec.\n",
987 			    TypeNames[f->f_type], f->f_prevcount,
988 			    repeatinterval[f->f_repeatcount]);
989 			fprintlog(f, 0, (char *)NULL);
990 			BACKOFF(f);
991 		}
992 	}
993 	(void)alarm(TIMERINTVL);
994 }
995 
996 /*
997  * Print syslogd errors some place.
998  */
999 void
1000 logerror(type)
1001 	char *type;
1002 {
1003 	char buf[100];
1004 
1005 	if (errno)
1006 		(void)snprintf(buf,
1007 		    sizeof(buf), "syslogd: %s: %s", type, strerror(errno));
1008 	else
1009 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
1010 	errno = 0;
1011 	dprintf("%s\n", buf);
1012 	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1013 }
1014 
1015 void
1016 die(signo)
1017 	int signo;
1018 {
1019 	struct filed *f;
1020 	char buf[100], **p;
1021 
1022 	for (f = Files; f != NULL; f = f->f_next) {
1023 		/* flush any pending output */
1024 		if (f->f_prevcount)
1025 			fprintlog(f, 0, (char *)NULL);
1026 	}
1027 	if (signo) {
1028 		dprintf("syslogd: exiting on signal %d\n", signo);
1029 		(void)snprintf(buf, sizeof buf, "exiting on signal %d", signo);
1030 		errno = 0;
1031 		logerror(buf);
1032 	}
1033 	for (p = LogPaths; p && *p; p++)
1034 		unlink(*p);
1035 	exit(0);
1036 }
1037 
1038 /*
1039  *  INIT -- Initialize syslogd from configuration table
1040  */
1041 void
1042 init(signo)
1043 	int signo;
1044 {
1045 	int i;
1046 	FILE *cf;
1047 	struct filed *f, *next, **nextp;
1048 	char *p;
1049 	char cline[LINE_MAX];
1050 
1051 	dprintf("init\n");
1052 
1053 	/*
1054 	 *  Close all open log files.
1055 	 */
1056 	Initialized = 0;
1057 	for (f = Files; f != NULL; f = next) {
1058 		/* flush any pending output */
1059 		if (f->f_prevcount)
1060 			fprintlog(f, 0, (char *)NULL);
1061 
1062 		switch (f->f_type) {
1063 		case F_FILE:
1064 		case F_TTY:
1065 		case F_CONSOLE:
1066 			(void)close(f->f_file);
1067 			break;
1068 		case F_FORW:
1069 			if (f->f_un.f_forw.f_addr)
1070 				freeaddrinfo(f->f_un.f_forw.f_addr);
1071 			break;
1072 		}
1073 		next = f->f_next;
1074 		free((char *)f);
1075 	}
1076 	Files = NULL;
1077 	nextp = &Files;
1078 
1079 	/*
1080 	 *  Close all open sockets
1081 	 */
1082 
1083 	if (finet) {
1084 		for (i = 0; i < *finet; i++) {
1085 			if (close(finet[i+1]) < 0) {
1086 				logerror("close");
1087 				die(0);
1088 			}
1089 		}
1090 	}
1091 
1092 	/*
1093 	 *  Reset counter of forwarding actions
1094 	 */
1095 
1096 	NumForwards=0;
1097 
1098 	/* open the configuration file */
1099 	if ((cf = fopen(ConfFile, "r")) == NULL) {
1100 		dprintf("cannot open %s\n", ConfFile);
1101 		*nextp = (struct filed *)calloc(1, sizeof(*f));
1102 		cfline("*.ERR\t/dev/console", *nextp);
1103 		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1104 		cfline("*.PANIC\t*", (*nextp)->f_next);
1105 		Initialized = 1;
1106 		return;
1107 	}
1108 
1109 	/*
1110 	 *  Foreach line in the conf table, open that file.
1111 	 */
1112 	f = NULL;
1113 	while (fgets(cline, sizeof(cline), cf) != NULL) {
1114 		/*
1115 		 * check for end-of-section, comments, strip off trailing
1116 		 * spaces and newline character.
1117 		 */
1118 		for (p = cline; isspace(*p); ++p)
1119 			continue;
1120 		if (*p == '\0' || *p == '#')
1121 			continue;
1122 		for (p = strchr(cline, '\0'); isspace(*--p);)
1123 			continue;
1124 		*++p = '\0';
1125 		f = (struct filed *)calloc(1, sizeof(*f));
1126 		*nextp = f;
1127 		nextp = &f->f_next;
1128 		cfline(cline, f);
1129 	}
1130 
1131 	/* close the configuration file */
1132 	(void)fclose(cf);
1133 
1134 	Initialized = 1;
1135 
1136 	if (Debug) {
1137 		for (f = Files; f; f = f->f_next) {
1138 			for (i = 0; i <= LOG_NFACILITIES; i++)
1139 				if (f->f_pmask[i] == INTERNAL_NOPRI)
1140 					printf("X ");
1141 				else
1142 					printf("%d ", f->f_pmask[i]);
1143 			printf("%s: ", TypeNames[f->f_type]);
1144 			switch (f->f_type) {
1145 			case F_FILE:
1146 			case F_TTY:
1147 			case F_CONSOLE:
1148 				printf("%s", f->f_un.f_fname);
1149 				break;
1150 
1151 			case F_FORW:
1152 				printf("%s", f->f_un.f_forw.f_hname);
1153 				break;
1154 
1155 			case F_USERS:
1156 				for (i = 0;
1157 				    i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1158 					printf("%s, ", f->f_un.f_uname[i]);
1159 				break;
1160 			}
1161 			printf("\n");
1162 		}
1163 	}
1164 
1165 	finet = socksetup(PF_UNSPEC);
1166 	if (finet) {
1167 		if (SecureMode) {
1168 			for (i = 0; i < *finet; i++) {
1169 				if (shutdown(finet[i+1], SHUT_RD) < 0) {
1170 					logerror("shutdown");
1171 					die(0);
1172 				}
1173 			}
1174 		} else
1175 			dprintf("listening on inet and/or inet6 socket\n");
1176 		dprintf("sending on inet and/or inet6 socket\n");
1177 	}
1178 
1179 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1180 	dprintf("syslogd: restarted\n");
1181 }
1182 
1183 /*
1184  * Crack a configuration file line
1185  */
1186 void
1187 cfline(line, f)
1188 	char *line;
1189 	struct filed *f;
1190 {
1191 	struct addrinfo hints, *res;
1192 	int    error, i, pri;
1193 	char   *bp, *p, *q;
1194 	char   buf[MAXLINE], ebuf[100];
1195 
1196 	dprintf("cfline(%s)\n", line);
1197 
1198 	errno = 0;	/* keep strerror() stuff out of logerror messages */
1199 
1200 	/* clear out file entry */
1201 	memset(f, 0, sizeof(*f));
1202 	for (i = 0; i <= LOG_NFACILITIES; i++)
1203 		f->f_pmask[i] = INTERNAL_NOPRI;
1204 
1205 	/* scan through the list of selectors */
1206 	for (p = line; *p && *p != '\t';) {
1207 
1208 		/* find the end of this facility name list */
1209 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
1210 			continue;
1211 
1212 		/* collect priority name */
1213 		for (bp = buf; *q && !strchr("\t,;", *q); )
1214 			*bp++ = *q++;
1215 		*bp = '\0';
1216 
1217 		/* skip cruft */
1218 		while (strchr(", ;", *q))
1219 			q++;
1220 
1221 		/* decode priority name */
1222 		if (*buf == '*')
1223 			pri = LOG_PRIMASK + 1;
1224 		else {
1225 			pri = decode(buf, prioritynames);
1226 			if (pri < 0) {
1227 				(void)snprintf(ebuf, sizeof ebuf,
1228 				    "unknown priority name \"%s\"", buf);
1229 				logerror(ebuf);
1230 				return;
1231 			}
1232 		}
1233 
1234 		/* scan facilities */
1235 		while (*p && !strchr("\t.;", *p)) {
1236 			for (bp = buf; *p && !strchr("\t,;.", *p); )
1237 				*bp++ = *p++;
1238 			*bp = '\0';
1239 			if (*buf == '*')
1240 				for (i = 0; i < LOG_NFACILITIES; i++)
1241 					f->f_pmask[i] = pri;
1242 			else {
1243 				i = decode(buf, facilitynames);
1244 				if (i < 0) {
1245 					(void)snprintf(ebuf, sizeof ebuf,
1246 					    "unknown facility name \"%s\"",
1247 					    buf);
1248 					logerror(ebuf);
1249 					return;
1250 				}
1251 				f->f_pmask[i >> 3] = pri;
1252 			}
1253 			while (*p == ',' || *p == ' ')
1254 				p++;
1255 		}
1256 
1257 		p = q;
1258 	}
1259 
1260 	/* skip to action part */
1261 	while (*p == '\t')
1262 		p++;
1263 
1264 	switch (*p)
1265 	{
1266 	case '@':
1267 		(void)strcpy(f->f_un.f_forw.f_hname, ++p);
1268 		memset(&hints, 0, sizeof(hints));
1269 		hints.ai_family = AF_UNSPEC;
1270 		hints.ai_socktype = SOCK_DGRAM;
1271 		hints.ai_protocol = 0;
1272 		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
1273 		    &res);
1274 		if (error) {
1275 			logerror(gai_strerror(error));
1276 			break;
1277 		}
1278 		f->f_un.f_forw.f_addr = res;
1279 		f->f_type = F_FORW;
1280 		NumForwards++;
1281 		break;
1282 
1283 	case '/':
1284 		(void)strcpy(f->f_un.f_fname, p);
1285 		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1286 			f->f_type = F_UNUSED;
1287 			logerror(p);
1288 			break;
1289 		}
1290 		if (isatty(f->f_file))
1291 			f->f_type = F_TTY;
1292 		else
1293 			f->f_type = F_FILE;
1294 		if (strcmp(p, ctty) == 0)
1295 			f->f_type = F_CONSOLE;
1296 		break;
1297 
1298 	case '*':
1299 		f->f_type = F_WALL;
1300 		break;
1301 
1302 	default:
1303 		for (i = 0; i < MAXUNAMES && *p; i++) {
1304 			for (q = p; *q && *q != ','; )
1305 				q++;
1306 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1307 			if ((q - p) > UT_NAMESIZE)
1308 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1309 			else
1310 				f->f_un.f_uname[i][q - p] = '\0';
1311 			while (*q == ',' || *q == ' ')
1312 				q++;
1313 			p = q;
1314 		}
1315 		f->f_type = F_USERS;
1316 		break;
1317 	}
1318 }
1319 
1320 
1321 /*
1322  *  Decode a symbolic name to a numeric value
1323  */
1324 int
1325 decode(name, codetab)
1326 	const char *name;
1327 	CODE *codetab;
1328 {
1329 	CODE *c;
1330 	char *p, buf[40];
1331 
1332 	if (isdigit(*name))
1333 		return (atoi(name));
1334 
1335 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1336 		if (isupper(*name))
1337 			*p = tolower(*name);
1338 		else
1339 			*p = *name;
1340 	}
1341 	*p = '\0';
1342 	for (c = codetab; c->c_name; c++)
1343 		if (!strcmp(buf, c->c_name))
1344 			return (c->c_val);
1345 
1346 	return (-1);
1347 }
1348 
1349 /*
1350  * Retrieve the size of the kernel message buffer, via sysctl.
1351  */
1352 int
1353 getmsgbufsize()
1354 {
1355 	int msgbufsize, mib[2];
1356 	size_t size;
1357 
1358 	mib[0] = CTL_KERN;
1359 	mib[1] = KERN_MSGBUFSIZE;
1360 	size = sizeof msgbufsize;
1361 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
1362 		dprintf("couldn't get kern.msgbufsize\n");
1363 		return (0);
1364 	}
1365 	return (msgbufsize);
1366 }
1367 
1368 int *
1369 socksetup(af)
1370 	int af;
1371 {
1372 	struct addrinfo hints, *res, *r;
1373 	int error, maxs, *s, *socks;
1374 
1375 	if(SecureMode && !NumForwards)
1376 		return(NULL);
1377 
1378 	memset(&hints, 0, sizeof(hints));
1379 	hints.ai_flags = AI_PASSIVE;
1380 	hints.ai_family = af;
1381 	hints.ai_socktype = SOCK_DGRAM;
1382 	error = getaddrinfo(NULL, "syslog", &hints, &res);
1383 	if (error) {
1384 		logerror(gai_strerror(error));
1385 		errno = 0;
1386 		die(0);
1387 	}
1388 
1389 	/* Count max number of sockets we may open */
1390 	for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
1391 		continue;
1392 	socks = malloc ((maxs+1) * sizeof(int));
1393 	if (!socks) {
1394 		logerror("couldn't allocate memory for sockets");
1395 		die(0);
1396 	}
1397 
1398 	*socks = 0;   /* num of sockets counter at start of array */
1399 	s = socks+1;
1400 	for (r = res; r; r = r->ai_next) {
1401 		*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
1402 		if (*s < 0) {
1403 			logerror("socket");
1404 			continue;
1405 		}
1406 		if (!SecureMode && bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
1407 			close (*s);
1408 			logerror("bind");
1409 			continue;
1410 		}
1411 
1412 		*socks = *socks + 1;
1413 		s++;
1414 	}
1415 
1416 	if (*socks == 0) {
1417 		free (socks);
1418 		if(Debug)
1419 			return(NULL);
1420 		else
1421 			die(0);
1422 	}
1423 	if (res)
1424 		freeaddrinfo(res);
1425 
1426 	return(socks);
1427 }
1428