From 8996216f5b1c8305e98a2b888e1d27748b5ba500 Mon Sep 17 00:00:00 2001 From: pjd Date: Wed, 3 Jul 2013 20:58:58 +0000 Subject: Style cleanups. Submitted by: Mariusz Zaborski Sponsored by: Google Summer of Code 2013 Reviewed by: pjd MFC after: 1 month --- usr.sbin/rwhod/rwhod.c | 386 +++++++++++++++++++++++++------------------------ 1 file changed, 199 insertions(+), 187 deletions(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 16bf948..8a20a43 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -1,6 +1,6 @@ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. +/*- + * Copyright (c) 1983, 1993 The Regents of the University of California. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,47 +60,17 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +#include #include #include #include #include #include -#include #include -#include -#include - -/* - * This version of Berkeley's rwhod has been modified to use IP multicast - * datagrams, under control of a new command-line option: - * - * rwhod -m causes rwhod to use IP multicast (instead of - * broadcast or unicast) on all interfaces that have - * the IFF_MULTICAST flag set in their "ifnet" structs - * (excluding the loopback interface). The multicast - * reports are sent with a time-to-live of 1, to prevent - * forwarding beyond the directly-connected subnet(s). - * - * rwhod -m causes rwhod to send IP multicast datagrams with a - * time-to-live of , via a SINGLE interface rather - * than all interfaces. must be between 0 and - * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" - * is different than "-m", in that "-m 1" specifies - * transmission on one interface only. - * - * When "-m" is used without a argument, the program accepts multicast - * rwhod reports from all multicast-capable interfaces. If a argument - * is given, it accepts multicast reports from only one interface, the one - * on which reports are sent (which may be controlled via the host's routing - * table). Regardless of the "-m" option, the program accepts broadcast or - * unicast reports from all interfaces. Thus, this program will hear the - * reports of old, non-multicasting rwhods, but, if multicasting is used, - * those old rwhods won't hear the reports generated by this program. - * - * -- Steve Deering, Stanford University, February 1989 - */ +#include #define UNPRIV_USER "daemon" #define UNPRIV_GROUP "daemon" @@ -112,15 +82,15 @@ __FBSDID("$FreeBSD$"); #define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */ #define INADDR_WHOD_GROUP (u_long)0xe0000103 /* 224.0.1.3 */ - /* (belongs in protocols/rwhod.h) */ + /* (belongs in protocols/rwhod.h) */ -int insecure_mode; -int quiet_mode; -int iff_flag = IFF_POINTOPOINT; -int multicast_mode = NO_MULTICAST; -int multicast_scope; -struct sockaddr_in multicast_addr = - { sizeof multicast_addr, AF_INET, 0, { 0 }, { 0 } }; +int insecure_mode; +int quiet_mode; +int iff_flag = IFF_POINTOPOINT; +int multicast_mode = NO_MULTICAST; +int multicast_scope; +struct sockaddr_in multicast_addr = + { sizeof(multicast_addr), AF_INET, 0, { 0 }, { 0 } }; /* * Alarm interval. Don't forget to change the down time check in ruptime @@ -137,72 +107,109 @@ char myname[MAXHOSTNAMELEN]; */ struct neighbor { struct neighbor *n_next; - char *n_name; /* interface name */ + char *n_name; /* interface name */ struct sockaddr *n_addr; /* who to send to */ - int n_addrlen; /* size of address */ - int n_flags; /* should forward?, interface flags */ + int n_addrlen; /* size of address */ + int n_flags; /* should forward?, interface flags */ }; struct neighbor *neighbors; struct whod mywd; -struct servent *sp; +struct servent *sp; int s; #define WHDRSIZE (int)(sizeof(mywd) - sizeof(mywd.wd_we)) -void run_as(uid_t *, gid_t *); -int configure(int); -void getboottime(int); -void onalrm(int); -void quit(const char *); -void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); -int verify(char *, int); +int configure(int so); +void getboottime(int signo __unused); +void onalrm(int signo __unused); +void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo); +void run_as(uid_t *uid, gid_t *gid); +void quit(const char *msg); +int verify(char *name, int maxlen); static void usage(void); + #ifdef DEBUG -char *interval(int, char *); -void Sendto(int, const void *, size_t, int, const struct sockaddr *, int); +char *interval(int time, char *updown); +void Sendto(int s, const void *buf, size_t cc, int flags, + const struct sockaddr *to, int tolen); #define sendto Sendto #endif +/* + * This version of Berkeley's rwhod has been modified to use IP multicast + * datagrams, under control of a new command-line option: + * + * rwhod -m causes rwhod to use IP multicast (instead of + * broadcast or unicast) on all interfaces that have + * the IFF_MULTICAST flag set in their "ifnet" structs + * (excluding the loopback interface). The multicast + * reports are sent with a time-to-live of 1, to prevent + * forwarding beyond the directly-connected subnet(s). + * + * rwhod -m causes rwhod to send IP multicast datagrams with a + * time-to-live of , via a SINGLE interface rather + * than all interfaces. must be between 0 and + * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" + * is different than "-m", in that "-m 1" specifies + * transmission on one interface only. + * + * When "-m" is used without a argument, the program accepts multicast + * rwhod reports from all multicast-capable interfaces. If a argument + * is given, it accepts multicast reports from only one interface, the one + * on which reports are sent (which may be controlled via the host's routing + * table). Regardless of the "-m" option, the program accepts broadcast or + * unicast reports from all interfaces. Thus, this program will hear the + * reports of old, non-multicasting rwhods, but, if multicasting is used, + * those old rwhods won't hear the reports generated by this program. + * + * -- Steve Deering, Stanford University, February 1989 + */ int main(int argc, char *argv[]) { struct sockaddr_in from; struct stat st; char path[64]; - int on = 1; + int on; char *cp; struct sockaddr_in soin; uid_t unpriv_uid; gid_t unpriv_gid; + on = 1; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); - argv++; argc--; + argv++; + argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && isdigit(*(argv + 1)[0])) { - argv++, argc--; + argv++; + argc--; multicast_mode = SCOPED_MULTICAST; multicast_scope = atoi(*argv); - if (multicast_scope > MAX_MULTICAST_SCOPE) + if (multicast_scope > MAX_MULTICAST_SCOPE) { errx(1, "ttl must not exceed %u", - MAX_MULTICAST_SCOPE); + MAX_MULTICAST_SCOPE); + } + } else { + multicast_mode = PER_INTERFACE_MULTICAST; } - else multicast_mode = PER_INTERFACE_MULTICAST; - } - else if (strcmp(*argv, "-i") == 0) + } else if (strcmp(*argv, "-i") == 0) { insecure_mode = 1; - else if (strcmp(*argv, "-l") == 0) + } else if (strcmp(*argv, "-l") == 0) { quiet_mode = 1; - else if (strcmp(*argv, "-p") == 0) + } else if (strcmp(*argv, "-p") == 0) { iff_flag = 0; - else + } else { usage(); - argv++, argc--; + } + argv++; + argc--; } if (argc > 0) usage(); @@ -229,8 +236,7 @@ main(int argc, char *argv[]) } if ((cp = strchr(myname, '.')) != NULL) *cp = '\0'; - strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1); - mywd.wd_hostname[sizeof(mywd.wd_hostname) - 1] = '\0'; + strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname)); getboottime(0); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); @@ -252,7 +258,7 @@ main(int argc, char *argv[]) syslog(LOG_ERR, "setgid: %m"); exit(1); } - if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */ + if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */ syslog(LOG_ERR, "setgroups: %m"); exit(1); } @@ -268,12 +274,13 @@ main(int argc, char *argv[]) } for (;;) { struct whod wd; - socklen_t len = sizeof(from); + socklen_t len; int cc, whod; time_t t; - cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0, - (struct sockaddr *)&from, &len); + len = sizeof(from); + cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, + &len); if (cc <= 0) { if (cc < 0 && errno != EINTR) syslog(LOG_WARNING, "recv: %m"); @@ -293,12 +300,12 @@ main(int argc, char *argv[]) continue; if (wd.wd_type != WHODTYPE_STATUS) continue; - if (!verify(wd.wd_hostname, sizeof wd.wd_hostname)) { + if (!verify(wd.wd_hostname, sizeof(wd.wd_hostname))) { syslog(LOG_WARNING, "malformed host name from %s", inet_ntoa(from.sin_addr)); continue; } - (void) snprintf(path, sizeof path, "whod.%s", wd.wd_hostname); + (void) snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname); /* * Rather than truncating and growing the file each time, * use ftruncate if size is less than previous size. @@ -310,9 +317,10 @@ main(int argc, char *argv[]) } #if ENDIAN != BIG_ENDIAN { - int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); struct whoent *we; + int i, n; + n = (cc - WHDRSIZE) / sizeof(struct whoent); /* undo header byte swapping before writing to file */ wd.wd_sendtime = ntohl(wd.wd_sendtime); for (i = 0; i < 3; i++) @@ -337,29 +345,28 @@ main(int argc, char *argv[]) } static void -usage() +usage(void) { + fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); exit(1); } void -run_as(uid, gid) - uid_t *uid; - gid_t *gid; +run_as(uid_t *uid, gid_t *gid) { struct passwd *pw; struct group *gr; pw = getpwnam(UNPRIV_USER); - if (!pw) { + if (pw == NULL) { syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); exit(1); } *uid = pw->pw_uid; gr = getgrnam(UNPRIV_GROUP); - if (!gr) { + if (gr == NULL) { syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); exit(1); } @@ -372,16 +379,16 @@ run_as(uid, gid) * to be created. Sorry, but blanks aren't allowed. */ int -verify(name, maxlen) - register char *name; - register int maxlen; +verify(char *name, int maxlen) { - register int size = 0; + int size; - while (*name && size < maxlen - 1) { - if (!isascii(*name) || !(isalnum(*name) || ispunct(*name))) + size = 0; + while (*name != '\0' && size < maxlen - 1) { + if (!isascii(*name) || !isalnum(*name) || ispunct(*name)) return (0); - name++, size++; + name++; + size++; } *name = '\0'; return (size > 0); @@ -390,15 +397,16 @@ verify(name, maxlen) void onalrm(int signo __unused) { - struct neighbor *np; - struct whoent *we = mywd.wd_we, *wend; - struct stat stb; - struct utmpx *ut; static int alarmcount = 0; double avenrun[3]; time_t now; int i, cc; + struct utmpx *ut; + struct stat stb; + struct neighbor *np; + struct whoent *we, *wend; + we = mywd.wd_we; now = time(NULL); if (alarmcount % 10 == 0) getboottime(0); @@ -418,7 +426,7 @@ onalrm(int signo __unused) } endutxent(); - if (chdir(_PATH_DEV)) { + if (chdir(_PATH_DEV) < 0) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); exit(1); } @@ -428,7 +436,7 @@ onalrm(int signo __unused) we->we_idle = htonl(now - stb.st_atime); we++; } - (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); + (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); for (i = 0; i < 3; i++) mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); cc = (char *)wend - (char *)&mywd; @@ -439,27 +447,32 @@ onalrm(int signo __unused) (void) sendto(s, (char *)&mywd, cc, 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)); - } - else for (np = neighbors; np != NULL; np = np->n_next) { - if (multicast_mode == PER_INTERFACE_MULTICAST && - np->n_flags & IFF_MULTICAST) { - /* - * Select the outgoing interface for the multicast. - */ - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, - &(((struct sockaddr_in *)np->n_addr)->sin_addr), - sizeof(struct in_addr)) < 0) { - syslog(LOG_ERR, - "setsockopt IP_MULTICAST_IF: %m"); - exit(1); + } else { + for (np = neighbors; np != NULL; np = np->n_next) { + if (multicast_mode == PER_INTERFACE_MULTICAST && + (np->n_flags & IFF_MULTICAST) != 0) { + /* + * Select the outgoing interface for the + * multicast. + */ + if (setsockopt(s, IPPROTO_IP, + IP_MULTICAST_IF, + &(((struct sockaddr_in *)np->n_addr)->sin_addr), + sizeof(struct in_addr)) < 0) { + syslog(LOG_ERR, + "setsockopt IP_MULTICAST_IF: %m"); + exit(1); + } + (void) sendto(s, (char *)&mywd, cc, 0, + (struct sockaddr *)&multicast_addr, + sizeof(multicast_addr)); + } else { + (void) sendto(s, (char *)&mywd, cc, 0, + np->n_addr, np->n_addrlen); } - (void) sendto(s, (char *)&mywd, cc, 0, - (struct sockaddr *)&multicast_addr, - sizeof(multicast_addr)); - } else (void) sendto(s, (char *)&mywd, cc, 0, - np->n_addr, np->n_addrlen); + } } - if (chdir(_PATH_RWHODIR)) { + if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); exit(1); } @@ -467,8 +480,7 @@ onalrm(int signo __unused) } void -getboottime(signo) - int signo __unused; +getboottime(int signo __unused) { int mib[2]; size_t size; @@ -485,26 +497,25 @@ getboottime(signo) } void -quit(msg) - const char *msg; +quit(const char *msg) { + syslog(LOG_ERR, "%s", msg); exit(1); } void -rt_xaddrs(cp, cplim, rtinfo) - register caddr_t cp, cplim; - register struct rt_addrinfo *rtinfo; +rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) { - register struct sockaddr *sa; - register int i; + struct sockaddr *sa; + int i; memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); - for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { + for (i = 0; i < RTAX_MAX && cp < cplim; i++) { if ((rtinfo->rti_addrs & (1 << i)) == 0) continue; - rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; + sa = (struct sockaddr *)cp; + rtinfo->rti_info[i] = sa; cp += SA_SIZE(sa); } } @@ -514,18 +525,18 @@ rt_xaddrs(cp, cplim, rtinfo) * networks which deserve status information. */ int -configure(so) - int so; +configure(int so) { - register struct neighbor *np; - register struct if_msghdr *ifm; - register struct ifa_msghdr *ifam; + struct neighbor *np; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; size_t needed; - int mib[6], flags = 0, len; + int mib[6], flags, lflags, len; char *buf, *lim, *next; struct rt_addrinfo info; + flags = 0; if (multicast_mode != NO_MULTICAST) { multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); multicast_addr.sin_port = sp->s_port; @@ -538,19 +549,19 @@ configure(so) mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { + &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, - "setsockopt IP_ADD_MEMBERSHIP: %m"); - return(0); + "setsockopt IP_ADD_MEMBERSHIP: %m"); + return (0); } ttl = multicast_scope; - if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, - &ttl, sizeof(ttl)) < 0) { + if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, + sizeof(ttl)) < 0) { syslog(LOG_ERR, - "setsockopt IP_MULTICAST_TTL: %m"); - return(0); + "setsockopt IP_MULTICAST_TTL: %m"); + return (0); } - return(1); + return (1); } mib[0] = CTL_NET; @@ -575,34 +586,38 @@ configure(so) flags = ifm->ifm_flags; continue; } - if ((flags & IFF_UP) == 0 || - (flags & (((multicast_mode == PER_INTERFACE_MULTICAST) ? - IFF_MULTICAST : 0) | - IFF_BROADCAST|iff_flag)) == 0) + if ((flags & IFF_UP) == 0) + continue; + lflags = IFF_BROADCAST | iff_flag; + if (multicast_mode == PER_INTERFACE_MULTICAST) + lflags |= IFF_MULTICAST; + if ((flags & lflags) == 0) continue; if (ifm->ifm_type != RTM_NEWADDR) quit("out of sync parsing NET_RT_IFLIST"); ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, - &info); + &info); /* gag, wish we could get rid of Internet dependencies */ -#define dstaddr info.rti_info[RTAX_BRD] -#define ifaddr info.rti_info[RTAX_IFA] -#define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr -#define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port +#define dstaddr info.rti_info[RTAX_BRD] +#define ifaddr info.rti_info[RTAX_IFA] +#define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr +#define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port if (dstaddr == 0 || dstaddr->sa_family != AF_INET) continue; PORT_SA(dstaddr) = sp->s_port; - for (np = neighbors; np != NULL; np = np->n_next) + for (np = neighbors; np != NULL; np = np->n_next) { if (memcmp(sdl->sdl_data, np->n_name, - sdl->sdl_nlen) == 0 && - IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) + sdl->sdl_nlen) == 0 && + IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) { break; + } + } if (np != NULL) continue; len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1; - np = (struct neighbor *)malloc(len); + np = malloc(len); if (np == NULL) quit("malloc of neighbor structure"); memset(np, 0, len); @@ -613,24 +628,24 @@ configure(so) memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen); memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); if (multicast_mode == PER_INTERFACE_MULTICAST && - (flags & IFF_MULTICAST) && - !(flags & IFF_LOOPBACK)) { + (flags & IFF_MULTICAST) != 0 && + (flags & IFF_LOOPBACK) == 0) { struct ip_mreq mreq; memcpy((char *)np->n_addr, (char *)ifaddr, - np->n_addrlen); + np->n_addrlen); mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = - ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; + ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { + &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); #if 0 /* Fall back to broadcast on this if. */ np->n_flags &= ~IFF_MULTICAST; #else - free((char *)np); + free(np); continue; #endif } @@ -644,36 +659,32 @@ configure(so) #ifdef DEBUG void -Sendto(s, buf, cc, flags, to, tolen) - int s; - const void *buf; - size_t cc; - int flags; - const struct sockaddr *to; - int tolen; +Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, + int tolen) { - register struct whod *w = (struct whod *)buf; - register struct whoent *we; - struct sockaddr_in *sin = (struct sockaddr_in *)to; + struct whod *w; + struct whoent *we; + struct sockaddr_in *sin; + w = (struct whod *)buf; + sin = (struct sockaddr_in *)to; printf("sendto %x.%d\n", ntohl(sin->sin_addr.s_addr), - ntohs(sin->sin_port)); + ntohs(sin->sin_port)); printf("hostname %s %s\n", w->wd_hostname, - interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); + interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); printf("load %4.2f, %4.2f, %4.2f\n", ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, ntohl(w->wd_loadav[2]) / 100.0); cc -= WHDRSIZE; for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) { time_t t = _time32_to_time(ntohl(we->we_utmp.out_time)); - printf("%-8.8s %s:%s %.12s", - we->we_utmp.out_name, - w->wd_hostname, we->we_utmp.out_line, - ctime(&t)+4); + + printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name, + w->wd_hostname, we->we_utmp.out_line, ctime(&t) + 4); we->we_idle = ntohl(we->we_idle) / 60; - if (we->we_idle) { - if (we->we_idle >= 100*60) - we->we_idle = 100*60 - 1; + if (we->we_idle != 0) { + if (we->we_idle >= 100 * 60) + we->we_idle = 100 * 60 - 1; if (we->we_idle >= 60) printf(" %2d", we->we_idle / 60); else @@ -685,26 +696,27 @@ Sendto(s, buf, cc, flags, to, tolen) } char * -interval(time, updown) - int time; - char *updown; +interval(int time, char *updown) { static char resbuf[32]; int days, hours, minutes; - if (time < 0 || time > 3*30*24*60*60) { + if (time < 0 || time > 3 * 30 * 24 * 60 * 60) { (void) sprintf(resbuf, " %s ??:??", updown); return (resbuf); } minutes = (time + 59) / 60; /* round to minutes */ - hours = minutes / 60; minutes %= 60; - days = hours / 24; hours %= 24; - if (days) + hours = minutes / 60; + minutes %= 60; + days = hours / 24; + hours %= 24; + if (days > 0) { (void) sprintf(resbuf, "%s %2d+%02d:%02d", updown, days, hours, minutes); - else + } else { (void) sprintf(resbuf, "%s %2d:%02d", updown, hours, minutes); + } return (resbuf); } #endif -- cgit v1.1 From 22651ea46d39aca94adcd29f086934b568eedff6 Mon Sep 17 00:00:00 2001 From: pjd Date: Wed, 3 Jul 2013 21:04:20 +0000 Subject: The whole sending functionality was implemented within signal handler, which is very bad idea. Split sending and receiving in two processes, which fixes this problem and will help to sandbox rwhod. Submitted by: Mariusz Zaborski Sponsored by: Google Summer of Code 2013 Reviewed by: pjd MFC after: 1 month --- usr.sbin/rwhod/rwhod.c | 294 +++++++++++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 133 deletions(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 8a20a43..0b01f3f 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1983, 1993 The Regents of the University of California. + * Copyright (c) 2013 Mariusz Zaborski * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +49,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include @@ -93,10 +96,10 @@ struct sockaddr_in multicast_addr = { sizeof(multicast_addr), AF_INET, 0, { 0 }, { 0 } }; /* - * Alarm interval. Don't forget to change the down time check in ruptime + * Sleep interval. Don't forget to change the down time check in ruptime * if this is changed. */ -#define AL_INTERVAL (3 * 60) +#define SL_INTERVAL (3 * 60) char myname[MAXHOSTNAMELEN]; @@ -117,15 +120,18 @@ struct neighbor *neighbors; struct whod mywd; struct servent *sp; int s; +int fdp; +pid_t pid_child_receiver; #define WHDRSIZE (int)(sizeof(mywd) - sizeof(mywd.wd_we)) int configure(int so); void getboottime(int signo __unused); -void onalrm(int signo __unused); +void receiver_process(void); void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo); void run_as(uid_t *uid, gid_t *gid); void quit(const char *msg); +void sender_process(void); int verify(char *name, int maxlen); static void usage(void); @@ -168,9 +174,6 @@ void Sendto(int s, const void *buf, size_t cc, int flags, int main(int argc, char *argv[]) { - struct sockaddr_in from; - struct stat st; - char path[64]; int on; char *cp; struct sockaddr_in soin; @@ -269,16 +272,83 @@ main(int argc, char *argv[]) if (!configure(s)) exit(1); if (!quiet_mode) { - signal(SIGALRM, onalrm); - onalrm(0); + pid_child_receiver = pdfork(&fdp, 0); + if (pid_child_receiver == 0) { + receiver_process(); + } else if (pid_child_receiver > 0) { + sender_process(); + } else if (pid_child_receiver == -1) { + syslog(LOG_ERR, "pdfork: %m"); + exit(1); + } + } else { + receiver_process(); } - for (;;) { - struct whod wd; - socklen_t len; - int cc, whod; - time_t t; +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); + exit(1); +} + +void +run_as(uid_t *uid, gid_t *gid) +{ + struct passwd *pw; + struct group *gr; - len = sizeof(from); + pw = getpwnam(UNPRIV_USER); + if (pw == NULL) { + syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); + exit(1); + } + *uid = pw->pw_uid; + + gr = getgrnam(UNPRIV_GROUP); + if (gr == NULL) { + syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); + exit(1); + } + *gid = gr->gr_gid; +} + +/* + * Check out host name for unprintables + * and other funnies before allowing a file + * to be created. Sorry, but blanks aren't allowed. + */ +int +verify(char *name, int maxlen) +{ + int size; + + size = 0; + while (*name != '\0' && size < maxlen - 1) { + if (!isascii(*name) || !isalnum(*name) || ispunct(*name)) + return (0); + name++; + size++; + } + *name = '\0'; + return (size > 0); +} + +void +receiver_process(void) +{ + struct sockaddr_in from; + struct stat st; + char path[64]; + struct whod wd; + socklen_t len; + int cc, whod; + time_t t; + + len = sizeof(from); + for (;;) { cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, &len); if (cc <= 0) { @@ -344,139 +414,97 @@ main(int argc, char *argv[]) } } -static void -usage(void) -{ - - fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); - exit(1); -} - -void -run_as(uid_t *uid, gid_t *gid) -{ - struct passwd *pw; - struct group *gr; - - pw = getpwnam(UNPRIV_USER); - if (pw == NULL) { - syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); - exit(1); - } - *uid = pw->pw_uid; - - gr = getgrnam(UNPRIV_GROUP); - if (gr == NULL) { - syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); - exit(1); - } - *gid = gr->gr_gid; -} - -/* - * Check out host name for unprintables - * and other funnies before allowing a file - * to be created. Sorry, but blanks aren't allowed. - */ -int -verify(char *name, int maxlen) -{ - int size; - - size = 0; - while (*name != '\0' && size < maxlen - 1) { - if (!isascii(*name) || !isalnum(*name) || ispunct(*name)) - return (0); - name++; - size++; - } - *name = '\0'; - return (size > 0); -} - void -onalrm(int signo __unused) +sender_process(void) { - static int alarmcount = 0; + int sendcount; double avenrun[3]; time_t now; - int i, cc; + int i, cc, status; struct utmpx *ut; struct stat stb; struct neighbor *np; struct whoent *we, *wend; - we = mywd.wd_we; - now = time(NULL); - if (alarmcount % 10 == 0) - getboottime(0); - alarmcount++; - wend = &mywd.wd_we[1024 / sizeof(struct whoent)]; - setutxent(); - while ((ut = getutxent()) != NULL && we < wend) { - if (ut->ut_type != USER_PROCESS) - continue; - strncpy(we->we_utmp.out_line, ut->ut_line, - sizeof(we->we_utmp.out_line)); - strncpy(we->we_utmp.out_name, ut->ut_user, - sizeof(we->we_utmp.out_name)); - we->we_utmp.out_time = - htonl(_time_to_time32(ut->ut_tv.tv_sec)); - we++; - } - endutxent(); + sendcount = 0; + for (;;) { + we = mywd.wd_we; + now = time(NULL); + if (sendcount % 10 == 0) + getboottime(0); + sendcount++; + wend = &mywd.wd_we[1024 / sizeof(struct whoent)]; + setutxent(); + while ((ut = getutxent()) != NULL && we < wend) { + if (ut->ut_type != USER_PROCESS) + continue; + strncpy(we->we_utmp.out_line, ut->ut_line, + sizeof(we->we_utmp.out_line)); + strncpy(we->we_utmp.out_name, ut->ut_user, + sizeof(we->we_utmp.out_name)); + we->we_utmp.out_time = + htonl(_time_to_time32(ut->ut_tv.tv_sec)); + we++; + } + endutxent(); - if (chdir(_PATH_DEV) < 0) { - syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); - exit(1); - } - wend = we; - for (we = mywd.wd_we; we < wend; we++) { - if (stat(we->we_utmp.out_line, &stb) >= 0) - we->we_idle = htonl(now - stb.st_atime); - we++; - } - (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); - for (i = 0; i < 3; i++) - mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); - cc = (char *)wend - (char *)&mywd; - mywd.wd_sendtime = htonl(_time_to_time32(time(NULL))); - mywd.wd_vers = WHODVERSION; - mywd.wd_type = WHODTYPE_STATUS; - if (multicast_mode == SCOPED_MULTICAST) { - (void) sendto(s, (char *)&mywd, cc, 0, - (struct sockaddr *)&multicast_addr, - sizeof(multicast_addr)); - } else { - for (np = neighbors; np != NULL; np = np->n_next) { - if (multicast_mode == PER_INTERFACE_MULTICAST && - (np->n_flags & IFF_MULTICAST) != 0) { - /* - * Select the outgoing interface for the - * multicast. - */ - if (setsockopt(s, IPPROTO_IP, - IP_MULTICAST_IF, - &(((struct sockaddr_in *)np->n_addr)->sin_addr), - sizeof(struct in_addr)) < 0) { - syslog(LOG_ERR, - "setsockopt IP_MULTICAST_IF: %m"); - exit(1); + if (chdir(_PATH_DEV) < 0) { + syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); + exit(1); + } + wend = we; + for (we = mywd.wd_we; we < wend; we++) { + if (stat(we->we_utmp.out_line, &stb) >= 0) + we->we_idle = htonl(now - stb.st_atime); + we++; + } + (void) getloadavg(avenrun, + sizeof(avenrun) / sizeof(avenrun[0])); + for (i = 0; i < 3; i++) + mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); + cc = (char *)wend - (char *)&mywd; + mywd.wd_sendtime = htonl(_time_to_time32(time(NULL))); + mywd.wd_vers = WHODVERSION; + mywd.wd_type = WHODTYPE_STATUS; + if (multicast_mode == SCOPED_MULTICAST) { + (void) sendto(s, (char *)&mywd, cc, 0, + (struct sockaddr *)&multicast_addr, + sizeof(multicast_addr)); + } else { + for (np = neighbors; np != NULL; np = np->n_next) { + if (multicast_mode == PER_INTERFACE_MULTICAST && + (np->n_flags & IFF_MULTICAST) != 0) { + /* + * Select the outgoing interface for the + * multicast. + */ + if (setsockopt(s, IPPROTO_IP, + IP_MULTICAST_IF, + &(((struct sockaddr_in *)np->n_addr)->sin_addr), + sizeof(struct in_addr)) < 0) { + syslog(LOG_ERR, + "setsockopt IP_MULTICAST_IF: %m"); + exit(1); + } + (void) sendto(s, (char *)&mywd, cc, 0, + (struct sockaddr *)&multicast_addr, + sizeof(multicast_addr)); + } else { + (void) sendto(s, (char *)&mywd, cc, 0, + np->n_addr, np->n_addrlen); } - (void) sendto(s, (char *)&mywd, cc, 0, - (struct sockaddr *)&multicast_addr, - sizeof(multicast_addr)); - } else { - (void) sendto(s, (char *)&mywd, cc, 0, - np->n_addr, np->n_addrlen); } } + if (chdir(_PATH_RWHODIR) < 0) { + syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); + exit(1); + } + if (waitpid(pid_child_receiver, &status, WNOHANG) == + pid_child_receiver) { + break; + } + sleep(SL_INTERVAL); } - if (chdir(_PATH_RWHODIR) < 0) { - syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); - exit(1); - } - (void) alarm(AL_INTERVAL); } void -- cgit v1.1 From 9256efca5e1c834cea4f307b2f9a54f095eb1753 Mon Sep 17 00:00:00 2001 From: pjd Date: Wed, 3 Jul 2013 21:07:02 +0000 Subject: Sandbox rwhod(8) receiver process using capability mode and Capsicum capabilities. rwhod(8) receiver can now only receive packages, write to /var/rwho/ directory and log to syslog. Submitted by: Mariusz Zaborski Sponsored by: Google Summer of Code 2013 Reviewed by: pjd MFC after: 1 month --- usr.sbin/rwhod/rwhod.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 0b01f3f..26b0500 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -43,6 +43,7 @@ static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93"; #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -220,7 +221,7 @@ main(int argc, char *argv[]) daemon(1, 0); #endif (void) signal(SIGHUP, getboottime); - openlog("rwhod", LOG_PID, LOG_DAEMON); + openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) { syslog(LOG_ERR, "who/udp: unknown service"); @@ -342,12 +343,27 @@ receiver_process(void) struct sockaddr_in from; struct stat st; char path[64]; + int dirfd; struct whod wd; socklen_t len; int cc, whod; time_t t; len = sizeof(from); + dirfd = open(".", O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR); + exit(1); + } + if (cap_rights_limit(dirfd, CAP_CREATE | CAP_WRITE | CAP_FTRUNCATE | + CAP_SEEK | CAP_LOOKUP | CAP_FSTAT) < 0 && errno != ENOSYS) { + syslog(LOG_WARNING, "cap_rights_limit: %m"); + exit(1); + } + if (cap_enter() < 0 && errno != ENOSYS) { + syslog(LOG_ERR, "cap_enter: %m"); + exit(1); + } for (;;) { cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, &len); @@ -380,11 +396,16 @@ receiver_process(void) * Rather than truncating and growing the file each time, * use ftruncate if size is less than previous size. */ - whod = open(path, O_WRONLY | O_CREAT, 0644); + whod = openat(dirfd, path, O_WRONLY | O_CREAT, 0644); if (whod < 0) { syslog(LOG_WARNING, "%s: %m", path); continue; } + if (cap_rights_limit(whod, CAP_WRITE | CAP_FTRUNCATE | + CAP_FSTAT) < 0 && errno != ENOSYS) { + syslog(LOG_WARNING, "cap_rights_limit: %m"); + exit(1); + } #if ENDIAN != BIG_ENDIAN { struct whoent *we; @@ -412,6 +433,7 @@ receiver_process(void) ftruncate(whod, cc); (void) close(whod); } + (void) close(dirfd); } void -- cgit v1.1 From d635351bf100453ec236d47fe886f6816ec75d50 Mon Sep 17 00:00:00 2001 From: hrs Date: Sat, 17 Aug 2013 07:12:52 +0000 Subject: Unbreak rwhod(8): - It did not work with GENERIC kernel after r250603 because options PROCDESC was required for pdfork(2). It now just uses fork(2) instead when this syscall is not available. - Fix verify(). This function was broken in r250602 because the outermost "()" was removed from the condition !(isalnum() || ispunct()). It prevented hostnames including "-", for example. --- usr.sbin/rwhod/rwhod.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 26b0500..d6a597f 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -274,6 +274,15 @@ main(int argc, char *argv[]) exit(1); if (!quiet_mode) { pid_child_receiver = pdfork(&fdp, 0); + if (pid_child_receiver == -1) { + if (errno != ENOSYS) { + syslog(LOG_ERR, "pdfork: %m"); + exit(1); + } else { + pid_child_receiver = fork(); + fdp = -1; + } + } if (pid_child_receiver == 0) { receiver_process(); } else if (pid_child_receiver > 0) { @@ -328,7 +337,7 @@ verify(char *name, int maxlen) size = 0; while (*name != '\0' && size < maxlen - 1) { - if (!isascii(*name) || !isalnum(*name) || ispunct(*name)) + if (!isascii(*name) || !(isalnum(*name) || ispunct(*name))) return (0); name++; size++; -- cgit v1.1 From 92598e5bb7bceae383734e69877709b2af64aa6a Mon Sep 17 00:00:00 2001 From: pjd Date: Sun, 18 Aug 2013 11:25:42 +0000 Subject: Cast argument of is*() ctype functions to unsigned char. Without the cast there is ambiguity between 0xFF and -1 (EOF). Suggested by: jilles Submitted by: Mariusz Zaborski Sponsored by: Google Summer of Code 2013 --- usr.sbin/rwhod/rwhod.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index d6a597f..25b8692 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -337,8 +337,11 @@ verify(char *name, int maxlen) size = 0; while (*name != '\0' && size < maxlen - 1) { - if (!isascii(*name) || !(isalnum(*name) || ispunct(*name))) + if (!isascii((unsigned char)*name) || + !(isalnum((unsigned char)*name) || + ispunct((unsigned char)*name))) { return (0); + } name++; size++; } -- cgit v1.1 From 029a6f5d92dc57925b5f155d94d6e01fdab7a45d Mon Sep 17 00:00:00 2001 From: pjd Date: Thu, 5 Sep 2013 00:09:56 +0000 Subject: Change the cap_rights_t type from uint64_t to a structure that we can extend in the future in a backward compatible (API and ABI) way. The cap_rights_t represents capability rights. We used to use one bit to represent one right, but we are running out of spare bits. Currently the new structure provides place for 114 rights (so 50 more than the previous cap_rights_t), but it is possible to grow the structure to hold at least 285 rights, although we can make it even larger if 285 rights won't be enough. The structure definition looks like this: struct cap_rights { uint64_t cr_rights[CAP_RIGHTS_VERSION + 2]; }; The initial CAP_RIGHTS_VERSION is 0. The top two bits in the first element of the cr_rights[] array contain total number of elements in the array - 2. This means if those two bits are equal to 0, we have 2 array elements. The top two bits in all remaining array elements should be 0. The next five bits in all array elements contain array index. Only one bit is used and bit position in this five-bits range defines array index. This means there can be at most five array elements in the future. To define new right the CAPRIGHT() macro must be used. The macro takes two arguments - an array index and a bit to set, eg. #define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL) We still support aliases that combine few rights, but the rights have to belong to the same array element, eg: #define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL) #define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL) #define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP) There is new API to manage the new cap_rights_t structure: cap_rights_t *cap_rights_init(cap_rights_t *rights, ...); void cap_rights_set(cap_rights_t *rights, ...); void cap_rights_clear(cap_rights_t *rights, ...); bool cap_rights_is_set(const cap_rights_t *rights, ...); bool cap_rights_is_valid(const cap_rights_t *rights); void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); Capability rights to the cap_rights_init(), cap_rights_set(), cap_rights_clear() and cap_rights_is_set() functions are provided by separating them with commas, eg: cap_rights_t rights; cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT); There is no need to terminate the list of rights, as those functions are actually macros that take care of the termination, eg: #define cap_rights_set(rights, ...) \ __cap_rights_set((rights), __VA_ARGS__, 0ULL) void __cap_rights_set(cap_rights_t *rights, ...); Thanks to using one bit as an array index we can assert in those functions that there are no two rights belonging to different array elements provided together. For example this is illegal and will be detected, because CAP_LOOKUP belongs to element 0 and CAP_PDKILL to element 1: cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL); Providing several rights that belongs to the same array's element this way is correct, but is not advised. It should only be used for aliases definition. This commit also breaks compatibility with some existing Capsicum system calls, but I see no other way to do that. This should be fine as Capsicum is still experimental and this change is not going to 9.x. Sponsored by: The FreeBSD Foundation --- usr.sbin/rwhod/rwhod.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 25b8692..5dc6079 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -354,6 +354,7 @@ receiver_process(void) { struct sockaddr_in from; struct stat st; + cap_rights_t rights; char path[64]; int dirfd; struct whod wd; @@ -367,8 +368,9 @@ receiver_process(void) syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR); exit(1); } - if (cap_rights_limit(dirfd, CAP_CREATE | CAP_WRITE | CAP_FTRUNCATE | - CAP_SEEK | CAP_LOOKUP | CAP_FSTAT) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_CREATE, CAP_FSTAT, CAP_FTRUNCATE, + CAP_LOOKUP, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(dirfd, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } @@ -413,8 +415,8 @@ receiver_process(void) syslog(LOG_WARNING, "%s: %m", path); continue; } - if (cap_rights_limit(whod, CAP_WRITE | CAP_FTRUNCATE | - CAP_FSTAT) < 0 && errno != ENOSYS) { + cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_WRITE); + if (cap_rights_limit(whod, &rights) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } -- cgit v1.1 From 3c622b2c1ff0effcf62f9b3ce3c9c698382a1fd4 Mon Sep 17 00:00:00 2001 From: pjd Date: Thu, 5 Sep 2013 01:05:48 +0000 Subject: Remove fallback to fork(2) if pdfork(2) is not available. If the parent process dies, the process descriptor will be closed and pdfork(2)ed child will be killed, which is not the case when regular fork(2) is used. The PROCDESC option is now part of the GENERIC kernel configuration, so we can start depending on it. Add UPDATING entry to inform that this option is now required and log detailed instruction to syslog if pdfork(2) is not available: The pdfork(2) system call is not available; recompile the kernel with options PROCDESC Submitted by: Mariusz Zaborski Sponsored by: Google Summer of Code 2013 --- usr.sbin/rwhod/rwhod.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'usr.sbin/rwhod') diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index 5dc6079..87a4166 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -274,21 +274,17 @@ main(int argc, char *argv[]) exit(1); if (!quiet_mode) { pid_child_receiver = pdfork(&fdp, 0); - if (pid_child_receiver == -1) { - if (errno != ENOSYS) { - syslog(LOG_ERR, "pdfork: %m"); - exit(1); - } else { - pid_child_receiver = fork(); - fdp = -1; - } - } if (pid_child_receiver == 0) { receiver_process(); } else if (pid_child_receiver > 0) { sender_process(); } else if (pid_child_receiver == -1) { - syslog(LOG_ERR, "pdfork: %m"); + if (errno == ENOSYS) { + syslog(LOG_ERR, + "The pdfork(2) system call is not available; recompile the kernel with options PROCDESC"); + } else { + syslog(LOG_ERR, "pdfork: %m"); + } exit(1); } } else { -- cgit v1.1