Convert 29 more function definitions to prototype style (multiple parameters in one...
[glibc.git] / inet / rcmd.c
blobace6b14a939bf8efeff7e7947230eee0b74c1210
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 #include <wchar.h>
84 #include <sys/uio.h>
87 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
88 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
89 const char *, const char *, const char *);
90 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
91 int superuser, const char *ruser,
92 const char *luser, const char *rhost);
93 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
94 int superuser, const char *ruser,
95 const char *luser);
96 int iruserok_af (const void *raddr, int superuser, const char *ruser,
97 const char *luser, sa_family_t af);
98 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
99 const char *luser);
101 libc_hidden_proto (iruserok_af)
103 libc_freeres_ptr(static char *ahostbuf);
106 rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
107 const char *cmd, int *fd2p, sa_family_t af)
109 char paddr[INET6_ADDRSTRLEN];
110 struct addrinfo hints, *res, *ai;
111 union
113 struct sockaddr sa;
114 struct sockaddr_storage ss;
115 struct sockaddr_in sin;
116 struct sockaddr_in6 sin6;
117 } 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 if (error == EAI_NONAME && *ahost != NULL)
143 __fxprintf(NULL, "%s: Unknown host\n", *ahost);
144 else
145 __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
146 gai_strerror(error));
148 return -1;
151 pfd[0].events = POLLIN;
152 pfd[1].events = POLLIN;
154 if (res->ai_canonname){
155 free (ahostbuf);
156 ahostbuf = strdup (res->ai_canonname);
157 if (ahostbuf == NULL) {
158 __fxprintf(NULL, "%s",
159 _("rcmd: Cannot allocate memory\n"));
160 return -1;
162 *ahost = ahostbuf;
163 } else
164 *ahost = NULL;
165 ai = res;
166 refused = 0;
167 oldmask = __sigblock(sigmask(SIGURG));
168 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
169 char errbuf[200];
171 s = rresvport_af(&lport, ai->ai_family);
172 if (s < 0) {
173 if (errno == EAGAIN)
174 __fxprintf(NULL, "%s", _("\
175 rcmd: socket: All ports in use\n"));
176 else
177 __fxprintf(NULL, "rcmd: socket: %m\n");
179 __sigsetmask(oldmask);
180 freeaddrinfo(res);
181 return -1;
183 __fcntl(s, F_SETOWN, pid);
184 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
185 break;
186 (void)__close(s);
187 if (errno == EADDRINUSE) {
188 lport--;
189 continue;
191 if (errno == ECONNREFUSED)
192 refused = 1;
193 if (ai->ai_next != NULL) {
194 int oerrno = errno;
195 char *buf = NULL;
197 getnameinfo(ai->ai_addr, ai->ai_addrlen,
198 paddr, sizeof(paddr),
199 NULL, 0,
200 NI_NUMERICHOST);
202 if (__asprintf (&buf, _("connect to address %s: "),
203 paddr) >= 0)
205 __fxprintf(NULL, "%s", buf);
206 free (buf);
208 __set_errno (oerrno);
209 perror(0);
210 ai = ai->ai_next;
211 getnameinfo(ai->ai_addr, ai->ai_addrlen,
212 paddr, sizeof(paddr),
213 NULL, 0,
214 NI_NUMERICHOST);
215 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
217 __fxprintf (NULL, "%s", buf);
218 free (buf);
220 continue;
222 if (refused && timo <= 16) {
223 (void)__sleep(timo);
224 timo *= 2;
225 ai = res;
226 refused = 0;
227 continue;
229 freeaddrinfo(res);
230 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
231 __strerror_r(errno, errbuf, sizeof (errbuf)));
232 __sigsetmask(oldmask);
233 return -1;
235 lport--;
236 if (fd2p == 0) {
237 __write(s, "", 1);
238 lport = 0;
239 } else {
240 char num[8];
241 int s2 = rresvport_af(&lport, ai->ai_family), s3;
242 socklen_t len = ai->ai_addrlen;
244 if (s2 < 0)
245 goto bad;
246 __listen(s2, 1);
247 (void)__snprintf(num, sizeof(num), "%d", lport);
248 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
249 char *buf = NULL;
251 if (__asprintf (&buf, _("\
252 rcmd: write (setting up stderr): %m\n")) >= 0)
254 __fxprintf(NULL, "%s", buf);
255 free (buf);
257 (void)__close(s2);
258 goto bad;
260 pfd[0].fd = s;
261 pfd[1].fd = s2;
262 __set_errno (0);
263 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
264 char *buf = NULL;
266 if ((errno != 0
267 && __asprintf(&buf, _("\
268 rcmd: poll (setting up stderr): %m\n")) >= 0)
269 || (errno == 0
270 && __asprintf(&buf, _("\
271 poll: protocol failure in circuit setup\n")) >= 0))
273 __fxprintf (NULL, "%s", buf);
274 free (buf);
276 (void)__close(s2);
277 goto bad;
279 s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
280 switch (from.sa.sa_family) {
281 case AF_INET:
282 rport = ntohs(from.sin.sin_port);
283 break;
284 case AF_INET6:
285 rport = ntohs(from.sin6.sin6_port);
286 break;
287 default:
288 rport = 0;
289 break;
291 (void)__close(s2);
292 if (s3 < 0) {
293 (void)__fxprintf(NULL, "rcmd: accept: %m\n");
294 lport = 0;
295 goto bad;
297 *fd2p = s3;
299 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
300 char *buf = NULL;
302 if (__asprintf(&buf, _("\
303 socket: protocol failure in circuit setup\n")) >= 0)
305 __fxprintf (NULL, "%s", buf);
306 free (buf);
308 goto bad2;
311 struct iovec iov[3] =
313 [0] = { .iov_base = (void *) locuser,
314 .iov_len = strlen (locuser) + 1 },
315 [1] = { .iov_base = (void *) remuser,
316 .iov_len = strlen (remuser) + 1 },
317 [2] = { .iov_base = (void *) cmd,
318 .iov_len = strlen (cmd) + 1 }
320 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
321 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
322 if (n != 1) {
323 char *buf = NULL;
325 if ((n == 0
326 && __asprintf(&buf, _("rcmd: %s: short read"),
327 *ahost) >= 0)
328 || (n != 0
329 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
331 __fxprintf (NULL, "%s", buf);
332 free (buf);
334 goto bad2;
336 if (c != 0) {
337 while (__read(s, &c, 1) == 1) {
338 (void)__write(STDERR_FILENO, &c, 1);
339 if (c == '\n')
340 break;
342 goto bad2;
344 __sigsetmask(oldmask);
345 freeaddrinfo(res);
346 return s;
347 bad2:
348 if (lport)
349 (void)__close(*fd2p);
350 bad:
351 (void)__close(s);
352 __sigsetmask(oldmask);
353 freeaddrinfo(res);
354 return -1;
356 libc_hidden_def (rcmd_af)
359 rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
360 const char *cmd, int *fd2p)
362 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
366 rresvport_af (int *alport, sa_family_t family)
368 union {
369 struct sockaddr generic;
370 struct sockaddr_in in;
371 struct sockaddr_in6 in6;
372 } ss;
373 int s;
374 size_t len;
375 uint16_t *sport;
377 switch(family){
378 case AF_INET:
379 len = sizeof(struct sockaddr_in);
380 sport = &ss.in.sin_port;
381 break;
382 case AF_INET6:
383 len = sizeof(struct sockaddr_in6);
384 sport = &ss.in6.sin6_port;
385 break;
386 default:
387 __set_errno (EAFNOSUPPORT);
388 return -1;
390 s = __socket(family, SOCK_STREAM, 0);
391 if (s < 0)
392 return -1;
394 memset (&ss, '\0', sizeof(ss));
395 #ifdef SALEN
396 ss.generic.__ss_len = len;
397 #endif
398 ss.generic.sa_family = family;
400 /* Ignore invalid values. */
401 if (*alport < IPPORT_RESERVED / 2)
402 *alport = IPPORT_RESERVED / 2;
403 else if (*alport >= IPPORT_RESERVED)
404 *alport = IPPORT_RESERVED - 1;
406 int start = *alport;
407 do {
408 *sport = htons((uint16_t) *alport);
409 if (__bind(s, &ss.generic, len) >= 0)
410 return s;
411 if (errno != EADDRINUSE) {
412 (void)__close(s);
413 return -1;
415 if ((*alport)-- == IPPORT_RESERVED/2)
416 *alport = IPPORT_RESERVED - 1;
417 } while (*alport != start);
418 (void)__close(s);
419 __set_errno (EAGAIN);
420 return -1;
422 libc_hidden_def (rresvport_af)
425 rresvport (int *alport)
427 return rresvport_af(alport, AF_INET);
430 int __check_rhosts_file = 1;
431 char *__rcmd_errstr;
434 ruserok_af (const char *rhost, int superuser, const char *ruser,
435 const char *luser, sa_family_t af)
437 struct addrinfo hints, *res, *res0;
438 int gai;
439 int ret;
441 memset (&hints, '\0', sizeof(hints));
442 hints.ai_family = af;
443 gai = getaddrinfo(rhost, NULL, &hints, &res0);
444 if (gai)
445 return -1;
446 ret = -1;
447 for (res=res0; res; res=res->ai_next)
448 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
449 superuser, ruser, luser, rhost) == 0){
450 ret = 0;
451 break;
453 freeaddrinfo(res0);
454 return (ret);
456 libc_hidden_def (ruserok_af)
459 ruserok (const char *rhost, int superuser, const char *ruser,
460 const char *luser)
462 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
465 /* Extremely paranoid file open function. */
466 static FILE *
467 iruserfopen (const char *file, uid_t okuser)
469 struct stat64 st;
470 char *cp = NULL;
471 FILE *res = NULL;
473 /* If not a regular file, if owned by someone other than user or
474 root, if writeable by anyone but the owner, or if hardlinked
475 anywhere, quit. */
476 if (__lxstat64 (_STAT_VER, file, &st))
477 cp = _("lstat failed");
478 else if (!S_ISREG (st.st_mode))
479 cp = _("not regular file");
480 else
482 res = fopen (file, "rce");
483 if (!res)
484 cp = _("cannot open");
485 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
486 cp = _("fstat failed");
487 else if (st.st_uid && st.st_uid != okuser)
488 cp = _("bad owner");
489 else if (st.st_mode & (S_IWGRP|S_IWOTH))
490 cp = _("writeable by other than owner");
491 else if (st.st_nlink > 1)
492 cp = _("hard linked somewhere");
495 /* If there were any problems, quit. */
496 if (cp != NULL)
498 __rcmd_errstr = cp;
499 if (res)
500 fclose (res);
501 return NULL;
504 /* No threads use this stream. */
505 __fsetlocking (res, FSETLOCKING_BYCALLER);
507 return res;
511 * New .rhosts strategy: We are passed an ip address. We spin through
512 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
513 * has ip addresses, we don't have to trust a nameserver. When it
514 * contains hostnames, we spin through the list of addresses the nameserver
515 * gives us and look for a match.
517 * Returns 0 if ok, -1 if not ok.
519 static int
520 ruserok2_sa (struct sockaddr *ra, size_t ralen, int superuser,
521 const char *ruser, const char *luser, const char *rhost)
523 FILE *hostf = NULL;
524 int isbad = -1;
526 if (!superuser)
527 hostf = iruserfopen (_PATH_HEQUIV, 0);
529 if (hostf)
531 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
532 fclose (hostf);
534 if (!isbad)
535 return 0;
538 if (__check_rhosts_file || superuser)
540 char *pbuf;
541 struct passwd pwdbuf, *pwd;
542 size_t dirlen;
543 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
544 char *buffer = __alloca (buflen);
545 uid_t uid;
547 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
548 || pwd == NULL)
549 return -1;
551 dirlen = strlen (pwd->pw_dir);
552 pbuf = alloca (dirlen + sizeof "/.rhosts");
553 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
554 "/.rhosts", sizeof "/.rhosts");
556 /* Change effective uid while reading .rhosts. If root and
557 reading an NFS mounted file system, can't read files that
558 are protected read/write owner only. */
559 uid = __geteuid ();
560 seteuid (pwd->pw_uid);
561 hostf = iruserfopen (pbuf, pwd->pw_uid);
563 if (hostf != NULL)
565 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
566 fclose (hostf);
569 seteuid (uid);
570 return isbad;
572 return -1;
575 * ruserok_sa() is now discussed on ipng, so
576 * currently disabled for external use
578 static int
579 ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
580 const char *ruser, const char *luser)
582 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
585 /* This is the exported version. */
587 iruserok_af (const void *raddr, int superuser, const char *ruser,
588 const char *luser, sa_family_t af)
590 union {
591 struct sockaddr generic;
592 struct sockaddr_in in;
593 struct sockaddr_in6 in6;
594 } ra;
595 size_t ralen;
597 memset (&ra, '\0', sizeof(ra));
598 switch (af){
599 case AF_INET:
600 ra.in.sin_family = AF_INET;
601 memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
602 ralen = sizeof(struct sockaddr_in);
603 break;
604 case AF_INET6:
605 ra.in6.sin6_family = AF_INET6;
606 memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
607 ralen = sizeof(struct sockaddr_in6);
608 break;
609 default:
610 return 0;
612 return ruserok_sa (&ra.generic, ralen, superuser, ruser, luser);
614 libc_hidden_def (iruserok_af)
617 iruserok (u_int32_t raddr, int superuser, const char *ruser, const char *luser)
619 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
623 * XXX
624 * Don't make static, used by lpd(8).
626 * This function is not used anymore. It is only present because lpd(8)
627 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
628 * argument. This means that netgroups won't work in .rhost/hosts.equiv
629 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
630 * or PAM.
631 * Returns 0 if ok, -1 if not ok.
634 __ivaliduser (FILE *hostf, u_int32_t raddr, const char *luser,
635 const char *ruser)
637 struct sockaddr_in ra;
638 memset(&ra, '\0', sizeof(ra));
639 ra.sin_family = AF_INET;
640 ra.sin_addr.s_addr = raddr;
641 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
642 luser, ruser, "-");
646 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
647 static int
648 internal_function
649 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
650 const char *rhost)
652 struct addrinfo hints, *res0, *res;
653 char raddr[INET6_ADDRSTRLEN];
654 int match;
655 int negate=1; /* Multiply return with this to get -1 instead of 1 */
657 /* Check nis netgroup. */
658 if (strncmp ("+@", lhost, 2) == 0)
659 return innetgr (&lhost[2], rhost, NULL, NULL);
661 if (strncmp ("-@", lhost, 2) == 0)
662 return -innetgr (&lhost[2], rhost, NULL, NULL);
664 /* -host */
665 if (strncmp ("-", lhost,1) == 0) {
666 negate = -1;
667 lhost++;
668 } else if (strcmp ("+",lhost) == 0) {
669 return 1; /* asking for trouble, but ok.. */
672 /* Try for raw ip address first. */
673 /* XXX */
674 if (getnameinfo(ra, ralen,
675 raddr, sizeof(raddr), NULL, 0,
676 NI_NUMERICHOST) == 0
677 && strcmp(raddr, lhost) == 0)
678 return negate;
680 /* Better be a hostname. */
681 match = 0;
682 memset(&hints, '\0', sizeof(hints));
683 hints.ai_family = ra->sa_family;
684 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
685 /* Spin through ip addresses. */
686 for (res = res0; res; res = res->ai_next)
688 if (res->ai_family == ra->sa_family
689 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
691 match = 1;
692 break;
695 freeaddrinfo (res0);
697 return negate * match;
700 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
701 static int
702 internal_function
703 __icheckuser (const char *luser, const char *ruser)
706 luser is user entry from .rhosts/hosts.equiv file
707 ruser is user id on remote host
710 /* [-+]@netgroup */
711 if (strncmp ("+@", luser, 2) == 0)
712 return innetgr (&luser[2], NULL, ruser, NULL);
714 if (strncmp ("-@", luser,2) == 0)
715 return -innetgr (&luser[2], NULL, ruser, NULL);
717 /* -user */
718 if (strncmp ("-", luser, 1) == 0)
719 return -(strcmp (&luser[1], ruser) == 0);
721 /* + */
722 if (strcmp ("+", luser) == 0)
723 return 1;
725 /* simple string match */
726 return strcmp (ruser, luser) == 0;
730 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
732 static int
733 __isempty (char *p)
735 while (*p && isspace (*p)) {
736 ++p;
739 return (*p == '\0' || *p == '#') ? 1 : 0 ;
743 * Returns 0 if positive match, -1 if _not_ ok.
745 static int
746 __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
747 const char *luser, const char *ruser, const char *rhost)
749 const char *user;
750 char *p;
751 int hcheck, ucheck;
752 char *buf = NULL;
753 size_t bufsize = 0;
754 int retval = -1;
756 while (__getline (&buf, &bufsize, hostf) > 0) {
757 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
758 p = buf;
760 /* Skip empty or comment lines */
761 if (__isempty (p)) {
762 continue;
765 for (;*p && !isspace(*p); ++p) {
766 *p = _tolower (*p);
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);
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;
780 *p = '\0'; /* <nul> terminate username (+host?) */
782 /* buf -> host(?) ; user -> username(?) */
783 if (*buf == '\0')
784 break;
785 if (*user == '\0')
786 user = luser;
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 (user, ruser);
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 == '-') {
802 /* Next check host part. */
803 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
805 /* Negative '-host user(?)' match? */
806 if (hcheck < 0)
807 break;
809 /* Positive 'host user' match? */
810 if (hcheck > 0 && ucheck > 0) {
811 retval = 0;
812 break;
815 /* Negative 'host -user' match? */
816 if (hcheck > 0 && ucheck < 0)
817 break;
819 /* Neither, go on looking for match. */
823 free (buf);
825 return retval;