Logo Search packages:      
Sourcecode: jftpgw version File versions  Download package

active.c

/* 
 * Copyright (C) 1999-2004 Joachim Wieland <joe@mcknight.de>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111, USA.
 */

#include "jftpgw.h"

extern int timeout;
static struct portrangestruct *actvrangeserver = (struct portrangestruct*) 0;
static struct portrangestruct *actvrangeclient = (struct portrangestruct*) 0;
static void sayact(int, char*, int);

int portcommandcheck(const char* buffer, struct sockaddr_in* sin,
                              struct clientinfo* clntinfo) {
      int cs = clntinfo->clientsocket;
      char* beginning = 0;
      int ret;

      clntinfo->clientmode = ACTIVE;
      beginning = strchr(buffer, ' ');
      if (!beginning) {
            /* It should not fail, since we are testing for "PORT " in
             * cmds.c */
            jlog(3, "Invalid PORT command (no space): %s", buffer);
            say(cs, "500 Invalid PORT command (no space char)\r\n");
            return -1;
      }
      beginning++;
      ret = parsesock(beginning, sin, ACTIVE);
      if (ret) {
            jlog(3, "Error parsing the PORT command: %s (%s)",
                        buffer, beginning);
            say(cs, "501 Error parsing the PORT command\r\n");
            return -1;
      }
      if (config_get_bool("allowforeignaddress") == 0) {
            char* sin_addr = strdup(inet_ntoa(sin->sin_addr));
            enough_mem (sin_addr);
            if (0 != strcmp(sin_addr,
                        get_char_ip(GET_IP_CLIENT, clntinfo))) {

                  jlog(3, "Illegal foreign address %s in PORT command.",
                              inet_ntoa(sin->sin_addr));
                  jlog(5, "Expected address %s instead",
                              get_char_ip(GET_IP_CLIENT, clntinfo));
                  say(cs, "500 Illegal address in PORT command\r\n");
                  free(sin_addr);
                  return -1;
            }
            free(sin_addr);
      }
      if (config_get_bool("allowreservedports") == 0) {
            if (ntohs(sin->sin_port) < IPPORT_RESERVED) {
                  jlog(3, "Illegal port %d in PORT command.",
                              ntohs(sin->sin_port));
                  say(cs, "500 Illegal port in PORT command\r\n");
                  return -1;
            }
      }
      /* seems to be okay */
      return 0;
}


/* 
 * activeclient() reads the "PORT x,x,x,x,x,x" command from the client,
 * opens that port on the client's side and returns the socket descriptor
 * 
 * Parameters: buffer: contains the "PORT x,x,x,x,x,x" command
 *             clntinfo: the connection variables
 * 
 * Returns: -1 on error, 0 on success
 *
 * Called by: passcmd (if cmd starts with PORT)
 * 
 * */

int activeclient(char* buffer, struct clientinfo* clntinfo) {
      struct sockaddr_in sin;
      struct portrangestruct* prs;
      int ret;

      ret = portcommandcheck(buffer, &sin, clntinfo);
      if (ret < 0) {
            return ret;
      }
      jlog(8, "Opening the active FTP port %d on %s",
                  ntohs(sin.sin_port), inet_ntoa(sin.sin_addr));
      if (clntinfo->waitforconnect == &clntinfo->dataclientsock) {
            clntinfo->waitforconnect = (int*) 0;
      }
      if ( ! actvrangeclient ) {
            const char* range = config_get_option("activeportrangeclient");
            if ( ! range ) {
                  range = config_get_option("activeportrange");
            }
            actvrangeclient = config_parse_portranges(range);
      }
      if ( ! actvrangeclient ) {
            prs = config_port2portrange(clntinfo->dataport);
      } else {
            prs = actvrangeclient;
      }
      ret = openportiaddr(sin.sin_addr.s_addr,          /* dest ip   */
                      ntohs(sin.sin_port),          /* dest port */
                      clntinfo->data_addr_to_client,/* source ip, port */
                      prs);
      if (ret < 0) {
            jlog(8, "setting dataclientsock to -1 (openport error)");
            clntinfo->dataclientsock = -1;
            return -1;
      }
      clntinfo->dataclientsock = ret;

      return 0;
}


