]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/syslogd/syslogd.c
This commit was generated by cvs2svn to compensate for changes in r52400,
[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 <regex.h>
103 #include <setjmp.h>
104 #include <signal.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <sysexits.h>
109 #include <unistd.h>
110 #include <utmp.h>
111 #include "pathnames.h"
112
113 #define SYSLOG_NAMES
114 #include <sys/syslog.h>
115
116 const char      *ConfFile = _PATH_LOGCONF;
117 const char      *PidFile = _PATH_LOGPID;
118 const char      ctty[] = _PATH_CONSOLE;
119
120 #define dprintf         if (Debug) printf
121
122 #define MAXUNAMES       20      /* maximum number of user names */
123
124 #define MAXFUNIX       20
125
126 int nfunix = 1;
127 char *funixn[MAXFUNIX] = { _PATH_LOG };
128 int funix[MAXFUNIX];
129
130 /*
131  * Flags to logmsg().
132  */
133
134 #define IGN_CONS        0x001   /* don't print on console */
135 #define SYNC_FILE       0x002   /* do fsync on file after printing */
136 #define ADDDATE         0x004   /* add a date to the message */
137 #define MARK            0x008   /* this message is a mark */
138 #define ISKERNEL        0x010   /* kernel generated message */
139
140 /*
141  * This structure represents the files that will have log
142  * copies printed.
143  */
144
145 struct filed {
146         struct  filed *f_next;          /* next in linked list */
147         short   f_type;                 /* entry type, see below */
148         short   f_file;                 /* file descriptor */
149         time_t  f_time;                 /* time this was last written */
150         u_char  f_pmask[LOG_NFACILITIES+1];     /* priority mask */
151         u_char  f_pcmp[LOG_NFACILITIES+1];      /* compare priority */
152 #define PRI_LT  0x1
153 #define PRI_EQ  0x2
154 #define PRI_GT  0x4
155         char    *f_program;             /* program this applies to */
156         union {
157                 char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
158                 struct {
159                         char    f_hname[MAXHOSTNAMELEN+1];
160                         struct sockaddr_in      f_addr;
161                 } f_forw;               /* forwarding address */
162                 char    f_fname[MAXPATHLEN];
163                 struct {
164                         char    f_pname[MAXPATHLEN];
165                         pid_t   f_pid;
166                 } f_pipe;
167         } f_un;
168         char    f_prevline[MAXSVLINE];          /* last message logged */
169         char    f_lasttime[16];                 /* time of last occurrence */
170         char    f_prevhost[MAXHOSTNAMELEN+1];   /* host from which recd. */
171         int     f_prevpri;                      /* pri of f_prevline */
172         int     f_prevlen;                      /* length of f_prevline */
173         int     f_prevcount;                    /* repetition cnt of prevline */
174         int     f_repeatcount;                  /* number of "repeated" msgs */
175 };
176
177 /*
178  * Queue of about-to-be dead processes we should watch out for.
179  */
180
181 TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
182 struct stailhead *deadq_headp;
183
184 struct deadq_entry {
185         pid_t                           dq_pid;
186         int                             dq_timeout;
187         TAILQ_ENTRY(deadq_entry)        dq_entries;
188 };
189
190 /*
191  * The timeout to apply to processes waiting on the dead queue.  Unit
192  * of measure is `mark intervals', i.e. 20 minutes by default.
193  * Processes on the dead queue will be terminated after that time.
194  */
195
196 #define DQ_TIMO_INIT    2
197
198 typedef struct deadq_entry *dq_t;
199
200
201 /*
202  * Struct to hold records of network addresses that are allowed to log
203  * to us.
204  */
205 struct allowedpeer {
206         int isnumeric;
207         u_short port;
208         union {
209                 struct {
210                         struct in_addr addr;
211                         struct in_addr mask;
212                 } numeric;
213                 char *name;
214         } u;
215 #define a_addr u.numeric.addr
216 #define a_mask u.numeric.mask
217 #define a_name u.name
218 };
219
220
221 /*
222  * Intervals at which we flush out "message repeated" messages,
223  * in seconds after previous message is logged.  After each flush,
224  * we move to the next interval until we reach the largest.
225  */
226 int     repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
227 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
228 #define REPEATTIME(f)   ((f)->f_time + repeatinterval[(f)->f_repeatcount])
229 #define BACKOFF(f)      { if (++(f)->f_repeatcount > MAXREPEAT) \
230                                  (f)->f_repeatcount = MAXREPEAT; \
231                         }
232
233 /* values for f_type */
234 #define F_UNUSED        0               /* unused entry */
235 #define F_FILE          1               /* regular file */
236 #define F_TTY           2               /* terminal */
237 #define F_CONSOLE       3               /* console terminal */
238 #define F_FORW          4               /* remote machine */
239 #define F_USERS         5               /* list of users */
240 #define F_WALL          6               /* everyone logged on */
241 #define F_PIPE          7               /* pipe to program */
242
243 char    *TypeNames[8] = {
244         "UNUSED",       "FILE",         "TTY",          "CONSOLE",
245         "FORW",         "USERS",        "WALL",         "PIPE"
246 };
247
248 struct  filed *Files;
249 struct  filed consfile;
250
251 int     Debug;                  /* debug flag */
252 char    LocalHostName[MAXHOSTNAMELEN+1];        /* our hostname */
253 char    *LocalDomain;           /* our local domain name */
254 int     finet = -1;             /* Internet datagram socket */
255 int     fklog = -1;             /* /dev/klog */
256 int     LogPort;                /* port number for INET connections */
257 int     Initialized = 0;        /* set when we have initialized ourselves */
258 int     MarkInterval = 20 * 60; /* interval between marks in seconds */
259 int     MarkSeq = 0;            /* mark sequence number */
260 int     SecureMode = 0;         /* when true, receive only unix domain socks */
261 u_int   Vogons = 0;             /* packets arriving in SecureMode */
262
263 char    bootfile[MAXLINE+1];    /* booted kernel file */
264
265 struct allowedpeer *AllowedPeers;
266 int     NumAllowed = 0;         /* # of AllowedPeer entries */
267
268 int     UniquePriority = 0;     /* Only log specified priority? */
269 int     LogFacPri = 0;          /* Put facility and priority in log message: */
270                                 /* 0=no, 1=numeric, 2=names */
271
272 int     allowaddr __P((char *));
273 void    cfline __P((char *, struct filed *, char *));
274 char   *cvthname __P((struct sockaddr_in *));
275 void    deadq_enter __P((pid_t));
276 int     decode __P((const char *, CODE *));
277 void    die __P((int));
278 void    domark __P((int));
279 void    fprintlog __P((struct filed *, int, char *));
280 void    init __P((int));
281 void    logerror __P((const char *));
282 void    logmsg __P((int, char *, char *, int));
283 void    printline __P((char *, char *));
284 void    printsys __P((char *));
285 int     p_open __P((char *, pid_t *));
286 void    readklog __P((void));
287 void    reapchild __P((int));
288 char   *ttymsg __P((struct iovec *, int, char *, int));
289 static void     usage __P((void));
290 int     validate __P((struct sockaddr_in *, const char *));
291 void    wallmsg __P((struct filed *, struct iovec *));
292 int     waitdaemon __P((int, int, int));
293 void    timedout __P((int));
294
295 int
296 main(argc, argv)
297         int argc;
298         char *argv[];
299 {
300         int ch, i, l, len;
301         struct sockaddr_un sunx, fromunix;
302         struct sockaddr_in sin, frominet;
303         FILE *fp;
304         char *p, *hname, line[MAXLINE + 1];
305         struct timeval tv, *tvp;
306         pid_t ppid = 1;
307
308         while ((ch = getopt(argc, argv, "a:dl:f:m:p:suv")) != -1)
309                 switch(ch) {
310                 case 'd':               /* debug */
311                         Debug++;
312                         break;
313                 case 'a':               /* allow specific network addresses only */
314                         if (allowaddr(optarg) == -1)
315                                 usage();
316                         break;
317                 case 'f':               /* configuration file */
318                         ConfFile = optarg;
319                         break;
320                 case 'm':               /* mark interval */
321                         MarkInterval = atoi(optarg) * 60;
322                         break;
323                 case 'p':               /* path */
324                         funixn[0] = optarg;
325                         break;
326                 case 's':               /* no network mode */
327                         SecureMode++;
328                         break;
329                 case 'l':
330                         if (nfunix < MAXFUNIX)
331                                 funixn[nfunix++] = optarg;
332                         else
333                                 fprintf(stderr,
334                                    "syslogd: out of descriptors, ignoring %s\n",
335                                         optarg);
336                         break;
337                 case 'u':               /* only log specified priority */
338                         UniquePriority++;
339                         break;
340                 case 'v':               /* log facility and priority */
341                         LogFacPri++;
342                         break;
343                 case '?':
344                 default:
345                         usage();
346                 }
347         if ((argc -= optind) != 0)
348                 usage();
349
350         if (!Debug) {
351                 ppid = waitdaemon(0, 0, 30);
352                 if (ppid < 0)
353                         err(1, "could not become daemon");
354         } else
355                 setlinebuf(stdout);
356
357         if (NumAllowed)
358                 endservent();
359
360         consfile.f_type = F_CONSOLE;
361         (void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
362         (void)gethostname(LocalHostName, sizeof(LocalHostName));
363         if ((p = strchr(LocalHostName, '.')) != NULL) {
364                 *p++ = '\0';
365                 LocalDomain = p;
366         } else
367                 LocalDomain = "";
368         (void)strcpy(bootfile, getbootfile());
369         (void)signal(SIGTERM, die);
370         (void)signal(SIGINT, Debug ? die : SIG_IGN);
371         (void)signal(SIGQUIT, Debug ? die : SIG_IGN);
372         (void)signal(SIGCHLD, reapchild);
373         (void)signal(SIGALRM, domark);
374         (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */
375         (void)alarm(TIMERINTVL);
376
377         TAILQ_INIT(&deadq_head);
378
379 #ifndef SUN_LEN
380 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
381 #endif
382         for (i = 0; i < nfunix; i++) {
383                 memset(&sunx, 0, sizeof(sunx));
384                 sunx.sun_family = AF_UNIX;
385                 (void)strncpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
386                 funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
387                 if (funix[i] < 0 ||
388                     bind(funix[i], (struct sockaddr *)&sunx,
389                          SUN_LEN(&sunx)) < 0 ||
390                     chmod(funixn[i], 0666) < 0) {
391                         (void) snprintf(line, sizeof line,
392                                         "cannot create %s", funixn[i]);
393                         logerror(line);
394                         dprintf("cannot create %s (%d)\n", funixn[i], errno);
395                         if (i == 0)
396                                 die(0);
397                 }
398         }
399         if (SecureMode <= 1)
400                 finet = socket(AF_INET, SOCK_DGRAM, 0);
401         if (finet >= 0) {
402                 struct servent *sp;
403
404                 sp = getservbyname("syslog", "udp");
405                 if (sp == NULL) {
406                         errno = 0;
407                         logerror("syslog/udp: unknown service");
408                         die(0);
409                 }
410                 memset(&sin, 0, sizeof(sin));
411                 sin.sin_family = AF_INET;
412                 sin.sin_port = LogPort = sp->s_port;
413
414                 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
415                         logerror("bind");
416                         if (!Debug)
417                                 die(0);
418                 }
419         }
420
421         if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
422                 if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0)
423                         fklog = -1;
424         if (fklog < 0)
425                 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
426
427         /* tuck my process id away */
428         fp = fopen(PidFile, "w");
429         if (fp != NULL) {
430                 fprintf(fp, "%d\n", getpid());
431                 (void) fclose(fp);
432         }
433
434         dprintf("off & running....\n");
435
436         init(0);
437         (void)signal(SIGHUP, init);
438
439         tvp = &tv;
440         tv.tv_sec = tv.tv_usec = 0;
441
442         for (;;) {
443                 fd_set readfds;
444                 int nfds = 0;
445
446                 FD_ZERO(&readfds);
447                 if (fklog != -1) {
448                         FD_SET(fklog, &readfds);
449                         if (fklog > nfds)
450                                 nfds = fklog;
451                 }
452                 if (finet != -1) {
453                         FD_SET(finet, &readfds);
454                         if (finet > nfds)
455                                 nfds = finet;
456                 }
457                 for (i = 0; i < nfunix; i++) {
458                         if (funix[i] != -1) {
459                                 FD_SET(funix[i], &readfds);
460                                 if (funix[i] > nfds)
461                                         nfds = funix[i];
462                         }
463                 }
464
465                 /*dprintf("readfds = %#x\n", readfds);*/
466                 nfds = select(nfds+1, &readfds, (fd_set *)NULL,
467                               (fd_set *)NULL, tvp);
468                 if (nfds == 0) {
469                         if (tvp) {
470                                 tvp = NULL;
471                                 if (ppid != 1)
472                                         kill(ppid, SIGALRM);
473                         }
474                         continue;
475                 }
476                 if (nfds < 0) {
477                         if (errno != EINTR)
478                                 logerror("select");
479                         continue;
480                 }
481                 /*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/
482                 if (fklog != -1 && FD_ISSET(fklog, &readfds))
483                         readklog();
484                 if (finet != -1 && FD_ISSET(finet, &readfds)) {
485                         len = sizeof(frominet);
486                         l = recvfrom(finet, line, MAXLINE, 0,
487                             (struct sockaddr *)&frominet, &len);
488                         if (SecureMode) {
489                                 Vogons++;
490                                 if (!(Vogons & (Vogons - 1))) {
491                                         (void)snprintf(line, sizeof line,
492 "syslogd: discarded %d unwanted packets in secure mode, last from %s", Vogons,
493                                                 inet_ntoa(frominet.sin_addr));
494                                         logmsg(LOG_SYSLOG|LOG_AUTH, line,
495                                             LocalHostName, ADDDATE);
496                                 }
497                         } else if (l > 0) {
498                                 line[l] = '\0';
499                                 hname = cvthname(&frominet);
500                                 if (validate(&frominet, hname))
501                                         printline(hname, line);
502                         } else if (l < 0 && errno != EINTR)
503                                 logerror("recvfrom inet");
504                 }
505                 for (i = 0; i < nfunix; i++) {
506                         if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) {
507                                 len = sizeof(fromunix);
508                                 l = recvfrom(funix[i], line, MAXLINE, 0,
509                                     (struct sockaddr *)&fromunix, &len);
510                                 if (l > 0) {
511                                         line[l] = '\0';
512                                         printline(LocalHostName, line);
513                                 } else if (l < 0 && errno != EINTR)
514                                         logerror("recvfrom unix");
515                         }
516                 }
517         }
518 }
519
520 static void
521 usage()
522 {
523
524         fprintf(stderr, "%s\n%s\n%s\n",
525                 "usage: syslogd [-dsuv] [-a allowed_peer] [-f config_file]",
526                 "               [-m mark_interval] [-p log_socket]",
527                 "               [-l log_socket]");
528         exit(1);
529 }
530
531 /*
532  * Take a raw input line, decode the message, and print the message
533  * on the appropriate log files.
534  */
535 void
536 printline(hname, msg)
537         char *hname;
538         char *msg;
539 {
540         int c, pri;
541         char *p, *q, line[MAXLINE + 1];
542
543         /* test for special codes */
544         pri = DEFUPRI;
545         p = msg;
546         if (*p == '<') {
547                 pri = 0;
548                 while (isdigit(*++p))
549                         pri = 10 * pri + (*p - '0');
550                 if (*p == '>')
551                         ++p;
552         }
553         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
554                 pri = DEFUPRI;
555
556         /* don't allow users to log kernel messages */
557         if (LOG_FAC(pri) == LOG_KERN)
558                 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
559
560         q = line;
561
562         while ((c = *p++ & 0177) != '\0' &&
563             q < &line[sizeof(line) - 1])
564                 if (iscntrl(c))
565                         if (c == '\n')
566                                 *q++ = ' ';
567                         else if (c == '\t')
568                                 *q++ = '\t';
569                         else {
570                                 *q++ = '^';
571                                 *q++ = c ^ 0100;
572                         }
573                 else
574                         *q++ = c;
575         *q = '\0';
576
577         logmsg(pri, line, hname, 0);
578 }
579
580 /*
581  * Read /dev/klog while data are available, split into lines.
582  */
583 void
584 readklog()
585 {
586         char *p, *q, line[MAXLINE + 1];
587         int len, i;
588
589         len = 0;
590         for (;;) {
591                 i = read(fklog, line + len, MAXLINE - 1 - len);
592                 if (i > 0)
593                         line[i + len] = '\0';
594                 else if (i < 0 && errno != EINTR && errno != EAGAIN) {
595                         logerror("klog");
596                         fklog = -1;
597                         break;
598                 } else
599                         break;
600
601                 for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
602                         *q = '\0';
603                         printsys(p);
604                 }
605                 len = strlen(p);
606                 if (len >= MAXLINE - 1) {
607                         printsys(p);
608                         len = 0;
609                 }
610                 if (len > 0) 
611                         memmove(line, p, len + 1);
612         }
613         if (len > 0)
614                 printsys(line);
615 }
616
617 /*
618  * Take a raw input line from /dev/klog, format similar to syslog().
619  */
620 void
621 printsys(p)
622         char *p;
623 {
624         int pri, flags;
625
626         flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */
627         pri = DEFSPRI;
628         if (*p == '<') {
629                 pri = 0;
630                 while (isdigit(*++p))
631                         pri = 10 * pri + (*p - '0');
632                 if (*p == '>')
633                         ++p;
634         } else {
635                 /* kernel printf's come out on console */
636                 flags |= IGN_CONS;
637         }
638         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
639                 pri = DEFSPRI;
640         logmsg(pri, p, LocalHostName, flags);
641 }
642
643 time_t  now;
644
645 /*
646  * Log a message to the appropriate log files, users, etc. based on
647  * the priority.
648  */
649 void
650 logmsg(pri, msg, from, flags)
651         int pri;
652         char *msg, *from;
653         int flags;
654 {
655         struct filed *f;
656         int i, fac, msglen, omask, prilev;
657         char *timestamp;
658         char prog[NAME_MAX+1];
659         char buf[MAXLINE+1];
660
661         dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
662             pri, flags, from, msg);
663
664         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
665
666         /*
667          * Check to see if msg looks non-standard.
668          */
669         msglen = strlen(msg);
670         if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
671             msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
672                 flags |= ADDDATE;
673
674         (void)time(&now);
675         if (flags & ADDDATE)
676                 timestamp = ctime(&now) + 4;
677         else {
678                 timestamp = msg;
679                 msg += 16;
680                 msglen -= 16;
681         }
682
683         /* skip leading blanks */
684         while(isspace(*msg)) {
685                 msg++;
686                 msglen--;
687         }
688
689         /* extract facility and priority level */
690         if (flags & MARK)
691                 fac = LOG_NFACILITIES;
692         else
693                 fac = LOG_FAC(pri);
694         prilev = LOG_PRI(pri);
695
696         /* extract program name */
697         for(i = 0; i < NAME_MAX; i++) {
698                 if(!isalnum(msg[i]))
699                         break;
700                 prog[i] = msg[i];
701         }
702         prog[i] = 0;
703
704         /* add kernel prefix for kernel messages */
705         if (flags & ISKERNEL) {
706                 snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg);
707                 msg = buf;
708                 msglen = strlen(buf);
709         }
710
711         /* log the message to the particular outputs */
712         if (!Initialized) {
713                 f = &consfile;
714                 f->f_file = open(ctty, O_WRONLY, 0);
715
716                 if (f->f_file >= 0) {
717                         fprintlog(f, flags, msg);
718                         (void)close(f->f_file);
719                 }
720                 (void)sigsetmask(omask);
721                 return;
722         }
723         for (f = Files; f; f = f->f_next) {
724                 /* skip messages that are incorrect priority */
725                 if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
726                      ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
727                      ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
728                      )
729                     || f->f_pmask[fac] == INTERNAL_NOPRI)
730                         continue;
731                 /* skip messages with the incorrect program name */
732                 if(f->f_program)
733                         if(strcmp(prog, f->f_program) != 0)
734                                 continue;
735
736                 if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
737                         continue;
738
739                 /* don't output marks to recently written files */
740                 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
741                         continue;
742
743                 /*
744                  * suppress duplicate lines to this file
745                  */
746                 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
747                     !strcmp(msg, f->f_prevline) &&
748                     !strcasecmp(from, f->f_prevhost)) {
749                         (void)strncpy(f->f_lasttime, timestamp, 15);
750                         f->f_prevcount++;
751                         dprintf("msg repeated %d times, %ld sec of %d\n",
752                             f->f_prevcount, (long)(now - f->f_time),
753                             repeatinterval[f->f_repeatcount]);
754                         /*
755                          * If domark would have logged this by now,
756                          * flush it now (so we don't hold isolated messages),
757                          * but back off so we'll flush less often
758                          * in the future.
759                          */
760                         if (now > REPEATTIME(f)) {
761                                 fprintlog(f, flags, (char *)NULL);
762                                 BACKOFF(f);
763                         }
764                 } else {
765                         /* new line, save it */
766                         if (f->f_prevcount)
767                                 fprintlog(f, 0, (char *)NULL);
768                         f->f_repeatcount = 0;
769                         f->f_prevpri = pri;
770                         (void)strncpy(f->f_lasttime, timestamp, 15);
771                         (void)strncpy(f->f_prevhost, from,
772                                         sizeof(f->f_prevhost)-1);
773                         f->f_prevhost[sizeof(f->f_prevhost)-1] = '\0';
774                         if (msglen < MAXSVLINE) {
775                                 f->f_prevlen = msglen;
776                                 (void)strcpy(f->f_prevline, msg);
777                                 fprintlog(f, flags, (char *)NULL);
778                         } else {
779                                 f->f_prevline[0] = 0;
780                                 f->f_prevlen = 0;
781                                 fprintlog(f, flags, msg);
782                         }
783                 }
784         }
785         (void)sigsetmask(omask);
786 }
787
788 void
789 fprintlog(f, flags, msg)
790         struct filed *f;
791         int flags;
792         char *msg;
793 {
794         struct iovec iov[7];
795         struct iovec *v;
796         int l;
797         char line[MAXLINE + 1], repbuf[80], greetings[200];
798         char *msgret;
799
800         v = iov;
801         if (f->f_type == F_WALL) {
802                 v->iov_base = greetings;
803                 v->iov_len = snprintf(greetings, sizeof greetings,
804                     "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
805                     f->f_prevhost, ctime(&now));
806                 v++;
807                 v->iov_base = "";
808                 v->iov_len = 0;
809                 v++;
810         } else {
811                 v->iov_base = f->f_lasttime;
812                 v->iov_len = 15;
813                 v++;
814                 v->iov_base = " ";
815                 v->iov_len = 1;
816                 v++;
817         }
818
819         if (LogFacPri) {
820                 static char fp_buf[30]; /* Hollow laugh */
821                 int fac = f->f_prevpri & LOG_FACMASK;
822                 int pri = LOG_PRI(f->f_prevpri);
823                 char *f_s = 0;
824                 char f_n[5];    /* Hollow laugh */
825                 char *p_s = 0;
826                 char p_n[5];    /* Hollow laugh */
827
828                 if (LogFacPri > 1) {
829                   CODE *c;
830
831                   for (c = facilitynames; c; c++) {
832                     if (c->c_val == fac) {
833                       f_s = c->c_name;
834                       break;
835                     }
836                   }
837                   for (c = prioritynames; c; c++) {
838                     if (c->c_val == pri) {
839                       p_s = c->c_name;
840                       break;
841                     }
842                   }
843                 }
844                 if (!f_s) {
845                   snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
846                   f_s = f_n;
847                 }
848                 if (!p_s) {
849                   snprintf(p_n, sizeof p_n, "%d", pri);
850                   p_s = p_n;
851                 }
852                 snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
853                 v->iov_base = fp_buf;
854                 v->iov_len = strlen(fp_buf);
855         } else {
856                 v->iov_base="";
857                 v->iov_len = 0;
858         }
859         v++;
860
861         v->iov_base = f->f_prevhost;
862         v->iov_len = strlen(v->iov_base);
863         v++;
864         v->iov_base = " ";
865         v->iov_len = 1;
866         v++;
867
868         if (msg) {
869                 v->iov_base = msg;
870                 v->iov_len = strlen(msg);
871         } else if (f->f_prevcount > 1) {
872                 v->iov_base = repbuf;
873                 v->iov_len = sprintf(repbuf, "last message repeated %d times",
874                     f->f_prevcount);
875         } else {
876                 v->iov_base = f->f_prevline;
877                 v->iov_len = f->f_prevlen;
878         }
879         v++;
880
881         dprintf("Logging to %s", TypeNames[f->f_type]);
882         f->f_time = now;
883
884         switch (f->f_type) {
885         case F_UNUSED:
886                 dprintf("\n");
887                 break;
888
889         case F_FORW:
890                 dprintf(" %s\n", f->f_un.f_forw.f_hname);
891                 /* check for local vs remote messages */
892                 if (strcasecmp(f->f_prevhost, LocalHostName))
893                         l = snprintf(line, sizeof line - 1,
894                             "<%d>%.15s Forwarded from %s: %s",
895                             f->f_prevpri, iov[0].iov_base, f->f_prevhost,
896                             iov[5].iov_base);
897                 else
898                         l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
899                              f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
900                 if (l > MAXLINE)
901                         l = MAXLINE;
902                 if ((finet >= 0) &&
903                      (sendto(finet, line, l, 0,
904                              (struct sockaddr *)&f->f_un.f_forw.f_addr,
905                              sizeof(f->f_un.f_forw.f_addr)) != l)) {
906                         int e = errno;
907                         (void)close(f->f_file);
908                         f->f_type = F_UNUSED;
909                         errno = e;
910                         logerror("sendto");
911                 }
912                 break;
913
914         case F_FILE:
915                 dprintf(" %s\n", f->f_un.f_fname);
916                 v->iov_base = "\n";
917                 v->iov_len = 1;
918                 if (writev(f->f_file, iov, 7) < 0) {
919                         int e = errno;
920                         (void)close(f->f_file);
921                         f->f_type = F_UNUSED;
922                         errno = e;
923                         logerror(f->f_un.f_fname);
924                 } else if (flags & SYNC_FILE)
925                         (void)fsync(f->f_file);
926                 break;
927
928         case F_PIPE:
929                 dprintf(" %s\n", f->f_un.f_pipe.f_pname);
930                 v->iov_base = "\n";
931                 v->iov_len = 1;
932                 if (f->f_un.f_pipe.f_pid == 0) {
933                         if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
934                                                 &f->f_un.f_pipe.f_pid)) < 0) {
935                                 f->f_type = F_UNUSED;
936                                 logerror(f->f_un.f_pipe.f_pname);
937                                 break;
938                         }
939                 }
940                 if (writev(f->f_file, iov, 7) < 0) {
941                         int e = errno;
942                         (void)close(f->f_file);
943                         if (f->f_un.f_pipe.f_pid > 0)
944                                 deadq_enter(f->f_un.f_pipe.f_pid);
945                         f->f_un.f_pipe.f_pid = 0;
946                         errno = e;
947                         logerror(f->f_un.f_pipe.f_pname);
948                 }
949                 break;
950
951         case F_CONSOLE:
952                 if (flags & IGN_CONS) {
953                         dprintf(" (ignored)\n");
954                         break;
955                 }
956                 /* FALLTHROUGH */
957
958         case F_TTY:
959                 dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
960                 v->iov_base = "\r\n";
961                 v->iov_len = 2;
962
963                 errno = 0;      /* ttymsg() only sometimes returns an errno */
964                 if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
965                         f->f_type = F_UNUSED;
966                         logerror(msgret);
967                 }
968                 break;
969
970         case F_USERS:
971         case F_WALL:
972                 dprintf("\n");
973                 v->iov_base = "\r\n";
974                 v->iov_len = 2;
975                 wallmsg(f, iov);
976                 break;
977         }
978         f->f_prevcount = 0;
979 }
980
981 /*
982  *  WALLMSG -- Write a message to the world at large
983  *
984  *      Write the specified message to either the entire
985  *      world, or a list of approved users.
986  */
987 void
988 wallmsg(f, iov)
989         struct filed *f;
990         struct iovec *iov;
991 {
992         static int reenter;                     /* avoid calling ourselves */
993         FILE *uf;
994         struct utmp ut;
995         int i;
996         char *p;
997         char line[sizeof(ut.ut_line) + 1];
998
999         if (reenter++)
1000                 return;
1001         if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
1002                 logerror(_PATH_UTMP);
1003                 reenter = 0;
1004                 return;
1005         }
1006         /* NOSTRICT */
1007         while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1008                 if (ut.ut_name[0] == '\0')
1009                         continue;
1010                 strncpy(line, ut.ut_line, sizeof(ut.ut_line));
1011                 line[sizeof(ut.ut_line)] = '\0';
1012                 if (f->f_type == F_WALL) {
1013                         if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) {
1014                                 errno = 0;      /* already in msg */
1015                                 logerror(p);
1016                         }
1017                         continue;
1018                 }
1019                 /* should we send the message to this user? */
1020                 for (i = 0; i < MAXUNAMES; i++) {
1021                         if (!f->f_un.f_uname[i][0])
1022                                 break;
1023                         if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1024                             UT_NAMESIZE)) {
1025                                 if ((p = ttymsg(iov, 7, line, TTYMSGTIME))
1026                                                                 != NULL) {
1027                                         errno = 0;      /* already in msg */
1028                                         logerror(p);
1029                                 }
1030                                 break;
1031                         }
1032                 }
1033         }
1034         (void)fclose(uf);
1035         reenter = 0;
1036 }
1037
1038 void
1039 reapchild(signo)
1040         int signo;
1041 {
1042         int status, code;
1043         pid_t pid;
1044         struct filed *f;
1045         char buf[256];
1046         const char *reason;
1047         dq_t q;
1048
1049         while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
1050                 if (!Initialized)
1051                         /* Don't tell while we are initting. */
1052                         continue;
1053
1054                 /* First, look if it's a process from the dead queue. */
1055                 for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1056                         if (q->dq_pid == pid) {
1057                                 TAILQ_REMOVE(&deadq_head, q, dq_entries);
1058                                 free(q);
1059                                 goto oncemore;
1060                         }
1061
1062                 /* Now, look in list of active processes. */
1063                 for (f = Files; f; f = f->f_next)
1064                         if (f->f_type == F_PIPE &&
1065                             f->f_un.f_pipe.f_pid == pid) {
1066                                 (void)close(f->f_file);
1067
1068                                 errno = 0; /* Keep strerror() stuff out of logerror messages. */
1069                                 f->f_un.f_pipe.f_pid = 0;
1070                                 if (WIFSIGNALED(status)) {
1071                                         reason = "due to signal";
1072                                         code = WTERMSIG(status);
1073                                 } else {
1074                                         reason = "with status";
1075                                         code = WEXITSTATUS(status);
1076                                         if (code == 0)
1077                                                 goto oncemore; /* Exited OK. */
1078                                 }
1079                                 (void)snprintf(buf, sizeof buf,
1080                                 "Logging subprocess %d (%s) exited %s %d.",
1081                                                pid, f->f_un.f_pipe.f_pname,
1082                                                reason, code);
1083                                 logerror(buf);
1084                                 break;
1085                         }
1086           oncemore:
1087         }
1088 }
1089
1090 /*
1091  * Return a printable representation of a host address.
1092  */
1093 char *
1094 cvthname(f)
1095         struct sockaddr_in *f;
1096 {
1097         struct hostent *hp;
1098         sigset_t omask, nmask;
1099         char *p;
1100
1101         dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
1102
1103         if (f->sin_family != AF_INET) {
1104                 dprintf("Malformed from address\n");
1105                 return ("???");
1106         }
1107         sigemptyset(&nmask);
1108         sigaddset(&nmask, SIGHUP);
1109         sigprocmask(SIG_BLOCK, &nmask, &omask);
1110         hp = gethostbyaddr((char *)&f->sin_addr,
1111             sizeof(struct in_addr), f->sin_family);
1112         sigprocmask(SIG_SETMASK, &omask, NULL);
1113         if (hp == 0) {
1114                 dprintf("Host name for your address (%s) unknown\n",
1115                         inet_ntoa(f->sin_addr));
1116                 return (inet_ntoa(f->sin_addr));
1117         }
1118         if ((p = strchr(hp->h_name, '.')) &&
1119             strcasecmp(p + 1, LocalDomain) == 0)
1120                 *p = '\0';
1121         return (hp->h_name);
1122 }
1123
1124 void
1125 domark(signo)
1126         int signo;
1127 {
1128         struct filed *f;
1129         dq_t q;
1130
1131         now = time((time_t *)NULL);
1132         MarkSeq += TIMERINTVL;
1133         if (MarkSeq >= MarkInterval) {
1134                 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1135                 MarkSeq = 0;
1136         }
1137
1138         for (f = Files; f; f = f->f_next) {
1139                 if (f->f_prevcount && now >= REPEATTIME(f)) {
1140                         dprintf("flush %s: repeated %d times, %d sec.\n",
1141                             TypeNames[f->f_type], f->f_prevcount,
1142                             repeatinterval[f->f_repeatcount]);
1143                         fprintlog(f, 0, (char *)NULL);
1144                         BACKOFF(f);
1145                 }
1146         }
1147
1148         /* Walk the dead queue, and see if we should signal somebody. */
1149         for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1150                 switch (q->dq_timeout) {
1151                 case 0:
1152                         /* Already signalled once, try harder now. */
1153                         kill(q->dq_pid, SIGKILL);
1154                         break;
1155
1156                 case 1:
1157                         /*
1158                          * Timed out on dead queue, send terminate
1159                          * signal.  Note that we leave the removal
1160                          * from the dead queue to reapchild(), which
1161                          * will also log the event.
1162                          */
1163                         kill(q->dq_pid, SIGTERM);
1164                         /* FALLTROUGH */
1165
1166                 default:
1167                         q->dq_timeout--;
1168                 }
1169
1170         (void)alarm(TIMERINTVL);
1171 }
1172
1173 /*
1174  * Print syslogd errors some place.
1175  */
1176 void
1177 logerror(type)
1178         const char *type;
1179 {
1180         char buf[512];
1181
1182         if (errno)
1183                 (void)snprintf(buf,
1184                     sizeof buf, "syslogd: %s: %s", type, strerror(errno));
1185         else
1186                 (void)snprintf(buf, sizeof buf, "syslogd: %s", type);
1187         errno = 0;
1188         dprintf("%s\n", buf);
1189         logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1190 }
1191
1192 void
1193 die(signo)
1194         int signo;
1195 {
1196         struct filed *f;
1197         int was_initialized;
1198         char buf[100];
1199         int i;
1200
1201         was_initialized = Initialized;
1202         Initialized = 0;        /* Don't log SIGCHLDs. */
1203         for (f = Files; f != NULL; f = f->f_next) {
1204                 /* flush any pending output */
1205                 if (f->f_prevcount)
1206                         fprintlog(f, 0, (char *)NULL);
1207                 if (f->f_type == F_PIPE)
1208                         (void)close(f->f_file);
1209         }
1210         Initialized = was_initialized;
1211         if (signo) {
1212                 dprintf("syslogd: exiting on signal %d\n", signo);
1213                 (void)sprintf(buf, "exiting on signal %d", signo);
1214                 errno = 0;
1215                 logerror(buf);
1216         }
1217         for (i = 0; i < nfunix; i++)
1218                 if (funixn[i] && funix[i] != -1)
1219                         (void)unlink(funixn[i]);
1220         exit(1);
1221 }
1222
1223 /*
1224  *  INIT -- Initialize syslogd from configuration table
1225  */
1226 void
1227 init(signo)
1228         int signo;
1229 {
1230         int i;
1231         FILE *cf;
1232         struct filed *f, *next, **nextp;
1233         char *p;
1234         char cline[LINE_MAX];
1235         char prog[NAME_MAX+1];
1236
1237         dprintf("init\n");
1238
1239         /*
1240          *  Close all open log files.
1241          */
1242         Initialized = 0;
1243         for (f = Files; f != NULL; f = next) {
1244                 /* flush any pending output */
1245                 if (f->f_prevcount)
1246                         fprintlog(f, 0, (char *)NULL);
1247
1248                 switch (f->f_type) {
1249                 case F_FILE:
1250                 case F_FORW:
1251                 case F_CONSOLE:
1252                 case F_TTY:
1253                         (void)close(f->f_file);
1254                         break;
1255                 case F_PIPE:
1256                         (void)close(f->f_file);
1257                         if (f->f_un.f_pipe.f_pid > 0)
1258                                 deadq_enter(f->f_un.f_pipe.f_pid);
1259                         f->f_un.f_pipe.f_pid = 0;
1260                         break;
1261                 }
1262                 next = f->f_next;
1263                 if(f->f_program) free(f->f_program);
1264                 free((char *)f);
1265         }
1266         Files = NULL;
1267         nextp = &Files;
1268
1269         /* open the configuration file */
1270         if ((cf = fopen(ConfFile, "r")) == NULL) {
1271                 dprintf("cannot open %s\n", ConfFile);
1272                 *nextp = (struct filed *)calloc(1, sizeof(*f));
1273                 cfline("*.ERR\t/dev/console", *nextp, "*");
1274                 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1275                 cfline("*.PANIC\t*", (*nextp)->f_next, "*");
1276                 Initialized = 1;
1277                 return;
1278         }
1279
1280         /*
1281          *  Foreach line in the conf table, open that file.
1282          */
1283         f = NULL;
1284         strcpy(prog, "*");
1285         while (fgets(cline, sizeof(cline), cf) != NULL) {
1286                 /*
1287                  * check for end-of-section, comments, strip off trailing
1288                  * spaces and newline character. #!prog is treated specially:
1289                  * following lines apply only to that program.
1290                  */
1291                 for (p = cline; isspace(*p); ++p)
1292                         continue;
1293                 if (*p == 0)
1294                         continue;
1295                 if(*p == '#') {
1296                         p++;
1297                         if(*p!='!')
1298                                 continue;
1299                 }
1300                 if(*p=='!') {
1301                         p++;
1302                         while(isspace(*p)) p++;
1303                         if((!*p) || (*p == '*')) {
1304                                 strcpy(prog, "*");
1305                                 continue;
1306                         }
1307                         for(i = 0; i < NAME_MAX; i++) {
1308                                 if(!isalnum(p[i]))
1309                                         break;
1310                                 prog[i] = p[i];
1311                         }
1312                         prog[i] = 0;
1313                         continue;
1314                 }
1315                 for (p = strchr(cline, '\0'); isspace(*--p);)
1316                         continue;
1317                 *++p = '\0';
1318                 f = (struct filed *)calloc(1, sizeof(*f));
1319                 *nextp = f;
1320                 nextp = &f->f_next;
1321                 cfline(cline, f, prog);
1322         }
1323
1324         /* close the configuration file */
1325         (void)fclose(cf);
1326
1327         Initialized = 1;
1328
1329         if (Debug) {
1330                 for (f = Files; f; f = f->f_next) {
1331                         for (i = 0; i <= LOG_NFACILITIES; i++)
1332                                 if (f->f_pmask[i] == INTERNAL_NOPRI)
1333                                         printf("X ");
1334                                 else
1335                                         printf("%d ", f->f_pmask[i]);
1336                         printf("%s: ", TypeNames[f->f_type]);
1337                         switch (f->f_type) {
1338                         case F_FILE:
1339                                 printf("%s", f->f_un.f_fname);
1340                                 break;
1341
1342                         case F_CONSOLE:
1343                         case F_TTY:
1344                                 printf("%s%s", _PATH_DEV, f->f_un.f_fname);
1345                                 break;
1346
1347                         case F_FORW:
1348                                 printf("%s", f->f_un.f_forw.f_hname);
1349                                 break;
1350
1351                         case F_PIPE:
1352                                 printf("%s", f->f_un.f_pipe.f_pname);
1353                                 break;
1354
1355                         case F_USERS:
1356                                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1357                                         printf("%s, ", f->f_un.f_uname[i]);
1358                                 break;
1359                         }
1360                         if(f->f_program) {
1361                                 printf(" (%s)", f->f_program);
1362                         }
1363                         printf("\n");
1364                 }
1365         }
1366
1367         logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1368         dprintf("syslogd: restarted\n");
1369 }
1370
1371 /*
1372  * Crack a configuration file line
1373  */
1374 void
1375 cfline(line, f, prog)
1376         char *line;
1377         struct filed *f;
1378         char *prog;
1379 {
1380         struct hostent *hp;
1381         int i, pri;
1382         char *bp, *p, *q;
1383         char buf[MAXLINE], ebuf[100];
1384
1385         dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
1386
1387         errno = 0;      /* keep strerror() stuff out of logerror messages */
1388
1389         /* clear out file entry */
1390         memset(f, 0, sizeof(*f));
1391         for (i = 0; i <= LOG_NFACILITIES; i++)
1392                 f->f_pmask[i] = INTERNAL_NOPRI;
1393
1394         /* save program name if any */
1395         if(prog && *prog=='*') prog = NULL;
1396         if(prog) {
1397                 f->f_program = calloc(1, strlen(prog)+1);
1398                 if(f->f_program) {
1399                         strcpy(f->f_program, prog);
1400                 }
1401         }
1402
1403         /* scan through the list of selectors */
1404         for (p = line; *p && *p != '\t' && *p != ' ';) {
1405                 int pri_done;
1406                 int pri_cmp;
1407
1408                 /* find the end of this facility name list */
1409                 for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
1410                         continue;
1411
1412                 /* get the priority comparison */
1413                 pri_cmp = 0;
1414                 pri_done = 0;
1415                 while (!pri_done) {
1416                         switch (*q) {
1417                         case '<':
1418                                 pri_cmp |= PRI_LT;
1419                                 q++;
1420                                 break;
1421                         case '=':
1422                                 pri_cmp |= PRI_EQ;
1423                                 q++;
1424                                 break;
1425                         case '>':
1426                                 pri_cmp |= PRI_GT;
1427                                 q++;
1428                                 break;
1429                         default:
1430                                 pri_done++;
1431                                 break;
1432                         }
1433                 }
1434                 if (!pri_cmp)
1435                         pri_cmp = (UniquePriority)
1436                                   ? (PRI_EQ)
1437                                   : (PRI_EQ | PRI_GT)
1438                                   ;
1439
1440                 /* collect priority name */
1441                 for (bp = buf; *q && !strchr("\t,; ", *q); )
1442                         *bp++ = *q++;
1443                 *bp = '\0';
1444
1445                 /* skip cruft */
1446                 while (strchr(",;", *q))
1447                         q++;
1448
1449                 /* decode priority name */
1450                 if (*buf == '*')
1451                         pri = LOG_PRIMASK + 1;
1452                 else {
1453                         pri = decode(buf, prioritynames);
1454                         if (pri < 0) {
1455                                 (void)snprintf(ebuf, sizeof ebuf,
1456                                     "unknown priority name \"%s\"", buf);
1457                                 logerror(ebuf);
1458                                 return;
1459                         }
1460                 }
1461
1462                 /* scan facilities */
1463                 while (*p && !strchr("\t.; ", *p)) {
1464                         for (bp = buf; *p && !strchr("\t,;. ", *p); )
1465                                 *bp++ = *p++;
1466                         *bp = '\0';
1467
1468                         if (*buf == '*')
1469                                 for (i = 0; i < LOG_NFACILITIES; i++) {
1470                                         f->f_pmask[i] = pri;
1471                                         f->f_pcmp[i] = pri_cmp;
1472                                 }
1473                         else {
1474                                 i = decode(buf, facilitynames);
1475                                 if (i < 0) {
1476                                         (void)snprintf(ebuf, sizeof ebuf,
1477                                             "unknown facility name \"%s\"",
1478                                             buf);
1479                                         logerror(ebuf);
1480                                         return;
1481                                 }
1482                                 f->f_pmask[i >> 3] = pri;
1483                                 f->f_pcmp[i >> 3] = pri_cmp;
1484                         }
1485                         while (*p == ',' || *p == ' ')
1486                                 p++;
1487                 }
1488
1489                 p = q;
1490         }
1491
1492         /* skip to action part */
1493         while (*p == '\t' || *p == ' ')
1494                 p++;
1495
1496         switch (*p)
1497         {
1498         case '@':
1499                 (void)strncpy(f->f_un.f_forw.f_hname, ++p,
1500                         sizeof(f->f_un.f_forw.f_hname)-1);
1501                 f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';          
1502                 hp = gethostbyname(f->f_un.f_forw.f_hname);
1503                 if (hp == NULL) {
1504                         extern int h_errno;
1505
1506                         logerror(hstrerror(h_errno));
1507                         break;
1508                 }
1509                 memset(&f->f_un.f_forw.f_addr, 0,
1510                          sizeof(f->f_un.f_forw.f_addr));
1511                 f->f_un.f_forw.f_addr.sin_family = AF_INET;
1512                 f->f_un.f_forw.f_addr.sin_port = LogPort;
1513                 memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
1514                 f->f_type = F_FORW;
1515                 break;
1516
1517         case '/':
1518                 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1519                         f->f_type = F_UNUSED;
1520                         logerror(p);
1521                         break;
1522                 }
1523                 if (isatty(f->f_file)) {
1524                         if (strcmp(p, ctty) == 0)
1525                                 f->f_type = F_CONSOLE;
1526                         else
1527                                 f->f_type = F_TTY;
1528                         (void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
1529                 } else {
1530                         (void)strcpy(f->f_un.f_fname, p);
1531                         f->f_type = F_FILE;
1532                 }
1533                 break;
1534
1535         case '|':
1536                 f->f_un.f_pipe.f_pid = 0;
1537                 (void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
1538                 f->f_type = F_PIPE;
1539                 break;
1540
1541         case '*':
1542                 f->f_type = F_WALL;
1543                 break;
1544
1545         default:
1546                 for (i = 0; i < MAXUNAMES && *p; i++) {
1547                         for (q = p; *q && *q != ','; )
1548                                 q++;
1549                         (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1550                         if ((q - p) > UT_NAMESIZE)
1551                                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1552                         else
1553                                 f->f_un.f_uname[i][q - p] = '\0';
1554                         while (*q == ',' || *q == ' ')
1555                                 q++;
1556                         p = q;
1557                 }
1558                 f->f_type = F_USERS;
1559                 break;
1560         }
1561 }
1562
1563
1564 /*
1565  *  Decode a symbolic name to a numeric value
1566  */
1567 int
1568 decode(name, codetab)
1569         const char *name;
1570         CODE *codetab;
1571 {
1572         CODE *c;
1573         char *p, buf[40];
1574
1575         if (isdigit(*name))
1576                 return (atoi(name));
1577
1578         for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1579                 if (isupper(*name))
1580                         *p = tolower(*name);
1581                 else
1582                         *p = *name;
1583         }
1584         *p = '\0';
1585         for (c = codetab; c->c_name; c++)
1586                 if (!strcmp(buf, c->c_name))
1587                         return (c->c_val);
1588
1589         return (-1);
1590 }
1591
1592 /*
1593  * fork off and become a daemon, but wait for the child to come online
1594  * before returing to the parent, or we get disk thrashing at boot etc.
1595  * Set a timer so we don't hang forever if it wedges.
1596  */
1597 int
1598 waitdaemon(nochdir, noclose, maxwait)
1599         int nochdir, noclose, maxwait;
1600 {
1601         int fd;
1602         int status;
1603         pid_t pid, childpid;
1604
1605         switch (childpid = fork()) {
1606         case -1:
1607                 return (-1);
1608         case 0:
1609                 break;
1610         default:
1611                 signal(SIGALRM, timedout);
1612                 alarm(maxwait);
1613                 while ((pid = wait3(&status, 0, NULL)) != -1) {
1614                         if (WIFEXITED(status))
1615                                 errx(1, "child pid %d exited with return code %d",
1616                                         pid, WEXITSTATUS(status));
1617                         if (WIFSIGNALED(status))
1618                                 errx(1, "child pid %d exited on signal %d%s",
1619                                         pid, WTERMSIG(status),
1620                                         WCOREDUMP(status) ? " (core dumped)" :
1621                                         "");
1622                         if (pid == childpid)    /* it's gone... */
1623                                 break;
1624                 }
1625                 exit(0);
1626         }
1627
1628         if (setsid() == -1)
1629                 return (-1);
1630
1631         if (!nochdir)
1632                 (void)chdir("/");
1633
1634         if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1635                 (void)dup2(fd, STDIN_FILENO);
1636                 (void)dup2(fd, STDOUT_FILENO);
1637                 (void)dup2(fd, STDERR_FILENO);
1638                 if (fd > 2)
1639                         (void)close (fd);
1640         }
1641         return (getppid());
1642 }
1643
1644 /*
1645  * We get a SIGALRM from the child when it's running and finished doing it's
1646  * fsync()'s or O_SYNC writes for all the boot messages.
1647  *
1648  * We also get a signal from the kernel if the timer expires, so check to
1649  * see what happened.
1650  */
1651 void
1652 timedout(sig)
1653         int sig __unused;
1654 {
1655         int left;
1656         left = alarm(0);
1657         signal(SIGALRM, SIG_DFL);
1658         if (left == 0)
1659                 errx(1, "timed out waiting for child");
1660         else
1661                 exit(0);
1662 }
1663
1664 /*
1665  * Add `s' to the list of allowable peer addresses to accept messages
1666  * from.
1667  *
1668  * `s' is a string in the form:
1669  *
1670  *    [*]domainname[:{servicename|portnumber|*}]
1671  *
1672  * or
1673  *
1674  *    netaddr/maskbits[:{servicename|portnumber|*}]
1675  *
1676  * Returns -1 on error, 0 if the argument was valid.
1677  */
1678 int
1679 allowaddr(s)
1680         char *s;
1681 {
1682         char *cp1, *cp2;
1683         struct allowedpeer ap;
1684         struct servent *se;
1685         regex_t re;
1686         int i;
1687
1688         if ((cp1 = strrchr(s, ':'))) {
1689                 /* service/port provided */
1690                 *cp1++ = '\0';
1691                 if (strlen(cp1) == 1 && *cp1 == '*')
1692                         /* any port allowed */
1693                         ap.port = htons(0);
1694                 else if ((se = getservbyname(cp1, "udp")))
1695                         ap.port = se->s_port;
1696                 else {
1697                         ap.port = htons((int)strtol(cp1, &cp2, 0));
1698                         if (*cp2 != '\0')
1699                                 return -1; /* port not numeric */
1700                 }
1701         } else {
1702                 if ((se = getservbyname("syslog", "udp")))
1703                         ap.port = se->s_port;
1704                 else
1705                         /* sanity, should not happen */
1706                         ap.port = htons(514);
1707         }
1708
1709         /* the regexp's are ugly, but the cleanest way */
1710
1711         if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$",
1712                     REG_EXTENDED))
1713                 /* if RE compilation fails, that's an internal error */
1714                 abort();
1715         if (regexec(&re, s, 0, 0, 0) == 0) {
1716                 /* arg `s' is numeric */
1717                 ap.isnumeric = 1;
1718                 if ((cp1 = strchr(s, '/')) != NULL) {
1719                         *cp1++ = '\0';
1720                         i = atoi(cp1);
1721                         if (i < 0 || i > 32)
1722                                 return -1;
1723                         /* convert masklen to netmask */
1724                         ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
1725                 }
1726                 if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
1727                         return -1;
1728                 if (cp1 == NULL) {
1729                         /* use default netmask */
1730                         if (IN_CLASSA(ntohl(ap.a_addr.s_addr)))
1731                                 ap.a_mask.s_addr = htonl(IN_CLASSA_NET);
1732                         else if (IN_CLASSB(ntohl(ap.a_addr.s_addr)))
1733                                 ap.a_mask.s_addr = htonl(IN_CLASSB_NET);
1734                         else
1735                                 ap.a_mask.s_addr = htonl(IN_CLASSC_NET);
1736                 }
1737         } else {
1738                 /* arg `s' is domain name */
1739                 ap.isnumeric = 0;
1740                 ap.a_name = s;
1741         }
1742         regfree(&re);
1743
1744         if (Debug) {
1745                 printf("allowaddr: rule %d: ", NumAllowed);
1746                 if (ap.isnumeric) {
1747                         printf("numeric, ");
1748                         printf("addr = %s, ",
1749                                addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0));
1750                         printf("mask = %s; ",
1751                                addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0));
1752                 } else
1753                         printf("domainname = %s; ", ap.a_name);
1754                 printf("port = %d\n", ntohs(ap.port));
1755         }
1756
1757         if ((AllowedPeers = realloc(AllowedPeers,
1758                                     ++NumAllowed * sizeof(struct allowedpeer)))
1759             == NULL) {
1760                 fprintf(stderr, "Out of memory!\n");
1761                 exit(EX_OSERR);
1762         }
1763         memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
1764         return 0;
1765 }
1766
1767 /*
1768  * Validate that the remote peer has permission to log to us.
1769  */
1770 int
1771 validate(sin, hname)
1772         struct sockaddr_in *sin;
1773         const char *hname;
1774 {
1775         int i;
1776         size_t l1, l2;
1777         char *cp, name[MAXHOSTNAMELEN];
1778         struct allowedpeer *ap;
1779
1780         if (NumAllowed == 0)
1781                 /* traditional behaviour, allow everything */
1782                 return 1;
1783
1784         strncpy(name, hname, sizeof name);
1785         if (strchr(name, '.') == NULL) {
1786                 strncat(name, ".", sizeof name - strlen(name) - 1);
1787                 strncat(name, LocalDomain, sizeof name - strlen(name) - 1);
1788         }
1789         dprintf("validate: dgram from IP %s, port %d, name %s;\n",
1790                 addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0),
1791                 ntohs(sin->sin_port), name);
1792
1793         /* now, walk down the list */
1794         for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
1795                 if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) {
1796                         dprintf("rejected in rule %d due to port mismatch.\n", i);
1797                         continue;
1798                 }
1799
1800                 if (ap->isnumeric) {
1801                         if ((sin->sin_addr.s_addr & ap->a_mask.s_addr)
1802                             != ap->a_addr.s_addr) {
1803                                 dprintf("rejected in rule %d due to IP mismatch.\n", i);
1804                                 continue;
1805                         }
1806                 } else {
1807                         cp = ap->a_name;
1808                         l1 = strlen(name);
1809                         if (*cp == '*') {
1810                                 /* allow wildmatch */
1811                                 cp++;
1812                                 l2 = strlen(cp);
1813                                 if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
1814                                         dprintf("rejected in rule %d due to name mismatch.\n", i);
1815                                         continue;
1816                                 }
1817                         } else {
1818                                 /* exact match */
1819                                 l2 = strlen(cp);
1820                                 if (l2 != l1 || memcmp(cp, name, l1) != 0) {
1821                                         dprintf("rejected in rule %d due to name mismatch.\n", i);
1822                                         continue;
1823                                 }
1824                         }
1825                 }
1826                 dprintf("accepted in rule %d.\n", i);
1827                 return 1;       /* hooray! */
1828         }
1829         return 0;
1830 }
1831
1832 /*
1833  * Fairly similar to popen(3), but returns an open descriptor, as
1834  * opposed to a FILE *.
1835  */
1836 int
1837 p_open(prog, pid)
1838         char *prog;
1839         pid_t *pid;
1840 {
1841         int pfd[2], nulldesc, i;
1842         sigset_t omask, mask;
1843         char *argv[4]; /* sh -c cmd NULL */
1844         char errmsg[200];
1845
1846         if (pipe(pfd) == -1)
1847                 return -1;
1848         if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
1849                 /* we are royally screwed anyway */
1850                 return -1;
1851
1852         sigemptyset(&mask);
1853         sigaddset(&mask, SIGALRM);
1854         sigaddset(&mask, SIGHUP);
1855         sigprocmask(SIG_BLOCK, &mask, &omask);
1856         switch ((*pid = fork())) {
1857         case -1:
1858                 sigprocmask(SIG_SETMASK, &omask, 0);
1859                 close(nulldesc);
1860                 return -1;
1861
1862         case 0:
1863                 argv[0] = "sh";
1864                 argv[1] = "-c";
1865                 argv[2] = prog;
1866                 argv[3] = NULL;
1867
1868                 alarm(0);
1869                 (void)setsid(); /* Avoid catching SIGHUPs. */
1870
1871                 /*
1872                  * Throw away pending signals, and reset signal
1873                  * behaviour to standard values.
1874                  */
1875                 signal(SIGALRM, SIG_IGN);
1876                 signal(SIGHUP, SIG_IGN);
1877                 sigprocmask(SIG_SETMASK, &omask, 0);
1878                 signal(SIGPIPE, SIG_DFL);
1879                 signal(SIGQUIT, SIG_DFL);
1880                 signal(SIGALRM, SIG_DFL);
1881                 signal(SIGHUP, SIG_DFL);
1882
1883                 dup2(pfd[0], STDIN_FILENO);
1884                 dup2(nulldesc, STDOUT_FILENO);
1885                 dup2(nulldesc, STDERR_FILENO);
1886                 for (i = getdtablesize(); i > 2; i--)
1887                         (void) close(i);
1888
1889                 (void) execvp(_PATH_BSHELL, argv);
1890                 _exit(255);
1891         }
1892
1893         sigprocmask(SIG_SETMASK, &omask, 0);
1894         close(nulldesc);
1895         close(pfd[0]);
1896         /*
1897          * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
1898          * supposed to get an EWOULDBLOCK on writev(2), which is
1899          * caught by the logic above anyway, which will in turn close
1900          * the pipe, and fork a new logging subprocess if necessary.
1901          * The stale subprocess will be killed some time later unless
1902          * it terminated itself due to closing its input pipe (so we
1903          * get rid of really dead puppies).
1904          */
1905         if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
1906                 /* This is bad. */
1907                 (void)snprintf(errmsg, sizeof errmsg,
1908                                "Warning: cannot change pipe to PID %d to "
1909                                "non-blocking behaviour.",
1910                                (int)*pid);
1911                 logerror(errmsg);
1912         }
1913         return pfd[1];
1914 }
1915
1916 void
1917 deadq_enter(pid)
1918         pid_t pid;
1919 {
1920         dq_t p;
1921
1922         p = malloc(sizeof(struct deadq_entry));
1923         if (p == 0) {
1924                 errno = 0;
1925                 logerror("panic: out of virtual memory!");
1926                 exit(1);
1927         }
1928
1929         p->dq_pid = pid;
1930         p->dq_timeout = DQ_TIMO_INIT;
1931         TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
1932 }