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