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 <stdlib.h> 49 #include <poll.h> 50 51 int 52 rcmd(char **ahost, int rport, const char *locuser, const char *remuser, 53 const char *cmd, int *fd2p) 54 { 55 return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); 56 } 57 58 int 59 rcmd_af(char **ahost, int porta, const char *locuser, const char *remuser, 60 const char *cmd, int *fd2p, int af) 61 { 62 static char hbuf[HOST_NAME_MAX+1]; 63 char pbuf[NI_MAXSERV]; 64 struct addrinfo hints, *res, *r; 65 int error; 66 struct sockaddr_storage from; 67 sigset_t oldmask, mask; 68 pid_t pid; 69 int s, lport, timo; 70 char c, *p; 71 int refused; 72 in_port_t rport = porta; 73 74 /* call rcmdsh() with specified remote shell if appropriate. */ 75 if (!issetugid() && (p = getenv("RSH")) && *p) { 76 struct servent *sp = getservbyname("shell", "tcp"); 77 78 if (sp && sp->s_port == rport) 79 return (rcmdsh(ahost, rport, locuser, remuser, 80 cmd, p)); 81 } 82 83 /* use rsh(1) if non-root and remote port is shell. */ 84 if (geteuid()) { 85 struct servent *sp = getservbyname("shell", "tcp"); 86 87 if (sp && sp->s_port == rport) 88 return (rcmdsh(ahost, rport, locuser, remuser, 89 cmd, NULL)); 90 } 91 92 pid = getpid(); 93 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); 94 memset(&hints, 0, sizeof(hints)); 95 hints.ai_family = af; 96 hints.ai_socktype = SOCK_STREAM; 97 hints.ai_flags = AI_CANONNAME; 98 error = getaddrinfo(*ahost, pbuf, &hints, &res); 99 if (error) { 100 (void)fprintf(stderr, "rcmd: %s: %s\n", *ahost, 101 gai_strerror(error)); 102 return (-1); 103 } 104 if (res->ai_canonname) { 105 strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); 106 *ahost = hbuf; 107 } else 108 ; /*XXX*/ 109 110 r = res; 111 refused = 0; 112 sigemptyset(&mask); 113 sigaddset(&mask, SIGURG); 114 sigprocmask(SIG_BLOCK, &mask, &oldmask); 115 for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 116 s = rresvport_af(&lport, r->ai_family); 117 if (s < 0) { 118 if (errno == EAGAIN) 119 (void)fprintf(stderr, 120 "rcmd: socket: All ports in use\n"); 121 else 122 (void)fprintf(stderr, "rcmd: socket: %s\n", 123 strerror(errno)); 124 if (r->ai_next) { 125 r = r->ai_next; 126 continue; 127 } else { 128 sigprocmask(SIG_SETMASK, &oldmask, NULL); 129 freeaddrinfo(res); 130 return (-1); 131 } 132 } 133 fcntl(s, F_SETOWN, pid); 134 if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) 135 break; 136 (void)close(s); 137 if (errno == EADDRINUSE) { 138 lport--; 139 continue; 140 } 141 if (errno == ECONNREFUSED) 142 refused++; 143 if (r->ai_next) { 144 int oerrno = errno; 145 char hbuf[NI_MAXHOST]; 146 const int niflags = NI_NUMERICHOST; 147 148 hbuf[0] = '\0'; 149 if (getnameinfo(r->ai_addr, r->ai_addrlen, 150 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) 151 strlcpy(hbuf, "(invalid)", sizeof hbuf); 152 (void)fprintf(stderr, "connect to address %s: ", hbuf); 153 errno = oerrno; 154 perror(0); 155 r = r->ai_next; 156 hbuf[0] = '\0'; 157 if (getnameinfo(r->ai_addr, r->ai_addrlen, 158 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) 159 strlcpy(hbuf, "(invalid)", sizeof hbuf); 160 (void)fprintf(stderr, "Trying %s...\n", hbuf); 161 continue; 162 } 163 if (refused && timo <= 16) { 164 (void)sleep(timo); 165 timo *= 2; 166 r = res; 167 refused = 0; 168 continue; 169 } 170 (void)fprintf(stderr, "%s: %s\n", res->ai_canonname, 171 strerror(errno)); 172 sigprocmask(SIG_SETMASK, &oldmask, NULL); 173 freeaddrinfo(res); 174 return (-1); 175 } 176 /* given "af" can be PF_UNSPEC, we need the real af for "s" */ 177 af = r->ai_family; 178 freeaddrinfo(res); 179 if (fd2p == 0) { 180 write(s, "", 1); 181 lport = 0; 182 } else { 183 struct pollfd pfd[2]; 184 char num[8]; 185 int s2 = rresvport_af(&lport, af), s3; 186 socklen_t len = sizeof(from); 187 188 if (s2 < 0) 189 goto bad; 190 191 listen(s2, 1); 192 (void)snprintf(num, sizeof(num), "%d", lport); 193 if (write(s, num, strlen(num)+1) != strlen(num)+1) { 194 (void)fprintf(stderr, 195 "rcmd: write (setting up stderr): %s\n", 196 strerror(errno)); 197 (void)close(s2); 198 goto bad; 199 } 200 again: 201 pfd[0].fd = s; 202 pfd[0].events = POLLIN; 203 pfd[1].fd = s2; 204 pfd[1].events = POLLIN; 205 206 errno = 0; 207 if (poll(pfd, 2, INFTIM) < 1 || 208 (pfd[1].revents & (POLLIN|POLLHUP)) == 0) { 209 if (errno != 0) 210 (void)fprintf(stderr, 211 "rcmd: poll (setting up stderr): %s\n", 212 strerror(errno)); 213 else 214 (void)fprintf(stderr, 215 "poll: protocol failure in circuit setup\n"); 216 (void)close(s2); 217 goto bad; 218 } 219 s3 = accept(s2, (struct sockaddr *)&from, &len); 220 if (s3 < 0) { 221 (void)fprintf(stderr, 222 "rcmd: accept: %s\n", strerror(errno)); 223 lport = 0; 224 close(s2); 225 goto bad; 226 } 227 228 /* 229 * XXX careful for ftp bounce attacks. If discovered, shut them 230 * down and check for the real auxiliary channel to connect. 231 */ 232 switch (from.ss_family) { 233 case AF_INET: 234 case AF_INET6: 235 if (getnameinfo((struct sockaddr *)&from, len, 236 NULL, 0, num, sizeof(num), NI_NUMERICSERV) == 0 && 237 atoi(num) != 20) { 238 break; 239 } 240 close(s3); 241 goto again; 242 default: 243 break; 244 } 245 (void)close(s2); 246 247 *fd2p = s3; 248 switch (from.ss_family) { 249 case AF_INET: 250 case AF_INET6: 251 if (getnameinfo((struct sockaddr *)&from, len, 252 NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 || 253 (atoi(num) >= IPPORT_RESERVED || 254 atoi(num) < IPPORT_RESERVED / 2)) { 255 (void)fprintf(stderr, 256 "socket: protocol failure in circuit setup.\n"); 257 goto bad2; 258 } 259 break; 260 default: 261 break; 262 } 263 } 264 (void)write(s, locuser, strlen(locuser)+1); 265 (void)write(s, remuser, strlen(remuser)+1); 266 (void)write(s, cmd, strlen(cmd)+1); 267 if (read(s, &c, 1) != 1) { 268 (void)fprintf(stderr, 269 "rcmd: %s: %s\n", *ahost, strerror(errno)); 270 goto bad2; 271 } 272 if (c != 0) { 273 while (read(s, &c, 1) == 1) { 274 (void)write(STDERR_FILENO, &c, 1); 275 if (c == '\n') 276 break; 277 } 278 goto bad2; 279 } 280 sigprocmask(SIG_SETMASK, &oldmask, NULL); 281 return (s); 282 bad2: 283 if (lport) 284 (void)close(*fd2p); 285 bad: 286 (void)close(s); 287 sigprocmask(SIG_SETMASK, &oldmask, NULL); 288 return (-1); 289 } 290 291