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