Annotation of src/usr.sbin/rwhod/rwhod.c, Revision 1.39
1.39 ! joerg 1: /* $NetBSD: rwhod.c,v 1.38 2009/04/18 13:05:54 lukem Exp $ */
1.24 christos 2:
1.1 cgd 3: /*
1.8 jtc 4: * Copyright (c) 1983, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.22 agc 15: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.11 lukem 32: #include <sys/cdefs.h>
1.1 cgd 33: #ifndef lint
1.37 lukem 34: __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
35: The Regents of the University of California. All rights reserved.");
1.1 cgd 36: #endif /* not lint */
37:
38: #ifndef lint
1.11 lukem 39: #if 0
40: static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";
41: #else
1.39 ! joerg 42: __RCSID("$NetBSD: rwhod.c,v 1.38 2009/04/18 13:05:54 lukem Exp $");
1.11 lukem 43: #endif
1.1 cgd 44: #endif /* not lint */
45:
46: #include <sys/param.h>
47: #include <sys/socket.h>
48: #include <sys/stat.h>
49: #include <sys/signal.h>
50: #include <sys/ioctl.h>
1.8 jtc 51: #include <sys/sysctl.h>
1.1 cgd 52:
53: #include <net/if.h>
1.8 jtc 54: #include <net/if_dl.h>
55: #include <net/route.h>
1.1 cgd 56: #include <netinet/in.h>
1.8 jtc 57: #include <protocols/rwhod.h>
1.11 lukem 58: #include <arpa/inet.h>
1.1 cgd 59:
1.8 jtc 60: #include <ctype.h>
1.12 lukem 61: #include <err.h>
1.1 cgd 62: #include <errno.h>
1.8 jtc 63: #include <fcntl.h>
1.1 cgd 64: #include <netdb.h>
1.8 jtc 65: #include <paths.h>
1.24 christos 66: #include <poll.h>
1.8 jtc 67: #include <stdio.h>
68: #include <stdlib.h>
69: #include <string.h>
1.1 cgd 70: #include <syslog.h>
1.8 jtc 71: #include <unistd.h>
1.15 thorpej 72: #include <util.h>
1.1 cgd 73:
1.19 christos 74: #include "utmpentry.h"
1.29 christos 75:
1.26 peter 76: #define CHECK_INTERVAL (3 * 60)
1.1 cgd 77:
1.29 christos 78: /* Time interval limit; ruptime will think that we are down > than this */
79: #define MAX_INTERVAL (11 * 60)
80:
81:
1.24 christos 82: static char myname[MAXHOSTNAMELEN + 1];
1.1 cgd 83:
84: /*
1.8 jtc 85: * We communicate with each neighbor in a list constructed at the time we're
86: * started up. Neighbors are currently directly connected via a hardware
87: * interface.
1.1 cgd 88: */
1.26 peter 89: struct neighbor {
1.1 cgd 90: struct neighbor *n_next;
91: char *n_name; /* interface name */
1.14 mrg 92: struct sockaddr *n_addr; /* who to send to */
1.1 cgd 93: int n_addrlen; /* size of address */
94: int n_flags; /* should forward?, interface flags */
95: };
96:
1.24 christos 97: static struct neighbor *neighbors;
98: static struct whod mywd;
99: static struct servent *sp;
100: static volatile sig_atomic_t onsighup;
1.1 cgd 101:
1.8 jtc 102: #define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))
1.1 cgd 103:
1.24 christos 104: static int configure(int);
105: static void getboottime(void);
106: static void send_host_information(int);
1.26 peter 107: static void sighup(int);
1.24 christos 108: static void handleread(int);
1.39 ! joerg 109: __dead static void quit(const char *);
1.24 christos 110: static void rt_xaddrs(void *, void *, struct rt_addrinfo *);
1.31 tsarna 111: static int drop_privs(char *);
1.35 perry 112: static void usage(void) __dead;
1.24 christos 113: static int verify(const char *);
1.8 jtc 114: #ifdef DEBUG
1.24 christos 115: static char *interval(int, const char *);
116: static ssize_t Sendto(int, const void *, size_t, int,
117: const struct sockaddr *, socklen_t);
1.30 christos 118: #else
119: #define Sendto sendto
1.8 jtc 120: #endif
1.1 cgd 121:
1.8 jtc 122: int
1.24 christos 123: main(int argc, char *argv[])
1.1 cgd 124: {
1.28 christos 125: int s, ch;
126: int time_interval = 180; /* Default time (180 seconds) */
127: char *cp, *ep;
1.26 peter 128: socklen_t on = 1;
1.24 christos 129: struct sockaddr_in sasin;
130: struct pollfd pfd[1];
1.26 peter 131: struct timeval delta, next, now;
1.31 tsarna 132: char *newuser = NULL;
1.1 cgd 133:
1.28 christos 134: setprogname(argv[0]);
135:
1.12 lukem 136: if (getuid())
1.26 peter 137: errx(EXIT_FAILURE, "not super user");
1.28 christos 138:
1.31 tsarna 139: while ((ch = getopt(argc, argv, "i:u:")) != -1) {
1.28 christos 140: switch (ch) {
1.29 christos 141: case 'i':
1.28 christos 142: time_interval = (int)strtol(optarg, &ep, 10);
143:
144: switch (*ep) {
145: case '\0':
146: break;
147: case 'm':
148: case 'M':
149: /* Time in minutes. */
150: time_interval *= 60;
151: if (ep[1] == '\0')
152: break;
153: /*FALLTHROUGH*/
154: default:
155: errx(1, "Invalid argument: `%s'", optarg);
156: }
157:
158: if (time_interval <= 0)
1.29 christos 159: errx(1, "Interval must be greater than 0");
1.28 christos 160:
1.29 christos 161: if (time_interval > MAX_INTERVAL)
162: errx(1, "Interval cannot be greater than"
163: " %d minutes", MAX_INTERVAL / 60);
1.28 christos 164: break;
1.31 tsarna 165:
166: case 'u':
167: newuser = optarg;
168: break;
169:
1.28 christos 170: default:
171: usage();
172: }
173: }
174:
1.1 cgd 175: sp = getservbyname("who", "udp");
1.12 lukem 176: if (sp == NULL)
1.26 peter 177: errx(EXIT_FAILURE, "udp/who: unknown service");
1.1 cgd 178: #ifndef DEBUG
1.26 peter 179: (void)daemon(1, 0);
180: (void)pidfile(NULL);
1.1 cgd 181: #endif
1.12 lukem 182: if (chdir(_PATH_RWHODIR) < 0)
1.26 peter 183: err(EXIT_FAILURE, "%s", _PATH_RWHODIR);
184: (void)signal(SIGHUP, sighup);
1.30 christos 185: openlog(getprogname(), LOG_PID, LOG_DAEMON);
1.1 cgd 186: /*
187: * Establish host name as returned by system.
188: */
1.8 jtc 189: if (gethostname(myname, sizeof(myname) - 1) < 0) {
1.1 cgd 190: syslog(LOG_ERR, "gethostname: %m");
1.26 peter 191: exit(EXIT_FAILURE);
1.1 cgd 192: }
1.13 mrg 193: myname[sizeof(myname) - 1] = '\0';
1.12 lukem 194: if ((cp = strchr(myname, '.')) != NULL)
1.1 cgd 195: *cp = '\0';
1.24 christos 196: (void)strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1);
197: getboottime();
1.1 cgd 198: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
199: syslog(LOG_ERR, "socket: %m");
1.26 peter 200: exit(EXIT_FAILURE);
1.1 cgd 201: }
1.8 jtc 202: if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
1.1 cgd 203: syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
1.26 peter 204: exit(EXIT_FAILURE);
1.1 cgd 205: }
1.24 christos 206: (void)memset(&sasin, 0, sizeof(sasin));
207: sasin.sin_family = AF_INET;
208: sasin.sin_port = sp->s_port;
209: if (bind(s, (struct sockaddr *)&sasin, sizeof(sasin)) < 0) {
1.1 cgd 210: syslog(LOG_ERR, "bind: %m");
1.26 peter 211: exit(EXIT_FAILURE);
1.1 cgd 212: }
213: if (!configure(s))
1.26 peter 214: exit(EXIT_FAILURE);
1.24 christos 215:
1.31 tsarna 216: if (newuser)
217: if (!drop_privs(newuser))
218: exit(EXIT_FAILURE);
219:
1.24 christos 220: send_host_information(s);
1.28 christos 221: delta.tv_sec = time_interval;
1.26 peter 222: delta.tv_usec = 0;
1.24 christos 223: gettimeofday(&now, NULL);
1.26 peter 224: timeradd(&now, &delta, &next);
1.24 christos 225:
226: pfd[0].fd = s;
1.25 christos 227: pfd[0].events = POLLIN;
1.24 christos 228:
1.1 cgd 229: for (;;) {
1.24 christos 230: int n;
1.1 cgd 231:
1.24 christos 232: n = poll(pfd, 1, 1000);
233:
234: if (onsighup) {
235: onsighup = 0;
236: getboottime();
1.1 cgd 237: }
1.24 christos 238:
239: if (n == 1)
240: handleread(s);
241:
242: (void)gettimeofday(&now, NULL);
1.26 peter 243: if (timercmp(&now, &next, >)) {
1.24 christos 244: send_host_information(s);
1.26 peter 245: timeradd(&now, &delta, &next);
1.16 mjl 246: }
1.24 christos 247: }
1.26 peter 248:
249: /* NOTREACHED */
250: return 0;
1.24 christos 251: }
252:
253: static void
1.26 peter 254: sighup(int signo __unused)
1.24 christos 255: {
256: onsighup = 1;
257: }
258:
259: static void
260: handleread(int s)
261: {
262: struct sockaddr_in from;
263: struct stat st;
264: char path[64];
265: struct whod wd;
266: int cc, whod;
267: socklen_t len = sizeof(from);
268:
269: cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,
270: (struct sockaddr *)&from, &len);
271: if (cc <= 0) {
272: if (cc < 0 && errno != EINTR)
273: syslog(LOG_WARNING, "recv: %m");
274: return;
275: }
276: if (from.sin_port != sp->s_port) {
277: syslog(LOG_WARNING, "%d: bad from port",
278: ntohs(from.sin_port));
279: return;
280: }
1.38 lukem 281: if (cc < (int)WHDRSIZE) {
1.24 christos 282: syslog(LOG_WARNING, "Short packet from %s",
283: inet_ntoa(from.sin_addr));
284: return;
285: }
286:
287: if (wd.wd_vers != WHODVERSION)
288: return;
289: if (wd.wd_type != WHODTYPE_STATUS)
290: return;
1.27 junyoung 291: /*
1.24 christos 292: * Ensure null termination of the name within the packet.
293: * Otherwise we might overflow or read past the end.
294: */
295: wd.wd_hostname[sizeof(wd.wd_hostname)-1] = 0;
296: if (!verify(wd.wd_hostname)) {
297: syslog(LOG_WARNING, "malformed host name from %s",
298: inet_ntoa(from.sin_addr));
299: return;
300: }
301: (void)snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname);
302: /*
303: * Rather than truncating and growing the file each time,
304: * use ftruncate if size is less than previous size.
305: */
306: whod = open(path, O_WRONLY | O_CREAT, 0644);
307: if (whod < 0) {
308: syslog(LOG_WARNING, "%s: %m", path);
309: return;
310: }
1.1 cgd 311: #if ENDIAN != BIG_ENDIAN
1.24 christos 312: {
1.26 peter 313: int i, n = (cc - WHDRSIZE) / sizeof(struct whoent);
1.24 christos 314: struct whoent *we;
315:
316: /* undo header byte swapping before writing to file */
317: wd.wd_sendtime = ntohl(wd.wd_sendtime);
318: for (i = 0; i < 3; i++)
319: wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
320: wd.wd_boottime = ntohl(wd.wd_boottime);
321: we = wd.wd_we;
322: for (i = 0; i < n; i++) {
323: we->we_idle = ntohl(we->we_idle);
324: we->we_utmp.out_time =
325: ntohl(we->we_utmp.out_time);
326: we++;
1.1 cgd 327: }
1.24 christos 328: }
1.1 cgd 329: #endif
1.34 mrg 330: wd.wd_recvtime = time(NULL);
1.24 christos 331: (void)write(whod, (char *)&wd, cc);
332: if (fstat(whod, &st) < 0 || st.st_size > cc)
333: (void)ftruncate(whod, cc);
334: (void)close(whod);
1.1 cgd 335: }
336:
337: /*
338: * Check out host name for unprintables
339: * and other funnies before allowing a file
340: * to be created. Sorry, but blanks aren't allowed.
341: */
1.24 christos 342: static int
343: verify(const char *name)
1.1 cgd 344: {
1.12 lukem 345: int size = 0;
1.1 cgd 346:
347: while (*name) {
1.24 christos 348: if (!isascii((unsigned char)*name) ||
349: !(isalnum((unsigned char)*name) ||
350: ispunct((unsigned char)*name)))
351: return 0;
1.1 cgd 352: name++, size++;
353: }
1.24 christos 354: return size > 0;
1.1 cgd 355: }
356:
1.24 christos 357: static void
358: send_host_information(int s)
1.1 cgd 359: {
1.12 lukem 360: struct neighbor *np;
361: struct whoent *we = mywd.wd_we, *wlast;
1.27 junyoung 362: int i, cc, utmpent = 0;
1.1 cgd 363: struct stat stb;
1.8 jtc 364: double avenrun[3];
365: time_t now;
1.19 christos 366: static struct utmpentry *ohead = NULL;
367: struct utmpentry *ep;
1.26 peter 368: static int count = 0;
1.1 cgd 369:
1.8 jtc 370: now = time(NULL);
1.26 peter 371: if (count % 10 == 0)
1.24 christos 372: getboottime();
1.26 peter 373: count++;
1.19 christos 374:
375: (void)getutentries(NULL, &ep);
1.36 dholland 376: /* XXX probably should expose utmp mtime, check that instead */
1.19 christos 377: if (ep != ohead) {
378: wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1];
379: for (; ep; ep = ep->next) {
380: (void)strncpy(we->we_utmp.out_line, ep->line,
1.33 christos 381: sizeof(we->we_utmp.out_line));
1.19 christos 382: (void)strncpy(we->we_utmp.out_name, ep->name,
1.33 christos 383: sizeof(we->we_utmp.out_name));
1.19 christos 384: we->we_utmp.out_time = htonl(ep->tv.tv_sec);
385: if (we >= wlast)
386: break;
387: we++;
1.1 cgd 388: }
389: utmpent = we - mywd.wd_we;
390: }
391:
392: /*
393: * The test on utmpent looks silly---after all, if no one is
394: * logged on, why worry about efficiency?---but is useful on
395: * (e.g.) compute servers.
396: */
397: if (utmpent && chdir(_PATH_DEV)) {
398: syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV);
1.26 peter 399: exit(EXIT_FAILURE);
1.1 cgd 400: }
401: we = mywd.wd_we;
402: for (i = 0; i < utmpent; i++) {
403: if (stat(we->we_utmp.out_line, &stb) >= 0)
404: we->we_idle = htonl(now - stb.st_atime);
405: we++;
406: }
1.8 jtc 407: (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
1.1 cgd 408: for (i = 0; i < 3; i++)
409: mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
410: cc = (char *)we - (char *)&mywd;
411: mywd.wd_sendtime = htonl(time(0));
412: mywd.wd_vers = WHODVERSION;
413: mywd.wd_type = WHODTYPE_STATUS;
414: for (np = neighbors; np != NULL; np = np->n_next)
1.30 christos 415: (void)Sendto(s, (char *)&mywd, cc, 0,
1.8 jtc 416: np->n_addr, np->n_addrlen);
1.1 cgd 417: if (utmpent && chdir(_PATH_RWHODIR)) {
418: syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
1.26 peter 419: exit(EXIT_FAILURE);
1.1 cgd 420: }
421: }
422:
1.24 christos 423: static void
424: getboottime(void)
1.1 cgd 425: {
1.8 jtc 426: int mib[2];
427: size_t size;
428: struct timeval tm;
429:
430: mib[0] = CTL_KERN;
431: mib[1] = KERN_BOOTTIME;
432: size = sizeof(tm);
433: if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) {
434: syslog(LOG_ERR, "cannot get boottime: %m");
1.26 peter 435: exit(EXIT_FAILURE);
1.8 jtc 436: }
437: mywd.wd_boottime = htonl(tm.tv_sec);
438: }
439:
1.24 christos 440: static void
441: quit(const char *msg)
1.8 jtc 442: {
1.18 is 443: syslog(LOG_ERR, "%s", msg);
1.26 peter 444: exit(EXIT_FAILURE);
1.8 jtc 445: }
446:
447: #define ROUNDUP(a) \
448: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1.24 christos 449: #define ADVANCE(x, n) ((char *)(x) + ROUNDUP((n)->sa_len))
1.8 jtc 450:
1.24 christos 451: static void
452: rt_xaddrs(void *cp, void *cplim, struct rt_addrinfo *rtinfo)
1.8 jtc 453: {
1.12 lukem 454: struct sockaddr *sa;
455: int i;
1.8 jtc 456:
1.24 christos 457: (void)memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
1.8 jtc 458: for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
459: if ((rtinfo->rti_addrs & (1 << i)) == 0)
460: continue;
461: rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
1.24 christos 462: cp = ADVANCE(cp, sa);
1.8 jtc 463: }
1.1 cgd 464: }
465:
466: /*
467: * Figure out device configuration and select
468: * networks which deserve status information.
469: */
1.24 christos 470: static int
471: configure(int s)
1.1 cgd 472: {
1.12 lukem 473: struct neighbor *np;
474: struct if_msghdr *ifm;
475: struct ifa_msghdr *ifam;
1.8 jtc 476: struct sockaddr_dl *sdl;
477: size_t needed;
478: int mib[6], flags = 0, len;
479: char *buf, *lim, *next;
480: struct rt_addrinfo info;
1.24 christos 481: struct sockaddr_in dstaddr;
1.8 jtc 482:
483: mib[0] = CTL_NET;
484: mib[1] = PF_ROUTE;
485: mib[2] = 0;
486: mib[3] = AF_INET;
487: mib[4] = NET_RT_IFLIST;
488: mib[5] = 0;
489: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
490: quit("route-sysctl-estimate");
491: if ((buf = malloc(needed)) == NULL)
492: quit("malloc");
493: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
494: quit("actual retrieval of interface table");
495: lim = buf + needed;
496:
497: sdl = NULL; /* XXX just to keep gcc -Wall happy */
498: for (next = buf; next < lim; next += ifm->ifm_msglen) {
499: ifm = (struct if_msghdr *)next;
500: if (ifm->ifm_type == RTM_IFINFO) {
501: sdl = (struct sockaddr_dl *)(ifm + 1);
502: flags = ifm->ifm_flags;
503: continue;
504: }
505: if ((flags & IFF_UP) == 0 ||
506: (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
507: continue;
508: if (ifm->ifm_type != RTM_NEWADDR)
509: quit("out of sync parsing NET_RT_IFLIST");
510: ifam = (struct ifa_msghdr *)ifm;
511: info.rti_addrs = ifam->ifam_addrs;
1.24 christos 512: rt_xaddrs((ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
1.8 jtc 513: /* gag, wish we could get rid of Internet dependencies */
1.24 christos 514: if (info.rti_info[RTAX_BRD] == NULL ||
515: info.rti_info[RTAX_BRD]->sa_family != AF_INET)
516: continue;
517: (void)memcpy(&dstaddr, info.rti_info[RTAX_BRD],
518: sizeof(dstaddr));
1.8 jtc 519: #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr
520: #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port
1.24 christos 521: PORT_SA(&dstaddr) = sp->s_port;
1.1 cgd 522: for (np = neighbors; np != NULL; np = np->n_next)
1.8 jtc 523: if (memcmp(sdl->sdl_data, np->n_name,
524: sdl->sdl_nlen) == 0 &&
1.24 christos 525: IPADDR_SA(np->n_addr) == IPADDR_SA(&dstaddr))
1.1 cgd 526: break;
527: if (np != NULL)
528: continue;
1.24 christos 529: len = sizeof(*np) + dstaddr.sin_len + sdl->sdl_nlen + 1;
1.8 jtc 530: np = (struct neighbor *)malloc(len);
1.1 cgd 531: if (np == NULL)
1.8 jtc 532: quit("malloc of neighbor structure");
1.24 christos 533: (void)memset(np, 0, len);
1.8 jtc 534: np->n_flags = flags;
535: np->n_addr = (struct sockaddr *)(np + 1);
1.24 christos 536: np->n_addrlen = dstaddr.sin_len;
1.8 jtc 537: np->n_name = np->n_addrlen + (char *)np->n_addr;
1.1 cgd 538: np->n_next = neighbors;
539: neighbors = np;
1.24 christos 540: (void)memcpy(np->n_addr, &dstaddr, np->n_addrlen);
541: (void)memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen);
1.1 cgd 542: }
1.8 jtc 543: free(buf);
1.1 cgd 544: return (1);
545: }
546:
547: #ifdef DEBUG
1.24 christos 548: static ssize_t
549: Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to,
550: socklen_t tolen)
1.1 cgd 551: {
1.12 lukem 552: struct whod *w = (struct whod *)buf;
553: struct whoent *we;
1.24 christos 554: struct sockaddr_in *sasin = (struct sockaddr_in *)to;
1.30 christos 555: ssize_t ret;
556:
557: ret = sendto(s, buf, cc, flags, to, tolen);
1.1 cgd 558:
1.28 christos 559: printf("sendto %s.%d\n", inet_ntoa(sasin->sin_addr),
1.24 christos 560: ntohs(sasin->sin_port));
1.1 cgd 561: printf("hostname %s %s\n", w->wd_hostname,
562: interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));
563: printf("load %4.2f, %4.2f, %4.2f\n",
564: ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
565: ntohl(w->wd_loadav[2]) / 100.0);
566: cc -= WHDRSIZE;
1.8 jtc 567: for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) {
1.1 cgd 568: time_t t = ntohl(we->we_utmp.out_time);
1.20 christos 569: printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name,
570: w->wd_hostname, we->we_utmp.out_line, ctime(&t)+4);
1.1 cgd 571: we->we_idle = ntohl(we->we_idle) / 60;
572: if (we->we_idle) {
573: if (we->we_idle >= 100*60)
574: we->we_idle = 100*60 - 1;
575: if (we->we_idle >= 60)
576: printf(" %2d", we->we_idle / 60);
577: else
578: printf(" ");
579: printf(":%02d", we->we_idle % 60);
580: }
581: printf("\n");
582: }
1.30 christos 583: return ret;
1.1 cgd 584: }
585:
1.24 christos 586: static char *
587: interval(int time, const char *updown)
1.1 cgd 588: {
589: static char resbuf[32];
590: int days, hours, minutes;
591:
592: if (time < 0 || time > 3*30*24*60*60) {
1.21 itojun 593: (void)snprintf(resbuf, sizeof(resbuf), " %s ??:??", updown);
1.1 cgd 594: return (resbuf);
595: }
596: minutes = (time + 59) / 60; /* round to minutes */
597: hours = minutes / 60; minutes %= 60;
598: days = hours / 24; hours %= 24;
599: if (days)
1.21 itojun 600: (void)snprintf(resbuf, sizeof(resbuf), "%s %2d+%02d:%02d",
1.1 cgd 601: updown, days, hours, minutes);
602: else
1.21 itojun 603: (void)snprintf(resbuf, sizeof(resbuf), "%s %2d:%02d",
1.1 cgd 604: updown, hours, minutes);
1.24 christos 605: return resbuf;
1.1 cgd 606: }
607: #endif
1.28 christos 608:
1.31 tsarna 609: static int
610: drop_privs(char *newuser)
611: {
612: struct passwd *pw;
613: gid_t gidset[1];
614:
615: pw = getpwnam(newuser);
616: if (pw == NULL) {
617: syslog(LOG_ERR, "no user %.100s", newuser);
618: return 0;
619: }
620:
621: endpwent();
622:
623: gidset[0] = pw->pw_gid;
624: if (setgroups(1, gidset) == -1) {
625: syslog(LOG_ERR, "setgroups: %m");
626: return 0;
627: }
628:
629: if (setgid(pw->pw_gid) == -1) {
630: syslog(LOG_ERR, "setgid: %m");
631: return 0;
632: }
633:
634: if (setuid(pw->pw_uid) == -1) {
635: syslog(LOG_ERR, "setuid: %m");
636: return 0;
637: }
638:
639: return 1;
640: }
641:
1.28 christos 642: static void
643: usage(void)
644: {
1.32 wiz 645: (void)fprintf(stderr, "Usage: %s [-i interval] [-u user]\n", getprogname());
1.30 christos 646: exit(EXIT_FAILURE);
1.28 christos 647: }
CVSweb <webmaster@jp.NetBSD.org>