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