11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1983, 1990, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 496196Sdes * Copyright (c) 2002 Networks Associates Technology, Inc. 596196Sdes * All rights reserved. 61590Srgrimes * 796196Sdes * Portions of this software were developed for the FreeBSD Project by 896196Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network 996196Sdes * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1096196Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 1196196Sdes * 121590Srgrimes * Redistribution and use in source and binary forms, with or without 131590Srgrimes * modification, are permitted provided that the following conditions 141590Srgrimes * are met: 151590Srgrimes * 1. Redistributions of source code must retain the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer. 171590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181590Srgrimes * notice, this list of conditions and the following disclaimer in the 191590Srgrimes * documentation and/or other materials provided with the distribution. 201590Srgrimes * 3. All advertising materials mentioning features or use of this software 211590Srgrimes * must display the following acknowledgement: 221590Srgrimes * This product includes software developed by the University of 231590Srgrimes * California, Berkeley and its contributors. 241590Srgrimes * 4. Neither the name of the University nor the names of its contributors 251590Srgrimes * may be used to endorse or promote products derived from this software 261590Srgrimes * without specific prior written permission. 271590Srgrimes * 281590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 291590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 301590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 311590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 321590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 361590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 371590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 381590Srgrimes * SUCH DAMAGE. 391590Srgrimes */ 401590Srgrimes 411590Srgrimes#ifndef lint 4227954Scharnierstatic const char copyright[] = 431590Srgrimes"@(#) Copyright (c) 1983, 1990, 1993, 1994\n\ 441590Srgrimes The Regents of the University of California. All rights reserved.\n"; 451590Srgrimes#endif /* not lint */ 461590Srgrimes 47119850Scharnier#if 0 481590Srgrimes#ifndef lint 4993022Smarkmstatic const char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94"; 501590Srgrimes#endif /* not lint */ 51119850Scharnier#endif 521590Srgrimes 5393022Smarkm#include <sys/cdefs.h> 5493022Smarkm__FBSDID("$FreeBSD: stable/10/usr.bin/rsh/rsh.c 325474 2017-11-06 12:45:51Z eugen $"); 5593022Smarkm 5643851Sdes#include <sys/param.h> 571590Srgrimes#include <sys/signal.h> 581590Srgrimes#include <sys/socket.h> 591590Srgrimes#include <sys/ioctl.h> 601590Srgrimes#include <sys/file.h> 6118067Sjkh#include <sys/time.h> 621590Srgrimes 631590Srgrimes#include <netinet/in.h> 641590Srgrimes#include <netdb.h> 651590Srgrimes 661590Srgrimes#include <err.h> 671590Srgrimes#include <errno.h> 6840103Smarkm#include <libutil.h> 6996196Sdes#include <paths.h> 701590Srgrimes#include <pwd.h> 711590Srgrimes#include <signal.h> 721590Srgrimes#include <stdio.h> 731590Srgrimes#include <stdlib.h> 741590Srgrimes#include <string.h> 751590Srgrimes#include <unistd.h> 761590Srgrimes 771590Srgrimes/* 781590Srgrimes * rsh - remote shell 791590Srgrimes */ 801590Srgrimesint rfd2; 811590Srgrimes 8257232Sshinint family = PF_UNSPEC; 8393022Smarkmchar rlogin[] = "rlogin"; 8457232Sshin 85101833Siedowsevoid connect_timeout(int); 8693412Sobrienchar *copyargs(char * const *); 8792921Simpvoid sendsig(int); 88325474Seugenvoid talk(int, int, long, pid_t, int, int); 8992921Simpvoid usage(void); 901590Srgrimes 911590Srgrimesint 9293022Smarkmmain(int argc, char *argv[]) 931590Srgrimes{ 9493412Sobrien struct passwd const *pw; 9593412Sobrien struct servent const *sp; 961590Srgrimes long omask; 97325474Seugen int argoff, asrsh, ch, dflag, nflag, Nflag, one, rem; 9833649Sjb pid_t pid = 0; 991590Srgrimes uid_t uid; 1001590Srgrimes char *args, *host, *p, *user; 10118067Sjkh int timeout = 0; 1021590Srgrimes 103325474Seugen argoff = asrsh = dflag = nflag = Nflag = 0; 1041590Srgrimes one = 1; 1051590Srgrimes host = user = NULL; 1061590Srgrimes 1071590Srgrimes /* if called as something other than "rsh", use it as the host name */ 10829922Smarkm if ((p = strrchr(argv[0], '/'))) 1091590Srgrimes ++p; 1101590Srgrimes else 1111590Srgrimes p = argv[0]; 1121590Srgrimes if (strcmp(p, "rsh")) 1131590Srgrimes host = p; 1141590Srgrimes else 1151590Srgrimes asrsh = 1; 1161590Srgrimes 1171590Srgrimes /* handle "rsh host flags" */ 1181590Srgrimes if (!host && argc > 2 && argv[1][0] != '-') { 1191590Srgrimes host = argv[1]; 1201590Srgrimes argoff = 1; 1211590Srgrimes } 1221590Srgrimes 123325474Seugen#define OPTIONS "468LNde:l:nt:w" 12424360Simp while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 1251590Srgrimes switch(ch) { 12657232Sshin case '4': 12757232Sshin family = PF_INET; 12857232Sshin break; 12957232Sshin 13057232Sshin case '6': 13157232Sshin family = PF_INET6; 13257232Sshin break; 13357232Sshin 134325474Seugen case 'N': 135325474Seugen Nflag = 1; 136325474Seugen nflag = 0; 137325474Seugen break; 1381590Srgrimes case 'L': /* -8Lew are ignored to allow rlogin aliases */ 1391590Srgrimes case 'e': 1401590Srgrimes case 'w': 1411590Srgrimes case '8': 1421590Srgrimes break; 1431590Srgrimes case 'd': 1441590Srgrimes dflag = 1; 1451590Srgrimes break; 1461590Srgrimes case 'l': 1471590Srgrimes user = optarg; 1481590Srgrimes break; 1491590Srgrimes case 'n': 1501590Srgrimes nflag = 1; 151325474Seugen Nflag = 0; 1521590Srgrimes break; 15318067Sjkh case 't': 15418067Sjkh timeout = atoi(optarg); 15518067Sjkh break; 1561590Srgrimes case '?': 1571590Srgrimes default: 1581590Srgrimes usage(); 1591590Srgrimes } 1601590Srgrimes optind += argoff; 1611590Srgrimes 1621590Srgrimes /* if haven't gotten a host yet, do so */ 1631590Srgrimes if (!host && !(host = argv[optind++])) 1641590Srgrimes usage(); 1651590Srgrimes 1661590Srgrimes /* if no further arguments, must have been called as rlogin. */ 1671590Srgrimes if (!argv[optind]) { 1681590Srgrimes if (asrsh) 16993022Smarkm *argv = rlogin; 1701590Srgrimes execv(_PATH_RLOGIN, argv); 1711590Srgrimes err(1, "can't exec %s", _PATH_RLOGIN); 1721590Srgrimes } 1731590Srgrimes 1741590Srgrimes argc -= optind; 1751590Srgrimes argv += optind; 1761590Srgrimes 1771590Srgrimes if (!(pw = getpwuid(uid = getuid()))) 1781590Srgrimes errx(1, "unknown user id"); 1791590Srgrimes if (!user) 1801590Srgrimes user = pw->pw_name; 1811590Srgrimes 1821590Srgrimes args = copyargs(argv); 1831590Srgrimes 1841590Srgrimes sp = NULL; 1851590Srgrimes if (sp == NULL) 1861590Srgrimes sp = getservbyname("shell", "tcp"); 1871590Srgrimes if (sp == NULL) 1881590Srgrimes errx(1, "shell/tcp: unknown service"); 1891590Srgrimes 190101833Siedowse if (timeout) { 191101833Siedowse signal(SIGALRM, connect_timeout); 192101833Siedowse alarm(timeout); 193101833Siedowse } 19456590Sshin rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2, 19557232Sshin family); 196101833Siedowse if (timeout) { 197101833Siedowse signal(SIGALRM, SIG_DFL); 198101833Siedowse alarm(0); 199101833Siedowse } 2001590Srgrimes 2011590Srgrimes if (rem < 0) 2021590Srgrimes exit(1); 2031590Srgrimes 2041590Srgrimes if (rfd2 < 0) 2051590Srgrimes errx(1, "can't establish stderr"); 2061590Srgrimes if (dflag) { 2071590Srgrimes if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 2081590Srgrimes sizeof(one)) < 0) 2091590Srgrimes warn("setsockopt"); 2101590Srgrimes if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, 2111590Srgrimes sizeof(one)) < 0) 2121590Srgrimes warn("setsockopt"); 2131590Srgrimes } 2141590Srgrimes 2151590Srgrimes (void)setuid(uid); 2161590Srgrimes omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); 2171590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2181590Srgrimes (void)signal(SIGINT, sendsig); 2191590Srgrimes if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2201590Srgrimes (void)signal(SIGQUIT, sendsig); 2211590Srgrimes if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2221590Srgrimes (void)signal(SIGTERM, sendsig); 2231590Srgrimes 2241590Srgrimes if (!nflag) { 2251590Srgrimes pid = fork(); 2261590Srgrimes if (pid < 0) 2271590Srgrimes err(1, "fork"); 2281590Srgrimes } 22996196Sdes else 230146078Sjmallett (void)shutdown(rem, SHUT_WR); 2311590Srgrimes 232105269Smarkm (void)ioctl(rfd2, FIONBIO, &one); 233105269Smarkm (void)ioctl(rem, FIONBIO, &one); 2341590Srgrimes 235325474Seugen talk(nflag, Nflag, omask, pid, rem, timeout); 2361590Srgrimes 2371590Srgrimes if (!nflag) 2381590Srgrimes (void)kill(pid, SIGKILL); 2391590Srgrimes exit(0); 2401590Srgrimes} 2411590Srgrimes 2421590Srgrimesvoid 243325474Seugentalk(int nflag, int Nflag, long omask, pid_t pid, int rem, int timeout) 2441590Srgrimes{ 2451590Srgrimes int cc, wc; 2461590Srgrimes fd_set readfrom, ready, rembits; 24793412Sobrien char buf[BUFSIZ]; 24893412Sobrien const char *bp; 24918067Sjkh struct timeval tvtimeout; 25043851Sdes int nfds, srval; 2511590Srgrimes 2521590Srgrimes if (!nflag && pid == 0) { 2531590Srgrimes (void)close(rfd2); 2541590Srgrimes 2551590Srgrimesreread: errno = 0; 2561590Srgrimes if ((cc = read(0, buf, sizeof buf)) <= 0) 2571590Srgrimes goto done; 2581590Srgrimes bp = buf; 2591590Srgrimes 2608874Srgrimesrewrite: 261103131Snectar if (rem >= FD_SETSIZE) 262103131Snectar errx(1, "descriptor too big"); 2631590Srgrimes FD_ZERO(&rembits); 2641590Srgrimes FD_SET(rem, &rembits); 26543851Sdes nfds = rem + 1; 26643851Sdes if (select(nfds, 0, &rembits, 0, 0) < 0) { 2671590Srgrimes if (errno != EINTR) 2681590Srgrimes err(1, "select"); 2691590Srgrimes goto rewrite; 2701590Srgrimes } 2711590Srgrimes if (!FD_ISSET(rem, &rembits)) 2721590Srgrimes goto rewrite; 273105269Smarkm wc = write(rem, bp, cc); 2741590Srgrimes if (wc < 0) { 2751590Srgrimes if (errno == EWOULDBLOCK) 2761590Srgrimes goto rewrite; 2771590Srgrimes goto done; 2781590Srgrimes } 2791590Srgrimes bp += wc; 2801590Srgrimes cc -= wc; 2811590Srgrimes if (cc == 0) 2821590Srgrimes goto reread; 2831590Srgrimes goto rewrite; 284325474Seugendone: if (!Nflag) 285325474Seugen (void)shutdown(rem, SHUT_WR); 2861590Srgrimes exit(0); 2871590Srgrimes } 2881590Srgrimes 28918067Sjkh tvtimeout.tv_sec = timeout; 29018067Sjkh tvtimeout.tv_usec = 0; 29118067Sjkh 2921590Srgrimes (void)sigsetmask(omask); 293103131Snectar if (rfd2 >= FD_SETSIZE || rem >= FD_SETSIZE) 294103131Snectar errx(1, "descriptor too big"); 2951590Srgrimes FD_ZERO(&readfrom); 2961590Srgrimes FD_SET(rfd2, &readfrom); 2971590Srgrimes FD_SET(rem, &readfrom); 29843851Sdes nfds = MAX(rfd2+1, rem+1); 2991590Srgrimes do { 3001590Srgrimes ready = readfrom; 30118067Sjkh if (timeout) { 30243851Sdes srval = select(nfds, &ready, 0, 0, &tvtimeout); 30318067Sjkh } else { 30443851Sdes srval = select(nfds, &ready, 0, 0, 0); 30518067Sjkh } 30618067Sjkh 30718067Sjkh if (srval < 0) { 3081590Srgrimes if (errno != EINTR) 3091590Srgrimes err(1, "select"); 3101590Srgrimes continue; 3111590Srgrimes } 31218067Sjkh if (srval == 0) 313119850Scharnier errx(1, "timeout reached (%d seconds)", timeout); 3141590Srgrimes if (FD_ISSET(rfd2, &ready)) { 3151590Srgrimes errno = 0; 316105269Smarkm cc = read(rfd2, buf, sizeof buf); 3171590Srgrimes if (cc <= 0) { 3181590Srgrimes if (errno != EWOULDBLOCK) 3191590Srgrimes FD_CLR(rfd2, &readfrom); 3201590Srgrimes } else 32180381Ssheldonh (void)write(STDERR_FILENO, buf, cc); 3221590Srgrimes } 3231590Srgrimes if (FD_ISSET(rem, &ready)) { 3241590Srgrimes errno = 0; 325105269Smarkm cc = read(rem, buf, sizeof buf); 3261590Srgrimes if (cc <= 0) { 3271590Srgrimes if (errno != EWOULDBLOCK) 3281590Srgrimes FD_CLR(rem, &readfrom); 3291590Srgrimes } else 33080381Ssheldonh (void)write(STDOUT_FILENO, buf, cc); 3311590Srgrimes } 3321590Srgrimes } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); 3331590Srgrimes} 3341590Srgrimes 3351590Srgrimesvoid 336216585Scharnierconnect_timeout(int sig __unused) 337101833Siedowse{ 338101833Siedowse char message[] = "timeout reached before connection completed.\n"; 339101833Siedowse 340101833Siedowse write(STDERR_FILENO, message, sizeof(message) - 1); 341101833Siedowse _exit(1); 342101833Siedowse} 343101833Siedowse 344101833Siedowsevoid 34593022Smarkmsendsig(int sig) 3461590Srgrimes{ 3471590Srgrimes char signo; 3481590Srgrimes 3491590Srgrimes signo = sig; 350105269Smarkm (void)write(rfd2, &signo, 1); 3511590Srgrimes} 3521590Srgrimes 3531590Srgrimeschar * 35493412Sobriencopyargs(char * const *argv) 3551590Srgrimes{ 3561590Srgrimes int cc; 35793412Sobrien char *args, *p; 35893412Sobrien char * const *ap; 3591590Srgrimes 3601590Srgrimes cc = 0; 3611590Srgrimes for (ap = argv; *ap; ++ap) 3621590Srgrimes cc += strlen(*ap) + 1; 3631590Srgrimes if (!(args = malloc((u_int)cc))) 3641590Srgrimes err(1, NULL); 3651590Srgrimes for (p = args, ap = argv; *ap; ++ap) { 3661590Srgrimes (void)strcpy(p, *ap); 3671590Srgrimes for (p = strcpy(p, *ap); *p; ++p); 3681590Srgrimes if (ap[1]) 3691590Srgrimes *p++ = ' '; 3701590Srgrimes } 3711590Srgrimes return (args); 3721590Srgrimes} 3731590Srgrimes 3741590Srgrimesvoid 37593022Smarkmusage(void) 3761590Srgrimes{ 3771590Srgrimes 3781590Srgrimes (void)fprintf(stderr, 379325474Seugen "usage: rsh [-46Ndn] [-l username] [-t timeout] host [command]\n"); 3801590Srgrimes exit(1); 3811590Srgrimes} 382