summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/rcmd.c
diff options
context:
space:
mode:
authorcvs2svn <admin@example.com>2025-04-14 17:32:06 +0000
committercvs2svn <admin@example.com>2025-04-14 17:32:06 +0000
commiteb8dd9dca1228af0cd132f515509051ecfabf6f6 (patch)
treeedb6da6af7e865d488dc1a29309f1e1ec226e603 /src/lib/libc/net/rcmd.c
parent247f0352e0ed72a4f476db9dc91f4d982bc83eb2 (diff)
downloadopenbsd-tb_20250414.tar.gz
openbsd-tb_20250414.tar.bz2
openbsd-tb_20250414.zip
This commit was manufactured by cvs2git to create tag 'tb_20250414'.tb_20250414
Diffstat (limited to 'src/lib/libc/net/rcmd.c')
-rw-r--r--src/lib/libc/net/rcmd.c296
1 files changed, 0 insertions, 296 deletions
diff --git a/src/lib/libc/net/rcmd.c b/src/lib/libc/net/rcmd.c
deleted file mode 100644
index bf68603649..0000000000
--- a/src/lib/libc/net/rcmd.c
+++ /dev/null
@@ -1,296 +0,0 @@
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