Get syslog to do your bidding and send logs to a remote machine.
A quick run-through on how to make syslogd be promiscuous and take logs from strangers.From the man page:
Syslogd reads and logs messages to the system console, log files,
other machines and/or users as specified by its configuration file.
Sometimes it’s useful to take advantage of that third part of syslog: logging to other machines. I wanted to log when users logged in but did not receive a kerberos ticket, and I wanted to be able to check just one log. Maybe that wasn’t the best way to attack my specific problem, but it worked for me, and I thought you might benefit from my findings.
It is not too much work to modify syslogd’s configuration files
on Mac OS X to send logging information to a remote syslogd host. Similarly, it is a relatively straightforward task to change the syslogd flags so that it accepts log messages from other machines.
Note: the man page for syslogd is currently out of date. I used the freebsd man page for syslogd when configuring my setup.
One reason to do centralized logging: It is easy to monitor one centralized log in realtime, either with the Console application or with “tail -f” in the command line.
One reason to not do centralized logging is security. If you tell syslogd to accept logging messages from a particular IP address or range of IP addresses, it doesn’t do any authentication, and IP addresses are easy to spoof. The logging messages are sent in cleartext. For what it’s worth, you must leave UDP port 541 open to remote logging clients.
Consider an alternative: use crontab and scp to securely copy the log files from various hosts (see related afp548.com article about
ssh to use scp without passwords). Note that you will have to figure out how to extend this if you want to do realtime log monitoring.
Some things to think about before you dive in:
- What is it you are trying to log?
- Who will send the logging messages?
- Who will receive the logging messages?
- What facility and priority (a.k.a severity) will you use? I just picked from local1-local7, and debug. If you really want deeper understanding, check out RFC3164, which defines the syslog protocol.
Here are the actual steps:
-
Set up the syslog server to accept remote logging messages.
Warning: making a mistake when you edit /private/etc/rc can really ruin your day. You know the drill,
backup (and make backup of the rc file) before continuing.-
<code> <p> Modify (as root) /private/etc/rc to allow remote logging messages. The default line relevant here is <pre>/usr/sbin/syslogd -s -m 0</pre> The <tt> -s</tt> flag disallows remote submissions. You want to remove that. Add the <tt> -a</tt> flag, which defines allowed peers. If you want to allow messages from any IP address starting with <tt>10.1</tt>, you can specify <tt> -a 10.1.0.0/16</tt>. So in my case, I used <pre>/usr/sbin/syslogd -m 0 -a 10.0.0.0/8</pre> </li> <li> Modify (as root) /private/etc/syslog.conf to tell syslogd where to stash the logging messages. If you want local2.debug messages to go to /var/log/local2.log, add the following line to /private/etc/syslog.conf:local2 <pre>local2.log /var/log/local2.log</pre> </li> <li> Create (as root) the log files if they don't already exist <pre>sudo touch /var/log/local2.log</pre> </li> <li> Kill and restart syslogd. It's not enough to send a HUP signal. <p> <tt> sudo killall syslogd <p> sudo /usr/sbin/syslogd -m 0 -a 10.0.0.0/8 </tt> </li> <li> Beyond the scope of this article: logging rotation. Sorry. </li> <p> </ul> <li> Set up the computers which will send messages <p> <ol> <li> Modify (as root)<tt>/private/etc/syslog.conf</tt>, specifying which facility.priority you'd like and the remote logging host <p> Example: <pre>local7.* @66.92.134.160</pre> Will send the all local7 logging messages to the machine at IP address 66.92.134.160. </li> <li> Tell syslogd to reload its configuration <p> <tt>sudo killall -HUP syslogd</tt> </li> </ol> </li> <p> <li> Test <p> <ol> <li> On the remote clent, use the <tt>logger</tt> command: <p> <tt>logger -p <i>facility.priority message</i></tt> <p> <tt>logger -p local1.debug "Quota reached - Good joerb"</tt> <p> </li> <li> Look at the log on the central logging host, using Console or <tt>tail</tt>. <p> <tt>tail -f /var/log/local.log</tt> </li> </ol> </li> </ol> </code>
Gotchas to watch out for in your testing and in general use:
-
Exclamation point from the shell
Your shell may try to use history substitution if use use ! with logger
logger -p local5.debug "This will not work!"
logger -p local5.debug "This will work, but it is a cheesy hack with a space after exclamation point! "
logger -p local5.debug 'This will work because of the single quote instead of double quote!'
logger -p local5.debug It is OK to not use quotes at all!
-
Repeated messages (with duplicate content) might not show up immediately, as in:
Last message repeated 47 times
My example
You can stop reading now, but you might be interested in how I applied centralized logging.
I wanted to know if there is ever a user who logs in but has not received any Kerberos tickets, signalling that user may be a victim of trying to convert too many users at once from password type of shadow to password type of Open Directory (don’t try to change more than around 100 users at once in Workgroup Manager!). One non-intrusive fix for this is to ask the user to manually change their password.
I also wanted to know if a user logs in but someone else already has an afp volume mounted, signalling possible but likely automount problems. I also have a logout hook which logs if the user logs out but they still have AFP volumes mounted while they log out. Bad situation!
One complication is that loginhooks are run as root but I want to check for kerberos tickets for the user (logouthooks are run as the currently logging out user).
I used su -c to run a command as the currently logging in user. klist -s returns 0 if there are no tickets, or 1 if the user does have >0 tickets. I sent a message if the klist -s returns 0.
Here are three scripts for your perusal:
-
The login script, which pretty much sums up this article in its comments
and sets the stage for the other two scripts.#!/bin/sh #/Library/Hooks/LoginInfo.sh #Arek Dreyer [email protected] # Login hook to test whether or not a user has received a TGT on login # Loginhooks are run with the username in $1 # klist will normally list the kerberos tickets, # but in silent mode, it will return # 0 if there are tickets # 1 if there are no tickets # # Rather than output to a local log, output to the LOCAL1 facility, using # in this example, a host at 66.92.134.160. We specify the default port 514, # but we don't really have to. # At each local machine, add the line to /etc/syslog.conf (without leading #) #local1.debug @66.92.134.160:514 #local3.debug @66.92.134.160:514 # # # Then tell the syslogd about the new change: # sudo killall -HUP syslogd # # At the central logging host, #add the following to the end of /etc/syslog.conf: #local1.* /var/log/LoginHook.sh #local3.* /var/log/LogoutHook.sh # # At the central logging host, edit /etc/rc so that the syslogd will accept # messages from hosts on its local subnet # Old: # #/usr/sbin/syslogd -s -m 0 # New: # Syslogd flags: # -s Operate in secure mode. Do not log messages from remote # machines. If specified twice, no network socket will be opened # at all, which also disables logging to remote machines. # -a allowed_peer # Allow allowed_peer to log to this syslogd using UDP datagrams. # Multiple -a options may be specified. # /usr/sbin/syslogd -a 10.0.0.0/8 -m 0 # # # You'll have to actually stop syslogd and start it with the new flags: # (On the central logging host) # sudo killall syslogd # sudo /usr/sbin/syslogd -a 10.0.0.0/8 -m 0 # PATH=/bin:/usr/bin; export PATH USER=$1 /usr/bin/su ${USER} -c "/usr/bin/klist -s" KRESULT=$? if [ ${KRESULT} -eq 1 ] then /usr/bin/logger -p local1.debug "No tickets for ${USER}" fi MOUNTS=$(/sbin/mount | /usr/bin/grep afp | grep -v ${USER}) if [ -n "${MOUNTS}" ] then logger -p local1.debug "${MOUNTS}" fi
-
The logout script:
#!/bin/sh #/Library/Hooks/LogoutInfo.sh #Arek Dreyer [email protected] PATH=/bin:/usr/bin; export PATH USER=$1 MOUNTS=$(/sbin/mount | /usr/bin/grep afp | grep -v ${USER}) if [ -n "${MOUNTS}" ] then logger -p local3.debug "${MOUNTS}" else logger -p local3.debug "${USER} logged out." fi
-
A script to set things up on a logging client
#!/bin/sh #LoginHookSetup.sh #Arek Dreyer [email protected] PATH=/bin:/usr/bin; export PATH defaults write com.apple.loginwindow LoginHook /Library/Hooks/LoginInfo.sh defaults write com.apple.loginwindow LogoutHook /Library/Hooks/LogoutInfo.sh killall -HUP syslogd
Any questions?
-
Exclamation point from the shell
-
The author mentions that adding log rotation is beyond the scope of the
article, but it’s actually pretty simple. As long as you’re storing your new
syslogd log file somewhere in /var/log, then just open the ‘/etc/periodic/
weekly/500.weekly’ file and look for the section that begins like so:
printf %s "Rotating log files:"
cd /var/log
Then add your logfile name (as specified in the article steps) to the line that
starts:
for i in http://ftp.log lookupd.log (etc).
Simple!
syslogd is now started by launchctl in 10.4.3, and has moved from /private/etc/rc – see
/System/Library/LaunchDaemons/com.apple.syslogd.plist
Russ
This article is for Panther. [story:20050816135035340] is for Tiger.