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