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