source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/rcmd.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 21.9 KB
Line 
1/*
2 * Copyright (C) 1998 WIDE Project.
3 * 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 * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 * Copyright (c) 1983, 1993, 1994
31 *      The Regents of the University of California.  All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 4. Neither the name of the University nor the names of its contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58#if defined(LIBC_SCCS) && !defined(lint)
59static char sccsid[] = "@(#)rcmd.c      8.3 (Berkeley) 3/26/94";
60#endif /* LIBC_SCCS and not lint */
61
62#include <sys/param.h>
63#include <sys/poll.h>
64#include <sys/socket.h>
65#include <sys/stat.h>
66
67#include <netinet/in.h>
68#include <arpa/inet.h>
69
70#include <alloca.h>
71#include <signal.h>
72#include <fcntl.h>
73#include <netdb.h>
74#include <unistd.h>
75#include <pwd.h>
76#include <errno.h>
77#include <stdio.h>
78#include <stdio_ext.h>
79#include <ctype.h>
80#include <string.h>
81#include <libintl.h>
82#include <stdlib.h>
83#include <wchar.h>
84#include <sys/uio.h>
85
86#include "local.h"
87
88
89int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
90static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
91                            const char *, const char *, const char *);
92static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
93                        int superuser, const char *ruser,
94                        const char *luser, const char *rhost);
95static int ruserok_sa (struct sockaddr *ra, size_t ralen,
96                        int superuser, const char *ruser,
97                        const char *luser);
98int iruserok_af (const void *raddr, int superuser, const char *ruser,
99                 const char *luser, sa_family_t af);
100int iruserok (u_int32_t raddr, int superuser, const char *ruser,
101              const char *luser);
102
103libc_hidden_proto (iruserok_af)
104
105libc_freeres_ptr(static char *ahostbuf);
106
107int
108rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
109        char **ahost;
110        u_short rport;
111        const char *locuser, *remuser, *cmd;
112        int *fd2p;
113        sa_family_t af;
114{
115        char paddr[INET6_ADDRSTRLEN];
116        struct addrinfo hints, *res, *ai;
117        struct sockaddr_storage from;
118        struct pollfd pfd[2];
119        int32_t oldmask;
120        pid_t pid;
121        int s, lport, timo, error;
122        char c;
123        int refused;
124        char num[8];
125        ssize_t n;
126
127        if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
128          {
129            __set_errno (EAFNOSUPPORT);
130            return -1;
131          }
132
133        pid = __getpid();
134
135        memset(&hints, '\0', sizeof(hints));
136        hints.ai_flags = AI_CANONNAME;
137        hints.ai_family = af;
138        hints.ai_socktype = SOCK_STREAM;
139        (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
140        error = getaddrinfo(*ahost, num, &hints, &res);
141        if (error) {
142                if (error == EAI_NONAME && *ahost != NULL) {
143                        if (_IO_fwide (stderr, 0) > 0)
144                                __fwprintf(stderr, L"%s: Unknown host\n",
145                                           *ahost);
146                        else
147                                fprintf(stderr, "%s: Unknown host\n", *ahost);
148                } else {
149                        if (_IO_fwide (stderr, 0) > 0)
150                                __fwprintf(stderr, L"rcmd: getaddrinfo: %s\n",
151                                           gai_strerror(error));
152                        else
153                                fprintf(stderr, "rcmd: getaddrinfo: %s\n",
154                                        gai_strerror(error));
155                }
156                return (-1);
157        }
158
159        pfd[0].events = POLLIN;
160        pfd[1].events = POLLIN;
161
162        if (res->ai_canonname){
163                free (ahostbuf);
164                ahostbuf = strdup (res->ai_canonname);
165                if (ahostbuf == NULL) {
166                        if (_IO_fwide (stderr, 0) > 0)
167                                __fwprintf(stderr, L"%s",
168                                           _("rcmd: Cannot allocate memory\n"));
169                        else
170                                fputs(_("rcmd: Cannot allocate memory\n"),
171                                      stderr);
172                        return (-1);
173                }
174                *ahost = ahostbuf;
175        } else
176                *ahost = NULL;
177        ai = res;
178        refused = 0;
179        oldmask = __sigblock(sigmask(SIGURG));
180        for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
181                char errbuf[200];
182
183                s = rresvport_af(&lport, ai->ai_family);
184                if (s < 0) {
185                        if (errno == EAGAIN) {
186                                if (_IO_fwide (stderr, 0) > 0)
187                                        __fwprintf(stderr, L"%s",
188                                                   _("rcmd: socket: All ports in use\n"));
189                                else
190                                        fputs(_("rcmd: socket: All ports in use\n"),
191                                              stderr);
192                        } else {
193                                if (_IO_fwide (stderr, 0) > 0)
194                                        __fwprintf(stderr,
195                                                   L"rcmd: socket: %m\n");
196                                else
197                                        fprintf(stderr, "rcmd: socket: %m\n");
198                        }
199                        __sigsetmask(oldmask);
200                        freeaddrinfo(res);
201                        return -1;
202                }
203                __fcntl(s, F_SETOWN, pid);
204                if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
205                        break;
206                (void)__close(s);
207                if (errno == EADDRINUSE) {
208                        lport--;
209                        continue;
210                }
211                if (errno == ECONNREFUSED)
212                        refused = 1;
213                if (ai->ai_next != NULL) {
214                        int oerrno = errno;
215                        char *buf = NULL;
216
217                        getnameinfo(ai->ai_addr, ai->ai_addrlen,
218                                    paddr, sizeof(paddr),
219                                    NULL, 0,
220                                    NI_NUMERICHOST);
221
222                        if (__asprintf (&buf, _("connect to address %s: "),
223                                        paddr) >= 0)
224                          {
225                            if (_IO_fwide (stderr, 0) > 0)
226                              __fwprintf(stderr, L"%s", buf);
227                            else
228                              fputs (buf, stderr);
229                            free (buf);
230                          }
231                        __set_errno (oerrno);
232                        perror(0);
233                        ai = ai->ai_next;
234                        getnameinfo(ai->ai_addr, ai->ai_addrlen,
235                                    paddr, sizeof(paddr),
236                                    NULL, 0,
237                                    NI_NUMERICHOST);
238                        if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
239                          {
240                            if (_IO_fwide (stderr, 0) > 0)
241                              __fwprintf (stderr, L"%s", buf);
242                            else
243                              fputs (buf, stderr);
244                            free (buf);
245                          }
246                        continue;
247                }
248                if (refused && timo <= 16) {
249                        (void)sleep(timo);
250                        timo *= 2;
251                        ai = res;
252                        refused = 0;
253                        continue;
254                }
255                freeaddrinfo(res);
256                if (_IO_fwide (stderr, 0) > 0)
257                        (void)__fwprintf(stderr, L"%s: %s\n", *ahost,
258                                         strerror_r(errno,
259                                                      errbuf, sizeof (errbuf)));
260                else
261                        (void)fprintf(stderr, "%s: %s\n", *ahost,
262                                      strerror_r(errno,
263                                                   errbuf, sizeof (errbuf)));
264                __sigsetmask(oldmask);
265                return -1;
266        }
267        lport--;
268        if (fd2p == 0) {
269                __write(s, "", 1);
270                lport = 0;
271        } else {
272                char num[8];
273                int s2 = rresvport_af(&lport, ai->ai_family), s3;
274                socklen_t len = ai->ai_addrlen;
275
276                if (s2 < 0)
277                        goto bad;
278                listen(s2, 1);
279                (void)snprintf(num, sizeof(num), "%d", lport);
280                if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
281                        char *buf = NULL;
282
283                        if (__asprintf (&buf, _("\
284rcmd: write (setting up stderr): %m\n")) >= 0)
285                          {
286                            if (_IO_fwide (stderr, 0) > 0)
287                              __fwprintf(stderr, L"%s", buf);
288                            else
289                              fputs (buf, stderr);
290                            free (buf);
291                          }
292                        (void)__close(s2);
293                        goto bad;
294                }
295                pfd[0].fd = s;
296                pfd[1].fd = s2;
297                __set_errno (0);
298                if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
299                        char *buf = NULL;
300
301                        if ((errno != 0
302                             && __asprintf(&buf, _("\
303rcmd: poll (setting up stderr): %m\n")) >= 0)
304                            || (errno == 0
305                                && __asprintf(&buf, _("\
306poll: protocol failure in circuit setup\n")) >= 0))
307                          {
308                            if (_IO_fwide (stderr, 0) > 0)
309                              __fwprintf (stderr, L"%s", buf);
310                            else
311                              fputs (buf, stderr);
312                            free  (buf);
313                          }
314                        (void)__close(s2);
315                        goto bad;
316                }
317                s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
318                                                &len));
319                switch (from.ss_family) {
320                case AF_INET:
321                        rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
322                        break;
323                case AF_INET6:
324                        rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
325                        break;
326                default:
327                        rport = 0;
328                        break;
329                }
330                (void)__close(s2);
331                if (s3 < 0) {
332                        if (_IO_fwide (stderr, 0) > 0)
333                                (void)__fwprintf(stderr,
334                                                 L"rcmd: accept: %m\n");
335                        else
336                                (void)fprintf(stderr,
337                                              "rcmd: accept: %m\n");
338                        lport = 0;
339                        goto bad;
340                }
341                *fd2p = s3;
342
343                if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
344                        char *buf = NULL;
345
346                        if (__asprintf(&buf, _("\
347socket: protocol failure in circuit setup\n")) >= 0)
348                          {
349                            if (_IO_fwide (stderr, 0) > 0)
350                              __fwprintf (stderr, L"%s", buf);
351                            else
352                              fputs (buf, stderr);
353                            free (buf);
354                          }
355                        goto bad2;
356                }
357        }
358        struct iovec iov[3] =
359          {
360            [0] = { .iov_base = (void *) locuser,
361                    .iov_len = strlen (locuser) + 1 },
362            [1] = { .iov_base = (void *) remuser,
363                    .iov_len = strlen (remuser) + 1 },
364            [2] = { .iov_base = (void *) cmd,
365                    .iov_len = strlen (cmd) + 1 }
366          };
367        (void) TEMP_FAILURE_RETRY (writev (s, iov, 3));
368        n = TEMP_FAILURE_RETRY (read(s, &c, 1));
369        if (n != 1) {
370                char *buf = NULL;
371
372                if ((n == 0
373                     && asprintf(&buf, _("rcmd: %s: short read"),
374                                   *ahost) >= 0)
375                    || (n != 0
376                        && asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
377                  {
378                    if (_IO_fwide (stderr, 0) > 0)
379                      __fwprintf (stderr, L"%s", buf);
380                    else
381                      fputs (buf, stderr);
382                    free (buf);
383                  }
384                goto bad2;
385        }
386        if (c != 0) {
387                while (__read(s, &c, 1) == 1) {
388                        (void)__write(STDERR_FILENO, &c, 1);
389                        if (c == '\n')
390                                break;
391                }
392                goto bad2;
393        }
394        __sigsetmask(oldmask);
395        freeaddrinfo(res);
396        return s;
397bad2:
398        if (lport)
399                (void)__close(*fd2p);
400bad:
401        (void)__close(s);
402        __sigsetmask(oldmask);
403        freeaddrinfo(res);
404        return -1;
405}
406libc_hidden_def (rcmd_af)
407
408int
409rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
410        char **ahost;
411        u_short rport;
412        const char *locuser, *remuser, *cmd;
413        int *fd2p;
414{
415  return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
416}
417
418int
419rresvport_af(alport, family)
420        int *alport;
421        sa_family_t family;
422{
423        struct sockaddr_storage ss;
424        int s;
425        size_t len;
426        uint16_t *sport;
427
428        switch(family){
429        case AF_INET:
430                len = sizeof(struct sockaddr_in);
431                sport = &((struct sockaddr_in *)&ss)->sin_port;
432                break;
433        case AF_INET6:
434                len = sizeof(struct sockaddr_in6);
435                sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
436                break;
437        default:
438                __set_errno (EAFNOSUPPORT);
439                return -1;
440        }
441        s = __socket(family, SOCK_STREAM, 0);
442        if (s < 0)
443                return -1;
444
445        memset (&ss, '\0', sizeof(ss));
446#ifdef SALEN
447        ss.__ss_len = len;
448#endif
449        ss.ss_family = family;
450
451        /* Ignore invalid values.  */
452        if (*alport < IPPORT_RESERVED / 2)
453                *alport = IPPORT_RESERVED / 2;
454        else if (*alport >= IPPORT_RESERVED)
455                *alport = IPPORT_RESERVED - 1;
456
457        int start = *alport;
458        do {
459                *sport = htons((uint16_t) *alport);
460                if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
461                        return s;
462                if (errno != EADDRINUSE) {
463                        (void)__close(s);
464                        return -1;
465                }
466                if ((*alport)-- == IPPORT_RESERVED/2)
467                        *alport = IPPORT_RESERVED - 1;
468        } while (*alport != start);
469        (void)__close(s);
470        __set_errno (EAGAIN);
471        return -1;
472}
473libc_hidden_def (rresvport_af)
474
475int
476rresvport(alport)
477        int *alport;
478{
479        return rresvport_af(alport, AF_INET);
480}
481
482int     __check_rhosts_file = 1;
483char    *__rcmd_errstr;
484
485int
486ruserok_af(rhost, superuser, ruser, luser, af)
487        const char *rhost, *ruser, *luser;
488        int superuser;
489        sa_family_t af;
490{
491        struct addrinfo hints, *res, *res0;
492        int gai;
493        int ret;
494
495        memset (&hints, '\0', sizeof(hints));
496        hints.ai_family = af;
497        gai = getaddrinfo(rhost, NULL, &hints, &res0);
498        if (gai)
499                return -1;
500        ret = -1;
501        for (res=res0; res; res=res->ai_next)
502                if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
503                                superuser, ruser, luser, rhost) == 0){
504                        ret = 0;
505                        break;
506                }
507        freeaddrinfo(res0);
508        return (ret);
509}
510libc_hidden_def (ruserok_af)
511
512int
513ruserok(rhost, superuser, ruser, luser)
514        const char *rhost, *ruser, *luser;
515        int superuser;
516{
517        return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
518}
519
520/* Extremely paranoid file open function. */
521static FILE *
522iruserfopen (const char *file, uid_t okuser)
523{
524  struct stat64 st;
525  char *cp = NULL;
526  FILE *res = NULL;
527
528  /* If not a regular file, if owned by someone other than user or
529     root, if writeable by anyone but the owner, or if hardlinked
530     anywhere, quit.  */
531  cp = NULL;
532  if (__lxstat64 (_STAT_VER, file, &st))
533    cp = _("lstat failed");
534  else if (!S_ISREG (st.st_mode))
535    cp = _("not regular file");
536  else
537    {
538      res = fopen (file, "rc");
539      if (!res)
540        cp = _("cannot open");
541      else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
542        cp = _("fstat failed");
543      else if (st.st_uid && st.st_uid != okuser)
544        cp = _("bad owner");
545      else if (st.st_mode & (S_IWGRP|S_IWOTH))
546        cp = _("writeable by other than owner");
547      else if (st.st_nlink > 1)
548        cp = _("hard linked somewhere");
549    }
550
551  /* If there were any problems, quit.  */
552  if (cp != NULL)
553    {
554      __rcmd_errstr = cp;
555      if (res)
556        fclose (res);
557      return NULL;
558    }
559
560  /* No threads use this stream.  */
561  __fsetlocking (res, FSETLOCKING_BYCALLER);
562
563  return res;
564}
565
566/*
567 * New .rhosts strategy: We are passed an ip address. We spin through
568 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
569 * has ip addresses, we don't have to trust a nameserver.  When it
570 * contains hostnames, we spin through the list of addresses the nameserver
571 * gives us and look for a match.
572 *
573 * Returns 0 if ok, -1 if not ok.
574 */
575static int
576ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
577     struct sockaddr *ra;
578     size_t ralen;
579     int superuser;
580     const char *ruser, *luser, *rhost;
581{
582  FILE *hostf = NULL;
583  int isbad = -1;
584
585  if (!superuser)
586    hostf = iruserfopen (_PATH_HEQUIV, 0);
587
588  if (hostf)
589    {
590      isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
591      fclose (hostf);
592
593      if (!isbad)
594        return 0;
595    }
596
597  if (__check_rhosts_file || superuser)
598    {
599      char *pbuf;
600      struct passwd pwdbuf, *pwd;
601      size_t dirlen;
602      size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
603      char *buffer = __alloca (buflen);
604      uid_t uid;
605
606      if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
607          || pwd == NULL)
608        return -1;
609
610      dirlen = strlen (pwd->pw_dir);
611      pbuf = alloca (dirlen + sizeof "/.rhosts");
612      __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
613                 "/.rhosts", sizeof "/.rhosts");
614
615       /* Change effective uid while reading .rhosts.  If root and
616          reading an NFS mounted file system, can't read files that
617          are protected read/write owner only.  */
618       uid = __geteuid ();
619       seteuid (pwd->pw_uid);
620       hostf = iruserfopen (pbuf, pwd->pw_uid);
621
622       if (hostf != NULL)
623         {
624           isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
625           fclose (hostf);
626         }
627
628       seteuid (uid);
629       return isbad;
630    }
631  return -1;
632}
633/*
634 * ruserok_sa() is now discussed on ipng, so
635 * currently disabled for external use
636 */
637static int ruserok_sa(ra, ralen, superuser, ruser, luser)
638     struct sockaddr *ra;
639     size_t ralen;
640     int superuser;
641     const char *ruser, *luser;
642{
643  return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
644}
645
646/* This is the exported version.  */
647int
648iruserok_af (raddr, superuser, ruser, luser, af)
649     const void *raddr;
650     int superuser;
651     const char *ruser, *luser;
652     sa_family_t af;
653{
654  struct sockaddr_storage ra;
655  size_t ralen;
656
657  memset (&ra, '\0', sizeof(ra));
658  switch (af){
659  case AF_INET:
660    ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
661    memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
662            sizeof(struct in_addr));
663    ralen = sizeof(struct sockaddr_in);
664    break;
665  case AF_INET6:
666    ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
667    memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
668            sizeof(struct in6_addr));
669    ralen = sizeof(struct sockaddr_in6);
670    break;
671  default:
672    return 0;
673  }
674  return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
675}
676libc_hidden_def (iruserok_af)
677
678int
679iruserok (raddr, superuser, ruser, luser)
680     u_int32_t raddr;
681     int superuser;
682     const char *ruser, *luser;
683{
684  return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
685}
686
687/*
688 * XXX
689 * Don't make static, used by lpd(8).
690 *
691 * This function is not used anymore. It is only present because lpd(8)
692 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
693 * argument. This means that netgroups won't work in .rhost/hosts.equiv
694 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
695 * or PAM.
696 * Returns 0 if ok, -1 if not ok.
697 */
698int
699__ivaliduser(hostf, raddr, luser, ruser)
700        FILE *hostf;
701        u_int32_t raddr;
702        const char *luser, *ruser;
703{
704        struct sockaddr_in ra;
705        memset(&ra, '\0', sizeof(ra));
706        ra.sin_family = AF_INET;
707        ra.sin_addr.s_addr = raddr;
708        return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
709                               luser, ruser, "-");
710}
711
712
713/* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
714static int
715internal_function
716__checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
717                const char *rhost)
718{
719        struct addrinfo hints, *res0, *res;
720        char raddr[INET6_ADDRSTRLEN];
721        int match;
722        int negate=1;    /* Multiply return with this to get -1 instead of 1 */
723
724        /* Check nis netgroup.  */
725        if (strncmp ("+@", lhost, 2) == 0)
726                return innetgr (&lhost[2], rhost, NULL, NULL);
727
728        if (strncmp ("-@", lhost, 2) == 0)
729                return -innetgr (&lhost[2], rhost, NULL, NULL);
730
731        /* -host */
732        if (strncmp ("-", lhost,1) == 0) {
733                negate = -1;
734                lhost++;
735        } else if (strcmp ("+",lhost) == 0) {
736                return 1;                    /* asking for trouble, but ok.. */
737        }
738
739        /* Try for raw ip address first. */
740        /* XXX */
741        if (getnameinfo(ra, ralen,
742                        raddr, sizeof(raddr), NULL, 0,
743                        NI_NUMERICHOST) == 0
744            && strcmp(raddr, lhost) == 0)
745                return negate;
746
747        /* Better be a hostname. */
748        match = 0;
749        memset(&hints, '\0', sizeof(hints));
750        hints.ai_family = ra->sa_family;
751        if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
752                /* Spin through ip addresses. */
753                for (res = res0; res; res = res->ai_next)
754                  {
755                    if (res->ai_family == ra->sa_family
756                        && !memcmp(res->ai_addr, ra, res->ai_addrlen))
757                      {
758                        match = 1;
759                        break;
760                      }
761                  }
762                freeaddrinfo (res0);
763        }
764        return negate * match;
765}
766
767/* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
768static int
769internal_function
770__icheckuser (const char *luser, const char *ruser)
771{
772    /*
773      luser is user entry from .rhosts/hosts.equiv file
774      ruser is user id on remote host
775      */
776
777    /* [-+]@netgroup */
778    if (strncmp ("+@", luser, 2) == 0)
779        return innetgr (&luser[2], NULL, ruser, NULL);
780
781    if (strncmp ("-@", luser,2) == 0)
782        return -innetgr (&luser[2], NULL, ruser, NULL);
783
784    /* -user */
785    if (strncmp ("-", luser, 1) == 0)
786        return -(strcmp (&luser[1], ruser) == 0);
787
788    /* + */
789    if (strcmp ("+", luser) == 0)
790        return 1;
791
792    /* simple string match */
793    return strcmp (ruser, luser) == 0;
794}
795
796/*
797 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
798 */
799static int
800__isempty (char *p)
801{
802    while (*p && isspace (*p)) {
803        ++p;
804    }
805
806    return (*p == '\0' || *p == '#') ? 1 : 0 ;
807}
808
809/*
810 * Returns 0 if positive match, -1 if _not_ ok.
811 */
812static int
813__validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
814        FILE *hostf;
815        struct sockaddr *ra;
816        size_t ralen;
817        const char *luser, *ruser, *rhost;
818{
819    register const char *user;
820    register char *p;
821    int hcheck, ucheck;
822    char *buf = NULL;
823    size_t bufsize = 0;
824    int retval = -1;
825
826    while (__getline (&buf, &bufsize, hostf) > 0) {
827        buf[bufsize - 1] = '\0'; /* Make sure it's terminated.  */
828        p = buf;
829
830        /* Skip empty or comment lines */
831        if (__isempty (p)) {
832            continue;
833        }
834
835        for (;*p && !isspace(*p); ++p) {
836            *p = _tolower (*p);
837        }
838
839        /* Next we want to find the permitted name for the remote user.  */
840        if (*p == ' ' || *p == '\t') {
841            /* <nul> terminate hostname and skip spaces */
842            for (*p++='\0'; *p && isspace (*p); ++p);
843
844            user = p;                   /* this is the user's name */
845            while (*p && !isspace (*p))
846                ++p;                    /* find end of user's name */
847        } else
848            user = p;
849
850        *p = '\0';              /* <nul> terminate username (+host?) */
851
852        /* buf -> host(?) ; user -> username(?) */
853
854        /* First check host part */
855        hcheck = __checkhost_sa (ra, ralen, buf, rhost);
856
857        if (hcheck < 0)
858            break;
859
860        if (hcheck) {
861            /* Then check user part */
862            if (! (*user))
863                user = luser;
864
865            ucheck = __icheckuser (user, ruser);
866
867            /* Positive 'host user' match? */
868            if (ucheck > 0) {
869                retval = 0;
870                break;
871            }
872
873            /* Negative 'host -user' match? */
874            if (ucheck < 0)
875                break;
876
877            /* Neither, go on looking for match */
878        }
879    }
880
881    if (buf != NULL)
882      free (buf);
883
884    return retval;
885}
Note: See TracBrowser for help on using the repository browser.