]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/syslogd/syslogd.c
This commit was generated by cvs2svn to compensate for changes in r80357,
[FreeBSD/FreeBSD.git] / usr.sbin / syslogd / syslogd.c
1 /*
2  * Copyright (c) 1983, 1988, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)syslogd.c   8.3 (Berkeley) 4/4/94";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47
48 /*
49  *  syslogd -- log system messages
50  *
51  * This program implements a system log. It takes a series of lines.
52  * Each line may have a priority, signified as "<n>" as
53  * the first characters of the line.  If this is
54  * not present, a default priority is used.
55  *
56  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
57  * cause it to reread its configuration file.
58  *
59  * Defined Constants:
60  *
61  * MAXLINE -- the maximimum line length that can be handled.
62  * DEFUPRI -- the default priority for user messages
63  * DEFSPRI -- the default priority for kernel messages
64  *
65  * Author: Eric Allman
66  * extensive changes by Ralph Campbell
67  * more extensive changes by Eric Allman (again)
68  * Extension to log by program name as well as facility and priority
69  *   by Peter da Silva.
70  * -u and -v by Harlan Stenn.
71  * Priority comparison code by Harlan Stenn.
72  */
73
74 #define MAXLINE         1024            /* maximum line length */
75 #define MAXSVLINE       120             /* maximum saved line length */
76 #define DEFUPRI         (LOG_USER|LOG_NOTICE)
77 #define DEFSPRI         (LOG_KERN|LOG_CRIT)
78 #define TIMERINTVL      30              /* interval for checking flush, mark */
79 #define TTYMSGTIME      1               /* timed out passed to ttymsg */
80
81 #include <sys/param.h>
82 #include <sys/ioctl.h>
83 #include <sys/stat.h>
84 #include <sys/wait.h>
85 #include <sys/socket.h>
86 #include <sys/queue.h>
87 #include <sys/uio.h>
88 #include <sys/un.h>
89 #include <sys/time.h>
90 #include <sys/resource.h>
91 #include <sys/syslimits.h>
92 #include <paths.h>
93
94 #include <netinet/in.h>
95 #include <netdb.h>
96 #include <arpa/inet.h>
97
98 #include <ctype.h>
99 #include <err.h>
100 #include <errno.h>
101 #include <fcntl.h>
102 #include <setjmp.h>
103 #include <signal.h>
104 #include <stdio.h>
105 #include <stdlib.h>
106 #include <string.h>
107 #include <sysexits.h>
108 #include <unistd.h>
109 #include <utmp.h>
110 #include "pathnames.h"
111
112 #define SYSLOG_NAMES
113 #include <sys/syslog.h>
114
115 #ifdef NI_WITHSCOPEID
116 static const int withscopeid = NI_WITHSCOPEID;
117 #else
118 static const int withscopeid = 0;
119 #endif
120
121 const char      *ConfFile = _PATH_LOGCONF;
122 const char      *PidFile = _PATH_LOGPID;
123 const char      ctty[] = _PATH_CONSOLE;
124
125 #define dprintf         if (Debug) printf
126
127 #define MAXUNAMES       20      /* maximum number of user names */
128
129 #define MAXFUNIX       20
130
131 int nfunix = 1;
132 char *funixn[MAXFUNIX] = { _PATH_LOG };
133 int funix[MAXFUNIX];
134
135 /*
136  * Flags to logmsg().
137  */
138
139 #define IGN_CONS        0x001   /* don't print on console */
140 #define SYNC_FILE       0x002   /* do fsync on file after printing */
141 #define ADDDATE         0x004   /* add a date to the message */
142 #define MARK            0x008   /* this message is a mark */
143 #define ISKERNEL        0x010   /* kernel generated message */
144
145 /*
146  * This structure represents the files that will have log
147  * copies printed.
148  */
149
150 struct filed {
151         struct  filed *f_next;          /* next in linked list */
152         short   f_type;                 /* entry type, see below */
153         short   f_file;                 /* file descriptor */
154         time_t  f_time;                 /* time this was last written */
155         char    *f_host;                /* host from which to recd. */
156         u_char  f_pmask[LOG_NFACILITIES+1];     /* priority mask */
157         u_char  f_pcmp[LOG_NFACILITIES+1];      /* compare priority */
158 #define PRI_LT  0x1
159 #define PRI_EQ  0x2
160 #define PRI_GT  0x4
161         char    *f_program;             /* program this applies to */
162         union {
163                 char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
164                 struct {
165                         char    f_hname[MAXHOSTNAMELEN];
166                         struct addrinfo *f_addr;
167
168                 } f_forw;               /* forwarding address */
169                 char    f_fname[MAXPATHLEN];
170                 struct {
171                         char    f_pname[MAXPATHLEN];
172                         pid_t   f_pid;
173                 } f_pipe;
174         } f_un;
175         char    f_prevline[MAXSVLINE];          /* last message logged */
176         char    f_lasttime[16];                 /* time of last occurrence */
177         char    f_prevhost[MAXHOSTNAMELEN];     /* host from which recd. */
178         int     f_prevpri;                      /* pri of f_prevline */
179         int     f_prevlen;                      /* length of f_prevline */
180         int     f_prevcount;                    /* repetition cnt of prevline */
181         int     f_repeatcount;                  /* number of "repeated" msgs */
182 };
183
184 /*
185  * Queue of about-to-be dead processes we should watch out for.
186  */
187
188 TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
189 struct stailhead *deadq_headp;
190
191 struct deadq_entry {
192         pid_t                           dq_pid;
193         int                             dq_timeout;
194         TAILQ_ENTRY(deadq_entry)        dq_entries;
195 };
196
197 /*
198  * The timeout to apply to processes waiting on the dead queue.  Unit
199  * of measure is `mark intervals', i.e. 20 minutes by default.
200  * Processes on the dead queue will be terminated after that time.
201  */
202
203 #define DQ_TIMO_INIT    2
204
205 typedef struct deadq_entry *dq_t;
206
207
208 /*
209  * Struct to hold records of network addresses that are allowed to log
210  * to us.
211  */
212 struct allowedpeer {
213         int isnumeric;
214         u_short port;
215         union {
216                 struct {
217                         struct sockaddr_storage addr;
218                         struct sockaddr_storage mask;
219                 } numeric;
220                 char *name;
221         } u;
222 #define a_addr u.numeric.addr
223 #define a_mask u.numeric.mask
224 #define a_name u.name
225 };
226
227
228 /*
229  * Intervals at which we flush out "message repeated" messages,
230  * in seconds after previous message is logged.  After each flush,
231  * we move to the next interval until we reach the largest.
232  */
233 int     repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
234 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
235 #define REPEATTIME(f)   ((f)->f_time + repeatinterval[(f)->f_repeatcount])
236 #define BACKOFF(f)      { if (++(f)->f_repeatcount > MAXREPEAT) \
237                                  (f)->f_repeatcount = MAXREPEAT; \
238                         }
239
240 /* values for f_type */
241 #define F_UNUSED        0               /* unused entry */
242 #define F_FILE          1               /* regular file */
243 #define F_TTY           2               /* terminal */
244 #define F_CONSOLE       3               /* console terminal */
245 #define F_FORW          4               /* remote machine */
246 #define F_USERS         5               /* list of users */
247 #define F_WALL          6               /* everyone logged on */
248 #define F_PIPE          7               /* pipe to program */
249
250 char    *TypeNames[8] = {
251         "UNUSED",       "FILE",         "TTY",          "CONSOLE",
252         "FORW",         "USERS",        "WALL",         "PIPE"
253 };
254
255 struct  filed *Files;
256 struct  filed consfile;
257
258 int     Debug;                  /* debug flag */
259 int     resolve = 1;            /* resolve hostname */
260 char    LocalHostName[MAXHOSTNAMELEN];  /* our hostname */
261 char    *LocalDomain;           /* our local domain name */
262 int     *finet = NULL;          /* Internet datagram socket */
263 int     fklog = -1;             /* /dev/klog */
264 int     Initialized = 0;        /* set when we have initialized ourselves */
265 int     MarkInterval = 20 * 60; /* interval between marks in seconds */
266 int     MarkSeq = 0;            /* mark sequence number */
267 int     SecureMode = 0;         /* when true, receive only unix domain socks */
268 #ifdef INET6
269 int     family = PF_UNSPEC;     /* protocol family (IPv4, IPv6 or both) */
270 #else
271 int     family = PF_INET;       /* protocol family (IPv4 only) */
272 #endif
273 int     send_to_all = 0;        /* send message to all IPv4/IPv6 addresses */
274
275 char    bootfile[MAXLINE+1];    /* booted kernel file */
276
277 struct allowedpeer *AllowedPeers;
278 int     NumAllowed = 0;         /* # of AllowedPeer entries */
279
280 int     UniquePriority = 0;     /* Only log specified priority? */
281 int     LogFacPri = 0;          /* Put facility and priority in log message: */
282                                 /* 0=no, 1=numeric, 2=names */
283 int     KeepKernFac = 0;        /* Keep remotely logged kernel facility */
284
285 int     allowaddr __P((char *));
286 void    cfline __P((char *, struct filed *, char *, char *));
287 char   *cvthname __P((struct sockaddr *));
288 void    deadq_enter __P((pid_t, const char *));
289 int     deadq_remove __P((pid_t));
290 int     decode __P((const char *, CODE *));
291 void    die __P((int));
292 void    domark __P((int));
293 void    fprintlog __P((struct filed *, int, char *));
294 int*    socksetup __P((int));
295 void    init __P((int));
296 void    logerror __P((const char *));
297 void    logmsg __P((int, char *, char *, int));
298 void    log_deadchild __P((pid_t, int, const char *));
299 void    printline __P((char *, char *));
300 void    printsys __P((char *));
301 int     p_open __P((char *, pid_t *));
302 void    readklog __P((void));
303 void    reapchild __P((int));
304 char   *ttymsg __P((struct iovec *, int, char *, int));
305 static void     usage __P((void));
306 int     validate __P((struct sockaddr *, const char *));
307 static void     unmapped __P((struct sockaddr *));
308 void    wallmsg __P((struct filed *, struct iovec *));
309 int     waitdaemon __P((int, int, int));
310 void    timedout __P((int));
311
312 int
313 main(argc, argv)
314         int argc;
315         char *argv[];
316 {
317         int ch, i, l;
318         struct sockaddr_un sunx, fromunix;
319         struct sockaddr_storage frominet;
320         FILE *fp;
321         char *p, *hname, line[MAXLINE + 1];
322         struct timeval tv, *tvp;
323         struct sigaction sact;
324         sigset_t mask;
325         pid_t ppid = 1;
326         socklen_t len;
327
328         while ((ch = getopt(argc, argv, "46Aa:df:kl:m:np:P:suv")) != -1)
329                 switch (ch) {
330                 case '4':
331                         family = PF_INET;
332                         break;
333 #ifdef INET6
334                 case '6':
335                         family = PF_INET6;
336                         break;
337 #endif
338                 case 'A':
339                         send_to_all++;
340                         break;
341                 case 'a':               /* allow specific network addresses only */
342                         if (allowaddr(optarg) == -1)
343                                 usage();
344                         break;
345                 case 'd':               /* debug */
346                         Debug++;
347                         break;
348                 case 'f':               /* configuration file */
349                         ConfFile = optarg;
350                         break;
351                 case 'k':               /* keep remote kern fac */
352                         KeepKernFac = 1;
353                         break;
354                 case 'l':
355                         if (nfunix < MAXFUNIX)
356                                 funixn[nfunix++] = optarg;
357                         else
358                                 warnx("out of descriptors, ignoring %s",
359                                         optarg);
360                         break;
361                 case 'm':               /* mark interval */
362                         MarkInterval = atoi(optarg) * 60;
363                         break;
364                 case 'n':
365                         resolve = 0;
366                         break;
367                 case 'p':               /* path */
368                         funixn[0] = optarg;
369                         break;
370                 case 'P':               /* path for alt. PID */
371                         PidFile = optarg;
372                         break;
373                 case 's':               /* no network mode */
374                         SecureMode++;
375                         break;
376                 case 'u':               /* only log specified priority */
377                         UniquePriority++;
378                         break;
379                 case 'v':               /* log facility and priority */
380                         LogFacPri++;
381                         break;
382                 case '?':
383                 default:
384                         usage();
385                 }
386         if ((argc -= optind) != 0)
387                 usage();
388
389         if (!Debug) {
390                 ppid = waitdaemon(0, 0, 30);
391                 if (ppid < 0)
392                         err(1, "could not become daemon");
393         } else
394                 setlinebuf(stdout);
395
396         if (NumAllowed)
397                 endservent();
398
399         consfile.f_type = F_CONSOLE;
400         (void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
401         (void)gethostname(LocalHostName, sizeof(LocalHostName));
402         if ((p = strchr(LocalHostName, '.')) != NULL) {
403                 *p++ = '\0';
404                 LocalDomain = p;
405         } else
406                 LocalDomain = "";
407         (void)strcpy(bootfile, getbootfile());
408         (void)signal(SIGTERM, die);
409         (void)signal(SIGINT, Debug ? die : SIG_IGN);
410         (void)signal(SIGQUIT, Debug ? die : SIG_IGN);
411         /*
412          * We don't want the SIGCHLD and SIGHUP handlers to interfere
413          * with each other; they are likely candidates for being called
414          * simultaneously (SIGHUP closes pipe descriptor, process dies,
415          * SIGCHLD happens).
416          */
417         sigemptyset(&mask);
418         sigaddset(&mask, SIGHUP);
419         sact.sa_handler = reapchild;
420         sact.sa_mask = mask;
421         sact.sa_flags = SA_RESTART;
422         (void)sigaction(SIGCHLD, &sact, NULL);
423         (void)signal(SIGALRM, domark);
424         (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */
425         (void)alarm(TIMERINTVL);
426
427         TAILQ_INIT(&deadq_head);
428
429 #ifndef SUN_LEN
430 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
431 #endif
432         for (i = 0; i < nfunix; i++) {
433                 memset(&sunx, 0, sizeof(sunx));
434                 sunx.sun_family = AF_UNIX;
435                 (void)strncpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
436                 funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
437                 if (funix[i] < 0 ||
438                     bind(funix[i], (struct sockaddr *)&sunx,
439                          SUN_LEN(&sunx)) < 0 ||
440                     chmod(funixn[i], 0666) < 0) {
441                         (void) snprintf(line, sizeof line,
442                                         "cannot create %s", funixn[i]);
443                         logerror(line);
444                         dprintf("cannot create %s (%d)\n", funixn[i], errno);
445                         if (i == 0)
446                                 die(0);
447                 }
448         }
449         if (SecureMode <= 1)
450                 finet = socksetup(family);
451
452         if (finet) {
453                 if (SecureMode) {
454                         for (i = 0; i < *finet; i++) {
455                                 if (shutdown(finet[i+1], SHUT_RD) < 0) {
456                                         logerror("shutdown");
457                                         if (!Debug)
458                                                 die(0);
459                                 }
460                         }
461                 } else
462                         dprintf("listening on inet and/or inet6 socket\n");
463                 dprintf("sending on inet and/or inet6 socket\n");
464         }
465
466         if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
467                 if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0)
468                         fklog = -1;
469         if (fklog < 0)
470                 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
471
472         /* tuck my process id away */
473         fp = fopen(PidFile, "w");
474         if (fp != NULL) {
475                 fprintf(fp, "%d\n", getpid());
476                 (void) fclose(fp);
477         }
478
479         dprintf("off & running....\n");
480
481         init(0);
482         /* prevent SIGHUP and SIGCHLD handlers from running in parallel */
483         sigemptyset(&mask);
484         sigaddset(&mask, SIGCHLD);
485         sact.sa_handler = init;
486         sact.sa_mask = mask;
487         sact.sa_flags = SA_RESTART;
488         (void)sigaction(SIGHUP, &sact, NULL);
489
490         tvp = &tv;
491         tv.tv_sec = tv.tv_usec = 0;
492
493         for (;;) {
494                 fd_set readfds;
495                 int nfds = 0;
496
497                 FD_ZERO(&readfds);
498                 if (fklog != -1) {
499                         FD_SET(fklog, &readfds);
500                         if (fklog > nfds)
501                                 nfds = fklog;
502                 }
503                 if (finet && !SecureMode) {
504                         for (i = 0; i < *finet; i++) {
505                                 FD_SET(finet[i+1], &readfds);
506                                 if (finet[i+1] > nfds)
507                                         nfds = finet[i+1];
508                         }
509                 }
510                 for (i = 0; i < nfunix; i++) {
511                         if (funix[i] != -1) {
512                                 FD_SET(funix[i], &readfds);
513                                 if (funix[i] > nfds)
514                                         nfds = funix[i];
515                         }
516                 }
517
518                 /*dprintf("readfds = %#x\n", readfds);*/
519                 nfds = select(nfds+1, &readfds, (fd_set *)NULL,
520                               (fd_set *)NULL, tvp);
521                 if (nfds == 0) {
522                         if (tvp) {
523                                 tvp = NULL;
524                                 if (ppid != 1)
525                                         kill(ppid, SIGALRM);
526                         }
527                         continue;
528                 }
529                 if (nfds < 0) {
530                         if (errno != EINTR)
531                                 logerror("select");
532                         continue;
533                 }
534                 /*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/
535                 if (fklog != -1 && FD_ISSET(fklog, &readfds))
536                         readklog();
537                 if (finet && !SecureMode) {
538                         for (i = 0; i < *finet; i++) {
539                                 if (FD_ISSET(finet[i+1], &readfds)) {
540                                         len = sizeof(frominet);
541                                         l = recvfrom(finet[i+1], line, MAXLINE,
542                                              0, (struct sockaddr *)&frominet,
543                                              &len);
544                                         if (l > 0) {
545                                                 line[l] = '\0';
546                                                 hname = cvthname((struct sockaddr *)&frominet);
547                                                 unmapped((struct sockaddr *)&frominet);
548                                                 if (validate((struct sockaddr *)&frominet, hname))
549                                                         printline(hname, line);
550                                         } else if (l < 0 && errno != EINTR)
551                                                 logerror("recvfrom inet");
552                                 }
553                         }
554                 }
555                 for (i = 0; i < nfunix; i++) {
556                         if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) {
557                                 len = sizeof(fromunix);
558                                 l = recvfrom(funix[i], line, MAXLINE, 0,
559                                     (struct sockaddr *)&fromunix, &len);
560                                 if (l > 0) {
561                                         line[l] = '\0';
562                                         printline(LocalHostName, line);
563                                 } else if (l < 0 && errno != EINTR)
564                                         logerror("recvfrom unix");
565                         }
566                 }
567         }
568 }
569
570 static void
571 unmapped(sa)
572         struct sockaddr *sa;
573 {
574         struct sockaddr_in6 *sin6;
575         struct sockaddr_in sin;
576
577         if (sa->sa_family != AF_INET6)
578                 return;
579         if (sa->sa_len != sizeof(struct sockaddr_in6) ||
580             sizeof(sin) > sa->sa_len)
581                 return;
582         sin6 = (struct sockaddr_in6 *)sa;
583         if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
584                 return;
585
586         memset(&sin, 0, sizeof(sin));
587         sin.sin_family = AF_INET;
588         sin.sin_len = sizeof(struct sockaddr_in);
589         memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
590                sizeof(sin.sin_addr));
591         sin.sin_port = sin6->sin6_port;
592
593         memcpy(sa, &sin, sin.sin_len);
594 }
595
596 static void
597 usage()
598 {
599
600         fprintf(stderr, "%s\n%s\n%s\n",
601                 "usage: syslogd [-46Adnsuv] [-a allowed_peer] [-f config_file]",
602                 "               [-m mark_interval] [-l log_socket]",
603                 "               [-p log_socket] [-P pid_file]");
604         exit(1);
605 }
606
607 /*
608  * Take a raw input line, decode the message, and print the message
609  * on the appropriate log files.
610  */
611 void
612 printline(hname, msg)
613         char *hname;
614         char *msg;
615 {
616         int c, pri;
617         char *p, *q, line[MAXLINE + 1];
618
619         /* test for special codes */
620         pri = DEFUPRI;
621         p = msg;
622         if (*p == '<') {
623                 pri = 0;
624                 while (isdigit(*++p))
625                         pri = 10 * pri + (*p - '0');
626                 if (*p == '>')
627                         ++p;
628         }
629         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
630                 pri = DEFUPRI;
631
632         /* don't allow users to log kernel messages */
633         if (LOG_FAC(pri) == LOG_KERN && !KeepKernFac)
634                 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
635
636         q = line;
637
638         while ((c = (unsigned char)*p++) != '\0' &&
639             q < &line[sizeof(line) - 4]) {
640                 if ((c & 0x80) && c < 0xA0) {
641                         c &= 0x7F;
642                         *q++ = 'M';
643                         *q++ = '-';
644                 }
645                 if (isascii(c) && iscntrl(c)) {
646                         if (c == '\n')
647                                 *q++ = ' ';
648                         else if (c == '\t')
649                                 *q++ = '\t';
650                         else {
651                                 *q++ = '^';
652                                 *q++ = c ^ 0100;
653                         }
654                 } else
655                         *q++ = c;
656         }
657         *q = '\0';
658
659         logmsg(pri, line, hname, 0);
660 }
661
662 /*
663  * Read /dev/klog while data are available, split into lines.
664  */
665 void
666 readklog()
667 {
668         char *p, *q, line[MAXLINE + 1];
669         int len, i;
670
671         len = 0;
672         for (;;) {
673                 i = read(fklog, line + len, MAXLINE - 1 - len);
674                 if (i > 0)
675                         line[i + len] = '\0';
676                 else if (i < 0 && errno != EINTR && errno != EAGAIN) {
677                         logerror("klog");
678                         fklog = -1;
679                         break;
680                 } else
681                         break;
682
683                 for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
684                         *q = '\0';
685                         printsys(p);
686                 }
687                 len = strlen(p);
688                 if (len >= MAXLINE - 1) {
689                         printsys(p);
690                         len = 0;
691                 }
692                 if (len > 0) 
693                         memmove(line, p, len + 1);
694         }
695         if (len > 0)
696                 printsys(line);
697 }
698
699 /*
700  * Take a raw input line from /dev/klog, format similar to syslog().
701  */
702 void
703 printsys(p)
704         char *p;
705 {
706         int pri, flags;
707
708         flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */
709         pri = DEFSPRI;
710         if (*p == '<') {
711                 pri = 0;
712                 while (isdigit(*++p))
713                         pri = 10 * pri + (*p - '0');
714                 if (*p == '>')
715                         ++p;
716                 if ((pri & LOG_FACMASK) == LOG_CONSOLE)
717                         flags |= IGN_CONS;
718         } else {
719                 /* kernel printf's come out on console */
720                 flags |= IGN_CONS;
721         }
722         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
723                 pri = DEFSPRI;
724         logmsg(pri, p, LocalHostName, flags);
725 }
726
727 time_t  now;
728
729 /*
730  * Log a message to the appropriate log files, users, etc. based on
731  * the priority.
732  */
733 void
734 logmsg(pri, msg, from, flags)
735         int pri;
736         char *msg, *from;
737         int flags;
738 {
739         struct filed *f;
740         int i, fac, msglen, omask, prilev;
741         char *timestamp;
742         char prog[NAME_MAX+1];
743         char buf[MAXLINE+1];
744
745         dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
746             pri, flags, from, msg);
747
748         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
749
750         /*
751          * Check to see if msg looks non-standard.
752          */
753         msglen = strlen(msg);
754         if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
755             msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
756                 flags |= ADDDATE;
757
758         (void)time(&now);
759         if (flags & ADDDATE)
760                 timestamp = ctime(&now) + 4;
761         else {
762                 timestamp = msg;
763                 msg += 16;
764                 msglen -= 16;
765         }
766
767         /* skip leading blanks */
768         while (isspace(*msg)) {
769                 msg++;
770                 msglen--;
771         }
772
773         /* extract facility and priority level */
774         if (flags & MARK)
775                 fac = LOG_NFACILITIES;
776         else
777                 fac = LOG_FAC(pri);
778         prilev = LOG_PRI(pri);
779
780         /* extract program name */
781         for (i = 0; i < NAME_MAX; i++) {
782                 if (!isalnum(msg[i]))
783                         break;
784                 prog[i] = msg[i];
785         }
786         prog[i] = 0;
787
788         /* add kernel prefix for kernel messages */
789         if (flags & ISKERNEL) {
790                 snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg);
791                 msg = buf;
792                 msglen = strlen(buf);
793         }
794
795         /* log the message to the particular outputs */
796         if (!Initialized) {
797                 f = &consfile;
798                 f->f_file = open(ctty, O_WRONLY, 0);
799
800                 if (f->f_file >= 0) {
801                         fprintlog(f, flags, msg);
802                         (void)close(f->f_file);
803                 }
804                 (void)sigsetmask(omask);
805                 return;
806         }
807         for (f = Files; f; f = f->f_next) {
808                 /* skip messages that are incorrect priority */
809                 if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
810                      ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
811                      ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
812                      )
813                     || f->f_pmask[fac] == INTERNAL_NOPRI)
814                         continue;
815                 /* skip messages with the incorrect hostname */
816                 if (f->f_host)
817                         switch (f->f_host[0]) {
818                         case '+':
819                                 if (strcmp(from, f->f_host + 1) != 0)
820                                         continue;
821                                 break;
822                         case '-':
823                                 if (strcmp(from, f->f_host + 1) == 0)
824                                         continue;
825                                 break;
826                         }
827
828                 /* skip messages with the incorrect program name */
829                 if (f->f_program)
830                         if (strcmp(prog, f->f_program) != 0)
831                                 continue;
832
833                 if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
834                         continue;
835
836                 /* don't output marks to recently written files */
837                 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
838                         continue;
839
840                 /*
841                  * suppress duplicate lines to this file
842                  */
843                 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
844                     !strcmp(msg, f->f_prevline) &&
845                     !strcasecmp(from, f->f_prevhost)) {
846                         (void)strncpy(f->f_lasttime, timestamp, 15);
847                         f->f_prevcount++;
848                         dprintf("msg repeated %d times, %ld sec of %d\n",
849                             f->f_prevcount, (long)(now - f->f_time),
850                             repeatinterval[f->f_repeatcount]);
851                         /*
852                          * If domark would have logged this by now,
853                          * flush it now (so we don't hold isolated messages),
854                          * but back off so we'll flush less often
855                          * in the future.
856                          */
857                         if (now > REPEATTIME(f)) {
858                                 fprintlog(f, flags, (char *)NULL);
859                                 BACKOFF(f);
860                         }
861                 } else {
862                         /* new line, save it */
863                         if (f->f_prevcount)
864                                 fprintlog(f, 0, (char *)NULL);
865                         f->f_repeatcount = 0;
866                         f->f_prevpri = pri;
867                         (void)strncpy(f->f_lasttime, timestamp, 15);
868                         (void)strncpy(f->f_prevhost, from,
869                                         sizeof(f->f_prevhost)-1);
870                         f->f_prevhost[sizeof(f->f_prevhost)-1] = '\0';
871                         if (msglen < MAXSVLINE) {
872                                 f->f_prevlen = msglen;
873                                 (void)strcpy(f->f_prevline, msg);
874                                 fprintlog(f, flags, (char *)NULL);
875                         } else {
876                                 f->f_prevline[0] = 0;
877                                 f->f_prevlen = 0;
878                                 fprintlog(f, flags, msg);
879                         }
880                 }
881         }
882         (void)sigsetmask(omask);
883 }
884
885 void
886 fprintlog(f, flags, msg)
887         struct filed *f;
888         int flags;
889         char *msg;
890 {
891         struct iovec iov[7];
892         struct iovec *v;
893         struct addrinfo *r;
894         int i, l, lsent = 0;
895         char line[MAXLINE + 1], repbuf[80], greetings[200];
896         char *msgret;
897
898         v = iov;
899         if (f->f_type == F_WALL) {
900                 v->iov_base = greetings;
901                 v->iov_len = snprintf(greetings, sizeof greetings,
902                     "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
903                     f->f_prevhost, ctime(&now));
904                 v++;
905                 v->iov_base = "";
906                 v->iov_len = 0;
907                 v++;
908         } else {
909                 v->iov_base = f->f_lasttime;
910                 v->iov_len = 15;
911                 v++;
912                 v->iov_base = " ";
913                 v->iov_len = 1;
914                 v++;
915         }
916
917         if (LogFacPri) {
918                 static char fp_buf[30]; /* Hollow laugh */
919                 int fac = f->f_prevpri & LOG_FACMASK;
920                 int pri = LOG_PRI(f->f_prevpri);
921                 const char *f_s = NULL;
922                 char f_n[5];    /* Hollow laugh */
923                 const char *p_s = NULL;
924                 char p_n[5];    /* Hollow laugh */
925
926                 if (LogFacPri > 1) {
927                   CODE *c;
928
929                   for (c = facilitynames; c->c_name; c++) {
930                     if (c->c_val == fac) {
931                       f_s = c->c_name;
932                       break;
933                     }
934                   }
935                   for (c = prioritynames; c->c_name; c++) {
936                     if (c->c_val == pri) {
937                       p_s = c->c_name;
938                       break;
939                     }
940                   }
941                 }
942                 if (!f_s) {
943                   snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
944                   f_s = f_n;
945                 }
946                 if (!p_s) {
947                   snprintf(p_n, sizeof p_n, "%d", pri);
948                   p_s = p_n;
949                 }
950                 snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
951                 v->iov_base = fp_buf;
952                 v->iov_len = strlen(fp_buf);
953         } else {
954                 v->iov_base="";
955                 v->iov_len = 0;
956         }
957         v++;
958
959         v->iov_base = f->f_prevhost;
960         v->iov_len = strlen(v->iov_base);
961         v++;
962         v->iov_base = " ";
963         v->iov_len = 1;
964         v++;
965
966         if (msg) {
967                 v->iov_base = msg;
968                 v->iov_len = strlen(msg);
969         } else if (f->f_prevcount > 1) {
970                 v->iov_base = repbuf;
971                 v->iov_len = sprintf(repbuf, "last message repeated %d times",
972                     f->f_prevcount);
973         } else {
974                 v->iov_base = f->f_prevline;
975                 v->iov_len = f->f_prevlen;
976         }
977         v++;
978
979         dprintf("Logging to %s", TypeNames[f->f_type]);
980         f->f_time = now;
981
982         switch (f->f_type) {
983         case F_UNUSED:
984                 dprintf("\n");
985                 break;
986
987         case F_FORW:
988                 dprintf(" %s\n", f->f_un.f_forw.f_hname);
989                 /* check for local vs remote messages */
990                 if (strcasecmp(f->f_prevhost, LocalHostName))
991                         l = snprintf(line, sizeof line - 1,
992                             "<%d>%.15s Forwarded from %s: %s",
993                             f->f_prevpri, iov[0].iov_base, f->f_prevhost,
994                             iov[5].iov_base);
995                 else
996                         l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
997                              f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
998                 if (l > MAXLINE)
999                         l = MAXLINE;
1000
1001                 if (finet) {
1002                         for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
1003                                 for (i = 0; i < *finet; i++) {
1004 #if 0 
1005                                         /*
1006                                          * should we check AF first, or just
1007                                          * trial and error? FWD
1008                                          */
1009                                         if (r->ai_family ==
1010                                             address_family_of(finet[i+1])) 
1011 #endif
1012                                         lsent = sendto(finet[i+1], line, l, 0,
1013                                             r->ai_addr, r->ai_addrlen);
1014                                         if (lsent == l) 
1015                                                 break;
1016                                 }
1017                                 if (lsent == l && !send_to_all) 
1018                                         break;
1019                         }
1020                         if (lsent != l) {
1021                                 int e = errno;
1022                                 (void)close(f->f_file);
1023                                 errno = e;
1024                                 f->f_type = F_UNUSED;
1025                                 logerror("sendto");
1026                         }
1027                 }
1028                 break;
1029
1030         case F_FILE:
1031                 dprintf(" %s\n", f->f_un.f_fname);
1032                 v->iov_base = "\n";
1033                 v->iov_len = 1;
1034                 if (writev(f->f_file, iov, 7) < 0) {
1035                         int e = errno;
1036                         (void)close(f->f_file);
1037                         f->f_type = F_UNUSED;
1038                         errno = e;
1039                         logerror(f->f_un.f_fname);
1040                 } else if (flags & SYNC_FILE)
1041                         (void)fsync(f->f_file);
1042                 break;
1043
1044         case F_PIPE:
1045                 dprintf(" %s\n", f->f_un.f_pipe.f_pname);
1046                 v->iov_base = "\n";
1047                 v->iov_len = 1;
1048                 if (f->f_un.f_pipe.f_pid == 0) {
1049                         if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
1050                                                 &f->f_un.f_pipe.f_pid)) < 0) {
1051                                 f->f_type = F_UNUSED;
1052                                 logerror(f->f_un.f_pipe.f_pname);
1053                                 break;
1054                         }
1055                 }
1056                 if (writev(f->f_file, iov, 7) < 0) {
1057                         int e = errno;
1058                         (void)close(f->f_file);
1059                         if (f->f_un.f_pipe.f_pid > 0)
1060                                 deadq_enter(f->f_un.f_pipe.f_pid,
1061                                             f->f_un.f_pipe.f_pname);
1062                         f->f_un.f_pipe.f_pid = 0;
1063                         errno = e;
1064                         logerror(f->f_un.f_pipe.f_pname);
1065                 }
1066                 break;
1067
1068         case F_CONSOLE:
1069                 if (flags & IGN_CONS) {
1070                         dprintf(" (ignored)\n");
1071                         break;
1072                 }
1073                 /* FALLTHROUGH */
1074
1075         case F_TTY:
1076                 dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
1077                 v->iov_base = "\r\n";
1078                 v->iov_len = 2;
1079
1080                 errno = 0;      /* ttymsg() only sometimes returns an errno */
1081                 if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
1082                         f->f_type = F_UNUSED;
1083                         logerror(msgret);
1084                 }
1085                 break;
1086
1087         case F_USERS:
1088         case F_WALL:
1089                 dprintf("\n");
1090                 v->iov_base = "\r\n";
1091                 v->iov_len = 2;
1092                 wallmsg(f, iov);
1093                 break;
1094         }
1095         f->f_prevcount = 0;
1096 }
1097
1098 /*
1099  *  WALLMSG -- Write a message to the world at large
1100  *
1101  *      Write the specified message to either the entire
1102  *      world, or a list of approved users.
1103  */
1104 void
1105 wallmsg(f, iov)
1106         struct filed *f;
1107         struct iovec *iov;
1108 {
1109         static int reenter;                     /* avoid calling ourselves */
1110         FILE *uf;
1111         struct utmp ut;
1112         int i;
1113         char *p;
1114         char line[sizeof(ut.ut_line) + 1];
1115
1116         if (reenter++)
1117                 return;
1118         if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
1119                 logerror(_PATH_UTMP);
1120                 reenter = 0;
1121                 return;
1122         }
1123         /* NOSTRICT */
1124         while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1125                 if (ut.ut_name[0] == '\0')
1126                         continue;
1127                 strncpy(line, ut.ut_line, sizeof(ut.ut_line));
1128                 line[sizeof(ut.ut_line)] = '\0';
1129                 if (f->f_type == F_WALL) {
1130                         if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) {
1131                                 errno = 0;      /* already in msg */
1132                                 logerror(p);
1133                         }
1134                         continue;
1135                 }
1136                 /* should we send the message to this user? */
1137                 for (i = 0; i < MAXUNAMES; i++) {
1138                         if (!f->f_un.f_uname[i][0])
1139                                 break;
1140                         if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1141                             UT_NAMESIZE)) {
1142                                 if ((p = ttymsg(iov, 7, line, TTYMSGTIME))
1143                                                                 != NULL) {
1144                                         errno = 0;      /* already in msg */
1145                                         logerror(p);
1146                                 }
1147                                 break;
1148                         }
1149                 }
1150         }
1151         (void)fclose(uf);
1152         reenter = 0;
1153 }
1154
1155 void
1156 reapchild(signo)
1157         int signo;
1158 {
1159         int status;
1160         pid_t pid;
1161         struct filed *f;
1162
1163         while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
1164                 if (!Initialized)
1165                         /* Don't tell while we are initting. */
1166                         continue;
1167
1168                 /* First, look if it's a process from the dead queue. */
1169                 if (deadq_remove(pid))
1170                         goto oncemore;
1171
1172                 /* Now, look in list of active processes. */
1173                 for (f = Files; f; f = f->f_next)
1174                         if (f->f_type == F_PIPE &&
1175                             f->f_un.f_pipe.f_pid == pid) {
1176                                 (void)close(f->f_file);
1177                                 f->f_un.f_pipe.f_pid = 0;
1178                                 log_deadchild(pid, status,
1179                                               f->f_un.f_pipe.f_pname);
1180                                 break;
1181                         }
1182           oncemore:
1183                 continue;
1184         }
1185 }
1186
1187 /*
1188  * Return a printable representation of a host address.
1189  */
1190 char *
1191 cvthname(f)
1192         struct sockaddr *f;
1193 {
1194         int error;
1195         sigset_t omask, nmask;
1196         char *p;
1197         static char hname[NI_MAXHOST], ip[NI_MAXHOST];
1198
1199         error = getnameinfo((struct sockaddr *)f,
1200                             ((struct sockaddr *)f)->sa_len,
1201                             ip, sizeof ip, NULL, 0,
1202                             NI_NUMERICHOST | withscopeid);
1203         dprintf("cvthname(%s)\n", ip);
1204
1205         if (error) {
1206                 dprintf("Malformed from address %s\n", gai_strerror(error));
1207                 return ("???");
1208         }
1209         if (!resolve)
1210                 return (ip);
1211
1212         sigemptyset(&nmask);
1213         sigaddset(&nmask, SIGHUP);
1214         sigprocmask(SIG_BLOCK, &nmask, &omask);
1215         error = getnameinfo((struct sockaddr *)f,
1216                             ((struct sockaddr *)f)->sa_len,
1217                             hname, sizeof hname, NULL, 0,
1218                             NI_NAMEREQD | withscopeid);
1219         sigprocmask(SIG_SETMASK, &omask, NULL);
1220         if (error) {
1221                 dprintf("Host name for your address (%s) unknown\n", ip);
1222                 return (ip);
1223         }
1224         if ((p = strchr(hname, '.')) && strcasecmp(p + 1, LocalDomain) == 0)
1225                 *p = '\0';
1226         return (hname);
1227 }
1228
1229 void
1230 domark(signo)
1231         int signo;
1232 {
1233         struct filed *f;
1234         dq_t q;
1235
1236         now = time((time_t *)NULL);
1237         MarkSeq += TIMERINTVL;
1238         if (MarkSeq >= MarkInterval) {
1239                 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1240                 MarkSeq = 0;
1241         }
1242
1243         for (f = Files; f; f = f->f_next) {
1244                 if (f->f_prevcount && now >= REPEATTIME(f)) {
1245                         dprintf("flush %s: repeated %d times, %d sec.\n",
1246                             TypeNames[f->f_type], f->f_prevcount,
1247                             repeatinterval[f->f_repeatcount]);
1248                         fprintlog(f, 0, (char *)NULL);
1249                         BACKOFF(f);
1250                 }
1251         }
1252
1253         /* Walk the dead queue, and see if we should signal somebody. */
1254         for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1255                 switch (q->dq_timeout) {
1256                 case 0:
1257                         /* Already signalled once, try harder now. */
1258                         if (kill(q->dq_pid, SIGKILL) != 0)
1259                                 (void)deadq_remove(q->dq_pid);
1260                         break;
1261
1262                 case 1:
1263                         /*
1264                          * Timed out on dead queue, send terminate
1265                          * signal.  Note that we leave the removal
1266                          * from the dead queue to reapchild(), which
1267                          * will also log the event (unless the process
1268                          * didn't even really exist, in case we simply
1269                          * drop it from the dead queue).
1270                          */
1271                         if (kill(q->dq_pid, SIGTERM) != 0)
1272                                 (void)deadq_remove(q->dq_pid);
1273                         /* FALLTHROUGH */
1274
1275                 default:
1276                         q->dq_timeout--;
1277                 }
1278
1279         (void)alarm(TIMERINTVL);
1280 }
1281
1282 /*
1283  * Print syslogd errors some place.
1284  */
1285 void
1286 logerror(type)
1287         const char *type;
1288 {
1289         char buf[512];
1290
1291         if (errno)
1292                 (void)snprintf(buf,
1293                     sizeof buf, "syslogd: %s: %s", type, strerror(errno));
1294         else
1295                 (void)snprintf(buf, sizeof buf, "syslogd: %s", type);
1296         errno = 0;
1297         dprintf("%s\n", buf);
1298         logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1299 }
1300
1301 void
1302 die(signo)
1303         int signo;
1304 {
1305         struct filed *f;
1306         int was_initialized;
1307         char buf[100];
1308         int i;
1309
1310         was_initialized = Initialized;
1311         Initialized = 0;        /* Don't log SIGCHLDs. */
1312         for (f = Files; f != NULL; f = f->f_next) {
1313                 /* flush any pending output */
1314                 if (f->f_prevcount)
1315                         fprintlog(f, 0, (char *)NULL);
1316                 if (f->f_type == F_PIPE)
1317                         (void)close(f->f_file);
1318         }
1319         Initialized = was_initialized;
1320         if (signo) {
1321                 dprintf("syslogd: exiting on signal %d\n", signo);
1322                 (void)sprintf(buf, "exiting on signal %d", signo);
1323                 errno = 0;
1324                 logerror(buf);
1325         }
1326         for (i = 0; i < nfunix; i++)
1327                 if (funixn[i] && funix[i] != -1)
1328                         (void)unlink(funixn[i]);
1329         exit(1);
1330 }
1331
1332 /*
1333  *  INIT -- Initialize syslogd from configuration table
1334  */
1335 void
1336 init(signo)
1337         int signo;
1338 {
1339         int i;
1340         FILE *cf;
1341         struct filed *f, *next, **nextp;
1342         char *p;
1343         char cline[LINE_MAX];
1344         char prog[NAME_MAX+1];
1345         char host[MAXHOSTNAMELEN];
1346
1347         dprintf("init\n");
1348
1349         /*
1350          *  Close all open log files.
1351          */
1352         Initialized = 0;
1353         for (f = Files; f != NULL; f = next) {
1354                 /* flush any pending output */
1355                 if (f->f_prevcount)
1356                         fprintlog(f, 0, (char *)NULL);
1357
1358                 switch (f->f_type) {
1359                 case F_FILE:
1360                 case F_FORW:
1361                 case F_CONSOLE:
1362                 case F_TTY:
1363                         (void)close(f->f_file);
1364                         break;
1365                 case F_PIPE:
1366                         (void)close(f->f_file);
1367                         if (f->f_un.f_pipe.f_pid > 0)
1368                                 deadq_enter(f->f_un.f_pipe.f_pid,
1369                                             f->f_un.f_pipe.f_pname);
1370                         f->f_un.f_pipe.f_pid = 0;
1371                         break;
1372                 }
1373                 next = f->f_next;
1374                 if (f->f_program) free(f->f_program);
1375                 if (f->f_host) free(f->f_host);
1376                 free((char *)f);
1377         }
1378         Files = NULL;
1379         nextp = &Files;
1380
1381         /* open the configuration file */
1382         if ((cf = fopen(ConfFile, "r")) == NULL) {
1383                 dprintf("cannot open %s\n", ConfFile);
1384                 *nextp = (struct filed *)calloc(1, sizeof(*f));
1385                 cfline("*.ERR\t/dev/console", *nextp, "*", "*");
1386                 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1387                 cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
1388                 Initialized = 1;
1389                 return;
1390         }
1391
1392         /*
1393          *  Foreach line in the conf table, open that file.
1394          */
1395         f = NULL;
1396         strcpy(host, "*");
1397         strcpy(prog, "*");
1398         while (fgets(cline, sizeof(cline), cf) != NULL) {
1399                 /*
1400                  * check for end-of-section, comments, strip off trailing
1401                  * spaces and newline character. #!prog is treated specially:
1402                  * following lines apply only to that program.
1403                  */
1404                 for (p = cline; isspace(*p); ++p)
1405                         continue;
1406                 if (*p == 0)
1407                         continue;
1408                 if (*p == '#') {
1409                         p++;
1410                         if (*p != '!' && *p != '+' && *p != '-')
1411                                 continue;
1412                 }
1413                 if (*p == '+' || *p == '-') {
1414                         host[0] = *p++;
1415                         while (isspace(*p)) p++;
1416                         if ((!*p) || (*p == '*')) {
1417                                 strcpy(host, "*");
1418                                 continue;
1419                         }
1420                         if (*p == '@')
1421                                 p = LocalHostName;
1422                         for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
1423                                 if (!isalnum(*p) && *p != '.' && *p != '-')
1424                                         break;
1425                                 host[i] = *p++;
1426                         }
1427                         host[i] = '\0';
1428                         continue;
1429                 }
1430                 if (*p == '!') {
1431                         p++;
1432                         while (isspace(*p)) p++;
1433                         if ((!*p) || (*p == '*')) {
1434                                 strcpy(prog, "*");
1435                                 continue;
1436                         }
1437                         for (i = 0; i < NAME_MAX; i++) {
1438                                 if (!isalnum(p[i]))
1439                                         break;
1440                                 prog[i] = p[i];
1441                         }
1442                         prog[i] = 0;
1443                         continue;
1444                 }
1445                 for (p = strchr(cline, '\0'); isspace(*--p);)
1446                         continue;
1447                 *++p = '\0';
1448                 f = (struct filed *)calloc(1, sizeof(*f));
1449                 *nextp = f;
1450                 nextp = &f->f_next;
1451                 cfline(cline, f, prog, host);
1452         }
1453
1454         /* close the configuration file */
1455         (void)fclose(cf);
1456
1457         Initialized = 1;
1458
1459         if (Debug) {
1460                 for (f = Files; f; f = f->f_next) {
1461                         for (i = 0; i <= LOG_NFACILITIES; i++)
1462                                 if (f->f_pmask[i] == INTERNAL_NOPRI)
1463                                         printf("X ");
1464                                 else
1465                                         printf("%d ", f->f_pmask[i]);
1466                         printf("%s: ", TypeNames[f->f_type]);
1467                         switch (f->f_type) {
1468                         case F_FILE:
1469                                 printf("%s", f->f_un.f_fname);
1470                                 break;
1471
1472                         case F_CONSOLE:
1473                         case F_TTY:
1474                                 printf("%s%s", _PATH_DEV, f->f_un.f_fname);
1475                                 break;
1476
1477                         case F_FORW:
1478                                 printf("%s", f->f_un.f_forw.f_hname);
1479                                 break;
1480
1481                         case F_PIPE:
1482                                 printf("%s", f->f_un.f_pipe.f_pname);
1483                                 break;
1484
1485                         case F_USERS:
1486                                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1487                                         printf("%s, ", f->f_un.f_uname[i]);
1488                                 break;
1489                         }
1490                         if (f->f_program)
1491                                 printf(" (%s)", f->f_program);
1492                         printf("\n");
1493                 }
1494         }
1495
1496         logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1497         dprintf("syslogd: restarted\n");
1498 }
1499
1500 /*
1501  * Crack a configuration file line
1502  */
1503 void
1504 cfline(line, f, prog, host)
1505         char *line;
1506         struct filed *f;
1507         char *prog;
1508         char *host;
1509 {
1510         struct addrinfo hints, *res;
1511         int error, i, pri;
1512         char *bp, *p, *q;
1513         char buf[MAXLINE], ebuf[100];
1514
1515         dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
1516
1517         errno = 0;      /* keep strerror() stuff out of logerror messages */
1518
1519         /* clear out file entry */
1520         memset(f, 0, sizeof(*f));
1521         for (i = 0; i <= LOG_NFACILITIES; i++)
1522                 f->f_pmask[i] = INTERNAL_NOPRI;
1523
1524         /* save hostname if any */
1525         if (host && *host == '*')
1526                 host = NULL;
1527         if (host)
1528                 f->f_host = strdup(host);
1529
1530         /* save program name if any */
1531         if (prog && *prog == '*')
1532                 prog = NULL;
1533         if (prog)
1534                 f->f_program = strdup(prog);
1535
1536         /* scan through the list of selectors */
1537         for (p = line; *p && *p != '\t' && *p != ' ';) {
1538                 int pri_done;
1539                 int pri_cmp;
1540
1541                 /* find the end of this facility name list */
1542                 for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
1543                         continue;
1544
1545                 /* get the priority comparison */
1546                 pri_cmp = 0;
1547                 pri_done = 0;
1548                 while (!pri_done) {
1549                         switch (*q) {
1550                         case '<':
1551                                 pri_cmp |= PRI_LT;
1552                                 q++;
1553                                 break;
1554                         case '=':
1555                                 pri_cmp |= PRI_EQ;
1556                                 q++;
1557                                 break;
1558                         case '>':
1559                                 pri_cmp |= PRI_GT;
1560                                 q++;
1561                                 break;
1562                         default:
1563                                 pri_done++;
1564                                 break;
1565                         }
1566                 }
1567                 if (!pri_cmp)
1568                         pri_cmp = (UniquePriority)
1569                                   ? (PRI_EQ)
1570                                   : (PRI_EQ | PRI_GT)
1571                                   ;
1572
1573                 /* collect priority name */
1574                 for (bp = buf; *q && !strchr("\t,; ", *q); )
1575                         *bp++ = *q++;
1576                 *bp = '\0';
1577
1578                 /* skip cruft */
1579                 while (strchr(",;", *q))
1580                         q++;
1581
1582                 /* decode priority name */
1583                 if (*buf == '*')
1584                         pri = LOG_PRIMASK + 1;
1585                 else {
1586                         pri = decode(buf, prioritynames);
1587                         if (pri < 0) {
1588                                 (void)snprintf(ebuf, sizeof ebuf,
1589                                     "unknown priority name \"%s\"", buf);
1590                                 logerror(ebuf);
1591                                 return;
1592                         }
1593                 }
1594
1595                 /* scan facilities */
1596                 while (*p && !strchr("\t.; ", *p)) {
1597                         for (bp = buf; *p && !strchr("\t,;. ", *p); )
1598                                 *bp++ = *p++;
1599                         *bp = '\0';
1600
1601                         if (*buf == '*')
1602                                 for (i = 0; i < LOG_NFACILITIES; i++) {
1603                                         f->f_pmask[i] = pri;
1604                                         f->f_pcmp[i] = pri_cmp;
1605                                 }
1606                         else {
1607                                 i = decode(buf, facilitynames);
1608                                 if (i < 0) {
1609                                         (void)snprintf(ebuf, sizeof ebuf,
1610                                             "unknown facility name \"%s\"",
1611                                             buf);
1612                                         logerror(ebuf);
1613                                         return;
1614                                 }
1615                                 f->f_pmask[i >> 3] = pri;
1616                                 f->f_pcmp[i >> 3] = pri_cmp;
1617                         }
1618                         while (*p == ',' || *p == ' ')
1619                                 p++;
1620                 }
1621
1622                 p = q;
1623         }
1624
1625         /* skip to action part */
1626         while (*p == '\t' || *p == ' ')
1627                 p++;
1628
1629         switch (*p)
1630         {
1631         case '@':
1632                 (void)strncpy(f->f_un.f_forw.f_hname, ++p,
1633                         sizeof(f->f_un.f_forw.f_hname)-1);
1634                 f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';
1635                 memset(&hints, 0, sizeof(hints));
1636                 hints.ai_family = family;
1637                 hints.ai_socktype = SOCK_DGRAM;
1638                 error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
1639                                     &res);
1640                 if (error) {
1641                         logerror(gai_strerror(error));
1642                         break;
1643                 }
1644                 f->f_un.f_forw.f_addr = res;
1645                 f->f_type = F_FORW;
1646                 break;
1647
1648         case '/':
1649                 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1650                         f->f_type = F_UNUSED;
1651                         logerror(p);
1652                         break;
1653                 }
1654                 if (isatty(f->f_file)) {
1655                         if (strcmp(p, ctty) == 0)
1656                                 f->f_type = F_CONSOLE;
1657                         else
1658                                 f->f_type = F_TTY;
1659                         (void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
1660                 } else {
1661                         (void)strcpy(f->f_un.f_fname, p);
1662                         f->f_type = F_FILE;
1663                 }
1664                 break;
1665
1666         case '|':
1667                 f->f_un.f_pipe.f_pid = 0;
1668                 (void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
1669                 f->f_type = F_PIPE;
1670                 break;
1671
1672         case '*':
1673                 f->f_type = F_WALL;
1674                 break;
1675
1676         default:
1677                 for (i = 0; i < MAXUNAMES && *p; i++) {
1678                         for (q = p; *q && *q != ','; )
1679                                 q++;
1680                         (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1681                         if ((q - p) > UT_NAMESIZE)
1682                                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1683                         else
1684                                 f->f_un.f_uname[i][q - p] = '\0';
1685                         while (*q == ',' || *q == ' ')
1686                                 q++;
1687                         p = q;
1688                 }
1689                 f->f_type = F_USERS;
1690                 break;
1691         }
1692 }
1693
1694
1695 /*
1696  *  Decode a symbolic name to a numeric value
1697  */
1698 int
1699 decode(name, codetab)
1700         const char *name;
1701         CODE *codetab;
1702 {
1703         CODE *c;
1704         char *p, buf[40];
1705
1706         if (isdigit(*name))
1707                 return (atoi(name));
1708
1709         for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1710                 if (isupper(*name))
1711                         *p = tolower(*name);
1712                 else
1713                         *p = *name;
1714         }
1715         *p = '\0';
1716         for (c = codetab; c->c_name; c++)
1717                 if (!strcmp(buf, c->c_name))
1718                         return (c->c_val);
1719
1720         return (-1);
1721 }
1722
1723 /*
1724  * fork off and become a daemon, but wait for the child to come online
1725  * before returing to the parent, or we get disk thrashing at boot etc.
1726  * Set a timer so we don't hang forever if it wedges.
1727  */
1728 int
1729 waitdaemon(nochdir, noclose, maxwait)
1730         int nochdir, noclose, maxwait;
1731 {
1732         int fd;
1733         int status;
1734         pid_t pid, childpid;
1735
1736         switch (childpid = fork()) {
1737         case -1:
1738                 return (-1);
1739         case 0:
1740                 break;
1741         default:
1742                 signal(SIGALRM, timedout);
1743                 alarm(maxwait);
1744                 while ((pid = wait3(&status, 0, NULL)) != -1) {
1745                         if (WIFEXITED(status))
1746                                 errx(1, "child pid %d exited with return code %d",
1747                                         pid, WEXITSTATUS(status));
1748                         if (WIFSIGNALED(status))
1749                                 errx(1, "child pid %d exited on signal %d%s",
1750                                         pid, WTERMSIG(status),
1751                                         WCOREDUMP(status) ? " (core dumped)" :
1752                                         "");
1753                         if (pid == childpid)    /* it's gone... */
1754                                 break;
1755                 }
1756                 exit(0);
1757         }
1758
1759         if (setsid() == -1)
1760                 return (-1);
1761
1762         if (!nochdir)
1763                 (void)chdir("/");
1764
1765         if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1766                 (void)dup2(fd, STDIN_FILENO);
1767                 (void)dup2(fd, STDOUT_FILENO);
1768                 (void)dup2(fd, STDERR_FILENO);
1769                 if (fd > 2)
1770                         (void)close (fd);
1771         }
1772         return (getppid());
1773 }
1774
1775 /*
1776  * We get a SIGALRM from the child when it's running and finished doing it's
1777  * fsync()'s or O_SYNC writes for all the boot messages.
1778  *
1779  * We also get a signal from the kernel if the timer expires, so check to
1780  * see what happened.
1781  */
1782 void
1783 timedout(sig)
1784         int sig __unused;
1785 {
1786         int left;
1787         left = alarm(0);
1788         signal(SIGALRM, SIG_DFL);
1789         if (left == 0)
1790                 errx(1, "timed out waiting for child");
1791         else
1792                 exit(0);
1793 }
1794
1795 /*
1796  * Add `s' to the list of allowable peer addresses to accept messages
1797  * from.
1798  *
1799  * `s' is a string in the form:
1800  *
1801  *    [*]domainname[:{servicename|portnumber|*}]
1802  *
1803  * or
1804  *
1805  *    netaddr/maskbits[:{servicename|portnumber|*}]
1806  *
1807  * Returns -1 on error, 0 if the argument was valid.
1808  */
1809 int
1810 allowaddr(s)
1811         char *s;
1812 {
1813         char *cp1, *cp2;
1814         struct allowedpeer ap;
1815         struct servent *se;
1816         int masklen = -1, i;
1817         struct addrinfo hints, *res;
1818         struct in_addr *addrp, *maskp;
1819         u_int32_t *addr6p, *mask6p;
1820         char ip[NI_MAXHOST];
1821
1822 #ifdef INET6
1823         if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
1824 #endif
1825                 cp1 = s;
1826         if ((cp1 = strrchr(cp1, ':'))) {
1827                 /* service/port provided */
1828                 *cp1++ = '\0';
1829                 if (strlen(cp1) == 1 && *cp1 == '*')
1830                         /* any port allowed */
1831                         ap.port = 0;
1832                 else if ((se = getservbyname(cp1, "udp")))
1833                         ap.port = ntohs(se->s_port);
1834                 else {
1835                         ap.port = strtol(cp1, &cp2, 0);
1836                         if (*cp2 != '\0')
1837                                 return -1; /* port not numeric */
1838                 }
1839         } else {
1840                 if ((se = getservbyname("syslog", "udp")))
1841                         ap.port = ntohs(se->s_port);
1842                 else
1843                         /* sanity, should not happen */
1844                         ap.port = 514;
1845         }
1846
1847         if ((cp1 = strchr(s, '/')) != NULL &&
1848             strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
1849                 *cp1 = '\0';
1850                 if ((masklen = atoi(cp1 + 1)) < 0)
1851                         return -1;
1852         }
1853 #ifdef INET6
1854         if (*s == '[') {
1855                 cp2 = s + strlen(s) - 1;
1856                 if (*cp2 == ']') {
1857                         ++s;
1858                         *cp2 = '\0';
1859                 } else
1860                         cp2 = NULL;
1861         } else
1862                 cp2 = NULL;
1863 #endif
1864         memset(&hints, 0, sizeof(hints));
1865         hints.ai_family = PF_UNSPEC;
1866         hints.ai_socktype = SOCK_DGRAM;
1867         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1868         if (getaddrinfo(s, NULL, &hints, &res) == 0) {
1869                 ap.isnumeric = 1;
1870                 memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
1871                 memset(&ap.a_mask, 0, sizeof(ap.a_mask));
1872                 ap.a_mask.ss_family = res->ai_family;
1873                 if (res->ai_family == AF_INET) {
1874                         ap.a_mask.ss_len = sizeof(struct sockaddr_in);
1875                         maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
1876                         addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
1877                         if (masklen < 0) {
1878                                 /* use default netmask */
1879                                 if (IN_CLASSA(ntohl(addrp->s_addr)))
1880                                         maskp->s_addr = htonl(IN_CLASSA_NET);
1881                                 else if (IN_CLASSB(ntohl(addrp->s_addr)))
1882                                         maskp->s_addr = htonl(IN_CLASSB_NET);
1883                                 else
1884                                         maskp->s_addr = htonl(IN_CLASSC_NET);
1885                         } else if (masklen <= 32) {
1886                                 /* convert masklen to netmask */
1887                                 maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
1888                         } else {
1889                                 freeaddrinfo(res);
1890                                 return -1;
1891                         }
1892                         /* Lose any host bits in the network number. */
1893                         addrp->s_addr &= maskp->s_addr;
1894                 }
1895 #ifdef INET6
1896                 else if (res->ai_family == AF_INET6 && masklen <= 128) {
1897                         ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
1898                         if (masklen < 0)
1899                                 masklen = 128;
1900                         mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
1901                         /* convert masklen to netmask */
1902                         while (masklen > 0) {
1903                                 if (masklen < 32) {
1904                                         *mask6p = htonl(~(0xffffffff >> masklen));
1905                                         break;
1906                                 }
1907                                 *mask6p++ = 0xffffffff;
1908                                 masklen -= 32;
1909                         }
1910                         /* Lose any host bits in the network number. */
1911                         mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
1912                         addr6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_addr)->sin6_addr;
1913                         for (i = 0; i < 4; i++)
1914                                 addr6p[i] &= mask6p[i];
1915                 }
1916 #endif
1917                 else {
1918                         freeaddrinfo(res);
1919                         return -1;
1920                 }
1921                 freeaddrinfo(res);
1922         } else {
1923                 /* arg `s' is domain name */
1924                 ap.isnumeric = 0;
1925                 ap.a_name = s;
1926                 if (cp1)
1927                         *cp1 = '/';
1928 #ifdef INET6
1929                 if (cp2) {
1930                         *cp2 = ']';
1931                         --s;
1932                 }
1933 #endif
1934         }
1935
1936         if (Debug) {
1937                 printf("allowaddr: rule %d: ", NumAllowed);
1938                 if (ap.isnumeric) {
1939                         printf("numeric, ");
1940                         getnameinfo((struct sockaddr *)&ap.a_addr,
1941                                     ((struct sockaddr *)&ap.a_addr)->sa_len,
1942                                     ip, sizeof ip, NULL, 0,
1943                                     NI_NUMERICHOST | withscopeid);
1944                         printf("addr = %s, ", ip);
1945                         getnameinfo((struct sockaddr *)&ap.a_mask,
1946                                     ((struct sockaddr *)&ap.a_mask)->sa_len,
1947                                     ip, sizeof ip, NULL, 0,
1948                                     NI_NUMERICHOST | withscopeid);
1949                         printf("mask = %s; ", ip);
1950                 } else
1951                         printf("domainname = %s; ", ap.a_name);
1952                 printf("port = %d\n", ap.port);
1953         }
1954
1955         if ((AllowedPeers = realloc(AllowedPeers,
1956                                     ++NumAllowed * sizeof(struct allowedpeer)))
1957             == NULL) {
1958                 fprintf(stderr, "Out of memory!\n");
1959                 exit(EX_OSERR);
1960         }
1961         memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
1962         return 0;
1963 }
1964
1965 /*
1966  * Validate that the remote peer has permission to log to us.
1967  */
1968 int
1969 validate(sa, hname)
1970         struct sockaddr *sa;
1971         const char *hname;
1972 {
1973         int i, j, reject;
1974         size_t l1, l2;
1975         char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
1976         struct allowedpeer *ap;
1977         struct sockaddr_in *sin, *a4p = NULL, *m4p = NULL;
1978         struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
1979         struct addrinfo hints, *res;
1980         u_short sport;
1981
1982         if (NumAllowed == 0)
1983                 /* traditional behaviour, allow everything */
1984                 return 1;
1985
1986         strlcpy(name, hname, sizeof name);
1987         memset(&hints, 0, sizeof(hints));
1988         hints.ai_family = PF_UNSPEC;
1989         hints.ai_socktype = SOCK_DGRAM;
1990         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1991         if (getaddrinfo(name, NULL, &hints, &res) == 0)
1992                 freeaddrinfo(res);
1993         else if (strchr(name, '.') == NULL) {
1994                 strlcat(name, ".", sizeof name);
1995                 strlcat(name, LocalDomain, sizeof name);
1996         }
1997         if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
1998                         NI_NUMERICHOST | withscopeid | NI_NUMERICSERV) != 0)
1999                 return 0;       /* for safety, should not occur */
2000         dprintf("validate: dgram from IP %s, port %s, name %s;\n",
2001                 ip, port, name);
2002         sport = atoi(port);
2003
2004         /* now, walk down the list */
2005         for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
2006                 if (ap->port != 0 && ap->port != sport) {
2007                         dprintf("rejected in rule %d due to port mismatch.\n", i);
2008                         continue;
2009                 }
2010
2011                 if (ap->isnumeric) {
2012                         if (ap->a_addr.ss_family != sa->sa_family) {
2013                                 dprintf("rejected in rule %d due to address family mismatch.\n", i);
2014                                 continue;
2015                         }
2016                         if (ap->a_addr.ss_family == AF_INET) {
2017                                 sin = (struct sockaddr_in *)sa;
2018                                 a4p = (struct sockaddr_in *)&ap->a_addr;
2019                                 m4p = (struct sockaddr_in *)&ap->a_mask;
2020                                 if ((sin->sin_addr.s_addr & m4p->sin_addr.s_addr)
2021                                     != a4p->sin_addr.s_addr) {
2022                                         dprintf("rejected in rule %d due to IP mismatch.\n", i);
2023                                         continue;
2024                                 }
2025                         }
2026 #ifdef INET6
2027                         else if (ap->a_addr.ss_family == AF_INET6) {
2028                                 sin6 = (struct sockaddr_in6 *)sa;
2029                                 a6p = (struct sockaddr_in6 *)&ap->a_addr;
2030                                 m6p = (struct sockaddr_in6 *)&ap->a_mask;
2031 #ifdef NI_WITHSCOPEID
2032                                 if (a6p->sin6_scope_id != 0 &&
2033                                     sin6->sin6_scope_id != a6p->sin6_scope_id) {
2034                                         dprintf("rejected in rule %d due to scope mismatch.\n", i);
2035                                         continue;
2036                                 }
2037 #endif
2038                                 reject = 0;
2039                                 for (j = 0; j < 16; j += 4) {
2040                                         if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j])
2041                                             != *(u_int32_t *)&a6p->sin6_addr.s6_addr[j]) {
2042                                                 ++reject;
2043                                                 break;
2044                                         }
2045                                 }
2046                                 if (reject) {
2047                                         dprintf("rejected in rule %d due to IP mismatch.\n", i);
2048                                         continue;
2049                                 }
2050                         }
2051 #endif
2052                         else
2053                                 continue;
2054                 } else {
2055                         cp = ap->a_name;
2056                         l1 = strlen(name);
2057                         if (*cp == '*') {
2058                                 /* allow wildmatch */
2059                                 cp++;
2060                                 l2 = strlen(cp);
2061                                 if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
2062                                         dprintf("rejected in rule %d due to name mismatch.\n", i);
2063                                         continue;
2064                                 }
2065                         } else {
2066                                 /* exact match */
2067                                 l2 = strlen(cp);
2068                                 if (l2 != l1 || memcmp(cp, name, l1) != 0) {
2069                                         dprintf("rejected in rule %d due to name mismatch.\n", i);
2070                                         continue;
2071                                 }
2072                         }
2073                 }
2074                 dprintf("accepted in rule %d.\n", i);
2075                 return 1;       /* hooray! */
2076         }
2077         return 0;
2078 }
2079
2080 /*
2081  * Fairly similar to popen(3), but returns an open descriptor, as
2082  * opposed to a FILE *.
2083  */
2084 int
2085 p_open(prog, pid)
2086         char *prog;
2087         pid_t *pid;
2088 {
2089         int pfd[2], nulldesc, i;
2090         sigset_t omask, mask;
2091         char *argv[4]; /* sh -c cmd NULL */
2092         char errmsg[200];
2093
2094         if (pipe(pfd) == -1)
2095                 return -1;
2096         if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
2097                 /* we are royally screwed anyway */
2098                 return -1;
2099
2100         sigemptyset(&mask);
2101         sigaddset(&mask, SIGALRM);
2102         sigaddset(&mask, SIGHUP);
2103         sigprocmask(SIG_BLOCK, &mask, &omask);
2104         switch ((*pid = fork())) {
2105         case -1:
2106                 sigprocmask(SIG_SETMASK, &omask, 0);
2107                 close(nulldesc);
2108                 return -1;
2109
2110         case 0:
2111                 argv[0] = "sh";
2112                 argv[1] = "-c";
2113                 argv[2] = prog;
2114                 argv[3] = NULL;
2115
2116                 alarm(0);
2117                 (void)setsid(); /* Avoid catching SIGHUPs. */
2118
2119                 /*
2120                  * Throw away pending signals, and reset signal
2121                  * behaviour to standard values.
2122                  */
2123                 signal(SIGALRM, SIG_IGN);
2124                 signal(SIGHUP, SIG_IGN);
2125                 sigprocmask(SIG_SETMASK, &omask, 0);
2126                 signal(SIGPIPE, SIG_DFL);
2127                 signal(SIGQUIT, SIG_DFL);
2128                 signal(SIGALRM, SIG_DFL);
2129                 signal(SIGHUP, SIG_DFL);
2130
2131                 dup2(pfd[0], STDIN_FILENO);
2132                 dup2(nulldesc, STDOUT_FILENO);
2133                 dup2(nulldesc, STDERR_FILENO);
2134                 for (i = getdtablesize(); i > 2; i--)
2135                         (void) close(i);
2136
2137                 (void) execvp(_PATH_BSHELL, argv);
2138                 _exit(255);
2139         }
2140
2141         sigprocmask(SIG_SETMASK, &omask, 0);
2142         close(nulldesc);
2143         close(pfd[0]);
2144         /*
2145          * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
2146          * supposed to get an EWOULDBLOCK on writev(2), which is
2147          * caught by the logic above anyway, which will in turn close
2148          * the pipe, and fork a new logging subprocess if necessary.
2149          * The stale subprocess will be killed some time later unless
2150          * it terminated itself due to closing its input pipe (so we
2151          * get rid of really dead puppies).
2152          */
2153         if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
2154                 /* This is bad. */
2155                 (void)snprintf(errmsg, sizeof errmsg,
2156                                "Warning: cannot change pipe to PID %d to "
2157                                "non-blocking behaviour.",
2158                                (int)*pid);
2159                 logerror(errmsg);
2160         }
2161         return pfd[1];
2162 }
2163
2164 void
2165 deadq_enter(pid, name)
2166         pid_t pid;
2167         const char *name;
2168 {
2169         dq_t p;
2170         int status;
2171
2172         /*
2173          * Be paranoid, if we can't signal the process, don't enter it
2174          * into the dead queue (perhaps it's already dead).  If possible,
2175          * we try to fetch and log the child's status.
2176          */
2177         if (kill(pid, 0) != 0) {
2178                 if (waitpid(pid, &status, WNOHANG) > 0)
2179                         log_deadchild(pid, status, name);
2180                 return;
2181         }
2182
2183         p = malloc(sizeof(struct deadq_entry));
2184         if (p == 0) {
2185                 errno = 0;
2186                 logerror("panic: out of virtual memory!");
2187                 exit(1);
2188         }
2189
2190         p->dq_pid = pid;
2191         p->dq_timeout = DQ_TIMO_INIT;
2192         TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
2193 }
2194
2195 int
2196 deadq_remove(pid)
2197         pid_t pid;
2198 {
2199         dq_t q;
2200
2201         for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
2202                 if (q->dq_pid == pid) {
2203                         TAILQ_REMOVE(&deadq_head, q, dq_entries);
2204                                 free(q);
2205                                 return 1;
2206                 }
2207
2208         return 0;
2209 }
2210
2211 void
2212 log_deadchild(pid, status, name)
2213         pid_t pid;
2214         int status;
2215         const char *name;
2216 {
2217         int code;
2218         char buf[256];
2219         const char *reason;
2220
2221         errno = 0; /* Keep strerror() stuff out of logerror messages. */
2222         if (WIFSIGNALED(status)) {
2223                 reason = "due to signal";
2224                 code = WTERMSIG(status);
2225         } else {
2226                 reason = "with status";
2227                 code = WEXITSTATUS(status);
2228                 if (code == 0)
2229                         return;
2230         }
2231         (void)snprintf(buf, sizeof buf,
2232                        "Logging subprocess %d (%s) exited %s %d.",
2233                        pid, name, reason, code);
2234         logerror(buf);
2235 }
2236
2237 int *
2238 socksetup(af)
2239         int af;
2240 {
2241         struct addrinfo hints, *res, *r;
2242         int error, maxs, *s, *socks;
2243
2244         memset(&hints, 0, sizeof(hints));
2245         hints.ai_flags = AI_PASSIVE;
2246         hints.ai_family = af;
2247         hints.ai_socktype = SOCK_DGRAM;
2248         error = getaddrinfo(NULL, "syslog", &hints, &res);
2249         if (error) {
2250                 logerror(gai_strerror(error));
2251                 errno = 0;
2252                 die(0);
2253         }
2254
2255         /* Count max number of sockets we may open */
2256         for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
2257         socks = malloc((maxs+1) * sizeof(int));
2258         if (!socks) {
2259                 logerror("couldn't allocate memory for sockets");
2260                 die(0);
2261         }
2262
2263         *socks = 0;   /* num of sockets counter at start of array */
2264         s = socks + 1;
2265         for (r = res; r; r = r->ai_next) {
2266                 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
2267                 if (*s < 0) {
2268                         logerror("socket");
2269                         continue;
2270                 }
2271 #ifdef IPV6_BINDV6ONLY
2272                 if (r->ai_family == AF_INET6) {
2273                         int on = 1;
2274                         if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
2275                                        (char *)&on, sizeof (on)) < 0) {
2276                                 logerror("setsockopt");
2277                                 close(*s);
2278                                 continue;
2279                         }
2280                 }
2281 #endif
2282                 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
2283                         close(*s);
2284                         logerror("bind");
2285                         continue;
2286                 }
2287
2288                 (*socks)++;
2289                 s++;
2290         }
2291
2292         if (*socks == 0) {
2293                 free(socks);
2294                 if (Debug)
2295                         return(NULL);
2296                 else
2297                         die(0);
2298         }
2299         if (res)
2300                 freeaddrinfo(res);
2301
2302         return(socks);
2303 }