OSDN Git Service

1bd511d26e790ca9bbc85ac199338bbc4255917c
[uclinux-h8/uClibc.git] / libc / inet / rpc / rcmd.c
1 /*
2  * Copyright (c) 1983, 1993, 1994
3  *      The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */ 
33
34 #if 0
35 static char sccsid[] = "@(#)rcmd.c      8.3 (Berkeley) 3/26/94";
36 #endif /* LIBC_SCCS and not lint */
37
38 #define __UCLIBC_HIDE_DEPRECATED__
39 #define __FORCE_GLIBC
40 #include <features.h>
41 #include <ctype.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <alloca.h>
47 #include <signal.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <pwd.h>
51 #include <sys/param.h>
52 #include <sys/poll.h>
53 #include <sys/socket.h>
54 #include <sys/stat.h>
55 #include <netdb.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58
59 libc_hidden_proto(memcmp)
60 libc_hidden_proto(strcat)
61 libc_hidden_proto(strchr)
62 libc_hidden_proto(strcmp)
63 libc_hidden_proto(strcpy)
64 libc_hidden_proto(strlen)
65 libc_hidden_proto(strncmp)
66 libc_hidden_proto(strnlen)
67 libc_hidden_proto(bcopy)
68 libc_hidden_proto(getpid)
69 libc_hidden_proto(socket)
70 libc_hidden_proto(close)
71 libc_hidden_proto(fcntl)
72 libc_hidden_proto(read)
73 libc_hidden_proto(write)
74 libc_hidden_proto(perror)
75 libc_hidden_proto(lstat)
76 libc_hidden_proto(fstat)
77 libc_hidden_proto(tolower)
78 libc_hidden_proto(sysconf)
79 libc_hidden_proto(getline)
80 libc_hidden_proto(geteuid)
81 libc_hidden_proto(seteuid)
82 libc_hidden_proto(getpwnam_r)
83 libc_hidden_proto(gethostbyname)
84 libc_hidden_proto(gethostbyname_r)
85 libc_hidden_proto(fileno)
86 libc_hidden_proto(sleep)
87 libc_hidden_proto(inet_addr)
88 libc_hidden_proto(inet_ntoa)
89 libc_hidden_proto(herror)
90 libc_hidden_proto(bind)
91 libc_hidden_proto(connect)
92 libc_hidden_proto(sigblock)
93 libc_hidden_proto(snprintf)
94 libc_hidden_proto(poll)
95 libc_hidden_proto(accept)
96 libc_hidden_proto(listen)
97 libc_hidden_proto(sigsetmask)
98 libc_hidden_proto(getc_unlocked)
99 libc_hidden_proto(__fgetc_unlocked)
100 libc_hidden_proto(fopen)
101 libc_hidden_proto(fclose)
102 libc_hidden_proto(fprintf)
103 libc_hidden_proto(__h_errno_location)
104 libc_hidden_proto(stderr)
105 #ifdef __UCLIBC_HAS_XLOCALE__
106 libc_hidden_proto(__ctype_b_loc)
107 libc_hidden_proto(__ctype_tolower_loc)
108 #else
109 libc_hidden_proto(__ctype_b)
110 libc_hidden_proto(__ctype_tolower)
111 #endif
112
113 libc_hidden_proto(rresvport)
114
115 /* some forward declarations */
116 static int __ivaliduser2(FILE *hostf, u_int32_t raddr,
117                          const char *luser, const char *ruser, const char *rhost);
118 static int iruserok2 (u_int32_t raddr, int superuser, const char *ruser, 
119                       const char *luser, const char *rhost);
120
121
122 int rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
123      char **ahost;
124      u_short rport;
125      const char *locuser, *remuser, *cmd;
126      int *fd2p;
127 {
128 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
129         int herr;
130         struct hostent hostbuf;
131         size_t hstbuflen;
132         char *tmphstbuf;
133 #endif
134         struct hostent *hp;
135         struct sockaddr_in sin, from;
136         struct pollfd pfd[2];
137         int32_t oldmask;
138         pid_t pid;
139         int s, lport, timo;
140         char c;
141
142         pid = getpid();
143
144 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
145         hstbuflen = 1024;
146 #ifdef __ARCH_HAS_MMU__
147         tmphstbuf = alloca (hstbuflen);
148 #else
149         tmphstbuf = malloc (hstbuflen);
150 #endif
151
152         while (gethostbyname_r (*ahost, &hostbuf, tmphstbuf, 
153                     hstbuflen, &hp, &herr) != 0 || hp == NULL)
154         {
155             if (herr != NETDB_INTERNAL || errno != ERANGE)
156             {
157                 __set_h_errno (herr);
158 #ifndef __ARCH_HAS_MMU__
159                 free(tmphstbuf);
160 #endif
161                 herror(*ahost);
162                 return -1;
163             }
164             else
165             {
166                 /* Enlarge the buffer.  */
167                 hstbuflen *= 2;
168 #ifdef __ARCH_HAS_MMU__
169                 tmphstbuf = alloca (hstbuflen);
170 #else
171                 if (tmphstbuf) {
172                     free(tmphstbuf);
173                 }
174                 tmphstbuf = malloc (hstbuflen);
175 #endif
176             }
177         }
178 #ifndef __ARCH_HAS_MMU__
179         free(tmphstbuf);
180 #endif
181 #else /* call the non-reentrant version */
182         if ((hp = gethostbyname(*ahost)) == NULL) {
183             return -1;
184         }
185 #endif
186         pfd[0].events = POLLIN;
187         pfd[1].events = POLLIN;
188         
189         *ahost = hp->h_name;
190         oldmask = sigblock(sigmask(SIGURG)); /* __sigblock */
191         for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
192                 s = rresvport(&lport);
193                 if (s < 0) {
194                         if (errno == EAGAIN)
195                             (void)fprintf(stderr,
196                                           "rcmd: socket: All ports in use\n");
197                         else
198                             (void)fprintf(stderr, "rcmd: socket: %m\n");
199                         sigsetmask(oldmask); /* sigsetmask */
200                         return -1;
201                 }
202                 fcntl(s, F_SETOWN, pid);
203                 sin.sin_family = hp->h_addrtype;
204                 bcopy(hp->h_addr_list[0], &sin.sin_addr,
205                       MIN (sizeof (sin.sin_addr), hp->h_length));
206                 sin.sin_port = rport;
207                 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) /* __connect */
208                         break;
209                 (void)close(s);
210                 if (errno == EADDRINUSE) {
211                         lport--;
212                         continue;
213                 }
214                 if (errno == ECONNREFUSED && timo <= 16) {
215                         (void)sleep(timo); /* __sleep */
216                         timo *= 2;
217                         continue;
218                 }
219                 if (hp->h_addr_list[1] != NULL) {
220                         int oerrno = errno;
221
222                         (void)fprintf(stderr, "connect to address %s: ",
223                             inet_ntoa(sin.sin_addr));
224                         __set_errno (oerrno);
225                         perror(0);
226                         hp->h_addr_list++;
227                         bcopy(hp->h_addr_list[0], &sin.sin_addr,
228                               MIN (sizeof (sin.sin_addr), hp->h_length));
229                         (void)fprintf(stderr, "Trying %s...\n",
230                             inet_ntoa(sin.sin_addr));
231                         continue;
232                 }
233                 (void)fprintf(stderr, "%s: %m\n", hp->h_name);
234                 sigsetmask(oldmask); /* __sigsetmask */
235                 return -1;
236         }
237         lport--;
238         if (fd2p == 0) {
239                 write(s, "", 1);
240                 lport = 0;
241         } else {
242                 char num[8];
243                 int s2 = rresvport(&lport), s3;
244                 socklen_t len = sizeof(from);
245
246                 if (s2 < 0)
247                         goto bad;
248                 listen(s2, 1);
249                 (void)snprintf(num, sizeof(num), "%d", lport); /* __snprintf */
250                 if (write(s, num, strlen(num)+1) != strlen(num)+1) {
251                         (void)fprintf(stderr,
252                                       "rcmd: write (setting up stderr): %m\n");
253                         (void)close(s2);
254                         goto bad;
255                 }
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                     if (errno != 0)
261                         (void)fprintf(stderr, "rcmd: poll (setting up stderr): %m\n");
262                     else
263                         (void)fprintf(stderr, "poll: protocol failure in circuit setup\n");
264                         (void)close(s2);
265                         goto bad;
266                 }
267                 s3 = accept(s2, (struct sockaddr *)&from, &len);
268                 (void)close(s2);
269                 if (s3 < 0) {
270                         (void)fprintf(stderr,
271                             "rcmd: accept: %m\n");
272                         lport = 0;
273                         goto bad;
274                 }
275                 *fd2p = s3;
276                 from.sin_port = ntohs((u_short)from.sin_port);
277                 if (from.sin_family != AF_INET ||
278                     from.sin_port >= IPPORT_RESERVED ||
279                     from.sin_port < IPPORT_RESERVED / 2) {
280                         (void)fprintf(stderr,
281                             "socket: protocol failure in circuit setup\n");
282                         goto bad2;
283                 }
284         }
285         (void)write(s, locuser, strlen(locuser)+1);
286         (void)write(s, remuser, strlen(remuser)+1);
287         (void)write(s, cmd, strlen(cmd)+1);
288         if (read(s, &c, 1) != 1) {
289                 (void)fprintf(stderr,
290                     "rcmd: %s: %m\n", *ahost);
291                 goto bad2;
292         }
293         if (c != 0) {
294                 while (read(s, &c, 1) == 1) {
295                         (void)write(STDERR_FILENO, &c, 1);
296                         if (c == '\n')
297                                 break;
298                 }
299                 goto bad2;
300         }
301         sigsetmask(oldmask);
302         return s;
303 bad2:
304         if (lport)
305                 (void)close(*fd2p);
306 bad:
307         (void)close(s);
308         sigsetmask(oldmask);
309         return -1;
310 }
311
312 int rresvport(int *alport)
313 {
314     struct sockaddr_in sin;
315     int s;
316
317     sin.sin_family = AF_INET;
318     sin.sin_addr.s_addr = INADDR_ANY;
319     s = socket(AF_INET, SOCK_STREAM, 0);
320     if (s < 0)
321         return -1;
322     for (;;) {
323         sin.sin_port = htons((u_short)*alport);
324         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
325             return s;
326         if (errno != EADDRINUSE) {
327             (void)close(s);
328             return -1;
329         }
330         (*alport)--;
331         if (*alport == IPPORT_RESERVED/2) {
332             (void)close(s);
333             __set_errno (EAGAIN);               /* close */
334             return -1;
335         }
336     }
337     
338     return -1;
339 }
340 libc_hidden_def(rresvport)
341
342 static int  __check_rhosts_file = 1;
343 static char *__rcmd_errstr;
344
345 int ruserok(rhost, superuser, ruser, luser)
346         const char *rhost, *ruser, *luser;
347         int superuser;
348 {
349         struct hostent *hp;
350         u_int32_t addr;
351         char **ap;
352 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
353         size_t buflen;
354         char *buffer;
355         int herr;
356         struct hostent hostbuf;
357 #endif
358
359 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
360         buflen = 1024;
361 #ifdef __ARCH_HAS_MMU__
362         buffer = alloca (buflen);
363 #else
364         buffer = malloc (buflen);
365 #endif
366
367         while (gethostbyname_r (rhost, &hostbuf, buffer, 
368                     buflen, &hp, &herr) != 0 || hp == NULL) 
369         {
370             if (herr != NETDB_INTERNAL || errno != ERANGE) {
371 #ifndef __ARCH_HAS_MMU__
372                 free(buffer);
373 #endif
374                 return -1;
375             } else
376             {
377                 /* Enlarge the buffer.  */
378                 buflen *= 2;
379 #ifdef __ARCH_HAS_MMU__
380                 buffer = alloca (buflen);
381 #else
382                 if (buffer) {
383                     free(buffer);
384                 }
385                 buffer = malloc (buflen);
386 #endif
387             }
388         }
389 #ifndef __ARCH_HAS_MMU__
390         free(buffer);
391 #endif
392 #else
393         if ((hp = gethostbyname(rhost)) == NULL) {
394                 return -1;
395         }
396 #endif
397         for (ap = hp->h_addr_list; *ap; ++ap) {
398                 bcopy(*ap, &addr, sizeof(addr));
399                 if (iruserok2(addr, superuser, ruser, luser, rhost) == 0)
400                         return 0;
401         }
402         return -1;
403 }
404
405
406 /* Extremely paranoid file open function. */
407 static FILE *
408 iruserfopen (char *file, uid_t okuser)
409 {
410   struct stat st;
411   char *cp = NULL;
412   FILE *res = NULL;
413
414   /* If not a regular file, if owned by someone other than user or
415      root, if writeable by anyone but the owner, or if hardlinked
416      anywhere, quit.  */
417   cp = NULL;
418   if (lstat (file, &st))
419     cp = "lstat failed";
420   else if (!S_ISREG (st.st_mode))
421     cp = "not regular file";
422   else
423     {
424       res = fopen (file, "r");
425       if (!res)
426         cp = "cannot open";
427       else if (fstat (fileno (res), &st) < 0)
428         cp = "fstat failed";
429       else if (st.st_uid && st.st_uid != okuser)
430         cp = "bad owner";
431       else if (st.st_mode & (S_IWGRP|S_IWOTH))
432         cp = "writeable by other than owner";
433       else if (st.st_nlink > 1)
434         cp = "hard linked somewhere";
435     }
436
437   /* If there were any problems, quit.  */
438   if (cp != NULL)
439     {
440       __rcmd_errstr = cp;
441       if (res)
442         fclose (res);
443       return NULL;
444     }
445
446   return res;
447 }
448
449
450 /*
451  * New .rhosts strategy: We are passed an ip address. We spin through
452  * hosts.equiv and .rhosts looking for a match. When the .rhosts only
453  * has ip addresses, we don't have to trust a nameserver.  When it
454  * contains hostnames, we spin through the list of addresses the nameserver
455  * gives us and look for a match.
456  *
457  * Returns 0 if ok, -1 if not ok.
458  */
459 static int
460 iruserok2 (raddr, superuser, ruser, luser, rhost)
461      u_int32_t raddr;
462      int superuser;
463      const char *ruser, *luser, *rhost;
464 {
465         FILE *hostf = NULL;
466         int isbad = -1;
467
468         if (!superuser)
469                 hostf = iruserfopen (_PATH_HEQUIV, 0);
470         
471         if (hostf) {
472                 isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
473                 fclose (hostf);
474
475                 if (!isbad)
476                         return 0;
477         }
478
479         if (__check_rhosts_file || superuser) {
480                 char *pbuf;
481                 struct passwd *pwd;
482                 size_t dirlen;
483                 uid_t uid;
484
485 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
486                 size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
487                 struct passwd pwdbuf;
488 #ifdef __ARCH_HAS_MMU__
489                 char *buffer = alloca (buflen);
490 #else
491                 char *buffer = malloc (buflen);
492 #endif
493
494                 if (getpwnam_r (luser, &pwdbuf, buffer, 
495                             buflen, &pwd) != 0 || pwd == NULL)
496                 {
497 #ifndef __ARCH_HAS_MMU__
498                         free(buffer);
499 #endif
500                         return -1;
501                 }
502 #ifndef __ARCH_HAS_MMU__
503                 free(buffer);
504 #endif
505 #else
506                 if ((pwd = getpwnam(luser)) == NULL)
507                         return -1;
508 #endif
509
510                 dirlen = strlen (pwd->pw_dir);
511                 pbuf = malloc (dirlen + sizeof "/.rhosts");
512                 strcpy (pbuf, pwd->pw_dir);
513                 strcat (pbuf, "/.rhosts");
514
515                 /* Change effective uid while reading .rhosts.  If root and
516                    reading an NFS mounted file system, can't read files that
517                    are protected read/write owner only.  */
518                 uid = geteuid ();
519                 seteuid (pwd->pw_uid);
520                 hostf = iruserfopen (pbuf, pwd->pw_uid);
521                 free(pbuf);
522                 
523                 if (hostf != NULL) {
524                         isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
525                         fclose (hostf);
526                 }
527                 
528                 seteuid (uid);
529                 return isbad;
530         }
531         return -1;
532 }
533
534 /* This is the exported version.  */
535 int iruserok (u_int32_t raddr, int superuser, const char * ruser, const char * luser)
536 {
537         return iruserok2 (raddr, superuser, ruser, luser, "-");
538 }
539
540
541 /*
542  * XXX
543  * Don't make static, used by lpd(8).
544  *
545  * This function is not used anymore. It is only present because lpd(8)
546  * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
547  * argument. This means that netgroups won't work in .rhost/hosts.equiv
548  * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
549  * or PAM.
550  * Returns 0 if ok, -1 if not ok.
551  */
552 int
553 __ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser)
554 {
555         return __ivaliduser2(hostf, raddr, luser, ruser, "-");
556 }
557
558
559 /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
560 static int
561 __icheckhost (u_int32_t raddr, char *lhost, const char *rhost)
562 {
563         struct hostent *hp;
564         u_int32_t laddr;
565         int negate=1;    /* Multiply return with this to get -1 instead of 1 */
566         char **pp;
567
568 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
569         int save_errno;
570         size_t buflen;
571         char *buffer;
572         struct hostent hostbuf;
573         int herr;
574 #endif
575
576 #ifdef HAVE_NETGROUP
577         /* Check nis netgroup.  */
578         if (strncmp ("+@", lhost, 2) == 0)
579                 return innetgr (&lhost[2], rhost, NULL, NULL);
580
581         if (strncmp ("-@", lhost, 2) == 0)
582                 return -innetgr (&lhost[2], rhost, NULL, NULL);
583 #endif /* HAVE_NETGROUP */
584
585         /* -host */
586         if (strncmp ("-", lhost,1) == 0) {
587                 negate = -1;
588                 lhost++;
589         } else if (strcmp ("+",lhost) == 0) {
590                 return 1;                    /* asking for trouble, but ok.. */
591         }
592
593         /* Try for raw ip address first. */
594         if (isdigit (*lhost) && (laddr = inet_addr (lhost)) != INADDR_NONE)
595                 return negate * (! (raddr ^ laddr));
596
597         /* Better be a hostname. */
598 #ifdef __UCLIBC_HAS_REENTRANT_RPC__
599         buflen = 1024;
600         buffer = malloc(buflen);
601         save_errno = errno;
602
603         while (gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr)
604                != 0) {
605             free(buffer);
606             return (0);
607         }
608         free(buffer);
609         __set_errno (save_errno);
610 #else
611         hp = gethostbyname(lhost);
612 #endif /* __UCLIBC_HAS_REENTRANT_RPC__ */
613
614         if (hp == NULL)
615                 return 0;
616
617         /* Spin through ip addresses. */
618         for (pp = hp->h_addr_list; *pp; ++pp)
619                 if (!memcmp (&raddr, *pp, sizeof (u_int32_t)))
620                         return negate;
621
622         /* No match. */
623         return (0);
624 }
625
626 /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
627 static int
628 __icheckuser (const char *luser, const char *ruser)
629 {
630
631     /*
632       luser is user entry from .rhosts/hosts.equiv file
633       ruser is user id on remote host
634       */
635
636 #ifdef HAVE_NETGROUP
637     /* [-+]@netgroup */
638     if (strncmp ("+@", luser, 2) == 0)
639         return innetgr (&luser[2], NULL, ruser, NULL);
640
641     if (strncmp ("-@", luser,2) == 0)
642         return -innetgr (&luser[2], NULL, ruser, NULL);
643 #endif /* HAVE_NETGROUP */
644
645     /* -user */
646     if (strncmp ("-", luser, 1) == 0)
647         return -(strcmp (&luser[1], ruser) == 0);
648
649     /* + */
650     if (strcmp ("+", luser) == 0)
651         return 1;
652
653     /* simple string match */
654     return strcmp (ruser, luser) == 0;
655 }
656
657 /*
658  * Returns 1 for blank lines (or only comment lines) and 0 otherwise
659  */
660 static int
661 __isempty(char *p)
662 {
663     while (*p && isspace (*p)) {
664         ++p;
665     }
666
667     return (*p == '\0' || *p == '#') ? 1 : 0 ;
668 }
669
670 /*
671  * Returns 0 if positive match, -1 if _not_ ok.
672  */
673 static int
674 __ivaliduser2(hostf, raddr, luser, ruser, rhost)
675         FILE *hostf;
676         u_int32_t raddr;
677         const char *luser, *ruser, *rhost;
678 {
679     register const char *user;
680     register char *p;
681     int hcheck, ucheck;
682     char *buf = NULL;
683     size_t bufsize = 0;
684     int retval = -1;
685
686     while (getline (&buf, &bufsize, hostf) > 0) {
687         buf[bufsize - 1] = '\0'; /* Make sure it's terminated.  */
688         p = buf;
689
690         /* Skip empty or comment lines */
691         if (__isempty (p)) {
692             continue;
693         }
694
695         /* Skip lines that are too long. */
696         if (strchr (p, '\n') == NULL) {
697             int ch = getc_unlocked (hostf);
698
699             while (ch != '\n' && ch != EOF)
700               ch = getc_unlocked (hostf);
701             continue;
702         }
703
704         for (;*p && !isspace(*p); ++p) {
705             *p = tolower (*p);
706         }
707
708         /* Next we want to find the permitted name for the remote user.  */
709         if (*p == ' ' || *p == '\t') {
710             /* <nul> terminate hostname and skip spaces */
711             for (*p++='\0'; *p && isspace (*p); ++p);
712
713             user = p;                   /* this is the user's name */
714             while (*p && !isspace (*p))
715                 ++p;                    /* find end of user's name */
716         } else
717             user = p;
718
719         *p = '\0';              /* <nul> terminate username (+host?) */
720
721         /* buf -> host(?) ; user -> username(?) */
722
723         /* First check host part */
724         hcheck = __icheckhost (raddr, buf, rhost);
725
726         if (hcheck < 0)
727             break;
728
729         if (hcheck) {
730             /* Then check user part */
731             if (! (*user))
732                 user = luser;
733
734             ucheck = __icheckuser (user, ruser);
735
736             /* Positive 'host user' match? */
737             if (ucheck > 0) {
738                 retval = 0;
739                 break;
740             }
741
742             /* Negative 'host -user' match? */
743             if (ucheck < 0)
744                 break;
745
746             /* Neither, go on looking for match */
747         }
748     }
749
750     if (buf != NULL)
751       free (buf);
752
753     return retval;
754 }