--- netkit-rwho-0.17.orig/debian/copyright +++ netkit-rwho-0.17/debian/copyright @@ -0,0 +1,16 @@ +This package was split from netstd by Herbert Xu herbert@debian.org on +Tue, 2 Nov 1999 14:47:51 +1100. + +netstd was created by Peter Tobias tobias@et-inf.fho-emden.de on +Wed, 20 Jul 1994 17:23:21 +0200. + +It was downloaded from ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/. + +Copyright: + +Copyright (c) 1983-1991 The Regents of the University of California. +Copyright (c) 1993 Peter Eriksson, Signum Support AB + +The license can be found in /usr/share/common-licenses/BSD. + +$Id: copyright,v 1.2 2000/07/18 11:48:41 herbert Exp $ --- netkit-rwho-0.17.orig/debian/rwho.dirs +++ netkit-rwho-0.17/debian/rwho.dirs @@ -0,0 +1,2 @@ +usr/bin +usr/share/man/man1 --- netkit-rwho-0.17.orig/debian/rwhod.cron.monthly +++ netkit-rwho-0.17/debian/rwhod.cron.monthly @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id: rwhod.cron.monthly,v 1.1 2001/10/06 02:09:28 herbert Exp $ + +find /var/spool/rwho -mindepth 1 -mtime +30 -print0 | xargs -r0 rm --- netkit-rwho-0.17.orig/debian/rwhod.default +++ netkit-rwho-0.17/debian/rwhod.default @@ -0,0 +1,2 @@ +# Options for the rwhod daemon. +RWHOD_OPTIONS="-b" --- netkit-rwho-0.17.orig/debian/rwhod.dirs +++ netkit-rwho-0.17/debian/rwhod.dirs @@ -0,0 +1,2 @@ +usr/sbin +usr/share/man/man8 --- netkit-rwho-0.17.orig/debian/rwhod.docs +++ netkit-rwho-0.17/debian/rwhod.docs @@ -0,0 +1 @@ +README --- netkit-rwho-0.17.orig/debian/rwhod.postinst +++ netkit-rwho-0.17/debian/rwhod.postinst @@ -0,0 +1,10 @@ +#!/bin/sh -e +# $Id: rwhod.postinst,v 1.2 1999/11/12 22:13:05 herbert Exp $ + +if ! id -u rwhod >/dev/null 2>&1; then + adduser --quiet --system --home /var/spool/rwho rwhod +fi +mkdir -p -m 755 /var/spool/rwho +chown -R rwhod /var/spool/rwho + +#DEBHELPER# --- netkit-rwho-0.17.orig/debian/rwhod.postrm +++ netkit-rwho-0.17/debian/rwhod.postrm @@ -0,0 +1,10 @@ +#!/bin/sh -e +# $Id: rwhod.postrm,v 1.2 1999/11/12 04:58:48 herbert Exp $ + +if [ "$1" = purge ]; then + if command -v userdel >/dev/null 2>&1; then + userdel -r rwhod + fi +fi + +#DEBHELPER# --- netkit-rwho-0.17.orig/debian/rwhod.preinst +++ netkit-rwho-0.17/debian/rwhod.preinst @@ -0,0 +1,10 @@ +#!/bin/sh -e +# $Id: rwhod.preinst,v 1.2 1999/11/14 22:32:47 herbert Exp $ + +# If we're upgrading from and old version of netstd, make sure that we stop +# their rwhod server if it's running. +if [ "$1" = install -a -x /etc/init.d/netstd_misc -a -x /usr/sbin/rwhod ]; then + start-stop-daemon --stop --quiet --oknodo --exec /usr/sbin/rwhod +fi + +#DEBHELPER# --- netkit-rwho-0.17.orig/debian/rwhod.init +++ netkit-rwho-0.17/debian/rwhod.init @@ -0,0 +1,71 @@ +#!/bin/sh -e + +### BEGIN INIT INFO +# Provides: rwhod +# Required-Start: $remote_fs $network $syslog +# Required-Stop: $remote_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Server for rwho and ruptime services +### END INIT INFO + +# rwhod Startup script for the rwhod server. +# +# Modified for rwhod +# by Herbert Xu +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# Improved for option handling and LSB compliance +# by Alberto Gonzalez Iniesta +# +# Version: $Id: rwhod.init,v 1.5 2000/07/18 12:25:51 herbert Exp $ + +test $DEBIAN_SCRIPT_DEBUG && set -v -x + +DESC="System status server" +DAEMON="/usr/sbin/rwhod" +CONF_FILE="/etc/default/rwhod" +# default options. Change them in /etc/default/rwhod +RWHOD_OPTIONS="-b" + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +if test -e $CONF_FILE ; then + . $CONF_FILE +fi + +start_stop() { + case "$1" in + start) + log_daemon_msg "Starting $DESC" "rwhod" + start-stop-daemon --start --oknodo --quiet \ + --exec $DAEMON -- $RWHOD_OPTIONS + log_end_msg $? + ;; + stop) + log_daemon_msg "Stopping $DESC" "rwhod" + start-stop-daemon --stop --oknodo --quiet \ + --exec $DAEMON + log_end_msg $? + ;; + restart | force-reload) + start_stop stop + sleep 1 + start_stop start + ;; + status) + status_of_proc $DAEMON "rwhod" + ;; + *) + log_success_msg "Usage: $0 {start|stop|restart|force-reload|status}\n" >&2 + exit 1 + ;; + esac +} + +start_stop "$@" + +exit 0 --- netkit-rwho-0.17.orig/debian/compat +++ netkit-rwho-0.17/debian/compat @@ -0,0 +1 @@ +7 --- netkit-rwho-0.17.orig/debian/changelog +++ netkit-rwho-0.17/debian/changelog @@ -0,0 +1,164 @@ +netkit-rwho (0.17-12) unstable; urgency=low + + * The Petter & Peter release. + * debian/rules & debian/control clean up & updating + * Moved to debhelper compat 7 + * Added dependency on $syslog to init.d script (Closes: #541484) + * Added "status" target on init.d script (Closes: #528846) + + -- Alberto Gonzalez Iniesta Mon, 07 Sep 2009 12:45:09 +0200 + +netkit-rwho (0.17-11) unstable; urgency=low + + * rwhod.c: Fixed colon position in getopt. + (Closes: #468491, #480842) + Thanks Ludovico Gardenghi for noticing. + + -- Alberto Gonzalez Iniesta Tue, 22 Jul 2008 18:05:55 +0200 + +netkit-rwho (0.17-10) unstable; urgency=low + + * LSB header in init.d script. Change $local_fs to $remote_fs. + (Closes: #458505) + * Changed init.d script to use LSB output functions. + (Closes: #457660) + * Bumped Standards-Version to 3.7.3.0 + + -- Alberto Gonzalez Iniesta Sun, 10 Feb 2008 13:05:01 +0100 + +netkit-rwho (0.17-9) unstable; urgency=low + + * Condition the call to userdel in postrm. (Closes: #417021) + * Added support for specifying rwhod options in /etc/default/rwhod. + (Closes: #406093) + * Moved to debhelper compatibility 4. Created debian/compat. + * Bumped Standards-Version to 3.7.2.2 + * init.d script: Added LSB section + * Corrected man page on -u option. (Closes: #337730) + * Fixed -? option handling and added -h with the same behaviour. + (Closes: #337732) + + -- Alberto Gonzalez Iniesta Fri, 06 Apr 2007 13:03:22 +0200 + +netkit-rwho (0.17-8) unstable; urgency=high + + * Security: Check for the packet size to fix denial of service + [rwhod/rwhod.c, CAN-2004-1180]. Set urgency to high due to this. + Thanks Martin 'Joey' Schulze for the patch. + * Changed maintainer email address. + + -- Alberto Gonzalez Iniesta Fri, 11 Feb 2005 12:39:18 +0100 + +netkit-rwho (0.17-7) unstable; urgency=low + + * New Maintainer. (Closes: #249713) + * Added versioned Build-Depends on debhelper. + * Bumped Standards-Version to 3.6.1, no change. + + -- Alberto Gonzalez Iniesta Wed, 19 May 2004 16:34:35 +0200 + +netkit-rwho (0.17-6) unstable; urgency=low + + * Fixed resetting of forwarded_packets counter. + + -- Herbert Xu Sun, 27 Oct 2002 21:16:49 +1100 + +netkit-rwho (0.17-5) unstable; urgency=low + + * Call configure before forking to fix forwarding (Jerome Petazzoni). + + -- Herbert Xu Sun, 1 Sep 2002 09:10:51 +1000 + +netkit-rwho (0.17-4) unstable; urgency=low + + * Clean up old rwho files (Philippe Troin, closes: #114337). + + -- Herbert Xu Sat, 6 Oct 2001 12:07:44 +1000 + +netkit-rwho (0.17-3) unstable; urgency=low + + * Don't stat tty devices with colons in it (closes: #95788). + + -- Herbert Xu Thu, 3 May 2001 19:27:57 +1000 + +netkit-rwho (0.17-2) unstable; urgency=low + + * Fixed pointless PREREQ check that caused the arm build to fail. + + -- Herbert Xu Sat, 17 Feb 2001 22:16:14 +1100 + +netkit-rwho (0.17-1) unstable; urgency=low + + * New upstream release. + * Turned chroot off since it stops logging. + * Fixed null termination bug with wd_hostname. + * Print numbers-and-dots instead of raw IP address (Peter Maydell, + closes: #77272). + + -- Herbert Xu Sun, 19 Nov 2000 19:06:59 +1100 + +netkit-rwho (0.16-1) unstable; urgency=low + + * New upstream release. + * Merged ruptime into the rwho package. + * Run rwhod with -b by default (closes: #59981). + + -- Herbert Xu Tue, 18 Jul 2000 22:23:23 +1000 + +netkit-rwho (0.10-8) frozen unstable; urgency=low + + * Fixed a typo in the init script that stopped rwhod from being restarted + (closes: #51375, #59283, #59363). + + -- Herbert Xu Wed, 8 Mar 2000 15:26:32 +1100 + +netkit-rwho (0.10-7) unstable; urgency=low + + * Modified init.d script so that rwhod is only started if it isn't already + running (closes: #50488). + + -- Herbert Xu Thu, 18 Nov 1999 14:13:28 +1100 + +netkit-rwho (0.10-6) unstable; urgency=low + + * Added a check for the existence of /usr/sbin/rwhod before trying to stop it + (closes: #50186). + + -- Herbert Xu Mon, 15 Nov 1999 09:31:44 +1100 + +netkit-rwho (0.10-5) unstable; urgency=low + + * Always create /var/spool/rwho in postinst (closes: #50070). + + -- Herbert Xu Sat, 13 Nov 1999 23:35:00 +1100 + +netkit-rwho (0.10-4) unstable; urgency=low + + * Fixed typo in postrm, thanks to James A. Treacy (closes: #49950). + + -- Herbert Xu Fri, 12 Nov 1999 15:58:11 +1100 + +netkit-rwho (0.10-3) unstable; urgency=low + + * Added dependency on adduser and passwd for rwhod (closes: #49871). + * Added postrm script to remove the rwhod user upon purging. + * Added preinst script to stop any running rwhod server when upgrading from + netstd (closes: #49515). + + -- Herbert Xu Thu, 11 Nov 1999 19:35:22 +1100 + +netkit-rwho (0.10-2) unstable; urgency=low + + * rwho now depends on rwhod. + + -- Herbert Xu Sun, 7 Nov 1999 10:26:40 +1100 + +netkit-rwho (0.10-1) unstable; urgency=low + + * Initial release (closes: #46652). + * Alpha fixes thanks to Bruce Murphy (closes: #39155). + * Run as rwhod after binding. + * Added forwarding support with patch from Philippe Troin (closes: #43797). + + -- Herbert Xu Tue, 2 Nov 1999 15:45:41 +1100 + --- netkit-rwho-0.17.orig/debian/rules +++ netkit-rwho-0.17/debian/rules @@ -0,0 +1,90 @@ +#!/usr/bin/make -f +# GNU copyright 1997 to 1999 by Joey Hess. +# Copyright (c) 1999 Herbert Xu +# $Id: rules,v 1.6 2002/08/31 23:12:27 herbert Exp $ + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +build: build-stamp +build-stamp: + dh_testdir + + if [ ! -f MCONFIG ]; then \ + ./configure; \ + sed -e 's/^CFLAGS=\(.*\)$$/CFLAGS= -g \1/' MCONFIG \ + > MCONFIG.new; \ + mv MCONFIG.new MCONFIG; \ + fi + $(MAKE) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp install-stamp + + [ ! -f MCONFIG ] || $(MAKE) distclean + + dh_clean + +install: DH_OPTIONS= +install: build install-stamp +install-stamp: + dh_testdir + dh_testroot + dh_prep + dh_installdirs + + install rwhod/rwhod debian/rwhod/usr/sbin + install rwho/rwho debian/rwho/usr/bin + install ruptime/ruptime debian/rwho/usr/bin + cp rwhod/rwhod.8 debian/rwhod/usr/share/man/man8 + cp rwho/rwho.1 debian/rwho/usr/share/man/man1 + cp ruptime/ruptime.1 debian/rwho/usr/share/man/man1 + + dh_installinit -prwhod + dh_strip + touch install-stamp + +# This single target is used to build all the packages, all at once, or +# one at a time. So keep in mind: any options passed to commands here will +# affect _all_ packages. Anything you want to only affect one package +# should be put in another target, such as the install target. +binary-common: + dh_testdir + dh_testroot + dh_installdocs + dh_installexamples + dh_installmenu + dh_installcron + dh_installinfo + dh_installchangelogs ChangeLog + dh_link + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +# Build architecture independant packages using the common target. +binary-indep: install +# (Uncomment this next line if you have such packages.) +# $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common + +# Build architecture dependant packages using the common target. +binary-arch: install + $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common + +# Any other binary targets build just one binary package at a time. +binary-%: build install + make -f debian/rules binary-common DH_OPTIONS=-p$* + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install --- netkit-rwho-0.17.orig/debian/control +++ netkit-rwho-0.17/debian/control @@ -0,0 +1,31 @@ +Source: netkit-rwho +Section: net +Priority: optional +Maintainer: Alberto Gonzalez Iniesta +Standards-Version: 3.8.3.0 +Build-Depends: debhelper (>= 7) + +Package: rwhod +Architecture: any +Depends: adduser, lsb-base (>= 3.2-13), passwd, ${shlibs:Depends}, ${misc:Depends} +Replaces: netstd +Description: System status server + Rwhod is the server which maintains the database used by the rwho(1) + and ruptime(1) programs. Its operation is predicated on the ability to + broadcast messages on a network. + +Package: rwho +Architecture: any +Depends: rwhod, ${shlibs:Depends}, ${misc:Depends} +Replaces: netstd, ruptime +Conflicts: ruptime +Description: Clients to query the rwho server + The rwho command produces output similar to who, but for all machines on + the local network. If no report has been received from a machine for 11 + minutes then rwho assumes the machine is down, and does not report users + last known to be logged into that machine. + . + The ruptime command gives a status line like uptime for each machine on the + local network; these are formed from packets broadcast by each host on the + network once a minute. + --- netkit-rwho-0.17.orig/ruptime/ruptime.c +++ netkit-rwho-0.17/ruptime/ruptime.c @@ -212,7 +212,7 @@ static char resbuf[32]; int days, hours, minutes; - if (tval < 0 || tval > 999*24*60*60) { + if (tval < 0) { (void)snprintf(resbuf, sizeof(resbuf), "%s ??:??", updown); return(resbuf); } @@ -220,10 +220,10 @@ hours = minutes / 60; minutes %= 60; days = hours / 24; hours %= 24; if (days) - (void)snprintf(resbuf, sizeof(resbuf), "%s %3d+%02d:%02d", + (void)snprintf(resbuf, sizeof(resbuf), "%s %4d+%02d:%02d", updown, days, hours, minutes); else - (void)snprintf(resbuf, sizeof(resbuf), "%s %2d:%02d", + (void)snprintf(resbuf, sizeof(resbuf), "%s %2d:%02d", updown, hours, minutes); return(resbuf); } --- netkit-rwho-0.17.orig/rwho/Makefile +++ netkit-rwho-0.17/rwho/Makefile @@ -3,8 +3,6 @@ include ../MCONFIG include ../MRULES -CFLAGS += -I../include - rwho: rwho.o $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ --- netkit-rwho-0.17.orig/rwhod/Makefile +++ netkit-rwho-0.17/rwhod/Makefile @@ -3,8 +3,11 @@ include ../MCONFIG include ../MRULES -CFLAGS += -I../include -OBJS = rwhod.o daemon.o +ifneq ($(USE_GLIBC),1) +CFLAGS += -D_GNU_SOURCE +endif + +OBJS = rwhod.o rwhod: $(OBJS) $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ --- netkit-rwho-0.17.orig/rwhod/rwhod.8 +++ netkit-rwho-0.17/rwhod/rwhod.8 @@ -32,7 +32,10 @@ .\" from: @(#)rwhod.8 6.5 (Berkeley) 3/16/91 .\" $Id: rwhod.8,v 1.16 2000/07/30 23:57:06 dholland Exp $ .\" -.Dd May 13, 1997 +.\" Modified by Philippe Troin : added interface +.\" options and forwarding. + +.Dd March 10, 1999 .Dt RWHOD 8 .Os "Linux NetKit (0.17)" .Sh NAME @@ -40,7 +43,8 @@ .Nd system status server .Sh SYNOPSIS .Nm rwhod -.Op Fl bpa +.Op Fl bpaf +.Op -i ... .Op Fl u Ar user .Sh DESCRIPTION .Nm Rwhod @@ -67,22 +71,6 @@ in the ``rwho'' service specification; see .Xr services 5 . .Pp -If the -.Fl b -flag is supplied, only broadcast interfaces, such as ethernets, will -be used. -If the -.Fl p -flag is supplied, only point-to-point interfaces will be used. If the -.Fl a -flag is supplied, or no flags are supplied, all interfaces will be -used. -.Pp -If the -.Fl u -flag is supplied, rwhod will run as the specified user instead of as -root. -.Pp The messages sent and received, are of the form: .Bd -literal -offset indent struct outmp { @@ -145,16 +133,78 @@ .Nm Rwhod recomputes the system boot time every 30 minutes because on some (non-Linux) systems it is not a totally reliable process. +.Sh FLAGS +If the +.Fl b +flag is supplied, only broadcast interfaces, such as ethernets, will +be used. +If the +.Fl p +flag is supplied, only point-to-point interfaces will be used. If the +.Fl a +flag is supplied, or no flags are supplied, all interfaces will be +used. +.Pp +Alternately, you may specify interfaces by name by providing one or +more +.Fl i +options followed by the interface name. +.Pp +If the +.Fl u +flag is supplied, rwhod will run as the specified user instead of as +rwhod. The initial user until the daemon drops privileges is root. +.Pp +.Nm Rwhod +can also forward packets between interfaces if started with +.Fl f. +Please read the +.Xr CAVEATS +section before enabling +.Xr rwhod +forwarding. +.Sh CAVEATS +While +.Xr rwhod +listens on any interface present on the host, it will only send (or +forward) to the interfaces determined by the +.Fl a b p i +flags. +.Pp +When operating in forwarding mode (with +.Fl f +), +.Xr rwhod +forwards all correct rwhod packets received on an interface to all the +other interfaces. You can create a broadcast storm if there is a +loop in your network and all the routers in the loop run in forwarding +mode. To prevent this from happenning, +.Xr rwhod +will shut down forwarding (and log the event to the syslog) if more +than one +.Xr rwhod +packet is forwarded per second on average over the last three +minutes. If this happens, you must break the loop of forwarding routers. .Sh SEE ALSO .Xr rwho 1 , .Xr ruptime 1 .Sh BUGS -There should be a way to relay status information between networks. +Some kind of proxying feature might be useful if your router doesn't +run +.Xr rwhod. +.Pp People often interpret the server dying -or network communtication failures +or network communication failures as a machine going down. +.Pp +.Xr Rwhod +doesn't refresh its interface list, which might be useful when using +.Fl a b p. .Sh HISTORY The .Nm command appeared in .Bx 4.2 . +.Pp +Philippe Troin implemented forwarding and interface +selection flags. --- netkit-rwho-0.17.orig/rwhod/rwhod.c +++ netkit-rwho-0.17/rwhod/rwhod.c @@ -29,6 +29,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + + * Modified by Philippe Troin (added options & implemented + * them. + */ char copyright[] = @@ -47,6 +51,7 @@ #include #include #include +#include #include #include @@ -69,11 +74,13 @@ #include #include #include - -#include "daemon.h" +#include +#include #include "../version.h" +typedef struct sockaddr_in SA; + #define ENDIAN LITTLE_ENDIAN /* @@ -95,7 +102,16 @@ static void broadcaster(void); static int configure(int s); static int verify(const char *name); +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) static int getloadavg(double ptr[3], int n); +#endif + +/* This is the list of interface we want to listen on */ +struct wanted_neigh { + struct wanted_neigh *w_next; + char *w_ifname; + enum { W_USED_NOT, W_USED_ONCE, W_USED_MULTI } w_used; +}; /* * We communicate with each neighbor in @@ -103,21 +119,30 @@ * started up. Neighbors are currently * directly connected via a hardware interface. */ -struct neighbor { +struct neighbor { struct neighbor *n_next; char *n_name; /* interface name */ - char *n_addr; /* who to send to */ + SA *n_myaddr; /* My address on this i/f */ + SA *n_mask; /* Netmask on this i/f */ + SA *n_dstaddr; /* who to send to */ int n_addrlen; /* size of address */ int n_flags; /* should forward?, interface flags */ }; +static struct wanted_neigh *wanted_neigh; static struct neighbor *neighbors; static struct servent *sp; static int sk; -static int use_pointopoint = 0; -static int use_broadcast = 0; +static int use_pointopoint; +static int use_broadcast; static int need_init = 1; -static int child_pid = 0; +static int child_pid; +static int use_forwarding; +static int forwarded_packets; + +/* Max number of packets to forward between each alarm() tick. + If this number is exceeded, then the forwarding is switched off. */ +#define MAX_FWD_PACKETS (AL_INTERVAL) #define WHDRSIZE (((caddr_t) &((struct whod *) 0)->wd_we) \ - ((caddr_t) 0)) @@ -126,24 +151,48 @@ static void termhandler(int); static void sendpacket(struct whod *); static void getboottime(struct whod *); +static void forward(const SA *, const struct whod *, int cc); +static void usage(void); int main(int argc, char *argv[]) { + struct wanted_neigh *wn; + int wn_dup; struct sockaddr_in from; - struct passwd *pw = 0; + struct passwd *pw; struct stat st; char path[64]; - char *user = NULL; + char *user = "rwhod"; int on = 1; int opt; + time_t before; if (getuid()) { fprintf(stderr, "rwhod: not super user\n"); + } + openlog("rwhod", LOG_PID, LOG_DAEMON); + sp = getservbyname("who", "udp"); + if (sp == 0) { + fprintf(stderr, "rwhod: udp/who: unknown service\n"); + exit(1); + } + if ((sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket: %m"); + exit(1); + } + if (setsockopt(sk, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { + syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); + exit(1); + } + sine.sin_family = AF_INET; + sine.sin_port = sp->s_port; + if (bind(sk, (struct sockaddr *)&sine, sizeof(sine)) < 0) { + syslog(LOG_ERR, "bind: %m"); exit(1); } - while ((opt = getopt(argc, argv, "bpau:")) != EOF) { + while ((opt = getopt(argc, argv, "bpai:h?fu:")) != EOF) { switch (opt) { case 'b': use_broadcast = 1; @@ -155,31 +204,61 @@ use_broadcast = 1; use_pointopoint = 1; break; + case 'f': + use_forwarding = 1; + break; + case 'i': + wn_dup = 0; + for (wn = wanted_neigh; wn; wn = wn->w_next) { + if (strcmp(wn->w_ifname, optarg)== 0) { + wn_dup = 1; + break; + } + } + if (wn_dup) { + fprintf(stderr, "rwhod: warning: " + "duplicate interface %s in arguments\n", + optarg); + } else { + wn = malloc(sizeof(struct wanted_neigh)); + if (wn == NULL) { + fprintf(stderr, "rwhod: out of memory\n"); + exit(2); + } + wn->w_next = wanted_neigh; + wn->w_ifname = malloc(strlen(optarg)+1); + wn->w_used = W_USED_NOT; + if (wn->w_ifname == NULL) { + fprintf(stderr, "rwhod: out of memory\n"); + exit(2); + } + strcpy(wn->w_ifname, optarg); + wanted_neigh = wn; + } + break; case 'u': user = optarg; break; case '?': + case 'h': default: - fprintf(stderr, "usage: rwhod [-bpa] [-u user]\n"); - exit(1); - break; + usage(); } } if (optinds_port; - if (bind(sk, (struct sockaddr *)&sine, sizeof(sine)) < 0) { - syslog(LOG_ERR, "bind: %m"); - exit(1); - } (void) umask(022); signal(SIGTERM, termhandler); - child_pid = fork(); - if (child_pid < 0) { - syslog(LOG_ERR, "fork: %m"); - exit(1); - } - if (child_pid == 0) { - broadcaster(); - exit(0); - } /* We have to drop privs in two steps--first get the * account info, then drop privs after chroot */ - if (user && (pw = getpwnam(user)) == NULL) { + if ((pw = getpwnam(user)) == NULL) { syslog(LOG_ERR, "unknown user: %s", user); exit(1); } - /* Chroot to the spool directory - * (note this is already our $cwd) */ - if (chroot(_PATH_RWHODIR) < 0) { - syslog(LOG_ERR, "chroot(%s): %m", _PATH_RWHODIR); - kill(child_pid, SIGTERM); - exit(1); - } - /* Now drop privs */ - if (pw) { + if (pw->pw_uid) { if (setgroups(1, &pw->pw_gid) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) { @@ -244,10 +290,28 @@ } } + if (!configure(sk)) + exit(1); + + child_pid = fork(); + if (child_pid < 0) { + syslog(LOG_ERR, "fork: %m"); + exit(1); + } + if (child_pid == 0) { + broadcaster(); + exit(0); + } + + before = 0; for (;;) { struct whod wd; int cc, whod; +#ifdef __GLIBC__ + socklen_t len = sizeof(from); +#else size_t len = sizeof(from); +#endif memset(&wd, 0, sizeof(wd)); cc = recvfrom(sk, (char *)&wd, sizeof(struct whod), 0, @@ -257,6 +321,8 @@ syslog(LOG_WARNING, "recv: %m"); continue; } + if (cc < WHDRSIZE) + continue; if (from.sin_port != sp->s_port) { syslog(LOG_WARNING, "%d: bad from port", ntohs(from.sin_port)); @@ -266,14 +332,24 @@ continue; if (wd.wd_type != WHODTYPE_STATUS) continue; + + if (use_forwarding) { + time_t now = time(NULL); + if ((uintmax_t) (now - before) >= AL_INTERVAL) { + before = now; + forwarded_packets = 0; + } + forward(&from, &wd, cc); + } + /* * Ensure null termination of the name within the packet. * Otherwise we might overflow or read past the end. */ wd.wd_hostname[sizeof(wd.wd_hostname)-1] = 0; if (!verify(wd.wd_hostname)) { - syslog(LOG_WARNING, "malformed host name from %x", - from.sin_addr); + syslog(LOG_WARNING, "malformed host name from %s", + inet_ntoa(from.sin_addr)); continue; } snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname); @@ -306,7 +382,7 @@ } #endif wd.wd_recvtime = time(NULL); - write(whod, (char *)&wd, cc); + write(whod, &wd, cc); if (fstat(whod, &st) < 0 || st.st_size > cc) ftruncate(whod, cc); (void) close(whod); @@ -345,9 +421,6 @@ size_t mynamelen; struct whod mywd; - if (!configure(sk)) - exit(1); - /* * Establish host name as returned by system. */ @@ -357,7 +430,7 @@ } if ((cp = index(myname, '.')) != NULL) *cp = '\0'; - mynamelen = strlen(myname); + mynamelen = strlen(myname) + 1; if (mynamelen > sizeof(mywd.wd_hostname)) mynamelen = sizeof(mywd.wd_hostname); strncpy(mywd.wd_hostname, myname, mynamelen); @@ -448,7 +521,9 @@ } we = wd->wd_we; for (i = 0; i < nutmps; i++) { - if (stat(we->we_utmp.out_line, &stb) >= 0) + const char *p = we->we_utmp.out_line; + + if (!strchr(p, ':') && stat(p, &stb) >= 0) we->we_idle = htonl(now - stb.st_atime); we++; } @@ -460,10 +535,10 @@ wd->wd_vers = WHODVERSION; wd->wd_type = WHODTYPE_STATUS; for (np = neighbors; np != NULL; np = np->n_next) { - if (sendto(sk, (char *)wd, cc, 0, - (struct sockaddr *) np->n_addr, np->n_addrlen) < 0) + if (sendto(sk, wd, cc, 0, + (struct sockaddr *) np->n_dstaddr, np->n_addrlen) < 0) syslog(LOG_ERR, "sendto(%s): %m", - inet_ntoa(((struct sockaddr_in *)np->n_addr)->sin_addr)); + inet_ntoa(np->n_dstaddr->sin_addr)); } if (nutmps && chdir(_PATH_RWHODIR)) { @@ -472,6 +547,7 @@ } } +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) /* * Taken from: * @@ -518,6 +594,7 @@ fclose(fp); return 0; } +#endif /* __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) */ void @@ -566,7 +643,7 @@ exit(1); } (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET); - (void) read(kmemf, (char *)&wd->wd_boottime, + (void) read(kmemf, &wd->wd_boottime, sizeof (wd->wd_boottime)); wd->wd_boottime = htonl(wd->wd_boottime); #endif @@ -584,10 +661,11 @@ struct ifreq ifreq, *ifr; struct sockaddr_in *sn; register struct neighbor *np; + struct wanted_neigh *wn; ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; - if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { syslog(LOG_ERR, "ioctl (get interface configuration)"); return (0); } @@ -600,7 +678,11 @@ #endif cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; +#ifdef linux + cp += sizeof(struct ifreq)) { +#else cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { +#endif ifr = (struct ifreq *)cp; for (np = neighbors; np != NULL; np = np->n_next) if (np->n_name && @@ -614,63 +696,170 @@ continue; np->n_name = malloc(strlen(ifr->ifr_name) + 1); if (np->n_name == NULL) { - free((char *)np); + free(np); continue; } strcpy(np->n_name, ifr->ifr_name); np->n_addrlen = sizeof (ifr->ifr_addr); - np->n_addr = malloc(np->n_addrlen); - if (np->n_addr == NULL) { + + np->n_dstaddr = malloc(np->n_addrlen); + if (np->n_dstaddr == NULL) { + free(np->n_name); + free(np); + continue; + } + bzero(np->n_dstaddr, np->n_addrlen); + + np->n_myaddr = malloc(np->n_addrlen); + if (np->n_myaddr == NULL) { + free(np->n_dstaddr); free(np->n_name); - free((char *)np); + free(np); continue; } - bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen); - if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + bzero(np->n_myaddr, np->n_addrlen); + + np->n_mask = malloc(np->n_addrlen); + if (np->n_mask == NULL) { + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); + free(np); + continue; + } + bzero(np->n_mask, np->n_addrlen); + + /* Initialize both my address and destination address by + the interface address. The destination address will be + overwritten when the interface has IFF_BROADCAST or + IFF_POINTOPOINT. */ + bcopy(&ifr->ifr_addr, np->n_dstaddr, np->n_addrlen); + bcopy(&ifr->ifr_addr, np->n_myaddr, np->n_addrlen); + + if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) { syslog(LOG_ERR, "ioctl (get interface flags)"); - free((char *)np); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); + free(np); continue; } if ((ifreq.ifr_flags & IFF_UP) == 0 || - (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) { - free((char *)np); + (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0 || + (ifreq.ifr_flags & IFF_LOOPBACK) != 0) { + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); + free(np); continue; } + if (wanted_neigh) { + int found = 0; + for (wn = wanted_neigh; wn; wn = wn->w_next) + if (strcmp(wn->w_ifname, ifreq.ifr_name)==0) { + found = 1; + break; + } + if (!found) { + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); + free(np); + continue; + } + switch (wn->w_used) { + case W_USED_NOT: + wn->w_used = W_USED_ONCE; + break; + case W_USED_ONCE: + syslog(LOG_ERR, + "specified interface %s more than once", + wn->w_ifname); + wn->w_used = W_USED_MULTI; + break; + case W_USED_MULTI: + /* oh well... don't tell again... */ + break; + default: + syslog(LOG_CRIT, "w_used=%d on %s", + wn->w_used, wn->w_ifname); + abort(); + } + } np->n_flags = ifreq.ifr_flags; if (np->n_flags & IFF_POINTOPOINT) { - if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { + if (ioctl(s, SIOCGIFDSTADDR, &ifreq) < 0) { syslog(LOG_ERR, "ioctl (get dstaddr)"); + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); free(np); continue; } - if (!use_pointopoint) { + if (!wanted_neigh && !use_pointopoint) { + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); free(np); continue; } /* we assume addresses are all the same size */ - bcopy((char *)&ifreq.ifr_dstaddr, - np->n_addr, np->n_addrlen); + bcopy(&ifreq.ifr_dstaddr, np->n_dstaddr, np->n_addrlen); } if (np->n_flags & IFF_BROADCAST) { - if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + if (ioctl(s, SIOCGIFBRDADDR, &ifreq) < 0) { syslog(LOG_ERR, "ioctl (get broadaddr)"); + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); free(np); continue; } - if (!use_broadcast) { + if (!wanted_neigh && !use_broadcast) { + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); free(np); continue; } /* we assume addresses are all the same size */ - bcopy((char *)&ifreq.ifr_broadaddr, - np->n_addr, np->n_addrlen); + bcopy(&ifreq.ifr_broadaddr, np->n_dstaddr, np->n_addrlen); + + /* Get netmask */ + if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) { + syslog(LOG_ERR, "ioctl (get netmask)"); + free(np->n_mask); + free(np->n_myaddr); + free(np->n_dstaddr); + free(np->n_name); + free(np); + continue; + } + bcopy((char*)&ifreq.ifr_netmask, + np->n_mask, np->n_addrlen); } /* gag, wish we could get rid of Internet dependencies */ - sn = (struct sockaddr_in *)np->n_addr; + sn = (SA *)np->n_dstaddr; sn->sin_port = sp->s_port; np->n_next = neighbors; neighbors = np; } + + /* Check for unfound i/f */ + for (wn = wanted_neigh; wn; wn = wn->w_next) + if (wn->w_used == W_USED_NOT) + syslog(LOG_WARNING, "didn't find interface %s", + wn->w_ifname); + + /* Dump out used i/f */ + for (np = neighbors; np; np = np->n_next) + syslog(LOG_INFO, "sending on interface %s", np->n_name); + return (1); } @@ -692,7 +881,7 @@ { register struct whod *w = (struct whod *)buf; register struct whoent *we; - struct sockaddr_in *sn = (struct sockaddr_in *)to; + struct sockaddr_in *sn = (SA *)to; char *interval(); printf("sendto %x.%d\n", ntohl(sn->sin_addr.s_addr), ntohs(sn->sin_port)); @@ -746,3 +935,63 @@ return (resbuf); } #endif + +/* Eventually forward the packet */ +static void +forward(const SA *from, const struct whod *wd, int cc) +{ + struct neighbor *np; + int looped_back = 0; + + /* Scan to see if the packet was sent by us */ + for (np = neighbors; np != NULL; np = np->n_next) + if (from->sin_addr.s_addr == + np->n_myaddr->sin_addr.s_addr) { + looped_back = 1; + break; + } + + if (!looped_back) { + sigset_t saved_set; + sigset_t mask_set; + + sigemptyset(&mask_set); + sigaddset(&mask_set, SIGALRM); + sigprocmask(SIG_BLOCK, &mask_set, &saved_set); + + if (++forwarded_packets > MAX_FWD_PACKETS) { + syslog(LOG_ERR, "too many forward requests, " + "disabling forwarding"); + use_forwarding = 0; + } + + sigprocmask(SIG_SETMASK, &saved_set, NULL); + + /* Re-broadcast packet on all interfaces... */ + for (np = neighbors; np != NULL; np = np->n_next) { + /* .. but do not rebroadcast on the incoming interface */ + if (((np->n_flags & IFF_BROADCAST) && + (from->sin_addr.s_addr & + np->n_mask->sin_addr.s_addr) != + (np->n_myaddr->sin_addr.s_addr & + np->n_mask->sin_addr.s_addr)) || + ((np->n_flags & IFF_POINTOPOINT) && + (from->sin_addr.s_addr) != + np->n_dstaddr->sin_addr.s_addr)) { + if (sendto(sk, wd, cc, 0, + (struct sockaddr *)np->n_dstaddr, + np->n_addrlen) < 0) + syslog(LOG_ERR, + "forwarding sendto(%s): %m", + inet_ntoa(np->n_dstaddr->sin_addr)); + } + } + } +} + +static void +usage() +{ + fprintf(stderr, "usage: rwhod [-bpaf] [-i ] [-u user]...\n"); + exit(1); +}