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