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