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