OSDN Git Service

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