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