1 /*- 2 * Copyright (c) 1983, 1990 The 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 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/ 42 static char rcsid[] = "$Id: rsh.c,v 1.2 1993/08/01 18:09:05 mycroft Exp $"; 43 #endif /* not lint */ 44 45 /* 46 * $Source: /cvsroot/src/usr.bin/rsh/rsh.c,v $ 47 * $Header: /cvsroot/src/usr.bin/rsh/rsh.c,v 1.2 1993/08/01 18:09:05 mycroft Exp $ 48 */ 49 50 #include <sys/types.h> 51 #include <sys/signal.h> 52 #include <sys/socket.h> 53 #include <sys/ioctl.h> 54 #include <sys/file.h> 55 56 #include <netinet/in.h> 57 #include <netdb.h> 58 59 #include <pwd.h> 60 #include <stdio.h> 61 #include <errno.h> 62 #include <string.h> 63 #include <varargs.h> 64 #include "pathnames.h" 65 66 #ifdef KERBEROS 67 #include <kerberosIV/des.h> 68 #include <kerberosIV/krb.h> 69 70 CREDENTIALS cred; 71 Key_schedule schedule; 72 int use_kerberos = 1, doencrypt; 73 char dst_realm_buf[REALM_SZ], *dest_realm; 74 extern char *krb_realmofhost(); 75 #endif 76 77 /* 78 * rsh - remote shell 79 */ 80 extern int errno; 81 int rfd2; 82 83 main(argc, argv) 84 int argc; 85 char **argv; 86 { 87 extern char *optarg; 88 extern int optind; 89 struct passwd *pw; 90 struct servent *sp; 91 long omask; 92 int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid; 93 register char *p; 94 char *args, *host, *user, *copyargs(); 95 void sendsig(); 96 97 argoff = asrsh = dflag = nflag = 0; 98 one = 1; 99 host = user = NULL; 100 101 /* if called as something other than "rsh", use it as the host name */ 102 if (p = rindex(argv[0], '/')) 103 ++p; 104 else 105 p = argv[0]; 106 if (strcmp(p, "rsh")) 107 host = p; 108 else 109 asrsh = 1; 110 111 /* handle "rsh host flags" */ 112 if (!host && argc > 2 && argv[1][0] != '-') { 113 host = argv[1]; 114 argoff = 1; 115 } 116 117 #ifdef KERBEROS 118 #ifdef CRYPT 119 #define OPTIONS "8KLdek:l:nwx" 120 #else 121 #define OPTIONS "8KLdek:l:nw" 122 #endif 123 #else 124 #define OPTIONS "8KLdel:nw" 125 #endif 126 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 127 switch(ch) { 128 case 'K': 129 #ifdef KERBEROS 130 use_kerberos = 0; 131 #endif 132 break; 133 case 'L': /* -8Lew are ignored to allow rlogin aliases */ 134 case 'e': 135 case 'w': 136 case '8': 137 break; 138 case 'd': 139 dflag = 1; 140 break; 141 case 'l': 142 user = optarg; 143 break; 144 #ifdef KERBEROS 145 case 'k': 146 dest_realm = dst_realm_buf; 147 strncpy(dest_realm, optarg, REALM_SZ); 148 break; 149 #endif 150 case 'n': 151 nflag = 1; 152 break; 153 #ifdef KERBEROS 154 #ifdef CRYPT 155 case 'x': 156 doencrypt = 1; 157 des_set_key(cred.session, schedule); 158 break; 159 #endif 160 #endif 161 case '?': 162 default: 163 usage(); 164 } 165 optind += argoff; 166 167 /* if haven't gotten a host yet, do so */ 168 if (!host && !(host = argv[optind++])) 169 usage(); 170 171 /* if no further arguments, must have been called as rlogin. */ 172 if (!argv[optind]) { 173 if (asrsh) 174 *argv = "rlogin"; 175 execv(_PATH_RLOGIN, argv); 176 (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN); 177 exit(1); 178 } 179 180 argc -= optind; 181 argv += optind; 182 183 if (!(pw = getpwuid(uid = getuid()))) { 184 (void)fprintf(stderr, "rsh: unknown user id.\n"); 185 exit(1); 186 } 187 if (!user) 188 user = pw->pw_name; 189 190 #ifdef KERBEROS 191 #ifdef CRYPT 192 /* -x turns off -n */ 193 if (doencrypt) 194 nflag = 0; 195 #endif 196 #endif 197 198 args = copyargs(argv); 199 200 sp = NULL; 201 #ifdef KERBEROS 202 if (use_kerberos) { 203 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); 204 if (sp == NULL) { 205 use_kerberos = 0; 206 warning("can't get entry for %s/tcp service", 207 doencrypt ? "ekshell" : "kshell"); 208 } 209 } 210 #endif 211 if (sp == NULL) 212 sp = getservbyname("shell", "tcp"); 213 if (sp == NULL) { 214 (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n"); 215 exit(1); 216 } 217 218 #ifdef KERBEROS 219 try_connect: 220 if (use_kerberos) { 221 rem = KSUCCESS; 222 errno = 0; 223 if (dest_realm == NULL) 224 dest_realm = krb_realmofhost(host); 225 226 #ifdef CRYPT 227 if (doencrypt) 228 rem = krcmd_mutual(&host, sp->s_port, user, args, 229 &rfd2, dest_realm, &cred, schedule); 230 else 231 #endif 232 rem = krcmd(&host, sp->s_port, user, args, &rfd2, 233 dest_realm); 234 if (rem < 0) { 235 use_kerberos = 0; 236 sp = getservbyname("shell", "tcp"); 237 if (sp == NULL) { 238 (void)fprintf(stderr, 239 "rsh: unknown service shell/tcp.\n"); 240 exit(1); 241 } 242 if (errno == ECONNREFUSED) 243 warning("remote host doesn't support Kerberos"); 244 if (errno == ENOENT) 245 warning("can't provide Kerberos auth data"); 246 goto try_connect; 247 } 248 } else { 249 if (doencrypt) { 250 (void)fprintf(stderr, 251 "rsh: the -x flag requires Kerberos authentication.\n"); 252 exit(1); 253 } 254 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 255 } 256 #else 257 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 258 #endif 259 260 if (rem < 0) 261 exit(1); 262 263 if (rfd2 < 0) { 264 (void)fprintf(stderr, "rsh: can't establish stderr.\n"); 265 exit(1); 266 } 267 if (dflag) { 268 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 269 sizeof(one)) < 0) 270 (void)fprintf(stderr, "rsh: setsockopt: %s.\n", 271 strerror(errno)); 272 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, 273 sizeof(one)) < 0) 274 (void)fprintf(stderr, "rsh: setsockopt: %s.\n", 275 strerror(errno)); 276 } 277 278 (void)setuid(uid); 279 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); 280 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 281 (void)signal(SIGINT, sendsig); 282 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 283 (void)signal(SIGQUIT, sendsig); 284 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 285 (void)signal(SIGTERM, sendsig); 286 287 if (!nflag) { 288 pid = fork(); 289 if (pid < 0) { 290 (void)fprintf(stderr, 291 "rsh: fork: %s.\n", strerror(errno)); 292 exit(1); 293 } 294 } 295 296 #ifdef KERBEROS 297 #ifdef CRYPT 298 if (!doencrypt) 299 #endif 300 #endif 301 { 302 (void)ioctl(rfd2, FIONBIO, &one); 303 (void)ioctl(rem, FIONBIO, &one); 304 } 305 306 talk(nflag, omask, pid, rem); 307 308 if (!nflag) 309 (void)kill(pid, SIGKILL); 310 exit(0); 311 } 312 313 talk(nflag, omask, pid, rem) 314 int nflag, pid; 315 long omask; 316 register int rem; 317 { 318 register int cc, wc; 319 register char *bp; 320 int readfrom, ready, rembits; 321 char buf[BUFSIZ]; 322 323 if (!nflag && pid == 0) { 324 (void)close(rfd2); 325 326 reread: errno = 0; 327 if ((cc = read(0, buf, sizeof buf)) <= 0) 328 goto done; 329 bp = buf; 330 331 rewrite: rembits = 1 << rem; 332 if (select(16, 0, &rembits, 0, 0) < 0) { 333 if (errno != EINTR) { 334 (void)fprintf(stderr, 335 "rsh: select: %s.\n", strerror(errno)); 336 exit(1); 337 } 338 goto rewrite; 339 } 340 if ((rembits & (1 << rem)) == 0) 341 goto rewrite; 342 #ifdef KERBEROS 343 #ifdef CRYPT 344 if (doencrypt) 345 wc = des_write(rem, bp, cc); 346 else 347 #endif 348 #endif 349 wc = write(rem, bp, cc); 350 if (wc < 0) { 351 if (errno == EWOULDBLOCK) 352 goto rewrite; 353 goto done; 354 } 355 bp += wc; 356 cc -= wc; 357 if (cc == 0) 358 goto reread; 359 goto rewrite; 360 done: 361 (void)shutdown(rem, 1); 362 exit(0); 363 } 364 365 (void)sigsetmask(omask); 366 readfrom = (1 << rfd2) | (1 << rem); 367 do { 368 ready = readfrom; 369 if (select(16, &ready, 0, 0, 0) < 0) { 370 if (errno != EINTR) { 371 (void)fprintf(stderr, 372 "rsh: select: %s.\n", strerror(errno)); 373 exit(1); 374 } 375 continue; 376 } 377 if (ready & (1 << rfd2)) { 378 errno = 0; 379 #ifdef KERBEROS 380 #ifdef CRYPT 381 if (doencrypt) 382 cc = des_read(rfd2, buf, sizeof buf); 383 else 384 #endif 385 #endif 386 cc = read(rfd2, buf, sizeof buf); 387 if (cc <= 0) { 388 if (errno != EWOULDBLOCK) 389 readfrom &= ~(1 << rfd2); 390 } else 391 (void)write(2, buf, cc); 392 } 393 if (ready & (1 << rem)) { 394 errno = 0; 395 #ifdef KERBEROS 396 #ifdef CRYPT 397 if (doencrypt) 398 cc = des_read(rem, buf, sizeof buf); 399 else 400 #endif 401 #endif 402 cc = read(rem, buf, sizeof buf); 403 if (cc <= 0) { 404 if (errno != EWOULDBLOCK) 405 readfrom &= ~(1 << rem); 406 } else 407 (void)write(1, buf, cc); 408 } 409 } while (readfrom); 410 } 411 412 void 413 sendsig(signo) 414 char signo; 415 { 416 #ifdef KERBEROS 417 #ifdef CRYPT 418 if (doencrypt) 419 (void)des_write(rfd2, &signo, 1); 420 else 421 #endif 422 #endif 423 (void)write(rfd2, &signo, 1); 424 } 425 426 #ifdef KERBEROS 427 /* VARARGS */ 428 warning(va_alist) 429 va_dcl 430 { 431 va_list ap; 432 char *fmt; 433 434 (void)fprintf(stderr, "rsh: warning, using standard rsh: "); 435 va_start(ap); 436 fmt = va_arg(ap, char *); 437 vfprintf(stderr, fmt, ap); 438 va_end(ap); 439 (void)fprintf(stderr, ".\n"); 440 } 441 #endif 442 443 char * 444 copyargs(argv) 445 char **argv; 446 { 447 register int cc; 448 register char **ap, *p; 449 char *args, *malloc(); 450 451 cc = 0; 452 for (ap = argv; *ap; ++ap) 453 cc += strlen(*ap) + 1; 454 if (!(args = malloc((u_int)cc))) { 455 (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM)); 456 exit(1); 457 } 458 for (p = args, ap = argv; *ap; ++ap) { 459 (void)strcpy(p, *ap); 460 for (p = strcpy(p, *ap); *p; ++p); 461 if (ap[1]) 462 *p++ = ' '; 463 } 464 return(args); 465 } 466 467 usage() 468 { 469 (void)fprintf(stderr, 470 "usage: rsh [-nd%s]%s[-l login] host [command]\n", 471 #ifdef KERBEROS 472 #ifdef CRYPT 473 "x", " [-k realm] "); 474 #else 475 "", " [-k realm] "); 476 #endif 477 #else 478 "", " "); 479 #endif 480 exit(1); 481 } 482