/***************************************
This is part of frox: A simple transparent FTP proxy
Copyright (C) 2000 James Hollingshead
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-1307 USA
ntp.c -- non transparent proxying stuff
Overview:
ntp_changedest gets called just before the proxy connects to the
remote server. If the connection is destined for a remote machine then
we assume that is the destination and that no ntp support is required.
Otherwise we send a welcome to the client and read a reply of the form
"USER username[@host[:port]]". If necessary we then change the
destination (in the global "info" structure), save the hostname, and
return. We also call set config.transdata=FALSE to stop NAT on data
connections for this session.
We also need get called(ntp_senduser) when the remote server sends us
a 220 welcome message. If we have already welcomed the client we send
the login name we got then to the server and return TRUE. Otherwise we
return FALSE and the main proxy code will forward the welcome on to
the client.
config.fakentp is set where other code in frox wishes to know the
username before it makes a connection - normally because there are
ACLs or config file subsections based on the username. In this case
we use the ntp code to do this, but don't parse the username to do
an address change.
***************************************/
#include <sys/ioctl.h>
#include <netdb.h>
#include "common.h"
#include "cache.h"
#include "control.h"
#include "ntp.h"
#include "ccp.h"
#include "os.h"
#include "ftp-cmds.h"
void parseuser(sstr * arg);
static int working = FALSE;
static int faking = FALSE;
/* ------------------------------------------------------------- **
** Called before the proxy connects to the server.
**
** Send client "220 Send Login", read and parse reply.
** ------------------------------------------------------------- */
void ntp_changedest(void)
{
sstr *cmd, *arg;
struct sockaddr_in tmp;
if(!config.ntp) {
if(config.fakentp)
faking = TRUE;
else
return;
}
if(config.ntpdest.sin_addr.s_addr) {
/*Don't do ntp proxying unless the connection is to NTPDest. */
get_orig_dest(info->client_control.fd, &tmp);
if(tmp.sin_addr.s_addr != config.ntpdest.sin_addr.s_addr
|| (config.ntpdest.sin_port &&
tmp.sin_port != config.ntpdest.sin_port))
faking = TRUE;
}
if(faking && !config.fakentp)
return;
working = TRUE;
send_cmessage(220, faking ? "Frox. Please login." :
"Frox transparent ftp proxy. Login with username[@host[:port]]");
info->greeting = FAKED;
do {
get_command(&cmd, &arg);
if(!sstr_casecmp2(cmd, "QUIT"))
die(INFO, "Client closed connecton", 0, 0, 0);
if(sstr_casecmp2(cmd, "USER"))
send_cmessage(530, "Please login with USER first");
} while(sstr_casecmp2(cmd, "USER"));
if(!faking)
parseuser(arg);
else
sstr_cpy(info->username, arg);
if(sstr_casecmp2(info->username, "ftp")
&& sstr_casecmp2(info->username, "anonymous"))
info->anonymous = 0;
else
info->anonymous = 1;
}
/* ------------------------------------------------------------- **
** If we have a username send it to the server.
** ------------------------------------------------------------- */
void ntp_senduser(void)
{
int i;
sstr *msg, *tmp;
if(!working)
return;
if(info->greeting != DONE) {
get_message(&i, &msg);
if(i != 220) {
die(INFO, "Unable to contact server in ntp",
421, "Server Unable to accept connection", 0);
}
}
info->greeting = DONE;
working = FALSE;
tmp = sstr_dup2("USER");
user_munge(tmp, NULL);
sstr_free(tmp);
}
/* ------------------------------------------------------------- **
** Parse the user command, resolve the hostname if present, and do
** security checks. If all ok alter info->server_control.address.
** We check for @ from the far end to allow usernames with @s in
** them.
** ------------------------------------------------------------- */
void parseuser(sstr * arg)
{
struct hostent *hostinfo;
sstr *host = NULL;
int sep, i, port = 0;
sstr *tok;
for(i = sstr_len(arg) - 1; i >= 0; i--)
if(sstr_getchar(arg, i) == '@')
break;
if(i == -1) {
sstr_cpy(info->username, arg);
return;
}
sstr_split(arg, info->username, 0, i);
sstr_split(arg, NULL, 0, 1);
tok = sstr_init(MAX_LINE_LEN);
sep = sstr_token(arg, tok, ":", 0);
host = (sep == -1 ? arg : tok);
if(sep == ':')
port = sstr_atoi(arg);
else
port = 21;
write_log(VERBOSE, "NTP: Host=%s", sstr_buf(host));
write_log(VERBOSE, "NTP: Port=%d", port);
/*Turn off data connection NAT for this connection! */
config.transdata = FALSE;
hostinfo = gethostbyname(sstr_buf(host));
if(!hostinfo)
die(INFO, "Unable to find NTP host",
501, "Can't find that host", 0);
if(hostinfo->h_addrtype != AF_INET)
die(INFO, "Invalid NTP host", 501, "Invalid host", 0);
info->server_control.address.sin_addr =
*((struct in_addr *) hostinfo->h_addr_list[0]);
info->server_control.address.sin_port = htons(port);
info->server_control.address.sin_family = AF_INET;
/*We used to change apparent_server_address here, but I don't
think that is right. Makes no difference as we have turned
off TransparentData connections above and that is all it is
used for. */
sstr_cpy(info->server_name, host);
sstr_free(tok);
}
syntax highlighted by Code2HTML, v. 0.9.1