1 /* $OpenBSD: syslogd.c,v 1.110 2014/02/04 23:28:05 bluhm 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 /* 33 * syslogd -- log system messages 34 * 35 * This program implements a system log. It takes a series of lines. 36 * Each line may have a priority, signified as "<n>" as 37 * the first characters of the line. If this is 38 * not present, a default priority is used. 39 * 40 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 41 * cause it to reread its configuration file. 42 * 43 * Defined Constants: 44 * 45 * MAXLINE -- the maximum line length that can be handled. 46 * DEFUPRI -- the default priority for user messages 47 * DEFSPRI -- the default priority for kernel messages 48 * 49 * Author: Eric Allman 50 * extensive changes by Ralph Campbell 51 * more extensive changes by Eric Allman (again) 52 * memory buffer logging by Damien Miller 53 */ 54 55 #define MAXLINE 1024 /* maximum line length */ 56 #define MIN_MEMBUF (MAXLINE * 4) /* Minimum memory buffer size */ 57 #define MAX_MEMBUF (256 * 1024) /* Maximum memory buffer size */ 58 #define MAX_MEMBUF_NAME 64 /* Max length of membuf log name */ 59 #define MAXSVLINE 120 /* maximum saved line length */ 60 #define DEFUPRI (LOG_USER|LOG_NOTICE) 61 #define DEFSPRI (LOG_KERN|LOG_CRIT) 62 #define TIMERINTVL 30 /* interval for checking flush, mark */ 63 #define TTYMSGTIME 1 /* timeout passed to ttymsg */ 64 65 #include <sys/param.h> 66 #include <sys/ioctl.h> 67 #include <sys/stat.h> 68 #include <sys/wait.h> 69 #include <sys/socket.h> 70 #include <sys/msgbuf.h> 71 #include <sys/uio.h> 72 #include <sys/sysctl.h> 73 #include <sys/un.h> 74 #include <sys/time.h> 75 #include <sys/resource.h> 76 77 #include <netinet/in.h> 78 #include <netdb.h> 79 #include <arpa/inet.h> 80 81 #include <ctype.h> 82 #include <errno.h> 83 #include <err.h> 84 #include <fcntl.h> 85 #include <paths.h> 86 #include <poll.h> 87 #include <signal.h> 88 #include <stdio.h> 89 #include <stdlib.h> 90 #include <string.h> 91 #include <unistd.h> 92 #include <utmp.h> 93 #include <vis.h> 94 95 #define SYSLOG_NAMES 96 #include <sys/syslog.h> 97 98 #include "syslogd.h" 99 100 char *ConfFile = _PATH_LOGCONF; 101 const char ctty[] = _PATH_CONSOLE; 102 103 #define MAXUNAMES 20 /* maximum number of user names */ 104 105 106 /* 107 * Flags to logmsg(). 108 */ 109 110 #define IGN_CONS 0x001 /* don't print on console */ 111 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 112 #define ADDDATE 0x004 /* add a date to the message */ 113 #define MARK 0x008 /* this message is a mark */ 114 115 /* 116 * This structure represents the files that will have log 117 * copies printed. 118 */ 119 120 struct filed { 121 struct filed *f_next; /* next in linked list */ 122 short f_type; /* entry type, see below */ 123 short f_file; /* file descriptor */ 124 time_t f_time; /* time this was last written */ 125 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 126 char *f_program; /* program this applies to */ 127 union { 128 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 129 struct { 130 char f_hname[MAXHOSTNAMELEN]; 131 struct sockaddr_storage f_addr; 132 } f_forw; /* forwarding address */ 133 char f_fname[MAXPATHLEN]; 134 struct { 135 char f_mname[MAX_MEMBUF_NAME]; 136 struct ringbuf *f_rb; 137 int f_overflow; 138 int f_attached; 139 size_t f_len; 140 } f_mb; /* Memory buffer */ 141 } f_un; 142 char f_prevline[MAXSVLINE]; /* last message logged */ 143 char f_lasttime[16]; /* time of last occurrence */ 144 char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */ 145 int f_prevpri; /* pri of f_prevline */ 146 int f_prevlen; /* length of f_prevline */ 147 int f_prevcount; /* repetition cnt of prevline */ 148 unsigned int f_repeatcount; /* number of "repeated" msgs */ 149 int f_quick; /* abort when matched */ 150 time_t f_lasterrtime; /* last error was reported */ 151 }; 152 153 /* 154 * Intervals at which we flush out "message repeated" messages, 155 * in seconds after previous message is logged. After each flush, 156 * we move to the next interval until we reach the largest. 157 */ 158 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 159 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 160 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 161 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 162 (f)->f_repeatcount = MAXREPEAT; \ 163 } 164 165 /* values for f_type */ 166 #define F_UNUSED 0 /* unused entry */ 167 #define F_FILE 1 /* regular file */ 168 #define F_TTY 2 /* terminal */ 169 #define F_CONSOLE 3 /* console terminal */ 170 #define F_FORW 4 /* remote machine */ 171 #define F_USERS 5 /* list of users */ 172 #define F_WALL 6 /* everyone logged on */ 173 #define F_MEMBUF 7 /* memory buffer */ 174 #define F_PIPE 8 /* pipe to external program */ 175 176 char *TypeNames[9] = { 177 "UNUSED", "FILE", "TTY", "CONSOLE", 178 "FORW", "USERS", "WALL", "MEMBUF", 179 "PIPE" 180 }; 181 182 struct filed *Files; 183 struct filed consfile; 184 185 int nfunix = 1; /* Number of Unix domain sockets requested */ 186 char *funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */ 187 int Debug; /* debug flag */ 188 int Startup = 1; /* startup flag */ 189 char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 190 char *LocalDomain; /* our local domain name */ 191 int InetInuse = 0; /* non-zero if INET sockets are being used */ 192 int Initialized = 0; /* set when we have initialized ourselves */ 193 194 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 195 int MarkSeq = 0; /* mark sequence number */ 196 int SecureMode = 1; /* when true, speak only unix domain socks */ 197 int NoDNS = 0; /* when true, will refrain from doing DNS lookups */ 198 int IncludeHostname = 0; /* include RFC 3164 style hostnames when forwarding */ 199 200 char *ctlsock_path = NULL; /* Path to control socket */ 201 202 #define CTL_READING_CMD 1 203 #define CTL_WRITING_REPLY 2 204 #define CTL_WRITING_CONT_REPLY 3 205 int ctl_state = 0; /* What the control socket is up to */ 206 int membuf_drop = 0; /* logs were dropped in continuous membuf read */ 207 208 /* 209 * Client protocol NB. all numeric fields in network byte order 210 */ 211 #define CTL_VERSION 2 212 213 /* Request */ 214 struct { 215 u_int32_t version; 216 #define CMD_READ 1 /* Read out log */ 217 #define CMD_READ_CLEAR 2 /* Read and clear log */ 218 #define CMD_CLEAR 3 /* Clear log */ 219 #define CMD_LIST 4 /* List available logs */ 220 #define CMD_FLAGS 5 /* Query flags only */ 221 #define CMD_READ_CONT 6 /* Read out log continuously */ 222 u_int32_t cmd; 223 u_int32_t lines; 224 char logname[MAX_MEMBUF_NAME]; 225 } ctl_cmd; 226 227 size_t ctl_cmd_bytes = 0; /* number of bytes of ctl_cmd read */ 228 229 /* Reply */ 230 struct ctl_reply_hdr { 231 u_int32_t version; 232 #define CTL_HDR_FLAG_OVERFLOW 0x01 233 u_int32_t flags; 234 /* Reply text follows, up to MAX_MEMBUF long */ 235 }; 236 237 #define CTL_HDR_LEN (sizeof(struct ctl_reply_hdr)) 238 #define CTL_REPLY_MAXSIZE (CTL_HDR_LEN + MAX_MEMBUF) 239 #define CTL_REPLY_SIZE (strlen(reply_text) + CTL_HDR_LEN) 240 241 char *ctl_reply = NULL; /* Buffer for control connection reply */ 242 char *reply_text; /* Start of reply text in buffer */ 243 size_t ctl_reply_size = 0; /* Number of bytes used in reply */ 244 size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */ 245 246 struct pollfd pfd[N_PFD]; 247 248 volatile sig_atomic_t MarkSet; 249 volatile sig_atomic_t WantDie; 250 volatile sig_atomic_t DoInit; 251 252 struct filed *cfline(char *, char *); 253 void cvthname(struct sockaddr_in *, char *, size_t); 254 int decode(const char *, const CODE *); 255 void dodie(int); 256 void doinit(int); 257 void die(int); 258 void domark(int); 259 void markit(void); 260 void fprintlog(struct filed *, int, char *); 261 void init(void); 262 void logerror(const char *); 263 void logmsg(int, char *, char *, int); 264 struct filed *find_dup(struct filed *); 265 void printline(char *, char *); 266 void printsys(char *); 267 void reapchild(int); 268 char *ttymsg(struct iovec *, int, char *, int); 269 void usage(void); 270 void wallmsg(struct filed *, struct iovec *); 271 int getmsgbufsize(void); 272 int unix_socket(char *, int, mode_t); 273 void double_rbuf(int); 274 void ctlsock_accept_handler(void); 275 void ctlconn_read_handler(void); 276 void ctlconn_write_handler(void); 277 void tailify_replytext(char *, int); 278 void logto_ctlconn(char *); 279 280 int 281 main(int argc, char *argv[]) 282 { 283 int ch, i, linesize, fd; 284 struct sockaddr_un fromunix; 285 struct sockaddr_in frominet; 286 socklen_t len; 287 char *p, *line; 288 char resolve[MAXHOSTNAMELEN]; 289 int lockpipe[2] = { -1, -1}, nullfd; 290 struct addrinfo hints, *res, *res0; 291 FILE *fp; 292 293 while ((ch = getopt(argc, argv, "dhnuf:m:p:a:s:")) != -1) 294 switch (ch) { 295 case 'd': /* debug */ 296 Debug++; 297 break; 298 case 'f': /* configuration file */ 299 ConfFile = optarg; 300 break; 301 case 'h': /* RFC 3164 hostnames */ 302 IncludeHostname = 1; 303 break; 304 case 'm': /* mark interval */ 305 MarkInterval = atoi(optarg) * 60; 306 break; 307 case 'n': /* don't do DNS lookups */ 308 NoDNS = 1; 309 break; 310 case 'p': /* path */ 311 funixn[0] = optarg; 312 break; 313 case 'u': /* allow udp input port */ 314 SecureMode = 0; 315 break; 316 case 'a': 317 if (nfunix >= MAXFUNIX) 318 fprintf(stderr, "syslogd: " 319 "out of descriptors, ignoring %s\n", 320 optarg); 321 else 322 funixn[nfunix++] = optarg; 323 break; 324 case 's': 325 ctlsock_path = optarg; 326 break; 327 default: 328 usage(); 329 } 330 if ((argc -= optind) != 0) 331 usage(); 332 333 if (Debug) 334 setlinebuf(stdout); 335 336 if ((fd = nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 337 logerror("Couldn't open /dev/null"); 338 die(0); 339 } 340 while (fd++ <= 2) { 341 if (fcntl(fd, F_GETFL, 0) == -1) 342 if (dup2(nullfd, fd) == -1) 343 logerror("dup2"); 344 } 345 346 consfile.f_type = F_CONSOLE; 347 (void)strlcpy(consfile.f_un.f_fname, ctty, 348 sizeof(consfile.f_un.f_fname)); 349 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 350 if ((p = strchr(LocalHostName, '.')) != NULL) { 351 *p++ = '\0'; 352 LocalDomain = p; 353 } else 354 LocalDomain = ""; 355 356 linesize = getmsgbufsize(); 357 if (linesize < MAXLINE) 358 linesize = MAXLINE; 359 linesize++; 360 if ((line = malloc(linesize)) == NULL) { 361 logerror("Couldn't allocate line buffer"); 362 die(0); 363 } 364 365 /* Clear poll array, set all fds to ignore */ 366 for (i = 0; i < N_PFD; i++) { 367 pfd[i].fd = -1; 368 pfd[i].events = 0; 369 } 370 371 memset(&hints, 0, sizeof(hints)); 372 hints.ai_family = AF_INET; 373 hints.ai_socktype = SOCK_DGRAM; 374 hints.ai_protocol = IPPROTO_UDP; 375 hints.ai_flags = AI_PASSIVE; 376 377 i = getaddrinfo(NULL, "syslog", &hints, &res0); 378 if (i) { 379 errno = 0; 380 logerror("syslog/udp: unknown service"); 381 die(0); 382 } 383 384 for (res = res0; res; res = res->ai_next) { 385 struct pollfd *pfdp; 386 387 if (res->ai_family == AF_INET) 388 pfdp = &pfd[PFD_INET]; 389 else { 390 /* 391 * XXX AF_INET6 is skipped on purpose, need to 392 * fix '@' handling first. 393 */ 394 continue; 395 } 396 397 if (pfdp->fd >= 0) 398 continue; 399 400 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 401 if (fd < 0) 402 continue; 403 404 if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { 405 logerror("bind"); 406 close(fd); 407 if (!Debug) 408 die(0); 409 fd = -1; 410 continue; 411 } 412 413 InetInuse = 1; 414 pfdp->fd = fd; 415 if (SecureMode) 416 shutdown(pfdp->fd, SHUT_RD); 417 else { 418 double_rbuf(pfdp->fd); 419 pfdp->events = POLLIN; 420 } 421 } 422 423 freeaddrinfo(res0); 424 425 #ifndef SUN_LEN 426 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 427 #endif 428 for (i = 0; i < nfunix; i++) { 429 if ((fd = unix_socket(funixn[i], SOCK_DGRAM, 0666)) == -1) { 430 if (i == 0 && !Debug) 431 die(0); 432 continue; 433 } 434 double_rbuf(fd); 435 pfd[PFD_UNIX_0 + i].fd = fd; 436 pfd[PFD_UNIX_0 + i].events = POLLIN; 437 } 438 439 if (ctlsock_path != NULL) { 440 fd = unix_socket(ctlsock_path, SOCK_STREAM, 0600); 441 if (fd != -1) { 442 if (listen(fd, 16) == -1) { 443 logerror("ctlsock listen"); 444 die(0); 445 } 446 pfd[PFD_CTLSOCK].fd = fd; 447 pfd[PFD_CTLSOCK].events = POLLIN; 448 } else if (!Debug) 449 die(0); 450 } 451 452 if ((fd = open(_PATH_KLOG, O_RDONLY, 0)) == -1) { 453 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 454 } else { 455 pfd[PFD_KLOG].fd = fd; 456 pfd[PFD_KLOG].events = POLLIN; 457 } 458 459 dprintf("off & running....\n"); 460 461 chdir("/"); 462 463 tzset(); 464 465 if (!Debug) { 466 char c; 467 468 pipe(lockpipe); 469 470 switch(fork()) { 471 case -1: 472 exit(1); 473 case 0: 474 setsid(); 475 close(lockpipe[0]); 476 break; 477 default: 478 close(lockpipe[1]); 479 read(lockpipe[0], &c, 1); 480 _exit(0); 481 } 482 } 483 484 /* tuck my process id away */ 485 if (!Debug) { 486 fp = fopen(_PATH_LOGPID, "w"); 487 if (fp != NULL) { 488 fprintf(fp, "%ld\n", (long)getpid()); 489 (void) fclose(fp); 490 } 491 } 492 493 /* Privilege separation begins here */ 494 if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0) 495 errx(1, "unable to privsep"); 496 497 /* Process is now unprivileged and inside a chroot */ 498 init(); 499 500 Startup = 0; 501 502 /* Allocate ctl socket reply buffer if we have a ctl socket */ 503 if (pfd[PFD_CTLSOCK].fd != -1 && 504 (ctl_reply = malloc(CTL_REPLY_MAXSIZE)) == NULL) { 505 logerror("Couldn't allocate ctlsock reply buffer"); 506 die(0); 507 } 508 reply_text = ctl_reply + CTL_HDR_LEN; 509 510 if (!Debug) { 511 dup2(nullfd, STDIN_FILENO); 512 dup2(nullfd, STDOUT_FILENO); 513 dup2(nullfd, STDERR_FILENO); 514 if (nullfd > 2) 515 close(nullfd); 516 close(lockpipe[1]); 517 } 518 519 /* 520 * Signal to the priv process that the initial config parsing is done 521 * so that it will reject any future attempts to open more files 522 */ 523 priv_config_parse_done(); 524 525 (void)signal(SIGHUP, doinit); 526 (void)signal(SIGTERM, dodie); 527 (void)signal(SIGINT, Debug ? dodie : SIG_IGN); 528 (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); 529 (void)signal(SIGCHLD, reapchild); 530 (void)signal(SIGALRM, domark); 531 (void)signal(SIGPIPE, SIG_IGN); 532 (void)alarm(TIMERINTVL); 533 534 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: start", LocalHostName, ADDDATE); 535 dprintf("syslogd: started\n"); 536 537 for (;;) { 538 if (MarkSet) 539 markit(); 540 if (WantDie) 541 die(WantDie); 542 543 if (DoInit) { 544 init(); 545 DoInit = 0; 546 547 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", 548 LocalHostName, ADDDATE); 549 dprintf("syslogd: restarted\n"); 550 } 551 552 switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) { 553 case 0: 554 continue; 555 case -1: 556 if (errno != EINTR) 557 logerror("poll"); 558 continue; 559 } 560 561 if ((pfd[PFD_KLOG].revents & POLLIN) != 0) { 562 i = read(pfd[PFD_KLOG].fd, line, linesize - 1); 563 if (i > 0) { 564 line[i] = '\0'; 565 printsys(line); 566 } else if (i < 0 && errno != EINTR) { 567 logerror("klog"); 568 pfd[PFD_KLOG].fd = -1; 569 pfd[PFD_KLOG].events = 0; 570 } 571 } 572 if ((pfd[PFD_INET].revents & POLLIN) != 0) { 573 len = sizeof(frominet); 574 i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0, 575 (struct sockaddr *)&frominet, &len); 576 if (i > 0) { 577 line[i] = '\0'; 578 cvthname(&frominet, resolve, 579 sizeof resolve); 580 dprintf("cvthname res: %s\n", resolve); 581 printline(resolve, line); 582 } else if (i < 0 && errno != EINTR) 583 logerror("recvfrom inet"); 584 } 585 if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0) 586 ctlsock_accept_handler(); 587 if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0) 588 ctlconn_read_handler(); 589 if ((pfd[PFD_CTLCONN].revents & POLLOUT) != 0) 590 ctlconn_write_handler(); 591 592 for (i = 0; i < nfunix; i++) { 593 if ((pfd[PFD_UNIX_0 + i].revents & POLLIN) != 0) { 594 ssize_t rlen; 595 596 len = sizeof(fromunix); 597 rlen = recvfrom(pfd[PFD_UNIX_0 + i].fd, line, 598 MAXLINE, 0, (struct sockaddr *)&fromunix, 599 &len); 600 if (rlen > 0) { 601 line[rlen] = '\0'; 602 printline(LocalHostName, line); 603 } else if (rlen == -1 && errno != EINTR) 604 logerror("recvfrom unix"); 605 } 606 } 607 } 608 /* NOTREACHED */ 609 free(pfd); 610 return (0); 611 } 612 613 void 614 usage(void) 615 { 616 617 (void)fprintf(stderr, 618 "usage: syslogd [-dhnu] [-a path] [-f config_file] [-m mark_interval]\n" 619 " [-p log_socket] [-s reporting_socket]\n"); 620 exit(1); 621 } 622 623 /* 624 * Take a raw input line, decode the message, and print the message 625 * on the appropriate log files. 626 */ 627 void 628 printline(char *hname, char *msg) 629 { 630 int pri; 631 char *p, *q, line[MAXLINE + 1]; 632 633 /* test for special codes */ 634 pri = DEFUPRI; 635 p = msg; 636 if (*p == '<') { 637 pri = 0; 638 while (isdigit((unsigned char)*++p)) 639 pri = 10 * pri + (*p - '0'); 640 if (*p == '>') 641 ++p; 642 } 643 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 644 pri = DEFUPRI; 645 646 /* 647 * Don't allow users to log kernel messages. 648 * NOTE: since LOG_KERN == 0 this will also match 649 * messages with no facility specified. 650 */ 651 if (LOG_FAC(pri) == LOG_KERN) 652 pri = LOG_USER | LOG_PRI(pri); 653 654 for (q = line; *p && q < &line[sizeof(line) - 4]; p++) { 655 if (*p == '\n') 656 *q++ = ' '; 657 else 658 q = vis(q, *p, 0, 0); 659 } 660 *q = '\0'; 661 662 logmsg(pri, line, hname, 0); 663 } 664 665 /* 666 * Take a raw input line from /dev/klog, split and format similar to syslog(). 667 */ 668 void 669 printsys(char *msg) 670 { 671 int c, pri, flags; 672 char *lp, *p, *q, line[MAXLINE + 1]; 673 674 (void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX); 675 lp = line + strlen(line); 676 for (p = msg; *p != '\0'; ) { 677 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 678 pri = DEFSPRI; 679 if (*p == '<') { 680 pri = 0; 681 while (isdigit((unsigned char)*++p)) 682 pri = 10 * pri + (*p - '0'); 683 if (*p == '>') 684 ++p; 685 } else { 686 /* kernel printf's come out on console */ 687 flags |= IGN_CONS; 688 } 689 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 690 pri = DEFSPRI; 691 692 q = lp; 693 while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4]) 694 q = vis(q, c, 0, 0); 695 696 logmsg(pri, line, LocalHostName, flags); 697 } 698 } 699 700 time_t now; 701 702 /* 703 * Log a message to the appropriate log files, users, etc. based on 704 * the priority. 705 */ 706 void 707 logmsg(int pri, char *msg, char *from, int flags) 708 { 709 struct filed *f; 710 int fac, msglen, prilev, i; 711 sigset_t mask, omask; 712 char *timestamp; 713 char prog[NAME_MAX+1]; 714 715 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 716 pri, flags, from, msg); 717 718 sigemptyset(&mask); 719 sigaddset(&mask, SIGALRM); 720 sigaddset(&mask, SIGHUP); 721 sigprocmask(SIG_BLOCK, &mask, &omask); 722 723 /* 724 * Check to see if msg looks non-standard. 725 */ 726 msglen = strlen(msg); 727 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 728 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 729 flags |= ADDDATE; 730 731 (void)time(&now); 732 if (flags & ADDDATE) 733 timestamp = ctime(&now) + 4; 734 else { 735 timestamp = msg; 736 msg += 16; 737 msglen -= 16; 738 } 739 740 /* extract facility and priority level */ 741 if (flags & MARK) 742 fac = LOG_NFACILITIES; 743 else 744 fac = LOG_FAC(pri); 745 prilev = LOG_PRI(pri); 746 747 /* extract program name */ 748 while (isspace((unsigned char)*msg)) 749 msg++; 750 for (i = 0; i < NAME_MAX; i++) { 751 if (!isalnum((unsigned char)msg[i]) && msg[i] != '-') 752 break; 753 prog[i] = msg[i]; 754 } 755 prog[i] = 0; 756 757 /* log the message to the particular outputs */ 758 if (!Initialized) { 759 f = &consfile; 760 f->f_file = priv_open_tty(ctty); 761 762 if (f->f_file >= 0) { 763 fprintlog(f, flags, msg); 764 (void)close(f->f_file); 765 f->f_file = -1; 766 } 767 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 768 return; 769 } 770 for (f = Files; f; f = f->f_next) { 771 /* skip messages that are incorrect priority */ 772 if (f->f_pmask[fac] < prilev || 773 f->f_pmask[fac] == INTERNAL_NOPRI) 774 continue; 775 776 /* skip messages with the incorrect program name */ 777 if (f->f_program) 778 if (strcmp(prog, f->f_program) != 0) 779 continue; 780 781 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 782 continue; 783 784 /* don't output marks to recently written files */ 785 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 786 continue; 787 788 /* 789 * suppress duplicate lines to this file 790 */ 791 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 792 !strcmp(msg, f->f_prevline) && 793 !strcmp(from, f->f_prevhost)) { 794 strlcpy(f->f_lasttime, timestamp, 16); 795 f->f_prevcount++; 796 dprintf("msg repeated %d times, %ld sec of %d\n", 797 f->f_prevcount, (long)(now - f->f_time), 798 repeatinterval[f->f_repeatcount]); 799 /* 800 * If domark would have logged this by now, 801 * flush it now (so we don't hold isolated messages), 802 * but back off so we'll flush less often 803 * in the future. 804 */ 805 if (now > REPEATTIME(f)) { 806 fprintlog(f, flags, (char *)NULL); 807 BACKOFF(f); 808 } 809 } else { 810 /* new line, save it */ 811 if (f->f_prevcount) 812 fprintlog(f, 0, (char *)NULL); 813 f->f_repeatcount = 0; 814 f->f_prevpri = pri; 815 strlcpy(f->f_lasttime, timestamp, 16); 816 strlcpy(f->f_prevhost, from, 817 sizeof(f->f_prevhost)); 818 if (msglen < MAXSVLINE) { 819 f->f_prevlen = msglen; 820 strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); 821 fprintlog(f, flags, (char *)NULL); 822 } else { 823 f->f_prevline[0] = 0; 824 f->f_prevlen = 0; 825 fprintlog(f, flags, msg); 826 } 827 } 828 829 if (f->f_quick) 830 break; 831 } 832 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 833 } 834 835 void 836 fprintlog(struct filed *f, int flags, char *msg) 837 { 838 struct iovec iov[6]; 839 struct iovec *v; 840 int l, retryonce; 841 char line[MAXLINE + 1], repbuf[80], greetings[500]; 842 843 v = iov; 844 if (f->f_type == F_WALL) { 845 if ((l = snprintf(greetings, sizeof(greetings), 846 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 847 f->f_prevhost, ctime(&now))) >= sizeof(greetings) || 848 l == -1) 849 l = strlen(greetings); 850 v->iov_base = greetings; 851 v->iov_len = l; 852 v++; 853 v->iov_base = ""; 854 v->iov_len = 0; 855 v++; 856 } else { 857 v->iov_base = f->f_lasttime; 858 v->iov_len = 15; 859 v++; 860 v->iov_base = " "; 861 v->iov_len = 1; 862 v++; 863 } 864 v->iov_base = f->f_prevhost; 865 v->iov_len = strlen(v->iov_base); 866 v++; 867 v->iov_base = " "; 868 v->iov_len = 1; 869 v++; 870 871 if (msg) { 872 v->iov_base = msg; 873 v->iov_len = strlen(msg); 874 } else if (f->f_prevcount > 1) { 875 if ((l = snprintf(repbuf, sizeof(repbuf), 876 "last message repeated %d times", f->f_prevcount)) >= 877 sizeof(repbuf) || l == -1) 878 l = strlen(repbuf); 879 v->iov_base = repbuf; 880 v->iov_len = l; 881 } else { 882 v->iov_base = f->f_prevline; 883 v->iov_len = f->f_prevlen; 884 } 885 v++; 886 887 dprintf("Logging to %s", TypeNames[f->f_type]); 888 f->f_time = now; 889 890 switch (f->f_type) { 891 case F_UNUSED: 892 dprintf("\n"); 893 break; 894 895 case F_FORW: 896 dprintf(" %s\n", f->f_un.f_forw.f_hname); 897 if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s%s%s", 898 f->f_prevpri, (char *)iov[0].iov_base, 899 IncludeHostname ? LocalHostName : "", 900 IncludeHostname ? " " : "", 901 (char *)iov[4].iov_base)) >= sizeof(line) || l == -1) 902 l = strlen(line); 903 if (sendto(pfd[PFD_INET].fd, line, l, 0, 904 (struct sockaddr *)&f->f_un.f_forw.f_addr, 905 f->f_un.f_forw.f_addr.ss_len) != l) { 906 switch (errno) { 907 case EHOSTDOWN: 908 case EHOSTUNREACH: 909 case ENETDOWN: 910 case ENETUNREACH: 911 case ENOBUFS: 912 /* silently dropped */ 913 break; 914 default: 915 f->f_type = F_UNUSED; 916 logerror("sendto"); 917 break; 918 } 919 } 920 break; 921 922 case F_CONSOLE: 923 if (flags & IGN_CONS) { 924 dprintf(" (ignored)\n"); 925 break; 926 } 927 /* FALLTHROUGH */ 928 929 case F_TTY: 930 case F_FILE: 931 case F_PIPE: 932 dprintf(" %s\n", f->f_un.f_fname); 933 if (f->f_type != F_FILE && f->f_type != F_PIPE) { 934 v->iov_base = "\r\n"; 935 v->iov_len = 2; 936 } else { 937 v->iov_base = "\n"; 938 v->iov_len = 1; 939 } 940 retryonce = 0; 941 again: 942 if (writev(f->f_file, iov, 6) < 0) { 943 int e = errno; 944 945 /* pipe is non-blocking. log and drop message if full */ 946 if (e == EAGAIN && f->f_type == F_PIPE) { 947 if (now - f->f_lasterrtime > 120) { 948 f->f_lasterrtime = now; 949 logerror(f->f_un.f_fname); 950 } 951 break; 952 } 953 954 (void)close(f->f_file); 955 /* 956 * Check for errors on TTY's or program pipes. 957 * Errors happen due to loss of tty or died programs. 958 */ 959 if (e == EAGAIN) { 960 /* 961 * Silently drop messages on blocked write. 962 * This can happen when logging to a locked tty. 963 */ 964 break; 965 } else if ((e == EIO || e == EBADF) && 966 f->f_type != F_FILE && f->f_type != F_PIPE && 967 !retryonce) { 968 f->f_file = priv_open_tty(f->f_un.f_fname); 969 retryonce = 1; 970 if (f->f_file < 0) { 971 f->f_type = F_UNUSED; 972 logerror(f->f_un.f_fname); 973 } else 974 goto again; 975 } else if ((e == EPIPE || e == EBADF) && 976 f->f_type == F_PIPE && !retryonce) { 977 f->f_file = priv_open_log(f->f_un.f_fname); 978 retryonce = 1; 979 if (f->f_file < 0) { 980 f->f_type = F_UNUSED; 981 logerror(f->f_un.f_fname); 982 } else 983 goto again; 984 } else { 985 f->f_type = F_UNUSED; 986 f->f_file = -1; 987 errno = e; 988 logerror(f->f_un.f_fname); 989 } 990 } else if (flags & SYNC_FILE) 991 (void)fsync(f->f_file); 992 break; 993 994 case F_USERS: 995 case F_WALL: 996 dprintf("\n"); 997 v->iov_base = "\r\n"; 998 v->iov_len = 2; 999 wallmsg(f, iov); 1000 break; 1001 1002 case F_MEMBUF: 1003 dprintf("\n"); 1004 snprintf(line, sizeof(line), "%.15s %s %s", 1005 (char *)iov[0].iov_base, (char *)iov[2].iov_base, 1006 (char *)iov[4].iov_base); 1007 if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1) 1008 f->f_un.f_mb.f_overflow = 1; 1009 if (f->f_un.f_mb.f_attached) 1010 logto_ctlconn(line); 1011 break; 1012 } 1013 f->f_prevcount = 0; 1014 } 1015 1016 /* 1017 * WALLMSG -- Write a message to the world at large 1018 * 1019 * Write the specified message to either the entire 1020 * world, or a list of approved users. 1021 */ 1022 void 1023 wallmsg(struct filed *f, struct iovec *iov) 1024 { 1025 struct utmp ut; 1026 char line[sizeof(ut.ut_line) + 1], *p; 1027 static int reenter; /* avoid calling ourselves */ 1028 FILE *uf; 1029 int i; 1030 1031 if (reenter++) 1032 return; 1033 if ((uf = priv_open_utmp()) == NULL) { 1034 logerror(_PATH_UTMP); 1035 reenter = 0; 1036 return; 1037 } 1038 /* NOSTRICT */ 1039 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 1040 if (ut.ut_name[0] == '\0') 1041 continue; 1042 /* must use strncpy since ut_* may not be NUL terminated */ 1043 strncpy(line, ut.ut_line, sizeof(line) - 1); 1044 line[sizeof(line) - 1] = '\0'; 1045 if (f->f_type == F_WALL) { 1046 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 1047 errno = 0; /* already in msg */ 1048 logerror(p); 1049 } 1050 continue; 1051 } 1052 /* should we send the message to this user? */ 1053 for (i = 0; i < MAXUNAMES; i++) { 1054 if (!f->f_un.f_uname[i][0]) 1055 break; 1056 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 1057 UT_NAMESIZE)) { 1058 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 1059 != NULL) { 1060 errno = 0; /* already in msg */ 1061 logerror(p); 1062 } 1063 break; 1064 } 1065 } 1066 } 1067 (void)fclose(uf); 1068 reenter = 0; 1069 } 1070 1071 /* ARGSUSED */ 1072 void 1073 reapchild(int signo) 1074 { 1075 int save_errno = errno; 1076 int status; 1077 1078 while (waitpid(-1, &status, WNOHANG) > 0) 1079 ; 1080 errno = save_errno; 1081 } 1082 1083 /* 1084 * Return a printable representation of a host address. 1085 */ 1086 void 1087 cvthname(struct sockaddr_in *f, char *result, size_t res_len) 1088 { 1089 sigset_t omask, nmask; 1090 char *p, *ip; 1091 int ret_len; 1092 1093 if (f->sin_family != AF_INET) { 1094 dprintf("Malformed from address\n"); 1095 strlcpy(result, "???", res_len); 1096 return; 1097 } 1098 1099 ip = inet_ntoa(f->sin_addr); 1100 dprintf("cvthname(%s)\n", ip); 1101 if (NoDNS) { 1102 strlcpy(result, ip, res_len); 1103 return; 1104 } 1105 1106 sigemptyset(&nmask); 1107 sigaddset(&nmask, SIGHUP); 1108 sigprocmask(SIG_BLOCK, &nmask, &omask); 1109 1110 ret_len = priv_gethostbyaddr((char *)&f->sin_addr, 1111 sizeof(struct in_addr), f->sin_family, result, res_len); 1112 1113 sigprocmask(SIG_SETMASK, &omask, NULL); 1114 if (ret_len == 0) { 1115 dprintf("Host name for your address (%s) unknown\n", ip); 1116 strlcpy(result, ip, res_len); 1117 } else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0) 1118 *p = '\0'; 1119 } 1120 1121 void 1122 dodie(int signo) 1123 { 1124 WantDie = signo; 1125 } 1126 1127 /* ARGSUSED */ 1128 void 1129 domark(int signo) 1130 { 1131 MarkSet = 1; 1132 } 1133 1134 /* ARGSUSED */ 1135 void 1136 doinit(int signo) 1137 { 1138 DoInit = 1; 1139 } 1140 1141 /* 1142 * Print syslogd errors some place. 1143 */ 1144 void 1145 logerror(const char *type) 1146 { 1147 char buf[100]; 1148 1149 if (errno) 1150 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1151 type, strerror(errno)); 1152 else 1153 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 1154 errno = 0; 1155 dprintf("%s\n", buf); 1156 if (Startup) 1157 fprintf(stderr, "%s\n", buf); 1158 else 1159 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1160 } 1161 1162 void 1163 die(int signo) 1164 { 1165 struct filed *f; 1166 int was_initialized = Initialized; 1167 char buf[100]; 1168 1169 Initialized = 0; /* Don't log SIGCHLDs */ 1170 alarm(0); 1171 for (f = Files; f != NULL; f = f->f_next) { 1172 /* flush any pending output */ 1173 if (f->f_prevcount) 1174 fprintlog(f, 0, (char *)NULL); 1175 } 1176 Initialized = was_initialized; 1177 if (signo) { 1178 dprintf("syslogd: exiting on signal %d\n", signo); 1179 (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); 1180 errno = 0; 1181 logerror(buf); 1182 } 1183 dprintf("[unpriv] syslogd child about to exit\n"); 1184 exit(0); 1185 } 1186 1187 /* 1188 * INIT -- Initialize syslogd from configuration table 1189 */ 1190 void 1191 init(void) 1192 { 1193 char cline[LINE_MAX], prog[NAME_MAX+1], *p; 1194 struct filed *f, *next, **nextp, *mb, *m; 1195 FILE *cf; 1196 int i; 1197 1198 dprintf("init\n"); 1199 1200 /* If config file has been modified, then just die to restart */ 1201 if (priv_config_modified()) { 1202 dprintf("config file changed: dying\n"); 1203 die(0); 1204 } 1205 1206 /* 1207 * Close all open log files. 1208 */ 1209 Initialized = 0; 1210 mb = NULL; 1211 for (f = Files; f != NULL; f = next) { 1212 /* flush any pending output */ 1213 if (f->f_prevcount) 1214 fprintlog(f, 0, (char *)NULL); 1215 1216 switch (f->f_type) { 1217 case F_FILE: 1218 case F_TTY: 1219 case F_CONSOLE: 1220 case F_PIPE: 1221 (void)close(f->f_file); 1222 break; 1223 case F_FORW: 1224 break; 1225 } 1226 next = f->f_next; 1227 if (f->f_program) 1228 free(f->f_program); 1229 if (f->f_type == F_MEMBUF) { 1230 f->f_next = mb; 1231 f->f_program = NULL; 1232 dprintf("add %p to mb: %p\n", f, mb); 1233 mb = f; 1234 } else 1235 free((char *)f); 1236 } 1237 Files = NULL; 1238 nextp = &Files; 1239 1240 /* open the configuration file */ 1241 if ((cf = priv_open_config()) == NULL) { 1242 dprintf("cannot open %s\n", ConfFile); 1243 *nextp = cfline("*.ERR\t/dev/console", "*"); 1244 (*nextp)->f_next = cfline("*.PANIC\t*", "*"); 1245 Initialized = 1; 1246 return; 1247 } 1248 1249 /* 1250 * Foreach line in the conf table, open that file. 1251 */ 1252 f = NULL; 1253 strlcpy(prog, "*", sizeof(prog)); 1254 while (fgets(cline, sizeof(cline), cf) != NULL) { 1255 /* 1256 * check for end-of-section, comments, strip off trailing 1257 * spaces and newline character. !prog is treated 1258 * specially: the following lines apply only to that program. 1259 */ 1260 for (p = cline; isspace((unsigned char)*p); ++p) 1261 continue; 1262 if (*p == '\0' || *p == '#') 1263 continue; 1264 if (*p == '!') { 1265 p++; 1266 while (isspace((unsigned char)*p)) 1267 p++; 1268 if (!*p || (*p == '*' && (!p[1] || 1269 isspace((unsigned char)p[1])))) { 1270 strlcpy(prog, "*", sizeof(prog)); 1271 continue; 1272 } 1273 for (i = 0; i < NAME_MAX; i++) { 1274 if (!isalnum((unsigned char)p[i]) && 1275 p[i] != '-' && p[i] != '!') 1276 break; 1277 prog[i] = p[i]; 1278 } 1279 prog[i] = 0; 1280 continue; 1281 } 1282 p = cline + strlen(cline); 1283 while (p > cline) 1284 if (!isspace((unsigned char)*--p)) { 1285 p++; 1286 break; 1287 } 1288 *p = '\0'; 1289 f = cfline(cline, prog); 1290 if (f != NULL) { 1291 *nextp = f; 1292 nextp = &f->f_next; 1293 } 1294 } 1295 1296 /* Match and initialize the memory buffers */ 1297 for (f = Files; f != NULL; f = f->f_next) { 1298 if (f->f_type != F_MEMBUF) 1299 continue; 1300 dprintf("Initialize membuf %s at %p\n", f->f_un.f_mb.f_mname, f); 1301 1302 for (m = mb; m != NULL; m = m->f_next) { 1303 if (m->f_un.f_mb.f_rb == NULL) 1304 continue; 1305 if (strcmp(m->f_un.f_mb.f_mname, 1306 f->f_un.f_mb.f_mname) == 0) 1307 break; 1308 } 1309 if (m == NULL) { 1310 dprintf("Membuf no match\n"); 1311 f->f_un.f_mb.f_rb = ringbuf_init(f->f_un.f_mb.f_len); 1312 if (f->f_un.f_mb.f_rb == NULL) { 1313 f->f_type = F_UNUSED; 1314 logerror("Failed to allocate membuf"); 1315 } 1316 } else { 1317 dprintf("Membuf match f:%p, m:%p\n", f, m); 1318 f->f_un = m->f_un; 1319 m->f_un.f_mb.f_rb = NULL; 1320 } 1321 } 1322 1323 /* make sure remaining buffers are freed */ 1324 while (mb != NULL) { 1325 m = mb; 1326 if (m->f_un.f_mb.f_rb != NULL) { 1327 logerror("Mismatched membuf"); 1328 ringbuf_free(m->f_un.f_mb.f_rb); 1329 } 1330 dprintf("Freeing membuf %p\n", m); 1331 1332 mb = m->f_next; 1333 free(m); 1334 } 1335 1336 /* close the configuration file */ 1337 (void)fclose(cf); 1338 1339 Initialized = 1; 1340 1341 if (Debug) { 1342 for (f = Files; f; f = f->f_next) { 1343 for (i = 0; i <= LOG_NFACILITIES; i++) 1344 if (f->f_pmask[i] == INTERNAL_NOPRI) 1345 printf("X "); 1346 else 1347 printf("%d ", f->f_pmask[i]); 1348 printf("%s: ", TypeNames[f->f_type]); 1349 switch (f->f_type) { 1350 case F_FILE: 1351 case F_TTY: 1352 case F_CONSOLE: 1353 case F_PIPE: 1354 printf("%s", f->f_un.f_fname); 1355 break; 1356 1357 case F_FORW: 1358 printf("%s", f->f_un.f_forw.f_hname); 1359 break; 1360 1361 case F_USERS: 1362 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1363 printf("%s, ", f->f_un.f_uname[i]); 1364 break; 1365 1366 case F_MEMBUF: 1367 printf("%s", f->f_un.f_mb.f_mname); 1368 break; 1369 1370 } 1371 if (f->f_program) 1372 printf(" (%s)", f->f_program); 1373 printf("\n"); 1374 } 1375 } 1376 } 1377 1378 #define progmatches(p1, p2) \ 1379 (p1 == p2 || (p1 != NULL && p2 != NULL && strcmp(p1, p2) == 0)) 1380 1381 /* 1382 * Spot a line with a duplicate file, pipe, console, tty, or membuf target. 1383 */ 1384 struct filed * 1385 find_dup(struct filed *f) 1386 { 1387 struct filed *list; 1388 1389 for (list = Files; list; list = list->f_next) { 1390 if (list->f_quick || f->f_quick) 1391 continue; 1392 switch (list->f_type) { 1393 case F_FILE: 1394 case F_TTY: 1395 case F_CONSOLE: 1396 case F_PIPE: 1397 if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 && 1398 progmatches(list->f_program, f->f_program)) 1399 return (list); 1400 break; 1401 case F_MEMBUF: 1402 if (strcmp(list->f_un.f_mb.f_mname, 1403 f->f_un.f_mb.f_mname) == 0 && 1404 progmatches(list->f_program, f->f_program)) 1405 return (list); 1406 break; 1407 } 1408 } 1409 return (NULL); 1410 } 1411 1412 /* 1413 * Crack a configuration file line 1414 */ 1415 struct filed * 1416 cfline(char *line, char *prog) 1417 { 1418 int i, pri, addr_len; 1419 size_t rb_len; 1420 char *bp, *p, *q, *cp; 1421 char buf[MAXLINE], ebuf[100]; 1422 struct filed *xf, *f, *d; 1423 1424 dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog); 1425 1426 errno = 0; /* keep strerror() stuff out of logerror messages */ 1427 1428 if ((f = calloc(1, sizeof(*f))) == NULL) { 1429 logerror("Couldn't allocate struct filed"); 1430 die(0); 1431 } 1432 for (i = 0; i <= LOG_NFACILITIES; i++) 1433 f->f_pmask[i] = INTERNAL_NOPRI; 1434 1435 /* save program name if any */ 1436 if (*prog == '!') { 1437 f->f_quick = 1; 1438 prog++; 1439 } else 1440 f->f_quick = 0; 1441 if (!strcmp(prog, "*")) 1442 prog = NULL; 1443 else { 1444 f->f_program = calloc(1, strlen(prog)+1); 1445 if (f->f_program) 1446 strlcpy(f->f_program, prog, strlen(prog)+1); 1447 } 1448 1449 /* scan through the list of selectors */ 1450 for (p = line; *p && *p != '\t';) { 1451 1452 /* find the end of this facility name list */ 1453 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1454 continue; 1455 1456 /* collect priority name */ 1457 for (bp = buf; *q && !strchr("\t,;", *q); ) 1458 *bp++ = *q++; 1459 *bp = '\0'; 1460 1461 /* skip cruft */ 1462 while (*q && strchr(", ;", *q)) 1463 q++; 1464 1465 /* decode priority name */ 1466 if (*buf == '*') 1467 pri = LOG_PRIMASK + 1; 1468 else { 1469 /* ignore trailing spaces */ 1470 for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) { 1471 buf[i]='\0'; 1472 } 1473 1474 pri = decode(buf, prioritynames); 1475 if (pri < 0) { 1476 (void)snprintf(ebuf, sizeof ebuf, 1477 "unknown priority name \"%s\"", buf); 1478 logerror(ebuf); 1479 free(f); 1480 return (NULL); 1481 } 1482 } 1483 1484 /* scan facilities */ 1485 while (*p && !strchr("\t.;", *p)) { 1486 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1487 *bp++ = *p++; 1488 *bp = '\0'; 1489 if (*buf == '*') 1490 for (i = 0; i < LOG_NFACILITIES; i++) 1491 f->f_pmask[i] = pri; 1492 else { 1493 i = decode(buf, facilitynames); 1494 if (i < 0) { 1495 (void)snprintf(ebuf, sizeof(ebuf), 1496 "unknown facility name \"%s\"", 1497 buf); 1498 logerror(ebuf); 1499 free(f); 1500 return (NULL); 1501 } 1502 f->f_pmask[i >> 3] = pri; 1503 } 1504 while (*p == ',' || *p == ' ') 1505 p++; 1506 } 1507 1508 p = q; 1509 } 1510 1511 /* skip to action part */ 1512 while (*p == '\t') 1513 p++; 1514 1515 switch (*p) { 1516 case '@': 1517 if (!InetInuse) 1518 break; 1519 if ((cp = strrchr(++p, ':')) != NULL) 1520 *cp++ = '\0'; 1521 if ((strlcpy(f->f_un.f_forw.f_hname, p, 1522 sizeof(f->f_un.f_forw.f_hname)) >= 1523 sizeof(f->f_un.f_forw.f_hname))) { 1524 snprintf(ebuf, sizeof(ebuf), "hostname too long \"%s\"", 1525 p); 1526 logerror(ebuf); 1527 break; 1528 } 1529 addr_len = priv_gethostserv(f->f_un.f_forw.f_hname, 1530 cp == NULL ? "syslog" : cp, 1531 (struct sockaddr*)&f->f_un.f_forw.f_addr, 1532 sizeof(f->f_un.f_forw.f_addr)); 1533 if (addr_len < 1) { 1534 snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"", p); 1535 logerror(ebuf); 1536 break; 1537 } 1538 f->f_type = F_FORW; 1539 break; 1540 1541 case '/': 1542 case '|': 1543 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1544 d = find_dup(f); 1545 if (d != NULL) { 1546 for (i = 0; i <= LOG_NFACILITIES; i++) 1547 if (f->f_pmask[i] != INTERNAL_NOPRI) 1548 d->f_pmask[i] = f->f_pmask[i]; 1549 free(f); 1550 return (NULL); 1551 } 1552 if (strcmp(p, ctty) == 0) 1553 f->f_file = priv_open_tty(p); 1554 else 1555 f->f_file = priv_open_log(p); 1556 if (f->f_file < 0) { 1557 f->f_type = F_UNUSED; 1558 logerror(p); 1559 break; 1560 } 1561 if (isatty(f->f_file)) { 1562 if (strcmp(p, ctty) == 0) 1563 f->f_type = F_CONSOLE; 1564 else 1565 f->f_type = F_TTY; 1566 } else { 1567 if (*p == '|') 1568 f->f_type = F_PIPE; 1569 else { 1570 f->f_type = F_FILE; 1571 1572 /* Clear O_NONBLOCK flag on f->f_file */ 1573 if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { 1574 i &= ~O_NONBLOCK; 1575 fcntl(f->f_file, F_SETFL, i); 1576 } 1577 } 1578 } 1579 break; 1580 1581 case '*': 1582 f->f_type = F_WALL; 1583 break; 1584 1585 case ':': 1586 f->f_type = F_MEMBUF; 1587 1588 /* Parse buffer size (in kb) */ 1589 errno = 0; 1590 rb_len = strtoul(++p, &q, 0); 1591 if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) || 1592 *q != ':' || rb_len == 0) { 1593 f->f_type = F_UNUSED; 1594 logerror(p); 1595 break; 1596 } 1597 q++; 1598 rb_len *= 1024; 1599 1600 /* Copy buffer name */ 1601 for(i = 0; i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) { 1602 if (!isalnum((unsigned char)q[i])) 1603 break; 1604 f->f_un.f_mb.f_mname[i] = q[i]; 1605 } 1606 1607 /* Make sure buffer name is unique */ 1608 xf = find_dup(f); 1609 1610 /* Error on missing or non-unique name, or bad buffer length */ 1611 if (i == 0 || rb_len > MAX_MEMBUF || xf != NULL) { 1612 f->f_type = F_UNUSED; 1613 logerror(p); 1614 break; 1615 } 1616 1617 /* Set buffer length */ 1618 rb_len = MAX(rb_len, MIN_MEMBUF); 1619 f->f_un.f_mb.f_len = rb_len; 1620 f->f_un.f_mb.f_overflow = 0; 1621 f->f_un.f_mb.f_attached = 0; 1622 break; 1623 1624 default: 1625 for (i = 0; i < MAXUNAMES && *p; i++) { 1626 for (q = p; *q && *q != ','; ) 1627 q++; 1628 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1629 if ((q - p) > UT_NAMESIZE) 1630 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1631 else 1632 f->f_un.f_uname[i][q - p] = '\0'; 1633 while (*q == ',' || *q == ' ') 1634 q++; 1635 p = q; 1636 } 1637 f->f_type = F_USERS; 1638 break; 1639 } 1640 return (f); 1641 } 1642 1643 1644 /* 1645 * Retrieve the size of the kernel message buffer, via sysctl. 1646 */ 1647 int 1648 getmsgbufsize(void) 1649 { 1650 int msgbufsize, mib[2]; 1651 size_t size; 1652 1653 mib[0] = CTL_KERN; 1654 mib[1] = KERN_MSGBUFSIZE; 1655 size = sizeof msgbufsize; 1656 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1657 dprintf("couldn't get kern.msgbufsize\n"); 1658 return (0); 1659 } 1660 return (msgbufsize); 1661 } 1662 1663 /* 1664 * Decode a symbolic name to a numeric value 1665 */ 1666 int 1667 decode(const char *name, const CODE *codetab) 1668 { 1669 const CODE *c; 1670 char *p, buf[40]; 1671 1672 if (isdigit((unsigned char)*name)) 1673 return (atoi(name)); 1674 1675 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1676 if (isupper((unsigned char)*name)) 1677 *p = tolower((unsigned char)*name); 1678 else 1679 *p = *name; 1680 } 1681 *p = '\0'; 1682 for (c = codetab; c->c_name; c++) 1683 if (!strcmp(buf, c->c_name)) 1684 return (c->c_val); 1685 1686 return (-1); 1687 } 1688 1689 void 1690 markit(void) 1691 { 1692 struct filed *f; 1693 1694 now = time(NULL); 1695 MarkSeq += TIMERINTVL; 1696 if (MarkSeq >= MarkInterval) { 1697 logmsg(LOG_INFO, "-- MARK --", 1698 LocalHostName, ADDDATE|MARK); 1699 MarkSeq = 0; 1700 } 1701 1702 for (f = Files; f; f = f->f_next) { 1703 if (f->f_prevcount && now >= REPEATTIME(f)) { 1704 dprintf("flush %s: repeated %d times, %d sec.\n", 1705 TypeNames[f->f_type], f->f_prevcount, 1706 repeatinterval[f->f_repeatcount]); 1707 fprintlog(f, 0, (char *)NULL); 1708 BACKOFF(f); 1709 } 1710 } 1711 MarkSet = 0; 1712 (void)alarm(TIMERINTVL); 1713 } 1714 1715 int 1716 unix_socket(char *path, int type, mode_t mode) 1717 { 1718 struct sockaddr_un s_un; 1719 char errbuf[512]; 1720 int fd; 1721 mode_t old_umask; 1722 1723 memset(&s_un, 0, sizeof(s_un)); 1724 s_un.sun_family = AF_UNIX; 1725 if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) > 1726 sizeof(s_un.sun_path)) { 1727 snprintf(errbuf, sizeof(errbuf), "socket path too long: %s", 1728 path); 1729 logerror(errbuf); 1730 die(0); 1731 } 1732 1733 if ((fd = socket(AF_UNIX, type, 0)) == -1) { 1734 logerror("socket"); 1735 return (-1); 1736 } 1737 1738 if (Debug) { 1739 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 || 1740 errno == EPROTOTYPE) { 1741 close(fd); 1742 errno = EISCONN; 1743 logerror("connect"); 1744 return (-1); 1745 } 1746 } 1747 1748 old_umask = umask(0177); 1749 1750 unlink(path); 1751 if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) { 1752 snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path); 1753 logerror(errbuf); 1754 umask(old_umask); 1755 close(fd); 1756 return (-1); 1757 } 1758 1759 umask(old_umask); 1760 1761 if (chmod(path, mode) == -1) { 1762 snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path); 1763 logerror(errbuf); 1764 close(fd); 1765 unlink(path); 1766 return (-1); 1767 } 1768 1769 return (fd); 1770 } 1771 1772 void 1773 double_rbuf(int fd) 1774 { 1775 socklen_t slen, len; 1776 1777 slen = sizeof(len); 1778 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { 1779 len *= 2; 1780 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); 1781 } 1782 } 1783 1784 static void 1785 ctlconn_cleanup(void) 1786 { 1787 struct filed *f; 1788 1789 if (pfd[PFD_CTLCONN].fd != -1) 1790 close(pfd[PFD_CTLCONN].fd); 1791 1792 pfd[PFD_CTLCONN].fd = -1; 1793 pfd[PFD_CTLCONN].events = pfd[PFD_CTLCONN].revents = 0; 1794 1795 pfd[PFD_CTLSOCK].events = POLLIN; 1796 1797 if (ctl_state == CTL_WRITING_CONT_REPLY) 1798 for (f = Files; f != NULL; f = f->f_next) 1799 if (f->f_type == F_MEMBUF) 1800 f->f_un.f_mb.f_attached = 0; 1801 1802 ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0; 1803 } 1804 1805 void 1806 ctlsock_accept_handler(void) 1807 { 1808 int fd, flags; 1809 1810 dprintf("Accepting control connection\n"); 1811 fd = accept(pfd[PFD_CTLSOCK].fd, NULL, NULL); 1812 if (fd == -1) { 1813 if (errno != EINTR && errno != EWOULDBLOCK && 1814 errno != ECONNABORTED) 1815 logerror("accept ctlsock"); 1816 return; 1817 } 1818 1819 ctlconn_cleanup(); 1820 1821 /* Only one connection at a time */ 1822 pfd[PFD_CTLSOCK].events = pfd[PFD_CTLSOCK].revents = 0; 1823 1824 if ((flags = fcntl(fd, F_GETFL)) == -1 || 1825 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 1826 logerror("fcntl ctlconn"); 1827 close(fd); 1828 return; 1829 } 1830 1831 pfd[PFD_CTLCONN].fd = fd; 1832 pfd[PFD_CTLCONN].events = POLLIN; 1833 ctl_state = CTL_READING_CMD; 1834 ctl_cmd_bytes = 0; 1835 } 1836 1837 static struct filed 1838 *find_membuf_log(const char *name) 1839 { 1840 struct filed *f; 1841 1842 for (f = Files; f != NULL; f = f->f_next) { 1843 if (f->f_type == F_MEMBUF && 1844 strcmp(f->f_un.f_mb.f_mname, name) == 0) 1845 break; 1846 } 1847 return (f); 1848 } 1849 1850 void 1851 ctlconn_read_handler(void) 1852 { 1853 ssize_t n; 1854 struct filed *f; 1855 u_int32_t flags = 0; 1856 struct ctl_reply_hdr *reply_hdr = (struct ctl_reply_hdr *)ctl_reply; 1857 1858 if (ctl_state == CTL_WRITING_REPLY || 1859 ctl_state == CTL_WRITING_CONT_REPLY) { 1860 /* client has closed the connection */ 1861 ctlconn_cleanup(); 1862 return; 1863 } 1864 1865 retry: 1866 n = read(pfd[PFD_CTLCONN].fd, (char*)&ctl_cmd + ctl_cmd_bytes, 1867 sizeof(ctl_cmd) - ctl_cmd_bytes); 1868 switch (n) { 1869 case -1: 1870 if (errno == EINTR) 1871 goto retry; 1872 logerror("ctlconn read"); 1873 /* FALLTHROUGH */ 1874 case 0: 1875 ctlconn_cleanup(); 1876 return; 1877 default: 1878 ctl_cmd_bytes += n; 1879 } 1880 1881 if (ctl_cmd_bytes < sizeof(ctl_cmd)) 1882 return; 1883 1884 if (ntohl(ctl_cmd.version) != CTL_VERSION) { 1885 logerror("Unknown client protocol version"); 1886 ctlconn_cleanup(); 1887 return; 1888 } 1889 1890 /* Ensure that logname is \0 terminated */ 1891 if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) { 1892 logerror("Corrupt ctlsock command"); 1893 ctlconn_cleanup(); 1894 return; 1895 } 1896 1897 *reply_text = '\0'; 1898 1899 ctl_reply_size = ctl_reply_offset = 0; 1900 memset(reply_hdr, '\0', sizeof(*reply_hdr)); 1901 1902 ctl_cmd.cmd = ntohl(ctl_cmd.cmd); 1903 dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname); 1904 1905 switch (ctl_cmd.cmd) { 1906 case CMD_READ: 1907 case CMD_READ_CLEAR: 1908 case CMD_READ_CONT: 1909 case CMD_FLAGS: 1910 f = find_membuf_log(ctl_cmd.logname); 1911 if (f == NULL) { 1912 strlcpy(reply_text, "No such log\n", MAX_MEMBUF); 1913 } else { 1914 if (ctl_cmd.cmd != CMD_FLAGS) { 1915 ringbuf_to_string(reply_text, MAX_MEMBUF, 1916 f->f_un.f_mb.f_rb); 1917 } 1918 if (f->f_un.f_mb.f_overflow) 1919 flags |= CTL_HDR_FLAG_OVERFLOW; 1920 if (ctl_cmd.cmd == CMD_READ_CLEAR) { 1921 ringbuf_clear(f->f_un.f_mb.f_rb); 1922 f->f_un.f_mb.f_overflow = 0; 1923 } 1924 if (ctl_cmd.cmd == CMD_READ_CONT) { 1925 f->f_un.f_mb.f_attached = 1; 1926 tailify_replytext(reply_text, 1927 ctl_cmd.lines > 0 ? ctl_cmd.lines : 10); 1928 } else if (ctl_cmd.lines > 0) { 1929 tailify_replytext(reply_text, ctl_cmd.lines); 1930 } 1931 } 1932 break; 1933 case CMD_CLEAR: 1934 f = find_membuf_log(ctl_cmd.logname); 1935 if (f == NULL) { 1936 strlcpy(reply_text, "No such log\n", MAX_MEMBUF); 1937 } else { 1938 ringbuf_clear(f->f_un.f_mb.f_rb); 1939 if (f->f_un.f_mb.f_overflow) 1940 flags |= CTL_HDR_FLAG_OVERFLOW; 1941 f->f_un.f_mb.f_overflow = 0; 1942 strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF); 1943 } 1944 break; 1945 case CMD_LIST: 1946 for (f = Files; f != NULL; f = f->f_next) { 1947 if (f->f_type == F_MEMBUF) { 1948 strlcat(reply_text, f->f_un.f_mb.f_mname, 1949 MAX_MEMBUF); 1950 if (f->f_un.f_mb.f_overflow) { 1951 strlcat(reply_text, "*", MAX_MEMBUF); 1952 flags |= CTL_HDR_FLAG_OVERFLOW; 1953 } 1954 strlcat(reply_text, " ", MAX_MEMBUF); 1955 } 1956 } 1957 strlcat(reply_text, "\n", MAX_MEMBUF); 1958 break; 1959 default: 1960 logerror("Unsupported ctlsock command"); 1961 ctlconn_cleanup(); 1962 return; 1963 } 1964 reply_hdr->version = htonl(CTL_VERSION); 1965 reply_hdr->flags = htonl(flags); 1966 1967 ctl_reply_size = CTL_REPLY_SIZE; 1968 dprintf("ctlcmd reply length %lu\n", (u_long)ctl_reply_size); 1969 1970 /* Otherwise, set up to write out reply */ 1971 ctl_state = (ctl_cmd.cmd == CMD_READ_CONT) ? 1972 CTL_WRITING_CONT_REPLY : CTL_WRITING_REPLY; 1973 1974 pfd[PFD_CTLCONN].events = POLLOUT; 1975 1976 /* monitor terminating syslogc */ 1977 pfd[PFD_CTLCONN].events |= POLLIN; 1978 1979 /* another syslogc can kick us out */ 1980 if (ctl_state == CTL_WRITING_CONT_REPLY) 1981 pfd[PFD_CTLSOCK].events = POLLIN; 1982 1983 } 1984 1985 void 1986 ctlconn_write_handler(void) 1987 { 1988 ssize_t n; 1989 1990 if (!(ctl_state == CTL_WRITING_REPLY || 1991 ctl_state == CTL_WRITING_CONT_REPLY)) { 1992 /* Shouldn't be here! */ 1993 logerror("ctlconn_write with bad ctl_state"); 1994 ctlconn_cleanup(); 1995 return; 1996 } 1997 retry: 1998 n = write(pfd[PFD_CTLCONN].fd, ctl_reply + ctl_reply_offset, 1999 ctl_reply_size - ctl_reply_offset); 2000 switch (n) { 2001 case -1: 2002 if (errno == EINTR) 2003 goto retry; 2004 if (errno != EPIPE) 2005 logerror("ctlconn write"); 2006 /* FALLTHROUGH */ 2007 case 0: 2008 ctlconn_cleanup(); 2009 return; 2010 default: 2011 ctl_reply_offset += n; 2012 } 2013 if (ctl_reply_offset >= ctl_reply_size) { 2014 /* 2015 * Make space in the buffer for continous writes. 2016 * Set offset behind reply header to skip it 2017 */ 2018 if (ctl_state == CTL_WRITING_CONT_REPLY) { 2019 *reply_text = '\0'; 2020 ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE; 2021 2022 /* Now is a good time to report dropped lines */ 2023 if (membuf_drop) { 2024 strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF); 2025 ctl_reply_size = CTL_REPLY_SIZE; 2026 membuf_drop = 0; 2027 } else { 2028 /* Nothing left to write */ 2029 pfd[PFD_CTLCONN].events = POLLIN; 2030 } 2031 } else 2032 ctlconn_cleanup(); 2033 } 2034 } 2035 2036 /* Shorten replytext to number of lines */ 2037 void 2038 tailify_replytext(char *replytext, int lines) 2039 { 2040 char *start, *nl; 2041 int count = 0; 2042 start = nl = replytext; 2043 2044 while ((nl = strchr(nl, '\n')) != NULL) { 2045 nl++; 2046 if (++count > lines) { 2047 start = strchr(start, '\n'); 2048 start++; 2049 } 2050 } 2051 if (start != replytext) { 2052 int len = strlen(start); 2053 memmove(replytext, start, len); 2054 *(replytext + len) = '\0'; 2055 } 2056 } 2057 2058 void 2059 logto_ctlconn(char *line) 2060 { 2061 size_t l; 2062 2063 if (membuf_drop) 2064 return; 2065 2066 l = strlen(line); 2067 if (l + 2 > (CTL_REPLY_MAXSIZE - ctl_reply_size)) { 2068 /* remember line drops for later report */ 2069 membuf_drop = 1; 2070 return; 2071 } 2072 memcpy(ctl_reply + ctl_reply_size, line, l); 2073 memcpy(ctl_reply + ctl_reply_size + l, "\n", 2); 2074 ctl_reply_size += l + 1; 2075 pfd[PFD_CTLCONN].events |= POLLOUT; 2076 } 2077