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

fw_auth_cmds.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"
#include "cmds.h"

/* static functions here */
static int cmds_after_user(struct conn_info_st*);
static int cmds_after_pass(struct conn_info_st*);

int login(struct clientinfo*, int);


struct destination_t {
      char* hostname;
      unsigned int port;
};


/* returns 0 if the user has supplied the correct password */
static
int fw_validate_user(const char* user,
                 const char* fwpass,
                 const char* method,
                 const char* pass) {

      if (cryptcmp(pass, fwpass) == 0) {
            return 0;
      }

      return 1;
}

/* returns 0 if the user has supplied the correct password */
static
int fw_validate(const char* fwuser, const char* fwpass) {
      struct slist_t* acct_list = config_get_option_array("account");
      struct slist_t* account, *acct_line;
      const char* user, *method, *pass;

      if ( ! acct_list ) {
            jlog(5, "No account information found for %s", fwuser);
            return 1;
      }

      /* reverse the list to keep the paradigma: if there are several
       * similar options, the last one is taken */
      acct_list = slist_reverse(acct_list);

      account = acct_list;

      do {
            acct_line = config_split_line( account -> value, WHITESPACES );

            if (!acct_line) {
                  goto error_line;
            }
            user = acct_line->value;
            if (!user || !strlen(user) || !acct_line->next) {
                  goto error_line;
            }
            method = acct_line->next->value;
            if (!method || !strlen(method) || !acct_line->next->next) {
                  goto error_line;
            }
            pass = acct_line->next->next->value;
            if (!pass || !strlen(pass)) {
                  goto error_line;
            }

            /* parsing went fine down here */

            if (strcmp(user, fwuser) == 0) {
                  /* jump out of the loop */
                  int ret;
                  slist_destroy(acct_list);
                  ret = fw_validate_user(fwuser, fwpass, method, pass);
                  slist_destroy(acct_line);
                  return ret;
            }
            continue;
error_line:
            slist_destroy(acct_line);
            jlog(5, "Incorrect account specification: %s", account->value);
      } while ( (account = account -> next) );

      slist_destroy(acct_list);

      return 1;
}


int std_reset(const char* args, struct conn_info_st* conn_info) {
      /* set all values to (char*) 0 after free()ing */
      struct clientinfo* c = conn_info->clntinfo;

      jlog(8, "resetting login information");

      if (!c->transparent == TRANSPARENT_YES ||
          !config_compare_option("logintime", "connect")) {

            c->login.stage = LOGIN_ST_NOT_CONNECTED;
            if (c->destination) {
                  free(c->destination);
                  c->destination = (char*) 0;
            }
            c->destinationport = 0;
      }
      if (c->user) {
            free(c->user);
            c->user = (char*) 0;
      }
      if (c->pass) {
            free(c->pass);
            c->pass = (char*) 0;
      }
      if (c->anon_user) {
            free(c->anon_user);
            c->anon_user = (char*) 0;
      }
      if (c->fw_auth.user) {
            free(c->fw_auth.user);
            c->fw_auth.user = (char*) 0;
      }
      if (c->fw_auth.pass) {
            free(c->fw_auth.pass);
            c->fw_auth.pass = (char*) 0;
      }
      if (c->before_forward.user) {
            free(c->before_forward.user);
            c->before_forward.user = (char*) 0;
      }
      if (c->before_forward.destination) {
            free(c->before_forward.destination);
            c->before_forward.destination = (char*) 0;
      }
      if (c->login.authresp.fullmsg) {
            free(c->login.authresp.fullmsg);
            c->login.authresp.fullmsg = (char*) 0;
            c->login.authresp.lastmsg = (char*) 0;
      }

      return CMD_HANDLED;
}


#define DELIMITERS "@,: \t"

static
struct destination_t fw_auth_parse_host_port(const char* cmd) {
      struct destination_t dest = { (char*) 0, 0 };
      char* portstr;
      int offset = 0;

