1/*
2 * Copyright (c) 1995, 1996, 1998 Theo de Raadt.  All rights reserved.
3 * Copyright (c) 1983, 1993, 1994
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/socket.h>
32#include <sys/stat.h>
33
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <signal.h>
38#include <fcntl.h>
39#include <netdb.h>
40#include <unistd.h>
41#include <limits.h>
42#include <pwd.h>
43#include <errno.h>
44#include <stdio.h>
45#include <ctype.h>
46#include <string.h>
47#include <syslog.h>
48#include <time.h>
49#include <stdlib.h>
50#include <poll.h>
51
52int
53rcmd(char **ahost, int rport, const char *locuser, const char *remuser,
54    const char *cmd, int *fd2p)
55{
56	return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
57}
58
59int
60rcmd_af(char **ahost, int porta, const char *locuser, const char *remuser,
61    const char *cmd, int *fd2p, int af)
62{
63	static char hbuf[HOST_NAME_MAX+1];
64	char pbuf[NI_MAXSERV];
65	struct addrinfo hints, *res, *r;
66	int error;
67	struct sockaddr_storage from;
68	sigset_t oldmask, mask;
69	pid_t pid;
70	int s, lport;
71	struct timespec timo;
72	char c, *p;
73	int refused;
74	in_port_t rport = porta;
75	int numread;
76
77	/* call rcmdsh() with specified remote shell if appropriate. */
78	if (!issetugid() && (p = getenv("RSH")) && *p) {
79		struct servent *sp = getservbyname("shell", "tcp");
80
81		if (sp && sp->s_port == rport)
82			return (rcmdsh(ahost, rport, locuser, remuser,
83			    cmd, p));
84	}
85
86	/* use rsh(1) if non-root and remote port is shell. */
87	if (geteuid()) {
88		struct servent *sp = getservbyname("shell", "tcp");
89
90		if (sp && sp->s_port == rport)
91			return (rcmdsh(ahost, rport, locuser, remuser,
92			    cmd, NULL));
93	}
94
95	pid = getpid();
96	snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
97	memset(&hints, 0, sizeof(hints));
98	hints.ai_family = af;
99	hints.ai_socktype = SOCK_STREAM;
100	hints.ai_flags = AI_CANONNAME;
101	error = getaddrinfo(*ahost, pbuf, &hints, &res);
102	if (error) {
103		(void)fprintf(stderr, "rcmd: %s: %s\n", *ahost,
104		    gai_strerror(error));
105		return (-1);
106	}
107	if (res->ai_canonname) {
108		strlcpy(hbuf, res->ai_canonname, sizeof(hbuf));
109		*ahost = hbuf;
110	} else
111		; /*XXX*/
112
113	r = res;
114	refused = 0;
115	timespecclear(&timo);
116	sigemptyset(&mask);
117	sigaddset(&mask, SIGURG);
118	sigprocmask(SIG_BLOCK, &mask, &oldmask);
119	for (timo.tv_sec = 1, lport = IPPORT_RESERVED - 1;;) {
120		s = rresvport_af(&lport, r->ai_family);
121		if (s < 0) {
122			if (errno == EAGAIN)
123				(void)fprintf(stderr,
124				    "rcmd: socket: All ports in use\n");
125			else
126				(void)fprintf(stderr, "rcmd: socket: %s\n",
127				    strerror(errno));
128			if (r->ai_next) {
129				r = r->ai_next;
130				continue;
131			} else {
132				sigprocmask(SIG_SETMASK, &oldmask, NULL);
133				freeaddrinfo(res);
134				return (-1);
135			}
136		}
137		fcntl(s, F_SETOWN, pid);
138		if (connect(s, r->ai_addr, r->ai_addrlen) >= 0)
139			break;
140		(void)close(s);
141		if (errno == EADDRINUSE) {
142			lport--;
143			continue;
144		}
145		if (errno == ECONNREFUSED)
146			refused++;
147		if (r->ai_next) {
148			int oerrno = errno;
149			char hbuf[NI_MAXHOST];
150			const int niflags = NI_NUMERICHOST;
151
152			hbuf[0] = '\0';
153			if (getnameinfo(r->ai_addr, r->ai_addrlen,
154			    hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
155				strlcpy(hbuf, "(invalid)", sizeof hbuf);
156			(void)fprintf(stderr, "connect to address %s: ", hbuf);
157			errno = oerrno;
158			perror(0);
159			r = r->ai_next;
160			hbuf[0] = '\0';
161			if (getnameinfo(r->ai_addr, r->ai_addrlen,
162			    hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
163				strlcpy(hbuf, "(invalid)", sizeof hbuf);
164			(void)fprintf(stderr, "Trying %s...\n", hbuf);
165			continue;
166		}
167		if (refused && timo.tv_sec <= 16) {
168			(void)nanosleep(&timo, NULL);
169			timo.tv_sec *= 2;
170			r = res;
171			refused = 0;
172			continue;
173		}
174		(void)fprintf(stderr, "%s: %s\n", res->ai_canonname,
175		    strerror(errno));
176		sigprocmask(SIG_SETMASK, &oldmask, NULL);
177		freeaddrinfo(res);
178		return (-1);
179	}
180	/* given "af" can be PF_UNSPEC, we need the real af for "s" */
181	af = r->ai_family;
182	freeaddrinfo(res);
183	if (fd2p == 0) {
184		write(s, "", 1);
185		lport = 0;
186	} else {
187		struct pollfd pfd[2];
188		char num[8];
189		int s2 = rresvport_af(&lport, af), s3;
190		socklen_t len = sizeof(from);
191
192		if (s2 < 0)
193			goto bad;
194
195		listen(s2, 1);
196		(void)snprintf(num, sizeof(num), "%d", lport);
197		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
198			(void)fprintf(stderr,
199			    "rcmd: write (setting up stderr): %s\n",
200			    strerror(errno));
201			(void)close(s2);
202			goto bad;
203		}
204again:
205		pfd[0].fd = s;
206		pfd[0].events = POLLIN;
207		pfd[1].fd = s2;
208		pfd[1].events = POLLIN;
209
210		errno = 0;
211		if (poll(pfd, 2, INFTIM) < 1 ||
212		    (pfd[1].revents & (POLLIN|POLLHUP)) == 0) {
213			if (errno != 0)
214				(void)fprintf(stderr,
215				    "rcmd: poll (setting up stderr): %s\n",
216				    strerror(errno));
217			else
218				(void)fprintf(stderr,
219				"poll: protocol failure in circuit setup\n");
220			(void)close(s2);
221			goto bad;
222		}
223		s3 = accept(s2, (struct sockaddr *)&from, &len);
224		if (s3 < 0) {
225			(void)fprintf(stderr,
226			    "rcmd: accept: %s\n", strerror(errno));
227			lport = 0;
228			close(s2);
229			goto bad;
230		}
231
232		/*
233		 * XXX careful for ftp bounce attacks. If discovered, shut them
234		 * down and check for the real auxiliary channel to connect.
235		 */
236		switch (from.ss_family) {
237		case AF_INET:
238		case AF_INET6:
239			if (getnameinfo((struct sockaddr *)&from, len,
240			    NULL, 0, num, sizeof(num), NI_NUMERICSERV) == 0 &&
241			    atoi(num) != 20) {
242				break;
243			}
244			close(s3);
245			goto again;
246		default:
247			break;
248		}
249		(void)close(s2);
250
251		*fd2p = s3;
252		switch (from.ss_family) {
253		case AF_INET:
254		case AF_INET6:
255			if (getnameinfo((struct sockaddr *)&from, len,
256			    NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 ||
257			    (atoi(num) >= IPPORT_RESERVED ||
258			     atoi(num) < IPPORT_RESERVED / 2)) {
259				(void)fprintf(stderr,
260				    "socket: protocol failure in circuit setup.\n");
261				goto bad2;
262			}
263			break;
264		default:
265			break;
266		}
267	}
268	(void)write(s, locuser, strlen(locuser)+1);
269	(void)write(s, remuser, strlen(remuser)+1);
270	(void)write(s, cmd, strlen(cmd)+1);
271	if ((numread = read(s, &c, 1)) != 1) {
272		(void)fprintf(stderr,
273		    "rcmd: %s: %s\n", *ahost,
274		    numread == -1 ? strerror(errno) : "Short read");
275		goto bad2;
276	}
277	if (c != 0) {
278		while (read(s, &c, 1) == 1) {
279			(void)write(STDERR_FILENO, &c, 1);
280			if (c == '\n')
281				break;
282		}
283		goto bad2;
284	}
285	sigprocmask(SIG_SETMASK, &oldmask, NULL);
286	return (s);
287bad2:
288	if (lport)
289		(void)close(*fd2p);
290bad:
291	(void)close(s);
292	sigprocmask(SIG_SETMASK, &oldmask, NULL);
293	return (-1);
294}
295DEF_WEAK(rcmd_af);
296
297