xref: /csrg-svn/libexec/rexecd/rexecd.c (revision 6442)
1*6442Swnj #ifndef lint
2*6442Swnj static char sccsid[] = "@(#)rexecd.c	4.1 82/04/02";
3*6442Swnj #endif
4*6442Swnj 
5*6442Swnj #include <stdio.h>
6*6442Swnj #include <sys/ioctl.h>
7*6442Swnj #include <sys/param.h>
8*6442Swnj #include <sys/socket.h>
9*6442Swnj #include <net/in.h>
10*6442Swnj #include <errno.h>
11*6442Swnj #include <pwd.h>
12*6442Swnj #include <wait.h>
13*6442Swnj #include <signal.h>
14*6442Swnj 
15*6442Swnj extern	errno;
16*6442Swnj struct	sockaddr_in sin = { AF_INET, IPPORT_EXECSERVER };
17*6442Swnj struct	passwd *getpwnam();
18*6442Swnj char	*crypt(), *rindex(), *sprintf();
19*6442Swnj int	options = SO_ACCEPTCONN|SO_KEEPALIVE;
20*6442Swnj /* VARARGS 1 */
21*6442Swnj int	error();
22*6442Swnj /*
23*6442Swnj  * remote execute server:
24*6442Swnj  *	username\0
25*6442Swnj  *	password\0
26*6442Swnj  *	command\0
27*6442Swnj  *	data
28*6442Swnj  */
29*6442Swnj main(argc, argv)
30*6442Swnj 	int argc;
31*6442Swnj 	char **argv;
32*6442Swnj {
33*6442Swnj 	union wait status;
34*6442Swnj 	int f;
35*6442Swnj 	struct sockaddr_in from;
36*6442Swnj 
37*6442Swnj #ifndef DEBUG
38*6442Swnj 	if (fork())
39*6442Swnj 		exit(0);
40*6442Swnj 	for (f = 0; f < 10; f++)
41*6442Swnj 		(void) close(f);
42*6442Swnj 	(void) open("/", 0);
43*6442Swnj 	(void) dup2(0, 1);
44*6442Swnj 	(void) dup2(0, 2);
45*6442Swnj 	{ int t = open("/dev/tty", 2);
46*6442Swnj 	  if (t >= 0) {
47*6442Swnj 		ioctl(t, TIOCNOTTY, (char *)0);
48*6442Swnj 		(void) close(t);
49*6442Swnj 	  }
50*6442Swnj 	}
51*6442Swnj #endif
52*6442Swnj #if vax
53*6442Swnj 	sin.sin_port = htons(sin.sin_port);
54*6442Swnj #endif
55*6442Swnj 	argc--, argv++;
56*6442Swnj 	if (argc > 0 && !strcmp(argv[0], "-d"))
57*6442Swnj 		options |= SO_DEBUG;
58*6442Swnj 	for (;;) {
59*6442Swnj 		errno = 0;
60*6442Swnj 		f = socket(SOCK_STREAM, 0, &sin, options);
61*6442Swnj 		if (f < 0) {
62*6442Swnj 			perror("socket");
63*6442Swnj 			sleep(5);
64*6442Swnj 			continue;
65*6442Swnj 		}
66*6442Swnj 		if (accept(f, &from) < 0) {
67*6442Swnj 			perror("accept");
68*6442Swnj 			(void) close(f);
69*6442Swnj 			sleep(1);
70*6442Swnj 			continue;
71*6442Swnj 		}
72*6442Swnj 		if (fork() == 0)
73*6442Swnj 			doit(f, &from);
74*6442Swnj 		(void) close(f);
75*6442Swnj 		while(wait3(status, WNOHANG, 0) > 0)
76*6442Swnj 			continue;
77*6442Swnj 	}
78*6442Swnj }
79*6442Swnj 
80*6442Swnj char	username[20] = "USER=";
81*6442Swnj char	homedir[64] = "HOME=";
82*6442Swnj char	shell[64] = "SHELL=";
83*6442Swnj char	*envinit[] =
84*6442Swnj 	    {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
85*6442Swnj char	**environ;
86*6442Swnj 
87*6442Swnj struct	sockaddr_in asin = { AF_INET };
88*6442Swnj 
89*6442Swnj doit(f, fromp)
90*6442Swnj 	int f;
91*6442Swnj 	struct sockaddr_in *fromp;
92*6442Swnj {
93*6442Swnj 	char cmdbuf[NCARGS+1], *cp, *namep;
94*6442Swnj 	char user[16], pass[16];
95*6442Swnj 	struct passwd *pwd;
96*6442Swnj 	int s;
97*6442Swnj 	short port;
98*6442Swnj 	int pv[2], pid, ready, readfrom, cc;
99*6442Swnj 	char buf[BUFSIZ], sig;
100*6442Swnj 	int one = 1;
101*6442Swnj 
102*6442Swnj 	(void) signal(SIGINT, SIG_DFL);
103*6442Swnj 	(void) signal(SIGQUIT, SIG_DFL);
104*6442Swnj 	(void) signal(SIGTERM, SIG_DFL);
105*6442Swnj #ifdef DEBUG
106*6442Swnj 	{ int t = open("/dev/tty", 2);
107*6442Swnj 	  if (t >= 0) {
108*6442Swnj 		ioctl(t, TIOCNOTTY, (char *)0);
109*6442Swnj 		(void) close(t);
110*6442Swnj 	  }
111*6442Swnj 	}
112*6442Swnj #endif
113*6442Swnj 	dup2(f, 0);
114*6442Swnj 	dup2(f, 1);
115*6442Swnj 	dup2(f, 2);
116*6442Swnj #if vax
117*6442Swnj 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
118*6442Swnj #endif
119*6442Swnj 	(void) alarm(60);
120*6442Swnj 	port = 0;
121*6442Swnj 	for (;;) {
122*6442Swnj 		char c;
123*6442Swnj 		if (read(f, &c, 1) != 1)
124*6442Swnj 			exit(1);
125*6442Swnj 		if (c == 0)
126*6442Swnj 			break;
127*6442Swnj 		port = port * 10 + c - '0';
128*6442Swnj 	}
129*6442Swnj 	(void) alarm(0);
130*6442Swnj 	if (port != 0) {
131*6442Swnj 		s = socket(SOCK_STREAM, 0, &asin, 0);
132*6442Swnj 		if (s < 0)
133*6442Swnj 			exit(1);
134*6442Swnj 		(void) alarm(60);
135*6442Swnj 		fromp->sin_port = port;
136*6442Swnj #if vax
137*6442Swnj 		fromp->sin_port = ntohs(fromp->sin_port);
138*6442Swnj #endif
139*6442Swnj 		if (connect(s, fromp) < 0)
140*6442Swnj 			exit(1);
141*6442Swnj 		(void) alarm(0);
142*6442Swnj 	}
143*6442Swnj 	getstr(user, sizeof(user), "username");
144*6442Swnj 	getstr(pass, sizeof(pass), "password");
145*6442Swnj 	getstr(cmdbuf, sizeof(cmdbuf), "command");
146*6442Swnj 	setpwent();
147*6442Swnj 	pwd = getpwnam(user);
148*6442Swnj 	if (pwd == NULL) {
149*6442Swnj 		error("Login incorrect.\n");
150*6442Swnj 		exit(1);
151*6442Swnj 	}
152*6442Swnj 	endpwent();
153*6442Swnj 	if (*pwd->pw_passwd != '\0') {
154*6442Swnj 		namep = crypt(pass, pwd->pw_passwd);
155*6442Swnj 		if (strcmp(namep, pwd->pw_passwd)) {
156*6442Swnj 			error("Password incorrect.\n");
157*6442Swnj 			exit(1);
158*6442Swnj 		}
159*6442Swnj 	}
160*6442Swnj 	if (chdir(pwd->pw_dir) < 0) {
161*6442Swnj 		error("No remote directory.\n");
162*6442Swnj 		exit(1);
163*6442Swnj 	}
164*6442Swnj 	(void) write(2, "\0", 1);
165*6442Swnj 	if (port) {
166*6442Swnj 		(void) pipe(pv);
167*6442Swnj 		pid = fork();
168*6442Swnj 		if (pid == -1)  {
169*6442Swnj 			error("Try again.\n");
170*6442Swnj 			exit(1);
171*6442Swnj 		}
172*6442Swnj 		if (pid) {
173*6442Swnj 			(void) close(0); (void) close(1); (void) close(2);
174*6442Swnj 			(void) close(f); (void) close(pv[1]);
175*6442Swnj 			readfrom = (1<<s) | (1<<pv[0]);
176*6442Swnj 			ioctl(pv[1], FIONBIO, (char *)&one);
177*6442Swnj 			/* should set s nbio! */
178*6442Swnj 			do {
179*6442Swnj 				ready = readfrom;
180*6442Swnj 				(void) select(32, &ready, 0, 1000000);
181*6442Swnj 				if (ready & (1<<s)) {
182*6442Swnj 					if (read(s, &sig, 1) <= 0)
183*6442Swnj 						readfrom &= ~(1<<s);
184*6442Swnj 					else
185*6442Swnj 						killpg(pid, sig);
186*6442Swnj 				}
187*6442Swnj 				if (ready & (1<<pv[0])) {
188*6442Swnj 					cc = read(pv[0], buf, sizeof (buf));
189*6442Swnj 					if (cc <= 0) {
190*6442Swnj 						int done = 1+1;
191*6442Swnj 						ioctl(s, SIOCDONE, (char *)&done);
192*6442Swnj 						readfrom &= ~(1<<pv[0]);
193*6442Swnj 					} else
194*6442Swnj 						(void) write(s, buf, cc);
195*6442Swnj 				}
196*6442Swnj 			} while (readfrom);
197*6442Swnj 			exit(0);
198*6442Swnj 		}
199*6442Swnj 		setpgrp(0, getpid());
200*6442Swnj 		(void) close(s); (void)close(pv[0]);
201*6442Swnj 		dup2(pv[1], 2);
202*6442Swnj 	}
203*6442Swnj 	if (*pwd->pw_shell == '\0')
204*6442Swnj 		pwd->pw_shell = "/bin/sh";
205*6442Swnj 	(void) close(f);
206*6442Swnj 	inigrp(pwd->pw_name, pwd->pw_gid);
207*6442Swnj 	(void) setuid(pwd->pw_uid);
208*6442Swnj 	(void) setgid(pwd->pw_gid);
209*6442Swnj 	environ = envinit;
210*6442Swnj 	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
211*6442Swnj 	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
212*6442Swnj 	strncat(username, pwd->pw_name, sizeof(username)-6);
213*6442Swnj 	cp = rindex(pwd->pw_shell, '/');
214*6442Swnj 	if (cp)
215*6442Swnj 		cp++;
216*6442Swnj 	else
217*6442Swnj 		cp = pwd->pw_shell;
218*6442Swnj 	execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
219*6442Swnj 	perror(pwd->pw_shell);
220*6442Swnj 	exit(1);
221*6442Swnj }
222*6442Swnj 
223*6442Swnj /* VARARGS 1 */
224*6442Swnj error(fmt, a1, a2, a3)
225*6442Swnj 	char *fmt;
226*6442Swnj 	int a1, a2, a3;
227*6442Swnj {
228*6442Swnj 	char buf[BUFSIZ];
229*6442Swnj 
230*6442Swnj 	buf[0] = 1;
231*6442Swnj 	(void) sprintf(buf+1, fmt, a1, a2, a3);
232*6442Swnj 	(void) write(2, buf, strlen(buf));
233*6442Swnj }
234*6442Swnj 
235*6442Swnj getstr(buf, cnt, err)
236*6442Swnj 	char *buf;
237*6442Swnj 	int cnt;
238*6442Swnj 	char *err;
239*6442Swnj {
240*6442Swnj 	char c;
241*6442Swnj 
242*6442Swnj 	do {
243*6442Swnj 		if (read(0, &c, 1) != 1)
244*6442Swnj 			exit(1);
245*6442Swnj 		*buf++ = c;
246*6442Swnj 		if (--cnt == 0) {
247*6442Swnj 			error("%s too long\n", err);
248*6442Swnj 			exit(1);
249*6442Swnj 		}
250*6442Swnj 	} while (c != 0);
251*6442Swnj }
252