1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <limits.h>
41 #include <stdio.h>
42 #include <ctype.h>
43 #include <pwd.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <signal.h>
48 #include <libintl.h>
49 #include <sys/socket.h>
50 #include <sys/stat.h>
51
52 #include <netinet/in.h>
53 #include <netinet/tcp.h>
54 #include <inet/common.h>
55
56 #include <netdb.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <stdlib.h>
62 #include <grp.h>
63 #include <alloca.h>
64 #include <arpa/inet.h>
65
66 #include <priv_utils.h>
67
68 #ifdef SYSV
69 #define bcopy(s1, s2, len) (void) memcpy(s2, s1, len)
70 #define bzero(s, len) (void) memset(s, 0, len)
71 #define index(s, c) strchr(s, c)
72 char *strchr();
73 #else
74 char *index();
75 #endif /* SYSV */
76
77 extern int usingypmap();
78
79 static int _validuser(FILE *hostf, char *rhost, const char *luser,
80 const char *ruser, int baselen);
81 static int _checkhost(char *rhost, char *lhost, int len);
82
83
84 #ifdef NIS
85 static char *domain;
86 #endif
87
88 int
rcmd(char ** ahost,unsigned short rport,const char * locuser,const char * remuser,const char * cmd,int * fd2p)89 rcmd(char **ahost, unsigned short rport, const char *locuser,
90 const char *remuser, const char *cmd, int *fd2p)
91 {
92 int rcmd_ret;
93
94 rcmd_ret = rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p,
95 AF_INET);
96 return (rcmd_ret);
97 }
98
99 int
rcmd_af(char ** ahost,unsigned short rport,const char * locuser,const char * remuser,const char * cmd,int * fd2p,int af)100 rcmd_af(char **ahost, unsigned short rport, const char *locuser,
101 const char *remuser, const char *cmd, int *fd2p, int af)
102 {
103 int s, timo = 1;
104 ssize_t retval;
105 pid_t pid;
106 struct sockaddr_storage caddr, faddr;
107 struct sockaddr_in *sin;
108 struct sockaddr_in6 *sin6;
109 struct addrinfo hints;
110 struct addrinfo *res, *resp;
111 size_t addrlen;
112 int rc;
113 #define MAX_SHORTSTRLEN 6
114 char aport[MAX_SHORTSTRLEN];
115 char c;
116 int lport = 0;
117 #ifdef SYSV
118 sigset_t oldmask;
119 sigset_t newmask;
120 struct sigaction oldaction;
121 struct sigaction newaction;
122 #else
123 int oldmask;
124 #endif /* SYSV */
125 fd_set fdset;
126 int selret;
127 char *addr;
128 static char hostname[MAXHOSTNAMELEN];
129 socklen_t len;
130 char abuf[INET6_ADDRSTRLEN];
131
132 if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
133 errno = EAFNOSUPPORT;
134 return (-1);
135 }
136
137 pid = getpid();
138 memset(&hints, 0, sizeof (hints));
139 hints.ai_socktype = SOCK_STREAM;
140 hints.ai_flags = AI_CANONNAME;
141 if (af == AF_INET6) {
142 hints.ai_flags |= AI_V4MAPPED;
143 hints.ai_family = AF_UNSPEC;
144 } else {
145 hints.ai_family = af;
146 }
147 (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
148 rc = getaddrinfo(*ahost, aport, &hints, &res);
149 if (rc != 0) {
150 (void) fprintf(stderr,
151 dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"),
152 *ahost, rc == EAI_AGAIN ? " (try again later)" : "");
153 return (-1);
154 }
155 resp = res;
156 (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
157 *ahost = hostname;
158 #ifdef SYSV
159 /* ignore SIGPIPE */
160 bzero((char *)&newaction, sizeof (newaction));
161 newaction.sa_handler = SIG_IGN;
162 (void) sigaction(SIGPIPE, &newaction, &oldaction);
163
164 /* block SIGURG */
165 bzero((char *)&newmask, sizeof (newmask));
166 (void) sigaddset(&newmask, SIGURG);
167 (void) sigprocmask(SIG_BLOCK, &newmask, &oldmask);
168 #else
169 oldmask = _sigblock(sigmask(SIGURG));
170 #endif /* SYSV */
171 for (;;) {
172 s = rresvport_af(&lport, res->ai_family);
173 if (s < 0) {
174 int af = res->ai_family;
175
176 /*
177 * See if we have any addresses of a different type
178 * to try.
179 */
180 while (res != NULL && res->ai_family == af)
181 res = res->ai_next;
182
183 if (res != NULL)
184 continue;
185
186 if (errno == EAGAIN)
187 (void) fprintf(stderr,
188 dgettext(TEXT_DOMAIN,
189 "socket: All ports in use\n"));
190 else
191 perror("rcmd: socket");
192 #ifdef SYSV
193 /* restore original SIGPIPE handler */
194 (void) sigaction(SIGPIPE, &oldaction,
195 (struct sigaction *)0);
196
197 /* restore original signal mask */
198 (void) sigprocmask(SIG_SETMASK, &oldmask,
199 (sigset_t *)0);
200 #else
201 sigsetmask(oldmask);
202 #endif /* SYSV */
203 freeaddrinfo(resp);
204 return (-1);
205 }
206 bzero((char *)&caddr, sizeof (caddr));
207 bcopy(res->ai_addr, &caddr, res->ai_addrlen);
208 addrlen = res->ai_addrlen;
209 if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) {
210 struct in6_addr ia6;
211 struct sockaddr_in6 *in6addr;
212 IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *)
213 res->ai_addr)->sin_addr, &ia6);
214 in6addr = (struct sockaddr_in6 *)&caddr;
215 in6addr->sin6_addr = ia6;
216 in6addr->sin6_family = AF_INET6;
217 addrlen = sizeof (struct sockaddr_in6);
218 }
219 (void) fcntl(s, F_SETOWN, pid);
220 if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0)
221 break;
222 (void) close(s);
223 if (errno == EADDRINUSE) {
224 lport = 0;
225 continue;
226 }
227 if (errno == ECONNREFUSED && timo <= 16) {
228 (void) sleep(timo);
229 timo *= 2;
230 continue;
231 }
232 if (res->ai_next != NULL) {
233 int oerrno = errno;
234 if (res->ai_addr->sa_family == AF_INET6)
235 addr = (char *)&((struct sockaddr_in6 *)
236 res->ai_addr)->sin6_addr;
237 else
238 addr = (char *)&((struct sockaddr_in *)
239 res->ai_addr)->sin_addr;
240 (void) fprintf(stderr,
241 dgettext(TEXT_DOMAIN, "connect to address %s: "),
242 inet_ntop(res->ai_addr->sa_family, addr,
243 abuf, sizeof (abuf)));
244 errno = oerrno;
245 perror(0);
246 res = res->ai_next;
247 if (res->ai_addr->sa_family == AF_INET6)
248 addr = (char *)&((struct sockaddr_in6 *)
249 res->ai_addr)->sin6_addr;
250 else
251 addr = (char *)&((struct sockaddr_in *)
252 res->ai_addr)->sin_addr;
253 (void) fprintf(stderr,
254 dgettext(TEXT_DOMAIN, "Trying %s...\n"),
255 inet_ntop(res->ai_addr->sa_family, addr,
256 abuf, sizeof (abuf)));
257 continue;
258 }
259 perror(*ahost);
260 freeaddrinfo(resp);
261 #ifdef SYSV
262 /* restore original SIGPIPE handler */
263 (void) sigaction(SIGPIPE, &oldaction,
264 (struct sigaction *)0);
265
266 /* restore original signal mask */
267 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
268 #else
269 sigsetmask(oldmask);
270 #endif /* SYSV */
271 return (-1);
272 }
273 lport = 0;
274 if (fd2p == NULL) {
275 (void) write(s, "", 1);
276 } else {
277 int s2 = rresvport_af(&lport, res->ai_family), s3 = -1;
278
279 len = (socklen_t)sizeof (faddr);
280
281 if (s2 < 0)
282 goto bad;
283 (void) listen(s2, 1);
284 (void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport);
285 if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) {
286 perror(dgettext(TEXT_DOMAIN,
287 "write: setting up stderr"));
288 (void) close(s2);
289 goto bad;
290 }
291 FD_ZERO(&fdset);
292 FD_SET(s, &fdset);
293 FD_SET(s2, &fdset);
294 while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0,
295 (fd_set *)0, (struct timeval *)0)) > 0) {
296 if (FD_ISSET(s, &fdset)) {
297 /*
298 * Something's wrong: we should get no
299 * data on this connection at this point,
300 * so we assume that the connection has
301 * gone away.
302 */
303 (void) close(s2);
304 goto bad;
305 }
306 if (FD_ISSET(s2, &fdset)) {
307 /*
308 * We assume this is an incoming connect
309 * request and proceed normally.
310 */
311 s3 = accept(s2, (struct sockaddr *)&faddr,
312 &len);
313 FD_CLR(s2, &fdset);
314 (void) close(s2);
315 if (s3 < 0) {
316 perror("accept");
317 lport = 0;
318 goto bad;
319 } else {
320 break;
321 }
322 }
323 }
324 if (selret == -1) {
325 /*
326 * This should not happen, and we treat it as
327 * a fatal error.
328 */
329 (void) close(s2);
330 goto bad;
331 }
332
333 *fd2p = s3;
334 switch (faddr.ss_family) {
335 case AF_INET:
336 sin = (struct sockaddr_in *)&faddr;
337 if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
338 (void) fprintf(stderr,
339 dgettext(TEXT_DOMAIN,
340 "socket: protocol failure in circuit "
341 "setup.\n"));
342 goto bad2;
343 }
344 break;
345 case AF_INET6:
346 sin6 = (struct sockaddr_in6 *)&faddr;
347 if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) {
348 (void) fprintf(stderr,
349 dgettext(TEXT_DOMAIN,
350 "socket: protocol failure in circuit "
351 "setup.\n"));
352 goto bad2;
353 }
354 break;
355 default:
356 (void) fprintf(stderr,
357 dgettext(TEXT_DOMAIN,
358 "socket: protocol failure in circuit setup.\n"));
359 goto bad2;
360 }
361 }
362 (void) write(s, locuser, strlen(locuser)+1);
363 (void) write(s, remuser, strlen(remuser)+1);
364 (void) write(s, cmd, strlen(cmd)+1);
365 retval = read(s, &c, 1);
366 if (retval != 1) {
367 if (retval == 0) {
368 (void) fprintf(stderr,
369 dgettext(TEXT_DOMAIN,
370 "Protocol error, %s closed connection\n"),
371 *ahost);
372 } else if (retval < 0) {
373 perror(*ahost);
374 } else {
375 (void) fprintf(stderr,
376 dgettext(TEXT_DOMAIN,
377 "Protocol error, %s sent %d bytes\n"),
378 *ahost, retval);
379 }
380 goto bad2;
381 }
382 if (c != 0) {
383 while (read(s, &c, 1) == 1) {
384 (void) write(2, &c, 1);
385 if (c == '\n')
386 break;
387 }
388 goto bad2;
389 }
390 #ifdef SYSV
391 /* restore original SIGPIPE handler */
392 (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
393
394 /* restore original signal mask */
395 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
396 #else
397 sigsetmask(oldmask);
398 #endif /* SYSV */
399 freeaddrinfo(resp);
400 return (s);
401 bad2:
402 if (lport)
403 (void) close(*fd2p);
404 bad:
405 (void) close(s);
406 #ifdef SYSV
407 /* restore original SIGPIPE handler */
408 (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
409
410 /* restore original signal mask */
411 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
412 #else
413 sigsetmask(oldmask);
414 #endif /* SYSV */
415 freeaddrinfo(resp);
416 return (-1);
417 }
418
419 static int
_rresvport_addr(int * alport,struct sockaddr_storage * addr)420 _rresvport_addr(int *alport, struct sockaddr_storage *addr)
421 {
422 struct sockaddr_in *sin = NULL;
423 struct sockaddr_in6 *sin6 = NULL;
424 int s;
425 socklen_t len;
426 int on = 1;
427 int off = 0;
428
429 if (addr->ss_family == AF_INET) {
430 sin = (struct sockaddr_in *)addr;
431 len = sizeof (struct sockaddr_in);
432 } else if (addr->ss_family == AF_INET6) {
433 sin6 = (struct sockaddr_in6 *)addr;
434 len = sizeof (struct sockaddr_in6);
435 } else {
436 errno = EAFNOSUPPORT;
437 return (-1);
438 }
439 s = socket(addr->ss_family, SOCK_STREAM, 0);
440 if (s < 0)
441 return (-1);
442
443 /*
444 * Set SO_EXCLBIND to get a "unique" port, which is not bound
445 * to any other sockets.
446 */
447 if (setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &on, sizeof (on)) < 0) {
448 (void) close(s);
449 return (-1);
450 }
451
452 /* Try to bind() to the given port first. */
453 if (*alport != 0) {
454 if (sin != NULL) {
455 sin->sin_port = htons((ushort_t)*alport);
456 } else {
457 sin6->sin6_port = htons((ushort_t)*alport);
458 }
459 if (bind(s, (struct sockaddr *)addr, len) >= 0) {
460 /* To be safe, need to turn off SO_EXCLBIND. */
461 (void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off,
462 sizeof (off));
463 return (s);
464 }
465 if (errno != EADDRINUSE) {
466 (void) close(s);
467 return (-1);
468 }
469 }
470
471 /*
472 * If no port is given or the above bind() does not succeed, set
473 * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the
474 * priviledged range for us.
475 */
476 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
477 sizeof (on)) < 0) {
478 (void) close(s);
479 return (-1);
480 }
481 if (addr->ss_family == AF_INET) {
482 sin->sin_port = 0;
483 } else {
484 sin6->sin6_port = 0;
485 }
486 if (bind(s, (struct sockaddr *)addr, len) >= 0) {
487 /*
488 * We need to tell the caller what the port is.
489 */
490 if (getsockname(s, (struct sockaddr *)addr, &len) < 0) {
491 (void) close(s);
492 return (-1);
493 }
494 switch (addr->ss_family) {
495 case AF_INET6:
496 sin6 = (struct sockaddr_in6 *)addr;
497 *alport = ntohs(sin6->sin6_port);
498 break;
499 case AF_INET:
500 sin = (struct sockaddr_in *)addr;
501 *alport = ntohs(sin->sin_port);
502 break;
503 }
504
505 /*
506 * To be safe, always turn off these options when we are done.
507 */
508 (void) setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &off,
509 sizeof (off));
510 (void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off,
511 sizeof (off));
512 return (s);
513 }
514 (void) close(s);
515 return (-1);
516 }
517
518 int
rresvport_addr(int * alport,struct sockaddr_storage * addr)519 rresvport_addr(int *alport, struct sockaddr_storage *addr)
520 {
521 int res, err;
522
523 (void) __priv_bracket(PRIV_ON);
524
525 res = _rresvport_addr(alport, addr);
526
527 err = errno;
528 (void) __priv_bracket(PRIV_OFF);
529 errno = err;
530
531 return (res);
532 }
533
534 int
rresvport_af(int * alport,int af)535 rresvport_af(int *alport, int af)
536 {
537 struct sockaddr_storage laddr;
538
539 bzero(&laddr, sizeof (laddr));
540 if (af == AF_INET || af == AF_INET6) {
541 laddr.ss_family = (sa_family_t)af;
542 } else {
543 errno = EAFNOSUPPORT;
544 return (-1);
545 }
546 return (rresvport_addr(alport, &laddr));
547 }
548
549 int
rresvport(int * alport)550 rresvport(int *alport)
551 {
552 return (rresvport_af(alport, AF_INET));
553 }
554
555 int
ruserok(const char * rhost,int superuser,const char * ruser,const char * luser)556 ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
557 {
558 FILE *hostf;
559 char fhost[MAXHOSTNAMELEN];
560 const char *sp;
561 char *p;
562 int baselen = -1;
563
564 struct stat64 sbuf;
565 struct passwd *pwd;
566 char pbuf[MAXPATHLEN];
567 uid_t uid = (uid_t)-1;
568 gid_t gid = (gid_t)-1;
569 int maxgrp = getgroups(0, NULL);
570 gid_t *grouplist = alloca(maxgrp * sizeof (gid_t));
571 int ngroups;
572
573 sp = rhost;
574 p = fhost;
575 while (*sp) {
576 if (*sp == '.') {
577 if (baselen == -1)
578 baselen = (int)(sp - rhost);
579 *p++ = *sp++;
580 } else {
581 *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
582 }
583 }
584 *p = '\0';
585
586 /* check /etc/hosts.equiv */
587 if (!superuser) {
588 if ((hostf = fopen("/etc/hosts.equiv", "rF")) != NULL) {
589 if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
590 (void) fclose(hostf);
591 return (0);
592 }
593 (void) fclose(hostf);
594 }
595 }
596
597 /* check ~/.rhosts */
598
599 if ((pwd = getpwnam(luser)) == NULL)
600 return (-1);
601 (void) strcpy(pbuf, pwd->pw_dir);
602 (void) strcat(pbuf, "/.rhosts");
603
604 /*
605 * Read .rhosts as the local user to avoid NFS mapping the root uid
606 * to something that can't read .rhosts.
607 */
608 gid = getegid();
609 uid = geteuid();
610 if ((ngroups = getgroups(maxgrp, grouplist)) == -1)
611 return (-1);
612
613 (void) setegid(pwd->pw_gid);
614 (void) initgroups(pwd->pw_name, pwd->pw_gid);
615 (void) seteuid(pwd->pw_uid);
616 if ((hostf = fopen(pbuf, "rF")) == NULL) {
617 if (gid != (gid_t)-1)
618 (void) setegid(gid);
619 if (uid != (uid_t)-1)
620 (void) seteuid(uid);
621 (void) setgroups(ngroups, grouplist);
622 return (-1);
623 }
624 (void) fstat64(fileno(hostf), &sbuf);
625 if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
626 (void) fclose(hostf);
627 if (gid != (gid_t)-1)
628 (void) setegid(gid);
629 if (uid != (uid_t)-1)
630 (void) seteuid(uid);
631 (void) setgroups(ngroups, grouplist);
632 return (-1);
633 }
634
635 if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
636 (void) fclose(hostf);
637 if (gid != (gid_t)-1)
638 (void) setegid(gid);
639 if (uid != (uid_t)-1)
640 (void) seteuid(uid);
641 (void) setgroups(ngroups, grouplist);
642 return (0);
643 }
644
645 (void) fclose(hostf);
646 if (gid != (gid_t)-1)
647 (void) setegid(gid);
648 if (uid != (uid_t)-1)
649 (void) seteuid(uid);
650 (void) setgroups(ngroups, grouplist);
651 return (-1);
652 }
653
654 static int
_validuser(FILE * hostf,char * rhost,const char * luser,const char * ruser,int baselen)655 _validuser(FILE *hostf, char *rhost, const char *luser,
656 const char *ruser, int baselen)
657 {
658 char *user;
659 char ahost[BUFSIZ];
660 char *uchost = NULL;
661 int hostmatch, usermatch;
662 char *p;
663
664 #ifdef NIS
665 if (domain == NULL) {
666 (void) usingypmap(&domain, NULL);
667 }
668 #endif /* NIS */
669
670 while (fgets(ahost, (int)sizeof (ahost), hostf)) {
671 uchost = NULL;
672 hostmatch = usermatch = 0;
673 p = ahost;
674 /*
675 * We can get a line bigger than our buffer. If so we skip
676 * the offending line.
677 */
678 if (strchr(p, '\n') == NULL) {
679 while (fgets(ahost, (int)sizeof (ahost), hostf) &&
680 strchr(ahost, '\n') == NULL)
681 ;
682 continue;
683 }
684 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
685 /*
686 * Both host and user ``names'' can be netgroups,
687 * and must have their case preserved. Case is
688 * preserved for user names because we break out
689 * of this loop when finding a field separator.
690 * To do so for host names, we must make a copy of
691 * the host name field.
692 */
693 if (isupper(*p)) {
694 if (uchost == NULL)
695 uchost = strdup(ahost);
696 *p = tolower(*p);
697 }
698 p++;
699 }
700 if (*p != '\0' && uchost != NULL)
701 uchost[p - ahost] = '\0';
702 if (*p == ' ' || *p == '\t') {
703 *p++ = '\0';
704 while (*p == ' ' || *p == '\t')
705 p++;
706 user = p;
707 while (*p != '\n' && *p != ' ' && *p != '\t' &&
708 *p != '\0')
709 p++;
710 } else
711 user = p;
712 *p = '\0';
713 if (ahost[0] == '+' && ahost[1] == 0) {
714 hostmatch = 1;
715 #ifdef NIS
716 } else if (ahost[0] == '+' && ahost[1] == '@') {
717 if (uchost != NULL) {
718 hostmatch = innetgr(uchost + 2, rhost,
719 NULL, domain);
720 } else {
721 hostmatch = innetgr(ahost + 2, rhost,
722 NULL, domain);
723 }
724 } else if (ahost[0] == '-' && ahost[1] == '@') {
725 if (uchost != NULL) {
726 if (innetgr(uchost + 2, rhost, NULL, domain))
727 break;
728 } else {
729 if (innetgr(ahost + 2, rhost, NULL, domain))
730 break;
731 }
732 }
733 #endif /* NIS */
734 else if (ahost[0] == '-') {
735 if (_checkhost(rhost, ahost+1, baselen))
736 break;
737 } else {
738 hostmatch = _checkhost(rhost, ahost, baselen);
739 }
740
741 if (user[0]) {
742 if (user[0] == '+' && user[1] == 0) {
743 usermatch = 1;
744 #ifdef NIS
745 } else if (user[0] == '+' && user[1] == '@') {
746 usermatch = innetgr(user+2, NULL,
747 ruser, domain);
748 } else if (user[0] == '-' && user[1] == '@') {
749 if (hostmatch &&
750 innetgr(user+2, NULL, ruser, domain))
751 break;
752 }
753 #endif /* NIS */
754 else if (user[0] == '-') {
755 if (hostmatch && (strcmp(user+1, ruser) == 0))
756 break;
757 } else {
758 usermatch = (strcmp(user, ruser) == 0);
759 }
760 } else {
761 usermatch = (strcmp(ruser, luser) == 0);
762 }
763
764 if (uchost != NULL) {
765 free(uchost);
766 uchost = NULL;
767 }
768
769 if (hostmatch && usermatch)
770 return (0);
771 }
772
773 if (uchost != NULL)
774 free(uchost);
775 return (-1);
776 }
777
778 static int
_checkhost(char * rhost,char * lhost,int len)779 _checkhost(char *rhost, char *lhost, int len)
780 {
781 static char *ldomain;
782 static char *domainp;
783 static int nodomain;
784 char *cp;
785
786 if (ldomain == NULL) {
787 ldomain = (char *)malloc(MAXHOSTNAMELEN+1);
788 if (ldomain == 0)
789 return (0);
790 }
791
792 if (len == -1)
793 return (strcmp(rhost, lhost) == 0);
794 if (strncmp(rhost, lhost, len))
795 return (0);
796 if (strcmp(rhost, lhost) == 0)
797 return (1);
798 if (*(lhost + len) != '\0')
799 return (0);
800 if (nodomain)
801 return (0);
802 if (!domainp) {
803 /*
804 * "domainp" points after the first dot in the host name
805 */
806 if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) {
807 nodomain = 1;
808 return (0);
809 }
810 ldomain[MAXHOSTNAMELEN] = '\0';
811 if ((domainp = index(ldomain, '.')) == NULL) {
812 nodomain = 1;
813 return (0);
814 }
815 domainp++;
816 cp = domainp;
817 while (*cp) {
818 *cp = isupper(*cp) ? tolower(*cp) : *cp;
819 cp++;
820 }
821 }
822 return (strcmp(domainp, rhost + len + 1) == 0);
823 }
824