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/param.h> 32 #include <sys/socket.h> 33 #include <sys/stat.h> 34 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 38 #include <signal.h> 39 #include <fcntl.h> 40 #include <netdb.h> 41 #include <unistd.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 50 int 51 rcmd(char **ahost, int rport, const char *locuser, const char *remuser, 52 const char *cmd, int *fd2p) 53 { 54 return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); 55 } 56 57 int 58 rcmd_af(char **ahost, int porta, const char *locuser, const char *remuser, 59 const char *cmd, int *fd2p, int af) 60 { 61 static char hbuf[MAXHOSTNAMELEN]; 62 char pbuf[NI_MAXSERV]; 63 struct addrinfo hints, *res, *r; 64 int error; 65 struct sockaddr_storage from; 66 fd_set *readsp = NULL; 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 #if 0 101 warnx("%s: %s", *ahost, gai_strerror(error)); 102 #endif 103 return (-1); 104 } 105 if (res->ai_canonname) { 106 strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); 107 *ahost = hbuf; 108 } else 109 ; /*XXX*/ 110 111 r = res; 112 refused = 0; 113 sigemptyset(&mask); 114 sigaddset(&mask, SIGURG); 115 sigprocmask(SIG_BLOCK, &mask, &oldmask); 116 for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 117 s = rresvport_af(&lport, r->ai_family); 118 if (s < 0) { 119 if (errno == EAGAIN) 120 (void)fprintf(stderr, 121 "rcmd: socket: All ports in use\n"); 122 else 123 (void)fprintf(stderr, "rcmd: socket: %s\n", 124 strerror(errno)); 125 if (r->ai_next) { 126 r = r->ai_next; 127 continue; 128 } else { 129 sigprocmask(SIG_SETMASK, &oldmask, NULL); 130 freeaddrinfo(res); 131 return (-1); 132 } 133 } 134 fcntl(s, F_SETOWN, pid); 135 if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) 136 break; 137 (void)close(s); 138 if (errno == EADDRINUSE) { 139 lport--; 140 continue; 141 } 142 if (errno == ECONNREFUSED) 143 refused++; 144 if (r->ai_next) { 145 int oerrno = errno; 146 char hbuf[NI_MAXHOST]; 147 const int niflags = NI_NUMERICHOST; 148 149 hbuf[0] = '\0'; 150 if (getnameinfo(r->ai_addr, r->ai_addrlen, 151 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) 152 strlcpy(hbuf, "(invalid)", sizeof hbuf); 153 (void)fprintf(stderr, "connect to address %s: ", hbuf); 154 errno = oerrno; 155 perror(0); 156 r = r->ai_next; 157 hbuf[0] = '\0'; 158 if (getnameinfo(r->ai_addr, r->ai_addrlen, 159 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) 160 strlcpy(hbuf, "(invalid)", sizeof hbuf); 161 (void)fprintf(stderr, "Trying %s...\n", hbuf); 162 continue; 163 } 164 if (refused && timo <= 16) { 165 (void)sleep(timo); 166 timo *= 2; 167 r = res; 168 refused = 0; 169 continue; 170 } 171 (void)fprintf(stderr, "%s: %s\n", res->ai_canonname, 172 strerror(errno)); 173 sigprocmask(SIG_SETMASK, &oldmask, NULL); 174 freeaddrinfo(res); 175 return (-1); 176 } 177 /* given "af" can be PF_UNSPEC, we need the real af for "s" */ 178 af = r->ai_family; 179 freeaddrinfo(res); 180 #if 0 181 /* 182 * try to rresvport() to the same port. This will make rresvport() 183 * fail it's first bind, resulting in it choosing a random port. 184 */ 185 lport--; 186 #endif 187 if (fd2p == 0) { 188 write(s, "", 1); 189 lport = 0; 190 } else { 191 char num[8]; 192 int s2 = rresvport_af(&lport, af), s3; 193 socklen_t len = sizeof(from); 194 int fdssize = howmany(MAX(s, s2)+1, NFDBITS) * sizeof(fd_mask); 195 196 if (s2 < 0) 197 goto bad; 198 readsp = (fd_set *)malloc(fdssize); 199 if (readsp == NULL) { 200 close(s2); 201 goto bad; 202 } 203 listen(s2, 1); 204 (void)snprintf(num, sizeof(num), "%d", lport); 205 if (write(s, num, strlen(num)+1) != strlen(num)+1) { 206 (void)fprintf(stderr, 207 "rcmd: write (setting up stderr): %s\n", 208 strerror(errno)); 209 (void)close(s2); 210 goto bad; 211 } 212 again: 213 bzero(readsp, fdssize); 214 FD_SET(s, readsp); 215 FD_SET(s2, readsp); 216 errno = 0; 217 if (select(MAX(s, s2) + 1, readsp, 0, 0, 0) < 1 || 218 !FD_ISSET(s2, readsp)) { 219 if (errno != 0) 220 (void)fprintf(stderr, 221 "rcmd: select (setting up stderr): %s\n", 222 strerror(errno)); 223 else 224 (void)fprintf(stderr, 225 "select: protocol failure in circuit setup\n"); 226 (void)close(s2); 227 goto bad; 228 } 229 s3 = accept(s2, (struct sockaddr *)&from, &len); 230 if (s3 < 0) { 231 (void)fprintf(stderr, 232 "rcmd: accept: %s\n", strerror(errno)); 233 lport = 0; 234 close(s2); 235 goto bad; 236 } 237 238 /* 239 * XXX careful for ftp bounce attacks. If discovered, shut them 240 * down and check for the real auxiliary channel to connect. 241 */ 242 switch (from.ss_family) { 243 case AF_INET: 244 case AF_INET6: 245 if (getnameinfo((struct sockaddr *)&from, len, 246 NULL, 0, num, sizeof(num), NI_NUMERICSERV) == 0 && 247 atoi(num) != 20) { 248 break; 249 } 250 close(s3); 251 goto again; 252 default: 253 break; 254 } 255 (void)close(s2); 256 257 *fd2p = s3; 258 switch (from.ss_family) { 259 case AF_INET: 260 case AF_INET6: 261 if (getnameinfo((struct sockaddr *)&from, len, 262 NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 || 263 (atoi(num) >= IPPORT_RESERVED || 264 atoi(num) < IPPORT_RESERVED / 2)) { 265 (void)fprintf(stderr, 266 "socket: protocol failure in circuit setup.\n"); 267 goto bad2; 268 } 269 break; 270 default: 271 break; 272 } 273 } 274 (void)write(s, locuser, strlen(locuser)+1); 275 (void)write(s, remuser, strlen(remuser)+1); 276 (void)write(s, cmd, strlen(cmd)+1); 277 if (read(s, &c, 1) != 1) { 278 (void)fprintf(stderr, 279 "rcmd: %s: %s\n", *ahost, strerror(errno)); 280 goto bad2; 281 } 282 if (c != 0) { 283 while (read(s, &c, 1) == 1) { 284 (void)write(STDERR_FILENO, &c, 1); 285 if (c == '\n') 286 break; 287 } 288 goto bad2; 289 } 290 sigprocmask(SIG_SETMASK, &oldmask, NULL); 291 free(readsp); 292 return (s); 293 bad2: 294 if (lport) 295 (void)close(*fd2p); 296 bad: 297 if (readsp) 298 free(readsp); 299 (void)close(s); 300 sigprocmask(SIG_SETMASK, &oldmask, NULL); 301 return (-1); 302 } 303 304