From 05f2f1839c2712ca77e86aa679dc909d051fc23b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 8 Nov 2004 13:52:36 +0000 Subject: Initial revision --- ANNOUNCE | 62 ++ CHANGES | 32 + COPYING | 339 +++++++ INSTALL | 37 + MANIFEST | 62 ++ Makefile | 122 +++ NEWS | 170 ++++ README.1st | 65 ++ README.linux | 72 ++ klogd.8 | 441 +++++++++ klogd.c | 1191 +++++++++++++++++++++++ klogd.h | 40 + ksym.c | 901 ++++++++++++++++++ ksym_mod.c | 700 ++++++++++++++ ksyms.h | 35 + modutils.patch | 65 ++ oops.c | 118 +++ oops_test.c | 52 ++ pidfile.c | 130 +++ pidfile.h | 50 + sysklogd.8 | 607 ++++++++++++ syslog-tst.conf | 0 syslog.c | 254 +++++ syslog.conf | 46 + syslog.conf.5 | 397 ++++++++ syslog_tst.c | 74 ++ syslogd.8 | 1 + syslogd.c | 2803 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ version.h | 2 + 29 files changed, 8868 insertions(+) create mode 100644 ANNOUNCE create mode 100644 CHANGES create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 MANIFEST create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README.1st create mode 100644 README.linux create mode 100644 klogd.8 create mode 100644 klogd.c create mode 100644 klogd.h create mode 100644 ksym.c create mode 100644 ksym_mod.c create mode 100644 ksyms.h create mode 100644 modutils.patch create mode 100644 oops.c create mode 100644 oops_test.c create mode 100644 pidfile.c create mode 100644 pidfile.h create mode 100644 sysklogd.8 create mode 100644 syslog-tst.conf create mode 100644 syslog.c create mode 100644 syslog.conf create mode 100644 syslog.conf.5 create mode 100644 syslog_tst.c create mode 100644 syslogd.8 create mode 100644 syslogd.c create mode 100644 version.h 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 + - 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 + - printline() fixes + - priority decoding fix + . Daniel Jacobowitz + - printchopped() fix + . Keith Owens + - 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 + - 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. + + + Copyright (C) 19yy + + 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. + + , 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 diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..94d281c5 --- /dev/null +++ b/NEWS @@ -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 + + 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 + * 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 . + * + * Thu Aug 21 12:11:27 MET DST 1997: Martin Schulze + * Fixed little mistake which prevented klogd from accepting a + * console log + * + * Fri Jan 9 00:39:52 CET 1998: Martin Schulze + * 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 + * 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 for + * informing me. + * + * Fri Jan 9 23:38:19 CET 1998: Florian La Roche + * Added -x switch to omit EIP translation and System.map evaluation. + * + * Sun Jan 25 20:47:46 CET 1998: Martin Schulze + * 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 + * 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 + * 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 + * Used unsigned long and strtoul() to resolve kernel oops symbols. + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze + * 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 + * Skip newline when reading in messages. + * + * Tue Sep 12 22:14:33 CEST 2000: Martin Schulze + * Don't feed a buffer directly to a printf-type routine, use + * "%s" as format string instead. Thanks to Jouko Pynnönen + * for pointing this out. + * + * Tue Sep 12 22:44:57 CEST 2000: Martin Schulze + * 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 + * for the patch. + * + * Mon Sep 18 09:32:27 CEST 2000: Martin Schulze + * Added patch to fix priority decoding after moving kernel + * messgages into "%s". Thanks to Solar Designer + * for the patch. + * + * Sun Mar 11 20:23:44 CET 2001: Martin Schulze + * Stop LogLine() from being called with wrong argument when a + * former calculation failed already. Thanks to Thomas Roessler + * for providing a patch. + * + * Ignore zero bytes, no busy loop is entered anymore. Several + * people have submitted patches: Troels Walsted Hansen + * , Wolfgang Oertl + * and Thomas Roessler. + */ + + +/* Includes. */ +#include +#include +#include +#include +#include +#if !defined(__GLIBC__) +#include +#endif /* __GLIBC__ */ +#include +#include +#include +#include "klogd.h" +#include "ksyms.h" +#ifndef TESTING +#include "pidfile.h" +#endif +#include "version.h" + +#define __LIBRARY__ +#include +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include +#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]", + * 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 + + 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 +#include +#include + + +/* 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, ...); diff --git a/ksym.c b/ksym.c new file mode 100644 index 00000000..0a6d7151 --- /dev/null +++ b/ksym.c @@ -0,0 +1,901 @@ +/* + ksym.c - functions for kernel address->symbol translation + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + 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 + * 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 + * Switched to fgets() as gets() is not buffer overrun secure. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze + * 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 + * 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 + * Fixed bug that caused klogd to die if there is no sym_array available. + * + * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze + * Close symbol file in InitKsyms() when an error occurred. + */ + + +/* Includes. */ +#include +#include +#include +#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 + +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 + 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 . + * + * Sat Jan 10 15:00:18 CET 1998: Martin Schulze + * 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 . + * + * Sun Jan 25 20:57:34 CET 1998: Martin Schulze + * Another patch for Linux/alpha by Christopher C Chimelis + * . + * + * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues + * 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 + * Removed as it's no longer part of recent glibc + * versions. Added prototyp for llseek() which has been + * forgotton in from glibc. Added more log + * information if problems occurred while reading a system map + * file, by submission from Mark Simon Phillips . + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze + * 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 . + * + * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze + * Changed llseek() to lseek64() in order to skip a libc warning. + */ + + +/* Includes. */ +#include +#include +#include +#include +#include +#include +#include +#if !defined(__GLIBC__) +#include +#include +#else /* __GLIBC__ */ +#include +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 +#include +#include + +#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 +#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 + + +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 + 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; + } diff --git a/oops.c b/oops.c new file mode 100644 index 00000000..14573f0f --- /dev/null +++ b/oops.c @@ -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 +#include +#include +#include + +/* Standard module stuff. */ +#if defined(NEW_MODULES) +#include +#else +#include +#include +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 + X(oops_open), + X(oops_ioctl), + X(oops), +#include +}; + +/* 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 +#include +#include +#include + + +/* 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 + + 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 +#include +#include +#include +#include +#include +#include + +/* 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 + + 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 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 + * Use SOCK_DGRAM for loggin, renables it to work. + * + */ + +#include +#include +#include +#include +#include +#if 0 +#include "syslog.h" +#include "pathnames.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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' && t1iov_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 +.\" +.\" 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 +#include +#include +#include +#include + +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 "" 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 + * 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 + * for sending me a patch. + * + * Mon May 20 13:29:32 MET DST 1996: Miquel van Smoorenburg + * 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 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 + * 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 . + * + * Thu Jan 1 16:04:52 CET 1998: Martin Schulze . + * 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 for fiddling this out. + * + * Thu Jan 8 22:46:35 CET 1998: Martin Schulze + * 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 + * Fixed small bugs in F_FORW_UNKN meachanism. Thanks to Torsten + * Neumann for pointing me to it. + * + * Mon Jan 12 19:50:58 CET 1998: Martin Schulze + * Modified debug output concerning remote receiption. + * + * Mon Feb 23 23:32:35 CET 1998: Topi Miettinen + * 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 + * Fixed little comparison mistake that prevented the MARK + * feature to work properly. + * + * Wed Feb 25 13:21:44 CET 1998: Martin Schulze + * 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 + * 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 + * 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 + * Redirected some error output with regard to argument parsing to + * stderr. + * + * Mon Oct 12 14:02:51 CEST 1998: Martin Schulze + * 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 + * 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 + * Code cleanups with regard to bsd -> posix transition and + * stronger security (buffer length checking). Thanks to Topi + * Miettinen + * . index() --> strchr() + * . sprintf() --> snprintf() + * . bcopy() --> memcpy() + * . bzero() --> memset() + * . UNAMESZ --> UT_NAMESIZE + * . sys_errlist --> strerror() + * + * Mon Oct 12 20:22:59 CEST 1998: Martin Schulze + * 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 . + * + * Mon Oct 12 20:49:18 MET DST 1998: Martin Schulze + * 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 + * Modified printline() to support 8bit characters - such as + * russion letters. Thanks to Vladas Lapinskas . + * + * Sat Nov 14 02:29:37 CET 1998: Martin Schulze + * ``-m 0'' now turns of MARK logging entirely. + * + * Tue Jan 19 01:04:18 MET 1999: Martin Schulze + * Finally fixed an error with `-a' processing, thanks to Topi + * Miettinen . + * + * Sun May 23 10:08:53 CEST 1999: Martin Schulze + * 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 + * 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 + * . + * + * Sun Sep 17 21:26:16 CEST 2000: Martin Schulze + * Don't close open sockets upon reload. Thanks to Bill + * Nottingham. + * + * Mon Sep 18 09:10:47 CEST 2000: Martin Schulze + * Fixed bug in printchopped() that caused syslogd to emit + * kern.emerg messages when splitting long lines. Thanks to + * Daniel Jacobowitz for the fix. + * + * Mon Sep 18 15:33:26 CEST 2000: Martin Schulze + * 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 for the patch. + * + * Sun Mar 11 20:23:44 CET 2001: Martin Schulze + * Don't return a closed fd if `-a' is called with a wrong path. + * Thanks to Bill Nottingham 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 +#include +#include +#ifdef SYSV +#include +#endif +#include +#include +#include +#include +#include +#include + +#define SYSLOG_NAMES +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SYSV +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifndef TESTING +#include "pidfile.h" +#endif +#include "version.h" + +#if defined(__linux__) +#include +#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<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<f_pmask[i] |= (1<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<f_pmask[i] |= (1<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<f_pmask[i >> 3] |= (1<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<f_pmask[i >> 3] |= (1<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" -- cgit v1.2.3