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