Update.
[glibc.git] / inet / rcmd.c
blob758f6c953b21fd7c1ce962c85ea102b01551c0ff
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 <ctype.h>
79 #include <string.h>
80 #include <libintl.h>
81 #include <stdlib.h>
84 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
85 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
86 const char *, const char *, const char *);
87 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
88 int superuser, const char *ruser,
89 const char *luser, const char *rhost);
90 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
91 int superuser, const char *ruser,
92 const char *luser);
93 int iruserok_af (const void *raddr, int superuser, const char *ruser,
94 const char *luser, sa_family_t af);
95 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
96 const char *luser);
98 static char ahostbuf[NI_MAXHOST];
101 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
102 char **ahost;
103 u_short rport;
104 const char *locuser, *remuser, *cmd;
105 int *fd2p;
106 sa_family_t af;
108 char paddr[INET6_ADDRSTRLEN];
109 struct addrinfo hints, *res, *ai;
110 struct sockaddr_storage from;
111 struct pollfd pfd[2];
112 int32_t oldmask;
113 pid_t pid;
114 int s, lport, timo, error;
115 char c;
116 int refused;
117 char num[8];
118 ssize_t n;
120 if (af != AF_INET && af != AF_INET6)
122 __set_errno (EAFNOSUPPORT);
123 return -1;
126 pid = __getpid();
128 memset(&hints, '\0', sizeof(hints));
129 hints.ai_flags = AI_CANONNAME;
130 hints.ai_family = af;
131 hints.ai_socktype = SOCK_STREAM;
132 (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
133 error = getaddrinfo(*ahost, num, &hints, &res);
134 if (error) {
135 fprintf(stderr, "rcmd: getaddrinfo: %s\n",
136 gai_strerror(error));
137 return (-1);
140 pfd[0].events = POLLIN;
141 pfd[1].events = POLLIN;
143 if (res->ai_canonname){
144 strncpy(ahostbuf, res->ai_canonname, sizeof(ahostbuf));
145 ahostbuf[sizeof(ahostbuf)-1] = '\0';
146 *ahost = ahostbuf;
148 else
149 *ahost = NULL;
150 ai = res;
151 refused = 0;
152 oldmask = __sigblock(sigmask(SIGURG));
153 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
154 s = rresvport_af(&lport, ai->ai_family);
155 if (s < 0) {
156 if (errno == EAGAIN)
157 fprintf(stderr,
158 _("rcmd: socket: All ports in use\n"));
159 else
160 fprintf(stderr, "rcmd: socket: %m\n");
161 __sigsetmask(oldmask);
162 freeaddrinfo(res);
163 return -1;
165 __fcntl(s, F_SETOWN, pid);
166 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
167 break;
168 (void)__close(s);
169 if (errno == EADDRINUSE) {
170 lport--;
171 continue;
173 if (errno == ECONNREFUSED)
174 refused = 1;
175 if (ai->ai_next != NULL) {
176 int oerrno = errno;
178 getnameinfo(ai->ai_addr, ai->ai_addrlen,
179 paddr, sizeof(paddr),
180 NULL, 0,
181 NI_NUMERICHOST);
182 fprintf(stderr, "connect to address %s: ", paddr);
183 __set_errno (oerrno);
184 perror(0);
185 ai = ai->ai_next;
186 getnameinfo(ai->ai_addr, ai->ai_addrlen,
187 paddr, sizeof(paddr),
188 NULL, 0,
189 NI_NUMERICHOST);
190 fprintf(stderr, "Trying %s...\n", paddr);
191 continue;
193 if (refused && timo <= 16) {
194 (void)sleep(timo);
195 timo *= 2;
196 ai = res;
197 refused = 0;
198 continue;
200 freeaddrinfo(res);
201 (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno));
202 __sigsetmask(oldmask);
203 return -1;
205 lport--;
206 if (fd2p == 0) {
207 __write(s, "", 1);
208 lport = 0;
209 } else {
210 char num[8];
211 int s2 = rresvport_af(&lport, ai->ai_family), s3;
212 size_t len = ai->ai_addrlen;
214 if (s2 < 0)
215 goto bad;
216 listen(s2, 1);
217 (void)__snprintf(num, sizeof(num), "%d", lport);
218 if (__write(s, num, strlen(num)+1) != strlen(num)+1) {
219 (void)fprintf(stderr,
220 _("rcmd: write (setting up stderr): %m\n"));
221 (void)__close(s2);
222 goto bad;
224 pfd[0].fd = s;
225 pfd[1].fd = s2;
226 __set_errno (0);
227 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
228 if (errno != 0)
229 (void)fprintf(stderr,
230 _("rcmd: poll (setting up stderr): %m\n"));
231 else
232 (void)fprintf(stderr,
233 _("poll: protocol failure in circuit setup\n"));
234 (void)__close(s2);
235 goto bad;
237 s3 = accept(s2, (struct sockaddr *)&from, &len);
238 switch (from.__ss_family) {
239 case AF_INET:
240 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
241 break;
242 case AF_INET6:
243 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
244 break;
245 default:
246 rport = 0;
247 break;
249 (void)__close(s2);
250 if (s3 < 0) {
251 (void)fprintf(stderr,
252 "rcmd: accept: %m\n");
253 lport = 0;
254 goto bad;
256 *fd2p = s3;
258 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
259 (void)fprintf(stderr,
260 _("socket: protocol failure in circuit setup\n"));
261 goto bad2;
264 (void)__write(s, locuser, strlen(locuser)+1);
265 (void)__write(s, remuser, strlen(remuser)+1);
266 (void)__write(s, cmd, strlen(cmd)+1);
267 n = __read(s, &c, 1);
268 if (n != 1) {
269 if (n == 0)
270 (void)fprintf(stderr, _("rcmd: %s: short read"),
271 *ahost);
272 else
273 (void)fprintf(stderr, "rcmd: %s: %m\n", *ahost);
274 goto bad2;
276 if (c != 0) {
277 while (__read(s, &c, 1) == 1) {
278 (void)__write(STDERR_FILENO, &c, 1);
279 if (c == '\n')
280 break;
282 goto bad2;
284 __sigsetmask(oldmask);
285 freeaddrinfo(res);
286 return s;
287 bad2:
288 if (lport)
289 (void)__close(*fd2p);
290 bad:
291 (void)__close(s);
292 __sigsetmask(oldmask);
293 freeaddrinfo(res);
294 return -1;
298 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
299 char **ahost;
300 u_short rport;
301 const char *locuser, *remuser, *cmd;
302 int *fd2p;
304 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
308 rresvport_af(alport, family)
309 int *alport;
310 sa_family_t family;
312 struct sockaddr_storage ss;
313 int s;
314 size_t len;
315 uint16_t *sport;
317 switch(family){
318 case AF_INET:
319 len = sizeof(struct sockaddr_in);
320 sport = &((struct sockaddr_in *)&ss)->sin_port;
321 break;
322 case AF_INET6:
323 len = sizeof(struct sockaddr_in6);
324 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
325 break;
326 default:
327 __set_errno (EAFNOSUPPORT);
328 return -1;
330 s = socket(family, SOCK_STREAM, 0);
331 if (s < 0)
332 return -1;
334 memset (&ss, '\0', sizeof(ss));
335 #ifdef SALEN
336 ss.__ss_len = len;
337 #endif
338 ss.__ss_family = family;
340 for (;;) {
341 *sport = htons((uint16_t) *alport);
342 if (bind(s, (struct sockaddr *)&ss, len) >= 0)
343 return s;
344 if (errno != EADDRINUSE) {
345 (void)__close(s);
346 return -1;
348 (*alport)--;
349 if (*alport == IPPORT_RESERVED/2)
350 break;
352 (void)__close(s);
353 __set_errno (EAGAIN);
354 return -1;
358 rresvport(alport)
359 int *alport;
361 return rresvport_af(alport, AF_INET);
364 int __check_rhosts_file = 1;
365 char *__rcmd_errstr;
368 ruserok_af(rhost, superuser, ruser, luser, af)
369 const char *rhost, *ruser, *luser;
370 int superuser;
371 sa_family_t af;
373 struct addrinfo hints, *res, *res0;
374 int gai;
375 int ret;
377 memset (&hints, '\0', sizeof(hints));
378 hints.ai_family = af;
379 gai = getaddrinfo(rhost, NULL, &hints, &res0);
380 if (gai)
381 return -1;
382 ret = -1;
383 for (res=res0; res; res=res->ai_next)
384 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
385 superuser, ruser, luser, rhost) == 0){
386 ret = 0;
387 break;
389 freeaddrinfo(res0);
390 return (ret);
393 ruserok(rhost, superuser, ruser, luser)
394 const char *rhost, *ruser, *luser;
395 int superuser;
397 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
400 /* Extremely paranoid file open function. */
401 static FILE *
402 iruserfopen (const char *file, uid_t okuser)
404 struct stat st;
405 char *cp = NULL;
406 FILE *res = NULL;
408 /* If not a regular file, if owned by someone other than user or
409 root, if writeable by anyone but the owner, or if hardlinked
410 anywhere, quit. */
411 cp = NULL;
412 if (__lxstat (_STAT_VER, file, &st))
413 cp = _("lstat failed");
414 else if (!S_ISREG (st.st_mode))
415 cp = _("not regular file");
416 else
418 res = fopen (file, "r");
419 if (!res)
420 cp = _("cannot open");
421 else if (__fxstat (_STAT_VER, fileno (res), &st) < 0)
422 cp = _("fstat failed");
423 else if (st.st_uid && st.st_uid != okuser)
424 cp = _("bad owner");
425 else if (st.st_mode & (S_IWGRP|S_IWOTH))
426 cp = _("writeable by other than owner");
427 else if (st.st_nlink > 1)
428 cp = _("hard linked somewhere");
431 /* If there were any problems, quit. */
432 if (cp != NULL)
434 __rcmd_errstr = cp;
435 if (res)
436 fclose (res);
437 return NULL;
440 return res;
444 * New .rhosts strategy: We are passed an ip address. We spin through
445 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
446 * has ip addresses, we don't have to trust a nameserver. When it
447 * contains hostnames, we spin through the list of addresses the nameserver
448 * gives us and look for a match.
450 * Returns 0 if ok, -1 if not ok.
452 static int
453 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
454 struct sockaddr *ra;
455 size_t ralen;
456 int superuser;
457 const char *ruser, *luser, *rhost;
459 FILE *hostf = NULL;
460 int isbad = -1;
462 if (!superuser)
463 hostf = iruserfopen (_PATH_HEQUIV, 0);
465 if (hostf)
467 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
468 fclose (hostf);
470 if (!isbad)
471 return 0;
474 if (__check_rhosts_file || superuser)
476 char *pbuf;
477 struct passwd pwdbuf, *pwd;
478 size_t dirlen;
479 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
480 char *buffer = __alloca (buflen);
481 uid_t uid;
483 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
484 || pwd == NULL)
485 return -1;
487 dirlen = strlen (pwd->pw_dir);
488 pbuf = alloca (dirlen + sizeof "/.rhosts");
489 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
490 "/.rhosts", sizeof "/.rhosts");
492 /* Change effective uid while reading .rhosts. If root and
493 reading an NFS mounted file system, can't read files that
494 are protected read/write owner only. */
495 uid = __geteuid ();
496 seteuid (pwd->pw_uid);
497 hostf = iruserfopen (pbuf, pwd->pw_uid);
499 if (hostf != NULL)
501 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
502 fclose (hostf);
505 seteuid (uid);
506 return isbad;
508 return -1;
511 * ruserok_sa() is now discussed on ipng, so
512 * currently disabled for external use
514 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
515 struct sockaddr *ra;
516 size_t ralen;
517 int superuser;
518 const char *ruser, *luser;
520 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
523 /* This is the exported version. */
525 iruserok_af (raddr, superuser, ruser, luser, af)
526 const void *raddr;
527 int superuser;
528 const char *ruser, *luser;
529 sa_family_t af;
531 struct sockaddr_storage ra;
532 size_t ralen;
534 memset (&ra, '\0', sizeof(ra));
535 switch (af){
536 case AF_INET:
537 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
538 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
539 sizeof(struct in_addr));
540 ralen = sizeof(struct sockaddr_in);
541 break;
542 case AF_INET6:
543 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
544 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
545 sizeof(struct in6_addr));
546 ralen = sizeof(struct sockaddr_in6);
547 break;
548 default:
549 return 0;
551 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
554 iruserok (raddr, superuser, ruser, luser)
555 u_int32_t raddr;
556 int superuser;
557 const char *ruser, *luser;
559 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
563 * XXX
564 * Don't make static, used by lpd(8).
566 * This function is not used anymore. It is only present because lpd(8)
567 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
568 * argument. This means that netgroups won't work in .rhost/hosts.equiv
569 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
570 * or PAM.
571 * Returns 0 if ok, -1 if not ok.
574 __ivaliduser(hostf, raddr, luser, ruser)
575 FILE *hostf;
576 u_int32_t raddr;
577 const char *luser, *ruser;
579 struct sockaddr_in ra;
580 memset(&ra, '\0', sizeof(ra));
581 ra.sin_family = AF_INET;
582 ra.sin_addr.s_addr = raddr;
583 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
584 luser, ruser, "-");
588 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
589 static int
590 internal_function
591 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
592 const char *rhost)
594 struct addrinfo hints, *res0, *res;
595 char raddr[INET6_ADDRSTRLEN];
596 int match;
597 int negate=1; /* Multiply return with this to get -1 instead of 1 */
599 /* Check nis netgroup. */
600 if (strncmp ("+@", lhost, 2) == 0)
601 return innetgr (&lhost[2], rhost, NULL, NULL);
603 if (strncmp ("-@", lhost, 2) == 0)
604 return -innetgr (&lhost[2], rhost, NULL, NULL);
606 /* -host */
607 if (strncmp ("-", lhost,1) == 0) {
608 negate = -1;
609 lhost++;
610 } else if (strcmp ("+",lhost) == 0) {
611 return 1; /* asking for trouble, but ok.. */
614 /* Try for raw ip address first. */
615 /* XXX */
616 if (getnameinfo(ra, ralen,
617 raddr, sizeof(raddr), NULL, 0,
618 NI_NUMERICHOST) == 0)
619 return negate * (strcmp(raddr, lhost) == 0);
621 /* Better be a hostname. */
622 match = 0;
623 memset(&hints, '\0', sizeof(hints));
624 hints.ai_family = ra->sa_family;
625 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
626 /* Spin through ip addresses. */
627 for (res = res0; res; res = res->ai_next)
629 if (res->ai_family == ra->sa_family
630 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
632 match = 1;
633 break;
636 freeaddrinfo (res0);
638 return negate * match;
641 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
642 static int
643 internal_function
644 __icheckuser (const char *luser, const char *ruser)
647 luser is user entry from .rhosts/hosts.equiv file
648 ruser is user id on remote host
651 /* [-+]@netgroup */
652 if (strncmp ("+@", luser, 2) == 0)
653 return innetgr (&luser[2], NULL, ruser, NULL);
655 if (strncmp ("-@", luser,2) == 0)
656 return -innetgr (&luser[2], NULL, ruser, NULL);
658 /* -user */
659 if (strncmp ("-", luser, 1) == 0)
660 return -(strcmp (&luser[1], ruser) == 0);
662 /* + */
663 if (strcmp ("+", luser) == 0)
664 return 1;
666 /* simple string match */
667 return strcmp (ruser, luser) == 0;
671 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
673 static int
674 __isempty (char *p)
676 while (*p && isspace (*p)) {
677 ++p;
680 return (*p == '\0' || *p == '#') ? 1 : 0 ;
684 * Returns 0 if positive match, -1 if _not_ ok.
686 static int
687 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
688 FILE *hostf;
689 struct sockaddr *ra;
690 size_t ralen;
691 const char *luser, *ruser, *rhost;
693 register const char *user;
694 register char *p;
695 int hcheck, ucheck;
696 char *buf = NULL;
697 size_t bufsize = 0;
698 int retval = -1;
700 while (__getline (&buf, &bufsize, hostf) > 0) {
701 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
702 p = buf;
704 /* Skip empty or comment lines */
705 if (__isempty (p)) {
706 continue;
709 /* Skip lines that are too long. */
710 if (strchr (p, '\n') == NULL) {
711 int ch = getc_unlocked (hostf);
713 while (ch != '\n' && ch != EOF)
714 ch = getc_unlocked (hostf);
715 continue;
718 for (;*p && !isspace(*p); ++p) {
719 *p = _tolower (*p);
722 /* Next we want to find the permitted name for the remote user. */
723 if (*p == ' ' || *p == '\t') {
724 /* <nul> terminate hostname and skip spaces */
725 for (*p++='\0'; *p && isspace (*p); ++p);
727 user = p; /* this is the user's name */
728 while (*p && !isspace (*p))
729 ++p; /* find end of user's name */
730 } else
731 user = p;
733 *p = '\0'; /* <nul> terminate username (+host?) */
735 /* buf -> host(?) ; user -> username(?) */
737 /* First check host part */
738 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
740 if (hcheck < 0)
741 break;
743 if (hcheck) {
744 /* Then check user part */
745 if (! (*user))
746 user = luser;
748 ucheck = __icheckuser (user, ruser);
750 /* Positive 'host user' match? */
751 if (ucheck > 0) {
752 retval = 0;
753 break;
756 /* Negative 'host -user' match? */
757 if (ucheck < 0)
758 break;
760 /* Neither, go on looking for match */
764 if (buf != NULL)
765 free (buf);
767 return retval;