      if (! cmd) {
            return dest;
      }
      dest.hostname = quotstrtok(cmd, DELIMITERS, &offset);
      if (!dest.hostname) {
            return dest;
      }
      if (strlen(dest.hostname) == 0) {
            free(dest.hostname);
            dest.hostname = (char*) 0;
            return dest;
      }
      portstr = quotstrtok(cmd, DELIMITERS, &offset);
      dest.port = conv_char2long(portstr,
                  config_get_ioption(("serverport"), DEFAULTSERVERPORT));
      return dest;
}


static
int fw_forward(const char* user,
                const char* dest,
                struct clientinfo* clntinfo) {

      if ( ! user ) {
            say(clntinfo->clientsocket, "500 Expecting user name\r\n");
            jlog(5, "No username given");
            return CMD_ERROR;
      }

      if (clntinfo->forward.passauth && user && dest) {
            clntinfo->destination = strdup(dest);
            enough_mem(clntinfo->destination);
      }

      if (strcmp(user, "*") == 0) {
            /* keep the old user name */
            jlog(8, "no new user name - keeping old one: %s",
                                    clntinfo->user);
      } else {
            free(clntinfo->user);
            clntinfo->user = strdup(user);
            enough_mem(clntinfo->user);
      }

      if (!dest || strlen(dest) == 0 || strcmp(dest, "*") == 0) {
            /* keep the old one */
            jlog(8, "no new destination - keeping old one: %s",
                              clntinfo->destination);
      } else {
            free(clntinfo->destination);
            clntinfo->destination = strdup(dest);
            enough_mem(clntinfo->destination);
      }
      return CMD_HANDLED;
}


static
int fw_transparent(struct clientinfo* clntinfo) {
      const char* transfor_opt = config_get_option("transparent-forward");
      /* check for transdest */
      /* opt => dest => forwardhost */
      struct sockaddr_in t_in;

      if (clntinfo->transparent == TRANSPARENT_NO) {
            /* not in transparent mode */
            jlog(9, "fw_transparent: not in transparent mode");
            return CMD_HANDLED;
      }

      if (transfor_opt) {
            /* transparent forward active */
            jlog(9, "fw_transparent: transparent forward active");
            return CMD_HANDLED;
      }

      if (clntinfo->destination) {
            jlog(9, "fw_transparent: Destination already set");
            return CMD_HANDLED;
      }

      if (config_get_bool("transparent-proxy") == 0) {
            jlog(4, "No destination set and transparent proxy support disabled");
            say(clntinfo->clientsocket, "500 No destination\r\n");
            return CMD_ERROR;
      }
      t_in = clntinfo->transparent_destination;
      clntinfo->destination = strdup(inet_ntoa(t_in.sin_addr));
      clntinfo->destinationport =
           ntohs(clntinfo->transparent_destination.sin_port);

      /* Determine the IP the client sees of us */
      if (strcasecmp(config_get_option("getinternalip"),
                                    "configuration") == 0) {
            clntinfo->addr_to_client =
                  config_get_addroption("dataclientaddress", INADDR_ANY);
      } else {
            clntinfo->addr_to_client =
            socketinfo_get_local_addr_by_sending(clntinfo->clientsocket);
      }

      jlog(8, "Using transparent proxy. Connecting to %s port %d. User: %s",
                        clntinfo->destination,
                        clntinfo->destinationport,
                        clntinfo->user);

      return CMD_HANDLED;
}


