xref: /csrg-svn/libexec/rshd/rshd.c (revision 30265)
121176Sdist /*
221176Sdist  * Copyright (c) 1983 Regents of the University of California.
321176Sdist  * All rights reserved.  The Berkeley software License Agreement
421176Sdist  * specifies the terms and conditions for redistribution.
521176Sdist  */
621176Sdist 
76454Swnj #ifndef lint
821176Sdist char copyright[] =
921176Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021176Sdist  All rights reserved.\n";
1121176Sdist #endif not lint
126454Swnj 
1321176Sdist #ifndef lint
14*30265Smckusick static char sccsid[] = "@(#)rshd.c	5.8 (Berkeley) 12/09/86";
1521176Sdist #endif not lint
1621176Sdist 
1716370Skarels /*
1816370Skarels  * remote shell server:
1916370Skarels  *	remuser\0
2016370Skarels  *	locuser\0
2116370Skarels  *	command\0
2216370Skarels  *	data
2316370Skarels  */
246454Swnj #include <sys/ioctl.h>
256454Swnj #include <sys/param.h>
266454Swnj #include <sys/socket.h>
2727901Slepreau #include <sys/time.h>
289212Ssam 
299212Ssam #include <netinet/in.h>
309212Ssam 
3124903Sbloom #include <arpa/inet.h>
3224903Sbloom 
339212Ssam #include <stdio.h>
346454Swnj #include <errno.h>
356454Swnj #include <pwd.h>
366454Swnj #include <signal.h>
378380Ssam #include <netdb.h>
3817187Sralph #include <syslog.h>
396454Swnj 
406454Swnj int	errno;
4127901Slepreau char	*index(), *rindex(), *strncat();
4227901Slepreau /*VARARGS1*/
436454Swnj int	error();
4416370Skarels 
4527901Slepreau /*ARGSUSED*/
466454Swnj main(argc, argv)
476454Swnj 	int argc;
486454Swnj 	char **argv;
496454Swnj {
5017156Ssam 	struct linger linger;
5117156Ssam 	int on = 1, fromlen;
526454Swnj 	struct sockaddr_in from;
536454Swnj 
5424851Seric 	openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON);
5516370Skarels 	fromlen = sizeof (from);
5616370Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
5716370Skarels 		fprintf(stderr, "%s: ", argv[0]);
5816370Skarels 		perror("getpeername");
5916370Skarels 		_exit(1);
608380Ssam 	}
6127901Slepreau 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
6227901Slepreau 	    sizeof (on)) < 0)
6317187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
6417156Ssam 	linger.l_onoff = 1;
6517156Ssam 	linger.l_linger = 60;			/* XXX */
6627901Slepreau 	if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
6727901Slepreau 	    sizeof (linger)) < 0)
6817187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
6916370Skarels 	doit(dup(0), &from);
706454Swnj }
716454Swnj 
726454Swnj char	username[20] = "USER=";
736454Swnj char	homedir[64] = "HOME=";
746454Swnj char	shell[64] = "SHELL=";
756454Swnj char	*envinit[] =
766454Swnj 	    {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
776454Swnj char	**environ;
786454Swnj 
796454Swnj doit(f, fromp)
806454Swnj 	int f;
816454Swnj 	struct sockaddr_in *fromp;
826454Swnj {
836454Swnj 	char cmdbuf[NCARGS+1], *cp;
846454Swnj 	char locuser[16], remuser[16];
856454Swnj 	struct passwd *pwd;
8627901Slepreau 	int s;
878380Ssam 	struct hostent *hp;
8825985Skarels 	char *hostname;
896454Swnj 	short port;
906454Swnj 	int pv[2], pid, ready, readfrom, cc;
916454Swnj 	char buf[BUFSIZ], sig;
926454Swnj 	int one = 1;
936454Swnj 
946454Swnj 	(void) signal(SIGINT, SIG_DFL);
956454Swnj 	(void) signal(SIGQUIT, SIG_DFL);
966454Swnj 	(void) signal(SIGTERM, SIG_DFL);
9710883Ssam #ifdef DEBUG
986454Swnj 	{ int t = open("/dev/tty", 2);
996454Swnj 	  if (t >= 0) {
1006454Swnj 		ioctl(t, TIOCNOTTY, (char *)0);
1016454Swnj 		(void) close(t);
1026454Swnj 	  }
1036454Swnj 	}
1046454Swnj #endif
1056454Swnj 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
1066454Swnj 	if (fromp->sin_family != AF_INET ||
10710596Ssam 	    fromp->sin_port >= IPPORT_RESERVED) {
10817187Sralph 		syslog(LOG_ERR, "malformed from address\n");
1096454Swnj 		exit(1);
11010596Ssam 	}
1116454Swnj 	(void) alarm(60);
1126454Swnj 	port = 0;
1136454Swnj 	for (;;) {
1146454Swnj 		char c;
11510596Ssam 		if (read(f, &c, 1) != 1) {
11617187Sralph 			syslog(LOG_ERR, "read: %m");
11711238Ssam 			shutdown(f, 1+1);
1186454Swnj 			exit(1);
11910596Ssam 		}
1206454Swnj 		if (c == 0)
1216454Swnj 			break;
1226454Swnj 		port = port * 10 + c - '0';
1236454Swnj 	}
1246454Swnj 	(void) alarm(0);
1256454Swnj 	if (port != 0) {
12627901Slepreau 		int lport = IPPORT_RESERVED - 1;
12710273Ssam 		s = rresvport(&lport);
12810596Ssam 		if (s < 0) {
12917187Sralph 			syslog(LOG_ERR, "can't get stderr port: %m");
1306454Swnj 			exit(1);
13110596Ssam 		}
13210596Ssam 		if (port >= IPPORT_RESERVED) {
13317187Sralph 			syslog(LOG_ERR, "2nd port not reserved\n");
13410596Ssam 			exit(1);
13510596Ssam 		}
1369243Ssam 		fromp->sin_port = htons((u_short)port);
13727901Slepreau 		if (connect(s, fromp, sizeof (*fromp)) < 0) {
13825985Skarels 			syslog(LOG_INFO, "connect second port: %m");
1396454Swnj 			exit(1);
14010596Ssam 		}
1416454Swnj 	}
14210596Ssam 	dup2(f, 0);
14310596Ssam 	dup2(f, 1);
14410596Ssam 	dup2(f, 2);
14527901Slepreau 	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
1468380Ssam 		fromp->sin_family);
14725985Skarels 	if (hp)
14825985Skarels 		hostname = hp->h_name;
14925985Skarels 	else
15025985Skarels 		hostname = inet_ntoa(fromp->sin_addr);
1516454Swnj 	getstr(remuser, sizeof(remuser), "remuser");
1526454Swnj 	getstr(locuser, sizeof(locuser), "locuser");
1536454Swnj 	getstr(cmdbuf, sizeof(cmdbuf), "command");
1546454Swnj 	setpwent();
1556454Swnj 	pwd = getpwnam(locuser);
1566454Swnj 	if (pwd == NULL) {
1576454Swnj 		error("Login incorrect.\n");
1586454Swnj 		exit(1);
1596454Swnj 	}
1606454Swnj 	endpwent();
1616454Swnj 	if (chdir(pwd->pw_dir) < 0) {
16227901Slepreau 		(void) chdir("/");
16316370Skarels #ifdef notdef
1646454Swnj 		error("No remote directory.\n");
1656454Swnj 		exit(1);
16616370Skarels #endif
1676454Swnj 	}
16824447Sbloom 	if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
16925985Skarels 	    ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
1706454Swnj 		error("Permission denied.\n");
1716454Swnj 		exit(1);
1726454Swnj 	}
1736454Swnj 	(void) write(2, "\0", 1);
1746454Swnj 	if (port) {
1756454Swnj 		if (pipe(pv) < 0) {
1766454Swnj 			error("Can't make pipe.\n");
1776454Swnj 			exit(1);
1786454Swnj 		}
1796454Swnj 		pid = fork();
1806454Swnj 		if (pid == -1)  {
1816454Swnj 			error("Try again.\n");
1826454Swnj 			exit(1);
1836454Swnj 		}
1846454Swnj 		if (pid) {
1856454Swnj 			(void) close(0); (void) close(1); (void) close(2);
1866454Swnj 			(void) close(f); (void) close(pv[1]);
1876454Swnj 			readfrom = (1<<s) | (1<<pv[0]);
188*30265Smckusick 			ioctl(pv[0], FIONBIO, (char *)&one);
1896454Swnj 			/* should set s nbio! */
1906454Swnj 			do {
1916454Swnj 				ready = readfrom;
19227901Slepreau 				if (select(16, &ready, (fd_set *)0,
19327901Slepreau 				    (fd_set *)0, (struct timeval *)0) < 0)
1949212Ssam 					break;
1956454Swnj 				if (ready & (1<<s)) {
1966454Swnj 					if (read(s, &sig, 1) <= 0)
1976454Swnj 						readfrom &= ~(1<<s);
1986454Swnj 					else
1996454Swnj 						killpg(pid, sig);
2006454Swnj 				}
2016454Swnj 				if (ready & (1<<pv[0])) {
20211238Ssam 					errno = 0;
2036454Swnj 					cc = read(pv[0], buf, sizeof (buf));
2046454Swnj 					if (cc <= 0) {
20510194Ssam 						shutdown(s, 1+1);
2066454Swnj 						readfrom &= ~(1<<pv[0]);
2076454Swnj 					} else
2086454Swnj 						(void) write(s, buf, cc);
2096454Swnj 				}
2106454Swnj 			} while (readfrom);
2116454Swnj 			exit(0);
2126454Swnj 		}
2136454Swnj 		setpgrp(0, getpid());
2146454Swnj 		(void) close(s); (void) close(pv[0]);
2156454Swnj 		dup2(pv[1], 2);
2166454Swnj 	}
2176454Swnj 	if (*pwd->pw_shell == '\0')
2186454Swnj 		pwd->pw_shell = "/bin/sh";
2196454Swnj 	(void) close(f);
22027901Slepreau 	(void) setgid((gid_t)pwd->pw_gid);
2219212Ssam 	initgroups(pwd->pw_name, pwd->pw_gid);
22227901Slepreau 	(void) setuid((uid_t)pwd->pw_uid);
2236454Swnj 	environ = envinit;
2246454Swnj 	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
2256454Swnj 	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
2266454Swnj 	strncat(username, pwd->pw_name, sizeof(username)-6);
2276454Swnj 	cp = rindex(pwd->pw_shell, '/');
2286454Swnj 	if (cp)
2296454Swnj 		cp++;
2306454Swnj 	else
2316454Swnj 		cp = pwd->pw_shell;
2326454Swnj 	execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
2336454Swnj 	perror(pwd->pw_shell);
2346454Swnj 	exit(1);
2356454Swnj }
2366454Swnj 
23727901Slepreau /*VARARGS1*/
23825663Smckusick error(fmt, a1, a2, a3)
2396454Swnj 	char *fmt;
24025663Smckusick 	int a1, a2, a3;
2416454Swnj {
2426454Swnj 	char buf[BUFSIZ];
2436454Swnj 
2446454Swnj 	buf[0] = 1;
24525663Smckusick 	(void) sprintf(buf+1, fmt, a1, a2, a3);
2466454Swnj 	(void) write(2, buf, strlen(buf));
2476454Swnj }
2486454Swnj 
2496454Swnj getstr(buf, cnt, err)
2506454Swnj 	char *buf;
2516454Swnj 	int cnt;
2526454Swnj 	char *err;
2536454Swnj {
2546454Swnj 	char c;
2556454Swnj 
2566454Swnj 	do {
2576454Swnj 		if (read(0, &c, 1) != 1)
2586454Swnj 			exit(1);
2596454Swnj 		*buf++ = c;
2606454Swnj 		if (--cnt == 0) {
2616454Swnj 			error("%s too long\n", err);
2626454Swnj 			exit(1);
2636454Swnj 		}
2646454Swnj 	} while (c != 0);
2656454Swnj }
266