1 /* $OpenBSD: ftp-proxy.c,v 1.35 2004/03/14 21:51:44 dhartmei Exp $ */ 2 3 /* 4 * Copyright (c) 1996-2001 5 * Obtuse Systems Corporation. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the Obtuse Systems nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL OBTUSE SYSTEMS CORPORATION OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 /* 37 * ftp proxy, Originally based on juniper_ftp_proxy from the Obtuse 38 * Systems juniper firewall, written by Dan Boulet <danny@obtuse.com> 39 * and Bob Beck <beck@obtuse.com> 40 * 41 * This version basically passes everything through unchanged except 42 * for the PORT and the * "227 Entering Passive Mode" reply. 43 * 44 * A PORT command is handled by noting the IP address and port number 45 * specified and then configuring a listen port on some very high port 46 * number and telling the server about it using a PORT message. 47 * We then watch for an in-bound connection on the port from the server 48 * and connect to the client's port when it happens. 49 * 50 * A "227 Entering Passive Mode" reply is handled by noting the IP address 51 * and port number specified and then configuring a listen port on some 52 * very high port number and telling the client about it using a 53 * "227 Entering Passive Mode" reply. 54 * We then watch for an in-bound connection on the port from the client 55 * and connect to the server's port when it happens. 56 * 57 * supports tcp wrapper lookups/access control with the -w flag using 58 * the real destination address - the tcp wrapper stuff is done after 59 * the real destination address is retrieved from pf 60 * 61 */ 62 63 /* 64 * TODO: 65 * Plenty, this is very basic, with the idea to get it in clean first. 66 * 67 * - IPv6 and EPASV support 68 * - Content filter support 69 * - filename filter support 70 * - per-user rules perhaps. 71 */ 72 73 #include <sys/param.h> 74 #include <sys/time.h> 75 #include <sys/socket.h> 76 77 #include <net/if.h> 78 #include <netinet/in.h> 79 80 #include <arpa/inet.h> 81 82 #include <ctype.h> 83 #include <errno.h> 84 #include <grp.h> 85 #include <netdb.h> 86 #include <pwd.h> 87 #include <signal.h> 88 #include <stdarg.h> 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <string.h> 92 #include <sysexits.h> 93 #include <syslog.h> 94 #include <unistd.h> 95 96 #include "util.h" 97 98 #ifdef LIBWRAP 99 #include <tcpd.h> 100 int allow_severity = LOG_INFO; 101 int deny_severity = LOG_NOTICE; 102 #endif /* LIBWRAP */ 103 104 int min_port = IPPORT_HIFIRSTAUTO; 105 int max_port = IPPORT_HILASTAUTO; 106 107 #define STARTBUFSIZE 1024 /* Must be at least 3 */ 108 109 /* 110 * Variables used to support PORT mode connections. 111 * 112 * This gets a bit complicated. 113 * 114 * If PORT mode is on then client_listen_sa describes the socket that 115 * the real client is listening on and server_listen_sa describes the 116 * socket that we are listening on (waiting for the real server to connect 117 * with us). 118 * 119 * If PASV mode is on then client_listen_sa describes the socket that 120 * we are listening on (waiting for the real client to connect to us on) 121 * and server_listen_sa describes the socket that the real server is 122 * listening on. 123 * 124 * If the socket we are listening on gets a connection then we connect 125 * to the other side's socket. Similarly, if a connected socket is 126 * shutdown then we shutdown the other side's socket. 127 */ 128 129 double xfer_start_time; 130 131 struct sockaddr_in real_server_sa; 132 struct sockaddr_in client_listen_sa; 133 struct sockaddr_in server_listen_sa; 134 135 int client_listen_socket = -1; /* Only used in PASV mode */ 136 int client_data_socket = -1; /* Connected socket to real client */ 137 int server_listen_socket = -1; /* Only used in PORT mode */ 138 int server_data_socket = -1; /* Connected socket to real server */ 139 int client_data_bytes, server_data_bytes; 140 141 int AnonFtpOnly; 142 int Verbose; 143 int NatMode; 144 145 char ClientName[NI_MAXHOST]; 146 char RealServerName[NI_MAXHOST]; 147 char OurName[NI_MAXHOST]; 148 149 char *User = "proxy"; 150 char *Group; 151 152 extern int Debug_Level; 153 extern int Use_Rdns; 154 extern in_addr_t Bind_Addr; 155 extern char *__progname; 156 157 typedef enum { 158 UNKNOWN_MODE, 159 PORT_MODE, 160 PASV_MODE, 161 EPRT_MODE, 162 EPSV_MODE 163 } connection_mode_t; 164 165 connection_mode_t connection_mode; 166 167 extern void debuglog(int debug_level, const char *fmt, ...); 168 double wallclock_time(void); 169 void show_xfer_stats(void); 170 void log_control_command (char *cmd, int client); 171 int new_dataconn(int server); 172 void do_client_cmd(struct csiob *client, struct csiob *server); 173 void do_server_reply(struct csiob *server, struct csiob *client); 174 static void 175 usage(void) 176 { 177 syslog(LOG_NOTICE, 178 "usage: %s [-AnrVw] [-a address] [-D debuglevel [-g group]" 179 " [-M maxport] [-m minport] [-t timeout] [-u user]", __progname); 180 exit(EX_USAGE); 181 } 182 183 static void 184 close_client_data(void) 185 { 186 if (client_data_socket >= 0) { 187 shutdown(client_data_socket, 2); 188 close(client_data_socket); 189 client_data_socket = -1; 190 } 191 } 192 193 static void 194 close_server_data(void) 195 { 196 if (server_data_socket >= 0) { 197 shutdown(server_data_socket, 2); 198 close(server_data_socket); 199 server_data_socket = -1; 200 } 201 } 202 203 static void 204 drop_privs(void) 205 { 206 struct passwd *pw; 207 struct group *gr; 208 uid_t uid = 0; 209 gid_t gid = 0; 210 211 if (User != NULL) { 212 pw = getpwnam(User); 213 if (pw == NULL) { 214 syslog(LOG_ERR, "cannot find user %s", User); 215 exit(EX_USAGE); 216 } 217 uid = pw->pw_uid; 218 gid = pw->pw_gid; 219 } 220 221 if (Group != NULL) { 222 gr = getgrnam(Group); 223 if (gr == NULL) { 224 syslog(LOG_ERR, "cannot find group %s", Group); 225 exit(EX_USAGE); 226 } 227 gid = gr->gr_gid; 228 } 229 230 if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) { 231 syslog(LOG_ERR, "cannot drop group privs (%m)"); 232 exit(EX_CONFIG); 233 } 234 235 if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) { 236 syslog(LOG_ERR, "cannot drop root privs (%m)"); 237 exit(EX_CONFIG); 238 } 239 } 240 241 #ifdef LIBWRAP 242 /* 243 * Check a connection against the tcpwrapper, log if we're going to 244 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames 245 * if we are set to do reverse DNS, otherwise no. 246 */ 247 static int 248 check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin) 249 { 250 char cname[NI_MAXHOST]; 251 char sname[NI_MAXHOST]; 252 struct request_info request; 253 int i; 254 255 request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN, 256 client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR, 257 inet_ntoa(client_sin->sin_addr), 0); 258 259 if (Use_Rdns) { 260 /* 261 * We already looked these up, but we have to do it again 262 * for tcp wrapper, to ensure that we get the DNS name, since 263 * the tcp wrapper cares about these things, and we don't 264 * want to pass in a printed address as a name. 265 */ 266 i = getnameinfo((struct sockaddr *) &client_sin->sin_addr, 267 sizeof(&client_sin->sin_addr), cname, sizeof(cname), 268 NULL, 0, NI_NAMEREQD); 269 270 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) 271 strlcpy(cname, STRING_UNKNOWN, sizeof(cname)); 272 273 i = getnameinfo((struct sockaddr *)&server_sin->sin_addr, 274 sizeof(&server_sin->sin_addr), sname, sizeof(sname), 275 NULL, 0, NI_NAMEREQD); 276 277 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) 278 strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); 279 } else { 280 /* 281 * ensure the TCP wrapper doesn't start doing 282 * reverse DNS lookups if we aren't supposed to. 283 */ 284 strlcpy(cname, STRING_UNKNOWN, sizeof(cname)); 285 strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); 286 } 287 288 request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr), 289 0); 290 request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0); 291 292 if (!hosts_access(&request)) { 293 syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s", 294 ClientName, RealServerName); 295 return(0); 296 } 297 return(1); 298 } 299 #endif /* LIBWRAP */ 300 301 double 302 wallclock_time(void) 303 { 304 struct timeval tv; 305 306 gettimeofday(&tv, NULL); 307 return(tv.tv_sec + tv.tv_usec / 1e6); 308 } 309 310 /* 311 * Show the stats for this data transfer 312 */ 313 void 314 show_xfer_stats(void) 315 { 316 char tbuf[1000]; 317 double delta; 318 size_t len; 319 int i; 320 321 if (!Verbose) 322 return; 323 324 delta = wallclock_time() - xfer_start_time; 325 326 if (delta < 0.001) 327 delta = 0.001; 328 329 if (client_data_bytes == 0 && server_data_bytes == 0) { 330 syslog(LOG_INFO, 331 "data transfer complete (no bytes transferred)"); 332 return; 333 } 334 335 len = sizeof(tbuf); 336 337 if (delta >= 60) { 338 int idelta; 339 340 idelta = delta + 0.5; 341 if (idelta >= 60*60) { 342 i = snprintf(tbuf, len, 343 "data transfer complete (%dh %dm %ds", 344 idelta / (60*60), (idelta % (60*60)) / 60, 345 idelta % 60); 346 if (i >= len) 347 goto logit; 348 len -= i; 349 } else { 350 i = snprintf(tbuf, len, 351 "data transfer complete (%dm %ds", idelta / 60, 352 idelta % 60); 353 if (i >= len) 354 goto logit; 355 len -= i; 356 } 357 } else { 358 i = snprintf(tbuf, len, "data transfer complete (%.1fs", 359 delta); 360 if (i >= len) 361 goto logit; 362 len -= i; 363 } 364 365 if (client_data_bytes > 0) { 366 i = snprintf(&tbuf[strlen(tbuf)], len, 367 ", %d bytes to server) (%.1fKB/s", client_data_bytes, 368 (client_data_bytes / delta) / (double)1024); 369 if (i >= len) 370 goto logit; 371 len -= i; 372 } 373 if (server_data_bytes > 0) { 374 i = snprintf(&tbuf[strlen(tbuf)], len, 375 ", %d bytes to client) (%.1fKB/s", server_data_bytes, 376 (server_data_bytes / delta) / (double)1024); 377 if (i >= len) 378 goto logit; 379 len -= i; 380 } 381 strlcat(tbuf, ")", sizeof(tbuf)); 382 logit: 383 syslog(LOG_INFO, "%s", tbuf); 384 } 385 386 void 387 log_control_command (char *cmd, int client) 388 { 389 /* log an ftp control command or reply */ 390 char *logstring; 391 int level = LOG_DEBUG; 392 393 if (!Verbose) 394 return; 395 396 /* don't log passwords */ 397 if (strncasecmp(cmd, "pass ", 5) == 0) 398 logstring = "PASS XXXX"; 399 else 400 logstring = cmd; 401 if (client) { 402 /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */ 403 if ((strncasecmp(cmd, "user ", 5) == 0) || 404 (strncasecmp(cmd, "retr ", 5) == 0) || 405 (strncasecmp(cmd, "cwd ", 4) == 0) || 406 (strncasecmp(cmd, "stor " ,5) == 0)) 407 level = LOG_INFO; 408 } 409 syslog(level, "%s %s", client ? "client:" : " server:", 410 logstring); 411 } 412 413 /* 414 * set ourselves up for a new data connection. Direction is toward client if 415 * "server" is 0, towards server otherwise. 416 */ 417 int 418 new_dataconn(int server) 419 { 420 /* 421 * Close existing data conn. 422 */ 423 424 if (client_listen_socket != -1) { 425 close(client_listen_socket); 426 client_listen_socket = -1; 427 } 428 close_client_data(); 429 430 if (server_listen_socket != -1) { 431 close(server_listen_socket); 432 server_listen_socket = -1; 433 } 434 close_server_data(); 435 436 if (server) { 437 bzero(&server_listen_sa, sizeof(server_listen_sa)); 438 server_listen_socket = get_backchannel_socket(SOCK_STREAM, 439 min_port, max_port, -1, 1, &server_listen_sa); 440 441 if (server_listen_socket == -1) { 442 syslog(LOG_INFO, "server socket bind() failed (%m)"); 443 exit(EX_OSERR); 444 } 445 if (listen(server_listen_socket, 5) != 0) { 446 syslog(LOG_INFO, "server socket listen() failed (%m)"); 447 exit(EX_OSERR); 448 } 449 } else { 450 bzero(&client_listen_sa, sizeof(client_listen_sa)); 451 client_listen_socket = get_backchannel_socket(SOCK_STREAM, 452 min_port, max_port, -1, 1, &client_listen_sa); 453 454 if (client_listen_socket == -1) { 455 syslog(LOG_NOTICE, 456 "cannot get client listen socket (%m)"); 457 exit(EX_OSERR); 458 } 459 if (listen(client_listen_socket, 5) != 0) { 460 syslog(LOG_NOTICE, 461 "cannot listen on client socket (%m)"); 462 exit(EX_OSERR); 463 } 464 } 465 return(0); 466 } 467 468 static void 469 connect_pasv_backchannel(void) 470 { 471 struct sockaddr_in listen_sa; 472 socklen_t salen; 473 474 /* 475 * We are about to accept a connection from the client. 476 * This is a PASV data connection. 477 */ 478 debuglog(2, "client listen socket ready"); 479 480 close_server_data(); 481 close_client_data(); 482 483 salen = sizeof(listen_sa); 484 client_data_socket = accept(client_listen_socket, 485 (struct sockaddr *)&listen_sa, &salen); 486 487 if (client_data_socket < 0) { 488 syslog(LOG_NOTICE, "accept() failed (%m)"); 489 exit(EX_OSERR); 490 } 491 close(client_listen_socket); 492 client_listen_socket = -1; 493 memset(&listen_sa, 0, sizeof(listen_sa)); 494 495 server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port, 496 max_port, -1, 1, &listen_sa); 497 if (server_data_socket < 0) { 498 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)"); 499 exit(EX_OSERR); 500 } 501 if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa, 502 sizeof(server_listen_sa)) != 0) { 503 syslog(LOG_NOTICE, "connect() failed (%m)"); 504 exit(EX_NOHOST); 505 } 506 client_data_bytes = 0; 507 server_data_bytes = 0; 508 xfer_start_time = wallclock_time(); 509 } 510 511 static void 512 connect_port_backchannel(void) 513 { 514 struct sockaddr_in listen_sa; 515 socklen_t salen; 516 517 /* 518 * We are about to accept a connection from the server. 519 * This is a PORT or EPRT data connection. 520 */ 521 debuglog(2, "server listen socket ready"); 522 523 close_server_data(); 524 close_client_data(); 525 526 salen = sizeof(listen_sa); 527 server_data_socket = accept(server_listen_socket, 528 (struct sockaddr *)&listen_sa, &salen); 529 if (server_data_socket < 0) { 530 syslog(LOG_NOTICE, "accept() failed (%m)"); 531 exit(EX_OSERR); 532 } 533 close(server_listen_socket); 534 server_listen_socket = -1; 535 536 if (getuid() != 0) { 537 /* 538 * We're not running as root, so we get a backchannel 539 * socket bound in our designated range, instead of 540 * getting one bound to port 20 - This is deliberately 541 * not RFC compliant. 542 */ 543 bzero(&listen_sa.sin_addr, sizeof(struct in_addr)); 544 client_data_socket = get_backchannel_socket(SOCK_STREAM, 545 min_port, max_port, -1, 1, &listen_sa); 546 if (client_data_socket < 0) { 547 syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)"); 548 exit(EX_OSERR); 549 } 550 551 } else { 552 553 /* 554 * We're root, get our backchannel socket bound to port 555 * 20 here, so we're fully RFC compliant. 556 */ 557 client_data_socket = socket(AF_INET, SOCK_STREAM, 0); 558 559 salen = 1; 560 listen_sa.sin_family = AF_INET; 561 bzero(&listen_sa.sin_addr, sizeof(struct in_addr)); 562 listen_sa.sin_port = htons(20); 563 564 if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR, 565 &salen, sizeof(salen)) == -1) { 566 syslog(LOG_NOTICE, "setsockopt() failed (%m)"); 567 exit(EX_OSERR); 568 } 569 570 if (bind(client_data_socket, (struct sockaddr *)&listen_sa, 571 sizeof(listen_sa)) == - 1) { 572 syslog(LOG_NOTICE, "data channel bind() failed (%m)"); 573 exit(EX_OSERR); 574 } 575 } 576 577 if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa, 578 sizeof(client_listen_sa)) != 0) { 579 syslog(LOG_INFO, "cannot connect data channel (%m)"); 580 exit(EX_NOHOST); 581 } 582 583 client_data_bytes = 0; 584 server_data_bytes = 0; 585 xfer_start_time = wallclock_time(); 586 } 587 588 void 589 do_client_cmd(struct csiob *client, struct csiob *server) 590 { 591 int i, j, rv; 592 char tbuf[100]; 593 char *sendbuf = NULL; 594 595 log_control_command((char *)client->line_buffer, 1); 596 597 /* client->line_buffer is an ftp control command. 598 * There is no reason for these to be very long. 599 * In the interest of limiting buffer overrun attempts, 600 * we catch them here. 601 */ 602 if (strlen((char *)client->line_buffer) > 512) { 603 syslog(LOG_NOTICE, "excessively long control command"); 604 exit(EX_DATAERR); 605 } 606 607 /* 608 * Check the client user provided if needed 609 */ 610 if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ", 611 strlen("user ")) == 0) { 612 char *cp; 613 614 cp = (char *) client->line_buffer + strlen("user "); 615 if ((strcasecmp(cp, "ftp\r\n") != 0) && 616 (strcasecmp(cp, "anonymous\r\n") != 0)) { 617 /* 618 * this isn't anonymous - give the client an 619 * error before they send a password 620 */ 621 snprintf(tbuf, sizeof(tbuf), 622 "500 Only anonymous FTP is allowed\r\n"); 623 j = 0; 624 i = strlen(tbuf); 625 do { 626 rv = send(client->fd, tbuf + j, i - j, 0); 627 if (rv == -1 && errno != EAGAIN && 628 errno != EINTR) 629 break; 630 else if (rv != -1) 631 j += rv; 632 } while (j >= 0 && j < i); 633 sendbuf = NULL; 634 } else 635 sendbuf = (char *)client->line_buffer; 636 } else if ((strncasecmp((char *)client->line_buffer, "eprt ", 637 strlen("eprt ")) == 0)) { 638 639 /* Watch out for EPRT commands */ 640 char *line = NULL, *q, *p, *result[3], delim; 641 struct addrinfo hints, *res = NULL; 642 unsigned long proto; 643 644 j = 0; 645 line = strdup((char *)client->line_buffer+strlen("eprt ")); 646 if (line == NULL) { 647 syslog(LOG_ERR, "insufficient memory"); 648 exit(EX_UNAVAILABLE); 649 } 650 p = line; 651 delim = p[0]; 652 p++; 653 654 memset(result,0, sizeof(result)); 655 for (i = 0; i < 3; i++) { 656 q = strchr(p, delim); 657 if (!q || *q != delim) 658 goto parsefail; 659 *q++ = '\0'; 660 result[i] = p; 661 p = q; 662 } 663 664 proto = strtoul(result[0], &p, 10); 665 if (!*result[0] || *p) 666 goto protounsupp; 667 668 memset(&hints, 0, sizeof(hints)); 669 if (proto != 1) /* 1 == AF_INET - all we support for now */ 670 goto protounsupp; 671 hints.ai_family = AF_INET; 672 hints.ai_socktype = SOCK_STREAM; 673 hints.ai_flags = AI_NUMERICHOST; /*no DNS*/ 674 if (getaddrinfo(result[1], result[2], &hints, &res)) 675 goto parsefail; 676 if (res->ai_next) 677 goto parsefail; 678 if (sizeof(client_listen_sa) < res->ai_addrlen) 679 goto parsefail; 680 memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen); 681 682 debuglog(1, "client wants us to use %s:%u", 683 inet_ntoa(client_listen_sa.sin_addr), 684 htons(client_listen_sa.sin_port)); 685 686 /* 687 * Configure our own listen socket and tell the server about it 688 */ 689 new_dataconn(1); 690 connection_mode = EPRT_MODE; 691 692 debuglog(1, "we want server to use %s:%u", 693 inet_ntoa(server->sa.sin_addr), 694 ntohs(server_listen_sa.sin_port)); 695 696 snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1, 697 inet_ntoa(server->sa.sin_addr), 698 ntohs(server_listen_sa.sin_port)); 699 debuglog(1, "to server (modified): %s", tbuf); 700 sendbuf = tbuf; 701 goto out; 702 parsefail: 703 snprintf(tbuf, sizeof(tbuf), 704 "500 Invalid argument; rejected\r\n"); 705 sendbuf = NULL; 706 goto out; 707 protounsupp: 708 /* we only support AF_INET for now */ 709 if (proto == 2) 710 snprintf(tbuf, sizeof(tbuf), 711 "522 Protocol not supported, use (1)\r\n"); 712 else 713 snprintf(tbuf, sizeof(tbuf), 714 "501 Protocol not supported\r\n"); 715 sendbuf = NULL; 716 out: 717 if (line) 718 free(line); 719 if (res) 720 freeaddrinfo(res); 721 if (sendbuf == NULL) { 722 debuglog(1, "to client (modified): %s", tbuf); 723 i = strlen(tbuf); 724 do { 725 rv = send(client->fd, tbuf + j, i - j, 0); 726 if (rv == -1 && errno != EAGAIN && 727 errno != EINTR) 728 break; 729 else if (rv != -1) 730 j += rv; 731 } while (j >= 0 && j < i); 732 } 733 } else if (!NatMode && (strncasecmp((char *)client->line_buffer, 734 "epsv", strlen("epsv")) == 0)) { 735 736 /* 737 * If we aren't in NAT mode, deal with EPSV. 738 * EPSV is a problem - Unlike PASV, the reply from the 739 * server contains *only* a port, we can't modify the reply 740 * to the client and get the client to connect to us without 741 * resorting to using a dynamic rdr rule we have to add in 742 * for the reply to this connection, and take away afterwards. 743 * so this will wait until we have the right solution for rule 744 * additions/deletions in pf. 745 * 746 * in the meantime we just tell the client we don't do it, 747 * and most clients should fall back to using PASV. 748 */ 749 750 snprintf(tbuf, sizeof(tbuf), 751 "500 EPSV command not understood\r\n"); 752 debuglog(1, "to client (modified): %s", tbuf); 753 j = 0; 754 i = strlen(tbuf); 755 do { 756 rv = send(client->fd, tbuf + j, i - j, 0); 757 if (rv == -1 && errno != EAGAIN && errno != EINTR) 758 break; 759 else if (rv != -1) 760 j += rv; 761 } while (j >= 0 && j < i); 762 sendbuf = NULL; 763 } else if (strncasecmp((char *)client->line_buffer, "port ", 764 strlen("port ")) == 0) { 765 unsigned int values[6]; 766 char *tailptr; 767 768 debuglog(1, "Got a PORT command"); 769 770 tailptr = (char *)&client->line_buffer[strlen("port ")]; 771 values[0] = 0; 772 773 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], 774 &values[1], &values[2], &values[3], &values[4], 775 &values[5]); 776 if (i != 6) { 777 syslog(LOG_INFO, "malformed PORT command (%s)", 778 client->line_buffer); 779 exit(EX_DATAERR); 780 } 781 782 for (i = 0; i<6; i++) { 783 if (values[i] > 255) { 784 syslog(LOG_INFO, 785 "malformed PORT command (%s)", 786 client->line_buffer); 787 exit(EX_DATAERR); 788 } 789 } 790 791 client_listen_sa.sin_family = AF_INET; 792 client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) | 793 (values[1] << 16) | (values[2] << 8) | 794 (values[3] << 0)); 795 796 client_listen_sa.sin_port = htons((values[4] << 8) | 797 values[5]); 798 debuglog(1, "client wants us to use %u.%u.%u.%u:%u", 799 values[0], values[1], values[2], values[3], 800 (values[4] << 8) | values[5]); 801 802 /* 803 * Configure our own listen socket and tell the server about it 804 */ 805 new_dataconn(1); 806 connection_mode = PORT_MODE; 807 808 debuglog(1, "we want server to use %s:%u", 809 inet_ntoa(server->sa.sin_addr), 810 ntohs(server_listen_sa.sin_port)); 811 812 snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n", 813 ((u_char *)&server->sa.sin_addr.s_addr)[0], 814 ((u_char *)&server->sa.sin_addr.s_addr)[1], 815 ((u_char *)&server->sa.sin_addr.s_addr)[2], 816 ((u_char *)&server->sa.sin_addr.s_addr)[3], 817 ((u_char *)&server_listen_sa.sin_port)[0], 818 ((u_char *)&server_listen_sa.sin_port)[1]); 819 820 debuglog(1, "to server (modified): %s", tbuf); 821 822 sendbuf = tbuf; 823 } else 824 sendbuf = (char *)client->line_buffer; 825 826 /* 827 *send our (possibly modified) control command in sendbuf 828 * on it's way to the server 829 */ 830 if (sendbuf != NULL) { 831 j = 0; 832 i = strlen(sendbuf); 833 do { 834 rv = send(server->fd, sendbuf + j, i - j, 0); 835 if (rv == -1 && errno != EAGAIN && errno != EINTR) 836 break; 837 else if (rv != -1) 838 j += rv; 839 } while (j >= 0 && j < i); 840 } 841 } 842 843 void 844 do_server_reply(struct csiob *server, struct csiob *client) 845 { 846 int code, i, j, rv; 847 struct in_addr *iap; 848 static int continuing = 0; 849 char tbuf[100], *sendbuf, *p; 850 851 log_control_command((char *)server->line_buffer, 0); 852 853 if (strlen((char *)server->line_buffer) > 512) { 854 /* 855 * someone's playing games. Have a cow in the syslogs and 856 * exit - we don't pass this on for fear of hurting 857 * our other end, which might be poorly implemented. 858 */ 859 syslog(LOG_NOTICE, "long FTP control reply"); 860 exit(EX_DATAERR); 861 } 862 863 /* 864 * Watch out for "227 Entering Passive Mode ..." replies 865 */ 866 code = strtol((char *)server->line_buffer, &p, 10); 867 if (isspace(server->line_buffer[0])) 868 code = 0; 869 if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) { 870 if (continuing) 871 goto sendit; 872 syslog(LOG_INFO, "malformed control reply"); 873 exit(EX_DATAERR); 874 } 875 if (code <= 0 || code > 999) { 876 if (continuing) 877 goto sendit; 878 syslog(LOG_INFO, "invalid server reply code %d", code); 879 exit(EX_DATAERR); 880 } 881 if (*p == '-') 882 continuing = 1; 883 else 884 continuing = 0; 885 if (code == 227 && !NatMode) { 886 unsigned int values[6]; 887 char *tailptr; 888 889 debuglog(1, "Got a PASV reply"); 890 debuglog(1, "{%s}", (char *)server->line_buffer); 891 892 tailptr = (char *)strchr((char *)server->line_buffer, '('); 893 if (tailptr == NULL) { 894 tailptr = strrchr((char *)server->line_buffer, ' '); 895 if (tailptr == NULL) { 896 syslog(LOG_NOTICE, "malformed 227 reply"); 897 exit(EX_DATAERR); 898 } 899 } 900 tailptr++; /* skip past space or ( */ 901 902 values[0] = 0; 903 904 i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], 905 &values[1], &values[2], &values[3], &values[4], 906 &values[5]); 907 if (i != 6) { 908 syslog(LOG_INFO, "malformed PASV reply (%s)", 909 client->line_buffer); 910 exit(EX_DATAERR); 911 } 912 for (i = 0; i<6; i++) 913 if (values[i] > 255) { 914 syslog(LOG_INFO, "malformed PASV reply(%s)", 915 client->line_buffer); 916 exit(EX_DATAERR); 917 } 918 919 server_listen_sa.sin_family = AF_INET; 920 server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) | 921 (values[1] << 16) | (values[2] << 8) | (values[3] << 0)); 922 server_listen_sa.sin_port = htons((values[4] << 8) | 923 values[5]); 924 925 debuglog(1, "server wants us to use %s:%u", 926 inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) | 927 values[5]); 928 929 new_dataconn(0); 930 connection_mode = PASV_MODE; 931 iap = &(server->sa.sin_addr); 932 933 debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap), 934 htons(client_listen_sa.sin_port)); 935 936 snprintf(tbuf, sizeof(tbuf), 937 "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n", 938 ((u_char *)iap)[0], ((u_char *)iap)[1], 939 ((u_char *)iap)[2], ((u_char *)iap)[3], 940 ((u_char *)&client_listen_sa.sin_port)[0], 941 ((u_char *)&client_listen_sa.sin_port)[1]); 942 debuglog(1, "to client (modified): %s", tbuf); 943 sendbuf = tbuf; 944 } else { 945 sendit: 946 sendbuf = (char *)server->line_buffer; 947 } 948 949 /* 950 * send our (possibly modified) control command in sendbuf 951 * on it's way to the client 952 */ 953 j = 0; 954 i = strlen(sendbuf); 955 do { 956 rv = send(client->fd, sendbuf + j, i - j, 0); 957 if (rv == -1 && errno != EAGAIN && errno != EINTR) 958 break; 959 else if (rv != -1) 960 j += rv; 961 } while (j >= 0 && j < i); 962 963 } 964 965 int 966 main(int argc, char *argv[]) 967 { 968 struct csiob client_iob, server_iob; 969 struct sigaction new_sa, old_sa; 970 int sval, ch, flags, i; 971 socklen_t salen; 972 int one = 1; 973 long timeout_seconds = 0; 974 struct timeval tv; 975 #ifdef LIBWRAP 976 int use_tcpwrapper = 0; 977 #endif /* LIBWRAP */ 978 979 while ((ch = getopt(argc, argv, "a:D:g:m:M:t:u:AnVwr")) != -1) { 980 char *p; 981 switch (ch) { 982 case 'a': 983 if (!*optarg) 984 usage(); 985 if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) { 986 syslog(LOG_NOTICE, 987 "%s: invalid address", optarg); 988 usage(); 989 } 990 break; 991 case 'A': 992 AnonFtpOnly = 1; /* restrict to anon usernames only */ 993 break; 994 case 'D': 995 Debug_Level = strtol(optarg, &p, 10); 996 if (!*optarg || *p) 997 usage(); 998 break; 999 case 'g': 1000 Group = optarg; 1001 break; 1002 case 'm': 1003 min_port = strtol(optarg, &p, 10); 1004 if (!*optarg || *p) 1005 usage(); 1006 if (min_port < 0 || min_port > USHRT_MAX) 1007 usage(); 1008 break; 1009 case 'M': 1010 max_port = strtol(optarg, &p, 10); 1011 if (!*optarg || *p) 1012 usage(); 1013 if (max_port < 0 || max_port > USHRT_MAX) 1014 usage(); 1015 break; 1016 case 'n': 1017 NatMode = 1; /* pass all passives, we're using NAT */ 1018 break; 1019 case 'r': 1020 Use_Rdns = 1; /* look up hostnames */ 1021 break; 1022 case 't': 1023 timeout_seconds = strtol(optarg, &p, 10); 1024 if (!*optarg || *p) 1025 usage(); 1026 break; 1027 case 'u': 1028 User = optarg; 1029 break; 1030 case 'V': 1031 Verbose = 1; 1032 break; 1033 #ifdef LIBWRAP 1034 case 'w': 1035 use_tcpwrapper = 1; /* do the libwrap thing */ 1036 break; 1037 #endif /* LIBWRAP */ 1038 default: 1039 usage(); 1040 /* NOTREACHED */ 1041 } 1042 } 1043 argc -= optind; 1044 argv += optind; 1045 1046 if (max_port < min_port) 1047 usage(); 1048 1049 openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 1050 1051 setlinebuf(stdout); 1052 setlinebuf(stderr); 1053 1054 memset(&client_iob, 0, sizeof(client_iob)); 1055 memset(&server_iob, 0, sizeof(server_iob)); 1056 1057 if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1) 1058 exit(EX_PROTOCOL); 1059 1060 /* 1061 * We may now drop root privs, as we have done our ioctl for 1062 * pf. If we do drop root, we can't make backchannel connections 1063 * for PORT and EPRT come from port 20, which is not strictly 1064 * RFC compliant. This shouldn't cause problems for all but 1065 * the stupidest ftp clients and the stupidest packet filters. 1066 */ 1067 drop_privs(); 1068 1069 /* 1070 * We check_host after get_proxy_env so that checks are done 1071 * against the original destination endpoint, not the endpoint 1072 * of our side of the rdr. This allows the use of tcpwrapper 1073 * rules to restrict destinations as well as sources of connections 1074 * for ftp. 1075 */ 1076 if (Use_Rdns) 1077 flags = 0; 1078 else 1079 flags = NI_NUMERICHOST | NI_NUMERICSERV; 1080 1081 i = getnameinfo((struct sockaddr *)&client_iob.sa, 1082 sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0, 1083 flags); 1084 1085 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1086 debuglog(2, "name resolution failure (client)"); 1087 exit(EX_OSERR); 1088 } 1089 1090 i = getnameinfo((struct sockaddr *)&real_server_sa, 1091 sizeof(real_server_sa), RealServerName, sizeof(RealServerName), 1092 NULL, 0, flags); 1093 1094 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1095 debuglog(2, "name resolution failure (server)"); 1096 exit(EX_OSERR); 1097 } 1098 1099 #ifdef LIBWRAP 1100 if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa)) 1101 exit(EX_NOPERM); 1102 #endif 1103 1104 client_iob.fd = 0; 1105 1106 syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName, 1107 ntohs(client_iob.sa.sin_port), RealServerName, 1108 ntohs(real_server_sa.sin_port)); 1109 1110 server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port, 1111 -1, 1, &server_iob.sa); 1112 1113 if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa, 1114 sizeof(real_server_sa)) != 0) { 1115 syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName, 1116 ntohs(real_server_sa.sin_port)); 1117 exit(EX_NOHOST); 1118 } 1119 1120 /* 1121 * Now that we are connected to the real server, get the name 1122 * of our end of the server socket so we know our IP address 1123 * from the real server's perspective. 1124 */ 1125 salen = sizeof(server_iob.sa); 1126 getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen); 1127 1128 i = getnameinfo((struct sockaddr *)&server_iob.sa, 1129 sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags); 1130 1131 if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { 1132 debuglog(2, "name resolution failure (local)"); 1133 exit(EX_OSERR); 1134 } 1135 1136 debuglog(1, "local socket is %s:%u", OurName, 1137 ntohs(server_iob.sa.sin_port)); 1138 1139 /* ignore SIGPIPE */ 1140 bzero(&new_sa, sizeof(new_sa)); 1141 new_sa.sa_handler = SIG_IGN; 1142 (void)sigemptyset(&new_sa.sa_mask); 1143 new_sa.sa_flags = SA_RESTART; 1144 if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) { 1145 syslog(LOG_ERR, "sigaction() failed (%m)"); 1146 exit(EX_OSERR); 1147 } 1148 1149 if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one, 1150 sizeof(one)) == -1) { 1151 syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)"); 1152 exit(EX_OSERR); 1153 } 1154 1155 client_iob.line_buffer_size = STARTBUFSIZE; 1156 client_iob.line_buffer = malloc(client_iob.line_buffer_size); 1157 client_iob.io_buffer_size = STARTBUFSIZE; 1158 client_iob.io_buffer = malloc(client_iob.io_buffer_size); 1159 client_iob.next_byte = 0; 1160 client_iob.io_buffer_len = 0; 1161 client_iob.alive = 1; 1162 client_iob.who = "client"; 1163 client_iob.send_oob_flags = 0; 1164 client_iob.real_sa = client_iob.sa; 1165 1166 server_iob.line_buffer_size = STARTBUFSIZE; 1167 server_iob.line_buffer = malloc(server_iob.line_buffer_size); 1168 server_iob.io_buffer_size = STARTBUFSIZE; 1169 server_iob.io_buffer = malloc(server_iob.io_buffer_size); 1170 server_iob.next_byte = 0; 1171 server_iob.io_buffer_len = 0; 1172 server_iob.alive = 1; 1173 server_iob.who = "server"; 1174 server_iob.send_oob_flags = MSG_OOB; 1175 server_iob.real_sa = real_server_sa; 1176 1177 if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL || 1178 server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) { 1179 syslog (LOG_NOTICE, "insufficient memory"); 1180 exit(EX_UNAVAILABLE); 1181 } 1182 1183 while (client_iob.alive || server_iob.alive) { 1184 int maxfd = 0; 1185 fd_set *fdsp; 1186 1187 if (client_iob.fd > maxfd) 1188 maxfd = client_iob.fd; 1189 if (client_listen_socket > maxfd) 1190 maxfd = client_listen_socket; 1191 if (client_data_socket > maxfd) 1192 maxfd = client_data_socket; 1193 if (server_iob.fd > maxfd) 1194 maxfd = server_iob.fd; 1195 if (server_listen_socket > maxfd) 1196 maxfd = server_listen_socket; 1197 if (server_data_socket > maxfd) 1198 maxfd = server_data_socket; 1199 1200 debuglog(3, "client is %s; server is %s", 1201 client_iob.alive ? "alive" : "dead", 1202 server_iob.alive ? "alive" : "dead"); 1203 1204 fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS), 1205 sizeof(fd_mask)); 1206 if (fdsp == NULL) { 1207 syslog(LOG_NOTICE, "insufficient memory"); 1208 exit(EX_UNAVAILABLE); 1209 } 1210 1211 if (client_iob.alive && telnet_getline(&client_iob, 1212 &server_iob)) { 1213 debuglog(3, "client line buffer is \"%s\"", 1214 (char *)client_iob.line_buffer); 1215 if (client_iob.line_buffer[0] != '\0') 1216 do_client_cmd(&client_iob, &server_iob); 1217 } else if (server_iob.alive && telnet_getline(&server_iob, 1218 &client_iob)) { 1219 debuglog(3, "server line buffer is \"%s\"", 1220 (char *)server_iob.line_buffer); 1221 if (server_iob.line_buffer[0] != '\0') 1222 do_server_reply(&server_iob, &client_iob); 1223 } else { 1224 if (client_iob.alive) { 1225 FD_SET(client_iob.fd, fdsp); 1226 if (client_listen_socket >= 0) 1227 FD_SET(client_listen_socket, fdsp); 1228 if (client_data_socket >= 0) 1229 FD_SET(client_data_socket, fdsp); 1230 } 1231 if (server_iob.alive) { 1232 FD_SET(server_iob.fd, fdsp); 1233 if (server_listen_socket >= 0) 1234 FD_SET(server_listen_socket, fdsp); 1235 if (server_data_socket >= 0) 1236 FD_SET(server_data_socket, fdsp); 1237 } 1238 tv.tv_sec = timeout_seconds; 1239 tv.tv_usec = 0; 1240 1241 doselect: 1242 sval = select(maxfd + 1, fdsp, NULL, NULL, 1243 (tv.tv_sec == 0) ? NULL : &tv); 1244 if (sval == 0) { 1245 /* 1246 * This proxy has timed out. Expire it 1247 * quietly with an obituary in the syslogs 1248 * for any passing mourners. 1249 */ 1250 syslog(LOG_INFO, 1251 "timeout: no data for %ld seconds", 1252 timeout_seconds); 1253 exit(EX_OK); 1254 } 1255 if (sval == -1) { 1256 if (errno == EINTR || errno == EAGAIN) 1257 goto doselect; 1258 syslog(LOG_NOTICE, 1259 "select() failed (%m)"); 1260 exit(EX_OSERR); 1261 } 1262 if (client_data_socket >= 0 && 1263 FD_ISSET(client_data_socket, fdsp)) { 1264 int rval; 1265 1266 debuglog(3, "transfer: client to server"); 1267 rval = xfer_data("client to server", 1268 client_data_socket, 1269 server_data_socket, 1270 client_iob.sa.sin_addr, 1271 real_server_sa.sin_addr); 1272 if (rval <= 0) { 1273 close_client_data(); 1274 close_server_data(); 1275 show_xfer_stats(); 1276 } else 1277 client_data_bytes += rval; 1278 } 1279 if (server_data_socket >= 0 && 1280 FD_ISSET(server_data_socket, fdsp)) { 1281 int rval; 1282 1283 debuglog(3, "transfer: server to client"); 1284 rval = xfer_data("server to client", 1285 server_data_socket, 1286 client_data_socket, 1287 real_server_sa.sin_addr, 1288 client_iob.sa.sin_addr); 1289 if (rval <= 0) { 1290 close_client_data(); 1291 close_server_data(); 1292 show_xfer_stats(); 1293 } else 1294 server_data_bytes += rval; 1295 } 1296 if (server_listen_socket >= 0 && 1297 FD_ISSET(server_listen_socket, fdsp)) { 1298 connect_port_backchannel(); 1299 } 1300 if (client_listen_socket >= 0 && 1301 FD_ISSET(client_listen_socket, fdsp)) { 1302 connect_pasv_backchannel(); 1303 } 1304 if (client_iob.alive && 1305 FD_ISSET(client_iob.fd, fdsp)) { 1306 client_iob.data_available = 1; 1307 } 1308 if (server_iob.alive && 1309 FD_ISSET(server_iob.fd, fdsp)) { 1310 server_iob.data_available = 1; 1311 } 1312 } 1313 free(fdsp); 1314 if (client_iob.got_eof) { 1315 shutdown(server_iob.fd, 1); 1316 shutdown(client_iob.fd, 0); 1317 client_iob.got_eof = 0; 1318 client_iob.alive = 0; 1319 } 1320 if (server_iob.got_eof) { 1321 shutdown(client_iob.fd, 1); 1322 shutdown(server_iob.fd, 0); 1323 server_iob.got_eof = 0; 1324 server_iob.alive = 0; 1325 } 1326 } 1327 1328 if (Verbose) 1329 syslog(LOG_INFO, "session ended"); 1330 1331 exit(EX_OK); 1332 } 1333