1 /* $OpenBSD: syslogd.c,v 1.76 2004/04/15 18:13:07 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.76 2004/04/15 18:13:07 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 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) != -1) { 336 struct servent *sp; 337 338 /* XXX use getaddrinfo */ 339 sp = getservbyname("syslog", "udp"); 340 if (sp == NULL) { 341 errno = 0; 342 logerror("syslog/udp: unknown service"); 343 die(0); 344 } 345 memset(&sin, 0, sizeof(sin)); 346 sin.sin_len = sizeof(sin); 347 sin.sin_family = AF_INET; 348 sin.sin_port = LogPort = sp->s_port; 349 if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 350 logerror("bind"); 351 if (!Debug) 352 die(0); 353 } else { 354 InetInuse = 1; 355 double_rbuf(fd); 356 pfd[PFD_INET].fd = fd; 357 pfd[PFD_INET].events = POLLIN; 358 } 359 } 360 361 #ifndef SUN_LEN 362 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 363 #endif 364 for (i = 0; i < nfunix; i++) { 365 if ((fd = unix_socket(funixn[i], SOCK_DGRAM, 0666)) == -1) { 366 if (i == 0 && !Debug) 367 die(0); 368 continue; 369 } 370 double_rbuf(fd); 371 pfd[PFD_UNIX_0 + i].fd = fd; 372 pfd[PFD_UNIX_0 + i].events = POLLIN; 373 } 374 375 if (ctlsock_path != NULL) { 376 fd = unix_socket(ctlsock_path, SOCK_STREAM, 0600); 377 if (fd != -1) { 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 } else if (!Debug) 385 die(0); 386 } 387 388 if ((fd = open(_PATH_KLOG, O_RDONLY, 0)) == -1) { 389 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 390 } else { 391 pfd[PFD_KLOG].fd = fd; 392 pfd[PFD_KLOG].events = POLLIN; 393 } 394 395 dprintf("off & running....\n"); 396 397 chdir("/"); 398 399 tzset(); 400 401 if (!Debug) { 402 char c; 403 404 pipe(lockpipe); 405 406 switch(fork()) { 407 case -1: 408 exit(1); 409 case 0: 410 setsid(); 411 nullfd = open(_PATH_DEVNULL, O_RDWR); 412 close(lockpipe[0]); 413 break; 414 default: 415 close(lockpipe[1]); 416 read(lockpipe[0], &c, 1); 417 _exit(0); 418 } 419 } 420 421 /* tuck my process id away */ 422 if (!Debug) { 423 fp = fopen(_PATH_LOGPID, "w"); 424 if (fp != NULL) { 425 fprintf(fp, "%ld\n", (long)getpid()); 426 (void) fclose(fp); 427 } 428 } 429 430 /* Privilege separation begins here */ 431 if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0) 432 errx(1, "unable to privsep"); 433 434 /* Process is now unprivileged and inside a chroot */ 435 init(); 436 437 Startup = 0; 438 439 /* Allocate ctl socket reply buffer if we have a ctl socket */ 440 if (pfd[PFD_CTLSOCK].fd != -1 && 441 (ctl_reply = malloc(MAX_MEMBUF)) == NULL) { 442 logerror("Couldn't allocate ctlsock reply buffer"); 443 die(0); 444 } 445 446 if (!Debug) { 447 dup2(nullfd, STDIN_FILENO); 448 dup2(nullfd, STDOUT_FILENO); 449 dup2(nullfd, STDERR_FILENO); 450 if (nullfd > 2) 451 close(nullfd); 452 close(lockpipe[1]); 453 } 454 455 /* 456 * Signal to the priv process that the initial config parsing is done 457 * so that it will reject any future attempts to open more files 458 */ 459 priv_config_parse_done(); 460 461 (void)signal(SIGHUP, doinit); 462 (void)signal(SIGTERM, dodie); 463 (void)signal(SIGINT, Debug ? dodie : SIG_IGN); 464 (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); 465 (void)signal(SIGCHLD, reapchild); 466 (void)signal(SIGALRM, domark); 467 (void)signal(SIGPIPE, SIG_IGN); 468 (void)alarm(TIMERINTVL); 469 470 for (;;) { 471 if (MarkSet) 472 markit(); 473 if (WantDie) 474 die(WantDie); 475 476 if (DoInit) { 477 init(); 478 DoInit = 0; 479 } 480 481 switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) { 482 case 0: 483 continue; 484 case -1: 485 if (errno != EINTR) 486 logerror("poll"); 487 continue; 488 } 489 490 if ((pfd[PFD_KLOG].revents & POLLIN) != 0) { 491 i = read(pfd[PFD_KLOG].fd, line, linesize - 1); 492 if (i > 0) { 493 line[i] = '\0'; 494 printsys(line); 495 } else if (i < 0 && errno != EINTR) { 496 logerror("klog"); 497 pfd[PFD_KLOG].fd = -1; 498 pfd[PFD_KLOG].events = 0; 499 } 500 } 501 if ((pfd[PFD_INET].revents & POLLIN) != 0) { 502 len = sizeof(frominet); 503 i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0, 504 (struct sockaddr *)&frominet, &len); 505 if (SecureMode) { 506 /* silently drop it */ 507 } else { 508 if (i > 0) { 509 line[i] = '\0'; 510 cvthname(&frominet, resolve, 511 sizeof resolve); 512 dprintf("cvthname res: %s\n", resolve); 513 printline(resolve, line); 514 } else if (i < 0 && errno != EINTR) 515 logerror("recvfrom inet"); 516 } 517 } 518 if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0) 519 ctlsock_accept_handler(); 520 if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0) 521 ctlconn_read_handler(); 522 if ((pfd[PFD_CTLCONN].revents & POLLOUT) != 0) 523 ctlconn_write_handler(); 524 525 for (i = 0; i < nfunix; i++) { 526 if ((pfd[PFD_UNIX_0 + i].revents & POLLIN) != 0) { 527 len = sizeof(fromunix); 528 len = recvfrom(pfd[PFD_UNIX_0 + i].fd, line, 529 MAXLINE, 0, (struct sockaddr *)&fromunix, 530 &len); 531 if (len > 0) { 532 line[len] = '\0'; 533 printline(LocalHostName, line); 534 } else if (len < 0 && errno != EINTR) 535 logerror("recvfrom unix"); 536 } 537 } 538 } 539 /* NOTREACHED */ 540 free(pfd); 541 return (0); 542 } 543 544 void 545 usage(void) 546 { 547 548 (void)fprintf(stderr, 549 "usage: syslogd [-dnu] [-a path] [-f config_file] [-m mark_interval]\n" 550 " [-p log_socket] [-s reporting_socket]\n"); 551 exit(1); 552 } 553 554 /* 555 * Take a raw input line, decode the message, and print the message 556 * on the appropriate log files. 557 */ 558 void 559 printline(char *hname, char *msg) 560 { 561 int pri; 562 char *p, *q, line[MAXLINE + 1]; 563 564 /* test for special codes */ 565 pri = DEFUPRI; 566 p = msg; 567 if (*p == '<') { 568 pri = 0; 569 while (isdigit(*++p)) 570 pri = 10 * pri + (*p - '0'); 571 if (*p == '>') 572 ++p; 573 } 574 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 575 pri = DEFUPRI; 576 577 /* 578 * Don't allow users to log kernel messages. 579 * NOTE: since LOG_KERN == 0 this will also match 580 * messages with no facility specified. 581 */ 582 if (LOG_FAC(pri) == LOG_KERN) 583 pri = LOG_USER | LOG_PRI(pri); 584 585 for (q = line; *p && q < &line[sizeof(line) - 4]; p++) { 586 if (*p == '\n') 587 *q++ = ' '; 588 else 589 q = vis(q, *p, 0, 0); 590 } 591 *q = '\0'; 592 593 logmsg(pri, line, hname, 0); 594 } 595 596 /* 597 * Take a raw input line from /dev/klog, split and format similar to syslog(). 598 */ 599 void 600 printsys(char *msg) 601 { 602 int c, pri, flags; 603 char *lp, *p, *q, line[MAXLINE + 1]; 604 605 (void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX); 606 lp = line + strlen(line); 607 for (p = msg; *p != '\0'; ) { 608 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 609 pri = DEFSPRI; 610 if (*p == '<') { 611 pri = 0; 612 while (isdigit(*++p)) 613 pri = 10 * pri + (*p - '0'); 614 if (*p == '>') 615 ++p; 616 } else { 617 /* kernel printf's come out on console */ 618 flags |= IGN_CONS; 619 } 620 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 621 pri = DEFSPRI; 622 623 q = lp; 624 while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4]) 625 q = vis(q, c, 0, 0); 626 627 logmsg(pri, line, LocalHostName, flags); 628 } 629 } 630 631 time_t now; 632 633 /* 634 * Log a message to the appropriate log files, users, etc. based on 635 * the priority. 636 */ 637 void 638 logmsg(int pri, char *msg, char *from, int flags) 639 { 640 struct filed *f; 641 int fac, msglen, prilev, i; 642 sigset_t mask, omask; 643 char *timestamp; 644 char prog[NAME_MAX+1]; 645 646 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 647 pri, flags, from, msg); 648 649 sigemptyset(&mask); 650 sigaddset(&mask, SIGALRM); 651 sigaddset(&mask, SIGHUP); 652 sigprocmask(SIG_BLOCK, &mask, &omask); 653 654 /* 655 * Check to see if msg looks non-standard. 656 */ 657 msglen = strlen(msg); 658 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 659 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 660 flags |= ADDDATE; 661 662 (void)time(&now); 663 if (flags & ADDDATE) 664 timestamp = ctime(&now) + 4; 665 else { 666 timestamp = msg; 667 msg += 16; 668 msglen -= 16; 669 } 670 671 /* extract facility and priority level */ 672 if (flags & MARK) 673 fac = LOG_NFACILITIES; 674 else 675 fac = LOG_FAC(pri); 676 prilev = LOG_PRI(pri); 677 678 /* extract program name */ 679 for(i = 0; i < NAME_MAX; i++) { 680 if (!isalnum(msg[i])) 681 break; 682 prog[i] = msg[i]; 683 } 684 prog[i] = 0; 685 686 /* log the message to the particular outputs */ 687 if (!Initialized) { 688 f = &consfile; 689 f->f_file = priv_open_tty(ctty); 690 691 if (f->f_file >= 0) { 692 fprintlog(f, flags, msg); 693 (void)close(f->f_file); 694 f->f_file = -1; 695 } 696 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 697 return; 698 } 699 for (f = Files; f; f = f->f_next) { 700 /* skip messages that are incorrect priority */ 701 if (f->f_pmask[fac] < prilev || 702 f->f_pmask[fac] == INTERNAL_NOPRI) 703 continue; 704 705 /* skip messages with the incorrect program name */ 706 if (f->f_program) 707 if (strcmp(prog, f->f_program) != 0) 708 continue; 709 710 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 711 continue; 712 713 /* don't output marks to recently written files */ 714 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 715 continue; 716 717 /* 718 * suppress duplicate lines to this file 719 */ 720 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 721 !strcmp(msg, f->f_prevline) && 722 !strcmp(from, f->f_prevhost)) { 723 strlcpy(f->f_lasttime, timestamp, 16); 724 f->f_prevcount++; 725 dprintf("msg repeated %d times, %ld sec of %d\n", 726 f->f_prevcount, (long)(now - f->f_time), 727 repeatinterval[f->f_repeatcount]); 728 /* 729 * If domark would have logged this by now, 730 * flush it now (so we don't hold isolated messages), 731 * but back off so we'll flush less often 732 * in the future. 733 */ 734 if (now > REPEATTIME(f)) { 735 fprintlog(f, flags, (char *)NULL); 736 BACKOFF(f); 737 } 738 } else { 739 /* new line, save it */ 740 if (f->f_prevcount) 741 fprintlog(f, 0, (char *)NULL); 742 f->f_repeatcount = 0; 743 f->f_prevpri = pri; 744 strlcpy(f->f_lasttime, timestamp, 16); 745 strlcpy(f->f_prevhost, from, 746 sizeof(f->f_prevhost)); 747 if (msglen < MAXSVLINE) { 748 f->f_prevlen = msglen; 749 strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); 750 fprintlog(f, flags, (char *)NULL); 751 } else { 752 f->f_prevline[0] = 0; 753 f->f_prevlen = 0; 754 fprintlog(f, flags, msg); 755 } 756 } 757 } 758 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 759 } 760 761 void 762 fprintlog(struct filed *f, int flags, char *msg) 763 { 764 struct iovec iov[6]; 765 struct iovec *v; 766 int l; 767 char line[MAXLINE + 1], repbuf[80], greetings[500]; 768 769 v = iov; 770 if (f->f_type == F_WALL) { 771 if ((l = snprintf(greetings, sizeof(greetings), 772 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 773 f->f_prevhost, ctime(&now))) >= sizeof(greetings) || 774 l == -1) 775 l = strlen(greetings); 776 v->iov_base = greetings; 777 v->iov_len = l; 778 v++; 779 v->iov_base = ""; 780 v->iov_len = 0; 781 v++; 782 } else { 783 v->iov_base = f->f_lasttime; 784 v->iov_len = 15; 785 v++; 786 v->iov_base = " "; 787 v->iov_len = 1; 788 v++; 789 } 790 v->iov_base = f->f_prevhost; 791 v->iov_len = strlen(v->iov_base); 792 v++; 793 v->iov_base = " "; 794 v->iov_len = 1; 795 v++; 796 797 if (msg) { 798 v->iov_base = msg; 799 v->iov_len = strlen(msg); 800 } else if (f->f_prevcount > 1) { 801 if ((l = snprintf(repbuf, sizeof(repbuf), 802 "last message repeated %d times", f->f_prevcount)) >= 803 sizeof(repbuf) || l == -1) 804 l = strlen(repbuf); 805 v->iov_base = repbuf; 806 v->iov_len = l; 807 } else { 808 v->iov_base = f->f_prevline; 809 v->iov_len = f->f_prevlen; 810 } 811 v++; 812 813 dprintf("Logging to %s", TypeNames[f->f_type]); 814 f->f_time = now; 815 816 switch (f->f_type) { 817 case F_UNUSED: 818 dprintf("\n"); 819 break; 820 821 case F_FORW: 822 dprintf(" %s\n", f->f_un.f_forw.f_hname); 823 if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s", 824 f->f_prevpri, (char *)iov[0].iov_base, 825 (char *)iov[4].iov_base)) >= sizeof(line) || l == -1) 826 l = strlen(line); 827 if (sendto(pfd[PFD_INET].fd, line, l, 0, 828 (struct sockaddr *)&f->f_un.f_forw.f_addr, 829 sizeof(f->f_un.f_forw.f_addr)) != l) { 830 f->f_type = F_UNUSED; 831 logerror("sendto"); 832 } 833 break; 834 835 case F_CONSOLE: 836 if (flags & IGN_CONS) { 837 dprintf(" (ignored)\n"); 838 break; 839 } 840 /* FALLTHROUGH */ 841 842 case F_TTY: 843 case F_FILE: 844 dprintf(" %s\n", f->f_un.f_fname); 845 if (f->f_type != F_FILE) { 846 v->iov_base = "\r\n"; 847 v->iov_len = 2; 848 } else { 849 v->iov_base = "\n"; 850 v->iov_len = 1; 851 } 852 again: 853 if (writev(f->f_file, iov, 6) < 0) { 854 int e = errno; 855 (void)close(f->f_file); 856 /* 857 * Check for errors on TTY's due to loss of tty 858 */ 859 if (e == EAGAIN) { 860 /* 861 * Silently drop messages on blocked write. 862 * This can happen when logging to a locked tty. 863 */ 864 break; 865 } else if ((e == EIO || e == EBADF) && 866 f->f_type != F_FILE) { 867 f->f_file = priv_open_tty(f->f_un.f_fname); 868 if (f->f_file < 0) { 869 f->f_type = F_UNUSED; 870 logerror(f->f_un.f_fname); 871 } else 872 goto again; 873 } else { 874 f->f_type = F_UNUSED; 875 f->f_file = -1; 876 errno = e; 877 logerror(f->f_un.f_fname); 878 } 879 } else if (flags & SYNC_FILE) 880 (void)fsync(f->f_file); 881 break; 882 883 case F_USERS: 884 case F_WALL: 885 dprintf("\n"); 886 v->iov_base = "\r\n"; 887 v->iov_len = 2; 888 wallmsg(f, iov); 889 break; 890 891 case F_MEMBUF: 892 dprintf("\n"); 893 snprintf(line, sizeof(line), "%.15s %s", 894 (char *)iov[0].iov_base, (char *)iov[4].iov_base); 895 ringbuf_append_line(f->f_un.f_mb.f_rb, line); 896 break; 897 } 898 f->f_prevcount = 0; 899 } 900 901 /* 902 * WALLMSG -- Write a message to the world at large 903 * 904 * Write the specified message to either the entire 905 * world, or a list of approved users. 906 */ 907 void 908 wallmsg(struct filed *f, struct iovec *iov) 909 { 910 struct utmp ut; 911 char line[sizeof(ut.ut_line) + 1], *p; 912 static int reenter; /* avoid calling ourselves */ 913 FILE *uf; 914 int i; 915 916 if (reenter++) 917 return; 918 if ((uf = priv_open_utmp()) == NULL) { 919 logerror(_PATH_UTMP); 920 reenter = 0; 921 return; 922 } 923 /* NOSTRICT */ 924 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 925 if (ut.ut_name[0] == '\0') 926 continue; 927 /* must use strncpy since ut_* may not be NUL terminated */ 928 strncpy(line, ut.ut_line, sizeof(line) - 1); 929 line[sizeof(line) - 1] = '\0'; 930 if (f->f_type == F_WALL) { 931 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 932 errno = 0; /* already in msg */ 933 logerror(p); 934 } 935 continue; 936 } 937 /* should we send the message to this user? */ 938 for (i = 0; i < MAXUNAMES; i++) { 939 if (!f->f_un.f_uname[i][0]) 940 break; 941 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 942 UT_NAMESIZE)) { 943 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 944 != NULL) { 945 errno = 0; /* already in msg */ 946 logerror(p); 947 } 948 break; 949 } 950 } 951 } 952 (void)fclose(uf); 953 reenter = 0; 954 } 955 956 void 957 reapchild(int signo) 958 { 959 int save_errno = errno; 960 int status; 961 962 while (waitpid(-1, &status, WNOHANG) > 0) 963 ; 964 errno = save_errno; 965 } 966 967 /* 968 * Return a printable representation of a host address. 969 */ 970 void 971 cvthname(struct sockaddr_in *f, char *result, size_t res_len) 972 { 973 sigset_t omask, nmask; 974 char *p, *ip; 975 int ret_len; 976 977 if (f->sin_family != AF_INET) { 978 dprintf("Malformed from address\n"); 979 strlcpy(result, "???", res_len); 980 return; 981 } 982 983 ip = inet_ntoa(f->sin_addr); 984 dprintf("cvthname(%s)\n", ip); 985 if (NoDNS) { 986 strlcpy(result, ip, res_len); 987 return; 988 } 989 990 sigemptyset(&nmask); 991 sigaddset(&nmask, SIGHUP); 992 sigprocmask(SIG_BLOCK, &nmask, &omask); 993 994 ret_len = priv_gethostbyaddr((char *)&f->sin_addr, 995 sizeof(struct in_addr), f->sin_family, result, res_len); 996 997 sigprocmask(SIG_SETMASK, &omask, NULL); 998 if (ret_len == 0) { 999 dprintf("Host name for your address (%s) unknown\n", ip); 1000 strlcpy(result, ip, res_len); 1001 } else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0) 1002 *p = '\0'; 1003 } 1004 1005 void 1006 dodie(int signo) 1007 { 1008 WantDie = signo; 1009 } 1010 1011 void 1012 domark(int signo) 1013 { 1014 MarkSet = 1; 1015 } 1016 1017 void 1018 doinit(int signo) 1019 { 1020 DoInit = 1; 1021 } 1022 1023 /* 1024 * Print syslogd errors some place. 1025 */ 1026 void 1027 logerror(char *type) 1028 { 1029 char buf[100]; 1030 1031 if (errno) 1032 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1033 type, strerror(errno)); 1034 else 1035 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 1036 errno = 0; 1037 dprintf("%s\n", buf); 1038 if (Startup) 1039 fprintf(stderr, "%s\n", buf); 1040 else 1041 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1042 } 1043 1044 void 1045 die(int signo) 1046 { 1047 struct filed *f; 1048 int was_initialized = Initialized; 1049 char buf[100]; 1050 1051 Initialized = 0; /* Don't log SIGCHLDs */ 1052 alarm(0); 1053 for (f = Files; f != NULL; f = f->f_next) { 1054 /* flush any pending output */ 1055 if (f->f_prevcount) 1056 fprintlog(f, 0, (char *)NULL); 1057 } 1058 Initialized = was_initialized; 1059 if (signo) { 1060 dprintf("syslogd: exiting on signal %d\n", signo); 1061 (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); 1062 errno = 0; 1063 logerror(buf); 1064 } 1065 dprintf("[unpriv] syslogd child about to exit\n"); 1066 exit(0); 1067 } 1068 1069 /* 1070 * INIT -- Initialize syslogd from configuration table 1071 */ 1072 void 1073 init(void) 1074 { 1075 char cline[LINE_MAX], prog[NAME_MAX+1], *p; 1076 struct filed *f, *next, **nextp; 1077 FILE *cf; 1078 int i; 1079 1080 dprintf("init\n"); 1081 1082 /* If config file has been modified, then just die to restart */ 1083 if (priv_config_modified()) { 1084 dprintf("config file changed: dying\n"); 1085 die(0); 1086 } 1087 1088 /* 1089 * Close all open log files. 1090 */ 1091 Initialized = 0; 1092 for (f = Files; f != NULL; f = next) { 1093 /* flush any pending output */ 1094 if (f->f_prevcount) 1095 fprintlog(f, 0, (char *)NULL); 1096 1097 switch (f->f_type) { 1098 case F_FILE: 1099 case F_TTY: 1100 case F_CONSOLE: 1101 (void)close(f->f_file); 1102 break; 1103 case F_FORW: 1104 break; 1105 } 1106 next = f->f_next; 1107 if (f->f_program) 1108 free(f->f_program); 1109 free((char *)f); 1110 } 1111 Files = NULL; 1112 nextp = &Files; 1113 1114 /* open the configuration file */ 1115 if ((cf = priv_open_config()) == NULL) { 1116 dprintf("cannot open %s\n", ConfFile); 1117 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1118 cfline("*.ERR\t/dev/console", *nextp, "*"); 1119 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1120 cfline("*.PANIC\t*", (*nextp)->f_next, "*"); 1121 Initialized = 1; 1122 return; 1123 } 1124 1125 /* 1126 * Foreach line in the conf table, open that file. 1127 */ 1128 f = NULL; 1129 strlcpy(prog, "*", sizeof(prog)); 1130 while (fgets(cline, sizeof(cline), cf) != NULL) { 1131 /* 1132 * check for end-of-section, comments, strip off trailing 1133 * spaces and newline character. !prog is treated 1134 * specially: the following lines apply only to that program. 1135 */ 1136 for (p = cline; isspace(*p); ++p) 1137 continue; 1138 if (*p == '\0' || *p == '#') 1139 continue; 1140 if (*p == '!') { 1141 p++; 1142 while (isspace(*p)) 1143 p++; 1144 if (!*p) { 1145 strlcpy(prog, "*", sizeof(prog)); 1146 continue; 1147 } 1148 for (i = 0; i < NAME_MAX; i++) { 1149 if (!isalnum(p[i])) 1150 break; 1151 prog[i] = p[i]; 1152 } 1153 prog[i] = 0; 1154 continue; 1155 } 1156 p = cline + strlen(cline); 1157 while (p > cline) 1158 if (!isspace(*--p)) { 1159 p++; 1160 break; 1161 } 1162 *p = '\0'; 1163 f = (struct filed *)calloc(1, sizeof(*f)); 1164 *nextp = f; 1165 nextp = &f->f_next; 1166 cfline(cline, f, prog); 1167 } 1168 1169 /* close the configuration file */ 1170 (void)fclose(cf); 1171 1172 Initialized = 1; 1173 1174 if (Debug) { 1175 for (f = Files; f; f = f->f_next) { 1176 for (i = 0; i <= LOG_NFACILITIES; i++) 1177 if (f->f_pmask[i] == INTERNAL_NOPRI) 1178 printf("X "); 1179 else 1180 printf("%d ", f->f_pmask[i]); 1181 printf("%s: ", TypeNames[f->f_type]); 1182 switch (f->f_type) { 1183 case F_FILE: 1184 case F_TTY: 1185 case F_CONSOLE: 1186 printf("%s", f->f_un.f_fname); 1187 break; 1188 1189 case F_FORW: 1190 printf("%s", f->f_un.f_forw.f_hname); 1191 break; 1192 1193 case F_USERS: 1194 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1195 printf("%s, ", f->f_un.f_uname[i]); 1196 break; 1197 1198 case F_MEMBUF: 1199 printf("%s", f->f_un.f_mb.f_mname); 1200 break; 1201 1202 } 1203 if (f->f_program) 1204 printf(" (%s)", f->f_program); 1205 printf("\n"); 1206 } 1207 } 1208 1209 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, 1210 ADDDATE); 1211 dprintf("syslogd: restarted\n"); 1212 } 1213 1214 /* 1215 * Crack a configuration file line 1216 */ 1217 void 1218 cfline(char *line, struct filed *f, char *prog) 1219 { 1220 int i, pri, addr_len; 1221 size_t rb_len; 1222 char *bp, *p, *q; 1223 char buf[MAXLINE], ebuf[100]; 1224 char addr[MAXHOSTNAMELEN]; 1225 struct filed *xf; 1226 1227 dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog); 1228 1229 errno = 0; /* keep strerror() stuff out of logerror messages */ 1230 1231 /* clear out file entry */ 1232 memset(f, 0, sizeof(*f)); 1233 for (i = 0; i <= LOG_NFACILITIES; i++) 1234 f->f_pmask[i] = INTERNAL_NOPRI; 1235 1236 /* save program name if any */ 1237 if (!strcmp(prog, "*")) 1238 prog = NULL; 1239 else { 1240 f->f_program = calloc(1, strlen(prog)+1); 1241 if (f->f_program) 1242 strlcpy(f->f_program, prog, strlen(prog)+1); 1243 } 1244 1245 /* scan through the list of selectors */ 1246 for (p = line; *p && *p != '\t';) { 1247 1248 /* find the end of this facility name list */ 1249 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1250 continue; 1251 1252 /* collect priority name */ 1253 for (bp = buf; *q && !strchr("\t,;", *q); ) 1254 *bp++ = *q++; 1255 *bp = '\0'; 1256 1257 /* skip cruft */ 1258 while (strchr(", ;", *q)) 1259 q++; 1260 1261 /* decode priority name */ 1262 if (*buf == '*') 1263 pri = LOG_PRIMASK + 1; 1264 else { 1265 /* ignore trailing spaces */ 1266 int i; 1267 for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) { 1268 buf[i]='\0'; 1269 } 1270 1271 pri = decode(buf, prioritynames); 1272 if (pri < 0) { 1273 (void)snprintf(ebuf, sizeof ebuf, 1274 "unknown priority name \"%s\"", buf); 1275 logerror(ebuf); 1276 return; 1277 } 1278 } 1279 1280 /* scan facilities */ 1281 while (*p && !strchr("\t.;", *p)) { 1282 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1283 *bp++ = *p++; 1284 *bp = '\0'; 1285 if (*buf == '*') 1286 for (i = 0; i < LOG_NFACILITIES; i++) 1287 f->f_pmask[i] = pri; 1288 else { 1289 i = decode(buf, facilitynames); 1290 if (i < 0) { 1291 (void)snprintf(ebuf, sizeof(ebuf), 1292 "unknown facility name \"%s\"", 1293 buf); 1294 logerror(ebuf); 1295 return; 1296 } 1297 f->f_pmask[i >> 3] = pri; 1298 } 1299 while (*p == ',' || *p == ' ') 1300 p++; 1301 } 1302 1303 p = q; 1304 } 1305 1306 /* skip to action part */ 1307 while (*p == '\t') 1308 p++; 1309 1310 switch (*p) { 1311 case '@': 1312 if (!InetInuse) 1313 break; 1314 (void)strlcpy(f->f_un.f_forw.f_hname, ++p, 1315 sizeof(f->f_un.f_forw.f_hname)); 1316 addr_len = priv_gethostbyname(f->f_un.f_forw.f_hname, 1317 addr, sizeof addr); 1318 if (addr_len < 1) { 1319 logerror((char *)hstrerror(h_errno)); 1320 break; 1321 } 1322 memset(&f->f_un.f_forw.f_addr, 0, 1323 sizeof(f->f_un.f_forw.f_addr)); 1324 f->f_un.f_forw.f_addr.sin_len = sizeof(f->f_un.f_forw.f_addr); 1325 f->f_un.f_forw.f_addr.sin_family = AF_INET; 1326 f->f_un.f_forw.f_addr.sin_port = LogPort; 1327 memmove(&f->f_un.f_forw.f_addr.sin_addr, addr, addr_len); 1328 f->f_type = F_FORW; 1329 break; 1330 1331 case '/': 1332 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1333 if (strcmp(p, ctty) == 0) 1334 f->f_file = priv_open_tty(p); 1335 else 1336 f->f_file = priv_open_log(p); 1337 if (f->f_file < 0) { 1338 f->f_type = F_UNUSED; 1339 logerror(p); 1340 break; 1341 } 1342 if (isatty(f->f_file)) { 1343 if (strcmp(p, ctty) == 0) 1344 f->f_type = F_CONSOLE; 1345 else 1346 f->f_type = F_TTY; 1347 } else { 1348 f->f_type = F_FILE; 1349 /* Clear O_NONBLOCK flag on f->f_file */ 1350 if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { 1351 i &= ~O_NONBLOCK; 1352 fcntl(f->f_file, F_SETFL, i); 1353 } 1354 } 1355 break; 1356 1357 case '*': 1358 f->f_type = F_WALL; 1359 break; 1360 1361 case ':': 1362 f->f_type = F_MEMBUF; 1363 1364 /* Parse buffer size (in kb) */ 1365 errno = 0; 1366 rb_len = strtoul(++p, &q, 0); 1367 if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) || 1368 *q != ':' || rb_len == 0) { 1369 f->f_type = F_UNUSED; 1370 logerror(p); 1371 break; 1372 } 1373 q++; 1374 rb_len *= 1024; 1375 1376 /* Copy buffer name */ 1377 for(i = 0; i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) { 1378 if (!isalnum(q[i])) 1379 break; 1380 f->f_un.f_mb.f_mname[i] = q[i]; 1381 } 1382 1383 /* Make sure buffer name is unique */ 1384 for (xf = Files; i != 0 && xf != f; xf = xf->f_next) { 1385 if (xf->f_type == F_MEMBUF && 1386 strcmp(xf->f_un.f_mb.f_mname, 1387 f->f_un.f_mb.f_mname) == 0) 1388 break; 1389 } 1390 1391 /* Error on missing or non-unique name, or bad buffer length */ 1392 if (i == 0 || rb_len > MAX_MEMBUF || xf != f) { 1393 f->f_type = F_UNUSED; 1394 logerror(p); 1395 break; 1396 } 1397 1398 /* Allocate buffer */ 1399 rb_len = MAX(rb_len, MIN_MEMBUF); 1400 if ((f->f_un.f_mb.f_rb = ringbuf_init(rb_len)) == NULL) { 1401 f->f_type = F_UNUSED; 1402 logerror(p); 1403 break; 1404 } 1405 break; 1406 1407 default: 1408 for (i = 0; i < MAXUNAMES && *p; i++) { 1409 for (q = p; *q && *q != ','; ) 1410 q++; 1411 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1412 if ((q - p) > UT_NAMESIZE) 1413 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1414 else 1415 f->f_un.f_uname[i][q - p] = '\0'; 1416 while (*q == ',' || *q == ' ') 1417 q++; 1418 p = q; 1419 } 1420 f->f_type = F_USERS; 1421 break; 1422 } 1423 } 1424 1425 1426 /* 1427 * Retrieve the size of the kernel message buffer, via sysctl. 1428 */ 1429 int 1430 getmsgbufsize(void) 1431 { 1432 int msgbufsize, mib[2]; 1433 size_t size; 1434 1435 mib[0] = CTL_KERN; 1436 mib[1] = KERN_MSGBUFSIZE; 1437 size = sizeof msgbufsize; 1438 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1439 dprintf("couldn't get kern.msgbufsize\n"); 1440 return (0); 1441 } 1442 return (msgbufsize); 1443 } 1444 1445 /* 1446 * Decode a symbolic name to a numeric value 1447 */ 1448 int 1449 decode(const char *name, const CODE *codetab) 1450 { 1451 const CODE *c; 1452 char *p, buf[40]; 1453 1454 if (isdigit(*name)) 1455 return (atoi(name)); 1456 1457 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1458 if (isupper(*name)) 1459 *p = tolower(*name); 1460 else 1461 *p = *name; 1462 } 1463 *p = '\0'; 1464 for (c = codetab; c->c_name; c++) 1465 if (!strcmp(buf, c->c_name)) 1466 return (c->c_val); 1467 1468 return (-1); 1469 } 1470 1471 void 1472 markit(void) 1473 { 1474 struct filed *f; 1475 1476 now = time((time_t *)NULL); 1477 MarkSeq += TIMERINTVL; 1478 if (MarkSeq >= MarkInterval) { 1479 logmsg(LOG_INFO, "-- MARK --", 1480 LocalHostName, ADDDATE|MARK); 1481 MarkSeq = 0; 1482 } 1483 1484 for (f = Files; f; f = f->f_next) { 1485 if (f->f_prevcount && now >= REPEATTIME(f)) { 1486 dprintf("flush %s: repeated %d times, %d sec.\n", 1487 TypeNames[f->f_type], f->f_prevcount, 1488 repeatinterval[f->f_repeatcount]); 1489 fprintlog(f, 0, (char *)NULL); 1490 BACKOFF(f); 1491 } 1492 } 1493 MarkSet = 0; 1494 (void)alarm(TIMERINTVL); 1495 } 1496 1497 int 1498 unix_socket(char *path, int type, mode_t mode) 1499 { 1500 struct sockaddr_un s_un; 1501 char errbuf[512]; 1502 int fd; 1503 mode_t old_umask; 1504 1505 memset(&s_un, 0, sizeof(s_un)); 1506 s_un.sun_family = AF_UNIX; 1507 if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) > 1508 sizeof(s_un.sun_path)) { 1509 snprintf(errbuf, sizeof(errbuf), "socket path too long: %s", 1510 path); 1511 logerror(errbuf); 1512 die(0); 1513 } 1514 1515 if ((fd = socket(AF_UNIX, type, 0)) == -1) { 1516 logerror("socket"); 1517 return (-1); 1518 } 1519 1520 if (Debug) { 1521 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 || 1522 errno == EPROTOTYPE) { 1523 close(fd); 1524 errno = EISCONN; 1525 logerror("connect"); 1526 return (-1); 1527 } 1528 } 1529 1530 old_umask = umask(0177); 1531 1532 unlink(path); 1533 if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) { 1534 snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path); 1535 logerror(errbuf); 1536 umask(old_umask); 1537 close(fd); 1538 return (-1); 1539 } 1540 1541 umask(old_umask); 1542 1543 if (chmod(path, mode) == -1) { 1544 snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path); 1545 logerror(errbuf); 1546 close(fd); 1547 unlink(path); 1548 return (-1); 1549 } 1550 1551 return (fd); 1552 } 1553 1554 void 1555 double_rbuf(int fd) 1556 { 1557 socklen_t slen, len; 1558 1559 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { 1560 len *= 2; 1561 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); 1562 } 1563 } 1564 1565 static void 1566 ctlconn_cleanup(void) 1567 { 1568 if (pfd[PFD_CTLCONN].fd != -1) 1569 close(pfd[PFD_CTLCONN].fd); 1570 1571 pfd[PFD_CTLCONN].fd = -1; 1572 pfd[PFD_CTLCONN].events = pfd[PFD_CTLCONN].revents = 0; 1573 1574 pfd[PFD_CTLSOCK].events = POLLIN; 1575 1576 ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0; 1577 } 1578 1579 void 1580 ctlsock_accept_handler(void) 1581 { 1582 int fd, flags; 1583 1584 dprintf("Accepting control connection\n"); 1585 fd = accept(pfd[PFD_CTLSOCK].fd, NULL, NULL); 1586 if (fd == -1) { 1587 if (errno != EINTR && errno != ECONNABORTED) 1588 logerror("accept ctlsock"); 1589 return; 1590 } 1591 1592 ctlconn_cleanup(); 1593 1594 /* Only one connection at a time */ 1595 pfd[PFD_CTLSOCK].events = pfd[PFD_CTLSOCK].revents = 0; 1596 1597 if ((flags = fcntl(fd, F_GETFL)) == -1 || 1598 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 1599 logerror("fcntl ctlconn"); 1600 close(fd); 1601 return; 1602 } 1603 1604 pfd[PFD_CTLCONN].fd = fd; 1605 pfd[PFD_CTLCONN].events = POLLIN; 1606 ctl_state = CTL_READING_CMD; 1607 ctl_cmd_bytes = 0; 1608 } 1609 1610 static struct filed 1611 *find_membuf_log(const char *name) 1612 { 1613 struct filed *f; 1614 1615 for (f = Files; f != NULL; f = f->f_next) { 1616 if (f->f_type == F_MEMBUF && 1617 strcmp(f->f_un.f_mb.f_mname, name) == 0) 1618 break; 1619 } 1620 return (f); 1621 } 1622 1623 void 1624 ctlconn_read_handler(void) 1625 { 1626 ssize_t n; 1627 struct filed *f; 1628 1629 if (ctl_state != CTL_READING_CMD) { 1630 /* Shouldn't be here! */ 1631 logerror("ctlconn_read with bad ctl_state"); 1632 ctlconn_cleanup(); 1633 return; 1634 } 1635 retry: 1636 n = read(pfd[PFD_CTLCONN].fd, (char*)&ctl_cmd + ctl_cmd_bytes, 1637 sizeof(ctl_cmd) - ctl_cmd_bytes); 1638 switch (n) { 1639 case -1: 1640 if (errno == EINTR) 1641 goto retry; 1642 logerror("ctlconn read"); 1643 /* FALLTHROUGH */ 1644 case 0: 1645 ctlconn_cleanup(); 1646 return; 1647 default: 1648 ctl_cmd_bytes += n; 1649 } 1650 1651 if (ctl_cmd_bytes < sizeof(ctl_cmd)) 1652 return; 1653 1654 /* Ensure that logname is \0 terminated */ 1655 if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) { 1656 logerror("Corrupt ctlsock command"); 1657 ctlconn_cleanup(); 1658 return; 1659 } 1660 1661 ctl_reply_size = ctl_reply_offset = 0; 1662 *ctl_reply = '\0'; 1663 1664 dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname); 1665 1666 switch (ctl_cmd.cmd) { 1667 case CMD_READ: 1668 case CMD_READ_CLEAR: 1669 f = find_membuf_log(ctl_cmd.logname); 1670 if (f == NULL) { 1671 strlcpy(ctl_reply, "No such log\n", MAX_MEMBUF); 1672 } else { 1673 ringbuf_to_string(ctl_reply, MAX_MEMBUF, 1674 f->f_un.f_mb.f_rb); 1675 if (ctl_cmd.cmd == CMD_READ_CLEAR) 1676 ringbuf_clear(f->f_un.f_mb.f_rb); 1677 } 1678 ctl_reply_size = strlen(ctl_reply); 1679 break; 1680 case CMD_CLEAR: 1681 f = find_membuf_log(ctl_cmd.logname); 1682 if (f == NULL) { 1683 strlcpy(ctl_reply, "No such log\n", MAX_MEMBUF); 1684 } else { 1685 ringbuf_clear(f->f_un.f_mb.f_rb); 1686 strlcpy(ctl_reply, "Log cleared\n", MAX_MEMBUF); 1687 } 1688 ctl_reply_size = strlen(ctl_reply); 1689 break; 1690 case CMD_LIST: 1691 for (f = Files; f != NULL; f = f->f_next) { 1692 if (f->f_type == F_MEMBUF) { 1693 strlcat(ctl_reply, f->f_un.f_mb.f_mname, 1694 MAX_MEMBUF); 1695 strlcat(ctl_reply, " ", MAX_MEMBUF); 1696 } 1697 } 1698 strlcat(ctl_reply, "\n", MAX_MEMBUF); 1699 ctl_reply_size = strlen(ctl_reply); 1700 break; 1701 default: 1702 logerror("Unsupported ctlsock command"); 1703 ctlconn_cleanup(); 1704 return; 1705 } 1706 1707 dprintf("ctlcmd reply length %d\n", ctl_reply_size); 1708 1709 /* If there is no reply, close the connection now */ 1710 if (ctl_reply_size == 0) { 1711 ctlconn_cleanup(); 1712 return; 1713 } 1714 1715 /* Otherwise, set up to write out reply */ 1716 ctl_state = CTL_WRITING_REPLY; 1717 pfd[PFD_CTLCONN].events = POLLOUT; 1718 pfd[PFD_CTLCONN].revents = 0; 1719 } 1720 1721 void 1722 ctlconn_write_handler(void) 1723 { 1724 ssize_t n; 1725 1726 if (ctl_state != CTL_WRITING_REPLY) { 1727 /* Shouldn't be here! */ 1728 logerror("ctlconn_write with bad ctl_state"); 1729 ctlconn_cleanup(); 1730 return; 1731 } 1732 retry: 1733 n = write(pfd[PFD_CTLCONN].fd, ctl_reply + ctl_reply_offset, 1734 ctl_reply_size - ctl_reply_offset); 1735 switch (n) { 1736 case -1: 1737 if (errno == EINTR) 1738 goto retry; 1739 if (errno != EPIPE) 1740 logerror("ctlconn write"); 1741 /* FALLTHROUGH */ 1742 case 0: 1743 ctlconn_cleanup(); 1744 return; 1745 default: 1746 ctl_reply_offset += n; 1747 } 1748 1749 if (ctl_reply_offset >= ctl_reply_size) 1750 ctlconn_cleanup(); 1751 } 1752