Document changes
[infodrom/sysklogd] / syslogd.c
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #if !defined(lint) && !defined(NO_SCCS)
19 char copyright2[] =
20 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23
24 #if !defined(lint) && !defined(NO_SCCS)
25 static char sccsid[] = "@(#)syslogd.c   5.27 (Berkeley) 10/10/88";
26 #endif /* not lint */
27
28 /*
29  *  syslogd -- log system messages
30  *
31  * This program implements a system log. It takes a series of lines.
32  * Each line may have a priority, signified as "<n>" as
33  * the first characters of the line.  If this is
34  * not present, a default priority is used.
35  *
36  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
37  * cause it to reread its configuration file.
38  *
39  * Defined Constants:
40  *
41  * MAXLINE -- the maximum line length that can be handled.
42  * DEFUPRI -- the default priority for user messages
43  * DEFSPRI -- the default priority for kernel messages
44  *
45  * Author: Eric Allman
46  * extensive changes by Ralph Campbell
47  * more extensive changes by Eric Allman (again)
48  *
49  * Steve Lord:  Fix UNIX domain socket code, added linux kernel logging
50  *              change defines to
51  *              SYSLOG_INET     - listen on a UDP socket
52  *              SYSLOG_UNIXAF   - listen on unix domain socket
53  *              SYSLOG_KERNEL   - listen to linux kernel
54  *
55  * Mon Feb 22 09:55:42 CST 1993:  Dr. Wettstein
56  *      Additional modifications to the source.  Changed priority scheme
57  *      to increase the level of configurability.  In its stock configuration
58  *      syslogd no longer logs all messages of a certain priority and above
59  *      to a log file.  The * wildcard is supported to specify all priorities.
60  *      Note that this is a departure from the BSD standard.
61  *
62  *      Syslogd will now listen to both the inetd and the unixd socket.  The
63  *      strategy is to allow all local programs to direct their output to
64  *      syslogd through the unixd socket while the program listens to the
65  *      inetd socket to get messages forwarded from other hosts.
66  *
67  * Fri Mar 12 16:55:33 CST 1993:  Dr. Wettstein
68  *      Thanks to Stephen Tweedie (dcs.ed.ac.uk!sct) for helpful bug-fixes
69  *      and an enlightened commentary on the prioritization problem.
70  *
71  *      Changed the priority scheme so that the default behavior mimics the
72  *      standard BSD.  In this scenario all messages of a specified priority
73  *      and above are logged.
74  *
75  *      Add the ability to specify a wildcard (=) as the first character
76  *      of the priority name.  Doing this specifies that ONLY messages with
77  *      this level of priority are to be logged.  For example:
78  *
79  *              *.=debug                        /usr/adm/debug
80  *
81  *      Would log only messages with a priority of debug to the /usr/adm/debug
82  *      file.
83  *
84  *      Providing an * as the priority specifies that all messages are to be
85  *      logged.  Note that this case is degenerate with specifying a priority
86  *      level of debug.  The wildcard * was retained because I believe that
87  *      this is more intuitive.
88  *
89  * Thu Jun 24 11:34:13 CDT 1993:  Dr. Wettstein
90  *      Modified sources to incorporate changes in libc4.4.  Messages from
91  *      syslog are now null-terminated, syslogd code now parses messages
92  *      based on this termination scheme.  Linux as of libc4.4 supports the
93  *      fsync system call.  Modified code to fsync after all writes to
94  *      log files.
95  *
96  * Sat Dec 11 11:59:43 CST 1993:  Dr. Wettstein
97  *      Extensive changes to the source code to allow compilation with no
98  *      complaints with -Wall.
99  *
100  *      Reorganized the facility and priority name arrays so that they
101  *      compatible with the syslog.h source found in /usr/include/syslog.h.
102  *      NOTE that this should really be changed.  The reason I do not
103  *      allow the use of the values defined in syslog.h is on account of
104  *      the extensions made to allow the wildcard character in the
105  *      priority field.  To fix this properly one should malloc an array,
106  *      copy the contents of the array defined by syslog.h and then
107  *      make whatever modifications that are desired.  Next round.
108  *
109  * Thu Jan  6 12:07:36 CST 1994:  Dr. Wettstein
110  *      Added support for proper decomposition and re-assembly of
111  *      fragment messages on UNIX domain sockets.  Lack of this capability
112  *      was causing 'partial' messages to be output.  Since facility and
113  *      priority information is encoded as a leader on the messages this
114  *      was causing lines to be placed in erroneous files.
115  *
116  *      Also added a patch from Shane Alderton (shane@ion.apana.org.au) to
117  *      correct a problem with syslogd dumping core when an attempt was made
118  *      to write log messages to a logged-on user.  Thank you.
119  *
120  *      Many thanks to Juha Virtanen (jiivee@hut.fi) for a series of
121  *      interchanges which lead to the fixing of problems with messages set
122  *      to priorities of none and emerg.  Also thanks to Juha for a patch
123  *      to exclude users with a class of LOGIN from receiving messages.
124  *
125  *      Shane Alderton provided an additional patch to fix zombies which
126  *      were conceived when messages were written to multiple users.
127  *
128  * Mon Feb  6 09:57:10 CST 1995:  Dr. Wettstein
129  *      Patch to properly reset the single priority message flag.  Thanks
130  *      to Christopher Gori for spotting this bug and forwarding a patch.
131  *
132  * Wed Feb 22 15:38:31 CST 1995:  Dr. Wettstein
133  *      Added version information to startup messages.
134  *
135  *      Added defines so that paths to important files are taken from
136  *      the definitions in paths.h.  Hopefully this will insure that
137  *      everything follows the FSSTND standards.  Thanks to Chris Metcalf
138  *      for a set of patches to provide this functionality.  Also thanks
139  *      Elias Levy for prompting me to get these into the sources.
140  *
141  * Wed Jul 26 18:57:23 MET DST 1995:  Martin Schulze
142  *      Linux' gethostname only returns the hostname and not the fqdn as
143  *      expected in the code. But if you call hostname with an fqdn then
144  *      gethostname will return an fqdn, so we have to mention that. This
145  *      has been changed.
146  *
147  *      The 'LocalDomain' and the hostname of a remote machine is
148  *      converted to lower case, because the original caused some
149  *      inconsistency, because the (at least my) nameserver did respond an
150  *      fqdn containing of upper- _and_ lowercase letters while
151  *      'LocalDomain' consisted only of lowercase letters and that didn't
152  *      match.
153  *
154  * Sat Aug  5 18:59:15 MET DST 1995:  Martin Schulze
155  *      Now no messages that were received from any remote host are sent
156  *      out to another. At my domain this missing feature caused ugly
157  *      syslog-loops, sometimes.
158  *
159  *      Remember that no message is sent out. I can't figure out any
160  *      scenario where it might be useful to change this behavior and to
161  *      send out messages to other hosts than the one from which we
162  *      received the message, but I might be shortsighted. :-/
163  *
164  * Thu Aug 10 19:01:08 MET DST 1995:  Martin Schulze
165  *      Added my pidfile.[ch] to it to perform a better handling with
166  *      pidfiles. Now both, syslogd and klogd, can only be started
167  *      once. They check the pidfile.
168  *
169  * Sun Aug 13 19:01:41 MET DST 1995:  Martin Schulze
170  *      Add an addition to syslog.conf's interpretation. If a priority
171  *      begins with an exclamation mark ('!') the normal interpretation
172  *      of the priority is inverted: ".!*" is the same as ".none", ".!=info"
173  *      don't logs the info priority, ".!crit" won't log any message with
174  *      the priority crit or higher. For example:
175  *
176  *              mail.*;mail.!=info              /usr/adm/mail
177  *
178  *      Would log all messages of the facility mail except those with
179  *      the priority info to /usr/adm/mail. This makes the syslogd
180  *      much more flexible.
181  *
182  *      Defined TABLE_ALLPRI=255 and changed some occurrences.
183  *
184  * Sat Aug 19 21:40:13 MET DST 1995:  Martin Schulze
185  *      Making the table of facilities and priorities while in debug
186  *      mode more readable.
187  *
188  *      If debugging is turned on, printing the whole table of
189  *      facilities and priorities every hexadecimal or 'X' entry is
190  *      now 2 characters wide.
191  *
192  *      The number of the entry is prepended to each line of
193  *      facilities and priorities, and F_UNUSED lines are not shown
194  *      anymore.
195  *
196  *      Corrected some #ifdef SYSV's.
197  *
198  * Mon Aug 21 22:10:35 MET DST 1995:  Martin Schulze
199  *      Corrected a strange behavior during parsing of configuration
200  *      file. The original BSD syslogd doesn't understand spaces as
201  *      separators between specifier and action. This syslogd now
202  *      understands them. The old behavior caused some confusion over
203  *      the Linux community.
204  *
205  * Thu Oct 19 00:02:07 MET 1995:  Martin Schulze
206  *      The default behavior has changed for security reasons. The
207  *      syslogd will not receive any remote message unless you turn
208  *      reception on with the "-r" option.
209  *
210  *      Not defining SYSLOG_INET will result in not doing any network
211  *      activity, i.e. not sending or receiving messages.  I changed
212  *      this because the old idea is implemented with the "-r" option
213  *      and the old thing didn't work anyway.
214  *
215  * Thu Oct 26 13:14:06 MET 1995:  Martin Schulze
216  *      Added another logfile type F_FORW_UNKN.  The problem I ran into
217  *      was a name server that runs on my machine and a forwarder of
218  *      kern.crit to another host.  The hosts address can only be
219  *      fetched using the nameserver.  But named is started after
220  *      syslogd, so syslogd complained.
221  *
222  *      This logfile type will retry to get the address of the
223  *      hostname ten times and then complain.  This should be enough to
224  *      get the named up and running during boot sequence.
225  *
226  * Fri Oct 27 14:08:15 1995:  Dr. Wettstein
227  *      Changed static array of logfiles to a dynamic array. This
228  *      can grow during process.
229  *
230  * Fri Nov 10 23:08:18 1995:  Martin Schulze
231  *      Inserted a new tabular sys_h_errlist that contains plain text
232  *      for error codes that are returned from the net subsystem and
233  *      stored in h_errno. I have also changed some wrong lookups to
234  *      sys_errlist.
235  *
236  * Wed Nov 22 22:32:55 1995:  Martin Schulze
237  *      Added the fabulous strip-domain feature that allows us to
238  *      strip off (several) domain names from the fqdn and only log
239  *      the simple hostname. This is useful if you're in a LAN that
240  *      has a central log server and also different domains.
241  *
242  *      I have also also added the -l switch do define hosts as
243  *      local. These will get logged with their simple hostname, too.
244  *
245  * Thu Nov 23 19:02:56 MET DST 1995:  Martin Schulze
246  *      Added the possibility to omit fsyncing of logfiles after every
247  *      write. This will give some performance back if you have
248  *      programs that log in a very verbose manner (like innd or
249  *      smartlist). Thanks to Stephen R. van den Berg <srb@cuci.nl>
250  *      for the idea.
251  *
252  * Thu Jan 18 11:14:36 CST 1996:  Dr. Wettstein
253  *      Added patche from beta-testers to stop compile error.  Also
254  *      added removal of pid file as part of termination cleanup.
255  *
256  * Wed Feb 14 12:42:09 CST 1996:  Dr. Wettstein
257  *      Allowed forwarding of messages received from remote hosts to
258  *      be controlled by a command-line switch.  Specifying -h allows
259  *      forwarding.  The default behavior is to disable forwarding of
260  *      messages which were received from a remote host.
261  *
262  *      Parent process of syslogd does not exit until child process has
263  *      finished initialization process.  This allows rc.* startup to
264  *      pause until syslogd facility is up and operating.
265  *
266  *      Re-arranged the select code to move UNIX domain socket accepts
267  *      to be processed later.  This was a contributed change which
268  *      has been proposed to correct the delays sometimes encountered
269  *      when syslogd starts up.
270  *
271  *      Minor code cleanups.
272  *
273  * Thu May  2 15:15:33 CDT 1996:  Dr. Wettstein
274  *      Fixed bug in init function which resulted in file descripters
275  *      being orphaned when syslogd process was re-initialized with SIGHUP
276  *      signal.  Thanks to Edvard Tuinder
277  *      (Edvard.Tuinder@praseodymium.cistron.nl) for putting me on the
278  *      trail of this bug.  I am amazed that we didn't catch this one
279  *      before now.
280  *
281  * Tue May 14 00:03:35 MET DST 1996:  Martin Schulze
282  *      Corrected a mistake that causes the syslogd to stop logging at
283  *      some virtual consoles under Linux. This was caused by checking
284  *      the wrong error code. Thanks to Michael Nonweiler
285  *      <mrn20@hermes.cam.ac.uk> for sending me a patch.
286  *
287  * Mon May 20 13:29:32 MET DST 1996:  Miquel van Smoorenburg <miquels@cistron.nl>
288  *      Added continuation line supported and fixed a bug in
289  *      the init() code.
290  *
291  * Tue May 28 00:58:45 MET DST 1996:  Martin Schulze
292  *      Corrected behaviour of blocking pipes - i.e. the whole system
293  *      hung.  Michael Nonweiler <mrn20@hermes.cam.ac.uk> has sent us
294  *      a patch to correct this.  A new logfile type F_PIPE has been
295  *      introduced.
296  *
297  * Mon Feb 3 10:12:15 MET DST 1997:  Martin Schulze
298  *      Corrected behaviour of logfiles if the file can't be opened.
299  *      There was a bug that causes syslogd to try to log into non
300  *      existing files which ate cpu power.
301  *
302  * Sun Feb 9 03:22:12 MET DST 1997:  Martin Schulze
303  *      Modified syslogd.c to not kill itself which confuses bash 2.0.
304  *
305  * Mon Feb 10 00:09:11 MET DST 1997:  Martin Schulze
306  *      Improved debug code to decode the numeric facility/priority
307  *      pair into textual information.
308  *
309  * Tue Jun 10 12:35:10 MET DST 1997:  Martin Schulze
310  *      Corrected freeing of logfiles.  Thanks to Jos Vos <jos@xos.nl>
311  *      for reporting the bug and sending an idea to fix the problem.
312  *
313  * Tue Jun 10 12:51:41 MET DST 1997:  Martin Schulze
314  *      Removed sleep(10) from parent process.  This has caused a slow
315  *      startup in former times - and I don't see any reason for this.
316  *
317  * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman
318  *      Some more glibc patches made by <mdorman@debian.org>.
319  *
320  * Thu Jan  1 16:04:52 CET 1998: Martin Schulze <joey@infodrom.north.de
321  *      Applied patch from Herbert Thielen <Herbert.Thielen@lpr.e-technik.tu-muenchen.de>.
322  *      This included some balance parentheses for emacs and a bug in
323  *      the exclamation mark handling.
324  *
325  *      Fixed small bug which caused syslogd to write messages to the
326  *      wrong logfile under some very rare conditions.  Thanks to
327  *      Herbert Xu <herbert@gondor.apana.org.au> for fiddling this out.
328  *
329  * Thu Jan  8 22:46:35 CET 1998: Martin Schulze <joey@infodrom.north.de>
330  *      Reworked one line of the above patch as it prevented syslogd
331  *      from binding the socket with the result that no messages were
332  *      forwarded to other hosts.
333  *
334  * Sat Jan 10 01:33:06 CET 1998: Martin Schulze <joey@infodrom.north.de>
335  *      Fixed small bugs in F_FORW_UNKN meachanism.  Thanks to Torsten
336  *      Neumann <torsten@londo.rhein-main.de> for pointing me to it.
337  *
338  * Mon Jan 12 19:50:58 CET 1998: Martin Schulze <joey@infodrom.north.de>
339  *      Modified debug output concerning remote receiption.
340  *
341  * Mon Feb 23 23:32:35 CET 1998: Topi Miettinen <Topi.Miettinen@ml.tele.fi>
342  *      Re-worked handling of Unix and UDP sockets to support closing /
343  *      opening of them in order to have it open only if it is needed
344  *      either for forwarding to a remote host or by receiption from
345  *      the network.
346  *
347  * Wed Feb 25 10:54:09 CET 1998: Martin Schulze <joey@infodrom.north.de>
348  *      Fixed little comparison mistake that prevented the MARK
349  *      feature to work properly.
350  *
351  * Wed Feb 25 13:21:44 CET 1998: Martin Schulze <joey@infodrom.north.de>
352  *      Corrected Topi's patch as it prevented forwarding during
353  *      startup due to an unknown LogPort.
354  *
355  * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze <joey@infodrom.north.de>
356  *      Added support for TESTING define which will turn syslogd into
357  *      stdio-mode used for debugging.
358  *
359  * Sun Oct 11 20:16:59 CEST 1998: Martin Schulze <joey@infodrom.north.de>
360  *      Reworked the initialization/fork code.  Now the parent
361  *      process activates a signal handler which the daughter process
362  *      will raise if it is initialized.  Only after that one the
363  *      parent process may exit.  Otherwise klogd might try to flush
364  *      its log cache while syslogd can't receive the messages yet.
365  *
366  * Mon Oct 12 13:30:35 CEST 1998: Martin Schulze <joey@infodrom.north.de>
367  *      Redirected some error output with regard to argument parsing to
368  *      stderr.
369  *
370  * Mon Oct 12 14:02:51 CEST 1998: Martin Schulze <joey@infodrom.north.de>
371  *      Applied patch provided vom Topi Miettinen with regard to the
372  *      people from OpenBSD.  This provides the additional '-a'
373  *      argument used for specifying additional UNIX domain sockets to
374  *      listen to.  This is been used with chroot()'ed named's for
375  *      example.  See for http://www.psionic.com/papers/dns.html
376  *
377  * Mon Oct 12 18:29:44 CEST 1998: Martin Schulze <joey@infodrom.north.de>
378  *      Added `ftp' facility which was introduced in glibc version 2.
379  *      It's #ifdef'ed so won't harm with older libraries.
380  *
381  * Mon Oct 12 19:59:21 MET DST 1998: Martin Schulze <joey@infodrom.north.de>
382  *      Code cleanups with regard to bsd -> posix transition and
383  *      stronger security (buffer length checking).  Thanks to Topi
384  *      Miettinen <tom@medialab.sonera.net>
385  *      . index() --> strchr()
386  *      . sprintf() --> snprintf()
387  *      . bcopy() --> memcpy()
388  *      . bzero() --> memset()
389  *      . UNAMESZ --> UT_NAMESIZE
390  *      . sys_errlist --> strerror()
391  *
392  * Mon Oct 12 20:22:59 CEST 1998: Martin Schulze <joey@infodrom.north.de>
393  *      Added support for setutent()/getutent()/endutend() instead of
394  *      binary reading the UTMP file.  This is the the most portable
395  *      way.  This allows /var/run/utmp format to change, even to a
396  *      real database or utmp daemon. Also if utmp file locking is
397  *      implemented in libc, syslog will use it immediately.  Thanks
398  *      to Topi Miettinen <tom@medialab.sonera.net>.
399  *
400  * Mon Oct 12 20:49:18 MET DST 1998: Martin Schulze <joey@infodrom.north.de>
401  *      Avoid logging of SIGCHLD when syslogd is in the process of
402  *      exiting and closing its files.  Again thanks to Topi.
403  *
404  * Mon Oct 12 22:18:34 CEST 1998: Martin Schulze <joey@infodrom.north.de>
405  *      Modified printline() to support 8bit characters - such as
406  *      russion letters.  Thanks to Vladas Lapinskas <lapinskas@mail.iae.lt>.
407  *
408  * Sat Nov 14 02:29:37 CET 1998: Martin Schulze <joey@infodrom.north.de>
409  *      ``-m 0'' now turns of MARK logging entirely.
410  *
411  * Tue Jan 19 01:04:18 MET 1999: Martin Schulze <joey@infodrom.north.de>
412  *      Finally fixed an error with `-a' processing, thanks to Topi
413  *      Miettinen <tom@medialab.sonera.net>.
414  *
415  * Sun May 23 10:08:53 CEST 1999: Martin Schulze <joey@infodrom.north.de>
416  *      Removed superflous call to utmpname().  The path to the utmp
417  *      file is defined in the used libc and should not be hardcoded
418  *      into the syslogd binary referring the system it was compiled on.
419  *
420  * Sun Sep 17 21:26:16 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
421  *      Don't close open sockets upon reload.  Thanks to Bill
422  *      Nottingham.
423  *
424  * Mon Sep 18 09:10:47 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
425  *      Fixed bug in printchopped() that caused syslogd to emit
426  *      kern.emerg messages when splitting long lines.  Thanks to
427  *      Daniel Jacobowitz <dan@debian.org> for the fix.
428  *
429  * Mon Sep 18 15:33:26 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
430  *      Removed unixm/unix domain sockets and switch to Datagram Unix
431  *      Sockets.  This should remove one possibility to play DoS with
432  *      syslogd.  Thanks to Olaf Kirch <okir@caldera.de> for the patch.
433  *
434  * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de>
435  *      Don't return a closed fd if `-a' is called with a wrong path.
436  *      Thanks to Bill Nottingham <notting@redhat.com> for providing
437  *      a patch.
438  * Thu Apr 13 05:08:10 CEST 2001: Jon Burgess <Jon_Burgess@eur.3com.com>
439  *      Moved the installation of the signal handler up a little bit
440  *      so it guaranteed to be available when the child is forked,
441  *      hence, fixing a  race condition.  This used to create problems
442  *      with UML and fast machines.
443  *
444  * Sat Apr 17 18:03:05 CEST 2004: Steve Grubb <linux_4ever@yahoo.com>
445  *      Correct memory allocation for for commandline arguments in
446  *      crunch_list().
447  *
448  * Thu Apr 29 12:38:39 CEST 2004: Solar Designer <solar@openwall.com>
449  *      Applied Openwall paranoia patches to improve crunch_list().
450  *
451  * Tue May  4 16:47:30 CEST 2004: Solar Designer <solar@openwall.com>
452  *      Ensure that "len" is not placed in a register, and that the
453  *      endtty() signal handler is not installed too early which could
454  *      cause a segmentation fault or worse.
455  *
456  * Tue May  4 16:52:01 CEST 2004: Solar Designer <solar@openwall.com>
457  *      Adjust the size of a variable to prevent a buffer overflow
458  *      should _PATH_DEV ever contain something different than "/dev/".
459  *
460  * Tue Nov  2 20:28:23 CET 2004: Colin Phipps <cph@cph.demon.co.uk>
461  *      Don't block on the network socket, in case a packet gets lost
462  *      between select and recv.
463  *
464  * Sun Nov  7 12:28:47 CET 2004: Martin Schulze <joey@infodrom.org>
465  *      Discard any timestamp information found in received syslog
466  *      messages.  This will affect local messages sent from a
467  *      different timezone.
468  *
469  * Sun Nov  7 13:47:00 CET 2004: Martin Schulze <joey@infodrom.org>
470  *      Remove trailing newline when forwarding messages.
471  *
472  * Thu May 25 09:47:38 CEST 2006: Martin Schulze <joey@infodrom.org>
473  *      Reset the 'restart' flag immediately after entering the
474  *      restart code, so that subsequent SIGHUPs are able to set it
475  *      again and cause a new restart.  This fixes a race condition
476  *      when somebody sends tons of HUP signals.
477  *
478  * Thu May 24 15:24:49 CEST 2007: Martin Schulze <joey@infodrom.org>
479  *      Ignore errors caused by filled up disks so that the log
480  *      continues to be written as soon as space becomes available
481  *      again.
482  *
483  * Sat May 26 10:05:05 CEST 2007: Martin Schulze <joey@infodrom.org>
484  *      Only try to gather the local domain name when messages are to
485  *      be received from the network, it's not needed otherwise.
486  *
487  * Sat May 26 12:22:44 CEST 2007: Martin Schulze <joey@infodrom.org>
488  *      Properly accompany the MARK message with the facility.
489  *
490  * Mon May 28 19:44:39 CEST 2007: Martin Schulze <joey@infodrom.org>
491  *      Notify the waiting parent process if the client dies to it
492  *      doesn't wait the entire five minutes.
493  *
494  * Wed Jul  4 21:02:22 CEST 2007: Martin Schulze <joey@infodrom.org>
495  *      Open a pipe with O_NOCTTY to avoid them becoming the controlling
496  *      tty and normal files with O_NONBLOCK to avoid blocking.
497  *
498  * Fri Oct 26 17:21:15 CEST 2007: Thomas Jarosch <thomas.jarosch@intra2net.com>
499  *      Move hostname setting code from main() into init().
500  *
501  * Wed May  7 21:00:39 CEST 2007: Martin Schulze <joey@infodrom.org>
502  *      Make sure that the service name is only queried, when it is needed,
503  *      i.e. when we are sending to or receiving from the network.
504  *
505  * Fri Sep 10 08:29:04 CEST 2010: Martin Schulze <joey@infodrom.org>
506  *      Replace strcpy with memmove to fix continuation line problems
507  *      on 64bit architectures, patch by David Couture.
508  */
509
510
511 #define MAXLINE         1024            /* maximum line length */
512 #define MAXSVLINE       240             /* maximum saved line length */
513 #define DEFUPRI         (LOG_USER|LOG_NOTICE)
514 #define DEFSPRI         (LOG_KERN|LOG_CRIT)
515 #define TIMERINTVL      30              /* interval for checking flush, mark */
516
517 #define CONT_LINE       1               /* Allow continuation lines */
518
519 #include <unistd.h>
520 #include <stdlib.h>
521 #include <stdio.h>
522 #ifdef SYSV
523 #include <sys/types.h>
524 #endif
525 #include <utmp.h>
526 #include <ctype.h>
527 #include <string.h>
528 #include <setjmp.h>
529 #include <stdarg.h>
530 #include <time.h>
531
532 #define SYSLOG_NAMES
533 #include <sys/syslog.h>
534 #include <sys/param.h>
535 #include <sys/errno.h>
536 #include <sys/ioctl.h>
537 #include <sys/stat.h>
538 #include <sys/wait.h>
539 #include <sys/socket.h>
540 #include <sys/file.h>
541 #ifdef SYSV
542 #include <fcntl.h>
543 #else
544 #include <sys/msgbuf.h>
545 #endif
546 #include <sys/uio.h>
547 #include <sys/un.h>
548 #include <sys/time.h>
549 #include <sys/resource.h>
550 #include <signal.h>
551
552 #include <netinet/in.h>
553 #include <netdb.h>
554 #include <syscall.h>
555 #include <arpa/nameser.h>
556 #include <arpa/inet.h>
557 #include <resolv.h>
558 #ifndef TESTING
559 #include "pidfile.h"
560 #endif
561 #include "version.h"
562
563 #if defined(__linux__)
564 #include <paths.h>
565 #endif
566
567 #ifndef UTMP_FILE
568 #ifdef UTMP_FILENAME
569 #define UTMP_FILE UTMP_FILENAME
570 #else
571 #ifdef _PATH_UTMP
572 #define UTMP_FILE _PATH_UTMP
573 #else
574 #define UTMP_FILE "/etc/utmp"
575 #endif
576 #endif
577 #endif
578
579 #ifndef _PATH_LOGCONF 
580 #define _PATH_LOGCONF   "/etc/syslog.conf"
581 #endif
582
583 #if defined(SYSLOGD_PIDNAME)
584 #undef _PATH_LOGPID
585 #if defined(FSSTND)
586 #define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME
587 #else
588 #define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME
589 #endif
590 #else
591 #ifndef _PATH_LOGPID
592 #if defined(FSSTND)
593 #define _PATH_LOGPID _PATH_VARRUN "syslogd.pid"
594 #else
595 #define _PATH_LOGPID "/etc/syslogd.pid"
596 #endif
597 #endif
598 #endif
599
600 #ifndef _PATH_DEV
601 #define _PATH_DEV       "/dev/"
602 #endif
603
604 #ifndef _PATH_CONSOLE
605 #define _PATH_CONSOLE   "/dev/console"
606 #endif
607
608 #ifndef _PATH_TTY
609 #define _PATH_TTY       "/dev/tty"
610 #endif
611
612 #ifndef _PATH_LOG
613 #define _PATH_LOG       "/dev/log"
614 #endif
615
616 char    *ConfFile = _PATH_LOGCONF;
617 char    *PidFile = _PATH_LOGPID;
618 char    ctty[] = _PATH_CONSOLE;
619
620 char    **parts;
621
622 static int debugging_on = 0;
623 static int nlogs = -1;
624 static int restart = 0;
625
626 #define MAXFUNIX        20
627
628 int nfunix = 1;
629 char *funixn[MAXFUNIX] = { _PATH_LOG };
630 int funix[MAXFUNIX] = { -1, };
631
632 #ifdef UT_NAMESIZE
633 # define UNAMESZ        UT_NAMESIZE     /* length of a login name */
634 #else
635 # define UNAMESZ        8       /* length of a login name */
636 #endif
637 #define MAXUNAMES       20      /* maximum number of user names */
638 #define MAXFNAME        200     /* max file pathname length */
639
640 #define INTERNAL_NOPRI  0x10    /* the "no priority" priority */
641 #define TABLE_NOPRI     0       /* Value to indicate no priority in f_pmask */
642 #define TABLE_ALLPRI    0xFF    /* Value to indicate all priorities in f_pmask */
643 #define LOG_MARK        LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */
644
645 #define MAX_PRI         191     /* Maximum Priority per RFC 3164 */
646
647 /*
648  * Flags to logmsg().
649  */
650
651 #define IGN_CONS        0x001   /* don't print on console */
652 #define SYNC_FILE       0x002   /* do fsync on file after printing */
653 #define ADDDATE         0x004   /* add a date to the message */
654 #define MARK            0x008   /* this message is a mark */
655
656 /*
657  * This table contains plain text for h_errno errors used by the
658  * net subsystem.
659  */
660 const char *sys_h_errlist[] = {
661     "No problem",                                               /* NETDB_SUCCESS */
662     "Authoritative answer: host not found",                     /* HOST_NOT_FOUND */
663     "Non-authoritative answer: host not found, or serverfail",  /* TRY_AGAIN */
664     "Non recoverable errors",                                   /* NO_RECOVERY */
665     "Valid name, no data record of requested type",             /* NO_DATA */
666     "no address, look for MX record"                            /* NO_ADDRESS */
667  };
668
669 /*
670  * This structure represents the files that will have log
671  * copies printed.
672  */
673
674 struct filed {
675 #ifndef SYSV
676         struct  filed *f_next;          /* next in linked list */
677 #endif
678         short   f_type;                 /* entry type, see below */
679         short   f_file;                 /* file descriptor */
680         time_t  f_time;                 /* time this was last written */
681         char    *f_host;                /* host from which to recd. */
682         u_char  f_pmask[LOG_NFACILITIES+1];     /* priority mask */
683         union {
684                 char    f_uname[MAXUNAMES][UNAMESZ+1];
685                 struct {
686                         char    f_hname[MAXHOSTNAMELEN+1];
687                         struct addrinfo *f_addr;
688                 } f_forw;               /* forwarding address */
689                 char    f_fname[MAXFNAME];
690         } f_un;
691         char    f_prevline[MAXSVLINE];          /* last message logged */
692         char    f_lasttime[16];                 /* time of last occurrence */
693         char    f_prevhost[MAXHOSTNAMELEN+1];   /* host from which recd. */
694         int     f_prevpri;                      /* pri of f_prevline */
695         int     f_prevlen;                      /* length of f_prevline */
696         int     f_prevcount;                    /* repetition cnt of prevline */
697         int     f_repeatcount;                  /* number of "repeated" msgs */
698         int     f_flags;                        /* store some additional flags */
699 };
700
701 /*
702  * Intervals at which we flush out "message repeated" messages,
703  * in seconds after previous message is logged.  After each flush,
704  * we move to the next interval until we reach the largest.
705  */
706 int     repeatinterval[] = { 30, 60 };  /* # of secs before flush */
707 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
708 #define REPEATTIME(f)   ((f)->f_time + repeatinterval[(f)->f_repeatcount])
709 #define BACKOFF(f)      { if (++(f)->f_repeatcount > MAXREPEAT) \
710                                  (f)->f_repeatcount = MAXREPEAT; \
711                         }
712 #ifdef SYSLOG_INET
713 #define INET_SUSPEND_TIME 180           /* equal to 3 minutes */
714 #define INET_RETRY_MAX 10               /* maximum of retries for getaddrinfo() */
715 #endif
716
717 #define LIST_DELIMITER  ':'             /* delimiter between two hosts */
718
719 /* values for f_type */
720 #define F_UNUSED        0               /* unused entry */
721 #define F_FILE          1               /* regular file */
722 #define F_TTY           2               /* terminal */
723 #define F_CONSOLE       3               /* console terminal */
724 #define F_FORW          4               /* remote machine */
725 #define F_USERS         5               /* list of users */
726 #define F_WALL          6               /* everyone logged on */
727 #define F_FORW_SUSP     7               /* suspended host forwarding */
728 #define F_FORW_UNKN     8               /* unknown host forwarding */
729 #define F_PIPE          9               /* named pipe */
730 char    *TypeNames[] = {
731         "UNUSED",       "FILE",         "TTY",          "CONSOLE",
732         "FORW",         "USERS",        "WALL",         "FORW(SUSPENDED)",
733         "FORW(UNKNOWN)", "PIPE"
734 };
735
736 struct  filed *Files = (struct filed *) 0;
737 struct  filed consfile;
738
739 struct code {
740         char    *c_name;
741         int     c_val;
742 };
743
744 struct code     PriNames[] = {
745         {"alert",       LOG_ALERT},
746         {"crit",        LOG_CRIT},
747         {"debug",       LOG_DEBUG},
748         {"emerg",       LOG_EMERG},
749         {"err",         LOG_ERR},
750         {"error",       LOG_ERR},               /* DEPRECATED */
751         {"info",        LOG_INFO},
752         {"none",        INTERNAL_NOPRI},        /* INTERNAL */
753         {"notice",      LOG_NOTICE},
754         {"panic",       LOG_EMERG},             /* DEPRECATED */
755         {"warn",        LOG_WARNING},           /* DEPRECATED */
756         {"warning",     LOG_WARNING},
757         {"*",           TABLE_ALLPRI},
758         {NULL,          -1}
759 };
760
761 struct code     FacNames[] = {
762         {"auth",         LOG_AUTH},
763         {"authpriv",     LOG_AUTHPRIV},
764         {"cron",         LOG_CRON},
765         {"daemon",       LOG_DAEMON},
766         {"kern",         LOG_KERN},
767         {"lpr",          LOG_LPR},
768         {"mail",         LOG_MAIL},
769         {"mark",         LOG_MARK},             /* INTERNAL */
770         {"news",         LOG_NEWS},
771         {"security",     LOG_AUTH},             /* DEPRECATED */
772         {"syslog",       LOG_SYSLOG},
773         {"user",         LOG_USER},
774         {"uucp",         LOG_UUCP},
775 #if defined(LOG_FTP)
776         {"ftp",          LOG_FTP},
777 #endif
778         {"local0",       LOG_LOCAL0},
779         {"local1",       LOG_LOCAL1},
780         {"local2",       LOG_LOCAL2},
781         {"local3",       LOG_LOCAL3},
782         {"local4",       LOG_LOCAL4},
783         {"local5",       LOG_LOCAL5},
784         {"local6",       LOG_LOCAL6},
785         {"local7",       LOG_LOCAL7},
786         {NULL,           -1},
787 };
788
789 int     Debug;                  /* debug flag */
790 char    LocalHostName[MAXHOSTNAMELEN+1];        /* our hostname */
791 char    *LocalDomain;           /* our local domain name */
792 char    *emptystring = "";
793 int     InetInuse = 0;          /* non-zero if INET sockets are being used */
794 int     *finet = NULL;          /* Internet datagram sockets */
795 int     Initialized = 0;        /* set when we have initialized ourselves */
796 int     MarkInterval = 20 * 60; /* interval between marks in seconds */
797 #ifdef INET6
798 int     family = PF_UNSPEC;     /* protocol family (IPv4, IPv6 or both) */
799 #else
800 int     family = PF_INET;       /* protocol family (IPv4 only) */
801 #endif
802 int     send_to_all = 0;        /* send message to all IPv4/IPv6 addresses */
803 int     MarkSeq = 0;            /* mark sequence number */
804 int     LastAlarm = 0;          /* last value passed to alarm() (seconds)  */
805 int     DupesPending = 0;       /* Number of unflushed duplicate messages */
806 int     NoFork = 0;             /* don't fork - don't run in daemon mode */
807 int     AcceptRemote = 0;       /* receive messages that come via UDP */
808 char    **StripDomains = NULL;  /* these domains may be stripped before writing logs */
809 char    **LocalHosts = NULL;    /* these hosts are logged with their hostname */
810 int     NoHops = 1;             /* Can we bounce syslog messages through an
811                                    intermediate host. */
812
813 extern  int errno;
814
815 /* Function prototypes. */
816 int main(int argc, char **argv);
817 char **crunch_list(char *list);
818 int usage(void);
819 void untty(void);
820 void printchopped(const char *hname, char *msg, int len, int fd);
821 void printline(const char *hname, char *msg);
822 void printsys(char *msg);
823 void logmsg(int pri, char *msg, const char *from, int flags);
824 void fprintlog(register struct filed *f, char *from, int flags, char *msg);
825 void endtty();
826 void wallmsg(register struct filed *f, struct iovec *iov);
827 void reapchild();
828 const char *cvtaddr(struct sockaddr_storage *f, int len);
829 const char *cvthname(struct sockaddr_storage *f, int len);
830 void domark();
831 void debug_switch();
832 void logerror(const char *type);
833 void die(int sig);
834 #ifndef TESTING
835 void doexit(int sig);
836 #endif
837 void init();
838 void cfline(char *line, register struct filed *f);
839 int decode(char *name, struct code *codetab);
840 #if defined(__GLIBC__)
841 #define dprintf mydprintf
842 #endif /* __GLIBC__ */
843 static void dprintf(char *, ...);
844 static void allocate_log(void);
845 void sighup_handler();
846
847 #ifdef SYSLOG_UNIXAF
848 static int create_unix_socket(const char *path);
849 #endif
850 #ifdef SYSLOG_INET
851 static int *create_inet_sockets();
852 #endif
853
854 int main(argc, argv)
855         int argc;
856         char **argv;
857 {
858         register int i;
859 #ifndef TESTING
860         ssize_t msglen;
861 #endif
862 #if !defined(__GLIBC__)
863         int len, num_fds;
864 #else /* __GLIBC__ */
865 #ifndef TESTING
866         socklen_t len;
867 #endif
868         int num_fds;
869 #endif /* __GLIBC__ */
870         /*
871          * It took me quite some time to figure out how this is
872          * supposed to work so I guess I should better write it down.
873          * unixm is a list of file descriptors from which one can
874          * read().  This is in contrary to readfds which is a list of
875          * file descriptors where activity is monitored by select()
876          * and from which one cannot read().  -Joey
877          *
878          * Changed: unixm is gone, since we now use datagram unix sockets.
879          * Hence we recv() from unix sockets directly (rather than
880          * first accept()ing connections on them), so there's no need
881          * for separate book-keeping.  --okir
882          */
883         fd_set readfds;
884
885 #ifndef TESTING
886         int     fd;
887 #ifdef  SYSLOG_INET
888         struct sockaddr_storage frominet;
889 #endif
890         pid_t ppid = getpid();
891 #endif
892         int ch;
893
894         char line[MAXLINE +1];
895         extern int optind;
896         extern char *optarg;
897         int maxfds;
898
899 #ifndef TESTING
900         chdir ("/");
901 #endif
902         for (i = 1; i < MAXFUNIX; i++) {
903                 funixn[i] = "";
904                 funix[i]  = -1;
905         }
906
907         while ((ch = getopt(argc, argv, "46Aa:dhf:l:m:np:rs:v")) != EOF)
908                 switch((char)ch) {
909                 case '4':
910                         family = PF_INET;
911                         break;
912 #ifdef INET6
913                 case '6':
914                         family = PF_INET6;
915                         break;
916 #endif
917                 case 'A':
918                         send_to_all++;
919                         break;
920                 case 'a':
921                         if (nfunix < MAXFUNIX)
922                                 funixn[nfunix++] = optarg;
923                         else
924                                 fprintf(stderr, "Out of descriptors, ignoring %s\n", optarg);
925                         break;
926                 case 'd':               /* debug */
927                         Debug = 1;
928                         break;
929                 case 'f':               /* configuration file */
930                         ConfFile = optarg;
931                         break;
932                 case 'h':
933                         NoHops = 0;
934                         break;
935                 case 'l':
936                         if (LocalHosts) {
937                                 fprintf (stderr, "Only one -l argument allowed," \
938                                         "the first one is taken.\n");
939                                 break;
940                         }
941                         LocalHosts = crunch_list(optarg);
942                         break;
943                 case 'm':               /* mark interval */
944                         MarkInterval = atoi(optarg) * 60;
945                         break;
946                 case 'n':               /* don't fork */
947                         NoFork = 1;
948                         break;
949                 case 'p':               /* path to regular log socket */
950                         funixn[0] = optarg;
951                         break;
952                 case 'r':               /* accept remote messages */
953                         AcceptRemote = 1;
954                         break;
955                 case 's':
956                         if (StripDomains) {
957                                 fprintf (stderr, "Only one -s argument allowed," \
958                                         "the first one is taken.\n");
959                                 break;
960                         }
961                         StripDomains = crunch_list(optarg);
962                         break;
963                 case 'v':
964                         printf("syslogd %s.%s\n", VERSION, PATCHLEVEL);
965                         exit (0);
966                 case '?':
967                 default:
968                         usage();
969                 }
970         if ((argc -= optind))
971                 usage();
972
973 #ifndef TESTING
974         if ( !(Debug || NoFork) )
975         {
976                 dprintf("Checking pidfile.\n");
977                 if (!check_pid(PidFile))
978                 {
979                         signal (SIGTERM, doexit);
980                         if (fork()) {
981                                 /*
982                                  * Parent process
983                                  */
984                                 sleep(300);
985                                 /*
986                                  * Not reached unless something major went wrong.  5
987                                  * minutes should be a fair amount of time to wait.
988                                  * Please note that this procedure is important since
989                                  * the father must not exit before syslogd isn't
990                                  * initialized or the klogd won't be able to flush its
991                                  * logs.  -Joey
992                                  */
993                                 exit(1);
994                         }
995                         signal (SIGTERM, SIG_DFL);
996                         num_fds = getdtablesize();
997                         for (i= 0; i < num_fds; i++)
998                                 (void) close(i);
999                         untty();
1000                 }
1001                 else
1002                 {
1003                         fputs("syslogd: Already running.\n", stderr);
1004                         exit(1);
1005                 }
1006         }
1007         else
1008 #endif
1009                 debugging_on = 1;
1010 #ifndef SYSV
1011         else
1012                 setlinebuf(stdout);
1013 #endif
1014
1015 #ifndef TESTING
1016         /* tuck my process id away */
1017         if ( !Debug )
1018         {
1019                 dprintf("Writing pidfile.\n");
1020                 if (!check_pid(PidFile))
1021                 {
1022                         if (!write_pid(PidFile))
1023                         {
1024                                 dprintf("Can't write pid.\n");
1025                                 if (getpid() != ppid)
1026                                         kill (ppid, SIGTERM);
1027                                 exit(1);
1028                         }
1029                 }
1030                 else
1031                 {
1032                         dprintf("Pidfile (and pid) already exist.\n");
1033                         if (getpid() != ppid)
1034                                 kill (ppid, SIGTERM);
1035                         exit(1);
1036                 }
1037         } /* if ( !Debug ) */
1038 #endif
1039
1040         consfile.f_type = F_CONSOLE;
1041         (void) strcpy(consfile.f_un.f_fname, ctty);
1042
1043         /* Initialization is done by init() */
1044         (void) strcpy(LocalHostName, emptystring);
1045         LocalDomain = emptystring;
1046
1047         (void) signal(SIGTERM, die);
1048         (void) signal(SIGINT, Debug ? die : SIG_IGN);
1049         (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
1050         (void) signal(SIGCHLD, reapchild);
1051         (void) signal(SIGALRM, domark);
1052         (void) signal(SIGUSR1, Debug ? debug_switch : SIG_IGN);
1053         (void) signal(SIGXFSZ, SIG_IGN);
1054
1055         LastAlarm = MarkInterval;
1056         alarm(LastAlarm);
1057
1058         /* Create a partial message table for all file descriptors. */
1059         num_fds = getdtablesize();
1060         dprintf("Allocated parts table for %d file descriptors.\n", num_fds);
1061         if ( (parts = (char **) malloc(num_fds * sizeof(char *))) == \
1062             (char **) 0 )
1063         {
1064                 logerror("Cannot allocate memory for message parts table.");
1065 #ifndef TESTING
1066                 if (getpid() != ppid)
1067                         kill (ppid, SIGTERM);
1068 #endif
1069                 die(0);
1070         }
1071         for(i= 0; i < num_fds; ++i)
1072             parts[i] = (char *) 0;
1073
1074         dprintf("Starting.\n");
1075         init();
1076 #ifndef TESTING
1077         if ( Debug )
1078         {
1079                 dprintf("Debugging disabled, SIGUSR1 to turn on debugging.\n");
1080                 debugging_on = 0;
1081         }
1082         /*
1083          * Send a signal to the parent to it can terminate.
1084          */
1085         if (getpid() != ppid)
1086                 kill (ppid, SIGTERM);
1087 #endif
1088
1089         /* Main loop begins here. */
1090         for (;;) {
1091                 int nfds;
1092                 errno = 0;
1093                 FD_ZERO(&readfds);
1094                 maxfds = 0;
1095 #ifdef SYSLOG_UNIXAF
1096 #ifndef TESTING
1097                 /*
1098                  * Add the Unix Domain Sockets to the list of read
1099                  * descriptors.
1100                  */
1101                 /* Copy master connections */
1102                 for (i = 0; i < nfunix; i++) {
1103                         if (funix[i] != -1) {
1104                                 FD_SET(funix[i], &readfds);
1105                                 if (funix[i]>maxfds) maxfds=funix[i];
1106                         }
1107                 }
1108 #endif
1109 #endif
1110 #ifdef SYSLOG_INET
1111 #ifndef TESTING
1112                 /*
1113                  * Add the Internet Domain Socket to the list of read
1114                  * descriptors.
1115                  */
1116                 if ( InetInuse && AcceptRemote ) {
1117                         for (i = 0; i < *finet; i++) {
1118                                 if (finet[i+1] != -1)
1119                                         FD_SET(finet[i+1], &readfds);
1120                                 if (finet[i+1]>maxfds) maxfds=finet[i+1];
1121                         }
1122                         dprintf("Listening on syslog UDP port.\n");
1123                 }
1124 #endif
1125 #endif
1126 #ifdef TESTING
1127                 FD_SET(fileno(stdin), &readfds);
1128                 if (fileno(stdin) > maxfds) maxfds = fileno(stdin);
1129
1130                 dprintf("Listening on stdin.  Press Ctrl-C to interrupt.\n");
1131 #endif
1132
1133                 if ( debugging_on )
1134                 {
1135                         dprintf("Calling select, active file descriptors (max %d): ", maxfds);
1136                         for (nfds= 0; nfds <= maxfds; ++nfds)
1137                                 if ( FD_ISSET(nfds, &readfds) )
1138                                         dprintf("%d ", nfds);
1139                         dprintf("\n");
1140                 }
1141                 nfds = select(maxfds+1, (fd_set *) &readfds, (fd_set *) NULL,
1142                                   (fd_set *) NULL, (struct timeval *) NULL);
1143                 if ( restart )
1144                 {
1145                         restart = 0;
1146                         dprintf("\nReceived SIGHUP, reloading syslogd.\n");
1147                         init();
1148                         continue;
1149                 }
1150                 if (nfds == 0) {
1151                         dprintf("No select activity.\n");
1152                         continue;
1153                 }
1154                 if (nfds < 0) {
1155                         if (errno != EINTR)
1156                                 logerror("select");
1157                         dprintf("Select interrupted.\n");
1158                         continue;
1159                 }
1160
1161                 if ( debugging_on )
1162                 {
1163                         dprintf("\nSuccessful select, descriptor count = %d, " \
1164                                 "Activity on: ", nfds);
1165                         for (nfds= 0; nfds <= maxfds; ++nfds)
1166                                 if ( FD_ISSET(nfds, &readfds) )
1167                                         dprintf("%d ", nfds);
1168                         dprintf(("\n"));
1169                 }
1170
1171 #ifndef TESTING
1172 #ifdef SYSLOG_UNIXAF
1173                 for (i = 0; i < nfunix; i++) {
1174                     if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) {
1175                         memset(line, 0, sizeof(line));
1176                         msglen = recv(fd, line, MAXLINE - 2, 0);
1177                         dprintf("Message from UNIX socket: #%d\n", fd);
1178                         if (msglen > 0)
1179                                 printchopped(LocalHostName, line, msglen + 2,  fd);
1180                         else if (msglen < 0 && errno != EINTR) {
1181                                 dprintf("UNIX socket error: %d = %s.\n", \
1182                                         errno, strerror(errno));
1183                                 logerror("recvfrom UNIX");
1184                         }
1185                     }
1186                 }
1187 #endif
1188
1189 #ifdef SYSLOG_INET
1190                 if (InetInuse && AcceptRemote && finet) {
1191                         for (i = 0; i < *finet; i++) {
1192                                 if (finet[i+1] != -1 && FD_ISSET(finet[i+1], &readfds)) {
1193                                         len = sizeof(frominet);
1194                                         memset(line, 0, sizeof(line));
1195                                         msglen = recvfrom(finet[i+1], line, MAXLINE - 2, 0, \
1196                                                      (struct sockaddr *) &frominet, &len);
1197                                         if (Debug) {
1198                                                 const char *addr = cvtaddr(&frominet, len);
1199                                                 dprintf("Message from inetd socket: #%d, host: %s\n",
1200                                                         i+1, addr);
1201                                         }
1202                                         if (msglen > 0) {
1203                                                 /* Note that if cvthname() returns NULL then
1204                                                    we shouldn't attempt to log the line -- jch */
1205                                                 const char *from = cvthname(&frominet, len);
1206                                                 if (from)
1207                                                         printchopped(from, line,
1208                                                                      msglen + 2,  finet[i+1]);
1209                                         } else if (msglen < 0 && errno != EINTR && errno != EAGAIN) {
1210                                                 dprintf("INET socket error: %d = %s.\n", \
1211                                                         errno, strerror(errno));
1212                                                 logerror("recvfrom inet");
1213                                                 /* should be harmless now that we set
1214                                                  * BSDCOMPAT on the socket */
1215                                                 sleep(1);
1216                                         }
1217                                 }
1218                         }
1219                 }
1220 #endif
1221 #else
1222                 if ( FD_ISSET(fileno(stdin), &readfds) ) {
1223                         dprintf("Message from stdin.\n");
1224                         memset(line, '\0', sizeof(line));
1225                         line[0] = '.';
1226                         parts[fileno(stdin)] = (char *) 0;
1227                         i = read(fileno(stdin), line, MAXLINE);
1228                         if (i > 0) {
1229                                 printchopped(LocalHostName, line, i+1, fileno(stdin));
1230                         } else if (i < 0) {
1231                                 if (errno != EINTR) {
1232                                         logerror("stdin");
1233                                 }
1234                         }
1235                         FD_CLR(fileno(stdin), &readfds);
1236                   }
1237
1238 #endif
1239         }
1240 }
1241
1242 int usage()
1243 {
1244         fprintf(stderr, "usage: syslogd [-46Adrvh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \
1245                 " [-s domainlist] [-f conffile]\n");
1246         exit(1);
1247 }
1248
1249 #ifdef SYSLOG_UNIXAF
1250 static int create_unix_socket(const char *path)
1251 {
1252         struct sockaddr_un sunx;
1253         int fd;
1254         char line[MAXLINE +1];
1255
1256         if (path[0] == '\0')
1257                 return -1;
1258
1259         (void) unlink(path);
1260
1261         memset(&sunx, 0, sizeof(sunx));
1262         sunx.sun_family = AF_UNIX;
1263         (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path));
1264         fd = socket(AF_UNIX, SOCK_DGRAM, 0);
1265         if (fd < 0 || bind(fd, (struct sockaddr *) &sunx,
1266                            sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 ||
1267             chmod(path, 0666) < 0) {
1268                 (void) snprintf(line, sizeof(line), "cannot create %s", path);
1269                 logerror(line);
1270                 dprintf("cannot create %s (%d).\n", path, errno);
1271                 close(fd);
1272 #ifndef SYSV
1273                 die(0);
1274 #endif
1275                 return -1;
1276         }
1277         return fd;
1278 }
1279 #endif
1280
1281 #ifdef SYSLOG_INET
1282 static int *create_inet_sockets()
1283 {
1284         struct addrinfo hints, *res, *r;
1285         int error, maxs, *s, *socks;
1286         int on = 1, sockflags;
1287
1288         memset(&hints, 0, sizeof(hints));
1289         hints.ai_flags = AI_PASSIVE;
1290         hints.ai_family = family;
1291         hints.ai_socktype = SOCK_DGRAM;
1292         error = getaddrinfo(NULL, "syslog", &hints, &res);
1293         if (error) {
1294                 logerror("network logging disabled (syslog/udp service unknown).");
1295                 logerror("see syslogd(8) for details of whether and how to enable it.");
1296                 logerror(gai_strerror(error));
1297                 return NULL;
1298         }
1299
1300         /* Count max number of sockets we may open */
1301         for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
1302         socks = malloc((maxs+1) * sizeof(int));
1303         if (!socks) {
1304                 logerror("couldn't allocate memory for sockets");
1305                 die(0);
1306         }
1307
1308         *socks = 0;     /* num of sockets counter at start of array */
1309         s = socks + 1;
1310         for (r = res; r; r = r->ai_next) {
1311                 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
1312                 if (*s < 0) {
1313                         logerror("socket");
1314                         continue;
1315                 }
1316                 if (r->ai_family == AF_INET6) {
1317                         if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
1318                                        (char *) &on, sizeof(on)) < 0) {
1319                                 logerror("setsockopt (IPV6_ONLY), suspending IPv6");
1320                                 close(*s);
1321                                 continue;
1322                         }
1323                 }
1324                 if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
1325                                (char *) &on, sizeof(on)) < 0 ) {
1326                         logerror("setsockopt(REUSEADDR), suspending inet");
1327                         close(*s);
1328                         continue;
1329                 }
1330                 /* We must not block on the network socket, in case a packet
1331                  * gets lost between select and recv, otherise the process
1332                  * will stall until the timeout, and other processes trying to
1333                  * log will also stall.
1334                  */
1335                 if ((sockflags = fcntl(*s, F_GETFL)) != -1) {
1336                         sockflags |= O_NONBLOCK;
1337                         /*
1338                          * SETFL could fail too, so get it caught by the subsequent
1339                          * error check.
1340                          */
1341                         sockflags = fcntl(*s, F_SETFL, sockflags);
1342                 }
1343                 if (sockflags == -1) {
1344                         logerror("fcntl(O_NONBLOCK), suspending inet");
1345                         close(*s);
1346                         continue;
1347                 }
1348                 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
1349                         logerror("bind, suspending inet");
1350                         close(*s);
1351                         continue;
1352                 }
1353                 (*socks)++;
1354                 s++;
1355         }
1356         if (res)
1357                 freeaddrinfo(res);
1358         if (*socks == 0) {
1359                 logerror("no valid sockets, suspending inet");
1360                 free(socks);
1361                 return NULL;
1362         }
1363         return socks;
1364 }
1365 #endif
1366
1367 char **
1368 crunch_list(list)
1369         char *list;
1370 {
1371         int i, m, n;
1372         char *p, *q;
1373         char **result = NULL;
1374
1375         p = list;
1376         
1377         /* strip off trailing delimiters */
1378         while (*p && p[strlen(p)-1] == LIST_DELIMITER)
1379                 p[strlen(p)-1] = '\0';
1380         /* cut off leading delimiters */
1381         while (p[0] == LIST_DELIMITER)
1382                 p++; 
1383         
1384         /* count delimiters to calculate the number of elements */
1385         for (n = i = 0; p[i]; i++)
1386                 if (p[i] == LIST_DELIMITER) n++;
1387         
1388         if ((result = (char **)malloc(sizeof(char *) * (n + 2))) == NULL) {
1389                 printf ("Sorry, can't get enough memory, exiting.\n");
1390                 exit(1);
1391         }
1392         
1393         /*
1394          * We now can assume that the first and last
1395          * characters are different from any delimiters,
1396          * so we don't have to care about this.
1397          */
1398         m = 0;
1399         while ((q = strchr(p, LIST_DELIMITER)) && m < n) {
1400                 result[m] = (char *) malloc((q - p + 1) * sizeof(char));
1401                 if (result[m] == NULL) {
1402                         printf ("Sorry, can't get enough memory, exiting.\n");
1403                         exit(1);
1404                 }
1405                 memcpy(result[m], p, q - p);
1406                 result[m][q - p] = '\0';
1407                 p = q; p++;
1408                 m++;
1409         }
1410         if ((result[m] = strdup(p)) == NULL) {
1411                 printf ("Sorry, can't get enough memory, exiting.\n");
1412                 exit(1);
1413         }
1414         result[++m] = NULL;
1415
1416 #if 0
1417         m = 0;
1418         while (result[m])
1419                 dprintf ("#%d: %s\n", m, result[m++]);
1420 #endif
1421         return result;
1422 }
1423
1424
1425 void untty()
1426 #ifdef SYSV
1427 {
1428         if ( !Debug ) {
1429                 setsid();
1430         }
1431         return;
1432 }
1433
1434 #else
1435 {
1436         int i;
1437
1438         if ( !Debug ) {
1439                 i = open(_PATH_TTY, O_RDWR);
1440                 if (i >= 0) {
1441                         (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
1442                         (void) close(i);
1443                 }
1444         }
1445 }
1446 #endif
1447
1448
1449 /*
1450  * Parse the line to make sure that the msg is not a composite of more
1451  * than one message.
1452  */
1453
1454 void printchopped(hname, msg, len, fd)
1455         const char *hname;
1456         char *msg;
1457         int len;
1458         int fd;
1459 {
1460         auto int ptlngth;
1461
1462         auto char *start = msg,
1463                   *p,
1464                   *end,
1465                   tmpline[MAXLINE + 1];
1466
1467         dprintf("Message length: %d, File descriptor: %d.\n", len, fd);
1468         tmpline[0] = '\0';
1469         if ( parts[fd] != (char *) 0 )
1470         {
1471                 dprintf("Including part from messages.\n");
1472                 strcpy(tmpline, parts[fd]);
1473                 free(parts[fd]);
1474                 parts[fd] = (char *) 0;
1475                 if ( (strlen(msg) + strlen(tmpline)) > MAXLINE )
1476                 {
1477                         logerror("Cannot glue message parts together");
1478                         printline(hname, tmpline);
1479                         start = msg;
1480                 }
1481                 else
1482                 {
1483                         dprintf("Previous: %s\n", tmpline);
1484                         dprintf("Next: %s\n", msg);
1485                         strcat(tmpline, msg);   /* length checked above */
1486                         printline(hname, tmpline);
1487                         if ( (strlen(msg) + 1) == len )
1488                                 return;
1489                         else
1490                                 start = strchr(msg, '\0') + 1;
1491                 }
1492         }
1493
1494         if ( msg[len-1] != '\0' )
1495         {
1496                 msg[len] = '\0';
1497                 for(p= msg+len-1; *p != '\0' && p > msg; )
1498                         --p;
1499                 if(*p == '\0') p++;
1500                 ptlngth = strlen(p);
1501                 if ( (parts[fd] = malloc(ptlngth + 1)) == (char *) 0 )
1502                         logerror("Cannot allocate memory for message part.");
1503                 else
1504                 {
1505                         strcpy(parts[fd], p);
1506                         dprintf("Saving partial msg: %s\n", parts[fd]);
1507                         memset(p, '\0', ptlngth);
1508                 }
1509         }
1510
1511         do {
1512                 end = strchr(start + 1, '\0');
1513                 printline(hname, start);
1514                 start = end + 1;
1515         } while ( *start != '\0' );
1516
1517         return;
1518 }
1519
1520
1521
1522 /*
1523  * Take a raw input line, decode the message, and print the message
1524  * on the appropriate log files.
1525  */
1526
1527 void printline(hname, msg)
1528         const char *hname;
1529         char *msg;
1530 {
1531         register char *p, *q;
1532         register unsigned char c;
1533         char line[MAXLINE + 1];
1534         unsigned int pri;               // Valid Priority values are 0-191
1535         int prilen=0;                   // Track Priority value string len
1536         int msglen;
1537
1538         /* test for special codes */
1539         msglen=strlen(msg);
1540         pri = DEFUPRI;
1541         p = msg;
1542
1543         if (*p == '<') {
1544                 pri = 0;
1545                 while (--msglen > 0 && isdigit((unsigned char)*++p) &&
1546                                         pri <= MAX_PRI) {
1547                         pri = 10 * pri + (*p - '0');
1548                         prilen++;
1549                 }
1550                 if (*p == '>' && prilen)
1551                         ++p;
1552                 else {
1553                         pri = DEFUPRI;
1554                         p = msg;
1555                 }
1556         }
1557
1558         if ((pri &~ (LOG_FACMASK|LOG_PRIMASK)) || (pri > MAX_PRI)) {
1559                 pri = DEFUPRI;
1560                 p = msg;
1561         }
1562
1563         memset (line, 0, sizeof(line));
1564         q = line;
1565         while ((c = *p++) && q < &line[sizeof(line) - 4]) {
1566                 if (c == '\n' || c == 127)
1567                         *q++ = ' ';
1568                 else if (c < 040) {
1569                         *q++ = '^';
1570                         *q++ = c ^ 0100;
1571                 } else
1572                         *q++ = c;
1573         }
1574         *q = '\0';
1575
1576         logmsg(pri, line, hname, SYNC_FILE);
1577         return;
1578 }
1579
1580
1581
1582 /*
1583  * Take a raw input line from /dev/klog, split and format similar to syslog().
1584  */
1585
1586 void printsys(msg)
1587         char *msg;
1588 {
1589         register char *p, *q;
1590         register int c;
1591         char line[MAXLINE + 1];
1592         int pri, flags;
1593         char *lp;
1594
1595         (void) snprintf(line, sizeof(line), "vmunix: ");
1596         lp = line + strlen(line);
1597         for (p = msg; *p != '\0'; ) {
1598                 flags = ADDDATE;
1599                 pri = DEFSPRI;
1600                 if (*p == '<') {
1601                         pri = 0;
1602                         while (isdigit(*++p))
1603                                 pri = 10 * pri + (*p - '0');
1604                         if (*p == '>')
1605                                 ++p;
1606                 } else {
1607                         /* kernel printf's come out on console */
1608                         flags |= IGN_CONS;
1609                 }
1610                 if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1611                         pri = DEFSPRI;
1612                 q = lp;
1613                 while (*p != '\0' && (c = *p++) != '\n' &&
1614                     q < &line[MAXLINE])
1615                         *q++ = c;
1616                 *q = '\0';
1617                 logmsg(pri, line, LocalHostName, flags);
1618         }
1619         return;
1620 }
1621
1622 /*
1623  * Decode a priority into textual information like auth.emerg.
1624  */
1625 char *textpri(pri)
1626         int pri;
1627 {
1628         static char res[20];
1629         CODE *c_pri, *c_fac;
1630
1631         for (c_fac = facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
1632         for (c_pri = prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
1633
1634         snprintf (res, sizeof(res), "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
1635
1636         return res;
1637 }
1638
1639 time_t  now;
1640
1641 /*
1642  * Log a message to the appropriate log files, users, etc. based on
1643  * the priority.
1644  */
1645
1646 void logmsg(pri, msg, from, flags)
1647         int pri;
1648         char *msg;
1649         const char *from;
1650         int flags;
1651 {
1652         register struct filed *f;
1653         int fac, prilev, lognum;
1654         int msglen;
1655         char *timestamp;
1656 #ifdef __gnu_linux__
1657         sigset_t mask;
1658 #else
1659 #ifndef SYSV
1660         sigset_t omask;
1661 #endif
1662 #endif
1663
1664         dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, from, msg);
1665
1666 #ifdef __gnu_linux__
1667         sigemptyset(&mask);
1668         sigaddset(&mask, SIGHUP);
1669         sigaddset(&mask, SIGALRM);
1670         sigprocmask(SIG_BLOCK, &mask, NULL);
1671 #else
1672 #ifndef SYSV
1673         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
1674 #endif
1675 #endif
1676
1677         /*
1678          * Check to see if msg looks non-standard.
1679          *
1680          * A message looks like
1681          * Nov 17 11:42:33 CRON[
1682          * 01234567890123456
1683          *    ^  ^  ^  ^  ^
1684          *
1685          * Remote messages are not accompanied by a timestamp.
1686          * Local messages are accompanied by a timestamp (program's timezone)
1687          */
1688         msglen = strlen(msg);
1689         if (!(msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
1690             msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')) {
1691                 msg += 16;
1692                 msglen -= 16;
1693         }
1694
1695         (void) time(&now);
1696         timestamp = ctime(&now) + 4;
1697
1698         /* extract facility and priority level */
1699         fac = LOG_FAC(pri);
1700         prilev = LOG_PRI(pri);
1701
1702         /* log the message to the particular outputs */
1703         if (!Initialized) {
1704                 f = &consfile;
1705                 f->f_file = open(ctty, O_WRONLY|O_NOCTTY);
1706
1707                 if (f->f_file >= 0) {
1708                         untty();
1709                         fprintlog(f, (char *)from, flags, msg);
1710                         (void) close(f->f_file);
1711                         f->f_file = -1;
1712                 }
1713 #ifdef __gnu_linux__
1714                 sigprocmask(SIG_UNBLOCK, &mask, NULL);
1715 #else
1716 #ifndef SYSV
1717                 (void) sigsetmask(omask);
1718 #endif
1719 #endif
1720                 return;
1721         }
1722 #ifdef SYSV
1723         for (lognum = 0; lognum <= nlogs; lognum++) {
1724                 f = &Files[lognum];
1725 #else
1726         for (f = Files; f; f = f->f_next) {
1727 #endif
1728
1729                 /* skip messages that are incorrect priority */
1730                 if ( (f->f_pmask[fac] == TABLE_NOPRI) || \
1731                     ((f->f_pmask[fac] & (1<<prilev)) == 0) )
1732                         continue;
1733
1734                 if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
1735                         continue;
1736
1737                 /* don't output marks to recently written files */
1738                 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
1739                         continue;
1740
1741                 /*
1742                  * suppress duplicate lines to this file
1743                  */
1744                 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
1745                     !strcmp(msg, f->f_prevline) &&
1746                     !strcmp(from, f->f_prevhost)) {
1747                         (void) strncpy(f->f_lasttime, timestamp, 15);
1748                         f->f_prevcount++;
1749                         dprintf("msg repeated %d times, %ld sec of %d.\n",
1750                             f->f_prevcount, now - f->f_time,
1751                             repeatinterval[f->f_repeatcount]);
1752
1753                         if (f->f_prevcount == 1 && DupesPending++ == 0) {
1754                                 int seconds;
1755                                 dprintf("setting alarm to flush duplicate messages\n");
1756
1757                                 seconds = alarm(0);
1758                                 MarkSeq += LastAlarm - seconds;
1759                                 LastAlarm = seconds;
1760                                 if (LastAlarm > TIMERINTVL)
1761                                         LastAlarm = TIMERINTVL;
1762                                 alarm(LastAlarm);
1763                         }
1764
1765                         /*
1766                          * If domark would have logged this by now,
1767                          * flush it now (so we don't hold isolated messages),
1768                          * but back off so we'll flush less often
1769                          * in the future.
1770                          */
1771                         if (now > REPEATTIME(f)) {
1772                                 fprintlog(f, (char *)from, flags, (char *)NULL);
1773                                 BACKOFF(f);
1774                         }
1775                 } else {
1776                         /* new line, save it */
1777                         if (f->f_prevcount) {
1778                                 fprintlog(f, (char *)from, 0, (char *)NULL);
1779
1780                                 if (--DupesPending == 0) {
1781                                         dprintf("unsetting duplicate message flush alarm\n");
1782
1783                                         MarkSeq += LastAlarm - alarm(0);
1784                                         LastAlarm = MarkInterval - MarkSeq;
1785                                         alarm(LastAlarm);
1786                                 }
1787                         }
1788                         f->f_prevpri = pri;
1789                         f->f_repeatcount = 0;
1790                         (void) strncpy(f->f_lasttime, timestamp, 15);
1791                         (void) strncpy(f->f_prevhost, from,
1792                                         sizeof(f->f_prevhost));
1793                         if (msglen < MAXSVLINE) {
1794                                 f->f_prevlen = msglen;
1795                                 (void) strcpy(f->f_prevline, msg);
1796                                 fprintlog(f, (char *)from, flags, (char *)NULL);
1797                         } else {
1798                                 f->f_prevline[0] = 0;
1799                                 f->f_prevlen = 0;
1800                                 fprintlog(f, (char *)from, flags, msg);
1801                         }
1802                 }
1803         }
1804 #ifdef __gnu_linux__
1805         sigprocmask(SIG_UNBLOCK, &mask, NULL);
1806 #else
1807 #ifndef SYSV
1808         (void) sigsetmask(omask);
1809 #endif
1810 #endif
1811 }
1812 #if FALSE
1813 } /* balance parentheses for emacs */
1814 #endif
1815
1816 void fprintlog(f, from, flags, msg)
1817         register struct filed *f;
1818         char *from;
1819         int flags;
1820         char *msg;
1821 {
1822         struct iovec iov[6];
1823         register struct iovec *v = iov;
1824         char repbuf[80];
1825 #ifdef SYSLOG_INET
1826         register int l;
1827         char line[MAXLINE + 1];
1828         time_t fwd_suspend;
1829         struct addrinfo hints, *ai;
1830         int err;
1831 #endif
1832
1833         dprintf("Called fprintlog, ");
1834
1835         v->iov_base = f->f_lasttime;
1836         v->iov_len = 15;
1837         v++;
1838         v->iov_base = " ";
1839         v->iov_len = 1;
1840         v++;
1841         v->iov_base = f->f_prevhost;
1842         v->iov_len = strlen(v->iov_base);
1843         v++;
1844         v->iov_base = " ";
1845         v->iov_len = 1;
1846         v++;
1847         if (msg) {
1848                 v->iov_base = msg;
1849                 v->iov_len = strlen(msg);
1850         } else if (f->f_prevcount > 1) {
1851                 (void) snprintf(repbuf, sizeof(repbuf), "last message repeated %d times",
1852                     f->f_prevcount);
1853                 v->iov_base = repbuf;
1854                 v->iov_len = strlen(repbuf);
1855         } else {
1856                 v->iov_base = f->f_prevline;
1857                 v->iov_len = f->f_prevlen;
1858         }
1859         v++;
1860
1861         dprintf("logging to %s", TypeNames[f->f_type]);
1862
1863         switch (f->f_type) {
1864         case F_UNUSED:
1865                 f->f_time = now;
1866                 dprintf("\n");
1867                 break;
1868
1869 #ifdef SYSLOG_INET
1870         case F_FORW_SUSP:
1871                 fwd_suspend = time((time_t *) 0) - f->f_time;
1872                 if ( fwd_suspend >= INET_SUSPEND_TIME ) {
1873                         dprintf("\nForwarding suspension over, " \
1874                                 "retrying FORW ");
1875                         f->f_type = F_FORW;
1876                         goto f_forw;
1877                 }
1878                 else {
1879                         dprintf(" %s\n", f->f_un.f_forw.f_hname);
1880                         dprintf("Forwarding suspension not over, time " \
1881                                 "left: %d.\n", INET_SUSPEND_TIME - \
1882                                 fwd_suspend);
1883                 }
1884                 break;
1885                 
1886         /*
1887          * The trick is to wait some time, then retry to get the
1888          * address. If that fails retry x times and then give up.
1889          *
1890          * You'll run into this problem mostly if the name server you
1891          * need for resolving the address is on the same machine, but
1892          * is started after syslogd. 
1893          */
1894         case F_FORW_UNKN:
1895                 dprintf(" %s\n", f->f_un.f_forw.f_hname);
1896                 fwd_suspend = time((time_t *) 0) - f->f_time;
1897                 if ( fwd_suspend >= INET_SUSPEND_TIME ) {
1898                         dprintf("Forwarding suspension to unknown over, retrying\n");
1899                         memset(&hints, 0, sizeof(hints));
1900                         hints.ai_family = family;
1901                         hints.ai_socktype = SOCK_DGRAM;
1902                         if ((err = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, &ai))) {
1903                                 dprintf("Failure: %s\n", gai_strerror(err));
1904                                 dprintf("Retries: %d\n", f->f_prevcount);
1905                                 if ( --f->f_prevcount < 0 ) {
1906                                         dprintf("Giving up.\n");
1907                                         f->f_type = F_UNUSED;
1908                                 }
1909                                 else
1910                                         dprintf("Left retries: %d\n", f->f_prevcount);
1911                         }
1912                         else {
1913                                 dprintf("%s found, resuming.\n", f->f_un.f_forw.f_hname);
1914                                 f->f_un.f_forw.f_addr = ai;
1915                                 f->f_prevcount = 0;
1916                                 f->f_type = F_FORW;
1917                                 goto f_forw;
1918                         }
1919                 }
1920                 else
1921                         dprintf("Forwarding suspension not over, time " \
1922                                 "left: %d\n", INET_SUSPEND_TIME - fwd_suspend);
1923                 break;
1924
1925         case F_FORW:
1926                 /* 
1927                  * Don't send any message to a remote host if it
1928                  * already comes from one. (we don't care 'bout who
1929                  * sent the message, we don't send it anyway)  -Joey
1930                  */
1931         f_forw:
1932                 dprintf(" %s\n", f->f_un.f_forw.f_hname);
1933                 if ( strcmp(from, LocalHostName) && NoHops )
1934                         dprintf("Not sending message to remote.\n");
1935                 else if (finet) {
1936                         int i;
1937                         f->f_time = now;
1938                         (void) snprintf(line, sizeof(line), "<%d>%s", f->f_prevpri, \
1939                                 (char *) iov[4].iov_base);
1940                         l = strlen(line);
1941                         if (l > MAXLINE)
1942                                 l = MAXLINE;
1943                         err = -1;
1944                         for (ai = f->f_un.f_forw.f_addr; ai; ai = ai->ai_next) {
1945                                 for (i = 0; i < *finet; i++) {
1946                                         int lsent;
1947                                         lsent = sendto(finet[i+1], line, l, 0,
1948                                                        ai->ai_addr, ai->ai_addrlen);
1949                                         if (lsent == l) {
1950                                                 err = -1;
1951                                                 break;
1952                                         }
1953                                         err = errno;
1954                                 }
1955                                 if (err == -1 && !send_to_all)
1956                                         break;
1957                         }
1958                         if (err != -1) {
1959                                 dprintf("INET sendto error: %d = %s.\n", 
1960                                         err, strerror(err));
1961                                 f->f_type = F_FORW_SUSP;
1962                                 errno = err;
1963                                 logerror("sendto");
1964                         }
1965                 }
1966                 break;
1967 #endif
1968
1969         case F_CONSOLE:
1970                 f->f_time = now;
1971 #ifdef UNIXPC
1972                 if (1) {
1973 #else
1974                 if (flags & IGN_CONS) { 
1975 #endif
1976                         dprintf(" (ignored).\n");
1977                         break;
1978                 }
1979                 /* FALLTHROUGH */
1980
1981         case F_TTY:
1982         case F_FILE:
1983         case F_PIPE:
1984                 f->f_time = now;
1985                 dprintf(" %s\n", f->f_un.f_fname);
1986                 if (f->f_type == F_TTY || f->f_type == F_CONSOLE) {
1987                         v->iov_base = "\r\n";
1988                         v->iov_len = 2;
1989                 } else {
1990                         v->iov_base = "\n";
1991                         v->iov_len = 1;
1992                 }
1993         again:
1994                 /* f->f_file == -1 is an indicator that we couldn't
1995                    open the file at startup. */
1996                 if (f->f_file == -1)
1997                         break;
1998
1999                 if (writev(f->f_file, iov, 6) < 0) {
2000                         int e = errno;
2001
2002                         /* If a named pipe is full, just ignore it for now */
2003                         if (f->f_type == F_PIPE && e == EAGAIN)
2004                                 break;
2005
2006                         /* If the filesystem is filled up, just ignore
2007                            it for now and continue writing when
2008                            possible */
2009                         if (f->f_type == F_FILE && e == ENOSPC)
2010                                 break;
2011
2012                         (void) close(f->f_file);
2013                         /*
2014                          * Check for EBADF on TTY's due to vhangup() XXX
2015                          * Linux uses EIO instead (mrn 12 May 96)
2016                          */
2017                         if ((f->f_type == F_TTY || f->f_type == F_CONSOLE)
2018 #ifdef linux
2019                                 && e == EIO) {
2020 #else
2021                                 && e == EBADF) {
2022 #endif
2023                                 f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_NOCTTY);
2024                                 if (f->f_file < 0) {
2025                                         f->f_type = F_UNUSED;
2026                                         logerror(f->f_un.f_fname);
2027                                 } else {
2028                                         untty();
2029                                         goto again;
2030                                 }
2031                         } else {
2032                                 f->f_type = F_UNUSED;
2033                                 errno = e;
2034                                 logerror(f->f_un.f_fname);
2035                         }
2036                 } else if (f->f_type == F_FILE && (f->f_flags & SYNC_FILE))
2037                         (void) fsync(f->f_file);
2038                 break;
2039
2040         case F_USERS:
2041         case F_WALL:
2042                 f->f_time = now;
2043                 dprintf("\n");
2044                 v->iov_base = "\r\n";
2045                 v->iov_len = 2;
2046                 wallmsg(f, iov);
2047                 break;
2048         } /* switch */
2049         if (f->f_type != F_FORW_UNKN)
2050                 f->f_prevcount = 0;
2051         return;         
2052 }
2053 #if FALSE
2054 }} /* balance parentheses for emacs */
2055 #endif
2056
2057 jmp_buf ttybuf;
2058
2059 void endtty()
2060 {
2061         longjmp(ttybuf, 1);
2062 }
2063
2064 /*
2065  *  WALLMSG -- Write a message to the world at large
2066  *
2067  *      Write the specified message to either the entire
2068  *      world, or a list of approved users.
2069  */
2070
2071 void wallmsg(f, iov)
2072         register struct filed *f;
2073         struct iovec *iov;
2074 {
2075         char p[sizeof (_PATH_DEV) + UNAMESZ];
2076         register int i;
2077         int ttyf, len;
2078         static int reenter = 0;
2079         struct utmp ut;
2080         struct utmp *uptr;
2081         char greetings[200];
2082
2083         (void) &len;
2084
2085         if (reenter++)
2086                 return;
2087
2088         /* open the user login file */
2089         setutent();
2090
2091
2092         /*
2093          * Might as well fork instead of using nonblocking I/O
2094          * and doing notty().
2095          */
2096         if (fork() == 0) {
2097                 (void) signal(SIGTERM, SIG_DFL);
2098                 (void) alarm(0);
2099 #ifndef SYSV
2100                 (void) signal(SIGTTOU, SIG_IGN);
2101                 (void) sigsetmask(0);
2102 #endif
2103                 (void) snprintf(greetings, sizeof(greetings),
2104                     "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
2105                         (char *) iov[2].iov_base, ctime(&now));
2106                 len = strlen(greetings);
2107
2108                 /* scan the user login file */
2109                 while ((uptr = getutent())) {
2110                         memcpy(&ut, uptr, sizeof(ut));
2111                         /* is this slot used? */
2112                         if (ut.ut_name[0] == '\0')
2113                                 continue;
2114                         if (ut.ut_type != USER_PROCESS)
2115                                 continue;
2116                         if (!(strcmp (ut.ut_name,"LOGIN"))) /* paranoia */
2117                                 continue;
2118
2119                         /* should we send the message to this user? */
2120                         if (f->f_type == F_USERS) {
2121                                 for (i = 0; i < MAXUNAMES; i++) {
2122                                         if (!f->f_un.f_uname[i][0]) {
2123                                                 i = MAXUNAMES;
2124                                                 break;
2125                                         }
2126                                         if (strncmp(f->f_un.f_uname[i],
2127                                             ut.ut_name, UNAMESZ) == 0)
2128                                                 break;
2129                                 }
2130                                 if (i >= MAXUNAMES)
2131                                         continue;
2132                         }
2133
2134                         /* compute the device name */
2135                         strcpy(p, _PATH_DEV);
2136                         strncat(p, ut.ut_line, UNAMESZ);
2137
2138                         if (f->f_type == F_WALL) {
2139                                 iov[0].iov_base = greetings;
2140                                 iov[0].iov_len = len;
2141                                 iov[1].iov_len = 0;
2142                         }
2143                         if (setjmp(ttybuf) == 0) {
2144                                 (void) signal(SIGALRM, endtty);
2145                                 (void) alarm(15);
2146                                 /* open the terminal */
2147                                 ttyf = open(p, O_WRONLY|O_NOCTTY);
2148                                 if (ttyf >= 0) {
2149                                         struct stat statb;
2150
2151                                         if (fstat(ttyf, &statb) == 0 &&
2152                                             (statb.st_mode & S_IWRITE))
2153                                                 (void) writev(ttyf, iov, 6);
2154                                         close(ttyf);
2155                                         ttyf = -1;
2156                                 }
2157                         }
2158                         (void) alarm(0);
2159                 }
2160                 exit(0);
2161         }
2162         /* close the user login file */
2163         endutent();
2164         reenter = 0;
2165 }
2166
2167 void reapchild()
2168 {
2169         int saved_errno = errno;
2170 #if defined(SYSV) && !defined(linux)
2171         (void) signal(SIGCHLD, reapchild);      /* reset signal handler -ASP */
2172         wait ((int *)0);
2173 #else
2174         union wait status;
2175
2176         while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
2177                 ;
2178 #endif
2179 #ifdef linux
2180         (void) signal(SIGCHLD, reapchild);      /* reset signal handler -ASP */
2181 #endif
2182         errno = saved_errno;
2183 }
2184
2185 const char *cvtaddr (struct sockaddr_storage *f, int len)
2186 {
2187         static char ip[NI_MAXHOST];
2188
2189         if (getnameinfo((struct sockaddr *) f, len,
2190                         ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
2191                 return "???";
2192         return ip;
2193 }
2194
2195 /*
2196  * Return a printable representation of a host address.
2197  *
2198  * Here we could check if the host is permitted to send us syslog
2199  * messages.  We just have to check the hostname we're about to return
2200  * and compared it (case-insensitively) to a blacklist or whitelist.
2201  * Callers of cvthname() need to know that if NULL is returned then
2202  * the host is to be ignored.
2203  */
2204 const char *cvthname(struct sockaddr_storage *f, int len)
2205 {
2206         static char hname[NI_MAXHOST];
2207         int error;
2208         register char *p;
2209         int count;
2210
2211         if ((error = getnameinfo((struct sockaddr *) f, len,
2212                                  hname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) {
2213                 dprintf("Host name for your address (%s) unknown: %s\n", gai_strerror(error));
2214                 if ((error = getnameinfo((struct sockaddr *) f, len,
2215                                          hname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) {
2216                         dprintf("Malformed from address: %s\n", gai_strerror(error));
2217                         return "???";
2218                 }
2219                 return hname;
2220         }
2221         /*
2222          * Convert to lower case, just like LocalDomain above
2223          */
2224         for (p = hname; *p ; p++)
2225                 if (isupper(*p))
2226                         *p = tolower(*p);
2227
2228         /*
2229          * Notice that the string still contains the fqdn, but your
2230          * hostname and domain are separated by a '\0'.
2231          */
2232         if ((p = strchr(hname, '.'))) {
2233                 if (strcmp(p + 1, LocalDomain) == 0) {
2234                         *p = '\0';
2235                         return (hname);
2236                 } else {
2237                         if (StripDomains) {
2238                                 count=0;
2239                                 while (StripDomains[count]) {
2240                                         if (strcmp(p + 1, StripDomains[count]) == 0) {
2241                                                 *p = '\0';
2242                                                 return (hname);
2243                                         }
2244                                         count++;
2245                                 }
2246                         }
2247                         if (LocalHosts) {
2248                                 count=0;
2249                                 while (LocalHosts[count]) {
2250                                         if (!strcmp(hname, LocalHosts[count])) {
2251                                                 *p = '\0';
2252                                                 return (hname);
2253                                         }
2254                                         count++;
2255                                 }
2256                         }
2257                 }
2258         }
2259
2260         return (hname);
2261 }
2262
2263 void domark()
2264 {
2265         register struct filed *f;
2266 #ifdef SYSV
2267         int lognum;
2268 #endif
2269
2270         if (MarkInterval > 0) {
2271                 now = time(0);
2272                 MarkSeq += LastAlarm;
2273                 if (MarkSeq >= MarkInterval) {
2274                         logmsg(LOG_MARK|LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
2275                         MarkSeq -= MarkInterval;
2276                 }
2277         }
2278
2279 #ifdef SYSV
2280         for (lognum = 0; lognum <= nlogs; lognum++) {
2281                 f = &Files[lognum];
2282 #else
2283         for (f = Files; f; f = f->f_next) {
2284 #endif
2285                 if (f->f_prevcount && now >= REPEATTIME(f)) {
2286                         dprintf("flush %s: repeated %d times, %d sec.\n",
2287                                 TypeNames[f->f_type], f->f_prevcount,
2288                                 repeatinterval[f->f_repeatcount]);
2289                         fprintlog(f, LocalHostName, 0, (char *)NULL);
2290                         BACKOFF(f);
2291                         DupesPending--;
2292                 }
2293         }
2294         (void) signal(SIGALRM, domark);
2295
2296         LastAlarm = MarkInterval - MarkSeq;
2297         if (DupesPending && LastAlarm > TIMERINTVL)
2298                 LastAlarm = TIMERINTVL;
2299
2300         (void) alarm(LastAlarm);
2301 }
2302
2303 void debug_switch()
2304
2305 {
2306         dprintf("Switching debugging_on to %s\n", (debugging_on == 0) ? "true" : "false");
2307         debugging_on = (debugging_on == 0) ? 1 : 0;
2308         signal(SIGUSR1, debug_switch);
2309 }
2310
2311
2312 /*
2313  * Print syslogd errors some place.
2314  */
2315 void logerror(const char *type)
2316 {
2317         char buf[100];
2318
2319         dprintf("Called logerr, msg: %s\n", type);
2320
2321         if (errno == 0)
2322                 (void) snprintf(buf, sizeof(buf), "syslogd: %s", type);
2323         else
2324                 (void) snprintf(buf, sizeof(buf), "syslogd: %s: %s", type, strerror(errno));
2325         errno = 0;
2326         logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
2327         return;
2328 }
2329
2330 void die(sig)
2331
2332         int sig;
2333         
2334 {
2335         register struct filed *f;
2336         char buf[100];
2337         int lognum;
2338         int i;
2339         int was_initialized = Initialized;
2340
2341         Initialized = 0;        /* Don't log SIGCHLDs in case we
2342                                    receive one during exiting */
2343
2344         for (lognum = 0; lognum <= nlogs; lognum++) {
2345                 f = &Files[lognum];
2346                 /* flush any pending output */
2347                 if (f->f_prevcount)
2348                         fprintlog(f, LocalHostName, 0, (char *)NULL);
2349         }
2350
2351         Initialized = was_initialized;
2352         if (sig) {
2353                 dprintf("syslogd: exiting on signal %d\n", sig);
2354                 (void) snprintf(buf, sizeof(buf), "exiting on signal %d", sig);
2355                 errno = 0;
2356                 logmsg(LOG_SYSLOG|LOG_INFO, buf, LocalHostName, ADDDATE);
2357         }
2358
2359         /* Close the UNIX sockets. */
2360         for (i = 0; i < nfunix; i++)
2361                 if (funix[i] != -1)
2362                         close(funix[i]);
2363         /* Close the inet sockets. */
2364         if (InetInuse && finet) {
2365                 for (i = 0; i < *finet; i++)
2366                         close(finet[i+1]);
2367                 free(finet);
2368         }
2369
2370         /* Clean-up files. */
2371         for (i = 0; i < nfunix; i++)
2372                 if (funixn[i] && funix[i] != -1)
2373                         (void)unlink(funixn[i]);
2374 #ifndef TESTING
2375         (void) remove_pid(PidFile);
2376 #endif
2377         exit(0);
2378 }
2379
2380 /*
2381  * Signal handler to terminate the parent process.
2382  */
2383 #ifndef TESTING
2384 void doexit(sig)
2385         int sig;
2386 {
2387         exit (0);
2388 }
2389 #endif
2390
2391 /*
2392  *  INIT -- Initialize syslogd from configuration table
2393  */
2394
2395 void init()
2396 {
2397         register int i, lognum;
2398         register FILE *cf;
2399         register struct filed *f;
2400 #ifndef TESTING
2401 #ifndef SYSV
2402         register struct filed **nextp = (struct filed **) 0;
2403 #endif
2404 #endif
2405         register char *p;
2406         register unsigned int Forwarding = 0;
2407 #ifdef CONT_LINE
2408         char cbuf[BUFSIZ];
2409         char *cline;
2410 #else
2411         char cline[BUFSIZ];
2412 #endif
2413         struct hostent *hent;
2414
2415         /*
2416          *  Close all open log files and free log descriptor array.
2417          */
2418         dprintf("Called init.\n");
2419         Initialized = 0;
2420         if ( nlogs > -1 )
2421         {
2422                 dprintf("Initializing log structures.\n");
2423
2424                 for (lognum = 0; lognum <= nlogs; lognum++ ) {
2425                         f = &Files[lognum];
2426
2427                         /* flush any pending output */
2428                         if (f->f_prevcount)
2429                                 fprintlog(f, LocalHostName, 0, (char *)NULL);
2430
2431                         switch (f->f_type) {
2432                         case F_FILE:
2433                         case F_PIPE:
2434                         case F_TTY:
2435                         case F_CONSOLE:
2436                                 (void) close(f->f_file);
2437                                 break;
2438                         case F_FORW:
2439                         case F_FORW_SUSP:
2440                                 freeaddrinfo(f->f_un.f_forw.f_addr);
2441                                 break;
2442                         }
2443                 }
2444
2445                 /*
2446                  * This is needed especially when HUPing syslogd as the
2447                  * structure would grow infinitively.  -Joey
2448                  */
2449                 nlogs = -1;
2450                 free((void *) Files);
2451                 Files = (struct filed *) 0;
2452         }
2453         
2454
2455 #ifdef SYSV
2456         lognum = 0;
2457 #else
2458         f = NULL;
2459 #endif
2460
2461         /* Get hostname */
2462         (void) gethostname(LocalHostName, sizeof(LocalHostName));
2463         LocalDomain = emptystring;
2464         if ( (p = strchr(LocalHostName, '.')) ) {
2465                 *p++ = '\0';
2466                 LocalDomain = p;
2467         }
2468         else if ( AcceptRemote )
2469         {
2470                 /*
2471                  * It's not clearly defined whether gethostname()
2472                  * should return the simple hostname or the fqdn. A
2473                  * good piece of software should be aware of both and
2474                  * we want to distribute good software.  Joey
2475                  *
2476                  * Good software also always checks its return values...
2477                  * If syslogd starts up before DNS is up & /etc/hosts
2478                  * doesn't have LocalHostName listed, gethostbyname will
2479                  * return NULL. 
2480                  */
2481                 hent = gethostbyname(LocalHostName);
2482                 if ( hent )
2483                         snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name);
2484                         
2485                 if ( (p = strchr(LocalHostName, '.')) )
2486                 {
2487                         *p++ = '\0';
2488                         LocalDomain = p;
2489                 }
2490         }
2491
2492         /*
2493          * Convert to lower case to recognize the correct domain laterly
2494          */
2495         for (p = (char *)LocalDomain; *p ; p++)
2496                 if (isupper(*p))
2497                         *p = tolower(*p);
2498
2499         /* open the configuration file */
2500         if ((cf = fopen(ConfFile, "r")) == NULL) {
2501                 dprintf("cannot open %s.\n", ConfFile);
2502 #ifdef SYSV
2503                 allocate_log();
2504                 f = &Files[lognum++];
2505 #ifndef TESTING
2506                 cfline("*.err\t" _PATH_CONSOLE, f);
2507 #else
2508                 snprintf(cbuf,sizeof(cbuf), "*.*\t%s", ttyname(0));
2509                 cfline(cbuf, f);
2510 #endif
2511 #else
2512                 *nextp = (struct filed *)calloc(1, sizeof(*f));
2513                 cfline("*.ERR\t" _PATH_CONSOLE, *nextp);
2514                 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f))        /* ASP */
2515                 cfline("*.PANIC\t*", (*nextp)->f_next);
2516 #endif
2517                 Initialized = 1;
2518                 return;
2519         }
2520
2521         /*
2522          *  Foreach line in the conf table, open that file.
2523          */
2524 #if CONT_LINE
2525         cline = cbuf;
2526         while (fgets(cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) {
2527 #else
2528         while (fgets(cline, sizeof(cline), cf) != NULL) {
2529 #endif
2530                 /*
2531                  * check for end-of-section, comments, strip off trailing
2532                  * spaces and newline character.
2533                  */
2534                 for (p = cline; isspace(*p); ++p);
2535                 if (*p == '\0' || *p == '#')
2536                         continue;
2537 #if CONT_LINE
2538                 memmove(cline, p, strlen(p)+1);
2539 #endif
2540                 for (p = strchr(cline, '\0'); isspace(*--p););
2541 #if CONT_LINE
2542                 if (*p == '\\') {
2543                         if ((p - cbuf) > BUFSIZ - 30) {
2544                                 /* Oops the buffer is full - what now? */
2545                                 cline = cbuf;
2546                         } else {
2547                                 *p = 0;
2548                                 cline = p;
2549                                 continue;
2550                         }
2551                 }  else
2552                         cline = cbuf;
2553 #endif
2554                 *++p = '\0';
2555 #ifndef SYSV
2556                 f = (struct filed *)calloc(1, sizeof(*f));
2557                 *nextp = f;
2558                 nextp = &f->f_next;
2559 #endif
2560                 allocate_log();
2561                 f = &Files[lognum++];
2562 #if CONT_LINE
2563                 cfline(cbuf, f);
2564 #else
2565                 cfline(cline, f);
2566 #endif
2567                 if (f->f_type == F_FORW || f->f_type == F_FORW_SUSP || f->f_type == F_FORW_UNKN) {
2568                         Forwarding++;
2569                 }
2570         }
2571
2572         /* close the configuration file */
2573         (void) fclose(cf);
2574
2575 #ifdef SYSLOG_UNIXAF
2576         for (i = 0; i < nfunix; i++) {
2577                 if (funix[i] != -1)
2578                         /* Don't close the socket, preserve it instead
2579                         close(funix[i]);
2580                         */
2581                         continue;
2582                 if ((funix[i] = create_unix_socket(funixn[i])) != -1)
2583                         dprintf("Opened UNIX socket `%s'.\n", funixn[i]);
2584         }
2585 #endif
2586
2587 #ifdef SYSLOG_INET
2588         if (Forwarding || AcceptRemote) {
2589                 if (!finet) {
2590                         finet = create_inet_sockets();
2591                         if (finet) {
2592                                 InetInuse = 1;
2593                                 dprintf("Opened syslog UDP port.\n");
2594                         }
2595                 }
2596         }
2597         else {
2598                 if (finet) {
2599                         for (i = 0; i < *finet; i++)
2600                                 if (finet[i+1] != -1)
2601                                         close(finet[i+1]);
2602                         free(finet);
2603                         finet = NULL;
2604                 }
2605                 InetInuse = 0;
2606         }
2607 #endif
2608
2609         Initialized = 1;
2610
2611         if ( Debug ) {
2612 #ifdef SYSV
2613                 for (lognum = 0; lognum <= nlogs; lognum++) {
2614                         f = &Files[lognum];
2615                         if (f->f_type != F_UNUSED) {
2616                                 printf ("%2d: ", lognum);
2617 #else
2618                 for (f = Files; f; f = f->f_next) {
2619                         if (f->f_type != F_UNUSED) {
2620 #endif
2621                                 for (i = 0; i <= LOG_NFACILITIES; i++)
2622                                         if (f->f_pmask[i] == TABLE_NOPRI)
2623                                                 printf(" X ");
2624                                         else
2625                                                 printf("%2X ", f->f_pmask[i]);
2626                                 printf("%s: ", TypeNames[f->f_type]);
2627                                 switch (f->f_type) {
2628                                 case F_FILE:
2629                                 case F_PIPE:
2630                                 case F_TTY:
2631                                 case F_CONSOLE:
2632                                         printf("%s", f->f_un.f_fname);
2633                                         if (f->f_file == -1)
2634                                                 printf(" (unused)");
2635                                         break;
2636
2637                                 case F_FORW:
2638                                 case F_FORW_SUSP:
2639                                 case F_FORW_UNKN:
2640                                         printf("%s", f->f_un.f_forw.f_hname);
2641                                         break;
2642
2643                                 case F_USERS:
2644                                         for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
2645                                                 printf("%s, ", f->f_un.f_uname[i]);
2646                                         break;
2647                                 }
2648                                 printf("\n");
2649                         }
2650                 }
2651         }
2652
2653         if ( AcceptRemote )
2654 #ifdef DEBRELEASE
2655                 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \
2656                        ": restart (remote reception)." , LocalHostName, \
2657                         ADDDATE);
2658 #else
2659                 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \
2660                        ": restart (remote reception)." , LocalHostName, \
2661                         ADDDATE);
2662 #endif
2663         else
2664 #ifdef DEBRELEASE
2665                 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \
2666                        ": restart." , LocalHostName, ADDDATE);
2667 #else
2668                 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \
2669                        ": restart." , LocalHostName, ADDDATE);
2670 #endif
2671         (void) signal(SIGHUP, sighup_handler);
2672         dprintf("syslogd: restarted.\n");
2673 }
2674 #if FALSE
2675 }}} /* balance parentheses for emacs */
2676 #endif
2677
2678 /*
2679  * Crack a configuration file line
2680  */
2681
2682 void cfline(line, f)
2683         char *line;
2684         register struct filed *f;
2685 {
2686         register char *p;
2687         register char *q;
2688         register int i, i2;
2689         char *bp;
2690         int pri;
2691         int singlpri = 0;
2692         int ignorepri = 0;
2693         int syncfile;
2694 #ifdef SYSLOG_INET
2695         struct addrinfo hints, *ai;
2696 #endif
2697         char buf[MAXLINE];
2698         char xbuf[200];
2699
2700         dprintf("cfline(%s)\n", line);
2701
2702         errno = 0;      /* keep strerror() stuff out of logerror messages */
2703
2704         /* clear out file entry */
2705 #ifndef SYSV
2706         memset((char *) f, 0, sizeof(*f));
2707 #endif
2708         for (i = 0; i <= LOG_NFACILITIES; i++) {
2709                 f->f_pmask[i] = TABLE_NOPRI;
2710                 f->f_flags = 0;
2711         }
2712
2713         /* scan through the list of selectors */
2714         for (p = line; *p && *p != '\t' && *p != ' ';) {
2715
2716                 /* find the end of this facility name list */
2717                 for (q = p; *q && *q != '\t' && *q++ != '.'; )
2718                         continue;
2719
2720                 /* collect priority name */
2721                 for (bp = buf; *q && !strchr("\t ,;", *q); )
2722                         *bp++ = *q++;
2723                 *bp = '\0';
2724
2725                 /* skip cruft */
2726                 while (strchr(",;", *q))
2727                         q++;
2728
2729                 /* decode priority name */
2730                 if ( *buf == '!' ) {
2731                         ignorepri = 1;
2732                         for (bp=buf; *(bp+1); bp++)
2733                                 *bp=*(bp+1);
2734                         *bp='\0';
2735                 }
2736                 else {
2737                         ignorepri = 0;
2738                 }
2739                 if ( *buf == '=' )
2740                 {
2741                         singlpri = 1;
2742                         pri = decode(&buf[1], PriNames);
2743                 }
2744                 else {
2745                         singlpri = 0;
2746                         pri = decode(buf, PriNames);
2747                 }
2748
2749                 if (pri < 0) {
2750                         (void) snprintf(xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf);
2751                         logerror(xbuf);
2752                         return;
2753                 }
2754
2755                 /* scan facilities */
2756                 while (*p && !strchr("\t .;", *p)) {
2757                         for (bp = buf; *p && !strchr("\t ,;.", *p); )
2758                                 *bp++ = *p++;
2759                         *bp = '\0';
2760                         if (*buf == '*') {
2761                                 for (i = 0; i <= LOG_NFACILITIES; i++) {
2762                                         if ( pri == INTERNAL_NOPRI ) {
2763                                                 if ( ignorepri )
2764                                                         f->f_pmask[i] = TABLE_ALLPRI;
2765                                                 else
2766                                                         f->f_pmask[i] = TABLE_NOPRI;
2767                                         }
2768                                         else if ( singlpri ) {
2769                                                 if ( ignorepri )
2770                                                         f->f_pmask[i] &= ~(1<<pri);
2771                                                 else
2772                                                         f->f_pmask[i] |= (1<<pri);
2773                                         }
2774                                         else
2775                                         {
2776                                                 if ( pri == TABLE_ALLPRI ) {
2777                                                         if ( ignorepri )
2778                                                                 f->f_pmask[i] = TABLE_NOPRI;
2779                                                         else
2780                                                                 f->f_pmask[i] = TABLE_ALLPRI;
2781                                                 }
2782                                                 else
2783                                                 {
2784                                                         if ( ignorepri )
2785                                                                 for (i2= 0; i2 <= pri; ++i2)
2786                                                                         f->f_pmask[i] &= ~(1<<i2);
2787                                                         else
2788                                                                 for (i2= 0; i2 <= pri; ++i2)
2789                                                                         f->f_pmask[i] |= (1<<i2);
2790                                                 }
2791                                         }
2792                                 }
2793                         } else {
2794                                 i = decode(buf, FacNames);
2795                                 if (i < 0) {
2796
2797                                         (void) snprintf(xbuf, sizeof(xbuf), "unknown facility name \"%s\"", buf);
2798                                         logerror(xbuf);
2799                                         return;
2800                                 }
2801
2802                                 if ( pri == INTERNAL_NOPRI ) {
2803                                         if ( ignorepri )
2804                                                 f->f_pmask[i >> 3] = TABLE_ALLPRI;
2805                                         else
2806                                                 f->f_pmask[i >> 3] = TABLE_NOPRI;
2807                                 } else if ( singlpri ) {
2808                                         if ( ignorepri )
2809                                                 f->f_pmask[i >> 3] &= ~(1<<pri);
2810                                         else
2811                                                 f->f_pmask[i >> 3] |= (1<<pri);
2812                                 } else {
2813                                         if ( pri == TABLE_ALLPRI ) {
2814                                                 if ( ignorepri )
2815                                                         f->f_pmask[i >> 3] = TABLE_NOPRI;
2816                                                 else
2817                                                         f->f_pmask[i >> 3] = TABLE_ALLPRI;
2818                                         } else {
2819                                                 if ( ignorepri )
2820                                                         for (i2= 0; i2 <= pri; ++i2)
2821                                                                 f->f_pmask[i >> 3] &= ~(1<<i2);
2822                                                 else
2823                                                         for (i2= 0; i2 <= pri; ++i2)
2824                                                                 f->f_pmask[i >> 3] |= (1<<i2);
2825                                         }
2826                                 }
2827                         }
2828                         while (*p == ',' || *p == ' ')
2829                                 p++;
2830                 }
2831
2832                 p = q;
2833         }
2834
2835         /* skip to action part */
2836         while (*p == '\t' || *p == ' ')
2837                 p++;
2838
2839         if (*p == '-')
2840         {
2841                 syncfile = 0;
2842                 p++;
2843         } else
2844                 syncfile = 1;
2845
2846         dprintf("leading char in action: %c\n", *p);
2847         switch (*p)
2848         {
2849         case '@':
2850 #ifdef SYSLOG_INET
2851                 (void) strcpy(f->f_un.f_forw.f_hname, ++p);
2852                 dprintf("forwarding host: %s\n", p);    /*ASP*/
2853                 memset(&hints, 0, sizeof(hints));
2854                 hints.ai_family = family;
2855                 hints.ai_socktype = SOCK_DGRAM;
2856                 if (getaddrinfo(p, "syslog", &hints, &ai)) {
2857                         /*
2858                          * The host might be unknown due to an
2859                          * inaccessible nameserver (perhaps on the
2860                          * same host). We try to get the ip number
2861                          * later, like FORW_SUSP.
2862                          */
2863                         f->f_type = F_FORW_UNKN;
2864                         f->f_prevcount = INET_RETRY_MAX;
2865                         f->f_time = time ( (time_t *)0 );
2866                         f->f_un.f_forw.f_addr = NULL;
2867                 } else {
2868                         f->f_type = F_FORW;
2869                         f->f_un.f_forw.f_addr = ai;
2870                 }
2871 #endif
2872                 break;
2873
2874         case '|':
2875         case '/':
2876                 (void) strcpy(f->f_un.f_fname, p);
2877                 dprintf ("filename: %s\n", p);  /*ASP*/
2878                 if (syncfile)
2879                         f->f_flags |= SYNC_FILE;
2880                 if ( *p == '|' ) {
2881                         f->f_file = open(++p, O_RDWR|O_NONBLOCK|O_NOCTTY);
2882                         f->f_type = F_PIPE;
2883                 } else {
2884                         f->f_file = open(p, O_WRONLY|O_APPEND|O_CREAT|O_NONBLOCK|O_NOCTTY,
2885                                          0644);
2886                         f->f_type = F_FILE;
2887                 }
2888                         
2889                 if ( f->f_file < 0 ){
2890                         f->f_file = -1;
2891                         dprintf("Error opening log file: %s\n", p);
2892                         logerror(p);
2893                         break;
2894                 }
2895                 if (isatty(f->f_file)) {
2896                         f->f_type = F_TTY;
2897                         untty();
2898                 }
2899                 if (strcmp(p, ctty) == 0)
2900                         f->f_type = F_CONSOLE;
2901                 break;
2902
2903         case '*':
2904                 dprintf ("write-all\n");
2905                 f->f_type = F_WALL;
2906                 break;
2907
2908         default:
2909                 dprintf ("users: %s\n", p);     /* ASP */
2910                 for (i = 0; i < MAXUNAMES && *p; i++) {
2911                         for (q = p; *q && *q != ','; )
2912                                 q++;
2913                         (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
2914                         if ((q - p) > UNAMESZ)
2915                                 f->f_un.f_uname[i][UNAMESZ] = '\0';
2916                         else
2917                                 f->f_un.f_uname[i][q - p] = '\0';
2918                         while (*q == ',' || *q == ' ')
2919                                 q++;
2920                         p = q;
2921                 }
2922                 f->f_type = F_USERS;
2923                 break;
2924         }
2925         return;
2926 }
2927
2928
2929 /*
2930  *  Decode a symbolic name to a numeric value
2931  */
2932
2933 int decode(name, codetab)
2934         char *name;
2935         struct code *codetab;
2936 {
2937         register struct code *c;
2938         register char *p;
2939         char buf[80];
2940
2941         dprintf ("symbolic name: %s", name);
2942         if (isdigit(*name))
2943         {
2944                 dprintf ("\n");
2945                 return (atoi(name));
2946         }
2947         (void) strncpy(buf, name, 79);
2948         for (p = buf; *p; p++)
2949                 if (isupper(*p))
2950                         *p = tolower(*p);
2951         for (c = codetab; c->c_name; c++)
2952                 if (!strcmp(buf, c->c_name))
2953                 {
2954                         dprintf (" ==> %d\n", c->c_val);
2955                         return (c->c_val);
2956                 }
2957         return (-1);
2958 }
2959
2960 static void dprintf(char *fmt, ...)
2961
2962 {
2963         va_list ap;
2964
2965         if ( !(Debug && debugging_on) )
2966                 return;
2967         
2968         va_start(ap, fmt);
2969         vfprintf(stdout, fmt, ap);
2970         va_end(ap);
2971
2972         fflush(stdout);
2973         return;
2974 }
2975
2976
2977 /*
2978  * The following function is responsible for allocating/reallocating the
2979  * array which holds the structures which define the logging outputs.
2980  */
2981 static void allocate_log()
2982
2983 {
2984         dprintf("Called allocate_log, nlogs = %d.\n", nlogs);
2985         
2986         /*
2987          * Decide whether the array needs to be initialized or needs to
2988          * grow.
2989          */
2990         if ( nlogs == -1 )
2991         {
2992                 Files = (struct filed *) malloc(sizeof(struct filed));
2993                 if ( Files == (void *) 0 )
2994                 {
2995                         dprintf("Cannot initialize log structure.");
2996                         logerror("Cannot initialize log structure.");
2997                         return;
2998                 }
2999         }
3000         else
3001         {
3002                 /* Re-allocate the array. */
3003                 Files = (struct filed *) realloc(Files, (nlogs+2) * \
3004                                                   sizeof(struct filed));
3005                 if ( Files == (struct filed *) 0 )
3006                 {
3007                         dprintf("Cannot grow log structure.");
3008                         logerror("Cannot grow log structure.");
3009                         return;
3010                 }
3011         }
3012         
3013         /*
3014          * Initialize the array element, bump the number of elements in the
3015          * the array and return.
3016          */
3017         ++nlogs;
3018         memset(&Files[nlogs], '\0', sizeof(struct filed));
3019         return;
3020 }
3021
3022
3023 /*
3024  * The following function is resposible for handling a SIGHUP signal.  Since
3025  * we are now doing mallocs/free as part of init we had better not being
3026  * doing this during a signal handler.  Instead this function simply sets
3027  * a flag variable which will tell the main loop to go through a restart.
3028  */
3029 void sighup_handler()
3030
3031 {
3032         restart = 1;
3033         signal(SIGHUP, sighup_handler);
3034         return;
3035 }
3036
3037 /*
3038  * Local variables:
3039  *  c-indent-level: 8
3040  *  c-basic-offset: 8
3041  *  tab-width: 8
3042  * End:
3043  */
3044