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.3 (Berkeley) 04/06/94"; 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 if (!user) 167 user = pw->pw_name; 168 169 #ifdef KERBEROS 170 #ifdef CRYPT 171 /* -x turns off -n */ 172 if (doencrypt) 173 nflag = 0; 174 #endif 175 #endif 176 177 args = copyargs(argv); 178 179 sp = NULL; 180 #ifdef KERBEROS 181 if (use_kerberos) { 182 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); 183 if (sp == NULL) { 184 use_kerberos = 0; 185 warning("can't get entry for %s/tcp service", 186 doencrypt ? "ekshell" : "kshell"); 187 } 188 } 189 #endif 190 if (sp == NULL) 191 sp = getservbyname("shell", "tcp"); 192 if (sp == NULL) 193 errx(1, "shell/tcp: unknown service"); 194 195 #ifdef KERBEROS 196 try_connect: 197 if (use_kerberos) { 198 struct hostent *hp; 199 200 /* fully qualify hostname (needed for krb_realmofhost) */ 201 hp = gethostbyname(host); 202 if (hp != NULL && !(host = strdup(hp->h_name))) 203 err(1, NULL); 204 205 rem = KSUCCESS; 206 errno = 0; 207 if (dest_realm == NULL) 208 dest_realm = krb_realmofhost(host); 209 210 #ifdef CRYPT 211 if (doencrypt) 212 rem = krcmd_mutual(&host, sp->s_port, user, args, 213 &rfd2, dest_realm, &cred, schedule); 214 else 215 #endif 216 rem = krcmd(&host, sp->s_port, user, args, &rfd2, 217 dest_realm); 218 if (rem < 0) { 219 use_kerberos = 0; 220 sp = getservbyname("shell", "tcp"); 221 if (sp == NULL) 222 errx(1, "shell/tcp: unknown service"); 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 errx(1, "the -x flag requires Kerberos authentication"); 232 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 233 } 234 #else 235 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 236 #endif 237 238 if (rem < 0) 239 exit(1); 240 241 if (rfd2 < 0) 242 errx(1, "can't establish stderr"); 243 if (dflag) { 244 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 245 sizeof(one)) < 0) 246 warn("setsockopt"); 247 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, 248 sizeof(one)) < 0) 249 warn("setsockopt"); 250 } 251 252 (void)setuid(uid); 253 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); 254 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 255 (void)signal(SIGINT, sendsig); 256 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 257 (void)signal(SIGQUIT, sendsig); 258 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 259 (void)signal(SIGTERM, sendsig); 260 261 if (!nflag) { 262 pid = fork(); 263 if (pid < 0) 264 err(1, "fork"); 265 } 266 267 #ifdef KERBEROS 268 #ifdef CRYPT 269 if (!doencrypt) 270 #endif 271 #endif 272 { 273 (void)ioctl(rfd2, FIONBIO, &one); 274 (void)ioctl(rem, FIONBIO, &one); 275 } 276 277 talk(nflag, omask, pid, rem); 278 279 if (!nflag) 280 (void)kill(pid, SIGKILL); 281 exit(0); 282 } 283 284 void 285 talk(nflag, omask, pid, rem) 286 int nflag; 287 long omask; 288 pid_t pid; 289 int rem; 290 { 291 int cc, wc; 292 fd_set readfrom, ready, rembits; 293 char *bp, buf[BUFSIZ]; 294 295 if (!nflag && pid == 0) { 296 (void)close(rfd2); 297 298 reread: errno = 0; 299 if ((cc = read(0, buf, sizeof buf)) <= 0) 300 goto done; 301 bp = buf; 302 303 rewrite: 304 FD_ZERO(&rembits); 305 FD_SET(rem, &rembits); 306 if (select(16, 0, &rembits, 0, 0) < 0) { 307 if (errno != EINTR) 308 err(1, "select"); 309 goto rewrite; 310 } 311 if (!FD_ISSET(rem, &rembits)) 312 goto rewrite; 313 #ifdef KERBEROS 314 #ifdef CRYPT 315 if (doencrypt) 316 wc = des_write(rem, bp, cc); 317 else 318 #endif 319 #endif 320 wc = write(rem, bp, cc); 321 if (wc < 0) { 322 if (errno == EWOULDBLOCK) 323 goto rewrite; 324 goto done; 325 } 326 bp += wc; 327 cc -= wc; 328 if (cc == 0) 329 goto reread; 330 goto rewrite; 331 done: 332 (void)shutdown(rem, 1); 333 exit(0); 334 } 335 336 (void)sigsetmask(omask); 337 FD_ZERO(&readfrom); 338 FD_SET(rfd2, &readfrom); 339 FD_SET(rem, &readfrom); 340 do { 341 ready = readfrom; 342 if (select(16, &ready, 0, 0, 0) < 0) { 343 if (errno != EINTR) 344 err(1, "select"); 345 continue; 346 } 347 if (FD_ISSET(rfd2, &ready)) { 348 errno = 0; 349 #ifdef KERBEROS 350 #ifdef CRYPT 351 if (doencrypt) 352 cc = des_read(rfd2, buf, sizeof buf); 353 else 354 #endif 355 #endif 356 cc = read(rfd2, buf, sizeof buf); 357 if (cc <= 0) { 358 if (errno != EWOULDBLOCK) 359 FD_CLR(rfd2, &readfrom); 360 } else 361 (void)write(2, buf, cc); 362 } 363 if (FD_ISSET(rem, &ready)) { 364 errno = 0; 365 #ifdef KERBEROS 366 #ifdef CRYPT 367 if (doencrypt) 368 cc = des_read(rem, buf, sizeof buf); 369 else 370 #endif 371 #endif 372 cc = read(rem, buf, sizeof buf); 373 if (cc <= 0) { 374 if (errno != EWOULDBLOCK) 375 FD_CLR(rem, &readfrom); 376 } else 377 (void)write(1, buf, cc); 378 } 379 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); 380 } 381 382 void 383 sendsig(sig) 384 int sig; 385 { 386 char signo; 387 388 signo = sig; 389 #ifdef KERBEROS 390 #ifdef CRYPT 391 if (doencrypt) 392 (void)des_write(rfd2, &signo, 1); 393 else 394 #endif 395 #endif 396 (void)write(rfd2, &signo, 1); 397 } 398 399 #ifdef KERBEROS 400 /* VARARGS */ 401 void 402 warning(va_alist) 403 va_dcl 404 { 405 va_list ap; 406 char *fmt; 407 408 (void)fprintf(stderr, "rsh: warning, using standard rsh: "); 409 va_start(ap); 410 fmt = va_arg(ap, char *); 411 vfprintf(stderr, fmt, ap); 412 va_end(ap); 413 (void)fprintf(stderr, ".\n"); 414 } 415 #endif 416 417 char * 418 copyargs(argv) 419 char **argv; 420 { 421 int cc; 422 char **ap, *args, *p; 423 424 cc = 0; 425 for (ap = argv; *ap; ++ap) 426 cc += strlen(*ap) + 1; 427 if (!(args = malloc((u_int)cc))) 428 err(1, NULL); 429 for (p = args, ap = argv; *ap; ++ap) { 430 (void)strcpy(p, *ap); 431 for (p = strcpy(p, *ap); *p; ++p); 432 if (ap[1]) 433 *p++ = ' '; 434 } 435 return (args); 436 } 437 438 void 439 usage() 440 { 441 442 (void)fprintf(stderr, 443 "usage: rsh [-nd%s]%s[-l login] host [command]\n", 444 #ifdef KERBEROS 445 #ifdef CRYPT 446 "x", " [-k realm] "); 447 #else 448 "", " [-k realm] "); 449 #endif 450 #else 451 "", " "); 452 #endif 453 exit(1); 454 } 455