* sysdeps/m68k/Makefile (CFLAGS-.oS): Append -fPIC.
[glibc.git] / inet / rcmd.c
blobeed5ed389e4991ea34993fa0dbd316df5de6d29d
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 libc_freeres_ptr(static char *ahostbuf);
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 free (ahostbuf);
157 ahostbuf = strdup (res->ai_canonname);
158 if (ahostbuf == NULL) {
159 #ifdef USE_IN_LIBIO
160 if (_IO_fwide (stderr, 0) > 0)
161 __fwprintf(stderr, L"%s",
162 _("rcmd: Cannot allocate memory\n"));
163 else
164 #endif
165 fputs(_("rcmd: Cannot allocate memory\n"),
166 stderr);
167 return (-1);
169 *ahost = ahostbuf;
170 } else
171 *ahost = NULL;
172 ai = res;
173 refused = 0;
174 oldmask = __sigblock(sigmask(SIGURG));
175 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
176 char errbuf[200];
178 s = rresvport_af(&lport, ai->ai_family);
179 if (s < 0) {
180 if (errno == EAGAIN) {
181 #ifdef USE_IN_LIBIO
182 if (_IO_fwide (stderr, 0) > 0)
183 __fwprintf(stderr, L"%s",
184 _("rcmd: socket: All ports in use\n"));
185 else
186 #endif
187 fputs(_("rcmd: socket: All ports in use\n"),
188 stderr);
189 } else {
190 #ifdef USE_IN_LIBIO
191 if (_IO_fwide (stderr, 0) > 0)
192 __fwprintf(stderr,
193 L"rcmd: socket: %m\n");
194 else
195 #endif
196 fprintf(stderr, "rcmd: socket: %m\n");
198 __sigsetmask(oldmask);
199 freeaddrinfo(res);
200 return -1;
202 __fcntl(s, F_SETOWN, pid);
203 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
204 break;
205 (void)__close(s);
206 if (errno == EADDRINUSE) {
207 lport--;
208 continue;
210 if (errno == ECONNREFUSED)
211 refused = 1;
212 if (ai->ai_next != NULL) {
213 int oerrno = errno;
214 char *buf = NULL;
216 getnameinfo(ai->ai_addr, ai->ai_addrlen,
217 paddr, sizeof(paddr),
218 NULL, 0,
219 NI_NUMERICHOST);
221 if (__asprintf (&buf, _("connect to address %s: "),
222 paddr) >= 0)
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);
232 __set_errno (oerrno);
233 perror(0);
234 ai = ai->ai_next;
235 getnameinfo(ai->ai_addr, ai->ai_addrlen,
236 paddr, sizeof(paddr),
237 NULL, 0,
238 NI_NUMERICHOST);
239 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
241 #ifdef USE_IN_LIBIO
242 if (_IO_fwide (stderr, 0) > 0)
243 __fwprintf (stderr, L"%s", buf);
244 else
245 #endif
246 fputs (buf, stderr);
247 free (buf);
249 continue;
251 if (refused && timo <= 16) {
252 (void)__sleep(timo);
253 timo *= 2;
254 ai = res;
255 refused = 0;
256 continue;
258 freeaddrinfo(res);
259 #ifdef USE_IN_LIBIO
260 if (_IO_fwide (stderr, 0) > 0)
261 (void)__fwprintf(stderr, L"%s: %s\n", *ahost,
262 __strerror_r(errno,
263 errbuf, sizeof (errbuf)));
264 else
265 #endif
266 (void)fprintf(stderr, "%s: %s\n", *ahost,
267 __strerror_r(errno,
268 errbuf, sizeof (errbuf)));
269 __sigsetmask(oldmask);
270 return -1;
272 lport--;
273 if (fd2p == 0) {
274 __write(s, "", 1);
275 lport = 0;
276 } else {
277 char num[8];
278 int s2 = rresvport_af(&lport, ai->ai_family), s3;
279 socklen_t len = ai->ai_addrlen;
281 if (s2 < 0)
282 goto bad;
283 __listen(s2, 1);
284 (void)__snprintf(num, sizeof(num), "%d", lport);
285 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
286 char *buf = NULL;
288 if (__asprintf (&buf, _("\
289 rcmd: write (setting up stderr): %m\n")) >= 0)
291 #ifdef USE_IN_LIBIO
292 if (_IO_fwide (stderr, 0) > 0)
293 __fwprintf(stderr, L"%s", buf);
294 else
295 #endif
296 fputs (buf, stderr);
297 free (buf);
299 (void)__close(s2);
300 goto bad;
302 pfd[0].fd = s;
303 pfd[1].fd = s2;
304 __set_errno (0);
305 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
306 char *buf = NULL;
308 if ((errno != 0
309 && __asprintf(&buf, _("\
310 rcmd: poll (setting up stderr): %m\n")) >= 0)
311 || (errno == 0
312 && __asprintf(&buf, _("\
313 poll: protocol failure in circuit setup\n")) >= 0))
315 #ifdef USE_IN_LIBIO
316 if (_IO_fwide (stderr, 0) > 0)
317 __fwprintf (stderr, L"%s", buf);
318 else
319 #endif
320 fputs (buf, stderr);
321 free (buf);
323 (void)__close(s2);
324 goto bad;
326 s3 = accept(s2, (struct sockaddr *)&from, &len);
327 switch (from.ss_family) {
328 case AF_INET:
329 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
330 break;
331 case AF_INET6:
332 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
333 break;
334 default:
335 rport = 0;
336 break;
338 (void)__close(s2);
339 if (s3 < 0) {
340 #ifdef USE_IN_LIBIO
341 if (_IO_fwide (stderr, 0) > 0)
342 (void)__fwprintf(stderr,
343 L"rcmd: accept: %m\n");
344 else
345 #endif
346 (void)fprintf(stderr,
347 "rcmd: accept: %m\n");
348 lport = 0;
349 goto bad;
351 *fd2p = s3;
353 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
354 char *buf = NULL;
356 if (__asprintf(&buf, _("\
357 socket: protocol failure in circuit setup\n")) >= 0)
359 #ifdef USE_IN_LIBIO
360 if (_IO_fwide (stderr, 0) > 0)
361 __fwprintf (stderr, L"%s", buf);
362 else
363 #endif
364 fputs (buf, stderr);
365 free (buf);
367 goto bad2;
370 (void)__write(s, locuser, strlen(locuser)+1);
371 (void)__write(s, remuser, strlen(remuser)+1);
372 (void)__write(s, cmd, strlen(cmd)+1);
373 n = __read(s, &c, 1);
374 if (n != 1) {
375 char *buf = NULL;
377 if ((n == 0
378 && __asprintf(&buf, _("rcmd: %s: short read"),
379 *ahost) >= 0)
380 || (n != 0
381 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
383 #ifdef USE_IN_LIBIO
384 if (_IO_fwide (stderr, 0) > 0)
385 __fwprintf (stderr, L"%s", buf);
386 else
387 #endif
388 fputs (buf, stderr);
389 free (buf);
391 goto bad2;
393 if (c != 0) {
394 while (__read(s, &c, 1) == 1) {
395 (void)__write(STDERR_FILENO, &c, 1);
396 if (c == '\n')
397 break;
399 goto bad2;
401 __sigsetmask(oldmask);
402 freeaddrinfo(res);
403 return s;
404 bad2:
405 if (lport)
406 (void)__close(*fd2p);
407 bad:
408 (void)__close(s);
409 __sigsetmask(oldmask);
410 freeaddrinfo(res);
411 return -1;
413 libc_hidden_def (rcmd_af)
416 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
417 char **ahost;
418 u_short rport;
419 const char *locuser, *remuser, *cmd;
420 int *fd2p;
422 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
426 rresvport_af(alport, family)
427 int *alport;
428 sa_family_t family;
430 struct sockaddr_storage ss;
431 int s;
432 size_t len;
433 uint16_t *sport;
435 switch(family){
436 case AF_INET:
437 len = sizeof(struct sockaddr_in);
438 sport = &((struct sockaddr_in *)&ss)->sin_port;
439 break;
440 case AF_INET6:
441 len = sizeof(struct sockaddr_in6);
442 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
443 break;
444 default:
445 __set_errno (EAFNOSUPPORT);
446 return -1;
448 s = __socket(family, SOCK_STREAM, 0);
449 if (s < 0)
450 return -1;
452 memset (&ss, '\0', sizeof(ss));
453 #ifdef SALEN
454 ss.__ss_len = len;
455 #endif
456 ss.ss_family = family;
458 for (;;) {
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;
466 (*alport)--;
467 if (*alport == IPPORT_RESERVED/2)
468 break;
470 (void)__close(s);
471 __set_errno (EAGAIN);
472 return -1;
474 libc_hidden_def (rresvport_af)
477 rresvport(alport)
478 int *alport;
480 return rresvport_af(alport, AF_INET);
483 int __check_rhosts_file = 1;
484 char *__rcmd_errstr;
487 ruserok_af(rhost, superuser, ruser, luser, af)
488 const char *rhost, *ruser, *luser;
489 int superuser;
490 sa_family_t af;
492 struct addrinfo hints, *res, *res0;
493 int gai;
494 int ret;
496 memset (&hints, '\0', sizeof(hints));
497 hints.ai_family = af;
498 gai = getaddrinfo(rhost, NULL, &hints, &res0);
499 if (gai)
500 return -1;
501 ret = -1;
502 for (res=res0; res; res=res->ai_next)
503 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
504 superuser, ruser, luser, rhost) == 0){
505 ret = 0;
506 break;
508 freeaddrinfo(res0);
509 return (ret);
511 libc_hidden_def (ruserok_af)
514 ruserok(rhost, superuser, ruser, luser)
515 const char *rhost, *ruser, *luser;
516 int superuser;
518 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
521 /* Extremely paranoid file open function. */
522 static FILE *
523 iruserfopen (const char *file, uid_t okuser)
525 struct stat64 st;
526 char *cp = NULL;
527 FILE *res = NULL;
529 /* If not a regular file, if owned by someone other than user or
530 root, if writeable by anyone but the owner, or if hardlinked
531 anywhere, quit. */
532 cp = NULL;
533 if (__lxstat64 (_STAT_VER, file, &st))
534 cp = _("lstat failed");
535 else if (!S_ISREG (st.st_mode))
536 cp = _("not regular file");
537 else
539 res = fopen (file, "r");
540 if (!res)
541 cp = _("cannot open");
542 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
543 cp = _("fstat failed");
544 else if (st.st_uid && st.st_uid != okuser)
545 cp = _("bad owner");
546 else if (st.st_mode & (S_IWGRP|S_IWOTH))
547 cp = _("writeable by other than owner");
548 else if (st.st_nlink > 1)
549 cp = _("hard linked somewhere");
552 /* If there were any problems, quit. */
553 if (cp != NULL)
555 __rcmd_errstr = cp;
556 if (res)
557 fclose (res);
558 return NULL;
561 /* No threads use this stream. */
562 __fsetlocking (res, FSETLOCKING_BYCALLER);
564 return res;
568 * New .rhosts strategy: We are passed an ip address. We spin through
569 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
570 * has ip addresses, we don't have to trust a nameserver. When it
571 * contains hostnames, we spin through the list of addresses the nameserver
572 * gives us and look for a match.
574 * Returns 0 if ok, -1 if not ok.
576 static int
577 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
578 struct sockaddr *ra;
579 size_t ralen;
580 int superuser;
581 const char *ruser, *luser, *rhost;
583 FILE *hostf = NULL;
584 int isbad = -1;
586 if (!superuser)
587 hostf = iruserfopen (_PATH_HEQUIV, 0);
589 if (hostf)
591 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
592 fclose (hostf);
594 if (!isbad)
595 return 0;
598 if (__check_rhosts_file || superuser)
600 char *pbuf;
601 struct passwd pwdbuf, *pwd;
602 size_t dirlen;
603 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
604 char *buffer = __alloca (buflen);
605 uid_t uid;
607 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
608 || pwd == NULL)
609 return -1;
611 dirlen = strlen (pwd->pw_dir);
612 pbuf = alloca (dirlen + sizeof "/.rhosts");
613 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
614 "/.rhosts", sizeof "/.rhosts");
616 /* Change effective uid while reading .rhosts. If root and
617 reading an NFS mounted file system, can't read files that
618 are protected read/write owner only. */
619 uid = __geteuid ();
620 seteuid (pwd->pw_uid);
621 hostf = iruserfopen (pbuf, pwd->pw_uid);
623 if (hostf != NULL)
625 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
626 fclose (hostf);
629 seteuid (uid);
630 return isbad;
632 return -1;
635 * ruserok_sa() is now discussed on ipng, so
636 * currently disabled for external use
638 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
639 struct sockaddr *ra;
640 size_t ralen;
641 int superuser;
642 const char *ruser, *luser;
644 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
647 /* This is the exported version. */
649 iruserok_af (raddr, superuser, ruser, luser, af)
650 const void *raddr;
651 int superuser;
652 const char *ruser, *luser;
653 sa_family_t af;
655 struct sockaddr_storage ra;
656 size_t ralen;
658 memset (&ra, '\0', sizeof(ra));
659 switch (af){
660 case AF_INET:
661 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
662 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
663 sizeof(struct in_addr));
664 ralen = sizeof(struct sockaddr_in);
665 break;
666 case AF_INET6:
667 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
668 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
669 sizeof(struct in6_addr));
670 ralen = sizeof(struct sockaddr_in6);
671 break;
672 default:
673 return 0;
675 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
677 libc_hidden_def (iruserok_af)
680 iruserok (raddr, superuser, ruser, luser)
681 u_int32_t raddr;
682 int superuser;
683 const char *ruser, *luser;
685 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
689 * XXX
690 * Don't make static, used by lpd(8).
692 * This function is not used anymore. It is only present because lpd(8)
693 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
694 * argument. This means that netgroups won't work in .rhost/hosts.equiv
695 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
696 * or PAM.
697 * Returns 0 if ok, -1 if not ok.
700 __ivaliduser(hostf, raddr, luser, ruser)
701 FILE *hostf;
702 u_int32_t raddr;
703 const char *luser, *ruser;
705 struct sockaddr_in ra;
706 memset(&ra, '\0', sizeof(ra));
707 ra.sin_family = AF_INET;
708 ra.sin_addr.s_addr = raddr;
709 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
710 luser, ruser, "-");
714 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
715 static int
716 internal_function
717 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
718 const char *rhost)
720 struct addrinfo hints, *res0, *res;
721 char raddr[INET6_ADDRSTRLEN];
722 int match;
723 int negate=1; /* Multiply return with this to get -1 instead of 1 */
725 /* Check nis netgroup. */
726 if (strncmp ("+@", lhost, 2) == 0)
727 return innetgr (&lhost[2], rhost, NULL, NULL);
729 if (strncmp ("-@", lhost, 2) == 0)
730 return -innetgr (&lhost[2], rhost, NULL, NULL);
732 /* -host */
733 if (strncmp ("-", lhost,1) == 0) {
734 negate = -1;
735 lhost++;
736 } else if (strcmp ("+",lhost) == 0) {
737 return 1; /* asking for trouble, but ok.. */
740 /* Try for raw ip address first. */
741 /* XXX */
742 if (getnameinfo(ra, ralen,
743 raddr, sizeof(raddr), NULL, 0,
744 NI_NUMERICHOST) == 0
745 && strcmp(raddr, lhost) == 0)
746 return negate;
748 /* Better be a hostname. */
749 match = 0;
750 memset(&hints, '\0', sizeof(hints));
751 hints.ai_family = ra->sa_family;
752 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
753 /* Spin through ip addresses. */
754 for (res = res0; res; res = res->ai_next)
756 if (res->ai_family == ra->sa_family
757 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
759 match = 1;
760 break;
763 freeaddrinfo (res0);
765 return negate * match;
768 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
769 static int
770 internal_function
771 __icheckuser (const char *luser, const char *ruser)
774 luser is user entry from .rhosts/hosts.equiv file
775 ruser is user id on remote host
778 /* [-+]@netgroup */
779 if (strncmp ("+@", luser, 2) == 0)
780 return innetgr (&luser[2], NULL, ruser, NULL);
782 if (strncmp ("-@", luser,2) == 0)
783 return -innetgr (&luser[2], NULL, ruser, NULL);
785 /* -user */
786 if (strncmp ("-", luser, 1) == 0)
787 return -(strcmp (&luser[1], ruser) == 0);
789 /* + */
790 if (strcmp ("+", luser) == 0)
791 return 1;
793 /* simple string match */
794 return strcmp (ruser, luser) == 0;
798 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
800 static int
801 __isempty (char *p)
803 while (*p && isspace (*p)) {
804 ++p;
807 return (*p == '\0' || *p == '#') ? 1 : 0 ;
811 * Returns 0 if positive match, -1 if _not_ ok.
813 static int
814 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
815 FILE *hostf;
816 struct sockaddr *ra;
817 size_t ralen;
818 const char *luser, *ruser, *rhost;
820 register const char *user;
821 register char *p;
822 int hcheck, ucheck;
823 char *buf = NULL;
824 size_t bufsize = 0;
825 int retval = -1;
827 while (__getline (&buf, &bufsize, hostf) > 0) {
828 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
829 p = buf;
831 /* Skip empty or comment lines */
832 if (__isempty (p)) {
833 continue;
836 /* Skip lines that are too long. */
837 if (strchr (p, '\n') == NULL) {
838 int ch = getc_unlocked (hostf);
840 while (ch != '\n' && ch != EOF)
841 ch = getc_unlocked (hostf);
842 continue;
845 for (;*p && !isspace(*p); ++p) {
846 *p = _tolower (*p);
849 /* Next we want to find the permitted name for the remote user. */
850 if (*p == ' ' || *p == '\t') {
851 /* <nul> terminate hostname and skip spaces */
852 for (*p++='\0'; *p && isspace (*p); ++p);
854 user = p; /* this is the user's name */
855 while (*p && !isspace (*p))
856 ++p; /* find end of user's name */
857 } else
858 user = p;
860 *p = '\0'; /* <nul> terminate username (+host?) */
862 /* buf -> host(?) ; user -> username(?) */
864 /* First check host part */
865 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
867 if (hcheck < 0)
868 break;
870 if (hcheck) {
871 /* Then check user part */
872 if (! (*user))
873 user = luser;
875 ucheck = __icheckuser (user, ruser);
877 /* Positive 'host user' match? */
878 if (ucheck > 0) {
879 retval = 0;
880 break;
883 /* Negative 'host -user' match? */
884 if (ucheck < 0)
885 break;
887 /* Neither, go on looking for match */
891 if (buf != NULL)
892 free (buf);
894 return retval;