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