semtimedop implementation for Linux/m68k.
[glibc.git] / inet / rcmd.c
blob42871f7950e93ed5b3b44ebea5e2dd00e13711f2
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
86 #include <sys/uio.h>
89 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
90 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
91 const char *, const char *, const char *);
92 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
93 int superuser, const char *ruser,
94 const char *luser, const char *rhost);
95 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
96 int superuser, const char *ruser,
97 const char *luser);
98 int iruserok_af (const void *raddr, int superuser, const char *ruser,
99 const char *luser, sa_family_t af);
100 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
101 const char *luser);
103 libc_hidden_proto (iruserok_af)
105 libc_freeres_ptr(static char *ahostbuf);
108 rcmd_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;
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;
127 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
129 __set_errno (EAFNOSUPPORT);
130 return -1;
133 pid = __getpid();
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 #ifdef USE_IN_LIBIO
143 if (_IO_fwide (stderr, 0) > 0)
144 __fwprintf(stderr, L"rcmd: getaddrinfo: %s\n",
145 gai_strerror(error));
146 else
147 #endif
148 fprintf(stderr, "rcmd: getaddrinfo: %s\n",
149 gai_strerror(error));
150 return (-1);
153 pfd[0].events = POLLIN;
154 pfd[1].events = POLLIN;
156 if (res->ai_canonname){
157 free (ahostbuf);
158 ahostbuf = strdup (res->ai_canonname);
159 if (ahostbuf == NULL) {
160 #ifdef USE_IN_LIBIO
161 if (_IO_fwide (stderr, 0) > 0)
162 __fwprintf(stderr, L"%s",
163 _("rcmd: Cannot allocate memory\n"));
164 else
165 #endif
166 fputs(_("rcmd: Cannot allocate memory\n"),
167 stderr);
168 return (-1);
170 *ahost = ahostbuf;
171 } else
172 *ahost = NULL;
173 ai = res;
174 refused = 0;
175 oldmask = __sigblock(sigmask(SIGURG));
176 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
177 char errbuf[200];
179 s = rresvport_af(&lport, ai->ai_family);
180 if (s < 0) {
181 if (errno == EAGAIN) {
182 #ifdef USE_IN_LIBIO
183 if (_IO_fwide (stderr, 0) > 0)
184 __fwprintf(stderr, L"%s",
185 _("rcmd: socket: All ports in use\n"));
186 else
187 #endif
188 fputs(_("rcmd: socket: All ports in use\n"),
189 stderr);
190 } else {
191 #ifdef USE_IN_LIBIO
192 if (_IO_fwide (stderr, 0) > 0)
193 __fwprintf(stderr,
194 L"rcmd: socket: %m\n");
195 else
196 #endif
197 fprintf(stderr, "rcmd: socket: %m\n");
199 __sigsetmask(oldmask);
200 freeaddrinfo(res);
201 return -1;
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;
211 if (errno == ECONNREFUSED)
212 refused = 1;
213 if (ai->ai_next != NULL) {
214 int oerrno = errno;
215 char *buf = NULL;
217 getnameinfo(ai->ai_addr, ai->ai_addrlen,
218 paddr, sizeof(paddr),
219 NULL, 0,
220 NI_NUMERICHOST);
222 if (__asprintf (&buf, _("connect to address %s: "),
223 paddr) >= 0)
225 #ifdef USE_IN_LIBIO
226 if (_IO_fwide (stderr, 0) > 0)
227 __fwprintf(stderr, L"%s", buf);
228 else
229 #endif
230 fputs (buf, stderr);
231 free (buf);
233 __set_errno (oerrno);
234 perror(0);
235 ai = ai->ai_next;
236 getnameinfo(ai->ai_addr, ai->ai_addrlen,
237 paddr, sizeof(paddr),
238 NULL, 0,
239 NI_NUMERICHOST);
240 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
242 #ifdef USE_IN_LIBIO
243 if (_IO_fwide (stderr, 0) > 0)
244 __fwprintf (stderr, L"%s", buf);
245 else
246 #endif
247 fputs (buf, stderr);
248 free (buf);
250 continue;
252 if (refused && timo <= 16) {
253 (void)__sleep(timo);
254 timo *= 2;
255 ai = res;
256 refused = 0;
257 continue;
259 freeaddrinfo(res);
260 #ifdef USE_IN_LIBIO
261 if (_IO_fwide (stderr, 0) > 0)
262 (void)__fwprintf(stderr, L"%s: %s\n", *ahost,
263 __strerror_r(errno,
264 errbuf, sizeof (errbuf)));
265 else
266 #endif
267 (void)fprintf(stderr, "%s: %s\n", *ahost,
268 __strerror_r(errno,
269 errbuf, sizeof (errbuf)));
270 __sigsetmask(oldmask);
271 return -1;
273 lport--;
274 if (fd2p == 0) {
275 __write(s, "", 1);
276 lport = 0;
277 } else {
278 char num[8];
279 int s2 = rresvport_af(&lport, ai->ai_family), s3;
280 socklen_t len = ai->ai_addrlen;
282 if (s2 < 0)
283 goto bad;
284 __listen(s2, 1);
285 (void)__snprintf(num, sizeof(num), "%d", lport);
286 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
287 char *buf = NULL;
289 if (__asprintf (&buf, _("\
290 rcmd: write (setting up stderr): %m\n")) >= 0)
292 #ifdef USE_IN_LIBIO
293 if (_IO_fwide (stderr, 0) > 0)
294 __fwprintf(stderr, L"%s", buf);
295 else
296 #endif
297 fputs (buf, stderr);
298 free (buf);
300 (void)__close(s2);
301 goto bad;
303 pfd[0].fd = s;
304 pfd[1].fd = s2;
305 __set_errno (0);
306 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
307 char *buf = NULL;
309 if ((errno != 0
310 && __asprintf(&buf, _("\
311 rcmd: poll (setting up stderr): %m\n")) >= 0)
312 || (errno == 0
313 && __asprintf(&buf, _("\
314 poll: protocol failure in circuit setup\n")) >= 0))
316 #ifdef USE_IN_LIBIO
317 if (_IO_fwide (stderr, 0) > 0)
318 __fwprintf (stderr, L"%s", buf);
319 else
320 #endif
321 fputs (buf, stderr);
322 free (buf);
324 (void)__close(s2);
325 goto bad;
327 s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
328 &len));
329 switch (from.ss_family) {
330 case AF_INET:
331 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
332 break;
333 case AF_INET6:
334 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
335 break;
336 default:
337 rport = 0;
338 break;
340 (void)__close(s2);
341 if (s3 < 0) {
342 #ifdef USE_IN_LIBIO
343 if (_IO_fwide (stderr, 0) > 0)
344 (void)__fwprintf(stderr,
345 L"rcmd: accept: %m\n");
346 else
347 #endif
348 (void)fprintf(stderr,
349 "rcmd: accept: %m\n");
350 lport = 0;
351 goto bad;
353 *fd2p = s3;
355 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
356 char *buf = NULL;
358 if (__asprintf(&buf, _("\
359 socket: protocol failure in circuit setup\n")) >= 0)
361 #ifdef USE_IN_LIBIO
362 if (_IO_fwide (stderr, 0) > 0)
363 __fwprintf (stderr, L"%s", buf);
364 else
365 #endif
366 fputs (buf, stderr);
367 free (buf);
369 goto bad2;
372 struct iovec iov[3] =
374 [0] = { .iov_base = (void *) locuser,
375 .iov_len = strlen (locuser) + 1 },
376 [1] = { .iov_base = (void *) remuser,
377 .iov_len = strlen (remuser) + 1 },
378 [2] = { .iov_base = (void *) cmd,
379 .iov_len = strlen (cmd) + 1 }
381 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
382 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
383 if (n != 1) {
384 char *buf = NULL;
386 if ((n == 0
387 && __asprintf(&buf, _("rcmd: %s: short read"),
388 *ahost) >= 0)
389 || (n != 0
390 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
392 #ifdef USE_IN_LIBIO
393 if (_IO_fwide (stderr, 0) > 0)
394 __fwprintf (stderr, L"%s", buf);
395 else
396 #endif
397 fputs (buf, stderr);
398 free (buf);
400 goto bad2;
402 if (c != 0) {
403 while (__read(s, &c, 1) == 1) {
404 (void)__write(STDERR_FILENO, &c, 1);
405 if (c == '\n')
406 break;
408 goto bad2;
410 __sigsetmask(oldmask);
411 freeaddrinfo(res);
412 return s;
413 bad2:
414 if (lport)
415 (void)__close(*fd2p);
416 bad:
417 (void)__close(s);
418 __sigsetmask(oldmask);
419 freeaddrinfo(res);
420 return -1;
422 libc_hidden_def (rcmd_af)
425 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
426 char **ahost;
427 u_short rport;
428 const char *locuser, *remuser, *cmd;
429 int *fd2p;
431 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
435 rresvport_af(alport, family)
436 int *alport;
437 sa_family_t family;
439 struct sockaddr_storage ss;
440 int s;
441 size_t len;
442 uint16_t *sport;
444 switch(family){
445 case AF_INET:
446 len = sizeof(struct sockaddr_in);
447 sport = &((struct sockaddr_in *)&ss)->sin_port;
448 break;
449 case AF_INET6:
450 len = sizeof(struct sockaddr_in6);
451 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
452 break;
453 default:
454 __set_errno (EAFNOSUPPORT);
455 return -1;
457 s = __socket(family, SOCK_STREAM, 0);
458 if (s < 0)
459 return -1;
461 memset (&ss, '\0', sizeof(ss));
462 #ifdef SALEN
463 ss.__ss_len = len;
464 #endif
465 ss.ss_family = family;
467 /* Ignore invalid values. */
468 if (*alport < IPPORT_RESERVED / 2)
469 *alport = IPPORT_RESERVED / 2;
470 else if (*alport >= IPPORT_RESERVED)
471 *alport = IPPORT_RESERVED - 1;
473 int start = *alport;
474 do {
475 *sport = htons((uint16_t) *alport);
476 if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
477 return s;
478 if (errno != EADDRINUSE) {
479 (void)__close(s);
480 return -1;
482 if ((*alport)-- == IPPORT_RESERVED/2)
483 *alport = IPPORT_RESERVED - 1;
484 } while (*alport != start);
485 (void)__close(s);
486 __set_errno (EAGAIN);
487 return -1;
489 libc_hidden_def (rresvport_af)
492 rresvport(alport)
493 int *alport;
495 return rresvport_af(alport, AF_INET);
498 int __check_rhosts_file = 1;
499 char *__rcmd_errstr;
502 ruserok_af(rhost, superuser, ruser, luser, af)
503 const char *rhost, *ruser, *luser;
504 int superuser;
505 sa_family_t af;
507 struct addrinfo hints, *res, *res0;
508 int gai;
509 int ret;
511 memset (&hints, '\0', sizeof(hints));
512 hints.ai_family = af;
513 gai = getaddrinfo(rhost, NULL, &hints, &res0);
514 if (gai)
515 return -1;
516 ret = -1;
517 for (res=res0; res; res=res->ai_next)
518 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
519 superuser, ruser, luser, rhost) == 0){
520 ret = 0;
521 break;
523 freeaddrinfo(res0);
524 return (ret);
526 libc_hidden_def (ruserok_af)
529 ruserok(rhost, superuser, ruser, luser)
530 const char *rhost, *ruser, *luser;
531 int superuser;
533 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
536 /* Extremely paranoid file open function. */
537 static FILE *
538 iruserfopen (const char *file, uid_t okuser)
540 struct stat64 st;
541 char *cp = NULL;
542 FILE *res = NULL;
544 /* If not a regular file, if owned by someone other than user or
545 root, if writeable by anyone but the owner, or if hardlinked
546 anywhere, quit. */
547 cp = NULL;
548 if (__lxstat64 (_STAT_VER, file, &st))
549 cp = _("lstat failed");
550 else if (!S_ISREG (st.st_mode))
551 cp = _("not regular file");
552 else
554 res = fopen (file, "r");
555 if (!res)
556 cp = _("cannot open");
557 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
558 cp = _("fstat failed");
559 else if (st.st_uid && st.st_uid != okuser)
560 cp = _("bad owner");
561 else if (st.st_mode & (S_IWGRP|S_IWOTH))
562 cp = _("writeable by other than owner");
563 else if (st.st_nlink > 1)
564 cp = _("hard linked somewhere");
567 /* If there were any problems, quit. */
568 if (cp != NULL)
570 __rcmd_errstr = cp;
571 if (res)
572 fclose (res);
573 return NULL;
576 /* No threads use this stream. */
577 __fsetlocking (res, FSETLOCKING_BYCALLER);
579 return res;
583 * New .rhosts strategy: We are passed an ip address. We spin through
584 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
585 * has ip addresses, we don't have to trust a nameserver. When it
586 * contains hostnames, we spin through the list of addresses the nameserver
587 * gives us and look for a match.
589 * Returns 0 if ok, -1 if not ok.
591 static int
592 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
593 struct sockaddr *ra;
594 size_t ralen;
595 int superuser;
596 const char *ruser, *luser, *rhost;
598 FILE *hostf = NULL;
599 int isbad = -1;
601 if (!superuser)
602 hostf = iruserfopen (_PATH_HEQUIV, 0);
604 if (hostf)
606 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
607 fclose (hostf);
609 if (!isbad)
610 return 0;
613 if (__check_rhosts_file || superuser)
615 char *pbuf;
616 struct passwd pwdbuf, *pwd;
617 size_t dirlen;
618 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
619 char *buffer = __alloca (buflen);
620 uid_t uid;
622 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
623 || pwd == NULL)
624 return -1;
626 dirlen = strlen (pwd->pw_dir);
627 pbuf = alloca (dirlen + sizeof "/.rhosts");
628 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
629 "/.rhosts", sizeof "/.rhosts");
631 /* Change effective uid while reading .rhosts. If root and
632 reading an NFS mounted file system, can't read files that
633 are protected read/write owner only. */
634 uid = __geteuid ();
635 seteuid (pwd->pw_uid);
636 hostf = iruserfopen (pbuf, pwd->pw_uid);
638 if (hostf != NULL)
640 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
641 fclose (hostf);
644 seteuid (uid);
645 return isbad;
647 return -1;
650 * ruserok_sa() is now discussed on ipng, so
651 * currently disabled for external use
653 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
654 struct sockaddr *ra;
655 size_t ralen;
656 int superuser;
657 const char *ruser, *luser;
659 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
662 /* This is the exported version. */
664 iruserok_af (raddr, superuser, ruser, luser, af)
665 const void *raddr;
666 int superuser;
667 const char *ruser, *luser;
668 sa_family_t af;
670 struct sockaddr_storage ra;
671 size_t ralen;
673 memset (&ra, '\0', sizeof(ra));
674 switch (af){
675 case AF_INET:
676 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
677 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
678 sizeof(struct in_addr));
679 ralen = sizeof(struct sockaddr_in);
680 break;
681 case AF_INET6:
682 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
683 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
684 sizeof(struct in6_addr));
685 ralen = sizeof(struct sockaddr_in6);
686 break;
687 default:
688 return 0;
690 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
692 libc_hidden_def (iruserok_af)
695 iruserok (raddr, superuser, ruser, luser)
696 u_int32_t raddr;
697 int superuser;
698 const char *ruser, *luser;
700 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
704 * XXX
705 * Don't make static, used by lpd(8).
707 * This function is not used anymore. It is only present because lpd(8)
708 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
709 * argument. This means that netgroups won't work in .rhost/hosts.equiv
710 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
711 * or PAM.
712 * Returns 0 if ok, -1 if not ok.
715 __ivaliduser(hostf, raddr, luser, ruser)
716 FILE *hostf;
717 u_int32_t raddr;
718 const char *luser, *ruser;
720 struct sockaddr_in ra;
721 memset(&ra, '\0', sizeof(ra));
722 ra.sin_family = AF_INET;
723 ra.sin_addr.s_addr = raddr;
724 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
725 luser, ruser, "-");
729 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
730 static int
731 internal_function
732 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
733 const char *rhost)
735 struct addrinfo hints, *res0, *res;
736 char raddr[INET6_ADDRSTRLEN];
737 int match;
738 int negate=1; /* Multiply return with this to get -1 instead of 1 */
740 /* Check nis netgroup. */
741 if (strncmp ("+@", lhost, 2) == 0)
742 return innetgr (&lhost[2], rhost, NULL, NULL);
744 if (strncmp ("-@", lhost, 2) == 0)
745 return -innetgr (&lhost[2], rhost, NULL, NULL);
747 /* -host */
748 if (strncmp ("-", lhost,1) == 0) {
749 negate = -1;
750 lhost++;
751 } else if (strcmp ("+",lhost) == 0) {
752 return 1; /* asking for trouble, but ok.. */
755 /* Try for raw ip address first. */
756 /* XXX */
757 if (getnameinfo(ra, ralen,
758 raddr, sizeof(raddr), NULL, 0,
759 NI_NUMERICHOST) == 0
760 && strcmp(raddr, lhost) == 0)
761 return negate;
763 /* Better be a hostname. */
764 match = 0;
765 memset(&hints, '\0', sizeof(hints));
766 hints.ai_family = ra->sa_family;
767 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
768 /* Spin through ip addresses. */
769 for (res = res0; res; res = res->ai_next)
771 if (res->ai_family == ra->sa_family
772 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
774 match = 1;
775 break;
778 freeaddrinfo (res0);
780 return negate * match;
783 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
784 static int
785 internal_function
786 __icheckuser (const char *luser, const char *ruser)
789 luser is user entry from .rhosts/hosts.equiv file
790 ruser is user id on remote host
793 /* [-+]@netgroup */
794 if (strncmp ("+@", luser, 2) == 0)
795 return innetgr (&luser[2], NULL, ruser, NULL);
797 if (strncmp ("-@", luser,2) == 0)
798 return -innetgr (&luser[2], NULL, ruser, NULL);
800 /* -user */
801 if (strncmp ("-", luser, 1) == 0)
802 return -(strcmp (&luser[1], ruser) == 0);
804 /* + */
805 if (strcmp ("+", luser) == 0)
806 return 1;
808 /* simple string match */
809 return strcmp (ruser, luser) == 0;
813 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
815 static int
816 __isempty (char *p)
818 while (*p && isspace (*p)) {
819 ++p;
822 return (*p == '\0' || *p == '#') ? 1 : 0 ;
826 * Returns 0 if positive match, -1 if _not_ ok.
828 static int
829 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
830 FILE *hostf;
831 struct sockaddr *ra;
832 size_t ralen;
833 const char *luser, *ruser, *rhost;
835 register const char *user;
836 register char *p;
837 int hcheck, ucheck;
838 char *buf = NULL;
839 size_t bufsize = 0;
840 int retval = -1;
842 while (__getline (&buf, &bufsize, hostf) > 0) {
843 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
844 p = buf;
846 /* Skip empty or comment lines */
847 if (__isempty (p)) {
848 continue;
851 /* Skip lines that are too long. */
852 if (strchr (p, '\n') == NULL) {
853 int ch = getc_unlocked (hostf);
855 while (ch != '\n' && ch != EOF)
856 ch = getc_unlocked (hostf);
857 continue;
860 for (;*p && !isspace(*p); ++p) {
861 *p = _tolower (*p);
864 /* Next we want to find the permitted name for the remote user. */
865 if (*p == ' ' || *p == '\t') {
866 /* <nul> terminate hostname and skip spaces */
867 for (*p++='\0'; *p && isspace (*p); ++p);
869 user = p; /* this is the user's name */
870 while (*p && !isspace (*p))
871 ++p; /* find end of user's name */
872 } else
873 user = p;
875 *p = '\0'; /* <nul> terminate username (+host?) */
877 /* buf -> host(?) ; user -> username(?) */
879 /* First check host part */
880 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
882 if (hcheck < 0)
883 break;
885 if (hcheck) {
886 /* Then check user part */
887 if (! (*user))
888 user = luser;
890 ucheck = __icheckuser (user, ruser);
892 /* Positive 'host user' match? */
893 if (ucheck > 0) {
894 retval = 0;
895 break;
898 /* Negative 'host -user' match? */
899 if (ucheck < 0)
900 break;
902 /* Neither, go on looking for match */
906 if (buf != NULL)
907 free (buf);
909 return retval;