rsh.c revision 1591
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[] = "@(#)rsh.c 8.3 (Berkeley) 4/6/94"; 42#endif /* not lint */ 43 44/* 45 * $Source: mit/rsh/RCS/rsh.c,v $ 46 * $Header: mit/rsh/RCS/rsh.c,v 5.1 89/07/31 19:28:59 kfall Exp Locker: kfall $ 47 */ 48 49#include <sys/types.h> 50#include <sys/signal.h> 51#include <sys/socket.h> 52#include <sys/ioctl.h> 53#include <sys/file.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 <kerberosIV/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)); 89void usage __P((void)); 90void warning __P(()); 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 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 "8KLdek:l:nwx" 128#else 129#define OPTIONS "8KLdek:l:nw" 130#endif 131#else 132#define OPTIONS "8KLdel:nw" 133#endif 134 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 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 des_set_key(cred.session, schedule); 166 break; 167#endif 168#endif 169 case '?': 170 default: 171 usage(); 172 } 173 optind += argoff; 174 175 /* if haven't gotten a host yet, do so */ 176 if (!host && !(host = argv[optind++])) 177 usage(); 178 179 /* if no further arguments, must have been called as rlogin. */ 180 if (!argv[optind]) { 181 if (asrsh) 182 *argv = "rlogin"; 183 execv(_PATH_RLOGIN, argv); 184 err(1, "can't exec %s", _PATH_RLOGIN); 185 } 186 187 argc -= optind; 188 argv += optind; 189 190 if (!(pw = getpwuid(uid = getuid()))) 191 errx(1, "unknown user id"); 192 if (!user) 193 user = pw->pw_name; 194 195#ifdef KERBEROS 196#ifdef CRYPT 197 /* -x turns off -n */ 198 if (doencrypt) 199 nflag = 0; 200#endif 201#endif 202 203 args = copyargs(argv); 204 205 sp = NULL; 206#ifdef KERBEROS 207 if (use_kerberos) { 208 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); 209 if (sp == NULL) { 210 use_kerberos = 0; 211 warning("can't get entry for %s/tcp service", 212 doencrypt ? "ekshell" : "kshell"); 213 } 214 } 215#endif 216 if (sp == NULL) 217 sp = getservbyname("shell", "tcp"); 218 if (sp == NULL) 219 errx(1, "shell/tcp: unknown service"); 220 221#ifdef KERBEROS 222try_connect: 223 if (use_kerberos) { 224 struct hostent *hp; 225 226 /* fully qualify hostname (needed for krb_realmofhost) */ 227 hp = gethostbyname(host); 228 if (hp != NULL && !(host = strdup(hp->h_name))) 229 err(1, NULL); 230 231 rem = KSUCCESS; 232 errno = 0; 233 if (dest_realm == NULL) 234 dest_realm = krb_realmofhost(host); 235 236#ifdef CRYPT 237 if (doencrypt) 238 rem = krcmd_mutual(&host, sp->s_port, user, args, 239 &rfd2, dest_realm, &cred, schedule); 240 else 241#endif 242 rem = krcmd(&host, sp->s_port, user, args, &rfd2, 243 dest_realm); 244 if (rem < 0) { 245 use_kerberos = 0; 246 sp = getservbyname("shell", "tcp"); 247 if (sp == NULL) 248 errx(1, "shell/tcp: unknown service"); 249 if (errno == ECONNREFUSED) 250 warning("remote host doesn't support Kerberos"); 251 if (errno == ENOENT) 252 warning("can't provide Kerberos auth data"); 253 goto try_connect; 254 } 255 } else { 256 if (doencrypt) 257 errx(1, "the -x flag requires Kerberos authentication"); 258 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 259 } 260#else 261 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); 262#endif 263 264 if (rem < 0) 265 exit(1); 266 267 if (rfd2 < 0) 268 errx(1, "can't establish stderr"); 269 if (dflag) { 270 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 271 sizeof(one)) < 0) 272 warn("setsockopt"); 273 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, 274 sizeof(one)) < 0) 275 warn("setsockopt"); 276 } 277 278 (void)setuid(uid); 279 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); 280 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 281 (void)signal(SIGINT, sendsig); 282 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 283 (void)signal(SIGQUIT, sendsig); 284 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 285 (void)signal(SIGTERM, sendsig); 286 287 if (!nflag) { 288 pid = fork(); 289 if (pid < 0) 290 err(1, "fork"); 291 } 292 293#ifdef KERBEROS 294#ifdef CRYPT 295 if (!doencrypt) 296#endif 297#endif 298 { 299 (void)ioctl(rfd2, FIONBIO, &one); 300 (void)ioctl(rem, FIONBIO, &one); 301 } 302 303 talk(nflag, omask, pid, rem); 304 305 if (!nflag) 306 (void)kill(pid, SIGKILL); 307 exit(0); 308} 309 310void 311talk(nflag, omask, pid, rem) 312 int nflag; 313 long omask; 314 pid_t pid; 315 int rem; 316{ 317 int cc, wc; 318 fd_set readfrom, ready, rembits; 319 char *bp, buf[BUFSIZ]; 320 321 if (!nflag && pid == 0) { 322 (void)close(rfd2); 323 324reread: errno = 0; 325 if ((cc = read(0, buf, sizeof buf)) <= 0) 326 goto done; 327 bp = buf; 328 329rewrite: 330 FD_ZERO(&rembits); 331 FD_SET(rem, &rembits); 332 if (select(16, 0, &rembits, 0, 0) < 0) { 333 if (errno != EINTR) 334 err(1, "select"); 335 goto rewrite; 336 } 337 if (!FD_ISSET(rem, &rembits)) 338 goto rewrite; 339#ifdef KERBEROS 340#ifdef CRYPT 341 if (doencrypt) 342 wc = des_write(rem, bp, cc); 343 else 344#endif 345#endif 346 wc = write(rem, bp, cc); 347 if (wc < 0) { 348 if (errno == EWOULDBLOCK) 349 goto rewrite; 350 goto done; 351 } 352 bp += wc; 353 cc -= wc; 354 if (cc == 0) 355 goto reread; 356 goto rewrite; 357done: 358 (void)shutdown(rem, 1); 359 exit(0); 360 } 361 362 (void)sigsetmask(omask); 363 FD_ZERO(&readfrom); 364 FD_SET(rfd2, &readfrom); 365 FD_SET(rem, &readfrom); 366 do { 367 ready = readfrom; 368 if (select(16, &ready, 0, 0, 0) < 0) { 369 if (errno != EINTR) 370 err(1, "select"); 371 continue; 372 } 373 if (FD_ISSET(rfd2, &ready)) { 374 errno = 0; 375#ifdef KERBEROS 376#ifdef CRYPT 377 if (doencrypt) 378 cc = des_read(rfd2, buf, sizeof buf); 379 else 380#endif 381#endif 382 cc = read(rfd2, buf, sizeof buf); 383 if (cc <= 0) { 384 if (errno != EWOULDBLOCK) 385 FD_CLR(rfd2, &readfrom); 386 } else 387 (void)write(2, buf, cc); 388 } 389 if (FD_ISSET(rem, &ready)) { 390 errno = 0; 391#ifdef KERBEROS 392#ifdef CRYPT 393 if (doencrypt) 394 cc = des_read(rem, buf, sizeof buf); 395 else 396#endif 397#endif 398 cc = read(rem, buf, sizeof buf); 399 if (cc <= 0) { 400 if (errno != EWOULDBLOCK) 401 FD_CLR(rem, &readfrom); 402 } else 403 (void)write(1, buf, cc); 404 } 405 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); 406} 407 408void 409sendsig(sig) 410 int sig; 411{ 412 char signo; 413 414 signo = sig; 415#ifdef KERBEROS 416#ifdef CRYPT 417 if (doencrypt) 418 (void)des_write(rfd2, &signo, 1); 419 else 420#endif 421#endif 422 (void)write(rfd2, &signo, 1); 423} 424 425#ifdef KERBEROS 426/* VARARGS */ 427void 428warning(va_alist) 429va_dcl 430{ 431 va_list ap; 432 char *fmt; 433 434 (void)fprintf(stderr, "rsh: warning, using standard rsh: "); 435 va_start(ap); 436 fmt = va_arg(ap, char *); 437 vfprintf(stderr, fmt, ap); 438 va_end(ap); 439 (void)fprintf(stderr, ".\n"); 440} 441#endif 442 443char * 444copyargs(argv) 445 char **argv; 446{ 447 int cc; 448 char **ap, *args, *p; 449 450 cc = 0; 451 for (ap = argv; *ap; ++ap) 452 cc += strlen(*ap) + 1; 453 if (!(args = malloc((u_int)cc))) 454 err(1, NULL); 455 for (p = args, ap = argv; *ap; ++ap) { 456 (void)strcpy(p, *ap); 457 for (p = strcpy(p, *ap); *p; ++p); 458 if (ap[1]) 459 *p++ = ' '; 460 } 461 return (args); 462} 463 464void 465usage() 466{ 467 468 (void)fprintf(stderr, 469 "usage: rsh [-nd%s]%s[-l login] host [command]\n", 470#ifdef KERBEROS 471#ifdef CRYPT 472 "x", " [-k realm] "); 473#else 474 "", " [-k realm] "); 475#endif 476#else 477 "", " "); 478#endif 479 exit(1); 480} 481