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