static
int fw_transparent_forward(struct clientinfo* clntinfo) {
      const char* transforward_opt = config_get_option("transparent-forward");
      size_t usersize;
      struct destination_t destination;
      char* transparent_target;

      if (! transforward_opt) {
            return CMD_HANDLED;
      }

      if (clntinfo->transparent == TRANSPARENT_NO) {
            /* not in transparent mode */
            return CMD_HANDLED;
      }

      /* determine the intended destination */
      transparent_target = socketinfo_get_transparent_target_char(
                              clntinfo->clientsocket);
      if (!transparent_target) {
            jlog(4, "Could not get transparent destination");
            say(clntinfo->clientsocket, "500 Error logging in\r\n");
            return CMD_ERROR;
      }

      if (!clntinfo->before_forward.user) {
            char* myself;
            struct in_addr myself_in;

            clntinfo->before_forward.user = strdup(clntinfo->user);
            /* if there was a transparent forward, the original
             * destination was the proxy's interface */
            clntinfo->before_forward.dest_ip
                  = socketinfo_get_local_ip(clntinfo->clientsocket);
            myself_in.s_addr = clntinfo->before_forward.dest_ip;
            myself = inet_ntoa(myself_in);
            if (myself) {
                  clntinfo->before_forward.destination = strdup(myself);
            } else {
                  clntinfo->before_forward.destination = " -error- ";
            }
            clntinfo->before_forward.destinationport
                  = socketinfo_get_local_port(clntinfo->clientsocket);
      }

      if (config_get_bool("transparent-forward-include-port") == 0) {
            char* colon = strrchr(transparent_target, ':');
            if (colon) { *colon = '\0'; }
      }

      /* resize the new USER buffer */
      usersize = strlen(clntinfo->user)
                  + 1 /* @ */
                  + strlen(transparent_target)
                  + 1  /* scnprintf seems to need it */
                  + 1; /* Terminate */

      /* write user@dest into user field. dest is the intended destination */
      clntinfo->user = realloc(clntinfo->user, usersize);
      enough_mem(clntinfo->user);
      scnprintf(clntinfo->user, usersize, "@");
      scnprintf(clntinfo->user, usersize, transparent_target);
      free(transparent_target);

      /* replace dest by the specified forward */
      if (!config_compare_option("logintime", "connect")) {
            destination = fw_auth_parse_host_port(transforward_opt);
            if (! destination.hostname) {
                  say(clntinfo->clientsocket,
                                    "500 Error logging in\r\n");
                  jlog(4, "Could not parse transparent forward target\r\n");
                  return CMD_ERROR;
            }
            free(clntinfo->destination);
            clntinfo->destination = destination.hostname;
            clntinfo->destinationport = destination.port;
            destination.hostname = (char*) 0;
      } else {
            /* this has already been done in bindport.c */
      }

      /* Determine the IP the client sees of us */
      if (strcasecmp(config_get_option("getinternalip"),
                                    "configuration") == 0) {
            clntinfo->addr_to_client =
                  config_get_addroption("dataclientaddress", INADDR_ANY);
      } else {
            clntinfo->addr_to_client =
            socketinfo_get_local_addr_by_sending(clntinfo->clientsocket);
      }
      clntinfo->transparent = TRANSPARENT_YES;

      jlog(8, "Using transparent forward. Connecting to %s port %d. User: %s",
                              clntinfo->destination,
                              clntinfo->destinationport,
                              clntinfo->user);

      return CMD_HANDLED;
}


static
int fw_port_mode(const char* portstr,
             const char* modestr,
             struct clientinfo* clntinfo) {
      long int pno;

      if (portstr) {
            pno = strtol(portstr, NULL, 10);
            if ((errno == ERANGE && (pno == LONG_MIN || pno == LONG_MAX))
                  || pno == 0) {
                  /* it was not a number */
                  clntinfo->destinationport = 0;
                  /* maybe it is a mode */
                  modestr = portstr;
                  portstr = (char*) 0;
            } else {
                  clntinfo->destinationport = pno;
            }
      }
      if (!clntinfo->destinationport) {
            clntinfo->destinationport
                  = config_get_ioption("serverport",
                                    DEFAULTSERVERPORT);
      }
      clntinfo->servermode = UNSPEC;
      if (modestr) {
            if (modestr && (strchr("ap", *modestr))) {
                  jlog(9, "mode specified: %s", modestr);
                  switch (*modestr) {
                        case 'a': 
                              clntinfo->servermode = ACTIVE;
                              jlog(9, "p-s: active");
                              break;
                        case 'p':
                              clntinfo->servermode = PASSIVE;
                              jlog(9, "p-s: passive");
                              break;
                  }
            }
      }
      return CMD_HANDLED;
}

