406 lines
7.3 KiB
C
406 lines
7.3 KiB
C
|
/* ftpd.c Copyright 1992-2000 by Michael Temari All Rights Reserved
|
||
|
*
|
||
|
* ftpd An FTP server program for use with Minix.
|
||
|
*
|
||
|
* Usage: Minix usage: tcpd ftp ftpd
|
||
|
*
|
||
|
* 06/14/92 Tnet Release Michael Temari
|
||
|
* 01/15/96 0.30 Michael Temari
|
||
|
* 01/25/96 0.90 Michael Temari
|
||
|
* 03/17/96 0.91 Michael Temari
|
||
|
* 06/27/96 0.92 Michael Temari
|
||
|
* 07/02/96 0.93 Michael Temari
|
||
|
* 07/15/96 0.94 Michael Temari
|
||
|
* 08/27/96 0.95 Michael Temari
|
||
|
* 02/09/97 0.96 Michael Temari
|
||
|
* 02/10/97 0.97 Michael Temari
|
||
|
* 09/25/97 0.98 Michael Temari
|
||
|
* 03/10/00 0.99 Michael Temari, <Michael@TemWare.Com>
|
||
|
* 12/12/03 1.00 Michael Temari, <Michael@TemWare.Com>
|
||
|
* 02/06/05 1.01 Michael Temari, <Michael@TemWare.Com>
|
||
|
* 02/12/05 2.00 Michael Temari, <Michael@TemWare.Com>
|
||
|
*/
|
||
|
|
||
|
char *FtpdVersion = "2.00";
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <signal.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
#include <unistd.h>
|
||
|
#include <net/gen/in.h>
|
||
|
#include <net/gen/tcp.h>
|
||
|
|
||
|
#include "ftpd.h"
|
||
|
#include "access.h"
|
||
|
#include "file.h"
|
||
|
#include "net.h"
|
||
|
|
||
|
_PROTOTYPE(static void init, (void));
|
||
|
_PROTOTYPE(static int doHELP, (char *buff));
|
||
|
_PROTOTYPE(static int doNOOP, (char *buff));
|
||
|
_PROTOTYPE(static int doUNIMP, (char *buff));
|
||
|
_PROTOTYPE(static int getline, (char *line, int len));
|
||
|
|
||
|
FILE *msgfile = (FILE *)NULL;
|
||
|
|
||
|
/* The following defines the inactivity timeout in seconds */
|
||
|
#define INACTIVITY_TIMEOUT 60*5
|
||
|
|
||
|
char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||
|
char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||
|
|
||
|
char line[512];
|
||
|
|
||
|
int type, format, mode, structure;
|
||
|
int ftpdata_fd = -1;
|
||
|
int loggedin, gotuser, anonymous;
|
||
|
char username[80];
|
||
|
char anonpass[128];
|
||
|
char newroot[128];
|
||
|
|
||
|
ipaddr_t myipaddr, rmtipaddr, dataaddr;
|
||
|
tcpport_t myport, rmtport, dataport;
|
||
|
|
||
|
char myhostname[256], rmthostname[256];
|
||
|
|
||
|
#define FTPD_LOG "/usr/adm/ftpd.log"
|
||
|
#define FTPD_MSG "/etc/ftpd_msg"
|
||
|
|
||
|
FILE *logfile;
|
||
|
|
||
|
int timeout = 0;
|
||
|
|
||
|
_PROTOTYPE(static int doHELP, (char *buff));
|
||
|
_PROTOTYPE(int readline, (char **args));
|
||
|
_PROTOTYPE(void Timeout, (int sig));
|
||
|
_PROTOTYPE(int main, (int argc, char *argv[]));
|
||
|
|
||
|
struct commands {
|
||
|
char *name;
|
||
|
_PROTOTYPE(int (*func), (char *buff));
|
||
|
};
|
||
|
|
||
|
struct commands commands[] = {
|
||
|
"ABOR", doUNIMP,
|
||
|
"ACCT", doUNIMP,
|
||
|
"ALLO", doALLO,
|
||
|
"APPE", doAPPE,
|
||
|
"CDUP", doCDUP,
|
||
|
"CWD", doCWD,
|
||
|
"DELE", doDELE,
|
||
|
"HELP", doHELP,
|
||
|
"LIST", doLIST,
|
||
|
"MDTM", doMDTM,
|
||
|
"MKD", doMKD,
|
||
|
"MODE", doMODE,
|
||
|
"NLST", doNLST,
|
||
|
"NOOP", doNOOP,
|
||
|
"PASS", doPASS,
|
||
|
"PASV", doPASV,
|
||
|
"PORT", doPORT,
|
||
|
"PWD", doPWD,
|
||
|
"QUIT", doQUIT,
|
||
|
"REIN", doUNIMP,
|
||
|
"REST", doREST,
|
||
|
"RETR", doRETR,
|
||
|
"RMD", doRMD,
|
||
|
"RNFR", doRNFR,
|
||
|
"RNTO", doRNTO,
|
||
|
"SITE", doSITE,
|
||
|
"SIZE", doSIZE,
|
||
|
"SMNT", doUNIMP,
|
||
|
"STAT", doSTAT,
|
||
|
"STOR", doSTOR,
|
||
|
"STOU", doSTOU,
|
||
|
"STRU", doSTRU,
|
||
|
"SYST", doSYST,
|
||
|
"TYPE", doTYPE,
|
||
|
"USER", doUSER,
|
||
|
"XCUP", doCDUP,
|
||
|
"XCWD", doCWD,
|
||
|
"XMKD", doMKD,
|
||
|
"XPWD", doPWD,
|
||
|
"XRMD", doRMD,
|
||
|
"", (int (*)())0
|
||
|
};
|
||
|
|
||
|
static void init()
|
||
|
{
|
||
|
loggedin = 0;
|
||
|
gotuser = 0;
|
||
|
anonymous = 0;
|
||
|
newroot[0] = '\0';
|
||
|
type = TYPE_A;
|
||
|
format = 0;
|
||
|
mode = MODE_S;
|
||
|
structure = 0;
|
||
|
ftpdata_fd = -1;
|
||
|
username[0] = '\0';
|
||
|
anonpass[0] = '\0';
|
||
|
}
|
||
|
|
||
|
/* nothing, nada, zilch... */
|
||
|
static int doNOOP(buff)
|
||
|
char *buff;
|
||
|
{
|
||
|
printf("200 NOOP to you too!\r\n");
|
||
|
|
||
|
return(GOOD);
|
||
|
}
|
||
|
|
||
|
/* giv'em help, what a USER! */
|
||
|
static int doHELP(buff)
|
||
|
char *buff;
|
||
|
{
|
||
|
struct commands *cmd;
|
||
|
char star;
|
||
|
int i;
|
||
|
char *space = " ";
|
||
|
|
||
|
printf("214-Here is a list of available ftp commands\r\n");
|
||
|
printf(" Those with '*' are not yet implemented.\r\n");
|
||
|
|
||
|
i = 0;
|
||
|
for(cmd = commands; *cmd->name != '\0'; cmd++) {
|
||
|
if(cmd->func == doUNIMP)
|
||
|
star = '*';
|
||
|
else
|
||
|
star = ' ';
|
||
|
printf(" %s%c%s", cmd->name, star, space + strlen(cmd->name));
|
||
|
if(++i == 6) {
|
||
|
printf("\r\n");
|
||
|
i = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(i)
|
||
|
printf("\r\n");
|
||
|
|
||
|
printf("214 That's all the help you get.\r\n");
|
||
|
|
||
|
return(GOOD);
|
||
|
}
|
||
|
|
||
|
/* not implemented */
|
||
|
static int doUNIMP(buff)
|
||
|
char *buff;
|
||
|
{
|
||
|
printf("502 Command \"%s\" not implemented!\r\n", line);
|
||
|
|
||
|
return(GOOD);
|
||
|
}
|
||
|
|
||
|
/* convert line for use */
|
||
|
void cvtline(args)
|
||
|
char **args;
|
||
|
{
|
||
|
char *p;
|
||
|
|
||
|
p = line + strlen(line);
|
||
|
while(--p >= line)
|
||
|
if(*p == '\r' || *p == '\n' || isspace(*p))
|
||
|
*p = '\0';
|
||
|
else
|
||
|
break;
|
||
|
|
||
|
p = line;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
logit("COMMAND", line);
|
||
|
#endif
|
||
|
|
||
|
while(*p && !isspace(*p)) {
|
||
|
*p = toupper(*p);
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
if(*p) {
|
||
|
*p = '\0';
|
||
|
p++;
|
||
|
while(*p && isspace(*p))
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
*args = p;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static int getline(line, len)
|
||
|
char *line;
|
||
|
int len;
|
||
|
{
|
||
|
int s;
|
||
|
int gotcr;
|
||
|
|
||
|
/* leave room for at end for null */
|
||
|
len--;
|
||
|
|
||
|
/* got to be able to put in at least 1 character */
|
||
|
if(len < 1)
|
||
|
return(-1);
|
||
|
|
||
|
gotcr = 0;
|
||
|
while(len-- > 0) {
|
||
|
s = read(0, line, 1);
|
||
|
if(s != 1)
|
||
|
return(-1);
|
||
|
if(*line == '\n')
|
||
|
break;
|
||
|
gotcr = (*line == '\r');
|
||
|
line++;
|
||
|
}
|
||
|
if(gotcr)
|
||
|
--line;
|
||
|
|
||
|
*line = '\0';
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
int readline(args)
|
||
|
char **args;
|
||
|
{
|
||
|
if(getline(line, sizeof(line)))
|
||
|
return(BAD);
|
||
|
|
||
|
cvtline(args);
|
||
|
|
||
|
return(GOOD);
|
||
|
}
|
||
|
|
||
|
/* signal handler for inactivity timeout */
|
||
|
void Timeout(sig)
|
||
|
int sig;
|
||
|
{
|
||
|
timeout = 1;
|
||
|
|
||
|
printf("421 Inactivity timer expired.\r\n");
|
||
|
}
|
||
|
|
||
|
/* logit */
|
||
|
void logit(type, parm)
|
||
|
char *type;
|
||
|
char *parm;
|
||
|
{
|
||
|
time_t now;
|
||
|
struct tm *tm;
|
||
|
|
||
|
if(logfile == (FILE *)NULL)
|
||
|
return;
|
||
|
|
||
|
time(&now);
|
||
|
tm = localtime(&now);
|
||
|
fprintf(logfile, "%4d%02d%02d%02d%02d%02d ",
|
||
|
1900+tm->tm_year,
|
||
|
tm->tm_mon + 1,
|
||
|
tm->tm_mday,
|
||
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||
|
fprintf(logfile, "%s %s %s %s %s\n",
|
||
|
rmthostname, username, anonymous ? anonpass : username, type, parm);
|
||
|
fflush(logfile);
|
||
|
}
|
||
|
|
||
|
void showmsg(reply, filename)
|
||
|
char *reply;
|
||
|
char *filename;
|
||
|
{
|
||
|
FILE *mfp;
|
||
|
char *pe;
|
||
|
static char mline[256];
|
||
|
|
||
|
if(filename == (char *)NULL)
|
||
|
mfp = msgfile;
|
||
|
else
|
||
|
mfp = fopen(filename, "r");
|
||
|
|
||
|
if(mfp == (FILE *)NULL)
|
||
|
return;
|
||
|
|
||
|
while(fgets(mline, sizeof(mline), mfp) != (char *)NULL) {
|
||
|
pe = mline + strlen(mline);
|
||
|
while(--pe >= mline)
|
||
|
if(*pe == '\r' || *pe == '\n')
|
||
|
*pe = '\0';
|
||
|
else
|
||
|
break;
|
||
|
printf("%s- %s\r\n", reply, mline);
|
||
|
}
|
||
|
|
||
|
if(filename != (char *)NULL)
|
||
|
fclose(mfp);
|
||
|
}
|
||
|
|
||
|
int main(argc, argv)
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
struct commands *cmd;
|
||
|
char *args;
|
||
|
int status;
|
||
|
time_t now;
|
||
|
struct tm *tm;
|
||
|
int s;
|
||
|
|
||
|
GetNetInfo();
|
||
|
|
||
|
/* open transfer log file if it exists */
|
||
|
if((logfile = fopen(FTPD_LOG, "r")) != (FILE *)NULL) {
|
||
|
fclose(logfile);
|
||
|
logfile = fopen(FTPD_LOG, "a");
|
||
|
}
|
||
|
|
||
|
/* open login msg file */
|
||
|
msgfile = fopen(FTPD_MSG, "r");
|
||
|
|
||
|
/* Let's initialize some stuff */
|
||
|
init();
|
||
|
|
||
|
/* Log the connection */
|
||
|
logit("CONNECT", "");
|
||
|
|
||
|
/* Tell 'em we are ready */
|
||
|
time(&now);
|
||
|
tm = localtime(&now);
|
||
|
printf("220 FTP service (Ftpd %s) ready on %s at ",
|
||
|
FtpdVersion, myhostname);
|
||
|
printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
|
||
|
tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
|
||
|
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||
|
tzname[tm->tm_isdst]);
|
||
|
fflush(stdout);
|
||
|
|
||
|
/* Loop here getting commands */
|
||
|
while(1) {
|
||
|
signal(SIGALRM, Timeout);
|
||
|
alarm(INACTIVITY_TIMEOUT);
|
||
|
if(readline(&args) != GOOD) {
|
||
|
if(!timeout)
|
||
|
printf("221 Control connection closing (EOF).\r\n");
|
||
|
break;
|
||
|
}
|
||
|
alarm(0);
|
||
|
for(cmd = commands; *cmd->name != '\0'; cmd++)
|
||
|
if(!strcmp(line, cmd->name))
|
||
|
break;
|
||
|
if(*cmd->name != '\0')
|
||
|
status = (*cmd->func)(args);
|
||
|
else {
|
||
|
printf("500 Command \"%s\" not recognized.\r\n", line);
|
||
|
status = GOOD;
|
||
|
}
|
||
|
fflush(stdout);
|
||
|
if(status != GOOD)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
CleanUpPasv();
|
||
|
|
||
|
return(-1);
|
||
|
}
|