rsh.c revision 29922
1/*- 2 * Copyright (c) 1983, 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1990, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94"; 43#endif 44static char rcsid[] = 45 "$Id$"; 46#endif /* not lint */ 47 48#include <sys/types.h> 49#include <sys/signal.h> 50#include <sys/socket.h> 51#include <sys/ioctl.h> 52#include <sys/file.h> 53#include <sys/time.h> 54 55#include <netinet/in.h> 56#include <netdb.h> 57 58#include <err.h> 59#include <errno.h> 60#include <pwd.h> 61#include <signal.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <unistd.h> 66#include <err.h> 67 68#include "pathnames.h" 69 70#ifdef KERBEROS 71#include <des.h> 72#include <krb.h> 73#include "krb.h" 74 75CREDENTIALS cred; 76Key_schedule schedule; 77int use_kerberos = 1, doencrypt; 78char dst_realm_buf[REALM_SZ], *dest_realm; 79extern char *krb_realmofhost(); 80#endif 81 82/* 83 * rsh - remote shell 84 */ 85int rfd2; 86 87char *copyargs __P((char **)); 88void sendsig __P((int)); 89void talk __P((int, long, pid_t, int, int)); 90void usage __P((void)); 91 92int 93main(argc, argv) 94 int argc; 95 char **argv; 96{ 97 struct passwd *pw; 98 struct servent *sp; 99 long omask; 100 int argoff, asrsh, ch, dflag, nflag, one, rem; 101 pid_t pid; 102 uid_t uid; 103 char *args, *host, *p, *user; 104 int timeout = 0; 105 106 argoff = asrsh = dflag = nflag = 0; 107 one = 1; 108 host = user = NULL; 109 110 /* if called as something other than "rsh", use it as the host name */ 111 if ((p = strrchr(argv[0], '/'))) 112 ++p; 113 else 114 p = argv[0]; 115 if (strcmp(p, "rsh")) 116 host = p; 117 else 118 asrsh = 1; 119 120 /* handle "rsh host flags" */ 121 if (!host && argc > 2 && argv[1][0] != '-') { 122 host = argv[1]; 123 argoff = 1; 124 } 125 126#ifdef KERBEROS 127#ifdef CRYPT 128#define OPTIONS "8KLde:k:l:nt:wx" 129#else 130#define OPTIONS "8KLde:k:l:nt:w" 131#endif 132#else 133#define OPTIONS "8KLde:l:nt:w" 134#endif 135 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 136 switch(ch) { 137 case 'K': 138#ifdef KERBEROS 139 use_kerberos = 0; 140#endif 141 break; 142 case 'L': /* -8Lew are ignored to allow rlogin aliases */ 143 case 'e': 144 case 'w': 145 case '8': 146 break; 147 case 'd': 148 dflag = 1; 149 break; 150 case 'l': 151 user = optarg; 152 break; 153#ifdef KERBEROS 154 case 'k': 155 dest_realm = dst_realm_buf; 156 strncpy(dest_realm, optarg, REALM_SZ); 157 break; 158#endif 159 case 'n': 160 nflag = 1; 161 break; 162#ifdef KERBEROS 163#ifdef CRYPT 164 case 'x': 165 doencrypt = 1; 166 break; 167#endif 168#endif 169 case 't': 170 timeout = atoi(optarg); 171 break; 172 case '?': 173 default: 174 usage(); 175 } 176 optind += argoff; 177 178 /* if haven't gotten a host yet, do so */ 179 if (!host && !(host = argv[optind++])) 180 usage(); 181 182 /* if no further arguments, must have been called as rlogin. */ 183 if (!argv[optind]) { 184 if (asrsh) 185 *argv = "rlogin"; 186 execv(_PATH_RLOGIN, argv); 187 err(1, "can't exec %s", _PATH_RLOGIN); 188 } 189 190 argc -= optind; 191 argv += optind; 192 193 if (!(pw = getpwuid(uid = getuid()))) 194 errx(1, "unknown user id"); 195 if (!user) 196 user = pw->pw_name; 197 198#ifdef KERBEROS 199#ifdef CRYPT 200 /* -x turns off -n */ 201 if (doencrypt) 202 nflag = 0; 203#endif 204#endif 205 206 args = copyargs(argv); 207 208 sp = NULL; 209#ifdef KERBEROS 210 if (use_kerberos) { 211 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); 212 if (sp == NULL) { 213 use_kerberos = 0; 214 warnx( 215 "warning, using standard rsh: can't get entry for %s/tcp service", 216 doencrypt ? "ekshell" : "kshell"); 217 } 218 } 219#endif 220 if (sp == NULL) 221 sp = getservbyname("shell", "tcp"); 222 if (sp == NULL) 223 errx(1, "shell/tcp: unknown service"); 224 225#ifdef KERBEROS 226try_connect: 227 if (use_kerberos) { 228 struct hostent *hp; 229 230 /* fully qualify hostname (needed for krb_realmofhost) */ 231 hp = gethostbyname(host); 232 if (hp != NULL && !(host = strdup(hp->h_name))) 233 err(1, NULL); 234 235 rem = KSUCCESS; 236 errno = 0; 237 if (dest_realm == NULL) 238 dest_realm = krb_realmofhost(host); 239 240#ifdef CRYPT 241 if (doencrypt) { 242 rem = krcmd_mutual(&host, sp->s_port, user, args, 243 &rfd2, dest_realm, &cred, schedule); 244 des_set_key(&cred.session, schedule); 245 } else 246#endif 247 rem = krcmd(&host, sp->s_port, user, args, &rfd2, 248 dest_realm); 249 if (rem < 0) { 250 use_kerberos = 0; 251 sp = getservbyname("shell", "tcp"); 252 if (sp == NULL) 253 errx(1, "shell/tcp: unknown service"); 254 if (errno == ECONNREFUSED) 255 warnx( 256 "warning, using standard rsh: remote host doesn't support Kerberos"); 257 if (errno == ENOENT) 258 warnx( 259 "warning, using standard rsh: can't provide Kerberos auth data"); 260 goto try_connect; 261 } 262 } else { 263 if (doencrypt) 264 errx(1, "the -x flag requires Kerberos authentication"); 265 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 266 } 267#else 268 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 269#endif 270 271 if (rem < 0) 272 exit(1); 273 274 if (rfd2 < 0) 275 errx(1, "can't establish stderr"); 276 if (dflag) { 277 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 278 sizeof(one)) < 0) 279 warn("setsockopt"); 280 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, 281 sizeof(one)) < 0) 282 warn("setsockopt"); 283 } 284 285 (void)setuid(uid); 286 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); 287 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 288 (void)signal(SIGINT, sendsig); 289 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 290 (void)signal(SIGQUIT, sendsig); 291 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 292 (void)signal(SIGTERM, sendsig); 293 294 if (!nflag) { 295 pid = fork(); 296 if (pid < 0) 297 err(1, "fork"); 298 } 299 300#ifdef KERBEROS 301#ifdef CRYPT 302 if (!doencrypt) 303#endif 304#endif 305 { 306 (void)ioctl(rfd2, FIONBIO, &one); 307 (void)ioctl(rem, FIONBIO, &one); 308 } 309 310 talk(nflag, omask, pid, rem, timeout); 311 312 if (!nflag) 313 (void)kill(pid, SIGKILL); 314 exit(0); 315} 316 317void 318talk(nflag, omask, pid, rem, timeout) 319 int nflag; 320 long omask; 321 pid_t pid; 322 int rem; 323{ 324 int cc, wc; 325 fd_set readfrom, ready, rembits; 326 char *bp, buf[BUFSIZ]; 327 struct timeval tvtimeout; 328 int srval; 329 330 if (!nflag && pid == 0) { 331 (void)close(rfd2); 332 333reread: errno = 0; 334 if ((cc = read(0, buf, sizeof buf)) <= 0) 335 goto done; 336 bp = buf; 337 338rewrite: 339 FD_ZERO(&rembits); 340 FD_SET(rem, &rembits); 341 if (select(16, 0, &rembits, 0, 0) < 0) { 342 if (errno != EINTR) 343 err(1, "select"); 344 goto rewrite; 345 } 346 if (!FD_ISSET(rem, &rembits)) 347 goto rewrite; 348#ifdef KERBEROS 349#ifdef CRYPT 350 if (doencrypt) 351 wc = des_enc_write(rem, bp, cc, schedule, &cred.session); 352 else 353#endif 354#endif 355 wc = write(rem, bp, cc); 356 if (wc < 0) { 357 if (errno == EWOULDBLOCK) 358 goto rewrite; 359 goto done; 360 } 361 bp += wc; 362 cc -= wc; 363 if (cc == 0) 364 goto reread; 365 goto rewrite; 366done: 367 (void)shutdown(rem, 1); 368 exit(0); 369 } 370 371 tvtimeout.tv_sec = timeout; 372 tvtimeout.tv_usec = 0; 373 374 (void)sigsetmask(omask); 375 FD_ZERO(&readfrom); 376 FD_SET(rfd2, &readfrom); 377 FD_SET(rem, &readfrom); 378 do { 379 ready = readfrom; 380 if (timeout) { 381 srval = select(16, &ready, 0, 0, &tvtimeout); 382 } else { 383 srval = select(16, &ready, 0, 0, 0); 384 } 385 386 if (srval < 0) { 387 if (errno != EINTR) 388 err(1, "select"); 389 continue; 390 } 391 if (srval == 0) 392 errx(1, "timeout reached (%d seconds)\n", timeout); 393 if (FD_ISSET(rfd2, &ready)) { 394 errno = 0; 395#ifdef KERBEROS 396#ifdef CRYPT 397 if (doencrypt) 398 cc = des_enc_read(rfd2, buf, sizeof buf, schedule, &cred.session); 399 else 400#endif 401#endif 402 cc = read(rfd2, buf, sizeof buf); 403 if (cc <= 0) { 404 if (errno != EWOULDBLOCK) 405 FD_CLR(rfd2, &readfrom); 406 } else 407 (void)write(2, buf, cc); 408 } 409 if (FD_ISSET(rem, &ready)) { 410 errno = 0; 411#ifdef KERBEROS 412#ifdef CRYPT 413 if (doencrypt) 414 cc = des_enc_read(rem, buf, sizeof buf, schedule, &cred.session); 415 else 416#endif 417#endif 418 cc = read(rem, buf, sizeof buf); 419 if (cc <= 0) { 420 if (errno != EWOULDBLOCK) 421 FD_CLR(rem, &readfrom); 422 } else 423 (void)write(1, buf, cc); 424 } 425 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); 426} 427 428void 429sendsig(sig) 430 int sig; 431{ 432 char signo; 433 434 signo = sig; 435#ifdef KERBEROS 436#ifdef CRYPT 437 if (doencrypt) 438 (void)des_enc_write(rfd2, &signo, 1, schedule, &cred.session); 439 else 440#endif 441#endif 442 (void)write(rfd2, &signo, 1); 443} 444 445char * 446copyargs(argv) 447 char **argv; 448{ 449 int cc; 450 char **ap, *args, *p; 451 452 cc = 0; 453 for (ap = argv; *ap; ++ap) 454 cc += strlen(*ap) + 1; 455 if (!(args = malloc((u_int)cc))) 456 err(1, NULL); 457 for (p = args, ap = argv; *ap; ++ap) { 458 (void)strcpy(p, *ap); 459 for (p = strcpy(p, *ap); *p; ++p); 460 if (ap[1]) 461 *p++ = ' '; 462 } 463 return (args); 464} 465 466void 467usage() 468{ 469 470 (void)fprintf(stderr, 471 "usage: rsh [-nd%s]%s[-l login] [-t timeout] host [command]\n", 472#ifdef KERBEROS 473#ifdef CRYPT 474 "x", " [-k realm] "); 475#else 476 "", " [-k realm] "); 477#endif 478#else 479 "", " "); 480#endif 481 exit(1); 482} 483 484