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 2008 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 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <limits.h> 43 #include <stdio.h> 44 #include <ctype.h> 45 #include <pwd.h> 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/file.h> 49 #include <signal.h> 50 #include <libintl.h> 51 #include <sys/socket.h> 52 #include <sys/stat.h> 53 54 #include <netinet/in.h> 55 #include <netinet/tcp.h> 56 #include <inet/common.h> 57 58 #include <netdb.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <unistd.h> 62 #include <string.h> 63 #include <stdlib.h> 64 #include <grp.h> 65 #include <arpa/inet.h> 66 67 #include <priv_utils.h> 68 69 #ifdef SYSV 70 #define bcopy(s1, s2, len) (void) memcpy(s2, s1, len) 71 #define bzero(s, len) (void) memset(s, 0, len) 72 #define index(s, c) strchr(s, c) 73 char *strchr(); 74 #else 75 char *index(); 76 #endif /* SYSV */ 77 78 extern int usingypmap(); 79 80 static int _validuser(FILE *hostf, char *rhost, const char *luser, 81 const char *ruser, int baselen); 82 static int _checkhost(char *rhost, char *lhost, int len); 83 84 85 #ifdef NIS 86 static char *domain; 87 #endif 88 89 int 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, 100 const char *remuser, const char *cmd, int *fd2p, int af) 101 { 102 int s, timo = 1; 103 ssize_t retval; 104 pid_t pid; 105 struct sockaddr_storage caddr, faddr; 106 struct sockaddr_in *sin; 107 struct sockaddr_in6 *sin6; 108 struct addrinfo hints; 109 struct addrinfo *res, *resp; 110 size_t addrlen; 111 int rc; 112 #define MAX_SHORTSTRLEN 6 113 char aport[MAX_SHORTSTRLEN]; 114 char c; 115 int lport = 0; 116 #ifdef SYSV 117 sigset_t oldmask; 118 sigset_t newmask; 119 struct sigaction oldaction; 120 struct sigaction newaction; 121 #else 122 int oldmask; 123 #endif /* SYSV */ 124 fd_set fdset; 125 int selret; 126 char *addr; 127 static char hostname[MAXHOSTNAMELEN]; 128 socklen_t len; 129 char abuf[INET6_ADDRSTRLEN]; 130 131 if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) { 132 errno = EAFNOSUPPORT; 133 return (-1); 134 } 135 136 pid = getpid(); 137 memset(&hints, 0, sizeof (hints)); 138 hints.ai_socktype = SOCK_STREAM; 139 hints.ai_flags = AI_CANONNAME; 140 if (af == AF_INET6) { 141 hints.ai_flags |= AI_V4MAPPED; 142 hints.ai_family = AF_UNSPEC; 143 } else { 144 hints.ai_family = af; 145 } 146 (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport)); 147 rc = getaddrinfo(*ahost, aport, &hints, &res); 148 if (rc != 0) { 149 (void) fprintf(stderr, 150 dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"), 151 *ahost, rc == EAI_AGAIN ? " (try again later)" : ""); 152 return (-1); 153 } 154 resp = res; 155 (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN); 156 *ahost = hostname; 157 #ifdef SYSV 158 /* ignore SIGPIPE */ 159 bzero((char *)&newaction, sizeof (newaction)); 160 newaction.sa_handler = SIG_IGN; 161 (void) sigaction(SIGPIPE, &newaction, &oldaction); 162 163 /* block SIGURG */ 164 bzero((char *)&newmask, sizeof (newmask)); 165 (void) sigaddset(&newmask, SIGURG); 166 (void) sigprocmask(SIG_BLOCK, &newmask, &oldmask); 167 #else 168 oldmask = _sigblock(sigmask(SIGURG)); 169 #endif /* SYSV */ 170 for (;;) { 171 s = rresvport_af(&lport, res->ai_family); 172 if (s < 0) { 173 int af = res->ai_family; 174 175 /* 176 * See if we have any addresses of a different type 177 * to try. 178 */ 179 while (res != NULL && res->ai_family == af) 180 res = res->ai_next; 181 182 if (res != NULL) 183 continue; 184 185 if (errno == EAGAIN) 186 (void) fprintf(stderr, 187 dgettext(TEXT_DOMAIN, 188 "socket: All ports in use\n")); 189 else 190 perror("rcmd: socket"); 191 #ifdef SYSV 192 /* restore original SIGPIPE handler */ 193 (void) sigaction(SIGPIPE, &oldaction, 194 (struct sigaction *)0); 195 196 /* restore original signal mask */ 197 (void) sigprocmask(SIG_SETMASK, &oldmask, 198 (sigset_t *)0); 199 #else 200 sigsetmask(oldmask); 201 #endif /* SYSV */ 202 freeaddrinfo(resp); 203 return (-1); 204 } 205 bzero((char *)&caddr, sizeof (caddr)); 206 bcopy(res->ai_addr, &caddr, res->ai_addrlen); 207 addrlen = res->ai_addrlen; 208 if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) { 209 struct in6_addr ia6; 210 struct sockaddr_in6 *in6addr; 211 IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *) 212 res->ai_addr)->sin_addr, &ia6); 213 in6addr = (struct sockaddr_in6 *)&caddr; 214 in6addr->sin6_addr = ia6; 215 in6addr->sin6_family = AF_INET6; 216 addrlen = sizeof (struct sockaddr_in6); 217 } 218 (void) fcntl(s, F_SETOWN, pid); 219 if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0) 220 break; 221 (void) close(s); 222 if (errno == EADDRINUSE) { 223 lport = 0; 224 continue; 225 } 226 if (errno == ECONNREFUSED && timo <= 16) { 227 (void) sleep(timo); 228 timo *= 2; 229 continue; 230 } 231 if (res->ai_next != NULL) { 232 int oerrno = errno; 233 if (res->ai_addr->sa_family == AF_INET6) 234 addr = (char *)&((struct sockaddr_in6 *) 235 res->ai_addr)->sin6_addr; 236 else 237 addr = (char *)&((struct sockaddr_in *) 238 res->ai_addr)->sin_addr; 239 (void) fprintf(stderr, 240 dgettext(TEXT_DOMAIN, "connect to address %s: "), 241 inet_ntop(res->ai_addr->sa_family, addr, 242 abuf, sizeof (abuf))); 243 errno = oerrno; 244 perror(0); 245 res = res->ai_next; 246 if (res->ai_addr->sa_family == AF_INET6) 247 addr = (char *)&((struct sockaddr_in6 *) 248 res->ai_addr)->sin6_addr; 249 else 250 addr = (char *)&((struct sockaddr_in *) 251 res->ai_addr)->sin_addr; 252 (void) fprintf(stderr, 253 dgettext(TEXT_DOMAIN, "Trying %s...\n"), 254 inet_ntop(res->ai_addr->sa_family, addr, 255 abuf, sizeof (abuf))); 256 continue; 257 } 258 perror(*ahost); 259 freeaddrinfo(resp); 260 #ifdef SYSV 261 /* restore original SIGPIPE handler */ 262 (void) sigaction(SIGPIPE, &oldaction, 263 (struct sigaction *)0); 264 265 /* restore original signal mask */ 266 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 267 #else 268 sigsetmask(oldmask); 269 #endif /* SYSV */ 270 return (-1); 271 } 272 lport = 0; 273 if (fd2p == 0) { 274 (void) write(s, "", 1); 275 } else { 276 int s2 = rresvport_af(&lport, res->ai_family), s3; 277 278 len = (socklen_t)sizeof (faddr); 279 280 if (s2 < 0) 281 goto bad; 282 (void) listen(s2, 1); 283 (void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport); 284 if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) { 285 perror(dgettext(TEXT_DOMAIN, 286 "write: setting up stderr")); 287 (void) close(s2); 288 goto bad; 289 } 290 FD_ZERO(&fdset); 291 FD_SET(s, &fdset); 292 FD_SET(s2, &fdset); 293 while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0, 294 (fd_set *)0, (struct timeval *)0)) > 0) { 295 if (FD_ISSET(s, &fdset)) { 296 /* 297 * Something's wrong: we should get no 298 * data on this connection at this point, 299 * so we assume that the connection has 300 * gone away. 301 */ 302 (void) close(s2); 303 goto bad; 304 } 305 if (FD_ISSET(s2, &fdset)) { 306 /* 307 * We assume this is an incoming connect 308 * request and proceed normally. 309 */ 310 s3 = accept(s2, (struct sockaddr *)&faddr, 311 &len); 312 FD_CLR(s2, &fdset); 313 (void) close(s2); 314 if (s3 < 0) { 315 perror("accept"); 316 lport = 0; 317 goto bad; 318 } 319 else 320 break; 321 } 322 } 323 if (selret == -1) { 324 /* 325 * This should not happen, and we treat it as 326 * a fatal error. 327 */ 328 (void) close(s2); 329 goto bad; 330 } 331 332 *fd2p = s3; 333 switch (faddr.ss_family) { 334 case AF_INET: 335 sin = (struct sockaddr_in *)&faddr; 336 if (ntohs(sin->sin_port) >= IPPORT_RESERVED) { 337 (void) fprintf(stderr, 338 dgettext(TEXT_DOMAIN, 339 "socket: protocol failure in circuit " 340 "setup.\n")); 341 goto bad2; 342 } 343 break; 344 case AF_INET6: 345 sin6 = (struct sockaddr_in6 *)&faddr; 346 if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) { 347 (void) fprintf(stderr, 348 dgettext(TEXT_DOMAIN, 349 "socket: protocol failure in circuit " 350 "setup.\n")); 351 goto bad2; 352 } 353 break; 354 default: 355 (void) fprintf(stderr, 356 dgettext(TEXT_DOMAIN, 357 "socket: protocol failure in circuit setup.\n")); 358 goto bad2; 359 } 360 } 361 (void) write(s, locuser, strlen(locuser)+1); 362 (void) write(s, remuser, strlen(remuser)+1); 363 (void) write(s, cmd, strlen(cmd)+1); 364 retval = read(s, &c, 1); 365 if (retval != 1) { 366 if (retval == 0) { 367 (void) fprintf(stderr, 368 dgettext(TEXT_DOMAIN, 369 "Protocol error, %s closed connection\n"), 370 *ahost); 371 } else if (retval < 0) { 372 perror(*ahost); 373 } else { 374 (void) fprintf(stderr, 375 dgettext(TEXT_DOMAIN, 376 "Protocol error, %s sent %d bytes\n"), 377 *ahost, retval); 378 } 379 goto bad2; 380 } 381 if (c != 0) { 382 while (read(s, &c, 1) == 1) { 383 (void) write(2, &c, 1); 384 if (c == '\n') 385 break; 386 } 387 goto bad2; 388 } 389 #ifdef SYSV 390 /* restore original SIGPIPE handler */ 391 (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); 392 393 /* restore original signal mask */ 394 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 395 #else 396 sigsetmask(oldmask); 397 #endif /* SYSV */ 398 freeaddrinfo(resp); 399 return (s); 400 bad2: 401 if (lport) 402 (void) close(*fd2p); 403 bad: 404 (void) close(s); 405 #ifdef SYSV 406 /* restore original SIGPIPE handler */ 407 (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); 408 409 /* restore original signal mask */ 410 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 411 #else 412 sigsetmask(oldmask); 413 #endif /* SYSV */ 414 freeaddrinfo(resp); 415 return (-1); 416 } 417 418 static int 419 _rresvport_addr(int *alport, struct sockaddr_storage *addr) 420 { 421 struct sockaddr_in *sin; 422 struct sockaddr_in6 *sin6; 423 int s; 424 socklen_t len; 425 int on = 1; 426 int off = 0; 427 428 if (addr->ss_family == AF_INET) { 429 sin = (struct sockaddr_in *)addr; 430 len = sizeof (struct sockaddr_in); 431 } else if (addr->ss_family == AF_INET6) { 432 sin6 = (struct sockaddr_in6 *)addr; 433 len = sizeof (struct sockaddr_in6); 434 } else { 435 errno = EAFNOSUPPORT; 436 return (-1); 437 } 438 s = socket(addr->ss_family, SOCK_STREAM, 0); 439 if (s < 0) 440 return (-1); 441 442 /* 443 * Set SO_EXCLBIND to get a "unique" port, which is not bound 444 * to any other sockets. 445 */ 446 if (setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &on, sizeof (on)) < 0) { 447 (void) close(s); 448 return (-1); 449 } 450 451 /* Try to bind() to the given port first. */ 452 if (*alport != 0) { 453 if (addr->ss_family == AF_INET) { 454 sin->sin_port = htons((ushort_t)*alport); 455 } else { 456 sin6->sin6_port = htons((ushort_t)*alport); 457 } 458 if (bind(s, (struct sockaddr *)addr, len) >= 0) { 459 /* To be safe, need to turn off SO_EXCLBIND. */ 460 (void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off, 461 sizeof (off)); 462 return (s); 463 } 464 if (errno != EADDRINUSE) { 465 (void) close(s); 466 return (-1); 467 } 468 } 469 470 /* 471 * If no port is given or the above bind() does not succeed, set 472 * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the 473 * priviledged range for us. 474 */ 475 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 476 sizeof (on)) < 0) { 477 (void) close(s); 478 return (-1); 479 } 480 if (addr->ss_family == AF_INET) { 481 sin->sin_port = 0; 482 } else { 483 sin6->sin6_port = 0; 484 } 485 if (bind(s, (struct sockaddr *)addr, len) >= 0) { 486 /* 487 * We need to tell the caller what the port is. 488 */ 489 if (getsockname(s, (struct sockaddr *)addr, &len) < 0) { 490 (void) close(s); 491 return (-1); 492 } 493 switch (addr->ss_family) { 494 case AF_INET6: 495 sin6 = (struct sockaddr_in6 *)addr; 496 *alport = ntohs(sin6->sin6_port); 497 break; 498 case AF_INET: 499 sin = (struct sockaddr_in *)addr; 500 *alport = ntohs(sin->sin_port); 501 break; 502 } 503 504 /* 505 * To be safe, always turn off these options when we are done. 506 */ 507 (void) setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &off, 508 sizeof (off)); 509 (void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off, 510 sizeof (off)); 511 return (s); 512 } 513 (void) close(s); 514 return (-1); 515 } 516 517 int 518 rresvport_addr(int *alport, struct sockaddr_storage *addr) 519 { 520 int res, err; 521 522 (void) __priv_bracket(PRIV_ON); 523 524 res = _rresvport_addr(alport, addr); 525 526 err = errno; 527 (void) __priv_bracket(PRIV_OFF); 528 errno = err; 529 530 return (res); 531 } 532 533 int 534 rresvport_af(int *alport, int af) 535 { 536 struct sockaddr_storage laddr; 537 538 bzero(&laddr, sizeof (laddr)); 539 if (af == AF_INET || af == AF_INET6) { 540 laddr.ss_family = (sa_family_t)af; 541 } else { 542 errno = EAFNOSUPPORT; 543 return (-1); 544 } 545 return (rresvport_addr(alport, &laddr)); 546 } 547 548 int 549 rresvport(int *alport) 550 { 551 return (rresvport_af(alport, AF_INET)); 552 } 553 554 int 555 ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) 556 { 557 FILE *hostf; 558 char fhost[MAXHOSTNAMELEN]; 559 const char *sp; 560 char *p; 561 int baselen = -1; 562 563 struct stat64 sbuf; 564 struct passwd *pwd; 565 char pbuf[MAXPATHLEN]; 566 uid_t uid = (uid_t)-1; 567 gid_t gid = (gid_t)-1; 568 gid_t grouplist[NGROUPS_MAX]; 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(NGROUPS_MAX, 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 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 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] = NULL; 803 if ((domainp = index(ldomain, '.')) == (char *)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