S390: Move utf8-utf32-z9.c to multiarch folder and use s390_libc_ifunc_expr macro.
[glibc.git] / inet / rcmd.c
blobc285b9ecd62533d3d6b0b89173d83ee79134fea4
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 #include <sys/param.h>
59 #include <sys/poll.h>
60 #include <sys/socket.h>
61 #include <sys/stat.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
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>
83 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
84 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
85 const char *, const char *, const char *);
86 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
87 int superuser, const char *ruser,
88 const char *luser, const char *rhost);
89 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
90 int superuser, const char *ruser,
91 const char *luser);
92 int iruserok_af (const void *raddr, int superuser, const char *ruser,
93 const char *luser, sa_family_t af);
94 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
95 const char *luser);
97 libc_hidden_proto (iruserok_af)
99 libc_freeres_ptr(static char *ahostbuf);
102 rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
103 const char *cmd, int *fd2p, sa_family_t af)
105 char paddr[INET6_ADDRSTRLEN];
106 struct addrinfo hints, *res, *ai;
107 union
109 struct sockaddr sa;
110 struct sockaddr_storage ss;
111 struct sockaddr_in sin;
112 struct sockaddr_in6 sin6;
113 } from;
114 struct pollfd pfd[2];
115 int32_t oldmask;
116 pid_t pid;
117 int s, lport, timo, error;
118 char c;
119 int refused;
120 char num[8];
121 ssize_t n;
123 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
125 __set_errno (EAFNOSUPPORT);
126 return -1;
129 pid = __getpid();
131 memset(&hints, '\0', sizeof(hints));
132 hints.ai_flags = AI_CANONNAME;
133 hints.ai_family = af;
134 hints.ai_socktype = SOCK_STREAM;
135 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
136 error = getaddrinfo(*ahost, num, &hints, &res);
137 if (error) {
138 if (error == EAI_NONAME && *ahost != NULL)
139 __fxprintf(NULL, "%s: Unknown host\n", *ahost);
140 else
141 __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
142 gai_strerror(error));
144 return -1;
147 pfd[0].events = POLLIN;
148 pfd[1].events = POLLIN;
150 if (res->ai_canonname){
151 free (ahostbuf);
152 ahostbuf = __strdup (res->ai_canonname);
153 if (ahostbuf == NULL) {
154 __fxprintf(NULL, "%s",
155 _("rcmd: Cannot allocate memory\n"));
156 return -1;
158 *ahost = ahostbuf;
159 } else
160 *ahost = NULL;
161 ai = res;
162 refused = 0;
163 oldmask = __sigblock(sigmask(SIGURG));
164 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
165 char errbuf[200];
167 s = rresvport_af(&lport, ai->ai_family);
168 if (s < 0) {
169 if (errno == EAGAIN)
170 __fxprintf(NULL, "%s", _("\
171 rcmd: socket: All ports in use\n"));
172 else
173 __fxprintf(NULL, "rcmd: socket: %m\n");
175 __sigsetmask(oldmask);
176 freeaddrinfo(res);
177 return -1;
179 __fcntl(s, F_SETOWN, pid);
180 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
181 break;
182 (void)__close(s);
183 if (errno == EADDRINUSE) {
184 lport--;
185 continue;
187 if (errno == ECONNREFUSED)
188 refused = 1;
189 if (ai->ai_next != NULL) {
190 int oerrno = errno;
191 char *buf = NULL;
193 getnameinfo(ai->ai_addr, ai->ai_addrlen,
194 paddr, sizeof(paddr),
195 NULL, 0,
196 NI_NUMERICHOST);
198 if (__asprintf (&buf, _("connect to address %s: "),
199 paddr) >= 0)
201 __fxprintf(NULL, "%s", buf);
202 free (buf);
204 __set_errno (oerrno);
205 perror(0);
206 ai = ai->ai_next;
207 getnameinfo(ai->ai_addr, ai->ai_addrlen,
208 paddr, sizeof(paddr),
209 NULL, 0,
210 NI_NUMERICHOST);
211 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
213 __fxprintf (NULL, "%s", buf);
214 free (buf);
216 continue;
218 if (refused && timo <= 16) {
219 (void)__sleep(timo);
220 timo *= 2;
221 ai = res;
222 refused = 0;
223 continue;
225 freeaddrinfo(res);
226 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
227 __strerror_r(errno, errbuf, sizeof (errbuf)));
228 __sigsetmask(oldmask);
229 return -1;
231 lport--;
232 if (fd2p == 0) {
233 __write(s, "", 1);
234 lport = 0;
235 } else {
236 char num[8];
237 int s2 = rresvport_af(&lport, ai->ai_family), s3;
238 socklen_t len = ai->ai_addrlen;
240 if (s2 < 0)
241 goto bad;
242 __listen(s2, 1);
243 (void)__snprintf(num, sizeof(num), "%d", lport);
244 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
245 char *buf = NULL;
247 if (__asprintf (&buf, _("\
248 rcmd: write (setting up stderr): %m\n")) >= 0)
250 __fxprintf(NULL, "%s", buf);
251 free (buf);
253 (void)__close(s2);
254 goto bad;
256 pfd[0].fd = s;
257 pfd[1].fd = s2;
258 __set_errno (0);
259 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
260 char *buf = NULL;
262 if ((errno != 0
263 && __asprintf(&buf, _("\
264 rcmd: poll (setting up stderr): %m\n")) >= 0)
265 || (errno == 0
266 && __asprintf(&buf, _("\
267 poll: protocol failure in circuit setup\n")) >= 0))
269 __fxprintf (NULL, "%s", buf);
270 free (buf);
272 (void)__close(s2);
273 goto bad;
275 s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
276 switch (from.sa.sa_family) {
277 case AF_INET:
278 rport = ntohs(from.sin.sin_port);
279 break;
280 case AF_INET6:
281 rport = ntohs(from.sin6.sin6_port);
282 break;
283 default:
284 rport = 0;
285 break;
287 (void)__close(s2);
288 if (s3 < 0) {
289 (void)__fxprintf(NULL, "rcmd: accept: %m\n");
290 lport = 0;
291 goto bad;
293 *fd2p = s3;
295 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
296 char *buf = NULL;
298 if (__asprintf(&buf, _("\
299 socket: protocol failure in circuit setup\n")) >= 0)
301 __fxprintf (NULL, "%s", buf);
302 free (buf);
304 goto bad2;
307 struct iovec iov[3] =
309 [0] = { .iov_base = (void *) locuser,
310 .iov_len = strlen (locuser) + 1 },
311 [1] = { .iov_base = (void *) remuser,
312 .iov_len = strlen (remuser) + 1 },
313 [2] = { .iov_base = (void *) cmd,
314 .iov_len = strlen (cmd) + 1 }
316 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
317 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
318 if (n != 1) {
319 char *buf = NULL;
321 if ((n == 0
322 && __asprintf(&buf, _("rcmd: %s: short read"),
323 *ahost) >= 0)
324 || (n != 0
325 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
327 __fxprintf (NULL, "%s", buf);
328 free (buf);
330 goto bad2;
332 if (c != 0) {
333 while (__read(s, &c, 1) == 1) {
334 (void)__write(STDERR_FILENO, &c, 1);
335 if (c == '\n')
336 break;
338 goto bad2;
340 __sigsetmask(oldmask);
341 freeaddrinfo(res);
342 return s;
343 bad2:
344 if (lport)
345 (void)__close(*fd2p);
346 bad:
347 (void)__close(s);
348 __sigsetmask(oldmask);
349 freeaddrinfo(res);
350 return -1;
352 libc_hidden_def (rcmd_af)
355 rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
356 const char *cmd, int *fd2p)
358 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
362 rresvport_af (int *alport, sa_family_t family)
364 union {
365 struct sockaddr generic;
366 struct sockaddr_in in;
367 struct sockaddr_in6 in6;
368 } ss;
369 int s;
370 size_t len;
371 uint16_t *sport;
373 switch(family){
374 case AF_INET:
375 len = sizeof(struct sockaddr_in);
376 sport = &ss.in.sin_port;
377 break;
378 case AF_INET6:
379 len = sizeof(struct sockaddr_in6);
380 sport = &ss.in6.sin6_port;
381 break;
382 default:
383 __set_errno (EAFNOSUPPORT);
384 return -1;
386 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
387 s = __socket(family, SOCK_STREAM, 0);
388 if (s < 0)
389 return -1;
391 memset (&ss, '\0', sizeof(ss));
392 #ifdef SALEN
393 ss.generic.__ss_len = len;
394 #endif
395 ss.generic.sa_family = family;
397 /* Ignore invalid values. */
398 if (*alport < IPPORT_RESERVED / 2)
399 *alport = IPPORT_RESERVED / 2;
400 else if (*alport >= IPPORT_RESERVED)
401 *alport = IPPORT_RESERVED - 1;
403 int start = *alport;
404 do {
405 *sport = htons((uint16_t) *alport);
406 if (__bind(s, &ss.generic, len) >= 0)
407 return s;
408 if (errno != EADDRINUSE) {
409 (void)__close(s);
410 return -1;
412 if ((*alport)-- == IPPORT_RESERVED/2)
413 *alport = IPPORT_RESERVED - 1;
414 } while (*alport != start);
415 (void)__close(s);
416 __set_errno (EAGAIN);
417 return -1;
419 libc_hidden_def (rresvport_af)
422 rresvport (int *alport)
424 return rresvport_af(alport, AF_INET);
427 int __check_rhosts_file = 1;
428 char *__rcmd_errstr;
431 ruserok_af (const char *rhost, int superuser, const char *ruser,
432 const char *luser, sa_family_t af)
434 struct addrinfo hints, *res, *res0;
435 int gai;
436 int ret;
438 memset (&hints, '\0', sizeof(hints));
439 hints.ai_family = af;
440 gai = getaddrinfo(rhost, NULL, &hints, &res0);
441 if (gai)
442 return -1;
443 ret = -1;
444 for (res=res0; res; res=res->ai_next)
445 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
446 superuser, ruser, luser, rhost) == 0){
447 ret = 0;
448 break;
450 freeaddrinfo(res0);
451 return (ret);
453 libc_hidden_def (ruserok_af)
456 ruserok (const char *rhost, int superuser, const char *ruser,
457 const char *luser)
459 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
462 /* Extremely paranoid file open function. */
463 static FILE *
464 iruserfopen (const char *file, uid_t okuser)
466 struct stat64 st;
467 char *cp = NULL;
468 FILE *res = NULL;
470 /* If not a regular file, if owned by someone other than user or
471 root, if writeable by anyone but the owner, or if hardlinked
472 anywhere, quit. */
473 if (__lxstat64 (_STAT_VER, file, &st))
474 cp = _("lstat failed");
475 else if (!S_ISREG (st.st_mode))
476 cp = _("not regular file");
477 else
479 res = fopen (file, "rce");
480 if (!res)
481 cp = _("cannot open");
482 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
483 cp = _("fstat failed");
484 else if (st.st_uid && st.st_uid != okuser)
485 cp = _("bad owner");
486 else if (st.st_mode & (S_IWGRP|S_IWOTH))
487 cp = _("writeable by other than owner");
488 else if (st.st_nlink > 1)
489 cp = _("hard linked somewhere");
492 /* If there were any problems, quit. */
493 if (cp != NULL)
495 __rcmd_errstr = cp;
496 if (res)
497 fclose (res);
498 return NULL;
501 /* No threads use this stream. */
502 __fsetlocking (res, FSETLOCKING_BYCALLER);
504 return res;
508 * New .rhosts strategy: We are passed an ip address. We spin through
509 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
510 * has ip addresses, we don't have to trust a nameserver. When it
511 * contains hostnames, we spin through the list of addresses the nameserver
512 * gives us and look for a match.
514 * Returns 0 if ok, -1 if not ok.
516 static int
517 ruserok2_sa (struct sockaddr *ra, size_t ralen, int superuser,
518 const char *ruser, const char *luser, const char *rhost)
520 FILE *hostf = NULL;
521 int isbad = -1;
523 if (!superuser)
524 hostf = iruserfopen (_PATH_HEQUIV, 0);
526 if (hostf)
528 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
529 fclose (hostf);
531 if (!isbad)
532 return 0;
535 if (__check_rhosts_file || superuser)
537 char *pbuf;
538 struct passwd pwdbuf, *pwd;
539 size_t dirlen;
540 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
541 char *buffer = __alloca (buflen);
542 uid_t uid;
544 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
545 || pwd == NULL)
546 return -1;
548 dirlen = strlen (pwd->pw_dir);
549 pbuf = alloca (dirlen + sizeof "/.rhosts");
550 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
551 "/.rhosts", sizeof "/.rhosts");
553 /* Change effective uid while reading .rhosts. If root and
554 reading an NFS mounted file system, can't read files that
555 are protected read/write owner only. */
556 uid = __geteuid ();
557 seteuid (pwd->pw_uid);
558 hostf = iruserfopen (pbuf, pwd->pw_uid);
560 if (hostf != NULL)
562 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
563 fclose (hostf);
566 seteuid (uid);
567 return isbad;
569 return -1;
572 * ruserok_sa() is now discussed on ipng, so
573 * currently disabled for external use
575 static int
576 ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
577 const char *ruser, const char *luser)
579 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
582 /* This is the exported version. */
584 iruserok_af (const void *raddr, int superuser, const char *ruser,
585 const char *luser, sa_family_t af)
587 union {
588 struct sockaddr generic;
589 struct sockaddr_in in;
590 struct sockaddr_in6 in6;
591 } ra;
592 size_t ralen;
594 memset (&ra, '\0', sizeof(ra));
595 switch (af){
596 case AF_INET:
597 ra.in.sin_family = AF_INET;
598 memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
599 ralen = sizeof(struct sockaddr_in);
600 break;
601 case AF_INET6:
602 ra.in6.sin6_family = AF_INET6;
603 memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
604 ralen = sizeof(struct sockaddr_in6);
605 break;
606 default:
607 return 0;
609 return ruserok_sa (&ra.generic, ralen, superuser, ruser, luser);
611 libc_hidden_def (iruserok_af)
614 iruserok (u_int32_t raddr, int superuser, const char *ruser, const char *luser)
616 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
620 * XXX
621 * Don't make static, used by lpd(8).
623 * This function is not used anymore. It is only present because lpd(8)
624 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
625 * argument. This means that netgroups won't work in .rhost/hosts.equiv
626 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
627 * or PAM.
628 * Returns 0 if ok, -1 if not ok.
631 __ivaliduser (FILE *hostf, u_int32_t raddr, const char *luser,
632 const char *ruser)
634 struct sockaddr_in ra;
635 memset(&ra, '\0', sizeof(ra));
636 ra.sin_family = AF_INET;
637 ra.sin_addr.s_addr = raddr;
638 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
639 luser, ruser, "-");
643 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
644 static int
645 internal_function
646 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
647 const char *rhost)
649 struct addrinfo hints, *res0, *res;
650 char raddr[INET6_ADDRSTRLEN];
651 int match;
652 int negate=1; /* Multiply return with this to get -1 instead of 1 */
654 /* Check nis netgroup. */
655 if (strncmp ("+@", lhost, 2) == 0)
656 return innetgr (&lhost[2], rhost, NULL, NULL);
658 if (strncmp ("-@", lhost, 2) == 0)
659 return -innetgr (&lhost[2], rhost, NULL, NULL);
661 /* -host */
662 if (strncmp ("-", lhost,1) == 0) {
663 negate = -1;
664 lhost++;
665 } else if (strcmp ("+",lhost) == 0) {
666 return 1; /* asking for trouble, but ok.. */
669 /* Try for raw ip address first. */
670 /* XXX */
671 if (getnameinfo(ra, ralen,
672 raddr, sizeof(raddr), NULL, 0,
673 NI_NUMERICHOST) == 0
674 && strcmp(raddr, lhost) == 0)
675 return negate;
677 /* Better be a hostname. */
678 match = 0;
679 memset(&hints, '\0', sizeof(hints));
680 hints.ai_family = ra->sa_family;
681 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
682 /* Spin through ip addresses. */
683 for (res = res0; res; res = res->ai_next)
685 if (res->ai_family == ra->sa_family
686 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
688 match = 1;
689 break;
692 freeaddrinfo (res0);
694 return negate * match;
697 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
698 static int
699 internal_function
700 __icheckuser (const char *luser, const char *ruser)
703 luser is user entry from .rhosts/hosts.equiv file
704 ruser is user id on remote host
707 /* [-+]@netgroup */
708 if (strncmp ("+@", luser, 2) == 0)
709 return innetgr (&luser[2], NULL, ruser, NULL);
711 if (strncmp ("-@", luser,2) == 0)
712 return -innetgr (&luser[2], NULL, ruser, NULL);
714 /* -user */
715 if (strncmp ("-", luser, 1) == 0)
716 return -(strcmp (&luser[1], ruser) == 0);
718 /* + */
719 if (strcmp ("+", luser) == 0)
720 return 1;
722 /* simple string match */
723 return strcmp (ruser, luser) == 0;
727 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
729 static int
730 __isempty (char *p)
732 while (*p && isspace (*p)) {
733 ++p;
736 return (*p == '\0' || *p == '#') ? 1 : 0 ;
740 * Returns 0 if positive match, -1 if _not_ ok.
742 static int
743 __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
744 const char *luser, const char *ruser, const char *rhost)
746 const char *user;
747 char *p;
748 int hcheck, ucheck;
749 char *buf = NULL;
750 size_t bufsize = 0;
751 int retval = -1;
753 while (__getline (&buf, &bufsize, hostf) > 0) {
754 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
755 p = buf;
757 /* Skip empty or comment lines */
758 if (__isempty (p)) {
759 continue;
762 for (;*p && !isspace(*p); ++p) {
763 *p = _tolower (*p);
766 /* Next we want to find the permitted name for the remote user. */
767 if (*p == ' ' || *p == '\t') {
768 /* <nul> terminate hostname and skip spaces */
769 for (*p++='\0'; *p && isspace (*p); ++p);
771 user = p; /* this is the user's name */
772 while (*p && !isspace (*p))
773 ++p; /* find end of user's name */
774 } else
775 user = p;
777 *p = '\0'; /* <nul> terminate username (+host?) */
779 /* buf -> host(?) ; user -> username(?) */
780 if (*buf == '\0')
781 break;
782 if (*user == '\0')
783 user = luser;
785 /* First check the user part. In a naive implementation we
786 would check the host part first, then the user. However,
787 if we check the user first and reject the entry we will
788 have saved doing any host lookups to normalize the comparison
789 and that likely saves several DNS queries. Therefore we
790 check the user first. */
791 ucheck = __icheckuser (user, ruser);
793 /* Either we found the user, or we didn't and this is a
794 negative host check. We must do the negative host lookup
795 in order to preserve the semantics of stopping on this line
796 before processing others. */
797 if (ucheck != 0 || *buf == '-') {
799 /* Next check host part. */
800 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
802 /* Negative '-host user(?)' match? */
803 if (hcheck < 0)
804 break;
806 /* Positive 'host user' match? */
807 if (hcheck > 0 && ucheck > 0) {
808 retval = 0;
809 break;
812 /* Negative 'host -user' match? */
813 if (hcheck > 0 && ucheck < 0)
814 break;
816 /* Neither, go on looking for match. */
820 free (buf);
822 return retval;