int set_userdest(const char *buffer,
             int offset,
             struct clientinfo* clntinfo,
             const char* delimiters) {

      char* user, *host, *port, *mode;

      /* joe@host,21,p */
      /* joe */
      /* joe@host */
      /* joe,host,21,p */

      if (buffer[0] == '@') {
            user = (char*) 0;
      } else {
            user = quotstrtok(buffer, delimiters, &offset);
      }
      host = quotstrtok(buffer, delimiters, &offset);
      port = quotstrtok(buffer, delimiters, &offset);
      mode = quotstrtok(buffer, delimiters, &offset);

      if (fw_forward(user, host, clntinfo) != CMD_HANDLED) {
            free(user); free(host); free(port); free(mode);
            return CMD_ERROR;
      }
      if (fw_transparent_forward(clntinfo) != CMD_HANDLED) {
            free(user); free(host); free(port); free(mode);
            return CMD_ERROR;
      }
      if (fw_transparent(clntinfo) != CMD_HANDLED) {
            free(user); free(host); free(port); free(mode);
            return CMD_ERROR;
      }
      if (fw_port_mode(port, mode, clntinfo) != CMD_HANDLED) {
            free(user); free(host); free(port); free(mode);
            return CMD_ERROR;
      }
      free(user); free(host); free(port); free(mode);

      return CMD_HANDLED;
}

static
int std_user(const char* args, struct conn_info_st* conn_info,
                                    const char* delimiters) {
      int ret;
      char* args_copy = strdup(args);
      enough_mem(args_copy);

      if (conn_info->clntinfo->forward.passauth == 0) {
            /* passallauth was not set */
      } else {
            delimiters = "";
      }
      if (set_userdest(args_copy, strlen("USER "),
            conn_info->clntinfo, delimiters) != CMD_HANDLED) {

            free(args_copy);
            return CMD_ERROR;
      }
      free(args_copy);

      ret = cmds_after_user(conn_info);
      if (ret != CMD_HANDLED && ret != CMD_DONE) {
            return CMD_ERROR;
      }

      jlog(7, "Client logged in: User: %s, Dest: %s:%d",
                        conn_info->clntinfo->user,
                        conn_info->clntinfo->destination,
                        conn_info->clntinfo->destinationport);

      /* ret can be CMD_HANDLED or CMD_DONE */
      return ret;
}

int std_user_plain(const char* args, struct conn_info_st* conn_info) {
      return std_user(args, conn_info, "");
}

int std_user_split(const char* args, struct conn_info_st* conn_info) {
      return std_user(args, conn_info, DELIMITERS);
}

static
int cmds_after_user(struct conn_info_st* conn_info) {
      if (config_compare_option("logintime", "user")
            ||
          config_compare_option("logintime", "connect")) {
            /* connect if we should connect after having
             * received the USER command. Do not connect, if we
             * are already connected or should connect later on
             * */
            int ret, code;
            char* buffer;

            ret = login(conn_info->clntinfo, LOGIN_ST_USER);
            if (ret) { return CMD_ERROR; }
            if (conn_info->clntinfo->login.welcomemsg.fullmsg) {
               buffer = merge_responses(
                  conn_info->clntinfo->login.welcomemsg.fullmsg,
                  conn_info->clntinfo->login.authresp.fullmsg);
            } else {
                  buffer = strdup(conn_info->clntinfo->login.authresp.fullmsg);
            }
            say(conn_info->clntinfo->clientsocket, buffer);
            conn_info->lcs->respcode = getcode(buffer);
            free(buffer);

            /* okay, there was no problem sending the user name and
             * receiving the result, now check the result */
            code = getcode(conn_info->clntinfo->login.authresp.fullmsg);
            if (code != 331 && code != 230) {
                  jlog(6, "Didn't get successful message after sending "
                        "the user name: %s\n",
                        conn_info->clntinfo->login.authresp.fullmsg);
                  return CMD_ERROR;
            }
            /* Free the welcome message. The authentication
             * response is always free'ed in login_send_auth */
            free(conn_info->clntinfo->login.welcomemsg.fullmsg);
            conn_info->clntinfo->login.welcomemsg.fullmsg = (char*) 0;
            conn_info->clntinfo->login.auth_resp_sent = 1;
            if (code == 230) {
                  /* already logged in */
                  free(conn_info->clntinfo->login.authresp.fullmsg);
                  conn_info->clntinfo->login.authresp.fullmsg = (char*)0;
                  conn_info->clntinfo->login.stage = LOGIN_ST_LOGGEDIN;
                  if (login(conn_info->clntinfo, LOGIN_ST_FULL) < 0) {
                        return CMD_ERROR;
                  }
                  /* this is the only case where we return CMD_DONE so
                   * that the login handler doesn't wait for the
                   * command that would follow but knows that his job
                   * is finished */
                  return CMD_DONE;
            }

      } else {
            char* user;

            if (conn_info->clntinfo->before_forward.user) {
                  user = conn_info->clntinfo->before_forward.user;
            } else {
                  user = conn_info->clntinfo->user;
            }
            sayf(conn_info->clntinfo->clientsocket,
                        "331 Password required for %s.\r\n", user);
            conn_info->lcs->respcode = 331;
      }
      return CMD_HANDLED;
}

