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 = "from: @(#)rcmd.c 5.24 (Berkeley) 2/24/91";*/ 36 static char *rcsid = "$Id: rcmd.c,v 1.3 1993/08/26 00:46:13 jtc Exp $"; 37 #endif /* LIBC_SCCS and not lint */ 38 39 #include <sys/param.h> 40 #include <sys/socket.h> 41 #include <sys/stat.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <signal.h> 45 #include <fcntl.h> 46 #include <netdb.h> 47 #include <pwd.h> 48 #include <errno.h> 49 #include <stdio.h> 50 #include <ctype.h> 51 #include <unistd.h> 52 #include <string.h> 53 54 rcmd(ahost, rport, locuser, remuser, cmd, fd2p) 55 char **ahost; 56 u_short rport; 57 const char *locuser, *remuser, *cmd; 58 int *fd2p; 59 { 60 int s, timo = 1, pid; 61 long oldmask; 62 struct sockaddr_in sin, sin2, from; 63 char c; 64 int lport = IPPORT_RESERVED - 1; 65 struct hostent *hp; 66 fd_set reads; 67 68 pid = getpid(); 69 hp = gethostbyname(*ahost); 70 if (hp == 0) { 71 herror(*ahost); 72 return (-1); 73 } 74 *ahost = hp->h_name; 75 oldmask = sigblock(sigmask(SIGURG)); 76 for (;;) { 77 s = rresvport(&lport); 78 if (s < 0) { 79 if (errno == EAGAIN) 80 fprintf(stderr, "socket: All ports in use\n"); 81 else 82 perror("rcmd: socket"); 83 sigsetmask(oldmask); 84 return (-1); 85 } 86 fcntl(s, F_SETOWN, pid); 87 sin.sin_family = hp->h_addrtype; 88 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); 89 sin.sin_port = rport; 90 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 91 break; 92 (void) close(s); 93 if (errno == EADDRINUSE) { 94 lport--; 95 continue; 96 } 97 if (errno == ECONNREFUSED && timo <= 16) { 98 sleep(timo); 99 timo *= 2; 100 continue; 101 } 102 if (hp->h_addr_list[1] != NULL) { 103 int oerrno = errno; 104 105 fprintf(stderr, 106 "connect to address %s: ", inet_ntoa(sin.sin_addr)); 107 errno = oerrno; 108 perror(0); 109 hp->h_addr_list++; 110 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, 111 hp->h_length); 112 fprintf(stderr, "Trying %s...\n", 113 inet_ntoa(sin.sin_addr)); 114 continue; 115 } 116 perror(hp->h_name); 117 sigsetmask(oldmask); 118 return (-1); 119 } 120 lport--; 121 if (fd2p == 0) { 122 write(s, "", 1); 123 lport = 0; 124 } else { 125 char num[8]; 126 int s2 = rresvport(&lport), s3; 127 int len = sizeof (from); 128 129 if (s2 < 0) 130 goto bad; 131 listen(s2, 1); 132 (void) sprintf(num, "%d", lport); 133 if (write(s, num, strlen(num)+1) != strlen(num)+1) { 134 perror("write: setting up stderr"); 135 (void) close(s2); 136 goto bad; 137 } 138 FD_ZERO(&reads); 139 FD_SET(s, &reads); 140 FD_SET(s2, &reads); 141 errno = 0; 142 if (select(32, &reads, 0, 0, 0) < 1 || 143 !FD_ISSET(s2, &reads)) { 144 if (errno != 0) 145 perror("select: setting up stderr"); 146 else 147 fprintf(stderr, 148 "select: protocol failure in circuit setup.\n"); 149 (void) close(s2); 150 goto bad; 151 } 152 s3 = accept(s2, (struct sockaddr *)&from, &len); 153 (void) close(s2); 154 if (s3 < 0) { 155 perror("accept"); 156 lport = 0; 157 goto bad; 158 } 159 *fd2p = s3; 160 from.sin_port = ntohs((u_short)from.sin_port); 161 if (from.sin_family != AF_INET || 162 from.sin_port >= IPPORT_RESERVED || 163 from.sin_port < IPPORT_RESERVED / 2) { 164 fprintf(stderr, 165 "socket: protocol failure in circuit setup.\n"); 166 goto bad2; 167 } 168 } 169 (void) write(s, locuser, strlen(locuser)+1); 170 (void) write(s, remuser, strlen(remuser)+1); 171 (void) write(s, cmd, strlen(cmd)+1); 172 if (read(s, &c, 1) != 1) { 173 perror(*ahost); 174 goto bad2; 175 } 176 if (c != 0) { 177 while (read(s, &c, 1) == 1) { 178 (void) write(2, &c, 1); 179 if (c == '\n') 180 break; 181 } 182 goto bad2; 183 } 184 sigsetmask(oldmask); 185 return (s); 186 bad2: 187 if (lport) 188 (void) close(*fd2p); 189 bad: 190 (void) close(s); 191 sigsetmask(oldmask); 192 return (-1); 193 } 194 195 rresvport(alport) 196 int *alport; 197 { 198 struct sockaddr_in sin; 199 int s; 200 201 sin.sin_family = AF_INET; 202 sin.sin_addr.s_addr = INADDR_ANY; 203 s = socket(AF_INET, SOCK_STREAM, 0); 204 if (s < 0) 205 return (-1); 206 for (;;) { 207 sin.sin_port = htons((u_short)*alport); 208 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 209 return (s); 210 if (errno != EADDRINUSE) { 211 (void) close(s); 212 return (-1); 213 } 214 (*alport)--; 215 if (*alport == IPPORT_RESERVED/2) { 216 (void) close(s); 217 errno = EAGAIN; /* close */ 218 return (-1); 219 } 220 } 221 } 222 223 int _check_rhosts_file = 1; 224 225 ruserok(rhost, superuser, ruser, luser) 226 const char *rhost, *ruser, *luser; 227 int superuser; 228 { 229 FILE *hostf; 230 char fhost[MAXHOSTNAMELEN]; 231 int first = 1; 232 register char *sp, *p; 233 int baselen = -1; 234 235 sp = (char *)rhost; 236 p = fhost; 237 while (*sp) { 238 if (*sp == '.') { 239 if (baselen == -1) 240 baselen = sp - rhost; 241 *p++ = *sp++; 242 } else { 243 *p++ = isupper(*sp) ? tolower(*sp++) : *sp++; 244 } 245 } 246 *p = '\0'; 247 hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r"); 248 again: 249 if (hostf) { 250 if (!_validuser(hostf, fhost, luser, ruser, baselen)) { 251 (void) fclose(hostf); 252 return(0); 253 } 254 (void) fclose(hostf); 255 } 256 if (first == 1 && (_check_rhosts_file || superuser)) { 257 struct stat sbuf; 258 struct passwd *pwd; 259 char pbuf[MAXPATHLEN]; 260 261 first = 0; 262 if ((pwd = getpwnam(luser)) == NULL) 263 return(-1); 264 (void)strcpy(pbuf, pwd->pw_dir); 265 (void)strcat(pbuf, "/.rhosts"); 266 if ((hostf = fopen(pbuf, "r")) == NULL) 267 return(-1); 268 /* 269 * if owned by someone other than user or root or if 270 * writeable by anyone but the owner, quit 271 */ 272 if (fstat(fileno(hostf), &sbuf) || 273 sbuf.st_uid && sbuf.st_uid != pwd->pw_uid || 274 sbuf.st_mode&022) { 275 fclose(hostf); 276 return(-1); 277 } 278 goto again; 279 } 280 return (-1); 281 } 282 283 /* don't make static, used by lpd(8) */ 284 _validuser(hostf, rhost, luser, ruser, baselen) 285 char *rhost, *luser, *ruser; 286 FILE *hostf; 287 int baselen; 288 { 289 register char *p; 290 char *user, ahost[MAXHOSTNAMELEN]; 291 static int _checkhost(); 292 293 while (fgets(ahost, sizeof (ahost), hostf)) { 294 p = ahost; 295 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 296 *p = isupper(*p) ? tolower(*p) : *p; 297 p++; 298 } 299 if (*p == ' ' || *p == '\t') { 300 *p++ = '\0'; 301 while (*p == ' ' || *p == '\t') 302 p++; 303 user = p; 304 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') 305 p++; 306 } else 307 user = p; 308 *p = '\0'; 309 if (_checkhost(rhost, ahost, baselen) && 310 !strcmp(ruser, *user ? user : luser)) { 311 return (0); 312 } 313 } 314 return (-1); 315 } 316 317 static 318 _checkhost(rhost, lhost, len) 319 char *rhost, *lhost; 320 int len; 321 { 322 static char ldomain[MAXHOSTNAMELEN + 1]; 323 static char *domainp = NULL; 324 static int nodomain = 0; 325 register char *cp; 326 327 if (len == -1) 328 return(!strcmp(rhost, lhost)); 329 if (strncmp(rhost, lhost, len)) 330 return(0); 331 if (!strcmp(rhost, lhost)) 332 return(1); 333 if (*(lhost + len) != '\0') 334 return(0); 335 if (nodomain) 336 return(0); 337 if (!domainp) { 338 if (gethostname(ldomain, sizeof(ldomain)) == -1) { 339 nodomain = 1; 340 return(0); 341 } 342 ldomain[MAXHOSTNAMELEN] = NULL; 343 if ((domainp = index(ldomain, '.')) == (char *)NULL) { 344 nodomain = 1; 345 return(0); 346 } 347 for (cp = ++domainp; *cp; ++cp) 348 if (isupper(*cp)) 349 *cp = tolower(*cp); 350 } 351 return(!strcmp(domainp, rhost + len +1)); 352 } 353