1 /* $OpenBSD: syslogd.c,v 1.74 2004/01/19 16:06:05 millert 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static const char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 41 #else 42 static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.74 2004/01/19 16:06:05 millert Exp $"; 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 maximum 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 * memory buffer logging by Damien Miller 67 */ 68 69 #define MAXLINE 1024 /* maximum line length */ 70 #define MIN_MEMBUF (MAXLINE * 4) /* Minimum memory buffer size */ 71 #define MAX_MEMBUF (256 * 1024) /* Maximum memory buffer size */ 72 #define MAX_MEMBUF_NAME 64 /* Max length of membuf log name */ 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/sysctl.h> 87 #include <sys/un.h> 88 #include <sys/time.h> 89 #include <sys/resource.h> 90 91 #include <netinet/in.h> 92 #include <netdb.h> 93 #include <arpa/inet.h> 94 95 #include <ctype.h> 96 #include <errno.h> 97 #include <err.h> 98 #include <fcntl.h> 99 #include <paths.h> 100 #include <poll.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 <vis.h> 108 109 #define SYSLOG_NAMES 110 #include <sys/syslog.h> 111 112 #include "syslogd.h" 113 114 char *ConfFile = _PATH_LOGCONF; 115 const char ctty[] = _PATH_CONSOLE; 116 117 #define MAXUNAMES 20 /* maximum number of user names */ 118 119 120 /* 121 * Flags to logmsg(). 122 */ 123 124 #define IGN_CONS 0x001 /* don't print on console */ 125 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 126 #define ADDDATE 0x004 /* add a date to the message */ 127 #define MARK 0x008 /* this message is a mark */ 128 129 /* 130 * This structure represents the files that will have log 131 * copies printed. 132 */ 133 134 struct filed { 135 struct filed *f_next; /* next in linked list */ 136 short f_type; /* entry type, see below */ 137 short f_file; /* file descriptor */ 138 time_t f_time; /* time this was last written */ 139 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 140 char *f_program; /* program this applies to */ 141 union { 142 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 143 struct { 144 char f_hname[MAXHOSTNAMELEN]; 145 struct sockaddr_in f_addr; 146 } f_forw; /* forwarding address */ 147 char f_fname[MAXPATHLEN]; 148 struct { 149 char f_mname[MAX_MEMBUF_NAME]; 150 struct ringbuf *f_rb; 151 } f_mb; /* Memory buffer */ 152 } f_un; 153 char f_prevline[MAXSVLINE]; /* last message logged */ 154 char f_lasttime[16]; /* time of last occurrence */ 155 char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */ 156 int f_prevpri; /* pri of f_prevline */ 157 int f_prevlen; /* length of f_prevline */ 158 int f_prevcount; /* repetition cnt of prevline */ 159 int f_repeatcount; /* number of "repeated" msgs */ 160 }; 161 162 /* 163 * Intervals at which we flush out "message repeated" messages, 164 * in seconds after previous message is logged. After each flush, 165 * we move to the next interval until we reach the largest. 166 */ 167 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 168 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 169 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 170 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 171 (f)->f_repeatcount = MAXREPEAT; \ 172 } 173 174 /* values for f_type */ 175 #define F_UNUSED 0 /* unused entry */ 176 #define F_FILE 1 /* regular file */ 177 #define F_TTY 2 /* terminal */ 178 #define F_CONSOLE 3 /* console terminal */ 179 #define F_FORW 4 /* remote machine */ 180 #define F_USERS 5 /* list of users */ 181 #define F_WALL 6 /* everyone logged on */ 182 #define F_MEMBUF 7 /* memory buffer */ 183 184 char *TypeNames[8] = { 185 "UNUSED", "FILE", "TTY", "CONSOLE", 186 "FORW", "USERS", "WALL", "MEMBUF" 187 }; 188 189 struct filed *Files; 190 struct filed consfile; 191 192 int nfunix = 1; /* Number of Unix domain sockets requested */ 193 char *funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */ 194 int Debug; /* debug flag */ 195 int Startup = 1; /* startup flag */ 196 char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 197 char *LocalDomain; /* our local domain name */ 198 int InetInuse = 0; /* non-zero if INET sockets are being used */ 199 int LogPort; /* port number for INET connections */ 200 int Initialized = 0; /* set when we have initialized ourselves */ 201 202 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 203 int MarkSeq = 0; /* mark sequence number */ 204 int SecureMode = 1; /* when true, speak only unix domain socks */ 205 int NoDNS = 0; /* when true, will refrain from doing DNS lookups */ 206 207 char *ctlsock_path = NULL; /* Path to control socket */ 208 209 #define CTL_READING_CMD 1 210 #define CTL_WRITING_REPLY 2 211 int ctl_state = 0; /* What the control socket is up to */ 212 213 size_t ctl_cmd_bytes = 0; /* number of bytes of ctl_cmd read */ 214 struct { 215 #define CMD_READ 1 /* Read out log */ 216 #define CMD_READ_CLEAR 2 /* Read and clear log */ 217 #define CMD_CLEAR 3 /* Clear log */ 218 #define CMD_LIST 4 /* List available logs */ 219 int cmd; 220 char logname[MAX_MEMBUF_NAME]; 221 } ctl_cmd; 222 223 char *ctl_reply = NULL; /* Buffer for control connection reply */ 224 size_t ctl_reply_size = 0; /* Number of bytes used in reply */ 225 size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */ 226 227 struct pollfd pfd[N_PFD]; 228 229 volatile sig_atomic_t MarkSet; 230 volatile sig_atomic_t WantDie; 231 volatile sig_atomic_t DoInit; 232 233 void cfline(char *, struct filed *, char *); 234 void cvthname(struct sockaddr_in *, char *, size_t); 235 int decode(const char *, const CODE *); 236 void dodie(int); 237 void doinit(int); 238 void die(int); 239 void domark(int); 240 void markit(void); 241 void fprintlog(struct filed *, int, char *); 242 void init(void); 243 void logerror(char *); 244 void logmsg(int, char *, char *, int); 245 void printline(char *, char *); 246 void printsys(char *); 247 void reapchild(int); 248 char *ttymsg(struct iovec *, int, char *, int); 249 void usage(void); 250 void wallmsg(struct filed *, struct iovec *); 251 int getmsgbufsize(void); 252 int unix_socket(char *, int, mode_t); 253 void double_rbuf(int); 254 void ctlsock_accept_handler(void); 255 void ctlconn_read_handler(void); 256 void ctlconn_write_handler(void); 257 258 int 259 main(int argc, char *argv[]) 260 { 261 int ch, i, linesize, fd; 262 struct sockaddr_un fromunix; 263 struct sockaddr_in sin, frominet; 264 socklen_t len; 265 char *p, *line; 266 char resolve[MAXHOSTNAMELEN]; 267 int lockpipe[2], nullfd = -1; 268 FILE *fp; 269 270 while ((ch = getopt(argc, argv, "dnuf:m:p:a:s:")) != -1) 271 switch (ch) { 272 case 'd': /* debug */ 273 Debug++; 274 break; 275 case 'f': /* configuration file */ 276 ConfFile = optarg; 277 break; 278 case 'm': /* mark interval */ 279 MarkInterval = atoi(optarg) * 60; 280 break; 281 case 'n': /* don't do DNS lookups */ 282 NoDNS = 1; 283 break; 284 case 'p': /* path */ 285 funixn[0] = optarg; 286 break; 287 case 'u': /* allow udp input port */ 288 SecureMode = 0; 289 break; 290 case 'a': 291 if (nfunix >= MAXFUNIX) 292 fprintf(stderr, "syslogd: " 293 "out of descriptors, ignoring %s\n", 294 optarg); 295 else 296 funixn[nfunix++] = optarg; 297 break; 298 case 's': 299 ctlsock_path = optarg; 300 break; 301 default: 302 usage(); 303 } 304 if ((argc -= optind) != 0) 305 usage(); 306 307 if (Debug) 308 setlinebuf(stdout); 309 310 consfile.f_type = F_CONSOLE; 311 (void)strlcpy(consfile.f_un.f_fname, ctty, 312 sizeof(consfile.f_un.f_fname)); 313 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 314 if ((p = strchr(LocalHostName, '.')) != NULL) { 315 *p++ = '\0'; 316 LocalDomain = p; 317 } else 318 LocalDomain = ""; 319 320 linesize = getmsgbufsize(); 321 if (linesize < MAXLINE) 322 linesize = MAXLINE; 323 linesize++; 324 if ((line = malloc(linesize)) == NULL) { 325 logerror("Couldn't allocate line buffer"); 326 die(0); 327 } 328 329 /* Clear poll array, set all fds to ignore */ 330 for (i = 0; i < N_PFD; i++) { 331 pfd[i].fd = -1; 332 pfd[i].events = 0; 333 } 334 335 #ifndef SUN_LEN 336 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 337 #endif 338 for (i = 0; i < nfunix; i++) { 339 if ((fd = unix_socket(funixn[i], SOCK_DGRAM, 0666)) == -1) { 340 if (i == 0) 341 die(0); 342 continue; 343 } 344 double_rbuf(fd); 345 pfd[PFD_UNIX_0 + i].fd = fd; 346 pfd[PFD_UNIX_0 + i].events = POLLIN; 347 } 348 349 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) != -1) { 350 struct servent *sp; 351 352 /* XXX use getaddrinfo */ 353 sp = getservbyname("syslog", "udp"); 354 if (sp == NULL) { 355 errno = 0; 356 logerror("syslog/udp: unknown service"); 357 die(0); 358 } 359 memset(&sin, 0, sizeof(sin)); 360 sin.sin_len = sizeof(sin); 361 sin.sin_family = AF_INET; 362 sin.sin_port = LogPort = sp->s_port; 363 if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 364 logerror("bind"); 365 if (!Debug) 366 die(0); 367 } else { 368 InetInuse = 1; 369 double_rbuf(fd); 370 pfd[PFD_INET].fd = fd; 371 pfd[PFD_INET].events = POLLIN; 372 } 373 } 374 375 if (ctlsock_path != NULL) { 376 if ((fd = unix_socket(ctlsock_path, SOCK_STREAM, 0600)) == -1) 377 die(0); 378 if (listen(fd, 16) == -1) { 379 logerror("ctlsock listen"); 380 die(0); 381 } 382 pfd[PFD_CTLSOCK].fd = fd; 383 pfd[PFD_CTLSOCK].events = POLLIN; 384 } 385 386 if ((fd = open(_PATH_KLOG, O_RDONLY, 0)) == -1) { 387 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 388 } else { 389 pfd[PFD_KLOG].fd = fd; 390 pfd[PFD_KLOG].events = POLLIN; 391 } 392 393 dprintf("off & running....\n"); 394 395 chdir("/"); 396 397 tzset(); 398 399 if (!Debug) { 400 char c; 401 402 pipe(lockpipe); 403 404 switch(fork()) { 405 case -1: 406 exit(1); 407 case 0: 408 setsid(); 409 nullfd = open(_PATH_DEVNULL, O_RDWR); 410 close(lockpipe[0]); 411 break; 412 default: 413 close(lockpipe[1]); 414 read(lockpipe[0], &c, 1); 415 _exit(0); 416 } 417 } 418 419 /* tuck my process id away */ 420 if (!Debug) { 421 fp = fopen(_PATH_LOGPID, "w"); 422 if (fp != NULL) { 423 fprintf(fp, "%ld\n", (long)getpid()); 424 (void) fclose(fp); 425 } 426 } 427 428 /* Privilege separation begins here */ 429 if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0) 430 errx(1, "unable to privsep"); 431 432 /* Process is now unprivileged and inside a chroot */ 433 init(); 434 435 Startup = 0; 436 437 /* Allocate ctl socket reply buffer if we have a ctl socket */ 438 if (pfd[PFD_CTLSOCK].fd != -1 && 439 (ctl_reply = malloc(MAX_MEMBUF)) == NULL) { 440 logerror("Couldn't allocate ctlsock reply buffer"); 441 die(0); 442 } 443 444 if (!Debug) { 445 dup2(nullfd, STDIN_FILENO); 446 dup2(nullfd, STDOUT_FILENO); 447 dup2(nullfd, STDERR_FILENO); 448 if (nullfd > 2) 449 close(nullfd); 450 close(lockpipe[1]); 451 } 452 453 /* 454 * Signal to the priv process that the initial config parsing is done 455 * so that it will reject any future attempts to open more files 456 */ 457 priv_config_parse_done(); 458 459 (void)signal(SIGHUP, doinit); 460 (void)signal(SIGTERM, dodie); 461 (void)signal(SIGINT, Debug ? dodie : SIG_IGN); 462 (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); 463 (void)signal(SIGCHLD, reapchild); 464 (void)signal(SIGALRM, domark); 465 (void)signal(SIGPIPE, SIG_IGN); 466 (void)alarm(TIMERINTVL); 467 468 for (;;) { 469 if (MarkSet) 470 markit(); 471 if (WantDie) 472 die(WantDie); 473 474 if (DoInit) { 475 init(); 476 DoInit = 0; 477 } 478 479 switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) { 480 case 0: 481 continue; 482 case -1: 483 if (errno != EINTR) 484 logerror("poll"); 485 continue; 486 } 487 488 if ((pfd[PFD_KLOG].revents & POLLIN) != 0) { 489 i = read(pfd[PFD_KLOG].fd, line, linesize - 1); 490 if (i > 0) { 491 line[i] = '\0'; 492 printsys(line); 493 } else if (i < 0 && errno != EINTR) { 494 logerror("klog"); 495 pfd[PFD_KLOG].fd = -1; 496 pfd[PFD_KLOG].events = 0; 497 } 498 } 499 if ((pfd[PFD_INET].revents & POLLIN) != 0) { 500 len = sizeof(frominet); 501 i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0, 502 (struct sockaddr *)&frominet, &len); 503 if (SecureMode) { 504 /* silently drop it */ 505 } else { 506 if (i > 0) { 507 line[i] = '\0'; 508 cvthname(&frominet, resolve, 509 sizeof resolve); 510 dprintf("cvthname res: %s\n", resolve); 511 printline(resolve, line); 512 } else if (i < 0 && errno != EINTR) 513 logerror("recvfrom inet"); 514 } 515 } 516 if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0) 517 ctlsock_accept_handler(); 518 if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0) 519 ctlconn_read_handler(); 520 if ((pfd[PFD_CTLCONN].revents & POLLOUT) != 0) 521 ctlconn_write_handler(); 522 523 for (i = 0; i < nfunix; i++) { 524 if ((pfd[PFD_UNIX_0 + i].revents & POLLIN) != 0) { 525 len = sizeof(fromunix); 526 len = recvfrom(pfd[PFD_UNIX_0 + i].fd, line, 527 MAXLINE, 0, (struct sockaddr *)&fromunix, 528 &len); 529 if (len > 0) { 530 line[len] = '\0'; 531 printline(LocalHostName, line); 532 } else if (len < 0 && errno != EINTR) 533 logerror("recvfrom unix"); 534 } 535 } 536 } 537 /* NOTREACHED */ 538 free(pfd); 539 return (0); 540 } 541 542 void 543 usage(void) 544 { 545 546 (void)fprintf(stderr, 547 "usage: syslogd [-dnu] [-a path] [-f config_file] [-m mark_interval]\n" 548 " [-p log_socket] [-s reporting_socket]\n"); 549 exit(1); 550 } 551 552 /* 553 * Take a raw input line, decode the message, and print the message 554 * on the appropriate log files. 555 */ 556 void 557 printline(char *hname, char *msg) 558 { 559 int pri; 560 char *p, *q, line[MAXLINE + 1]; 561 562 /* test for special codes */ 563 pri = DEFUPRI; 564 p = msg; 565 if (*p == '<') { 566 pri = 0; 567 while (isdigit(*++p)) 568 pri = 10 * pri + (*p - '0'); 569 if (*p == '>') 570 ++p; 571 } 572 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 573 pri = DEFUPRI; 574 575 /* 576 * Don't allow users to log kernel messages. 577 * NOTE: since LOG_KERN == 0 this will also match 578 * messages with no facility specified. 579 */ 580 if (LOG_FAC(pri) == LOG_KERN) 581 pri = LOG_USER | LOG_PRI(pri); 582 583 for (q = line; *p && q < &line[sizeof(line) - 4]; p++) { 584 if (*p == '\n') 585 *q++ = ' '; 586 else 587 q = vis(q, *p, 0, 0); 588 } 589 *q = '\0'; 590 591 logmsg(pri, line, hname, 0); 592 } 593 594 /* 595 * Take a raw input line from /dev/klog, split and format similar to syslog(). 596 */ 597 void 598 printsys(char *msg) 599 { 600 int c, pri, flags; 601 char *lp, *p, *q, line[MAXLINE + 1]; 602 603 (void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX); 604 lp = line + strlen(line); 605 for (p = msg; *p != '\0'; ) { 606 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 607 pri = DEFSPRI; 608 if (*p == '<') { 609 pri = 0; 610 while (isdigit(*++p)) 611 pri = 10 * pri + (*p - '0'); 612 if (*p == '>') 613 ++p; 614 } else { 615 /* kernel printf's come out on console */ 616 flags |= IGN_CONS; 617 } 618 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 619 pri = DEFSPRI; 620 621 q = lp; 622 while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4]) 623 q = vis(q, c, 0, 0); 624 625 logmsg(pri, line, LocalHostName, flags); 626 } 627 } 628 629 time_t now; 630 631 /* 632 * Log a message to the appropriate log files, users, etc. based on 633 * the priority. 634 */ 635 void 636 logmsg(int pri, char *msg, char *from, int flags) 637 { 638 struct filed *f; 639 int fac, msglen, prilev, i; 640 sigset_t mask, omask; 641 char *timestamp; 642 char prog[NAME_MAX+1]; 643 644 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 645 pri, flags, from, msg); 646 647 sigemptyset(&mask); 648 sigaddset(&mask, SIGALRM); 649 sigaddset(&mask, SIGHUP); 650 sigprocmask(SIG_BLOCK, &mask, &omask); 651 652 /* 653 * Check to see if msg looks non-standard. 654 */ 655 msglen = strlen(msg); 656 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 657 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 658 flags |= ADDDATE; 659 660 (void)time(&now); 661 if (flags & ADDDATE) 662 timestamp = ctime(&now) + 4; 663 else { 664 timestamp = msg; 665 msg += 16; 666 msglen -= 16; 667 } 668 669 /* extract facility and priority level */ 670 if (flags & MARK) 671 fac = LOG_NFACILITIES; 672 else 673 fac = LOG_FAC(pri); 674 prilev = LOG_PRI(pri); 675 676 /* extract program name */ 677 for(i = 0; i < NAME_MAX; i++) { 678 if (!isalnum(msg[i])) 679 break; 680 prog[i] = msg[i]; 681 } 682 prog[i] = 0; 683 684 /* log the message to the particular outputs */ 685 if (!Initialized) { 686 f = &consfile; 687 f->f_file = priv_open_tty(ctty); 688 689 if (f->f_file >= 0) { 690 fprintlog(f, flags, msg); 691 (void)close(f->f_file); 692 f->f_file = -1; 693 } 694 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 695 return; 696 } 697 for (f = Files; f; f = f->f_next) { 698 /* skip messages that are incorrect priority */ 699 if (f->f_pmask[fac] < prilev || 700 f->f_pmask[fac] == INTERNAL_NOPRI) 701 continue; 702 703 /* skip messages with the incorrect program name */ 704 if (f->f_program) 705 if (strcmp(prog, f->f_program) != 0) 706 continue; 707 708 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 709 continue; 710 711 /* don't output marks to recently written files */ 712 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 713 continue; 714 715 /* 716 * suppress duplicate lines to this file 717 */ 718 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 719 !strcmp(msg, f->f_prevline) && 720 !strcmp(from, f->f_prevhost)) { 721 strlcpy(f->f_lasttime, timestamp, 16); 722 f->f_prevcount++; 723 dprintf("msg repeated %d times, %ld sec of %d\n", 724 f->f_prevcount, (long)(now - f->f_time), 725 repeatinterval[f->f_repeatcount]); 726 /* 727 * If domark would have logged this by now, 728 * flush it now (so we don't hold isolated messages), 729 * but back off so we'll flush less often 730 * in the future. 731 */ 732 if (now > REPEATTIME(f)) { 733 fprintlog(f, flags, (char *)NULL); 734 BACKOFF(f); 735 } 736 } else { 737 /* new line, save it */ 738 if (f->f_prevcount) 739 fprintlog(f, 0, (char *)NULL); 740 f->f_repeatcount = 0; 741 f->f_prevpri = pri; 742 strlcpy(f->f_lasttime, timestamp, 16); 743 strlcpy(f->f_prevhost, from, 744 sizeof(f->f_prevhost)); 745 if (msglen < MAXSVLINE) { 746 f->f_prevlen = msglen; 747 strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); 748 fprintlog(f, flags, (char *)NULL); 749 } else { 750 f->f_prevline[0] = 0; 751 f->f_prevlen = 0; 752 fprintlog(f, flags, msg); 753 } 754 } 755 } 756 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 757 } 758 759 void 760 fprintlog(struct filed *f, int flags, char *msg) 761 { 762 struct iovec iov[6]; 763 struct iovec *v; 764 int l; 765 char line[MAXLINE + 1], repbuf[80], greetings[500]; 766 767 v = iov; 768 if (f->f_type == F_WALL) { 769 if ((l = snprintf(greetings, sizeof(greetings), 770 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 771 f->f_prevhost, ctime(&now))) >= sizeof(greetings) || 772 l == -1) 773 l = strlen(greetings); 774 v->iov_base = greetings; 775 v->iov_len = l; 776 v++; 777 v->iov_base = ""; 778 v->iov_len = 0; 779 v++; 780 } else { 781 v->iov_base = f->f_lasttime; 782 v->iov_len = 15; 783 v++; 784 v->iov_base = " "; 785 v->iov_len = 1; 786 v++; 787 } 788 v->iov_base = f->f_prevhost; 789 v->iov_len = strlen(v->iov_base); 790 v++; 791 v->iov_base = " "; 792 v->iov_len = 1; 793 v++; 794 795 if (msg) { 796 v->iov_base = msg; 797 v->iov_len = strlen(msg); 798 } else if (f->f_prevcount > 1) { 799 if ((l = snprintf(repbuf, sizeof(repbuf), 800 "last message repeated %d times", f->f_prevcount)) >= 801 sizeof(repbuf) || l == -1) 802 l = strlen(repbuf); 803 v->iov_base = repbuf; 804 v->iov_len = l; 805 } else { 806 v->iov_base = f->f_prevline; 807 v->iov_len = f->f_prevlen; 808 } 809 v++; 810 811 dprintf("Logging to %s", TypeNames[f->f_type]); 812 f->f_time = now; 813 814 switch (f->f_type) { 815 case F_UNUSED: 816 dprintf("\n"); 817 break; 818 819 case F_FORW: 820 dprintf(" %s\n", f->f_un.f_forw.f_hname); 821 if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s", 822 f->f_prevpri, (char *)iov[0].iov_base, 823 (char *)iov[4].iov_base)) >= sizeof(line) || l == -1) 824 l = strlen(line); 825 if (sendto(pfd[PFD_INET].fd, line, l, 0, 826 (struct sockaddr *)&f->f_un.f_forw.f_addr, 827 sizeof(f->f_un.f_forw.f_addr)) != l) { 828 f->f_type = F_UNUSED; 829 logerror("sendto"); 830 } 831 break; 832 833 case F_CONSOLE: 834 if (flags & IGN_CONS) { 835 dprintf(" (ignored)\n"); 836 break; 837 } 838 /* FALLTHROUGH */ 839 840 case F_TTY: 841 case F_FILE: 842 dprintf(" %s\n", f->f_un.f_fname); 843 if (f->f_type != F_FILE) { 844 v->iov_base = "\r\n"; 845 v->iov_len = 2; 846 } else { 847 v->iov_base = "\n"; 848 v->iov_len = 1; 849 } 850 again: 851 if (writev(f->f_file, iov, 6) < 0) { 852 int e = errno; 853 (void)close(f->f_file); 854 /* 855 * Check for errors on TTY's due to loss of tty 856 */ 857 if (e == EAGAIN) { 858 /* 859 * Silently drop messages on blocked write. 860 * This can happen when logging to a locked tty. 861 */ 862 break; 863 } else if ((e == EIO || e == EBADF) && 864 f->f_type != F_FILE) { 865 f->f_file = priv_open_tty(f->f_un.f_fname); 866 if (f->f_file < 0) { 867 f->f_type = F_UNUSED; 868 logerror(f->f_un.f_fname); 869 } else 870 goto again; 871 } else { 872 f->f_type = F_UNUSED; 873 f->f_file = -1; 874 errno = e; 875 logerror(f->f_un.f_fname); 876 } 877 } else if (flags & SYNC_FILE) 878 (void)fsync(f->f_file); 879 break; 880 881 case F_USERS: 882 case F_WALL: 883 dprintf("\n"); 884 v->iov_base = "\r\n"; 885 v->iov_len = 2; 886 wallmsg(f, iov); 887 break; 888 889 case F_MEMBUF: 890 dprintf("\n"); 891 snprintf(line, sizeof(line), "%.15s %s", 892 (char *)iov[0].iov_base, (char *)iov[4].iov_base); 893 ringbuf_append_line(f->f_un.f_mb.f_rb, line); 894 break; 895 } 896 f->f_prevcount = 0; 897 } 898 899 /* 900 * WALLMSG -- Write a message to the world at large 901 * 902 * Write the specified message to either the entire 903 * world, or a list of approved users. 904 */ 905 void 906 wallmsg(struct filed *f, struct iovec *iov) 907 { 908 struct utmp ut; 909 char line[sizeof(ut.ut_line) + 1], *p; 910 static int reenter; /* avoid calling ourselves */ 911 FILE *uf; 912 int i; 913 914 if (reenter++) 915 return; 916 if ((uf = priv_open_utmp()) == NULL) { 917 logerror(_PATH_UTMP); 918 reenter = 0; 919 return; 920 } 921 /* NOSTRICT */ 922 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 923 if (ut.ut_name[0] == '\0') 924 continue; 925 /* must use strncpy since ut_* may not be NUL terminated */ 926 strncpy(line, ut.ut_line, sizeof(line) - 1); 927 line[sizeof(line) - 1] = '\0'; 928 if (f->f_type == F_WALL) { 929 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 930 errno = 0; /* already in msg */ 931 logerror(p); 932 } 933 continue; 934 } 935 /* should we send the message to this user? */ 936 for (i = 0; i < MAXUNAMES; i++) { 937 if (!f->f_un.f_uname[i][0]) 938 break; 939 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 940 UT_NAMESIZE)) { 941 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 942 != NULL) { 943 errno = 0; /* already in msg */ 944 logerror(p); 945 } 946 break; 947 } 948 } 949 } 950 (void)fclose(uf); 951 reenter = 0; 952 } 953 954 void 955 reapchild(int signo) 956 { 957 int save_errno = errno; 958 int status; 959 960 while (waitpid(-1, &status, WNOHANG) > 0) 961 ; 962 errno = save_errno; 963 } 964 965 /* 966 * Return a printable representation of a host address. 967 */ 968 void 969 cvthname(struct sockaddr_in *f, char *result, size_t res_len) 970 { 971 sigset_t omask, nmask; 972 char *p, *ip; 973 int ret_len; 974 975 if (f->sin_family != AF_INET) { 976 dprintf("Malformed from address\n"); 977 strlcpy(result, "???", res_len); 978 return; 979 } 980 981 ip = inet_ntoa(f->sin_addr); 982 dprintf("cvthname(%s)\n", ip); 983 if (NoDNS) { 984 strlcpy(result, ip, res_len); 985 return; 986 } 987 988 sigemptyset(&nmask); 989 sigaddset(&nmask, SIGHUP); 990 sigprocmask(SIG_BLOCK, &nmask, &omask); 991 992 ret_len = priv_gethostbyaddr((char *)&f->sin_addr, 993 sizeof(struct in_addr), f->sin_family, result, res_len); 994 995 sigprocmask(SIG_SETMASK, &omask, NULL); 996 if (ret_len == 0) { 997 dprintf("Host name for your address (%s) unknown\n", ip); 998 strlcpy(result, ip, res_len); 999 } else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0) 1000 *p = '\0'; 1001 } 1002 1003 void 1004 dodie(int signo) 1005 { 1006 WantDie = signo; 1007 } 1008 1009 void 1010 domark(int signo) 1011 { 1012 MarkSet = 1; 1013 } 1014 1015 void 1016 doinit(int signo) 1017 { 1018 DoInit = 1; 1019 } 1020 1021 /* 1022 * Print syslogd errors some place. 1023 */ 1024 void 1025 logerror(char *type) 1026 { 1027 char buf[100]; 1028 1029 if (errno) 1030 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1031 type, strerror(errno)); 1032 else 1033 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 1034 errno = 0; 1035 dprintf("%s\n", buf); 1036 if (Startup) 1037 fprintf(stderr, "%s\n", buf); 1038 else 1039 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1040 } 1041 1042 void 1043 die(int signo) 1044 { 1045 struct filed *f; 1046 int was_initialized = Initialized; 1047 char buf[100]; 1048 1049 Initialized = 0; /* Don't log SIGCHLDs */ 1050 alarm(0); 1051 for (f = Files; f != NULL; f = f->f_next) { 1052 /* flush any pending output */ 1053 if (f->f_prevcount) 1054 fprintlog(f, 0, (char *)NULL); 1055 } 1056 Initialized = was_initialized; 1057 if (signo) { 1058 dprintf("syslogd: exiting on signal %d\n", signo); 1059 (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); 1060 errno = 0; 1061 logerror(buf); 1062 } 1063 dprintf("[unpriv] syslogd child about to exit\n"); 1064 exit(0); 1065 } 1066 1067 /* 1068 * INIT -- Initialize syslogd from configuration table 1069 */ 1070 void 1071 init(void) 1072 { 1073 char cline[LINE_MAX], prog[NAME_MAX+1], *p; 1074 struct filed *f, *next, **nextp; 1075 FILE *cf; 1076 int i; 1077 1078 dprintf("init\n"); 1079 1080 /* If config file has been modified, then just die to restart */ 1081 if (priv_config_modified()) { 1082 dprintf("config file changed: dying\n"); 1083 die(0); 1084 } 1085 1086 /* 1087 * Close all open log files. 1088 */ 1089 Initialized = 0; 1090 for (f = Files; f != NULL; f = next) { 1091 /* flush any pending output */ 1092 if (f->f_prevcount) 1093 fprintlog(f, 0, (char *)NULL); 1094 1095 switch (f->f_type) { 1096 case F_FILE: 1097 case F_TTY: 1098 case F_CONSOLE: 1099 (void)close(f->f_file); 1100 break; 1101 case F_FORW: 1102 break; 1103 } 1104 next = f->f_next; 1105 if (f->f_program) 1106 free(f->f_program); 1107 free((char *)f); 1108 } 1109 Files = NULL; 1110 nextp = &Files; 1111 1112 /* open the configuration file */ 1113 if ((cf = priv_open_config()) == NULL) { 1114 dprintf("cannot open %s\n", ConfFile); 1115 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1116 cfline("*.ERR\t/dev/console", *nextp, "*"); 1117 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1118 cfline("*.PANIC\t*", (*nextp)->f_next, "*"); 1119 Initialized = 1; 1120 return; 1121 } 1122 1123 /* 1124 * Foreach line in the conf table, open that file. 1125 */ 1126 f = NULL; 1127 strlcpy(prog, "*", sizeof(prog)); 1128 while (fgets(cline, sizeof(cline), cf) != NULL) { 1129 /* 1130 * check for end-of-section, comments, strip off trailing 1131 * spaces and newline character. !prog is treated 1132 * specially: the following lines apply only to that program. 1133 */ 1134 for (p = cline; isspace(*p); ++p) 1135 continue; 1136 if (*p == '\0' || *p == '#') 1137 continue; 1138 if (*p == '!') { 1139 p++; 1140 while (isspace(*p)) 1141 p++; 1142 if (!*p) { 1143 strlcpy(prog, "*", sizeof(prog)); 1144 continue; 1145 } 1146 for (i = 0; i < NAME_MAX; i++) { 1147 if (!isalnum(p[i])) 1148 break; 1149 prog[i] = p[i]; 1150 } 1151 prog[i] = 0; 1152 continue; 1153 } 1154 p = cline + strlen(cline); 1155 while (p > cline) 1156 if (!isspace(*--p)) { 1157 p++; 1158 break; 1159 } 1160 *p = '\0'; 1161 f = (struct filed *)calloc(1, sizeof(*f)); 1162 *nextp = f; 1163 nextp = &f->f_next; 1164 cfline(cline, f, prog); 1165 } 1166 1167 /* close the configuration file */ 1168 (void)fclose(cf); 1169 1170 Initialized = 1; 1171 1172 if (Debug) { 1173 for (f = Files; f; f = f->f_next) { 1174 for (i = 0; i <= LOG_NFACILITIES; i++) 1175 if (f->f_pmask[i] == INTERNAL_NOPRI) 1176 printf("X "); 1177 else 1178 printf("%d ", f->f_pmask[i]); 1179 printf("%s: ", TypeNames[f->f_type]); 1180 switch (f->f_type) { 1181 case F_FILE: 1182 case F_TTY: 1183 case F_CONSOLE: 1184 printf("%s", f->f_un.f_fname); 1185 break; 1186 1187 case F_FORW: 1188 printf("%s", f->f_un.f_forw.f_hname); 1189 break; 1190 1191 case F_USERS: 1192 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1193 printf("%s, ", f->f_un.f_uname[i]); 1194 break; 1195 1196 case F_MEMBUF: 1197 printf("%s", f->f_un.f_mb.f_mname); 1198 break; 1199 1200 } 1201 if (f->f_program) 1202 printf(" (%s)", f->f_program); 1203 printf("\n"); 1204 } 1205 } 1206 1207 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, 1208 ADDDATE); 1209 dprintf("syslogd: restarted\n"); 1210 } 1211 1212 /* 1213 * Crack a configuration file line 1214 */ 1215 void 1216 cfline(char *line, struct filed *f, char *prog) 1217 { 1218 int i, pri, addr_len; 1219 size_t rb_len; 1220 char *bp, *p, *q; 1221 char buf[MAXLINE], ebuf[100]; 1222 char addr[MAXHOSTNAMELEN]; 1223 struct filed *xf; 1224 1225 dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog); 1226 1227 errno = 0; /* keep strerror() stuff out of logerror messages */ 1228 1229 /* clear out file entry */ 1230 memset(f, 0, sizeof(*f)); 1231 for (i = 0; i <= LOG_NFACILITIES; i++) 1232 f->f_pmask[i] = INTERNAL_NOPRI; 1233 1234 /* save program name if any */ 1235 if (!strcmp(prog, "*")) 1236 prog = NULL; 1237 else { 1238 f->f_program = calloc(1, strlen(prog)+1); 1239 if (f->f_program) 1240 strlcpy(f->f_program, prog, strlen(prog)+1); 1241 } 1242 1243 /* scan through the list of selectors */ 1244 for (p = line; *p && *p != '\t';) { 1245 1246 /* find the end of this facility name list */ 1247 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1248 continue; 1249 1250 /* collect priority name */ 1251 for (bp = buf; *q && !strchr("\t,;", *q); ) 1252 *bp++ = *q++; 1253 *bp = '\0'; 1254 1255 /* skip cruft */ 1256 while (strchr(", ;", *q)) 1257 q++; 1258 1259 /* decode priority name */ 1260 if (*buf == '*') 1261 pri = LOG_PRIMASK + 1; 1262 else { 1263 /* ignore trailing spaces */ 1264 int i; 1265 for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) { 1266 buf[i]='\0'; 1267 } 1268 1269 pri = decode(buf, prioritynames); 1270 if (pri < 0) { 1271 (void)snprintf(ebuf, sizeof ebuf, 1272 "unknown priority name \"%s\"", buf); 1273 logerror(ebuf); 1274 return; 1275 } 1276 } 1277 1278 /* scan facilities */ 1279 while (*p && !strchr("\t.;", *p)) { 1280 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1281 *bp++ = *p++; 1282 *bp = '\0'; 1283 if (*buf == '*') 1284 for (i = 0; i < LOG_NFACILITIES; i++) 1285 f->f_pmask[i] = pri; 1286 else { 1287 i = decode(buf, facilitynames); 1288 if (i < 0) { 1289 (void)snprintf(ebuf, sizeof(ebuf), 1290 "unknown facility name \"%s\"", 1291 buf); 1292 logerror(ebuf); 1293 return; 1294 } 1295 f->f_pmask[i >> 3] = pri; 1296 } 1297 while (*p == ',' || *p == ' ') 1298 p++; 1299 } 1300 1301 p = q; 1302 } 1303 1304 /* skip to action part */ 1305 while (*p == '\t') 1306 p++; 1307 1308 switch (*p) { 1309 case '@': 1310 if (!InetInuse) 1311 break; 1312 (void)strlcpy(f->f_un.f_forw.f_hname, ++p, 1313 sizeof(f->f_un.f_forw.f_hname)); 1314 addr_len = priv_gethostbyname(f->f_un.f_forw.f_hname, 1315 addr, sizeof addr); 1316 if (addr_len < 1) { 1317 logerror((char *)hstrerror(h_errno)); 1318 break; 1319 } 1320 memset(&f->f_un.f_forw.f_addr, 0, 1321 sizeof(f->f_un.f_forw.f_addr)); 1322 f->f_un.f_forw.f_addr.sin_len = sizeof(f->f_un.f_forw.f_addr); 1323 f->f_un.f_forw.f_addr.sin_family = AF_INET; 1324 f->f_un.f_forw.f_addr.sin_port = LogPort; 1325 memmove(&f->f_un.f_forw.f_addr.sin_addr, addr, addr_len); 1326 f->f_type = F_FORW; 1327 break; 1328 1329 case '/': 1330 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1331 if (strcmp(p, ctty) == 0) 1332 f->f_file = priv_open_tty(p); 1333 else 1334 f->f_file = priv_open_log(p); 1335 if (f->f_file < 0) { 1336 f->f_type = F_UNUSED; 1337 logerror(p); 1338 break; 1339 } 1340 if (isatty(f->f_file)) { 1341 if (strcmp(p, ctty) == 0) 1342 f->f_type = F_CONSOLE; 1343 else 1344 f->f_type = F_TTY; 1345 } else { 1346 f->f_type = F_FILE; 1347 /* Clear O_NONBLOCK flag on f->f_file */ 1348 if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { 1349 i &= ~O_NONBLOCK; 1350 fcntl(f->f_file, F_SETFL, i); 1351 } 1352 } 1353 break; 1354 1355 case '*': 1356 f->f_type = F_WALL; 1357 break; 1358 1359 case ':': 1360 f->f_type = F_MEMBUF; 1361 1362 /* Parse buffer size (in kb) */ 1363 errno = 0; 1364 rb_len = strtoul(++p, &q, 0); 1365 if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) || 1366 *q != ':' || rb_len == 0) { 1367 f->f_type = F_UNUSED; 1368 logerror(p); 1369 break; 1370 } 1371 q++; 1372 rb_len *= 1024; 1373 1374 /* Copy buffer name */ 1375 for(i = 0; i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) { 1376 if (!isalnum(q[i])) 1377 break; 1378 f->f_un.f_mb.f_mname[i] = q[i]; 1379 } 1380 1381 /* Make sure buffer name is unique */ 1382 for (xf = Files; i != 0 && xf != f; xf = xf->f_next) { 1383 if (xf->f_type == F_MEMBUF && 1384 strcmp(xf->f_un.f_mb.f_mname, 1385 f->f_un.f_mb.f_mname) == 0) 1386 break; 1387 } 1388 1389 /* Error on missing or non-unique name, or bad buffer length */ 1390 if (i == 0 || rb_len > MAX_MEMBUF || xf != f) { 1391 f->f_type = F_UNUSED; 1392 logerror(p); 1393 break; 1394 } 1395 1396 /* Allocate buffer */ 1397 rb_len = MAX(rb_len, MIN_MEMBUF); 1398 if ((f->f_un.f_mb.f_rb = ringbuf_init(rb_len)) == NULL) { 1399 f->f_type = F_UNUSED; 1400 logerror(p); 1401 break; 1402 } 1403 break; 1404 1405 default: 1406 for (i = 0; i < MAXUNAMES && *p; i++) { 1407 for (q = p; *q && *q != ','; ) 1408 q++; 1409 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1410 if ((q - p) > UT_NAMESIZE) 1411 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1412 else 1413 f->f_un.f_uname[i][q - p] = '\0'; 1414 while (*q == ',' || *q == ' ') 1415 q++; 1416 p = q; 1417 } 1418 f->f_type = F_USERS; 1419 break; 1420 } 1421 } 1422 1423 1424 /* 1425 * Retrieve the size of the kernel message buffer, via sysctl. 1426 */ 1427 int 1428 getmsgbufsize(void) 1429 { 1430 int msgbufsize, mib[2]; 1431 size_t size; 1432 1433 mib[0] = CTL_KERN; 1434 mib[1] = KERN_MSGBUFSIZE; 1435 size = sizeof msgbufsize; 1436 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1437 dprintf("couldn't get kern.msgbufsize\n"); 1438 return (0); 1439 } 1440 return (msgbufsize); 1441 } 1442 1443 /* 1444 * Decode a symbolic name to a numeric value 1445 */ 1446 int 1447 decode(const char *name, const CODE *codetab) 1448 { 1449 const CODE *c; 1450 char *p, buf[40]; 1451 1452 if (isdigit(*name)) 1453 return (atoi(name)); 1454 1455 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1456 if (isupper(*name)) 1457 *p = tolower(*name); 1458 else 1459 *p = *name; 1460 } 1461 *p = '\0'; 1462 for (c = codetab; c->c_name; c++) 1463 if (!strcmp(buf, c->c_name)) 1464 return (c->c_val); 1465 1466 return (-1); 1467 } 1468 1469 void 1470 markit(void) 1471 { 1472 struct filed *f; 1473 1474 now = time((time_t *)NULL); 1475 MarkSeq += TIMERINTVL; 1476 if (MarkSeq >= MarkInterval) { 1477 logmsg(LOG_INFO, "-- MARK --", 1478 LocalHostName, ADDDATE|MARK); 1479 MarkSeq = 0; 1480 } 1481 1482 for (f = Files; f; f = f->f_next) { 1483 if (f->f_prevcount && now >= REPEATTIME(f)) { 1484 dprintf("flush %s: repeated %d times, %d sec.\n", 1485 TypeNames[f->f_type], f->f_prevcount, 1486 repeatinterval[f->f_repeatcount]); 1487 fprintlog(f, 0, (char *)NULL); 1488 BACKOFF(f); 1489 } 1490 } 1491 MarkSet = 0; 1492 (void)alarm(TIMERINTVL); 1493 } 1494 1495 int 1496 unix_socket(char *path, int type, mode_t mode) 1497 { 1498 struct sockaddr_un s_un; 1499 char errbuf[512]; 1500 int fd; 1501 mode_t old_umask; 1502 1503 memset(&s_un, 0, sizeof(s_un)); 1504 s_un.sun_family = AF_UNIX; 1505 if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) > 1506 sizeof(s_un.sun_path)) { 1507 snprintf(errbuf, sizeof(errbuf), "socket path too long: %s", 1508 path); 1509 logerror(errbuf); 1510 die(0); 1511 } 1512 1513 if ((fd = socket(AF_UNIX, type, 0)) == -1) { 1514 logerror("socket"); 1515 return (-1); 1516 } 1517 1518 old_umask = umask(0177); 1519 1520 unlink(path); 1521 if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) { 1522 snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path); 1523 logerror(errbuf); 1524 umask(old_umask); 1525 close(fd); 1526 return (-1); 1527 } 1528 1529 umask(old_umask); 1530 1531 if (chmod(path, mode) == -1) { 1532 snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path); 1533 logerror(errbuf); 1534 close(fd); 1535 unlink(path); 1536 return (-1); 1537 } 1538 1539 return (fd); 1540 } 1541 1542 void 1543 double_rbuf(int fd) 1544 { 1545 socklen_t slen, len; 1546 1547 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { 1548 len *= 2; 1549 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); 1550 } 1551 } 1552 1553 static void 1554 ctlconn_cleanup(void) 1555 { 1556 if (pfd[PFD_CTLCONN].fd != -1) 1557 close(pfd[PFD_CTLCONN].fd); 1558 1559 pfd[PFD_CTLCONN].fd = -1; 1560 pfd[PFD_CTLCONN].events = pfd[PFD_CTLCONN].revents = 0; 1561 1562 pfd[PFD_CTLSOCK].events = POLLIN; 1563 1564 ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0; 1565 } 1566 1567 void 1568 ctlsock_accept_handler(void) 1569 { 1570 int fd, flags; 1571 1572 dprintf("Accepting control connection\n"); 1573 fd = accept(pfd[PFD_CTLSOCK].fd, NULL, NULL); 1574 if (fd == -1) { 1575 if (errno != EINTR && errno != ECONNABORTED) 1576 logerror("accept ctlsock"); 1577 return; 1578 } 1579 1580 ctlconn_cleanup(); 1581 1582 /* Only one connection at a time */ 1583 pfd[PFD_CTLSOCK].events = pfd[PFD_CTLSOCK].revents = 0; 1584 1585 if ((flags = fcntl(fd, F_GETFL)) == -1 || 1586 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 1587 logerror("fcntl ctlconn"); 1588 close(fd); 1589 return; 1590 } 1591 1592 pfd[PFD_CTLCONN].fd = fd; 1593 pfd[PFD_CTLCONN].events = POLLIN; 1594 ctl_state = CTL_READING_CMD; 1595 ctl_cmd_bytes = 0; 1596 } 1597 1598 static struct filed 1599 *find_membuf_log(const char *name) 1600 { 1601 struct filed *f; 1602 1603 for (f = Files; f != NULL; f = f->f_next) { 1604 if (f->f_type == F_MEMBUF && 1605 strcmp(f->f_un.f_mb.f_mname, name) == 0) 1606 break; 1607 } 1608 return (f); 1609 } 1610 1611 void 1612 ctlconn_read_handler(void) 1613 { 1614 ssize_t n; 1615 struct filed *f; 1616 1617 if (ctl_state != CTL_READING_CMD) { 1618 /* Shouldn't be here! */ 1619 logerror("ctlconn_read with bad ctl_state"); 1620 ctlconn_cleanup(); 1621 return; 1622 } 1623 retry: 1624 n = read(pfd[PFD_CTLCONN].fd, (char*)&ctl_cmd + ctl_cmd_bytes, 1625 sizeof(ctl_cmd) - ctl_cmd_bytes); 1626 switch (n) { 1627 case -1: 1628 if (errno == EINTR) 1629 goto retry; 1630 logerror("ctlconn read"); 1631 /* FALLTHROUGH */ 1632 case 0: 1633 ctlconn_cleanup(); 1634 return; 1635 default: 1636 ctl_cmd_bytes += n; 1637 } 1638 1639 if (ctl_cmd_bytes < sizeof(ctl_cmd)) 1640 return; 1641 1642 /* Ensure that logname is \0 terminated */ 1643 if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) { 1644 logerror("Corrupt ctlsock command"); 1645 ctlconn_cleanup(); 1646 return; 1647 } 1648 1649 ctl_reply_size = ctl_reply_offset = 0; 1650 *ctl_reply = '\0'; 1651 1652 dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname); 1653 1654 switch (ctl_cmd.cmd) { 1655 case CMD_READ: 1656 case CMD_READ_CLEAR: 1657 f = find_membuf_log(ctl_cmd.logname); 1658 if (f == NULL) { 1659 strlcpy(ctl_reply, "No such log\n", MAX_MEMBUF); 1660 } else { 1661 ringbuf_to_string(ctl_reply, MAX_MEMBUF, 1662 f->f_un.f_mb.f_rb); 1663 } 1664 ctl_reply_size = strlen(ctl_reply); 1665 1666 if (ctl_cmd.cmd == CMD_READ_CLEAR) 1667 ringbuf_clear(f->f_un.f_mb.f_rb); 1668 break; 1669 case CMD_CLEAR: 1670 f = find_membuf_log(ctl_cmd.logname); 1671 if (f == NULL) { 1672 strlcpy(ctl_reply, "No such log\n", MAX_MEMBUF); 1673 } else { 1674 ringbuf_clear(f->f_un.f_mb.f_rb); 1675 strlcpy(ctl_reply, "Log cleared\n", MAX_MEMBUF); 1676 } 1677 ctl_reply_size = strlen(ctl_reply); 1678 break; 1679 case CMD_LIST: 1680 for (f = Files; f != NULL; f = f->f_next) { 1681 if (f->f_type == F_MEMBUF) { 1682 strlcat(ctl_reply, f->f_un.f_mb.f_mname, 1683 MAX_MEMBUF); 1684 strlcat(ctl_reply, " ", MAX_MEMBUF); 1685 } 1686 } 1687 strlcat(ctl_reply, "\n", MAX_MEMBUF); 1688 ctl_reply_size = strlen(ctl_reply); 1689 break; 1690 default: 1691 logerror("Unsupported ctlsock command"); 1692 ctlconn_cleanup(); 1693 return; 1694 } 1695 1696 dprintf("ctlcmd reply length %d\n", ctl_reply_size); 1697 1698 /* If there is no reply, close the connection now */ 1699 if (ctl_reply_size == 0) { 1700 ctlconn_cleanup(); 1701 return; 1702 } 1703 1704 /* Otherwise, set up to write out reply */ 1705 ctl_state = CTL_WRITING_REPLY; 1706 pfd[PFD_CTLCONN].events = POLLOUT; 1707 pfd[PFD_CTLCONN].revents = 0; 1708 } 1709 1710 void 1711 ctlconn_write_handler(void) 1712 { 1713 ssize_t n; 1714 1715 if (ctl_state != CTL_WRITING_REPLY) { 1716 /* Shouldn't be here! */ 1717 logerror("ctlconn_write with bad ctl_state"); 1718 ctlconn_cleanup(); 1719 return; 1720 } 1721 retry: 1722 n = write(pfd[PFD_CTLCONN].fd, ctl_reply + ctl_reply_offset, 1723 ctl_reply_size - ctl_reply_offset); 1724 switch (n) { 1725 case -1: 1726 if (errno == EINTR) 1727 goto retry; 1728 if (errno != EPIPE) 1729 logerror("ctlconn write"); 1730 /* FALLTHROUGH */ 1731 case 0: 1732 ctlconn_cleanup(); 1733 return; 1734 default: 1735 ctl_reply_offset += n; 1736 } 1737 1738 if (ctl_reply_offset >= ctl_reply_size) 1739 ctlconn_cleanup(); 1740 } 1741