/*
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1