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