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#include <sys/param.h>
59#include <sys/poll.h>
60#include <sys/socket.h>
61#include <sys/stat.h>
62
63#include <netinet/in.h>
64#include <arpa/inet.h>
65
66#include <alloca.h>
67#include <signal.h>
68#include <fcntl.h>
69#include <netdb.h>
70#include <unistd.h>
71#include <pwd.h>
72#include <errno.h>
73#include <stdio.h>
74#include <stdio_ext.h>
75#include <ctype.h>
76#include <string.h>
77#include <libintl.h>
78#include <stdlib.h>
79#include <wchar.h>
80#include <sys/uio.h>
81#include <sigsetops.h>
82
83
84int __ivaliduser (FILE *, uint32_t, const char *, const char *);
85static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
86 const char *, const char *, const char *);
87static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
88 int superuser, const char *ruser,
89 const char *luser, const char *rhost);
90static int ruserok_sa (struct sockaddr *ra, size_t ralen,
91 int superuser, const char *ruser,
92 const char *luser);
93int iruserok_af (const void *raddr, int superuser, const char *ruser,
94 const char *luser, sa_family_t af);
95int iruserok (uint32_t raddr, int superuser, const char *ruser,
96 const char *luser);
97
98libc_hidden_proto (iruserok_af)
99
100libc_freeres_ptr(static char *ahostbuf);
101
102int
103rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
104 const char *cmd, int *fd2p, sa_family_t af)
105{
106 char paddr[INET6_ADDRSTRLEN];
107 struct addrinfo hints, *res, *ai;
108 union
109 {
110 struct sockaddr sa;
111 struct sockaddr_storage ss;
112 struct sockaddr_in sin;
113 struct sockaddr_in6 sin6;
114 } from;
115 struct pollfd pfd[2];
116 sigset_t mask, omask;
117
118 pid_t pid;
119 int s, lport, timo, error;
120 char c;
121 int refused;
122 char num[8];
123 ssize_t n;
124
125 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
126 {
127 __set_errno (EAFNOSUPPORT);
128 return -1;
129 }
130
131 pid = __getpid();
132
133 memset(&hints, '\0', sizeof(hints));
134 hints.ai_flags = AI_CANONNAME;
135 hints.ai_family = af;
136 hints.ai_socktype = SOCK_STREAM;
137 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
138 error = getaddrinfo(*ahost, num, &hints, &res);
139 if (error) {
140 if (error == EAI_NONAME && *ahost != NULL)
141 __fxprintf(NULL, fmt: "%s: Unknown host\n", *ahost);
142 else
143 __fxprintf(NULL, fmt: "rcmd: getaddrinfo: %s\n",
144 gai_strerror(error));
145
146 return -1;
147 }
148
149 pfd[0].events = POLLIN;
150 pfd[1].events = POLLIN;
151
152 if (res->ai_canonname){
153 free (ptr: ahostbuf);
154 ahostbuf = __strdup (res->ai_canonname);
155 if (ahostbuf == NULL) {
156 freeaddrinfo (res);
157 __fxprintf(NULL, fmt: "%s",
158 _("rcmd: Cannot allocate memory\n"));
159 return -1;
160 }
161 *ahost = ahostbuf;
162 } else
163 *ahost = NULL;
164 ai = res;
165 refused = 0;
166 __sigemptyset(set: &mask);
167 __sigaddset(set: &mask, SIGURG);
168 __sigprocmask (SIG_BLOCK, &mask, &omask);
169 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
170 char errbuf[200];
171
172 s = rresvport_af(&lport, ai->ai_family);
173 if (s < 0) {
174 if (errno == EAGAIN)
175 __fxprintf(NULL, fmt: "%s", _("\
176rcmd: socket: All ports in use\n"));
177 else
178 __fxprintf(NULL, fmt: "rcmd: socket: %m\n");
179
180 __sigprocmask (SIG_SETMASK, &omask, 0);
181 freeaddrinfo(res);
182 return -1;
183 }
184 __fcntl(s, F_SETOWN, pid);
185 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
186 break;
187 (void)__close(s);
188 if (errno == EADDRINUSE) {
189 lport--;
190 continue;
191 }
192 if (errno == ECONNREFUSED)
193 refused = 1;
194 if (ai->ai_next != NULL) {
195 int oerrno = errno;
196 char *buf = NULL;
197
198 getnameinfo(ai->ai_addr, ai->ai_addrlen,
199 paddr, sizeof(paddr),
200 NULL, 0,
201 NI_NUMERICHOST);
202
203 if (__asprintf (&buf, _("connect to address %s: "),
204 paddr) >= 0)
205 {
206 __fxprintf(NULL, fmt: "%s", buf);
207 free (ptr: buf);
208 }
209 __set_errno (oerrno);
210 perror(0);
211 ai = ai->ai_next;
212 getnameinfo(ai->ai_addr, ai->ai_addrlen,
213 paddr, sizeof(paddr),
214 NULL, 0,
215 NI_NUMERICHOST);
216 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
217 {
218 __fxprintf (NULL, fmt: "%s", buf);
219 free (ptr: buf);
220 }
221 continue;
222 }
223 if (refused && timo <= 16) {
224 (void)__sleep(seconds: timo);
225 timo *= 2;
226 ai = res;
227 refused = 0;
228 continue;
229 }
230 freeaddrinfo(res);
231 (void)__fxprintf(NULL, fmt: "%s: %s\n", *ahost,
232 __strerror_r(errno, errbuf, sizeof (errbuf)));
233 __sigprocmask (SIG_SETMASK, &omask, 0);
234 return -1;
235 }
236 lport--;
237 if (fd2p == 0) {
238 __write(s, "", 1);
239 lport = 0;
240 } else {
241 char num[8];
242 int s2 = rresvport_af(&lport, ai->ai_family), s3;
243 socklen_t len = ai->ai_addrlen;
244
245 if (s2 < 0)
246 goto bad;
247 __listen(fd: s2, n: 1);
248 (void)__snprintf(num, sizeof(num), "%d", lport);
249 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
250 char *buf = NULL;
251
252 if (__asprintf (&buf, _("\
253rcmd: write (setting up stderr): %m\n")) >= 0)
254 {
255 __fxprintf(NULL, fmt: "%s", buf);
256 free (ptr: buf);
257 }
258 (void)__close(s2);
259 goto bad;
260 }
261 pfd[0].fd = s;
262 pfd[1].fd = s2;
263 __set_errno (0);
264 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
265 char *buf = NULL;
266
267 if ((errno != 0
268 && __asprintf(&buf, _("\
269rcmd: poll (setting up stderr): %m\n")) >= 0)
270 || (errno == 0
271 && __asprintf(&buf, _("\
272poll: protocol failure in circuit setup\n")) >= 0))
273 {
274 __fxprintf (NULL, fmt: "%s", buf);
275 free (ptr: buf);
276 }
277 (void)__close(s2);
278 goto bad;
279 }
280 s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
281 switch (from.sa.sa_family) {
282 case AF_INET:
283 rport = ntohs(from.sin.sin_port);
284 break;
285 case AF_INET6:
286 rport = ntohs(from.sin6.sin6_port);
287 break;
288 default:
289 rport = 0;
290 break;
291 }
292 (void)__close(s2);
293 if (s3 < 0) {
294 (void)__fxprintf(NULL, fmt: "rcmd: accept: %m\n");
295 lport = 0;
296 goto bad;
297 }
298 *fd2p = s3;
299
300 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
301 char *buf = NULL;
302
303 if (__asprintf(&buf, _("\
304socket: protocol failure in circuit setup\n")) >= 0)
305 {
306 __fxprintf (NULL, fmt: "%s", buf);
307 free (ptr: buf);
308 }
309 goto bad2;
310 }
311 }
312 struct iovec iov[3] =
313 {
314 [0] = { .iov_base = (void *) locuser,
315 .iov_len = strlen (locuser) + 1 },
316 [1] = { .iov_base = (void *) remuser,
317 .iov_len = strlen (remuser) + 1 },
318 [2] = { .iov_base = (void *) cmd,
319 .iov_len = strlen (cmd) + 1 }
320 };
321 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
322 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
323 if (n != 1) {
324 char *buf = NULL;
325
326 if ((n == 0
327 && __asprintf(&buf, _("rcmd: %s: short read"),
328 *ahost) >= 0)
329 || (n != 0
330 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
331 {
332 __fxprintf (NULL, fmt: "%s", buf);
333 free (ptr: buf);
334 }
335 goto bad2;
336 }
337 if (c != 0) {
338 while (__read(s, &c, 1) == 1) {
339 (void)__write(STDERR_FILENO, &c, 1);
340 if (c == '\n')
341 break;
342 }
343 goto bad2;
344 }
345 __sigprocmask (SIG_SETMASK, &omask, 0);
346 freeaddrinfo(res);
347 return s;
348bad2:
349 if (lport)
350 (void)__close(*fd2p);
351bad:
352 (void)__close(s);
353 __sigprocmask (SIG_SETMASK, &omask, 0);
354 freeaddrinfo(res);
355 return -1;
356}
357libc_hidden_def (rcmd_af)
358
359int
360rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
361 const char *cmd, int *fd2p)
362{
363 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
364}
365
366int
367rresvport_af (int *alport, sa_family_t family)
368{
369 union {
370 struct sockaddr generic;
371 struct sockaddr_in in;
372 struct sockaddr_in6 in6;
373 } ss;
374 int s;
375 size_t len;
376 uint16_t *sport;
377
378 switch(family){
379 case AF_INET:
380 len = sizeof(struct sockaddr_in);
381 sport = &ss.in.sin_port;
382 break;
383 case AF_INET6:
384 len = sizeof(struct sockaddr_in6);
385 sport = &ss.in6.sin6_port;
386 break;
387 default:
388 __set_errno (EAFNOSUPPORT);
389 return -1;
390 }
391 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
392 s = __socket(family, SOCK_STREAM, 0);
393 if (s < 0)
394 return -1;
395
396 memset (&ss, '\0', sizeof(ss));
397#ifdef SALEN
398 ss.generic.__ss_len = len;
399#endif
400 ss.generic.sa_family = family;
401
402 /* Ignore invalid values. */
403 if (*alport < IPPORT_RESERVED / 2)
404 *alport = IPPORT_RESERVED / 2;
405 else if (*alport >= IPPORT_RESERVED)
406 *alport = IPPORT_RESERVED - 1;
407
408 int start = *alport;
409 do {
410 *sport = htons((uint16_t) *alport);
411 if (__bind(fd: s, addr: &ss.generic, len: len) >= 0)
412 return s;
413 if (errno != EADDRINUSE) {
414 (void)__close(s);
415 return -1;
416 }
417 if ((*alport)-- == IPPORT_RESERVED/2)
418 *alport = IPPORT_RESERVED - 1;
419 } while (*alport != start);
420 (void)__close(s);
421 __set_errno (EAGAIN);
422 return -1;
423}
424libc_hidden_def (rresvport_af)
425
426int
427rresvport (int *alport)
428{
429 return rresvport_af(alport, AF_INET);
430}
431
432int __check_rhosts_file = 1;
433char *__rcmd_errstr;
434
435int
436ruserok_af (const char *rhost, int superuser, const char *ruser,
437 const char *luser, sa_family_t af)
438{
439 struct addrinfo hints, *res, *res0;
440 int gai;
441 int ret;
442
443 memset (&hints, '\0', sizeof(hints));
444 hints.ai_family = af;
445 gai = getaddrinfo(rhost, NULL, &hints, &res0);
446 if (gai)
447 return -1;
448 ret = -1;
449 for (res=res0; res; res=res->ai_next)
450 if (ruserok2_sa(ra: res->ai_addr, ralen: res->ai_addrlen,
451 superuser, ruser, luser, rhost) == 0){
452 ret = 0;
453 break;
454 }
455 freeaddrinfo(res0);
456 return (ret);
457}
458libc_hidden_def (ruserok_af)
459
460int
461ruserok (const char *rhost, int superuser, const char *ruser,
462 const char *luser)
463{
464 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
465}
466
467/* Extremely paranoid file open function. */
468static FILE *
469iruserfopen (const char *file, uid_t okuser)
470{
471 struct __stat64_t64 st;
472 char *cp = NULL;
473 FILE *res = NULL;
474
475 /* If not a regular file, if owned by someone other than user or
476 root, if writeable by anyone but the owner, or if hardlinked
477 anywhere, quit. */
478 if (__lstat64_time64 (file, &st))
479 cp = _("lstat failed");
480 else if (!S_ISREG (st.st_mode))
481 cp = _("not regular file");
482 else
483 {
484 res = fopen (file, "rce");
485 if (!res)
486 cp = _("cannot open");
487 else if (__fstat64_time64 (fileno (res), &st) < 0)
488 cp = _("fstat failed");
489 else if (st.st_uid && st.st_uid != okuser)
490 cp = _("bad owner");
491 else if (st.st_mode & (S_IWGRP|S_IWOTH))
492 cp = _("writeable by other than owner");
493 else if (st.st_nlink > 1)
494 cp = _("hard linked somewhere");
495 }
496
497 /* If there were any problems, quit. */
498 if (cp != NULL)
499 {
500 __rcmd_errstr = cp;
501 if (res)
502 fclose (res);
503 return NULL;
504 }
505
506 /* No threads use this stream. */
507 __fsetlocking (res, FSETLOCKING_BYCALLER);
508
509 return res;
510}
511
512/*
513 * New .rhosts strategy: We are passed an ip address. We spin through
514 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
515 * has ip addresses, we don't have to trust a nameserver. When it
516 * contains hostnames, we spin through the list of addresses the nameserver
517 * gives us and look for a match.
518 *
519 * Returns 0 if ok, -1 if not ok.
520 */
521static int
522ruserok2_sa (struct sockaddr *ra, size_t ralen, int superuser,
523 const char *ruser, const char *luser, const char *rhost)
524{
525 FILE *hostf = NULL;
526 int isbad = -1;
527
528 if (!superuser)
529 hostf = iruserfopen (_PATH_HEQUIV, okuser: 0);
530
531 if (hostf)
532 {
533 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
534 fclose (hostf);
535
536 if (!isbad)
537 return 0;
538 }
539
540 if (__check_rhosts_file || superuser)
541 {
542 char *pbuf;
543 struct passwd pwdbuf, *pwd;
544 size_t dirlen;
545 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
546 char *buffer = __alloca (buflen);
547 uid_t uid;
548
549 if (__getpwnam_r (name: luser, resultbuf: &pwdbuf, buffer: buffer, buflen: buflen, result: &pwd) != 0
550 || pwd == NULL)
551 return -1;
552
553 dirlen = strlen (pwd->pw_dir);
554 pbuf = alloca (dirlen + sizeof "/.rhosts");
555 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
556 "/.rhosts", sizeof "/.rhosts");
557
558 /* Change effective uid while reading .rhosts. If root and
559 reading an NFS mounted file system, can't read files that
560 are protected read/write owner only. */
561 uid = __geteuid ();
562 seteuid (pwd->pw_uid);
563 hostf = iruserfopen (file: pbuf, okuser: pwd->pw_uid);
564
565 if (hostf != NULL)
566 {
567 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
568 fclose (hostf);
569 }
570
571 seteuid (uid);
572 return isbad;
573 }
574 return -1;
575}
576/*
577 * ruserok_sa() is now discussed on ipng, so
578 * currently disabled for external use
579 */
580static int
581ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
582 const char *ruser, const char *luser)
583{
584 return ruserok2_sa(ra, ralen, superuser, ruser, luser, rhost: "-");
585}
586
587/* This is the exported version. */
588int
589iruserok_af (const void *raddr, int superuser, const char *ruser,
590 const char *luser, sa_family_t af)
591{
592 union {
593 struct sockaddr generic;
594 struct sockaddr_in in;
595 struct sockaddr_in6 in6;
596 } ra;
597 size_t ralen;
598
599 memset (&ra, '\0', sizeof(ra));
600 switch (af){
601 case AF_INET:
602 ra.in.sin_family = AF_INET;
603 memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
604 ralen = sizeof(struct sockaddr_in);
605 break;
606 case AF_INET6:
607 ra.in6.sin6_family = AF_INET6;
608 memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
609 ralen = sizeof(struct sockaddr_in6);
610 break;
611 default:
612 return 0;
613 }
614 return ruserok_sa (ra: &ra.generic, ralen, superuser, ruser, luser);
615}
616libc_hidden_def (iruserok_af)
617
618int
619iruserok (uint32_t raddr, int superuser, const char *ruser, const char *luser)
620{
621 return iruserok_af (raddr: &raddr, superuser, ruser, luser, AF_INET);
622}
623
624/*
625 * XXX
626 * Don't make static, used by lpd(8).
627 *
628 * This function is not used anymore. It is only present because lpd(8)
629 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
630 * argument. This means that netgroups won't work in .rhost/hosts.equiv
631 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
632 * or PAM.
633 * Returns 0 if ok, -1 if not ok.
634 */
635int
636__ivaliduser (FILE *hostf, uint32_t raddr, const char *luser,
637 const char *ruser)
638{
639 struct sockaddr_in ra;
640 memset(&ra, '\0', sizeof(ra));
641 ra.sin_family = AF_INET;
642 ra.sin_addr.s_addr = raddr;
643 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
644 luser, ruser, "-");
645}
646
647
648/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
649static int
650__checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
651 const char *rhost)
652{
653 struct addrinfo hints, *res0, *res;
654 char raddr[INET6_ADDRSTRLEN];
655 int match;
656 int negate=1; /* Multiply return with this to get -1 instead of 1 */
657
658 /* Check nis netgroup. */
659 if (strncmp ("+@", lhost, 2) == 0)
660 return innetgr (&lhost[2], rhost, NULL, NULL);
661
662 if (strncmp ("-@", lhost, 2) == 0)
663 return -innetgr (&lhost[2], rhost, NULL, NULL);
664
665 /* -host */
666 if (strncmp ("-", lhost,1) == 0) {
667 negate = -1;
668 lhost++;
669 } else if (strcmp ("+",lhost) == 0) {
670 return 1; /* asking for trouble, but ok.. */
671 }
672
673 /* Try for raw ip address first. */
674 /* XXX */
675 if (getnameinfo(ra, ralen,
676 raddr, sizeof(raddr), NULL, 0,
677 NI_NUMERICHOST) == 0
678 && strcmp(raddr, lhost) == 0)
679 return negate;
680
681 /* Better be a hostname. */
682 match = 0;
683 memset(&hints, '\0', sizeof(hints));
684 hints.ai_family = ra->sa_family;
685 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
686 /* Spin through ip addresses. */
687 for (res = res0; res; res = res->ai_next)
688 {
689 if (res->ai_family == ra->sa_family
690 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
691 {
692 match = 1;
693 break;
694 }
695 }
696 freeaddrinfo (res0);
697 }
698 return negate * match;
699}
700
701/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
702static int
703__icheckuser (const char *luser, const char *ruser)
704{
705 /*
706 luser is user entry from .rhosts/hosts.equiv file
707 ruser is user id on remote host
708 */
709
710 /* [-+]@netgroup */
711 if (strncmp ("+@", luser, 2) == 0)
712 return innetgr (&luser[2], NULL, ruser, NULL);
713
714 if (strncmp ("-@", luser,2) == 0)
715 return -innetgr (&luser[2], NULL, ruser, NULL);
716
717 /* -user */
718 if (strncmp ("-", luser, 1) == 0)
719 return -(strcmp (&luser[1], ruser) == 0);
720
721 /* + */
722 if (strcmp ("+", luser) == 0)
723 return 1;
724
725 /* simple string match */
726 return strcmp (ruser, luser) == 0;
727}
728
729/*
730 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
731 */
732static int
733__isempty (char *p)
734{
735 while (*p && isspace (*p)) {
736 ++p;
737 }
738
739 return (*p == '\0' || *p == '#') ? 1 : 0 ;
740}
741
742/*
743 * Returns 0 if positive match, -1 if _not_ ok.
744 */
745static int
746__validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
747 const char *luser, const char *ruser, const char *rhost)
748{
749 const char *user;
750 char *p;
751 int hcheck, ucheck;
752 char *buf = NULL;
753 size_t bufsize = 0;
754 int retval = -1;
755
756 while (__getline (lineptr: &buf, n: &bufsize, stream: hostf) > 0) {
757 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
758 p = buf;
759
760 /* Skip empty or comment lines */
761 if (__isempty (p)) {
762 continue;
763 }
764
765 for (;*p && !isspace(*p); ++p) {
766 *p = _tolower (*p);
767 }
768
769 /* Next we want to find the permitted name for the remote user. */
770 if (*p == ' ' || *p == '\t') {
771 /* <nul> terminate hostname and skip spaces */
772 for (*p++='\0'; *p && isspace (*p); ++p);
773
774 user = p; /* this is the user's name */
775 while (*p && !isspace (*p))
776 ++p; /* find end of user's name */
777 } else
778 user = p;
779
780 *p = '\0'; /* <nul> terminate username (+host?) */
781
782 /* buf -> host(?) ; user -> username(?) */
783 if (*buf == '\0')
784 break;
785 if (*user == '\0')
786 user = luser;
787
788 /* First check the user part. In a naive implementation we
789 would check the host part first, then the user. However,
790 if we check the user first and reject the entry we will
791 have saved doing any host lookups to normalize the comparison
792 and that likely saves several DNS queries. Therefore we
793 check the user first. */
794 ucheck = __icheckuser (luser: user, ruser);
795
796 /* Either we found the user, or we didn't and this is a
797 negative host check. We must do the negative host lookup
798 in order to preserve the semantics of stopping on this line
799 before processing others. */
800 if (ucheck != 0 || *buf == '-') {
801
802 /* Next check host part. */
803 hcheck = __checkhost_sa (ra, ralen, lhost: buf, rhost);
804
805 /* Negative '-host user(?)' match? */
806 if (hcheck < 0)
807 break;
808
809 /* Positive 'host user' match? */
810 if (hcheck > 0 && ucheck > 0) {
811 retval = 0;
812 break;
813 }
814
815 /* Negative 'host -user' match? */
816 if (hcheck > 0 && ucheck < 0)
817 break;
818
819 /* Neither, go on looking for match. */
820 }
821 }
822
823 free (ptr: buf);
824
825 return retval;
826}
827

source code of glibc/inet/rcmd.c