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 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 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 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 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 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 550 rresvport(int *alport) 551 { 552 return (rresvport_af(alport, AF_INET)); 553 } 554 555 int 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 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 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