1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if defined(LIBC_SCCS) && !defined(lint) 35 static char sccsid[] = "@(#)rcmd.c 5.24 (Berkeley) 2/24/91"; 36 #endif /* LIBC_SCCS and not lint */ 37 38 #include <sys/param.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 #include <signal.h> 44 #include <fcntl.h> 45 #include <netdb.h> 46 #include <pwd.h> 47 #include <errno.h> 48 #include <stdio.h> 49 #include <ctype.h> 50 #include <unistd.h> 51 #include <string.h> 52 53 rcmd(ahost, rport, locuser, remuser, cmd, fd2p) 54 char **ahost; 55 u_short rport; 56 const char *locuser, *remuser, *cmd; 57 int *fd2p; 58 { 59 int s, timo = 1, pid; 60 long oldmask; 61 struct sockaddr_in sin, sin2, from; 62 char c; 63 int lport = IPPORT_RESERVED - 1; 64 struct hostent *hp; 65 fd_set reads; 66 67 pid = getpid(); 68 hp = gethostbyname(*ahost); 69 if (hp == 0) { 70 herror(*ahost); 71 return (-1); 72 } 73 *ahost = hp->h_name; 74 oldmask = sigblock(sigmask(SIGURG)); 75 for (;;) { 76 s = rresvport(&lport); 77 if (s < 0) { 78 if (errno == EAGAIN) 79 fprintf(stderr, "socket: All ports in use\n"); 80 else 81 perror("rcmd: socket"); 82 sigsetmask(oldmask); 83 return (-1); 84 } 85 fcntl(s, F_SETOWN, pid); 86 sin.sin_family = hp->h_addrtype; 87 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); 88 sin.sin_port = rport; 89 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 90 break; 91 (void) close(s); 92 if (errno == EADDRINUSE) { 93 lport--; 94 continue; 95 } 96 if (errno == ECONNREFUSED && timo <= 16) { 97 sleep(timo); 98 timo *= 2; 99 continue; 100 } 101 if (hp->h_addr_list[1] != NULL) { 102 int oerrno = errno; 103 104 fprintf(stderr, 105 "connect to address %s: ", inet_ntoa(sin.sin_addr)); 106 errno = oerrno; 107 perror(0); 108 hp->h_addr_list++; 109 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, 110 hp->h_length); 111 fprintf(stderr, "Trying %s...\n", 112 inet_ntoa(sin.sin_addr)); 113 continue; 114 } 115 perror(hp->h_name); 116 sigsetmask(oldmask); 117 return (-1); 118 } 119 lport--; 120 if (fd2p == 0) { 121 write(s, "", 1); 122 lport = 0; 123 } else { 124 char num[8]; 125 int s2 = rresvport(&lport), s3; 126 int len = sizeof (from); 127 128 if (s2 < 0) 129 goto bad; 130 listen(s2, 1); 131 (void) sprintf(num, "%d", lport); 132 if (write(s, num, strlen(num)+1) != strlen(num)+1) { 133 perror("write: setting up stderr"); 134 (void) close(s2); 135 goto bad; 136 } 137 FD_ZERO(&reads); 138 FD_SET(s, &reads); 139 FD_SET(s2, &reads); 140 errno = 0; 141 if (select(32, &reads, 0, 0, 0) < 1 || 142 !FD_ISSET(s2, &reads)) { 143 if (errno != 0) 144 perror("select: setting up stderr"); 145 else 146 fprintf(stderr, 147 "select: protocol failure in circuit setup.\n"); 148 (void) close(s2); 149 goto bad; 150 } 151 s3 = accept(s2, (struct sockaddr *)&from, &len); 152 (void) close(s2); 153 if (s3 < 0) { 154 perror("accept"); 155 lport = 0; 156 goto bad; 157 } 158 *fd2p = s3; 159 from.sin_port = ntohs((u_short)from.sin_port); 160 if (from.sin_family != AF_INET || 161 from.sin_port >= IPPORT_RESERVED || 162 from.sin_port < IPPORT_RESERVED / 2) { 163 fprintf(stderr, 164 "socket: protocol failure in circuit setup.\n"); 165 goto bad2; 166 } 167 } 168 (void) write(s, locuser, strlen(locuser)+1); 169 (void) write(s, remuser, strlen(remuser)+1); 170 (void) write(s, cmd, strlen(cmd)+1); 171 if (read(s, &c, 1) != 1) { 172 perror(*ahost); 173 goto bad2; 174 } 175 if (c != 0) { 176 while (read(s, &c, 1) == 1) { 177 (void) write(2, &c, 1); 178 if (c == '\n') 179 break; 180 } 181 goto bad2; 182 } 183 sigsetmask(oldmask); 184 return (s); 185 bad2: 186 if (lport) 187 (void) close(*fd2p); 188 bad: 189 (void) close(s); 190 sigsetmask(oldmask); 191 return (-1); 192 } 193 194 rresvport(alport) 195 int *alport; 196 { 197 struct sockaddr_in sin; 198 int s; 199 200 sin.sin_family = AF_INET; 201 sin.sin_addr.s_addr = INADDR_ANY; 202 s = socket(AF_INET, SOCK_STREAM, 0); 203 if (s < 0) 204 return (-1); 205 for (;;) { 206 sin.sin_port = htons((u_short)*alport); 207 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 208 return (s); 209 if (errno != EADDRINUSE) { 210 (void) close(s); 211 return (-1); 212 } 213 (*alport)--; 214 if (*alport == IPPORT_RESERVED/2) { 215 (void) close(s); 216 errno = EAGAIN; /* close */ 217 return (-1); 218 } 219 } 220 } 221 222 int _check_rhosts_file = 1; 223 224 ruserok(rhost, superuser, ruser, luser) 225 const char *rhost, *ruser, *luser; 226 int superuser; 227 { 228 FILE *hostf; 229 char fhost[MAXHOSTNAMELEN]; 230 int first = 1; 231 register char *sp, *p; 232 int baselen = -1; 233 234 sp = (char *)rhost; 235 p = fhost; 236 while (*sp) { 237 if (*sp == '.') { 238 if (baselen == -1) 239 baselen = sp - rhost; 240 *p++ = *sp++; 241 } else { 242 *p++ = isupper(*sp) ? tolower(*sp++) : *sp++; 243 } 244 } 245 *p = '\0'; 246 hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r"); 247 again: 248 if (hostf) { 249 if (!_validuser(hostf, fhost, luser, ruser, baselen)) { 250 (void) fclose(hostf); 251 return(0); 252 } 253 (void) fclose(hostf); 254 } 255 if (first == 1 && (_check_rhosts_file || superuser)) { 256 struct stat sbuf; 257 struct passwd *pwd; 258 char pbuf[MAXPATHLEN]; 259 260 first = 0; 261 if ((pwd = getpwnam(luser)) == NULL) 262 return(-1); 263 (void)strcpy(pbuf, pwd->pw_dir); 264 (void)strcat(pbuf, "/.rhosts"); 265 if ((hostf = fopen(pbuf, "r")) == NULL) 266 return(-1); 267 /* 268 * if owned by someone other than user or root or if 269 * writeable by anyone but the owner, quit 270 */ 271 if (fstat(fileno(hostf), &sbuf) || 272 sbuf.st_uid && sbuf.st_uid != pwd->pw_uid || 273 sbuf.st_mode&022) { 274 fclose(hostf); 275 return(-1); 276 } 277 goto again; 278 } 279 return (-1); 280 } 281 282 /* don't make static, used by lpd(8) */ 283 _validuser(hostf, rhost, luser, ruser, baselen) 284 char *rhost, *luser, *ruser; 285 FILE *hostf; 286 int baselen; 287 { 288 register char *p; 289 char *user, ahost[MAXHOSTNAMELEN]; 290 static int _checkhost(); 291 292 while (fgets(ahost, sizeof (ahost), hostf)) { 293 p = ahost; 294 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 295 *p = isupper(*p) ? tolower(*p) : *p; 296 p++; 297 } 298 if (*p == ' ' || *p == '\t') { 299 *p++ = '\0'; 300 while (*p == ' ' || *p == '\t') 301 p++; 302 user = p; 303 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') 304 p++; 305 } else 306 user = p; 307 *p = '\0'; 308 if (_checkhost(rhost, ahost, baselen) && 309 !strcmp(ruser, *user ? user : luser)) { 310 return (0); 311 } 312 } 313 return (-1); 314 } 315 316 static 317 _checkhost(rhost, lhost, len) 318 char *rhost, *lhost; 319 int len; 320 { 321 static char ldomain[MAXHOSTNAMELEN + 1]; 322 static char *domainp = NULL; 323 static int nodomain = 0; 324 register char *cp; 325 326 if (len == -1) 327 return(!strcmp(rhost, lhost)); 328 if (strncmp(rhost, lhost, len)) 329 return(0); 330 if (!strcmp(rhost, lhost)) 331 return(1); 332 if (*(lhost + len) != '\0') 333 return(0); 334 if (nodomain) 335 return(0); 336 if (!domainp) { 337 if (gethostname(ldomain, sizeof(ldomain)) == -1) { 338 nodomain = 1; 339 return(0); 340 } 341 ldomain[MAXHOSTNAMELEN] = NULL; 342 if ((domainp = index(ldomain, '.')) == (char *)NULL) { 343 nodomain = 1; 344 return(0); 345 } 346 for (cp = ++domainp; *cp; ++cp) 347 if (isupper(*cp)) 348 *cp = tolower(*cp); 349 } 350 return(!strcmp(domainp, rhost + len +1)); 351 } 352