1 /* $NetBSD: syslogd.c,v 1.51 2002/05/02 13:53:10 lukem 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.51 2002/05/02 13:53:10 lukem 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 } else 577 *maxszp *= 2; 578 *lp = realloc(*lp, sizeof(char *) * (*maxszp + 1)); 579 if (*lp == NULL) { 580 logerror("Couldn't allocate line buffer"); 581 die(0); 582 } 583 } 584 if (((*lp)[(*szp)++] = strdup(new)) == NULL) { 585 logerror("Couldn't allocate logpath"); 586 die(0); 587 } 588 (*lp)[(*szp)] = NULL; /* always keep it NULL terminated */ 589 } 590 591 /* do a file of log sockets */ 592 void 593 logpath_fileadd(lp, szp, maxszp, file) 594 char ***lp; 595 int *szp; 596 int *maxszp; 597 char *file; 598 { 599 FILE *fp; 600 char *line; 601 size_t len; 602 603 fp = fopen(file, "r"); 604 if (fp == NULL) { 605 logerror("Could not open socket file list `%s'", file); 606 die(0); 607 } 608 609 while ((line = fgetln(fp, &len))) { 610 line[len - 1] = 0; 611 logpath_add(lp, szp, maxszp, line); 612 } 613 fclose(fp); 614 } 615 616 /* 617 * Take a raw input line, decode the message, and print the message 618 * on the appropriate log files. 619 */ 620 void 621 printline(hname, msg) 622 char *hname; 623 char *msg; 624 { 625 int c, pri; 626 char *p, *q, line[MAXLINE + 1]; 627 628 /* test for special codes */ 629 pri = DEFUPRI; 630 p = msg; 631 if (*p == '<') { 632 pri = 0; 633 while (isdigit(*++p)) 634 pri = 10 * pri + (*p - '0'); 635 if (*p == '>') 636 ++p; 637 } 638 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 639 pri = DEFUPRI; 640 641 /* don't allow users to log kernel messages */ 642 if (LOG_FAC(pri) == LOG_KERN) 643 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 644 645 q = line; 646 647 while ((c = *p++) != '\0' && 648 q < &line[sizeof(line) - 2]) { 649 c &= 0177; 650 if (iscntrl(c)) 651 if (c == '\n') 652 *q++ = ' '; 653 else if (c == '\t') 654 *q++ = '\t'; 655 else { 656 *q++ = '^'; 657 *q++ = c ^ 0100; 658 } 659 else 660 *q++ = c; 661 } 662 *q = '\0'; 663 664 logmsg(pri, line, hname, 0); 665 } 666 667 /* 668 * Take a raw input line from /dev/klog, split and format similar to syslog(). 669 */ 670 void 671 printsys(msg) 672 char *msg; 673 { 674 int c, pri, flags; 675 char *lp, *p, *q, line[MAXLINE + 1]; 676 677 (void)strcpy(line, _PATH_UNIX); 678 (void)strcat(line, ": "); 679 lp = line + strlen(line); 680 for (p = msg; *p != '\0'; ) { 681 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 682 pri = DEFSPRI; 683 if (*p == '<') { 684 pri = 0; 685 while (isdigit(*++p)) 686 pri = 10 * pri + (*p - '0'); 687 if (*p == '>') 688 ++p; 689 } else { 690 /* kernel printf's come out on console */ 691 flags |= IGN_CONS; 692 } 693 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 694 pri = DEFSPRI; 695 q = lp; 696 while (*p != '\0' && (c = *p++) != '\n' && 697 q < &line[MAXLINE]) 698 *q++ = c; 699 *q = '\0'; 700 logmsg(pri, line, LocalHostName, flags); 701 } 702 } 703 704 time_t now; 705 706 /* 707 * Log a message to the appropriate log files, users, etc. based on 708 * the priority. 709 */ 710 void 711 logmsg(pri, msg, from, flags) 712 int pri; 713 char *msg, *from; 714 int flags; 715 { 716 struct filed *f; 717 int fac, msglen, omask, prilev; 718 char *timestamp; 719 720 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 721 pri, flags, from, msg); 722 723 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 724 725 /* 726 * Check to see if msg looks non-standard. 727 */ 728 msglen = strlen(msg); 729 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 730 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 731 flags |= ADDDATE; 732 733 (void)time(&now); 734 if (flags & ADDDATE) 735 timestamp = ctime(&now) + 4; 736 else { 737 timestamp = msg; 738 msg += 16; 739 msglen -= 16; 740 } 741 742 /* extract facility and priority level */ 743 if (flags & MARK) 744 fac = LOG_NFACILITIES; 745 else 746 fac = LOG_FAC(pri); 747 prilev = LOG_PRI(pri); 748 749 /* log the message to the particular outputs */ 750 if (!Initialized) { 751 f = &consfile; 752 f->f_file = open(ctty, O_WRONLY, 0); 753 754 if (f->f_file >= 0) { 755 fprintlog(f, flags, msg); 756 (void)close(f->f_file); 757 } 758 (void)sigsetmask(omask); 759 return; 760 } 761 for (f = Files; f; f = f->f_next) { 762 /* skip messages that are incorrect priority */ 763 if (f->f_pmask[fac] < prilev || 764 f->f_pmask[fac] == INTERNAL_NOPRI) 765 continue; 766 767 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 768 continue; 769 770 /* don't output marks to recently written files */ 771 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 772 continue; 773 774 /* 775 * suppress duplicate lines to this file 776 */ 777 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 778 !strcmp(msg, f->f_prevline) && 779 !strcmp(from, f->f_prevhost)) { 780 (void)strncpy(f->f_lasttime, timestamp, 15); 781 f->f_prevcount++; 782 dprintf("Msg repeated %d times, %ld sec of %d\n", 783 f->f_prevcount, (long)(now - f->f_time), 784 repeatinterval[f->f_repeatcount]); 785 /* 786 * If domark would have logged this by now, 787 * flush it now (so we don't hold isolated messages), 788 * but back off so we'll flush less often 789 * in the future. 790 */ 791 if (now > REPEATTIME(f)) { 792 fprintlog(f, flags, (char *)NULL); 793 BACKOFF(f); 794 } 795 } else { 796 /* new line, save it */ 797 if (f->f_prevcount) 798 fprintlog(f, 0, (char *)NULL); 799 f->f_repeatcount = 0; 800 f->f_prevpri = pri; 801 (void)strncpy(f->f_lasttime, timestamp, 15); 802 (void)strncpy(f->f_prevhost, from, 803 sizeof(f->f_prevhost)); 804 if (msglen < MAXSVLINE) { 805 f->f_prevlen = msglen; 806 (void)strcpy(f->f_prevline, msg); 807 fprintlog(f, flags, (char *)NULL); 808 } else { 809 f->f_prevline[0] = 0; 810 f->f_prevlen = 0; 811 fprintlog(f, flags, msg); 812 } 813 } 814 } 815 (void)sigsetmask(omask); 816 } 817 818 void 819 fprintlog(f, flags, msg) 820 struct filed *f; 821 int flags; 822 char *msg; 823 { 824 struct iovec iov[6]; 825 struct iovec *v; 826 struct addrinfo *r; 827 int j, l, lsent; 828 char line[MAXLINE + 1], repbuf[80], greetings[200]; 829 830 v = iov; 831 if (f->f_type == F_WALL) { 832 v->iov_base = greetings; 833 v->iov_len = snprintf(greetings, sizeof greetings, 834 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 835 f->f_prevhost, ctime(&now)); 836 v++; 837 v->iov_base = ""; 838 v->iov_len = 0; 839 v++; 840 } else { 841 v->iov_base = f->f_lasttime; 842 v->iov_len = 15; 843 v++; 844 v->iov_base = " "; 845 v->iov_len = 1; 846 v++; 847 } 848 v->iov_base = f->f_prevhost; 849 v->iov_len = strlen(v->iov_base); 850 v++; 851 v->iov_base = " "; 852 v->iov_len = 1; 853 v++; 854 855 if (msg) { 856 v->iov_base = msg; 857 v->iov_len = strlen(msg); 858 } else if (f->f_prevcount > 1) { 859 v->iov_base = repbuf; 860 v->iov_len = snprintf(repbuf, sizeof repbuf, 861 "last message repeated %d times", f->f_prevcount); 862 } else { 863 v->iov_base = f->f_prevline; 864 v->iov_len = f->f_prevlen; 865 } 866 v++; 867 868 dprintf("Logging to %s", TypeNames[f->f_type]); 869 f->f_time = now; 870 871 switch (f->f_type) { 872 case F_UNUSED: 873 dprintf("\n"); 874 break; 875 876 case F_FORW: 877 dprintf(" %s\n", f->f_un.f_forw.f_hname); 878 /* 879 * check for local vs remote messages 880 * (from FreeBSD PR#bin/7055) 881 */ 882 if (strcmp(f->f_prevhost, LocalHostName)) { 883 l = snprintf(line, sizeof(line) - 1, 884 "<%d>%.15s [%s]: %s", 885 f->f_prevpri, (char *) iov[0].iov_base, 886 f->f_prevhost, (char *) iov[4].iov_base); 887 } else { 888 l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s", 889 f->f_prevpri, (char *) iov[0].iov_base, 890 (char *) iov[4].iov_base); 891 } 892 if (l > MAXLINE) 893 l = MAXLINE; 894 if (finet) { 895 for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 896 for (j = 0; j < *finet; j++) { 897 #if 0 898 /* 899 * should we check AF first, or just 900 * trial and error? FWD 901 */ 902 if (r->ai_family == 903 address_family_of(finet[j+1])) 904 #endif 905 lsent = sendto(finet[j+1], line, l, 0, 906 r->ai_addr, r->ai_addrlen); 907 if (lsent == l) 908 break; 909 } 910 } 911 if (lsent != l) { 912 f->f_type = F_UNUSED; 913 logerror("sendto() failed"); 914 } 915 } 916 break; 917 918 case F_CONSOLE: 919 if (flags & IGN_CONS) { 920 dprintf(" (ignored)\n"); 921 break; 922 } 923 /* FALLTHROUGH */ 924 925 case F_TTY: 926 case F_FILE: 927 dprintf(" %s\n", f->f_un.f_fname); 928 if (f->f_type != F_FILE) { 929 v->iov_base = "\r\n"; 930 v->iov_len = 2; 931 } else { 932 v->iov_base = "\n"; 933 v->iov_len = 1; 934 } 935 again: 936 if (writev(f->f_file, iov, 6) < 0) { 937 int e = errno; 938 (void)close(f->f_file); 939 /* 940 * Check for errors on TTY's due to loss of tty 941 */ 942 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 943 f->f_file = open(f->f_un.f_fname, 944 O_WRONLY|O_APPEND, 0); 945 if (f->f_file < 0) { 946 f->f_type = F_UNUSED; 947 logerror(f->f_un.f_fname); 948 } else 949 goto again; 950 } else { 951 f->f_type = F_UNUSED; 952 errno = e; 953 logerror(f->f_un.f_fname); 954 } 955 } else if (flags & SYNC_FILE) 956 (void)fsync(f->f_file); 957 break; 958 959 case F_USERS: 960 case F_WALL: 961 dprintf("\n"); 962 v->iov_base = "\r\n"; 963 v->iov_len = 2; 964 wallmsg(f, iov); 965 break; 966 } 967 f->f_prevcount = 0; 968 } 969 970 /* 971 * WALLMSG -- Write a message to the world at large 972 * 973 * Write the specified message to either the entire 974 * world, or a list of approved users. 975 */ 976 void 977 wallmsg(f, iov) 978 struct filed *f; 979 struct iovec *iov; 980 { 981 static int reenter; /* avoid calling ourselves */ 982 FILE *uf; 983 struct utmp ut; 984 int i; 985 char *p; 986 char line[sizeof(ut.ut_line) + 1]; 987 988 if (reenter++) 989 return; 990 if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { 991 logerror(_PATH_UTMP); 992 reenter = 0; 993 return; 994 } 995 /* NOSTRICT */ 996 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 997 if (ut.ut_name[0] == '\0') 998 continue; 999 strncpy(line, ut.ut_line, sizeof(ut.ut_line)); 1000 line[sizeof(ut.ut_line)] = '\0'; 1001 if (f->f_type == F_WALL) { 1002 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 1003 errno = 0; /* already in msg */ 1004 logerror(p); 1005 } 1006 continue; 1007 } 1008 /* should we send the message to this user? */ 1009 for (i = 0; i < MAXUNAMES; i++) { 1010 if (!f->f_un.f_uname[i][0]) 1011 break; 1012 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 1013 UT_NAMESIZE)) { 1014 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 1015 != NULL) { 1016 errno = 0; /* already in msg */ 1017 logerror(p); 1018 } 1019 break; 1020 } 1021 } 1022 } 1023 (void)fclose(uf); 1024 reenter = 0; 1025 } 1026 1027 void 1028 reapchild(signo) 1029 int signo; 1030 { 1031 union wait status; 1032 1033 while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0) 1034 ; 1035 } 1036 1037 /* 1038 * Return a printable representation of a host address. 1039 */ 1040 char * 1041 cvthname(f) 1042 struct sockaddr_storage *f; 1043 { 1044 int error; 1045 char *p; 1046 #ifdef KAME_SCOPEID 1047 const int niflag = NI_DGRAM | NI_WITHSCOPEID; 1048 #else 1049 const int niflag = NI_DGRAM; 1050 #endif 1051 static char host[NI_MAXHOST], ip[NI_MAXHOST]; 1052 1053 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1054 ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag); 1055 1056 dprintf("cvthname(%s)\n", ip); 1057 1058 if (error) { 1059 dprintf("Malformed from address %s\n", gai_strerror(error)); 1060 return ("???"); 1061 } 1062 1063 if (!UseNameService) 1064 return (ip); 1065 1066 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1067 host, sizeof host, NULL, 0, niflag); 1068 if (error) { 1069 dprintf("Host name for your address (%s) unknown\n", ip); 1070 return (ip); 1071 } 1072 if ((p = strchr(host, '.')) && strcmp(p + 1, LocalDomain) == 0) 1073 *p = '\0'; 1074 return (host); 1075 } 1076 1077 void 1078 domark(signo) 1079 int signo; 1080 { 1081 struct filed *f; 1082 1083 now = time((time_t *)NULL); 1084 MarkSeq += TIMERINTVL; 1085 if (MarkSeq >= MarkInterval) { 1086 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 1087 MarkSeq = 0; 1088 } 1089 1090 for (f = Files; f; f = f->f_next) { 1091 if (f->f_prevcount && now >= REPEATTIME(f)) { 1092 dprintf("Flush %s: repeated %d times, %d sec.\n", 1093 TypeNames[f->f_type], f->f_prevcount, 1094 repeatinterval[f->f_repeatcount]); 1095 fprintlog(f, 0, (char *)NULL); 1096 BACKOFF(f); 1097 } 1098 } 1099 (void)alarm(TIMERINTVL); 1100 } 1101 1102 /* 1103 * Print syslogd errors some place. 1104 */ 1105 void 1106 logerror(const char *fmt, ...) 1107 { 1108 va_list ap; 1109 char tmpbuf[BUFSIZ]; 1110 char buf[BUFSIZ]; 1111 1112 va_start(ap, fmt); 1113 1114 (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap); 1115 1116 va_end(ap); 1117 1118 if (errno) 1119 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1120 tmpbuf, strerror(errno)); 1121 else 1122 (void)snprintf(buf, sizeof(buf), "syslogd: %s", tmpbuf); 1123 1124 if (daemonized) 1125 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1126 if (!daemonized && Debug) 1127 dprintf("%s\n", buf); 1128 if (!daemonized && !Debug) 1129 printf("%s\n", buf); 1130 1131 return; 1132 } 1133 1134 void 1135 die(signo) 1136 int signo; 1137 { 1138 struct filed *f; 1139 char **p; 1140 1141 for (f = Files; f != NULL; f = f->f_next) { 1142 /* flush any pending output */ 1143 if (f->f_prevcount) 1144 fprintlog(f, 0, (char *)NULL); 1145 } 1146 errno = 0; 1147 if (signo) 1148 logerror("Exiting on signal %d", signo); 1149 else 1150 logerror("Fatal error, exiting"); 1151 for (p = LogPaths; p && *p; p++) 1152 unlink(*p); 1153 exit(0); 1154 } 1155 1156 /* 1157 * INIT -- Initialize syslogd from configuration table 1158 */ 1159 void 1160 init(signo) 1161 int signo; 1162 { 1163 int i; 1164 FILE *cf; 1165 struct filed *f, *next, **nextp; 1166 char *p; 1167 char cline[LINE_MAX]; 1168 1169 dprintf("init\n"); 1170 1171 /* 1172 * Close all open log files. 1173 */ 1174 Initialized = 0; 1175 for (f = Files; f != NULL; f = next) { 1176 /* flush any pending output */ 1177 if (f->f_prevcount) 1178 fprintlog(f, 0, (char *)NULL); 1179 1180 switch (f->f_type) { 1181 case F_FILE: 1182 case F_TTY: 1183 case F_CONSOLE: 1184 (void)close(f->f_file); 1185 break; 1186 case F_FORW: 1187 if (f->f_un.f_forw.f_addr) 1188 freeaddrinfo(f->f_un.f_forw.f_addr); 1189 break; 1190 } 1191 next = f->f_next; 1192 free((char *)f); 1193 } 1194 Files = NULL; 1195 nextp = &Files; 1196 1197 /* 1198 * Close all open sockets 1199 */ 1200 1201 if (finet) { 1202 for (i = 0; i < *finet; i++) { 1203 if (close(finet[i+1]) < 0) { 1204 logerror("close() failed"); 1205 die(0); 1206 } 1207 } 1208 } 1209 1210 /* 1211 * Reset counter of forwarding actions 1212 */ 1213 1214 NumForwards=0; 1215 1216 /* open the configuration file */ 1217 if ((cf = fopen(ConfFile, "r")) == NULL) { 1218 dprintf("Cannot open `%s'\n", ConfFile); 1219 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1220 cfline("*.ERR\t/dev/console", *nextp); 1221 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1222 cfline("*.PANIC\t*", (*nextp)->f_next); 1223 Initialized = 1; 1224 return; 1225 } 1226 1227 /* 1228 * Foreach line in the conf table, open that file. 1229 */ 1230 f = NULL; 1231 while (fgets(cline, sizeof(cline), cf) != NULL) { 1232 /* 1233 * check for end-of-section, comments, strip off trailing 1234 * spaces and newline character. 1235 */ 1236 for (p = cline; isspace(*p); ++p) 1237 continue; 1238 if (*p == '\0' || *p == '#') 1239 continue; 1240 for (p = strchr(cline, '\0'); isspace(*--p);) 1241 continue; 1242 *++p = '\0'; 1243 f = (struct filed *)calloc(1, sizeof(*f)); 1244 *nextp = f; 1245 nextp = &f->f_next; 1246 cfline(cline, f); 1247 } 1248 1249 /* close the configuration file */ 1250 (void)fclose(cf); 1251 1252 Initialized = 1; 1253 1254 if (Debug) { 1255 for (f = Files; f; f = f->f_next) { 1256 for (i = 0; i <= LOG_NFACILITIES; i++) 1257 if (f->f_pmask[i] == INTERNAL_NOPRI) 1258 printf("X "); 1259 else 1260 printf("%d ", f->f_pmask[i]); 1261 printf("%s: ", TypeNames[f->f_type]); 1262 switch (f->f_type) { 1263 case F_FILE: 1264 case F_TTY: 1265 case F_CONSOLE: 1266 printf("%s", f->f_un.f_fname); 1267 break; 1268 1269 case F_FORW: 1270 printf("%s", f->f_un.f_forw.f_hname); 1271 break; 1272 1273 case F_USERS: 1274 for (i = 0; 1275 i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1276 printf("%s, ", f->f_un.f_uname[i]); 1277 break; 1278 } 1279 printf("\n"); 1280 } 1281 } 1282 1283 finet = socksetup(PF_UNSPEC); 1284 if (finet) { 1285 if (SecureMode) { 1286 for (i = 0; i < *finet; i++) { 1287 if (shutdown(finet[i+1], SHUT_RD) < 0) { 1288 logerror("shutdown() failed"); 1289 die(0); 1290 } 1291 } 1292 } else 1293 dprintf("Listening on inet and/or inet6 socket\n"); 1294 dprintf("Sending on inet and/or inet6 socket\n"); 1295 } 1296 1297 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 1298 dprintf("syslogd: restarted\n"); 1299 } 1300 1301 /* 1302 * Crack a configuration file line 1303 */ 1304 void 1305 cfline(line, f) 1306 char *line; 1307 struct filed *f; 1308 { 1309 struct addrinfo hints, *res; 1310 int error, i, pri; 1311 char *bp, *p, *q; 1312 char buf[MAXLINE]; 1313 int sp_err; 1314 1315 dprintf("cfline(%s)\n", line); 1316 1317 errno = 0; /* keep strerror() stuff out of logerror messages */ 1318 1319 /* clear out file entry */ 1320 memset(f, 0, sizeof(*f)); 1321 for (i = 0; i <= LOG_NFACILITIES; i++) 1322 f->f_pmask[i] = INTERNAL_NOPRI; 1323 1324 /* 1325 * There should not be any space before the log facility. 1326 * Check this is okay, complain and fix if it is not. 1327 */ 1328 q = line; 1329 if (isblank((unsigned char)*line)) { 1330 errno = 0; 1331 logerror( 1332 "Warning: `%s' space or tab before the log facility", 1333 line); 1334 /* Fix: strip all spaces/tabs before the log facility */ 1335 while (*q++ && isblank((unsigned char)*q)); 1336 line = q; 1337 } 1338 1339 /* 1340 * q is now at the first char of the log facility 1341 * There should be at least one tab after the log facility 1342 * Check this is okay, and complain and fix if it is not. 1343 */ 1344 q = line + strlen(line); 1345 while (!isblank((unsigned char)*q) && (q != line)) 1346 q--; 1347 if ((q == line) && strlen(line)) { 1348 /* No tabs or space in a non empty line: complain */ 1349 errno = 0; 1350 logerror( 1351 "Error: `%s' log facility or log target missing", 1352 line); 1353 } 1354 1355 /* q is at the end of the blank between the two fields */ 1356 sp_err = 0; 1357 while (isblank((unsigned char)*q) && (q != line)) 1358 if (*q-- == ' ') 1359 sp_err = 1; 1360 1361 if (sp_err) { 1362 /* 1363 * A space somewhere between the log facility 1364 * and the log target: complain 1365 */ 1366 errno = 0; 1367 logerror( 1368 "Warning: `%s' space found where tab is expected", 1369 line); 1370 /* ... and fix the problem: replace all spaces by tabs */ 1371 while (*++q && isblank((unsigned char)*q)) 1372 if (*q == ' ') 1373 *q='\t'; 1374 } 1375 1376 /* scan through the list of selectors */ 1377 for (p = line; *p && *p != '\t';) { 1378 1379 /* find the end of this facility name list */ 1380 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1381 continue; 1382 1383 /* collect priority name */ 1384 for (bp = buf; *q && !strchr("\t,;", *q); ) 1385 *bp++ = *q++; 1386 *bp = '\0'; 1387 1388 /* skip cruft */ 1389 while (strchr(", ;", *q)) 1390 q++; 1391 1392 /* decode priority name */ 1393 if (*buf == '*') 1394 pri = LOG_PRIMASK + 1; 1395 else { 1396 pri = decode(buf, prioritynames); 1397 if (pri < 0) { 1398 errno = 0; 1399 logerror("Unknown priority name `%s'", buf); 1400 return; 1401 } 1402 } 1403 1404 /* scan facilities */ 1405 while (*p && !strchr("\t.;", *p)) { 1406 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1407 *bp++ = *p++; 1408 *bp = '\0'; 1409 if (*buf == '*') 1410 for (i = 0; i < LOG_NFACILITIES; i++) 1411 f->f_pmask[i] = pri; 1412 else { 1413 i = decode(buf, facilitynames); 1414 if (i < 0) { 1415 errno = 0; 1416 logerror("Unknown facility name `%s'", 1417 buf); 1418 return; 1419 } 1420 f->f_pmask[i >> 3] = pri; 1421 } 1422 while (*p == ',' || *p == ' ') 1423 p++; 1424 } 1425 1426 p = q; 1427 } 1428 1429 /* skip to action part */ 1430 sp_err = 0; 1431 while ((*p == '\t') || (*p == ' ')) 1432 p++; 1433 1434 switch (*p) 1435 { 1436 case '@': 1437 (void)strcpy(f->f_un.f_forw.f_hname, ++p); 1438 memset(&hints, 0, sizeof(hints)); 1439 hints.ai_family = AF_UNSPEC; 1440 hints.ai_socktype = SOCK_DGRAM; 1441 hints.ai_protocol = 0; 1442 error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, 1443 &res); 1444 if (error) { 1445 logerror(gai_strerror(error)); 1446 break; 1447 } 1448 f->f_un.f_forw.f_addr = res; 1449 f->f_type = F_FORW; 1450 NumForwards++; 1451 break; 1452 1453 case '/': 1454 (void)strcpy(f->f_un.f_fname, p); 1455 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1456 f->f_type = F_UNUSED; 1457 logerror(p); 1458 break; 1459 } 1460 if (isatty(f->f_file)) 1461 f->f_type = F_TTY; 1462 else 1463 f->f_type = F_FILE; 1464 if (strcmp(p, ctty) == 0) 1465 f->f_type = F_CONSOLE; 1466 break; 1467 1468 case '*': 1469 f->f_type = F_WALL; 1470 break; 1471 1472 default: 1473 for (i = 0; i < MAXUNAMES && *p; i++) { 1474 for (q = p; *q && *q != ','; ) 1475 q++; 1476 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1477 if ((q - p) > UT_NAMESIZE) 1478 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1479 else 1480 f->f_un.f_uname[i][q - p] = '\0'; 1481 while (*q == ',' || *q == ' ') 1482 q++; 1483 p = q; 1484 } 1485 f->f_type = F_USERS; 1486 break; 1487 } 1488 } 1489 1490 1491 /* 1492 * Decode a symbolic name to a numeric value 1493 */ 1494 int 1495 decode(name, codetab) 1496 const char *name; 1497 CODE *codetab; 1498 { 1499 CODE *c; 1500 char *p, buf[40]; 1501 1502 if (isdigit(*name)) 1503 return (atoi(name)); 1504 1505 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1506 if (isupper(*name)) 1507 *p = tolower(*name); 1508 else 1509 *p = *name; 1510 } 1511 *p = '\0'; 1512 for (c = codetab; c->c_name; c++) 1513 if (!strcmp(buf, c->c_name)) 1514 return (c->c_val); 1515 1516 return (-1); 1517 } 1518 1519 /* 1520 * Retrieve the size of the kernel message buffer, via sysctl. 1521 */ 1522 int 1523 getmsgbufsize() 1524 { 1525 int msgbufsize, mib[2]; 1526 size_t size; 1527 1528 mib[0] = CTL_KERN; 1529 mib[1] = KERN_MSGBUFSIZE; 1530 size = sizeof msgbufsize; 1531 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1532 dprintf("Couldn't get kern.msgbufsize\n"); 1533 return (0); 1534 } 1535 return (msgbufsize); 1536 } 1537 1538 int * 1539 socksetup(af) 1540 int af; 1541 { 1542 struct addrinfo hints, *res, *r; 1543 int error, maxs, *s, *socks; 1544 1545 if(SecureMode && !NumForwards) 1546 return(NULL); 1547 1548 memset(&hints, 0, sizeof(hints)); 1549 hints.ai_flags = AI_PASSIVE; 1550 hints.ai_family = af; 1551 hints.ai_socktype = SOCK_DGRAM; 1552 error = getaddrinfo(NULL, "syslog", &hints, &res); 1553 if (error) { 1554 logerror(gai_strerror(error)); 1555 errno = 0; 1556 die(0); 1557 } 1558 1559 /* Count max number of sockets we may open */ 1560 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 1561 continue; 1562 socks = malloc ((maxs+1) * sizeof(int)); 1563 if (!socks) { 1564 logerror("Couldn't allocate memory for sockets"); 1565 die(0); 1566 } 1567 1568 *socks = 0; /* num of sockets counter at start of array */ 1569 s = socks+1; 1570 for (r = res; r; r = r->ai_next) { 1571 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 1572 if (*s < 0) { 1573 logerror("socket() failed"); 1574 continue; 1575 } 1576 if (!SecureMode && bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 1577 logerror("bind() failed"); 1578 close (*s); 1579 continue; 1580 } 1581 1582 *socks = *socks + 1; 1583 s++; 1584 } 1585 1586 if (*socks == 0) { 1587 free (socks); 1588 if(Debug) 1589 return(NULL); 1590 else 1591 die(0); 1592 } 1593 if (res) 1594 freeaddrinfo(res); 1595 1596 return(socks); 1597 } 1598