int std_pass(const char* args, struct conn_info_st* conn_info) {

      conn_info->clntinfo->pass = strdup(args + strlen("PASS "));
      enough_mem(conn_info->clntinfo->pass);

      return cmds_after_pass(conn_info);
}

static
int cmds_after_pass(struct conn_info_st* conn_info) {
      int ret;

      /* we are not yet connected to a server */
      ret = login(conn_info->clntinfo, LOGIN_ST_FULL);
      if (ret == CMD_ABORT) {
            return ret;
      }
      if (ret < 0) {
            /* login failed - do not print an error
             * message */
            /* conn_info->clntinfo->serversocket = ss = -1; */
            return CMD_ERROR;
      }
      return CMD_HANDLED;
}


static
int cmds_after_fwpass(struct conn_info_st* conn_info) {
      if (fw_validate(conn_info->clntinfo->fw_auth.user,
                  conn_info->clntinfo->fw_auth.pass) == 0) {

            say(conn_info->clntinfo->clientsocket,
                        "230 Login to firewall successful\r\n");
      } else {
            say(conn_info->clntinfo->clientsocket,
                        "530 Login failed.\r\n");
            return CMD_ERROR;
      }
      return CMD_HANDLED;
}


int fw_open(const char* args, struct conn_info_st* conn_info) {
      struct destination_t destination;
      char* space = (char*) 0;

      if (args) {
            space = strchr(args, ' ');
      }

      if ( !args || ! space || *(space + 1) == '\0') {
            say(conn_info->clntinfo->clientsocket,
                              "530-Not a valid password\r\n"
                              "530 Login failed.\r\n");
            return CMD_ERROR;
      }

      destination = fw_auth_parse_host_port(space + 1);

      if (destination.hostname == (char*) 0) {
            say(conn_info->clntinfo->clientsocket,
                              "530-Not a valid destination\r\n"
                              "530 Login failed.\r\n");
            return CMD_ERROR;
      }

      conn_info->clntinfo->destination = destination.hostname;
      conn_info->clntinfo->destinationport = destination.port;

      /* I don't know if 332 is the correct code */
      say(conn_info->clntinfo->clientsocket,
                  "220 Welcome. Please proceed.\r\n");
      return CMD_HANDLED;
}

int fw_site(const char* args, struct conn_info_st* conn_info) {
      return fw_open(args, conn_info);
}

static
int fw_set_user(const char* args, struct conn_info_st* conn_info) {
      /* just chop off the command and put everything in the user name */
      if ( ! args || *(args + strlen("USER ")) == '\0') {
            say(conn_info->clntinfo->clientsocket,
                        "530-Not a valid user name\r\n"
                        "530 Login failed.\r\n");
            return CMD_ERROR;
      }

      conn_info->clntinfo->user = strdup(args + strlen("USER "));
      enough_mem(conn_info->clntinfo->user);
      return CMD_HANDLED;
}

