1 /*        $NetBSD: syslogd.c,v 1.147 2024/11/09 16:31:31 jschauma Exp $         */
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993, 1994
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\
35           The Regents of the University of California.  All rights reserved.");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)syslogd.c   8.3 (Berkeley) 4/4/94";
41 #else
42 __RCSID("$NetBSD: syslogd.c,v 1.147 2024/11/09 16:31:31 jschauma Exp $");
43 #endif
44 #endif /* not lint */
45 
46 /*
47  *  syslogd -- log system messages
48  *
49  * This program implements a system log. It takes a series of lines.
50  * Each line may have a priority, signified as "<n>" as
51  * the first characters of the line.  If this is
52  * not present, a default priority is used.
53  *
54  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
55  * cause it to reread its configuration file.
56  *
57  * Defined Constants:
58  *
59  * MAXLINE -- the maximimum line length that can be handled.
60  * DEFUPRI -- the default priority for user messages
61  * DEFSPRI -- the default priority for kernel messages
62  *
63  * Author: Eric Allman
64  * extensive changes by Ralph Campbell
65  * more extensive changes by Eric Allman (again)
66  * Extension to log by program name as well as facility and priority
67  *   by Peter da Silva.
68  * -U and -v by Harlan Stenn.
69  * Priority comparison code by Harlan Stenn.
70  * TLS, syslog-protocol, and syslog-sign code by Martin Schuette.
71  */
72 #define SYSLOG_NAMES
73 #include <sys/stat.h>
74 #include <poll.h>
75 #include "syslogd.h"
76 #include "extern.h"
77 
78 #ifndef DISABLE_SIGN
79 #include "sign.h"
80 struct sign_global_t GlobalSign = {
81           .rsid = 0,
82           .sig2_delims = STAILQ_HEAD_INITIALIZER(GlobalSign.sig2_delims)
83 };
84 #endif /* !DISABLE_SIGN */
85 
86 #ifndef DISABLE_TLS
87 #include "tls.h"
88 #endif /* !DISABLE_TLS */
89 
90 #ifdef LIBWRAP
91 int allow_severity = LOG_AUTH|LOG_INFO;
92 int deny_severity = LOG_AUTH|LOG_WARNING;
93 #endif
94 
95 const char          *ConfFile = _PATH_LOGCONF;
96 char      ctty[] = _PATH_CONSOLE;
97 
98 /*
99  * Queue of about-to-be-dead processes we should watch out for.
100  */
101 TAILQ_HEAD(, deadq_entry) deadq_head = TAILQ_HEAD_INITIALIZER(deadq_head);
102 
103 typedef struct deadq_entry {
104           pid_t                                   dq_pid;
105           int                                     dq_timeout;
106           TAILQ_ENTRY(deadq_entry)      dq_entries;
107 } *dq_t;
108 
109 /*
110  * The timeout to apply to processes waiting on the dead queue.        Unit
111  * of measure is "mark intervals", i.e. 20 minutes by default.
112  * Processes on the dead queue will be terminated after that time.
113  */
114 #define DQ_TIMO_INIT          2
115 
116 #define   RCVBUFLEN 16384
117 int       buflen = RCVBUFLEN;
118 /*
119  * Intervals at which we flush out "message repeated" messages,
120  * in seconds after previous message is logged.    After each flush,
121  * we move to the next interval until we reach the largest.
122  */
123 int       repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
124 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
125 #define REPEATTIME(f)         ((f)->f_time + repeatinterval[(f)->f_repeatcount])
126 #define BACKOFF(f)  { if ((size_t)(++(f)->f_repeatcount) > MAXREPEAT) \
127                                          (f)->f_repeatcount = MAXREPEAT; \
128                               }
129 
130 /* values for f_type */
131 #define F_UNUSED    0                   /* unused entry */
132 #define F_FILE                1                   /* regular file */
133 #define F_TTY                 2                   /* terminal */
134 #define F_CONSOLE   3                   /* console terminal */
135 #define F_FORW                4                   /* remote machine */
136 #define F_USERS               5                   /* list of users */
137 #define F_WALL                6                   /* everyone logged on */
138 #define F_PIPE                7                   /* pipe to program */
139 #define F_FIFO                8                   /* mkfifo(2) file */
140 #define F_TLS                 9
141 
142 struct TypeInfo {
143           const char *name;
144           char         *queue_length_string;
145           const char *default_length_string;
146           char         *queue_size_string;
147           const char *default_size_string;
148           int64_t       queue_length;
149           int64_t       queue_size;
150           int   max_msg_length;
151 } TypeInfo[] = {
152           /* numeric values are set in init()
153            * -1 in length/size or max_msg_length means infinite */
154           {"UNUSED",  NULL,    "0", NULL,           "0", 0, 0,         0},
155           {"FILE",    NULL, "1024", NULL,          "1M", 0, 0, 16384},
156           {"TTY",       NULL,    "0", NULL,         "0", 0, 0,  1024},
157           {"CONSOLE", NULL,    "0", NULL,           "0", 0, 0,  1024},
158           {"FORW",    NULL,    "0", NULL,          "1M", 0, 0, 16384},
159           {"USERS",   NULL,    "0", NULL,           "0", 0, 0,  1024},
160           {"WALL",    NULL,    "0", NULL,           "0", 0, 0,  1024},
161           {"PIPE",    NULL, "1024", NULL,          "1M", 0, 0, 16384},
162           {"FIFO",    NULL, "1024", NULL,          "1M", 0, 0, 16384},
163 #ifndef DISABLE_TLS
164           {"TLS",       NULL,   "-1", NULL, "16M", 0, 0, 16384}
165 #endif /* !DISABLE_TLS */
166 };
167 
168 struct    filed *Files = NULL;
169 struct    filed consfile;
170 
171 time_t    now;
172 int       Debug = D_NONE;               /* debug flag */
173 int       daemonized = 0;               /* we are not daemonized yet */
174 char      *LocalFQDN = NULL;         /* our FQDN */
175 char      *oldLocalFQDN = NULL;                /* our previous FQDN */
176 char      LocalHostName[MAXHOSTNAMELEN]; /* our hostname */
177 struct socketEvent *finet;    /* Internet datagram sockets and events */
178 int   *funix;                           /* Unix domain datagram sockets */
179 #ifndef DISABLE_TLS
180 struct socketEvent *TLS_Listen_Set; /* TLS/TCP sockets and events */
181 #endif /* !DISABLE_TLS */
182 int       Initialized = 0;    /* set when we have initialized ourselves */
183 int       ShuttingDown;                 /* set when we die() */
184 int       MarkInterval = 20 * 60; /* interval between marks in seconds */
185 int       MarkSeq = 0;                  /* mark sequence number */
186 int       SecureMode = 0;               /* listen only on unix domain socks */
187 int       UseNameService = 1; /* make domain name queries */
188 int       NumForwards = 0;    /* number of forwarding actions in conf file */
189 char      **LogPaths;                   /* array of pathnames to read messages from */
190 int       NoRepeat = 0;                 /* disable "repeated"; log always */
191 int       RemoteAddDate = 0;  /* always add date to messages from network */
192 int       SyncKernel = 0;               /* write kernel messages synchronously */
193 int       UniquePriority = 0; /* only log specified priority */
194 int       LogFacPri = 0;                /* put facility and priority in log messages: */
195                                         /* 0=no, 1=numeric, 2=names */
196 int       LogOverflow = 1;    /* 0=no, any other value = yes */
197 bool      BSDOutputFormat = true;       /* if true emit traditional BSD Syslog lines,
198                                          * otherwise new syslog-protocol lines
199                                          *
200                                          * Open Issue: having a global flag is the
201                                          * easiest solution. If we get a more detailed
202                                          * config file this could/should be changed
203                                          * into a destination-specific flag.
204                                          * Most output code should be ready to handle
205                                          * this, it will only break some syslog-sign
206                                          * configurations (e.g. with SG="0").
207                                          */
208 bool      KernXlat = true;    /* translate kern.* -> user.* */
209 char      appname[]   = "syslogd";/* the APPNAME for own messages */
210 char   *include_pid;                    /* include PID in own messages */
211 char      include_pid_buf[11];
212 
213 
214 /* init and setup */
215 void                usage(void) __attribute__((__noreturn__));
216 void                set_debug(const char *);
217 void                logpath_add(char ***, int *, int *, const char *);
218 void                logpath_fileadd(char ***, int *, int *, const char *);
219 void                init(int fd, short event, void *ev);  /* SIGHUP kevent dispatch routine */
220 struct socketEvent*
221                     socksetup(int, const char *);
222 int                 getmsgbufsize(void);
223 char             *getLocalFQDN(void);
224 void                trim_anydomain(char *);
225 /* pipe & subprocess handling */
226 int                 p_open(char *, pid_t *);
227 void                deadq_enter(pid_t, const char *);
228 int                 deadq_remove(pid_t);
229 void                log_deadchild(pid_t, int, const char *);
230 void                reapchild(int fd, short event, void *ev); /* SIGCHLD kevent dispatch routine */
231 /* input message parsing & formatting */
232 const char     *cvthname(struct sockaddr_storage *);
233 void                printsys(char *);
234 struct buf_msg *printline_syslogprotocol(const char*, char*, int, int);
235 struct buf_msg *printline_bsdsyslog(const char*, char*, int, int);
236 struct buf_msg *printline_kernelprintf(const char*, char*, int, int);
237 size_t              check_timestamp(unsigned char *, char **, bool, bool);
238 char             *copy_utf8_ascii(char*, size_t);
239 uint_fast32_t       get_utf8_value(const char*);
240 unsigned  valid_utf8(const char *);
241 static unsigned check_sd(char*);
242 static unsigned check_msgid(char *);
243 /* event handling */
244 static void         dispatch_read_klog(int fd, short event, void *ev);
245 static void         dispatch_read_finet(int fd, short event, void *ev);
246 static void         dispatch_read_funix(int fd, short event, void *ev);
247 static void         domark(int fd, short event, void *ev); /* timer kevent dispatch routine */
248 /* log messages */
249 void                logmsg_async(int, const char *, const char *, int);
250 void                logmsg(struct buf_msg *);
251 int                 matches_spec(const char *, const char *,
252                     char *(*)(const char *, const char *));
253 void                udp_send(struct filed *, char *, size_t);
254 void                wallmsg(struct filed *, struct iovec *, size_t);
255 /* buffer & queue functions */
256 size_t              message_queue_purge(struct filed *f, size_t, int);
257 size_t              message_allqueues_check(void);
258 static struct buf_queue *
259                     find_qentry_to_delete(const struct buf_queue_head *, int, bool);
260 struct buf_queue *
261                     message_queue_add(struct filed *, struct buf_msg *);
262 size_t              buf_queue_obj_size(struct buf_queue*);
263 /* configuration & parsing */
264 void                cfline(size_t, const char *, struct filed *, const char *,
265     const char *);
266 void                read_config_file(FILE*, struct filed**);
267 void                store_sign_delim_sg2(char*);
268 int                 decode(const char *, CODE *);
269 bool                copy_config_value(const char *, char **, const char **,
270     const char *, int);
271 bool                copy_config_value_word(char **, const char **);
272 
273 /* config parsing */
274 #ifndef DISABLE_TLS
275 void                free_cred_SLIST(struct peer_cred_head *);
276 static inline void
277                     free_incoming_tls_sockets(void);
278 #endif /* !DISABLE_TLS */
279 static int writev1(int, struct iovec *, size_t);
280 
281 static void setsockbuf(int, const char *);
282 
283 /* for make_timestamp() */
284 char      timestamp[MAX_TIMESTAMPLEN + 1];
285 /*
286  * Global line buffer.        Since we only process one event at a time,
287  * a global one will do.  But for klog, we use own buffer so that
288  * partial line at the end of buffer can be deferred.
289  */
290 char *linebuf, *klog_linebuf;
291 size_t linebufsize, klog_linebufoff;
292 
293 static const char *bindhostname = NULL;
294 
295 #ifndef DISABLE_TLS
296 struct TLS_Incoming TLS_Incoming_Head = \
297           SLIST_HEAD_INITIALIZER(TLS_Incoming_Head);
298 extern char *SSL_ERRCODE[];
299 struct tls_global_options_t tls_opt;
300 #endif /* !DISABLE_TLS */
301 
302 int
main(int argc,char * argv[])303 main(int argc, char *argv[])
304 {
305           int ch, j, fklog;
306           int funixsize = 0, funixmaxsize = 0;
307           struct sockaddr_un sunx;
308           char **pp;
309           struct event *ev;
310           uid_t uid = 0;
311           gid_t gid = 0;
312           char *user = NULL;
313           char *group = NULL;
314           const char *root = "/";
315           char *endp;
316           struct group   *gr;
317           struct passwd  *pw;
318           unsigned long l;
319           char pfpath[PATH_MAX];
320 
321           /* should we set LC_TIME="C" to ensure correct timestamps&parsing? */
322           (void)setlocale(LC_ALL, "");
323 
324           while ((ch = getopt(argc, argv, "b:B:d::knsSf:m:o:p:P:ru:g:t:TUvX")) != -1)
325                     switch(ch) {
326                     case 'b':
327                               bindhostname = optarg;
328                               break;
329                     case 'B':
330                               buflen = atoi(optarg);
331                               if (buflen < RCVBUFLEN)
332                                         buflen = RCVBUFLEN;
333                               break;
334                     case 'd':           /* debug */
335                               if (optarg != NULL) {
336                                         /*
337                                          * getopt passes as optarg everything
338                                          * after 'd' in -darg, manually accept
339                                          * -d=arg too.
340                                          */
341                                         if (optarg[0] == '=')
342                                                   ++optarg;
343                               } else if (optind < argc) {
344                                         /*
345                                          * :: treats "-d ..." as missing
346                                          * optarg, so look ahead manually and
347                                          * pick up the next arg if it looks
348                                          * like one.
349                                          */
350                                         if (argv[optind][0] != '-') {
351                                                   optarg = argv[optind];
352                                                   ++optind;
353                                         }
354                               }
355                               set_debug(optarg);
356                               break;
357                     case 'f':           /* configuration file */
358                               ConfFile = optarg;
359                               break;
360                     case 'g':
361                               group = optarg;
362                               if (*group == '\0')
363                                         usage();
364                               break;
365                     case 'k':           /* pass-through (remote) kern.* */
366                               KernXlat = false;
367                               break;
368                     case 'm':           /* mark interval */
369                               MarkInterval = atoi(optarg) * 60;
370                               break;
371                     case 'n':           /* turn off DNS queries */
372                               UseNameService = 0;
373                               break;
374                     case 'o':           /* message format */
375 #define EQ(a)                 (strncmp(optarg, # a, sizeof(# a) - 1) == 0)
376                               if (EQ(bsd) || EQ(rfc3264))
377                                         BSDOutputFormat = true;
378                               else if (EQ(syslog) || EQ(rfc5424))
379                                         BSDOutputFormat = false;
380                               else
381                                         usage();
382                               /* TODO: implement additional output option "osyslog"
383                                *         for old syslogd behaviour as introduced after
384                                *         FreeBSD PR#bin/7055.
385                                */
386                               break;
387                     case 'p':           /* path */
388                               logpath_add(&LogPaths, &funixsize,
389                                   &funixmaxsize, optarg);
390                               break;
391                     case 'P':           /* file of paths */
392                               logpath_fileadd(&LogPaths, &funixsize,
393                                   &funixmaxsize, optarg);
394                               break;
395                     case 'r':           /* disable "repeated" compression */
396                               NoRepeat++;
397                               break;
398                     case 's':           /* no network listen mode */
399                               SecureMode++;
400                               break;
401                     case 'S':
402                               SyncKernel = 1;
403                               break;
404                     case 't':
405                               root = optarg;
406                               if (*root == '\0')
407                                         usage();
408                               break;
409                     case 'T':
410                               RemoteAddDate = 1;
411                               break;
412                     case 'u':
413                               user = optarg;
414                               if (*user == '\0')
415                                         usage();
416                               break;
417                     case 'U':           /* only log specified priority */
418                               UniquePriority = 1;
419                               break;
420                     case 'v':           /* log facility and priority */
421                               if (LogFacPri < 2)
422                                         LogFacPri++;
423                               break;
424                     case 'X':
425                               LogOverflow = 0;
426                               break;
427                     default:
428                               usage();
429                     }
430           if ((argc -= optind) != 0)
431                     usage();
432 
433           setlinebuf(stdout);
434           tzset(); /* init TZ information for localtime. */
435 
436           if (user != NULL) {
437                     if (isdigit((unsigned char)*user)) {
438                               errno = 0;
439                               endp = NULL;
440                               l = strtoul(user, &endp, 0);
441                               if (errno || *endp != '\0')
442                                         goto getuser;
443                               uid = (uid_t)l;
444                               if (uid != l) {/* TODO: never executed */
445                                         errno = 0;
446                                         logerror("UID out of range");
447                                         die(0, 0, NULL);
448                               }
449                     } else {
450 getuser:
451                               if ((pw = getpwnam(user)) != NULL) {
452                                         uid = pw->pw_uid;
453                               } else {
454                                         errno = 0;
455                                         logerror("Cannot find user `%s'", user);
456                                         die(0, 0, NULL);
457                               }
458                     }
459           }
460 
461           if (group != NULL) {
462                     if (isdigit((unsigned char)*group)) {
463                               errno = 0;
464                               endp = NULL;
465                               l = strtoul(group, &endp, 0);
466                               if (errno || *endp != '\0')
467                                         goto getgroup;
468                               gid = (gid_t)l;
469                               if (gid != l) {/* TODO: never executed */
470                                         errno = 0;
471                                         logerror("GID out of range");
472                                         die(0, 0, NULL);
473                               }
474                     } else {
475 getgroup:
476                               if ((gr = getgrnam(group)) != NULL) {
477                                         gid = gr->gr_gid;
478                               } else {
479                                         errno = 0;
480                                         logerror("Cannot find group `%s'", group);
481                                         die(0, 0, NULL);
482                               }
483                     }
484           }
485 
486           if (access(root, F_OK | R_OK)) {
487                     logerror("Cannot access `%s'", root);
488                     die(0, 0, NULL);
489           }
490 
491           consfile.f_type = F_CONSOLE;
492           (void)strlcpy(consfile.f_un.f_fname, ctty,
493               sizeof(consfile.f_un.f_fname));
494           linebufsize = getmsgbufsize();
495           if (linebufsize < MAXLINE)
496                     linebufsize = MAXLINE;
497           linebufsize++;
498 
499           if (!(linebuf = malloc(linebufsize))) {
500                     logerror("Couldn't allocate buffer");
501                     die(0, 0, NULL);
502           }
503           if (!(klog_linebuf = malloc(linebufsize))) {
504                     logerror("Couldn't allocate buffer for klog");
505                     die(0, 0, NULL);
506           }
507 
508 
509 #ifndef SUN_LEN
510 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
511 #endif
512           if (funixsize == 0)
513                     logpath_add(&LogPaths, &funixsize,
514                         &funixmaxsize, _PATH_LOG);
515           funix = malloc(sizeof(*funix) * funixsize);
516           if (funix == NULL) {
517                     logerror("Couldn't allocate funix descriptors");
518                     die(0, 0, NULL);
519           }
520           for (j = 0, pp = LogPaths; *pp; pp++, j++) {
521                     DPRINTF(D_NET, "Making unix dgram socket `%s'\n", *pp);
522                     unlink(*pp);
523                     memset(&sunx, 0, sizeof(sunx));
524                     sunx.sun_family = AF_LOCAL;
525                     (void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path));
526                     funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0);
527                     if (funix[j] < 0 || bind(funix[j],
528                         (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
529                         chmod(*pp, 0666) < 0) {
530                               logerror("Cannot create `%s'", *pp);
531                               die(0, 0, NULL);
532                     }
533                     setsockbuf(funix[j], *pp);
534                     DPRINTF(D_NET, "Listening on unix dgram socket `%s'\n", *pp);
535           }
536 
537           if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
538                     DPRINTF(D_FILE, "Can't open `%s' (%d)\n", _PATH_KLOG, errno);
539           } else {
540                     DPRINTF(D_FILE, "Listening on kernel log `%s' with fd %d\n",
541                         _PATH_KLOG, fklog);
542           }
543 
544 #if (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN))
545           /* basic OpenSSL init */
546           SSL_load_error_strings();
547           (void) SSL_library_init();
548           OpenSSL_add_all_digests();
549           /* OpenSSL PRNG needs /dev/urandom, thus initialize before chroot() */
550           if (!RAND_status()) {
551                     errno = 0;
552                     logerror("Unable to initialize OpenSSL PRNG");
553           } else {
554                     DPRINTF(D_TLS, "Initializing PRNG\n");
555           }
556 #endif /* (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN)) */
557 #ifndef DISABLE_SIGN
558           /* initialize rsid -- we will use that later to determine
559            * whether sign_global_init() was already called */
560           GlobalSign.rsid = 0;
561 #endif /* !DISABLE_SIGN */
562 #if (IETF_NUM_PRIVALUES != (LOG_NFACILITIES<<3))
563           logerror("Warning: system defines %d priority values, but "
564               "syslog-protocol/syslog-sign specify %d values",
565               LOG_NFACILITIES, IETF_NUM_PRIVALUES>>3);
566 #endif
567 
568 #ifdef __NetBSD_Version__
569           if ((uid != 0) || (gid != 0)) {
570                     /* Create the pidfile here so we can chown it to the target
571                      * user/group and possibly report any error before daemonizing.
572                      * We then call pidfile(3) again to write the actual
573                      * daemon pid below.
574                      *
575                      * Note: this will likely leave the truncated pidfile in
576                      * place upon exit, since the effective user is unlikely
577                      * to have write permissions to _PATH_VARRUN. */
578                     if (pidfile(NULL)) {
579                               logerror("Failed to create pidfile");
580                               die(0, 0, NULL);
581                     }
582                     j = sizeof(pfpath);
583                     if (snprintf(pfpath, j, "%s%s.pid",
584                                                   _PATH_VARRUN, getprogname()) >= j) {
585                               logerror("Pidfile path `%s' too long.", pfpath);
586                               die(0, 0, NULL);
587                     }
588                     if (chown(pfpath, uid, gid) < 0) {
589                               logerror("Failed to chown pidfile `%s` to `%d:%d`", pfpath, uid, gid);
590                               die(0, 0, NULL);
591                     }
592           }
593 #endif /* __NetBSD_Version__ */
594 
595           /*
596            * All files are open, we can drop privileges and chroot.
597            */
598           DPRINTF(D_MISC, "Attempt to chroot to `%s'\n", root);
599           if (chroot(root) == -1) {
600                     logerror("Failed to chroot to `%s'", root);
601                     die(0, 0, NULL);
602           }
603           DPRINTF(D_MISC, "Attempt to set GID/EGID to `%d'\n", gid);
604           if (setgid(gid) || setegid(gid)) {
605                     logerror("Failed to set gid to `%d'", gid);
606                     die(0, 0, NULL);
607           }
608           DPRINTF(D_MISC, "Attempt to set UID/EUID to `%d'\n", uid);
609           if (setuid(uid) || seteuid(uid)) {
610                     logerror("Failed to set uid to `%d'", uid);
611                     die(0, 0, NULL);
612           }
613           /*
614            * We cannot detach from the terminal before we are sure we won't
615            * have a fatal error, because error message would not go to the
616            * terminal and would not be logged because syslogd dies.
617            * All die() calls are behind us, we can call daemon().
618            */
619           if (!Debug) {
620                     (void)daemon(0, 0);
621                     daemonized = 1;
622                     /* Tuck my process id away, if I'm not in debug mode. */
623 #ifdef __NetBSD_Version__
624                     pidfile(NULL);
625 #endif /* __NetBSD_Version__ */
626           }
627 
628           include_pid = include_pid_buf;
629           snprintf(include_pid_buf, sizeof(include_pid_buf), "%d", getpid());
630 
631           /*
632            * Create the global kernel event descriptor.
633            *
634            * NOTE: We MUST do this after daemon(), because the kqueue()
635            * API dictates that kqueue descriptors are not inherited
636            * across forks (lame!).
637            */
638           (void)event_init();
639 
640           /*
641            * We must read the configuration file for the first time
642            * after the kqueue descriptor is created, because we install
643            * events during this process.
644            */
645           init(0, 0, NULL);
646 
647           /*
648            * Always exit on SIGTERM.  Also exit on SIGINT and SIGQUIT
649            * if we're debugging.
650            */
651           (void)signal(SIGTERM, SIG_IGN);
652           (void)signal(SIGINT, SIG_IGN);
653           (void)signal(SIGQUIT, SIG_IGN);
654 
655           ev = allocev();
656           signal_set(ev, SIGTERM, die, ev);
657           EVENT_ADD(ev);
658 
659           if (Debug) {
660                     ev = allocev();
661                     signal_set(ev, SIGINT, die, ev);
662                     EVENT_ADD(ev);
663                     ev = allocev();
664                     signal_set(ev, SIGQUIT, die, ev);
665                     EVENT_ADD(ev);
666           }
667 
668           ev = allocev();
669           signal_set(ev, SIGCHLD, reapchild, ev);
670           EVENT_ADD(ev);
671 
672           ev = allocev();
673           schedule_event(&ev,
674                     &((struct timeval){TIMERINTVL, 0}),
675                     domark, ev);
676 
677           (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */
678 
679           /* Re-read configuration on SIGHUP. */
680           (void) signal(SIGHUP, SIG_IGN);
681           ev = allocev();
682           signal_set(ev, SIGHUP, init, ev);
683           EVENT_ADD(ev);
684 
685 #ifndef DISABLE_TLS
686           ev = allocev();
687           signal_set(ev, SIGUSR1, dispatch_force_tls_reconnect, ev);
688           EVENT_ADD(ev);
689 #endif /* !DISABLE_TLS */
690 
691           if (fklog >= 0) {
692                     ev = allocev();
693                     DPRINTF(D_EVENT,
694                               "register klog for fd %d with ev@%p\n", fklog, ev);
695                     event_set(ev, fklog, EV_READ | EV_PERSIST,
696                               dispatch_read_klog, ev);
697                     EVENT_ADD(ev);
698           }
699           for (j = 0, pp = LogPaths; *pp; pp++, j++) {
700                     ev = allocev();
701                     event_set(ev, funix[j], EV_READ | EV_PERSIST,
702                               dispatch_read_funix, ev);
703                     EVENT_ADD(ev);
704           }
705 
706           DPRINTF(D_MISC, "Off & running....\n");
707 
708           j = event_dispatch();
709           /* normal termination via die(), reaching this is an error */
710           DPRINTF(D_MISC, "event_dispatch() returned %d\n", j);
711           die(0, 0, NULL);
712           /*NOTREACHED*/
713           return 0;
714 }
715 
716 void
usage(void)717 usage(void)
718 {
719 
720           (void)fprintf(stderr,
721               "usage: %s [-dknrSsTUvX] [-B buffer_length] [-b bind_address]\n"
722               "\t[-f config_file] [-g group]\n"
723               "\t[-m mark_interval] [-P file_list] [-p log_socket\n"
724               "\t[-p log_socket2 ...]] [-t chroot_dir] [-u user]\n",
725               getprogname());
726           exit(1);
727 }
728 
729 static void
setsockbuf(int fd,const char * name)730 setsockbuf(int fd, const char *name)
731 {
732           int curbuflen;
733           socklen_t socklen = sizeof(buflen);
734 
735           if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &curbuflen, &socklen) == -1) {
736                     logerror("getsockopt: SO_RCVBUF: `%s'", name);
737                     return;
738           }
739           if (curbuflen >= buflen)
740                     return;
741           if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buflen, socklen) == -1) {
742                     logerror("setsockopt: SO_RCVBUF: `%s'", name);
743                     return;
744           }
745 }
746 
747 /*
748  * Dispatch routine for reading /dev/klog
749  *
750  * Note: slightly different semantic in dispatch_read functions:
751  *         - read_klog() might give multiple messages in linebuf and
752  *           leaves the task of splitting them to printsys()
753  *         - all other read functions receive one message and
754  *           then call printline() with one buffer.
755  */
756 static void
dispatch_read_klog(int fd,short event,void * ev)757 dispatch_read_klog(int fd, short event, void *ev)
758 {
759           ssize_t rv;
760           size_t resid = linebufsize - klog_linebufoff;
761 
762           DPRINTF((D_CALL|D_EVENT), "Kernel log active (%d, %d, %p)"
763                     " with linebuf@%p, length %zu)\n", fd, event, ev,
764                     klog_linebuf, linebufsize);
765 
766           rv = read(fd, &klog_linebuf[klog_linebufoff], resid - 1);
767           if (rv > 0) {
768                     klog_linebuf[klog_linebufoff + rv] = '\0';
769                     printsys(klog_linebuf);
770           } else if (rv < 0 &&
771               errno != EINTR &&
772               (errno != ENOBUFS || LogOverflow))
773           {
774                     /*
775                      * /dev/klog has croaked.  Disable the event
776                      * so it won't bother us again.
777                      */
778                     logerror("klog failed");
779                     event_del(ev);
780           }
781 }
782 
783 /*
784  * Dispatch routine for reading Unix domain sockets.
785  */
786 static void
dispatch_read_funix(int fd,short event,void * ev)787 dispatch_read_funix(int fd, short event, void *ev)
788 {
789           struct sockaddr_un myname, fromunix;
790           ssize_t rv;
791           socklen_t sunlen;
792 
793           sunlen = sizeof(myname);
794           if (getsockname(fd, (struct sockaddr *)&myname, &sunlen) != 0) {
795                     /*
796                      * This should never happen, so ensure that it doesn't
797                      * happen again.
798                      */
799                     logerror("getsockname() unix failed");
800                     event_del(ev);
801                     return;
802           }
803 
804 #define SUN_PATHLEN(su) \
805           ((su)->sun_len - (sizeof(*(su)) - sizeof((su)->sun_path)))
806 
807           DPRINTF((D_CALL|D_EVENT|D_NET), "Unix socket (%.*s) active (%d, %d %p)"
808                     " with linebuf@%p, size %zu)\n", (int)SUN_PATHLEN(&myname),
809                     myname.sun_path, fd, event, ev, linebuf, linebufsize-1);
810 
811           sunlen = sizeof(fromunix);
812           rv = recvfrom(fd, linebuf, linebufsize-1, 0,
813               (struct sockaddr *)&fromunix, &sunlen);
814           if (rv > 0) {
815                     linebuf[rv] = '\0';
816                     printline(LocalFQDN, linebuf, 0);
817           } else if (rv < 0 &&
818               errno != EINTR &&
819               (errno != ENOBUFS || LogOverflow))
820           {
821                     logerror("recvfrom() unix `%.*s'",
822                               (int)SUN_PATHLEN(&myname), myname.sun_path);
823           }
824 }
825 
826 /*
827  * Dispatch routine for reading Internet sockets.
828  */
829 static void
dispatch_read_finet(int fd,short event,void * ev)830 dispatch_read_finet(int fd, short event, void *ev)
831 {
832 #ifdef LIBWRAP
833           struct request_info req;
834 #endif
835           struct sockaddr_storage frominet;
836           ssize_t rv;
837           socklen_t len;
838           int reject = 0;
839 
840           DPRINTF((D_CALL|D_EVENT|D_NET), "inet socket active (%d, %d %p) "
841                     " with linebuf@%p, size %zu)\n",
842                     fd, event, ev, linebuf, linebufsize-1);
843 
844 #ifdef LIBWRAP
845           request_init(&req, RQ_DAEMON, appname, RQ_FILE, fd, NULL);
846           fromhost(&req);
847           reject = !hosts_access(&req);
848           if (reject)
849                     DPRINTF(D_NET, "access denied\n");
850 #endif
851 
852           len = sizeof(frominet);
853           rv = recvfrom(fd, linebuf, linebufsize-1, 0,
854               (struct sockaddr *)&frominet, &len);
855           if (rv == 0 ||
856               (rv < 0 && (errno == EINTR ||
857                               (errno == ENOBUFS && LogOverflow == 0))))
858                     return;
859           else if (rv < 0) {
860                     logerror("recvfrom inet");
861                     return;
862           }
863 
864           linebuf[rv] = '\0';
865           if (!reject)
866                     printline(cvthname(&frominet), linebuf,
867                         RemoteAddDate ? ADDDATE : 0);
868 }
869 
870 /*
871  * given a pointer to an array of char *'s, a pointer to its current
872  * size and current allocated max size, and a new char * to add, add
873  * it, update everything as necessary, possibly allocating a new array
874  */
875 void
logpath_add(char *** lp,int * szp,int * maxszp,const char * new)876 logpath_add(char ***lp, int *szp, int *maxszp, const char *new)
877 {
878           char **nlp;
879           int newmaxsz;
880 
881           DPRINTF(D_FILE, "Adding `%s' to the %p logpath list\n", new, *lp);
882           if (*szp == *maxszp) {
883                     if (*maxszp == 0) {
884                               newmaxsz = 4;       /* start of with enough for now */
885                               *lp = NULL;
886                     } else
887                               newmaxsz = *maxszp * 2;
888                     nlp = realloc(*lp, sizeof(char *) * (newmaxsz + 1));
889                     if (nlp == NULL) {
890                               logerror("Couldn't allocate line buffer");
891                               die(0, 0, NULL);
892                     }
893                     *lp = nlp;
894                     *maxszp = newmaxsz;
895           }
896           if (((*lp)[(*szp)++] = strdup(new)) == NULL) {
897                     logerror("Couldn't allocate logpath");
898                     die(0, 0, NULL);
899           }
900           (*lp)[(*szp)] = NULL;                   /* always keep it NULL terminated */
901 }
902 
903 /* do a file of log sockets */
904 void
logpath_fileadd(char *** lp,int * szp,int * maxszp,const char * file)905 logpath_fileadd(char ***lp, int *szp, int *maxszp, const char *file)
906 {
907           FILE *fp;
908           char *line;
909           size_t len;
910 
911           fp = fopen(file, "r");
912           if (fp == NULL) {
913                     logerror("Could not open socket file list `%s'", file);
914                     die(0, 0, NULL);
915           }
916 
917           while ((line = fgetln(fp, &len)) != NULL) {
918                     line[len - 1] = 0;
919                     logpath_add(lp, szp, maxszp, line);
920           }
921           fclose(fp);
922 }
923 
924 /*
925  * checks UTF-8 codepoint
926  * returns either its length in bytes or 0 if *input is invalid
927 */
928 unsigned
valid_utf8(const char * c)929 valid_utf8(const char *c) {
930           unsigned rc, nb;
931 
932           /* first byte gives sequence length */
933                if ((*c & 0x80) == 0x00) return 1; /* 0bbbbbbb -- ASCII */
934           else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */
935           else if ((*c & 0xe0) == 0xc0) nb = 2;   /* 110bbbbb */
936           else if ((*c & 0xf0) == 0xe0) nb = 3;   /* 1110bbbb */
937           else if ((*c & 0xf8) == 0xf0) nb = 4;   /* 11110bbb */
938           else return 0; /* UTF-8 allows only up to 4 bytes */
939 
940           /* catch overlong encodings */
941           if ((*c & 0xfe) == 0xc0)
942                     return 0; /* 1100000b ... */
943           else if (((*c & 0xff) == 0xe0) && ((*(c+1) & 0xe0) == 0x80))
944                     return 0; /* 11100000 100bbbbb ... */
945           else if (((*c & 0xff) == 0xf0) && ((*(c+1) & 0xf0) == 0x80))
946                     return 0; /* 11110000 1000bbbb ... ... */
947 
948           /* and also filter UTF-16 surrogates (=invalid in UTF-8) */
949           if (((*c & 0xff) == 0xed) && ((*(c+1) & 0xe0) == 0xa0))
950                     return 0; /* 11101101 101bbbbb ... */
951 
952           rc = nb;
953           /* check trailing bytes */
954           switch (nb) {
955           default: return 0;
956           case 4: if ((*(c+3) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
957           case 3: if ((*(c+2) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
958           case 2: if ((*(c+1) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/
959           }
960           return rc;
961 }
962 #define UTF8CHARMAX 4
963 
964 /*
965  * read UTF-8 value
966  * returns a the codepoint number
967  */
968 uint_fast32_t
get_utf8_value(const char * c)969 get_utf8_value(const char *c) {
970           uint_fast32_t sum;
971           unsigned nb, i;
972 
973           /* first byte gives sequence length */
974                if ((*c & 0x80) == 0x00) return *c;/* 0bbbbbbb -- ASCII */
975           else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */
976           else if ((*c & 0xe0) == 0xc0) {                   /* 110bbbbb */
977                     nb = 2;
978                     sum = (*c & ~0xe0) & 0xff;
979           } else if ((*c & 0xf0) == 0xe0) {       /* 1110bbbb */
980                     nb = 3;
981                     sum = (*c & ~0xf0) & 0xff;
982           } else if ((*c & 0xf8) == 0xf0) {       /* 11110bbb */
983                     nb = 4;
984                     sum = (*c & ~0xf8) & 0xff;
985           } else return 0; /* UTF-8 allows only up to 4 bytes */
986 
987           /* check trailing bytes -- 10bbbbbb */
988           i = 1;
989           while (i < nb) {
990                     sum <<= 6;
991                     sum |= ((*(c+i) & ~0xc0) & 0xff);
992                     i++;
993           }
994           return sum;
995 }
996 
997 /* note previous versions transscribe
998  * control characters, e.g. \007 --> "^G"
999  * did anyone rely on that?
1000  *
1001  * this new version works on only one buffer and
1002  * replaces control characters with a space
1003  */
1004 #define NEXTFIELD(ptr) if (*(p) == ' ') (p)++; /* SP */                         \
1005                            else {                                                         \
1006                                         DPRINTF(D_DATA, "format error\n");      \
1007                                         if (*(p) == '\0') start = (p);                    \
1008                                         goto all_syslog_msg;                              \
1009                            }
1010 #define FORCE2ASCII(c) ((iscntrl((unsigned char)(c)) && (c) != '\t')  \
1011                               ? ((c) == '\n' ? ' ' : '?')                       \
1012                               : (c) & 0177)
1013 
1014 /* following syslog-protocol */
1015 #define printusascii(ch) (ch >= 33 && ch <= 126)
1016 #define sdname(ch) (ch != '=' && ch != ' ' \
1017                      && ch != ']' && ch != '"' \
1018                      && printusascii(ch))
1019 
1020 /* checks whether the first word of string p can be interpreted as
1021  * a syslog-protocol MSGID and if so returns its length.
1022  *
1023  * otherwise returns 0
1024  */
1025 static unsigned
check_msgid(char * p)1026 check_msgid(char *p)
1027 {
1028           char *q = p;
1029 
1030           /* consider the NILVALUE to be valid */
1031           if (*q == '-' && *(q+1) == ' ')
1032                     return 1;
1033 
1034           for (;;) {
1035                     if (*q == ' ')
1036                               return q - p;
1037                     else if (*q == '\0' || !printusascii(*q) || q - p >= MSGID_MAX)
1038                               return 0;
1039                     else
1040                               q++;
1041           }
1042 }
1043 
1044 /*
1045  * returns number of chars found in SD at beginning of string p
1046  * thus returns 0 if no valid SD is found
1047  *
1048  * if ascii == true then substitute all non-ASCII chars
1049  * otherwise use syslog-protocol rules to allow UTF-8 in values
1050  * note: one pass for filtering and scanning, so a found SD
1051  * is always filtered, but an invalid one could be partially
1052  * filtered up to the format error.
1053  */
1054 static unsigned
check_sd(char * p)1055 check_sd(char* p)
1056 {
1057           char *q = p;
1058           bool esc = false;
1059 
1060           /* consider the NILVALUE to be valid */
1061           if (*q == '-' && (*(q+1) == ' ' || *(q+1) == '\0'))
1062                     return 1;
1063 
1064           for(;;) { /* SD-ELEMENT */
1065                     if (*q++ != '[') return 0;
1066                     /* SD-ID */
1067                     if (!sdname(*q)) return 0;
1068                     while (sdname(*q)) {
1069                               *q = FORCE2ASCII(*q);
1070                               q++;
1071                     }
1072                     for(;;) { /* SD-PARAM */
1073                               if (*q == ']') {
1074                                         q++;
1075                                         if (*q == ' ' || *q == '\0') return q - p;
1076                                         else if (*q == '[') break;
1077                               } else if (*q++ != ' ') return 0;
1078 
1079                               /* PARAM-NAME */
1080                               if (!sdname(*q)) return 0;
1081                               while (sdname(*q)) {
1082                                         *q = FORCE2ASCII(*q);
1083                                         q++;
1084                               }
1085 
1086                               if (*q++ != '=') return 0;
1087                               if (*q++ != '"') return 0;
1088 
1089                               for(;;) { /* PARAM-VALUE */
1090                                         if (esc) {
1091                                                   esc = false;
1092                                                   if (*q == '\\' || *q == '"' ||
1093                                                       *q == ']') {
1094                                                             q++;
1095                                                             continue;
1096                                                   }
1097                                                   /* no else because invalid
1098                                                    * escape sequences are accepted */
1099                                         }
1100                                         else if (*q == '"') break;
1101                                         else if (*q == '\0' || *q == ']') return 0;
1102                                         else if (*q == '\\') esc = true;
1103                                         else {
1104                                                   int i;
1105                                                   i = valid_utf8(q);
1106                                                   if (i == 0)
1107                                                             *q = '?';
1108                                                   else if (i == 1)
1109                                                             *q = FORCE2ASCII(*q);
1110                                                   else /* multi byte char */
1111                                                             q += (i-1);
1112                                         }
1113                                         q++;
1114                               }
1115                               q++;
1116                     }
1117           }
1118 }
1119 
1120 struct buf_msg *
printline_syslogprotocol(const char * hname,char * msg,int flags,int pri)1121 printline_syslogprotocol(const char *hname, char *msg,
1122           int flags, int pri)
1123 {
1124           struct buf_msg *buffer;
1125           char *p, *start;
1126           unsigned sdlen = 0, i = 0;
1127           bool utf8allowed = false; /* for some fields */
1128 
1129           DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_syslogprotocol("
1130               "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
1131 
1132           buffer = buf_msg_new(0);
1133           p = msg;
1134           p += check_timestamp((unsigned char*) p,
1135                     &buffer->timestamp, true, !BSDOutputFormat);
1136           DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp);
1137 
1138           if (flags & ADDDATE) {
1139                     FREEPTR(buffer->timestamp);
1140                     buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
1141           }
1142 
1143           start = p;
1144           NEXTFIELD(p);
1145           /* extract host */
1146           for (start = p;; p++) {
1147                     if ((*p == ' ' || *p == '\0')
1148                         && start == p-1 && *(p-1) == '-') {
1149                               /* NILVALUE */
1150                               break;
1151                     } else if ((*p == ' ' || *p == '\0')
1152                         && (start != p-1 || *(p-1) != '-')) {
1153                               buffer->host = strndup(start, p - start);
1154                               break;
1155                     } else {
1156                               *p = FORCE2ASCII(*p);
1157                     }
1158           }
1159           /* p @ SP after host */
1160           DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host);
1161 
1162           /* extract app-name */
1163           NEXTFIELD(p);
1164           for (start = p;; p++) {
1165                     if ((*p == ' ' || *p == '\0')
1166                         && start == p-1 && *(p-1) == '-') {
1167                               /* NILVALUE */
1168                               break;
1169                     } else if ((*p == ' ' || *p == '\0')
1170                         && (start != p-1 || *(p-1) != '-')) {
1171                               buffer->prog = strndup(start, p - start);
1172                               break;
1173                     } else {
1174                               *p = FORCE2ASCII(*p);
1175                     }
1176           }
1177           DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog);
1178 
1179           /* extract procid */
1180           NEXTFIELD(p);
1181           for (start = p;; p++) {
1182                     if ((*p == ' ' || *p == '\0')
1183                         && start == p-1 && *(p-1) == '-') {
1184                               /* NILVALUE */
1185                               break;
1186                     } else if ((*p == ' ' || *p == '\0')
1187                         && (start != p-1 || *(p-1) != '-')) {
1188                               buffer->pid = strndup(start, p - start);
1189                               start = p;
1190                               break;
1191                     } else {
1192                               *p = FORCE2ASCII(*p);
1193                     }
1194           }
1195           DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid);
1196 
1197           /* extract msgid */
1198           NEXTFIELD(p);
1199           for (start = p;; p++) {
1200                     if ((*p == ' ' || *p == '\0')
1201                         && start == p-1 && *(p-1) == '-') {
1202                               /* NILVALUE */
1203                               start = p+1;
1204                               break;
1205                     } else if ((*p == ' ' || *p == '\0')
1206                         && (start != p-1 || *(p-1) != '-')) {
1207                               buffer->msgid = strndup(start, p - start);
1208                               start = p+1;
1209                               break;
1210                     } else {
1211                               *p = FORCE2ASCII(*p);
1212                     }
1213           }
1214           DPRINTF(D_DATA, "Got msgid \"%s\"\n", buffer->msgid);
1215 
1216           /* extract SD */
1217           NEXTFIELD(p);
1218           start = p;
1219           sdlen = check_sd(p);
1220           DPRINTF(D_DATA, "check_sd(\"%s\") returned %d\n", p, sdlen);
1221 
1222           if (sdlen == 1 && *p == '-') {
1223                     /* NILVALUE */
1224                     p++;
1225           } else if (sdlen > 1) {
1226                     buffer->sd = strndup(p, sdlen);
1227                     p += sdlen;
1228           } else {
1229                     DPRINTF(D_DATA, "format error\n");
1230           }
1231           if        (*p == '\0') start = p;
1232           else if (*p == ' ')  start = ++p; /* SP */
1233           DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
1234 
1235           /* and now the message itself
1236            * note: move back to last start to check for BOM
1237            */
1238 all_syslog_msg:
1239           p = start;
1240 
1241           /* check for UTF-8-BOM */
1242           if (IS_BOM(p)) {
1243                     DPRINTF(D_DATA, "UTF-8 BOM\n");
1244                     utf8allowed = true;
1245                     p += 3;
1246           }
1247 
1248           if (*p != '\0' && !utf8allowed) {
1249                     size_t msglen;
1250 
1251                     msglen = strlen(p);
1252                     assert(!buffer->msg);
1253                     buffer->msg = copy_utf8_ascii(p, msglen);
1254                     buffer->msgorig = buffer->msg;
1255                     buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
1256           } else if (*p != '\0' && utf8allowed) {
1257                     while (*p != '\0') {
1258                               i = valid_utf8(p);
1259                               if (i == 0)
1260                                         *p++ = '?';
1261                               else if (i == 1)
1262                                         *p = FORCE2ASCII(*p);
1263                               p += i;
1264                     }
1265                     assert(p != start);
1266                     assert(!buffer->msg);
1267                     buffer->msg = strndup(start, p - start);
1268                     buffer->msgorig = buffer->msg;
1269                     buffer->msglen = buffer->msgsize = 1 + p - start;
1270           }
1271           DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
1272 
1273           buffer->recvhost = strdup(hname);
1274           buffer->pri = pri;
1275           buffer->flags = flags;
1276 
1277           return buffer;
1278 }
1279 
1280 /* copies an input into a new ASCII buffer
1281  * ASCII controls are converted to format "^X"
1282  * multi-byte UTF-8 chars are converted to format "<ab><cd>"
1283  */
1284 #define INIT_BUFSIZE 512
1285 char *
copy_utf8_ascii(char * p,size_t p_len)1286 copy_utf8_ascii(char *p, size_t p_len)
1287 {
1288           size_t idst = 0, isrc = 0, dstsize = INIT_BUFSIZE, i;
1289           char *dst, *tmp_dst;
1290 
1291           MALLOC(dst, dstsize);
1292           while (isrc < p_len) {
1293                     if (dstsize < idst + 10) {
1294                               /* check for enough space for \0 and a UTF-8
1295                                * conversion; longest possible is <U+123456> */
1296                               tmp_dst = realloc(dst, dstsize + INIT_BUFSIZE);
1297                               if (!tmp_dst)
1298                                         break;
1299                               dst = tmp_dst;
1300                               dstsize += INIT_BUFSIZE;
1301                     }
1302 
1303                     i = valid_utf8(&p[isrc]);
1304                     if (i == 0) { /* invalid encoding */
1305                               dst[idst++] = '?';
1306                               isrc++;
1307                     } else if (i == 1) { /* check printable */
1308                               if (iscntrl((unsigned char)p[isrc])
1309                                && p[isrc] != '\t') {
1310                                         if (p[isrc] == '\n') {
1311                                                   dst[idst++] = ' ';
1312                                                   isrc++;
1313                                         } else {
1314                                                   dst[idst++] = '^';
1315                                                   dst[idst++] = p[isrc++] ^ 0100;
1316                                         }
1317                               } else
1318                                         dst[idst++] = p[isrc++];
1319                     } else {  /* convert UTF-8 to ASCII */
1320                               dst[idst++] = '<';
1321                               idst += snprintf(&dst[idst], dstsize - idst, "U+%x",
1322                                   get_utf8_value(&p[isrc]));
1323                               isrc += i;
1324                               dst[idst++] = '>';
1325                     }
1326           }
1327           dst[idst] = '\0';
1328 
1329           /* shrink buffer to right size */
1330           tmp_dst = realloc(dst, idst+1);
1331           if (tmp_dst)
1332                     return tmp_dst;
1333           else
1334                     return dst;
1335 }
1336 
1337 struct buf_msg *
printline_bsdsyslog(const char * hname,char * msg,int flags,int pri)1338 printline_bsdsyslog(const char *hname, char *msg,
1339           int flags, int pri)
1340 {
1341           struct buf_msg *buffer;
1342           char *p, *start;
1343           unsigned msgidlen = 0, sdlen = 0;
1344 
1345           DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_bsdsyslog("
1346                     "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
1347 
1348           buffer = buf_msg_new(0);
1349           p = msg;
1350           p += check_timestamp((unsigned char*) p,
1351                     &buffer->timestamp, false, !BSDOutputFormat);
1352           DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp);
1353 
1354           if (flags & ADDDATE || !buffer->timestamp) {
1355                     FREEPTR(buffer->timestamp);
1356                     buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
1357           }
1358 
1359           if (*p == ' ') p++; /* SP */
1360           else goto all_bsd_msg;
1361           /* in any error case we skip header parsing and
1362            * treat all following data as message content */
1363 
1364           /* extract host */
1365           for (start = p;; p++) {
1366                     if (*p == ' ' || *p == '\0') {
1367                               buffer->host = strndup(start, p - start);
1368                               break;
1369                     } else if (*p == '[' || (*p == ':'
1370                               && (*(p+1) == ' ' || *(p+1) == '\0'))) {
1371                               /* no host in message */
1372                               buffer->host = strdup(hname);
1373                               buffer->prog = strndup(start, p - start);
1374                               break;
1375                     } else {
1376                               *p = FORCE2ASCII(*p);
1377                     }
1378           }
1379           DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host);
1380           /* p @ SP after host, or @ :/[ after prog */
1381 
1382           /* extract program */
1383           if (!buffer->prog) {
1384                     if (*p == ' ') p++; /* SP */
1385                     else goto all_bsd_msg;
1386 
1387                     for (start = p;; p++) {
1388                               if (*p == ' ' || *p == '\0') { /* error */
1389                                         goto all_bsd_msg;
1390                               } else if (*p == '[' || (*p == ':'
1391                                         && (*(p+1) == ' ' || *(p+1) == '\0'))) {
1392                                         buffer->prog = strndup(start, p - start);
1393                                         break;
1394                               } else {
1395                                         *p = FORCE2ASCII(*p);
1396                               }
1397                     }
1398           }
1399           DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog);
1400           start = p;
1401 
1402           /* p @ :/[ after prog */
1403           if (*p == '[') {
1404                     p++;
1405                     if (*p == ' ') p++; /* SP */
1406                     for (start = p;; p++) {
1407                               if (*p == ' ' || *p == '\0') { /* error */
1408                                         goto all_bsd_msg;
1409                               } else if (*p == ']') {
1410                                         buffer->pid = strndup(start, p - start);
1411                                         break;
1412                               } else {
1413                                         *p = FORCE2ASCII(*p);
1414                               }
1415                     }
1416           }
1417           DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid);
1418 
1419           if (*p == ']') p++;
1420           if (*p == ':') p++;
1421           if (*p == ' ') p++;
1422 
1423           /* p @ msgid, @ opening [ of SD or @ first byte of message
1424            * accept either case and try to detect MSGID and SD fields
1425            *
1426            * only limitation: we do not accept UTF-8 data in
1427            * BSD Syslog messages -- so all SD values are ASCII-filtered
1428            *
1429            * I have found one scenario with 'unexpected' behaviour:
1430            * if there is only a SD intended, but a) it is short enough
1431            * to be a MSGID and b) the first word of the message can also
1432            * be parsed as an SD.
1433            * example:
1434            * "<35>Jul  6 12:39:08 tag[123]: [exampleSDID@0] - hello"
1435            * --> parsed as
1436            *     MSGID = "[exampleSDID@0]"
1437            *     SD    = "-"
1438            *     MSG   = "hello"
1439            */
1440           start = p;
1441           msgidlen = check_msgid(p);
1442           if (msgidlen) /* check for SD in 2nd field */
1443                     sdlen = check_sd(p+msgidlen+1);
1444 
1445           if (msgidlen && sdlen) {
1446                     /* MSGID in 1st and SD in 2nd field
1447                      * now check for NILVALUEs and copy */
1448                     if (msgidlen == 1 && *p == '-') {
1449                               p++; /* - */
1450                               p++; /* SP */
1451                               DPRINTF(D_DATA, "Got MSGID \"-\"\n");
1452                     } else {
1453                               /* only has ASCII chars after check_msgid() */
1454                               buffer->msgid = strndup(p, msgidlen);
1455                               p += msgidlen;
1456                               p++; /* SP */
1457                               DPRINTF(D_DATA, "Got MSGID \"%s\"\n",
1458                                         buffer->msgid);
1459                     }
1460           } else {
1461                     /* either no msgid or no SD in 2nd field
1462                      * --> check 1st field for SD */
1463                     DPRINTF(D_DATA, "No MSGID\n");
1464                     sdlen = check_sd(p);
1465           }
1466 
1467           if (sdlen == 0) {
1468                     DPRINTF(D_DATA, "No SD\n");
1469           } else if (sdlen > 1) {
1470                     buffer->sd = copy_utf8_ascii(p, sdlen);
1471                     DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
1472           } else if (sdlen == 1 && *p == '-') {
1473                     p++;
1474                     DPRINTF(D_DATA, "Got SD \"-\"\n");
1475           } else {
1476                     DPRINTF(D_DATA, "Error\n");
1477           }
1478 
1479           if (*p == ' ') p++;
1480           start = p;
1481           /* and now the message itself
1482            * note: do not reset start, because we might come here
1483            * by goto and want to have the incomplete field as part
1484            * of the msg
1485            */
1486 all_bsd_msg:
1487           if (*p != '\0') {
1488                     size_t msglen = strlen(p);
1489                     buffer->msg = copy_utf8_ascii(p, msglen);
1490                     buffer->msgorig = buffer->msg;
1491                     buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
1492           }
1493           DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
1494 
1495           buffer->recvhost = strdup(hname);
1496           buffer->pri = pri;
1497           buffer->flags = flags | BSDSYSLOG;
1498 
1499           return buffer;
1500 }
1501 
1502 struct buf_msg *
printline_kernelprintf(const char * hname,char * msg,int flags,int pri)1503 printline_kernelprintf(const char *hname, char *msg,
1504           int flags, int pri)
1505 {
1506           struct buf_msg *buffer;
1507           char *p;
1508           unsigned sdlen = 0;
1509 
1510           DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_kernelprintf("
1511                     "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri);
1512 
1513           buffer = buf_msg_new(0);
1514           buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
1515           buffer->pri = pri;
1516           buffer->flags = flags;
1517 
1518           /* assume there is no MSGID but there might be SD */
1519           p = msg;
1520           sdlen = check_sd(p);
1521 
1522           if (sdlen == 0) {
1523                     DPRINTF(D_DATA, "No SD\n");
1524           } else if (sdlen > 1) {
1525                     buffer->sd = copy_utf8_ascii(p, sdlen);
1526                     DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd);
1527           } else if (sdlen == 1 && *p == '-') {
1528                     p++;
1529                     DPRINTF(D_DATA, "Got SD \"-\"\n");
1530           } else {
1531                     DPRINTF(D_DATA, "Error\n");
1532           }
1533 
1534           if (*p == ' ') p++;
1535           if (*p != '\0') {
1536                     size_t msglen = strlen(p);
1537                     buffer->msg = copy_utf8_ascii(p, msglen);
1538                     buffer->msgorig = buffer->msg;
1539                     buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1;
1540           }
1541           DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg);
1542 
1543           return buffer;
1544 }
1545 
1546 /*
1547  * Take a raw input line, read priority and version, call the
1548  * right message parsing function, then call logmsg().
1549  */
1550 void
printline(const char * hname,char * msg,int flags)1551 printline(const char *hname, char *msg, int flags)
1552 {
1553           struct buf_msg *buffer;
1554           int pri;
1555           char *p, *q;
1556           long n;
1557           bool bsdsyslog = true;
1558 
1559           DPRINTF((D_CALL|D_BUFFER|D_DATA),
1560                     "printline(\"%s\", \"%s\", %d)\n", hname, msg, flags);
1561 
1562           /* test for special codes */
1563           pri = DEFUPRI;
1564           p = msg;
1565           if (*p == '<') {
1566                     errno = 0;
1567                     n = strtol(p + 1, &q, 10);
1568                     if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
1569                               p = q + 1;
1570                               pri = (int)n;
1571                               /* check for syslog-protocol version */
1572                               if (*p == '1' && p[1] == ' ') {
1573                                         p += 2;    /* skip version and space */
1574                                         bsdsyslog = false;
1575                               } else {
1576                                         bsdsyslog = true;
1577                               }
1578                     }
1579           }
1580           if (pri & ~(LOG_FACMASK|LOG_PRIMASK))
1581                     pri = DEFUPRI;
1582 
1583           /*
1584            * Don't (usually) allow users to log kernel messages.
1585            * NOTE: Since LOG_KERN == 0, this will also match
1586            *         messages with no facility specified.
1587            */
1588           if ((pri & LOG_FACMASK) == LOG_KERN && KernXlat)
1589                     pri = LOG_USER | LOG_PRI(pri);
1590 
1591           if (bsdsyslog) {
1592                     buffer = printline_bsdsyslog(hname, p, flags, pri);
1593           } else {
1594                     buffer = printline_syslogprotocol(hname, p, flags, pri);
1595           }
1596           logmsg(buffer);
1597           DELREF(buffer);
1598 }
1599 
1600 /*
1601  * Take a raw input line from /dev/klog, split and format similar to syslog().
1602  */
1603 void
printsys(char * msg)1604 printsys(char *msg)
1605 {
1606           int n, is_printf, pri, flags;
1607           char *p, *q;
1608           struct buf_msg *buffer;
1609 
1610           klog_linebufoff = 0;
1611           for (p = msg; *p != '\0'; ) {
1612                     bool bsdsyslog = true;
1613 
1614                     is_printf = 1;
1615                     flags = ISKERNEL | ADDDATE | BSDSYSLOG;
1616                     if (SyncKernel)
1617                               flags |= SYNC_FILE;
1618                     if (is_printf) /* kernel printf's come out on console */
1619                               flags |= IGN_CONS;
1620                     pri = DEFSPRI;
1621 
1622                     if (*p == '<') {
1623                               errno = 0;
1624                               n = (int)strtol(p + 1, &q, 10);
1625                               if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
1626                                         p = q + 1;
1627                                         is_printf = 0;
1628                                         pri = n;
1629                                         if (*p == '1') { /* syslog-protocol version */
1630                                                   p += 2;    /* skip version and space */
1631                                                   bsdsyslog = false;
1632                                         } else {
1633                                                   bsdsyslog = true;
1634                                         }
1635                               }
1636                     }
1637                     for (q = p; *q != '\0' && *q != '\n'; q++)
1638                               /* look for end of line; no further checks.
1639                                * trust the kernel to send ASCII only */;
1640                     if (*q != '\0')
1641                               *q++ = '\0';
1642                     else {
1643                               memcpy(linebuf, p, klog_linebufoff = q - p);
1644                               break;
1645                     }
1646 
1647                     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1648                               pri = DEFSPRI;
1649 
1650                     /* allow all kinds of input from kernel */
1651                     if (is_printf)
1652                               buffer = printline_kernelprintf(
1653                                   LocalFQDN, p, flags, pri);
1654                     else {
1655                               if (bsdsyslog)
1656                                         buffer = printline_bsdsyslog(
1657                                             LocalFQDN, p, flags, pri);
1658                               else
1659                                         buffer = printline_syslogprotocol(
1660                                             LocalFQDN, p, flags, pri);
1661                     }
1662 
1663                     /* set fields left open */
1664                     if (!buffer->prog)
1665                               buffer->prog = strdup(_PATH_UNIX);
1666                     if (!buffer->host)
1667                               buffer->host = LocalFQDN;
1668                     if (!buffer->recvhost)
1669                               buffer->recvhost = LocalFQDN;
1670 
1671                     logmsg(buffer);
1672                     DELREF(buffer);
1673                     p = q;
1674           }
1675 }
1676 
1677 /*
1678  * Check to see if `name' matches the provided specification, using the
1679  * specified strstr function.
1680  */
1681 int
matches_spec(const char * name,const char * spec,char * (* check)(const char *,const char *))1682 matches_spec(const char *name, const char *spec,
1683     char *(*check)(const char *, const char *))
1684 {
1685           const char *s;
1686           const char *cursor;
1687           char prev, next;
1688           size_t len;
1689 
1690           if (name[0] == '\0')
1691                     return 0;
1692 
1693           if (strchr(name, ',')) /* sanity */
1694                     return 0;
1695 
1696           len = strlen(name);
1697           cursor = spec;
1698           while ((s = (*check)(cursor, name)) != NULL) {
1699                     prev = s == spec ? ',' : *(s - 1);
1700                     cursor = s + len;
1701                     next = *cursor;
1702 
1703                     if (prev == ',' && (next == '\0' || next == ','))
1704                               return 1;
1705           }
1706 
1707           return 0;
1708 }
1709 
1710 /*
1711  * wrapper with old function signature,
1712  * keeps calling code shorter and hides buffer allocation
1713  */
1714 void
logmsg_async(int pri,const char * sd,const char * msg,int flags)1715 logmsg_async(int pri, const char *sd, const char *msg, int flags)
1716 {
1717           struct buf_msg *buffer;
1718           size_t msglen;
1719 
1720           DPRINTF((D_CALL|D_DATA), "logmsg_async(%d, \"%s\", \"%s\", %d)\n",
1721               pri, sd, msg, flags);
1722 
1723           if (msg) {
1724                     msglen = strlen(msg);
1725                     msglen++;           /* adds \0 */
1726                     buffer = buf_msg_new(msglen);
1727                     buffer->msglen = strlcpy(buffer->msg, msg, msglen) + 1;
1728           } else {
1729                     buffer = buf_msg_new(0);
1730           }
1731           if (sd) buffer->sd = strdup(sd);
1732           buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0);
1733           buffer->prog = appname;
1734           buffer->pid = include_pid;
1735           buffer->recvhost = buffer->host = LocalFQDN;
1736           buffer->pri = pri;
1737           buffer->flags = flags;
1738 
1739           logmsg(buffer);
1740           DELREF(buffer);
1741 }
1742 
1743 /* read timestamp in from_buf, convert into a timestamp in to_buf
1744  *
1745  * returns length of timestamp found in from_buf (= number of bytes consumed)
1746  */
1747 size_t
check_timestamp(unsigned char * from_buf,char ** to_buf,bool from_iso,bool to_iso)1748 check_timestamp(unsigned char *from_buf, char **to_buf,
1749           bool from_iso, bool to_iso)
1750 {
1751           unsigned char *q;
1752           int p;
1753           bool found_ts = false;
1754 
1755           DPRINTF((D_CALL|D_DATA), "check_timestamp(%p = \"%s\", from_iso=%d, "
1756               "to_iso=%d)\n", from_buf, from_buf, from_iso, to_iso);
1757 
1758           if (!from_buf) return 0;
1759           /*
1760            * Check to see if msg looks non-standard.
1761            * looks at every char because we do not have a msg length yet
1762            */
1763           /* detailed checking adapted from Albert Mietus' sl_timestamp.c */
1764           if (from_iso) {
1765                     if (from_buf[4] == '-' && from_buf[7] == '-'
1766                         && from_buf[10] == 'T' && from_buf[13] == ':'
1767                         && from_buf[16] == ':'
1768                         && isdigit(from_buf[0]) && isdigit(from_buf[1])
1769                         && isdigit(from_buf[2]) && isdigit(from_buf[3])  /* YYYY */
1770                         && isdigit(from_buf[5]) && isdigit(from_buf[6])
1771                         && isdigit(from_buf[8]) && isdigit(from_buf[9])  /* mm dd */
1772                         && isdigit(from_buf[11]) && isdigit(from_buf[12]) /* HH */
1773                         && isdigit(from_buf[14]) && isdigit(from_buf[15]) /* MM */
1774                         && isdigit(from_buf[17]) && isdigit(from_buf[18]) /* SS */
1775                         )  {
1776                               /* time-secfrac */
1777                               if (from_buf[19] == '.')
1778                                         for (p=20; isdigit(from_buf[p]); p++) /* NOP*/;
1779                               else
1780                                         p = 19;
1781                               /* time-offset */
1782                               if (from_buf[p] == 'Z'
1783                                || ((from_buf[p] == '+' || from_buf[p] == '-')
1784                                   && from_buf[p+3] == ':'
1785                                   && isdigit(from_buf[p+1]) && isdigit(from_buf[p+2])
1786                                   && isdigit(from_buf[p+4]) && isdigit(from_buf[p+5])
1787                                ))
1788                                         found_ts = true;
1789                     }
1790           } else {
1791                     if (from_buf[3] == ' ' && from_buf[6] == ' '
1792                         && from_buf[9] == ':' && from_buf[12] == ':'
1793                         && (from_buf[4] == ' ' || isdigit(from_buf[4]))
1794                         && isdigit(from_buf[5]) /* dd */
1795                         && isdigit(from_buf[7])  && isdigit(from_buf[8])   /* HH */
1796                         && isdigit(from_buf[10]) && isdigit(from_buf[11])  /* MM */
1797                         && isdigit(from_buf[13]) && isdigit(from_buf[14])  /* SS */
1798                         && isupper(from_buf[0]) && islower(from_buf[1]) /* month */
1799                         && islower(from_buf[2]))
1800                               found_ts = true;
1801           }
1802           if (!found_ts) {
1803                     if (from_buf[0] == '-' && from_buf[1] == ' ') {
1804                               /* NILVALUE */
1805                               if (to_iso) {
1806                                         /* with ISO = syslog-protocol output leave
1807                                          * it as is, because it is better to have
1808                                          * no timestamp than a wrong one.
1809                                          */
1810                                         *to_buf = strdup("-");
1811                               } else {
1812                                         /* with BSD Syslog the field is required
1813                                          * so replace it with current time
1814                                          */
1815                                         *to_buf = make_timestamp(NULL, false, 0);
1816                               }
1817                               return 2;
1818                     }
1819                     *to_buf = make_timestamp(NULL, false, 0);
1820                     return 0;
1821           }
1822 
1823           if (!from_iso && !to_iso) {
1824                     /* copy BSD timestamp */
1825                     DPRINTF(D_CALL, "check_timestamp(): copy BSD timestamp\n");
1826                     *to_buf = strndup((char *)from_buf, BSD_TIMESTAMPLEN);
1827                     return BSD_TIMESTAMPLEN;
1828           } else if (from_iso && to_iso) {
1829                     /* copy ISO timestamp */
1830                     DPRINTF(D_CALL, "check_timestamp(): copy ISO timestamp\n");
1831                     if (!(q = (unsigned char *) strchr((char *)from_buf, ' ')))
1832                               q = from_buf + strlen((char *)from_buf);
1833                     *to_buf = strndup((char *)from_buf, q - from_buf);
1834                     return q - from_buf;
1835           } else if (from_iso && !to_iso) {
1836                     /* convert ISO->BSD */
1837                     struct tm parsed;
1838                     time_t timeval;
1839                     char tsbuf[MAX_TIMESTAMPLEN];
1840                     int i = 0, j;
1841 
1842                     DPRINTF(D_CALL, "check_timestamp(): convert ISO->BSD\n");
1843                     for(i = 0; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
1844                         && from_buf[i] != '.' && from_buf[i] != ' '; i++)
1845                               tsbuf[i] = from_buf[i]; /* copy date & time */
1846                     j = i;
1847                     for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
1848                         && from_buf[i] != '+' && from_buf[i] != '-'
1849                         && from_buf[i] != 'Z' && from_buf[i] != ' '; i++)
1850                               ;                                /* skip fraction digits */
1851                     for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
1852                         && from_buf[i] != ':' && from_buf[i] != ' ' ; i++, j++)
1853                               tsbuf[j] = from_buf[i]; /* copy TZ */
1854                     if (from_buf[i] == ':') i++;  /* skip colon */
1855                     for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0'
1856                         && from_buf[i] != ' ' ; i++, j++)
1857                               tsbuf[j] = from_buf[i]; /* copy TZ */
1858 
1859                     (void)memset(&parsed, 0, sizeof(parsed));
1860                     (void)strptime(tsbuf, "%FT%T%z", &parsed);
1861                     parsed.tm_isdst = -1;
1862                     timeval = mktime(&parsed);
1863 
1864                     *to_buf = make_timestamp(&timeval, false, BSD_TIMESTAMPLEN);
1865                     return i;
1866           } else if (!from_iso && to_iso) {
1867                     /* convert BSD->ISO */
1868                     struct tm parsed;
1869                     struct tm *current;
1870                     time_t timeval;
1871 
1872                     (void)memset(&parsed, 0, sizeof(parsed));
1873                     parsed.tm_isdst = -1;
1874                     DPRINTF(D_CALL, "check_timestamp(): convert BSD->ISO\n");
1875                     strptime((char *)from_buf, "%b %d %T", &parsed);
1876                     current = gmtime(&now);
1877 
1878                     /* use current year and timezone */
1879                     parsed.tm_isdst = current->tm_isdst;
1880                     parsed.tm_gmtoff = current->tm_gmtoff;
1881                     parsed.tm_year = current->tm_year;
1882                     if (current->tm_mon == 0 && parsed.tm_mon == 11)
1883                               parsed.tm_year--;
1884 
1885                     timeval = mktime(&parsed);
1886                     *to_buf = make_timestamp(&timeval, true, MAX_TIMESTAMPLEN - 1);
1887 
1888                     return BSD_TIMESTAMPLEN;
1889           } else {
1890                     DPRINTF(D_MISC,
1891                               "Executing unreachable code in check_timestamp()\n");
1892                     return 0;
1893           }
1894 }
1895 
1896 /*
1897  * Log a message to the appropriate log files, users, etc. based on
1898  * the priority.
1899  */
1900 void
logmsg(struct buf_msg * buffer)1901 logmsg(struct buf_msg *buffer)
1902 {
1903           struct filed *f;
1904           int fac, omask, prilev;
1905 
1906           DPRINTF((D_CALL|D_BUFFER), "logmsg: buffer@%p, pri 0%o/%d, flags 0x%x,"
1907               " timestamp \"%s\", from \"%s\", sd \"%s\", msg \"%s\"\n",
1908               buffer, buffer->pri, buffer->pri, buffer->flags,
1909               buffer->timestamp, buffer->recvhost, buffer->sd, buffer->msg);
1910 
1911           omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
1912 
1913           /* sanity check */
1914           assert(buffer->refcount == 1);
1915           assert(buffer->msglen <= buffer->msgsize);
1916           assert(buffer->msgorig <= buffer->msg);
1917           assert((buffer->msg && buffer->msglen == strlen(buffer->msg)+1)
1918                 || (!buffer->msg && !buffer->msglen));
1919           if (!buffer->msg && !buffer->sd && !buffer->msgid)
1920                     DPRINTF(D_BUFFER, "Empty message?\n");
1921 
1922           /* extract facility and priority level */
1923           if (buffer->flags & MARK)
1924                     fac = LOG_NFACILITIES;
1925           else
1926                     fac = LOG_FAC(buffer->pri);
1927           prilev = LOG_PRI(buffer->pri);
1928 
1929           /* log the message to the particular outputs */
1930           if (!Initialized) {
1931                     f = &consfile;
1932                     f->f_file = open(ctty, O_WRONLY | O_NDELAY, 0);
1933 
1934                     if (f->f_file >= 0) {
1935                               DELREF(f->f_prevmsg);
1936                               f->f_prevmsg = NEWREF(buffer);
1937                               fprintlog(f, NEWREF(buffer), NULL);
1938                               DELREF(buffer);
1939                               (void)close(f->f_file);
1940                     }
1941                     (void)sigsetmask(omask);
1942                     return;
1943           }
1944 
1945           for (f = Files; f; f = f->f_next) {
1946                     char *h;  /* host to use for comparing */
1947 
1948                     /* skip messages that are incorrect priority */
1949                     if (!MATCH_PRI(f, fac, prilev)
1950                         || f->f_pmask[fac] == INTERNAL_NOPRI)
1951                               continue;
1952 
1953                     /* skip messages with the incorrect host name */
1954                     /* compare with host (which is supposedly more correct), */
1955                     /* but fallback to recvhost if host is NULL */
1956                     h = (buffer->host != NULL) ? buffer->host : buffer->recvhost;
1957                     if (f->f_host != NULL && h != NULL) {
1958                               char shost[MAXHOSTNAMELEN + 1];
1959 
1960                               if (BSDOutputFormat) {
1961                                         (void)strlcpy(shost, h, sizeof(shost));
1962                                         trim_anydomain(shost);
1963                                         h = shost;
1964                               }
1965                               switch (f->f_host[0]) {
1966                               case '+':
1967                                         if (! matches_spec(h, f->f_host + 1,
1968                                             strcasestr))
1969                                                   continue;
1970                                         break;
1971                               case '-':
1972                                         if (matches_spec(h, f->f_host + 1,
1973                                             strcasestr))
1974                                                   continue;
1975                                         break;
1976                               }
1977                     }
1978 
1979                     /* skip messages with the incorrect program name */
1980                     if (f->f_program != NULL && buffer->prog != NULL) {
1981                               switch (f->f_program[0]) {
1982                               case '+':
1983                                         if (!matches_spec(buffer->prog,
1984                                             f->f_program + 1, strstr))
1985                                                   continue;
1986                                         break;
1987                               case '-':
1988                                         if (matches_spec(buffer->prog,
1989                                             f->f_program + 1, strstr))
1990                                                   continue;
1991                                         break;
1992                               default:
1993                                         if (!matches_spec(buffer->prog,
1994                                             f->f_program, strstr))
1995                                                   continue;
1996                                         break;
1997                               }
1998                     }
1999 
2000                     if (f->f_type == F_CONSOLE && (buffer->flags & IGN_CONS))
2001                               continue;
2002 
2003                     /* don't output marks to recently written files */
2004                     if ((buffer->flags & MARK)
2005                      && (now - f->f_time) < MarkInterval / 2)
2006                               continue;
2007 
2008                     /*
2009                      * suppress duplicate lines to this file unless NoRepeat
2010                      */
2011 #define MSG_FIELD_EQ(x) ((!buffer->x && !f->f_prevmsg->x) ||          \
2012     (buffer->x && f->f_prevmsg->x && !strcmp(buffer->x, f->f_prevmsg->x)))
2013 
2014                     if ((buffer->flags & MARK) == 0 &&
2015                         f->f_prevmsg &&
2016                         buffer->msglen == f->f_prevmsg->msglen &&
2017                         !NoRepeat &&
2018                         MSG_FIELD_EQ(host) &&
2019                         MSG_FIELD_EQ(sd) &&
2020                         MSG_FIELD_EQ(msg)
2021                         ) {
2022                               f->f_prevcount++;
2023                               DPRINTF(D_DATA, "Msg repeated %d times, %ld sec of %d\n",
2024                                   f->f_prevcount, (long)(now - f->f_time),
2025                                   repeatinterval[f->f_repeatcount]);
2026                               /*
2027                                * If domark would have logged this by now,
2028                                * flush it now (so we don't hold isolated messages),
2029                                * but back off so we'll flush less often
2030                                * in the future.
2031                                */
2032                               if (now > REPEATTIME(f)) {
2033                                         fprintlog(f, NEWREF(buffer), NULL);
2034                                         DELREF(buffer);
2035                                         BACKOFF(f);
2036                               }
2037                     } else {
2038                               /* new line, save it */
2039                               if (f->f_prevcount)
2040                                         fprintlog(f, NULL, NULL);
2041                               f->f_repeatcount = 0;
2042                               DELREF(f->f_prevmsg);
2043                               f->f_prevmsg = NEWREF(buffer);
2044                               fprintlog(f, NEWREF(buffer), NULL);
2045                               DELREF(buffer);
2046                     }
2047           }
2048           (void)sigsetmask(omask);
2049 }
2050 
2051 /*
2052  * format one buffer into output format given by flag BSDOutputFormat
2053  * line is allocated and has to be free()d by caller
2054  * size_t pointers are optional, if not NULL then they will return
2055  *   different lengths used for formatting and output
2056  */
2057 #define OUT(x) ((x)?(x):"-")
2058 bool
format_buffer(struct buf_msg * buffer,char ** line,size_t * ptr_linelen,size_t * ptr_msglen,size_t * ptr_tlsprefixlen,size_t * ptr_prilen)2059 format_buffer(struct buf_msg *buffer, char **line, size_t *ptr_linelen,
2060           size_t *ptr_msglen, size_t *ptr_tlsprefixlen, size_t *ptr_prilen)
2061 {
2062 #define FPBUFSIZE 30
2063           static char ascii_empty[] = "";
2064           char fp_buf[FPBUFSIZE] = "\0";
2065           char *hostname, *shorthostname = NULL;
2066           char *ascii_sd = ascii_empty;
2067           char *ascii_msg = ascii_empty;
2068           size_t linelen, msglen, tlsprefixlen, prilen, j;
2069 
2070           DPRINTF(D_CALL, "format_buffer(%p)\n", buffer);
2071           if (!buffer) return false;
2072 
2073           /* All buffer fields are set with strdup(). To avoid problems
2074            * on memory exhaustion we allow them to be empty and replace
2075            * the essential fields with already allocated generic values.
2076            */
2077           if (!buffer->timestamp)
2078                     buffer->timestamp = timestamp;
2079           if (!buffer->host && !buffer->recvhost)
2080                     buffer->host = LocalFQDN;
2081 
2082           if (LogFacPri) {
2083                     const char *f_s = NULL, *p_s = NULL;
2084                     int fac = buffer->pri & LOG_FACMASK;
2085                     int pri = LOG_PRI(buffer->pri);
2086                     char f_n[5], p_n[5];
2087 
2088                     if (LogFacPri > 1) {
2089                               CODE *c;
2090 
2091                               for (c = facilitynames; c->c_name != NULL; c++) {
2092                                         if (c->c_val == fac) {
2093                                                   f_s = c->c_name;
2094                                                   break;
2095                                         }
2096                               }
2097                               for (c = prioritynames; c->c_name != NULL; c++) {
2098                                         if (c->c_val == pri) {
2099                                                   p_s = c->c_name;
2100                                                   break;
2101                                         }
2102                               }
2103                     }
2104                     if (f_s == NULL) {
2105                               snprintf(f_n, sizeof(f_n), "%d", LOG_FAC(fac));
2106                               f_s = f_n;
2107                     }
2108                     if (p_s == NULL) {
2109                               snprintf(p_n, sizeof(p_n), "%d", pri);
2110                               p_s = p_n;
2111                     }
2112                     snprintf(fp_buf, sizeof(fp_buf), "<%s.%s>", f_s, p_s);
2113           }
2114 
2115           /* hostname or FQDN */
2116           hostname = (buffer->host ? buffer->host : buffer->recvhost);
2117           if (BSDOutputFormat
2118            && (shorthostname = strdup(hostname))) {
2119                     /* if the previous BSD output format with "host [recvhost]:"
2120                      * gets implemented, this is the right place to distinguish
2121                      * between buffer->host and buffer->recvhost
2122                      */
2123                     trim_anydomain(shorthostname);
2124                     hostname = shorthostname;
2125           }
2126 
2127           /* new message formatting:
2128            * instead of using iov always assemble one complete TLS-ready line
2129            * with length and priority (depending on BSDOutputFormat either in
2130            * BSD Syslog or syslog-protocol format)
2131            *
2132            * additionally save the length of the prefixes,
2133            * so UDP destinations can skip the length prefix and
2134            * file/pipe/wall destinations can omit length and priority
2135            */
2136           /* first determine required space */
2137           if (BSDOutputFormat) {
2138                     /* only output ASCII chars */
2139                     if (buffer->sd)
2140                               ascii_sd = copy_utf8_ascii(buffer->sd,
2141                                         strlen(buffer->sd));
2142                     if (buffer->msg) {
2143                               if (IS_BOM(buffer->msg))
2144                                         ascii_msg = copy_utf8_ascii(buffer->msg,
2145                                                   buffer->msglen - 1);
2146                               else /* assume already converted at input */
2147                                         ascii_msg = buffer->msg;
2148                     }
2149                     msglen = snprintf(NULL, 0, "<%d>%s%.15s %s %s%s%s%s: %s%s%s",
2150                                    buffer->pri, fp_buf, buffer->timestamp,
2151                                    hostname, OUT(buffer->prog),
2152                                    buffer->pid ? "[" : "",
2153                                    buffer->pid ? buffer->pid : "",
2154                                    buffer->pid ? "]" : "", ascii_sd,
2155                                    (buffer->sd && buffer->msg ? " ": ""), ascii_msg);
2156           } else
2157                     msglen = snprintf(NULL, 0, "<%d>1 %s%s %s %s %s %s %s%s%s",
2158                                    buffer->pri, fp_buf, buffer->timestamp,
2159                                    hostname, OUT(buffer->prog), OUT(buffer->pid),
2160                                    OUT(buffer->msgid), OUT(buffer->sd),
2161                                    (buffer->msg ? " ": ""),
2162                                    (buffer->msg ? buffer->msg: ""));
2163           /* add space for length prefix */
2164           tlsprefixlen = 0;
2165           for (j = msglen; j; j /= 10)
2166                     tlsprefixlen++;
2167           /* one more for the space */
2168           tlsprefixlen++;
2169 
2170           prilen = snprintf(NULL, 0, "<%d>", buffer->pri);
2171           if (!BSDOutputFormat)
2172                     prilen += 2; /* version char and space */
2173           MALLOC(*line, msglen + tlsprefixlen + 1);
2174           if (BSDOutputFormat)
2175                     linelen = snprintf(*line,
2176                          msglen + tlsprefixlen + 1,
2177                          "%zu <%d>%s%.15s %s %s%s%s%s: %s%s%s",
2178                          msglen, buffer->pri, fp_buf, buffer->timestamp,
2179                          hostname, OUT(buffer->prog),
2180                          (buffer->pid ? "[" : ""),
2181                          (buffer->pid ? buffer->pid : ""),
2182                          (buffer->pid ? "]" : ""), ascii_sd,
2183                          (buffer->sd && buffer->msg ? " ": ""), ascii_msg);
2184           else
2185                     linelen = snprintf(*line,
2186                          msglen + tlsprefixlen + 1,
2187                          "%zu <%d>1 %s%s %s %s %s %s %s%s%s",
2188                          msglen, buffer->pri, fp_buf, buffer->timestamp,
2189                          hostname, OUT(buffer->prog), OUT(buffer->pid),
2190                          OUT(buffer->msgid), OUT(buffer->sd),
2191                          (buffer->msg ? " ": ""),
2192                          (buffer->msg ? buffer->msg: ""));
2193           DPRINTF(D_DATA, "formatted %zu octets to: '%.*s' (linelen %zu, "
2194               "msglen %zu, tlsprefixlen %zu, prilen %zu)\n", linelen,
2195               (int)linelen, *line, linelen, msglen, tlsprefixlen, prilen);
2196 
2197           FREEPTR(shorthostname);
2198           if (ascii_sd != ascii_empty)
2199                     FREEPTR(ascii_sd);
2200           if (ascii_msg != ascii_empty && ascii_msg != buffer->msg)
2201                     FREEPTR(ascii_msg);
2202 
2203           if (ptr_linelen)      *ptr_linelen      = linelen;
2204           if (ptr_msglen)           *ptr_msglen   = msglen;
2205           if (ptr_tlsprefixlen) *ptr_tlsprefixlen = tlsprefixlen;
2206           if (ptr_prilen)           *ptr_prilen   = prilen;
2207           return true;
2208 }
2209 
2210 /*
2211  * if qentry == NULL: new message, if temporarily undeliverable it will be enqueued
2212  * if qentry != NULL: a temporarily undeliverable message will not be enqueued,
2213  *                      but after delivery be removed from the queue
2214  */
2215 void
fprintlog(struct filed * f,struct buf_msg * passedbuffer,struct buf_queue * qentry)2216 fprintlog(struct filed *f, struct buf_msg *passedbuffer, struct buf_queue *qentry)
2217 {
2218           static char crnl[] = "\r\n";
2219           struct buf_msg *buffer = passedbuffer;
2220           struct iovec iov[4];
2221           struct iovec *v = iov;
2222           bool error = false;
2223           int e = 0, len = 0;
2224           size_t msglen, linelen, tlsprefixlen, prilen;
2225           char *p, *line = NULL, *lineptr = NULL;
2226 #ifndef DISABLE_SIGN
2227           bool newhash = false;
2228 #endif
2229 #define REPBUFSIZE 80
2230           char greetings[200];
2231 #define ADDEV() do { v++; assert((size_t)(v - iov) < A_CNT(iov)); } while(/*CONSTCOND*/0)
2232 
2233           DPRINTF(D_CALL, "fprintlog(%p, %p, %p)\n", f, buffer, qentry);
2234 
2235           f->f_time = now;
2236 
2237           /* increase refcount here and lower again at return.
2238            * this enables the buffer in the else branch to be freed
2239            * --> every branch needs one NEWREF() or buf_msg_new()! */
2240           if (buffer) {
2241                     (void)NEWREF(buffer);
2242           } else {
2243                     if (f->f_prevcount > 1) {
2244                               /* possible syslog-sign incompatibility:
2245                                * assume destinations f1 and f2 share one SG and
2246                                * get the same message sequence.
2247                                *
2248                                * now both f1 and f2 generate "repeated" messages
2249                                * "repeated" messages are different due to different
2250                                * timestamps
2251                                * the SG will get hashes for the two "repeated" messages
2252                                *
2253                                * now both f1 and f2 are just fine, but a verification
2254                                * will report that each 'lost' a message, i.e. the
2255                                * other's "repeated" message
2256                                *
2257                                * conditions for 'safe configurations':
2258                                * - use NoRepeat option,
2259                                * - use SG 3, or
2260                                * - have exactly one destination for every PRI
2261                                */
2262                               buffer = buf_msg_new(REPBUFSIZE);
2263                               buffer->msglen = snprintf(buffer->msg, REPBUFSIZE,
2264                                   "last message repeated %d times", f->f_prevcount);
2265                               buffer->timestamp = make_timestamp(NULL,
2266                                   !BSDOutputFormat, 0);
2267                               buffer->pri = f->f_prevmsg->pri;
2268                               buffer->host = LocalFQDN;
2269                               buffer->prog = appname;
2270                               buffer->pid = include_pid;
2271 
2272                     } else {
2273                               buffer = NEWREF(f->f_prevmsg);
2274                     }
2275           }
2276 
2277           /* no syslog-sign messages to tty/console/... */
2278           if ((buffer->flags & SIGN_MSG)
2279               && ((f->f_type == F_UNUSED)
2280               || (f->f_type == F_TTY)
2281               || (f->f_type == F_CONSOLE)
2282               || (f->f_type == F_USERS)
2283               || (f->f_type == F_WALL)
2284               || (f->f_type == F_FIFO))) {
2285                     DELREF(buffer);
2286                     return;
2287           }
2288 
2289           /* buffering works only for few types */
2290           if (qentry
2291               && (f->f_type != F_TLS)
2292               && (f->f_type != F_PIPE)
2293               && (f->f_type != F_FILE)
2294               && (f->f_type != F_FIFO)) {
2295                     errno = 0;
2296                     logerror("Warning: unexpected message type %d in buffer",
2297                         f->f_type);
2298                     DELREF(buffer);
2299                     return;
2300           }
2301 
2302           if (!format_buffer(buffer, &line,
2303               &linelen, &msglen, &tlsprefixlen, &prilen)) {
2304                     DPRINTF(D_CALL, "format_buffer() failed, skip message\n");
2305                     DELREF(buffer);
2306                     return;
2307           }
2308           /* assert maximum message length */
2309           if (TypeInfo[f->f_type].max_msg_length != -1
2310               && (size_t)TypeInfo[f->f_type].max_msg_length
2311               < linelen - tlsprefixlen - prilen) {
2312                     linelen = TypeInfo[f->f_type].max_msg_length
2313                         + tlsprefixlen + prilen;
2314                     DPRINTF(D_DATA, "truncating oversized message to %zu octets\n",
2315                         linelen);
2316           }
2317 
2318 #ifndef DISABLE_SIGN
2319           /* keep state between appending the hash (before buffer is sent)
2320            * and possibly sending a SB (after buffer is sent): */
2321           /* get hash */
2322           if (!(buffer->flags & SIGN_MSG) && !qentry) {
2323                     char *hash = NULL;
2324                     struct signature_group_t *sg;
2325 
2326                     if ((sg = sign_get_sg(buffer->pri, f)) != NULL) {
2327                               if (sign_msg_hash(line + tlsprefixlen, &hash))
2328                                         newhash = sign_append_hash(hash, sg);
2329                               else
2330                                         DPRINTF(D_SIGN,
2331                                                   "Unable to hash line \"%s\"\n", line);
2332                     }
2333           }
2334 #endif /* !DISABLE_SIGN */
2335 
2336           /* set start and length of buffer and/or fill iovec */
2337           switch (f->f_type) {
2338           case F_UNUSED:
2339                     /* nothing */
2340                     break;
2341           case F_TLS:
2342                     /* nothing, as TLS uses whole buffer to send */
2343                     lineptr = line;
2344                     len = linelen;
2345                     break;
2346           case F_FORW:
2347                     lineptr = line + tlsprefixlen;
2348                     len = linelen - tlsprefixlen;
2349                     break;
2350           case F_PIPE:
2351           case F_FIFO:
2352           case F_FILE:  /* fallthrough */
2353                     if (f->f_flags & FFLAG_FULL) {
2354                               v->iov_base = line + tlsprefixlen;
2355                               v->iov_len = linelen - tlsprefixlen;
2356                     } else {
2357                               v->iov_base = line + tlsprefixlen + prilen;
2358                               v->iov_len = linelen - tlsprefixlen - prilen;
2359                     }
2360                     ADDEV();
2361                     v->iov_base = &crnl[1];
2362                     v->iov_len = 1;
2363                     ADDEV();
2364                     break;
2365           case F_CONSOLE:
2366           case F_TTY:
2367                     /* filter non-ASCII */
2368                     p = line;
2369                     while (*p) {
2370                               *p = FORCE2ASCII(*p);
2371                               p++;
2372                     }
2373                     v->iov_base = line + tlsprefixlen + prilen;
2374                     v->iov_len = linelen - tlsprefixlen - prilen;
2375                     ADDEV();
2376                     v->iov_base = crnl;
2377                     v->iov_len = 2;
2378                     ADDEV();
2379                     break;
2380           case F_WALL:
2381                     v->iov_base = greetings;
2382                     v->iov_len = snprintf(greetings, sizeof(greetings),
2383                         "\r\n\7Message from syslogd@%s at %s ...\r\n",
2384                         (buffer->host ? buffer->host : buffer->recvhost),
2385                         buffer->timestamp);
2386                     ADDEV();
2387                     /* FALLTHROUGH */
2388           case F_USERS: /* fallthrough */
2389                     /* filter non-ASCII */
2390                     p = line;
2391                     while (*p) {
2392                               *p = FORCE2ASCII(*p);
2393                               p++;
2394                     }
2395                     v->iov_base = line + tlsprefixlen + prilen;
2396                     v->iov_len = linelen - tlsprefixlen - prilen;
2397                     ADDEV();
2398                     v->iov_base = &crnl[1];
2399                     v->iov_len = 1;
2400                     ADDEV();
2401                     break;
2402           }
2403 
2404           /* send */
2405           switch (f->f_type) {
2406           case F_UNUSED:
2407                     DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name);
2408                     break;
2409 
2410           case F_FORW:
2411                     DPRINTF(D_MISC, "Logging to %s %s\n",
2412                         TypeInfo[f->f_type].name, f->f_un.f_forw.f_hname);
2413                     udp_send(f, lineptr, len);
2414                     break;
2415 
2416 #ifndef DISABLE_TLS
2417           case F_TLS:
2418                     DPRINTF(D_MISC, "Logging to %s %s\n",
2419                         TypeInfo[f->f_type].name,
2420                         f->f_un.f_tls.tls_conn->hostname);
2421                     /* make sure every message gets queued once
2422                      * it will be removed when sendmsg is sent and free()d */
2423                     if (!qentry)
2424                               qentry = message_queue_add(f, NEWREF(buffer));
2425                     (void)tls_send(f, lineptr, len, qentry);
2426                     break;
2427 #endif /* !DISABLE_TLS */
2428 
2429           case F_PIPE:
2430                     DPRINTF(D_MISC, "Logging to %s %s\n",
2431                         TypeInfo[f->f_type].name, f->f_un.f_pipe.f_pname);
2432                     if (f->f_un.f_pipe.f_pid == 0) {
2433                               /* (re-)open */
2434                               if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
2435                                   &f->f_un.f_pipe.f_pid)) < 0) {
2436                                         f->f_type = F_UNUSED;
2437                                         logerror("%s", f->f_un.f_pipe.f_pname);
2438                                         message_queue_freeall(f);
2439                                         break;
2440                               } else if (!qentry) /* prevent recursion */
2441                                         SEND_QUEUE(f);
2442                     }
2443                     if (writev(f->f_file, iov, v - iov) < 0) {
2444                               e = errno;
2445                               if (f->f_un.f_pipe.f_pid > 0) {
2446                                         (void) close(f->f_file);
2447                                         deadq_enter(f->f_un.f_pipe.f_pid,
2448                                             f->f_un.f_pipe.f_pname);
2449                               }
2450                               f->f_un.f_pipe.f_pid = 0;
2451                               /*
2452                                * If the error was EPIPE, then what is likely
2453                                * has happened is we have a command that is
2454                                * designed to take a single message line and
2455                                * then exit, but we tried to feed it another
2456                                * one before we reaped the child and thus
2457                                * reset our state.
2458                                *
2459                                * Well, now we've reset our state, so try opening
2460                                * the pipe and sending the message again if EPIPE
2461                                * was the error.
2462                                */
2463                               if (e == EPIPE) {
2464                                         if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
2465                                              &f->f_un.f_pipe.f_pid)) < 0) {
2466                                                   f->f_type = F_UNUSED;
2467                                                   logerror("%s", f->f_un.f_pipe.f_pname);
2468                                                   message_queue_freeall(f);
2469                                                   break;
2470                                         }
2471                                         if (writev(f->f_file, iov, v - iov) < 0) {
2472                                                   e = errno;
2473                                                   if (f->f_un.f_pipe.f_pid > 0) {
2474                                                       (void) close(f->f_file);
2475                                                       deadq_enter(f->f_un.f_pipe.f_pid,
2476                                                             f->f_un.f_pipe.f_pname);
2477                                                   }
2478                                                   f->f_un.f_pipe.f_pid = 0;
2479                                                   error = true;       /* enqueue on return */
2480                                         } else
2481                                                   e = 0;
2482                               }
2483                               if (e != 0 && !error) {
2484                                         errno = e;
2485                                         logerror("%s", f->f_un.f_pipe.f_pname);
2486                               }
2487                     }
2488                     if (e == 0 && qentry) { /* sent buffered msg */
2489                               message_queue_remove(f, qentry);
2490                     }
2491                     break;
2492 
2493           case F_CONSOLE:
2494                     if (buffer->flags & IGN_CONS) {
2495                               DPRINTF(D_MISC, "Logging to %s (ignored)\n",
2496                                         TypeInfo[f->f_type].name);
2497                               break;
2498                     }
2499                     /* FALLTHROUGH */
2500 
2501           case F_TTY:
2502           case F_FILE:
2503                     DPRINTF(D_MISC, "Logging to %s %s\n",
2504                               TypeInfo[f->f_type].name, f->f_un.f_fname);
2505           again:
2506                     if ((f->f_type == F_FILE ? writev(f->f_file, iov, v - iov) :
2507                         writev1(f->f_file, iov, v - iov)) < 0) {
2508                               e = errno;
2509                               if (f->f_type == F_FILE && e == ENOSPC) {
2510                                         int lasterror = f->f_lasterror;
2511                                         f->f_lasterror = e;
2512                                         if (lasterror != e)
2513                                                   logerror("%s", f->f_un.f_fname);
2514                                         error = true;       /* enqueue on return */
2515                               }
2516                               (void)close(f->f_file);
2517                               /*
2518                                * Check for errors on TTY's due to loss of tty
2519                                */
2520                               if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
2521                                         f->f_file = open(f->f_un.f_fname,
2522                                             O_WRONLY|O_APPEND|O_NONBLOCK, 0);
2523                                         if (f->f_file < 0) {
2524                                                   f->f_type = F_UNUSED;
2525                                                   logerror("%s", f->f_un.f_fname);
2526                                                   message_queue_freeall(f);
2527                                         } else
2528                                                   goto again;
2529                               } else {
2530                                         f->f_type = F_UNUSED;
2531                                         errno = e;
2532                                         f->f_lasterror = e;
2533                                         logerror("%s", f->f_un.f_fname);
2534                                         message_queue_freeall(f);
2535                               }
2536                     } else {
2537                               f->f_lasterror = 0;
2538                               if ((buffer->flags & SYNC_FILE)
2539                                && (f->f_flags & FFLAG_SYNC))
2540                                         (void)fsync(f->f_file);
2541                               /* Problem with files: We cannot check beforehand if
2542                                * they would be writeable and call send_queue() first.
2543                                * So we call send_queue() after a successful write,
2544                                * which means the first message will be out of order.
2545                                */
2546                               if (!qentry) /* prevent recursion */
2547                                         SEND_QUEUE(f);
2548                               else if (qentry) /* sent buffered msg */
2549                                         message_queue_remove(f, qentry);
2550                     }
2551                     break;
2552 
2553           case F_FIFO:
2554                     DPRINTF(D_MISC, "Logging to %s %s\n",
2555                               TypeInfo[f->f_type].name, f->f_un.f_fname);
2556                     if (f->f_file < 0) {
2557                               f->f_file =
2558                                 open(f->f_un.f_fname, O_WRONLY|O_NONBLOCK, 0);
2559                               e = errno;
2560                               if (f->f_file < 0 && e == ENXIO) {
2561                                         /* Drop messages with no reader */
2562                                         if (qentry)
2563                                                   message_queue_remove(f, qentry);
2564                                         break;
2565                               }
2566                     }
2567 
2568                     if (f->f_file >= 0 && writev(f->f_file, iov, v - iov) < 0) {
2569                               e = errno;
2570 
2571                               /* Enqueue if the fifo buffer is full */
2572                               if (e == EAGAIN) {
2573                                         if (f->f_lasterror != e)
2574                                                   logerror("%s", f->f_un.f_fname);
2575                                         f->f_lasterror = e;
2576                                         error = true;       /* enqueue on return */
2577                                         break;
2578                               }
2579 
2580                               close(f->f_file);
2581                               f->f_file = -1;
2582 
2583                               /* Drop messages with no reader */
2584                               if (e == EPIPE) {
2585                                         if (qentry)
2586                                                   message_queue_remove(f, qentry);
2587                                         break;
2588                               }
2589                     }
2590 
2591                     if (f->f_file < 0) {
2592                               f->f_type = F_UNUSED;
2593                               errno = e;
2594                               f->f_lasterror = e;
2595                               logerror("%s", f->f_un.f_fname);
2596                               message_queue_freeall(f);
2597                               break;
2598                     }
2599 
2600                     f->f_lasterror = 0;
2601                     if (!qentry) /* prevent recursion (see comment for F_FILE) */
2602                               SEND_QUEUE(f);
2603                     if (qentry) /* sent buffered msg */
2604                               message_queue_remove(f, qentry);
2605                     break;
2606 
2607           case F_USERS:
2608           case F_WALL:
2609                     DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name);
2610                     wallmsg(f, iov, v - iov);
2611                     break;
2612           }
2613           f->f_prevcount = 0;
2614 
2615           if (error && !qentry)
2616                     message_queue_add(f, NEWREF(buffer));
2617 #ifndef DISABLE_SIGN
2618           if (newhash) {
2619                     struct signature_group_t *sg;
2620                     sg = sign_get_sg(buffer->pri, f);
2621                     (void)sign_send_signature_block(sg, false);
2622           }
2623 #endif /* !DISABLE_SIGN */
2624           /* this belongs to the ad-hoc buffer at the first if(buffer) */
2625           DELREF(buffer);
2626           /* TLS frees on its own */
2627           if (f->f_type != F_TLS)
2628                     FREEPTR(line);
2629 }
2630 
2631 /* send one line by UDP */
2632 void
udp_send(struct filed * f,char * line,size_t len)2633 udp_send(struct filed *f, char *line, size_t len)
2634 {
2635           int lsent, fail, retry, j;
2636           struct addrinfo *r;
2637 
2638           DPRINTF((D_NET|D_CALL), "udp_send(f=%p, line=\"%s\", "
2639               "len=%zu) to dest.\n", f, line, len);
2640 
2641           if (!finet)
2642                     return;
2643 
2644           lsent = -1;
2645           fail = 0;
2646           assert(f->f_type == F_FORW);
2647           for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
2648                     retry = 0;
2649                     for (j = 0; j < finet->fd; j++) {
2650                               if (finet[j+1].af != r->ai_family)
2651                                         continue;
2652 sendagain:
2653                               lsent = sendto(finet[j+1].fd, line, len, 0,
2654                                   r->ai_addr, r->ai_addrlen);
2655                               if (lsent == -1) {
2656                                         switch (errno) {
2657                                         case ENOBUFS:
2658                                                   /* wait/retry/drop */
2659                                                   if (++retry < 5) {
2660                                                             usleep(1000);
2661                                                             goto sendagain;
2662                                                   }
2663                                                   break;
2664                                         case EHOSTDOWN:
2665                                         case EHOSTUNREACH:
2666                                         case ENETDOWN:
2667                                                   /* drop */
2668                                                   break;
2669                                         default:
2670                                                   /* busted */
2671                                                   fail++;
2672                                                   break;
2673                                         }
2674                               } else if ((size_t)lsent == len)
2675                                         break;
2676                     }
2677                     if ((size_t)lsent != len && fail) {
2678                               f->f_type = F_UNUSED;
2679                               logerror("sendto() failed");
2680                     }
2681           }
2682 }
2683 
2684 /*
2685  *  WALLMSG -- Write a message to the world at large
2686  *
2687  *        Write the specified message to either the entire
2688  *        world, or a list of approved users.
2689  */
2690 void
wallmsg(struct filed * f,struct iovec * iov,size_t iovcnt)2691 wallmsg(struct filed *f, struct iovec *iov, size_t iovcnt)
2692 {
2693 #ifdef __NetBSD_Version__
2694           static int reenter;                     /* avoid calling ourselves */
2695           int i;
2696           char *p;
2697           struct utmpentry *ep;
2698 
2699           if (reenter++)
2700                     return;
2701 
2702           (void)getutentries(NULL, &ep);
2703           /* NOSTRICT */
2704           for (; ep; ep = ep->next) {
2705                     if (f->f_type == F_WALL) {
2706                               if ((p = ttymsg(iov, iovcnt, ep->line, TTYMSGTIME))
2707                                   != NULL) {
2708                                         errno = 0;          /* already in msg */
2709                                         logerror("%s", p);
2710                               }
2711                               continue;
2712                     }
2713                     /* should we send the message to this user? */
2714                     for (i = 0; i < MAXUNAMES; i++) {
2715                               if (!f->f_un.f_uname[i][0])
2716                                         break;
2717                               if (strcmp(f->f_un.f_uname[i], ep->name) == 0) {
2718                                         struct stat st;
2719                                         char tty[MAXPATHLEN];
2720                                         snprintf(tty, sizeof(tty), "%s/%s", _PATH_DEV,
2721                                             ep->line);
2722                                         if (stat(tty, &st) != -1 &&
2723                                             (st.st_mode & S_IWGRP) == 0)
2724                                                   break;
2725 
2726                                         if ((p = ttymsg(iov, iovcnt, ep->line,
2727                                             TTYMSGTIME)) != NULL) {
2728                                                   errno = 0;          /* already in msg */
2729                                                   logerror("%s", p);
2730                                         }
2731                                         break;
2732                               }
2733                     }
2734           }
2735           reenter = 0;
2736 #endif /* __NetBSD_Version__ */
2737 }
2738 
2739 void
2740 /*ARGSUSED*/
reapchild(int fd,short event,void * ev)2741 reapchild(int fd, short event, void *ev)
2742 {
2743           int status;
2744           pid_t pid;
2745           struct filed *f;
2746 
2747           while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
2748                     if (!Initialized || ShuttingDown) {
2749                               /*
2750                                * Be silent while we are initializing or
2751                                * shutting down.
2752                                */
2753                               continue;
2754                     }
2755 
2756                     if (deadq_remove(pid))
2757                               continue;
2758 
2759                     /* Now, look in the list of active processes. */
2760                     for (f = Files; f != NULL; f = f->f_next) {
2761                               if (f->f_type == F_PIPE &&
2762                                   f->f_un.f_pipe.f_pid == pid) {
2763                                         (void) close(f->f_file);
2764                                         f->f_un.f_pipe.f_pid = 0;
2765                                         log_deadchild(pid, status,
2766                                             f->f_un.f_pipe.f_pname);
2767                                         break;
2768                               }
2769                     }
2770           }
2771 }
2772 
2773 /*
2774  * Return a printable representation of a host address (FQDN if available)
2775  */
2776 const char *
cvthname(struct sockaddr_storage * f)2777 cvthname(struct sockaddr_storage *f)
2778 {
2779           int error;
2780           int niflag = NI_DGRAM;
2781           static char host[NI_MAXHOST], ip[NI_MAXHOST];
2782 
2783           error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
2784               ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag);
2785 
2786           DPRINTF(D_CALL, "cvthname(%s)\n", ip);
2787 
2788           if (error) {
2789                     DPRINTF(D_NET, "Malformed from address %s\n",
2790                         gai_strerror(error));
2791                     return "???";
2792           }
2793 
2794           if (!UseNameService)
2795                     return ip;
2796 
2797           error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
2798               host, sizeof host, NULL, 0, niflag);
2799           if (error) {
2800                     DPRINTF(D_NET, "Host name for your address (%s) unknown\n", ip);
2801                     return ip;
2802           }
2803 
2804           return host;
2805 }
2806 
2807 void
trim_anydomain(char * host)2808 trim_anydomain(char *host)
2809 {
2810           bool onlydigits = true;
2811           int i;
2812 
2813           if (!BSDOutputFormat)
2814                     return;
2815 
2816           /* if non-digits found, then assume hostname and cut at first dot (this
2817            * case also covers IPv6 addresses which should not contain dots),
2818            * if only digits then assume IPv4 address and do not cut at all */
2819           for (i = 0; host[i]; i++) {
2820                     if (host[i] == '.' && !onlydigits)
2821                               host[i] = '\0';
2822                     else if (!isdigit((unsigned char)host[i]) && host[i] != '.')
2823                               onlydigits = false;
2824           }
2825 }
2826 
2827 static void
2828 /*ARGSUSED*/
domark(int fd,short event,void * ev)2829 domark(int fd, short event, void *ev)
2830 {
2831           struct event *ev_pass = (struct event *)ev;
2832           struct filed *f;
2833           dq_t q, nextq;
2834           sigset_t newmask, omask;
2835 
2836           schedule_event(&ev_pass,
2837                     &((struct timeval){TIMERINTVL, 0}),
2838                     domark, ev_pass);
2839           DPRINTF((D_CALL|D_EVENT), "domark()\n");
2840 
2841           BLOCK_SIGNALS(omask, newmask);
2842           now = time(NULL);
2843           MarkSeq += TIMERINTVL;
2844           if (MarkSeq >= MarkInterval) {
2845                     logmsg_async(LOG_INFO, NULL, "-- MARK --", ADDDATE|MARK);
2846                     MarkSeq = 0;
2847           }
2848 
2849           for (f = Files; f; f = f->f_next) {
2850                     if (f->f_prevcount && now >= REPEATTIME(f)) {
2851                               DPRINTF(D_DATA, "Flush %s: repeated %d times, %d sec.\n",
2852                                   TypeInfo[f->f_type].name, f->f_prevcount,
2853                                   repeatinterval[f->f_repeatcount]);
2854                               fprintlog(f, NULL, NULL);
2855                               BACKOFF(f);
2856                     }
2857           }
2858           message_allqueues_check();
2859           RESTORE_SIGNALS(omask);
2860 
2861           /* Walk the dead queue, and see if we should signal somebody. */
2862           for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = nextq) {
2863                     nextq = TAILQ_NEXT(q, dq_entries);
2864                     switch (q->dq_timeout) {
2865                     case 0:
2866                               /* Already signalled once, try harder now. */
2867                               if (kill(q->dq_pid, SIGKILL) != 0)
2868                                         (void) deadq_remove(q->dq_pid);
2869                               break;
2870 
2871                     case 1:
2872                               /*
2873                                * Timed out on the dead queue, send terminate
2874                                * signal.  Note that we leave the removal from
2875                                * the dead queue to reapchild(), which will
2876                                * also log the event (unless the process
2877                                * didn't even really exist, in case we simply
2878                                * drop it from the dead queue).
2879                                */
2880                               if (kill(q->dq_pid, SIGTERM) != 0) {
2881                                         (void) deadq_remove(q->dq_pid);
2882                                         break;
2883                               }
2884                               /* FALLTHROUGH */
2885 
2886                     default:
2887                               q->dq_timeout--;
2888                     }
2889           }
2890 #ifndef DISABLE_SIGN
2891           if (GlobalSign.rsid) {        /* check if initialized */
2892                     struct signature_group_t *sg;
2893                     STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) {
2894                               sign_send_certificate_block(sg);
2895                     }
2896           }
2897 #endif /* !DISABLE_SIGN */
2898 }
2899 
2900 /*
2901  * Print syslogd errors some place.
2902  */
2903 void
logerror(const char * fmt,...)2904 logerror(const char *fmt, ...)
2905 {
2906           static int logerror_running;
2907           va_list ap;
2908           char tmpbuf[BUFSIZ];
2909           char buf[BUFSIZ];
2910           char *outbuf;
2911 
2912           /* If there's an error while trying to log an error, give up. */
2913           if (logerror_running)
2914                     return;
2915           logerror_running = 1;
2916 
2917           va_start(ap, fmt);
2918           (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
2919           va_end(ap);
2920 
2921           if (errno) {
2922                     (void)snprintf(buf, sizeof(buf), "%s: %s",
2923                         tmpbuf, strerror(errno));
2924                     outbuf = buf;
2925           } else {
2926                     (void)snprintf(buf, sizeof(buf), "%s", tmpbuf);
2927                     outbuf = tmpbuf;
2928           }
2929 
2930           if (daemonized)
2931                     logmsg_async(LOG_SYSLOG|LOG_ERR, NULL, outbuf, ADDDATE);
2932           if (!daemonized && Debug)
2933                     DPRINTF(D_MISC, "%s\n", outbuf);
2934           if (!daemonized && !Debug)
2935                     printf("%s: %s\n", getprogname(), outbuf);
2936 
2937           logerror_running = 0;
2938 }
2939 
2940 /*
2941  * Print syslogd info some place.
2942  */
2943 void
loginfo(const char * fmt,...)2944 loginfo(const char *fmt, ...)
2945 {
2946           va_list ap;
2947           char buf[BUFSIZ];
2948 
2949           va_start(ap, fmt);
2950           (void)vsnprintf(buf, sizeof(buf), fmt, ap);
2951           va_end(ap);
2952 
2953           DPRINTF(D_MISC, "%s\n", buf);
2954           logmsg_async(LOG_SYSLOG|LOG_INFO, NULL, buf, ADDDATE);
2955 }
2956 
2957 #ifndef DISABLE_TLS
2958 static inline void
free_incoming_tls_sockets(void)2959 free_incoming_tls_sockets(void)
2960 {
2961           struct TLS_Incoming_Conn *tls_in;
2962           int i;
2963 
2964           /*
2965            * close all listening and connected TLS sockets
2966            */
2967           if (TLS_Listen_Set)
2968                     for (i = 0; i < TLS_Listen_Set->fd; i++) {
2969                               if (close(TLS_Listen_Set[i+1].fd) == -1)
2970                                         logerror("close() failed");
2971                               DEL_EVENT(TLS_Listen_Set[i+1].ev);
2972                               FREEPTR(TLS_Listen_Set[i+1].ev);
2973                     }
2974           FREEPTR(TLS_Listen_Set);
2975           /* close/free incoming TLS connections */
2976           while (!SLIST_EMPTY(&TLS_Incoming_Head)) {
2977                     tls_in = SLIST_FIRST(&TLS_Incoming_Head);
2978                     SLIST_REMOVE_HEAD(&TLS_Incoming_Head, entries);
2979                     FREEPTR(tls_in->inbuf);
2980                     free_tls_conn(tls_in->tls_conn);
2981                     free(tls_in);
2982           }
2983 }
2984 #endif /* !DISABLE_TLS */
2985 
2986 void
2987 /*ARGSUSED*/
die(int fd,short event,void * ev)2988 die(int fd, short event, void *ev)
2989 {
2990           struct filed *f, *next;
2991           char **p;
2992           sigset_t newmask, omask;
2993           int i;
2994           size_t j;
2995 
2996           ShuttingDown = 1;   /* Don't log SIGCHLDs. */
2997           /* prevent recursive signals */
2998           BLOCK_SIGNALS(omask, newmask);
2999 
3000           errno = 0;
3001           if (ev != NULL)
3002                     logerror("Exiting on signal %d", fd);
3003           else
3004                     logerror("Fatal error, exiting");
3005 
3006           /*
3007            *  flush any pending output
3008            */
3009           for (f = Files; f != NULL; f = f->f_next) {
3010                     /* flush any pending output */
3011                     if (f->f_prevcount)
3012                               fprintlog(f, NULL, NULL);
3013                     SEND_QUEUE(f);
3014           }
3015 
3016 #ifndef DISABLE_TLS
3017           free_incoming_tls_sockets();
3018 #endif /* !DISABLE_TLS */
3019 #ifndef DISABLE_SIGN
3020           sign_global_free();
3021 #endif /* !DISABLE_SIGN */
3022 
3023           /*
3024            *  Close all open log files.
3025            */
3026           for (f = Files; f != NULL; f = next) {
3027                     message_queue_freeall(f);
3028 
3029                     switch (f->f_type) {
3030                     case F_FILE:
3031                     case F_TTY:
3032                     case F_CONSOLE:
3033                     case F_FIFO:
3034                               if (f->f_file >= 0)
3035                                         (void)close(f->f_file);
3036                               break;
3037                     case F_PIPE:
3038                               if (f->f_un.f_pipe.f_pid > 0) {
3039                                         (void)close(f->f_file);
3040                               }
3041                               f->f_un.f_pipe.f_pid = 0;
3042                               break;
3043                     case F_FORW:
3044                               if (f->f_un.f_forw.f_addr)
3045                                         freeaddrinfo(f->f_un.f_forw.f_addr);
3046                               break;
3047 #ifndef DISABLE_TLS
3048                     case F_TLS:
3049                               free_tls_conn(f->f_un.f_tls.tls_conn);
3050                               break;
3051 #endif /* !DISABLE_TLS */
3052                     }
3053                     next = f->f_next;
3054                     DELREF(f->f_prevmsg);
3055                     FREEPTR(f->f_program);
3056                     FREEPTR(f->f_host);
3057                     DEL_EVENT(f->f_sq_event);
3058                     free((char *)f);
3059           }
3060 
3061           /*
3062            *  Close all open UDP sockets
3063            */
3064           if (finet) {
3065                     for (i = 0; i < finet->fd; i++) {
3066                               (void)close(finet[i+1].fd);
3067                               DEL_EVENT(finet[i+1].ev);
3068                               FREEPTR(finet[i+1].ev);
3069                     }
3070                     FREEPTR(finet);
3071           }
3072 
3073           /* free config options */
3074           for (j = 0; j < A_CNT(TypeInfo); j++) {
3075                     FREEPTR(TypeInfo[j].queue_length_string);
3076                     FREEPTR(TypeInfo[j].queue_size_string);
3077           }
3078 
3079 #ifndef DISABLE_TLS
3080           FREEPTR(tls_opt.CAdir);
3081           FREEPTR(tls_opt.CAfile);
3082           FREEPTR(tls_opt.keyfile);
3083           FREEPTR(tls_opt.certfile);
3084           FREEPTR(tls_opt.x509verify);
3085           FREEPTR(tls_opt.bindhost);
3086           FREEPTR(tls_opt.bindport);
3087           FREEPTR(tls_opt.server);
3088           FREEPTR(tls_opt.gen_cert);
3089           free_cred_SLIST(&tls_opt.cert_head);
3090           free_cred_SLIST(&tls_opt.fprint_head);
3091           FREE_SSL_CTX(tls_opt.global_TLS_CTX);
3092 #endif /* !DISABLE_TLS */
3093 
3094           FREEPTR(funix);
3095           for (p = LogPaths; p && *p; p++)
3096                     unlink(*p);
3097           exit(0);
3098 }
3099 
3100 #ifndef DISABLE_SIGN
3101 /*
3102  * get one "sign_delim_sg2" item, convert and store in ordered queue
3103  */
3104 void
store_sign_delim_sg2(char * tmp_buf)3105 store_sign_delim_sg2(char *tmp_buf)
3106 {
3107           struct string_queue *sqentry, *sqe1, *sqe2;
3108 
3109           if(!(sqentry = malloc(sizeof(*sqentry)))) {
3110                     logerror("Unable to allocate memory");
3111                     return;
3112           }
3113           /*LINTED constcond/null effect */
3114           assert(sizeof(int64_t) == sizeof(uint_fast64_t));
3115           if (dehumanize_number(tmp_buf, (int64_t*) &(sqentry->key)) == -1
3116               || sqentry->key > (LOG_NFACILITIES<<3)) {
3117                     DPRINTF(D_PARSE, "invalid sign_delim_sg2: %s\n", tmp_buf);
3118                     free(sqentry);
3119                     FREEPTR(tmp_buf);
3120                     return;
3121           }
3122           sqentry->data = tmp_buf;
3123 
3124           if (STAILQ_EMPTY(&GlobalSign.sig2_delims)) {
3125                     STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims,
3126                         sqentry, entries);
3127                     return;
3128           }
3129 
3130           /* keep delimiters sorted */
3131           sqe1 = sqe2 = STAILQ_FIRST(&GlobalSign.sig2_delims);
3132           if (sqe1->key > sqentry->key) {
3133                     STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims,
3134                         sqentry, entries);
3135                     return;
3136           }
3137 
3138           while ((sqe1 = sqe2)
3139              && (sqe2 = STAILQ_NEXT(sqe1, entries))) {
3140                     if (sqe2->key > sqentry->key) {
3141                               break;
3142                     } else if (sqe2->key == sqentry->key) {
3143                               DPRINTF(D_PARSE, "duplicate sign_delim_sg2: %s\n",
3144                                   tmp_buf);
3145                               FREEPTR(sqentry);
3146                               FREEPTR(tmp_buf);
3147                               return;
3148                     }
3149           }
3150           STAILQ_INSERT_AFTER(&GlobalSign.sig2_delims, sqe1, sqentry, entries);
3151 }
3152 #endif /* !DISABLE_SIGN */
3153 
3154 /*
3155  * read syslog.conf
3156  */
3157 void
read_config_file(FILE * cf,struct filed ** f_ptr)3158 read_config_file(FILE *cf, struct filed **f_ptr)
3159 {
3160           size_t linenum = 0;
3161           size_t i;
3162           struct filed *f, **nextp;
3163           char cline[LINE_MAX];
3164           char prog[NAME_MAX + 1];
3165           char host[MAXHOSTNAMELEN];
3166           const char *p;
3167           char *q;
3168           bool found_keyword;
3169 #ifndef DISABLE_TLS
3170           struct peer_cred *cred = NULL;
3171           struct peer_cred_head *credhead = NULL;
3172 #endif /* !DISABLE_TLS */
3173 #ifndef DISABLE_SIGN
3174           char *sign_sg_str = NULL;
3175 #endif /* !DISABLE_SIGN */
3176 #if (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN))
3177           char *tmp_buf = NULL;
3178 #endif /* (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN)) */
3179           /* central list of recognized configuration keywords
3180            * and an address for their values as strings */
3181           const struct config_keywords {
3182                     const char *keyword;
3183                     char **variable;
3184           } config_keywords[] = {
3185 #ifndef DISABLE_TLS
3186                     /* TLS settings */
3187                     {"tls_ca",                      &tls_opt.CAfile},
3188                     {"tls_cadir",                   &tls_opt.CAdir},
3189                     {"tls_cert",                    &tls_opt.certfile},
3190                     {"tls_key",                     &tls_opt.keyfile},
3191                     {"tls_verify",                  &tls_opt.x509verify},
3192                     {"tls_bindport",      &tls_opt.bindport},
3193                     {"tls_bindhost",      &tls_opt.bindhost},
3194                     {"tls_server",                  &tls_opt.server},
3195                     {"tls_gen_cert",      &tls_opt.gen_cert},
3196                     /* special cases in parsing */
3197                     {"tls_allow_fingerprints",&tmp_buf},
3198                     {"tls_allow_clientcerts", &tmp_buf},
3199                     /* buffer settings */
3200                     {"tls_queue_length",            &TypeInfo[F_TLS].queue_length_string},
3201                     {"tls_queue_size",    &TypeInfo[F_TLS].queue_size_string},
3202 #endif /* !DISABLE_TLS */
3203                     {"file_queue_length",           &TypeInfo[F_FILE].queue_length_string},
3204                     {"pipe_queue_length",           &TypeInfo[F_PIPE].queue_length_string},
3205                     {"fifo_queue_length",           &TypeInfo[F_FIFO].queue_length_string},
3206                     {"file_queue_size",   &TypeInfo[F_FILE].queue_size_string},
3207                     {"pipe_queue_size",   &TypeInfo[F_PIPE].queue_size_string},
3208                     {"fifo_queue_size",   &TypeInfo[F_FIFO].queue_size_string},
3209 #ifndef DISABLE_SIGN
3210                     /* syslog-sign setting */
3211                     {"sign_sg",                     &sign_sg_str},
3212                     /* also special case in parsing */
3213                     {"sign_delim_sg2",    &tmp_buf},
3214 #endif /* !DISABLE_SIGN */
3215           };
3216 
3217           DPRINTF(D_CALL, "read_config_file()\n");
3218 
3219           /* free all previous config options */
3220           for (i = 0; i < A_CNT(TypeInfo); i++) {
3221                     if (TypeInfo[i].queue_length_string
3222                         && TypeInfo[i].queue_length_string
3223                         != TypeInfo[i].default_length_string) {
3224                               FREEPTR(TypeInfo[i].queue_length_string);
3225                               TypeInfo[i].queue_length_string =
3226                                         strdup(TypeInfo[i].default_length_string);
3227                      }
3228                     if (TypeInfo[i].queue_size_string
3229                         && TypeInfo[i].queue_size_string
3230                         != TypeInfo[i].default_size_string) {
3231                               FREEPTR(TypeInfo[i].queue_size_string);
3232                               TypeInfo[i].queue_size_string =
3233                                         strdup(TypeInfo[i].default_size_string);
3234                      }
3235           }
3236           for (i = 0; i < A_CNT(config_keywords); i++)
3237                     FREEPTR(*config_keywords[i].variable);
3238           /*
3239            * global settings
3240            */
3241           while (fgets(cline, sizeof(cline), cf) != NULL) {
3242                     linenum++;
3243                     for (p = cline; isspace((unsigned char)*p); ++p)
3244                               continue;
3245                     if ((*p == '\0') || (*p == '#'))
3246                               continue;
3247 
3248                     for (i = 0; i < A_CNT(config_keywords); i++) {
3249                               if (copy_config_value(config_keywords[i].keyword,
3250                                   config_keywords[i].variable, &p, ConfFile,
3251                                   linenum)) {
3252                                         DPRINTF((D_PARSE|D_MEM),
3253                                             "found option %s, saved @%p\n",
3254                                             config_keywords[i].keyword,
3255                                             *config_keywords[i].variable);
3256 #ifndef DISABLE_SIGN
3257                                         if (!strcmp("sign_delim_sg2",
3258                                             config_keywords[i].keyword))
3259                                                   do {
3260                                                             store_sign_delim_sg2(tmp_buf);
3261                                                   } while (copy_config_value_word(
3262                                                       &tmp_buf, &p));
3263 
3264 #endif /* !DISABLE_SIGN */
3265 
3266 #ifndef DISABLE_TLS
3267                                         /* special cases with multiple parameters */
3268                                         if (!strcmp("tls_allow_fingerprints",
3269                                             config_keywords[i].keyword))
3270                                                   credhead = &tls_opt.fprint_head;
3271                                         else if (!strcmp("tls_allow_clientcerts",
3272                                             config_keywords[i].keyword))
3273                                                   credhead = &tls_opt.cert_head;
3274 
3275                                         if (credhead) do {
3276                                                   if(!(cred = malloc(sizeof(*cred)))) {
3277                                                             logerror("Unable to "
3278                                                                       "allocate memory");
3279                                                             break;
3280                                                   }
3281                                                   cred->data = tmp_buf;
3282                                                   tmp_buf = NULL;
3283                                                   SLIST_INSERT_HEAD(credhead,
3284                                                             cred, entries);
3285                                         } while /* additional values? */
3286                                                   (copy_config_value_word(&tmp_buf, &p));
3287                                         credhead = NULL;
3288                                         break;
3289 #endif /* !DISABLE_TLS */
3290                               }
3291                     }
3292           }
3293           /* convert strings to integer values */
3294           for (i = 0; i < A_CNT(TypeInfo); i++) {
3295                     if (!TypeInfo[i].queue_length_string
3296                         || dehumanize_number(TypeInfo[i].queue_length_string,
3297                         &TypeInfo[i].queue_length) == -1)
3298                               if (dehumanize_number(TypeInfo[i].default_length_string,
3299                                   &TypeInfo[i].queue_length) == -1)
3300                                         abort();
3301                     if (!TypeInfo[i].queue_size_string
3302                         || dehumanize_number(TypeInfo[i].queue_size_string,
3303                         &TypeInfo[i].queue_size) == -1)
3304                               if (dehumanize_number(TypeInfo[i].default_size_string,
3305                                   &TypeInfo[i].queue_size) == -1)
3306                                         abort();
3307           }
3308 
3309 #ifndef DISABLE_SIGN
3310           if (sign_sg_str) {
3311                     if (sign_sg_str[1] == '\0'
3312                         && (sign_sg_str[0] == '0' || sign_sg_str[0] == '1'
3313                         || sign_sg_str[0] == '2' || sign_sg_str[0] == '3'))
3314                               GlobalSign.sg = sign_sg_str[0] - '0';
3315                     else {
3316                               GlobalSign.sg = SIGN_SG;
3317                               DPRINTF(D_MISC, "Invalid sign_sg value `%s', "
3318                                   "use default value `%d'\n",
3319                                   sign_sg_str, GlobalSign.sg);
3320                     }
3321           } else    /* disable syslog-sign */
3322                     GlobalSign.sg = -1;
3323 #endif /* !DISABLE_SIGN */
3324 
3325           rewind(cf);
3326           linenum = 0;
3327           /*
3328            *  Foreach line in the conf table, open that file.
3329            */
3330           f = NULL;
3331           nextp = &f;
3332 
3333           strcpy(prog, "*");
3334           strcpy(host, "*");
3335           while (fgets(cline, sizeof(cline), cf) != NULL) {
3336                     linenum++;
3337                     found_keyword = false;
3338                     /*
3339                      * check for end-of-section, comments, strip off trailing
3340                      * spaces and newline character.  #!prog is treated specially:
3341                      * following lines apply only to that program.
3342                      */
3343                     for (p = cline; isspace((unsigned char)*p); ++p)
3344                               continue;
3345                     if (*p == '\0')
3346                               continue;
3347                     if (*p == '#') {
3348                               p++;
3349                               if (*p != '!' && *p != '+' && *p != '-')
3350                                         continue;
3351                     }
3352 
3353                     for (i = 0; i < A_CNT(config_keywords); i++) {
3354                               if (!strncasecmp(p, config_keywords[i].keyword,
3355                                         strlen(config_keywords[i].keyword))) {
3356                                         DPRINTF(D_PARSE,
3357                                             "skip cline %zu with keyword %s\n",
3358                                             linenum, config_keywords[i].keyword);
3359                                         found_keyword = true;
3360                               }
3361                     }
3362                     if (found_keyword)
3363                               continue;
3364 
3365                     if (*p == '+' || *p == '-') {
3366                               host[0] = *p++;
3367                               while (isspace((unsigned char)*p))
3368                                         p++;
3369                               if (*p == '\0' || *p == '*') {
3370                                         strcpy(host, "*");
3371                                         continue;
3372                               }
3373                               /* the +hostname expression will continue
3374                                * to use the LocalHostName, not the FQDN */
3375                               for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
3376                                         if (*p == '@') {
3377                                                   (void)strncpy(&host[i], LocalHostName,
3378                                                       sizeof(host) - 1 - i);
3379                                                   host[sizeof(host) - 1] = '\0';
3380                                                   i = strlen(host) - 1;
3381                                                   p++;
3382                                                   continue;
3383                                         }
3384                                         if (!isalnum((unsigned char)*p) &&
3385                                             *p != '.' && *p != '-' && *p != ',')
3386                                                   break;
3387                                         host[i] = *p++;
3388                               }
3389                               host[i] = '\0';
3390                               continue;
3391                     }
3392                     if (*p == '!') {
3393                               p++;
3394                               while (isspace((unsigned char)*p))
3395                                         p++;
3396                               if (*p == '\0' || *p == '*') {
3397                                         strcpy(prog, "*");
3398                                         continue;
3399                               }
3400                               for (i = 0; i < NAME_MAX; i++) {
3401                                         if (!isprint((unsigned char)p[i]))
3402                                                   break;
3403                                         prog[i] = p[i];
3404                               }
3405                               prog[i] = '\0';
3406                               continue;
3407                     }
3408                     for (q = strchr(cline, '\0'); isspace((unsigned char)*--q);)
3409                               continue;
3410                     *++q = '\0';
3411                     if ((f = calloc(1, sizeof(*f))) == NULL) {
3412                               logerror("alloc failed");
3413                               die(0, 0, NULL);
3414                     }
3415                     if (!*f_ptr) *f_ptr = f; /* return first node */
3416                     *nextp = f;
3417                     nextp = &f->f_next;
3418                     cfline(linenum, cline, f, prog, host);
3419           }
3420 }
3421 
3422 /*
3423  *  INIT -- Initialize syslogd from configuration table
3424  */
3425 void
3426 /*ARGSUSED*/
init(int fd,short event,void * ev)3427 init(int fd, short event, void *ev)
3428 {
3429           FILE *cf;
3430           int i;
3431           struct filed *f, *newf, **nextp, *f2;
3432           char *p;
3433           sigset_t newmask, omask;
3434 #ifndef DISABLE_TLS
3435           char *tls_status_msg = NULL;
3436           struct peer_cred *cred = NULL;
3437 #endif /* !DISABLE_TLS */
3438 
3439           /* prevent recursive signals */
3440           BLOCK_SIGNALS(omask, newmask);
3441 
3442           DPRINTF((D_EVENT|D_CALL), "init\n");
3443 
3444           /*
3445            * be careful about dependencies and order of actions:
3446            * 1. flush buffer queues
3447            * 2. flush -sign SBs
3448            * 3. flush/delete buffer queue again, in case an SB got there
3449            * 4. close files/connections
3450            */
3451 
3452           /*
3453            *  flush any pending output
3454            */
3455           for (f = Files; f != NULL; f = f->f_next) {
3456                     /* flush any pending output */
3457                     if (f->f_prevcount)
3458                               fprintlog(f, NULL, NULL);
3459                     SEND_QUEUE(f);
3460           }
3461           /* some actions only on SIGHUP and not on first start */
3462           if (Initialized) {
3463 #ifndef DISABLE_SIGN
3464                     sign_global_free();
3465 #endif /* !DISABLE_SIGN */
3466 #ifndef DISABLE_TLS
3467                     free_incoming_tls_sockets();
3468 #endif /* !DISABLE_TLS */
3469                     Initialized = 0;
3470           }
3471           /*
3472            *  Close all open log files.
3473            */
3474           for (f = Files; f != NULL; f = f->f_next) {
3475                     switch (f->f_type) {
3476                     case F_FILE:
3477                     case F_TTY:
3478                     case F_CONSOLE:
3479                               (void)close(f->f_file);
3480                               break;
3481                     case F_PIPE:
3482                               if (f->f_un.f_pipe.f_pid > 0) {
3483                                         (void)close(f->f_file);
3484                                         deadq_enter(f->f_un.f_pipe.f_pid,
3485                                             f->f_un.f_pipe.f_pname);
3486                               }
3487                               f->f_un.f_pipe.f_pid = 0;
3488                               break;
3489                     case F_FORW:
3490                               if (f->f_un.f_forw.f_addr)
3491                                         freeaddrinfo(f->f_un.f_forw.f_addr);
3492                               break;
3493 #ifndef DISABLE_TLS
3494                     case F_TLS:
3495                               free_tls_sslptr(f->f_un.f_tls.tls_conn);
3496                               break;
3497 #endif /* !DISABLE_TLS */
3498                     }
3499           }
3500 
3501           /*
3502            *  Close all open UDP sockets
3503            */
3504           if (finet) {
3505                     for (i = 0; i < finet->fd; i++) {
3506                               if (close(finet[i+1].fd) < 0) {
3507                                         logerror("close() failed");
3508                                         die(0, 0, NULL);
3509                               }
3510                               DEL_EVENT(finet[i+1].ev);
3511                               FREEPTR(finet[i+1].ev);
3512                     }
3513                     FREEPTR(finet);
3514           }
3515 
3516           /* get FQDN and hostname/domain */
3517           FREEPTR(oldLocalFQDN);
3518           oldLocalFQDN = LocalFQDN;
3519           LocalFQDN = getLocalFQDN();
3520           if ((p = strchr(LocalFQDN, '.')) != NULL)
3521                     (void)strlcpy(LocalHostName, LocalFQDN, 1+p-LocalFQDN);
3522           else
3523                     (void)strlcpy(LocalHostName, LocalFQDN, sizeof(LocalHostName));
3524 
3525           /*
3526            *  Reset counter of forwarding actions
3527            */
3528 
3529           NumForwards=0;
3530 
3531           /* new destination list to replace Files */
3532           newf = NULL;
3533           nextp = &newf;
3534 
3535           /* open the configuration file */
3536           if ((cf = fopen(ConfFile, "r")) == NULL) {
3537                     DPRINTF(D_FILE, "Cannot open `%s'\n", ConfFile);
3538                     *nextp = (struct filed *)calloc(1, sizeof(*f));
3539                     cfline(0, "*.ERR\t/dev/console", *nextp, "*", "*");
3540                     (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
3541                     cfline(0, "*.PANIC\t*", (*nextp)->f_next, "*", "*");
3542                     Initialized = 1;
3543                     RESTORE_SIGNALS(omask);
3544                     return;
3545           }
3546 
3547 #ifndef DISABLE_TLS
3548           /* init with new TLS_CTX
3549            * as far as I see one cannot change the cert/key of an existing CTX
3550            */
3551           FREE_SSL_CTX(tls_opt.global_TLS_CTX);
3552 
3553           free_cred_SLIST(&tls_opt.cert_head);
3554           free_cred_SLIST(&tls_opt.fprint_head);
3555 #endif /* !DISABLE_TLS */
3556 
3557           /* read and close configuration file */
3558           read_config_file(cf, &newf);
3559           newf = *nextp;
3560           (void)fclose(cf);
3561           DPRINTF(D_MISC, "read_config_file() returned newf=%p\n", newf);
3562 
3563 #define MOVE_QUEUE(dst, src) do {                                     \
3564           struct buf_queue *buf;                                                \
3565           STAILQ_CONCAT(&dst->f_qhead, &src->f_qhead);                \
3566           STAILQ_FOREACH(buf, &dst->f_qhead, entries) {               \
3567                 dst->f_qelements++;                                   \
3568                 dst->f_qsize += buf_queue_obj_size(buf);              \
3569           }                                                                     \
3570           src->f_qsize = 0;                                           \
3571           src->f_qelements = 0;                                                 \
3572 } while (0)
3573 
3574           /*
3575            *  Free old log files.
3576            */
3577           for (f = Files; f != NULL;) {
3578                     struct filed *ftmp;
3579 
3580                     /* check if a new logfile is equal, if so pass the queue */
3581                     for (f2 = newf; f2 != NULL; f2 = f2->f_next) {
3582                               if (f->f_type == f2->f_type
3583                                   && ((f->f_type == F_PIPE
3584                                   && !strcmp(f->f_un.f_pipe.f_pname,
3585                                   f2->f_un.f_pipe.f_pname))
3586 #ifndef DISABLE_TLS
3587                                   || (f->f_type == F_TLS
3588                                   && !strcmp(f->f_un.f_tls.tls_conn->hostname,
3589                                   f2->f_un.f_tls.tls_conn->hostname)
3590                                   && !strcmp(f->f_un.f_tls.tls_conn->port,
3591                                   f2->f_un.f_tls.tls_conn->port))
3592 #endif /* !DISABLE_TLS */
3593                                   || (f->f_type == F_FORW
3594                                   && !strcmp(f->f_un.f_forw.f_hname,
3595                                   f2->f_un.f_forw.f_hname)))) {
3596                                         DPRINTF(D_BUFFER, "move queue from f@%p "
3597                                             "to f2@%p\n", f, f2);
3598                                         MOVE_QUEUE(f2, f);
3599                                }
3600                     }
3601                     message_queue_freeall(f);
3602                     DELREF(f->f_prevmsg);
3603 #ifndef DISABLE_TLS
3604                     if (f->f_type == F_TLS)
3605                               free_tls_conn(f->f_un.f_tls.tls_conn);
3606 #endif /* !DISABLE_TLS */
3607                     FREEPTR(f->f_program);
3608                     FREEPTR(f->f_host);
3609                     DEL_EVENT(f->f_sq_event);
3610 
3611                     ftmp = f->f_next;
3612                     free((char *)f);
3613                     f = ftmp;
3614           }
3615           Files = newf;
3616           Initialized = 1;
3617 
3618           if (Debug) {
3619                     for (f = Files; f; f = f->f_next) {
3620                               for (i = 0; i <= LOG_NFACILITIES; i++)
3621                                         if (f->f_pmask[i] == INTERNAL_NOPRI)
3622                                                   printf("X ");
3623                                         else
3624                                                   printf("%d ", f->f_pmask[i]);
3625                               printf("%s: ", TypeInfo[f->f_type].name);
3626                               switch (f->f_type) {
3627                               case F_FILE:
3628                               case F_TTY:
3629                               case F_CONSOLE:
3630                               case F_FIFO:
3631                                         printf("%s", f->f_un.f_fname);
3632                                         break;
3633 
3634                               case F_FORW:
3635                                         printf("%s", f->f_un.f_forw.f_hname);
3636                                         break;
3637 #ifndef DISABLE_TLS
3638                               case F_TLS:
3639                                         printf("[%s]", f->f_un.f_tls.tls_conn->hostname);
3640                                         break;
3641 #endif /* !DISABLE_TLS */
3642                               case F_PIPE:
3643                                         printf("%s", f->f_un.f_pipe.f_pname);
3644                                         break;
3645 
3646                               case F_USERS:
3647                                         for (i = 0;
3648                                             i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
3649                                                   printf("%s, ", f->f_un.f_uname[i]);
3650                                         break;
3651                               }
3652                               if (f->f_program != NULL)
3653                                         printf(" (%s)", f->f_program);
3654                               printf("\n");
3655                     }
3656           }
3657 
3658           finet = socksetup(PF_UNSPEC, bindhostname);
3659           if (finet) {
3660                     if (SecureMode) {
3661                               for (i = 0; i < finet->fd; i++) {
3662                                         if (shutdown(finet[i+1].fd, SHUT_RD) < 0) {
3663                                                   logerror("shutdown() failed");
3664                                                   die(0, 0, NULL);
3665                                         }
3666                               }
3667                     } else
3668                               DPRINTF(D_NET, "Listening on inet and/or inet6 socket\n");
3669                     DPRINTF(D_NET, "Sending on inet and/or inet6 socket\n");
3670           }
3671 
3672 #ifndef DISABLE_TLS
3673           /* TLS setup -- after all local destinations opened  */
3674           DPRINTF(D_PARSE, "Parsed options: tls_ca: %s, tls_cadir: %s, "
3675               "tls_cert: %s, tls_key: %s, tls_verify: %s, "
3676               "bind: %s:%s, max. queue_lengths: %"
3677               PRId64 ", %" PRId64 ", %" PRId64 ", "
3678               "max. queue_sizes: %"
3679               PRId64 ", %" PRId64 ", %" PRId64 "\n",
3680               tls_opt.CAfile, tls_opt.CAdir,
3681               tls_opt.certfile, tls_opt.keyfile, tls_opt.x509verify,
3682               tls_opt.bindhost, tls_opt.bindport,
3683               TypeInfo[F_TLS].queue_length, TypeInfo[F_FILE].queue_length,
3684               TypeInfo[F_PIPE].queue_length,
3685               TypeInfo[F_TLS].queue_size, TypeInfo[F_FILE].queue_size,
3686               TypeInfo[F_PIPE].queue_size);
3687           SLIST_FOREACH(cred, &tls_opt.cert_head, entries) {
3688                     DPRINTF(D_PARSE, "Accepting peer certificate "
3689                         "from file: \"%s\"\n", cred->data);
3690           }
3691           SLIST_FOREACH(cred, &tls_opt.fprint_head, entries) {
3692                     DPRINTF(D_PARSE, "Accepting peer certificate with "
3693                         "fingerprint: \"%s\"\n", cred->data);
3694           }
3695 
3696           /* Note: The order of initialization is important because syslog-sign
3697            * should use the TLS cert for signing. -- So we check first if TLS
3698            * will be used and initialize it before starting -sign.
3699            *
3700            * This means that if we are a client without TLS destinations TLS
3701            * will not be initialized and syslog-sign will generate a new key.
3702            * -- Even if the user has set a usable tls_cert.
3703            * Is this the expected behaviour? The alternative would be to always
3704            * initialize the TLS structures, even if they will not be needed
3705            * (or only needed to read the DSA key for -sign).
3706            */
3707 
3708           /* Initialize TLS only if used */
3709           if (tls_opt.server)
3710                     tls_status_msg = init_global_TLS_CTX();
3711           else
3712                     for (f = Files; f; f = f->f_next) {
3713                               if (f->f_type != F_TLS)
3714                                         continue;
3715                               tls_status_msg = init_global_TLS_CTX();
3716                               break;
3717                     }
3718 
3719 #endif /* !DISABLE_TLS */
3720 
3721 #ifndef DISABLE_SIGN
3722           /* only initialize -sign if actually used */
3723           if (GlobalSign.sg == 0 || GlobalSign.sg == 1 || GlobalSign.sg == 2)
3724                     (void)sign_global_init(Files);
3725           else if (GlobalSign.sg == 3)
3726                     for (f = Files; f; f = f->f_next)
3727                               if (f->f_flags & FFLAG_SIGN) {
3728                                         (void)sign_global_init(Files);
3729                                         break;
3730                               }
3731 #endif /* !DISABLE_SIGN */
3732 
3733 #ifndef DISABLE_TLS
3734           if (tls_status_msg) {
3735                     loginfo("%s", tls_status_msg);
3736                     free(tls_status_msg);
3737           }
3738           DPRINTF((D_NET|D_TLS), "Preparing sockets for TLS\n");
3739           TLS_Listen_Set =
3740                     socksetup_tls(PF_UNSPEC, tls_opt.bindhost, tls_opt.bindport);
3741 
3742           for (f = Files; f; f = f->f_next) {
3743                     if (f->f_type != F_TLS)
3744                               continue;
3745                     if (!tls_connect(f->f_un.f_tls.tls_conn)) {
3746                               logerror("Unable to connect to TLS server %s",
3747                                   f->f_un.f_tls.tls_conn->hostname);
3748                               /* Reconnect after x seconds  */
3749                               schedule_event(&f->f_un.f_tls.tls_conn->event,
3750                                   &((struct timeval){TLS_RECONNECT_SEC, 0}),
3751                                   tls_reconnect, f->f_un.f_tls.tls_conn);
3752                     }
3753           }
3754 #endif /* !DISABLE_TLS */
3755 
3756           loginfo("restart");
3757           /*
3758            * Log a change in hostname, but only on a restart (we detect this
3759            * by checking to see if we're passed a kevent).
3760            */
3761           if (oldLocalFQDN && strcmp(oldLocalFQDN, LocalFQDN) != 0)
3762                     loginfo("host name changed, \"%s\" to \"%s\"",
3763                         oldLocalFQDN, LocalFQDN);
3764 
3765           RESTORE_SIGNALS(omask);
3766 }
3767 
3768 /*
3769  * Crack a configuration file line
3770  */
3771 void
cfline(size_t linenum,const char * line,struct filed * f,const char * prog,const char * host)3772 cfline(size_t linenum, const char *line, struct filed *f, const char *prog,
3773     const char *host)
3774 {
3775           struct addrinfo hints, *res;
3776           int    error, i, pri, syncfile;
3777           const char   *p, *q;
3778           char *bp;
3779           char   buf[MAXLINE];
3780           struct stat sb;
3781 
3782           DPRINTF((D_CALL|D_PARSE),
3783                     "cfline(%zu, \"%s\", f, \"%s\", \"%s\")\n",
3784                     linenum, line, prog, host);
3785 
3786           errno = 0;          /* keep strerror() stuff out of logerror messages */
3787 
3788           /* clear out file entry */
3789           memset(f, 0, sizeof(*f));
3790           for (i = 0; i <= LOG_NFACILITIES; i++)
3791                     f->f_pmask[i] = INTERNAL_NOPRI;
3792           STAILQ_INIT(&f->f_qhead);
3793 
3794           /*
3795            * There should not be any space before the log facility.
3796            * Check this is okay, complain and fix if it is not.
3797            */
3798           q = line;
3799           if (isblank((unsigned char)*line)) {
3800                     errno = 0;
3801                     logerror("Warning: `%s' space or tab before the log facility",
3802                         line);
3803                     /* Fix: strip all spaces/tabs before the log facility */
3804                     while (*q++ && isblank((unsigned char)*q))
3805                               /* skip blanks */;
3806                     line = q;
3807           }
3808 
3809           /*
3810            * q is now at the first char of the log facility
3811            * There should be at least one tab after the log facility
3812            * Check this is okay, and complain and fix if it is not.
3813            */
3814           q = line + strlen(line);
3815           while (!isblank((unsigned char)*q) && (q != line))
3816                     q--;
3817           if ((q == line) && strlen(line)) {
3818                     /* No tabs or space in a non empty line: complain */
3819                     errno = 0;
3820                     logerror(
3821                         "Error: `%s' log facility or log target missing",
3822                         line);
3823                     return;
3824           }
3825 
3826           /* save host name, if any */
3827           if (*host == '*')
3828                     f->f_host = NULL;
3829           else {
3830                     f->f_host = strdup(host);
3831                     trim_anydomain(&f->f_host[1]);          /* skip +/- at beginning */
3832           }
3833 
3834           /* save program name, if any */
3835           if (*prog == '*')
3836                     f->f_program = NULL;
3837           else
3838                     f->f_program = strdup(prog);
3839 
3840           /* scan through the list of selectors */
3841           for (p = line; *p && !isblank((unsigned char)*p);) {
3842                     int pri_done, pri_cmp, pri_invert;
3843 
3844                     /* find the end of this facility name list */
3845                     for (q = p; *q && !isblank((unsigned char)*q) && *q++ != '.'; )
3846                               continue;
3847 
3848                     /* get the priority comparison */
3849                     pri_cmp = 0;
3850                     pri_done = 0;
3851                     pri_invert = 0;
3852                     if (*q == '!') {
3853                               pri_invert = 1;
3854                               q++;
3855                     }
3856                     while (! pri_done) {
3857                               switch (*q) {
3858                               case '<':
3859                                         pri_cmp = PRI_LT;
3860                                         q++;
3861                                         break;
3862                               case '=':
3863                                         pri_cmp = PRI_EQ;
3864                                         q++;
3865                                         break;
3866                               case '>':
3867                                         pri_cmp = PRI_GT;
3868                                         q++;
3869                                         break;
3870                               default:
3871                                         pri_done = 1;
3872                                         break;
3873                               }
3874                     }
3875 
3876                     /* collect priority name */
3877                     for (bp = buf; *q && !strchr("\t ,;", *q); )
3878                               *bp++ = *q++;
3879                     *bp = '\0';
3880 
3881                     /* skip cruft */
3882                     while (strchr(",;", *q))
3883                               q++;
3884 
3885                     /* decode priority name */
3886                     if (*buf == '*') {
3887                               pri = LOG_PRIMASK + 1;
3888                               pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
3889                     } else {
3890                               pri = decode(buf, prioritynames);
3891                               if (pri < 0) {
3892                                         errno = 0;
3893                                         logerror("Unknown priority name `%s'", buf);
3894                                         return;
3895                               }
3896                     }
3897                     if (pri_cmp == 0)
3898                               pri_cmp = UniquePriority ? PRI_EQ
3899                                                              : PRI_EQ | PRI_GT;
3900                     if (pri_invert)
3901                               pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
3902 
3903                     /* scan facilities */
3904                     while (*p && !strchr("\t .;", *p)) {
3905                               for (bp = buf; *p && !strchr("\t ,;.", *p); )
3906                                         *bp++ = *p++;
3907                               *bp = '\0';
3908                               if (*buf == '*')
3909                                         for (i = 0; i < LOG_NFACILITIES; i++) {
3910                                                   f->f_pmask[i] = pri;
3911                                                   f->f_pcmp[i] = pri_cmp;
3912                                         }
3913                               else {
3914                                         i = decode(buf, facilitynames);
3915                                         if (i < 0) {
3916                                                   errno = 0;
3917                                                   logerror("Unknown facility name `%s'",
3918                                                       buf);
3919                                                   return;
3920                                         }
3921                                         f->f_pmask[i >> 3] = pri;
3922                                         f->f_pcmp[i >> 3] = pri_cmp;
3923                               }
3924                               while (*p == ',' || *p == ' ')
3925                                         p++;
3926                     }
3927 
3928                     p = q;
3929           }
3930 
3931           /* skip to action part */
3932           while (isblank((unsigned char)*p))
3933                     p++;
3934 
3935           /*
3936            * should this be "#ifndef DISABLE_SIGN" or is it a general option?
3937            * '+' before file destination: write with PRI field for later
3938            * verification
3939            */
3940           if (*p == '+') {
3941                     f->f_flags |= FFLAG_FULL;
3942                     p++;
3943           }
3944           if (*p == '-') {
3945                     syncfile = 0;
3946                     p++;
3947           } else
3948                     syncfile = 1;
3949 
3950           switch (*p) {
3951           case '@':
3952 #ifndef DISABLE_SIGN
3953                     if (GlobalSign.sg == 3)
3954                               f->f_flags |= FFLAG_SIGN;
3955 #endif /* !DISABLE_SIGN */
3956 #ifndef DISABLE_TLS
3957                     if (*(p+1) == '[') {
3958                               /* TLS destination */
3959                               if (!parse_tls_destination(p, f, linenum)) {
3960                                         logerror("Unable to parse action %s", p);
3961                                         break;
3962                               }
3963                               f->f_type = F_TLS;
3964                               break;
3965                     }
3966 #endif /* !DISABLE_TLS */
3967                     (void)strlcpy(f->f_un.f_forw.f_hname, ++p,
3968                         sizeof(f->f_un.f_forw.f_hname));
3969                     memset(&hints, 0, sizeof(hints));
3970                     hints.ai_family = AF_UNSPEC;
3971                     hints.ai_socktype = SOCK_DGRAM;
3972                     hints.ai_protocol = 0;
3973                     error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
3974                         &res);
3975                     if (error) {
3976                               errno = 0;
3977                               logerror("%s", gai_strerror(error));
3978                               break;
3979                     }
3980                     f->f_un.f_forw.f_addr = res;
3981                     f->f_type = F_FORW;
3982                     NumForwards++;
3983                     break;
3984 
3985           case '/':
3986 #ifndef DISABLE_SIGN
3987                     if (GlobalSign.sg == 3)
3988                               f->f_flags |= FFLAG_SIGN;
3989 #endif /* !DISABLE_SIGN */
3990                     (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
3991                     if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NONBLOCK, 0)) < 0)
3992                     {
3993                               f->f_type = F_UNUSED;
3994                               logerror("%s", p);
3995                               break;
3996                     }
3997                     if (!fstat(f->f_file, &sb) && S_ISFIFO(sb.st_mode)) {
3998                               f->f_file = -1;
3999                               f->f_type = F_FIFO;
4000                               break;
4001                     }
4002 
4003                     if (isatty(f->f_file)) {
4004                               f->f_type = F_TTY;
4005                               if (strcmp(p, ctty) == 0)
4006                                         f->f_type = F_CONSOLE;
4007                     } else
4008                               f->f_type = F_FILE;
4009 
4010                     if (syncfile)
4011                               f->f_flags |= FFLAG_SYNC;
4012                     break;
4013 
4014           case '|':
4015 #ifndef DISABLE_SIGN
4016                     if (GlobalSign.sg == 3)
4017                               f->f_flags |= FFLAG_SIGN;
4018 #endif
4019                     f->f_un.f_pipe.f_pid = 0;
4020                     (void) strlcpy(f->f_un.f_pipe.f_pname, p + 1,
4021                         sizeof(f->f_un.f_pipe.f_pname));
4022                     f->f_type = F_PIPE;
4023                     break;
4024 
4025           case '*':
4026                     f->f_type = F_WALL;
4027                     break;
4028 
4029           default:
4030                     for (i = 0; i < MAXUNAMES && *p; i++) {
4031                               for (q = p; *q && *q != ','; )
4032                                         q++;
4033                               (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
4034                               if ((q - p) > UT_NAMESIZE)
4035                                         f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
4036                               else
4037                                         f->f_un.f_uname[i][q - p] = '\0';
4038                               while (*q == ',' || *q == ' ')
4039                                         q++;
4040                               p = q;
4041                     }
4042                     f->f_type = F_USERS;
4043                     break;
4044           }
4045 }
4046 
4047 
4048 /*
4049  *  Decode a symbolic name to a numeric value
4050  */
4051 int
decode(const char * name,CODE * codetab)4052 decode(const char *name, CODE *codetab)
4053 {
4054           CODE *c;
4055           char *p, buf[40];
4056 
4057           if (isdigit((unsigned char)*name))
4058                     return atoi(name);
4059 
4060           for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
4061                     if (isupper((unsigned char)*name))
4062                               *p = tolower((unsigned char)*name);
4063                     else
4064                               *p = *name;
4065           }
4066           *p = '\0';
4067           for (c = codetab; c->c_name; c++)
4068                     if (!strcmp(buf, c->c_name))
4069                               return c->c_val;
4070 
4071           return -1;
4072 }
4073 
4074 /*
4075  * Retrieve the size of the kernel message buffer, via sysctl.
4076  */
4077 int
getmsgbufsize(void)4078 getmsgbufsize(void)
4079 {
4080 #ifdef __NetBSD_Version__
4081           int msgbufsize, mib[2];
4082           size_t size;
4083 
4084           mib[0] = CTL_KERN;
4085           mib[1] = KERN_MSGBUFSIZE;
4086           size = sizeof msgbufsize;
4087           if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
4088                     DPRINTF(D_MISC, "Couldn't get kern.msgbufsize\n");
4089                     return 0;
4090           }
4091           return msgbufsize;
4092 #else
4093           return MAXLINE;
4094 #endif /* __NetBSD_Version__ */
4095 }
4096 
4097 /*
4098  * Retrieve the hostname, via sysctl.
4099  */
4100 char *
getLocalFQDN(void)4101 getLocalFQDN(void)
4102 {
4103           int mib[2];
4104           char *hostname;
4105           size_t len;
4106 
4107           mib[0] = CTL_KERN;
4108           mib[1] = KERN_HOSTNAME;
4109           sysctl(mib, 2, NULL, &len, NULL, 0);
4110 
4111           if (!(hostname = malloc(len))) {
4112                     logerror("Unable to allocate memory");
4113                     die(0,0,NULL);
4114           } else if (sysctl(mib, 2, hostname, &len, NULL, 0) == -1) {
4115                     DPRINTF(D_MISC, "Couldn't get kern.hostname\n");
4116                     (void)gethostname(hostname, sizeof(len));
4117           }
4118           return hostname;
4119 }
4120 
4121 struct socketEvent *
socksetup(int af,const char * hostname)4122 socksetup(int af, const char *hostname)
4123 {
4124           struct addrinfo hints, *res, *r;
4125           int error, maxs;
4126           int on = 1;
4127           struct socketEvent *s, *socks;
4128 
4129           if(SecureMode && !NumForwards)
4130                     return NULL;
4131 
4132           memset(&hints, 0, sizeof(hints));
4133           hints.ai_flags = AI_PASSIVE;
4134           hints.ai_family = af;
4135           hints.ai_socktype = SOCK_DGRAM;
4136           error = getaddrinfo(hostname, "syslog", &hints, &res);
4137           if (error) {
4138                     errno = 0;
4139                     logerror("%s", gai_strerror(error));
4140                     die(0, 0, NULL);
4141           }
4142 
4143           /* Count max number of sockets we may open */
4144           for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
4145                     continue;
4146           socks = calloc(maxs+1, sizeof(*socks));
4147           if (!socks) {
4148                     logerror("Couldn't allocate memory for sockets");
4149                     die(0, 0, NULL);
4150           }
4151 
4152           socks->fd = 0;       /* num of sockets counter at start of array */
4153           s = socks + 1;
4154           for (r = res; r; r = r->ai_next) {
4155                     s->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
4156                     if (s->fd < 0) {
4157                               logerror("socket() failed");
4158                               continue;
4159                     }
4160                     s->af = r->ai_family;
4161                     if (r->ai_family == AF_INET6 && setsockopt(s->fd, IPPROTO_IPV6,
4162                         IPV6_V6ONLY, &on, sizeof(on)) < 0) {
4163                               logerror("setsockopt(IPV6_V6ONLY) failed");
4164                               close(s->fd);
4165                               continue;
4166                     }
4167 
4168                     if (!SecureMode) {
4169                               if (bind(s->fd, r->ai_addr, r->ai_addrlen) < 0) {
4170                                         logerror("bind() failed");
4171                                         close(s->fd);
4172                                         continue;
4173                               }
4174                               s->ev = allocev();
4175                               event_set(s->ev, s->fd, EV_READ | EV_PERSIST,
4176                                         dispatch_read_finet, s->ev);
4177                               if (event_add(s->ev, NULL) == -1) {
4178                                         DPRINTF((D_EVENT|D_NET),
4179                                             "Failure in event_add()\n");
4180                               } else {
4181                                         DPRINTF((D_EVENT|D_NET),
4182                                             "Listen on UDP port "
4183                                             "(event@%p)\n", s->ev);
4184                               }
4185                     }
4186 
4187                     socks->fd++;  /* num counter */
4188                     s++;
4189           }
4190 
4191           if (res)
4192                     freeaddrinfo(res);
4193           if (socks->fd == 0) {
4194                     free (socks);
4195                     if(Debug)
4196                               return NULL;
4197                     else
4198                               die(0, 0, NULL);
4199           }
4200           return socks;
4201 }
4202 
4203 /*
4204  * Fairly similar to popen(3), but returns an open descriptor, as opposed
4205  * to a FILE *.
4206  */
4207 int
p_open(char * prog,pid_t * rpid)4208 p_open(char *prog, pid_t *rpid)
4209 {
4210           static char sh[] = "sh", mc[] = "-c";
4211           int pfd[2], nulldesc, i;
4212           pid_t pid;
4213           char *argv[4];      /* sh -c cmd NULL */
4214 
4215           if (pipe(pfd) == -1)
4216                     return -1;
4217           if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) {
4218                     /* We are royally screwed anyway. */
4219                     return -1;
4220           }
4221 
4222           switch ((pid = fork())) {
4223           case -1:
4224                     (void) close(nulldesc);
4225                     return -1;
4226 
4227           case 0:
4228                     argv[0] = sh;
4229                     argv[1] = mc;
4230                     argv[2] = prog;
4231                     argv[3] = NULL;
4232 
4233                     (void) setsid();    /* avoid catching SIGHUPs. */
4234 
4235                     /*
4236                      * Reset ignored signals to their default behavior.
4237                      */
4238                     (void)signal(SIGTERM, SIG_DFL);
4239                     (void)signal(SIGINT, SIG_DFL);
4240                     (void)signal(SIGQUIT, SIG_DFL);
4241                     (void)signal(SIGPIPE, SIG_DFL);
4242                     (void)signal(SIGHUP, SIG_DFL);
4243 
4244                     dup2(pfd[0], STDIN_FILENO);
4245                     dup2(nulldesc, STDOUT_FILENO);
4246                     dup2(nulldesc, STDERR_FILENO);
4247                     for (i = getdtablesize(); i > 2; i--)
4248                               (void) close(i);
4249 
4250                     (void) execvp(_PATH_BSHELL, argv);
4251                     _exit(255);
4252           }
4253 
4254           (void) close(nulldesc);
4255           (void) close(pfd[0]);
4256 
4257           /*
4258            * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
4259            * supposed to get an EWOULDBLOCK on writev(2), which is
4260            * caught by the logic above anyway, which will in turn
4261            * close the pipe, and fork a new logging subprocess if
4262            * necessary.  The stale subprocess will be killed some
4263            * time later unless it terminated itself due to closing
4264            * its input pipe.
4265            */
4266           if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
4267                     /* This is bad. */
4268                     logerror("Warning: cannot change pipe to pid %d to "
4269                         "non-blocking.", (int) pid);
4270           }
4271           *rpid = pid;
4272           return pfd[1];
4273 }
4274 
4275 void
deadq_enter(pid_t pid,const char * name)4276 deadq_enter(pid_t pid, const char *name)
4277 {
4278           dq_t p;
4279           int status;
4280 
4281           /*
4282            * Be paranoid: if we can't signal the process, don't enter it
4283            * into the dead queue (perhaps it's already dead).  If possible,
4284            * we try to fetch and log the child's status.
4285            */
4286           if (kill(pid, 0) != 0) {
4287                     if (waitpid(pid, &status, WNOHANG) > 0)
4288                               log_deadchild(pid, status, name);
4289                     return;
4290           }
4291 
4292           p = malloc(sizeof(*p));
4293           if (p == NULL) {
4294                     logerror("panic: out of memory!");
4295                     exit(1);
4296           }
4297 
4298           p->dq_pid = pid;
4299           p->dq_timeout = DQ_TIMO_INIT;
4300           TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
4301 }
4302 
4303 int
deadq_remove(pid_t pid)4304 deadq_remove(pid_t pid)
4305 {
4306           dq_t q;
4307 
4308           for (q = TAILQ_FIRST(&deadq_head); q != NULL;
4309                q = TAILQ_NEXT(q, dq_entries)) {
4310                     if (q->dq_pid == pid) {
4311                               TAILQ_REMOVE(&deadq_head, q, dq_entries);
4312                               free(q);
4313                               return 1;
4314                     }
4315           }
4316           return 0;
4317 }
4318 
4319 void
log_deadchild(pid_t pid,int status,const char * name)4320 log_deadchild(pid_t pid, int status, const char *name)
4321 {
4322           int code;
4323           char buf[256];
4324           const char *reason;
4325 
4326           /* Keep strerror() struff out of logerror messages. */
4327           errno = 0;
4328           if (WIFSIGNALED(status)) {
4329                     reason = "due to signal";
4330                     code = WTERMSIG(status);
4331           } else {
4332                     reason = "with status";
4333                     code = WEXITSTATUS(status);
4334                     if (code == 0)
4335                               return;
4336           }
4337           (void) snprintf(buf, sizeof(buf),
4338               "Logging subprocess %d (%s) exited %s %d.",
4339               pid, name, reason, code);
4340           logerror("%s", buf);
4341 }
4342 
4343 struct event *
allocev(void)4344 allocev(void)
4345 {
4346           struct event *ev;
4347 
4348           if (!(ev = calloc(1, sizeof(*ev))))
4349                     logerror("Unable to allocate memory");
4350           return ev;
4351 }
4352 
4353 /* *ev is allocated if necessary */
4354 void
schedule_event(struct event ** ev,struct timeval * tv,void (* cb)(int,short,void *),void * arg)4355 schedule_event(struct event **ev, struct timeval *tv,
4356           void (*cb)(int, short, void *), void *arg)
4357 {
4358           if (!*ev && !(*ev = allocev())) {
4359                     return;
4360           }
4361           event_set(*ev, 0, 0, cb, arg);
4362           DPRINTF(D_EVENT, "event_add(%s@%p)\n", "schedule_ev", *ev); \
4363           if (event_add(*ev, tv) == -1) {
4364                     DPRINTF(D_EVENT, "Failure in event_add()\n");
4365           }
4366 }
4367 
4368 #ifndef DISABLE_TLS
4369 /* abbreviation for freeing credential lists */
4370 void
free_cred_SLIST(struct peer_cred_head * head)4371 free_cred_SLIST(struct peer_cred_head *head)
4372 {
4373           struct peer_cred *cred;
4374 
4375           while (!SLIST_EMPTY(head)) {
4376                     cred = SLIST_FIRST(head);
4377                     SLIST_REMOVE_HEAD(head, entries);
4378                     FREEPTR(cred->data);
4379                     free(cred);
4380           }
4381 }
4382 #endif /* !DISABLE_TLS */
4383 
4384 /*
4385  * send message queue after reconnect
4386  */
4387 /*ARGSUSED*/
4388 void
send_queue(int fd,short event,void * arg)4389 send_queue(int fd, short event, void *arg)
4390 {
4391           struct filed *f = (struct filed *) arg;
4392           struct buf_queue *qentry;
4393 #define SQ_CHUNK_SIZE 250
4394           size_t cnt = 0;
4395 
4396 #ifndef DISABLE_TLS
4397           if (f->f_type == F_TLS) {
4398                     /* use a flag to prevent recursive calls to send_queue() */
4399                     if (f->f_un.f_tls.tls_conn->send_queue)
4400                               return;
4401                     else
4402                               f->f_un.f_tls.tls_conn->send_queue = true;
4403           }
4404           DPRINTF((D_DATA|D_CALL), "send_queue(f@%p with %zu msgs, "
4405                     "cnt@%p = %zu)\n", f, f->f_qelements, &cnt, cnt);
4406 #endif /* !DISABLE_TLS */
4407 
4408           while ((qentry = STAILQ_FIRST(&f->f_qhead))) {
4409 #ifndef DISABLE_TLS
4410                     /* send_queue() might be called with an unconnected destination
4411                      * from init() or die() or one message might take longer,
4412                      * leaving the connection in state ST_WAITING and thus not
4413                      * ready for the next message.
4414                      * this check is a shortcut to skip these unnecessary calls */
4415                     if (f->f_type == F_TLS
4416                         && f->f_un.f_tls.tls_conn->state != ST_TLS_EST) {
4417                               DPRINTF(D_TLS, "abort send_queue(cnt@%p = %zu) "
4418                                   "on TLS connection in state %d\n",
4419                                   &cnt, cnt, f->f_un.f_tls.tls_conn->state);
4420                               return;
4421                      }
4422 #endif /* !DISABLE_TLS */
4423                     fprintlog(f, qentry->msg, qentry);
4424 
4425                     /* Sending a long queue can take some time during which
4426                      * SIGHUP and SIGALRM are blocked and no events are handled.
4427                      * To avoid that we only send SQ_CHUNK_SIZE messages at once
4428                      * and then reschedule ourselves to continue. Thus the control
4429                      * will return first from all signal-protected functions so a
4430                      * possible SIGHUP/SIGALRM is handled and then back to the
4431                      * main loop which can handle possible input.
4432                      */
4433                     if (++cnt >= SQ_CHUNK_SIZE) {
4434                               if (!f->f_sq_event) { /* alloc on demand */
4435                                         f->f_sq_event = allocev();
4436                                         event_set(f->f_sq_event, 0, 0, send_queue, f);
4437                               }
4438                               if (event_add(f->f_sq_event, &((struct timeval){0, 1})) == -1) {
4439                                         DPRINTF(D_EVENT, "Failure in event_add()\n");
4440                               }
4441                               break;
4442                     }
4443           }
4444 #ifndef DISABLE_TLS
4445           if (f->f_type == F_TLS)
4446                     f->f_un.f_tls.tls_conn->send_queue = false;
4447 #endif
4448 
4449 }
4450 
4451 /*
4452  * finds the next queue element to delete
4453  *
4454  * has stateful behaviour, before using it call once with reset = true
4455  * after that every call will return one next queue elemen to delete,
4456  * depending on strategy either the oldest or the one with the lowest priority
4457  */
4458 static struct buf_queue *
find_qentry_to_delete(const struct buf_queue_head * head,int strategy,bool reset)4459 find_qentry_to_delete(const struct buf_queue_head *head, int strategy,
4460     bool reset)
4461 {
4462           static int pri;
4463           static struct buf_queue *qentry_static;
4464 
4465           struct buf_queue *qentry_tmp;
4466 
4467           if (reset || STAILQ_EMPTY(head)) {
4468                     pri = LOG_DEBUG;
4469                     qentry_static = STAILQ_FIRST(head);
4470                     return NULL;
4471           }
4472 
4473           /* find elements to delete */
4474           if (strategy == PURGE_BY_PRIORITY) {
4475                     qentry_tmp = qentry_static;
4476                     if (!qentry_tmp) return NULL;
4477                     while ((qentry_tmp = STAILQ_NEXT(qentry_tmp, entries)) != NULL)
4478                     {
4479                               if (LOG_PRI(qentry_tmp->msg->pri) == pri) {
4480                                         /* save the successor, because qentry_tmp
4481                                          * is probably deleted by the caller */
4482                                         qentry_static = STAILQ_NEXT(qentry_tmp, entries);
4483                                         return qentry_tmp;
4484                               }
4485                     }
4486                     /* nothing found in while loop --> next pri */
4487                     if (--pri)
4488                               return find_qentry_to_delete(head, strategy, false);
4489                     else
4490                               return NULL;
4491           } else /* strategy == PURGE_OLDEST or other value */ {
4492                     qentry_tmp = qentry_static;
4493                     qentry_static = STAILQ_NEXT(qentry_tmp, entries);
4494                     return qentry_tmp;  /* is NULL on empty queue */
4495           }
4496 }
4497 
4498 /* note on TAILQ: newest message added at TAIL,
4499  *                    oldest to be removed is FIRST
4500  */
4501 /*
4502  * checks length of a destination's message queue
4503  * if del_entries == 0 then assert queue length is
4504  *   less or equal to configured number of queue elements
4505  * otherwise del_entries tells how many entries to delete
4506  *
4507  * returns the number of removed queue elements
4508  * (which not necessarily means free'd messages)
4509  *
4510  * strategy PURGE_OLDEST to delete oldest entry, e.g. after it was resent
4511  * strategy PURGE_BY_PRIORITY to delete messages with lowest priority first,
4512  *        this is much slower but might be desirable when unsent messages have
4513  *        to be deleted, e.g. in call from domark()
4514  */
4515 size_t
message_queue_purge(struct filed * f,size_t del_entries,int strategy)4516 message_queue_purge(struct filed *f, size_t del_entries, int strategy)
4517 {
4518           size_t removed = 0;
4519           struct buf_queue *qentry = NULL;
4520 
4521           DPRINTF((D_CALL|D_BUFFER), "purge_message_queue(%p, %zu, %d) with "
4522               "f_qelements=%zu and f_qsize=%zu\n",
4523               f, del_entries, strategy,
4524               f->f_qelements, f->f_qsize);
4525 
4526           /* reset state */
4527           (void)find_qentry_to_delete(&f->f_qhead, strategy, true);
4528 
4529           while (removed < del_entries
4530               || (TypeInfo[f->f_type].queue_length != -1
4531               && (size_t)TypeInfo[f->f_type].queue_length <= f->f_qelements)
4532               || (TypeInfo[f->f_type].queue_size != -1
4533               && (size_t)TypeInfo[f->f_type].queue_size <= f->f_qsize)) {
4534                     qentry = find_qentry_to_delete(&f->f_qhead, strategy, 0);
4535                     if (message_queue_remove(f, qentry))
4536                               removed++;
4537                     else
4538                               break;
4539           }
4540           return removed;
4541 }
4542 
4543 /* run message_queue_purge() for all destinations to free memory */
4544 size_t
message_allqueues_purge(void)4545 message_allqueues_purge(void)
4546 {
4547           size_t sum = 0;
4548           struct filed *f;
4549 
4550           for (f = Files; f; f = f->f_next)
4551                     sum += message_queue_purge(f,
4552                         f->f_qelements/10, PURGE_BY_PRIORITY);
4553 
4554           DPRINTF(D_BUFFER,
4555               "message_allqueues_purge(): removed %zu buffer entries\n", sum);
4556           return sum;
4557 }
4558 
4559 /* run message_queue_purge() for all destinations to check limits */
4560 size_t
message_allqueues_check(void)4561 message_allqueues_check(void)
4562 {
4563           size_t sum = 0;
4564           struct filed *f;
4565 
4566           for (f = Files; f; f = f->f_next)
4567                     sum += message_queue_purge(f, 0, PURGE_BY_PRIORITY);
4568           DPRINTF(D_BUFFER,
4569               "message_allqueues_check(): removed %zu buffer entries\n", sum);
4570           return sum;
4571 }
4572 
4573 struct buf_msg *
buf_msg_new(const size_t len)4574 buf_msg_new(const size_t len)
4575 {
4576           struct buf_msg *newbuf;
4577 
4578           CALLOC(newbuf, sizeof(*newbuf));
4579 
4580           if (len) { /* len = 0 is valid */
4581                     MALLOC(newbuf->msg, len);
4582                     newbuf->msgorig = newbuf->msg;
4583                     newbuf->msgsize = len;
4584           }
4585           return NEWREF(newbuf);
4586 }
4587 
4588 void
buf_msg_free(struct buf_msg * buf)4589 buf_msg_free(struct buf_msg *buf)
4590 {
4591           if (!buf)
4592                     return;
4593 
4594           buf->refcount--;
4595           if (buf->refcount == 0) {
4596                     FREEPTR(buf->timestamp);
4597                     /* small optimizations: the host/recvhost may point to the
4598                      * global HostName/FQDN. of course this must not be free()d
4599                      * same goes for appname and include_pid
4600                      */
4601                     if (buf->recvhost != buf->host
4602                         && buf->recvhost != LocalHostName
4603                         && buf->recvhost != LocalFQDN
4604                         && buf->recvhost != oldLocalFQDN)
4605                               FREEPTR(buf->recvhost);
4606                     if (buf->host != LocalHostName
4607                         && buf->host != LocalFQDN
4608                         && buf->host != oldLocalFQDN)
4609                               FREEPTR(buf->host);
4610                     if (buf->prog != appname)
4611                               FREEPTR(buf->prog);
4612                     if (buf->pid != include_pid)
4613                               FREEPTR(buf->pid);
4614                     FREEPTR(buf->msgid);
4615                     FREEPTR(buf->sd);
4616                     FREEPTR(buf->msgorig);        /* instead of msg */
4617                     FREEPTR(buf);
4618           }
4619 }
4620 
4621 size_t
buf_queue_obj_size(struct buf_queue * qentry)4622 buf_queue_obj_size(struct buf_queue *qentry)
4623 {
4624           size_t sum = 0;
4625 
4626           if (!qentry)
4627                     return 0;
4628           sum += sizeof(*qentry)
4629               + sizeof(*qentry->msg)
4630               + qentry->msg->msgsize
4631               + SAFEstrlen(qentry->msg->timestamp)+1
4632               + SAFEstrlen(qentry->msg->msgid)+1;
4633           if (qentry->msg->prog
4634               && qentry->msg->prog != include_pid)
4635                     sum += strlen(qentry->msg->prog)+1;
4636           if (qentry->msg->pid
4637               && qentry->msg->pid != appname)
4638                     sum += strlen(qentry->msg->pid)+1;
4639           if (qentry->msg->recvhost
4640               && qentry->msg->recvhost != LocalHostName
4641               && qentry->msg->recvhost != LocalFQDN
4642               && qentry->msg->recvhost != oldLocalFQDN)
4643                     sum += strlen(qentry->msg->recvhost)+1;
4644           if (qentry->msg->host
4645               && qentry->msg->host != LocalHostName
4646               && qentry->msg->host != LocalFQDN
4647               && qentry->msg->host != oldLocalFQDN)
4648                     sum += strlen(qentry->msg->host)+1;
4649 
4650           return sum;
4651 }
4652 
4653 bool
message_queue_remove(struct filed * f,struct buf_queue * qentry)4654 message_queue_remove(struct filed *f, struct buf_queue *qentry)
4655 {
4656           if (!f || !qentry || !qentry->msg)
4657                     return false;
4658 
4659           assert(!STAILQ_EMPTY(&f->f_qhead));
4660           STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries);
4661           f->f_qelements--;
4662           f->f_qsize -= buf_queue_obj_size(qentry);
4663 
4664           DPRINTF(D_BUFFER, "msg @%p removed from queue @%p, new qlen = %zu\n",
4665               qentry->msg, f, f->f_qelements);
4666           DELREF(qentry->msg);
4667           FREEPTR(qentry);
4668           return true;
4669 }
4670 
4671 /*
4672  * returns *qentry on success and NULL on error
4673  */
4674 struct buf_queue *
message_queue_add(struct filed * f,struct buf_msg * buffer)4675 message_queue_add(struct filed *f, struct buf_msg *buffer)
4676 {
4677           struct buf_queue *qentry;
4678 
4679           /* check on every call or only every n-th time? */
4680           message_queue_purge(f, 0, PURGE_BY_PRIORITY);
4681 
4682           while (!(qentry = malloc(sizeof(*qentry)))
4683               && message_queue_purge(f, 1, PURGE_OLDEST))
4684                     continue;
4685           if (!qentry) {
4686                     logerror("Unable to allocate memory");
4687                     DPRINTF(D_BUFFER, "queue empty, no memory, msg dropped\n");
4688                     return NULL;
4689           } else {
4690                     qentry->msg = buffer;
4691                     f->f_qelements++;
4692                     f->f_qsize += buf_queue_obj_size(qentry);
4693                     STAILQ_INSERT_TAIL(&f->f_qhead, qentry, entries);
4694 
4695                     DPRINTF(D_BUFFER, "msg @%p queued @%p, qlen = %zu\n",
4696                         buffer, f, f->f_qelements);
4697                     return qentry;
4698           }
4699 }
4700 
4701 void
message_queue_freeall(struct filed * f)4702 message_queue_freeall(struct filed *f)
4703 {
4704           struct buf_queue *qentry;
4705 
4706           if (!f) return;
4707           DPRINTF(D_MEM, "message_queue_freeall(f@%p) with f_qhead@%p\n", f,
4708               &f->f_qhead);
4709 
4710           while (!STAILQ_EMPTY(&f->f_qhead)) {
4711                     qentry = STAILQ_FIRST(&f->f_qhead);
4712                     STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries);
4713                     DELREF(qentry->msg);
4714                     FREEPTR(qentry);
4715           }
4716 
4717           f->f_qelements = 0;
4718           f->f_qsize = 0;
4719 }
4720 
4721 #ifndef DISABLE_TLS
4722 /* utility function for tls_reconnect() */
4723 struct filed *
get_f_by_conninfo(struct tls_conn_settings * conn_info)4724 get_f_by_conninfo(struct tls_conn_settings *conn_info)
4725 {
4726           struct filed *f;
4727 
4728           for (f = Files; f; f = f->f_next) {
4729                     if ((f->f_type == F_TLS) && f->f_un.f_tls.tls_conn == conn_info)
4730                               return f;
4731           }
4732           DPRINTF(D_TLS, "get_f_by_conninfo() called on invalid conn_info\n");
4733           return NULL;
4734 }
4735 
4736 /*
4737  * Called on signal.
4738  * Lets the admin reconnect without waiting for the reconnect timer expires.
4739  */
4740 /*ARGSUSED*/
4741 void
dispatch_force_tls_reconnect(int fd,short event,void * ev)4742 dispatch_force_tls_reconnect(int fd, short event, void *ev)
4743 {
4744           struct filed *f;
4745           DPRINTF((D_TLS|D_CALL|D_EVENT), "dispatch_force_tls_reconnect()\n");
4746           for (f = Files; f; f = f->f_next) {
4747                     if (f->f_type == F_TLS &&
4748                         f->f_un.f_tls.tls_conn->state == ST_NONE)
4749                               tls_reconnect(fd, event, f->f_un.f_tls.tls_conn);
4750           }
4751 }
4752 #endif /* !DISABLE_TLS */
4753 
4754 /*
4755  * return a timestamp in a static buffer,
4756  * either format the timestamp given by parameter in_now
4757  * or use the current time if in_now is NULL.
4758  */
4759 char *
make_timestamp(time_t * in_now,bool iso,size_t tlen)4760 make_timestamp(time_t *in_now, bool iso, size_t tlen)
4761 {
4762           int frac_digits = 6;
4763           struct timeval tv;
4764           time_t mytime;
4765           struct tm ltime;
4766           int len = 0;
4767           int tzlen = 0;
4768           /* uses global var: time_t now; */
4769 
4770           if (in_now) {
4771                     mytime = *in_now;
4772           } else {
4773                     gettimeofday(&tv, NULL);
4774                     mytime = now = tv.tv_sec;
4775           }
4776 
4777           if (!iso) {
4778                     strlcpy(timestamp, ctime(&mytime) + 4, sizeof(timestamp));
4779                     timestamp[BSD_TIMESTAMPLEN] = '\0';
4780           } else {
4781                     localtime_r(&mytime, &ltime);
4782                     len += strftime(timestamp, sizeof(timestamp), "%FT%T", &ltime);
4783                     snprintf(&timestamp[len], frac_digits + 2, ".%.*jd",
4784                         frac_digits, (intmax_t)tv.tv_usec);
4785                     len += frac_digits + 1;
4786                     tzlen = strftime(&timestamp[len], sizeof(timestamp) - len, "%z",
4787                         &ltime);
4788                     len += tzlen;
4789 
4790                     if (tzlen == 5) {
4791                               /* strftime gives "+0200", but we need "+02:00" */
4792                               timestamp[len + 2] = '\0';
4793                               timestamp[len + 1] = timestamp[len];
4794                               timestamp[len] = timestamp[len - 1];
4795                               timestamp[len - 1] = timestamp[len - 2];
4796                               timestamp[len - 2] = ':';
4797                     }
4798           }
4799 
4800           switch (tlen) {
4801           case (size_t)-1:
4802                     return timestamp;
4803           case 0:
4804                     return strdup(timestamp);
4805           default:
4806                     return strndup(timestamp, tlen);
4807           }
4808 }
4809 
4810 /* auxiliary code to allocate memory and copy a string */
4811 bool
copy_string(char ** mem,const char * p,const char * q)4812 copy_string(char **mem, const char *p, const char *q)
4813 {
4814           const size_t len = 1 + q - p;
4815           if (!(*mem = malloc(len))) {
4816                     logerror("Unable to allocate memory for config");
4817                     return false;
4818           }
4819           strlcpy(*mem, p, len);
4820           return true;
4821 }
4822 
4823 /* keyword has to end with ",  everything until next " is copied */
4824 bool
copy_config_value_quoted(const char * keyword,char ** mem,const char ** p)4825 copy_config_value_quoted(const char *keyword, char **mem, const char **p)
4826 {
4827           const char *q;
4828           if (strncasecmp(*p, keyword, strlen(keyword)))
4829                     return false;
4830           q = *p += strlen(keyword);
4831           if (!(q = strchr(*p, '"'))) {
4832                     errno = 0;
4833                     logerror("unterminated \"\n");
4834                     return false;
4835           }
4836           if (!(copy_string(mem, *p, q)))
4837                     return false;
4838           *p = ++q;
4839           return true;
4840 }
4841 
4842 /* for config file:
4843  * following = required but whitespace allowed, quotes optional
4844  * if numeric, then conversion to integer and no memory allocation
4845  */
4846 bool
copy_config_value(const char * keyword,char ** mem,const char ** p,const char * file,int line)4847 copy_config_value(const char *keyword, char **mem,
4848           const char **p, const char *file, int line)
4849 {
4850           if (strncasecmp(*p, keyword, strlen(keyword)))
4851                     return false;
4852           *p += strlen(keyword);
4853 
4854           while (isspace((unsigned char)**p))
4855                     *p += 1;
4856           if (**p != '=') {
4857                     errno = 0;
4858                     logerror("expected \"=\" in file %s, line %d", file, line);
4859                     return false;
4860           }
4861           *p += 1;
4862 
4863           return copy_config_value_word(mem, p);
4864 }
4865 
4866 /* copy next parameter from a config line */
4867 bool
copy_config_value_word(char ** mem,const char ** p)4868 copy_config_value_word(char **mem, const char **p)
4869 {
4870           const char *q;
4871           while (isspace((unsigned char)**p))
4872                     *p += 1;
4873           if (**p == '"')
4874                     return copy_config_value_quoted("\"", mem, p);
4875 
4876           /* without quotes: find next whitespace or end of line */
4877           (void)((q = strchr(*p, ' ')) || (q = strchr(*p, '\t'))
4878                || (q = strchr(*p, '\n')) || (q = strchr(*p, '\0')));
4879 
4880           if (q-*p == 0 || !(copy_string(mem, *p, q)))
4881                     return false;
4882 
4883           *p = ++q;
4884           return true;
4885 }
4886 
4887 static int
writev1(int fd,struct iovec * iov,size_t count)4888 writev1(int fd, struct iovec *iov, size_t count)
4889 {
4890           ssize_t nw = 0, tot = 0;
4891           size_t ntries = 5;
4892 
4893           if (count == 0)
4894                     return 0;
4895           while (ntries--) {
4896                     switch ((nw = writev(fd, iov, count))) {
4897                     case -1:
4898                               if (errno == EAGAIN || errno == EWOULDBLOCK) {
4899                                         struct pollfd pfd;
4900                                         pfd.fd = fd;
4901                                         pfd.events = POLLOUT;
4902                                         pfd.revents = 0;
4903                                         (void)poll(&pfd, 1, 500);
4904                                         continue;
4905                               }
4906                               return -1;
4907                     case 0:
4908                               return 0;
4909                     default:
4910                               tot += nw;
4911                               while (nw > 0) {
4912                                         if (iov->iov_len > (size_t)nw) {
4913                                                   iov->iov_len -= nw;
4914                                                   iov->iov_base =
4915                                                       (char *)iov->iov_base + nw;
4916                                                   break;
4917                                         } else {
4918                                                   if (--count == 0)
4919                                                             return tot;
4920                                                   nw -= iov->iov_len;
4921                                                   iov++;
4922                                         }
4923                               }
4924                     }
4925           }
4926           return tot == 0 ? nw : tot;
4927 }
4928 
4929 
4930 #ifdef NDEBUG
4931 /*
4932  * -d also controls daemoniziation, so it makes sense even with
4933  * NDEBUG, but if the user also tries to specify the logging details
4934  * with an argument, warn them it's not compiled into this binary.
4935  */
4936 void
set_debug(const char * level)4937 set_debug(const char *level)
4938 {
4939           Debug = D_DEFAULT;
4940           if (level == NULL)
4941                     return;
4942 
4943           /* don't bother parsing the argument */
4944           fprintf(stderr,
4945                     "%s: debug logging is not compiled\n",
4946                     getprogname());
4947 }
4948 
4949 #else  /* !NDEBUG */
4950 void
set_debug(const char * level)4951 set_debug(const char *level)
4952 {
4953           if (level == NULL) {
4954                     Debug = D_DEFAULT; /* compat */
4955                     return;
4956           }
4957 
4958           /* skip initial whitespace for consistency with strto*l */
4959           while (isspace((unsigned char)*level))
4960                     ++level;
4961 
4962           /* accept ~num to mean "all except num" */
4963           bool invert = level[0] == '~';
4964           if (invert)
4965                     ++level;
4966 
4967           errno = 0;
4968           char *endp = NULL;
4969           unsigned long bits = strtoul(level, &endp, 0);
4970           if (errno || endp == level || *endp != '\0') {
4971                     fprintf(stderr, "%s: bad argument to -d\n", getprogname());
4972                     usage();
4973           }
4974           if (invert)
4975                     bits = ~bits;
4976 
4977           Debug = bits & D_ALL;
4978 
4979           /*
4980            * make it possible to use -d to stay in the foreground but
4981            * suppress all dbprintf output (there better be free bits in
4982            * typeof(Debug) that are not in D_ALL).
4983            */
4984           if (Debug == 0)
4985                     Debug = ~D_ALL;
4986 }
4987 #endif    /* !NDEBUG */
4988 
4989 
4990 #ifndef NDEBUG
4991 void
dbprintf(const char * fname,const char * funname,size_t lnum,const char * fmt,...)4992 dbprintf(const char *fname, const char *funname,
4993     size_t lnum, const char *fmt, ...)
4994 {
4995           va_list ap;
4996           char *ts;
4997 
4998           ts = make_timestamp(NULL, true, (size_t)-1);
4999           printf("%s:%s:%s:%.4zu\t", ts, fname, funname, lnum);
5000 
5001           va_start(ap, fmt);
5002           vprintf(fmt, ap);
5003           va_end(ap);
5004 }
5005 #endif
5006