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