1 /* $NetBSD: syslogd.c,v 1.45 2001/06/08 04:16:28 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 45 #else 46 __RCSID("$NetBSD: syslogd.c,v 1.45 2001/06/08 04:16:28 mrg Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 /* 51 * syslogd -- log system messages 52 * 53 * This program implements a system log. It takes a series of lines. 54 * Each line may have a priority, signified as "<n>" as 55 * the first characters of the line. If this is 56 * not present, a default priority is used. 57 * 58 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 59 * cause it to reread its configuration file. 60 * 61 * Defined Constants: 62 * 63 * MAXLINE -- the maximimum line length that can be handled. 64 * DEFUPRI -- the default priority for user messages 65 * DEFSPRI -- the default priority for kernel messages 66 * 67 * Author: Eric Allman 68 * extensive changes by Ralph Campbell 69 * more extensive changes by Eric Allman (again) 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 /* timeout 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/msgbuf.h> 85 #include <sys/uio.h> 86 #include <sys/poll.h> 87 #include <sys/un.h> 88 #include <sys/time.h> 89 #include <sys/resource.h> 90 #include <sys/sysctl.h> 91 92 #include <netinet/in.h> 93 #include <netdb.h> 94 #include <arpa/inet.h> 95 96 #include <ctype.h> 97 #include <errno.h> 98 #include <fcntl.h> 99 #include <locale.h> 100 #include <setjmp.h> 101 #include <signal.h> 102 #include <stdio.h> 103 #include <stdlib.h> 104 #include <string.h> 105 #include <unistd.h> 106 #include <utmp.h> 107 #include <util.h> 108 #include "pathnames.h" 109 110 #define SYSLOG_NAMES 111 #include <sys/syslog.h> 112 113 char *ConfFile = _PATH_LOGCONF; 114 char ctty[] = _PATH_CONSOLE; 115 116 #define FDMASK(fd) (1 << (fd)) 117 118 #define dprintf if (Debug) printf 119 120 #define MAXUNAMES 20 /* maximum number of user names */ 121 122 /* 123 * Flags to logmsg(). 124 */ 125 126 #define IGN_CONS 0x001 /* don't print on console */ 127 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 128 #define ADDDATE 0x004 /* add a date to the message */ 129 #define MARK 0x008 /* this message is a mark */ 130 131 /* 132 * This structure represents the files that will have log 133 * copies printed. 134 */ 135 136 struct filed { 137 struct filed *f_next; /* next in linked list */ 138 short f_type; /* entry type, see below */ 139 short f_file; /* file descriptor */ 140 time_t f_time; /* time this was last written */ 141 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 142 union { 143 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 144 struct { 145 char f_hname[MAXHOSTNAMELEN+1]; 146 struct addrinfo *f_addr; 147 } f_forw; /* forwarding address */ 148 char f_fname[MAXPATHLEN]; 149 } f_un; 150 char f_prevline[MAXSVLINE]; /* last message logged */ 151 char f_lasttime[16]; /* time of last occurrence */ 152 char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ 153 int f_prevpri; /* pri of f_prevline */ 154 int f_prevlen; /* length of f_prevline */ 155 int f_prevcount; /* repetition cnt of prevline */ 156 int f_repeatcount; /* number of "repeated" msgs */ 157 }; 158 159 /* 160 * Intervals at which we flush out "message repeated" messages, 161 * in seconds after previous message is logged. After each flush, 162 * we move to the next interval until we reach the largest. 163 */ 164 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 165 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 166 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 167 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 168 (f)->f_repeatcount = MAXREPEAT; \ 169 } 170 171 /* values for f_type */ 172 #define F_UNUSED 0 /* unused entry */ 173 #define F_FILE 1 /* regular file */ 174 #define F_TTY 2 /* terminal */ 175 #define F_CONSOLE 3 /* console terminal */ 176 #define F_FORW 4 /* remote machine */ 177 #define F_USERS 5 /* list of users */ 178 #define F_WALL 6 /* everyone logged on */ 179 180 char *TypeNames[7] = { 181 "UNUSED", "FILE", "TTY", "CONSOLE", 182 "FORW", "USERS", "WALL" 183 }; 184 185 struct filed *Files; 186 struct filed consfile; 187 188 int Debug; /* debug flag */ 189 char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ 190 char *LocalDomain; /* our local domain name */ 191 int *finet = NULL; /* Internet datagram sockets */ 192 int Initialized = 0; /* set when we have initialized ourselves */ 193 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 194 int MarkSeq = 0; /* mark sequence number */ 195 int SecureMode = 0; /* listen only on unix domain socks */ 196 int UseNameService = 1; /* make domain name queries */ 197 int NumForwards = 0; /* number of forwarding actions in conf file */ 198 char **LogPaths; /* array of pathnames to read messages from */ 199 200 void cfline __P((char *, struct filed *)); 201 char *cvthname __P((struct sockaddr_storage *)); 202 int decode __P((const char *, CODE *)); 203 void die __P((int)); 204 void domark __P((int)); 205 void fprintlog __P((struct filed *, int, char *)); 206 int getmsgbufsize __P((void)); 207 int* socksetup __P((int)); 208 void init __P((int)); 209 void logerror __P((char *)); 210 void logmsg __P((int, char *, char *, int)); 211 void printline __P((char *, char *)); 212 void printsys __P((char *)); 213 void reapchild __P((int)); 214 void usage __P((void)); 215 void wallmsg __P((struct filed *, struct iovec *)); 216 int main __P((int, char *[])); 217 void logpath_add __P((char ***, int *, int *, char *)); 218 void logpath_fileadd __P((char ***, int *, int *, char *)); 219 220 int 221 main(argc, argv) 222 int argc; 223 char *argv[]; 224 { 225 int ch, *funix, i, j, fklog, len, linesize; 226 int *nfinetix, nfklogix, nfunixbaseix, nfds; 227 int funixsize = 0, funixmaxsize = 0; 228 struct sockaddr_un sunx, fromunix; 229 struct sockaddr_storage frominet; 230 char *p, *line, **pp; 231 struct pollfd *readfds; 232 233 (void)setlocale(LC_ALL, ""); 234 235 while ((ch = getopt(argc, argv, "dnsf:m:p:P:")) != -1) 236 switch(ch) { 237 case 'd': /* debug */ 238 Debug++; 239 break; 240 case 'f': /* configuration file */ 241 ConfFile = optarg; 242 break; 243 case 'm': /* mark interval */ 244 MarkInterval = atoi(optarg) * 60; 245 break; 246 case 'n': /* turn off DNS queries */ 247 UseNameService = 0; 248 break; 249 case 'p': /* path */ 250 logpath_add(&LogPaths, &funixsize, 251 &funixmaxsize, optarg); 252 break; 253 case 'P': /* file of paths */ 254 logpath_fileadd(&LogPaths, &funixsize, 255 &funixmaxsize, optarg); 256 break; 257 case 's': /* no network listen mode */ 258 SecureMode++; 259 break; 260 case '?': 261 default: 262 usage(); 263 } 264 if ((argc -= optind) != 0) 265 usage(); 266 267 if (!Debug) 268 (void)daemon(0, 0); 269 else 270 setlinebuf(stdout); 271 272 consfile.f_type = F_CONSOLE; 273 (void)strcpy(consfile.f_un.f_fname, ctty); 274 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 275 LocalHostName[sizeof(LocalHostName) - 1] = '\0'; 276 if ((p = strchr(LocalHostName, '.')) != NULL) { 277 *p++ = '\0'; 278 LocalDomain = p; 279 } else 280 LocalDomain = ""; 281 linesize = getmsgbufsize(); 282 if (linesize < MAXLINE) 283 linesize = MAXLINE; 284 linesize++; 285 line = malloc(linesize); 286 if (line == NULL) { 287 logerror("couldn't allocate line buffer"); 288 die(0); 289 } 290 (void)signal(SIGTERM, die); 291 (void)signal(SIGINT, Debug ? die : SIG_IGN); 292 (void)signal(SIGQUIT, Debug ? die : SIG_IGN); 293 (void)signal(SIGCHLD, reapchild); 294 (void)signal(SIGALRM, domark); 295 (void)alarm(TIMERINTVL); 296 297 #ifndef SUN_LEN 298 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 299 #endif 300 if (funixsize == 0) 301 logpath_add(&LogPaths, &funixsize, 302 &funixmaxsize, _PATH_LOG); 303 funix = (int *)malloc(sizeof(int) * funixsize); 304 if (funix == NULL) { 305 logerror("couldn't allocate funix descriptors"); 306 die(0); 307 } 308 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 309 dprintf("making unix dgram socket %s\n", *pp); 310 unlink(*pp); 311 memset(&sunx, 0, sizeof(sunx)); 312 sunx.sun_family = AF_LOCAL; 313 (void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path)); 314 funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0); 315 if (funix[j] < 0 || bind(funix[j], 316 (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 317 chmod(*pp, 0666) < 0) { 318 int serrno = errno; 319 (void)snprintf(line, sizeof line, 320 "cannot create %s", *pp); 321 errno = serrno; 322 logerror(line); 323 errno = serrno; 324 dprintf("cannot create %s (%d)\n", *pp, errno); 325 die(0); 326 } 327 dprintf("listening on unix dgram socket %s\n", *pp); 328 } 329 330 init(0); 331 332 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) { 333 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 334 } else { 335 dprintf("listening on kernel log %s\n", _PATH_KLOG); 336 } 337 338 /* tuck my process id away, if i'm not in debug mode */ 339 if (Debug == 0) 340 pidfile(NULL); 341 342 dprintf("off & running....\n"); 343 344 (void)signal(SIGHUP, init); 345 346 /* setup pollfd set. */ 347 readfds = (struct pollfd *)malloc(sizeof(struct pollfd) * 348 (funixsize + (finet ? *finet : 0) + 1)); 349 if (readfds == NULL) { 350 logerror("couldn't allocate pollfds"); 351 die(0); 352 } 353 nfds = 0; 354 if (fklog >= 0) { 355 nfklogix = nfds++; 356 readfds[nfklogix].fd = fklog; 357 readfds[nfklogix].events = POLLIN | POLLPRI; 358 } 359 if (finet && !SecureMode) { 360 nfinetix = malloc(*finet * sizeof(*nfinetix)); 361 for (j = 0; j < *finet; j++) { 362 nfinetix[j] = nfds++; 363 readfds[nfinetix[j]].fd = finet[j+1]; 364 readfds[nfinetix[j]].events = POLLIN | POLLPRI; 365 } 366 } 367 nfunixbaseix = nfds; 368 for (j = 0, pp = LogPaths; *pp; pp++) { 369 readfds[nfds].fd = funix[j++]; 370 readfds[nfds++].events = POLLIN | POLLPRI; 371 } 372 373 for (;;) { 374 int rv; 375 376 rv = poll(readfds, nfds, INFTIM); 377 if (rv == 0) 378 continue; 379 if (rv < 0) { 380 if (errno != EINTR) 381 logerror("poll"); 382 continue; 383 } 384 dprintf("got a message (%d)\n", rv); 385 if (fklog >= 0 && 386 (readfds[nfklogix].revents & (POLLIN | POLLPRI))) { 387 dprintf("kernel log active\n"); 388 i = read(fklog, line, linesize - 1); 389 if (i > 0) { 390 line[i] = '\0'; 391 printsys(line); 392 } else if (i < 0 && errno != EINTR) { 393 logerror("klog"); 394 fklog = -1; 395 } 396 } 397 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 398 if ((readfds[nfunixbaseix + j].revents & 399 (POLLIN | POLLPRI)) == 0) 400 continue; 401 402 dprintf("unix socket (%s) active\n", *pp); 403 len = sizeof(fromunix); 404 i = recvfrom(funix[j], line, MAXLINE, 0, 405 (struct sockaddr *)&fromunix, &len); 406 if (i > 0) { 407 line[i] = '\0'; 408 printline(LocalHostName, line); 409 } else if (i < 0 && errno != EINTR) { 410 char buf[MAXPATHLEN]; 411 int serrno = errno; 412 413 (void)snprintf(buf, sizeof buf, 414 "recvfrom unix %s", *pp); 415 errno = serrno; 416 logerror(buf); 417 } 418 } 419 if (finet && !SecureMode) { 420 for (j = 0; j < *finet; j++) { 421 if (readfds[nfinetix[j]].revents & 422 (POLLIN | POLLPRI)) { 423 dprintf("inet socket active\n"); 424 len = sizeof(frominet); 425 i = recvfrom(finet[j+1], line, MAXLINE, 426 0, (struct sockaddr *)&frominet, 427 &len); 428 if (i > 0) { 429 line[i] = '\0'; 430 printline(cvthname(&frominet), 431 line); 432 } else if (i < 0 && errno != EINTR) 433 logerror("recvfrom inet"); 434 } 435 } 436 } 437 } 438 } 439 440 void 441 usage() 442 { 443 444 (void)fprintf(stderr, 445 "usage: %s [-ds] [-f conffile] [-m markinterval] [-P logpathfile] [-p logpath1] [-p logpath2 ..]\n", 446 getprogname()); 447 exit(1); 448 } 449 450 /* 451 * given a pointer to an array of char *'s, a pointer to it's current 452 * size and current allocated max size, and a new char * to add, add 453 * it, update everything as necessary, possibly allocating a new array 454 */ 455 void 456 logpath_add(lp, szp, maxszp, new) 457 char ***lp; 458 int *szp; 459 int *maxszp; 460 char *new; 461 { 462 463 dprintf("adding %s to the %p logpath list\n", new, *lp); 464 if (*szp == *maxszp) { 465 if (*maxszp == 0) { 466 *maxszp = 4; /* start of with enough for now */ 467 *lp = NULL; 468 } 469 else 470 *maxszp *= 2; 471 *lp = realloc(*lp, sizeof(char *) * (*maxszp + 1)); 472 if (*lp == NULL) { 473 logerror("couldn't allocate line buffer"); 474 die(0); 475 } 476 } 477 (*lp)[(*szp)++] = new; 478 (*lp)[(*szp)] = NULL; /* always keep it NULL terminated */ 479 } 480 481 /* do a file of log sockets */ 482 void 483 logpath_fileadd(lp, szp, maxszp, file) 484 char ***lp; 485 int *szp; 486 int *maxszp; 487 char *file; 488 { 489 FILE *fp; 490 char *line; 491 size_t len; 492 493 fp = fopen(file, "r"); 494 if (fp == NULL) { 495 int serrno = errno; 496 497 dprintf("can't open %s (%d)\n", file, errno); 498 errno = serrno; 499 logerror("could not open socket file list"); 500 die(0); 501 } 502 503 while ((line = fgetln(fp, &len))) { 504 line[len - 1] = 0; 505 logpath_add(lp, szp, maxszp, line); 506 } 507 fclose(fp); 508 } 509 510 /* 511 * Take a raw input line, decode the message, and print the message 512 * on the appropriate log files. 513 */ 514 void 515 printline(hname, msg) 516 char *hname; 517 char *msg; 518 { 519 int c, pri; 520 char *p, *q, line[MAXLINE + 1]; 521 522 /* test for special codes */ 523 pri = DEFUPRI; 524 p = msg; 525 if (*p == '<') { 526 pri = 0; 527 while (isdigit(*++p)) 528 pri = 10 * pri + (*p - '0'); 529 if (*p == '>') 530 ++p; 531 } 532 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 533 pri = DEFUPRI; 534 535 /* don't allow users to log kernel messages */ 536 if (LOG_FAC(pri) == LOG_KERN) 537 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 538 539 q = line; 540 541 while ((c = *p++) != '\0' && 542 q < &line[sizeof(line) - 2]) { 543 c &= 0177; 544 if (iscntrl(c)) 545 if (c == '\n') 546 *q++ = ' '; 547 else if (c == '\t') 548 *q++ = '\t'; 549 else { 550 *q++ = '^'; 551 *q++ = c ^ 0100; 552 } 553 else 554 *q++ = c; 555 } 556 *q = '\0'; 557 558 logmsg(pri, line, hname, 0); 559 } 560 561 /* 562 * Take a raw input line from /dev/klog, split and format similar to syslog(). 563 */ 564 void 565 printsys(msg) 566 char *msg; 567 { 568 int c, pri, flags; 569 char *lp, *p, *q, line[MAXLINE + 1]; 570 571 (void)strcpy(line, _PATH_UNIX); 572 (void)strcat(line, ": "); 573 lp = line + strlen(line); 574 for (p = msg; *p != '\0'; ) { 575 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 576 pri = DEFSPRI; 577 if (*p == '<') { 578 pri = 0; 579 while (isdigit(*++p)) 580 pri = 10 * pri + (*p - '0'); 581 if (*p == '>') 582 ++p; 583 } else { 584 /* kernel printf's come out on console */ 585 flags |= IGN_CONS; 586 } 587 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 588 pri = DEFSPRI; 589 q = lp; 590 while (*p != '\0' && (c = *p++) != '\n' && 591 q < &line[MAXLINE]) 592 *q++ = c; 593 *q = '\0'; 594 logmsg(pri, line, LocalHostName, flags); 595 } 596 } 597 598 time_t now; 599 600 /* 601 * Log a message to the appropriate log files, users, etc. based on 602 * the priority. 603 */ 604 void 605 logmsg(pri, msg, from, flags) 606 int pri; 607 char *msg, *from; 608 int flags; 609 { 610 struct filed *f; 611 int fac, msglen, omask, prilev; 612 char *timestamp; 613 614 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 615 pri, flags, from, msg); 616 617 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 618 619 /* 620 * Check to see if msg looks non-standard. 621 */ 622 msglen = strlen(msg); 623 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 624 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 625 flags |= ADDDATE; 626 627 (void)time(&now); 628 if (flags & ADDDATE) 629 timestamp = ctime(&now) + 4; 630 else { 631 timestamp = msg; 632 msg += 16; 633 msglen -= 16; 634 } 635 636 /* extract facility and priority level */ 637 if (flags & MARK) 638 fac = LOG_NFACILITIES; 639 else 640 fac = LOG_FAC(pri); 641 prilev = LOG_PRI(pri); 642 643 /* log the message to the particular outputs */ 644 if (!Initialized) { 645 f = &consfile; 646 f->f_file = open(ctty, O_WRONLY, 0); 647 648 if (f->f_file >= 0) { 649 fprintlog(f, flags, msg); 650 (void)close(f->f_file); 651 } 652 (void)sigsetmask(omask); 653 return; 654 } 655 for (f = Files; f; f = f->f_next) { 656 /* skip messages that are incorrect priority */ 657 if (f->f_pmask[fac] < prilev || 658 f->f_pmask[fac] == INTERNAL_NOPRI) 659 continue; 660 661 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 662 continue; 663 664 /* don't output marks to recently written files */ 665 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 666 continue; 667 668 /* 669 * suppress duplicate lines to this file 670 */ 671 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 672 !strcmp(msg, f->f_prevline) && 673 !strcmp(from, f->f_prevhost)) { 674 (void)strncpy(f->f_lasttime, timestamp, 15); 675 f->f_prevcount++; 676 dprintf("msg repeated %d times, %ld sec of %d\n", 677 f->f_prevcount, (long)(now - f->f_time), 678 repeatinterval[f->f_repeatcount]); 679 /* 680 * If domark would have logged this by now, 681 * flush it now (so we don't hold isolated messages), 682 * but back off so we'll flush less often 683 * in the future. 684 */ 685 if (now > REPEATTIME(f)) { 686 fprintlog(f, flags, (char *)NULL); 687 BACKOFF(f); 688 } 689 } else { 690 /* new line, save it */ 691 if (f->f_prevcount) 692 fprintlog(f, 0, (char *)NULL); 693 f->f_repeatcount = 0; 694 f->f_prevpri = pri; 695 (void)strncpy(f->f_lasttime, timestamp, 15); 696 (void)strncpy(f->f_prevhost, from, 697 sizeof(f->f_prevhost)); 698 if (msglen < MAXSVLINE) { 699 f->f_prevlen = msglen; 700 (void)strcpy(f->f_prevline, msg); 701 fprintlog(f, flags, (char *)NULL); 702 } else { 703 f->f_prevline[0] = 0; 704 f->f_prevlen = 0; 705 fprintlog(f, flags, msg); 706 } 707 } 708 } 709 (void)sigsetmask(omask); 710 } 711 712 void 713 fprintlog(f, flags, msg) 714 struct filed *f; 715 int flags; 716 char *msg; 717 { 718 struct iovec iov[6]; 719 struct iovec *v; 720 struct addrinfo *r; 721 int j, l, lsent; 722 char line[MAXLINE + 1], repbuf[80], greetings[200]; 723 724 v = iov; 725 if (f->f_type == F_WALL) { 726 v->iov_base = greetings; 727 v->iov_len = snprintf(greetings, sizeof greetings, 728 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 729 f->f_prevhost, ctime(&now)); 730 v++; 731 v->iov_base = ""; 732 v->iov_len = 0; 733 v++; 734 } else { 735 v->iov_base = f->f_lasttime; 736 v->iov_len = 15; 737 v++; 738 v->iov_base = " "; 739 v->iov_len = 1; 740 v++; 741 } 742 v->iov_base = f->f_prevhost; 743 v->iov_len = strlen(v->iov_base); 744 v++; 745 v->iov_base = " "; 746 v->iov_len = 1; 747 v++; 748 749 if (msg) { 750 v->iov_base = msg; 751 v->iov_len = strlen(msg); 752 } else if (f->f_prevcount > 1) { 753 v->iov_base = repbuf; 754 v->iov_len = snprintf(repbuf, sizeof repbuf, 755 "last message repeated %d times", f->f_prevcount); 756 } else { 757 v->iov_base = f->f_prevline; 758 v->iov_len = f->f_prevlen; 759 } 760 v++; 761 762 dprintf("Logging to %s", TypeNames[f->f_type]); 763 f->f_time = now; 764 765 switch (f->f_type) { 766 case F_UNUSED: 767 dprintf("\n"); 768 break; 769 770 case F_FORW: 771 dprintf(" %s\n", f->f_un.f_forw.f_hname); 772 /* 773 * check for local vs remote messages 774 * (from FreeBSD PR#bin/7055) 775 */ 776 if (strcmp(f->f_prevhost, LocalHostName)) { 777 l = snprintf(line, sizeof(line) - 1, 778 "<%d>%.15s [%s]: %s", 779 f->f_prevpri, (char *) iov[0].iov_base, 780 f->f_prevhost, (char *) iov[4].iov_base); 781 } else { 782 l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s", 783 f->f_prevpri, (char *) iov[0].iov_base, 784 (char *) iov[4].iov_base); 785 } 786 if (l > MAXLINE) 787 l = MAXLINE; 788 if (finet) { 789 for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 790 for (j = 0; j < *finet; j++) { 791 #if 0 792 /* 793 * should we check AF first, or just 794 * trial and error? FWD 795 */ 796 if (r->ai_family == 797 address_family_of(finet[j+1])) 798 #endif 799 lsent = sendto(finet[j+1], line, l, 0, 800 r->ai_addr, r->ai_addrlen); 801 if (lsent == l) 802 break; 803 } 804 } 805 if (lsent != l) { 806 f->f_type = F_UNUSED; 807 logerror("sendto"); 808 } 809 } 810 break; 811 812 case F_CONSOLE: 813 if (flags & IGN_CONS) { 814 dprintf(" (ignored)\n"); 815 break; 816 } 817 /* FALLTHROUGH */ 818 819 case F_TTY: 820 case F_FILE: 821 dprintf(" %s\n", f->f_un.f_fname); 822 if (f->f_type != F_FILE) { 823 v->iov_base = "\r\n"; 824 v->iov_len = 2; 825 } else { 826 v->iov_base = "\n"; 827 v->iov_len = 1; 828 } 829 again: 830 if (writev(f->f_file, iov, 6) < 0) { 831 int e = errno; 832 (void)close(f->f_file); 833 /* 834 * Check for errors on TTY's due to loss of tty 835 */ 836 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 837 f->f_file = open(f->f_un.f_fname, 838 O_WRONLY|O_APPEND, 0); 839 if (f->f_file < 0) { 840 f->f_type = F_UNUSED; 841 logerror(f->f_un.f_fname); 842 } else 843 goto again; 844 } else { 845 f->f_type = F_UNUSED; 846 errno = e; 847 logerror(f->f_un.f_fname); 848 } 849 } else if (flags & SYNC_FILE) 850 (void)fsync(f->f_file); 851 break; 852 853 case F_USERS: 854 case F_WALL: 855 dprintf("\n"); 856 v->iov_base = "\r\n"; 857 v->iov_len = 2; 858 wallmsg(f, iov); 859 break; 860 } 861 f->f_prevcount = 0; 862 } 863 864 /* 865 * WALLMSG -- Write a message to the world at large 866 * 867 * Write the specified message to either the entire 868 * world, or a list of approved users. 869 */ 870 void 871 wallmsg(f, iov) 872 struct filed *f; 873 struct iovec *iov; 874 { 875 static int reenter; /* avoid calling ourselves */ 876 FILE *uf; 877 struct utmp ut; 878 int i; 879 char *p; 880 char line[sizeof(ut.ut_line) + 1]; 881 882 if (reenter++) 883 return; 884 if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { 885 logerror(_PATH_UTMP); 886 reenter = 0; 887 return; 888 } 889 /* NOSTRICT */ 890 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 891 if (ut.ut_name[0] == '\0') 892 continue; 893 strncpy(line, ut.ut_line, sizeof(ut.ut_line)); 894 line[sizeof(ut.ut_line)] = '\0'; 895 if (f->f_type == F_WALL) { 896 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 897 errno = 0; /* already in msg */ 898 logerror(p); 899 } 900 continue; 901 } 902 /* should we send the message to this user? */ 903 for (i = 0; i < MAXUNAMES; i++) { 904 if (!f->f_un.f_uname[i][0]) 905 break; 906 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 907 UT_NAMESIZE)) { 908 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 909 != NULL) { 910 errno = 0; /* already in msg */ 911 logerror(p); 912 } 913 break; 914 } 915 } 916 } 917 (void)fclose(uf); 918 reenter = 0; 919 } 920 921 void 922 reapchild(signo) 923 int signo; 924 { 925 union wait status; 926 927 while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0) 928 ; 929 } 930 931 /* 932 * Return a printable representation of a host address. 933 */ 934 char * 935 cvthname(f) 936 struct sockaddr_storage *f; 937 { 938 int error; 939 char *p; 940 #ifdef KAME_SCOPEID 941 const int niflag = NI_DGRAM | NI_WITHSCOPEID; 942 #else 943 const int niflag = NI_DGRAM; 944 #endif 945 static char host[NI_MAXHOST], ip[NI_MAXHOST]; 946 947 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 948 ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag); 949 950 dprintf("cvthname(%s)\n", ip); 951 952 if (error) { 953 dprintf("Malformed from address %s\n", gai_strerror(error)); 954 return ("???"); 955 } 956 957 if (!UseNameService) 958 return (ip); 959 960 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 961 host, sizeof host, NULL, 0, niflag); 962 if (error) { 963 dprintf("Host name for your address (%s) unknown\n", ip); 964 return (ip); 965 } 966 if ((p = strchr(host, '.')) && strcmp(p + 1, LocalDomain) == 0) 967 *p = '\0'; 968 return (host); 969 } 970 971 void 972 domark(signo) 973 int signo; 974 { 975 struct filed *f; 976 977 now = time((time_t *)NULL); 978 MarkSeq += TIMERINTVL; 979 if (MarkSeq >= MarkInterval) { 980 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 981 MarkSeq = 0; 982 } 983 984 for (f = Files; f; f = f->f_next) { 985 if (f->f_prevcount && now >= REPEATTIME(f)) { 986 dprintf("flush %s: repeated %d times, %d sec.\n", 987 TypeNames[f->f_type], f->f_prevcount, 988 repeatinterval[f->f_repeatcount]); 989 fprintlog(f, 0, (char *)NULL); 990 BACKOFF(f); 991 } 992 } 993 (void)alarm(TIMERINTVL); 994 } 995 996 /* 997 * Print syslogd errors some place. 998 */ 999 void 1000 logerror(type) 1001 char *type; 1002 { 1003 char buf[100]; 1004 1005 if (errno) 1006 (void)snprintf(buf, 1007 sizeof(buf), "syslogd: %s: %s", type, strerror(errno)); 1008 else 1009 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 1010 errno = 0; 1011 dprintf("%s\n", buf); 1012 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1013 } 1014 1015 void 1016 die(signo) 1017 int signo; 1018 { 1019 struct filed *f; 1020 char buf[100], **p; 1021 1022 for (f = Files; f != NULL; f = f->f_next) { 1023 /* flush any pending output */ 1024 if (f->f_prevcount) 1025 fprintlog(f, 0, (char *)NULL); 1026 } 1027 if (signo) { 1028 dprintf("syslogd: exiting on signal %d\n", signo); 1029 (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); 1030 errno = 0; 1031 logerror(buf); 1032 } 1033 for (p = LogPaths; p && *p; p++) 1034 unlink(*p); 1035 exit(0); 1036 } 1037 1038 /* 1039 * INIT -- Initialize syslogd from configuration table 1040 */ 1041 void 1042 init(signo) 1043 int signo; 1044 { 1045 int i; 1046 FILE *cf; 1047 struct filed *f, *next, **nextp; 1048 char *p; 1049 char cline[LINE_MAX]; 1050 1051 dprintf("init\n"); 1052 1053 /* 1054 * Close all open log files. 1055 */ 1056 Initialized = 0; 1057 for (f = Files; f != NULL; f = next) { 1058 /* flush any pending output */ 1059 if (f->f_prevcount) 1060 fprintlog(f, 0, (char *)NULL); 1061 1062 switch (f->f_type) { 1063 case F_FILE: 1064 case F_TTY: 1065 case F_CONSOLE: 1066 (void)close(f->f_file); 1067 break; 1068 case F_FORW: 1069 if (f->f_un.f_forw.f_addr) 1070 freeaddrinfo(f->f_un.f_forw.f_addr); 1071 break; 1072 } 1073 next = f->f_next; 1074 free((char *)f); 1075 } 1076 Files = NULL; 1077 nextp = &Files; 1078 1079 /* 1080 * Close all open sockets 1081 */ 1082 1083 if (finet) { 1084 for (i = 0; i < *finet; i++) { 1085 if (close(finet[i+1]) < 0) { 1086 logerror("close"); 1087 die(0); 1088 } 1089 } 1090 } 1091 1092 /* 1093 * Reset counter of forwarding actions 1094 */ 1095 1096 NumForwards=0; 1097 1098 /* open the configuration file */ 1099 if ((cf = fopen(ConfFile, "r")) == NULL) { 1100 dprintf("cannot open %s\n", ConfFile); 1101 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1102 cfline("*.ERR\t/dev/console", *nextp); 1103 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1104 cfline("*.PANIC\t*", (*nextp)->f_next); 1105 Initialized = 1; 1106 return; 1107 } 1108 1109 /* 1110 * Foreach line in the conf table, open that file. 1111 */ 1112 f = NULL; 1113 while (fgets(cline, sizeof(cline), cf) != NULL) { 1114 /* 1115 * check for end-of-section, comments, strip off trailing 1116 * spaces and newline character. 1117 */ 1118 for (p = cline; isspace(*p); ++p) 1119 continue; 1120 if (*p == '\0' || *p == '#') 1121 continue; 1122 for (p = strchr(cline, '\0'); isspace(*--p);) 1123 continue; 1124 *++p = '\0'; 1125 f = (struct filed *)calloc(1, sizeof(*f)); 1126 *nextp = f; 1127 nextp = &f->f_next; 1128 cfline(cline, f); 1129 } 1130 1131 /* close the configuration file */ 1132 (void)fclose(cf); 1133 1134 Initialized = 1; 1135 1136 if (Debug) { 1137 for (f = Files; f; f = f->f_next) { 1138 for (i = 0; i <= LOG_NFACILITIES; i++) 1139 if (f->f_pmask[i] == INTERNAL_NOPRI) 1140 printf("X "); 1141 else 1142 printf("%d ", f->f_pmask[i]); 1143 printf("%s: ", TypeNames[f->f_type]); 1144 switch (f->f_type) { 1145 case F_FILE: 1146 case F_TTY: 1147 case F_CONSOLE: 1148 printf("%s", f->f_un.f_fname); 1149 break; 1150 1151 case F_FORW: 1152 printf("%s", f->f_un.f_forw.f_hname); 1153 break; 1154 1155 case F_USERS: 1156 for (i = 0; 1157 i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1158 printf("%s, ", f->f_un.f_uname[i]); 1159 break; 1160 } 1161 printf("\n"); 1162 } 1163 } 1164 1165 finet = socksetup(PF_UNSPEC); 1166 if (finet) { 1167 if (SecureMode) { 1168 for (i = 0; i < *finet; i++) { 1169 if (shutdown(finet[i+1], SHUT_RD) < 0) { 1170 logerror("shutdown"); 1171 die(0); 1172 } 1173 } 1174 } else 1175 dprintf("listening on inet and/or inet6 socket\n"); 1176 dprintf("sending on inet and/or inet6 socket\n"); 1177 } 1178 1179 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 1180 dprintf("syslogd: restarted\n"); 1181 } 1182 1183 /* 1184 * Crack a configuration file line 1185 */ 1186 void 1187 cfline(line, f) 1188 char *line; 1189 struct filed *f; 1190 { 1191 struct addrinfo hints, *res; 1192 int error, i, pri; 1193 char *bp, *p, *q; 1194 char buf[MAXLINE], ebuf[100]; 1195 1196 dprintf("cfline(%s)\n", line); 1197 1198 errno = 0; /* keep strerror() stuff out of logerror messages */ 1199 1200 /* clear out file entry */ 1201 memset(f, 0, sizeof(*f)); 1202 for (i = 0; i <= LOG_NFACILITIES; i++) 1203 f->f_pmask[i] = INTERNAL_NOPRI; 1204 1205 /* scan through the list of selectors */ 1206 for (p = line; *p && *p != '\t';) { 1207 1208 /* find the end of this facility name list */ 1209 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1210 continue; 1211 1212 /* collect priority name */ 1213 for (bp = buf; *q && !strchr("\t,;", *q); ) 1214 *bp++ = *q++; 1215 *bp = '\0'; 1216 1217 /* skip cruft */ 1218 while (strchr(", ;", *q)) 1219 q++; 1220 1221 /* decode priority name */ 1222 if (*buf == '*') 1223 pri = LOG_PRIMASK + 1; 1224 else { 1225 pri = decode(buf, prioritynames); 1226 if (pri < 0) { 1227 (void)snprintf(ebuf, sizeof ebuf, 1228 "unknown priority name \"%s\"", buf); 1229 logerror(ebuf); 1230 return; 1231 } 1232 } 1233 1234 /* scan facilities */ 1235 while (*p && !strchr("\t.;", *p)) { 1236 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1237 *bp++ = *p++; 1238 *bp = '\0'; 1239 if (*buf == '*') 1240 for (i = 0; i < LOG_NFACILITIES; i++) 1241 f->f_pmask[i] = pri; 1242 else { 1243 i = decode(buf, facilitynames); 1244 if (i < 0) { 1245 (void)snprintf(ebuf, sizeof ebuf, 1246 "unknown facility name \"%s\"", 1247 buf); 1248 logerror(ebuf); 1249 return; 1250 } 1251 f->f_pmask[i >> 3] = pri; 1252 } 1253 while (*p == ',' || *p == ' ') 1254 p++; 1255 } 1256 1257 p = q; 1258 } 1259 1260 /* skip to action part */ 1261 while (*p == '\t') 1262 p++; 1263 1264 switch (*p) 1265 { 1266 case '@': 1267 (void)strcpy(f->f_un.f_forw.f_hname, ++p); 1268 memset(&hints, 0, sizeof(hints)); 1269 hints.ai_family = AF_UNSPEC; 1270 hints.ai_socktype = SOCK_DGRAM; 1271 hints.ai_protocol = 0; 1272 error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, 1273 &res); 1274 if (error) { 1275 logerror(gai_strerror(error)); 1276 break; 1277 } 1278 f->f_un.f_forw.f_addr = res; 1279 f->f_type = F_FORW; 1280 NumForwards++; 1281 break; 1282 1283 case '/': 1284 (void)strcpy(f->f_un.f_fname, p); 1285 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1286 f->f_type = F_UNUSED; 1287 logerror(p); 1288 break; 1289 } 1290 if (isatty(f->f_file)) 1291 f->f_type = F_TTY; 1292 else 1293 f->f_type = F_FILE; 1294 if (strcmp(p, ctty) == 0) 1295 f->f_type = F_CONSOLE; 1296 break; 1297 1298 case '*': 1299 f->f_type = F_WALL; 1300 break; 1301 1302 default: 1303 for (i = 0; i < MAXUNAMES && *p; i++) { 1304 for (q = p; *q && *q != ','; ) 1305 q++; 1306 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1307 if ((q - p) > UT_NAMESIZE) 1308 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1309 else 1310 f->f_un.f_uname[i][q - p] = '\0'; 1311 while (*q == ',' || *q == ' ') 1312 q++; 1313 p = q; 1314 } 1315 f->f_type = F_USERS; 1316 break; 1317 } 1318 } 1319 1320 1321 /* 1322 * Decode a symbolic name to a numeric value 1323 */ 1324 int 1325 decode(name, codetab) 1326 const char *name; 1327 CODE *codetab; 1328 { 1329 CODE *c; 1330 char *p, buf[40]; 1331 1332 if (isdigit(*name)) 1333 return (atoi(name)); 1334 1335 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1336 if (isupper(*name)) 1337 *p = tolower(*name); 1338 else 1339 *p = *name; 1340 } 1341 *p = '\0'; 1342 for (c = codetab; c->c_name; c++) 1343 if (!strcmp(buf, c->c_name)) 1344 return (c->c_val); 1345 1346 return (-1); 1347 } 1348 1349 /* 1350 * Retrieve the size of the kernel message buffer, via sysctl. 1351 */ 1352 int 1353 getmsgbufsize() 1354 { 1355 int msgbufsize, mib[2]; 1356 size_t size; 1357 1358 mib[0] = CTL_KERN; 1359 mib[1] = KERN_MSGBUFSIZE; 1360 size = sizeof msgbufsize; 1361 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1362 dprintf("couldn't get kern.msgbufsize\n"); 1363 return (0); 1364 } 1365 return (msgbufsize); 1366 } 1367 1368 int * 1369 socksetup(af) 1370 int af; 1371 { 1372 struct addrinfo hints, *res, *r; 1373 int error, maxs, *s, *socks; 1374 1375 if(SecureMode && !NumForwards) 1376 return(NULL); 1377 1378 memset(&hints, 0, sizeof(hints)); 1379 hints.ai_flags = AI_PASSIVE; 1380 hints.ai_family = af; 1381 hints.ai_socktype = SOCK_DGRAM; 1382 error = getaddrinfo(NULL, "syslog", &hints, &res); 1383 if (error) { 1384 logerror(gai_strerror(error)); 1385 errno = 0; 1386 die(0); 1387 } 1388 1389 /* Count max number of sockets we may open */ 1390 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 1391 continue; 1392 socks = malloc ((maxs+1) * sizeof(int)); 1393 if (!socks) { 1394 logerror("couldn't allocate memory for sockets"); 1395 die(0); 1396 } 1397 1398 *socks = 0; /* num of sockets counter at start of array */ 1399 s = socks+1; 1400 for (r = res; r; r = r->ai_next) { 1401 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 1402 if (*s < 0) { 1403 logerror("socket"); 1404 continue; 1405 } 1406 if (!SecureMode && bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 1407 close (*s); 1408 logerror("bind"); 1409 continue; 1410 } 1411 1412 *socks = *socks + 1; 1413 s++; 1414 } 1415 1416 if (*socks == 0) { 1417 free (socks); 1418 if(Debug) 1419 return(NULL); 1420 else 1421 die(0); 1422 } 1423 if (res) 1424 freeaddrinfo(res); 1425 1426 return(socks); 1427 } 1428