diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2004-11-08 13:52:36 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2004-11-08 13:52:36 +0000 |
commit | 05f2f1839c2712ca77e86aa679dc909d051fc23b (patch) | |
tree | ff48843fbfd9c4a7cdf3c16609247f9ef3166f40 | |
download | rsyslog-05f2f1839c2712ca77e86aa679dc909d051fc23b.tar.gz rsyslog-05f2f1839c2712ca77e86aa679dc909d051fc23b.tar.xz rsyslog-05f2f1839c2712ca77e86aa679dc909d051fc23b.zip |
Initial revision
-rw-r--r-- | ANNOUNCE | 62 | ||||
-rw-r--r-- | CHANGES | 32 | ||||
-rw-r--r-- | COPYING | 339 | ||||
-rw-r--r-- | INSTALL | 37 | ||||
-rw-r--r-- | MANIFEST | 62 | ||||
-rw-r--r-- | Makefile | 122 | ||||
-rw-r--r-- | NEWS | 170 | ||||
-rw-r--r-- | README.1st | 65 | ||||
-rw-r--r-- | README.linux | 72 | ||||
-rw-r--r-- | klogd.8 | 441 | ||||
-rw-r--r-- | klogd.c | 1191 | ||||
-rw-r--r-- | klogd.h | 40 | ||||
-rw-r--r-- | ksym.c | 901 | ||||
-rw-r--r-- | ksym_mod.c | 700 | ||||
-rw-r--r-- | ksyms.h | 35 | ||||
-rw-r--r-- | modutils.patch | 65 | ||||
-rw-r--r-- | oops.c | 118 | ||||
-rw-r--r-- | oops_test.c | 52 | ||||
-rw-r--r-- | pidfile.c | 130 | ||||
-rw-r--r-- | pidfile.h | 50 | ||||
-rw-r--r-- | sysklogd.8 | 607 | ||||
-rw-r--r-- | syslog-tst.conf | 0 | ||||
-rw-r--r-- | syslog.c | 254 | ||||
-rw-r--r-- | syslog.conf | 46 | ||||
-rw-r--r-- | syslog.conf.5 | 397 | ||||
-rw-r--r-- | syslog_tst.c | 74 | ||||
-rw-r--r-- | syslogd.8 | 1 | ||||
-rw-r--r-- | syslogd.c | 2803 | ||||
-rw-r--r-- | version.h | 2 |
29 files changed, 8868 insertions, 0 deletions
diff --git a/ANNOUNCE b/ANNOUNCE new file mode 100644 index 00000000..aba171e7 --- /dev/null +++ b/ANNOUNCE @@ -0,0 +1,62 @@ +On behalf of the beta-testers and other members of the Linux INTERNET +community who have helped shape and debug this package I am pleased to +announce version 1.3-pl3 of the sysklogd package. + +This package implements two system log daemons. The syslogd daemon is +an enhanced version of the standard Berkeley utility program. This +daemon is responsible for providing logging of messages received from +programs and facilities on the local host as well as from remote +hosts. The klogd daemon listens to kernel message sources and is +responsible for prioritizing and processing operating system +messages. The klogd daemon can run as a client of syslogd or +optionally as a standalone program. + +This package is the culmination of about two years of experience and +bug reports on the 1.2 version from both the INTERNET and our +corporate Linux networks. The utilities in this package should provide +VERY reliable system logging. Klogd and syslogd have both been stress +tested in kernel development environments where literally hundreds of +megabytes of kernel messages have been blasted through them. If either +utility should fail I would appreciate a report and debug information +so that the bug can be reproduced and squashed. + +This package includes some major improvements. Some of them are listed +here: + + * klogd supports on-the-fly kernel address to symbol + translations. This requires that a valid kernel symbol map be + found at execution. + + * klogd also supports debugging of protection faults which occur + in kernel loadable modules. + + * syslogd has better handling of remote logging capabilities. + + * both klogd and syslogd can be controlled through commandline + options and signals. + + * both daemons are now FSSTND conform. + + * a syslog.conf(5) manpage is now available. + + * Spaces are now accepted in the syslog configuration + file. This should be a real crowd pleaser. + + * Syslogd now uses dynamic allocation of logging output + descriptors. There is no longer a static limit on the number + of log destinations that can be defined. + + * Numerous bug fixes and code cleanups. + +The new release can be obtained from either tsx-11.mit.edu or +sunsite.unc.edu. + +Thanks again to everyone who has contributed ideas, patches and bug +reports. Linux has a superior set of logging utilities thanks to +contributions from the entire community. + + +Dr. Greg Wettstein +Oncology Research Division Computing Facility +Roger Maris Cancer Center +greg@wind.enjellic.com diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000..25a50edc --- /dev/null +++ b/CHANGES @@ -0,0 +1,32 @@ +Version 1.4.1 + + . klogd will set the console log level only if `-c' is given on the + commandline, not overwriting local settings in `/etc/sysctl.conf'. + . Bugfix: klogd will use SOCK_DGRM as well, re-enables kernel logging + . Bugfix: Don't make syslogd fail with broken `-a' + . Bugfix: klogd will skip zero bytes and not enter a busy loop anymore + . Thomas Roessler <roessler@does-not-exist.org> + - Patch to prevent LogLine() from being invoked with a negative + counter as an argument. + +Version 1.4 + + . Skip newline when reading in klog messages + . Use lseek64() instead of llseek() which is deprecated these days + . Close symbol file before returning with 0 when an error occurred + while reading it. This will enable systems to umount that + partition with no open file descriptor left over. + . Solar Designer <solar@false.com> + - printline() fixes + - priority decoding fix + . Daniel Jacobowitz <dan@debian.org> + - printchopped() fix + . Keith Owens <kaos@ocs.com.au> + - Fixed bug that caused klogd to die if there is no sym_array available. + - When symbols are expanded, print the line twice. Once with + addresses converted to symbols, once with the raw text. Allows + external programs such as ksymoops do their own processing on the + original data. + . Olaf Kirch <okir@caldera.de> + - Remove Unix Domain Sockets and switch to Datagram Unix Sockets + . Several bugfixes and improvements, please refer to the .c files diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..a43ea212 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..c7a0ad9e --- /dev/null +++ b/INSTALL @@ -0,0 +1,37 @@ +1.) READ the README.linux file and the accompanying man pages. It will + save you some frustration. + +2.) Edit the Makefile for your installation. NOTE that if you have not + carried out step 1 you may make choices which could render your + system and/or these utilities unusable. Compile the utilities. + Compilation has been tested with versions 2.5.8, 2.6.3 and 2.7.0 of + the gcc compiler and libc versions 4.5.26 and 4.6.27. + +3.) The FSSTND makes suggestions as to appropriate locations for + system binaries. Since not everyone agrees with standards it is + up to the system administrator installing the utilities to choose + the most appropriate locations for the binaries and their + configuration files. By default the package will compile and + install following the FSSTND recommendations. If a decision is + made to change this behavior consult the makefile and the sources. + The FSSTND define controls selection of values which may be + influenced by the choice of conformance with the FSSTND or site + preferences. + +4.) For proper functioning both of these utilities are best run as root. + This is probably not much of a problem since they will probably be + started either by init or as part of the rc.* startup process. There + may be security concerns with running syslogd as root. Please repeat + step 1 if you are unsure of why this may be the case. + +5.) If kernel address to symbol translation is desired there is the + possibility that a new kernel will need to be compiled. The patches + to delimit kernel addresses requiring translation were added to + kernel 1.3.43. If this kernel or a newer kernel is used there is + no need to modify the kernel sources. + + If a kernel earlier than this is used the kernel sources will have to + be patched. The patch to delimit addresses for translation is included + with the sysklogd sources. The necessary modifications are quite + generic and should require little modification over a wide range of + kernel sources. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 00000000..be0cb61e --- /dev/null +++ b/MANIFEST @@ -0,0 +1,62 @@ +A virgin copy of these sources should include 12 files: + +MANIFEST: This file. + +INSTALL: Brief installation instructions. + +NEWS: Important changes. + +Makefile: A makefile to generate the binaries. + +README.linux: Documentation which may prove useful. + +klogd.c: Source code for the kernel log daemon. + +klogd.h: Global definitions required for the kernel log daemon. + +ksym.c: Source module for the kernel log daemon which implements + kernel numeric address to symbol translations. + +ksym_mod.c: Source module which contains functions which allow ksym.c + to resolve symbols found in loadable kernel modules. + +syslogd.c: Source code for the system log daemon. + +syslog.c: A slightly modified version of the syslog.c file found in + the standard libraries. This special version is needed + so that klogd will pass messages with kernel priority to + the syslogd facility. + +pidfile.c: Source implementing utility functions which are useful + for managing pid files. Used by both syslogd and klogd. + +pidfile.h: Include file containing global definitions for the + pid file utility functions. + +version.h: An include file for setting the version and patchlevel + for the package. + +syslog.conf: A sample configuration file. Note that this file uses + extensions to the BSD syntax. See the syslog.conf(5) + manpage for more details. + +syslog_tst.c: A simple program to test the system log utility. + +sysklogd.8: Man page documenting the general characteristics of this + package. + +klogd.8: Man page documenting the kernel log daemon. + +kernel.patch: A source code patch which modifies the linux kernel to + delimit addresses for symbolic translation by klogd. + +oops.c: C source for a loadable kernel module which can be used + to generate a kernel protection fault. This is used to + test the address resolution capabilities of klogd. + +oops_test.c: A small driver program used in conjunction with the oops + module to generate a kernel protection fault. + +modules.patch: A patch to the modules-2.0.0 package which provides for + automatic signalling of klogd whenever the kernel module + state changes. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6507e0a0 --- /dev/null +++ b/Makefile @@ -0,0 +1,122 @@ +# Makefile for syslogd and klogd daemons. + +CC= gcc +#CFLAGS= -g -DSYSV -Wall +#LDFLAGS= -g +CFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce +LDFLAGS= -s + +# Look where your install program is. +INSTALL = /usr/bin/install +BINDIR = /usr/sbin +MANDIR = /usr/man + +# There is one report that under an all ELF system there may be a need to +# explicilty link with libresolv.a. If linking syslogd fails you may wish +# to try uncommenting the following define. +# LIBS = /usr/lib/libresolv.a + +# A patch was forwarded which provided support for sysklogd under +# the ALPHA. This patch included a reference to a library which may be +# specific to the ALPHA. If you are attempting to build this package under +# an ALPHA and linking fails with unresolved references please try +# uncommenting the following define. +# LIBS = ${LIBS} -linux + +# Define the following to impart start-up delay in klogd. This is +# useful if klogd is started simultaneously or in close-proximity to syslogd. +# KLOGD_START_DELAY = -DKLOGD_DELAY=5 + +# The following define determines whether the package adheres to the +# file system standard. +FSSTND = -DFSSTND + +# The following define establishes ownership for the man pages. +# Avery tells me that there is a difference between Debian and +# Slackware. Rather than choose sides I am leaving it up to the user. +MAN_OWNER = root +# MAN_OWNER = man + +# The following define establishes the name of the pid file for the +# syslogd daemon. The library include file (paths.h) defines the +# name for the syslogd pid to be syslog.pid. A number of people have +# suggested that this should be syslogd.pid. You may cast your +# ballot below. +SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\" + +SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DNO_SCCS ${FSSTND} \ + ${SYSLOGD_PIDNAME} +SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING +KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} +DEB = + +.c.o: + ${CC} ${CFLAGS} -c $*.c + +all: syslogd klogd + +test: syslog_tst ksym oops_test tsyslogd + +install: install_man install_exec + +syslogd: syslogd.o pidfile.o + ${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o ${LIBS} + +klogd: klogd.o syslog.o pidfile.o ksym.o ksym_mod.o + ${CC} ${LDFLAGS} -o klogd klogd.o syslog.o pidfile.o ksym.o \ + ksym_mod.o ${LIBS} + +syslog_tst: syslog_tst.o + ${CC} ${LDFLAGS} -o syslog_tst syslog_tst.o + +tsyslogd: syslogd.c version.h + $(CC) $(CFLAGS) -g -DTESTING $(SYSLOGD_FLAGS) -o tsyslogd syslogd.c + +tklogd: klogd.c syslog.c ksym.c ksym_mod.c version.h + $(CC) $(CFLAGS) -g -DTESTING $(KLOGD_FLAGS) -o tklogd klogd.c syslog.c ksym.c ksym_mod.c + +syslogd.o: syslogd.c version.h + ${CC} ${CFLAGS} ${SYSLOGD_FLAGS} $(DEB) -c syslogd.c + +syslog.o: syslog.c + ${CC} ${CFLAGS} ${SYSLOG_FLAGS} -c syslog.c + +klogd.o: klogd.c klogd.h version.h + ${CC} ${CFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c + +ksym.o: ksym.c klogd.h + ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym.c + +ksym_mod.o: ksym_mod.c klogd.h + ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym_mod.c + +syslog_tst.o: syslog_tst.c + ${CC} ${CFLAGS} -c syslog_tst.c + +oops_test: oops.o + ${CC} ${CFLAGS} -o oops_test oops_test.c + +oops.o: oops.c + ${CC} ${CFLAGS} -D__KERNEL__ -DMODULE -c oops.c + +ksym: ksym_test.o ksym_mod.o + ${CC} ${LDFLAGS} -o ksym ksym_test.o ksym_mod.o + +ksym_test.o: ksym.c + ${CC} ${CFLAGS} -DTEST -o ksym_test.o -c ksym.c + +clean: + rm -f *.o *.log *~ *.orig + +clobber: clean + rm -f syslogd klogd ksym syslog_tst oops_test TAGS tsyslogd tklogd + +install_exec: syslogd klogd + ${INSTALL} -m 500 -s syslogd ${BINDIR}/syslogd + ${INSTALL} -m 500 -s klogd ${BINDIR}/klogd + +install_man: + ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 sysklogd.8 ${MANDIR}/man8/sysklogd.8 + ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 syslogd.8 ${MANDIR}/man8/syslogd.8 + ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 syslog.conf.5 ${MANDIR}/man5/syslog.conf.5 + ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 klogd.8 ${MANDIR}/man8/klogd.8 @@ -0,0 +1,170 @@ +Version 1.3 Patch Level 3 + +General. ------------------------------------------------------------------ +Update to documentation including klogd.8 manpage to reflect new features. + +Included patch for modules-2.0.0 package to provide support for signalling +klogd of changes in kernel module status. + +klogd --------------------------------------------------------------------- +Provided support for signalling klogd to reload static and kernel module +symbol information via SIGUSR1 and SIGUSR2. + +Implemented -p switch to cause a reload of kernel module symbol information +whenever a protection fault is detected. + +Informative message is printed whenever klogd state change occurs. + +Added -i and -I switches to signal the currently executing klogd daemon +to reload symbold information. + + +Version 1.3 Patch Level 2 + +General. ------------------------------------------------------------------ +Added oops.c and oops_test.c. Oops.c implements a kernel loadable module +which will generate a general protection fault. The oops_test.c program +generates a test program for exercising the loadable module. + +syslogd ------------------------------------------------------------------ +Fixed bug resulting in file descriptors being orphaned when syslogd was +initialized via signal handler. + +klogd --------------------------------------------------------------------- +Bug fix to prevent errors when reading symbol tables with 64 bit addresses. + +Added support for debugging of protection faults occuring in kernel +loadable modules. + + +Version 1.3 Patch Level 1 + +General. ------------------------------------------------------------------ +Cleanups in the Makefile. + +Patches to support compilation in the ALPHA environment. I have not +been able to test these personally so if anyone has any feedback I +would be interested in hearing from the Linux ALPHA community. + +Spelling and grammar corrections in the man pages. + +syslogd ------------------------------------------------------------------ +Patch to fix parsing of hostnames in syslogd.c. + +The return value of gethostbyname is now properly checked. This should +fix the problems with core dumps when name resolution failed. + +Bounds error fixed when setting the file descriptors for UNIX domain +sockets. + +klogd --------------------------------------------------------------------- +Error checking and reporting enhanced. I have a couple of reports +that klogd is experiencing errors when reading the /proc filesystem. +Any additional information would be appreciated. + +The sys_syslog function has been renamed to ksyslog. This was in a +set patches for ALPHA support so I am assuming that this is necessary +for that environment + + +Version 1.3 + +Numerous changes, performance enhancements, code cleanups and bug fixes. +Too many to individually summarize. Have a look at the top of each +source file for more information. + +** Default behavior of sysklogd is not to accept any message that +is sent via syslog/udp. To allow remote reception add -r to the +command-line arguments. + +** Spaces are now accepted in the syslog configuration file. This +should be a real crowd pleaser. + +syslogd now uses dynamic allocation of logging output descriptors. +There is no longer a static limit on the number of log destinations +that can be defined. + +klogd supports on-the-fly kernel address to symbol translations. +This requires that a valid kernel symbol map be found at execution. + +** The default level for console log messages was changed to 6. This +means that kernel messages with a priority less than or equal to 5 +(KERN_NOTICE) will be logged to the console. + + This item has been flagged because it results in a behavior + change which will be different if version 1.3 replaces an + existing 1.2 binary. Linus strongly suggested that this + behavior be changed and in the 1.3.3x kernels Linus in fact + made it impossible to set the console log level lower than + about 5. + + There were good reasons from his perspective for doing so. + The most troublesome being that user's of packaged + distributions were not able to generate register dumps with + the kernel debugging keys, most notably altgr-SCRLCK. + + If a kernels prior to 1.3.3x are being used the klogd daemon + invocation must be changed to something like: klogd -c 1 + + This will turn off logging of kernel messages to the console. + If you understand the ramifications of this the 1.3.3x kernels + can be patched to allow the suppression of console log + messages. It is important to be cognizant of the effects of + these changes. None the least of which is that Linus and Alan + will yell at you if you complain about not being able to + generate kernel debugging information.. :-) + +--------------------------------------------------------------------------- +Version 1.2 +Fixes to both klogd and syslogd so that the package will compile without +errors due to the vararg procedures. + +Modified pid files produced so that the names of the files are +klogd.pid and syslogd.pid respectively. + +Fixed bug in klogd which prevented output from being directed to a file +when the program was compiled to auto-background itself. In the +auto-backgrounding configuration the forked process was closing all its +file descriptors which was causing the errant behavior. + +Modified signal handling in klogd so that all signal are set to ignored +before establishing specific signal handlers. + +Fixed bug in syslogd which was causing a delay in opening of the /dev/log +UNIX domain socket. This should correct the race condition which was +preventing klogd from properly logging kernel messages when the two +daemons were started in rapid succession. + +Modified the closing/opening of file descriptors when syslogd was +compiled with auto-backgrounding support. Closes the potential for +a somewhat obscure bug caused by the /dev/log socket being opened on +fd 0. + +Changed the names of the man pages from an extension of 1 to 8. +--------------------------------------------------------------------------- +Version 1.1 +Extensive changes and additional functionality added to klogd. Please +see sources and man-pages for documentation. + +Fixed bugs in both syslogd and klogd with respect to fragmented +message re-assembly. Bootup messages should now be display properly. + +Fixed bug in syslogd which prevented proper logging of messages with +priority classes of none and emerg. + +Fixed bug which caused core dump when messages were logged to users. +Also fixed bug with messages to login type of LOGIN. + +Fixed problem with zombies being left when messages were logged to +multiple users. + +Enhanced functionality of syslog_tst program. + +Added man-pages. +--------------------------------------------------------------------------- + +--------------------------------------------------------------------------- +Version 1.0 + +Initial release. +--------------------------------------------------------------------------- diff --git a/README.1st b/README.1st new file mode 100644 index 00000000..39467563 --- /dev/null +++ b/README.1st @@ -0,0 +1,65 @@ +Very important information before using version 1.3 +--------------------------------------------------- + +The included version of syslogd behaves in a slightly different manner +to the one in former releases. Please review the following important +differences: + +* By default the syslog daemon doesn't accept any message from the + syslog/udp port. To enable this add "-r" to the command-line + arguments. You _have to_ add this on every host that should run as a + centralized network log server. + + You also should take a look at other new command-line arguments: + "-l" and "-s". + + The syslog daemon by default does not forward to a remote host any + log messages which it received from a remote host. This is an + attempt to prevent syslog loops. If you desire this behavior the + -h command-line switch can be used to enable this behavior. + +* Syslogd was designed to strip off the local domain from every + message that comes from any host in the same domain. Unfortunately + this feature didn't work in every cases. This is now corrected. So + you might not get the fqdn anymore. + + If you use any scripts that analyze logfiles, please bare this in + mind. + +* Syslogd doesn't touch the filemode of any logfile. If it has to + create one, it will be world-readable. If you do not want this + (i.e. if auth.* is logged) you have to create the file by hand and + change permissions. + +* If you notice that some of your programs make heavy use of the + syslog facility and your disks get loud you might want to turn + fsync()ing after each line off. But note that in doing so you + increase the likelihood of lost information in the event of a + system crash. + +* If you're going to start klogd or syslogd by init(8), you don't have + to hack the code anymore. Instead add "-n" to the command-line + arguments. + +* Klogd can now be used to decode EIP addresses if it can determine a + System.map file (command-line argument "-k"). This is a very useful + feature if your system crashes, but its usability depends on an + actual and correct System.map file. + +* Both system utilities now check for and respect the existence of .pid + files. If the utilities are started by configuration scripts on + stable systems there is the potential that the process ID numbers of + the utilities will be identical from one system boot to another. + This will cause both klogd and syslogd to terminate. + + Both klogd and syslogd will attempt to remove their .pid files when + they receive termination signals. The difficulty noted above + typically occurs when a system crash occurs or an uncatchable signal + (kill -9) is used to stop the daemons. + + The cleanest solution to this problem is to insure that the system + configuration scripts (rc.*) provide a clean working environment for + a freshly booted system. As part of the initialization process + these scripts should remove all old .pid files found in /var/run. + This will insure that klogd and syslogd start properly even if prior + executions have been terminated harshly. diff --git a/README.linux b/README.linux new file mode 100644 index 00000000..bfebf53e --- /dev/null +++ b/README.linux @@ -0,0 +1,72 @@ +Welcome to the sysklogd package for Linux. All the utility +documentation has now been moved into the man pages. Please review +these carefully before proceeding. + +Version 1.3 of the package is the culmination of about two years of +experience and bug reports on the 1.2 version from both the INTERNET +and our corporate Linux networks. The utilities in this package should +provide VERY reliable system logging. Klogd and syslogd have both +been stress tested in kernel development environments where literally +hundreds of megabytes of kernel messages have been blasted through +them. If either utility should fail the development team would +appreciate debug information so that the bug can be reproduced and +squashed. + +Both utilities (syslogd, klogd) can be either run from init or started +as part of the rc.* sequence. Caution should be used when starting +these utilities from init since the default configuration is for both of +these utilities to auto-background themselves. Depending on the +version of init being used this could either result in the process +table being filled or at least 10 copies of the daemon being started. +If auto-backgrounding is NOT desired the command line option -n should +be used to disable the auto-fork feature. + +I have found work on the sysklogd package to be an interesting example +of the powers of the INTERNET. Stephen, Juha, Shane, Martin and +myself have successfully collaborated on the development of this +package without ever having met each other, in fact we could pass on +the street without realizing it. What I have developed is a profound +respect for the personal capabilities of each one of these +individuals. Perhaps the greatest `Linux Legacy' will be that its +development/enhancement is truly an example of the powers of +international cooperation through the worldwide INTERNET. + +We would be interested in keeping track of any and all bug +fixes/changes that are made. At the time that work was started on the +sysklogd package the syslog(d) sources seemed to have fallen into +neglect. This work started with and continues the believe that it is +important to maintain consistent standardized system utilities +sources. Hopefully the Linux community will find these sources to be +a useful addition to the software gene pool. + +There is a mailing list covering this package and syslog in general. +The lists address is sysklogd@Infodrom.North.DE . To subscribe send a +mail to Majordomo@Infodrom.North.DE with a line "subscribe sysklogd" +in the message body. + +New versions of this package will be available at Joey's ftp server. +ftp://ftp.infodrom.north.de/pub/people/joey/sysklogd/ + +Best regards, + +Dr. Wettstein +Oncology Research Division Computing Facility +Roger Maris Cancer Center +Fargo, ND +greg@wind.enjellic.com + +Stephen Tweedie +Department of Computer Science +Edinburgh University, Scotland + +Juha Virtanen +jiivee@hut.fi + +Shane Alderton +shane@ion.apana.org.au + +Martin Schulze +Infodrom Oldenburg +joey@linux.de + +And a host of bug reporters whose contributions cannot be underestimated. diff --git a/klogd.8 b/klogd.8 new file mode 100644 index 00000000..02949dad --- /dev/null +++ b/klogd.8 @@ -0,0 +1,441 @@ +.\" Copyright 1994 Dr. Greg Wettstein, Enjellic Systems Development. +.\" May be distributed under the GNU General Public License +.\" Sun Jul 30 01:35:55 MET: Martin Schulze: Updates +.\" Sun Nov 19 23:22:21 MET: Martin Schulze: Updates +.\" Mon Aug 19 09:42:08 CDT 1996: Dr. G.W. Wettstein: Updates +.\" +.TH KLOGD 8 "21 August, 1999" "Version 1.4" "Linux System Administration" +.SH NAME +klogd \- Kernel Log Daemon +.LP +.SH SYNOPSIS +.B klogd +.RB [ " \-c " +.I n +] +.RB [ " \-d " ] +.RB [ " \-f " +.I fname +] +.RB [ " \-iI " ] +.RB [ " \-n " ] +.RB [ " \-o " ] +.RB [ " \-p " ] +.RB [ " \-s " ] +.RB [ " \-k " +.I fname +] +.RB [ " \-v " ] +.RB [ " \-x " ] +.RB [ " \-2 " ] +.LP +.SH DESCRIPTION +.B klogd +is a system daemon which intercepts and logs Linux kernel +messages. +.LP +.SH OPTIONS +.TP +.BI "\-c " n +Sets the default log level of console messages to \fIn\fR. +.TP +.B "\-d" +Enable debugging mode. This will generate \fBLOTS\fR of output to +stderr. +.TP +.BI "\-f " file +Log messages to the specified filename rather than to the syslog facility. +.TP +.BI "\-i \-I" +Signal the currently executing klogd daemon. Both of these switches control +the loading/reloading of symbol information. The \-i switch signals the +daemon to reload the kernel module symbols. The \-I switch signals for a +reload of both the static kernel symbols and the kernel module symbols. +.TP +.B "\-n" +Avoid auto-backgrounding. This is needed especially if the +.B klogd +is started and controlled by +.BR init (8). +.TP +.B "-o" +Execute in 'one\-shot' mode. This causes \fBklogd\fP to read and log +all the messages that are found in the kernel message buffers. After +a single read and log cycle the daemon exits. +.TP +.B "-p" +Enable paranoia. This option controls when klogd loads kernel module symbol +information. Setting this switch causes klogd to load the kernel module +symbol information whenever an Oops string is detected in the kernel message +stream. +.TP +.B "-s" +Force \fBklogd\fP to use the system call interface to the kernel message +buffers. +.TP +.BI "\-k " file +Use the specified file as the source of kernel symbol information. +.TP +.B "\-v" +Print version and exit. +.TP +.B "\-x" +Omits EIP translation and therefore doesn't read the System.map file. +.TP +.B "\-2" +When symbols are expanded, print the line twice. Once with addresses +converted to symbols, once with the raw text. This allows external +programs such as ksymoops do their own processing on the original +data. +.LP +.SH OVERVIEW +The functionality of klogd has been typically incorporated into other +versions of syslogd but this seems to be a poor place for it. In the +modern Linux kernel a number of kernel messaging issues such as +sourcing, prioritization and resolution of kernel addresses must be +addressed. Incorporating kernel logging into a separate process +offers a cleaner separation of services. + +In Linux there are two potential sources of kernel log information: the +.I /proc +file system and the syscall (sys_syslog) interface, although +ultimately they are one and the same. Klogd is designed to choose +whichever source of information is the most appropriate. It does this +by first checking for the presence of a mounted +.I /proc +file system. If this is found the +.I /proc/kmsg +file is used as the source of kernel log +information. If the proc file system is not mounted +.B klogd +uses a +system call to obtain kernel messages. The command line switch +.RB ( "\-s" ) +can be used to force klogd to use the system call interface as its +messaging source. + +If kernel messages are directed through the +.BR syslogd " daemon the " klogd +daemon, as of version 1.1, has the ability to properly prioritize +kernel messages. Prioritization of the kernel messages was added to it +at approximately version 0.99pl13 of the kernel. The raw kernel messages +are of the form: +.IP +\<[0\-7]\>Something said by the kernel. +.PP +The priority of the kernel message is encoded as a single numeric +digit enclosed inside the <> pair. The definitions of these values is +given in the kernel include file kernel.h. When a message is received +from the kernel the klogd daemon reads this priority level and assigns +the appropriate priority level to the syslog message. If file output +(\fB-f\fR) is used the prioritization sequence is left pre\-pended to the +kernel message. + +The +.B klogd +daemon also allows the ability to alter the presentation of +kernel messages to the system console. Consequent with the +prioritization of kernel messages was the inclusion of default +messaging levels for the kernel. In a stock kernel the the default +console log level is set to 7. Any messages with a priority level +numerically lower than 7 (higher priority) appear on the console. + +Messages of priority level 7 are considered to be 'debug' messages and +will thus not appear on the console. Many administrators, +particularly in a multi\-user environment, prefer that all kernel +messages be handled by klogd and either directed to a file or to +the syslogd daemon. This prevents 'nuisance' messages such as line +printer out of paper or disk change detected from cluttering the +console. + +When +.B \-c +is given on the commandline the +.B klogd +daemon will execute a system call to inhibit all kernel messages from +being displayed on the console. Former versions always issued this +system call and defaulted to all kernel messages except for panics. +This is handled differently nowardays so +.B klogd +doesn't need to set this value anymore. The +argument given to the \fB\-c\fR switch specifies the priority level of +messages which will be directed to the console. Note that messages of +a priority value LOWER than the indicated number will be directed to +the console. +.IP +For example, to have the kernel display all messages with a +priority level of 3 +.BR "" ( KERN_ERR ) +or more severe the following +command would be executed: +.IP +.nf + klogd \-c 4 +.fi +.PP +The definitions of the numeric values for kernel messages are given in +the file +.IR kernel.h " which can be found in the " /usr/include/linux +directory if the kernel sources are installed. These values parallel +the syslog priority values which are defined in the file +.IR syslog.h " found in the " /usr/include/sys " sub\-directory." + +The klogd daemon can also be used in a 'one\-shot' mode for reading the +kernel message buffers. One shot mode is selected by specifying the +\fB\-o\fR switch on the command line. Output will be directed to either the +syslogd daemon or to an alternate file specified by the \fB-f\fR switch. +.IP +For example, to read all the kernel messages after a system +boot and record them in a file called krnl.msg the following +command would be given. +.IP +.nf + klogd -o -f ./krnl.msg +.fi +.PP +.SH KERNEL ADDRESS RESOLUTION +If the kernel detects an internal error condition a general protection +fault will be triggered. As part of the GPF handling procedure the +kernel prints out a status report indicating the state of the +processor at the time of the fault. Included in this display are the +contents of the microprocessor's registers, the contents of the kernel +stack and a tracing of what functions were being executed at the time +of the fault. + +This information is +.B EXTREMELY IMPORTANT +in determining what caused the internal error condition. The +difficulty comes when a kernel developer attempts to analyze this +information. The raw numeric information present in the protection +fault printout is of very little use to the developers. This is due +to the fact that kernels are not identical and the addresses of +variable locations or functions will not be the same in all kernels. +In order to correctly diagnose the cause of failure a kernel developer +needs to know what specific kernel functions or variable locations +were involved in the error. + +As part of the kernel compilation process a listing is created which +specified the address locations of important variables and function in +the kernel being compiled. This listing is saved in a file called +System.map in the top of the kernel directory source tree. Using this +listing a kernel developer can determine exactly what the kernel was +doing when the error condition occurred. + +The process of resolving the numeric addresses from the protection +fault printout can be done manually or by using the +.B ksymoops +program which is included in the kernel sources. + +As a convenience +.B klogd +will attempt to resolve kernel numeric addresses to their symbolic +forms if a kernel symbol table is available at execution time. If you +require the original address of the symbol, use the +.B -2 +switch to preserve the numeric address. A +symbol table may be specified by using the \fB\-k\fR switch on the +command line. If a symbol file is not explicitly specified the +following filenames will be tried: + +.nf +.I /boot/System.map +.I /System.map +.I /usr/src/linux/System.map +.fi + +Version information is supplied in the system maps as of kernel +1.3.43. This version information is used to direct an intelligent +search of the list of symbol tables. This feature is useful since it +provides support for both production and experimental kernels. + +For example a production kernel may have its map file stored in +/boot/System.map. If an experimental or test kernel is compiled with +the sources in the 'standard' location of /usr/src/linux the system +map will be found in /usr/src/linux/System.map. When klogd starts +under the experimental kernel the map in /boot/System.map will be +bypassed in favor of the map in /usr/src/linux/System.map. + +Modern kernels as of 1.3.43 properly format important kernel addresses +so that they will be recognized and translated by klogd. Earlier +kernels require a source code patch be applied to the kernel sources. +This patch is supplied with the sysklogd sources. + +The process of analyzing kernel protections faults works very well +with a static kernel. Additional difficulties are encountered when +attempting to diagnose errors which occur in loadable kernel modules. +Loadable kernel modules are used to implement kernel functionality in +a form which can be loaded or unloaded at will. The use of loadable +modules is useful from a debugging standpoint and can also be useful +in decreasing the amount of memory required by a kernel. + +The difficulty with diagnosing errors in loadable modules is due to +the dynamic nature of the kernel modules. When a module is loaded the +kernel will allocate memory to hold the module, when the module is +unloaded this memory will be returned back to the kernel. This +dynamic memory allocation makes it impossible to produce a map file +which details the addresses of the variable and functions in a kernel +loadable module. Without this location map it is not possible for a +kernel developer to determine what went wrong if a protection fault +involves a kernel module. + +.B klogd +has support for dealing with the problem of diagnosing protection +faults in kernel loadable modules. At program start time or in +response to a signal the daemon will interrogate the kernel for a +listing of all modules loaded and the addresses in memory they are +loaded at. Individual modules can also register the locations of +important functions when the module is loaded. The addresses of these +exported symbols are also determined during this interrogation +process. + +When a protection fault occurs an attempt will be made to resolve +kernel addresses from the static symbol table. If this fails the +symbols from the currently loaded modules are examined in an attempt +to resolve the addresses. At the very minimum this allows klogd to +indicate which loadable module was responsible for generating the +protection fault. Additional information may be available if the +module developer chose to export symbol information from the module. + +Proper and accurate resolution of addresses in kernel modules requires +that +.B klogd +be informed whenever the kernel module status changes. The +.B \-i +and +.B \-I +switches can be used to signal the currently executing daemon that +symbol information be reloaded. Of most importance to proper +resolution of module symbols is the +.B \-i +switch. Each time a kernel module is loaded or removed from the +kernel the following command should be executed: + +.nf +.I klogd \-i +.fi + +The +.B \-p +switch can also be used to insure that module symbol information is up +to date. This switch instructs +.B klogd +to reload the module symbol information whenever a protection fault +is detected. Caution should be used before invoking the program in +\'paranoid\' mode. The stability of the kernel and the operating +environment is always under question when a protection fault occurs. +Since the klogd daemon must execute system calls in order to read the +module symbol information there is the possibility that the system may +be too unstable to capture useful information. A much better policy +is to insure that klogd is updated whenever a module is loaded or +unloaded. Having uptodate symbol information loaded increases the +probability of properly resolving a protection fault if it should occur. + +Included in the sysklogd source distribution is a patch to the +modules-2.0.0 package which allows the +.B insmod, +.B rmmod +and +.B modprobe +utilities to automatically signal +.B klogd +whenever a module is inserted or removed from the kernel. Using this +patch will insure that the symbol information maintained in klogd is +always consistent with the current kernel state. +.PP +.SH SIGNAL HANDLING +The +.B klogd +will respond to eight signals: +.BR SIGHUP ", " SIGINT ", " SIGKILL ", " SIGTERM ", " SIGTSTP ", " +.BR SIGUSR1 ", "SIGUSR2 " and " SIGCONT ". The" +.BR SIGINT ", " SIGKILL ", " SIGTERM " and " SIGHUP +signals will cause the daemon to close its kernel log sources and +terminate gracefully. + +The +.BR SIGTSTP " and " SIGCONT +signals are used to start and stop kernel logging. Upon receipt of a +.B SIGTSTP +signal the daemon will close its +log sources and spin in an idle loop. Subsequent receipt of a +.B SIGCONT +signal will cause the daemon to go through its initialization sequence +and re-choose an input source. Using +.BR SIGSTOP " and " SIGCONT +in combination the kernel log input can be re-chosen without stopping and +restarting the daemon. For example if the \fI/proc\fR file system is to be +un-mounted the following command sequence should be used: +.PP +.PD 0 +.TP + # kill -TSTP pid +.TP + # umount /proc +.TP + # kill -CONT pid +.PD +.PP +Notations will be made in the system logs with +.B LOG_INFO +priority +documenting the start/stop of logging. + +The +.BR SIGUSR1 " and " SIGUSR2 +signals are used to initiate loading/reloading of kernel symbol information. +Receipt of the +.B SIGUSR1 +signal will cause the kernel module symbols to be reloaded. Signaling the +daemon with +.B SIGUSR2 +will cause both the static kernel symbols and the kernel module symbols to +be reloaded. + +Provided that the System.map file is placed in an appropriate location the +signal of generally greatest usefulness is the +.B SIGUSR1 +signal. This signal is designed to be used to signal the daemon when kernel +modules are loaded/unloaded. Sending this signal to the daemon after a +kernel module state change will insure that proper resolution of symbols will +occur if a protection fault occurs in the address space occupied by a kernel +module. +.LP +.SH FILES +.PD 0 +.TP +.I /proc/kmsg +One Source for kernel messages +.B klogd +.TP +.I /var/run/klogd.pid +The file containing the process id of +.B klogd +.TP +.I /boot/System.map, /System.map, /usr/src/linux/System.map +Default locations for kernel system maps. +.PD +.SH BUGS +Probably numerous. Well formed context diffs appreciated. +.LP +.SH AUTHOR +The +.B klogd +was originally written by Steve Lord (lord@cray.com), Greg Wettstein +made major improvements. + +.PD 0 +.TP +Dr. Greg Wettstein (greg@wind.enjellic.com) +.TP +Enjellic Systems Development +.PD +.PP +.PD 0 +.TP +Oncology Research Divsion Computing Facility +.TP +Roger Maris Cancer Center +.TP +Fargo, ND 58122 +.PD +.zZ diff --git a/klogd.c b/klogd.c new file mode 100644 index 00000000..2c8e765e --- /dev/null +++ b/klogd.c @@ -0,0 +1,1191 @@ +/* + klogd.c - main program for Linux kernel log daemon. + Copyright (c) 1995 Dr. G.W. Wettstein <greg@wind.rmcc.com> + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Steve Lord (lord@cray.com) 7th Nov 92 + * + * Modified to check for kernel info by Dr. G.W. Wettstein 02/17/93. + * + * Fri Mar 12 16:53:56 CST 1993: Dr. Wettstein + * Modified LogLine to use a newline as the line separator in + * the kernel message buffer. + * + * Added debugging code to dump the contents of the kernel message + * buffer at the start of the LogLine function. + * + * Thu Jul 29 11:40:32 CDT 1993: Dr. Wettstein + * Added syscalls to turn off logging of kernel messages to the + * console when klogd becomes responsible for kernel messages. + * + * klogd now catches SIGTERM and SIGKILL signals. Receipt of these + * signals cases the clean_up function to be called which shuts down + * kernel logging and re-enables logging of messages to the console. + * + * Sat Dec 11 11:54:22 CST 1993: Dr. Wettstein + * Added fixes to allow compilation with no complaints with -Wall. + * + * When the daemon catches a fatal signal (SIGTERM, SIGKILL) a + * message is output to the logfile advising that the daemon is + * going to terminate. + * + * Thu Jan 6 11:54:10 CST 1994: Dr. Wettstein + * Major re-write/re-organization of the code. + * + * Klogd now assigns kernel messages to priority levels when output + * to the syslog facility is requested. The priority level is + * determined by decoding the prioritization sequence which is + * tagged onto the start of the kernel messages. + * + * Added the following program options: -f arg -c arg -s -o -d + * + * The -f switch can be used to specify that output should + * be written to the named file. + * + * The -c switch is used to specify the level of kernel + * messages which are to be directed to the console. + * + * The -s switch causes the program to use the syscall + * interface to the kernel message facility. This can be + * used to override the presence of the /proc filesystem. + * + * The -o switch causes the program to operate in 'one-shot' + * mode. A single call will be made to read the complete + * kernel buffer. The contents of the buffer will be + * output and the program will terminate. + * + * The -d switch causes 'debug' mode to be activated. This + * will cause the daemon to generate LOTS of output to stderr. + * + * The buffer decomposition function (LogLine) was re-written to + * squash a bug which was causing only partial kernel messages to + * be written to the syslog facility. + * + * The signal handling code was modified to properly differentiate + * between the STOP and TSTP signals. + * + * Added pid saving when the daemon detaches into the background. Thank + * you to Juha Virtanen (jiivee@hut.fi) for providing this patch. + * + * Mon Feb 6 07:31:29 CST 1995: Dr. Wettstein + * Significant re-organization of the signal handling code. The + * signal handlers now only set variables. Not earth shaking by any + * means but aesthetically pleasing to the code purists in the group. + * + * Patch to make things more compliant with the file system standards. + * Thanks to Chris Metcalf for prompting this helpful change. + * + * The routines responsible for reading the kernel log sources now + * initialize the buffers before reading. I think that this will + * solve problems with non-terminated kernel messages producing + * output of the form: new old old old + * + * This may also help influence the occassional reports of klogd + * failing under significant load. I think that the jury may still + * be out on this one though. My thanks to Joerg Ahrens for initially + * tipping me off to the source of this problem. Also thanks to + * Michael O'Reilly for tipping me off to the best fix for this problem. + * And last but not least Mark Lord for prompting me to try this as + * a means of attacking the stability problem. + * + * Specifying a - as the arguement to the -f switch will cause output + * to be directed to stdout rather than a filename of -. Thanks to + * Randy Appleton for a patch which prompted me to do this. + * + * Wed Feb 22 15:37:37 CST 1995: Dr. Wettstein + * Added version information to logging startup messages. + * + * Wed Jul 26 18:57:23 MET DST 1995: Martin Schulze + * Added an commandline argument "-n" to avoid forking. This obsoletes + * the compiler define NO_FORK. It's more useful to have this as an + * argument as there are many binary versions and one doesn't need to + * recompile the daemon. + * + * Thu Aug 10 19:01:08 MET DST 1995: Martin Schulze + * Added my pidfile.[ch] to it to perform a better handling with pidfiles. + * Now both, syslogd and klogd, can only be started once. They check the + * pidfile. + * + * Fri Nov 17 15:05:43 CST 1995: Dr. Wettstein + * Added support for kernel address translation. This required moving + * some definitions and includes to the new klogd.h file. Some small + * code cleanups and modifications. + * + * Mon Nov 20 10:03:39 MET 1995 + * Added -v option to print the version and exit. + * + * Thu Jan 18 11:19:46 CST 1996: Dr. Wettstein + * Added suggested patches from beta-testers. These address two + * two problems. The first is segmentation faults which occur with + * the ELF libraries. This was caused by passing a null pointer to + * the strcmp function. + * + * Added a second patch to remove the pidfile as part of the + * termination cleanup sequence. This minimizes the potential for + * conflicting pidfiles causing immediate termination at boot time. + * + * Wed Aug 21 09:13:03 CDT 1996: Dr. Wettstein + * Added ability to reload static symbols and kernel module symbols + * under control of SIGUSR1 and SIGUSR2 signals. + * + * Added -p switch to select 'paranoid' behavior with respect to the + * loading of kernel module symbols. + * + * Informative line now printed whenever a state change occurs due + * to signal reception by the daemon. + * + * Added the -i and -I command line switches to signal the currently + * executing daemon. + * + * Tue Nov 19 10:15:36 PST 1996: Leland Olds <olds@eskimo.com> + * Corrected vulnerability to buffer overruns by rewriting LogLine + * routine. Obscenely long kernel messages will now be broken up + * into lines no longer than LOG_LINE_LENGTH. + * + * The last version of LogLine was vulnerable to buffer overruns: + * - Kernel messages longer than LOG_LINE_LENGTH caused a buffer + * overrun. + * - If a line was determined to be shorter than LOG_LINE_LENGTH, + * the routine "ExpandKadds" could cause the line grow by + * an unknown amount and overrun a buffer. + * I turned these routines into a little parsing state machine that + * should not have these problems. + * + * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman + * Some more glibc patches made by <mdorman@debian.org>. + * + * Thu Aug 21 12:11:27 MET DST 1997: Martin Schulze <joey@infodrom.north.de> + * Fixed little mistake which prevented klogd from accepting a + * console log + * + * Fri Jan 9 00:39:52 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Changed the behaviour of klogd when receiving a terminate + * signal. Now the program terminates immediately instead of + * completing the receipt of a kernel message, i.e the read() + * call. The old behaveiour could result in klogd being + * recognized as being undead, because it'll only die after a + * message has been received. + * + * Fri Jan 9 11:03:48 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Corrected some code that caused klogd to dump core when + * receiving messages containing '%', some of them exist in + * 2.1.78. Thanks to Chu-yeon Park <kokids@doit.ajou.ac.kr> for + * informing me. + * + * Fri Jan 9 23:38:19 CET 1998: Florian La Roche <florian@knorke.saar.de> + * Added -x switch to omit EIP translation and System.map evaluation. + * + * Sun Jan 25 20:47:46 CET 1998: Martin Schulze <joey@infodrom.north.de> + * As the bug covering the %'s introduced a problem with + * unevaluated priorities I've worked out a real fix that strips + * %'s to an even number which is harmless for printf. + * + * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Added support for TESTING define which will turn klogd into + * stdio-mode used for debugging. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified System.map read function to try all possible map + * files until a file with matching version is found. Added support for + * Debian release. + * + * Mon Oct 12 13:01:27 MET DST 1998: Martin Schulze <joey@infodrom.north.de> + * Used unsigned long and strtoul() to resolve kernel oops symbols. + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de> + * Shortened LOG_LINE_LENGTH in order to get long lines splitted + * up earlier and syslogd has a better chance concatenating them + * together again. + * + * Sat Aug 21 12:27:02 CEST 1999: Martin Schulze <joey@infodrom.north.de> + * Skip newline when reading in messages. + * + * Tue Sep 12 22:14:33 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Don't feed a buffer directly to a printf-type routine, use + * "%s" as format string instead. Thanks to Jouko Pynnönen + * <jouko@solutions.fi> for pointing this out. + * + * Tue Sep 12 22:44:57 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Commandline option `-2': When symbols are expanded, print the + * line twice. Once with addresses converted to symbols, once with the + * raw text. Allows external programs such as ksymoops do their own + * processing on the original data. Thanks to Keith Owens + * <kaos@ocs.com.au> for the patch. + * + * Mon Sep 18 09:32:27 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Added patch to fix priority decoding after moving kernel + * messgages into "%s". Thanks to Solar Designer + * <solar@false.com> for the patch. + * + * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de> + * Stop LogLine() from being called with wrong argument when a + * former calculation failed already. Thanks to Thomas Roessler + * <roessler@does-not-exist.org> for providing a patch. + * + * Ignore zero bytes, no busy loop is entered anymore. Several + * people have submitted patches: Troels Walsted Hansen + * <troels@thule.no>, Wolfgang Oertl <Wolfgang.Oertl@uibk.ac.at> + * and Thomas Roessler. + */ + + +/* Includes. */ +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#if !defined(__GLIBC__) +#include <linux/time.h> +#endif /* __GLIBC__ */ +#include <stdarg.h> +#include <paths.h> +#include <stdlib.h> +#include "klogd.h" +#include "ksyms.h" +#ifndef TESTING +#include "pidfile.h" +#endif +#include "version.h" + +#define __LIBRARY__ +#include <linux/unistd.h> +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include <sys/klog.h> +#define ksyslog klogctl +#endif + +#define LOG_BUFFER_SIZE 4096 +#define LOG_LINE_LENGTH 1000 + +#ifndef TESTING +#if defined(FSSTND) +static char *PidFile = _PATH_VARRUN "klogd.pid"; +#else +static char *PidFile = "/etc/klogd.pid"; +#endif +#endif + +static int kmsg, + change_state = 0, + terminate = 0, + caught_TSTP = 0, + reload_symbols = 0, + console_log_level = -1; + +static int use_syscall = 0, + one_shot = 0, + symbol_lookup = 1, + no_fork = 0; /* don't fork - don't run in daemon mode */ + +static char *symfile = (char *) 0, + log_buffer[LOG_BUFFER_SIZE]; + +static FILE *output_file = (FILE *) 0; + +static enum LOGSRC {none, proc, kernel} logsrc; + +int debugging = 0; +int symbols_twice = 0; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); +static void CloseLogSrc(void); +extern void restart(int sig); +extern void stop_logging(int sig); +extern void stop_daemon(int sig); +extern void reload_daemon(int sig); +static void Terminate(void); +static void SignalDaemon(int); +static void ReloadSymbols(void); +static void ChangeLogging(void); +static enum LOGSRC GetKernelLogSrc(void); +static void LogLine(char *ptr, int len); +static void LogKernelLine(void); +static void LogProcLine(void); +extern int main(int argc, char *argv[]); + + +static void CloseLogSrc() + +{ + /* Turn on logging of messages to console. */ + ksyslog(7, NULL, 0); + + /* Shutdown the log sources. */ + switch ( logsrc ) + { + case kernel: + ksyslog(0, 0, 0); + Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + Syslog(LOG_INFO, "Kernel logging (proc) stopped."); + break; + case none: + break; + } + + if ( output_file != (FILE *) 0 ) + fflush(output_file); + return; +} + + +void restart(sig) + + int sig; + +{ + signal(SIGCONT, restart); + change_state = 1; + caught_TSTP = 0; + return; +} + + +void stop_logging(sig) + + int sig; + +{ + signal(SIGTSTP, stop_logging); + change_state = 1; + caught_TSTP = 1; + return; +} + + +void stop_daemon(sig) + + int sig; + +{ + Terminate(); + return; +} + + +void reload_daemon(sig) + + int sig; + +{ + change_state = 1; + reload_symbols = 1; + + + if ( sig == SIGUSR2 ) + { + ++reload_symbols; + signal(SIGUSR2, reload_daemon); + } + else + signal(SIGUSR1, reload_daemon); + + return; +} + + +static void Terminate() + +{ + CloseLogSrc(); + Syslog(LOG_INFO, "Kernel log daemon terminating."); + sleep(1); + if ( output_file != (FILE *) 0 ) + fclose(output_file); + closelog(); +#ifndef TESTING + (void) remove_pid(PidFile); +#endif + exit(1); +} + +static void SignalDaemon(sig) + + int sig; + +{ +#ifndef TESTING + auto int pid = check_pid(PidFile); + + kill(pid, sig); +#else + kill(getpid(), sig); +#endif + return; +} + + +static void ReloadSymbols() + +{ + if (symbol_lookup) { + if ( reload_symbols > 1 ) + InitKsyms(symfile); + InitMsyms(); + } + reload_symbols = change_state = 0; + return; +} + + +static void ChangeLogging(void) + +{ + /* Terminate kernel logging. */ + if ( terminate == 1 ) + Terminate(); + + /* Indicate that something is happening. */ + Syslog(LOG_INFO, "klogd %s.%s, ---------- state change ----------\n", \ + VERSION, PATCHLEVEL); + + /* Reload symbols. */ + if ( reload_symbols > 0 ) + { + ReloadSymbols(); + return; + } + + /* Stop kernel logging. */ + if ( caught_TSTP == 1 ) + { + CloseLogSrc(); + logsrc = none; + change_state = 0; + return; + } + + /* + * The rest of this function is responsible for restarting + * kernel logging after it was stopped. + * + * In the following section we make a decision based on the + * kernel log state as to what is causing us to restart. Somewhat + * groady but it keeps us from creating another static variable. + */ + if ( logsrc != none ) + { + Syslog(LOG_INFO, "Kernel logging re-started after SIGSTOP."); + change_state = 0; + return; + } + + /* Restart logging. */ + logsrc = GetKernelLogSrc(); + change_state = 0; + return; +} + + +static enum LOGSRC GetKernelLogSrc(void) + +{ + auto struct stat sb; + + + /* Set level of kernel console messaging.. */ + if ( (console_log_level != -1) + && (ksyslog(8, NULL, console_log_level) < 0) && \ + (errno == EINVAL) ) + { + /* + * An invalid arguement error probably indicates that + * a pre-0.14 kernel is being run. At this point we + * issue an error message and simply shut-off console + * logging completely. + */ + Syslog(LOG_WARNING, "Cannot set console log level - disabling " + "console output."); + ksyslog(6, NULL, 0); + } + + /* + * First do a stat to determine whether or not the proc based + * file system is available to get kernel messages from. + */ + if ( use_syscall || + ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) ) + { + /* Initialize kernel logging. */ + ksyslog(1, NULL, 0); +#ifdef DEBRELEASE + Syslog(LOG_INFO, "klogd %s.%s#%s, log source = ksyslog " + "started.", VERSION, PATCHLEVEL, DEBRELEASE); +#else + Syslog(LOG_INFO, "klogd %s.%s, log source = ksyslog " + "started.", VERSION, PATCHLEVEL); +#endif + return(kernel); + } + +#ifndef TESTING + if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 ) + { + fprintf(stderr, "klogd: Cannot open proc file system, " \ + "%d - %s.\n", errno, strerror(errno)); + ksyslog(7, NULL, 0); + exit(1); + } +#else + kmsg = fileno(stdin); +#endif + +#ifdef DEBRELEASE + Syslog(LOG_INFO, "klogd %s.%s#%s, log source = %s started.", \ + VERSION, PATCHLEVEL, DEBRELEASE, _PATH_KLOG); +#else + Syslog(LOG_INFO, "klogd %s.%s, log source = %s started.", \ + VERSION, PATCHLEVEL, _PATH_KLOG); +#endif + return(proc); +} + + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + char *argl; + + if ( debugging ) + { + fputs("Logging line:\n", stderr); + fprintf(stderr, "\tLine: %s\n", fmt); + fprintf(stderr, "\tPriority: %d\n", priority); + } + + /* Handle output to a file. */ + if ( output_file != (FILE *) 0 ) + { + va_start(ap, fmt); + vfprintf(output_file, fmt, ap); + va_end(ap); + fputc('\n', output_file); + fflush(output_file); + if (!one_shot) + fsync(fileno(output_file)); + return; + } + + /* Output using syslog. */ + if (!strcmp(fmt, "%s")) + { + va_start(ap, fmt); + argl = va_arg(ap, char *); + if (argl[0] == '<' && argl[1] && argl[2] == '>') + { + switch ( argl[1] ) + { + case '0': + priority = LOG_EMERG; + break; + case '1': + priority = LOG_ALERT; + break; + case '2': + priority = LOG_CRIT; + break; + case '3': + priority = LOG_ERR; + break; + case '4': + priority = LOG_WARNING; + break; + case '5': + priority = LOG_NOTICE; + break; + case '6': + priority = LOG_INFO; + break; + case '7': + default: + priority = LOG_DEBUG; + } + argl += 3; + } + syslog(priority, fmt, argl); + va_end(ap); +#ifdef TESTING + putchar('\n'); +#endif + return; + } + + va_start(ap, fmt); + vsyslog(priority, fmt, ap); + va_end(ap); +#ifdef TESTING + printf ("\n"); +#endif + + return; +} + + +/* + * Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( char *line, int space, + const char *ptr, int len, + const char *delim ) +{ + auto int i; + auto int count; + + count = len < space ? len : space; + + for(i=0; i<count && !strchr(delim, *ptr); i++ ) { *line++ = *ptr++; } + + return( i ); +} + +/* + * Messages are separated by "\n". Messages longer than + * LOG_LINE_LENGTH are broken up. + * + * Kernel symbols show up in the input buffer as : "[<aaaaaa>]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + * + * To preserve the original addresses, lines containing kernel symbols + * are output twice. Once with the symbols converted and again with the + * original text. Just in case somebody wants to run their own Oops + * analysis on the syslog, e.g. ksymoops. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static char line_buff[LOG_LINE_LENGTH]; + + static char *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static char *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + auto int symbols_expanded = 0; /* 1 if symbols were expanded */ + auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ + auto char *save_ptr = ptr; /* save start of input line */ + auto int save_len = len; /* save length at start of input line */ + + while( len > 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + if ( debugging ) + { + fputs("Line buffer full:\n", stderr); + fprintf(stderr, "\tLine: %s\n", line); + } + + Syslog( LOG_INFO, "%s", line_buff ); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + symbols_expanded = 0; + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin( line, space, ptr, len, "\n[%" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + + if( *ptr == '\0' ) /* zero byte */ + { + ptr++; /* skip zero byte */ + space -= 1; + len -= 1; + + break; + } + + if( *ptr == '\n' ) /* newline */ + { + ptr++; /* skip newline */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog( LOG_INFO, "%s", line_buff ); + line = line_buff; + space = sizeof(line_buff)-1; + if (symbols_twice) { + if (symbols_expanded) { + /* reprint this line without symbol lookup */ + symbols_expanded = 0; + skip_symbol_lookup = 1; + ptr = save_ptr; + len = save_len; + } + else + { + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + } + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + if (!skip_symbol_lookup) + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + if( *ptr == '%' ) /* dangerous printf marker */ + { + delta = 0; + while (len && *ptr == '%') + { + *line++ = *ptr++; /* copy it in */ + space -= 1; + len -= 1; + delta++; + } + if (delta % 2) /* odd amount of %'s */ + { + if (space) + { + *line++ = '%'; /* so simply add one */ + space -= 1; + } + else + { + *line++ = '\0'; /* remove the last one / terminate the string */ + } + + } + } + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + unsigned long value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtoul(sym_start+1, (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + symbol = LookupSymbol(value, &sym); + if ( !symbol_lookup || symbol == (char *) 0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + delta = sprintf( sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + symbols_expanded = 1; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; +} + + +static void LogKernelLine(void) + +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel log + * messages into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer))) < 0 ) + { + if ( errno == EINTR ) + return; + fprintf(stderr, "klogd: Error return from sys_sycall: " \ + "%d - %s\n", errno, strerror(errno)); + } + else + LogLine(log_buffer, rdcnt); + return; +} + + +static void LogProcLine(void) + +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel messages + * from the message pseudo-file into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) + { + if ( errno == EINTR ) + return; + Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", \ + errno, strerror(errno)); + } + else + LogLine(log_buffer, rdcnt); + + return; +} + + +int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int ch, + use_output = 0; + + auto char *log_level = (char *) 0, + *output = (char *) 0; + +#ifndef TESTING + chdir ("/"); +#endif + /* Parse the command-line. */ + while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF) + switch((char)ch) + { + case '2': /* Print lines with symbols twice. */ + symbols_twice = 1; + break; + case 'c': /* Set console message level. */ + log_level = optarg; + break; + case 'd': /* Activity debug mode. */ + debugging = 1; + break; + case 'f': /* Define an output file. */ + output = optarg; + use_output++; + break; + case 'i': /* Reload module symbols. */ + SignalDaemon(SIGUSR1); + return(0); + case 'I': + SignalDaemon(SIGUSR2); + return(0); + case 'k': /* Kernel symbol file. */ + symfile = optarg; + break; + case 'n': /* don't fork */ + no_fork++; + break; + case 'o': /* One-shot mode. */ + one_shot = 1; + break; + case 'p': + SetParanoiaLevel(1); /* Load symbols on oops. */ + break; + case 's': /* Use syscall interface. */ + use_syscall = 1; + break; + case 'v': + printf("klogd %s.%s\n", VERSION, PATCHLEVEL); + exit (1); + case 'x': + symbol_lookup = 0; + break; + } + + + /* Set console logging level. */ + if ( log_level != (char *) 0 ) + { + if ( (strlen(log_level) > 1) || \ + (strchr("12345678", *log_level) == (char *) 0) ) + { + fprintf(stderr, "klogd: Invalid console logging " + "level <%s> specified.\n", log_level); + return(1); + } + console_log_level = *log_level - '0'; + } + + +#ifndef TESTING + /* + * The following code allows klogd to auto-background itself. + * What happens is that the program forks and the parent quits. + * The child closes all its open file descriptors, and issues a + * call to setsid to establish itself as an independent session + * immune from control signals. + * + * fork() is only called if it should run in daemon mode, fork is + * not disabled with the command line argument and there's no + * such process running. + */ + if ( (!one_shot) && (!no_fork) ) + { + if (!check_pid(PidFile)) + { + if ( fork() == 0 ) + { + auto int fl; + int num_fds = getdtablesize(); + + /* This is the child closing its file descriptors. */ + for (fl= 0; fl <= num_fds; ++fl) + { + if ( fileno(stdout) == fl && use_output ) + if ( strcmp(output, "-") == 0 ) + continue; + close(fl); + } + + setsid(); + } + else + exit(0); + } + else + { + fputs("klogd: Already running.\n", stderr); + exit(1); + } + } + + + /* tuck my process id away */ + if (!check_pid(PidFile)) + { + if (!write_pid(PidFile)) + Terminate(); + } + else + { + fputs("klogd: Already running.\n", stderr); + Terminate(); + } +#endif + + /* Signal setups. */ + for (ch= 1; ch < NSIG; ++ch) + signal(ch, SIG_IGN); + signal(SIGINT, stop_daemon); + signal(SIGKILL, stop_daemon); + signal(SIGTERM, stop_daemon); + signal(SIGHUP, stop_daemon); + signal(SIGTSTP, stop_logging); + signal(SIGCONT, restart); + signal(SIGUSR1, reload_daemon); + signal(SIGUSR2, reload_daemon); + + + /* Open outputs. */ + if ( use_output ) + { + if ( strcmp(output, "-") == 0 ) + output_file = stdout; + else if ( (output_file = fopen(output, "w")) == (FILE *) 0 ) + { + fprintf(stderr, "klogd: Cannot open output file " \ + "%s - %s\n", output, strerror(errno)); + return(1); + } + } + else + openlog("kernel", 0, LOG_KERN); + + + /* Handle one-shot logging. */ + if ( one_shot ) + { + if (symbol_lookup) { + InitKsyms(symfile); + InitMsyms(); + } + if ( (logsrc = GetKernelLogSrc()) == kernel ) + LogKernelLine(); + else + LogProcLine(); + Terminate(); + } + + /* Determine where kernel logging information is to come from. */ +#if defined(KLOGD_DELAY) + sleep(KLOGD_DELAY); +#endif + logsrc = GetKernelLogSrc(); + if (symbol_lookup) { + InitKsyms(symfile); + InitMsyms(); + } + + /* The main loop. */ + while (1) + { + if ( change_state ) + ChangeLogging(); + switch ( logsrc ) + { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + pause(); + break; + } + } +} +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/klogd.h b/klogd.h new file mode 100644 index 00000000..ef60f088 --- /dev/null +++ b/klogd.h @@ -0,0 +1,40 @@ +/* + klogd.h - main header file for Linux kernel log daemon. + Copyright (c) 1995 Dr. G.W. Wettstein <greg@wind.rmcc.com> + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Symbols and definitions needed by klogd. + * + * Thu Nov 16 12:45:06 CST 1995: Dr. Wettstein + * Initial version. + */ + +/* Useful include files. */ +#include <stdio.h> +#include <syslog.h> +#include <string.h> + + +/* Function prototypes. */ +extern int InitKsyms(char *); +extern int InitMsyms(void); +extern char * ExpandKadds(char *, char *); +extern void SetParanoiaLevel(int); +extern void Syslog(int priority, char *fmt, ...); @@ -0,0 +1,901 @@ +/* + ksym.c - functions for kernel address->symbol translation + Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This file contains functions which handle the translation of kernel + * numeric addresses into symbols for the klogd utility. + * + * Sat Oct 28 09:00:14 CDT 1995: Dr. Wettstein + * Initial Version. + * + * Fri Nov 24 12:50:52 CST 1995: Dr. Wettstein + * Added VERBOSE_DEBUGGING define to make debugging output more + * manageable. + * + * Added support for verification of the loaded kernel symbols. If + * no version information can be be found in the mapfile a warning + * message is issued but translation will still take place. This + * will be the default case if kernel versions < 1.3.43 are used. + * + * If the symbols in the mapfile are of the same version as the kernel + * that is running an informative message is issued. If the symbols + * in the mapfile do not match the current kernel version a warning + * message is issued and translation is disabled. + * + * Wed Dec 6 16:14:11 CST 1995: Dr. Wettstein + * Added /boot/System.map to the list of symbol maps to search for. + * Also made this map the first item in the search list. I am open + * to CONSTRUCTIVE suggestions for any additions or corrections to + * the list of symbol maps to search for. Be forewarned that the + * list in use is the consensus agreement between myself, Linus and + * some package distributers. It is a given that no list will suit + * everyone's taste. If you have rabid concerns about the list + * please feel free to edit the system_maps array and compile your + * own binaries. + * + * Added support for searching of the list of symbol maps. This + * allows support for access to multiple symbol maps. The theory + * behind this is that a production kernel may have a system map in + * /boot/System.map. If a test kernel is booted this system map + * would be skipped in favor of one found in /usr/src/linux. + * + * Thu Jan 18 11:18:31 CST 1996: Dr. Wettstein + * Added patch from beta-testers to allow for reading of both + * ELF and a.out map files. + * + * Wed Aug 21 09:15:49 CDT 1996: Dr. Wettstein + * Reloading of kernel module symbols is now turned on by the + * SetParanoiaLevel function. The default behavior is to NOT reload + * the kernel module symbols when a protection fault is detected. + * + * Added support for freeing of the current kernel module symbols. + * This was necessary to support reloading of the kernel module symbols. + * + * When a matching static symbol table is loaded the kernel version + * number is printed. + * + * Mon Jun 9 17:12:42 CST 1997: Martin Schulze + * Added #1 and #2 to some error messages in order to being able + * to divide them (ulmo@Q.Net) + * + * Fri Jun 13 10:50:23 CST 1997: Martin Schulze + * Changed definition of LookupSymbol to non-static because it is + * used in klogd.c, too. + * + * Fri Jan 9 23:00:08 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed bug that caused klogd to die if there is no System.map available. + * + * Sun 29 Mar 18:14:07 BST 1998: Mark Simon Phillips <M.S.Phillips@nortel.co.uk> + * Switched to fgets() as gets() is not buffer overrun secure. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified loop for detecting the correct system map. Now it won't + * stop if a file has been found but doesn't contain the correct map. + * Special thanks go go Mark Simon Phillips for the hint. + * + * Mon Oct 12 00:42:30 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified CheckVersion() + * . Use shift to decode the kernel version + * . Compare integers of kernel version + * . extract major.minor.patch from utsname.release via sscanf() + * The reason lays in possible use of kernel flavours which + * modify utsname.release but no the Version_ symbol. + * + * Sun Feb 21 22:27:49 EST 1999: Keith Owens <kaos@ocs.com.au> + * Fixed bug that caused klogd to die if there is no sym_array available. + * + * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Close symbol file in InitKsyms() when an error occurred. + */ + + +/* Includes. */ +#include <stdlib.h> +#include <malloc.h> +#include <sys/utsname.h> +#include "klogd.h" +#include "ksyms.h" + +#define VERBOSE_DEBUGGING 0 + + +/* Variables static to this module. */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +static int num_syms = 0; +static int i_am_paranoid = 0; +static char vstring[12]; +static struct sym_table *sym_array = (struct sym_table *) 0; + +static char *system_maps[] = +{ + "/boot/System.map", + "/System.map", +#if defined(TEST) + "./System.map", +#endif + (char *) 0 +}; + + +#if defined(TEST) +int debugging; +#else +extern int debugging; +#endif + + +/* Function prototypes. */ +static char * FindSymbolFile(void); +static int AddSymbol(unsigned long, char*); +static void FreeSymbols(void); +static int CheckVersion(char *); +static int CheckMapVersion(char *); + + +/************************************************************************** + * Function: InitKsyms + * + * Purpose: This function is responsible for initializing and loading + * the data tables used by the kernel address translations. + * + * Arguements: (char *) mapfile + * + * mapfile:-> A pointer to a complete path + * specification of the file containing + * the kernel map to use. + * + * Return: int + * + * A boolean style context is returned. The return value will + * be true if initialization was successful. False if not. + **************************************************************************/ + +extern int InitKsyms(mapfile) + + char *mapfile; + +{ + auto char type, + sym[512]; + + auto int version = 0; + + auto unsigned long int address; + + auto FILE *sym_file; + + + /* Check and make sure that we are starting with a clean slate. */ + if ( num_syms > 0 ) + FreeSymbols(); + + + /* + * Search for and open the file containing the kernel symbols. + */ + if ( mapfile != (char *) 0 ) + { + if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) + { + Syslog(LOG_WARNING, "Cannot open map file: %s.", \ + mapfile); + return(0); + } + } + else + { + if ( (mapfile = FindSymbolFile()) == (char *) 0 ) + { + Syslog(LOG_WARNING, "Cannot find map file."); + if ( debugging ) + fputs("Cannot find map file.\n", stderr); + return(0); + } + + if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) + { + Syslog(LOG_WARNING, "Cannot open map file."); + if ( debugging ) + fputs("Cannot open map file.\n", stderr); + return(0); + } + } + + + /* + * Read the kernel symbol table file and add entries for each + * line. I suspect that the use of fscanf is not really in vogue + * but it was quick and dirty and IMHO suitable for fixed format + * data such as this. If anybody doesn't agree with this please + * e-mail me a diff containing a parser with suitable political + * correctness -- GW. + */ + while ( !feof(sym_file) ) + { + if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) + != 3 ) + { + Syslog(LOG_ERR, "Error in symbol table input (#1)."); + fclose(sym_file); + return(0); + } + if ( VERBOSE_DEBUGGING && debugging ) + fprintf(stderr, "Address: %lx, Type: %c, Symbol: %s\n", + address, type, sym); + + if ( AddSymbol(address, sym) == 0 ) + { + Syslog(LOG_ERR, "Error adding symbol - %s.", sym); + fclose(sym_file); + return(0); + } + + if ( version == 0 ) + version = CheckVersion(sym); + } + + + Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); + switch ( version ) + { + case -1: + Syslog(LOG_WARNING, "Symbols do not match kernel version."); + num_syms = 0; + break; + + case 0: + Syslog(LOG_WARNING, "Cannot verify that symbols match " \ + "kernel version."); + break; + + case 1: + Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring); + break; + } + + fclose(sym_file); + return(1); +} + + +/************************************************************************** + * Function: FindSymbolFile + * + * Purpose: This function is responsible for encapsulating the search + * for a valid symbol file. Encapsulating the search for + * the map file in this function allows an intelligent search + * process to be implemented. + * + * The list of symbol files will be searched until either a + * symbol file is found whose version matches the currently + * executing kernel or the end of the list is encountered. If + * the end of the list is encountered the first available + * symbol file is returned to the caller. + * + * This strategy allows klogd to locate valid symbol files + * for both a production and an experimental kernel. For + * example a map for a production kernel could be installed + * in /boot. If an experimental kernel is loaded the map + * in /boot will be skipped and the map in /usr/src/linux would + * be used if its version number matches the executing kernel. + * + * Arguements: None specified. + * + * Return: char * + * + * If a valid system map cannot be located a null pointer + * is returned to the caller. + * + * If the search is succesful a pointer is returned to the + * caller which points to the name of the file containing + * the symbol table to be used. + **************************************************************************/ + +static char * FindSymbolFile() + +{ + auto char *file = (char *) 0, + **mf = system_maps; + + auto struct utsname utsname; + static char symfile[100]; + + auto FILE *sym_file = (FILE *) 0; + + if ( uname(&utsname) < 0 ) + { + Syslog(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + + if ( debugging ) + fputs("Searching for symbol map.\n", stderr); + + for (mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) + { + + sprintf (symfile, "%s-%s", *mf, utsname.release); + if ( debugging ) + fprintf(stderr, "Trying %s.\n", symfile); + if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { + if (CheckMapVersion(symfile) == 1) + file = symfile; + } + if (sym_file == (FILE *) 0 || file == (char *) 0) { + sprintf (symfile, "%s", *mf); + if ( debugging ) + fprintf(stderr, "Trying %s.\n", symfile); + if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { + if (CheckMapVersion(symfile) == 1) + file = symfile; + } + } + + } + + /* + * At this stage of the game we are at the end of the symbol + * tables. + */ + if ( debugging ) + fprintf(stderr, "End of search list encountered.\n"); + return(file); +} + + +/************************************************************************** + * Function: CheckVersion + * + * Purpose: This function is responsible for determining whether or + * the system map being loaded matches the version of the + * currently running kernel. + * + * The kernel version is checked by examing a variable which + * is of the form: _Version_66347 (a.out) or Version_66437 (ELF). + * + * The suffix of this variable is the current kernel version + * of the kernel encoded in base 256. For example the + * above variable would be decoded as: + * + * (66347 = 1*65536 + 3*256 + 43 = 1.3.43) + * + * (Insert appropriate deities here) help us if Linus ever + * needs more than 255 patch levels to get a kernel out the + * door... :-) + * + * Arguements: (char *) version + * + * version:-> A pointer to the string which + * is to be decoded as a kernel + * version variable. + * + * Return: int + * + * -1:-> The currently running kernel version does + * not match this version string. + * + * 0:-> The string is not a kernel version variable. + * + * 1:-> The executing kernel is of the same version + * as the version string. + **************************************************************************/ + +static int CheckVersion(version) + + char *version; + + +{ + auto int vnum, + major, + minor, + patch; + +#ifndef TESTING + int kvnum; + auto struct utsname utsname; +#endif + + static char *prefix = { "Version_" }; + + + /* Early return if there is no hope. */ + if ( strncmp(version, prefix, strlen(prefix)) == 0 /* ELF */ || + (*version == '_' && + strncmp(++version, prefix, strlen(prefix)) == 0 ) /* a.out */ ) + ; + else + return(0); + + + /* + * Since the symbol looks like a kernel version we can start + * things out by decoding the version string into its component + * parts. + */ + vnum = atoi(version + strlen(prefix)); + patch = vnum & 0x000000FF; + minor = (vnum >> 8) & 0x000000FF; + major = (vnum >> 16) & 0x000000FF; + if ( debugging ) + fprintf(stderr, "Version string = %s, Major = %d, " \ + "Minor = %d, Patch = %d.\n", version + + strlen(prefix), major, minor, \ + patch); + sprintf(vstring, "%d.%d.%d", major, minor, patch); + +#ifndef TESTING + /* + * We should now have the version string in the vstring variable in + * the same format that it is stored in by the kernel. We now + * ask the kernel for its version information and compare the two + * values to determine if our system map matches the kernel + * version level. + */ + if ( uname(&utsname) < 0 ) + { + Syslog(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + if ( debugging ) + fprintf(stderr, "Comparing kernel %s with symbol table %s.\n",\ + utsname.release, vstring); + + if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) + { + Syslog(LOG_ERR, "Kernel send bogus release string `%s'.", + utsname.release); + return(0); + } + + /* Compute the version code from data sent by the kernel */ + kvnum = (major << 16) | (minor << 8) | patch; + + /* Failure. */ + if ( vnum != kvnum ) + return(-1); + + /* Success. */ +#endif + return(1); +} + + +/************************************************************************** + * Function: CheckMapVersion + * + * Purpose: This function is responsible for determining whether or + * the system map being loaded matches the version of the + * currently running kernel. It uses CheckVersion as + * backend. + * + * Arguements: (char *) fname + * + * fname:-> A pointer to the string which + * references the system map file to + * be used. + * + * Return: int + * + * -1:-> The currently running kernel version does + * not match the version in the given file. + * + * 0:-> No system map file or no version information. + * + * 1:-> The executing kernel is of the same version + * as the version of the map file. + **************************************************************************/ + +static int CheckMapVersion(fname) + + char *fname; + + +{ + int version; + FILE *sym_file; + auto unsigned long int address; + auto char type, + sym[512]; + + if ( (sym_file = fopen(fname, "r")) != (FILE *) 0 ) { + /* + * At this point a map file was successfully opened. We + * now need to search this file and look for version + * information. + */ + Syslog(LOG_INFO, "Inspecting %s", fname); + + version = 0; + while ( !feof(sym_file) && (version == 0) ) + { + if ( fscanf(sym_file, "%lx %c %s\n", &address, \ + &type, sym) != 3 ) + { + Syslog(LOG_ERR, "Error in symbol table input (#2)."); + fclose(sym_file); + return(0); + } + if ( VERBOSE_DEBUGGING && debugging ) + fprintf(stderr, "Address: %lx, Type: %c, " \ + "Symbol: %s\n", address, type, sym); + + version = CheckVersion(sym); + } + fclose(sym_file); + + switch ( version ) + { + case -1: + Syslog(LOG_ERR, "Symbol table has incorrect " \ + "version number.\n"); + break; + + case 0: + if ( debugging ) + fprintf(stderr, "No version information " \ + "found.\n"); + break; + case 1: + if ( debugging ) + fprintf(stderr, "Found table with " \ + "matching version number.\n"); + break; + } + + return(version); + } + + return(0); +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: (unsigned long) address, (char *) symbol + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ + +static int AddSymbol(address, symbol) + + unsigned long address; + + char *symbol; + +{ + /* Allocate the the symbol table entry. */ + sym_array = (struct sym_table *) realloc(sym_array, (num_syms+1) * \ + sizeof(struct sym_table)); + if ( sym_array == (struct sym_table *) 0 ) + return(0); + + /* Then the space for the symbol. */ + sym_array[num_syms].name = (char *) malloc(strlen(symbol)*sizeof(char)\ + + 1); + if ( sym_array[num_syms].name == (char *) 0 ) + return(0); + + sym_array[num_syms].value = address; + strcpy(sym_array[num_syms].name, symbol); + ++num_syms; + return(1); +} + + +/************************************************************************** + * Function: LookupSymbol + * + * Purpose: Find the symbol which is related to the given kernel + * address. + * + * Arguements: (long int) value, (struct symbol *) sym + * + * value:-> The address to be located. + * + * sym:-> A pointer to a structure which will be + * loaded with the symbol's parameters. + * + * Return: (char *) + * + * If a match cannot be found a diagnostic string is printed. + * If a match is found the pointer to the symbolic name most + * closely matching the address is returned. + **************************************************************************/ + +char * LookupSymbol(value, sym) + + unsigned long value; + + struct symbol *sym; + +{ + auto int lp; + + auto char *last; + + if (!sym_array) + return((char *) 0); + + last = sym_array[0].name; + sym->offset = 0; + sym->size = 0; + if ( value < sym_array[0].value ) + return((char *) 0); + + for(lp= 0; lp <= num_syms; ++lp) + { + if ( sym_array[lp].value > value ) + { + sym->offset = value - sym_array[lp-1].value; + sym->size = sym_array[lp].value - \ + sym_array[lp-1].value; + return(last); + } + last = sym_array[lp].name; + } + + if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 ) + return(last); + + return((char *) 0); +} + + +/************************************************************************** + * Function: FreeSymbols + * + * Purpose: This function is responsible for freeing all memory which + * has been allocated to hold the static symbol table. It + * also initializes the symbol count and in general prepares + * for a re-read of a static symbol table. + * + * Arguements: void + * + * Return: void + **************************************************************************/ + +static void FreeSymbols() + +{ + auto int lp; + + /* Free each piece of memory allocated for symbol names. */ + for(lp= 0; lp < num_syms; ++lp) + free(sym_array[lp].name); + + /* Whack the entire array and initialize everything. */ + free(sym_array); + sym_array = (struct sym_table *) 0; + num_syms = 0; + + return; +} + + +/************************************************************************** + * Function: LogExpanded + * + * Purpose: This function is responsible for logging a kernel message + * line after all potential numeric kernel addresses have + * been resolved symolically. + * + * Arguements: (char *) line, (char *) el + * + * line:-> A pointer to the buffer containing the kernel + * message to be expanded and logged. + * + * el:-> A pointer to the buffer into which the expanded + * kernel line will be written. + * + * Return: void + **************************************************************************/ + +extern char * ExpandKadds(line, el) + + char *line; + + char *el; + +{ + auto char dlm, + *kp, + *sl = line, + *elp = el, + *symbol; + + char num[15]; + auto unsigned long int value; + + auto struct symbol sym; + + + /* + * This is as handy a place to put this as anyplace. + * + * Since the insertion of kernel modules can occur in a somewhat + * dynamic fashion we need some mechanism to insure that the + * kernel symbol tables get read just prior to when they are + * needed. + * + * To accomplish this we look for the Oops string and use its + * presence as a signal to load the module symbols. + * + * This is not the best solution of course, especially if the + * kernel is rapidly going out to lunch. What really needs to + * be done is to somehow generate a callback from the + * kernel whenever a module is loaded or unloaded. I am + * open for patches. + */ + if ( i_am_paranoid && + (strstr(line, "Oops:") != (char *) 0) && !InitMsyms() ) + Syslog(LOG_WARNING, "Cannot load kernel module symbols.\n"); + + + /* + * Early return if there do not appear to be any kernel + * messages in this line. + */ + if ( (num_syms == 0) || + (kp = strstr(line, "[<")) == (char *) 0 ) + { + strcpy(el, line); + return(el); + } + + /* Loop through and expand all kernel messages. */ + do + { + while ( sl < kp+1 ) + *elp++ = *sl++; + + /* Now poised at a kernel delimiter. */ + if ( (kp = strstr(sl, ">]")) == (char *) 0 ) + { + strcpy(el, sl); + return(el); + } + dlm = *kp; + strncpy(num,sl+1,kp-sl-1); + num[kp-sl-1] = '\0'; + value = strtoul(num, (char **) 0, 16); + if ( (symbol = LookupSymbol(value, &sym)) == (char *) 0 ) + symbol = sl; + + strcat(elp, symbol); + elp += strlen(symbol); + if ( debugging ) + fprintf(stderr, "Symbol: %s = %lx = %s, %x/%d\n", \ + sl+1, value, \ + (sym.size==0) ? symbol+1 : symbol, \ + sym.offset, sym.size); + + value = 2; + if ( sym.size != 0 ) + { + --value; + ++kp; + elp += sprintf(elp, "+%x/%d", sym.offset, sym.size); + } + strncat(elp, kp, value); + elp += value; + sl = kp + value; + if ( (kp = strstr(sl, "[<")) == (char *) 0 ) + strcat(elp, sl); + } + while ( kp != (char *) 0); + + if ( debugging ) + fprintf(stderr, "Expanded line: %s\n", el); + return(el); +} + + +/************************************************************************** + * Function: SetParanoiaLevel + * + * Purpose: This function is an interface function for setting the + * mode of loadable module symbol lookups. Probably overkill + * but it does slay another global variable. + * + * Arguements: (int) level + * + * level:-> The amount of paranoia which is to be + * present when resolving kernel exceptions. + * Return: void + **************************************************************************/ + +extern void SetParanoiaLevel(level) + + int level; + +{ + i_am_paranoid = level; + return; +} + + +/* + * Setting the -DTEST define enables the following code fragment to + * be compiled. This produces a small standalone program which will + * echo the standard input of the process to stdout while translating + * all numeric kernel addresses into their symbolic equivalent. + */ +#if defined(TEST) + +#include <stdarg.h> + +extern int main(int, char **); + + +extern int main(int argc, char *argv[]) +{ + auto char line[1024], eline[2048]; + + debugging = 1; + + + if ( !InitKsyms((char *) 0) ) + { + fputs("ksym: Error loading system map.\n", stderr); + return(1); + } + + while ( !feof(stdin) ) + { + fgets(line, sizeof(line), stdin); + if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; /* Trash NL char */ + memset(eline, '\0', sizeof(eline)); + ExpandKadds(line, eline); + fprintf(stdout, "%s\n", eline); + } + + + return(0); +} + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stdout, "Pr: %d, ", priority); + vfprintf(stdout, fmt, ap); + va_end(ap); + fputc('\n', stdout); + + return; +} +#endif diff --git a/ksym_mod.c b/ksym_mod.c new file mode 100644 index 00000000..344963b2 --- /dev/null +++ b/ksym_mod.c @@ -0,0 +1,700 @@ +/* + ksym_mod.c - functions for building symbol lookup tables for klogd + Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This file implements functions which are useful for building + * a symbol lookup table based on the in kernel symbol table + * maintained by the Linux kernel. + * + * Proper logging of kernel panics generated by loadable modules + * tends to be difficult. Since the modules are loaded dynamically + * their addresses are not known at kernel load time. A general + * protection fault (Oops) cannot be properly deciphered with + * classic methods using the static symbol map produced at link time. + * + * One solution to this problem is to have klogd attempt to translate + * addresses from module when the fault occurs. By referencing the + * the kernel symbol table proper resolution of these symbols is made + * possible. + * + * At least that is the plan. + * + * Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein + * The situation where no module support has been compiled into a + * kernel is now detected. An informative message is output indicating + * that the kernel has no loadable module support whenever kernel + * module symbols are loaded. + * + * An informative message is printed indicating the number of kernel + * modules and the number of symbols loaded from these modules. + * + * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman + * Some more glibc patches made by <mdorman@debian.org>. + * + * Sat Jan 10 15:00:18 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed problem with klogd not being able to be built on a kernel + * newer than 2.1.18. It was caused by modified structures + * inside the kernel that were included. I have worked in a + * patch from Alessandro Suardi <asuardi@uninetcom.it>. + * + * Sun Jan 25 20:57:34 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Another patch for Linux/alpha by Christopher C Chimelis + * <chris@classnet.med.miami.edu>. + * + * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues <pmanuel@cindy.fe.up.pt> + * Changed lseek() to llseek() in order to support > 2GB address + * space which provided by kernels > 2.1.70. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Removed <sys/module.h> as it's no longer part of recent glibc + * versions. Added prototyp for llseek() which has been + * forgotton in <unistd.h> from glibc. Added more log + * information if problems occurred while reading a system map + * file, by submission from Mark Simon Phillips <M.S.Phillips@nortel.co.uk>. + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de> + * Corrected return value of AddModule if /dev/kmem can't be + * loaded. This will prevent klogd from segfaulting if /dev/kmem + * is not available. Patch from Topi Miettinen <tom@medialab.sonera.net>. + * + * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Changed llseek() to lseek64() in order to skip a libc warning. + */ + + +/* Includes. */ +#include <stdlib.h> +#include <malloc.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#if !defined(__GLIBC__) +#include <linux/time.h> +#include <linux/module.h> +#else /* __GLIBC__ */ +#include <linux/module.h> +extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); +extern int get_kernel_syms __P ((struct kernel_sym *__table)); +#endif /* __GLIBC__ */ +#include <stdarg.h> +#include <paths.h> +#include <linux/version.h> + +#include "klogd.h" +#include "ksyms.h" + + +#if !defined(__GLIBC__) +/* + * The following bit uses some kernel/library magic to product what + * looks like a function call to user level code. This function is + * actually a system call in disguise. The purpose of the getsyms + * call is to return a current copy of the in-kernel symbol table. + */ +#define __LIBRARY__ +#include <linux/unistd.h> +#define __NR_getsyms __NR_get_kernel_syms +_syscall1(int, getsyms, struct kernel_sym *, syms); +#undef __LIBRARY__ +extern int getsyms(struct kernel_sym *); +#else /* __GLIBC__ */ +#define getsyms get_kernel_syms +#endif /* __GLIBC__ */ + +/* Variables static to this module. */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +struct Module +{ + struct sym_table *sym_array; + int num_syms; + + char *name; + struct module module; +#if LINUX_VERSION_CODE >= 0x20112 + struct module_info module_info; +#endif +}; + +static int num_modules = 0; +struct Module *sym_array_modules = (struct Module *) 0; + +static int have_modules = 0; + +#if defined(TEST) +static int debugging = 1; +#else +extern int debugging; +#endif + + +/* Function prototypes. */ +static void FreeModules(void); +static int AddSymbol(struct Module *mp, unsigned long, char *); +static int AddModule(unsigned long, char *); +static int symsort(const void *, const void *); + + +/************************************************************************** + * Function: InitMsyms + * + * Purpose: This function is responsible for building a symbol + * table which can be used to resolve addresses for + * loadable modules. + * + * Arguements: Void + * + * Return: A boolean return value is assumed. + * + * A false value indicates that something went wrong. + * + * True if loading is successful. + **************************************************************************/ + +extern int InitMsyms() + +{ + auto int rtn, + tmp; + + auto struct kernel_sym *ksym_table, + *p; + + + /* Initialize the kernel module symbol table. */ + FreeModules(); + + + /* + * The system call which returns the kernel symbol table has + * essentialy two modes of operation. Called with a null pointer + * the system call returns the number of symbols defined in the + * the table. + * + * The second mode of operation is to pass a valid pointer to + * the call which will then load the current symbol table into + * the memory provided. + * + * Returning the symbol table is essentially an all or nothing + * proposition so we need to pre-allocate enough memory for the + * complete table regardless of how many symbols we need. + * + * Bummer. + */ + if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) + { + if ( errno == ENOSYS ) + Syslog(LOG_INFO, "No module symbols loaded - " + "kernel modules not enabled.\n"); + else + Syslog(LOG_ERR, "Error loading kernel symbols " \ + "- %s\n", strerror(errno)); + return(0); + } + if ( debugging ) + fprintf(stderr, "Loading kernel module symbols - " + "Size of table: %d\n", rtn); + + ksym_table = (struct kernel_sym *) malloc(rtn * \ + sizeof(struct kernel_sym)); + if ( ksym_table == (struct kernel_sym *) 0 ) + { + Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ + "symbol table.\n"); + return(0); + } + if ( (rtn = getsyms(ksym_table)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \ + strerror(errno)); + return(0); + } + + + /* + * Build a symbol table compatible with the other one used by + * klogd. + */ + tmp = rtn; + p = ksym_table; + while ( tmp-- ) + { + if ( !AddModule(p->value, p->name) ) + { + Syslog(LOG_WARNING, "Error adding kernel module table " + "entry.\n"); + free(ksym_table); + return(0); + } + ++p; + } + + /* Sort the symbol tables in each module. */ + for (rtn = tmp= 0; tmp < num_modules; ++tmp) + { + rtn += sym_array_modules[tmp].num_syms; + if ( sym_array_modules[tmp].num_syms < 2 ) + continue; + qsort(sym_array_modules[tmp].sym_array, \ + sym_array_modules[tmp].num_syms, \ + sizeof(struct sym_table), symsort); + } + + if ( rtn == 0 ) + Syslog(LOG_INFO, "No module symbols loaded."); + else + Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ + (rtn == 1) ? "symbol" : "symbols", \ + num_modules, (num_modules == 1) ? "." : "s."); + free(ksym_table); + return(1); +} + + +static int symsort(p1, p2) + + const void *p1; + + const void *p2; + +{ + auto const struct sym_table *sym1 = p1, + *sym2 = p2; + + if ( sym1->value < sym2->value ) + return(-1); + if ( sym1->value == sym2->value ) + return(0); + return(1); +} + + +/************************************************************************** + * Function: FreeModules + * + * Purpose: This function is used to free all memory which has been + * allocated for the modules and their symbols. + * + * Arguements: None specified. + * + * Return: void + **************************************************************************/ + +static void FreeModules() + +{ + auto int nmods, + nsyms; + + auto struct Module *mp; + + + /* Check to see if the module symbol tables need to be cleared. */ + have_modules = 0; + if ( num_modules == 0 ) + return; + + + for (nmods= 0; nmods < num_modules; ++nmods) + { + mp = &sym_array_modules[nmods]; + if ( mp->num_syms == 0 ) + continue; + + for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) + free(mp->sym_array[nsyms].name); + free(mp->sym_array); + } + + free(sym_array_modules); + sym_array_modules = (struct Module *) 0; + num_modules = 0; + return; +} + + +/************************************************************************** + * Function: AddModule + * + * Purpose: This function is responsible for adding a module to + * the list of currently loaded modules. + * + * Arguements: (unsigned long) address, (char *) symbol + * + * address:-> The address of the module. + * + * symbol:-> The name of the module. + * + * Return: int + **************************************************************************/ + +static int AddModule(address, symbol) + + unsigned long address; + + char *symbol; + +{ + auto int memfd; + + auto struct Module *mp; + + + /* Return if we have loaded the modules. */ + if ( have_modules ) + return(1); + + /* + * The following section of code is responsible for determining + * whether or not we are done reading the list of modules. + */ + if ( symbol[0] == '#' ) + { + + if ( symbol[1] == '\0' ) + { + /* + * A symbol which consists of a # sign only + * signifies a a resident kernel segment. When we + * hit one of these we are done reading the + * module list. + */ + have_modules = 1; + return(1); + } + /* Allocate space for the module. */ + sym_array_modules = (struct Module *) \ + realloc(sym_array_modules, \ + (num_modules+1) * sizeof(struct Module)); + if ( sym_array_modules == (struct Module *) 0 ) + { + Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); + return(0); + } + mp = &sym_array_modules[num_modules]; + + if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) + { + Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); + return(0); + } + if ( lseek64(memfd, address, SEEK_SET) < 0 ) + { + Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); + Syslog(LOG_WARNING, "Symbol %s, value %08x\n", symbol, address); + return(0); + } + if ( read(memfd, \ + (char *)&sym_array_modules[num_modules].module, \ + sizeof(struct module)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading module " + "descriptor.\n"); + return(0); + } + close(memfd); + + /* Save the module name. */ + mp->name = (char *) malloc(strlen(&symbol[1]) + 1); + if ( mp->name == (char *) 0 ) + return(0); + strcpy(mp->name, &symbol[1]); + + mp->num_syms = 0; + mp->sym_array = (struct sym_table *) 0; + ++num_modules; + return(1); + } + else + { + if (num_modules > 0) + mp = &sym_array_modules[num_modules - 1]; + else + mp = &sym_array_modules[0]; + AddSymbol(mp, address, symbol); + } + + + return(1); +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol + * + * mp:-> A pointer to the module which the symbol is + * to be added to. + * + * address:-> The address of the symbol. + * + * symbol:-> The name of the symbol. + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ + +static int AddSymbol(mp, address, symbol) + + struct Module *mp; + + unsigned long address; + + char *symbol; + +{ + auto int tmp; + + + /* Allocate space for the symbol table entry. */ + mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ + (mp->num_syms+1) * sizeof(struct sym_table)); + if ( mp->sym_array == (struct sym_table *) 0 ) + return(0); + + /* Then the space for the symbol. */ + tmp = strlen(symbol); + tmp += (strlen(mp->name) + 1); + mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); + if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) + return(0); + memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); + + /* Stuff interesting information into the module. */ + mp->sym_array[mp->num_syms].value = address; + strcpy(mp->sym_array[mp->num_syms].name, mp->name); + strcat(mp->sym_array[mp->num_syms].name, ":"); + strcat(mp->sym_array[mp->num_syms].name, symbol); + ++mp->num_syms; + + return(1); +} + + +/************************************************************************** + * Function: LookupModuleSymbol + * + * Purpose: Find the symbol which is related to the given address from + * a kernel module. + * + * Arguements: (long int) value, (struct symbol *) sym + * + * value:-> The address to be located. + * + * sym:-> A pointer to a structure which will be + * loaded with the symbol's parameters. + * + * Return: (char *) + * + * If a match cannot be found a diagnostic string is printed. + * If a match is found the pointer to the symbolic name most + * closely matching the address is returned. + **************************************************************************/ + +extern char * LookupModuleSymbol(value, sym) + + unsigned long value; + + struct symbol *sym; + +{ + auto int nmod, + nsym; + + auto struct sym_table *last; + + auto struct Module *mp; + + + sym->size = 0; + sym->offset = 0; + if ( num_modules == 0 ) + return((char *) 0); + + for(nmod= 0; nmod < num_modules; ++nmod) + { + mp = &sym_array_modules[nmod]; + + /* + * Run through the list of symbols in this module and + * see if the address can be resolved. + */ + for(nsym= 1, last = &mp->sym_array[0]; + nsym < mp->num_syms; + ++nsym) + { + if ( mp->sym_array[nsym].value > value ) + { + sym->offset = value - last->value; + sym->size = mp->sym_array[nsym].value - \ + last->value; + return(last->name); + } + last = &mp->sym_array[nsym]; + } + + + /* + * At this stage of the game we still cannot give up the + * ghost. There is the possibility that the address is + * from a module which has no symbols registered with + * the kernel. The solution is to compare the address + * against the starting address and extant of the module + * If it is in this range we can at least return the + * name of the module. + */ +#if LINUX_VERSION_CODE < 0x20112 + if ( (void *) value >= mp->module.addr && + (void *) value <= (mp->module.addr + \ + mp->module.size * 4096) ) +#else + if ( value >= mp->module_info.addr && + value <= (mp->module_info.addr + \ + mp->module.size * 4096) ) +#endif + { + /* + * A special case needs to be checked for. The above + * conditional tells us that we are within the + * extant of this module but symbol lookup has + * failed. + * + * We need to check to see if any symbols have + * been defined in this module. If there have been + * symbols defined the assumption must be made that + * the faulting address lies somewhere beyond the + * last symbol. About the only thing we can do + * at this point is use an offset from this + * symbol. + */ + if ( mp->num_syms > 0 ) + { + last = &mp->sym_array[mp->num_syms - 1]; +#if LINUX_VERSION_CODE < 0x20112 + sym->size = (int) mp->module.addr + \ + (mp->module.size * 4096) - value; +#else + sym->size = (int) mp->module_info.addr + \ + (mp->module.size * 4096) - value; +#endif + sym->offset = value - last->value; + return(last->name); + } + + /* + * There were no symbols defined for this module. + * Return the module name and the offset of the + * faulting address in the module. + */ + sym->size = mp->module.size * 4096; +#if LINUX_VERSION_CODE < 0x20112 + sym->offset = (void *) value - mp->module.addr; +#else + sym->offset = value - mp->module_info.addr; +#endif + return(mp->name); + } + } + + /* It has been a hopeless exercise. */ + return((char *) 0); +} + + +/* + * Setting the -DTEST define enables the following code fragment to + * be compiled. This produces a small standalone program which will + * dump the current kernel symbol table. + */ +#if defined(TEST) + +#include <stdarg.h> + + +extern int main(int, char **); + + +int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int lp, syms; + + + if ( !InitMsyms() ) + { + fprintf(stderr, "Cannot load module symbols.\n"); + return(1); + } + + printf("Number of modules: %d\n\n", num_modules); + + for(lp= 0; lp < num_modules; ++lp) + { + printf("Module #%d = %s, Number of symbols = %d\n", lp + 1, \ + sym_array_modules[lp].name, \ + sym_array_modules[lp].num_syms); + + for (syms= 0; syms < sym_array_modules[lp].num_syms; ++syms) + { + printf("\tSymbol #%d\n", syms + 1); + printf("\tName: %s\n", \ + sym_array_modules[lp].sym_array[syms].name); + printf("\tAddress: %lx\n\n", \ + sym_array_modules[lp].sym_array[syms].value); + } + } + + FreeModules(); + return(0); +} + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stdout, "Pr: %d, ", priority); + vfprintf(stdout, fmt, ap); + va_end(ap); + fputc('\n', stdout); + + return; +} + +#endif diff --git a/ksyms.h b/ksyms.h new file mode 100644 index 00000000..4e70ba05 --- /dev/null +++ b/ksyms.h @@ -0,0 +1,35 @@ +/* + ksym.h - Definitions for symbol table utilities. + Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Variables, structures and type definitions static to this module. */ + +struct symbol +{ + char *name; + int size; + int offset; +}; + + +/* Function prototypes. */ +extern char * LookupSymbol(unsigned long, struct symbol *); +extern char * LookupModuleSymbol(unsigned long int, struct symbol *); diff --git a/modutils.patch b/modutils.patch new file mode 100644 index 00000000..4dff7f35 --- /dev/null +++ b/modutils.patch @@ -0,0 +1,65 @@ +diff -u --new-file --recursive base/modules-2.0.0/depmod/modprobe.c ./modules-2.0.0/depmod/modprobe.c +--- base/modules-2.0.0/depmod/modprobe.c Mon Jun 10 05:29:08 1996 ++++ ./modules-2.0.0/depmod/modprobe.c Thu Aug 29 09:58:01 1996 +@@ -233,6 +233,13 @@ + verbose ("\r\t%s\n\t\t",cmd); + int ret = system(cmd); + #endif ++ if ( fork() == 0 ) ++ { ++ /* Child process. */ ++ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 ) ++ fprintf(stderr, "Failure in signaling klogd.\n"); ++ exit(0); ++ } + return ret; + } + /* +diff -u --new-file --recursive base/modules-2.0.0/insmod/insmod.c ./modules-2.0.0/insmod/insmod.c +--- base/modules-2.0.0/insmod/insmod.c Mon Jun 10 06:42:25 1996 ++++ ./modules-2.0.0/insmod/insmod.c Thu Aug 29 09:56:53 1996 +@@ -253,6 +253,18 @@ + ++n_stringpatches; + } + ++ ++void signal_klogd() { ++ if ( fork() == 0 ) ++ { ++ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 ) ++ fprintf(stderr, "Failure in signaling klogd.\n"); ++ exit(0); ++ } ++ return; ++} ++ ++ + int main(int argc, char **argv) + { + FILE *fp; +@@ -983,6 +995,8 @@ + symvalue(sp) + addr, symtype, symname(sp)); + } + ++ signal_klogd(); ++ + if (nksyms > 0) + free(ksymtab); /* it has done its job */ + +@@ -1292,6 +1306,7 @@ + --argc; + ++argv; + } ++ signal_klogd(); + return errors; + } + /* else recursive removal */ +@@ -1353,6 +1368,8 @@ + break; + } + } ++ ++ signal_klogd(); + + return errors; + } @@ -0,0 +1,118 @@ +/* + * Loadable driver which provides the ability to generate a kernel + * protection fault. Mainly useful for testing the address translation + * capabilities of klogd. + * + * Fri Oct 27 14:34:27 CDT 1995: Dr. Wettstein + * + * Initial version. + */ + +#define NEW_MODULES + +/* Kernel includes. */ +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/fs.h> + +/* Standard module stuff. */ +#if defined(NEW_MODULES) +#include <linux/module.h> +#else +#include <linux/module.h> +#include <linux/version.h> +char kernel_version[] = UTS_RELEASE; +#endif + + +static int major = 32; + + +#ifdef MODULE +static int oops_ioctl(struct inode *, struct file *, unsigned int cmd, unsigned long arg); +static int oops_open(struct inode * node, struct file * file); +static void oops(void); + +static struct symbol_table these_symbols = { +#include <linux/symtab_begin.h> + X(oops_open), + X(oops_ioctl), + X(oops), +#include <linux/symtab_end.h> +}; + +/* driver specific module definitions */ +static struct file_operations oops_fops1 = { + NULL, /* hw_lseek */ + NULL, /* hw_read */ + NULL, /* write */ + NULL, /* hw_readdir */ + NULL, /* hw_select */ + oops_ioctl, /* hw_ioctl */ + NULL, /* mmap */ + oops_open, /* hw_open */ + NULL, /* hw_release */ + NULL /* fsync */ +}; + +static int oops_open(struct inode * node, struct file * file) +{ + printk("Called oops_open.\n"); + return(0); +} + + +static int oops_ioctl(struct inode * node, struct file * file, \ + unsigned int cmd, unsigned long arg) +{ + + printk("Called oops_ioctl.\n"); + printk("Cmd: %d, Arg: %ld\n", cmd, arg); + if ( cmd == 1 ) + { + oops(); + } + + return(0); +} + +static void oops() + +{ + auto unsigned long *p = (unsigned long *) 828282828; + *p = 5; + return; +} + + +int +init_module(void) +{ + printk("oops: Module initilization.\n"); + if (register_chrdev(major, "oops", &oops_fops1)) { + printk("register_chrdev failed."); + return -EIO; + } + + printk("oops: Registering symbols.\n"); + register_symtab(&these_symbols); + + return 0; +} + + +void +cleanup_module(void) +{ + /* driver specific cleanups, ususally "unregister_*()" */ + printk("oops: Module unloadeding.\n"); + if (unregister_chrdev(major, "oops") != 0) + printk("cleanup_module failed\n"); + else + printk("cleanup_module succeeded\n"); + + return; + +} +#endif /* MODULE */ diff --git a/oops_test.c b/oops_test.c new file mode 100644 index 00000000..f710d4cd --- /dev/null +++ b/oops_test.c @@ -0,0 +1,52 @@ +/* + * This is a small test program for generating a kernel protection fault + * using the oops loadable module. + * + * Fri Apr 26 12:52:43 CDT 1996: Dr. Wettstein + * Initial version. + */ + + +/* Includes. */ +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + + +/* Function prototypes. */ +extern int main(int, char **); + + +extern int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int fd; + + if ( argc != 2 ) + { + fprintf(stderr, "No oops device specified.\n"); + return(1); + } + + if ( (fd = open(argv[1], O_RDONLY)) < 0 ) + { + fprintf(stderr, "Cannot open device: %s.\n", argv[1]); + return(1); + } + + if ( ioctl(fd, 1, 0) < 0 ) + { + fprintf(stderr, "Failed on oops.\n"); + return(1); + } + + printf("OOoops\n"); + + close(fd); + return(0); +} diff --git a/pidfile.c b/pidfile.c new file mode 100644 index 00000000..08520293 --- /dev/null +++ b/pidfile.c @@ -0,0 +1,130 @@ +/* + pidfile.c - interact with pidfiles + Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE> + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA +*/ + +/* + * Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze + * First version (v0.2) released + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <string.h> +#include <errno.h> +#include <signal.h> + +/* read_pid + * + * Reads the specified pidfile and returns the read pid. + * 0 is returned if either there's no pidfile, it's empty + * or no pid can be read. + */ +int read_pid (char *pidfile) +{ + FILE *f; + int pid; + + if (!(f=fopen(pidfile,"r"))) + return 0; + fscanf(f,"%d", &pid); + fclose(f); + return pid; +} + +/* check_pid + * + * Reads the pid using read_pid and looks up the pid in the process + * table (using /proc) to determine if the process already exists. If + * so 1 is returned, otherwise 0. + */ +int check_pid (char *pidfile) +{ + int pid = read_pid(pidfile); + + /* Amazing ! _I_ am already holding the pid file... */ + if ((!pid) || (pid == getpid ())) + return 0; + + /* + * The 'standard' method of doing this is to try and do a 'fake' kill + * of the process. If an ESRCH error is returned the process cannot + * be found -- GW + */ + /* But... errno is usually changed only on error.. */ + if (kill(pid, 0) && errno == ESRCH) + return(0); + + return pid; +} + +/* write_pid + * + * Writes the pid to the specified file. If that fails 0 is + * returned, otherwise the pid. + */ +int write_pid (char *pidfile) +{ + FILE *f; + int fd; + int pid; + + if ( ((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1) + || ((f = fdopen(fd, "r+")) == NULL) ) { + fprintf(stderr, "Can't open or create %s.\n", pidfile); + return 0; + } + + if (flock(fd, LOCK_EX|LOCK_NB) == -1) { + fscanf(f, "%d", &pid); + fclose(f); + printf("Can't lock, lock is held by pid %d.\n", pid); + return 0; + } + + pid = getpid(); + if (!fprintf(f,"%d\n", pid)) { + printf("Can't write pid , %s.\n", strerror(errno)); + close(fd); + return 0; + } + fflush(f); + + if (flock(fd, LOCK_UN) == -1) { + printf("Can't unlock pidfile %s, %s.\n", pidfile, strerror(errno)); + close(fd); + return 0; + } + close(fd); + + return pid; +} + +/* remove_pid + * + * Remove the the specified file. The result from unlink(2) + * is returned + */ +int remove_pid (char *pidfile) +{ + return unlink (pidfile); +} + diff --git a/pidfile.h b/pidfile.h new file mode 100644 index 00000000..19d19c16 --- /dev/null +++ b/pidfile.h @@ -0,0 +1,50 @@ +/* + pidfile.h - interact with pidfiles + Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE> + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. +*/ + +/* read_pid + * + * Reads the specified pidfile and returns the read pid. + * 0 is returned if either there's no pidfile, it's empty + * or no pid can be read. + */ +int read_pid (char *pidfile); + +/* check_pid + * + * Reads the pid using read_pid and looks up the pid in the process + * table (using /proc) to determine if the process already exists. If + * so 1 is returned, otherwise 0. + */ +int check_pid (char *pidfile); + +/* write_pid + * + * Writes the pid to the specified file. If that fails 0 is + * returned, otherwise the pid. + */ +int write_pid (char *pidfile); + +/* remove_pid + * + * Remove the the specified file. The result from unlink(2) + * is returned + */ +int remove_pid (char *pidfile); diff --git a/sysklogd.8 b/sysklogd.8 new file mode 100644 index 00000000..ccf1e654 --- /dev/null +++ b/sysklogd.8 @@ -0,0 +1,607 @@ +.\" Copyright 1994 Dr. Greg Wettstein, Enjellic Systems Development. +.\" May be distributed under the GNU General Public License +.\" Sun Aug 30 11:35:55 MET: Martin Schulze: Updates +.\" +.TH SYSKLOGD 8 "12 October 1998" "Version 1.3" "Linux System Administration" +.SH NAME +sysklogd \- Linux system logging utilities. +.SH SYNOPSIS +.B syslogd +.RB [ " \-a " +.I socket +] +.RB [ " \-d " ] +.RB [ " \-f " +.I config file +] +.RB [ " \-h " ] +.RB [ " \-l " +.I hostlist +] +.RB [ " \-m " +.I interval +] +.RB [ " \-n " ] +.RB [ " \-p" +.IB socket +] +.RB [ " \-r " ] +.RB [ " \-s " +.I domainlist +] +.RB [ " \-v " ] +.LP +.SH DESCRIPTION +.B Sysklogd +provides two system utilities which provide support for +system logging and kernel message trapping. Support of both internet and +unix domain sockets enables this utility package to support both local +and remote logging. + +System logging is provided by a version of +.BR syslogd (8) +derived from the +stock BSD sources. Support for kernel logging is provided by the +.BR klogd (8) +utility which allows kernel logging to be conducted in either a +standalone fashion or as a client of syslogd. + +.B Syslogd +provides a kind of logging that many modern programs use. Every logged +message contains at least a time and a hostname field, normally a +program name field, too, but that depends on how trusty the logging +program is. + +While the +.B syslogd +sources have been heavily modified a couple of notes +are in order. First of all there has been a systematic attempt to +insure that syslogd follows its default, standard BSD behavior. +The second important concept to note is that this version of syslogd +interacts transparently with the version of syslog found in the +standard libraries. If a binary linked to the standard shared +libraries fails to function correctly we would like an example of the +anomalous behavior. + +The main configuration file +.I /etc/syslog.conf +or an alternative file, given with the +.B "\-f" +option, is read at startup. Any lines that begin with the hash mark +(``#'') and empty lines are ignored. If an error occurs during parsing +the whole line is ignored. + +.LP +.SH OPTIONS +.TP +.BI "\-a " "socket" +Using this argument you can specify additional sockets from that +.B syslogd +has to listen to. This is needed if you're going to let some daemon +run within a chroot() environment. You can use up to 19 additional +sockets. If your environment needs even more, you have to increase +the symbol +.B MAXFUNIX +within the syslogd.c source file. An example for a chroot() daemon is +described by the people from OpenBSD at +http://www.psionic.com/papers/dns.html. +.TP +.B "\-d" +Turns on debug mode. Using this the daemon will not proceed a +.BR fork (2) +to set itself in the background, but opposite to that stay in the +foreground and write much debug information on the current tty. See the +DEBUGGING section for more information. +.TP +.BI "\-f " "config file" +Specify an alternative configuration file instead of +.IR /etc/syslog.conf "," +which is the default. +.TP +.BI "\-h " +By default syslogd will not forward messages it receives from remote hosts. +Specifying this switch on the command line will cause the log daemon to +forward any remote messages it receives to forwarding hosts which have been +defined. +.TP +.BI "\-l " "hostlist" +Specify a hostname that should be logged only with its simple hostname +and not the fqdn. Multiple hosts may be specified using the colon +(``:'') separator. +.TP +.BI "\-m " "interval" +The +.B syslogd +logs a mark timestamp regularly. The default +.I interval +between two \fI-- MARK --\fR lines is 20 minutes. This can be changed +with this option. Setting the +.I interval +to zero turns it off entirely. +.TP +.B "\-n" +Avoid auto-backgrounding. This is needed especially if the +.B syslogd +is started and controlled by +.BR init (8). +.TP +.BI "\-p " "socket" +You can specify an alternative unix domain socket instead of +.IR /dev/log "." +.TP +.B "\-r" +This option will enable the facility to receive message from the +network using an internet domain socket with the syslog service (see +.BR services (5)). +The default is to not receive any messages from the network. + +This option is introduced in version 1.3 of the sysklogd +package. Please note that the default behavior is the opposite of +how older versions behave, so you might have to turn this on. +.TP +.BI "\-s " "domainlist" +Specify a domainname that should be stripped off before +logging. Multiple domains may be specified using the colon (``:'') +separator. +Please be advised that no sub-domains may be specified but only entire +domains. For example if +.B "\-s north.de" +is specified and the host logging resolves to satu.infodrom.north.de +no domain would be cut, you will have to specify two domains like: +.BR "\-s north.de:infodrom.north.de" . +.TP +.B "\-v" +Print version and exit. +.LP +.SH SIGNALS +.B Syslogd +reacts to a set of signals. You may easily send a signal to +.B syslogd +using the following: +.IP +.nf +kill -SIGNAL `cat /var/run/syslogd.pid` +.fi +.PP +.TP +.B SIGHUP +This lets +.B syslogd +perform a re-initialization. All open files are closed, the +configuration file (default is +.IR /etc/syslog.conf ")" +will be reread and the +.BR syslog (3) +facility is started again. +.TP +.B SIGTERM +The +.B syslogd +will die. +.TP +.BR SIGINT ", " SIGQUIT +If debugging is enabled these are ignored, otherwise +.B syslogd +will die. +.TP +.B SIGUSR1 +Switch debugging on/off. This option can only be used if +.B syslogd +is started with the +.B "\-d" +debug option. +.TP +.B SIGCHLD +Wait for childs if some were born, because of wall'ing messages. +.LP +.SH CONFIGURATION FILE SYNTAX DIFFERENCES +.B Syslogd +uses a slightly different syntax for its configuration file than +the original BSD sources. Originally all messages of a specific priority +and above were forwarded to the log file. +.IP +For example the following line caused ALL output from daemons using +the daemon facilities (debug is the lowest priority, so every higher +will also match) to go into +.IR /usr/adm/daemons : +.IP +.nf + # Sample syslog.conf + daemon.debug /usr/adm/daemons +.fi +.PP +Under the new scheme this behavior remains the same. The difference +is the addition of four new specifiers, the asterisk (\fB*\fR) +wildcard, the equation sign (\fB=\fR), the exclamation mark +(\fB!\fR), and the minus sign (\fB-\fR). + +The \fB*\fR specifies that all messages for the +specified facility are to be directed to the destination. Note that +this behavior is degenerate with specifying a priority level of debug. +Users have indicated that the asterisk notation is more intuitive. + +The \fB=\fR wildcard is used to restrict logging to the specified priority +class. This allows, for example, routing only debug messages to a +particular logging source. +.IP +For example the following line in +.I syslog.conf +would direct debug messages from all sources to the +.I /usr/adm/debug +file. +.IP +.nf + # Sample syslog.conf + *.=debug /usr/adm/debug +.fi +.PP +.\" The \fB!\fR as the first character of a priority inverts the above +.\" mentioned interpretation. +The \fB!\fR is used to exclude logging of the specified +priorities. This affects all (!) possibilities of specifying priorities. +.IP +For example the following lines would log all messages of the facility +mail except those with the priority info to the +.I /usr/adm/mail +file. And all messages from news.info (including) to news.crit +(excluding) would be logged to the +.I /usr/adm/news +file. +.IP +.nf + # Sample syslog.conf + mail.*;mail.!=info /usr/adm/mail + news.info;news.!crit /usr/adm/news +.fi +.PP +You may use it intuitively as an exception specifier. The above +mentioned interpretation is simply inverted. Doing that you may use + +.nf + mail.none +.fi +or +.nf + mail.!* +.fi +or +.nf + mail.!debug +.fi + +to skip every message that comes with a mail facility. There is much +room to play with it. :-) + +The \fB-\fR may only be used to prefix a filename if you want to omit +sync'ing the file after every write to it. + +This may take some acclimatization for those individuals used to the +pure BSD behavior but testers have indicated that this syntax is +somewhat more flexible than the BSD behavior. Note that these changes +should not affect standard +.BR syslog.conf (5) +files. You must specifically +modify the configuration files to obtain the enhanced behavior. +.LP +.SH SUPPORT FOR REMOTE LOGGING +These modifications provide network support to the syslogd facility. +Network support means that messages can be forwarded from one node +running syslogd to another node running syslogd where they will be +actually logged to a disk file. + +To enable this you have to specify the +.B "\-r" +option on the command line. The default behavior is that +.B syslogd +won't listen to the network. + +The strategy is to have syslogd listen on a unix domain socket for +locally generated log messages. This behavior will allow syslogd to +inter-operate with the syslog found in the standard C library. At the +same time syslogd listens on the standard syslog port for messages +forwarded from other hosts. To have this work correctly the +.BR services (5) +files (typically found in +.IR /etc ) +must have the following +entry: +.IP +.nf + syslog 514/udp +.fi +.PP +If this entry is missing +.B syslogd +neither can receive remote messages nor send them, because the UDP +port cant be opened. Instead +.B syslogd +will die immediately, blowing out an error message. + +To cause messages to be forwarded to another host replace +the normal file line in the +.I syslog.conf +file with the name of the host to which the messages is to be sent +prepended with an @. +.IP +For example, to forward +.B ALL +messages to a remote host use the +following +.I syslog.conf +entry: +.IP +.nf + # Sample syslogd configuration file to + # messages to a remote host forward all. + *.* @hostname +.fi + +To forward all \fBkernel\fP messages to a remote host the +configuration file would be as follows: +.IP +.nf + # Sample configuration file to forward all kernel + # messages to a remote host. + kern.* @hostname +.fi +.PP + +If the remote hostname cannot be resolved at startup, because the +name-server might not be accessible (it may be started after syslogd) +you don't have to worry. +.B Syslogd +will retry to resolve the name ten times and then complain. Another +possibility to avoid this is to place the hostname in +.IR /etc/hosts . + +With normal +.BR syslogd s +you would get syslog-loops if you send out messages that were received +from a remote host to the same host (or more complicated to a third +host that sends it back to the first one, and so on). In my domain +(Infodrom Oldenburg) we accidently got one and our disks filled up +with the same single message. :-( + +To avoid this in further times no messages that were received from a +remote host are sent out to another (or the same) remote host +anymore. If there are scenarios where this doesn't make sense, please +drop me (Joey) a line. + +If the remote host is located in the same domain as the host, +.B syslogd +is running on, only the simple hostname will be logged instead of +the whole fqdn. + +In a local network you may provide a central log server to have all +the important information kept on one machine. If the network consists +of different domains you don't have to complain about logging fully +qualified names instead of simple hostnames. You may want to use the +strip-domain feature +.B \-s +of this server. You can tell the +.B syslogd +to strip off several domains other than the one the server is located +in and only log simple hostnames. + +Using the +.B \-l +option there's also a possibility to define single hosts as local +machines. This, too, results in logging only their simple hostnames +and not the fqdns. + +The UDP socket used to forward messages to remote hosts or to receive +messages from them is only opened when it is needed. In releases +prior to 1.3-23 it was opened every time but not opened for reading or +forwarding respectively. + +.SH OUTPUT TO NAMED PIPES (FIFOs) +This version of syslogd has support for logging output to named pipes +(fifos). A fifo or named pipe can be used as a destination for log +messages by prepending a pipy symbol (``|'') to the name of the +file. This is handy for debugging. Note that the fifo must be created +with the mkfifo command before syslogd is started. +.IP +The following configuration file routes debug messages from the +kernel to a fifo: +.IP +.nf + # Sample configuration to route kernel debugging + # messages ONLY to /usr/adm/debug which is a + # named pipe. + kern.=debug |/usr/adm/debug +.fi +.LP +.SH INSTALLATION CONCERNS +There is probably one important consideration when installing this +version of syslogd. This version of syslogd is dependent on proper +formatting of messages by the syslog function. The functioning of the +syslog function in the shared libraries changed somewhere in the +region of libc.so.4.[2-4].n. The specific change was to +null-terminate the message before transmitting it to the +.I /dev/log +socket. Proper functioning of this version of syslogd is dependent on +null-termination of the message. + +This problem will typically manifest itself if old statically linked +binaries are being used on the system. Binaries using old versions of +the syslog function will cause empty lines to be logged followed by +the message with the first character in the message removed. +Relinking these binaries to newer versions of the shared libraries +will correct this problem. + +Both the +.BR syslogd "(8) and the " klogd (8) +can either be run from +.BR init (8) +or started as part of the rc.* +sequence. If it is started from init the option \fI\-n\fR must be set, +otherwise you'll get tons of syslog daemons started. This is because +.BR init (8) +depends on the process ID. +.LP +.SH SECURITY THREATS +There is the potential for the syslogd daemon to be +used as a conduit for a denial of service attack. Thanks go to John +Morrison (jmorriso@rflab.ee.ubc.ca) for alerting me to this potential. +A rogue program(mer) could very easily flood the syslogd daemon with +syslog messages resulting in the log files consuming all the remaining +space on the filesystem. Activating logging over the inet domain +sockets will of course expose a system to risks outside of programs or +individuals on the local machine. + +There are a number of methods of protecting a machine: +.IP 1. +Implement kernel firewalling to limit which hosts or networks have +access to the 514/UDP socket. +.IP 2. +Logging can be directed to an isolated or non-root filesystem which, +if filled, will not impair the machine. +.IP 3. +The ext2 filesystem can be used which can be configured to limit a +certain percentage of a filesystem to usage by root only. \fBNOTE\fP +that this will require syslogd to be run as a non-root process. +\fBALSO NOTE\fP that this will prevent usage of remote logging since +syslogd will be unable to bind to the 514/UDP socket. +.IP 4. +Disabling inet domain sockets will limit risk to the local machine. +.IP 5. +Use step 4 and if the problem persists and is not secondary to a rogue +program/daemon get a 3.5 ft (approx. 1 meter) length of sucker rod* +and have a chat with the user in question. + +Sucker rod def. \(em 3/4, 7/8 or 1in. hardened steel rod, male +threaded on each end. Primary use in the oil industry in Western +North Dakota and other locations to pump 'suck' oil from oil wells. +Secondary uses are for the construction of cattle feed lots and for +dealing with the occasional recalcitrant or belligerent individual. +.LP +.SH DEBUGGING +When debugging is turned on using +.B "\-d" +option then +.B syslogd +will be very verbose by writing much of what it does on stdout. Whenever +the configuration file is reread and re-parsed you'll see a tabular, +corresponding to the internal data structure. This tabular consists of +four fields: +.TP +.I number +This field contains a serial number starting by zero. This number +represents the position in the internal data structure (i.e. the +array). If one number is left out then there might be an error in the +corresponding line in +.IR /etc/syslog.conf . +.TP +.I pattern +This field is tricky and represents the internal structure +exactly. Every column stands for a facility (refer to +.BR syslog (3)). +As you can see, there are still some facilities left free for former +use, only the left most are used. Every field in a column represents +the priorities (refer to +.BR syslog (3)). +.TP +.I action +This field describes the particular action that takes place whenever a +message is received that matches the pattern. Refer to the +.BR syslog.conf (5) +manpage for all possible actions. +.TP +.I arguments +This field shows additional arguments to the actions in the last +field. For file-logging this is the filename for the logfile; for +user-logging this is a list of users; for remote logging this is the +hostname of the machine to log to; for console-logging this is the +used console; for tty-logging this is the specified tty; wall has no +additional arguments. +.SH FILES +.PD 0 +.TP +.I /etc/syslog.conf +Configuration file for +.BR syslogd . +See +.BR syslog.conf (5) +for exact information. +.TP +.I /dev/log +The Unix domain socket to from where local syslog messages are read. +.TP +.I /var/run/syslogd.pid +The file containing the process id of +.BR syslogd . +.PD +.SH BUGS +If an error occurs in one line the whole rule is ignored. + +.B Syslogd +doesn't change the filemode of opened logfiles at any stage of +process. If a file is created it is world readable. If you want to +avoid this, you have to create it and change permissions on your own. +This could be done in combination with rotating logfiles using the +.BR savelog (8) +program that is shipped in the +.B smail +3.x distribution. Remember that it might be a security hole if +everybody is able to read auth.* messages as these might contain +passwords. +.LP +.SH SEE ALSO +.BR syslog.conf (5), +.BR klogd (8), +.BR logger (1), +.BR syslog (2), +.BR syslog (3), +.BR services (5), +.BR savelog (8) +.LP +.SH COLLABORATORS +.B Syslogd +is taken from BSD sources, Greg Wettstein (greg@wind.enjellic.com) +performed the port to Linux, Martin Schulze (joey@linux.de) +fixed some bugs and added several new features. +.B Klogd +was originally written by Steve Lord (lord@cray.com), Greg Wettstein +made major improvements. + +.PD 0 +.TP +Dr. Greg Wettstein +.TP +Enjellic Systems Development +.TP +Oncology Research Division Computing Facility +.TP +Roger Maris Cancer Center +.TP +Fargo, ND +.TP +greg@wind.enjellic.com + +.TP +Stephen Tweedie +.TP +Department of Computer Science +.TP +Edinburgh University, Scotland +.TP +sct@dcs.ed.ac.uk + +.TP +Juha Virtanen +.TP +jiivee@hut.fi + +.TP +Shane Alderton +.TP +shane@ion.apana.org.au + +.TP +Martin Schulze +.TP +Infodrom Oldenburg +.TP +joey@linux.de +.PD +.zZ diff --git a/syslog-tst.conf b/syslog-tst.conf new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/syslog-tst.conf diff --git a/syslog.c b/syslog.c new file mode 100644 index 00000000..0d63c81d --- /dev/null +++ b/syslog.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that: (1) source distributions retain this entire copyright notice and + * comment, and (2) distributions including binaries display the following + * acknowledgement: ``This product includes software developed by the + * University of California, Berkeley and its contributors'' in the + * documentation or other materials provided with the distribution and in + * all advertising materials mentioning features or use of this software. + * Neither the name of the University nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)syslog.c 5.28 (Berkeley) 6/27/90"; +#endif /* LIBC_SCCS and not lint */ + +/* + * SYSLOG -- print message on log file + * + * This routine looks a lot like printf, except that it outputs to the + * log file instead of the standard output. Also: + * adds a timestamp, + * prints the module name in front of the message, + * has some other formatting types (or will sometime), + * adds a newline on the end of the message. + * + * The output of this routine is intended to be read by syslogd(8). + * + * Author: Eric Allman + * Modified to use UNIX domain IPC by Ralph Campbell + * + * Sat Dec 11 11:58:31 CST 1993: Dr. Wettstein + * Changes to allow compilation with no complains under -Wall. + * + * Thu Jan 18 11:16:11 CST 1996: Dr. Wettstein + * Added patch to close potential security hole. This is the same + * patch which was announced in the linux-security mailing lists + * and incorporated into the libc version of syslog.c. + * + * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de> + * Use SOCK_DGRAM for loggin, renables it to work. + * + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/signal.h> +#include <sys/syslog.h> +#if 0 +#include "syslog.h" +#include "pathnames.h" +#endif + +#include <sys/uio.h> +#include <sys/wait.h> +#include <netdb.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <stdarg.h> +#include <paths.h> +#include <stdio.h> + +#define _PATH_LOGNAME "/dev/log" + +static int LogFile = -1; /* fd for log */ +static int connected; /* have done connect */ +static int LogStat = 0; /* status bits, set by openlog() */ +static const char *LogTag = "syslog"; /* string to tag the entry with */ +static int LogFacility = LOG_USER; /* default facility code */ + +void +syslog(int pri, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(pri, fmt, ap); + va_end(ap); +} + +void +vsyslog(pri, fmt, ap) + int pri; + const char *fmt; + va_list ap; +{ + register int cnt; + register char *p; + time_t now; + int fd, saved_errno; + char tbuf[2048], fmt_cpy[1024], *stdp = (char *) 0; + + saved_errno = errno; + + /* see if we should just throw out this message */ + if (!LOG_MASK(LOG_PRI(pri)) || (pri &~ (LOG_PRIMASK|LOG_FACMASK))) + return; + if (LogFile < 0 || !connected) + openlog(LogTag, LogStat | LOG_NDELAY, LogFacility); + + /* set default facility if none specified */ + if ((pri & LOG_FACMASK) == 0) + pri |= LogFacility; + + /* build the message */ + (void)time(&now); + (void)sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4); + for (p = tbuf; *p; ++p); + if (LogStat & LOG_PERROR) + stdp = p; + if (LogTag) { + (void)strcpy(p, LogTag); + for (; *p; ++p); + } + if (LogStat & LOG_PID) { + (void)sprintf(p, "[%d]", getpid()); + for (; *p; ++p); + } + if (LogTag) { + *p++ = ':'; + *p++ = ' '; + } + + /* substitute error message for %m */ + { + register char ch, *t1, *t2; + char *strerror(); + + for (t1 = fmt_cpy; + (ch = *fmt) != '\0' && t1<fmt_cpy+sizeof(fmt_cpy); + ++fmt) + if (ch == '%' && fmt[1] == 'm') { + ++fmt; + for (t2 = strerror(saved_errno); + (*t1 = *t2++); ++t1); + } + else + *t1++ = ch; + *t1 = '\0'; + } + + (void)vsprintf(p, fmt_cpy, ap); + + cnt = strlen(tbuf); + + /* output to stderr if requested */ + if (LogStat & LOG_PERROR) { + struct iovec iov[2]; + register struct iovec *v = iov; + + v->iov_base = stdp; + v->iov_len = cnt - (stdp - tbuf); + ++v; + v->iov_base = "\n"; + v->iov_len = 1; + (void)writev(2, iov, 2); + } + + /* output the message to the local logger */ + if (write(LogFile, tbuf, cnt + 1) >= 0 || !(LogStat&LOG_CONS)) + return; + + /* + * output the message to the console; don't worry about + * blocking, if console blocks everything will. + */ + if ((fd = open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) < 0) + return; + (void)strcat(tbuf, "\r\n"); + cnt += 2; + p = index(tbuf, '>') + 1; + (void)write(fd, p, cnt - (p - tbuf)); + (void)close(fd); +} + +#ifndef TESTING +static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */ +#endif +/* + * OPENLOG -- open system log + */ +void +openlog(ident, logstat, logfac) + const char *ident; + int logstat, logfac; +{ + if (ident != NULL) + LogTag = ident; + LogStat = logstat; + +#ifdef ALLOW_KERNEL_LOGGING + if ((logfac &~ LOG_FACMASK) == 0) +#else + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) +#endif + LogFacility = logfac; + +#ifndef TESTING + if (LogFile == -1) { + SyslogAddr.sa_family = AF_UNIX; + strncpy(SyslogAddr.sa_data, _PATH_LOGNAME, + sizeof(SyslogAddr.sa_data)); + if (LogStat & LOG_NDELAY) { + LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); +/* fcntl(LogFile, F_SETFD, 1); */ + } + } + if (LogFile != -1 && !connected && + connect(LogFile, &SyslogAddr, sizeof(SyslogAddr.sa_family)+ + strlen(SyslogAddr.sa_data)) != -1) +#else + LogFile = fileno(stdout); +#endif + connected = 1; +} + +/* + * CLOSELOG -- close the system log + */ +void +closelog() +{ +#ifndef TESTING + (void) close(LogFile); +#endif + LogFile = -1; + connected = 0; +} + +static int LogMask = 0xff; /* mask of priorities to be logged */ +/* + * SETLOGMASK -- set the log mask level + */ +int +setlogmask(pmask) + int pmask; +{ + int omask; + + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + return (omask); +} diff --git a/syslog.conf b/syslog.conf new file mode 100644 index 00000000..801f35fb --- /dev/null +++ b/syslog.conf @@ -0,0 +1,46 @@ +# /etc/syslog.conf - Configuration file for syslogd(8) +# +# For info about the format of this file, see "man syslog.conf". +# +*.=debug -/usr/adm/debug +*.warning /usr/adm/syslog + +# Store critical stuff in critical +# +*.=crit;kern.none /var/adm/critical + +# Kernel messages are first, stored in the kernel file, +# critical messages and higher ones also go to another +# host and to the console +# +kern.* /var/adm/kernel +kern.crit @finlandia +kern.crit /dev/console +kern.info;kern.!err /var/adm/kernel-info + +# The tcp wrapper loggs with mail.info, we display all +# the connections on tty12 +# +mail.=info /dev/tty12 + +# Store all mail concearning stuff in a file +# +mail.*;mail.!=info -/var/adm/mail + +# Log all mail.info and news.info messages to info +# +mail,news.=info -/var/adm/info + +# Log info and notice mesages to messages file +# +*.=info;*.=notice;mail.none -/usr/adm/messages +#*.=info;mail,news.none -/usr/adm/messages + +# Emergency messages will be displayed using wall +# +*.=emerg * + +# Messages of the priority alert will be directed +# to the operator +# +*.alert root,joey diff --git a/syslog.conf.5 b/syslog.conf.5 new file mode 100644 index 00000000..7f40c1cb --- /dev/null +++ b/syslog.conf.5 @@ -0,0 +1,397 @@ +.\" syslog.conf - syslogd(8) configuration file +.\" Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE> +.\" +.\" This file is part of the sysklogd package, a kernel and system log daemon. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. +.\" +.TH SYSLOG.CONF 5 "1 January 1998" "Version 1.3" "Linux System Administration" +.SH NAME +syslog.conf \- syslogd(8) configuration file +.SH DESCRIPTION +The +.I syslog.conf +file is the main configuration file for the +.BR syslogd (8) +which logs system messages on *nix systems. This file specifies rules +for logging. For special features see the +.BR sysklogd (8) +manpage. + +Every rule consists of two fields, a +.I selector +field and an +.I action +field. These two fields are separated by one or more spaces or +tabs. The selector field specifies a pattern of facilities and +priorities belonging to the specified action. + +Lines starting with a hash mark (``#'') and empty lines are ignored. + +This release of +.B syslogd +is able to understand an extended syntax. One rule can be divided +into several lines if the leading line is terminated with an backslash +(``\\''). + +.SH SELECTORS +The selector field itself again consists of two parts, a +.I facility +and a +.IR priority , +separated by a period (``.''). +Both parts are case insensitive and can also be specified as decimal +numbers, but don't do that, you have been warned. Both facilities and +priorities are described in +.BR syslog (3). +The names mentioned below correspond to the similar +.BR LOG_ -values +in +.IR /usr/include/syslog.h . + +The +.I facility +is one of the following keywords: +.BR auth ", " authpriv ", " cron ", " daemon ", " kern ", " lpr ", " +.BR mail ", " mark ", " news ", " security " (same as " auth "), " +.BR syslog ", " user ", " uucp " and " local0 " through " local7 . +The keyword +.B security +should not be used anymore and +.B mark +is only for internal use and therefore should not be used in +applications. Anyway, you may want to specify and redirect these +messages here. The +.I facility +specifies the subsystem that produced the message, i.e. all mail +programs log with the mail facility +.BR "" ( LOG_MAIL ) +if they log using syslog. + +The +.I priority +is one of the following keywords, in ascending order: +.BR debug ", " info ", " notice ", " warning ", " warn " (same as " +.BR warning "), " err ", " error " (same as " err "), " crit ", " +.BR alert ", " emerg ", " panic " (same as " emerg ). +The keywords +.BR error ", " warn " and " panic +are deprecated and should not be used anymore. The +.I priority +defines the severity of the message + +The behavior of the original BSD syslogd is that all messages of the +specified priority and higher are logged according to the given +action. This +.BR syslogd (8) +behaves the same, but has some extensions. + +In addition to the above mentioned names the +.BR syslogd (8) +understands the following extensions: An asterisk (``*'') stands for +all facilities or all priorities, depending on where it is used +(before or after the period). The keyword +.B none +stands for no priority of the given facility. + +You can specify multiple facilities with the same priority pattern in +one statement using the comma (``,'') operator. You may specify as +much facilities as you want. Remember that only the facility part from +such a statement is taken, a priority part would be skipped. + +Multiple selectors may be specified for a single +.I action +using the semicolon (``;'') separator. Remember that each selector in +the +.I selector +field is capable to overwrite the preceding ones. Using this +behavior you can exclude some priorities from the pattern. + +This +.BR syslogd (8) +has a syntax extension to the original BSD source, that makes its use +more intuitively. You may precede every priority with an equation sign +(``='') to specify only this single priority and not any of the +above. You may also (both is valid, too) precede the priority with an +exclamation mark (``!'') to ignore all that priorities, either exact +this one or this and any higher priority. If you use both extensions +than the exclamation mark must occur before the equation sign, just +use it intuitively. + +.SH ACTIONS +The action field of a rule describes the abstract term +``logfile''. A ``logfile'' need not to be a real file, btw. The +.BR syslogd (8) +provides the following actions. + +.SS Regular File +Typically messages are logged to real files. The file has to be +specified with full pathname, beginning with a slash ``/''. + +You may prefix each entry with the minus ``-'' sign to omit syncing +the file after every logging. Note that you might lose information if +the system crashes right behind a write attempt. Nevertheless this +might give you back some performance, especially if you run programs +that use logging in a very verbose manner. + +.SS Named Pipes +This version of +.BR syslogd (8) +has support for logging output to +named pipes (fifos). A fifo or named pipe can be used as +a destination for log messages by prepending a pipe symbol (``|'') to +the name of the file. This is handy for debugging. Note that the fifo +must be created with the +.BR mkfifo (1) +command before +.BR syslogd (8) +is started. + +.SS Terminal and Console +If the file you specified is a tty, special tty-handling is done, same +with +.IR /dev/console . + +.SS Remote Machine +This +.BR syslogd (8) +provides full remote logging, i.e. is able to send messages to a +remote host running +.BR syslogd (8) +and to receive messages from remote hosts. The remote +host won't forward the message again, it will just log them +locally. To forward messages to another host, prepend the hostname +with the at sign (``@''). + +Using this feature you're able to control all syslog messages on one +host, if all other machines will log remotely to that. This tears down +administration needs. + +.SS List of Users +Usually critical messages are also directed to ``root'' on that +machine. You can specify a list of users that shall get the message by +simply writing the login. You may specify more than one user by +separating them with commas (``,''). If they're logged in they +get the message. Don't think a mail would be sent, that might be too +late. + +.SS Everyone logged on +Emergency messages often go to all users currently online to notify +them that something strange is happening with the system. To specify +this +.IR wall (1)-feature +use an asterisk (``*''). + +.SH EXAMPLES +Here are some example, partially taken from a real existing site and +configuration. Hopefully they rub out all questions to the +configuration, if not, drop me (Joey) a line. +.IP +.nf +# Store critical stuff in critical +# +*.=crit;kern.none /var/adm/critical +.fi +.LP +This will store all messages with the priority +.B crit +in the file +.IR /var/adm/critical , +except for any kernel message. + +.IP +.nf +# Kernel messages are first, stored in the kernel +# file, critical messages and higher ones also go +# to another host and to the console +# +kern.* /var/adm/kernel +kern.crit @finlandia +kern.crit /dev/console +kern.info;kern.!err /var/adm/kernel-info +.fi +.LP +The first rule direct any message that has the kernel facility to the +file +.IR /var/adm/kernel . + +The second statement directs all kernel messages of the priority +.B crit +and higher to the remote host finlandia. This is useful, because if +the host crashes and the disks get irreparable errors you might not be +able to read the stored messages. If they're on a remote host, too, +you still can try to find out the reason for the crash. + +The third rule directs these messages to the actual console, so the +person who works on the machine will get them, too. + +The fourth line tells the syslogd to save all kernel messages that +come with priorities from +.BR info " up to " warning +in the file +.IR /var/adm/kernel-info . +Everything from +.I err +and higher is excluded. + +.IP +.nf +# The tcp wrapper loggs with mail.info, we display +# all the connections on tty12 +# +mail.=info /dev/tty12 +.fi +.LP +This directs all messages that uses +.BR mail.info " (in source " LOG_MAIL " | " LOG_INFO ) +to +.IR /dev/tty12 , +the 12th console. For example the tcpwrapper +.BR tcpd (8) +uses this as it's default. + +.IP +.nf +# Store all mail concerning stuff in a file +# +mail.*;mail.!=info /var/adm/mail +.fi +.LP +This pattern matches all messages that come with the +.B mail +facility, except for the +.B info +priority. These will be stored in the file +.IR /var/adm/mail . + +.IP +.nf +# Log all mail.info and news.info messages to info +# +mail,news.=info /var/adm/info +.fi +.LP +This will extract all messages that come either with +.BR mail.info " or with " news.info +and store them in the file +.IR /var/adm/info . + +.IP +.nf +# Log info and notice messages to messages file +# +*.=info;*.=notice;\\ + mail.none /var/log/messages +.fi +.LP +This lets the +.B syslogd +log all messages that come with either the +.BR info " or the " notice +facility into the file +.IR /var/log/messages , +except for all messages that use the +.B mail +facility. + +.IP +.nf +# Log info messages to messages file +# +*.=info;\\ + mail,news.none /var/log/messages +.fi +.LP +This statement causes the +.B syslogd +to log all messages that come with the +.B info +priority to the file +.IR /var/log/messages . +But any message coming either with the +.BR mail " or the " news +facility will not be stored. + +.IP +.nf +# Emergency messages will be displayed using wall +# +*.=emerg * +.fi +.LP +This rule tells the +.B syslogd +to write all emergency messages to all currently logged in users. This +is the wall action. + +.IP +.nf +# Messages of the priority alert will be directed +# to the operator +# +*.alert root,joey +.fi +.LP +This rule directs all messages with a priority of +.B alert +or higher to the terminals of the operator, i.e. of the users ``root'' +and ``joey'' if they're logged in. + +.IP +.nf +*.* @finlandia +.fi +.LP +This rule would redirect all messages to a remote host called +finlandia. This is useful especially in a cluster of machines where +all syslog messages will be stored on only one machine. + +.SH CONFIGURATION FILE SYNTAX DIFFERENCES +.B Syslogd +uses a slightly different syntax for its configuration file than +the original BSD sources. Originally all messages of a specific priority +and above were forwarded to the log file. The modifiers ``='', ``!'' +and ``-'' were added to make the +.B syslogd +more flexible and to use it in a more intuitive manner. + +The original BSD syslogd doesn't understand spaces as separators between +the selector and the action field. +.SH FILES +.PD 0 +.TP +.I /etc/syslog.conf +Configuration file for +.B syslogd + +.SH BUGS +The effects of multiple selectors are sometimes not intuitive. For +example ``mail.crit,*.err'' will select ``mail'' facility messages at +the level of ``err'' or higher, not at the level of ``crit'' or +higher. + +.SH SEE ALSO +.BR sysklogd (8), +.BR klogd (8), +.BR logger (1), +.BR syslog (2), +.BR syslog (3) + +.SH AUTHORS +The +.B syslogd +is taken from BSD sources, Greg Wettstein (greg@wind.enjellic.com) +performed the port to Linux, Martin Schulze (joey@linux.de) +made some bugfixes and added some new features. diff --git a/syslog_tst.c b/syslog_tst.c new file mode 100644 index 00000000..ca786018 --- /dev/null +++ b/syslog_tst.c @@ -0,0 +1,74 @@ +/* Program to test daemon logging. */ + +/* + * Sat Dec 11 12:07:50 CST 1993: Dr. Wettstein + * Compiles clean with -Wall. Renamed for first public distribution. + * Use this freely but if you make a ton of money with it I + * expect a cut... :-) + * + * Thu Jan 6 11:52:10 CST 1994: Dr. Wettstein + * Added support for reading getting log input from the standard + * input. To activate this use a - as the single arguement to the + * the program. Note that there is a hack in the code to pause + * after each 1K has been written. This eliminates what appears + * to be a problem with overrunning a UNIX domain socket with + * excessive amounts of input. + */ + +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/param.h> + +extern int main(int, char **); + + +int main(int argc, char *argv[]) +{ + auto char *nl, + bufr[512]; + auto int logged = 0; + + openlog("DOTEST", LOG_PID, LOG_DAEMON); + if (argc > 1) + { + if ( (*argv[1] == '-') && (*(argv[1]+1) == '\0') ) + { + while (!feof(stdin)) + if ( fgets(bufr, sizeof(bufr), stdin) != \ + (char *) 0 ) + { + if ( (nl = strrchr(bufr, '\n')) != \ + (char *) 0) + *nl = '\0'; + syslog(LOG_INFO, bufr); + logged += strlen(bufr); + if ( logged > 1024 ) + { + sleep(1); + logged = 0; + } + + } + } + else + while (argc-- > 1) + syslog(LOG_INFO, argv++[1]); + } + else + { + syslog(LOG_EMERG, "EMERG log."); + syslog(LOG_ALERT, "Alert log."); + syslog(LOG_CRIT, "Critical log."); + syslog(LOG_ERR, "Error log."); + syslog(LOG_WARNING, "Warning log."); + syslog(LOG_NOTICE, "Notice log."); + syslog(LOG_INFO, "Info log."); + syslog(LOG_DEBUG, "Debug log."); + closelog(); + return(0); + } + + return(0); +} diff --git a/syslogd.8 b/syslogd.8 new file mode 100644 index 00000000..d5ef84b6 --- /dev/null +++ b/syslogd.8 @@ -0,0 +1 @@ +.so man8/sysklogd.8 diff --git a/syslogd.c b/syslogd.c new file mode 100644 index 00000000..4c2014f6 --- /dev/null +++ b/syslogd.c @@ -0,0 +1,2803 @@ +/* + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if !defined(lint) && !defined(NO_SCCS) +char copyright2[] = +"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#if !defined(lint) && !defined(NO_SCCS) +static char sccsid[] = "@(#)syslogd.c 5.27 (Berkeley) 10/10/88"; +#endif /* not lint */ + +/* + * syslogd -- log system messages + * + * This program implements a system log. It takes a series of lines. + * Each line may have a priority, signified as "<n>" as + * the first characters of the line. If this is + * not present, a default priority is used. + * + * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will + * cause it to reread its configuration file. + * + * Defined Constants: + * + * MAXLINE -- the maximum line length that can be handled. + * DEFUPRI -- the default priority for user messages + * DEFSPRI -- the default priority for kernel messages + * + * Author: Eric Allman + * extensive changes by Ralph Campbell + * more extensive changes by Eric Allman (again) + * + * Steve Lord: Fix UNIX domain socket code, added linux kernel logging + * change defines to + * SYSLOG_INET - listen on a UDP socket + * SYSLOG_UNIXAF - listen on unix domain socket + * SYSLOG_KERNEL - listen to linux kernel + * + * Mon Feb 22 09:55:42 CST 1993: Dr. Wettstein + * Additional modifications to the source. Changed priority scheme + * to increase the level of configurability. In its stock configuration + * syslogd no longer logs all messages of a certain priority and above + * to a log file. The * wildcard is supported to specify all priorities. + * Note that this is a departure from the BSD standard. + * + * Syslogd will now listen to both the inetd and the unixd socket. The + * strategy is to allow all local programs to direct their output to + * syslogd through the unixd socket while the program listens to the + * inetd socket to get messages forwarded from other hosts. + * + * Fri Mar 12 16:55:33 CST 1993: Dr. Wettstein + * Thanks to Stephen Tweedie (dcs.ed.ac.uk!sct) for helpful bug-fixes + * and an enlightened commentary on the prioritization problem. + * + * Changed the priority scheme so that the default behavior mimics the + * standard BSD. In this scenario all messages of a specified priority + * and above are logged. + * + * Add the ability to specify a wildcard (=) as the first character + * of the priority name. Doing this specifies that ONLY messages with + * this level of priority are to be logged. For example: + * + * *.=debug /usr/adm/debug + * + * Would log only messages with a priority of debug to the /usr/adm/debug + * file. + * + * Providing an * as the priority specifies that all messages are to be + * logged. Note that this case is degenerate with specifying a priority + * level of debug. The wildcard * was retained because I believe that + * this is more intuitive. + * + * Thu Jun 24 11:34:13 CDT 1993: Dr. Wettstein + * Modified sources to incorporate changes in libc4.4. Messages from + * syslog are now null-terminated, syslogd code now parses messages + * based on this termination scheme. Linux as of libc4.4 supports the + * fsync system call. Modified code to fsync after all writes to + * log files. + * + * Sat Dec 11 11:59:43 CST 1993: Dr. Wettstein + * Extensive changes to the source code to allow compilation with no + * complaints with -Wall. + * + * Reorganized the facility and priority name arrays so that they + * compatible with the syslog.h source found in /usr/include/syslog.h. + * NOTE that this should really be changed. The reason I do not + * allow the use of the values defined in syslog.h is on account of + * the extensions made to allow the wildcard character in the + * priority field. To fix this properly one should malloc an array, + * copy the contents of the array defined by syslog.h and then + * make whatever modifications that are desired. Next round. + * + * Thu Jan 6 12:07:36 CST 1994: Dr. Wettstein + * Added support for proper decomposition and re-assembly of + * fragment messages on UNIX domain sockets. Lack of this capability + * was causing 'partial' messages to be output. Since facility and + * priority information is encoded as a leader on the messages this + * was causing lines to be placed in erroneous files. + * + * Also added a patch from Shane Alderton (shane@ion.apana.org.au) to + * correct a problem with syslogd dumping core when an attempt was made + * to write log messages to a logged-on user. Thank you. + * + * Many thanks to Juha Virtanen (jiivee@hut.fi) for a series of + * interchanges which lead to the fixing of problems with messages set + * to priorities of none and emerg. Also thanks to Juha for a patch + * to exclude users with a class of LOGIN from receiving messages. + * + * Shane Alderton provided an additional patch to fix zombies which + * were conceived when messages were written to multiple users. + * + * Mon Feb 6 09:57:10 CST 1995: Dr. Wettstein + * Patch to properly reset the single priority message flag. Thanks + * to Christopher Gori for spotting this bug and forwarding a patch. + * + * Wed Feb 22 15:38:31 CST 1995: Dr. Wettstein + * Added version information to startup messages. + * + * Added defines so that paths to important files are taken from + * the definitions in paths.h. Hopefully this will insure that + * everything follows the FSSTND standards. Thanks to Chris Metcalf + * for a set of patches to provide this functionality. Also thanks + * Elias Levy for prompting me to get these into the sources. + * + * Wed Jul 26 18:57:23 MET DST 1995: Martin Schulze + * Linux' gethostname only returns the hostname and not the fqdn as + * expected in the code. But if you call hostname with an fqdn then + * gethostname will return an fqdn, so we have to mention that. This + * has been changed. + * + * The 'LocalDomain' and the hostname of a remote machine is + * converted to lower case, because the original caused some + * inconsistency, because the (at least my) nameserver did respond an + * fqdn containing of upper- _and_ lowercase letters while + * 'LocalDomain' consisted only of lowercase letters and that didn't + * match. + * + * Sat Aug 5 18:59:15 MET DST 1995: Martin Schulze + * Now no messages that were received from any remote host are sent + * out to another. At my domain this missing feature caused ugly + * syslog-loops, sometimes. + * + * Remember that no message is sent out. I can't figure out any + * scenario where it might be useful to change this behavior and to + * send out messages to other hosts than the one from which we + * received the message, but I might be shortsighted. :-/ + * + * Thu Aug 10 19:01:08 MET DST 1995: Martin Schulze + * Added my pidfile.[ch] to it to perform a better handling with + * pidfiles. Now both, syslogd and klogd, can only be started + * once. They check the pidfile. + * + * Sun Aug 13 19:01:41 MET DST 1995: Martin Schulze + * Add an addition to syslog.conf's interpretation. If a priority + * begins with an exclamation mark ('!') the normal interpretation + * of the priority is inverted: ".!*" is the same as ".none", ".!=info" + * don't logs the info priority, ".!crit" won't log any message with + * the priority crit or higher. For example: + * + * mail.*;mail.!=info /usr/adm/mail + * + * Would log all messages of the facility mail except those with + * the priority info to /usr/adm/mail. This makes the syslogd + * much more flexible. + * + * Defined TABLE_ALLPRI=255 and changed some occurrences. + * + * Sat Aug 19 21:40:13 MET DST 1995: Martin Schulze + * Making the table of facilities and priorities while in debug + * mode more readable. + * + * If debugging is turned on, printing the whole table of + * facilities and priorities every hexadecimal or 'X' entry is + * now 2 characters wide. + * + * The number of the entry is prepended to each line of + * facilities and priorities, and F_UNUSED lines are not shown + * anymore. + * + * Corrected some #ifdef SYSV's. + * + * Mon Aug 21 22:10:35 MET DST 1995: Martin Schulze + * Corrected a strange behavior during parsing of configuration + * file. The original BSD syslogd doesn't understand spaces as + * separators between specifier and action. This syslogd now + * understands them. The old behavior caused some confusion over + * the Linux community. + * + * Thu Oct 19 00:02:07 MET 1995: Martin Schulze + * The default behavior has changed for security reasons. The + * syslogd will not receive any remote message unless you turn + * reception on with the "-r" option. + * + * Not defining SYSLOG_INET will result in not doing any network + * activity, i.e. not sending or receiving messages. I changed + * this because the old idea is implemented with the "-r" option + * and the old thing didn't work anyway. + * + * Thu Oct 26 13:14:06 MET 1995: Martin Schulze + * Added another logfile type F_FORW_UNKN. The problem I ran into + * was a name server that runs on my machine and a forwarder of + * kern.crit to another host. The hosts address can only be + * fetched using the nameserver. But named is started after + * syslogd, so syslogd complained. + * + * This logfile type will retry to get the address of the + * hostname ten times and then complain. This should be enough to + * get the named up and running during boot sequence. + * + * Fri Oct 27 14:08:15 1995: Dr. Wettstein + * Changed static array of logfiles to a dynamic array. This + * can grow during process. + * + * Fri Nov 10 23:08:18 1995: Martin Schulze + * Inserted a new tabular sys_h_errlist that contains plain text + * for error codes that are returned from the net subsystem and + * stored in h_errno. I have also changed some wrong lookups to + * sys_errlist. + * + * Wed Nov 22 22:32:55 1995: Martin Schulze + * Added the fabulous strip-domain feature that allows us to + * strip off (several) domain names from the fqdn and only log + * the simple hostname. This is useful if you're in a LAN that + * has a central log server and also different domains. + * + * I have also also added the -l switch do define hosts as + * local. These will get logged with their simple hostname, too. + * + * Thu Nov 23 19:02:56 MET DST 1995: Martin Schulze + * Added the possibility to omit fsyncing of logfiles after every + * write. This will give some performance back if you have + * programs that log in a very verbose manner (like innd or + * smartlist). Thanks to Stephen R. van den Berg <srb@cuci.nl> + * for the idea. + * + * Thu Jan 18 11:14:36 CST 1996: Dr. Wettstein + * Added patche from beta-testers to stop compile error. Also + * added removal of pid file as part of termination cleanup. + * + * Wed Feb 14 12:42:09 CST 1996: Dr. Wettstein + * Allowed forwarding of messages received from remote hosts to + * be controlled by a command-line switch. Specifying -h allows + * forwarding. The default behavior is to disable forwarding of + * messages which were received from a remote host. + * + * Parent process of syslogd does not exit until child process has + * finished initialization process. This allows rc.* startup to + * pause until syslogd facility is up and operating. + * + * Re-arranged the select code to move UNIX domain socket accepts + * to be processed later. This was a contributed change which + * has been proposed to correct the delays sometimes encountered + * when syslogd starts up. + * + * Minor code cleanups. + * + * Thu May 2 15:15:33 CDT 1996: Dr. Wettstein + * Fixed bug in init function which resulted in file descripters + * being orphaned when syslogd process was re-initialized with SIGHUP + * signal. Thanks to Edvard Tuinder + * (Edvard.Tuinder@praseodymium.cistron.nl) for putting me on the + * trail of this bug. I am amazed that we didn't catch this one + * before now. + * + * Tue May 14 00:03:35 MET DST 1996: Martin Schulze + * Corrected a mistake that causes the syslogd to stop logging at + * some virtual consoles under Linux. This was caused by checking + * the wrong error code. Thanks to Michael Nonweiler + * <mrn20@hermes.cam.ac.uk> for sending me a patch. + * + * Mon May 20 13:29:32 MET DST 1996: Miquel van Smoorenburg <miquels@cistron.nl> + * Added continuation line supported and fixed a bug in + * the init() code. + * + * Tue May 28 00:58:45 MET DST 1996: Martin Schulze + * Corrected behaviour of blocking pipes - i.e. the whole system + * hung. Michael Nonweiler <mrn20@hermes.cam.ac.uk> has sent us + * a patch to correct this. A new logfile type F_PIPE has been + * introduced. + * + * Mon Feb 3 10:12:15 MET DST 1997: Martin Schulze + * Corrected behaviour of logfiles if the file can't be opened. + * There was a bug that causes syslogd to try to log into non + * existing files which ate cpu power. + * + * Sun Feb 9 03:22:12 MET DST 1997: Martin Schulze + * Modified syslogd.c to not kill itself which confuses bash 2.0. + * + * Mon Feb 10 00:09:11 MET DST 1997: Martin Schulze + * Improved debug code to decode the numeric facility/priority + * pair into textual information. + * + * Tue Jun 10 12:35:10 MET DST 1997: Martin Schulze + * Corrected freeing of logfiles. Thanks to Jos Vos <jos@xos.nl> + * for reporting the bug and sending an idea to fix the problem. + * + * Tue Jun 10 12:51:41 MET DST 1997: Martin Schulze + * Removed sleep(10) from parent process. This has caused a slow + * startup in former times - and I don't see any reason for this. + * + * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman + * Some more glibc patches made by <mdorman@debian.org>. + * + * Thu Jan 1 16:04:52 CET 1998: Martin Schulze <joey@infodrom.north.de + * Applied patch from Herbert Thielen <Herbert.Thielen@lpr.e-technik.tu-muenchen.de>. + * This included some balance parentheses for emacs and a bug in + * the exclamation mark handling. + * + * Fixed small bug which caused syslogd to write messages to the + * wrong logfile under some very rare conditions. Thanks to + * Herbert Xu <herbert@gondor.apana.org.au> for fiddling this out. + * + * Thu Jan 8 22:46:35 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Reworked one line of the above patch as it prevented syslogd + * from binding the socket with the result that no messages were + * forwarded to other hosts. + * + * Sat Jan 10 01:33:06 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed small bugs in F_FORW_UNKN meachanism. Thanks to Torsten + * Neumann <torsten@londo.rhein-main.de> for pointing me to it. + * + * Mon Jan 12 19:50:58 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Modified debug output concerning remote receiption. + * + * Mon Feb 23 23:32:35 CET 1998: Topi Miettinen <Topi.Miettinen@ml.tele.fi> + * Re-worked handling of Unix and UDP sockets to support closing / + * opening of them in order to have it open only if it is needed + * either for forwarding to a remote host or by receiption from + * the network. + * + * Wed Feb 25 10:54:09 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed little comparison mistake that prevented the MARK + * feature to work properly. + * + * Wed Feb 25 13:21:44 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Corrected Topi's patch as it prevented forwarding during + * startup due to an unknown LogPort. + * + * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Added support for TESTING define which will turn syslogd into + * stdio-mode used for debugging. + * + * Sun Oct 11 20:16:59 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Reworked the initialization/fork code. Now the parent + * process activates a signal handler which the daughter process + * will raise if it is initialized. Only after that one the + * parent process may exit. Otherwise klogd might try to flush + * its log cache while syslogd can't receive the messages yet. + * + * Mon Oct 12 13:30:35 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Redirected some error output with regard to argument parsing to + * stderr. + * + * Mon Oct 12 14:02:51 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Applied patch provided vom Topi Miettinen with regard to the + * people from OpenBSD. This provides the additional '-a' + * argument used for specifying additional UNIX domain sockets to + * listen to. This is been used with chroot()'ed named's for + * example. See for http://www.psionic.com/papers/dns.html + * + * Mon Oct 12 18:29:44 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Added `ftp' facility which was introduced in glibc version 2. + * It's #ifdef'ed so won't harm with older libraries. + * + * Mon Oct 12 19:59:21 MET DST 1998: Martin Schulze <joey@infodrom.north.de> + * Code cleanups with regard to bsd -> posix transition and + * stronger security (buffer length checking). Thanks to Topi + * Miettinen <tom@medialab.sonera.net> + * . index() --> strchr() + * . sprintf() --> snprintf() + * . bcopy() --> memcpy() + * . bzero() --> memset() + * . UNAMESZ --> UT_NAMESIZE + * . sys_errlist --> strerror() + * + * Mon Oct 12 20:22:59 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Added support for setutent()/getutent()/endutend() instead of + * binary reading the UTMP file. This is the the most portable + * way. This allows /var/run/utmp format to change, even to a + * real database or utmp daemon. Also if utmp file locking is + * implemented in libc, syslog will use it immediately. Thanks + * to Topi Miettinen <tom@medialab.sonera.net>. + * + * Mon Oct 12 20:49:18 MET DST 1998: Martin Schulze <joey@infodrom.north.de> + * Avoid logging of SIGCHLD when syslogd is in the process of + * exiting and closing its files. Again thanks to Topi. + * + * Mon Oct 12 22:18:34 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified printline() to support 8bit characters - such as + * russion letters. Thanks to Vladas Lapinskas <lapinskas@mail.iae.lt>. + * + * Sat Nov 14 02:29:37 CET 1998: Martin Schulze <joey@infodrom.north.de> + * ``-m 0'' now turns of MARK logging entirely. + * + * Tue Jan 19 01:04:18 MET 1999: Martin Schulze <joey@infodrom.north.de> + * Finally fixed an error with `-a' processing, thanks to Topi + * Miettinen <tom@medialab.sonera.net>. + * + * Sun May 23 10:08:53 CEST 1999: Martin Schulze <joey@infodrom.north.de> + * Removed superflous call to utmpname(). The path to the utmp + * file is defined in the used libc and should not be hardcoded + * into the syslogd binary referring the system it was compiled on. + * + * Sun Sep 17 20:45:33 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Fixed some bugs in printline() code that did not escape + * control characters '\177' through '\237' and contained a + * single-byte buffer overflow. Thanks to Solar Designer + * <solar@false.com>. + * + * Sun Sep 17 21:26:16 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Don't close open sockets upon reload. Thanks to Bill + * Nottingham. + * + * Mon Sep 18 09:10:47 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Fixed bug in printchopped() that caused syslogd to emit + * kern.emerg messages when splitting long lines. Thanks to + * Daniel Jacobowitz <dan@debian.org> for the fix. + * + * Mon Sep 18 15:33:26 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Removed unixm/unix domain sockets and switch to Datagram Unix + * Sockets. This should remove one possibility to play DoS with + * syslogd. Thanks to Olaf Kirch <okir@caldera.de> for the patch. + * + * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de> + * Don't return a closed fd if `-a' is called with a wrong path. + * Thanks to Bill Nottingham <notting@redhat.com> for providing + * a patch. + */ + + +#define MAXLINE 1024 /* maximum line length */ +#define MAXSVLINE 240 /* maximum saved line length */ +#define DEFUPRI (LOG_USER|LOG_NOTICE) +#define DEFSPRI (LOG_KERN|LOG_CRIT) +#define TIMERINTVL 30 /* interval for checking flush, mark */ + +#define CONT_LINE 1 /* Allow continuation lines */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#ifdef SYSV +#include <sys/types.h> +#endif +#include <utmp.h> +#include <ctype.h> +#include <string.h> +#include <setjmp.h> +#include <stdarg.h> +#include <time.h> + +#define SYSLOG_NAMES +#include <sys/syslog.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/file.h> +#ifdef SYSV +#include <fcntl.h> +#else +#include <sys/msgbuf.h> +#endif +#include <sys/uio.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <signal.h> + +#include <netinet/in.h> +#include <netdb.h> +#include <syscall.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#ifndef TESTING +#include "pidfile.h" +#endif +#include "version.h" + +#if defined(__linux__) +#include <paths.h> +#endif + +#ifndef UTMP_FILE +#ifdef UTMP_FILENAME +#define UTMP_FILE UTMP_FILENAME +#else +#ifdef _PATH_UTMP +#define UTMP_FILE _PATH_UTMP +#else +#define UTMP_FILE "/etc/utmp" +#endif +#endif +#endif + +#ifndef _PATH_LOGCONF +#define _PATH_LOGCONF "/etc/syslog.conf" +#endif + +#if defined(SYSLOGD_PIDNAME) +#undef _PATH_LOGPID +#if defined(FSSTND) +#define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME +#else +#define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME +#endif +#else +#ifndef _PATH_LOGPID +#if defined(FSSTND) +#define _PATH_LOGPID _PATH_VARRUN "syslogd.pid" +#else +#define _PATH_LOGPID "/etc/syslogd.pid" +#endif +#endif +#endif + +#ifndef _PATH_DEV +#define _PATH_DEV "/dev/" +#endif + +#ifndef _PATH_CONSOLE +#define _PATH_CONSOLE "/dev/console" +#endif + +#ifndef _PATH_TTY +#define _PATH_TTY "/dev/tty" +#endif + +#ifndef _PATH_LOG +#define _PATH_LOG "/dev/log" +#endif + +char *ConfFile = _PATH_LOGCONF; +char *PidFile = _PATH_LOGPID; +char ctty[] = _PATH_CONSOLE; + +char **parts; + +int inetm = 0; +static int debugging_on = 0; +static int nlogs = -1; +static int restart = 0; + +#define MAXFUNIX 20 + +int nfunix = 1; +char *funixn[MAXFUNIX] = { _PATH_LOG }; +int funix[MAXFUNIX] = { -1, }; + +#ifdef UT_NAMESIZE +# define UNAMESZ UT_NAMESIZE /* length of a login name */ +#else +# define UNAMESZ 8 /* length of a login name */ +#endif +#define MAXUNAMES 20 /* maximum number of user names */ +#define MAXFNAME 200 /* max file pathname length */ + +#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ +#define TABLE_NOPRI 0 /* Value to indicate no priority in f_pmask */ +#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */ +#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */ + +/* + * Flags to logmsg(). + */ + +#define IGN_CONS 0x001 /* don't print on console */ +#define SYNC_FILE 0x002 /* do fsync on file after printing */ +#define ADDDATE 0x004 /* add a date to the message */ +#define MARK 0x008 /* this message is a mark */ + +/* + * This table contains plain text for h_errno errors used by the + * net subsystem. + */ +const char *sys_h_errlist[] = { + "No problem", /* NETDB_SUCCESS */ + "Authoritative answer: host not found", /* HOST_NOT_FOUND */ + "Non-authoritative answer: host not found, or serverfail", /* TRY_AGAIN */ + "Non recoverable errors", /* NO_RECOVERY */ + "Valid name, no data record of requested type", /* NO_DATA */ + "no address, look for MX record" /* NO_ADDRESS */ + }; + +/* + * This structure represents the files that will have log + * copies printed. + */ + +struct filed { +#ifndef SYSV + struct filed *f_next; /* next in linked list */ +#endif + short f_type; /* entry type, see below */ + short f_file; /* file descriptor */ + time_t f_time; /* time this was last written */ + u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ + union { + char f_uname[MAXUNAMES][UNAMESZ+1]; + struct { + char f_hname[MAXHOSTNAMELEN+1]; + struct sockaddr_in f_addr; + } f_forw; /* forwarding address */ + char f_fname[MAXFNAME]; + } f_un; + char f_prevline[MAXSVLINE]; /* last message logged */ + char f_lasttime[16]; /* time of last occurrence */ + char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ + int f_prevpri; /* pri of f_prevline */ + int f_prevlen; /* length of f_prevline */ + int f_prevcount; /* repetition cnt of prevline */ + int f_repeatcount; /* number of "repeated" msgs */ + int f_flags; /* store some additional flags */ +}; + +/* + * Intervals at which we flush out "message repeated" messages, + * in seconds after previous message is logged. After each flush, + * we move to the next interval until we reach the largest. + */ +int repeatinterval[] = { 30, 60 }; /* # of secs before flush */ +#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) +#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) +#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ + (f)->f_repeatcount = MAXREPEAT; \ + } +#ifdef SYSLOG_INET +#define INET_SUSPEND_TIME 180 /* equal to 3 minutes */ +#define INET_RETRY_MAX 10 /* maximum of retries for gethostbyname() */ +#endif + +#define LIST_DELIMITER ':' /* delimiter between two hosts */ + +/* values for f_type */ +#define F_UNUSED 0 /* unused entry */ +#define F_FILE 1 /* regular file */ +#define F_TTY 2 /* terminal */ +#define F_CONSOLE 3 /* console terminal */ +#define F_FORW 4 /* remote machine */ +#define F_USERS 5 /* list of users */ +#define F_WALL 6 /* everyone logged on */ +#define F_FORW_SUSP 7 /* suspended host forwarding */ +#define F_FORW_UNKN 8 /* unknown host forwarding */ +#define F_PIPE 9 /* named pipe */ +char *TypeNames[] = { + "UNUSED", "FILE", "TTY", "CONSOLE", + "FORW", "USERS", "WALL", "FORW(SUSPENDED)", + "FORW(UNKNOWN)", "PIPE" +}; + +struct filed *Files = (struct filed *) 0; +struct filed consfile; + +struct code { + char *c_name; + int c_val; +}; + +struct code PriNames[] = { + {"alert", LOG_ALERT}, + {"crit", LOG_CRIT}, + {"debug", LOG_DEBUG}, + {"emerg", LOG_EMERG}, + {"err", LOG_ERR}, + {"error", LOG_ERR}, /* DEPRECATED */ + {"info", LOG_INFO}, + {"none", INTERNAL_NOPRI}, /* INTERNAL */ + {"notice", LOG_NOTICE}, + {"panic", LOG_EMERG}, /* DEPRECATED */ + {"warn", LOG_WARNING}, /* DEPRECATED */ + {"warning", LOG_WARNING}, + {"*", TABLE_ALLPRI}, + {NULL, -1} +}; + +struct code FacNames[] = { + {"auth", LOG_AUTH}, + {"authpriv", LOG_AUTHPRIV}, + {"cron", LOG_CRON}, + {"daemon", LOG_DAEMON}, + {"kern", LOG_KERN}, + {"lpr", LOG_LPR}, + {"mail", LOG_MAIL}, + {"mark", LOG_MARK}, /* INTERNAL */ + {"news", LOG_NEWS}, + {"security", LOG_AUTH}, /* DEPRECATED */ + {"syslog", LOG_SYSLOG}, + {"user", LOG_USER}, + {"uucp", LOG_UUCP}, +#if defined(LOG_FTP) + {"ftp", LOG_FTP}, +#endif + {"local0", LOG_LOCAL0}, + {"local1", LOG_LOCAL1}, + {"local2", LOG_LOCAL2}, + {"local3", LOG_LOCAL3}, + {"local4", LOG_LOCAL4}, + {"local5", LOG_LOCAL5}, + {"local6", LOG_LOCAL6}, + {"local7", LOG_LOCAL7}, + {NULL, -1}, +}; + +int Debug; /* debug flag */ +char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ +char *LocalDomain; /* our local domain name */ +int InetInuse = 0; /* non-zero if INET sockets are being used */ +int finet = -1; /* Internet datagram socket */ +int LogPort; /* port number for INET connections */ +int Initialized = 0; /* set when we have initialized ourselves */ +int MarkInterval = 20 * 60; /* interval between marks in seconds */ +int MarkSeq = 0; /* mark sequence number */ +int NoFork = 0; /* don't fork - don't run in daemon mode */ +int AcceptRemote = 0; /* receive messages that come via UDP */ +char **StripDomains = NULL; /* these domains may be stripped before writing logs */ +char **LocalHosts = NULL; /* these hosts are logged with their hostname */ +int NoHops = 1; /* Can we bounce syslog messages through an + intermediate host. */ + +extern int errno; + +/* Function prototypes. */ +int main(int argc, char **argv); +char **crunch_list(char *list); +int usage(void); +void untty(void); +void printchopped(const char *hname, char *msg, int len, int fd); +void printline(const char *hname, char *msg); +void printsys(char *msg); +void logmsg(int pri, char *msg, const char *from, int flags); +void fprintlog(register struct filed *f, char *from, int flags, char *msg); +void endtty(); +void wallmsg(register struct filed *f, struct iovec *iov); +void reapchild(); +const char *cvthname(struct sockaddr_in *f); +void domark(); +void debug_switch(); +void logerror(char *type); +void die(int sig); +#ifndef TESTING +void doexit(int sig); +#endif +void init(); +void cfline(char *line, register struct filed *f); +int decode(char *name, struct code *codetab); +#if defined(__GLIBC__) +#define dprintf mydprintf +#endif /* __GLIBC__ */ +static void dprintf(char *, ...); +static void allocate_log(void); +void sighup_handler(); + +#ifdef SYSLOG_UNIXAF +static int create_unix_socket(const char *path); +#endif +#ifdef SYSLOG_INET +static int create_inet_socket(); +#endif + +int main(argc, argv) + int argc; + char **argv; +{ + register int i; + register char *p; +#if !defined(__GLIBC__) + int len, num_fds; +#else /* __GLIBC__ */ +#ifndef TESTING + size_t len; +#endif + int num_fds; +#endif /* __GLIBC__ */ + /* + * It took me quite some time to figure out how this is + * supposed to work so I guess I should better write it down. + * unixm is a list of file descriptors from which one can + * read(). This is in contrary to readfds which is a list of + * file descriptors where activity is monitored by select() + * and from which one cannot read(). -Joey + * + * Changed: unixm is gone, since we now use datagram unix sockets. + * Hence we recv() from unix sockets directly (rather than + * first accept()ing connections on them), so there's no need + * for separate book-keeping. --okir + */ + fd_set readfds; + +#ifndef TESTING + int fd; +#ifdef SYSLOG_INET + struct sockaddr_in frominet; + char *from; +#endif + pid_t ppid = getpid(); +#endif + int ch; + struct hostent *hent; + + char line[MAXLINE +1]; + extern int optind; + extern char *optarg; + int maxfds; + +#ifndef TESTING + chdir ("/"); +#endif + for (i = 1; i < MAXFUNIX; i++) { + funixn[i] = ""; + funix[i] = -1; + } + + while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF) + switch((char)ch) { + case 'a': + if (nfunix < MAXFUNIX) + funixn[nfunix++] = optarg; + else + fprintf(stderr, "Out of descriptors, ignoring %s\n", optarg); + break; + case 'd': /* debug */ + Debug = 1; + break; + case 'f': /* configuration file */ + ConfFile = optarg; + break; + case 'h': + NoHops = 0; + break; + case 'l': + if (LocalHosts) { + fprintf (stderr, "Only one -l argument allowed," \ + "the first one is taken.\n"); + break; + } + LocalHosts = crunch_list(optarg); + break; + case 'm': /* mark interval */ + MarkInterval = atoi(optarg) * 60; + break; + case 'n': /* don't fork */ + NoFork = 1; + break; + case 'p': /* path to regular log socket */ + funixn[0] = optarg; + break; + case 'r': /* accept remote messages */ + AcceptRemote = 1; + break; + case 's': + if (StripDomains) { + fprintf (stderr, "Only one -s argument allowed," \ + "the first one is taken.\n"); + break; + } + StripDomains = crunch_list(optarg); + break; + case 'v': + printf("syslogd %s.%s\n", VERSION, PATCHLEVEL); + exit (0); + case '?': + default: + usage(); + } + if ((argc -= optind)) + usage(); + +#ifndef TESTING + if ( !(Debug || NoFork) ) + { + dprintf("Checking pidfile.\n"); + if (!check_pid(PidFile)) + { + if (fork()) { + /* + * Parent process + */ + signal (SIGTERM, doexit); + sleep(300); + /* + * Not reached unless something major went wrong. 5 + * minutes should be a fair amount of time to wait. + * Please note that this procedure is important since + * the father must not exit before syslogd isn't + * initialized or the klogd won't be able to flush its + * logs. -Joey + */ + exit(1); + } + num_fds = getdtablesize(); + for (i= 0; i < num_fds; i++) + (void) close(i); + untty(); + } + else + { + fputs("syslogd: Already running.\n", stderr); + exit(1); + } + } + else +#endif + debugging_on = 1; +#ifndef SYSV + else + setlinebuf(stdout); +#endif + +#ifndef TESTING + /* tuck my process id away */ + if ( !Debug ) + { + dprintf("Writing pidfile.\n"); + if (!check_pid(PidFile)) + { + if (!write_pid(PidFile)) + { + dprintf("Can't write pid.\n"); + exit(1); + } + } + else + { + dprintf("Pidfile (and pid) already exist.\n"); + exit(1); + } + } /* if ( !Debug ) */ +#endif + + consfile.f_type = F_CONSOLE; + (void) strcpy(consfile.f_un.f_fname, ctty); + (void) gethostname(LocalHostName, sizeof(LocalHostName)); + if ( (p = strchr(LocalHostName, '.')) ) { + *p++ = '\0'; + LocalDomain = p; + } + else + { + LocalDomain = ""; + + /* + * It's not clearly defined whether gethostname() + * should return the simple hostname or the fqdn. A + * good piece of software should be aware of both and + * we want to distribute good software. Joey + * + * Good software also always checks its return values... + * If syslogd starts up before DNS is up & /etc/hosts + * doesn't have LocalHostName listed, gethostbyname will + * return NULL. + */ + hent = gethostbyname(LocalHostName); + if ( hent ) + snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name); + + if ( (p = strchr(LocalHostName, '.')) ) + { + *p++ = '\0'; + LocalDomain = p; + } + } + + /* + * Convert to lower case to recognize the correct domain laterly + */ + for (p = (char *)LocalDomain; *p ; p++) + if (isupper(*p)) + *p = tolower(*p); + + (void) signal(SIGTERM, die); + (void) signal(SIGINT, Debug ? die : SIG_IGN); + (void) signal(SIGQUIT, Debug ? die : SIG_IGN); + (void) signal(SIGCHLD, reapchild); + (void) signal(SIGALRM, domark); + (void) signal(SIGUSR1, Debug ? debug_switch : SIG_IGN); + (void) alarm(TIMERINTVL); + + /* Create a partial message table for all file descriptors. */ + num_fds = getdtablesize(); + dprintf("Allocated parts table for %d file descriptors.\n", num_fds); + if ( (parts = (char **) malloc(num_fds * sizeof(char *))) == \ + (char **) 0 ) + { + logerror("Cannot allocate memory for message parts table."); + die(0); + } + for(i= 0; i < num_fds; ++i) + parts[i] = (char *) 0; + + dprintf("Starting.\n"); + init(); +#ifndef TESTING + if ( Debug ) + { + dprintf("Debugging disabled, SIGUSR1 to turn on debugging.\n"); + debugging_on = 0; + } + /* + * Send a signal to the parent to it can terminate. + */ + if (getpid() != ppid) + kill (ppid, SIGTERM); +#endif + + /* Main loop begins here. */ + for (;;) { + int nfds; + errno = 0; + FD_ZERO(&readfds); + maxfds = 0; +#ifdef SYSLOG_UNIXAF +#ifndef TESTING + /* + * Add the Unix Domain Sockets to the list of read + * descriptors. + */ + /* Copy master connections */ + for (i = 0; i < nfunix; i++) { + if (funix[i] != -1) { + FD_SET(funix[i], &readfds); + if (funix[i]>maxfds) maxfds=funix[i]; + } + } +#endif +#endif +#ifdef SYSLOG_INET +#ifndef TESTING + /* + * Add the Internet Domain Socket to the list of read + * descriptors. + */ + if ( InetInuse && AcceptRemote ) { + FD_SET(inetm, &readfds); + if (inetm>maxfds) maxfds=inetm; + dprintf("Listening on syslog UDP port.\n"); + } +#endif +#endif +#ifdef TESTING + FD_SET(fileno(stdin), &readfds); + if (fileno(stdin) > maxfds) maxfds = fileno(stdin); + + dprintf("Listening on stdin. Press Ctrl-C to interrupt.\n"); +#endif + + if ( debugging_on ) + { + dprintf("Calling select, active file descriptors (max %d): ", maxfds); + for (nfds= 0; nfds <= maxfds; ++nfds) + if ( FD_ISSET(nfds, &readfds) ) + dprintf("%d ", nfds); + dprintf("\n"); + } + nfds = select(maxfds+1, (fd_set *) &readfds, (fd_set *) NULL, + (fd_set *) NULL, (struct timeval *) NULL); + if ( restart ) + { + dprintf("\nReceived SIGHUP, reloading syslogd.\n"); + init(); + restart = 0; + continue; + } + if (nfds == 0) { + dprintf("No select activity.\n"); + continue; + } + if (nfds < 0) { + if (errno != EINTR) + logerror("select"); + dprintf("Select interrupted.\n"); + continue; + } + + if ( debugging_on ) + { + dprintf("\nSuccessful select, descriptor count = %d, " \ + "Activity on: ", nfds); + for (nfds= 0; nfds <= maxfds; ++nfds) + if ( FD_ISSET(nfds, &readfds) ) + dprintf("%d ", nfds); + dprintf(("\n")); + } + +#ifndef TESTING +#ifdef SYSLOG_UNIXAF + for (i = 0; i < nfunix; i++) { + if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) { + memset(line, '\0', sizeof(line)); + i = recv(fd, line, MAXLINE - 2, 0); + dprintf("Message from UNIX socket: #%d\n", fd); + if (i > 0) { + line[i] = line[i+1] = '\0'; + printchopped(LocalHostName, line, i + 2, fd); + } else if (i < 0 && errno != EINTR) { + dprintf("UNIX socket error: %d = %s.\n", \ + errno, strerror(errno)); + logerror("recvfrom UNIX"); + } + } + } +#endif + +#ifdef SYSLOG_INET + if (InetInuse && AcceptRemote && FD_ISSET(inetm, &readfds)) { + len = sizeof(frominet); + memset(line, '\0', sizeof(line)); + i = recvfrom(finet, line, MAXLINE - 2, 0, \ + (struct sockaddr *) &frominet, &len); + dprintf("Message from inetd socket: #%d, host: %s\n", + inetm, inet_ntoa(frominet.sin_addr)); + if (i > 0) { + line[i] = line[i+1] = '\0'; + from = (char *)cvthname(&frominet); + /* + * Here we could check if the host is permitted + * to send us syslog messages. We just have to + * catch the result of cvthname, look for a dot + * and if that doesn't exist, replace the first + * '\0' with '.' and we have the fqdn in lowercase + * letters so we could match them against whatever. + * -Joey + */ + printchopped(from, line, \ + i + 2, finet); + } else if (i < 0 && errno != EINTR) { + dprintf("INET socket error: %d = %s.\n", \ + errno, strerror(errno)); + logerror("recvfrom inet"); + /* should be harmless now that we set + * BSDCOMPAT on the socket */ + sleep(10); + } + } +#endif +#else + if ( FD_ISSET(fileno(stdin), &readfds) ) { + dprintf("Message from stdin.\n"); + memset(line, '\0', sizeof(line)); + line[0] = '.'; + parts[fileno(stdin)] = (char *) 0; + i = read(fileno(stdin), line, MAXLINE); + if (i > 0) { + printchopped(LocalHostName, line, i+1, fileno(stdin)); + } else if (i < 0) { + if (errno != EINTR) { + logerror("stdin"); + } + } + FD_CLR(fileno(stdin), &readfds); + } + +#endif + } +} + +int usage() +{ + fprintf(stderr, "usage: syslogd [-drvh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \ + " [-s domainlist] [-f conffile]\n"); + exit(1); +} + +#ifdef SYSLOG_UNIXAF +static int create_unix_socket(const char *path) +{ + struct sockaddr_un sunx; + int fd; + char line[MAXLINE +1]; + + if (path[0] == '\0') + return -1; + + (void) unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, + sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 || + chmod(path, 0666) < 0) { + (void) snprintf(line, sizeof(line), "cannot create %s", path); + logerror(line); + dprintf("cannot create %s (%d).\n", path, errno); + close(fd); +#ifndef SYSV + die(0); +#endif + return -1; + } + return fd; +} +#endif + +#ifdef SYSLOG_INET +static int create_inet_socket() +{ + int fd, on = 1; + struct sockaddr_in sin; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + logerror("syslog: Unknown protocol, suspending inet service."); + return fd; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = LogPort; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, \ + (char *) &on, sizeof(on)) < 0 ) { + logerror("setsockopt(REUSEADDR), suspending inet"); + close(fd); + return -1; + } + /* We need to enable BSD compatibility. Otherwise an attacker + * could flood our log files by sending us tons of ICMP errors. + */ + if (setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, \ + (char *) &on, sizeof(on)) < 0) { + logerror("setsockopt(BSDCOMPAT), suspending inet"); + close(fd); + return -1; + } + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + logerror("bind, suspending inet"); + close(fd); + return -1; + } + return fd; +} +#endif + +char ** +crunch_list(list) + char *list; +{ + int count, i; + char *p, *q; + char **result = NULL; + + p = list; + + /* strip off trailing delimiters */ + while (p[strlen(p)-1] == LIST_DELIMITER) { + count--; + p[strlen(p)-1] = '\0'; + } + /* cut off leading delimiters */ + while (p[0] == LIST_DELIMITER) { + count--; + p++; + } + + /* count delimiters to calculate elements */ + for (count=i=0; p[i]; i++) + if (p[i] == LIST_DELIMITER) count++; + + if ((result = (char **)malloc(sizeof(char *) * count+2)) == NULL) { + printf ("Sorry, can't get enough memory, exiting.\n"); + exit(0); + } + + /* + * We now can assume that the first and last + * characters are different from any delimiters, + * so we don't have to care about this. + */ + count = 0; + while ((q=strchr(p, LIST_DELIMITER))) { + result[count] = (char *) malloc((q - p + 1) * sizeof(char)); + if (result[count] == NULL) { + printf ("Sorry, can't get enough memory, exiting.\n"); + exit(0); + } + strncpy(result[count], p, q - p); + result[count][q - p] = '\0'; + p = q; p++; + count++; + } + if ((result[count] = \ + (char *)malloc(sizeof(char) * strlen(p) + 1)) == NULL) { + printf ("Sorry, can't get enough memory, exiting.\n"); + exit(0); + } + strcpy(result[count],p); + result[++count] = NULL; + +#if 0 + count=0; + while (result[count]) + dprintf ("#%d: %s\n", count, StripDomains[count++]); +#endif + return result; +} + + +void untty() +#ifdef SYSV +{ + if ( !Debug ) { + setsid(); + } + return; +} + +#else +{ + int i; + + if ( !Debug ) { + i = open(_PATH_TTY, O_RDWR); + if (i >= 0) { + (void) ioctl(i, (int) TIOCNOTTY, (char *)0); + (void) close(i); + } + } +} +#endif + + +/* + * Parse the line to make sure that the msg is not a composite of more + * than one message. + */ + +void printchopped(hname, msg, len, fd) + const char *hname; + char *msg; + int len; + int fd; +{ + auto int ptlngth; + + auto char *start = msg, + *p, + *end, + tmpline[MAXLINE + 1]; + + dprintf("Message length: %d, File descriptor: %d.\n", len, fd); + tmpline[0] = '\0'; + if ( parts[fd] != (char *) 0 ) + { + dprintf("Including part from messages.\n"); + strcpy(tmpline, parts[fd]); + free(parts[fd]); + parts[fd] = (char *) 0; + if ( (strlen(msg) + strlen(tmpline)) > MAXLINE ) + { + logerror("Cannot glue message parts together"); + printline(hname, tmpline); + start = msg; + } + else + { + dprintf("Previous: %s\n", tmpline); + dprintf("Next: %s\n", msg); + strcat(tmpline, msg); /* length checked above */ + printline(hname, tmpline); + if ( (strlen(msg) + 1) == len ) + return; + else + start = strchr(msg, '\0') + 1; + } + } + + if ( msg[len-1] != '\0' ) + { + msg[len] = '\0'; + for(p= msg+len-1; *p != '\0' && p > msg; ) + --p; + if(*p == '\0') p++; + ptlngth = strlen(p); + if ( (parts[fd] = malloc(ptlngth + 1)) == (char *) 0 ) + logerror("Cannot allocate memory for message part."); + else + { + strcpy(parts[fd], p); + dprintf("Saving partial msg: %s\n", parts[fd]); + memset(p, '\0', ptlngth); + } + } + + do { + end = strchr(start + 1, '\0'); + printline(hname, start); + start = end + 1; + } while ( *start != '\0' ); + + return; +} + + + +/* + * Take a raw input line, decode the message, and print the message + * on the appropriate log files. + */ + +void printline(hname, msg) + const char *hname; + char *msg; +{ + register char *p, *q; + register unsigned char c; + char line[MAXLINE + 1]; + int pri; + + /* test for special codes */ + pri = DEFUPRI; + p = msg; + + if (*p == '<') { + pri = 0; + while (isdigit(*++p)) + { + pri = 10 * pri + (*p - '0'); + } + if (*p == '>') + ++p; + } + if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) + pri = DEFUPRI; + + memset (line, 0, sizeof(line)); + q = line; + while ((c = *p++) && q < &line[sizeof(line) - 4]) { + if (c == '\n') + *q++ = ' '; + else if (c < 040) { + *q++ = '^'; + *q++ = c ^ 0100; + } else if (c == 0177 || (c & 0177) < 040) { + *q++ = '\\'; + *q++ = '0' + ((c & 0300) >> 6); + *q++ = '0' + ((c & 0070) >> 3); + *q++ = '0' + (c & 0007); + } else + *q++ = c; + } + *q = '\0'; + + logmsg(pri, line, hname, SYNC_FILE); + return; +} + + + +/* + * Take a raw input line from /dev/klog, split and format similar to syslog(). + */ + +void printsys(msg) + char *msg; +{ + register char *p, *q; + register int c; + char line[MAXLINE + 1]; + int pri, flags; + char *lp; + + (void) snprintf(line, sizeof(line), "vmunix: "); + lp = line + strlen(line); + for (p = msg; *p != '\0'; ) { + flags = ADDDATE; + pri = DEFSPRI; + if (*p == '<') { + pri = 0; + while (isdigit(*++p)) + pri = 10 * pri + (*p - '0'); + if (*p == '>') + ++p; + } else { + /* kernel printf's come out on console */ + flags |= IGN_CONS; + } + if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) + pri = DEFSPRI; + q = lp; + while (*p != '\0' && (c = *p++) != '\n' && + q < &line[MAXLINE]) + *q++ = c; + *q = '\0'; + logmsg(pri, line, LocalHostName, flags); + } + return; +} + +/* + * Decode a priority into textual information like auth.emerg. + */ +char *textpri(pri) + int pri; +{ + static char res[20]; + CODE *c_pri, *c_fac; + + for (c_fac = facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++); + for (c_pri = prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); + + snprintf (res, sizeof(res), "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri); + + return res; +} + +time_t now; + +/* + * Log a message to the appropriate log files, users, etc. based on + * the priority. + */ + +void logmsg(pri, msg, from, flags) + int pri; + char *msg; + const char *from; + int flags; +{ + register struct filed *f; + int fac, prilev, lognum; + int msglen; + char *timestamp; + + dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, from, msg); + +#ifndef SYSV + omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); +#endif + + /* + * Check to see if msg looks non-standard. + */ + msglen = strlen(msg); + if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || + msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') + flags |= ADDDATE; + + (void) time(&now); + if (flags & ADDDATE) + timestamp = ctime(&now) + 4; + else { + timestamp = msg; + msg += 16; + msglen -= 16; + } + + /* extract facility and priority level */ + if (flags & MARK) + fac = LOG_NFACILITIES; + else + fac = LOG_FAC(pri); + prilev = LOG_PRI(pri); + + /* log the message to the particular outputs */ + if (!Initialized) { + f = &consfile; + f->f_file = open(ctty, O_WRONLY|O_NOCTTY); + + if (f->f_file >= 0) { + untty(); + fprintlog(f, (char *)from, flags, msg); + (void) close(f->f_file); + f->f_file = -1; + } +#ifndef SYSV + (void) sigsetmask(omask); +#endif + return; + } +#ifdef SYSV + for (lognum = 0; lognum <= nlogs; lognum++) { + f = &Files[lognum]; +#else + for (f = Files; f; f = f->f_next) { +#endif + + /* skip messages that are incorrect priority */ + if ( (f->f_pmask[fac] == TABLE_NOPRI) || \ + ((f->f_pmask[fac] & (1<<prilev)) == 0) ) + continue; + + if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) + continue; + + /* don't output marks to recently written files */ + if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) + continue; + + /* + * suppress duplicate lines to this file + */ + if ((flags & MARK) == 0 && msglen == f->f_prevlen && + !strcmp(msg, f->f_prevline) && + !strcmp(from, f->f_prevhost)) { + (void) strncpy(f->f_lasttime, timestamp, 15); + f->f_prevcount++; + dprintf("msg repeated %d times, %ld sec of %d.\n", + f->f_prevcount, now - f->f_time, + repeatinterval[f->f_repeatcount]); + /* + * If domark would have logged this by now, + * flush it now (so we don't hold isolated messages), + * but back off so we'll flush less often + * in the future. + */ + if (now > REPEATTIME(f)) { + fprintlog(f, (char *)from, flags, (char *)NULL); + BACKOFF(f); + } + } else { + /* new line, save it */ + if (f->f_prevcount) + fprintlog(f, (char *)from, 0, (char *)NULL); + f->f_prevpri = pri; + f->f_repeatcount = 0; + (void) strncpy(f->f_lasttime, timestamp, 15); + (void) strncpy(f->f_prevhost, from, + sizeof(f->f_prevhost)); + if (msglen < MAXSVLINE) { + f->f_prevlen = msglen; + (void) strcpy(f->f_prevline, msg); + fprintlog(f, (char *)from, flags, (char *)NULL); + } else { + f->f_prevline[0] = 0; + f->f_prevlen = 0; + fprintlog(f, (char *)from, flags, msg); + } + } + } +#ifndef SYSV + (void) sigsetmask(omask); +#endif +} +#if FALSE +} /* balance parentheses for emacs */ +#endif + +void fprintlog(f, from, flags, msg) + register struct filed *f; + char *from; + int flags; + char *msg; +{ + struct iovec iov[6]; + register struct iovec *v = iov; + char repbuf[80]; +#ifdef SYSLOG_INET + register int l; + char line[MAXLINE + 1]; + time_t fwd_suspend; + struct hostent *hp; +#endif + + dprintf("Called fprintlog, "); + + v->iov_base = f->f_lasttime; + v->iov_len = 15; + v++; + v->iov_base = " "; + v->iov_len = 1; + v++; + v->iov_base = f->f_prevhost; + v->iov_len = strlen(v->iov_base); + v++; + v->iov_base = " "; + v->iov_len = 1; + v++; + if (msg) { + v->iov_base = msg; + v->iov_len = strlen(msg); + } else if (f->f_prevcount > 1) { + (void) snprintf(repbuf, sizeof(repbuf), "last message repeated %d times", + f->f_prevcount); + v->iov_base = repbuf; + v->iov_len = strlen(repbuf); + } else { + v->iov_base = f->f_prevline; + v->iov_len = f->f_prevlen; + } + v++; + + dprintf("logging to %s", TypeNames[f->f_type]); + + switch (f->f_type) { + case F_UNUSED: + f->f_time = now; + dprintf("\n"); + break; + +#ifdef SYSLOG_INET + case F_FORW_SUSP: + fwd_suspend = time((time_t *) 0) - f->f_time; + if ( fwd_suspend >= INET_SUSPEND_TIME ) { + dprintf("\nForwarding suspension over, " \ + "retrying FORW "); + f->f_type = F_FORW; + goto f_forw; + } + else { + dprintf(" %s\n", f->f_un.f_forw.f_hname); + dprintf("Forwarding suspension not over, time " \ + "left: %d.\n", INET_SUSPEND_TIME - \ + fwd_suspend); + } + break; + + /* + * The trick is to wait some time, then retry to get the + * address. If that fails retry x times and then give up. + * + * You'll run into this problem mostly if the name server you + * need for resolving the address is on the same machine, but + * is started after syslogd. + */ + case F_FORW_UNKN: + dprintf(" %s\n", f->f_un.f_forw.f_hname); + fwd_suspend = time((time_t *) 0) - f->f_time; + if ( fwd_suspend >= INET_SUSPEND_TIME ) { + dprintf("Forwarding suspension to unknown over, retrying\n"); + if ( (hp = gethostbyname(f->f_un.f_forw.f_hname)) == NULL ) { + dprintf("Failure: %s\n", sys_h_errlist[h_errno]); + dprintf("Retries: %d\n", f->f_prevcount); + if ( --f->f_prevcount < 0 ) { + dprintf("Giving up.\n"); + f->f_type = F_UNUSED; + } + else + dprintf("Left retries: %d\n", f->f_prevcount); + } + else { + dprintf("%s found, resuming.\n", f->f_un.f_forw.f_hname); + memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); + f->f_prevcount = 0; + f->f_type = F_FORW; + goto f_forw; + } + } + else + dprintf("Forwarding suspension not over, time " \ + "left: %d\n", INET_SUSPEND_TIME - fwd_suspend); + break; + + case F_FORW: + /* + * Don't send any message to a remote host if it + * already comes from one. (we don't care 'bout who + * sent the message, we don't send it anyway) -Joey + */ + f_forw: + dprintf(" %s\n", f->f_un.f_forw.f_hname); + if ( strcmp(from, LocalHostName) && NoHops ) + dprintf("Not sending message to remote.\n"); + else { + f->f_time = now; + (void) snprintf(line, sizeof(line), "<%d>%s\n", f->f_prevpri, \ + (char *) iov[4].iov_base); + l = strlen(line); + if (l > MAXLINE) + l = MAXLINE; + if (sendto(finet, line, l, 0, \ + (struct sockaddr *) &f->f_un.f_forw.f_addr, + sizeof(f->f_un.f_forw.f_addr)) != l) { + int e = errno; + dprintf("INET sendto error: %d = %s.\n", + e, strerror(e)); + f->f_type = F_FORW_SUSP; + errno = e; + logerror("sendto"); + } + } + break; +#endif + + case F_CONSOLE: + f->f_time = now; +#ifdef UNIXPC + if (1) { +#else + if (flags & IGN_CONS) { +#endif + dprintf(" (ignored).\n"); + break; + } + /* FALLTHROUGH */ + + case F_TTY: + case F_FILE: + case F_PIPE: + f->f_time = now; + dprintf(" %s\n", f->f_un.f_fname); + if (f->f_type == F_TTY || f->f_type == F_CONSOLE) { + v->iov_base = "\r\n"; + v->iov_len = 2; + } else { + v->iov_base = "\n"; + v->iov_len = 1; + } + again: + /* f->f_file == -1 is an indicator that the we couldn't + open the file at startup. */ + if (f->f_file == -1) + break; + + if (writev(f->f_file, iov, 6) < 0) { + int e = errno; + + /* If a named pipe is full, just ignore it for now + - mrn 24 May 96 */ + if (f->f_type == F_PIPE && e == EAGAIN) + break; + + (void) close(f->f_file); + /* + * Check for EBADF on TTY's due to vhangup() XXX + * Linux uses EIO instead (mrn 12 May 96) + */ + if ((f->f_type == F_TTY || f->f_type == F_CONSOLE) +#ifdef linux + && e == EIO) { +#else + && e == EBADF) { +#endif + f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_NOCTTY); + if (f->f_file < 0) { + f->f_type = F_UNUSED; + logerror(f->f_un.f_fname); + } else { + untty(); + goto again; + } + } else { + f->f_type = F_UNUSED; + errno = e; + logerror(f->f_un.f_fname); + } + } else if (f->f_flags & SYNC_FILE) + (void) fsync(f->f_file); + break; + + case F_USERS: + case F_WALL: + f->f_time = now; + dprintf("\n"); + v->iov_base = "\r\n"; + v->iov_len = 2; + wallmsg(f, iov); + break; + } /* switch */ + if (f->f_type != F_FORW_UNKN) + f->f_prevcount = 0; + return; +} +#if FALSE +}} /* balance parentheses for emacs */ +#endif + +jmp_buf ttybuf; + +void endtty() +{ + longjmp(ttybuf, 1); +} + +/* + * WALLMSG -- Write a message to the world at large + * + * Write the specified message to either the entire + * world, or a list of approved users. + */ + +void wallmsg(f, iov) + register struct filed *f; + struct iovec *iov; +{ + char p[6 + UNAMESZ]; + register int i; + int ttyf, len; + static int reenter = 0; + struct utmp ut; + struct utmp *uptr; + char greetings[200]; + + if (reenter++) + return; + + /* open the user login file */ + setutent(); + + + /* + * Might as well fork instead of using nonblocking I/O + * and doing notty(). + */ + if (fork() == 0) { + (void) signal(SIGTERM, SIG_DFL); + (void) alarm(0); + (void) signal(SIGALRM, endtty); +#ifndef SYSV + (void) signal(SIGTTOU, SIG_IGN); + (void) sigsetmask(0); +#endif + (void) snprintf(greetings, sizeof(greetings), + "\r\n\7Message from syslogd@%s at %.24s ...\r\n", + (char *) iov[2].iov_base, ctime(&now)); + len = strlen(greetings); + + /* scan the user login file */ + while ((uptr = getutent())) { + memcpy(&ut, uptr, sizeof(ut)); + /* is this slot used? */ + if (ut.ut_name[0] == '\0') + continue; + if (ut.ut_type == LOGIN_PROCESS) + continue; + if (!(strcmp (ut.ut_name,"LOGIN"))) /* paranoia */ + continue; + + /* should we send the message to this user? */ + if (f->f_type == F_USERS) { + for (i = 0; i < MAXUNAMES; i++) { + if (!f->f_un.f_uname[i][0]) { + i = MAXUNAMES; + break; + } + if (strncmp(f->f_un.f_uname[i], + ut.ut_name, UNAMESZ) == 0) + break; + } + if (i >= MAXUNAMES) + continue; + } + + /* compute the device name */ + strcpy(p, _PATH_DEV); + strncat(p, ut.ut_line, UNAMESZ); + + if (f->f_type == F_WALL) { + iov[0].iov_base = greetings; + iov[0].iov_len = len; + iov[1].iov_len = 0; + } + if (setjmp(ttybuf) == 0) { + (void) alarm(15); + /* open the terminal */ + ttyf = open(p, O_WRONLY|O_NOCTTY); + if (ttyf >= 0) { + struct stat statb; + + if (fstat(ttyf, &statb) == 0 && + (statb.st_mode & S_IWRITE)) + (void) writev(ttyf, iov, 6); + close(ttyf); + ttyf = -1; + } + } + (void) alarm(0); + } + exit(0); + } + /* close the user login file */ + endutent(); + reenter = 0; +} + +void reapchild() +{ + int saved_errno = errno; +#if defined(SYSV) && !defined(linux) + (void) signal(SIGCHLD, reapchild); /* reset signal handler -ASP */ + wait ((int *)0); +#else + union wait status; + + while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) + ; +#endif +#ifdef linux + (void) signal(SIGCHLD, reapchild); /* reset signal handler -ASP */ +#endif + errno = saved_errno; +} + +/* + * Return a printable representation of a host address. + */ +const char *cvthname(f) + struct sockaddr_in *f; +{ + struct hostent *hp; + register char *p; + int count; + + if (f->sin_family != AF_INET) { + dprintf("Malformed from address.\n"); + return ("???"); + } + hp = gethostbyaddr((char *) &f->sin_addr, sizeof(struct in_addr), \ + f->sin_family); + if (hp == 0) { + dprintf("Host name for your address (%s) unknown.\n", + inet_ntoa(f->sin_addr)); + return (inet_ntoa(f->sin_addr)); + } + /* + * Convert to lower case, just like LocalDomain above + */ + for (p = (char *)hp->h_name; *p ; p++) + if (isupper(*p)) + *p = tolower(*p); + + /* + * Notice that the string still contains the fqdn, but your + * hostname and domain are separated by a '\0'. + */ + if ((p = strchr(hp->h_name, '.'))) { + if (strcmp(p + 1, LocalDomain) == 0) { + *p = '\0'; + return (hp->h_name); + } else { + if (StripDomains) { + count=0; + while (StripDomains[count]) { + if (strcmp(p + 1, StripDomains[count]) == 0) { + *p = '\0'; + return (hp->h_name); + } + count++; + } + } + if (LocalHosts) { + count=0; + while (LocalHosts[count]) { + if (!strcmp(hp->h_name, LocalHosts[count])) { + *p = '\0'; + return (hp->h_name); + } + count++; + } + } + } + } + + return (hp->h_name); +} + +void domark() +{ + register struct filed *f; +#ifdef SYSV + int lognum; +#endif + + if (MarkInterval > 0) { + now = time(0); + MarkSeq += TIMERINTVL; + if (MarkSeq >= MarkInterval) { + logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); + MarkSeq = 0; + } + +#ifdef SYSV + for (lognum = 0; lognum <= nlogs; lognum++) { + f = &Files[lognum]; +#else + for (f = Files; f; f = f->f_next) { +#endif + if (f->f_prevcount && now >= REPEATTIME(f)) { + dprintf("flush %s: repeated %d times, %d sec.\n", + TypeNames[f->f_type], f->f_prevcount, + repeatinterval[f->f_repeatcount]); + fprintlog(f, LocalHostName, 0, (char *)NULL); + BACKOFF(f); + } + } + } + (void) signal(SIGALRM, domark); + (void) alarm(TIMERINTVL); +} + +void debug_switch() + +{ + dprintf("Switching debugging_on to %s\n", (debugging_on == 0) ? "true" : "false"); + debugging_on = (debugging_on == 0) ? 1 : 0; + signal(SIGUSR1, debug_switch); +} + + +/* + * Print syslogd errors some place. + */ +void logerror(type) + char *type; +{ + char buf[100]; + + dprintf("Called logerr, msg: %s\n", type); + + if (errno == 0) + (void) snprintf(buf, sizeof(buf), "syslogd: %s", type); + else + (void) snprintf(buf, sizeof(buf), "syslogd: %s: %s", type, strerror(errno)); + errno = 0; + logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); + return; +} + +void die(sig) + + int sig; + +{ + register struct filed *f; + char buf[100]; + int lognum; + int i; + int was_initialized = Initialized; + + Initialized = 0; /* Don't log SIGCHLDs in case we + receive one during exiting */ + + for (lognum = 0; lognum <= nlogs; lognum++) { + f = &Files[lognum]; + /* flush any pending output */ + if (f->f_prevcount) + fprintlog(f, LocalHostName, 0, (char *)NULL); + } + + Initialized = was_initialized; + if (sig) { + dprintf("syslogd: exiting on signal %d\n", sig); + (void) snprintf(buf, sizeof(buf), "exiting on signal %d", sig); + errno = 0; + logmsg(LOG_SYSLOG|LOG_INFO, buf, LocalHostName, ADDDATE); + } + + /* Close the UNIX sockets. */ + for (i = 0; i < nfunix; i++) + if (funix[i] != -1) + close(funix[i]); + /* Close the inet socket. */ + if (InetInuse) close(inetm); + + /* Clean-up files. */ + for (i = 0; i < nfunix; i++) + if (funixn[i] && funix[i] != -1) + (void)unlink(funixn[i]); +#ifndef TESTING + (void) remove_pid(PidFile); +#endif + exit(0); +} + +/* + * Signal handler to terminate the parent process. + */ +#ifndef TESTING +void doexit(sig) + int sig; +{ + exit (0); +} +#endif + +/* + * INIT -- Initialize syslogd from configuration table + */ + +void init() +{ + register int i, lognum; + register FILE *cf; + register struct filed *f; +#ifndef TESTING +#ifndef SYSV + register struct filed **nextp = (struct filed **) 0; +#endif +#endif + register char *p; + register unsigned int Forwarding = 0; +#ifdef CONT_LINE + char cbuf[BUFSIZ]; + char *cline; +#else + char cline[BUFSIZ]; +#endif + struct servent *sp; + + sp = getservbyname("syslog", "udp"); + if (sp == NULL) { + errno = 0; + logerror("network logging disabled (syslog/udp service unknown)."); + logerror("see syslogd(8) for details of whether and how to enable it."); + return; + } + LogPort = sp->s_port; + + /* + * Close all open log files and free log descriptor array. + */ + dprintf("Called init.\n"); + Initialized = 0; + if ( nlogs > -1 ) + { + dprintf("Initializing log structures.\n"); + + for (lognum = 0; lognum <= nlogs; lognum++ ) { + f = &Files[lognum]; + + /* flush any pending output */ + if (f->f_prevcount) + fprintlog(f, LocalHostName, 0, (char *)NULL); + + switch (f->f_type) { + case F_FILE: + case F_PIPE: + case F_TTY: + case F_CONSOLE: + (void) close(f->f_file); + break; + } + } + + /* + * This is needed especially when HUPing syslogd as the + * structure would grow infinitively. -Joey + */ + nlogs = -1; + free((void *) Files); + Files = (struct filed *) 0; + } + + +#ifdef SYSV + lognum = 0; +#else + f = NULL; +#endif + + /* open the configuration file */ + if ((cf = fopen(ConfFile, "r")) == NULL) { + dprintf("cannot open %s.\n", ConfFile); +#ifdef SYSV + allocate_log(); + f = &Files[lognum++]; +#ifndef TESTING + cfline("*.err\t" _PATH_CONSOLE, f); +#else + snprintf(cbuf,sizeof(cbuf), "*.*\t%s", ttyname(0)); + cfline(cbuf, f); +#endif +#else + *nextp = (struct filed *)calloc(1, sizeof(*f)); + cfline("*.ERR\t" _PATH_CONSOLE, *nextp); + (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)) /* ASP */ + cfline("*.PANIC\t*", (*nextp)->f_next); +#endif + Initialized = 1; + return; + } + + /* + * Foreach line in the conf table, open that file. + */ +#if CONT_LINE + cline = cbuf; + while (fgets(cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { +#else + while (fgets(cline, sizeof(cline), cf) != NULL) { +#endif + /* + * check for end-of-section, comments, strip off trailing + * spaces and newline character. + */ + for (p = cline; isspace(*p); ++p); + if (*p == '\0' || *p == '#') + continue; +#if CONT_LINE + strcpy(cline, p); +#endif + for (p = strchr(cline, '\0'); isspace(*--p);); +#if CONT_LINE + if (*p == '\\') { + if ((p - cbuf) > BUFSIZ - 30) { + /* Oops the buffer is full - what now? */ + cline = cbuf; + } else { + *p = 0; + cline = p; + continue; + } + } else + cline = cbuf; +#endif + *++p = '\0'; +#ifndef SYSV + f = (struct filed *)calloc(1, sizeof(*f)); + *nextp = f; + nextp = &f->f_next; +#endif + allocate_log(); + f = &Files[lognum++]; +#if CONT_LINE + cfline(cbuf, f); +#else + cfline(cline, f); +#endif + if (f->f_type == F_FORW || f->f_type == F_FORW_SUSP || f->f_type == F_FORW_UNKN) { + Forwarding++; + } + } + + /* close the configuration file */ + (void) fclose(cf); + +#ifdef SYSLOG_UNIXAF + for (i = 0; i < nfunix; i++) { + if (funix[i] != -1) + /* Don't close the socket, preserve it instead + close(funix[i]); + */ + continue; + if ((funix[i] = create_unix_socket(funixn[i])) != -1) + dprintf("Opened UNIX socket `%s'.\n", funixn[i]); + } +#endif + +#ifdef SYSLOG_INET + if (Forwarding || AcceptRemote) { + if (finet < 0) { + finet = create_inet_socket(); + if (finet >= 0) { + InetInuse = 1; + dprintf("Opened syslog UDP port.\n"); + } + } + } + else { + if (finet >= 0) + close(finet); + finet = -1; + InetInuse = 0; + } + inetm = finet; +#endif + + Initialized = 1; + + if ( Debug ) { +#ifdef SYSV + for (lognum = 0; lognum <= nlogs; lognum++) { + f = &Files[lognum]; + if (f->f_type != F_UNUSED) { + printf ("%2d: ", lognum); +#else + for (f = Files; f; f = f->f_next) { + if (f->f_type != F_UNUSED) { +#endif + for (i = 0; i <= LOG_NFACILITIES; i++) + if (f->f_pmask[i] == TABLE_NOPRI) + printf(" X "); + else + printf("%2X ", f->f_pmask[i]); + printf("%s: ", TypeNames[f->f_type]); + switch (f->f_type) { + case F_FILE: + case F_PIPE: + case F_TTY: + case F_CONSOLE: + printf("%s", f->f_un.f_fname); + if (f->f_file == -1) + printf(" (unused)"); + break; + + case F_FORW: + case F_FORW_SUSP: + case F_FORW_UNKN: + printf("%s", f->f_un.f_forw.f_hname); + break; + + case F_USERS: + for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) + printf("%s, ", f->f_un.f_uname[i]); + break; + } + printf("\n"); + } + } + } + + if ( AcceptRemote ) +#ifdef DEBRELEASE + logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \ + ": restart (remote reception)." , LocalHostName, \ + ADDDATE); +#else + logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \ + ": restart (remote reception)." , LocalHostName, \ + ADDDATE); +#endif + else +#ifdef DEBRELEASE + logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \ + ": restart." , LocalHostName, ADDDATE); +#else + logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \ + ": restart." , LocalHostName, ADDDATE); +#endif + (void) signal(SIGHUP, sighup_handler); + dprintf("syslogd: restarted.\n"); +} +#if FALSE + }}} /* balance parentheses for emacs */ +#endif + +/* + * Crack a configuration file line + */ + +void cfline(line, f) + char *line; + register struct filed *f; +{ + register char *p; + register char *q; + register int i, i2; + char *bp; + int pri; + int singlpri = 0; + int ignorepri = 0; + int syncfile; +#ifdef SYSLOG_INET + struct hostent *hp; +#endif + char buf[MAXLINE]; + char xbuf[200]; + + dprintf("cfline(%s)\n", line); + + errno = 0; /* keep strerror() stuff out of logerror messages */ + + /* clear out file entry */ +#ifndef SYSV + memset((char *) f, 0, sizeof(*f)); +#endif + for (i = 0; i <= LOG_NFACILITIES; i++) { + f->f_pmask[i] = TABLE_NOPRI; + f->f_flags = 0; + } + + /* scan through the list of selectors */ + for (p = line; *p && *p != '\t' && *p != ' ';) { + + /* find the end of this facility name list */ + for (q = p; *q && *q != '\t' && *q++ != '.'; ) + continue; + + /* collect priority name */ + for (bp = buf; *q && !strchr("\t ,;", *q); ) + *bp++ = *q++; + *bp = '\0'; + + /* skip cruft */ + while (strchr(",;", *q)) + q++; + + /* decode priority name */ + if ( *buf == '!' ) { + ignorepri = 1; + for (bp=buf; *(bp+1); bp++) + *bp=*(bp+1); + *bp='\0'; + } + else { + ignorepri = 0; + } + if ( *buf == '=' ) + { + singlpri = 1; + pri = decode(&buf[1], PriNames); + } + else { + singlpri = 0; + pri = decode(buf, PriNames); + } + + if (pri < 0) { + (void) snprintf(xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf); + logerror(xbuf); + return; + } + + /* scan facilities */ + while (*p && !strchr("\t .;", *p)) { + for (bp = buf; *p && !strchr("\t ,;.", *p); ) + *bp++ = *p++; + *bp = '\0'; + if (*buf == '*') { + for (i = 0; i <= LOG_NFACILITIES; i++) { + if ( pri == INTERNAL_NOPRI ) { + if ( ignorepri ) + f->f_pmask[i] = TABLE_ALLPRI; + else + f->f_pmask[i] = TABLE_NOPRI; + } + else if ( singlpri ) { + if ( ignorepri ) + f->f_pmask[i] &= ~(1<<pri); + else + f->f_pmask[i] |= (1<<pri); + } + else + { + if ( pri == TABLE_ALLPRI ) { + if ( ignorepri ) + f->f_pmask[i] = TABLE_NOPRI; + else + f->f_pmask[i] = TABLE_ALLPRI; + } + else + { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + f->f_pmask[i] &= ~(1<<i2); + else + for (i2= 0; i2 <= pri; ++i2) + f->f_pmask[i] |= (1<<i2); + } + } + } + } else { + i = decode(buf, FacNames); + if (i < 0) { + + (void) snprintf(xbuf, sizeof(xbuf), "unknown facility name \"%s\"", buf); + logerror(xbuf); + return; + } + + if ( pri == INTERNAL_NOPRI ) { + if ( ignorepri ) + f->f_pmask[i >> 3] = TABLE_ALLPRI; + else + f->f_pmask[i >> 3] = TABLE_NOPRI; + } else if ( singlpri ) { + if ( ignorepri ) + f->f_pmask[i >> 3] &= ~(1<<pri); + else + f->f_pmask[i >> 3] |= (1<<pri); + } else { + if ( pri == TABLE_ALLPRI ) { + if ( ignorepri ) + f->f_pmask[i >> 3] = TABLE_NOPRI; + else + f->f_pmask[i >> 3] = TABLE_ALLPRI; + } else { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + f->f_pmask[i >> 3] &= ~(1<<i2); + else + for (i2= 0; i2 <= pri; ++i2) + f->f_pmask[i >> 3] |= (1<<i2); + } + } + } + while (*p == ',' || *p == ' ') + p++; + } + + p = q; + } + + /* skip to action part */ + while (*p == '\t' || *p == ' ') + p++; + + if (*p == '-') + { + syncfile = 0; + p++; + } else + syncfile = 1; + + dprintf("leading char in action: %c\n", *p); + switch (*p) + { + case '@': +#ifdef SYSLOG_INET + (void) strcpy(f->f_un.f_forw.f_hname, ++p); + dprintf("forwarding host: %s\n", p); /*ASP*/ + if ( (hp = gethostbyname(p)) == NULL ) { + f->f_type = F_FORW_UNKN; + f->f_prevcount = INET_RETRY_MAX; + f->f_time = time ( (time_t *)0 ); + } else { + f->f_type = F_FORW; + } + + memset((char *) &f->f_un.f_forw.f_addr, 0, + sizeof(f->f_un.f_forw.f_addr)); + f->f_un.f_forw.f_addr.sin_family = AF_INET; + f->f_un.f_forw.f_addr.sin_port = LogPort; + if ( f->f_type == F_FORW ) + memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); + /* + * Otherwise the host might be unknown due to an + * inaccessible nameserver (perhaps on the same + * host). We try to get the ip number later, like + * FORW_SUSP. + */ +#endif + break; + + case '|': + case '/': + (void) strcpy(f->f_un.f_fname, p); + dprintf ("filename: %s\n", p); /*ASP*/ + if (syncfile) + f->f_flags |= SYNC_FILE; + if ( *p == '|' ) { + f->f_file = open(++p, O_RDWR|O_NONBLOCK); + f->f_type = F_PIPE; + } else { + f->f_file = open(p, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + 0644); + f->f_type = F_FILE; + } + + if ( f->f_file < 0 ){ + f->f_file = -1; + dprintf("Error opening log file: %s\n", p); + logerror(p); + break; + } + if (isatty(f->f_file)) { + f->f_type = F_TTY; + untty(); + } + if (strcmp(p, ctty) == 0) + f->f_type = F_CONSOLE; + break; + + case '*': + dprintf ("write-all\n"); + f->f_type = F_WALL; + break; + + default: + dprintf ("users: %s\n", p); /* ASP */ + for (i = 0; i < MAXUNAMES && *p; i++) { + for (q = p; *q && *q != ','; ) + q++; + (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ); + if ((q - p) > UNAMESZ) + f->f_un.f_uname[i][UNAMESZ] = '\0'; + else + f->f_un.f_uname[i][q - p] = '\0'; + while (*q == ',' || *q == ' ') + q++; + p = q; + } + f->f_type = F_USERS; + break; + } + return; +} + + +/* + * Decode a symbolic name to a numeric value + */ + +int decode(name, codetab) + char *name; + struct code *codetab; +{ + register struct code *c; + register char *p; + char buf[80]; + + dprintf ("symbolic name: %s", name); + if (isdigit(*name)) + { + dprintf ("\n"); + return (atoi(name)); + } + (void) strncpy(buf, name, 79); + for (p = buf; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + for (c = codetab; c->c_name; c++) + if (!strcmp(buf, c->c_name)) + { + dprintf (" ==> %d\n", c->c_val); + return (c->c_val); + } + return (-1); +} + +static void dprintf(char *fmt, ...) + +{ + va_list ap; + + if ( !(Debug && debugging_on) ) + return; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); + + fflush(stdout); + return; +} + + +/* + * The following function is responsible for allocating/reallocating the + * array which holds the structures which define the logging outputs. + */ +static void allocate_log() + +{ + dprintf("Called allocate_log, nlogs = %d.\n", nlogs); + + /* + * Decide whether the array needs to be initialized or needs to + * grow. + */ + if ( nlogs == -1 ) + { + Files = (struct filed *) malloc(sizeof(struct filed)); + if ( Files == (void *) 0 ) + { + dprintf("Cannot initialize log structure."); + logerror("Cannot initialize log structure."); + return; + } + } + else + { + /* Re-allocate the array. */ + Files = (struct filed *) realloc(Files, (nlogs+2) * \ + sizeof(struct filed)); + if ( Files == (struct filed *) 0 ) + { + dprintf("Cannot grow log structure."); + logerror("Cannot grow log structure."); + return; + } + } + + /* + * Initialize the array element, bump the number of elements in the + * the array and return. + */ + ++nlogs; + memset(&Files[nlogs], '\0', sizeof(struct filed)); + return; +} + + +/* + * The following function is resposible for handling a SIGHUP signal. Since + * we are now doing mallocs/free as part of init we had better not being + * doing this during a signal handler. Instead this function simply sets + * a flag variable which will tell the main loop to go through a restart. + */ +void sighup_handler() + +{ + restart = 1; + signal(SIGHUP, sighup_handler); + return; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ + diff --git a/version.h b/version.h new file mode 100644 index 00000000..3188fc38 --- /dev/null +++ b/version.h @@ -0,0 +1,2 @@ +#define VERSION "1.4" +#define PATCHLEVEL "1" |