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