[BACK]Return to rwhod.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / rwhod

Annotation of src/usr.sbin/rwhod/rwhod.c, Revision 1.33

1.33    ! christos    1: /*     $NetBSD: rwhod.c,v 1.32 2005/09/12 18:34:37 wiz 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.11      lukem      34: __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
                     35:        The Regents of the University of California.  All rights reserved.\n");
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.33    ! christos   42: __RCSID("$NetBSD: rwhod.c,v 1.32 2005/09/12 18:34:37 wiz 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);
                    109: static void     quit(const char *);
                    110: static void     rt_xaddrs(void *, void *, struct rt_addrinfo *);
1.31      tsarna    111: static int      drop_privs(char *);
1.28      christos  112: static void     usage(void) __attribute__((__noreturn__));
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:        }
                    281:        if (cc < WHDRSIZE) {
                    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.24      christos  330:        (void)time((time_t *)&wd.wd_recvtime);
                    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);
                    376:        if (ep != ohead) {
                    377:                freeutentries(ep);
                    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>