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