source: rtems-libbsd/freebsd/lib/libc/net/rcmd.c @ 2404264

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 2404264 was 2404264, checked in by Sebastian Huber <sebastian.huber@…>, on 10/30/13 at 12:23:59

Revert superfluous changes

  • Property mode set to 100644
File size: 18.7 KB
Line 
1/*
2 * Copyright (c) 1983, 1993, 1994
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if defined(LIBC_SCCS) && !defined(lint)
31static char sccsid[] = "@(#)rcmd.c      8.3 (Berkeley) 3/26/94";
32#endif /* LIBC_SCCS and not lint */
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "namespace.h"
37#include <rtems/bsd/sys/param.h>
38#include <sys/socket.h>
39#include <sys/stat.h>
40
41#include <netinet/in.h>
42#include <arpa/inet.h>
43
44#include <signal.h>
45#include <fcntl.h>
46#include <netdb.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <pwd.h>
50#include <errno.h>
51#include <stdio.h>
52#include <ctype.h>
53#include <string.h>
54#include <rpc/rpc.h>
55#ifdef YP
56#include <rpcsvc/yp_prot.h>
57#include <rpcsvc/ypclnt.h>
58#endif
59#include <arpa/nameser.h>
60#include "un-namespace.h"
61
62extern int innetgr( const char *, const char *, const char *, const char * );
63
64#define max(a, b)       ((a > b) ? a : b)
65
66int __ivaliduser(FILE *, u_int32_t, const char *, const char *);
67int __ivaliduser_af(FILE *,const void *, const char *, const char *, int, int);
68int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, const char *,
69    const char *);
70static int __icheckhost(const struct sockaddr *, socklen_t, const char *);
71
72char paddr[NI_MAXHOST];
73
74int
75rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
76        char **ahost;
77        u_short rport;
78        const char *locuser, *remuser, *cmd;
79        int *fd2p;
80{
81        return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
82}
83
84int
85rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
86        char **ahost;
87        u_short rport;
88        const char *locuser, *remuser, *cmd;
89        int *fd2p;
90        int af;
91{
92        struct addrinfo hints, *res, *ai;
93        struct sockaddr_storage from;
94        fd_set reads;
95        sigset_t oldmask, newmask;
96        pid_t pid;
97        int s, aport, lport, timo, error;
98        char c, *p;
99        int refused, nres;
100        char num[8];
101        static char canonnamebuf[MAXDNAME];     /* is it proper here? */
102
103        /* call rcmdsh() with specified remote shell if appropriate. */
104        if (!issetugid() && (p = getenv("RSH"))) {
105                struct servent *sp = getservbyname("shell", "tcp");
106
107                if (sp && sp->s_port == rport)
108                        return (rcmdsh(ahost, rport, locuser, remuser,
109                            cmd, p));
110        }
111
112        /* use rsh(1) if non-root and remote port is shell. */
113        if (geteuid()) {
114                struct servent *sp = getservbyname("shell", "tcp");
115
116                if (sp && sp->s_port == rport)
117                        return (rcmdsh(ahost, rport, locuser, remuser,
118                            cmd, NULL));
119        }
120
121        pid = getpid();
122
123        memset(&hints, 0, sizeof(hints));
124        hints.ai_flags = AI_CANONNAME;
125        hints.ai_family = af;
126        hints.ai_socktype = SOCK_STREAM;
127        hints.ai_protocol = 0;
128        (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
129        error = getaddrinfo(*ahost, num, &hints, &res);
130        if (error) {
131                fprintf(stderr, "rcmd: getaddrinfo: %s\n",
132                        gai_strerror(error));
133                if (error == EAI_SYSTEM)
134                        fprintf(stderr, "rcmd: getaddrinfo: %s\n",
135                                strerror(errno));
136                return (-1);
137        }
138
139        if (res->ai_canonname
140         && strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) {
141                strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf));
142                *ahost = canonnamebuf;
143        }
144        nres = 0;
145        for (ai = res; ai; ai = ai->ai_next)
146                nres++;
147        ai = res;
148        refused = 0;
149        sigemptyset(&newmask);
150        sigaddset(&newmask, SIGURG);
151        _sigprocmask(SIG_BLOCK, (const sigset_t *)&newmask, &oldmask);
152        for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
153                s = rresvport_af(&lport, ai->ai_family);
154                if (s < 0) {
155                        if (errno != EAGAIN && ai->ai_next) {
156                                ai = ai->ai_next;
157                                continue;
158                        }
159                        if (errno == EAGAIN)
160                                (void)fprintf(stderr,
161                                    "rcmd: socket: All ports in use\n");
162                        else
163                                (void)fprintf(stderr, "rcmd: socket: %s\n",
164                                    strerror(errno));
165                        freeaddrinfo(res);
166                        _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
167                            NULL);
168                        return (-1);
169                }
170                _fcntl(s, F_SETOWN, pid);
171                if (_connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
172                        break;
173                (void)_close(s);
174                if (errno == EADDRINUSE) {
175                        lport--;
176                        continue;
177                }
178                if (errno == ECONNREFUSED)
179                        refused = 1;
180                if (ai->ai_next == NULL && (!refused || timo > 16)) {
181                        (void)fprintf(stderr, "%s: %s\n",
182                                      *ahost, strerror(errno));
183                        freeaddrinfo(res);
184                        _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
185                            NULL);
186                        return (-1);
187                }
188                if (nres > 1) {
189                        int oerrno = errno;
190
191                        getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
192                            sizeof(paddr), NULL, 0, NI_NUMERICHOST);
193                        (void)fprintf(stderr, "connect to address %s: ",
194                                      paddr);
195                        errno = oerrno;
196                        perror(0);
197                }
198                if ((ai = ai->ai_next) == NULL) {
199                        /* refused && timo <= 16 */
200                        struct timespec time_to_sleep, time_remaining;
201
202                        time_to_sleep.tv_sec = timo;
203                        time_to_sleep.tv_nsec = 0;
204                        (void)_nanosleep(&time_to_sleep, &time_remaining);
205                        timo *= 2;
206                        ai = res;
207                        refused = 0;
208                }
209                if (nres > 1) {
210                        getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
211                            sizeof(paddr), NULL, 0, NI_NUMERICHOST);
212                        fprintf(stderr, "Trying %s...\n", paddr);
213                }
214        }
215        lport--;
216        if (fd2p == 0) {
217                _write(s, "", 1);
218                lport = 0;
219        } else {
220                int s2 = rresvport_af(&lport, ai->ai_family), s3;
221                socklen_t len = ai->ai_addrlen;
222                int nfds;
223
224                if (s2 < 0)
225                        goto bad;
226                _listen(s2, 1);
227                (void)snprintf(num, sizeof(num), "%d", lport);
228                if (_write(s, num, strlen(num)+1) != strlen(num)+1) {
229                        (void)fprintf(stderr,
230                            "rcmd: write (setting up stderr): %s\n",
231                            strerror(errno));
232                        (void)_close(s2);
233                        goto bad;
234                }
235                nfds = max(s, s2)+1;
236                if(nfds > FD_SETSIZE) {
237                        fprintf(stderr, "rcmd: too many files\n");
238                        (void)_close(s2);
239                        goto bad;
240                }
241again:
242                FD_ZERO(&reads);
243                FD_SET(s, &reads);
244                FD_SET(s2, &reads);
245                errno = 0;
246                if (_select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
247                        if (errno != 0)
248                                (void)fprintf(stderr,
249                                    "rcmd: select (setting up stderr): %s\n",
250                                    strerror(errno));
251                        else
252                                (void)fprintf(stderr,
253                                "select: protocol failure in circuit setup\n");
254                        (void)_close(s2);
255                        goto bad;
256                }
257                s3 = _accept(s2, (struct sockaddr *)&from, &len);
258                switch (from.ss_family) {
259                case AF_INET:
260                        aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
261                        break;
262#ifdef INET6
263                case AF_INET6:
264                        aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
265                        break;
266#endif
267                default:
268                        aport = 0;      /* error */
269                        break;
270                }
271                /*
272                 * XXX careful for ftp bounce attacks. If discovered, shut them
273                 * down and check for the real auxiliary channel to connect.
274                 */
275                if (aport == 20) {
276                        _close(s3);
277                        goto again;
278                }
279                (void)_close(s2);
280                if (s3 < 0) {
281                        (void)fprintf(stderr,
282                            "rcmd: accept: %s\n", strerror(errno));
283                        lport = 0;
284                        goto bad;
285                }
286                *fd2p = s3;
287                if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
288                        (void)fprintf(stderr,
289                            "socket: protocol failure in circuit setup.\n");
290                        goto bad2;
291                }
292        }
293        (void)_write(s, locuser, strlen(locuser)+1);
294        (void)_write(s, remuser, strlen(remuser)+1);
295        (void)_write(s, cmd, strlen(cmd)+1);
296        if (_read(s, &c, 1) != 1) {
297                (void)fprintf(stderr,
298                    "rcmd: %s: %s\n", *ahost, strerror(errno));
299                goto bad2;
300        }
301        if (c != 0) {
302                while (_read(s, &c, 1) == 1) {
303                        (void)_write(STDERR_FILENO, &c, 1);
304                        if (c == '\n')
305                                break;
306                }
307                goto bad2;
308        }
309        _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
310        freeaddrinfo(res);
311        return (s);
312bad2:
313        if (lport)
314                (void)_close(*fd2p);
315bad:
316        (void)_close(s);
317        _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
318        freeaddrinfo(res);
319        return (-1);
320}
321
322int
323rresvport(port)
324        int *port;
325{
326        return rresvport_af(port, AF_INET);
327}
328
329int
330rresvport_af(alport, family)
331        int *alport, family;
332{
333        int s;
334        struct sockaddr_storage ss;
335        u_short *sport;
336
337        memset(&ss, 0, sizeof(ss));
338        ss.ss_family = family;
339        switch (family) {
340        case AF_INET:
341                ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
342                sport = &((struct sockaddr_in *)&ss)->sin_port;
343                ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
344                break;
345#ifdef INET6
346        case AF_INET6:
347                ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
348                sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
349                ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
350                break;
351#endif
352        default:
353                errno = EAFNOSUPPORT;
354                return -1;
355        }
356
357        s = _socket(ss.ss_family, SOCK_STREAM, 0);
358        if (s < 0)
359                return (-1);
360#if 0 /* compat_exact_traditional_rresvport_semantics */
361        sin.sin_port = htons((u_short)*alport);
362        if (_bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
363                return (s);
364        if (errno != EADDRINUSE) {
365                (void)_close(s);
366                return (-1);
367        }
368#endif
369        *sport = 0;
370        if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
371                (void)_close(s);
372                return (-1);
373        }
374        *alport = (int)ntohs(*sport);
375        return (s);
376}
377
378int     __check_rhosts_file = 1;
379char    *__rcmd_errstr;
380
381int
382ruserok(rhost, superuser, ruser, luser)
383        const char *rhost, *ruser, *luser;
384        int superuser;
385{
386        struct addrinfo hints, *res, *r;
387        int error;
388
389        memset(&hints, 0, sizeof(hints));
390        hints.ai_family = PF_UNSPEC;
391        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
392        error = getaddrinfo(rhost, "0", &hints, &res);
393        if (error)
394                return (-1);
395
396        for (r = res; r; r = r->ai_next) {
397                if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
398                    luser) == 0) {
399                        freeaddrinfo(res);
400                        return (0);
401                }
402        }
403        freeaddrinfo(res);
404        return (-1);
405}
406
407/*
408 * New .rhosts strategy: We are passed an ip address. We spin through
409 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
410 * has ip addresses, we don't have to trust a nameserver.  When it
411 * contains hostnames, we spin through the list of addresses the nameserver
412 * gives us and look for a match.
413 *
414 * Returns 0 if ok, -1 if not ok.
415 */
416int
417iruserok(raddr, superuser, ruser, luser)
418        unsigned long raddr;
419        int superuser;
420        const char *ruser, *luser;
421{
422        struct sockaddr_in sin;
423
424        memset(&sin, 0, sizeof(sin));
425        sin.sin_family = AF_INET;
426        sin.sin_len = sizeof(struct sockaddr_in);
427        memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
428        return iruserok_sa((struct sockaddr *)&sin, sin.sin_len, superuser,
429                ruser, luser);
430}
431
432/*
433 * AF independent extension of iruserok.
434 *
435 * Returns 0 if ok, -1 if not ok.
436 */
437int
438iruserok_sa(ra, rlen, superuser, ruser, luser)
439        const void *ra;
440        int rlen;
441        int superuser;
442        const char *ruser, *luser;
443{
444        char *cp;
445        struct stat sbuf;
446        struct passwd *pwd;
447        FILE *hostf;
448        uid_t uid;
449        int first;
450        char pbuf[MAXPATHLEN];
451        const struct sockaddr *raddr;
452        struct sockaddr_storage ss;
453
454        /* avoid alignment issue */
455        if (rlen > sizeof(ss))
456                return(-1);
457        memcpy(&ss, ra, rlen);
458        raddr = (struct sockaddr *)&ss;
459
460        first = 1;
461        hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
462again:
463        if (hostf) {
464                if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) {
465                        (void)fclose(hostf);
466                        return (0);
467                }
468                (void)fclose(hostf);
469        }
470        if (first == 1 && (__check_rhosts_file || superuser)) {
471                first = 0;
472                if ((pwd = getpwnam(luser)) == NULL)
473                        return (-1);
474                (void)strcpy(pbuf, pwd->pw_dir);
475                (void)strcat(pbuf, "/.rhosts");
476
477                /*
478                 * Change effective uid while opening .rhosts.  If root and
479                 * reading an NFS mounted file system, can't read files that
480                 * are protected read/write owner only.
481                 */
482                uid = geteuid();
483                (void)seteuid(pwd->pw_uid);
484                hostf = fopen(pbuf, "r");
485                (void)seteuid(uid);
486
487                if (hostf == NULL)
488                        return (-1);
489                /*
490                 * If not a regular file, or is owned by someone other than
491                 * user or root or if writeable by anyone but the owner, quit.
492                 */
493                cp = NULL;
494                if (lstat(pbuf, &sbuf) < 0)
495                        cp = ".rhosts lstat failed";
496                else if (!S_ISREG(sbuf.st_mode))
497                        cp = ".rhosts not regular file";
498                else if (_fstat(fileno(hostf), &sbuf) < 0)
499                        cp = ".rhosts fstat failed";
500                else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
501                        cp = "bad .rhosts owner";
502                else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
503                        cp = ".rhosts writeable by other than owner";
504                /* If there were any problems, quit. */
505                if (cp) {
506                        __rcmd_errstr = cp;
507                        (void)fclose(hostf);
508                        return (-1);
509                }
510                goto again;
511        }
512        return (-1);
513}
514
515/*
516 * XXX
517 * Don't make static, used by lpd(8).
518 *
519 * Returns 0 if ok, -1 if not ok.
520 */
521int
522__ivaliduser(hostf, raddr, luser, ruser)
523        FILE *hostf;
524        u_int32_t raddr;
525        const char *luser, *ruser;
526{
527        struct sockaddr_in sin;
528
529        memset(&sin, 0, sizeof(sin));
530        sin.sin_family = AF_INET;
531        sin.sin_len = sizeof(struct sockaddr_in);
532        memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
533        return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len,
534                luser, ruser);
535}
536
537/*
538 * Returns 0 if ok, -1 if not ok.
539 *
540 * XXX obsolete API.
541 */
542int
543__ivaliduser_af(hostf, raddr, luser, ruser, af, len)
544        FILE *hostf;
545        const void *raddr;
546        const char *luser, *ruser;
547        int af, len;
548{
549        struct sockaddr *sa = NULL;
550        struct sockaddr_in *sin = NULL;
551#ifdef INET6
552        struct sockaddr_in6 *sin6 = NULL;
553#endif
554        struct sockaddr_storage ss;
555
556        memset(&ss, 0, sizeof(ss));
557        switch (af) {
558        case AF_INET:
559                if (len != sizeof(sin->sin_addr))
560                        return -1;
561                sin = (struct sockaddr_in *)&ss;
562                sin->sin_family = AF_INET;
563                sin->sin_len = sizeof(struct sockaddr_in);
564                memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr));
565                break;
566#ifdef INET6
567        case AF_INET6:
568                if (len != sizeof(sin6->sin6_addr))
569                        return -1;
570                /* you will lose scope info */
571                sin6 = (struct sockaddr_in6 *)&ss;
572                sin6->sin6_family = AF_INET6;
573                sin6->sin6_len = sizeof(struct sockaddr_in6);
574                memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr));
575                break;
576#endif
577        default:
578                return -1;
579        }
580
581        sa = (struct sockaddr *)&ss;
582        return __ivaliduser_sa(hostf, sa, sa->sa_len, luser, ruser);
583}
584
585int
586__ivaliduser_sa(hostf, raddr, salen, luser, ruser)
587        FILE *hostf;
588        const struct sockaddr *raddr;
589        socklen_t salen;
590        const char *luser, *ruser;
591{
592        char *user, *p;
593        int ch;
594        char buf[MAXHOSTNAMELEN + 128];         /* host + login */
595        char hname[MAXHOSTNAMELEN];
596        /* Presumed guilty until proven innocent. */
597        int userok = 0, hostok = 0;
598#ifdef YP
599        char *ypdomain;
600
601        if (yp_get_default_domain(&ypdomain))
602                ypdomain = NULL;
603#else
604#define ypdomain NULL
605#endif
606        /* We need to get the damn hostname back for netgroup matching. */
607        if (getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0,
608                        NI_NAMEREQD) != 0)
609                hname[0] = '\0';
610
611        while (fgets(buf, sizeof(buf), hostf)) {
612                p = buf;
613                /* Skip lines that are too long. */
614                if (strchr(p, '\n') == NULL) {
615                        while ((ch = getc(hostf)) != '\n' && ch != EOF);
616                        continue;
617                }
618                if (*p == '\n' || *p == '#') {
619                        /* comment... */
620                        continue;
621                }
622                while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
623                        *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p;
624                        p++;
625                }
626                if (*p == ' ' || *p == '\t') {
627                        *p++ = '\0';
628                        while (*p == ' ' || *p == '\t')
629                                p++;
630                        user = p;
631                        while (*p != '\n' && *p != ' ' &&
632                            *p != '\t' && *p != '\0')
633                                p++;
634                } else
635                        user = p;
636                *p = '\0';
637                /*
638                 * Do +/- and +@/-@ checking. This looks really nasty,
639                 * but it matches SunOS's behavior so far as I can tell.
640                 */
641                switch(buf[0]) {
642                case '+':
643                        if (!buf[1]) {     /* '+' matches all hosts */
644                                hostok = 1;
645                                break;
646                        }
647                        if (buf[1] == '@')  /* match a host by netgroup */
648                                hostok = hname[0] != '\0' &&
649                                    innetgr(&buf[2], hname, NULL, ypdomain);
650                        else            /* match a host by addr */
651                                hostok = __icheckhost(raddr, salen,
652                                                      (char *)&buf[1]);
653                        break;
654                case '-':     /* reject '-' hosts and all their users */
655                        if (buf[1] == '@') {
656                                if (hname[0] == '\0' ||
657                                    innetgr(&buf[2], hname, NULL, ypdomain))
658                                        return(-1);
659                        } else {
660                                if (__icheckhost(raddr, salen,
661                                                 (char *)&buf[1]))
662                                        return(-1);
663                        }
664                        break;
665                default:  /* if no '+' or '-', do a simple match */
666                        hostok = __icheckhost(raddr, salen, buf);
667                        break;
668                }
669                switch(*user) {
670                case '+':
671                        if (!*(user+1)) {      /* '+' matches all users */
672                                userok = 1;
673                                break;
674                        }
675                        if (*(user+1) == '@')  /* match a user by netgroup */
676                                userok = innetgr(user+2, NULL, ruser, ypdomain);
677                        else       /* match a user by direct specification */
678                                userok = !(strcmp(ruser, user+1));
679                        break;
680                case '-':               /* if we matched a hostname, */
681                        if (hostok) {   /* check for user field rejections */
682                                if (!*(user+1))
683                                        return(-1);
684                                if (*(user+1) == '@') {
685                                        if (innetgr(user+2, NULL,
686                                                        ruser, ypdomain))
687                                                return(-1);
688                                } else {
689                                        if (!strcmp(ruser, user+1))
690                                                return(-1);
691                                }
692                        }
693                        break;
694                default:        /* no rejections: try to match the user */
695                        if (hostok)
696                                userok = !(strcmp(ruser,*user ? user : luser));
697                        break;
698                }
699                if (hostok && userok)
700                        return(0);
701        }
702        return (-1);
703}
704
705/*
706 * Returns "true" if match, 0 if no match.
707 */
708static int
709__icheckhost(raddr, salen, lhost)
710        const struct sockaddr *raddr;
711        socklen_t salen;
712        const char *lhost;
713{
714        struct sockaddr_in sin;
715        struct sockaddr_in6 *sin6;
716        struct addrinfo hints, *res, *r;
717        int error;
718        char h1[NI_MAXHOST], h2[NI_MAXHOST];
719
720        if (raddr->sa_family == AF_INET6) {
721                sin6 = (struct sockaddr_in6 *)raddr;
722                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
723                        memset(&sin, 0, sizeof(sin));
724                        sin.sin_family = AF_INET;
725                        sin.sin_len = sizeof(struct sockaddr_in);
726                        memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
727                               sizeof(sin.sin_addr));
728                        raddr = (struct sockaddr *)&sin;
729                        salen = sin.sin_len;
730                }
731        }
732
733        h1[0] = '\0';
734        if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
735                        NI_NUMERICHOST) != 0)
736                return (0);
737
738        /* Resolve laddr into sockaddr */
739        memset(&hints, 0, sizeof(hints));
740        hints.ai_family = raddr->sa_family;
741        hints.ai_socktype = SOCK_DGRAM; /*XXX dummy*/
742        res = NULL;
743        error = getaddrinfo(lhost, "0", &hints, &res);
744        if (error)
745                return (0);
746
747        for (r = res; r ; r = r->ai_next) {
748                h2[0] = '\0';
749                if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
750                                NULL, 0, NI_NUMERICHOST) != 0)
751                        continue;
752                if (strcmp(h1, h2) == 0) {
753                        freeaddrinfo(res);
754                        return (1);
755                }
756        }
757
758        /* No match. */
759        freeaddrinfo(res);
760        return (0);
761}
Note: See TracBrowser for help on using the repository browser.