Update.
[glibc.git] / inet / rcmd.c
blob2c0a34de493fc7df5dfb4fb2251c5e770d3b8dc1
1 /*
2 * Copyright (C) 1998 WIDE Project.
3 * All rights reserved.
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.
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.
30 * Copyright (c) 1983, 1993, 1994
31 * The Regents of the University of California. All rights reserved.
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.
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.
58 #if defined(LIBC_SCCS) && !defined(lint)
59 static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
60 #endif /* LIBC_SCCS and not lint */
62 #include <sys/param.h>
63 #include <sys/poll.h>
64 #include <sys/socket.h>
65 #include <sys/stat.h>
67 #include <netinet/in.h>
68 #include <arpa/inet.h>
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 #ifdef USE_IN_LIBIO
84 # include <wchar.h>
85 #endif
88 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
89 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
90 const char *, const char *, const char *);
91 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
92 int superuser, const char *ruser,
93 const char *luser, const char *rhost);
94 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
95 int superuser, const char *ruser,
96 const char *luser);
97 int iruserok_af (const void *raddr, int superuser, const char *ruser,
98 const char *luser, sa_family_t af);
99 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
100 const char *luser);
102 static char ahostbuf[NI_MAXHOST];
105 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
106 char **ahost;
107 u_short rport;
108 const char *locuser, *remuser, *cmd;
109 int *fd2p;
110 sa_family_t af;
112 char paddr[INET6_ADDRSTRLEN];
113 struct addrinfo hints, *res, *ai;
114 struct sockaddr_storage from;
115 struct pollfd pfd[2];
116 int32_t oldmask;
117 pid_t pid;
118 int s, lport, timo, error;
119 char c;
120 int refused;
121 char num[8];
122 ssize_t n;
124 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
126 __set_errno (EAFNOSUPPORT);
127 return -1;
130 pid = __getpid();
132 memset(&hints, '\0', sizeof(hints));
133 hints.ai_flags = AI_CANONNAME;
134 hints.ai_family = af;
135 hints.ai_socktype = SOCK_STREAM;
136 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
137 error = getaddrinfo(*ahost, num, &hints, &res);
138 if (error) {
139 #ifdef USE_IN_LIBIO
140 if (_IO_fwide (stderr, 0) > 0)
141 __fwprintf(stderr, L"rcmd: getaddrinfo: %s\n",
142 gai_strerror(error));
143 else
144 #endif
145 fprintf(stderr, "rcmd: getaddrinfo: %s\n",
146 gai_strerror(error));
147 return (-1);
150 pfd[0].events = POLLIN;
151 pfd[1].events = POLLIN;
153 if (res->ai_canonname){
154 strncpy(ahostbuf, res->ai_canonname, sizeof(ahostbuf));
155 ahostbuf[sizeof(ahostbuf)-1] = '\0';
156 *ahost = ahostbuf;
158 else
159 *ahost = NULL;
160 ai = res;
161 refused = 0;
162 oldmask = __sigblock(sigmask(SIGURG));
163 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
164 char errbuf[200];
166 s = rresvport_af(&lport, ai->ai_family);
167 if (s < 0) {
168 if (errno == EAGAIN) {
169 #ifdef USE_IN_LIBIO
170 if (_IO_fwide (stderr, 0) > 0)
171 __fwprintf(stderr, L"%s",
172 _("rcmd: socket: All ports in use\n"));
173 else
174 #endif
175 fputs(_("rcmd: socket: All ports in use\n"),
176 stderr);
177 } else {
178 #ifdef USE_IN_LIBIO
179 if (_IO_fwide (stderr, 0) > 0)
180 __fwprintf(stderr,
181 L"rcmd: socket: %m\n");
182 else
183 #endif
184 fprintf(stderr, "rcmd: socket: %m\n");
186 __sigsetmask(oldmask);
187 freeaddrinfo(res);
188 return -1;
190 __fcntl(s, F_SETOWN, pid);
191 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
192 break;
193 (void)__close(s);
194 if (errno == EADDRINUSE) {
195 lport--;
196 continue;
198 if (errno == ECONNREFUSED)
199 refused = 1;
200 if (ai->ai_next != NULL) {
201 int oerrno = errno;
202 char *buf = NULL;
204 getnameinfo(ai->ai_addr, ai->ai_addrlen,
205 paddr, sizeof(paddr),
206 NULL, 0,
207 NI_NUMERICHOST);
209 __asprintf (&buf, _("connect to address %s: "), paddr);
210 #ifdef USE_IN_LIBIO
211 if (_IO_fwide (stderr, 0) > 0)
212 __fwprintf(stderr, L"%s", buf);
213 else
214 #endif
215 fputs (buf, stderr);
216 __set_errno (oerrno);
217 perror(0);
218 ai = ai->ai_next;
219 getnameinfo(ai->ai_addr, ai->ai_addrlen,
220 paddr, sizeof(paddr),
221 NULL, 0,
222 NI_NUMERICHOST);
223 __asprintf (&buf, _("Trying %s...\n"), paddr);
224 #ifdef USE_IN_LIBIO
225 if (_IO_fwide (stderr, 0) > 0)
226 __fwprintf (stderr, L"%s", buf);
227 else
228 #endif
229 fputs (buf, stderr);
230 free (buf);
231 continue;
233 if (refused && timo <= 16) {
234 (void)__sleep(timo);
235 timo *= 2;
236 ai = res;
237 refused = 0;
238 continue;
240 freeaddrinfo(res);
241 #ifdef USE_IN_LIBIO
242 if (_IO_fwide (stderr, 0) > 0)
243 (void)__fwprintf(stderr, L"%s: %s\n", *ahost,
244 __strerror_r(errno,
245 errbuf, sizeof (errbuf)));
246 else
247 #endif
248 (void)fprintf(stderr, "%s: %s\n", *ahost,
249 __strerror_r(errno,
250 errbuf, sizeof (errbuf)));
251 __sigsetmask(oldmask);
252 return -1;
254 lport--;
255 if (fd2p == 0) {
256 __write(s, "", 1);
257 lport = 0;
258 } else {
259 char num[8];
260 int s2 = rresvport_af(&lport, ai->ai_family), s3;
261 socklen_t len = ai->ai_addrlen;
263 if (s2 < 0)
264 goto bad;
265 listen(s2, 1);
266 (void)__snprintf(num, sizeof(num), "%d", lport);
267 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
268 char *buf = NULL;
270 __asprintf (&buf, _("\
271 rcmd: write (setting up stderr): %m\n"));
272 #ifdef USE_IN_LIBIO
273 if (_IO_fwide (stderr, 0) > 0)
274 __fwprintf(stderr, L"%s", buf);
275 else
276 #endif
277 fputs (buf, stderr);
278 free (buf);
279 (void)__close(s2);
280 goto bad;
282 pfd[0].fd = s;
283 pfd[1].fd = s2;
284 __set_errno (0);
285 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
286 char *buf = NULL;
288 if (errno != 0)
289 __asprintf(&buf,
290 _("rcmd: poll (setting up stderr): %m\n"));
291 else
292 __asprintf(&buf,
293 _("poll: protocol failure in circuit setup\n"));
294 #ifdef USE_IN_LIBIO
295 if (_IO_fwide (stderr, 0) > 0)
296 __fwprintf (stderr, L"%s", buf);
297 else
298 #endif
299 fputs (buf, stderr);
300 free (buf);
301 (void)__close(s2);
302 goto bad;
304 s3 = accept(s2, (struct sockaddr *)&from, &len);
305 switch (from.ss_family) {
306 case AF_INET:
307 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
308 break;
309 case AF_INET6:
310 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
311 break;
312 default:
313 rport = 0;
314 break;
316 (void)__close(s2);
317 if (s3 < 0) {
318 #ifdef USE_IN_LIBIO
319 if (_IO_fwide (stderr, 0) > 0)
320 (void)__fwprintf(stderr,
321 L"rcmd: accept: %m\n");
322 else
323 #endif
324 (void)fprintf(stderr,
325 "rcmd: accept: %m\n");
326 lport = 0;
327 goto bad;
329 *fd2p = s3;
331 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
332 char *buf = NULL;
334 __asprintf(&buf,
335 _("socket: protocol failure in circuit setup\n"));
336 #ifdef USE_IN_LIBIO
337 if (_IO_fwide (stderr, 0) > 0)
338 __fwprintf (stderr, L"%s", buf);
339 else
340 #endif
341 fputs (buf, stderr);
342 free (buf);
343 goto bad2;
346 (void)__write(s, locuser, strlen(locuser)+1);
347 (void)__write(s, remuser, strlen(remuser)+1);
348 (void)__write(s, cmd, strlen(cmd)+1);
349 n = __read(s, &c, 1);
350 if (n != 1) {
351 char *buf = NULL;
353 if (n == 0)
354 __asprintf(&buf, _("rcmd: %s: short read"), *ahost);
355 else
356 __asprintf(&buf, "rcmd: %s: %m\n", *ahost);
357 #ifdef USE_IN_LIBIO
358 if (_IO_fwide (stderr, 0) > 0)
359 __fwprintf (stderr, L"%s", buf);
360 else
361 #endif
362 fputs (buf, stderr);
363 free (buf);
364 goto bad2;
366 if (c != 0) {
367 while (__read(s, &c, 1) == 1) {
368 (void)__write(STDERR_FILENO, &c, 1);
369 if (c == '\n')
370 break;
372 goto bad2;
374 __sigsetmask(oldmask);
375 freeaddrinfo(res);
376 return s;
377 bad2:
378 if (lport)
379 (void)__close(*fd2p);
380 bad:
381 (void)__close(s);
382 __sigsetmask(oldmask);
383 freeaddrinfo(res);
384 return -1;
388 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
389 char **ahost;
390 u_short rport;
391 const char *locuser, *remuser, *cmd;
392 int *fd2p;
394 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
398 rresvport_af(alport, family)
399 int *alport;
400 sa_family_t family;
402 struct sockaddr_storage ss;
403 int s;
404 size_t len;
405 uint16_t *sport;
407 switch(family){
408 case AF_INET:
409 len = sizeof(struct sockaddr_in);
410 sport = &((struct sockaddr_in *)&ss)->sin_port;
411 break;
412 case AF_INET6:
413 len = sizeof(struct sockaddr_in6);
414 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
415 break;
416 default:
417 __set_errno (EAFNOSUPPORT);
418 return -1;
420 s = __socket(family, SOCK_STREAM, 0);
421 if (s < 0)
422 return -1;
424 memset (&ss, '\0', sizeof(ss));
425 #ifdef SALEN
426 ss.__ss_len = len;
427 #endif
428 ss.ss_family = family;
430 for (;;) {
431 *sport = htons((uint16_t) *alport);
432 if (bind(s, (struct sockaddr *)&ss, len) >= 0)
433 return s;
434 if (errno != EADDRINUSE) {
435 (void)__close(s);
436 return -1;
438 (*alport)--;
439 if (*alport == IPPORT_RESERVED/2)
440 break;
442 (void)__close(s);
443 __set_errno (EAGAIN);
444 return -1;
448 rresvport(alport)
449 int *alport;
451 return rresvport_af(alport, AF_INET);
454 int __check_rhosts_file = 1;
455 char *__rcmd_errstr;
458 ruserok_af(rhost, superuser, ruser, luser, af)
459 const char *rhost, *ruser, *luser;
460 int superuser;
461 sa_family_t af;
463 struct addrinfo hints, *res, *res0;
464 int gai;
465 int ret;
467 memset (&hints, '\0', sizeof(hints));
468 hints.ai_family = af;
469 gai = getaddrinfo(rhost, NULL, &hints, &res0);
470 if (gai)
471 return -1;
472 ret = -1;
473 for (res=res0; res; res=res->ai_next)
474 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
475 superuser, ruser, luser, rhost) == 0){
476 ret = 0;
477 break;
479 freeaddrinfo(res0);
480 return (ret);
483 ruserok(rhost, superuser, ruser, luser)
484 const char *rhost, *ruser, *luser;
485 int superuser;
487 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
490 /* Extremely paranoid file open function. */
491 static FILE *
492 iruserfopen (const char *file, uid_t okuser)
494 struct stat64 st;
495 char *cp = NULL;
496 FILE *res = NULL;
498 /* If not a regular file, if owned by someone other than user or
499 root, if writeable by anyone but the owner, or if hardlinked
500 anywhere, quit. */
501 cp = NULL;
502 if (__lxstat64 (_STAT_VER, file, &st))
503 cp = _("lstat failed");
504 else if (!S_ISREG (st.st_mode))
505 cp = _("not regular file");
506 else
508 res = fopen (file, "r");
509 if (!res)
510 cp = _("cannot open");
511 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
512 cp = _("fstat failed");
513 else if (st.st_uid && st.st_uid != okuser)
514 cp = _("bad owner");
515 else if (st.st_mode & (S_IWGRP|S_IWOTH))
516 cp = _("writeable by other than owner");
517 else if (st.st_nlink > 1)
518 cp = _("hard linked somewhere");
521 /* If there were any problems, quit. */
522 if (cp != NULL)
524 __rcmd_errstr = cp;
525 if (res)
526 fclose (res);
527 return NULL;
530 /* No threads use this stream. */
531 __fsetlocking (res, FSETLOCKING_BYCALLER);
533 return res;
537 * New .rhosts strategy: We are passed an ip address. We spin through
538 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
539 * has ip addresses, we don't have to trust a nameserver. When it
540 * contains hostnames, we spin through the list of addresses the nameserver
541 * gives us and look for a match.
543 * Returns 0 if ok, -1 if not ok.
545 static int
546 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
547 struct sockaddr *ra;
548 size_t ralen;
549 int superuser;
550 const char *ruser, *luser, *rhost;
552 FILE *hostf = NULL;
553 int isbad = -1;
555 if (!superuser)
556 hostf = iruserfopen (_PATH_HEQUIV, 0);
558 if (hostf)
560 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
561 fclose (hostf);
563 if (!isbad)
564 return 0;
567 if (__check_rhosts_file || superuser)
569 char *pbuf;
570 struct passwd pwdbuf, *pwd;
571 size_t dirlen;
572 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
573 char *buffer = __alloca (buflen);
574 uid_t uid;
576 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
577 || pwd == NULL)
578 return -1;
580 dirlen = strlen (pwd->pw_dir);
581 pbuf = alloca (dirlen + sizeof "/.rhosts");
582 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
583 "/.rhosts", sizeof "/.rhosts");
585 /* Change effective uid while reading .rhosts. If root and
586 reading an NFS mounted file system, can't read files that
587 are protected read/write owner only. */
588 uid = __geteuid ();
589 seteuid (pwd->pw_uid);
590 hostf = iruserfopen (pbuf, pwd->pw_uid);
592 if (hostf != NULL)
594 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
595 fclose (hostf);
598 seteuid (uid);
599 return isbad;
601 return -1;
604 * ruserok_sa() is now discussed on ipng, so
605 * currently disabled for external use
607 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
608 struct sockaddr *ra;
609 size_t ralen;
610 int superuser;
611 const char *ruser, *luser;
613 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
616 /* This is the exported version. */
618 iruserok_af (raddr, superuser, ruser, luser, af)
619 const void *raddr;
620 int superuser;
621 const char *ruser, *luser;
622 sa_family_t af;
624 struct sockaddr_storage ra;
625 size_t ralen;
627 memset (&ra, '\0', sizeof(ra));
628 switch (af){
629 case AF_INET:
630 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
631 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
632 sizeof(struct in_addr));
633 ralen = sizeof(struct sockaddr_in);
634 break;
635 case AF_INET6:
636 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
637 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
638 sizeof(struct in6_addr));
639 ralen = sizeof(struct sockaddr_in6);
640 break;
641 default:
642 return 0;
644 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
647 iruserok (raddr, superuser, ruser, luser)
648 u_int32_t raddr;
649 int superuser;
650 const char *ruser, *luser;
652 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
656 * XXX
657 * Don't make static, used by lpd(8).
659 * This function is not used anymore. It is only present because lpd(8)
660 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
661 * argument. This means that netgroups won't work in .rhost/hosts.equiv
662 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
663 * or PAM.
664 * Returns 0 if ok, -1 if not ok.
667 __ivaliduser(hostf, raddr, luser, ruser)
668 FILE *hostf;
669 u_int32_t raddr;
670 const char *luser, *ruser;
672 struct sockaddr_in ra;
673 memset(&ra, '\0', sizeof(ra));
674 ra.sin_family = AF_INET;
675 ra.sin_addr.s_addr = raddr;
676 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
677 luser, ruser, "-");
681 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
682 static int
683 internal_function
684 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
685 const char *rhost)
687 struct addrinfo hints, *res0, *res;
688 char raddr[INET6_ADDRSTRLEN];
689 int match;
690 int negate=1; /* Multiply return with this to get -1 instead of 1 */
692 /* Check nis netgroup. */
693 if (strncmp ("+@", lhost, 2) == 0)
694 return innetgr (&lhost[2], rhost, NULL, NULL);
696 if (strncmp ("-@", lhost, 2) == 0)
697 return -innetgr (&lhost[2], rhost, NULL, NULL);
699 /* -host */
700 if (strncmp ("-", lhost,1) == 0) {
701 negate = -1;
702 lhost++;
703 } else if (strcmp ("+",lhost) == 0) {
704 return 1; /* asking for trouble, but ok.. */
707 /* Try for raw ip address first. */
708 /* XXX */
709 if (getnameinfo(ra, ralen,
710 raddr, sizeof(raddr), NULL, 0,
711 NI_NUMERICHOST) == 0
712 && strcmp(raddr, lhost) == 0)
713 return negate;
715 /* Better be a hostname. */
716 match = 0;
717 memset(&hints, '\0', sizeof(hints));
718 hints.ai_family = ra->sa_family;
719 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
720 /* Spin through ip addresses. */
721 for (res = res0; res; res = res->ai_next)
723 if (res->ai_family == ra->sa_family
724 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
726 match = 1;
727 break;
730 freeaddrinfo (res0);
732 return negate * match;
735 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
736 static int
737 internal_function
738 __icheckuser (const char *luser, const char *ruser)
741 luser is user entry from .rhosts/hosts.equiv file
742 ruser is user id on remote host
745 /* [-+]@netgroup */
746 if (strncmp ("+@", luser, 2) == 0)
747 return innetgr (&luser[2], NULL, ruser, NULL);
749 if (strncmp ("-@", luser,2) == 0)
750 return -innetgr (&luser[2], NULL, ruser, NULL);
752 /* -user */
753 if (strncmp ("-", luser, 1) == 0)
754 return -(strcmp (&luser[1], ruser) == 0);
756 /* + */
757 if (strcmp ("+", luser) == 0)
758 return 1;
760 /* simple string match */
761 return strcmp (ruser, luser) == 0;
765 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
767 static int
768 __isempty (char *p)
770 while (*p && isspace (*p)) {
771 ++p;
774 return (*p == '\0' || *p == '#') ? 1 : 0 ;
778 * Returns 0 if positive match, -1 if _not_ ok.
780 static int
781 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
782 FILE *hostf;
783 struct sockaddr *ra;
784 size_t ralen;
785 const char *luser, *ruser, *rhost;
787 register const char *user;
788 register char *p;
789 int hcheck, ucheck;
790 char *buf = NULL;
791 size_t bufsize = 0;
792 int retval = -1;
794 while (__getline (&buf, &bufsize, hostf) > 0) {
795 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
796 p = buf;
798 /* Skip empty or comment lines */
799 if (__isempty (p)) {
800 continue;
803 /* Skip lines that are too long. */
804 if (strchr (p, '\n') == NULL) {
805 int ch = getc_unlocked (hostf);
807 while (ch != '\n' && ch != EOF)
808 ch = getc_unlocked (hostf);
809 continue;
812 for (;*p && !isspace(*p); ++p) {
813 *p = _tolower (*p);
816 /* Next we want to find the permitted name for the remote user. */
817 if (*p == ' ' || *p == '\t') {
818 /* <nul> terminate hostname and skip spaces */
819 for (*p++='\0'; *p && isspace (*p); ++p);
821 user = p; /* this is the user's name */
822 while (*p && !isspace (*p))
823 ++p; /* find end of user's name */
824 } else
825 user = p;
827 *p = '\0'; /* <nul> terminate username (+host?) */
829 /* buf -> host(?) ; user -> username(?) */
831 /* First check host part */
832 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
834 if (hcheck < 0)
835 break;
837 if (hcheck) {
838 /* Then check user part */
839 if (! (*user))
840 user = luser;
842 ucheck = __icheckuser (user, ruser);
844 /* Positive 'host user' match? */
845 if (ucheck > 0) {
846 retval = 0;
847 break;
850 /* Negative 'host -user' match? */
851 if (ucheck < 0)
852 break;
854 /* Neither, go on looking for match */
858 if (buf != NULL)
859 free (buf);
861 return retval;