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