/* 
 * activeserver() opens a port on the proxy machine, determins the port
 * number and tells it to the server (along with the address of the interface
 * over which we connect to it).
 * 
 * Parameters: answer: A pointer to a pointer used to store the answer of the
 *                     server
 * 
 * Returns: -1 on error, 0 on success
 *
 * Called by: handlecmds (when client issued PORT or PASV)
 * 
 * */

int activeserver(char** answer, struct clientinfo *clntinfo) {

      int ret;
      struct sockaddr_in sin;
      int ss = clntinfo->serversocket;
      char* buffer;

      if ( ! actvrangeserver ) {
            const char* range = config_get_option("activeportrangeserver");
            if ( ! range ) {
                  range = config_get_option("activeportrange");
            }
            actvrangeserver = config_parse_portranges(range);
      }
      /* open a port on our side use the interface address through which
       * we are connected to the server */
      ret = openlocalport(&sin,                    /* for the return value */
                      clntinfo->data_addr_to_server,      /* source ip */
                      actvrangeserver);                /* source ports */
      if (clntinfo->waitforconnect == &clntinfo->dataserversock) {
            clntinfo->waitforconnect = (int*) 0;
      }
      if (ret < 0) {
            say(clntinfo->clientsocket,
                  "425 Could not establish a connection endpoint\r\n");
            *answer = 0;
            return -1;
      }

      clntinfo->dataserversock = ret;
      clntinfo->waitforconnect = &clntinfo->dataserversock;

      /* tell the server about the addr + port it can connect to */
      sin.sin_addr.s_addr = clntinfo->data_addr_to_server;
      sayact(ss, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

      buffer = ftp_readline(ss);
      *answer = buffer;
      if (!buffer) {
            if (timeout) {
                  jlog(2, "Timeout in %s line %d\n", __FILE__ ,__LINE__);
                  jlog(2, "Timed out reading answer for the PORT command");
                  say(clntinfo->clientsocket,
                  "500 Timeout waiting for answer for the PORT command\r\n");
            }
            else {
                  jlog(1, "Error in readline reading answer for the PORT command");
                  say(clntinfo->clientsocket,
                        "Error reading answer for PORT command\r\n");
            }
            return -1;
      }
      /* code 200 would be "PORT command successful" */
      if (!checkdigits(buffer, 200)) {
            jlog(1, "Failure sending PORT command (%s) to the server: %s",
                        inet_ntoa(sin.sin_addr), buffer);
            say(clntinfo->clientsocket,
                        "425 Can't establish connection\r\n");
            return -1;
      }
      return 0;

}

/* sayact() transforms the parameters ADDR and PORT to the 
 * "PORT x,x,x,x,x,x" notation and says it to the descriptor fd
 *
 * Paramters: fd: the file descriptor the command is written to
 *            addr: the address that should be included in dot notation
 *                  format
 *            port: the port that was opened on addr's side
 */

static void sayact(int fd, char* addr, int port) {
      unsigned short int lo, hi;
      char buffer[MAX_LINE_SIZE], *dot;

      hi = port % 256;
      lo = (port - hi) / 256;

      while ((dot = strchr(addr, '.'))) {
            *dot = ',';
      }
      snprintf(buffer, sizeof(buffer), "PORT %s,%d,%d\r\n",
            addr, lo, hi);
      
      say(fd, buffer);
}

void destroy_active_portrange() {
      config_destroy_portrange(actvrangeserver);
      config_destroy_portrange(actvrangeclient);
      actvrangeserver = (struct portrangestruct*) 0;
      actvrangeclient = (struct portrangestruct*) 0;
}


Generated by  Doxygen 1.6.0   Back to index