(atomic_add): Don't allow address register for operand 0.
[glibc.git] / inet / rcmd.c
blobde00bfaf1332013e2b3833435278f70f58bd7e2a
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>
85 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
86 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
87 const char *, const char *, const char *);
88 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
89 int superuser, const char *ruser,
90 const char *luser, const char *rhost);
91 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
92 int superuser, const char *ruser,
93 const char *luser);
94 int iruserok_af (const void *raddr, int superuser, const char *ruser,
95 const char *luser, sa_family_t af);
96 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
97 const char *luser);
99 static char ahostbuf[NI_MAXHOST];
102 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
103 char **ahost;
104 u_short rport;
105 const char *locuser, *remuser, *cmd;
106 int *fd2p;
107 sa_family_t af;
109 char paddr[INET6_ADDRSTRLEN];
110 struct addrinfo hints, *res, *ai;
111 struct sockaddr_storage from;
112 struct pollfd pfd[2];
113 int32_t oldmask;
114 pid_t pid;
115 int s, lport, timo, error;
116 char c;
117 int refused;
118 char num[8];
119 ssize_t n;
121 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
123 __set_errno (EAFNOSUPPORT);
124 return -1;
127 pid = __getpid();
129 memset(&hints, '\0', sizeof(hints));
130 hints.ai_flags = AI_CANONNAME;
131 hints.ai_family = af;
132 hints.ai_socktype = SOCK_STREAM;
133 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
134 error = getaddrinfo(*ahost, num, &hints, &res);
135 if (error) {
136 fprintf(stderr, "rcmd: getaddrinfo: %s\n",
137 gai_strerror(error));
138 return (-1);
141 pfd[0].events = POLLIN;
142 pfd[1].events = POLLIN;
144 if (res->ai_canonname){
145 strncpy(ahostbuf, res->ai_canonname, sizeof(ahostbuf));
146 ahostbuf[sizeof(ahostbuf)-1] = '\0';
147 *ahost = ahostbuf;
149 else
150 *ahost = NULL;
151 ai = res;
152 refused = 0;
153 oldmask = __sigblock(sigmask(SIGURG));
154 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
155 s = rresvport_af(&lport, ai->ai_family);
156 if (s < 0) {
157 if (errno == EAGAIN)
158 fprintf(stderr,
159 _("rcmd: socket: All ports in use\n"));
160 else
161 fprintf(stderr, "rcmd: socket: %m\n");
162 __sigsetmask(oldmask);
163 freeaddrinfo(res);
164 return -1;
166 __fcntl(s, F_SETOWN, pid);
167 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
168 break;
169 (void)__close(s);
170 if (errno == EADDRINUSE) {
171 lport--;
172 continue;
174 if (errno == ECONNREFUSED)
175 refused = 1;
176 if (ai->ai_next != NULL) {
177 int oerrno = errno;
179 getnameinfo(ai->ai_addr, ai->ai_addrlen,
180 paddr, sizeof(paddr),
181 NULL, 0,
182 NI_NUMERICHOST);
183 fprintf(stderr, "connect to address %s: ", paddr);
184 __set_errno (oerrno);
185 perror(0);
186 ai = ai->ai_next;
187 getnameinfo(ai->ai_addr, ai->ai_addrlen,
188 paddr, sizeof(paddr),
189 NULL, 0,
190 NI_NUMERICHOST);
191 fprintf(stderr, "Trying %s...\n", paddr);
192 continue;
194 if (refused && timo <= 16) {
195 (void)__sleep(timo);
196 timo *= 2;
197 ai = res;
198 refused = 0;
199 continue;
201 freeaddrinfo(res);
202 (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno));
203 __sigsetmask(oldmask);
204 return -1;
206 lport--;
207 if (fd2p == 0) {
208 __write(s, "", 1);
209 lport = 0;
210 } else {
211 char num[8];
212 int s2 = rresvport_af(&lport, ai->ai_family), s3;
213 socklen_t len = ai->ai_addrlen;
215 if (s2 < 0)
216 goto bad;
217 listen(s2, 1);
218 (void)__snprintf(num, sizeof(num), "%d", lport);
219 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
220 (void)fprintf(stderr,
221 _("rcmd: write (setting up stderr): %m\n"));
222 (void)__close(s2);
223 goto bad;
225 pfd[0].fd = s;
226 pfd[1].fd = s2;
227 __set_errno (0);
228 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
229 if (errno != 0)
230 (void)fprintf(stderr,
231 _("rcmd: poll (setting up stderr): %m\n"));
232 else
233 (void)fprintf(stderr,
234 _("poll: protocol failure in circuit setup\n"));
235 (void)__close(s2);
236 goto bad;
238 s3 = accept(s2, (struct sockaddr *)&from, &len);
239 switch (from.ss_family) {
240 case AF_INET:
241 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
242 break;
243 case AF_INET6:
244 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
245 break;
246 default:
247 rport = 0;
248 break;
250 (void)__close(s2);
251 if (s3 < 0) {
252 (void)fprintf(stderr,
253 "rcmd: accept: %m\n");
254 lport = 0;
255 goto bad;
257 *fd2p = s3;
259 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
260 (void)fprintf(stderr,
261 _("socket: protocol failure in circuit setup\n"));
262 goto bad2;
265 (void)__write(s, locuser, strlen(locuser)+1);
266 (void)__write(s, remuser, strlen(remuser)+1);
267 (void)__write(s, cmd, strlen(cmd)+1);
268 n = __read(s, &c, 1);
269 if (n != 1) {
270 if (n == 0)
271 (void)fprintf(stderr, _("rcmd: %s: short read"),
272 *ahost);
273 else
274 (void)fprintf(stderr, "rcmd: %s: %m\n", *ahost);
275 goto bad2;
277 if (c != 0) {
278 while (__read(s, &c, 1) == 1) {
279 (void)__write(STDERR_FILENO, &c, 1);
280 if (c == '\n')
281 break;
283 goto bad2;
285 __sigsetmask(oldmask);
286 freeaddrinfo(res);
287 return s;
288 bad2:
289 if (lport)
290 (void)__close(*fd2p);
291 bad:
292 (void)__close(s);
293 __sigsetmask(oldmask);
294 freeaddrinfo(res);
295 return -1;
299 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
300 char **ahost;
301 u_short rport;
302 const char *locuser, *remuser, *cmd;
303 int *fd2p;
305 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
309 rresvport_af(alport, family)
310 int *alport;
311 sa_family_t family;
313 struct sockaddr_storage ss;
314 int s;
315 size_t len;
316 uint16_t *sport;
318 switch(family){
319 case AF_INET:
320 len = sizeof(struct sockaddr_in);
321 sport = &((struct sockaddr_in *)&ss)->sin_port;
322 break;
323 case AF_INET6:
324 len = sizeof(struct sockaddr_in6);
325 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
326 break;
327 default:
328 __set_errno (EAFNOSUPPORT);
329 return -1;
331 s = __socket(family, SOCK_STREAM, 0);
332 if (s < 0)
333 return -1;
335 memset (&ss, '\0', sizeof(ss));
336 #ifdef SALEN
337 ss.__ss_len = len;
338 #endif
339 ss.ss_family = family;
341 for (;;) {
342 *sport = htons((uint16_t) *alport);
343 if (bind(s, (struct sockaddr *)&ss, len) >= 0)
344 return s;
345 if (errno != EADDRINUSE) {
346 (void)__close(s);
347 return -1;
349 (*alport)--;
350 if (*alport == IPPORT_RESERVED/2)
351 break;
353 (void)__close(s);
354 __set_errno (EAGAIN);
355 return -1;
359 rresvport(alport)
360 int *alport;
362 return rresvport_af(alport, AF_INET);
365 int __check_rhosts_file = 1;
366 char *__rcmd_errstr;
369 ruserok_af(rhost, superuser, ruser, luser, af)
370 const char *rhost, *ruser, *luser;
371 int superuser;
372 sa_family_t af;
374 struct addrinfo hints, *res, *res0;
375 int gai;
376 int ret;
378 memset (&hints, '\0', sizeof(hints));
379 hints.ai_family = af;
380 gai = getaddrinfo(rhost, NULL, &hints, &res0);
381 if (gai)
382 return -1;
383 ret = -1;
384 for (res=res0; res; res=res->ai_next)
385 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
386 superuser, ruser, luser, rhost) == 0){
387 ret = 0;
388 break;
390 freeaddrinfo(res0);
391 return (ret);
394 ruserok(rhost, superuser, ruser, luser)
395 const char *rhost, *ruser, *luser;
396 int superuser;
398 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
401 /* Extremely paranoid file open function. */
402 static FILE *
403 iruserfopen (const char *file, uid_t okuser)
405 struct stat64 st;
406 char *cp = NULL;
407 FILE *res = NULL;
409 /* If not a regular file, if owned by someone other than user or
410 root, if writeable by anyone but the owner, or if hardlinked
411 anywhere, quit. */
412 cp = NULL;
413 if (__lxstat64 (_STAT_VER, file, &st))
414 cp = _("lstat failed");
415 else if (!S_ISREG (st.st_mode))
416 cp = _("not regular file");
417 else
419 res = fopen (file, "r");
420 if (!res)
421 cp = _("cannot open");
422 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
423 cp = _("fstat failed");
424 else if (st.st_uid && st.st_uid != okuser)
425 cp = _("bad owner");
426 else if (st.st_mode & (S_IWGRP|S_IWOTH))
427 cp = _("writeable by other than owner");
428 else if (st.st_nlink > 1)
429 cp = _("hard linked somewhere");
432 /* If there were any problems, quit. */
433 if (cp != NULL)
435 __rcmd_errstr = cp;
436 if (res)
437 fclose (res);
438 return NULL;
441 /* No threads use this stream. */
442 __fsetlocking (res, FSETLOCKING_BYCALLER);
444 return res;
448 * New .rhosts strategy: We are passed an ip address. We spin through
449 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
450 * has ip addresses, we don't have to trust a nameserver. When it
451 * contains hostnames, we spin through the list of addresses the nameserver
452 * gives us and look for a match.
454 * Returns 0 if ok, -1 if not ok.
456 static int
457 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
458 struct sockaddr *ra;
459 size_t ralen;
460 int superuser;
461 const char *ruser, *luser, *rhost;
463 FILE *hostf = NULL;
464 int isbad = -1;
466 if (!superuser)
467 hostf = iruserfopen (_PATH_HEQUIV, 0);
469 if (hostf)
471 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
472 fclose (hostf);
474 if (!isbad)
475 return 0;
478 if (__check_rhosts_file || superuser)
480 char *pbuf;
481 struct passwd pwdbuf, *pwd;
482 size_t dirlen;
483 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
484 char *buffer = __alloca (buflen);
485 uid_t uid;
487 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
488 || pwd == NULL)
489 return -1;
491 dirlen = strlen (pwd->pw_dir);
492 pbuf = alloca (dirlen + sizeof "/.rhosts");
493 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
494 "/.rhosts", sizeof "/.rhosts");
496 /* Change effective uid while reading .rhosts. If root and
497 reading an NFS mounted file system, can't read files that
498 are protected read/write owner only. */
499 uid = __geteuid ();
500 seteuid (pwd->pw_uid);
501 hostf = iruserfopen (pbuf, pwd->pw_uid);
503 if (hostf != NULL)
505 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
506 fclose (hostf);
509 seteuid (uid);
510 return isbad;
512 return -1;
515 * ruserok_sa() is now discussed on ipng, so
516 * currently disabled for external use
518 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
519 struct sockaddr *ra;
520 size_t ralen;
521 int superuser;
522 const char *ruser, *luser;
524 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
527 /* This is the exported version. */
529 iruserok_af (raddr, superuser, ruser, luser, af)
530 const void *raddr;
531 int superuser;
532 const char *ruser, *luser;
533 sa_family_t af;
535 struct sockaddr_storage ra;
536 size_t ralen;
538 memset (&ra, '\0', sizeof(ra));
539 switch (af){
540 case AF_INET:
541 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
542 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
543 sizeof(struct in_addr));
544 ralen = sizeof(struct sockaddr_in);
545 break;
546 case AF_INET6:
547 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
548 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
549 sizeof(struct in6_addr));
550 ralen = sizeof(struct sockaddr_in6);
551 break;
552 default:
553 return 0;
555 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
558 iruserok (raddr, superuser, ruser, luser)
559 u_int32_t raddr;
560 int superuser;
561 const char *ruser, *luser;
563 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
567 * XXX
568 * Don't make static, used by lpd(8).
570 * This function is not used anymore. It is only present because lpd(8)
571 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
572 * argument. This means that netgroups won't work in .rhost/hosts.equiv
573 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
574 * or PAM.
575 * Returns 0 if ok, -1 if not ok.
578 __ivaliduser(hostf, raddr, luser, ruser)
579 FILE *hostf;
580 u_int32_t raddr;
581 const char *luser, *ruser;
583 struct sockaddr_in ra;
584 memset(&ra, '\0', sizeof(ra));
585 ra.sin_family = AF_INET;
586 ra.sin_addr.s_addr = raddr;
587 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
588 luser, ruser, "-");
592 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
593 static int
594 internal_function
595 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
596 const char *rhost)
598 struct addrinfo hints, *res0, *res;
599 char raddr[INET6_ADDRSTRLEN];
600 int match;
601 int negate=1; /* Multiply return with this to get -1 instead of 1 */
603 /* Check nis netgroup. */
604 if (strncmp ("+@", lhost, 2) == 0)
605 return innetgr (&lhost[2], rhost, NULL, NULL);
607 if (strncmp ("-@", lhost, 2) == 0)
608 return -innetgr (&lhost[2], rhost, NULL, NULL);
610 /* -host */
611 if (strncmp ("-", lhost,1) == 0) {
612 negate = -1;
613 lhost++;
614 } else if (strcmp ("+",lhost) == 0) {
615 return 1; /* asking for trouble, but ok.. */
618 /* Try for raw ip address first. */
619 /* XXX */
620 if (getnameinfo(ra, ralen,
621 raddr, sizeof(raddr), NULL, 0,
622 NI_NUMERICHOST) == 0
623 && strcmp(raddr, lhost) == 0)
624 return negate;
626 /* Better be a hostname. */
627 match = 0;
628 memset(&hints, '\0', sizeof(hints));
629 hints.ai_family = ra->sa_family;
630 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
631 /* Spin through ip addresses. */
632 for (res = res0; res; res = res->ai_next)
634 if (res->ai_family == ra->sa_family
635 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
637 match = 1;
638 break;
641 freeaddrinfo (res0);
643 return negate * match;
646 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
647 static int
648 internal_function
649 __icheckuser (const char *luser, const char *ruser)
652 luser is user entry from .rhosts/hosts.equiv file
653 ruser is user id on remote host
656 /* [-+]@netgroup */
657 if (strncmp ("+@", luser, 2) == 0)
658 return innetgr (&luser[2], NULL, ruser, NULL);
660 if (strncmp ("-@", luser,2) == 0)
661 return -innetgr (&luser[2], NULL, ruser, NULL);
663 /* -user */
664 if (strncmp ("-", luser, 1) == 0)
665 return -(strcmp (&luser[1], ruser) == 0);
667 /* + */
668 if (strcmp ("+", luser) == 0)
669 return 1;
671 /* simple string match */
672 return strcmp (ruser, luser) == 0;
676 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
678 static int
679 __isempty (char *p)
681 while (*p && isspace (*p)) {
682 ++p;
685 return (*p == '\0' || *p == '#') ? 1 : 0 ;
689 * Returns 0 if positive match, -1 if _not_ ok.
691 static int
692 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
693 FILE *hostf;
694 struct sockaddr *ra;
695 size_t ralen;
696 const char *luser, *ruser, *rhost;
698 register const char *user;
699 register char *p;
700 int hcheck, ucheck;
701 char *buf = NULL;
702 size_t bufsize = 0;
703 int retval = -1;
705 while (__getline (&buf, &bufsize, hostf) > 0) {
706 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
707 p = buf;
709 /* Skip empty or comment lines */
710 if (__isempty (p)) {
711 continue;
714 /* Skip lines that are too long. */
715 if (strchr (p, '\n') == NULL) {
716 int ch = getc_unlocked (hostf);
718 while (ch != '\n' && ch != EOF)
719 ch = getc_unlocked (hostf);
720 continue;
723 for (;*p && !isspace(*p); ++p) {
724 *p = _tolower (*p);
727 /* Next we want to find the permitted name for the remote user. */
728 if (*p == ' ' || *p == '\t') {
729 /* <nul> terminate hostname and skip spaces */
730 for (*p++='\0'; *p && isspace (*p); ++p);
732 user = p; /* this is the user's name */
733 while (*p && !isspace (*p))
734 ++p; /* find end of user's name */
735 } else
736 user = p;
738 *p = '\0'; /* <nul> terminate username (+host?) */
740 /* buf -> host(?) ; user -> username(?) */
742 /* First check host part */
743 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
745 if (hcheck < 0)
746 break;
748 if (hcheck) {
749 /* Then check user part */
750 if (! (*user))
751 user = luser;
753 ucheck = __icheckuser (user, ruser);
755 /* Positive 'host user' match? */
756 if (ucheck > 0) {
757 retval = 0;
758 break;
761 /* Negative 'host -user' match? */
762 if (ucheck < 0)
763 break;
765 /* Neither, go on looking for match */
769 if (buf != NULL)
770 free (buf);
772 return retval;