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