Line data Source code
1 : /* syslogd - log system messages
2 : Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 : 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software
4 : Foundation, Inc.
5 :
6 : This file is part of GNU Inetutils.
7 :
8 : GNU Inetutils is free software: you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation, either version 3 of the License, or (at
11 : your option) any later version.
12 :
13 : GNU Inetutils is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see `http://www.gnu.org/licenses/'. */
20 :
21 : /*
22 : * Copyright (c) 1983, 1988, 1993, 1994
23 : * The Regents of the University of California. All rights reserved.
24 : *
25 : * Redistribution and use in source and binary forms, with or without
26 : * modification, are permitted provided that the following conditions
27 : * are met:
28 : * 1. Redistributions of source code must retain the above copyright
29 : * notice, this list of conditions and the following disclaimer.
30 : * 2. Redistributions in binary form must reproduce the above copyright
31 : * notice, this list of conditions and the following disclaimer in the
32 : * documentation and/or other materials provided with the distribution.
33 : * 3. Neither the name of the University nor the names of its contributors
34 : * may be used to endorse or promote products derived from this software
35 : * without specific prior written permission.
36 : *
37 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 : * SUCH DAMAGE.
48 : */
49 :
50 : /*
51 : * syslogd -- log system messages
52 : *
53 : * This program implements a system log. It takes a series of lines.
54 : * Each line may have a priority, signified as "<n>" as the first
55 : * characters of the line. If this is not present, a default priority
56 : * is used.
57 : *
58 : * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup)
59 : * will cause it to reread its configuration file.
60 : *
61 : * Defined Constants:
62 : *
63 : * MAXLINE -- the maximum line length that can be handled.
64 : * DEFUPRI -- the default priority for user messages
65 : * DEFSPRI -- the default priority for kernel messages
66 : *
67 : * Author: Eric Allman
68 : * extensive changes by Ralph Campbell
69 : * more extensive changes by Eric Allman (again)
70 : */
71 :
72 : #include <config.h>
73 :
74 : #define IOVCNT 6 /* size of the iovec array */
75 : #define MAXLINE 1024 /* Maximum line length. */
76 : #define MAXSVLINE 240 /* Maximum saved line length. */
77 : #define DEFUPRI (LOG_USER|LOG_NOTICE)
78 : #define DEFSPRI (LOG_KERN|LOG_CRIT)
79 : #define TIMERINTVL 30 /* Interval for checking flush, mark. */
80 : #define TTYMSGTIME 10 /* Time out passed to ttymsg. */
81 :
82 : #include <sys/param.h>
83 : #include <sys/ioctl.h>
84 : #include <sys/stat.h>
85 : #include <sys/wait.h>
86 : #include <sys/socket.h>
87 : #include <sys/uio.h>
88 : #include <sys/un.h>
89 : #include <sys/time.h>
90 : #include <time.h>
91 : #include <sys/resource.h>
92 : #include <poll.h>
93 : #include <sys/types.h>
94 :
95 : #include <netinet/in.h>
96 : #include <netdb.h>
97 : #include <arpa/inet.h>
98 :
99 : #include <argp.h>
100 : #include <ctype.h>
101 : #include <errno.h>
102 : #include <fcntl.h>
103 : #include <setjmp.h>
104 : #include <signal.h>
105 : #include <stdio.h>
106 : #include <stdlib.h>
107 : #include <string.h>
108 : #include <dirent.h>
109 : #include <unistd.h>
110 :
111 : #include <stdarg.h>
112 :
113 : #define SYSLOG_NAMES
114 : #include <syslog.h>
115 : #ifndef HAVE_SYSLOG_INTERNAL
116 : # include "logprio.h"
117 : #endif
118 :
119 : #ifndef LOG_MAKEPRI
120 : # define LOG_MAKEPRI(fac, p) ((fac) | (p))
121 : #endif
122 :
123 : #include <error.h>
124 : #include <progname.h>
125 : #include <libinetutils.h>
126 : #include <readutmp.h> /* May define UTMP_NAME_FUNCTION. */
127 : #include "unused-parameter.h"
128 : #include "xalloc.h"
129 :
130 : /* A mask of all facilities mentioned explicitly in the configuration file
131 : *
132 : * This is used to support a virtual facility "**" that covers all the rest,
133 : * so that messages to unexpected facilities won't be lost when "*" is
134 : * not logged to a file.
135 : */
136 : int facilities_seen;
137 :
138 : char *selector; /* Program origin to select. */
139 :
140 : const char *ConfFile = PATH_LOGCONF; /* Default Configuration file. */
141 : const char *ConfDir = PATH_LOGCONFD; /* Default Configuration directory. */
142 : const char *PidFile = PATH_LOGPID; /* Default path to tuck pid. */
143 : char ctty[] = PATH_CONSOLE; /* Default console to send message info. */
144 :
145 : static int dbg_output; /* If true, print debug output in debug mode. */
146 : static int restart; /* If 1, indicates SIGHUP was dropped. */
147 :
148 : /* Unix socket family to listen. */
149 : struct funix
150 : {
151 : const char *name;
152 : int fd;
153 : } *funix;
154 :
155 : size_t nfunix; /* Number of unix sockets in the funix array. */
156 :
157 : /*
158 : * Flags to logmsg().
159 : */
160 :
161 : #define IGN_CONS 0x001 /* Don't print on console. */
162 : #define SYNC_FILE 0x002 /* Do fsync on file after printing. */
163 : #define ADDDATE 0x004 /* Add a date to the message. */
164 : #define MARK 0x008 /* This message is a mark. */
165 :
166 : /* This structure represents the files that will have log copies
167 : printed. */
168 :
169 : struct filed
170 : {
171 : struct filed *f_next; /* Next in linked list. */
172 : short f_type; /* Entry type, see below. */
173 : short f_file; /* File descriptor. */
174 : time_t f_time; /* Time this was last written. */
175 : unsigned char f_pmask[LOG_NFACILITIES + 1]; /* Priority mask. */
176 : union
177 : {
178 : struct
179 : {
180 : int f_nusers;
181 : char **f_unames;
182 : } f_user; /* Send a message to a user. */
183 : struct
184 : {
185 : char *f_hname;
186 : struct sockaddr_storage f_addr;
187 : socklen_t f_addrlen;
188 : } f_forw; /* Forwarding address. */
189 : char *f_fname; /* Name use for Files|Pipes|TTYs. */
190 : } f_un;
191 : char f_prevline[MAXSVLINE]; /* Last message logged. */
192 : char f_lasttime[16]; /* Time of last occurrence. */
193 : char *f_prevhost; /* Host from which recd. */
194 : char *f_progname; /* Submitting program. */
195 : int f_prognlen; /* Length of the same. */
196 : int f_prevpri; /* Pri of f_prevline. */
197 : int f_prevlen; /* Length of f_prevline. */
198 : int f_prevcount; /* Repetition cnt of prevline. */
199 : size_t f_repeatcount; /* Number of "repeated" msgs. */
200 : int f_flags; /* Additional flags see below. */
201 : };
202 :
203 : struct filed *Files; /* Linked list of files to log to. */
204 : struct filed consfile; /* Console `file'. */
205 :
206 : /* Values for f_type. */
207 : #define F_UNUSED 0 /* Unused entry. */
208 : #define F_FILE 1 /* Regular file. */
209 : #define F_TTY 2 /* Terminal. */
210 : #define F_CONSOLE 3 /* Console terminal. */
211 : #define F_FORW 4 /* Remote machine. */
212 : #define F_USERS 5 /* List of users. */
213 : #define F_WALL 6 /* Everyone logged on. */
214 : #define F_FORW_SUSP 7 /* Suspended host forwarding. */
215 : #define F_FORW_UNKN 8 /* Unknown host forwarding. */
216 : #define F_PIPE 9 /* Named pipe. */
217 :
218 : const char *TypeNames[] = {
219 : "UNUSED",
220 : "FILE",
221 : "TTY",
222 : "CONSOLE",
223 : "FORW",
224 : "USERS",
225 : "WALL",
226 : "FORW(SUSPENDED)",
227 : "FORW(UNKNOWN)",
228 : "PIPE"
229 : };
230 :
231 : /* Flags in filed.f_flags. */
232 : #define OMIT_SYNC 0x001 /* Omit fsync after printing. */
233 :
234 : /* Constants for the F_FORW_UNKN retry feature. */
235 : #define INET_SUSPEND_TIME 180 /* Number of seconds between attempts. */
236 : #define INET_RETRY_MAX 10 /* Number of times to try gethostbyname(). */
237 :
238 : /* Intervals at which we flush out "message repeated" messages, in
239 : seconds after previous message is logged. After each flush, we move
240 : to the next interval until we reach the largest. */
241 :
242 : int repeatinterval[] = { 30, 60 }; /* Number of seconds before flush. */
243 :
244 : #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
245 : #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
246 : #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
247 : (f)->f_repeatcount = MAXREPEAT; \
248 : }
249 :
250 : /* Delimiter in arguments to command line options `-s' and `-l'. */
251 : #define LIST_DELIMITER ':'
252 :
253 : extern int waitdaemon (int nochdir, int noclose, int maxwait);
254 :
255 : void cfline (const char *, struct filed *);
256 : const char *cvthname (struct sockaddr *, socklen_t);
257 : int decode (const char *, CODE *);
258 : void die (int);
259 : void doexit (int);
260 : void domark (int);
261 : void find_inet_port (const char *);
262 : void fprintlog (struct filed *, const char *, int, const char *);
263 : static int load_conffile (const char *, struct filed **);
264 : static int load_confdir (const char *, struct filed **);
265 : void init (int);
266 : void logerror (const char *);
267 : void logmsg (int, const char *, const char *, int);
268 : void printline (const char *, const char *);
269 : void printsys (const char *);
270 : char *ttymsg (struct iovec *, int, char *, int);
271 : void wallmsg (struct filed *, struct iovec *);
272 : char **crunch_list (char **oldlist, char *list);
273 : char *textpri (int pri);
274 : void dbg_toggle (int);
275 : static void dbg_printf (const char *, ...);
276 : void trigger_restart (int);
277 : static void add_funix (const char *path);
278 : static int create_unix_socket (const char *path);
279 : static void create_inet_socket (int af, int fd46[2]);
280 :
281 : char *LocalHostName; /* Our hostname. */
282 : char *LocalDomain; /* Our local domain name. */
283 : char *BindAddress = NULL; /* Binding address for INET listeners.
284 : * The default is a wildcard address. */
285 : char *BindPort = NULL; /* Optional non-standard port, instead
286 : * of the usual 514/udp. */
287 : #ifdef IPPORT_SYSLOG
288 : char portstr[8]; /* Fallback port number. */
289 : #endif
290 : char addrstr[INET6_ADDRSTRLEN]; /* Common address presentation. */
291 : char addrname[NI_MAXHOST]; /* Common name lookup. */
292 : int usefamily = AF_INET; /* Address family for INET services.
293 : * Each of the values `AF_INET' and `AF_INET6'
294 : * produces a single-stacked server. */
295 : int finet[2] = {-1, -1}; /* Internet datagram socket fd. */
296 : #define IU_FD_IP4 0 /* Indices for the address families. */
297 : #define IU_FD_IP6 1
298 : int fklog = -1; /* Kernel log device fd. */
299 : char *LogPortText = NULL; /* Service/port for INET connections. */
300 : char *LogForwardPort = NULL; /* Target port for message forwarding. */
301 : int Initialized; /* True when we are initialized. */
302 : int MarkInterval = 20 * 60; /* Interval between marks in seconds. */
303 : int MarkSeq; /* Mark sequence number. */
304 :
305 : int Debug; /* True if in debug mode. */
306 : int AcceptRemote; /* Receive messages that come via UDP. */
307 : char **StripDomains; /* Domains to be stripped before logging. */
308 : char **LocalHosts; /* Hosts to be logged by their hostname. */
309 : int NoDetach; /* Don't run in background and detach
310 : from ctty. */
311 : int NoHops = 1; /* Bounce syslog messages for other hosts. */
312 : int NoKLog; /* Don't attempt to log kernel device. */
313 : int NoUnixAF; /* Don't listen to unix sockets. */
314 : int NoForward; /* Don't forward messages. */
315 : time_t now; /* Time use for mark and forward supending. */
316 : int force_sync; /* GNU/Linux behaviour to sync on every line.
317 : This off by default. Set to 1 to enable. */
318 : int set_local_time = 0; /* Record local time, not message time. */
319 :
320 : const char args_doc[] = "";
321 : const char doc[] = "Log system messages.";
322 :
323 : /* Define keys for long options that do not have short counterparts. */
324 : enum {
325 : OPT_NO_FORWARD = 256,
326 : OPT_NO_KLOG,
327 : OPT_NO_UNIXAF,
328 : OPT_IPANY
329 : };
330 :
331 : static struct argp_option argp_options[] = {
332 : #define GRP 0
333 : /* Not sure about the long name. Maybe move into conffile even. */
334 : {NULL, 'a', "SOCKET", 0, "add unix socket to listen to (up to 19)", GRP+1},
335 : {NULL, 'l', "HOSTLIST", 0, "log hosts in HOSTLIST by their hostname", GRP+1},
336 : {NULL, 's', "DOMAINLIST", 0, "list of domains which should be stripped "
337 : "from the FQDN of hosts before logging their name", GRP+1},
338 : {"debug", 'd', NULL, 0, "print debug information (implies --no-detach)",
339 : GRP+1},
340 : {"hop", 'h', NULL, 0, "forward messages from remote hosts", GRP+1},
341 : {"inet", 'r', NULL, 0, "receive remote messages via internet domain socket",
342 : GRP+1},
343 : {"ipv4", '4', NULL, 0, "restrict to IPv4 transport (default)", GRP+1},
344 : {"ipv6", '6', NULL, 0, "restrict to IPv6 transport", GRP+1},
345 : {"ipany", OPT_IPANY, NULL, 0, "allow transport with IPv4 and IPv6", GRP+1},
346 : {"bind", 'b', "ADDR", 0, "bind listener to this address/name", GRP+1},
347 : {"bind-port", 'B', "PORT", 0, "bind listener to this port", GRP+1},
348 : {"mark", 'm', "INTVL", 0, "specify timestamp interval in minutes"
349 : " (0 for no timestamping)", GRP+1},
350 : {"no-detach", 'n', NULL, 0, "do not enter daemon mode", GRP+1},
351 : {"no-forward", OPT_NO_FORWARD, NULL, 0, "do not forward any messages "
352 : "(overrides --hop)", GRP+1},
353 : #ifdef PATH_KLOG
354 : {"no-klog", OPT_NO_KLOG, NULL, 0, "do not listen to kernel log device "
355 : PATH_KLOG, GRP+1},
356 : #endif
357 : {"no-unixaf", OPT_NO_UNIXAF, NULL, 0, "do not listen on unix domain "
358 : "sockets (overrides -a and -p)", GRP+1},
359 : {"pidfile", 'P', "FILE", 0, "override pidfile (default: "
360 : PATH_LOGPID ")", GRP+1},
361 : {"rcfile", 'f', "FILE", 0, "override configuration file (default: "
362 : PATH_LOGCONF ")",
363 : GRP+1},
364 : {"rcdir", 'D', "DIR", 0, "override configuration directory (default: "
365 : PATH_LOGCONFD ")", GRP+1},
366 : {"socket", 'p', "FILE", 0, "override default unix domain socket " PATH_LOG,
367 : GRP+1},
368 : {"sync", 'S', NULL, 0, "force a file sync on every line", GRP+1},
369 : {"local-time", 'T', NULL, 0, "set local time on received messages", GRP+1},
370 : #undef GRP
371 : {NULL, 0, NULL, 0, NULL, 0}
372 : };
373 :
374 : static error_t
375 15 : parse_opt (int key, char *arg, struct argp_state *state)
376 : {
377 : char *endptr;
378 : int v;
379 :
380 15 : switch (key)
381 : {
382 : case 'a':
383 2 : add_funix (arg);
384 2 : break;
385 :
386 : case 'l':
387 0 : LocalHosts = crunch_list (LocalHosts, arg);
388 0 : break;
389 :
390 : case 's':
391 0 : StripDomains = crunch_list (StripDomains, arg);
392 0 : break;
393 :
394 : case 'd':
395 0 : Debug = 1;
396 0 : NoDetach = 1;
397 0 : break;
398 :
399 : case 'h':
400 1 : NoHops = 0;
401 1 : break;
402 :
403 : case 'r':
404 1 : AcceptRemote = 1;
405 1 : break;
406 :
407 : case '4':
408 0 : usefamily = AF_INET;
409 0 : break;
410 :
411 : case '6':
412 0 : usefamily = AF_INET6;
413 0 : break;
414 :
415 : case OPT_IPANY:
416 1 : usefamily = AF_UNSPEC;
417 1 : break;
418 :
419 : case 'b':
420 0 : BindAddress = arg;
421 0 : break;
422 :
423 : case 'B':
424 1 : BindPort = arg;
425 1 : break;
426 :
427 : case 'm':
428 0 : v = strtol (arg, &endptr, 10);
429 0 : if (*endptr)
430 0 : argp_error (state, "invalid value (`%s' near `%s')", arg, endptr);
431 0 : MarkInterval = v * 60;
432 0 : break;
433 :
434 : case 'n':
435 0 : NoDetach = 1;
436 0 : break;
437 :
438 : case OPT_NO_FORWARD:
439 0 : NoForward = 1;
440 0 : break;
441 :
442 : case OPT_NO_KLOG:
443 0 : NoKLog = 1;
444 0 : break;
445 :
446 : case OPT_NO_UNIXAF:
447 0 : NoUnixAF = 1;
448 0 : break;
449 :
450 : case 'P':
451 1 : PidFile = arg;
452 1 : break;
453 :
454 : case 'f':
455 1 : ConfFile = arg;
456 1 : break;
457 :
458 : case 'D':
459 1 : ConfDir = arg;
460 1 : break;
461 :
462 : case 'p':
463 1 : funix[0].name = arg;
464 1 : funix[0].fd = -1;
465 1 : break;
466 :
467 : case 'S':
468 0 : force_sync = 1;
469 0 : break;
470 :
471 : case 'T':
472 0 : set_local_time = 1;
473 0 : break;
474 :
475 : default:
476 5 : return ARGP_ERR_UNKNOWN;
477 : }
478 :
479 10 : return 0;
480 : }
481 :
482 : static struct argp argp =
483 : {argp_options, parse_opt, args_doc, doc, NULL, NULL, NULL};
484 :
485 : int
486 1 : main (int argc, char *argv[])
487 : {
488 : size_t i;
489 : FILE *fp;
490 : char *p;
491 : char line[MAXLINE + 1];
492 : char kline[MAXLINE + 1];
493 1 : int kline_len = 0;
494 1 : pid_t ppid = 0; /* We run in debug mode and didn't fork. */
495 : struct pollfd *fdarray;
496 1 : unsigned long nfds = 0;
497 : #ifdef HAVE_SIGACTION
498 : struct sigaction sa;
499 : #endif
500 :
501 1 : set_program_name (argv[0]);
502 :
503 : /* Initialize PATH_LOG as the first element of the unix sockets array. */
504 1 : add_funix (PATH_LOG);
505 :
506 : /* Parse command line */
507 1 : iu_argp_init ("syslogd", default_program_authors);
508 1 : argp_parse (&argp, argc, argv, 0, NULL, NULL);
509 :
510 : /* Check desired port, if in demand at all. */
511 1 : find_inet_port (BindPort);
512 :
513 : /* Daemonise, if not, set the buffering for line buffer. */
514 1 : if (!NoDetach)
515 : {
516 : /* History: According to the GNU/Linux sysklogd ChangeLogs "Wed
517 : Feb 14 12:42:09 CST 1996: Dr. Wettstein Parent process of
518 : syslogd does not exit until child process has finished
519 : initialization process. This allows rc.* startup to pause
520 : until syslogd facility is up and operating."
521 :
522 : IMO, the GNU/Linux distributors should fix there booting
523 : sequence. But we still keep the approach. */
524 1 : signal (SIGTERM, doexit);
525 1 : ppid = waitdaemon (0, 0, 30);
526 1 : if (ppid < 0)
527 0 : error (EXIT_FAILURE, errno, "could not become daemon");
528 : }
529 : else
530 : {
531 0 : if (Debug)
532 0 : dbg_output = 1;
533 0 : setvbuf (stdout, 0, _IOLBF, 0);
534 : }
535 :
536 : /* Get our hostname. */
537 1 : LocalHostName = localhost ();
538 1 : if (LocalHostName == NULL)
539 0 : error (EXIT_FAILURE, errno, "can't get local host name");
540 :
541 : /* Get the domainname. */
542 1 : p = strchr (LocalHostName, '.');
543 1 : if (p != NULL)
544 : {
545 1 : *p++ = '\0';
546 1 : LocalDomain = p;
547 : }
548 : else
549 : {
550 : struct addrinfo hints, *rp;
551 : int err;
552 :
553 0 : memset (&hints, 0, sizeof (hints));
554 0 : hints.ai_family = AF_UNSPEC; /* Family is irrelevant. */
555 0 : hints.ai_flags = AI_CANONNAME;
556 :
557 : /* Try to resolve the domainname by calling DNS. */
558 0 : err = getaddrinfo (LocalHostName, NULL, &hints, &rp);
559 0 : if (err == 0)
560 : {
561 : /* Override what we had */
562 0 : free (LocalHostName);
563 0 : LocalHostName = strdup (rp->ai_canonname);
564 0 : p = strchr (LocalHostName, '.');
565 0 : if (p != NULL)
566 : {
567 0 : *p++ = '\0';
568 0 : LocalDomain = p;
569 : }
570 0 : freeaddrinfo (rp);
571 : }
572 0 : if (LocalDomain == NULL)
573 0 : LocalDomain = strdup ("");
574 : }
575 :
576 1 : consfile.f_type = F_CONSOLE;
577 1 : consfile.f_un.f_fname = strdup (ctty);
578 :
579 1 : signal (SIGTERM, die);
580 1 : signal (SIGINT, NoDetach ? die : SIG_IGN);
581 1 : signal (SIGQUIT, NoDetach ? die : SIG_IGN);
582 :
583 : #ifdef HAVE_SIGACTION
584 : /* Register repeatable actions portably! */
585 1 : sa.sa_flags = SA_RESTART;
586 1 : sigemptyset (&sa.sa_mask);
587 :
588 1 : sa.sa_handler = domark;
589 1 : (void) sigaction (SIGALRM, &sa, NULL);
590 :
591 1 : sa.sa_handler = NoDetach ? dbg_toggle : SIG_IGN;
592 1 : (void) sigaction (SIGUSR1, &sa, NULL);
593 : #else /* !HAVE_SIGACTION */
594 : signal (SIGALRM, domark);
595 : signal (SIGUSR1, NoDetach ? dbg_toggle : SIG_IGN);
596 : #endif
597 :
598 1 : alarm (TIMERINTVL);
599 :
600 : /* We add 3 = 1(klog) + 2(inet,inet6), even if they may stay unused. */
601 1 : fdarray = (struct pollfd *) malloc ((nfunix + 3) * sizeof (*fdarray));
602 1 : if (fdarray == NULL)
603 0 : error (EXIT_FAILURE, errno, "can't allocate fd table");
604 :
605 : /* read configuration file */
606 1 : init (0);
607 :
608 : #ifdef PATH_KLOG
609 : /* Initialize kernel logging and add to the list. */
610 1 : if (!NoKLog)
611 : {
612 1 : fklog = open (PATH_KLOG, O_RDONLY, 0);
613 1 : if (fklog >= 0)
614 : {
615 0 : fdarray[nfds].fd = fklog;
616 0 : fdarray[nfds].events = POLLIN | POLLPRI;
617 0 : nfds++;
618 0 : dbg_printf ("Klog open %s\n", PATH_KLOG);
619 : }
620 : else
621 1 : dbg_printf ("Can't open %s: %s\n", PATH_KLOG, strerror (errno));
622 : }
623 : #endif
624 :
625 : /* Initialize unix sockets. */
626 1 : if (!NoUnixAF)
627 : {
628 4 : for (i = 0; i < nfunix; i++)
629 : {
630 3 : funix[i].fd = create_unix_socket (funix[i].name);
631 3 : if (funix[i].fd >= 0)
632 : {
633 2 : fdarray[nfds].fd = funix[i].fd;
634 2 : fdarray[nfds].events = POLLIN | POLLPRI;
635 2 : nfds++;
636 2 : dbg_printf ("Opened UNIX socket `%s'.\n", funix[i].name);
637 : }
638 : else
639 1 : dbg_printf ("Can't open %s: %s\n", funix[i].name,
640 1 : strerror (errno));
641 : }
642 : }
643 :
644 : /* Initialize inet socket and add it to the list. */
645 1 : if (AcceptRemote)
646 : {
647 1 : create_inet_socket (usefamily, finet);
648 1 : if (finet[IU_FD_IP4] >= 0)
649 : {
650 : /* IPv4 socket is present. */
651 1 : fdarray[nfds].fd = finet[IU_FD_IP4];
652 1 : fdarray[nfds].events = POLLIN | POLLPRI;
653 1 : nfds++;
654 1 : dbg_printf ("Opened syslog UDP/IPv4 port.\n");
655 : }
656 1 : if (finet[IU_FD_IP6] >= 0)
657 : {
658 : /* IPv6 socket is present. */
659 1 : fdarray[nfds].fd = finet[IU_FD_IP6];
660 1 : fdarray[nfds].events = POLLIN | POLLPRI;
661 1 : nfds++;
662 1 : dbg_printf ("Opened syslog UDP/IPv6 port.\n");
663 : }
664 1 : if (finet[IU_FD_IP4] < 0 && finet[IU_FD_IP6] < 0)
665 0 : dbg_printf ("Can't open UDP port: %s\n", strerror (errno));
666 : }
667 :
668 : /* Tuck my process id away. */
669 1 : fp = fopen (PidFile, "w");
670 1 : if (fp != NULL)
671 : {
672 1 : fprintf (fp, "%d\n", (int) getpid ());
673 1 : fclose (fp);
674 : }
675 :
676 1 : dbg_printf ("off & running....\n");
677 :
678 : #ifdef HAVE_SIGACTION
679 : /* `sa' has been cleared already. */
680 1 : sa.sa_handler = trigger_restart;
681 1 : (void) sigaction (SIGHUP, &sa, NULL);
682 : #else /* !HAVE_SIGACTION */
683 : signal (SIGHUP, trigger_restart);
684 : #endif
685 :
686 1 : if (NoDetach)
687 : {
688 0 : dbg_output = 1;
689 0 : dbg_printf ("Debugging is disabled. Send SIGUSR1 to PID=%d "
690 : "to turn on debugging.\n", (int) getpid ());
691 0 : dbg_output = 0;
692 : }
693 :
694 : /* If we're doing waitdaemon(), tell the parent to exit,
695 : we are ready to roll. */
696 1 : if (ppid)
697 1 : kill (ppid, SIGTERM);
698 :
699 : for (;;)
700 : {
701 : int nready;
702 16 : nready = poll (fdarray, nfds, -1);
703 15 : if (nready == 0) /* ?? noop */
704 0 : continue;
705 :
706 : /* Sighup was dropped. */
707 15 : if (restart)
708 : {
709 1 : dbg_printf ("\nReceived SIGHUP, restarting syslogd.\n");
710 1 : init (0);
711 1 : restart = 0;
712 1 : continue;
713 : }
714 :
715 14 : if (nready < 0)
716 : {
717 0 : if (errno != EINTR)
718 0 : logerror ("poll");
719 0 : continue;
720 : }
721 :
722 : /*dbg_printf ("got a message (%d)\n", nready); */
723 :
724 70 : for (i = 0; i < nfds; i++)
725 56 : if (fdarray[i].revents & (POLLIN | POLLPRI))
726 : {
727 : int result;
728 : socklen_t len;
729 14 : if (fdarray[i].fd == -1)
730 0 : continue;
731 14 : else if (fdarray[i].fd == fklog)
732 : {
733 0 : result = read (fdarray[i].fd, &kline[kline_len],
734 : sizeof (kline) - kline_len - 1);
735 :
736 0 : if (result > 0)
737 : {
738 0 : kline_len += result;
739 : }
740 0 : else if (result < 0 && errno != EINTR)
741 : {
742 0 : logerror ("klog");
743 0 : fdarray[i].fd = fklog = -1;
744 : }
745 :
746 : while (1)
747 : {
748 : char *bol, *eol;
749 :
750 0 : kline[kline_len] = '\0';
751 :
752 0 : for (bol = kline, eol = strchr (kline, '\n'); eol;
753 0 : bol = eol, eol = strchr (bol, '\n'))
754 : {
755 0 : *(eol++) = '\0';
756 0 : kline_len -= (eol - bol);
757 0 : printsys (bol);
758 : }
759 :
760 : /* This loop makes sure the daemon won't lock up
761 : * on null bytes in the klog stream. They still hurt
762 : * efficiency, acting like a message separator that
763 : * forces a shift-and-reiterate when the buffer was
764 : * never full.
765 : */
766 0 : while (kline_len && !*bol)
767 : {
768 0 : bol++;
769 0 : kline_len--;
770 : }
771 :
772 0 : if (!kline_len)
773 0 : break;
774 :
775 0 : if (bol != kline)
776 : {
777 : /* shift the partial line to start of buffer, so
778 : * we can re-iterate.
779 : */
780 0 : memmove (kline, bol, kline_len);
781 : }
782 : else
783 : {
784 0 : if (kline_len < MAXLINE)
785 0 : break;
786 :
787 : /* The pathological case of a single message that
788 : * overfills our buffer. The best we can do is
789 : * log it in pieces.
790 : */
791 0 : printsys (kline);
792 :
793 : /* Clone priority signal if present
794 : * We merely shift the kline_len pointer after
795 : * it so the next chunk is written after it.
796 : *
797 : * strchr(kline,'>') is not used as it would allow
798 : * a pathological line ending in '>' to cause an
799 : * endless loop.
800 : */
801 0 : if (kline[0] == '<'
802 0 : && isdigit (kline[1]) && kline[2] == '>')
803 0 : kline_len = 3;
804 : else
805 0 : kline_len = 0;
806 : }
807 0 : }
808 : }
809 14 : else if (fdarray[i].fd == finet[IU_FD_IP4]
810 11 : || fdarray[i].fd == finet[IU_FD_IP6])
811 4 : {
812 : struct sockaddr_storage frominet;
813 : /*dbg_printf ("inet message\n"); */
814 4 : len = sizeof (frominet);
815 4 : memset (line, '\0', sizeof (line));
816 4 : result = recvfrom (fdarray[i].fd, line, MAXLINE, 0,
817 : (struct sockaddr *) &frominet, &len);
818 4 : if (result > 0)
819 : {
820 4 : line[result] = '\0';
821 4 : printline (cvthname ((struct sockaddr *) &frominet, len), line);
822 : }
823 0 : else if (result < 0 && errno != EINTR)
824 0 : logerror ("recvfrom inet");
825 : }
826 : else
827 : {
828 : struct sockaddr_un fromunix;
829 : /*dbg_printf ("unix message\n"); */
830 10 : len = sizeof (fromunix);
831 10 : result = recvfrom (fdarray[i].fd, line, MAXLINE, 0,
832 : (struct sockaddr *) &fromunix, &len);
833 10 : if (result > 0)
834 : {
835 10 : line[result] = '\0';
836 10 : printline (LocalHostName, line);
837 : }
838 0 : else if (result < 0 && errno != EINTR)
839 0 : logerror ("recvfrom unix");
840 : }
841 : }
842 42 : else if (fdarray[i].revents & POLLNVAL)
843 : {
844 0 : logerror ("poll nval\n");
845 0 : fdarray[i].fd = -1;
846 : }
847 42 : else if (fdarray[i].revents & POLLERR)
848 0 : logerror ("poll err\n");
849 42 : else if (fdarray[i].revents & POLLHUP)
850 0 : logerror ("poll hup\n");
851 15 : } /* for (;;) */
852 : } /* main */
853 :
854 : #ifndef SUN_LEN
855 : # define SUN_LEN(unp) (strlen((unp)->sun_path) + 3)
856 : #endif
857 :
858 : static void
859 3 : add_funix (const char *name)
860 : {
861 3 : funix = realloc (funix, (nfunix + 1) * sizeof (*funix));
862 3 : if (funix == NULL)
863 0 : error (EXIT_FAILURE, errno, "cannot allocate space for unix sockets");
864 :
865 3 : funix[nfunix].name = name;
866 3 : funix[nfunix].fd = -1;
867 3 : nfunix++;
868 3 : }
869 :
870 : static int
871 3 : create_unix_socket (const char *path)
872 : {
873 : int fd;
874 : struct sockaddr_un sunx;
875 : char line[MAXLINE + 1];
876 :
877 3 : if (path[0] == '\0')
878 0 : return -1;
879 :
880 3 : if (strlen (path) >= sizeof (sunx.sun_path))
881 : {
882 1 : snprintf (line, sizeof (line), "UNIX socket name too long: %s", path);
883 1 : logerror (line);
884 1 : return -1;
885 : }
886 :
887 2 : unlink (path);
888 :
889 2 : memset (&sunx, 0, sizeof (sunx));
890 2 : sunx.sun_family = AF_UNIX;
891 2 : strncpy (sunx.sun_path, path, sizeof (sunx.sun_path) - 1);
892 2 : fd = socket (AF_UNIX, SOCK_DGRAM, 0);
893 2 : if (fd < 0 || bind (fd, (struct sockaddr *) &sunx, SUN_LEN (&sunx)) < 0
894 2 : || chmod (path, 0666) < 0)
895 : {
896 0 : snprintf (line, sizeof (line), "cannot create %s", path);
897 0 : logerror (line);
898 0 : dbg_printf ("cannot create %s: %s\n", path, strerror (errno));
899 0 : close (fd);
900 0 : fd = -1;
901 : }
902 2 : return fd;
903 : }
904 :
905 : static void
906 1 : create_inet_socket (int af, int fd46[2])
907 : {
908 1 : int err, fd = -1;
909 : struct addrinfo hints, *rp, *ai;
910 :
911 : /* Invalidate old descriptors. */
912 1 : fd46[IU_FD_IP4] = fd46[IU_FD_IP6] = -1;
913 :
914 1 : if (!LogPortText)
915 : {
916 0 : dbg_printf ("No listen port has been accepted.\n");
917 0 : return;
918 : }
919 :
920 1 : memset (&hints, 0, sizeof (hints));
921 1 : hints.ai_family = af;
922 1 : hints.ai_socktype = SOCK_DGRAM;
923 1 : hints.ai_flags = AI_PASSIVE;
924 :
925 1 : err = getaddrinfo (BindAddress, LogPortText, &hints, &rp);
926 1 : if (err)
927 : {
928 0 : logerror ("lookup error, suspending inet service");
929 0 : return;
930 : }
931 :
932 3 : for (ai = rp; ai; ai = ai->ai_next)
933 : {
934 2 : int yes = 1;
935 :
936 2 : fd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
937 2 : if (fd < 0)
938 0 : continue;
939 :
940 2 : err = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes));
941 2 : if (err < 0)
942 0 : logerror ("failed to set SO_REUSEADDR");
943 :
944 2 : if (ai->ai_family == AF_INET6)
945 : {
946 : /* Avoid dual stacked sockets. Better to use distinct sockets. */
947 1 : (void) setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof (yes));
948 : }
949 :
950 2 : if (bind (fd, ai->ai_addr, ai->ai_addrlen) < 0)
951 : {
952 0 : close (fd);
953 0 : fd = -1;
954 0 : continue;
955 : }
956 : /* Register any success. */
957 2 : if (ai->ai_family == AF_INET && fd46[IU_FD_IP4] < 0)
958 1 : fd46[IU_FD_IP4] = fd;
959 1 : else if (ai->ai_family == AF_INET6 && fd46[IU_FD_IP6] < 0)
960 1 : fd46[IU_FD_IP6] = fd;
961 : }
962 1 : freeaddrinfo (rp);
963 :
964 1 : if (fd46[IU_FD_IP4] < 0 && fd46[IU_FD_IP6] < 0)
965 : {
966 0 : logerror ("inet service, failed lookup.");
967 0 : return;
968 : }
969 1 : return;
970 : }
971 :
972 : char **
973 0 : crunch_list (char **oldlist, char *list)
974 : {
975 : int count, i;
976 : char *p, *q;
977 :
978 0 : p = list;
979 :
980 : /* Strip off trailing delimiters. */
981 0 : while (p[strlen (p) - 1] == LIST_DELIMITER)
982 : {
983 0 : p[strlen (p) - 1] = '\0';
984 : }
985 : /* Cut off leading delimiters. */
986 0 : while (p[0] == LIST_DELIMITER)
987 : {
988 0 : p++;
989 : }
990 :
991 : /* Bailout early the string is empty. */
992 0 : if (*p == '\0')
993 0 : return oldlist;
994 :
995 : /* Count delimiters to calculate elements. */
996 0 : for (count = 1, i = 0; p[i]; i++)
997 0 : if (p[i] == LIST_DELIMITER)
998 0 : count++;
999 :
1000 : /* Count how many we add in the old list. */
1001 0 : for (i = 0; oldlist && oldlist[i]; i++)
1002 : ;
1003 :
1004 : /* allocate enough space */
1005 0 : oldlist = (char **) realloc (oldlist, (i + count + 1) * sizeof (*oldlist));
1006 0 : if (oldlist == NULL)
1007 0 : error (EXIT_FAILURE, errno, "can't allocate memory");
1008 :
1009 : /*
1010 : We now can assume that the first and last
1011 : characters are different from any delimiters,
1012 : so we don't have to care about it anymore. */
1013 :
1014 : /* Start from where we left last time. */
1015 0 : for (count = i; (q = strchr (p, LIST_DELIMITER)) != NULL;
1016 0 : count++, p = q, p++)
1017 : {
1018 0 : oldlist[count] = (char *) malloc ((q - p + 1) * sizeof (char));
1019 0 : if (oldlist[count] == NULL)
1020 0 : error (EXIT_FAILURE, errno, "can't allocate memory");
1021 :
1022 0 : strncpy (oldlist[count], p, q - p);
1023 0 : oldlist[count][q - p] = '\0';
1024 : }
1025 :
1026 : /* take the last one */
1027 0 : oldlist[count] = (char *) xmalloc ((strlen (p) + 1) * sizeof (char));
1028 0 : if (oldlist[count] == NULL)
1029 0 : error (EXIT_FAILURE, errno, "can't allocate memory");
1030 :
1031 0 : strcpy (oldlist[count], p);
1032 :
1033 0 : oldlist[++count] = NULL; /* terminate the array with a NULL */
1034 :
1035 0 : if (Debug)
1036 : {
1037 0 : for (count = 0; oldlist[count]; count++)
1038 0 : printf ("#%d: %s\n", count, oldlist[count]);
1039 : }
1040 0 : return oldlist;
1041 : }
1042 :
1043 : /* Take a raw input line, decode the message, and print the message on
1044 : the appropriate log files. */
1045 : void
1046 14 : printline (const char *hname, const char *msg)
1047 : {
1048 : int c, pri;
1049 : const char *p;
1050 : char *q, line[MAXLINE + 1];
1051 :
1052 : /* test for special codes */
1053 14 : pri = DEFUPRI;
1054 14 : p = msg;
1055 14 : if (*p == '<')
1056 : {
1057 14 : pri = 0;
1058 58 : while (isdigit (*++p))
1059 30 : pri = 10 * pri + (*p - '0');
1060 14 : if (*p == '>')
1061 14 : ++p;
1062 : }
1063 :
1064 : /* This overrides large positive and overflowing negative values. */
1065 14 : if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
1066 0 : pri = DEFUPRI;
1067 :
1068 : /* Avoid undefined facilities. */
1069 14 : if (LOG_FAC (pri) > LOG_NFACILITIES)
1070 1 : pri = DEFUPRI;
1071 :
1072 : /* Do not allow users to log kernel messages. */
1073 14 : if (LOG_FAC (pri) == (LOG_KERN >> 3))
1074 0 : pri = LOG_MAKEPRI (LOG_USER, LOG_PRI (pri));
1075 :
1076 14 : q = line;
1077 1088 : while ((c = *p++) != '\0' && q < &line[sizeof (line) - 1])
1078 1060 : if (iscntrl (c))
1079 0 : if (c == '\n')
1080 0 : *q++ = ' ';
1081 0 : else if (c == '\t')
1082 0 : *q++ = '\t';
1083 0 : else if (c >= 0177)
1084 0 : *q++ = c;
1085 : else
1086 : {
1087 0 : *q++ = '^';
1088 0 : *q++ = c ^ 0100;
1089 : }
1090 : else
1091 1060 : *q++ = c;
1092 14 : *q = '\0';
1093 :
1094 : /* This for the default behaviour on GNU/Linux syslogd who
1095 : sync on every line. */
1096 14 : if (force_sync)
1097 0 : logmsg (pri, line, hname, SYNC_FILE);
1098 : else
1099 14 : logmsg (pri, line, hname, 0);
1100 14 : }
1101 :
1102 : /* Take a raw input line from /dev/klog, split and format similar to
1103 : syslog(). */
1104 : void
1105 0 : printsys (const char *msg)
1106 : {
1107 : int c, pri, flags;
1108 : char *lp, *q, line[MAXLINE + 1];
1109 : const char *p;
1110 :
1111 0 : strcpy (line, "vmunix: ");
1112 0 : lp = line + strlen (line);
1113 0 : for (p = msg; *p != '\0';)
1114 : {
1115 0 : flags = SYNC_FILE | ADDDATE; /* Fsync after write. */
1116 0 : pri = DEFSPRI;
1117 0 : if (*p == '<')
1118 : {
1119 0 : pri = 0;
1120 0 : while (isdigit (*++p))
1121 0 : pri = 10 * pri + (*p - '0');
1122 0 : if (*p == '>')
1123 0 : ++p;
1124 : }
1125 : else
1126 : {
1127 : /* kernel printf's come out on console */
1128 0 : flags |= IGN_CONS;
1129 : }
1130 0 : if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
1131 0 : pri = DEFSPRI;
1132 0 : q = lp;
1133 0 : while (*p != '\0' && (c = *p++) != '\n' && q < &line[MAXLINE])
1134 0 : *q++ = c;
1135 0 : *q = '\0';
1136 0 : logmsg (pri, line, LocalHostName, flags);
1137 : }
1138 0 : }
1139 :
1140 : /* Decode a priority into textual information like auth.emerg. */
1141 : char *
1142 24 : textpri (int pri)
1143 : {
1144 : static char res[20];
1145 : CODE *c_pri, *c_fac;
1146 :
1147 319 : for (c_fac = facilitynames; c_fac->c_name
1148 566 : && !(c_fac->c_val == LOG_FAC (pri) << 3); c_fac++);
1149 178 : for (c_pri = prioritynames; c_pri->c_name
1150 284 : && !(c_pri->c_val == LOG_PRI (pri)); c_pri++);
1151 :
1152 24 : snprintf (res, sizeof (res), "%s.%s", c_fac->c_name, c_pri->c_name);
1153 :
1154 24 : return res;
1155 : }
1156 :
1157 : /* Log a message to the appropriate log files, users, etc. based on
1158 : the priority. */
1159 : void
1160 24 : logmsg (int pri, const char *msg, const char *from, int flags)
1161 : {
1162 : struct filed *f;
1163 : int fac, msglen, prilev;
1164 : #ifdef HAVE_SIGACTION
1165 : sigset_t sigs, osigs;
1166 : #else
1167 : int omask;
1168 : #endif
1169 :
1170 : const char *timestamp;
1171 :
1172 24 : dbg_printf ("(logmsg): %s (%d), flags %x, from %s, msg %s\n",
1173 : textpri (pri), pri, flags, from, msg);
1174 :
1175 : #ifdef HAVE_SIGACTION
1176 24 : sigemptyset (&sigs);
1177 24 : sigaddset (&sigs, SIGHUP);
1178 24 : sigaddset (&sigs, SIGALRM);
1179 24 : sigprocmask (SIG_BLOCK, &sigs, &osigs);
1180 : #else
1181 : omask = sigblock (sigmask (SIGHUP) | sigmask (SIGALRM));
1182 : #endif
1183 :
1184 : /* Check to see if msg looks non-standard. */
1185 24 : msglen = strlen (msg);
1186 38 : if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
1187 28 : msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
1188 10 : flags |= ADDDATE;
1189 :
1190 24 : time (&now);
1191 24 : if (flags & ADDDATE)
1192 10 : timestamp = ctime (&now) + 4;
1193 : else
1194 : {
1195 14 : if (set_local_time)
1196 0 : timestamp = ctime (&now) + 4;
1197 : else
1198 14 : timestamp = msg;
1199 14 : msg += 16;
1200 14 : msglen -= 16;
1201 : }
1202 :
1203 : /* Extract facility and priority level. */
1204 24 : if (flags & MARK)
1205 : #ifdef INTERNAL_MARK
1206 0 : fac = LOG_FAC (INTERNAL_MARK);
1207 : #else
1208 : fac = LOG_NFACILITIES;
1209 : #endif
1210 : else
1211 24 : fac = LOG_FAC (pri);
1212 24 : prilev = LOG_PRI (pri);
1213 :
1214 : /* Log the message to the particular outputs. */
1215 24 : if (!Initialized)
1216 : {
1217 6 : f = &consfile;
1218 6 : f->f_file = open (ctty, O_WRONLY, 0);
1219 6 : f->f_prevhost = strdup (LocalHostName);
1220 6 : if (f->f_file >= 0)
1221 : {
1222 6 : fprintlog (f, from, flags, msg);
1223 6 : close (f->f_file);
1224 : }
1225 : #ifdef HAVE_SIGACTION
1226 6 : sigprocmask (SIG_SETMASK, &osigs, 0);
1227 : #else
1228 : sigsetmask (omask);
1229 : #endif
1230 30 : return;
1231 : }
1232 129 : for (f = Files; f; f = f->f_next)
1233 : {
1234 : /* Skip messages that are incorrect priority. */
1235 111 : if (!(f->f_pmask[fac] & LOG_MASK (prilev)))
1236 75 : continue;
1237 :
1238 36 : if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
1239 0 : continue;
1240 :
1241 : /* Don't output marks to recently written files. */
1242 36 : if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
1243 0 : continue;
1244 :
1245 36 : if (f->f_progname)
1246 : {
1247 : /* The usual, and desirable, formattings are:
1248 : *
1249 : * prg: message text
1250 : * prg[PIDNO]: message text
1251 : */
1252 :
1253 : /* Skip on selector mismatch. */
1254 0 : if (strncmp (msg, f->f_progname, f->f_prognlen))
1255 0 : continue;
1256 :
1257 : /* Avoid matching on prefixes. */
1258 0 : if (isalnum (msg[f->f_prognlen])
1259 0 : || msg[f->f_prognlen] == '-'
1260 0 : || msg[f->f_prognlen] == '_')
1261 0 : continue;
1262 : }
1263 :
1264 : /* Suppress duplicate lines to this file. */
1265 36 : if ((flags & MARK) == 0 && msglen == f->f_prevlen && f->f_prevhost
1266 2 : && !strcmp (msg, f->f_prevline) && !strcmp (from, f->f_prevhost))
1267 : {
1268 0 : strncpy (f->f_lasttime, timestamp, sizeof (f->f_lasttime) - 1);
1269 0 : f->f_prevcount++;
1270 0 : dbg_printf ("msg repeated %d times, %ld sec of %d\n",
1271 0 : f->f_prevcount, now - f->f_time,
1272 0 : repeatinterval[f->f_repeatcount]);
1273 : /* If domark would have logged this by now, flush it now (so we
1274 : don't hold isolated messages), but back off so we'll flush
1275 : less often in the future. */
1276 0 : if (now > REPEATTIME (f))
1277 : {
1278 0 : fprintlog (f, from, flags, (char *) NULL);
1279 0 : BACKOFF (f);
1280 : }
1281 : }
1282 : else
1283 : {
1284 : /* New line, save it. */
1285 36 : if (f->f_prevcount)
1286 0 : fprintlog (f, from, 0, (char *) NULL);
1287 36 : f->f_repeatcount = 0;
1288 36 : strncpy (f->f_lasttime, timestamp, sizeof (f->f_lasttime) - 1);
1289 36 : free (f->f_prevhost);
1290 36 : f->f_prevhost = strdup (from);
1291 36 : if (msglen < MAXSVLINE)
1292 : {
1293 36 : f->f_prevlen = msglen;
1294 36 : f->f_prevpri = pri;
1295 36 : strcpy (f->f_prevline, msg);
1296 36 : fprintlog (f, from, flags, (char *) NULL);
1297 : }
1298 : else
1299 : {
1300 0 : f->f_prevline[0] = 0;
1301 0 : f->f_prevlen = 0;
1302 0 : fprintlog (f, from, flags, msg);
1303 : }
1304 : }
1305 : }
1306 : #ifdef HAVE_SIGACTION
1307 18 : sigprocmask (SIG_SETMASK, &osigs, 0);
1308 : #else
1309 : sigsetmask (omask);
1310 : #endif
1311 : }
1312 :
1313 : void
1314 42 : fprintlog (struct filed *f, const char *from, int flags, const char *msg)
1315 : {
1316 : struct iovec iov[IOVCNT];
1317 : struct iovec *v;
1318 : int l;
1319 : char line[MAXLINE + 1], repbuf[80], greetings[200];
1320 : time_t fwd_suspend;
1321 :
1322 42 : v = iov;
1323 : /* Be paranoid. */
1324 42 : memset (v, 0, sizeof (struct iovec) * IOVCNT);
1325 42 : if (f->f_type == F_WALL)
1326 : {
1327 0 : v->iov_base = greetings;
1328 0 : snprintf (greetings, sizeof (greetings),
1329 : "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
1330 : f->f_prevhost, ctime (&now));
1331 0 : v->iov_len = strlen (greetings);
1332 0 : v++;
1333 0 : v->iov_base = (char *) "";
1334 0 : v->iov_len = 0;
1335 0 : v++;
1336 : }
1337 : else
1338 : {
1339 42 : v->iov_base = f->f_lasttime;
1340 42 : v->iov_len = sizeof (f->f_lasttime) - 1;
1341 42 : v++;
1342 42 : v->iov_base = (char *) " ";
1343 42 : v->iov_len = 1;
1344 42 : v++;
1345 : }
1346 42 : if (f->f_prevhost)
1347 : {
1348 42 : v->iov_base = f->f_prevhost;
1349 42 : v->iov_len = strlen (v->iov_base);
1350 42 : v++;
1351 : }
1352 42 : v->iov_base = (char *) " ";
1353 42 : v->iov_len = 1;
1354 42 : v++;
1355 :
1356 42 : if (msg)
1357 : {
1358 6 : v->iov_base = (char *) msg;
1359 6 : v->iov_len = strlen (msg);
1360 : }
1361 36 : else if (f->f_prevcount > 1)
1362 : {
1363 0 : v->iov_base = repbuf;
1364 0 : snprintf (repbuf, sizeof (repbuf), "last message repeated %d times",
1365 : f->f_prevcount);
1366 0 : v->iov_len = strlen (repbuf);
1367 : }
1368 : else
1369 : {
1370 36 : v->iov_base = f->f_prevline;
1371 36 : v->iov_len = f->f_prevlen;
1372 : }
1373 42 : v++;
1374 :
1375 42 : dbg_printf ("Logging to %s", TypeNames[f->f_type]);
1376 :
1377 42 : switch (f->f_type)
1378 : {
1379 : case F_UNUSED:
1380 7 : f->f_time = now;
1381 7 : dbg_printf ("\n");
1382 7 : break;
1383 :
1384 : case F_FORW_SUSP:
1385 0 : fwd_suspend = time ((time_t *) 0) - f->f_time;
1386 0 : if (fwd_suspend >= INET_SUSPEND_TIME)
1387 : {
1388 0 : dbg_printf ("\nForwarding suspension over, retrying FORW ");
1389 0 : f->f_type = F_FORW;
1390 0 : goto f_forw;
1391 : }
1392 : else
1393 : {
1394 0 : dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
1395 0 : dbg_printf ("Forwarding suspension not over, time left: %d.\n",
1396 : INET_SUSPEND_TIME - fwd_suspend);
1397 : }
1398 0 : break;
1399 :
1400 : case F_FORW_UNKN:
1401 0 : dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
1402 0 : fwd_suspend = time ((time_t *) 0) - f->f_time;
1403 0 : if (fwd_suspend >= INET_SUSPEND_TIME)
1404 : {
1405 : struct addrinfo hints, *rp;
1406 : int err;
1407 :
1408 0 : memset (&hints, 0, sizeof (hints));
1409 0 : hints.ai_family = usefamily;
1410 : #ifdef AI_ADDRCONFIG
1411 0 : if (usefamily == AF_UNSPEC)
1412 0 : hints.ai_flags |= AI_ADDRCONFIG;
1413 : #endif
1414 0 : err = getaddrinfo (f->f_un.f_forw.f_hname, LogForwardPort,
1415 : &hints, &rp);
1416 0 : if (err)
1417 : {
1418 0 : dbg_printf ("Failure: %s\n", gai_strerror (err));
1419 0 : dbg_printf ("Retries: %d\n", f->f_prevcount);
1420 0 : if (--f->f_prevcount < 0)
1421 : {
1422 0 : f->f_type = F_UNUSED;
1423 0 : free (f->f_un.f_forw.f_hname);
1424 0 : f->f_un.f_forw.f_hname = NULL;
1425 : }
1426 : }
1427 : else
1428 : {
1429 0 : dbg_printf ("%s found, resuming.\n", f->f_un.f_forw.f_hname);
1430 0 : f->f_un.f_forw.f_addrlen = rp->ai_addrlen;
1431 0 : memcpy (&f->f_un.f_forw.f_addr, rp->ai_addr, rp->ai_addrlen);
1432 0 : freeaddrinfo (rp);
1433 0 : f->f_prevcount = 0;
1434 0 : f->f_type = F_FORW;
1435 0 : goto f_forw;
1436 : }
1437 : }
1438 : else
1439 0 : dbg_printf ("Forwarding suspension not over, time left: %d\n",
1440 : INET_SUSPEND_TIME - fwd_suspend);
1441 0 : break;
1442 :
1443 : case F_FORW:
1444 : f_forw:
1445 0 : dbg_printf (" %s\n", f->f_un.f_forw.f_hname);
1446 0 : if (strcasecmp (from, LocalHostName) && NoHops)
1447 0 : dbg_printf ("Not forwarding remote message.\n");
1448 0 : else if (NoForward)
1449 0 : dbg_printf ("Not forwarding because forwarding is disabled.\n");
1450 : else
1451 : {
1452 : int temp_finet, *pfinet; /* PFINET points to active fd. */
1453 :
1454 0 : if (f->f_un.f_forw.f_addr.ss_family == AF_INET)
1455 0 : pfinet = &finet[IU_FD_IP4];
1456 : else /* AF_INET6 */
1457 0 : pfinet = &finet[IU_FD_IP6];
1458 :
1459 0 : temp_finet = *pfinet;
1460 :
1461 0 : if (temp_finet < 0)
1462 : {
1463 : int err;
1464 : struct addrinfo hints, *rp;
1465 :
1466 : /* Forwarding needs a temporary socket.
1467 : * The source port is fixed! */
1468 0 : memset (&hints, 0, sizeof (hints));
1469 0 : hints.ai_family = f->f_un.f_forw.f_addr.ss_family;
1470 0 : hints.ai_socktype = SOCK_DGRAM;
1471 0 : hints.ai_flags = AI_PASSIVE;
1472 :
1473 0 : err = getaddrinfo (NULL, LogForwardPort, &hints, &rp);
1474 0 : if (err)
1475 : {
1476 0 : dbg_printf ("Not forwarding due to lookup failure: %s.\n",
1477 : gai_strerror(err));
1478 0 : break;
1479 : }
1480 0 : temp_finet = socket (rp->ai_family, rp->ai_socktype,
1481 0 : rp->ai_protocol);
1482 0 : if (temp_finet < 0)
1483 : {
1484 0 : dbg_printf ("Not forwarding due to socket failure.\n");
1485 0 : freeaddrinfo (rp);
1486 0 : break;
1487 : }
1488 :
1489 0 : err = bind (temp_finet, rp->ai_addr, rp->ai_addrlen);
1490 0 : freeaddrinfo (rp);
1491 0 : if (err)
1492 : {
1493 0 : dbg_printf ("Not forwarding due to bind error: %s.\n",
1494 0 : strerror (errno));
1495 0 : break;
1496 : }
1497 : } /* Creation of temporary outgoing socket since "finet < 0" */
1498 :
1499 0 : f->f_time = now;
1500 0 : snprintf (line, sizeof (line), "<%d>%.15s %s",
1501 0 : f->f_prevpri, (char *) iov[0].iov_base,
1502 0 : (char *) iov[4].iov_base);
1503 0 : l = strlen (line);
1504 0 : if (l > MAXLINE)
1505 0 : l = MAXLINE;
1506 0 : if (sendto (temp_finet, line, l, 0,
1507 0 : (struct sockaddr *) &f->f_un.f_forw.f_addr,
1508 0 : f->f_un.f_forw.f_addrlen) != l)
1509 : {
1510 0 : int e = errno;
1511 0 : dbg_printf ("INET sendto error: %d = %s.\n", e, strerror (e));
1512 0 : f->f_type = F_FORW_SUSP;
1513 0 : errno = e;
1514 0 : logerror ("sendto");
1515 : }
1516 :
1517 0 : if (*pfinet < 0)
1518 0 : close (temp_finet); /* Only temporary socket may be closed. */
1519 : }
1520 0 : break;
1521 :
1522 : case F_CONSOLE:
1523 6 : f->f_time = now;
1524 6 : if (flags & IGN_CONS)
1525 : {
1526 0 : dbg_printf (" (ignored)\n");
1527 0 : break;
1528 : }
1529 :
1530 : case F_TTY:
1531 : case F_FILE:
1532 : case F_PIPE:
1533 35 : f->f_time = now;
1534 35 : dbg_printf (" %s\n", f->f_un.f_fname);
1535 35 : if (f->f_type == F_TTY || f->f_type == F_CONSOLE)
1536 : {
1537 6 : v->iov_base = (char *) "\r\n";
1538 6 : v->iov_len = 2;
1539 : }
1540 : else
1541 : {
1542 29 : v->iov_base = (char *) "\n";
1543 29 : v->iov_len = 1;
1544 : }
1545 : again:
1546 35 : if (writev (f->f_file, iov, IOVCNT) < 0)
1547 : {
1548 0 : int e = errno;
1549 :
1550 : /* XXX: If a named pipe is full, ignore it. */
1551 0 : if (f->f_type == F_PIPE && e == EAGAIN)
1552 0 : break;
1553 :
1554 0 : close (f->f_file);
1555 : /* Check for errors on TTY's due to loss of tty. */
1556 0 : if ((e == EIO || e == EBADF)
1557 0 : && (f->f_type == F_TTY || f->f_type == F_CONSOLE))
1558 : {
1559 0 : f->f_file = open (f->f_un.f_fname, O_WRONLY | O_APPEND, 0);
1560 0 : if (f->f_file < 0)
1561 : {
1562 0 : f->f_type = F_UNUSED;
1563 0 : logerror (f->f_un.f_fname);
1564 0 : free (f->f_un.f_fname);
1565 0 : f->f_un.f_fname = NULL;
1566 : }
1567 : else
1568 0 : goto again;
1569 : }
1570 : else
1571 : {
1572 0 : f->f_type = F_UNUSED;
1573 0 : errno = e;
1574 0 : logerror (f->f_un.f_fname);
1575 0 : free (f->f_un.f_fname);
1576 0 : f->f_un.f_fname = NULL;
1577 : }
1578 : }
1579 35 : else if ((flags & SYNC_FILE) && !(f->f_flags & OMIT_SYNC))
1580 0 : fsync (f->f_file);
1581 35 : break;
1582 :
1583 : case F_USERS:
1584 : case F_WALL:
1585 0 : f->f_time = now;
1586 0 : dbg_printf ("\n");
1587 0 : v->iov_base = (char *) "\r\n";
1588 0 : v->iov_len = 2;
1589 0 : wallmsg (f, iov);
1590 0 : break;
1591 : }
1592 :
1593 42 : if (f->f_type != F_FORW_UNKN)
1594 42 : f->f_prevcount = 0;
1595 42 : }
1596 :
1597 : /* Write the specified message to either the entire world,
1598 : * or to a list of approved users. */
1599 : void
1600 0 : wallmsg (struct filed *f, struct iovec *iov)
1601 : {
1602 : static int reenter; /* Avoid calling ourselves. */
1603 : STRUCT_UTMP *utp;
1604 : #if defined UTMP_NAME_FUNCTION || !defined HAVE_GETUTXENT
1605 : STRUCT_UTMP *utmpbuf;
1606 : size_t utmp_count;
1607 : #endif /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
1608 : int i;
1609 : char *p;
1610 : char line[sizeof (utp->ut_line) + 1];
1611 :
1612 0 : if (reenter++)
1613 0 : return;
1614 :
1615 : #if !defined UTMP_NAME_FUNCTION && defined HAVE_GETUTXENT
1616 : setutxent ();
1617 :
1618 : while ((utp = getutxent ()))
1619 : #else /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
1620 0 : if (read_utmp (UTMP_FILE, &utmp_count, &utmpbuf,
1621 : READ_UTMP_USER_PROCESS | READ_UTMP_CHECK_PIDS) < 0)
1622 : {
1623 0 : logerror ("opening utmp file");
1624 0 : return;
1625 : }
1626 :
1627 0 : for (utp = utmpbuf; utp < utmpbuf + utmp_count; utp++)
1628 : #endif /* UTMP_NAME_FUNCTION || !HAVE_GETUTXENT */
1629 : {
1630 0 : strncpy (line, utp->ut_line, sizeof (utp->ut_line));
1631 0 : line[sizeof (utp->ut_line)] = '\0';
1632 0 : if (f->f_type == F_WALL)
1633 : {
1634 : /* Note we're using our own version of ttymsg
1635 : which does a double fork () to not have
1636 : zombies. No need to waitpid(). */
1637 0 : p = ttymsg (iov, IOVCNT, line, TTYMSGTIME);
1638 0 : if (p != NULL)
1639 : {
1640 0 : errno = 0; /* Already in message. */
1641 0 : logerror (p);
1642 : }
1643 0 : continue;
1644 : }
1645 : /* Should we send the message to this user? */
1646 0 : for (i = 0; i < f->f_un.f_user.f_nusers; i++)
1647 0 : if (!strncmp (f->f_un.f_user.f_unames[i], UT_USER (utp),
1648 : sizeof (UT_USER (utp))))
1649 : {
1650 0 : p = ttymsg (iov, IOVCNT, line, TTYMSGTIME);
1651 0 : if (p != NULL)
1652 : {
1653 0 : errno = 0; /* Already in message. */
1654 0 : logerror (p);
1655 : }
1656 0 : break;
1657 : }
1658 : }
1659 : #if defined UTMP_NAME_FUNCTION || !defined HAVE_GETUTXENT
1660 0 : free (utmpbuf);
1661 : #else /* !UTMP_NAME_FUNCTION && HAVE_GETUTXENT */
1662 : endutxent ();
1663 : #endif
1664 0 : reenter = 0;
1665 : }
1666 :
1667 : /* Return a printable representation of a host address. */
1668 : const char *
1669 4 : cvthname (struct sockaddr *f, socklen_t len)
1670 : {
1671 : int err;
1672 : char *p;
1673 :
1674 4 : err = getnameinfo (f, len, addrstr, sizeof (addrstr),
1675 : NULL, 0, NI_NUMERICHOST);
1676 4 : if (err)
1677 : {
1678 0 : dbg_printf ("Malformed from address: %s.\n",
1679 : gai_strerror (err));
1680 0 : return "???";
1681 : }
1682 :
1683 4 : dbg_printf ("cvthname(%s)\n", addrstr);
1684 :
1685 4 : err = getnameinfo (f, len, addrname, sizeof (addrname),
1686 : NULL, 0, NI_NAMEREQD);
1687 4 : if (err)
1688 : {
1689 0 : dbg_printf ("Host name for your address (%s) unknown.\n", addrstr);
1690 0 : return addrstr;
1691 : }
1692 :
1693 4 : p = strchr (addrname, '.');
1694 4 : if (p != NULL)
1695 : {
1696 4 : if (strcasecmp (p + 1, LocalDomain) == 0)
1697 0 : *p = '\0';
1698 : else
1699 : {
1700 : int count;
1701 :
1702 4 : if (StripDomains)
1703 : {
1704 0 : count = 0;
1705 0 : while (StripDomains[count])
1706 : {
1707 0 : if (strcasecmp (p + 1, StripDomains[count]) == 0)
1708 : {
1709 0 : *p = '\0';
1710 0 : return addrname;
1711 : }
1712 0 : count++;
1713 : }
1714 : }
1715 4 : if (LocalHosts)
1716 : {
1717 0 : count = 0;
1718 0 : while (LocalHosts[count])
1719 : {
1720 0 : if (strcasecmp (addrname, LocalHosts[count]) == 0)
1721 : {
1722 0 : *p = '\0';
1723 0 : return addrname;
1724 : }
1725 0 : count++;
1726 : }
1727 : }
1728 : }
1729 : }
1730 4 : return addrname;
1731 : }
1732 :
1733 : void
1734 0 : domark (int signo _GL_UNUSED_PARAMETER)
1735 : {
1736 : struct filed *f;
1737 :
1738 0 : now = time ((time_t *) NULL);
1739 0 : if (MarkInterval > 0)
1740 : {
1741 0 : MarkSeq += TIMERINTVL;
1742 0 : if (MarkSeq >= MarkInterval)
1743 : {
1744 0 : logmsg (LOG_INFO, "-- MARK --", LocalHostName, ADDDATE | MARK);
1745 0 : MarkSeq = 0;
1746 : }
1747 : }
1748 :
1749 0 : for (f = Files; f; f = f->f_next)
1750 : {
1751 0 : if (f->f_prevcount && now >= REPEATTIME (f))
1752 : {
1753 0 : dbg_printf ("flush %s: repeated %d times, %d sec.\n",
1754 0 : TypeNames[f->f_type], f->f_prevcount,
1755 0 : repeatinterval[f->f_repeatcount]);
1756 0 : fprintlog (f, LocalHostName, 0, (char *) NULL);
1757 0 : BACKOFF (f);
1758 : }
1759 : }
1760 :
1761 : #ifndef HAVE_SIGACTION
1762 : signal (SIGALRM, domark);
1763 : #endif
1764 0 : alarm (TIMERINTVL);
1765 0 : }
1766 :
1767 : /* Print syslogd errors some place. */
1768 : void
1769 8 : logerror (const char *type)
1770 : {
1771 : char buf[100];
1772 :
1773 8 : if (errno)
1774 1 : snprintf (buf, sizeof (buf), "syslogd: %s: %s", type, strerror (errno));
1775 : else
1776 7 : snprintf (buf, sizeof (buf), "syslogd: %s", type);
1777 8 : errno = 0;
1778 8 : dbg_printf ("%s\n", buf);
1779 8 : logmsg (LOG_SYSLOG | LOG_ERR, buf, LocalHostName, ADDDATE);
1780 8 : }
1781 :
1782 : void
1783 0 : doexit (int signo _GL_UNUSED_PARAMETER)
1784 : {
1785 0 : _exit (EXIT_SUCCESS);
1786 : }
1787 :
1788 : void
1789 1 : die (int signo)
1790 : {
1791 : struct filed *f;
1792 1 : int was_initialized = Initialized;
1793 : char buf[100];
1794 : size_t i;
1795 :
1796 1 : Initialized = 0; /* Don't log SIGCHLDs. */
1797 6 : for (f = Files; f != NULL; f = f->f_next)
1798 : {
1799 : /* Flush any pending output. */
1800 5 : if (f->f_prevcount)
1801 0 : fprintlog (f, LocalHostName, 0, (char *) NULL);
1802 : }
1803 1 : Initialized = was_initialized;
1804 1 : if (signo)
1805 : {
1806 1 : dbg_printf ("%s: exiting on signal %d\n",
1807 : program_invocation_name, signo);
1808 1 : snprintf (buf, sizeof (buf), "exiting on signal %d", signo);
1809 1 : errno = 0;
1810 1 : logerror (buf);
1811 : }
1812 :
1813 1 : if (fklog >= 0)
1814 0 : close (fklog);
1815 :
1816 4 : for (i = 0; i < nfunix; i++)
1817 3 : if (funix[i].fd >= 0)
1818 : {
1819 2 : close (funix[i].fd);
1820 2 : if (funix[i].name)
1821 2 : unlink (funix[i].name);
1822 : }
1823 :
1824 1 : if (finet[IU_FD_IP4] >= 0)
1825 1 : close (finet[IU_FD_IP4]);
1826 1 : if (finet[IU_FD_IP6] >= 0)
1827 1 : close (finet[IU_FD_IP6]);
1828 :
1829 1 : exit (EXIT_SUCCESS);
1830 : }
1831 :
1832 : /*
1833 : * Return zero on error.
1834 : */
1835 : static int
1836 4 : load_conffile (const char *filename, struct filed **nextp)
1837 : {
1838 : FILE *cf;
1839 : struct filed *f;
1840 : #ifndef LINE_MAX
1841 : # define LINE_MAX 2048
1842 : #endif
1843 4 : size_t line_max = LINE_MAX;
1844 : char *cbuf;
1845 : char *cline;
1846 4 : int cont_line = 0;
1847 :
1848 : /* Beware: Do not assume *nextp to be NULL. */
1849 :
1850 : /* Open the configuration file. */
1851 4 : cf = fopen (filename, "r");
1852 4 : if (cf == NULL)
1853 : {
1854 0 : dbg_printf ("cannot open %s\n", filename);
1855 :
1856 : /* Add emergency logging if everything else was missing. */
1857 0 : if (*nextp == NULL)
1858 : {
1859 : /* Send LOG_ERR to the system console. */
1860 0 : f = (struct filed *) calloc (1, sizeof (*f));
1861 0 : cfline ("*.ERR\t" PATH_CONSOLE, f); /* Erases *f! */
1862 :
1863 : /* Below that, send LOG_EMERG to all users. */
1864 0 : f->f_next = (struct filed *) calloc (1, sizeof (*f));
1865 0 : cfline ("*.PANIC\t*", f->f_next); /* Erases *(f->f_next)! */
1866 :
1867 0 : *nextp = f; /* Return this minimal table to the caller. */
1868 : }
1869 :
1870 0 : Initialized = 1;
1871 0 : return 1;
1872 : }
1873 :
1874 : /* Allocate a buffer for line parsing. */
1875 4 : cbuf = malloc (line_max);
1876 4 : if (cbuf == NULL)
1877 : {
1878 : /* There is no graceful recovery here. */
1879 0 : dbg_printf ("cannot allocate space for configuration\n");
1880 0 : fclose (cf);
1881 0 : return 0;
1882 : }
1883 4 : cline = cbuf;
1884 :
1885 : /* Reset selecting program. */
1886 4 : free (selector);
1887 4 : selector = NULL;
1888 :
1889 : /* Line parsing :
1890 : - skip comments,
1891 : - strip off trailing spaces,
1892 : - skip empty lines,
1893 : - glob leading spaces,
1894 : - readjust buffer if line is too big,
1895 : - deal with continuation lines, last char is '\' . */
1896 29 : while (fgets (cline, line_max - (cline - cbuf), cf) != NULL)
1897 : {
1898 : char *p;
1899 21 : size_t len = strlen (cline);
1900 :
1901 : /* If this is a continuation line, skip leading whitespace for
1902 : compatibility with sysklogd. Note that this requires
1903 : whitespace before the backslash in the previous line if you
1904 : want to separate the selector from the action. */
1905 21 : if (cont_line)
1906 : {
1907 1 : char *start = cline;
1908 5 : while (*start == ' ' || *start == '\t')
1909 3 : start++;
1910 1 : len = len - (start - cline);
1911 1 : memmove (cline, start, len + 1);
1912 1 : cont_line = 0;
1913 : }
1914 :
1915 : /* No newline, so the line is too big for the buffer. Readjust. */
1916 21 : if (strchr (cline, '\n') == NULL)
1917 : {
1918 0 : size_t offset = cline - cbuf;
1919 : char *tmp;
1920 0 : tmp = realloc (cbuf, line_max * 2);
1921 0 : if (tmp == NULL)
1922 : {
1923 : /* Sigh ... */
1924 0 : dbg_printf ("cannot allocate space configuration\n");
1925 0 : fclose (cf);
1926 0 : free (cbuf);
1927 0 : return 0;
1928 : }
1929 : else
1930 0 : cbuf = tmp;
1931 0 : line_max *= 2;
1932 0 : cline = cbuf + offset + len - 1;
1933 0 : continue;
1934 : }
1935 : else
1936 21 : cline = cbuf;
1937 :
1938 : /* Glob the leading spaces. */
1939 21 : for (p = cline; isspace (*p); ++p)
1940 : ;
1941 :
1942 : /* Record program selector.
1943 : *
1944 : * Acceptable formats are typically:
1945 : *
1946 : * !name
1947 : * #! name
1948 : * ! *
1949 : *
1950 : * The latter is clearing the previous setting.
1951 : */
1952 21 : if (*p == '!' || (*p == '#' && *(p + 1) == '!'))
1953 : {
1954 0 : if (*++p == '!')
1955 0 : ++p;
1956 0 : while (isspace (*p))
1957 0 : ++p;
1958 0 : if (*p == '\0')
1959 0 : continue;
1960 :
1961 : /* Reset previous setting. */
1962 0 : free (selector);
1963 0 : selector = NULL;
1964 :
1965 0 : if (*p != '*')
1966 : {
1967 : char *sep;
1968 :
1969 : /* BSD systems allow multiple selectors
1970 : * separated by commata. Strip away any
1971 : * additional names since at this time
1972 : * we only support a single name.
1973 : */
1974 0 : sep = strchr (p, ',');
1975 0 : if (sep)
1976 0 : *sep = '\0';
1977 :
1978 : /* Remove trailing whitespace. */
1979 0 : sep = strpbrk (p, " \t\n\r");
1980 0 : if (sep)
1981 0 : *sep = '\0';
1982 :
1983 0 : selector = strdup (p);
1984 : }
1985 0 : continue;
1986 : }
1987 :
1988 : /* Skip comments and empty line. */
1989 21 : if (*p == '\0' || *p == '#')
1990 7 : continue;
1991 :
1992 14 : memmove (cline, p, strlen (p) + 1);
1993 :
1994 : /* Cut the trailing spaces. */
1995 14 : for (p = strchr (cline, '\0'); isspace (*--p);)
1996 : ;
1997 :
1998 : /* if '\', indicates continuation on the next line. */
1999 14 : if (*p == '\\')
2000 : {
2001 1 : *p = '\0';
2002 1 : cline = p;
2003 1 : cont_line = 1;
2004 1 : continue;
2005 : }
2006 :
2007 13 : *++p = '\0';
2008 :
2009 : /* Send the line for more parsing.
2010 : * Then generate the new entry,
2011 : * inserting it at the head of
2012 : * the already existing table.
2013 : */
2014 13 : f = (struct filed *) calloc (1, sizeof (*f));
2015 13 : cfline (cbuf, f); /* Erases *f! */
2016 13 : f->f_next = *nextp;
2017 13 : *nextp = f;
2018 : }
2019 :
2020 : /* Close the configuration file. */
2021 4 : fclose (cf);
2022 4 : free (cbuf);
2023 :
2024 4 : return 1;
2025 : }
2026 :
2027 : /*
2028 : * Return zero on error.
2029 : */
2030 : static int
2031 2 : load_confdir (const char *dirname, struct filed **nextp)
2032 : {
2033 2 : int rc = 0, found = 0;
2034 : struct dirent *dent;
2035 : DIR *dir;
2036 :
2037 2 : dir = opendir (dirname);
2038 2 : if (dir == NULL)
2039 : {
2040 0 : dbg_printf ("cannot open %s\n", dirname);
2041 0 : return 1; /* Acceptable deviation. */
2042 : }
2043 :
2044 10 : while ((dent = readdir (dir)) != NULL)
2045 : {
2046 : struct stat st;
2047 : char *file;
2048 :
2049 6 : if (asprintf (&file, "%s/%s", dirname, dent->d_name) < 0)
2050 : {
2051 0 : dbg_printf ("cannot allocate space for configuration filename\n");
2052 0 : return 0;
2053 : }
2054 :
2055 6 : if (stat (file, &st) != 0)
2056 : {
2057 0 : dbg_printf ("cannot stat file configuration file\n");
2058 0 : continue;
2059 : }
2060 :
2061 :
2062 6 : if (S_ISREG(st.st_mode))
2063 : {
2064 2 : found++;
2065 2 : rc += load_conffile (file, nextp);
2066 : }
2067 :
2068 6 : free (file);
2069 : }
2070 :
2071 2 : closedir (dir);
2072 :
2073 : /* An empty directory is acceptable.
2074 : */
2075 2 : return (found ? rc : 1);
2076 : }
2077 :
2078 : /* INIT -- Initialize syslogd from configuration table. */
2079 : void
2080 2 : init (int signo _GL_UNUSED_PARAMETER)
2081 : {
2082 : int rc, ret;
2083 : struct filed *f, *next, **nextp;
2084 :
2085 2 : dbg_printf ("init\n");
2086 :
2087 : /* Close all open log files. */
2088 2 : Initialized = 0;
2089 10 : for (f = Files; f != NULL; f = next)
2090 : {
2091 : int j;
2092 :
2093 : /* Flush any pending output. */
2094 8 : if (f->f_prevcount)
2095 0 : fprintlog (f, LocalHostName, 0, (char *) NULL);
2096 :
2097 8 : switch (f->f_type)
2098 : {
2099 : case F_FILE:
2100 : case F_TTY:
2101 : case F_CONSOLE:
2102 : case F_PIPE:
2103 2 : free (f->f_un.f_fname);
2104 2 : close (f->f_file);
2105 2 : break;
2106 : case F_FORW:
2107 : case F_FORW_SUSP:
2108 : case F_FORW_UNKN:
2109 0 : free (f->f_un.f_forw.f_hname);
2110 0 : break;
2111 : case F_USERS:
2112 0 : for (j = 0; j < f->f_un.f_user.f_nusers; ++j)
2113 0 : free (f->f_un.f_user.f_unames[j]);
2114 0 : free (f->f_un.f_user.f_unames);
2115 0 : break;
2116 : }
2117 8 : free (f->f_progname);
2118 8 : free (f->f_prevhost);
2119 8 : next = f->f_next;
2120 8 : free (f);
2121 : }
2122 :
2123 2 : Files = NULL; /* Empty the table. */
2124 2 : nextp = &Files;
2125 2 : facilities_seen = 0;
2126 :
2127 2 : rc = load_conffile (ConfFile, nextp);
2128 :
2129 2 : ret = load_confdir (ConfDir, nextp);
2130 2 : if (!ret)
2131 0 : rc = 0; /* Some allocation errors were found. */
2132 :
2133 2 : Initialized = 1;
2134 :
2135 2 : if (Debug)
2136 : {
2137 0 : for (f = Files; f; f = f->f_next)
2138 : {
2139 : int i;
2140 0 : for (i = 0; i <= LOG_NFACILITIES; i++)
2141 0 : if (f->f_pmask[i] == 0)
2142 0 : dbg_printf (" X ");
2143 : else
2144 0 : dbg_printf ("%2x ", f->f_pmask[i]);
2145 0 : dbg_printf ("%s: ", TypeNames[f->f_type]);
2146 0 : switch (f->f_type)
2147 : {
2148 : case F_FILE:
2149 : case F_TTY:
2150 : case F_CONSOLE:
2151 : case F_PIPE:
2152 0 : dbg_printf ("%s", f->f_un.f_fname);
2153 0 : break;
2154 :
2155 : case F_FORW:
2156 : case F_FORW_SUSP:
2157 : case F_FORW_UNKN:
2158 0 : dbg_printf ("%s", f->f_un.f_forw.f_hname);
2159 0 : break;
2160 :
2161 : case F_USERS:
2162 0 : for (i = 0; i < f->f_un.f_user.f_nusers; i++)
2163 0 : dbg_printf ("%s, ", f->f_un.f_user.f_unames[i]);
2164 0 : break;
2165 : }
2166 0 : dbg_printf ("\n");
2167 : }
2168 : }
2169 :
2170 2 : if (AcceptRemote)
2171 2 : logmsg (LOG_SYSLOG | LOG_INFO, "syslogd (" PACKAGE_NAME
2172 : " " PACKAGE_VERSION "): restart (remote reception)",
2173 : LocalHostName, ADDDATE);
2174 : else
2175 0 : logmsg (LOG_SYSLOG | LOG_INFO, "syslogd (" PACKAGE_NAME
2176 : " " PACKAGE_VERSION "): restart", LocalHostName, ADDDATE);
2177 :
2178 2 : if (!rc)
2179 0 : logmsg (LOG_SYSLOG | LOG_ERR, "syslogd: Incomplete configuration.",
2180 : LocalHostName, ADDDATE);
2181 :
2182 2 : dbg_printf ("syslogd: restarted\n");
2183 2 : }
2184 :
2185 : /* Crack a configuration file line. */
2186 : void
2187 13 : cfline (const char *line, struct filed *f)
2188 : {
2189 : struct addrinfo hints, *rp;
2190 : int i, pri, negate_pri, excl_pri, err;
2191 : unsigned int pri_set, pri_clear;
2192 : char *bp;
2193 : const char *p, *q;
2194 : char buf[MAXLINE], ebuf[200];
2195 :
2196 26 : dbg_printf ("cfline(%s)%s%s\n", line,
2197 13 : selector ? " tagged " : "",
2198 13 : selector ? selector : "");
2199 :
2200 13 : errno = 0; /* keep strerror() stuff out of logerror messages */
2201 :
2202 : /* Clear out file entry. */
2203 13 : memset (f, 0, sizeof (*f));
2204 338 : for (i = 0; i <= LOG_NFACILITIES; i++)
2205 : {
2206 325 : f->f_pmask[i] = 0;
2207 325 : f->f_flags = 0;
2208 : }
2209 :
2210 : /* Scan through the list of selectors. */
2211 34 : for (p = line; *p && *p != '\t' && *p != ' ';)
2212 : {
2213 :
2214 : /* Find the end of this facility name list. */
2215 61 : for (q = p; *q && *q != '\t' && *q++ != '.';)
2216 35 : continue;
2217 :
2218 : /* Collect priority name. */
2219 65 : for (bp = buf; *q && !strchr ("\t ,;", *q);)
2220 39 : *bp++ = *q++;
2221 13 : *bp = '\0';
2222 :
2223 : /* Skip cruft. */
2224 26 : while (*q && strchr (",;", *q))
2225 0 : q++;
2226 :
2227 13 : bp = buf;
2228 13 : negate_pri = excl_pri = 0;
2229 :
2230 30 : while (*bp == '!' || *bp == '=')
2231 4 : switch (*bp++)
2232 : {
2233 : case '!':
2234 0 : negate_pri = 1;
2235 0 : break;
2236 :
2237 : case '=':
2238 4 : excl_pri = 1;
2239 4 : break;
2240 : }
2241 :
2242 : /* Decode priority name and set up bit masks. */
2243 13 : if (*bp == '*')
2244 : {
2245 3 : pri_clear = 0;
2246 3 : pri_set = LOG_UPTO (LOG_PRIMASK);
2247 : }
2248 : else
2249 : {
2250 10 : pri = decode (bp, prioritynames);
2251 10 : if (pri < 0 || (pri > LOG_PRIMASK && pri != INTERNAL_NOPRI))
2252 : {
2253 3 : snprintf (ebuf, sizeof (ebuf),
2254 : "unknown priority name \"%s\"", bp);
2255 3 : logerror (ebuf);
2256 3 : return;
2257 : }
2258 7 : if (pri == INTERNAL_NOPRI)
2259 : {
2260 0 : pri_clear = 255;
2261 0 : pri_set = 0;
2262 : }
2263 : else
2264 : {
2265 7 : pri_clear = 0;
2266 7 : pri_set = excl_pri ? LOG_MASK (pri) : LOG_UPTO (pri);
2267 : }
2268 : }
2269 10 : if (negate_pri)
2270 : {
2271 0 : unsigned int exchange = pri_set;
2272 0 : pri_set = pri_clear;
2273 0 : pri_clear = exchange;
2274 : }
2275 :
2276 : /* Scan facilities. */
2277 28 : while (*p && !strchr ("\t .;", *p))
2278 : {
2279 45 : for (bp = buf; *p && !strchr ("\t ,;.", *p);)
2280 25 : *bp++ = *p++;
2281 10 : *bp = '\0';
2282 10 : if (*buf == '*')
2283 130 : for (i = 0; i <= LOG_NFACILITIES; i++)
2284 : {
2285 : /* make "**" act as a wildcard only for facilities not
2286 : * specified elsewhere
2287 : */
2288 125 : if (buf[1] == '*' && ((1 << i) & facilities_seen))
2289 0 : continue;
2290 :
2291 125 : f->f_pmask[i] &= ~pri_clear;
2292 125 : f->f_pmask[i] |= pri_set;
2293 : }
2294 : else
2295 : {
2296 5 : i = decode (buf, facilitynames);
2297 :
2298 5 : if (i < 0 || i > (LOG_NFACILITIES << 3))
2299 : {
2300 2 : snprintf (ebuf, sizeof (ebuf),
2301 : "unknown facility name \"%s\"", buf);
2302 2 : logerror (ebuf);
2303 2 : return;
2304 : }
2305 :
2306 3 : f->f_pmask[LOG_FAC (i)] &= ~pri_clear;
2307 3 : f->f_pmask[LOG_FAC (i)] |= pri_set;
2308 :
2309 3 : facilities_seen |= (1 << LOG_FAC (i));
2310 : }
2311 16 : while (*p == ',' || *p == ' ')
2312 0 : p++;
2313 : }
2314 8 : p = q;
2315 : }
2316 :
2317 : /* Skip to action part. */
2318 24 : while (*p == '\t' || *p == ' ')
2319 8 : p++;
2320 :
2321 8 : if (*p == '-')
2322 : {
2323 0 : f->f_flags |= OMIT_SYNC;
2324 0 : p++;
2325 : }
2326 :
2327 8 : if (!strlen(p))
2328 : {
2329 : /* Invalidate an entry with empty action field. */
2330 1 : f->f_type = F_UNUSED;
2331 1 : logerror ("empty action field");
2332 1 : return;
2333 : }
2334 :
2335 7 : switch (*p)
2336 : {
2337 : case '@':
2338 0 : f->f_un.f_forw.f_hname = strdup (++p);
2339 0 : memset (&hints, 0, sizeof (hints));
2340 0 : hints.ai_family = usefamily;
2341 0 : hints.ai_socktype = SOCK_DGRAM;
2342 : #ifdef AI_ADDRCONFIG
2343 0 : if (usefamily == AF_UNSPEC)
2344 0 : hints.ai_flags |= AI_ADDRCONFIG;
2345 : #endif
2346 :
2347 0 : f->f_un.f_forw.f_addrlen = 0; /* Invalidate address. */
2348 0 : memset (&f->f_un.f_forw.f_addr, 0, sizeof (f->f_un.f_forw.f_addr));
2349 :
2350 0 : err = getaddrinfo (p, LogForwardPort, &hints, &rp);
2351 0 : if (err)
2352 : {
2353 0 : switch (err)
2354 : {
2355 : case EAI_AGAIN: /* Known kinds of temporary error. */
2356 : case EAI_MEMORY:
2357 0 : f->f_type = F_FORW_UNKN;
2358 0 : f->f_prevcount = INET_RETRY_MAX;
2359 0 : break;
2360 :
2361 : case EAI_NONAME: /* The most probable causes for failure. */
2362 : #if defined EAI_NODATA && (EAI_NODATA != EAI_NONAME) /* FreeBSD complains. */
2363 : case EAI_NODATA:
2364 : #endif
2365 : #ifdef EAI_ADDRFAMILY
2366 : case EAI_ADDRFAMILY:
2367 : #endif
2368 : default: /* Catch system exceptions. */
2369 0 : f->f_type = F_UNUSED;
2370 : }
2371 :
2372 0 : f->f_time = time ((time_t *) 0);
2373 : }
2374 : else
2375 : {
2376 0 : f->f_type = F_FORW;
2377 0 : f->f_un.f_forw.f_addrlen = rp->ai_addrlen;
2378 0 : memcpy (&f->f_un.f_forw.f_addr, rp->ai_addr, rp->ai_addrlen);
2379 0 : freeaddrinfo (rp);
2380 : }
2381 0 : break;
2382 :
2383 : case '|':
2384 0 : f->f_un.f_fname = strdup (p);
2385 0 : f->f_file = open (++p, O_RDWR | O_NONBLOCK);
2386 0 : if (f->f_file < 0)
2387 : {
2388 0 : f->f_type = F_UNUSED;
2389 0 : logerror (p);
2390 0 : free (f->f_un.f_fname);
2391 0 : f->f_un.f_fname = NULL;
2392 0 : break;
2393 : }
2394 0 : if (strcmp (p, ctty) == 0)
2395 0 : f->f_type = F_CONSOLE;
2396 0 : else if (isatty (f->f_file))
2397 0 : f->f_type = F_TTY;
2398 : else
2399 0 : f->f_type = F_PIPE;
2400 0 : break;
2401 :
2402 : case '/':
2403 7 : f->f_un.f_fname = strdup (p);
2404 7 : f->f_file = open (p, O_WRONLY | O_APPEND | O_CREAT, 0644);
2405 7 : if (f->f_file < 0)
2406 : {
2407 0 : f->f_type = F_UNUSED;
2408 0 : logerror (p);
2409 0 : free (f->f_un.f_fname);
2410 0 : f->f_un.f_fname = NULL;
2411 0 : break;
2412 : }
2413 7 : if (strcmp (p, ctty) == 0)
2414 0 : f->f_type = F_CONSOLE;
2415 7 : else if (isatty (f->f_file))
2416 0 : f->f_type = F_TTY;
2417 : else
2418 7 : f->f_type = F_FILE;
2419 7 : break;
2420 :
2421 : case '*':
2422 0 : f->f_type = F_WALL;
2423 0 : break;
2424 :
2425 : default:
2426 0 : f->f_un.f_user.f_nusers = 1;
2427 0 : for (q = p; *q; q++)
2428 0 : if (*q == ',')
2429 0 : f->f_un.f_user.f_nusers++;
2430 0 : f->f_un.f_user.f_unames =
2431 0 : (char **) malloc (f->f_un.f_user.f_nusers * sizeof (char *));
2432 0 : for (i = 0; *p; i++)
2433 : {
2434 0 : for (q = p; *q && *q != ',';)
2435 0 : q++;
2436 0 : f->f_un.f_user.f_unames[i] = malloc (q - p + 1);
2437 0 : if (f->f_un.f_user.f_unames[i])
2438 : {
2439 0 : strncpy (f->f_un.f_user.f_unames[i], p, q - p);
2440 0 : f->f_un.f_user.f_unames[i][q - p] = '\0';
2441 : }
2442 0 : while (*q == ',' || *q == ' ')
2443 0 : q++;
2444 0 : p = q;
2445 : }
2446 0 : f->f_type = F_USERS;
2447 0 : break;
2448 : }
2449 :
2450 : /* Set program selector. */
2451 7 : if (selector)
2452 : {
2453 0 : f->f_progname = strdup (selector);
2454 0 : f->f_prognlen = strlen (selector);
2455 : }
2456 : else
2457 7 : f->f_progname = NULL;
2458 : }
2459 :
2460 : /* Decode a symbolic name to a numeric value. */
2461 : int
2462 15 : decode (const char *name, CODE * codetab)
2463 : {
2464 : CODE *c;
2465 :
2466 15 : if (isdigit (*name))
2467 3 : return atoi (name);
2468 :
2469 132 : for (c = codetab; c->c_name; c++)
2470 129 : if (!strcasecmp (name, c->c_name))
2471 9 : return c->c_val;
2472 :
2473 3 : return -1;
2474 : }
2475 :
2476 : void
2477 0 : dbg_toggle (int signo _GL_UNUSED_PARAMETER)
2478 : {
2479 0 : int dbg_save = dbg_output;
2480 :
2481 0 : dbg_output = 1;
2482 0 : dbg_printf ("Switching dbg_output to %s.\n",
2483 : dbg_save == 0 ? "true" : "false");
2484 0 : dbg_output = (dbg_save == 0) ? 1 : 0;
2485 :
2486 : #ifndef HAVE_SIGACTION
2487 : signal (SIGUSR1, dbg_toggle);
2488 : #endif
2489 0 : }
2490 :
2491 : /* Ansi2knr will always change ... to va_list va_dcl */
2492 : static void
2493 146 : dbg_printf (const char *fmt, ...)
2494 : {
2495 : va_list ap;
2496 :
2497 146 : if (!(NoDetach && dbg_output))
2498 292 : return;
2499 :
2500 0 : va_start (ap, fmt);
2501 0 : vfprintf (stdout, fmt, ap);
2502 0 : va_end (ap);
2503 :
2504 0 : fflush (stdout);
2505 : }
2506 :
2507 : /* The following function is resposible for handling a SIGHUP signal.
2508 : Since we are now doing mallocs/free as part of init we had better
2509 : not being doing this during a signal handler. Instead we simply
2510 : set a flag variable which will tell the main loop to go through a
2511 : restart. */
2512 : void
2513 1 : trigger_restart (int signo _GL_UNUSED_PARAMETER)
2514 : {
2515 1 : restart = 1;
2516 : #ifndef HAVE_SIGACTION
2517 : signal (SIGHUP, trigger_restart);
2518 : #endif
2519 1 : }
2520 :
2521 : /* Override default port with a non-NULL argument.
2522 : * Otherwise identify the default syslog/udp with
2523 : * proper fallback to avoid resolve issues. */
2524 : void
2525 1 : find_inet_port (const char *port)
2526 : {
2527 : int err;
2528 : struct addrinfo hints, *ai;
2529 :
2530 : /* Fall back to numerical description. */
2531 : #ifdef IPPORT_SYSLOG
2532 : snprintf (portstr, sizeof (portstr), "%u", IPPORT_SYSLOG);
2533 : LogForwardPort = portstr;
2534 : #else
2535 1 : LogForwardPort = "514";
2536 : #endif
2537 :
2538 1 : memset (&hints, 0, sizeof (hints));
2539 1 : hints.ai_family = AF_UNSPEC;
2540 1 : hints.ai_socktype = SOCK_DGRAM;
2541 1 : hints.ai_flags = AI_PASSIVE;
2542 :
2543 1 : err = getaddrinfo (NULL, "syslog", &hints, &ai);
2544 1 : if (err == 0)
2545 : {
2546 1 : LogForwardPort = "syslog"; /* Symbolic name is usable. */
2547 1 : freeaddrinfo (ai);
2548 : }
2549 :
2550 1 : LogPortText = (char *) port;
2551 :
2552 1 : if (!LogPortText)
2553 : {
2554 0 : LogPortText = LogForwardPort;
2555 0 : return;
2556 : }
2557 :
2558 : /* Is the port specified on command line really usable? */
2559 1 : memset (&hints, 0, sizeof (hints));
2560 1 : hints.ai_family = AF_UNSPEC;
2561 1 : hints.ai_socktype = SOCK_DGRAM;
2562 1 : hints.ai_flags = AI_PASSIVE;
2563 :
2564 1 : err = getaddrinfo (NULL, LogPortText, &hints, &ai);
2565 1 : if (err != 0)
2566 : {
2567 : /* Not usable, disable listener.
2568 : * It is too early to report failure at this time. */
2569 0 : LogPortText = NULL;
2570 : }
2571 : else
2572 1 : freeaddrinfo (ai);
2573 :
2574 1 : return;
2575 : }
|