1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 1995 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* 7*0Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 8*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 9*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 10*0Sstevel@tonic-gate */ 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gate #include <stdio.h> 15*0Sstevel@tonic-gate #include <ctype.h> 16*0Sstevel@tonic-gate #include <pwd.h> 17*0Sstevel@tonic-gate #include <sys/param.h> 18*0Sstevel@tonic-gate #include <sys/file.h> 19*0Sstevel@tonic-gate #include <sys/signal.h> 20*0Sstevel@tonic-gate #include <sys/socket.h> 21*0Sstevel@tonic-gate #include <sys/stat.h> 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate #include <netinet/in.h> 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate #include <netdb.h> 26*0Sstevel@tonic-gate #include <errno.h> 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate extern errno; 29*0Sstevel@tonic-gate char *index(), *strcpy(); 30*0Sstevel@tonic-gate #ifndef S5EMUL 31*0Sstevel@tonic-gate char *sprintf(); 32*0Sstevel@tonic-gate #endif 33*0Sstevel@tonic-gate static char *domain; 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate int 36*0Sstevel@tonic-gate rcmd( 37*0Sstevel@tonic-gate char **ahost, 38*0Sstevel@tonic-gate unsigned short rport, 39*0Sstevel@tonic-gate const char *locuser, 40*0Sstevel@tonic-gate const char *remuser, 41*0Sstevel@tonic-gate const char *cmd, 42*0Sstevel@tonic-gate int *fd2p) 43*0Sstevel@tonic-gate { 44*0Sstevel@tonic-gate int s, timo = 1, pid, oldmask, retval; 45*0Sstevel@tonic-gate struct sockaddr_in sin, from; 46*0Sstevel@tonic-gate char c; 47*0Sstevel@tonic-gate int lport = IPPORT_RESERVED - 1; 48*0Sstevel@tonic-gate struct hostent *hp; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate pid = getpid(); 51*0Sstevel@tonic-gate hp = gethostbyname(*ahost); 52*0Sstevel@tonic-gate if (hp == 0) { 53*0Sstevel@tonic-gate fprintf(stderr, "%s: unknown host\n", *ahost); 54*0Sstevel@tonic-gate return (-1); 55*0Sstevel@tonic-gate } 56*0Sstevel@tonic-gate *ahost = hp->h_name; 57*0Sstevel@tonic-gate oldmask = sigblock(sigmask(SIGURG)); 58*0Sstevel@tonic-gate for (;;) { 59*0Sstevel@tonic-gate s = rresvport(&lport); 60*0Sstevel@tonic-gate if (s < 0) { 61*0Sstevel@tonic-gate if (errno == EAGAIN) 62*0Sstevel@tonic-gate fprintf(stderr, "socket: All ports in use\n"); 63*0Sstevel@tonic-gate else 64*0Sstevel@tonic-gate perror("rcmd: socket"); 65*0Sstevel@tonic-gate sigsetmask(oldmask); 66*0Sstevel@tonic-gate return (-1); 67*0Sstevel@tonic-gate } 68*0Sstevel@tonic-gate fcntl(s, F_SETOWN, pid); 69*0Sstevel@tonic-gate sin.sin_family = hp->h_addrtype; 70*0Sstevel@tonic-gate bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); 71*0Sstevel@tonic-gate sin.sin_port = rport; 72*0Sstevel@tonic-gate if (connect(s, &sin, sizeof (sin)) >= 0) 73*0Sstevel@tonic-gate break; 74*0Sstevel@tonic-gate (void) close(s); 75*0Sstevel@tonic-gate if (errno == EADDRINUSE) { 76*0Sstevel@tonic-gate lport--; 77*0Sstevel@tonic-gate continue; 78*0Sstevel@tonic-gate } 79*0Sstevel@tonic-gate if (errno == ECONNREFUSED && timo <= 16) { 80*0Sstevel@tonic-gate sleep(timo); 81*0Sstevel@tonic-gate timo *= 2; 82*0Sstevel@tonic-gate continue; 83*0Sstevel@tonic-gate } 84*0Sstevel@tonic-gate if (hp->h_addr_list[1] != NULL) { 85*0Sstevel@tonic-gate int oerrno = errno; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate fprintf(stderr, 88*0Sstevel@tonic-gate "connect to address %s: ", inet_ntoa(sin.sin_addr)); 89*0Sstevel@tonic-gate errno = oerrno; 90*0Sstevel@tonic-gate perror(0); 91*0Sstevel@tonic-gate hp->h_addr_list++; 92*0Sstevel@tonic-gate bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, 93*0Sstevel@tonic-gate hp->h_length); 94*0Sstevel@tonic-gate fprintf(stderr, "Trying %s...\n", 95*0Sstevel@tonic-gate inet_ntoa(sin.sin_addr)); 96*0Sstevel@tonic-gate continue; 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate perror(hp->h_name); 99*0Sstevel@tonic-gate sigsetmask(oldmask); 100*0Sstevel@tonic-gate return (-1); 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate lport--; 103*0Sstevel@tonic-gate if (fd2p == 0) { 104*0Sstevel@tonic-gate write(s, "", 1); 105*0Sstevel@tonic-gate lport = 0; 106*0Sstevel@tonic-gate } else { 107*0Sstevel@tonic-gate char num[8]; 108*0Sstevel@tonic-gate int s2 = rresvport(&lport), s3; 109*0Sstevel@tonic-gate int len = sizeof (from); 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate if (s2 < 0) 112*0Sstevel@tonic-gate goto bad; 113*0Sstevel@tonic-gate listen(s2, 1); 114*0Sstevel@tonic-gate (void) sprintf(num, "%d", lport); 115*0Sstevel@tonic-gate if (write(s, num, strlen(num)+1) != strlen(num)+1) { 116*0Sstevel@tonic-gate perror("write: setting up stderr"); 117*0Sstevel@tonic-gate (void) close(s2); 118*0Sstevel@tonic-gate goto bad; 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate s3 = accept(s2, &from, &len); 121*0Sstevel@tonic-gate (void) close(s2); 122*0Sstevel@tonic-gate if (s3 < 0) { 123*0Sstevel@tonic-gate perror("accept"); 124*0Sstevel@tonic-gate lport = 0; 125*0Sstevel@tonic-gate goto bad; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate *fd2p = s3; 128*0Sstevel@tonic-gate from.sin_port = ntohs((u_short)from.sin_port); 129*0Sstevel@tonic-gate if (from.sin_family != AF_INET || 130*0Sstevel@tonic-gate from.sin_port >= IPPORT_RESERVED) { 131*0Sstevel@tonic-gate fprintf(stderr, 132*0Sstevel@tonic-gate "socket: protocol failure in circuit setup.\n"); 133*0Sstevel@tonic-gate goto bad2; 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate (void) write(s, locuser, strlen(locuser)+1); 137*0Sstevel@tonic-gate (void) write(s, remuser, strlen(remuser)+1); 138*0Sstevel@tonic-gate (void) write(s, cmd, strlen(cmd)+1); 139*0Sstevel@tonic-gate retval = read(s, &c, 1); 140*0Sstevel@tonic-gate if (retval != 1) { 141*0Sstevel@tonic-gate if (retval == 0) { 142*0Sstevel@tonic-gate fprintf(stderr, 143*0Sstevel@tonic-gate "Protocol error, %s closed connection\n", *ahost); 144*0Sstevel@tonic-gate } else if (retval < 0) { 145*0Sstevel@tonic-gate perror(*ahost); 146*0Sstevel@tonic-gate } else { 147*0Sstevel@tonic-gate fprintf(stderr, 148*0Sstevel@tonic-gate "Protocol error, %s sent %d bytes\n", *ahost, retval); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate goto bad2; 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate if (c != 0) { 153*0Sstevel@tonic-gate while (read(s, &c, 1) == 1) { 154*0Sstevel@tonic-gate (void) write(2, &c, 1); 155*0Sstevel@tonic-gate if (c == '\n') 156*0Sstevel@tonic-gate break; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate goto bad2; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate sigsetmask(oldmask); 161*0Sstevel@tonic-gate return (s); 162*0Sstevel@tonic-gate bad2: 163*0Sstevel@tonic-gate if (lport) 164*0Sstevel@tonic-gate (void) close(*fd2p); 165*0Sstevel@tonic-gate bad: 166*0Sstevel@tonic-gate (void) close(s); 167*0Sstevel@tonic-gate sigsetmask(oldmask); 168*0Sstevel@tonic-gate return (-1); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate int 172*0Sstevel@tonic-gate rresvport(alport) 173*0Sstevel@tonic-gate int *alport; 174*0Sstevel@tonic-gate { 175*0Sstevel@tonic-gate struct sockaddr_in sin; 176*0Sstevel@tonic-gate int s; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate sin.sin_family = AF_INET; 179*0Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY; 180*0Sstevel@tonic-gate s = socket(AF_INET, SOCK_STREAM, 0); 181*0Sstevel@tonic-gate if (s < 0) 182*0Sstevel@tonic-gate return (-1); 183*0Sstevel@tonic-gate for (;;) { 184*0Sstevel@tonic-gate sin.sin_port = htons((u_short)*alport); 185*0Sstevel@tonic-gate if (bind(s, (caddr_t)&sin, sizeof (sin)) >= 0) 186*0Sstevel@tonic-gate return (s); 187*0Sstevel@tonic-gate if (errno != EADDRINUSE) { 188*0Sstevel@tonic-gate (void) close(s); 189*0Sstevel@tonic-gate return (-1); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate (*alport)--; 192*0Sstevel@tonic-gate if (*alport == IPPORT_RESERVED/2) { 193*0Sstevel@tonic-gate (void) close(s); 194*0Sstevel@tonic-gate errno = EAGAIN; /* close */ 195*0Sstevel@tonic-gate return (-1); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate int 201*0Sstevel@tonic-gate ruserok( 202*0Sstevel@tonic-gate const char *rhost, 203*0Sstevel@tonic-gate int superuser, 204*0Sstevel@tonic-gate const char *ruser, 205*0Sstevel@tonic-gate const char *luser) 206*0Sstevel@tonic-gate { 207*0Sstevel@tonic-gate FILE *hostf; 208*0Sstevel@tonic-gate char fhost[MAXHOSTNAMELEN]; 209*0Sstevel@tonic-gate register const char *sp; 210*0Sstevel@tonic-gate register char *p; 211*0Sstevel@tonic-gate int baselen = -1; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate struct stat sbuf; 214*0Sstevel@tonic-gate struct passwd *pwd; 215*0Sstevel@tonic-gate char pbuf[MAXPATHLEN]; 216*0Sstevel@tonic-gate int euid = -1; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate sp = rhost; 219*0Sstevel@tonic-gate p = fhost; 220*0Sstevel@tonic-gate while (*sp) { 221*0Sstevel@tonic-gate if (*sp == '.') { 222*0Sstevel@tonic-gate if (baselen == -1) 223*0Sstevel@tonic-gate baselen = sp - rhost; 224*0Sstevel@tonic-gate *p++ = *sp++; 225*0Sstevel@tonic-gate } else { 226*0Sstevel@tonic-gate *p++ = isupper(*sp) ? tolower(*sp++) : *sp++; 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate *p = '\0'; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* check /etc/hosts.equiv */ 232*0Sstevel@tonic-gate if (!superuser) { 233*0Sstevel@tonic-gate if ((hostf = fopen("/etc/hosts.equiv", "r")) != NULL) { 234*0Sstevel@tonic-gate if (!_validuser(hostf, fhost, luser, ruser, baselen)) { 235*0Sstevel@tonic-gate (void) fclose(hostf); 236*0Sstevel@tonic-gate return(0); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate (void) fclose(hostf); 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* check ~/.rhosts */ 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if ((pwd = getpwnam(luser)) == NULL) 245*0Sstevel@tonic-gate return(-1); 246*0Sstevel@tonic-gate (void)strcpy(pbuf, pwd->pw_dir); 247*0Sstevel@tonic-gate (void)strcat(pbuf, "/.rhosts"); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * Read .rhosts as the local user to avoid NFS mapping the root uid 251*0Sstevel@tonic-gate * to something that can't read .rhosts. 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate euid = geteuid(); 254*0Sstevel@tonic-gate (void) seteuid (pwd->pw_uid); 255*0Sstevel@tonic-gate if ((hostf = fopen(pbuf, "r")) == NULL) { 256*0Sstevel@tonic-gate if (euid != -1) 257*0Sstevel@tonic-gate (void) seteuid (euid); 258*0Sstevel@tonic-gate return(-1); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate (void)fstat(fileno(hostf), &sbuf); 261*0Sstevel@tonic-gate if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { 262*0Sstevel@tonic-gate fclose(hostf); 263*0Sstevel@tonic-gate if (euid != -1) 264*0Sstevel@tonic-gate (void) seteuid (euid); 265*0Sstevel@tonic-gate return(-1); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (!_validuser(hostf, fhost, luser, ruser, baselen)) { 269*0Sstevel@tonic-gate (void) fclose(hostf); 270*0Sstevel@tonic-gate if (euid != -1) 271*0Sstevel@tonic-gate (void) seteuid (euid); 272*0Sstevel@tonic-gate return(0); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate (void) fclose(hostf); 276*0Sstevel@tonic-gate if (euid != -1) 277*0Sstevel@tonic-gate (void) seteuid (euid); 278*0Sstevel@tonic-gate return (-1); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate _validuser(hostf, rhost, luser, ruser, baselen) 282*0Sstevel@tonic-gate char *rhost, *luser, *ruser; 283*0Sstevel@tonic-gate FILE *hostf; 284*0Sstevel@tonic-gate int baselen; 285*0Sstevel@tonic-gate { 286*0Sstevel@tonic-gate char *user; 287*0Sstevel@tonic-gate char ahost[MAXHOSTNAMELEN]; 288*0Sstevel@tonic-gate int hostmatch, usermatch; 289*0Sstevel@tonic-gate register char *p; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (domain == NULL) { 292*0Sstevel@tonic-gate (void) yp_get_default_domain(&domain); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate while (fgets(ahost, sizeof (ahost), hostf)) { 295*0Sstevel@tonic-gate hostmatch = usermatch = 0; /* bugid fix 1033104 */ 296*0Sstevel@tonic-gate p = ahost; 297*0Sstevel@tonic-gate while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 298*0Sstevel@tonic-gate *p = isupper(*p) ? tolower(*p) : *p; 299*0Sstevel@tonic-gate p++; 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate if (*p == ' ' || *p == '\t') { 302*0Sstevel@tonic-gate *p++ = '\0'; 303*0Sstevel@tonic-gate while (*p == ' ' || *p == '\t') 304*0Sstevel@tonic-gate p++; 305*0Sstevel@tonic-gate user = p; 306*0Sstevel@tonic-gate while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') 307*0Sstevel@tonic-gate p++; 308*0Sstevel@tonic-gate } else 309*0Sstevel@tonic-gate user = p; 310*0Sstevel@tonic-gate *p = '\0'; 311*0Sstevel@tonic-gate if (ahost[0] == '+' && ahost[1] == 0) 312*0Sstevel@tonic-gate hostmatch = 1; 313*0Sstevel@tonic-gate else if (ahost[0] == '+' && ahost[1] == '@') 314*0Sstevel@tonic-gate hostmatch = innetgr(ahost + 2, rhost, 315*0Sstevel@tonic-gate NULL, domain); 316*0Sstevel@tonic-gate else if (ahost[0] == '-' && ahost[1] == '@') { 317*0Sstevel@tonic-gate if (innetgr(ahost + 2, rhost, NULL, domain)) 318*0Sstevel@tonic-gate break; 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate else if (ahost[0] == '-') { 321*0Sstevel@tonic-gate if (_checkhost(rhost, ahost+1, baselen)) 322*0Sstevel@tonic-gate break; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate else 325*0Sstevel@tonic-gate hostmatch = _checkhost(rhost, ahost, baselen); 326*0Sstevel@tonic-gate if (user[0]) { 327*0Sstevel@tonic-gate if (user[0] == '+' && user[1] == 0) 328*0Sstevel@tonic-gate usermatch = 1; 329*0Sstevel@tonic-gate else if (user[0] == '+' && user[1] == '@') 330*0Sstevel@tonic-gate usermatch = innetgr(user+2, NULL, 331*0Sstevel@tonic-gate ruser, domain); 332*0Sstevel@tonic-gate else if (user[0] == '-' && user[1] == '@') { 333*0Sstevel@tonic-gate if (hostmatch && innetgr(user+2, NULL, 334*0Sstevel@tonic-gate ruser, domain)) 335*0Sstevel@tonic-gate break; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate else if (user[0] == '-') { 338*0Sstevel@tonic-gate if (hostmatch && !strcmp(user+1, ruser)) 339*0Sstevel@tonic-gate break; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate else 342*0Sstevel@tonic-gate usermatch = !strcmp(user, ruser); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate else 345*0Sstevel@tonic-gate usermatch = !strcmp(ruser, luser); 346*0Sstevel@tonic-gate if (hostmatch && usermatch) 347*0Sstevel@tonic-gate return (0); 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate return (-1); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate _checkhost(rhost, lhost, len) 353*0Sstevel@tonic-gate char *rhost, *lhost; 354*0Sstevel@tonic-gate int len; 355*0Sstevel@tonic-gate { 356*0Sstevel@tonic-gate static char *ldomain; 357*0Sstevel@tonic-gate static char *domainp; 358*0Sstevel@tonic-gate static int nodomain; 359*0Sstevel@tonic-gate register char *cp; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate if (ldomain == NULL) { 362*0Sstevel@tonic-gate ldomain = (char *)malloc(MAXHOSTNAMELEN+1); 363*0Sstevel@tonic-gate if (ldomain == 0) 364*0Sstevel@tonic-gate return (0); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate if (len == -1) 368*0Sstevel@tonic-gate return(!strcmp(rhost, lhost)); 369*0Sstevel@tonic-gate if (strncmp(rhost, lhost, len)) 370*0Sstevel@tonic-gate return(0); 371*0Sstevel@tonic-gate if (!strcmp(rhost, lhost)) 372*0Sstevel@tonic-gate return(1); 373*0Sstevel@tonic-gate if (*(lhost + len) != '\0') 374*0Sstevel@tonic-gate return(0); 375*0Sstevel@tonic-gate if (nodomain) 376*0Sstevel@tonic-gate return(0); 377*0Sstevel@tonic-gate if (!domainp) { 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * "domainp" points after the first dot in the host name 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) { 382*0Sstevel@tonic-gate nodomain = 1; 383*0Sstevel@tonic-gate return(0); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate ldomain[MAXHOSTNAMELEN] = NULL; 386*0Sstevel@tonic-gate if ((domainp = index(ldomain, '.')) == (char *)NULL) { 387*0Sstevel@tonic-gate nodomain = 1; 388*0Sstevel@tonic-gate return(0); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate domainp++; 391*0Sstevel@tonic-gate cp = domainp; 392*0Sstevel@tonic-gate while (*cp) { 393*0Sstevel@tonic-gate *cp = isupper(*cp) ? tolower(*cp) : *cp; 394*0Sstevel@tonic-gate cp++; 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate return(!strcmp(domainp, rhost + len +1)); 398*0Sstevel@tonic-gate } 399