Update.
[glibc.git] / inet / rcmd.c
blob08d9337431cb9ff973abee1b5423fc7492a2e90a
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 libc_hidden_proto (iruserok_af)
104 static char ahostbuf[NI_MAXHOST];
107 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
108 char **ahost;
109 u_short rport;
110 const char *locuser, *remuser, *cmd;
111 int *fd2p;
112 sa_family_t af;
114 char paddr[INET6_ADDRSTRLEN];
115 struct addrinfo hints, *res, *ai;
116 struct sockaddr_storage from;
117 struct pollfd pfd[2];
118 int32_t oldmask;
119 pid_t pid;
120 int s, lport, timo, error;
121 char c;
122 int refused;
123 char num[8];
124 ssize_t n;
126 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
128 __set_errno (EAFNOSUPPORT);
129 return -1;
132 pid = __getpid();
134 memset(&hints, '\0', sizeof(hints));
135 hints.ai_flags = AI_CANONNAME;
136 hints.ai_family = af;
137 hints.ai_socktype = SOCK_STREAM;
138 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
139 error = getaddrinfo(*ahost, num, &hints, &res);
140 if (error) {
141 #ifdef USE_IN_LIBIO
142 if (_IO_fwide (stderr, 0) > 0)
143 __fwprintf(stderr, L"rcmd: getaddrinfo: %s\n",
144 gai_strerror(error));
145 else
146 #endif
147 fprintf(stderr, "rcmd: getaddrinfo: %s\n",
148 gai_strerror(error));
149 return (-1);
152 pfd[0].events = POLLIN;
153 pfd[1].events = POLLIN;
155 if (res->ai_canonname){
156 strncpy(ahostbuf, res->ai_canonname, sizeof(ahostbuf));
157 ahostbuf[sizeof(ahostbuf)-1] = '\0';
158 *ahost = ahostbuf;
160 else
161 *ahost = NULL;
162 ai = res;
163 refused = 0;
164 oldmask = __sigblock(sigmask(SIGURG));
165 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
166 char errbuf[200];
168 s = rresvport_af(&lport, ai->ai_family);
169 if (s < 0) {
170 if (errno == EAGAIN) {
171 #ifdef USE_IN_LIBIO
172 if (_IO_fwide (stderr, 0) > 0)
173 __fwprintf(stderr, L"%s",
174 _("rcmd: socket: All ports in use\n"));
175 else
176 #endif
177 fputs(_("rcmd: socket: All ports in use\n"),
178 stderr);
179 } else {
180 #ifdef USE_IN_LIBIO
181 if (_IO_fwide (stderr, 0) > 0)
182 __fwprintf(stderr,
183 L"rcmd: socket: %m\n");
184 else
185 #endif
186 fprintf(stderr, "rcmd: socket: %m\n");
188 __sigsetmask(oldmask);
189 freeaddrinfo(res);
190 return -1;
192 __fcntl(s, F_SETOWN, pid);
193 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
194 break;
195 (void)__close(s);
196 if (errno == EADDRINUSE) {
197 lport--;
198 continue;
200 if (errno == ECONNREFUSED)
201 refused = 1;
202 if (ai->ai_next != NULL) {
203 int oerrno = errno;
204 char *buf = NULL;
206 getnameinfo(ai->ai_addr, ai->ai_addrlen,
207 paddr, sizeof(paddr),
208 NULL, 0,
209 NI_NUMERICHOST);
211 if (__asprintf (&buf, _("connect to address %s: "),
212 paddr) >= 0)
214 #ifdef USE_IN_LIBIO
215 if (_IO_fwide (stderr, 0) > 0)
216 __fwprintf(stderr, L"%s", buf);
217 else
218 #endif
219 fputs (buf, stderr);
220 free (buf);
222 __set_errno (oerrno);
223 perror(0);
224 ai = ai->ai_next;
225 getnameinfo(ai->ai_addr, ai->ai_addrlen,
226 paddr, sizeof(paddr),
227 NULL, 0,
228 NI_NUMERICHOST);
229 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
231 #ifdef USE_IN_LIBIO
232 if (_IO_fwide (stderr, 0) > 0)
233 __fwprintf (stderr, L"%s", buf);
234 else
235 #endif
236 fputs (buf, stderr);
237 free (buf);
239 continue;
241 if (refused && timo <= 16) {
242 (void)__sleep(timo);
243 timo *= 2;
244 ai = res;
245 refused = 0;
246 continue;
248 freeaddrinfo(res);
249 #ifdef USE_IN_LIBIO
250 if (_IO_fwide (stderr, 0) > 0)
251 (void)__fwprintf(stderr, L"%s: %s\n", *ahost,
252 __strerror_r(errno,
253 errbuf, sizeof (errbuf)));
254 else
255 #endif
256 (void)fprintf(stderr, "%s: %s\n", *ahost,
257 __strerror_r(errno,
258 errbuf, sizeof (errbuf)));
259 __sigsetmask(oldmask);
260 return -1;
262 lport--;
263 if (fd2p == 0) {
264 __write(s, "", 1);
265 lport = 0;
266 } else {
267 char num[8];
268 int s2 = rresvport_af(&lport, ai->ai_family), s3;
269 socklen_t len = ai->ai_addrlen;
271 if (s2 < 0)
272 goto bad;
273 __listen(s2, 1);
274 (void)__snprintf(num, sizeof(num), "%d", lport);
275 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
276 char *buf = NULL;
278 if (__asprintf (&buf, _("\
279 rcmd: write (setting up stderr): %m\n")) >= 0)
281 #ifdef USE_IN_LIBIO
282 if (_IO_fwide (stderr, 0) > 0)
283 __fwprintf(stderr, L"%s", buf);
284 else
285 #endif
286 fputs (buf, stderr);
287 free (buf);
289 (void)__close(s2);
290 goto bad;
292 pfd[0].fd = s;
293 pfd[1].fd = s2;
294 __set_errno (0);
295 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
296 char *buf = NULL;
298 if ((errno != 0
299 && __asprintf(&buf, _("\
300 rcmd: poll (setting up stderr): %m\n")) >= 0)
301 || (errno == 0
302 && __asprintf(&buf, _("\
303 poll: protocol failure in circuit setup\n")) >= 0))
305 #ifdef USE_IN_LIBIO
306 if (_IO_fwide (stderr, 0) > 0)
307 __fwprintf (stderr, L"%s", buf);
308 else
309 #endif
310 fputs (buf, stderr);
311 free (buf);
313 (void)__close(s2);
314 goto bad;
316 s3 = accept(s2, (struct sockaddr *)&from, &len);
317 switch (from.ss_family) {
318 case AF_INET:
319 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
320 break;
321 case AF_INET6:
322 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
323 break;
324 default:
325 rport = 0;
326 break;
328 (void)__close(s2);
329 if (s3 < 0) {
330 #ifdef USE_IN_LIBIO
331 if (_IO_fwide (stderr, 0) > 0)
332 (void)__fwprintf(stderr,
333 L"rcmd: accept: %m\n");
334 else
335 #endif
336 (void)fprintf(stderr,
337 "rcmd: accept: %m\n");
338 lport = 0;
339 goto bad;
341 *fd2p = s3;
343 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
344 char *buf = NULL;
346 if (__asprintf(&buf, _("\
347 socket: protocol failure in circuit setup\n")) >= 0)
349 #ifdef USE_IN_LIBIO
350 if (_IO_fwide (stderr, 0) > 0)
351 __fwprintf (stderr, L"%s", buf);
352 else
353 #endif
354 fputs (buf, stderr);
355 free (buf);
357 goto bad2;
360 (void)__write(s, locuser, strlen(locuser)+1);
361 (void)__write(s, remuser, strlen(remuser)+1);
362 (void)__write(s, cmd, strlen(cmd)+1);
363 n = __read(s, &c, 1);
364 if (n != 1) {
365 char *buf = NULL;
367 if ((n == 0
368 && __asprintf(&buf, _("rcmd: %s: short read"),
369 *ahost) >= 0)
370 || (n != 0
371 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
373 #ifdef USE_IN_LIBIO
374 if (_IO_fwide (stderr, 0) > 0)
375 __fwprintf (stderr, L"%s", buf);
376 else
377 #endif
378 fputs (buf, stderr);
379 free (buf);
381 goto bad2;
383 if (c != 0) {
384 while (__read(s, &c, 1) == 1) {
385 (void)__write(STDERR_FILENO, &c, 1);
386 if (c == '\n')
387 break;
389 goto bad2;
391 __sigsetmask(oldmask);
392 freeaddrinfo(res);
393 return s;
394 bad2:
395 if (lport)
396 (void)__close(*fd2p);
397 bad:
398 (void)__close(s);
399 __sigsetmask(oldmask);
400 freeaddrinfo(res);
401 return -1;
403 libc_hidden_def (rcmd_af)
406 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
407 char **ahost;
408 u_short rport;
409 const char *locuser, *remuser, *cmd;
410 int *fd2p;
412 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
416 rresvport_af(alport, family)
417 int *alport;
418 sa_family_t family;
420 struct sockaddr_storage ss;
421 int s;
422 size_t len;
423 uint16_t *sport;
425 switch(family){
426 case AF_INET:
427 len = sizeof(struct sockaddr_in);
428 sport = &((struct sockaddr_in *)&ss)->sin_port;
429 break;
430 case AF_INET6:
431 len = sizeof(struct sockaddr_in6);
432 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
433 break;
434 default:
435 __set_errno (EAFNOSUPPORT);
436 return -1;
438 s = __socket(family, SOCK_STREAM, 0);
439 if (s < 0)
440 return -1;
442 memset (&ss, '\0', sizeof(ss));
443 #ifdef SALEN
444 ss.__ss_len = len;
445 #endif
446 ss.ss_family = family;
448 for (;;) {
449 *sport = htons((uint16_t) *alport);
450 if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
451 return s;
452 if (errno != EADDRINUSE) {
453 (void)__close(s);
454 return -1;
456 (*alport)--;
457 if (*alport == IPPORT_RESERVED/2)
458 break;
460 (void)__close(s);
461 __set_errno (EAGAIN);
462 return -1;
464 libc_hidden_def (rresvport_af)
467 rresvport(alport)
468 int *alport;
470 return rresvport_af(alport, AF_INET);
473 int __check_rhosts_file = 1;
474 char *__rcmd_errstr;
477 ruserok_af(rhost, superuser, ruser, luser, af)
478 const char *rhost, *ruser, *luser;
479 int superuser;
480 sa_family_t af;
482 struct addrinfo hints, *res, *res0;
483 int gai;
484 int ret;
486 memset (&hints, '\0', sizeof(hints));
487 hints.ai_family = af;
488 gai = getaddrinfo(rhost, NULL, &hints, &res0);
489 if (gai)
490 return -1;
491 ret = -1;
492 for (res=res0; res; res=res->ai_next)
493 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
494 superuser, ruser, luser, rhost) == 0){
495 ret = 0;
496 break;
498 freeaddrinfo(res0);
499 return (ret);
501 libc_hidden_def (ruserok_af)
504 ruserok(rhost, superuser, ruser, luser)
505 const char *rhost, *ruser, *luser;
506 int superuser;
508 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
511 /* Extremely paranoid file open function. */
512 static FILE *
513 iruserfopen (const char *file, uid_t okuser)
515 struct stat64 st;
516 char *cp = NULL;
517 FILE *res = NULL;
519 /* If not a regular file, if owned by someone other than user or
520 root, if writeable by anyone but the owner, or if hardlinked
521 anywhere, quit. */
522 cp = NULL;
523 if (__lxstat64 (_STAT_VER, file, &st))
524 cp = _("lstat failed");
525 else if (!S_ISREG (st.st_mode))
526 cp = _("not regular file");
527 else
529 res = fopen (file, "r");
530 if (!res)
531 cp = _("cannot open");
532 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
533 cp = _("fstat failed");
534 else if (st.st_uid && st.st_uid != okuser)
535 cp = _("bad owner");
536 else if (st.st_mode & (S_IWGRP|S_IWOTH))
537 cp = _("writeable by other than owner");
538 else if (st.st_nlink > 1)
539 cp = _("hard linked somewhere");
542 /* If there were any problems, quit. */
543 if (cp != NULL)
545 __rcmd_errstr = cp;
546 if (res)
547 fclose (res);
548 return NULL;
551 /* No threads use this stream. */
552 __fsetlocking (res, FSETLOCKING_BYCALLER);
554 return res;
558 * New .rhosts strategy: We are passed an ip address. We spin through
559 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
560 * has ip addresses, we don't have to trust a nameserver. When it
561 * contains hostnames, we spin through the list of addresses the nameserver
562 * gives us and look for a match.
564 * Returns 0 if ok, -1 if not ok.
566 static int
567 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
568 struct sockaddr *ra;
569 size_t ralen;
570 int superuser;
571 const char *ruser, *luser, *rhost;
573 FILE *hostf = NULL;
574 int isbad = -1;
576 if (!superuser)
577 hostf = iruserfopen (_PATH_HEQUIV, 0);
579 if (hostf)
581 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
582 fclose (hostf);
584 if (!isbad)
585 return 0;
588 if (__check_rhosts_file || superuser)
590 char *pbuf;
591 struct passwd pwdbuf, *pwd;
592 size_t dirlen;
593 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
594 char *buffer = __alloca (buflen);
595 uid_t uid;
597 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
598 || pwd == NULL)
599 return -1;
601 dirlen = strlen (pwd->pw_dir);
602 pbuf = alloca (dirlen + sizeof "/.rhosts");
603 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
604 "/.rhosts", sizeof "/.rhosts");
606 /* Change effective uid while reading .rhosts. If root and
607 reading an NFS mounted file system, can't read files that
608 are protected read/write owner only. */
609 uid = __geteuid ();
610 seteuid (pwd->pw_uid);
611 hostf = iruserfopen (pbuf, pwd->pw_uid);
613 if (hostf != NULL)
615 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
616 fclose (hostf);
619 seteuid (uid);
620 return isbad;
622 return -1;
625 * ruserok_sa() is now discussed on ipng, so
626 * currently disabled for external use
628 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
629 struct sockaddr *ra;
630 size_t ralen;
631 int superuser;
632 const char *ruser, *luser;
634 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
637 /* This is the exported version. */
639 iruserok_af (raddr, superuser, ruser, luser, af)
640 const void *raddr;
641 int superuser;
642 const char *ruser, *luser;
643 sa_family_t af;
645 struct sockaddr_storage ra;
646 size_t ralen;
648 memset (&ra, '\0', sizeof(ra));
649 switch (af){
650 case AF_INET:
651 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
652 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
653 sizeof(struct in_addr));
654 ralen = sizeof(struct sockaddr_in);
655 break;
656 case AF_INET6:
657 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
658 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
659 sizeof(struct in6_addr));
660 ralen = sizeof(struct sockaddr_in6);
661 break;
662 default:
663 return 0;
665 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
667 libc_hidden_def (iruserok_af)
670 iruserok (raddr, superuser, ruser, luser)
671 u_int32_t raddr;
672 int superuser;
673 const char *ruser, *luser;
675 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
679 * XXX
680 * Don't make static, used by lpd(8).
682 * This function is not used anymore. It is only present because lpd(8)
683 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
684 * argument. This means that netgroups won't work in .rhost/hosts.equiv
685 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
686 * or PAM.
687 * Returns 0 if ok, -1 if not ok.
690 __ivaliduser(hostf, raddr, luser, ruser)
691 FILE *hostf;
692 u_int32_t raddr;
693 const char *luser, *ruser;
695 struct sockaddr_in ra;
696 memset(&ra, '\0', sizeof(ra));
697 ra.sin_family = AF_INET;
698 ra.sin_addr.s_addr = raddr;
699 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
700 luser, ruser, "-");
704 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
705 static int
706 internal_function
707 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
708 const char *rhost)
710 struct addrinfo hints, *res0, *res;
711 char raddr[INET6_ADDRSTRLEN];
712 int match;
713 int negate=1; /* Multiply return with this to get -1 instead of 1 */
715 /* Check nis netgroup. */
716 if (strncmp ("+@", lhost, 2) == 0)
717 return innetgr (&lhost[2], rhost, NULL, NULL);
719 if (strncmp ("-@", lhost, 2) == 0)
720 return -innetgr (&lhost[2], rhost, NULL, NULL);
722 /* -host */
723 if (strncmp ("-", lhost,1) == 0) {
724 negate = -1;
725 lhost++;
726 } else if (strcmp ("+",lhost) == 0) {
727 return 1; /* asking for trouble, but ok.. */
730 /* Try for raw ip address first. */
731 /* XXX */
732 if (getnameinfo(ra, ralen,
733 raddr, sizeof(raddr), NULL, 0,
734 NI_NUMERICHOST) == 0
735 && strcmp(raddr, lhost) == 0)
736 return negate;
738 /* Better be a hostname. */
739 match = 0;
740 memset(&hints, '\0', sizeof(hints));
741 hints.ai_family = ra->sa_family;
742 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
743 /* Spin through ip addresses. */
744 for (res = res0; res; res = res->ai_next)
746 if (res->ai_family == ra->sa_family
747 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
749 match = 1;
750 break;
753 freeaddrinfo (res0);
755 return negate * match;
758 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
759 static int
760 internal_function
761 __icheckuser (const char *luser, const char *ruser)
764 luser is user entry from .rhosts/hosts.equiv file
765 ruser is user id on remote host
768 /* [-+]@netgroup */
769 if (strncmp ("+@", luser, 2) == 0)
770 return innetgr (&luser[2], NULL, ruser, NULL);
772 if (strncmp ("-@", luser,2) == 0)
773 return -innetgr (&luser[2], NULL, ruser, NULL);
775 /* -user */
776 if (strncmp ("-", luser, 1) == 0)
777 return -(strcmp (&luser[1], ruser) == 0);
779 /* + */
780 if (strcmp ("+", luser) == 0)
781 return 1;
783 /* simple string match */
784 return strcmp (ruser, luser) == 0;
788 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
790 static int
791 __isempty (char *p)
793 while (*p && isspace (*p)) {
794 ++p;
797 return (*p == '\0' || *p == '#') ? 1 : 0 ;
801 * Returns 0 if positive match, -1 if _not_ ok.
803 static int
804 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
805 FILE *hostf;
806 struct sockaddr *ra;
807 size_t ralen;
808 const char *luser, *ruser, *rhost;
810 register const char *user;
811 register char *p;
812 int hcheck, ucheck;
813 char *buf = NULL;
814 size_t bufsize = 0;
815 int retval = -1;
817 while (__getline (&buf, &bufsize, hostf) > 0) {
818 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
819 p = buf;
821 /* Skip empty or comment lines */
822 if (__isempty (p)) {
823 continue;
826 /* Skip lines that are too long. */
827 if (strchr (p, '\n') == NULL) {
828 int ch = getc_unlocked (hostf);
830 while (ch != '\n' && ch != EOF)
831 ch = getc_unlocked (hostf);
832 continue;
835 for (;*p && !isspace(*p); ++p) {
836 *p = _tolower (*p);
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);
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;
850 *p = '\0'; /* <nul> terminate username (+host?) */
852 /* buf -> host(?) ; user -> username(?) */
854 /* First check host part */
855 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
857 if (hcheck < 0)
858 break;
860 if (hcheck) {
861 /* Then check user part */
862 if (! (*user))
863 user = luser;
865 ucheck = __icheckuser (user, ruser);
867 /* Positive 'host user' match? */
868 if (ucheck > 0) {
869 retval = 0;
870 break;
873 /* Negative 'host -user' match? */
874 if (ucheck < 0)
875 break;
877 /* Neither, go on looking for match */
881 if (buf != NULL)
882 free (buf);
884 return retval;