|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 12291 (0x3003)
Types: TextFile
Names: »ftpd.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/ftp-ftam/ftpd.c«
/* ftpd.c - FTAM/FTP gateway */
#ifndef lint
static char *rcsid = "$Header: /f/osi/ftp-ftam/RCS/ftpd.c,v 7.0 89/11/23 21:55:21 mrose Rel $";
#endif
/*
* $Header: /f/osi/ftp-ftam/RCS/ftpd.c,v 7.0 89/11/23 21:55:21 mrose Rel $
*
* Author: John A. Scott <Scott@GATEWAY.MITRE.ORG>
* The MITRE Corporation
* Washington C3I Division
* 7525 Colshire Drive
* Mclean, Virginia 22102
* +1-703-883-5915
*
* $Log: ftpd.c,v $
* Revision 7.0 89/11/23 21:55:21 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* The MITRE Corporation (hereafter MITRE) makes this software available
* on an "as is" basis. No guarantees, either explicit or implied, are
* given as to performance or suitability.
*
*/
/*
* Shamelessly taken from UCB
*/
/*
* FTP server.
*/
#include "config.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include <netdb.h>
#include <errno.h>
#include "general.h"
#include "manifest.h"
#include "logger.h"
extern LLog _ftam_log, *ftam_log;
#include <varargs.h>
char *ctime();
time_t time();
void adios (), advise ();
/*
* File containing login names
* NOT to be used on this machine.
* Commonly used to disallow uucp.
*/
/*
* This may be rework to provide bridge access control. JAS
*/
#define FTPUSERS "/usr/etc/ftpusers"
extern int errno;
extern char *sys_errlist[];
extern char ftam_error[];
extern char version[];
struct sockaddr_in ctrl_addr;
struct sockaddr_in data_source;
struct sockaddr_in data_dest;
struct sockaddr_in his_addr;
int data;
jmp_buf errcatch;
int logged_in;
int debug = 0;
int watch = 1;
int timeout;
int logging = 0;
int type;
int form;
int stru; /* avoid C keyword */
int mode;
int usedefault = 1; /* for data transfers */
char hostname[32];
char remotehost[32];
char *osi_host;
char *ftp_user;
char *ftp_account;
char *ftp_passwd;
int verbose = 0;
#define NVEC 100
char *vec[NVEC];
/*
* Timeout intervals for retrying connections
* to hosts that don't accept PORT cmds. This
* is a kludge, but given the problems with TCP...
*/
#define SWAITMAX 90 /* wait at most 90 seconds */
#define SWAITINT 5 /* interval between retries */
int swaitmax = SWAITMAX;
int swaitint = SWAITINT;
SFD lostconn();
main(argc, argv)
int argc;
char *argv[];
{
int addrlen;
char *ptr, *index();
struct servent *sp;
isodetailor (ptr = argv[0], 0);
argc--, argv++;
if (verbose = isatty (fileno (stderr)))
ll_dbinit (ftam_log, ptr);
else {
ftam_log -> ll_stat &= ~LLOGCLS;
ll_hdinit (ftam_log, ptr);
}
advise (NULLCP, "starting");
addrlen = sizeof his_addr;
if (getpeername (0, (struct sockaddr *) &his_addr, &addrlen) == NOTOK)
adios ("failed", "getpeername");
sp = getservbyname("ftp", "tcp");
if (sp == 0) {
advise(NULLCP, "ftp/tcp: unknown service");
abort();
exit(1);
}
ctrl_addr.sin_port = sp->s_port;
data_source.sin_port = htons(ntohs((u_short) sp->s_port) - 1);
(void)signal(SIGPIPE, lostconn);
(void)signal(SIGCHLD, SIG_IGN);
(void)dup2(0, 1);
/* do telnet option negotiation here */
/*
* Set up default state
*/
rcinit(); /* FTAM state initialize */
logged_in = 0;
data = -1;
type = TYPE_A;
form = FORM_N;
stru = STRU_F;
mode = MODE_S;
addrlen = sizeof ctrl_addr;
if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) == NOTOK)
adios ("failed", "getsockname");
(void)gethostname(hostname, sizeof (hostname));
ptr = index(hostname,'.'); /* strip off domain name */
if (ptr) *ptr = '\0';
reply(220, "%s FTP/FTAM gateway (%s) ready.",
hostname, version);
for (;;) {
(void)setjmp(errcatch);
(void)yyparse();
}
}
SFD
lostconn()
{
advise (NULLCP,"lost connection");
dologout(-1);
}
char *
savestr(s)
char *s;
{
char *malloc();
char *new = malloc((unsigned) (strlen(s) + 1));
if (new != NULL)
(void)strcpy(new, s);
return (new);
}
retrieve(name)
char *name;
{
int result;
/* FTAM file retrieval block function. Return values:
* OK -- file transfered without error
* NOTOK -- file transfer error
* DONE -- Problem opening TCP connection for transfer
* Error response made by dataconn routine.
*/
vec[0] = "f_get";
vec[1] = name;
vec[2] = NULL;
if ((result = f_get(vec)) == NOTOK){
reply(550, "%s: %s.", name, ftam_error);
} else if (result == OK)
reply(226, "Transfer complete.");
data = -1;
return;
}
ftp_store(name, modeX)
char *name, *modeX;
{
int result;
/*
* f_put is FTAM file storage block function. First arguement
* controls file overwrite or append selection.
* OK -- file transfered without error
* NOTOK -- file transfer error
* DONE -- Problem opening TCP connection for transfer
* Error response made by dataconn routine.
*/
vec[0] = strcmp(modeX,"a") ? "put" : "append";
vec[1] = name;
vec[2] = NULL;
if ((result = f_put(vec)) == NOTOK)
reply(550, "%s: %s.", name, ftam_error);
else if (result == OK)
reply(226, "Transfer complete.");
data = -1;
}
int
getdatasock()
{
/* UCB data socket creation routine */
int s;
#ifdef BSD43
int on = 1;
#endif
if (data >= 0)
return (data);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
return (NOTOK);
#ifndef BSD43
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) 0, 0) < 0)
#else
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof on) < 0)
#endif
goto bad;
/* anchor socket to avoid multi-homing problems */
data_source.sin_family = AF_INET;
data_source.sin_addr = ctrl_addr.sin_addr;
if (bind(s, (struct sockaddr *) &data_source, sizeof (data_source)) < 0)
goto bad;
return (s);
bad:
(void)close(s);
return (NOTOK);
}
int
dataconn(name)
char *name;
{
/* UCB data connection routine */
int retry = 0;
if (data >= 0) {
reply(125, "Using existing data connection for %s.",
name);
usedefault = 1;
return (data);
}
if (usedefault)
data_dest = his_addr;
usedefault = 1;
data = getdatasock();
if (data == NOTOK){
reply(425, "Can't create data socket (%s,%d): %s.",
inet_ntoa(data_source.sin_addr),
ntohs(data_source.sin_port),
sys_errlist[errno]);
return (NOTOK);
}
reply(150, "Opening data connection for %s (%s,%d).",
name, inet_ntoa(data_dest.sin_addr),
ntohs(data_dest.sin_port));
while (connect(data, (struct sockaddr *)&data_dest, sizeof (data_dest)) < 0) {
if (errno == EADDRINUSE && retry < swaitmax) {
sleep((unsigned) swaitint);
retry += swaitint;
continue;
}
reply(425, "Can't build data connection: %s.",
sys_errlist[errno]);
(void) close(data);
data = -1;
return (NOTOK);
}
return (data);
}
fatal(s)
char *s;
{
reply(451, "Error in server: %s\n", s);
/* reply(221, "Closing connection due to server error.");*/
dologout(0);
}
#ifndef lint
reply(va_alist)
va_dcl
{
int n;
va_list ap;
va_start (ap);
n = va_arg (ap, int);
_reply (n, ' ', ap);
va_end (ap);
}
lreply(va_alist)
va_dcl
{
int n;
va_list ap;
va_start (ap);
n = va_arg (ap, int);
_reply (n, '-', ap);
va_end (ap);
}
static _reply (n, c, ap)
int n;
char c;
va_list ap;
{
char buffer[BUFSIZ];
_asprintf (buffer, NULLCP, ap);
printf ("%d%c%s\r\n", n, c, buffer);
(void)fflush (stdout);
if (verbose)
advise (NULLCP,"<--- %d%c%s", n, c, buffer);
}
#else
/* VARARGS2 */
reply(n,fmt)
int n;
char *fmt;
{
reply(n,fmt);
}
/* VARARGS2 */
lreply(n,fmt)
int n;
char *fmt;
{
lreply(n,fmt);
}
#endif
replystr(s)
char *s;
{
printf("%s\r\n", s);
(void)fflush(stdout);
if (verbose)
advise(NULLCP,"<--- %s", s);
}
ack(s)
char *s;
{
reply(200, "%s command okay.", s);
}
nack(s)
char *s;
{
reply(502, "%s command not implemented.", s);
}
/*ARGSUSED*/
yyerror(s)
char *s;
{
reply(500, "Command not understood.");
}
ftp_delete(name)
char *name;
{
/* f_rm is the general purpose FTAM file/directory deletion routine.
* Change information is formatted in ftam_error.
*/
vec[0] = "f_rm";
vec[1] = name;
vec[2] = NULL;
if (f_rm(vec) == NOTOK){
reply(550, "%s: %s.", name, ftam_error);
return;
}
ack("DELE");
}
makedir(name)
char *name;
{
/* f_mkdir is the FTAM directory creation routine */
vec[0] = "f_mkdir";
vec[1] = name;
vec[2] = NULL;
if (f_mkdir(vec) == NOTOK){
reply(550, "%s: %s.", name, ftam_error);
return;
}
ack("MKDIR");
}
removedir(name)
char *name;
{
/* f_rm is the general purpose FTAM file/directory deletion routine.
*/
vec[0] = "f_rm";
vec[1] = name;
vec[2] = NULL;
if (f_rm(vec) == NOTOK){
reply(550, "%s: %s.", name, ftam_error);
return;
}
ack("RMDIR");
}
char *
renamefrom(name)
char *name;
{
reply(350, "Ready for destination name");
return (name);
}
renamecmd(from, to)
char *from, *to;
{
/* f_mv is FTAM block function to select and change attributes
* (i.e. file name)
*/
vec[0] ="f_mv";
vec[1] = from;
vec[2] = to;
vec[3] = NULL;
if (f_mv(vec) == NOTOK){
reply(550, "rename: %s.", ftam_error);
return;
}
ack("RNTO");
}
dolog(sin)
struct sockaddr_in *sin;
{
#ifdef notanymore
struct hostent *hp = gethostbyaddr((char*)&sin->sin_addr,
sizeof (struct in_addr), AF_INET);
#endif
time_t t;
#ifdef notanymore
if (hp) {
(void)strncpy(remotehost, hp->h_name, sizeof (remotehost));
endhostent();
} else
#endif
(void)strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof (remotehost));
t = time((time_t*)0);
if (!logging)
return;
advise(NULLCP,"connection from %s at %s", remotehost, ctime(&t));
}
directory(how,name)
char *how, *name;
{
int result;
/* f_ls does a directory contents transfer. The first arguement
* determines whether a name list (NLST) or long list (LIST) is returned.
* Results:
* OK -- list transfered without error
* NOTOK -- list transfer error
* DONE -- Problem opening TCP connection for transfer
* Error response made by dataconn routine.
*/
vec[0] = strcmp(how,"NLST") ? "dir" : "ls";
vec[1] = name;
vec[2] = NULL;
if ((result = f_ls(vec)) == OK)
reply(226, "Transfer complete.");
else if (result == NOTOK)
reply(500, ftam_error);
data = -1;
}
/*
* Execute FTAM login if all necessary arguements present
*/
dologin()
{
if (!ftp_user) {
reply(500,"Send USER command first");
return(0);
}
if (!ftp_passwd) {
reply(330,"Send PASS command");
return(0);
}
if (!osi_host){
/* Success is returned since most user FTP response scanners
* are not prepared for a continue at this point. The osi
* host may be specified by encoding it with the user name
* (i.e. user@osihost) or using the SITE command (SITE osihost).
* Gateway users are expected to know if the remote site
* requires account charging information. The bridge makes
* ACCT optional.
*/
reply(200,"Specify OSI destination with SITE command");
return(0);
}
vec[0] = "f_open";
vec[1] = osi_host;
vec[2] = ftp_user;
vec[3] = (ftp_account) ? "" : ftp_account;
vec[4] = ftp_passwd;
advise (NULLCP,
"attempting connection with OSI host \"%s\" for user \"%s\"",
osi_host, ftp_user);
/* f_open performs the FTAM initialization (including login) */
if (f_open(vec) == NOTOK){
reply(500,"Login failed");
return(0);
}
reply(200,"Logged into %s", osi_host);
return(1);
}
/*
* exit with supplied status.
*/
dologout(status)
int status;
{
vec[0] = "f_close";
vec[1] = NULL;
/* f_close performs the logout sequence and receives charging
* information
*/
(void) f_close(vec);
if (status>=0)
reply(221,"Logged off. %s",ftam_error);
/* beware of flushing buffers after a SIGPIPE */
_exit(status);
}
/*
* Check user requesting login priviledges.
* Disallow anyone mentioned in the file FTPUSERS
* to allow people such as uucp to be avoided.
*/
checkuser(name)
register char *name;
{
char line[BUFSIZ], *index();
FILE *fd, *fopen();
int found = 0;
fd = fopen(FTPUSERS, "r");
if (fd == NULL)
return (1);
while (fgets(line, sizeof (line), fd) != NULL) {
register char *cp = index(line, '\n');
if (cp)
*cp = '\0';
if (strcmp(line, name) == 0) {
found++;
break;
}
}
(void)fclose(fd);
return (!found);
}