int fw_user(const char* args, struct conn_info_st* conn_info) {
      if (fw_set_user(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      return cmds_after_user(conn_info);
}

static
int fw_set_pass(const char* args, struct conn_info_st* conn_info) {
      /* just chop off the command and put everything in the password */
      if ( ! args ) {
            say(conn_info->clntinfo->clientsocket,
                        "530-Not a valid password\r\n"
                        "530 Login failed.\r\n");
            return CMD_ERROR;
      }
      if (*(args + strlen("PASS")) == '\0' ||
            *(args + strlen("PASS ")) == '\0') {
            /* allow empty passwords, too */
            conn_info->clntinfo->pass = strdup("");
      } else {
            conn_info->clntinfo->pass = strdup(args + strlen("PASS "));
      }
      enough_mem(conn_info->clntinfo->pass);
      return CMD_HANDLED;
}

int fw_pass(const char* args, struct conn_info_st* conn_info) {
      if (fw_set_pass(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      return cmds_after_pass(conn_info);
}

static
int fw_set_fwpass(const char* args, struct conn_info_st* conn_info) {
      /* just chop off the command and put everything in the password */
      char* space = (char*) 0;
      if (args) {
            space = strchr(args, ' ');
      }
      if ( ! args || ! space || *(space + 1) == '\0') {
            say(conn_info->clntinfo->clientsocket,
                              "530-Not a valid password\r\n"
                              "530 Login failed.\r\n");
            return CMD_ERROR;
      }
      conn_info->clntinfo->fw_auth.pass = strdup(space + 1);
      enough_mem(conn_info->clntinfo->fw_auth.pass);
      return CMD_HANDLED;
}

int fw_fwpass(const char* args, struct conn_info_st* conn_info) {
      if (fw_set_fwpass(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      return cmds_after_fwpass(conn_info);
}

static
int fw_set_fwuser(const char* args, struct conn_info_st* conn_info) {
      /* just chop off the command and put everything in the user name */
      char* space = (char*) 0;
      if (args) {
            space = strchr(args, ' ');
      }
      if ( ! args || ! space || *(space + 1) == '\0') {
            say(conn_info->clntinfo->clientsocket,
                              "530-Not a valid user name\r\n"
                              "530 Login failed.\r\n");
            return CMD_ERROR;
      }
      conn_info->clntinfo->fw_auth.user = strdup(space + 1);
      enough_mem(conn_info->clntinfo->fw_auth.user);
      return CMD_HANDLED;
}

int fw_fwuser(const char* args, struct conn_info_st* conn_info) {
      if (fw_set_fwuser(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      say(conn_info->clntinfo->clientsocket,
                  "331 User name okay, send password.\r\n");
      return CMD_HANDLED;
}


int fw_user_type8(const char* args, struct conn_info_st* conn_info) {
      /* expecting "USER fwuser@real.host.name" */
      char* cmd_copy = strdup(args);
      char* atsign;
      struct destination_t destination = { (char*) 0, 0 };
      enough_mem(cmd_copy);

      atsign = strchr(cmd_copy, '@');
      if (atsign) {
            destination = fw_auth_parse_host_port(atsign + 1);

            *atsign ='\0';
            if (fw_fwuser(cmd_copy, conn_info) != CMD_HANDLED) {
                  free(cmd_copy);
                  return CMD_ERROR;
            }
      }
      free(cmd_copy);
      if (! atsign || destination.hostname == (char*) 0) {
            say(conn_info->clntinfo->clientsocket,
                        "530-Not a valid user name\r\n"
                        "530 Login failed.\r\n");
            return CMD_ERROR;
      }
      conn_info->clntinfo->destination = destination.hostname;
      conn_info->clntinfo->destinationport = destination.port;
      return CMD_HANDLED;
}

int fw_user_type7(const char* args, struct conn_info_st* conn_info) {
      char* user, *fwuser, *destchar;
      int offset = strlen("USER ");
      struct destination_t destination;

      if (config_compare_option("logintime", "pass") == 0) {
            jlog(4, "logintime has to be \"pass\" with loginstyle 7");
            say(conn_info->clntinfo->clientsocket,
                        "550 Login incorrect\r\n");
            return CMD_ERROR;
      }

      user = quotstrtok_prepend("USER ", args, "@", &offset);
      if ( fw_set_user(user, conn_info) != CMD_HANDLED) {
            free(user);
            return CMD_ERROR;
      }
      free(user);

      fwuser = quotstrtok_prepend("USER ", args, "@", &offset);
      if ( !fwuser || fw_set_fwuser(fwuser, conn_info) != CMD_HANDLED) {
            if (! fwuser) {
                  say(conn_info->clntinfo->clientsocket,
                              "550 USER not recognized\r\n");
            }
            free(fwuser);
            return CMD_ERROR;
      }
      free(fwuser);
      destchar = quotstrtok(args, "@\n", &offset);

      destination = fw_auth_parse_host_port(destchar);
      free(destchar);
      if ( ! destination.hostname ) {
            say(conn_info->clntinfo->clientsocket,
                        "550 USER not recognized\r\n");
            return CMD_ERROR;
      }
      conn_info->clntinfo->destination = destination.hostname;
      conn_info->clntinfo->destinationport = destination.port;

      return cmds_after_user(conn_info);
}

int fw_pass_type7(const char* args, struct conn_info_st* conn_info) {
      char* pass, *fwpass, *argscopy;
      const char* last_at;
      int offset;

      /* we have pass@fwpass but pass is likely to contain a "@" sign.
       * So we find the last @ sign and everything before is the
       * destination password, everything after is the firewall password */

      last_at = strrchr(args, '@');
      if (! last_at) {
            say(conn_info->clntinfo->clientsocket,
                        "550 PASS not recognized\r\n");
            return CMD_ERROR;
      }

      offset = 1;
      fwpass = quotstrtok_prepend("PASS ", last_at, "\n", &offset);
      if ( !fwpass || fw_set_fwpass(fwpass, conn_info) != CMD_HANDLED) {
            if (! fwpass) {
                  say(conn_info->clntinfo->clientsocket,
                              "550 PASS not recognized\r\n");
            }
            free(fwpass);
            return CMD_ERROR;
      }
      free(fwpass);

      argscopy = strdup(args);
      enough_mem(argscopy);

      /* the at sign is at
       *    args [ last_at - args ]
       * and, since argscopy is a copy of args, it is at
       *    argscopy [ last_at - args ]
       * as well.
       */
      argscopy[ last_at - args ] = '\0';

      /* But if we set a \0 at the location of the at-sign, the remaining
       * part is "PASS destpass" and this is what we're looking for */
      pass = argscopy;
      if ( !pass || fw_set_pass(pass, conn_info) != CMD_HANDLED) {
            if (! pass) {
                  say(conn_info->clntinfo->clientsocket,
                              "550 PASS not recognized\r\n");
            }
            free(pass);
            return CMD_ERROR;
      }
      free(pass);

      if (fw_validate(conn_info->clntinfo->fw_auth.user,
                  conn_info->clntinfo->fw_auth.pass) != 0) {
            say(conn_info->clntinfo->clientsocket,
                        "550 Login incorrect\r\n");
            return CMD_ERROR;
      }
      return cmds_after_pass(conn_info);
}

int fw_login_type2(const char* args, struct conn_info_st* conn_info) {
      static int stage;

      if (stage == 0) {
            if (fw_user(args, conn_info) == CMD_HANDLED) {
                  stage++;
            } else {
                  stage = 0;
            }
      }
      if (stage == 1) {
            if (std_user_split(args, conn_info) == CMD_HANDLED) {
                  stage++;
            }
      }

      return 0;
}


int fw_user_type9(const char* args, struct conn_info_st* conn_info) {
/*           "USER user@real.host.name fwuser"        */
      char* remoteuser;
      char* fwuser;
      int offset = strlen("USER ");

      remoteuser = quotstrtok_prepend("USER ", args, WHITESPACES, &offset);
      if (std_user_split(remoteuser, conn_info) != CMD_HANDLED) {
            free(remoteuser);
            return CMD_ERROR;
      }
      free(remoteuser);

      fwuser = quotstrtok_prepend("USER ", args, WHITESPACES, &offset);
      if (fw_set_fwuser(fwuser, conn_info) != CMD_HANDLED) {
            free(fwuser);
            return CMD_ERROR;
      }
      free(fwuser);

      return CMD_HANDLED;
}


int fw_pass_type9(const char* args, struct conn_info_st* conn_info) {
      /* Just register the password */

      if (fw_set_pass(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      say(conn_info->clntinfo->clientsocket,
                              "332 Need account for login.\r\n");
      return CMD_HANDLED;
}

int fw_acct_type9(const char* args, struct conn_info_st* conn_info) {
      if (fw_set_fwpass(args, conn_info) != CMD_HANDLED) {
            return CMD_ERROR;
      }
      return cmds_after_pass(conn_info);
}



Generated by  Doxygen 1.6.0   Back to index