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