Patch from Emmanuel Rauget (raguet@crf.canon.fr) to add a htons on the

sin_port.
This commit is contained in:
Joel Sherrill
1999-04-02 14:39:19 +00:00
parent 5345873a5b
commit 85e24a3237
6 changed files with 717 additions and 654 deletions

View File

@@ -1,39 +1,26 @@
/*
* FTP Server Daemon
/* FIXME: 1. Parse command is a hack. We can do better.
* 2. chdir is a hack. We can do better.
* 3. PWD doesn't work.
* 4. Some sort of access control?
*
* FTP Server Daemon
*
* Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
*
* $Id$
*/
/*
* Current state:
* To untar, put as "untar"
* CWD uses chdir
* This is bad due to global setting of chdir.
*
* Stored files come into RAM and are saved later. This is an artifact
* of a previous implementation (no filesystem -- had to do stuff with
* the "files" later). This can be eliminated once all of Jake's stuff
* is moved to devices/filesystems.
*
* CLOSE(S) doesn't seem to work. This causes problems in
* several areas. It lets too many file descriptors pile up
* and it doesn't seem to flush the stream.
*
* Is 'recv' what I want to use to get commands from the control port?
*
*/
/**************************************************************************
* ftpd.c *
**************************************************************************
* Description: *
* *
* This file contains the daemon which services requests that appear *
* on the 'FTP' port. This server is compatible with FTP, but it *
* also provides services specific to the Erithacus system. *
* This server is started at boot-time and runs forever. *
* on the FTP port. This server is compatible with FTP, but it *
* also provides 'hooks' to make it usable in situations where files *
* are not used/necessary. Once the server is started, it runs *
* forever. *
* *
* *
* Organization: *
* *
@@ -44,12 +31,6 @@
* is complete, the session task deletes itself. The daemon still *
* runs, however. *
* *
* Implementation Notes: *
* *
* The 'current working directory' implementation utilizes the *
* RTEMS filesystem cwd. This is no good since other processes *
* inherit the same cwd. *
* *
* *
* Supported commands are: *
* *
@@ -70,51 +51,34 @@
* and port (x*256 + y). *
* *
* *
* *
* The public routines contained in this file are: *
* *
* FTPD_Start - Starts the server daemon, then returns to its caller. *
* rtems_initialize_ftpd_start - Starts the server daemon, then *
* returns to its caller. *
* *
* *
* The private routines contained in this file are: *
* *
* FTPD_SendReply - Sends a reply code and text through the control *
* port. *
* FTPD_CommandStore - Performs the "STOR" command. *
* FTPD_CommandList - Performs the "LIST" command. *
* FTPD_CommandPort - Opens a data port (the "PORT" command). *
* FTPD_ParseCommand - Parses an incoming command. *
* FTPD_Session - Begins a service session. *
* FTPD_Daemon - Listens on the FTP port for service requests. *
* *
* *
* rtems_ftpd_send_reply - Sends a reply code and text through the *
* control port. *
* rtems_ftpd_command_retrieve - Performs to "RETR" command. *
* rtems_ftpd_command_store - Performs the "STOR" command. *
* rtems_ftpd_command_list - Performs the "LIST" command. *
* rtems_ftpd_command_port - Opens a data port (the "PORT" command). *
* rtems_ftpd_parse_command - Parses an incoming command. *
* rtmes_ftpd_session - Begins a service session. *
* rtems_ftpd_daemon - Listens on the FTP port for service *
* requests. *
*------------------------------------------------------------------------*
* *
* Jake Janovetz *
* University of Illinois *
* 1406 West Green Street *
* Urbana IL 61801 *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
/* Revision Control Information:
*
* $Source$
* $Id$
* $Log$
* Revision 1.3 1998/05/19 21:28:17 erithacus
* Update control socket to file I/O.
*
* Revision 1.2 1998/05/19 20:13:50 erithacus
* Remodeled to be entirely reentrant.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -133,9 +97,10 @@
#include <netinet/in.h>
#include "ftpd.h"
#include "untar.h"
extern struct rtems_ftpd_configuration rtems_ftpd_configuration;
/**************************************************************************
* Meanings of first and second digits of reply codes:
*
@@ -163,14 +128,6 @@
*************************************************************************/
/**************************************************************************
* Maximum buffer size for use by the transfer protocol.
* This will be eliminated when the filesystem is complete enough that
* we don't have to store the received data until we have something to
* do with it.
*************************************************************************/
#define FTPD_MAX_RECEIVESIZE (512*1024)
/**************************************************************************
* SessionInfo structure.
*
@@ -180,13 +137,14 @@
typedef struct
{
struct sockaddr_in data_addr; /* Data address for PORT commands */
int ctrl_sock; /* Control connection socker */
FILE *ctrl_fp; /* File pointer for control connection */
char cwd[255]; /* Current working directory */
/* Login -- future use -- */
int xfer_mode; /* Transfer mode (ASCII/binary) */
} FTPD_SessionInfo_t;
#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready."
#define FTPD_WELCOME_MESSAGE \
"Welcome to the RTEMS FTP server.\n" \
"\n" \
@@ -194,7 +152,7 @@ typedef struct
/**************************************************************************
* Function: FTPD_SendReply *
* Function: rtems_ftpd_send_reply *
**************************************************************************
* Description: *
* *
@@ -216,7 +174,7 @@ typedef struct
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_SendReply(int code, char *text)
rtems_ftpd_send_reply(int code, char *text)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -241,17 +199,19 @@ FTPD_SendReply(int code, char *text)
if (text != NULL)
{
sprintf(str, "%d %.70s\r\n", code, text);
fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
}
else
{
sprintf(str, "%d\r\n", code);
fprintf(info->ctrl_fp, "%d\r\n", code);
}
send(info->ctrl_sock, str, strlen(str), 0);
fflush(info->ctrl_fp);
}
/**************************************************************************
* Function: FTPD_CommandRetrieve *
* Function: rtems_ftpd_command_retrieve *
**************************************************************************
* Description: *
* *
@@ -274,12 +234,11 @@ FTPD_SendReply(int code, char *text)
* 04/29/98 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandRetrieve(char *filename)
rtems_ftpd_command_retrieve(char *filename)
{
int s;
int n;
FILE *fp;
int fd;
unsigned char *bufr;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -288,32 +247,31 @@ FTPD_CommandRetrieve(char *filename)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if ((fp = fopen(filename, "r")) == NULL)
if ((fd = open(filename, O_RDONLY)) == -1)
{
FTPD_SendReply(450, "Error opening file.");
rtems_ftpd_send_reply(450, "Error opening file.");
return(0);
}
bufr = (unsigned char *)malloc(BUFSIZ);
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
fclose(fp);
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
close(fd);
return(0);
}
/***********************************************************************
* Connect to the data connection (PORT made in an earlier PORT call).
**********************************************************************/
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
FTPD_SendReply(420, "Server error - could not connect socket.");
rtems_ftpd_send_reply(420, "Server error - could not connect socket.");
free(bufr);
fclose(fp);
close(fd);
close(s);
return(1);
}
@@ -321,18 +279,19 @@ FTPD_CommandRetrieve(char *filename)
/***********************************************************************
* Send the data over the ether.
**********************************************************************/
while ((n = fread(bufr, 1, BUFSIZ, fp)) != 0)
while ((n = read(fd, bufr, BUFSIZ)) > 0)
{
send(s, bufr, n, 0);
bufr[n-1] = '\0';
}
if (feof(fp))
if (n == 0)
{
FTPD_SendReply(210, "File sent successfully.");
rtems_ftpd_send_reply(210, "File sent successfully.");
}
else
{
FTPD_SendReply(450, "Retrieve failed.");
rtems_ftpd_send_reply(450, "Retrieve failed.");
}
if (close(s) != 0)
@@ -341,13 +300,13 @@ FTPD_CommandRetrieve(char *filename)
}
free(bufr);
fclose(fp);
close(fd);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandStore *
* Function: rtems_ftpd_command_store *
**************************************************************************
* Description: *
* *
@@ -370,15 +329,15 @@ FTPD_CommandRetrieve(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandStore(char *filename)
rtems_ftpd_command_store(char *filename)
{
char *bufr;
char *bigBufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
char *bufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
struct rtems_ftpd_hook *usehook = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
@@ -387,26 +346,17 @@ FTPD_CommandStore(char *filename)
bufr = (char *)malloc(BUFSIZ * sizeof(char));
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
return(1);
}
bigBufr = (char *)malloc(FTPD_MAX_RECEIVESIZE * sizeof(char));
if (bigBufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
free(bufr);
free(bigBufr);
close(s);
return(1);
}
@@ -414,22 +364,57 @@ FTPD_CommandStore(char *filename)
/***********************************************************************
* File: "/dev/null" just throws the data away.
* Otherwise, search our list of hooks to see if we need to do something
* special.
**********************************************************************/
if (!strncmp("/dev/null", filename, 9))
{
while ((n = read(s, bufr, BUFSIZ)) > 0);
}
else
else if (rtems_ftpd_configuration.hooks != NULL)
{
struct rtems_ftpd_hook *hook;
int i;
i = 0;
hook = &rtems_ftpd_configuration.hooks[i++];
while (hook->filename != NULL)
{
if (!strcmp(hook->filename, filename))
{
usehook = hook;
break;
}
hook = &rtems_ftpd_configuration.hooks[i++];
}
}
if (usehook != NULL)
{
char *bigBufr;
/***********************************************************************
* Allocate space for our "file".
**********************************************************************/
bigBufr = (char *)malloc(
rtems_ftpd_configuration.max_hook_filesize * sizeof(char));
if (bigBufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
/***********************************************************************
* Retrieve the file into our buffer space.
**********************************************************************/
size = 0;
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
if (size + n > FTPD_MAX_RECEIVESIZE)
if (size + n >
rtems_ftpd_configuration.max_hook_filesize * sizeof(char))
{
FTPD_SendReply(440, "Server error - Buffer size exceeded.");
rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded.");
free(bufr);
free(bigBufr);
close(s);
@@ -438,66 +423,60 @@ FTPD_CommandStore(char *filename)
memcpy(&bigBufr[size], bufr, n);
size += n;
}
}
free(bufr);
close(s);
close(s);
/***********************************************************************
* Figure out what to do with the data we just received.
**********************************************************************/
if (!strncmp("untar", filename, 5))
{
Untar_FromMemory(bigBufr, size);
FTPD_SendReply(210, "Untar successful.");
}
else
{
FILE *fp;
size_t len;
size_t written;
fp = fopen(filename, "w");
if (fp == NULL)
/***********************************************************************
* Call our hook.
**********************************************************************/
if ((usehook->hook_function)(bigBufr, size) == 0)
{
FTPD_SendReply(440, "Could not open file.");
free(bigBufr);
return(1);
}
n = 0;
written = 0;
while (n<size)
{
len = ((size-n>BUFSIZ)?(BUFSIZ):(size-n));
written = fwrite(&bigBufr[n], 1, len, fp);
n += written;
if (written != len)
{
break;
}
}
fclose(fp);
if (n == size)
{
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(210, "File transferred successfully.");
}
else
{
FTPD_SendReply(440, "Error during write.");
free(bigBufr);
rtems_ftpd_send_reply(440, "File transfer failed.");
}
free(bigBufr);
}
else
{
int fd;
size_t written;
fd = creat(filename, S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH);
if (fd == -1)
{
rtems_ftpd_send_reply(450, "Could not open file.");
close(s);
free(bufr);
return(1);
}
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
written = write(fd, bufr, n);
if (written == -1)
{
rtems_ftpd_send_reply(450, "Error during write.");
close(fd);
close(s);
free(bufr);
return(1);
}
}
close(fd);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
}
free(bigBufr);
free(bufr);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandList *
* Function: rtems_ftpd_command_list *
**************************************************************************
* Description: *
* *
@@ -518,7 +497,7 @@ FTPD_CommandStore(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandList(char *fname)
rtems_ftpd_command_list(char *fname)
{
int s;
rtems_status_code sc;
@@ -532,7 +511,7 @@ FTPD_CommandList(char *fname)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(150, "ASCII data connection for LIST.");
rtems_ftpd_send_reply(150, "ASCII data connection for LIST.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
@@ -548,7 +527,7 @@ FTPD_CommandList(char *fname)
fname, (info->xfer_mode==TYPE_A)?("\r"):(""));
send(s, dirline, strlen(dirline), 0);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
return;
}
while ((dp = readdir(dirp)) != NULL)
@@ -578,7 +557,7 @@ FTPD_CommandList(char *fname)
closedir(dirp);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
}
@@ -586,7 +565,7 @@ FTPD_CommandList(char *fname)
* Cheesy way to change directories
*/
static void
FTPD_CWD(char *dir)
rtems_ftpd_CWD(char *dir)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -597,17 +576,17 @@ FTPD_CWD(char *dir)
if (chdir(dir) == 0)
{
FTPD_SendReply(250, "CWD command successful.");
rtems_ftpd_send_reply(250, "CWD command successful.");
}
else
{
FTPD_SendReply(550, "CWD command failed.");
rtems_ftpd_send_reply(550, "CWD command failed.");
}
}
/**************************************************************************
* Function: FTPD_CommandPort *
* Function: rtems_ftpd_command_port *
**************************************************************************
* Description: *
* *
@@ -630,7 +609,7 @@ FTPD_CWD(char *dir)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandPort(char *bufr)
rtems_ftpd_command_port(char *bufr)
{
char *ip;
char *port;
@@ -656,13 +635,15 @@ FTPD_CommandPort(char *bufr)
/**************************************************************************
* Function: FTPD_ParseCommand *
* Function: rtems_ftpd_parse_command *
**************************************************************************
* Description: *
* *
* Here, we parse the commands that have come through the control *
* connection. *
* *
* FIXME: This section is somewhat of a hack. We should have a better *
* way to parse commands. *
* *
* Inputs: *
* *
@@ -678,7 +659,7 @@ FTPD_CommandPort(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_ParseCommand(char *bufr)
rtems_ftpd_parse_command(char *bufr)
{
char fname[255];
rtems_status_code sc;
@@ -690,71 +671,71 @@ FTPD_ParseCommand(char *bufr)
if (!strncmp("PORT", bufr, 4))
{
FTPD_SendReply(200, "PORT command successful.");
FTPD_CommandPort(&bufr[5]);
rtems_ftpd_send_reply(200, "PORT command successful.");
rtems_ftpd_command_port(&bufr[5]);
}
else if (!strncmp("RETR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandRetrieve(fname);
rtems_ftpd_command_retrieve(fname);
}
else if (!strncmp("STOR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandStore(fname);
rtems_ftpd_command_store(fname);
}
else if (!strncmp("LIST", bufr, 4))
{
if (bufr[5] == '\n')
{
FTPD_CommandList(".");
rtems_ftpd_command_list(".");
}
else
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandList(fname);
rtems_ftpd_command_list(fname);
}
}
else if (!strncmp("USER", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("SYST", bufr, 4))
{
FTPD_SendReply(240, "RTEMS");
rtems_ftpd_send_reply(240, "RTEMS");
}
else if (!strncmp("TYPE", bufr, 4))
{
if (bufr[5] == 'I')
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(200, "Type set to I.");
rtems_ftpd_send_reply(200, "Type set to I.");
}
else if (bufr[5] == 'A')
{
info->xfer_mode = TYPE_A;
FTPD_SendReply(200, "Type set to A.");
rtems_ftpd_send_reply(200, "Type set to A.");
}
else
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(504, "Type not implemented. Set to I.");
rtems_ftpd_send_reply(504, "Type not implemented. Set to I.");
}
}
else if (!strncmp("PASS", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("DELE", bufr, 4))
{
sscanf(&bufr[4], "%254s", fname);
if (unlink(fname) == 0)
{
FTPD_SendReply(257, "DELE successful.");
rtems_ftpd_send_reply(257, "DELE successful.");
}
else
{
FTPD_SendReply(550, "DELE failed.");
rtems_ftpd_send_reply(550, "DELE failed.");
}
}
else if (!strncmp("SITE CHMOD", bufr, 10))
@@ -764,11 +745,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[11], "%o %254s", &mask, fname);
if (chmod(fname, (mode_t)mask) == 0)
{
FTPD_SendReply(257, "CHMOD successful.");
rtems_ftpd_send_reply(257, "CHMOD successful.");
}
else
{
FTPD_SendReply(550, "CHMOD failed.");
rtems_ftpd_send_reply(550, "CHMOD failed.");
}
}
else if (!strncmp("RMD", bufr, 3))
@@ -776,11 +757,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (rmdir(fname) == 0)
{
FTPD_SendReply(257, "RMD successful.");
rtems_ftpd_send_reply(257, "RMD successful.");
}
else
{
FTPD_SendReply(550, "RMD failed.");
rtems_ftpd_send_reply(550, "RMD failed.");
}
}
else if (!strncmp("MKD", bufr, 3))
@@ -788,33 +769,34 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
{
FTPD_SendReply(257, "MKD successful.");
rtems_ftpd_send_reply(257, "MKD successful.");
}
else
{
FTPD_SendReply(550, "MKD failed.");
rtems_ftpd_send_reply(550, "MKD failed.");
}
}
else if (!strncmp("CWD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
FTPD_CWD(fname);
rtems_ftpd_CWD(fname);
}
else if (!strncmp("PWD", bufr, 3))
{
char *cwd = getcwd(0, 0);
sprintf(bufr, "\"%s\" is the current directory.", cwd);
FTPD_SendReply(250, bufr);
rtems_ftpd_send_reply(250, bufr);
free(cwd);
}
else
{
FTPD_SendReply(500, "Unrecognized/unsupported command.");
rtems_ftpd_send_reply(500, "Unrecognized/unsupported command.");
}
}
/**************************************************************************
* Function: FTPD_Session *
* Function: rtems_ftpd_session *
**************************************************************************
* Description: *
* *
@@ -827,7 +809,7 @@ FTPD_ParseCommand(char *bufr)
* *
* Inputs: *
* *
* rtems_task_argument arg - The FTPD_Daemon task passes the socket *
* rtems_task_argument arg - The daemon task passes the socket *
* which serves as the control connection. *
* *
* Output: *
@@ -839,7 +821,7 @@ FTPD_ParseCommand(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Session(rtems_task_argument arg)
rtems_ftpd_session(rtems_task_argument arg)
{
char cmd[256];
rtems_status_code sc;
@@ -849,7 +831,7 @@ FTPD_Session(rtems_task_argument arg)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(220, "Erithacus FTP server (Version 1.0) ready.");
rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE);
/***********************************************************************
* Set initial directory to "/".
@@ -858,7 +840,7 @@ FTPD_Session(rtems_task_argument arg)
info->xfer_mode = TYPE_A;
while (1)
{
if (recv(info->ctrl_sock, cmd, 256, 0) == -1)
if (fgets(cmd, 256, info->ctrl_fp) == NULL)
{
syslog(LOG_INFO, "ftpd: Connection aborted.");
break;
@@ -866,16 +848,16 @@ FTPD_Session(rtems_task_argument arg)
if (!strncmp("QUIT", cmd, 4))
{
FTPD_SendReply(221, "Goodbye.");
rtems_ftpd_send_reply(221, "Goodbye.");
break;
}
else
{
FTPD_ParseCommand(cmd);
rtems_ftpd_parse_command(cmd);
}
}
if (close(info->ctrl_sock) < 0)
if (fclose(info->ctrl_fp) != 0)
{
syslog(LOG_ERR, "ftpd: Could not close session.");
}
@@ -895,7 +877,7 @@ FTPD_Session(rtems_task_argument arg)
/**************************************************************************
* Function: FTPD_Daemon *
* Function: rtems_ftpd_daemon *
**************************************************************************
* Description: *
* *
@@ -918,7 +900,7 @@ FTPD_Session(rtems_task_argument arg)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Daemon()
rtems_ftpd_daemon()
{
int s;
int s1;
@@ -941,7 +923,7 @@ FTPD_Daemon()
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = FTPD_CONTROL_PORT;
localAddr.sin_port = htons(rtems_ftpd_configuration.port);
localAddr.sin_addr.s_addr = INADDR_ANY;
memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero));
if (bind(s, (struct sockaddr *)&localAddr,
@@ -1002,21 +984,28 @@ FTPD_Daemon()
/********************************************************************
* Send the socket on to the new session.
*******************************************************************/
info->ctrl_sock = s1;
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, FTPD_Session, 0);
if (sc != RTEMS_SUCCESSFUL)
if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
syslog(LOG_ERR, "ftpd: fdopen() on socket failed.");
close(s1);
}
else
{
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, rtems_ftpd_session, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
}
}
}
}
/**************************************************************************
* Function: FTPD_Start *
* Function: rtems_ftpd_start *
**************************************************************************
* Description: *
* *
@@ -1031,21 +1020,33 @@ FTPD_Daemon()
* *
* Output: *
* *
* none *
* int - RTEMS_SUCCESSFUL on successful start of the daemon. *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
void
FTPD_Start(rtems_task_priority priority)
int
rtems_initialize_ftpd()
{
rtems_status_code sc;
rtems_id tid;
if (rtems_ftpd_configuration.port == 0)
{
rtems_ftpd_configuration.port = FTPD_CONTROL_PORT;
}
/***********************************************************************
* Default FTPD priority.
**********************************************************************/
if (rtems_ftpd_configuration.priority == 0)
{
rtems_ftpd_configuration.priority = 40;
}
sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
priority, 8*1024,
rtems_ftpd_configuration.priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
@@ -1054,14 +1055,18 @@ FTPD_Start(rtems_task_priority priority)
{
syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
sc = rtems_task_start(tid, FTPD_Daemon, 0);
sc = rtems_task_start(tid, rtems_ftpd_daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
syslog(LOG_INFO, "ftpd: FTP daemon started.");
return(RTEMS_SUCCESSFUL);
}

View File

@@ -10,17 +10,33 @@
#define FTPD_CONTROL_PORT 21
typedef int (*rtems_ftpd_hookfunction)(unsigned char *, unsigned long);
struct rtems_ftpd_hook
{
char *filename;
rtems_ftpd_hookfunction hook_function;
};
struct rtems_ftpd_configuration
{
rtems_task_priority priority; /* FTPD task priority */
unsigned long max_hook_filesize; /* Maximum buffersize */
/* for hooks */
int port; /* Well-known port */
struct rtems_ftpd_hook *hooks; /* List of hooks */
};
/*
* Reply codes.
*/
#define PRELIM 1 /* positive preliminary */
#define COMPLETE 2 /* positive completion */
#define CONTINUE 3 /* positive intermediate */
#define TRANSIENT 4 /* transient negative completion */
#define ERROR 5 /* permanent negative completion */
void rtems_ftpd_sTart(rtems_task_priority priority);
int rtems_initialize_ftpd();
#endif /* __FTPD_H__ */

View File

@@ -1,39 +1,26 @@
/*
* FTP Server Daemon
/* FIXME: 1. Parse command is a hack. We can do better.
* 2. chdir is a hack. We can do better.
* 3. PWD doesn't work.
* 4. Some sort of access control?
*
* FTP Server Daemon
*
* Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
*
* $Id$
*/
/*
* Current state:
* To untar, put as "untar"
* CWD uses chdir
* This is bad due to global setting of chdir.
*
* Stored files come into RAM and are saved later. This is an artifact
* of a previous implementation (no filesystem -- had to do stuff with
* the "files" later). This can be eliminated once all of Jake's stuff
* is moved to devices/filesystems.
*
* CLOSE(S) doesn't seem to work. This causes problems in
* several areas. It lets too many file descriptors pile up
* and it doesn't seem to flush the stream.
*
* Is 'recv' what I want to use to get commands from the control port?
*
*/
/**************************************************************************
* ftpd.c *
**************************************************************************
* Description: *
* *
* This file contains the daemon which services requests that appear *
* on the 'FTP' port. This server is compatible with FTP, but it *
* also provides services specific to the Erithacus system. *
* This server is started at boot-time and runs forever. *
* on the FTP port. This server is compatible with FTP, but it *
* also provides 'hooks' to make it usable in situations where files *
* are not used/necessary. Once the server is started, it runs *
* forever. *
* *
* *
* Organization: *
* *
@@ -44,12 +31,6 @@
* is complete, the session task deletes itself. The daemon still *
* runs, however. *
* *
* Implementation Notes: *
* *
* The 'current working directory' implementation utilizes the *
* RTEMS filesystem cwd. This is no good since other processes *
* inherit the same cwd. *
* *
* *
* Supported commands are: *
* *
@@ -70,51 +51,34 @@
* and port (x*256 + y). *
* *
* *
* *
* The public routines contained in this file are: *
* *
* FTPD_Start - Starts the server daemon, then returns to its caller. *
* rtems_initialize_ftpd_start - Starts the server daemon, then *
* returns to its caller. *
* *
* *
* The private routines contained in this file are: *
* *
* FTPD_SendReply - Sends a reply code and text through the control *
* port. *
* FTPD_CommandStore - Performs the "STOR" command. *
* FTPD_CommandList - Performs the "LIST" command. *
* FTPD_CommandPort - Opens a data port (the "PORT" command). *
* FTPD_ParseCommand - Parses an incoming command. *
* FTPD_Session - Begins a service session. *
* FTPD_Daemon - Listens on the FTP port for service requests. *
* *
* *
* rtems_ftpd_send_reply - Sends a reply code and text through the *
* control port. *
* rtems_ftpd_command_retrieve - Performs to "RETR" command. *
* rtems_ftpd_command_store - Performs the "STOR" command. *
* rtems_ftpd_command_list - Performs the "LIST" command. *
* rtems_ftpd_command_port - Opens a data port (the "PORT" command). *
* rtems_ftpd_parse_command - Parses an incoming command. *
* rtmes_ftpd_session - Begins a service session. *
* rtems_ftpd_daemon - Listens on the FTP port for service *
* requests. *
*------------------------------------------------------------------------*
* *
* Jake Janovetz *
* University of Illinois *
* 1406 West Green Street *
* Urbana IL 61801 *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
/* Revision Control Information:
*
* $Source$
* $Id$
* $Log$
* Revision 1.3 1998/05/19 21:28:17 erithacus
* Update control socket to file I/O.
*
* Revision 1.2 1998/05/19 20:13:50 erithacus
* Remodeled to be entirely reentrant.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -133,9 +97,10 @@
#include <netinet/in.h>
#include "ftpd.h"
#include "untar.h"
extern struct rtems_ftpd_configuration rtems_ftpd_configuration;
/**************************************************************************
* Meanings of first and second digits of reply codes:
*
@@ -163,14 +128,6 @@
*************************************************************************/
/**************************************************************************
* Maximum buffer size for use by the transfer protocol.
* This will be eliminated when the filesystem is complete enough that
* we don't have to store the received data until we have something to
* do with it.
*************************************************************************/
#define FTPD_MAX_RECEIVESIZE (512*1024)
/**************************************************************************
* SessionInfo structure.
*
@@ -180,13 +137,14 @@
typedef struct
{
struct sockaddr_in data_addr; /* Data address for PORT commands */
int ctrl_sock; /* Control connection socker */
FILE *ctrl_fp; /* File pointer for control connection */
char cwd[255]; /* Current working directory */
/* Login -- future use -- */
int xfer_mode; /* Transfer mode (ASCII/binary) */
} FTPD_SessionInfo_t;
#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready."
#define FTPD_WELCOME_MESSAGE \
"Welcome to the RTEMS FTP server.\n" \
"\n" \
@@ -194,7 +152,7 @@ typedef struct
/**************************************************************************
* Function: FTPD_SendReply *
* Function: rtems_ftpd_send_reply *
**************************************************************************
* Description: *
* *
@@ -216,7 +174,7 @@ typedef struct
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_SendReply(int code, char *text)
rtems_ftpd_send_reply(int code, char *text)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -241,17 +199,19 @@ FTPD_SendReply(int code, char *text)
if (text != NULL)
{
sprintf(str, "%d %.70s\r\n", code, text);
fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
}
else
{
sprintf(str, "%d\r\n", code);
fprintf(info->ctrl_fp, "%d\r\n", code);
}
send(info->ctrl_sock, str, strlen(str), 0);
fflush(info->ctrl_fp);
}
/**************************************************************************
* Function: FTPD_CommandRetrieve *
* Function: rtems_ftpd_command_retrieve *
**************************************************************************
* Description: *
* *
@@ -274,12 +234,11 @@ FTPD_SendReply(int code, char *text)
* 04/29/98 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandRetrieve(char *filename)
rtems_ftpd_command_retrieve(char *filename)
{
int s;
int n;
FILE *fp;
int fd;
unsigned char *bufr;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -288,32 +247,31 @@ FTPD_CommandRetrieve(char *filename)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if ((fp = fopen(filename, "r")) == NULL)
if ((fd = open(filename, O_RDONLY)) == -1)
{
FTPD_SendReply(450, "Error opening file.");
rtems_ftpd_send_reply(450, "Error opening file.");
return(0);
}
bufr = (unsigned char *)malloc(BUFSIZ);
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
fclose(fp);
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
close(fd);
return(0);
}
/***********************************************************************
* Connect to the data connection (PORT made in an earlier PORT call).
**********************************************************************/
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
FTPD_SendReply(420, "Server error - could not connect socket.");
rtems_ftpd_send_reply(420, "Server error - could not connect socket.");
free(bufr);
fclose(fp);
close(fd);
close(s);
return(1);
}
@@ -321,18 +279,19 @@ FTPD_CommandRetrieve(char *filename)
/***********************************************************************
* Send the data over the ether.
**********************************************************************/
while ((n = fread(bufr, 1, BUFSIZ, fp)) != 0)
while ((n = read(fd, bufr, BUFSIZ)) > 0)
{
send(s, bufr, n, 0);
bufr[n-1] = '\0';
}
if (feof(fp))
if (n == 0)
{
FTPD_SendReply(210, "File sent successfully.");
rtems_ftpd_send_reply(210, "File sent successfully.");
}
else
{
FTPD_SendReply(450, "Retrieve failed.");
rtems_ftpd_send_reply(450, "Retrieve failed.");
}
if (close(s) != 0)
@@ -341,13 +300,13 @@ FTPD_CommandRetrieve(char *filename)
}
free(bufr);
fclose(fp);
close(fd);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandStore *
* Function: rtems_ftpd_command_store *
**************************************************************************
* Description: *
* *
@@ -370,15 +329,15 @@ FTPD_CommandRetrieve(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandStore(char *filename)
rtems_ftpd_command_store(char *filename)
{
char *bufr;
char *bigBufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
char *bufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
struct rtems_ftpd_hook *usehook = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
@@ -387,26 +346,17 @@ FTPD_CommandStore(char *filename)
bufr = (char *)malloc(BUFSIZ * sizeof(char));
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
return(1);
}
bigBufr = (char *)malloc(FTPD_MAX_RECEIVESIZE * sizeof(char));
if (bigBufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
free(bufr);
free(bigBufr);
close(s);
return(1);
}
@@ -414,22 +364,57 @@ FTPD_CommandStore(char *filename)
/***********************************************************************
* File: "/dev/null" just throws the data away.
* Otherwise, search our list of hooks to see if we need to do something
* special.
**********************************************************************/
if (!strncmp("/dev/null", filename, 9))
{
while ((n = read(s, bufr, BUFSIZ)) > 0);
}
else
else if (rtems_ftpd_configuration.hooks != NULL)
{
struct rtems_ftpd_hook *hook;
int i;
i = 0;
hook = &rtems_ftpd_configuration.hooks[i++];
while (hook->filename != NULL)
{
if (!strcmp(hook->filename, filename))
{
usehook = hook;
break;
}
hook = &rtems_ftpd_configuration.hooks[i++];
}
}
if (usehook != NULL)
{
char *bigBufr;
/***********************************************************************
* Allocate space for our "file".
**********************************************************************/
bigBufr = (char *)malloc(
rtems_ftpd_configuration.max_hook_filesize * sizeof(char));
if (bigBufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
/***********************************************************************
* Retrieve the file into our buffer space.
**********************************************************************/
size = 0;
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
if (size + n > FTPD_MAX_RECEIVESIZE)
if (size + n >
rtems_ftpd_configuration.max_hook_filesize * sizeof(char))
{
FTPD_SendReply(440, "Server error - Buffer size exceeded.");
rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded.");
free(bufr);
free(bigBufr);
close(s);
@@ -438,66 +423,60 @@ FTPD_CommandStore(char *filename)
memcpy(&bigBufr[size], bufr, n);
size += n;
}
}
free(bufr);
close(s);
close(s);
/***********************************************************************
* Figure out what to do with the data we just received.
**********************************************************************/
if (!strncmp("untar", filename, 5))
{
Untar_FromMemory(bigBufr, size);
FTPD_SendReply(210, "Untar successful.");
}
else
{
FILE *fp;
size_t len;
size_t written;
fp = fopen(filename, "w");
if (fp == NULL)
/***********************************************************************
* Call our hook.
**********************************************************************/
if ((usehook->hook_function)(bigBufr, size) == 0)
{
FTPD_SendReply(440, "Could not open file.");
free(bigBufr);
return(1);
}
n = 0;
written = 0;
while (n<size)
{
len = ((size-n>BUFSIZ)?(BUFSIZ):(size-n));
written = fwrite(&bigBufr[n], 1, len, fp);
n += written;
if (written != len)
{
break;
}
}
fclose(fp);
if (n == size)
{
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(210, "File transferred successfully.");
}
else
{
FTPD_SendReply(440, "Error during write.");
free(bigBufr);
rtems_ftpd_send_reply(440, "File transfer failed.");
}
free(bigBufr);
}
else
{
int fd;
size_t written;
fd = creat(filename, S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH);
if (fd == -1)
{
rtems_ftpd_send_reply(450, "Could not open file.");
close(s);
free(bufr);
return(1);
}
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
written = write(fd, bufr, n);
if (written == -1)
{
rtems_ftpd_send_reply(450, "Error during write.");
close(fd);
close(s);
free(bufr);
return(1);
}
}
close(fd);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
}
free(bigBufr);
free(bufr);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandList *
* Function: rtems_ftpd_command_list *
**************************************************************************
* Description: *
* *
@@ -518,7 +497,7 @@ FTPD_CommandStore(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandList(char *fname)
rtems_ftpd_command_list(char *fname)
{
int s;
rtems_status_code sc;
@@ -532,7 +511,7 @@ FTPD_CommandList(char *fname)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(150, "ASCII data connection for LIST.");
rtems_ftpd_send_reply(150, "ASCII data connection for LIST.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
@@ -548,7 +527,7 @@ FTPD_CommandList(char *fname)
fname, (info->xfer_mode==TYPE_A)?("\r"):(""));
send(s, dirline, strlen(dirline), 0);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
return;
}
while ((dp = readdir(dirp)) != NULL)
@@ -578,7 +557,7 @@ FTPD_CommandList(char *fname)
closedir(dirp);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
}
@@ -586,7 +565,7 @@ FTPD_CommandList(char *fname)
* Cheesy way to change directories
*/
static void
FTPD_CWD(char *dir)
rtems_ftpd_CWD(char *dir)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -597,17 +576,17 @@ FTPD_CWD(char *dir)
if (chdir(dir) == 0)
{
FTPD_SendReply(250, "CWD command successful.");
rtems_ftpd_send_reply(250, "CWD command successful.");
}
else
{
FTPD_SendReply(550, "CWD command failed.");
rtems_ftpd_send_reply(550, "CWD command failed.");
}
}
/**************************************************************************
* Function: FTPD_CommandPort *
* Function: rtems_ftpd_command_port *
**************************************************************************
* Description: *
* *
@@ -630,7 +609,7 @@ FTPD_CWD(char *dir)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandPort(char *bufr)
rtems_ftpd_command_port(char *bufr)
{
char *ip;
char *port;
@@ -656,13 +635,15 @@ FTPD_CommandPort(char *bufr)
/**************************************************************************
* Function: FTPD_ParseCommand *
* Function: rtems_ftpd_parse_command *
**************************************************************************
* Description: *
* *
* Here, we parse the commands that have come through the control *
* connection. *
* *
* FIXME: This section is somewhat of a hack. We should have a better *
* way to parse commands. *
* *
* Inputs: *
* *
@@ -678,7 +659,7 @@ FTPD_CommandPort(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_ParseCommand(char *bufr)
rtems_ftpd_parse_command(char *bufr)
{
char fname[255];
rtems_status_code sc;
@@ -690,71 +671,71 @@ FTPD_ParseCommand(char *bufr)
if (!strncmp("PORT", bufr, 4))
{
FTPD_SendReply(200, "PORT command successful.");
FTPD_CommandPort(&bufr[5]);
rtems_ftpd_send_reply(200, "PORT command successful.");
rtems_ftpd_command_port(&bufr[5]);
}
else if (!strncmp("RETR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandRetrieve(fname);
rtems_ftpd_command_retrieve(fname);
}
else if (!strncmp("STOR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandStore(fname);
rtems_ftpd_command_store(fname);
}
else if (!strncmp("LIST", bufr, 4))
{
if (bufr[5] == '\n')
{
FTPD_CommandList(".");
rtems_ftpd_command_list(".");
}
else
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandList(fname);
rtems_ftpd_command_list(fname);
}
}
else if (!strncmp("USER", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("SYST", bufr, 4))
{
FTPD_SendReply(240, "RTEMS");
rtems_ftpd_send_reply(240, "RTEMS");
}
else if (!strncmp("TYPE", bufr, 4))
{
if (bufr[5] == 'I')
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(200, "Type set to I.");
rtems_ftpd_send_reply(200, "Type set to I.");
}
else if (bufr[5] == 'A')
{
info->xfer_mode = TYPE_A;
FTPD_SendReply(200, "Type set to A.");
rtems_ftpd_send_reply(200, "Type set to A.");
}
else
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(504, "Type not implemented. Set to I.");
rtems_ftpd_send_reply(504, "Type not implemented. Set to I.");
}
}
else if (!strncmp("PASS", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("DELE", bufr, 4))
{
sscanf(&bufr[4], "%254s", fname);
if (unlink(fname) == 0)
{
FTPD_SendReply(257, "DELE successful.");
rtems_ftpd_send_reply(257, "DELE successful.");
}
else
{
FTPD_SendReply(550, "DELE failed.");
rtems_ftpd_send_reply(550, "DELE failed.");
}
}
else if (!strncmp("SITE CHMOD", bufr, 10))
@@ -764,11 +745,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[11], "%o %254s", &mask, fname);
if (chmod(fname, (mode_t)mask) == 0)
{
FTPD_SendReply(257, "CHMOD successful.");
rtems_ftpd_send_reply(257, "CHMOD successful.");
}
else
{
FTPD_SendReply(550, "CHMOD failed.");
rtems_ftpd_send_reply(550, "CHMOD failed.");
}
}
else if (!strncmp("RMD", bufr, 3))
@@ -776,11 +757,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (rmdir(fname) == 0)
{
FTPD_SendReply(257, "RMD successful.");
rtems_ftpd_send_reply(257, "RMD successful.");
}
else
{
FTPD_SendReply(550, "RMD failed.");
rtems_ftpd_send_reply(550, "RMD failed.");
}
}
else if (!strncmp("MKD", bufr, 3))
@@ -788,33 +769,34 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
{
FTPD_SendReply(257, "MKD successful.");
rtems_ftpd_send_reply(257, "MKD successful.");
}
else
{
FTPD_SendReply(550, "MKD failed.");
rtems_ftpd_send_reply(550, "MKD failed.");
}
}
else if (!strncmp("CWD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
FTPD_CWD(fname);
rtems_ftpd_CWD(fname);
}
else if (!strncmp("PWD", bufr, 3))
{
char *cwd = getcwd(0, 0);
sprintf(bufr, "\"%s\" is the current directory.", cwd);
FTPD_SendReply(250, bufr);
rtems_ftpd_send_reply(250, bufr);
free(cwd);
}
else
{
FTPD_SendReply(500, "Unrecognized/unsupported command.");
rtems_ftpd_send_reply(500, "Unrecognized/unsupported command.");
}
}
/**************************************************************************
* Function: FTPD_Session *
* Function: rtems_ftpd_session *
**************************************************************************
* Description: *
* *
@@ -827,7 +809,7 @@ FTPD_ParseCommand(char *bufr)
* *
* Inputs: *
* *
* rtems_task_argument arg - The FTPD_Daemon task passes the socket *
* rtems_task_argument arg - The daemon task passes the socket *
* which serves as the control connection. *
* *
* Output: *
@@ -839,7 +821,7 @@ FTPD_ParseCommand(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Session(rtems_task_argument arg)
rtems_ftpd_session(rtems_task_argument arg)
{
char cmd[256];
rtems_status_code sc;
@@ -849,7 +831,7 @@ FTPD_Session(rtems_task_argument arg)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(220, "Erithacus FTP server (Version 1.0) ready.");
rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE);
/***********************************************************************
* Set initial directory to "/".
@@ -858,7 +840,7 @@ FTPD_Session(rtems_task_argument arg)
info->xfer_mode = TYPE_A;
while (1)
{
if (recv(info->ctrl_sock, cmd, 256, 0) == -1)
if (fgets(cmd, 256, info->ctrl_fp) == NULL)
{
syslog(LOG_INFO, "ftpd: Connection aborted.");
break;
@@ -866,16 +848,16 @@ FTPD_Session(rtems_task_argument arg)
if (!strncmp("QUIT", cmd, 4))
{
FTPD_SendReply(221, "Goodbye.");
rtems_ftpd_send_reply(221, "Goodbye.");
break;
}
else
{
FTPD_ParseCommand(cmd);
rtems_ftpd_parse_command(cmd);
}
}
if (close(info->ctrl_sock) < 0)
if (fclose(info->ctrl_fp) != 0)
{
syslog(LOG_ERR, "ftpd: Could not close session.");
}
@@ -895,7 +877,7 @@ FTPD_Session(rtems_task_argument arg)
/**************************************************************************
* Function: FTPD_Daemon *
* Function: rtems_ftpd_daemon *
**************************************************************************
* Description: *
* *
@@ -918,7 +900,7 @@ FTPD_Session(rtems_task_argument arg)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Daemon()
rtems_ftpd_daemon()
{
int s;
int s1;
@@ -941,7 +923,7 @@ FTPD_Daemon()
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = FTPD_CONTROL_PORT;
localAddr.sin_port = htons(rtems_ftpd_configuration.port);
localAddr.sin_addr.s_addr = INADDR_ANY;
memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero));
if (bind(s, (struct sockaddr *)&localAddr,
@@ -1002,21 +984,28 @@ FTPD_Daemon()
/********************************************************************
* Send the socket on to the new session.
*******************************************************************/
info->ctrl_sock = s1;
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, FTPD_Session, 0);
if (sc != RTEMS_SUCCESSFUL)
if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
syslog(LOG_ERR, "ftpd: fdopen() on socket failed.");
close(s1);
}
else
{
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, rtems_ftpd_session, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
}
}
}
}
/**************************************************************************
* Function: FTPD_Start *
* Function: rtems_ftpd_start *
**************************************************************************
* Description: *
* *
@@ -1031,21 +1020,33 @@ FTPD_Daemon()
* *
* Output: *
* *
* none *
* int - RTEMS_SUCCESSFUL on successful start of the daemon. *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
void
FTPD_Start(rtems_task_priority priority)
int
rtems_initialize_ftpd()
{
rtems_status_code sc;
rtems_id tid;
if (rtems_ftpd_configuration.port == 0)
{
rtems_ftpd_configuration.port = FTPD_CONTROL_PORT;
}
/***********************************************************************
* Default FTPD priority.
**********************************************************************/
if (rtems_ftpd_configuration.priority == 0)
{
rtems_ftpd_configuration.priority = 40;
}
sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
priority, 8*1024,
rtems_ftpd_configuration.priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
@@ -1054,14 +1055,18 @@ FTPD_Start(rtems_task_priority priority)
{
syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
sc = rtems_task_start(tid, FTPD_Daemon, 0);
sc = rtems_task_start(tid, rtems_ftpd_daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
syslog(LOG_INFO, "ftpd: FTP daemon started.");
return(RTEMS_SUCCESSFUL);
}

View File

@@ -10,17 +10,33 @@
#define FTPD_CONTROL_PORT 21
typedef int (*rtems_ftpd_hookfunction)(unsigned char *, unsigned long);
struct rtems_ftpd_hook
{
char *filename;
rtems_ftpd_hookfunction hook_function;
};
struct rtems_ftpd_configuration
{
rtems_task_priority priority; /* FTPD task priority */
unsigned long max_hook_filesize; /* Maximum buffersize */
/* for hooks */
int port; /* Well-known port */
struct rtems_ftpd_hook *hooks; /* List of hooks */
};
/*
* Reply codes.
*/
#define PRELIM 1 /* positive preliminary */
#define COMPLETE 2 /* positive completion */
#define CONTINUE 3 /* positive intermediate */
#define TRANSIENT 4 /* transient negative completion */
#define ERROR 5 /* permanent negative completion */
void rtems_ftpd_sTart(rtems_task_priority priority);
int rtems_initialize_ftpd();
#endif /* __FTPD_H__ */

View File

@@ -1,39 +1,26 @@
/*
* FTP Server Daemon
/* FIXME: 1. Parse command is a hack. We can do better.
* 2. chdir is a hack. We can do better.
* 3. PWD doesn't work.
* 4. Some sort of access control?
*
* FTP Server Daemon
*
* Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
*
* $Id$
*/
/*
* Current state:
* To untar, put as "untar"
* CWD uses chdir
* This is bad due to global setting of chdir.
*
* Stored files come into RAM and are saved later. This is an artifact
* of a previous implementation (no filesystem -- had to do stuff with
* the "files" later). This can be eliminated once all of Jake's stuff
* is moved to devices/filesystems.
*
* CLOSE(S) doesn't seem to work. This causes problems in
* several areas. It lets too many file descriptors pile up
* and it doesn't seem to flush the stream.
*
* Is 'recv' what I want to use to get commands from the control port?
*
*/
/**************************************************************************
* ftpd.c *
**************************************************************************
* Description: *
* *
* This file contains the daemon which services requests that appear *
* on the 'FTP' port. This server is compatible with FTP, but it *
* also provides services specific to the Erithacus system. *
* This server is started at boot-time and runs forever. *
* on the FTP port. This server is compatible with FTP, but it *
* also provides 'hooks' to make it usable in situations where files *
* are not used/necessary. Once the server is started, it runs *
* forever. *
* *
* *
* Organization: *
* *
@@ -44,12 +31,6 @@
* is complete, the session task deletes itself. The daemon still *
* runs, however. *
* *
* Implementation Notes: *
* *
* The 'current working directory' implementation utilizes the *
* RTEMS filesystem cwd. This is no good since other processes *
* inherit the same cwd. *
* *
* *
* Supported commands are: *
* *
@@ -70,51 +51,34 @@
* and port (x*256 + y). *
* *
* *
* *
* The public routines contained in this file are: *
* *
* FTPD_Start - Starts the server daemon, then returns to its caller. *
* rtems_initialize_ftpd_start - Starts the server daemon, then *
* returns to its caller. *
* *
* *
* The private routines contained in this file are: *
* *
* FTPD_SendReply - Sends a reply code and text through the control *
* port. *
* FTPD_CommandStore - Performs the "STOR" command. *
* FTPD_CommandList - Performs the "LIST" command. *
* FTPD_CommandPort - Opens a data port (the "PORT" command). *
* FTPD_ParseCommand - Parses an incoming command. *
* FTPD_Session - Begins a service session. *
* FTPD_Daemon - Listens on the FTP port for service requests. *
* *
* *
* rtems_ftpd_send_reply - Sends a reply code and text through the *
* control port. *
* rtems_ftpd_command_retrieve - Performs to "RETR" command. *
* rtems_ftpd_command_store - Performs the "STOR" command. *
* rtems_ftpd_command_list - Performs the "LIST" command. *
* rtems_ftpd_command_port - Opens a data port (the "PORT" command). *
* rtems_ftpd_parse_command - Parses an incoming command. *
* rtmes_ftpd_session - Begins a service session. *
* rtems_ftpd_daemon - Listens on the FTP port for service *
* requests. *
*------------------------------------------------------------------------*
* *
* Jake Janovetz *
* University of Illinois *
* 1406 West Green Street *
* Urbana IL 61801 *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
/* Revision Control Information:
*
* $Source$
* $Id$
* $Log$
* Revision 1.3 1998/05/19 21:28:17 erithacus
* Update control socket to file I/O.
*
* Revision 1.2 1998/05/19 20:13:50 erithacus
* Remodeled to be entirely reentrant.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -133,9 +97,10 @@
#include <netinet/in.h>
#include "ftpd.h"
#include "untar.h"
extern struct rtems_ftpd_configuration rtems_ftpd_configuration;
/**************************************************************************
* Meanings of first and second digits of reply codes:
*
@@ -163,14 +128,6 @@
*************************************************************************/
/**************************************************************************
* Maximum buffer size for use by the transfer protocol.
* This will be eliminated when the filesystem is complete enough that
* we don't have to store the received data until we have something to
* do with it.
*************************************************************************/
#define FTPD_MAX_RECEIVESIZE (512*1024)
/**************************************************************************
* SessionInfo structure.
*
@@ -180,13 +137,14 @@
typedef struct
{
struct sockaddr_in data_addr; /* Data address for PORT commands */
int ctrl_sock; /* Control connection socker */
FILE *ctrl_fp; /* File pointer for control connection */
char cwd[255]; /* Current working directory */
/* Login -- future use -- */
int xfer_mode; /* Transfer mode (ASCII/binary) */
} FTPD_SessionInfo_t;
#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready."
#define FTPD_WELCOME_MESSAGE \
"Welcome to the RTEMS FTP server.\n" \
"\n" \
@@ -194,7 +152,7 @@ typedef struct
/**************************************************************************
* Function: FTPD_SendReply *
* Function: rtems_ftpd_send_reply *
**************************************************************************
* Description: *
* *
@@ -216,7 +174,7 @@ typedef struct
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_SendReply(int code, char *text)
rtems_ftpd_send_reply(int code, char *text)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -241,17 +199,19 @@ FTPD_SendReply(int code, char *text)
if (text != NULL)
{
sprintf(str, "%d %.70s\r\n", code, text);
fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
}
else
{
sprintf(str, "%d\r\n", code);
fprintf(info->ctrl_fp, "%d\r\n", code);
}
send(info->ctrl_sock, str, strlen(str), 0);
fflush(info->ctrl_fp);
}
/**************************************************************************
* Function: FTPD_CommandRetrieve *
* Function: rtems_ftpd_command_retrieve *
**************************************************************************
* Description: *
* *
@@ -274,12 +234,11 @@ FTPD_SendReply(int code, char *text)
* 04/29/98 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandRetrieve(char *filename)
rtems_ftpd_command_retrieve(char *filename)
{
int s;
int n;
FILE *fp;
int fd;
unsigned char *bufr;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -288,32 +247,31 @@ FTPD_CommandRetrieve(char *filename)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if ((fp = fopen(filename, "r")) == NULL)
if ((fd = open(filename, O_RDONLY)) == -1)
{
FTPD_SendReply(450, "Error opening file.");
rtems_ftpd_send_reply(450, "Error opening file.");
return(0);
}
bufr = (unsigned char *)malloc(BUFSIZ);
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
fclose(fp);
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
close(fd);
return(0);
}
/***********************************************************************
* Connect to the data connection (PORT made in an earlier PORT call).
**********************************************************************/
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
FTPD_SendReply(420, "Server error - could not connect socket.");
rtems_ftpd_send_reply(420, "Server error - could not connect socket.");
free(bufr);
fclose(fp);
close(fd);
close(s);
return(1);
}
@@ -321,18 +279,19 @@ FTPD_CommandRetrieve(char *filename)
/***********************************************************************
* Send the data over the ether.
**********************************************************************/
while ((n = fread(bufr, 1, BUFSIZ, fp)) != 0)
while ((n = read(fd, bufr, BUFSIZ)) > 0)
{
send(s, bufr, n, 0);
bufr[n-1] = '\0';
}
if (feof(fp))
if (n == 0)
{
FTPD_SendReply(210, "File sent successfully.");
rtems_ftpd_send_reply(210, "File sent successfully.");
}
else
{
FTPD_SendReply(450, "Retrieve failed.");
rtems_ftpd_send_reply(450, "Retrieve failed.");
}
if (close(s) != 0)
@@ -341,13 +300,13 @@ FTPD_CommandRetrieve(char *filename)
}
free(bufr);
fclose(fp);
close(fd);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandStore *
* Function: rtems_ftpd_command_store *
**************************************************************************
* Description: *
* *
@@ -370,15 +329,15 @@ FTPD_CommandRetrieve(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static int
FTPD_CommandStore(char *filename)
rtems_ftpd_command_store(char *filename)
{
char *bufr;
char *bigBufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
char *bufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
struct rtems_ftpd_hook *usehook = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
@@ -387,26 +346,17 @@ FTPD_CommandStore(char *filename)
bufr = (char *)malloc(BUFSIZ * sizeof(char));
if (bufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
return(1);
}
bigBufr = (char *)malloc(FTPD_MAX_RECEIVESIZE * sizeof(char));
if (bigBufr == NULL)
{
FTPD_SendReply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
FTPD_SendReply(150, "BINARY data connection.");
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
free(bufr);
free(bigBufr);
close(s);
return(1);
}
@@ -414,22 +364,57 @@ FTPD_CommandStore(char *filename)
/***********************************************************************
* File: "/dev/null" just throws the data away.
* Otherwise, search our list of hooks to see if we need to do something
* special.
**********************************************************************/
if (!strncmp("/dev/null", filename, 9))
{
while ((n = read(s, bufr, BUFSIZ)) > 0);
}
else
else if (rtems_ftpd_configuration.hooks != NULL)
{
struct rtems_ftpd_hook *hook;
int i;
i = 0;
hook = &rtems_ftpd_configuration.hooks[i++];
while (hook->filename != NULL)
{
if (!strcmp(hook->filename, filename))
{
usehook = hook;
break;
}
hook = &rtems_ftpd_configuration.hooks[i++];
}
}
if (usehook != NULL)
{
char *bigBufr;
/***********************************************************************
* Allocate space for our "file".
**********************************************************************/
bigBufr = (char *)malloc(
rtems_ftpd_configuration.max_hook_filesize * sizeof(char));
if (bigBufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
/***********************************************************************
* Retrieve the file into our buffer space.
**********************************************************************/
size = 0;
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
if (size + n > FTPD_MAX_RECEIVESIZE)
if (size + n >
rtems_ftpd_configuration.max_hook_filesize * sizeof(char))
{
FTPD_SendReply(440, "Server error - Buffer size exceeded.");
rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded.");
free(bufr);
free(bigBufr);
close(s);
@@ -438,66 +423,60 @@ FTPD_CommandStore(char *filename)
memcpy(&bigBufr[size], bufr, n);
size += n;
}
}
free(bufr);
close(s);
close(s);
/***********************************************************************
* Figure out what to do with the data we just received.
**********************************************************************/
if (!strncmp("untar", filename, 5))
{
Untar_FromMemory(bigBufr, size);
FTPD_SendReply(210, "Untar successful.");
}
else
{
FILE *fp;
size_t len;
size_t written;
fp = fopen(filename, "w");
if (fp == NULL)
/***********************************************************************
* Call our hook.
**********************************************************************/
if ((usehook->hook_function)(bigBufr, size) == 0)
{
FTPD_SendReply(440, "Could not open file.");
free(bigBufr);
return(1);
}
n = 0;
written = 0;
while (n<size)
{
len = ((size-n>BUFSIZ)?(BUFSIZ):(size-n));
written = fwrite(&bigBufr[n], 1, len, fp);
n += written;
if (written != len)
{
break;
}
}
fclose(fp);
if (n == size)
{
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(210, "File transferred successfully.");
}
else
{
FTPD_SendReply(440, "Error during write.");
free(bigBufr);
rtems_ftpd_send_reply(440, "File transfer failed.");
}
free(bigBufr);
}
else
{
int fd;
size_t written;
fd = creat(filename, S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH);
if (fd == -1)
{
rtems_ftpd_send_reply(450, "Could not open file.");
close(s);
free(bufr);
return(1);
}
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
written = write(fd, bufr, n);
if (written == -1)
{
rtems_ftpd_send_reply(450, "Error during write.");
close(fd);
close(s);
free(bufr);
return(1);
}
}
close(fd);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
}
free(bigBufr);
free(bufr);
return(0);
}
/**************************************************************************
* Function: FTPD_CommandList *
* Function: rtems_ftpd_command_list *
**************************************************************************
* Description: *
* *
@@ -518,7 +497,7 @@ FTPD_CommandStore(char *filename)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandList(char *fname)
rtems_ftpd_command_list(char *fname)
{
int s;
rtems_status_code sc;
@@ -532,7 +511,7 @@ FTPD_CommandList(char *fname)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(150, "ASCII data connection for LIST.");
rtems_ftpd_send_reply(150, "ASCII data connection for LIST.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
@@ -548,7 +527,7 @@ FTPD_CommandList(char *fname)
fname, (info->xfer_mode==TYPE_A)?("\r"):(""));
send(s, dirline, strlen(dirline), 0);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
return;
}
while ((dp = readdir(dirp)) != NULL)
@@ -578,7 +557,7 @@ FTPD_CommandList(char *fname)
closedir(dirp);
close(s);
FTPD_SendReply(226, "Transfer complete.");
rtems_ftpd_send_reply(226, "Transfer complete.");
}
@@ -586,7 +565,7 @@ FTPD_CommandList(char *fname)
* Cheesy way to change directories
*/
static void
FTPD_CWD(char *dir)
rtems_ftpd_CWD(char *dir)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
@@ -597,17 +576,17 @@ FTPD_CWD(char *dir)
if (chdir(dir) == 0)
{
FTPD_SendReply(250, "CWD command successful.");
rtems_ftpd_send_reply(250, "CWD command successful.");
}
else
{
FTPD_SendReply(550, "CWD command failed.");
rtems_ftpd_send_reply(550, "CWD command failed.");
}
}
/**************************************************************************
* Function: FTPD_CommandPort *
* Function: rtems_ftpd_command_port *
**************************************************************************
* Description: *
* *
@@ -630,7 +609,7 @@ FTPD_CWD(char *dir)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_CommandPort(char *bufr)
rtems_ftpd_command_port(char *bufr)
{
char *ip;
char *port;
@@ -656,13 +635,15 @@ FTPD_CommandPort(char *bufr)
/**************************************************************************
* Function: FTPD_ParseCommand *
* Function: rtems_ftpd_parse_command *
**************************************************************************
* Description: *
* *
* Here, we parse the commands that have come through the control *
* connection. *
* *
* FIXME: This section is somewhat of a hack. We should have a better *
* way to parse commands. *
* *
* Inputs: *
* *
@@ -678,7 +659,7 @@ FTPD_CommandPort(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_ParseCommand(char *bufr)
rtems_ftpd_parse_command(char *bufr)
{
char fname[255];
rtems_status_code sc;
@@ -690,71 +671,71 @@ FTPD_ParseCommand(char *bufr)
if (!strncmp("PORT", bufr, 4))
{
FTPD_SendReply(200, "PORT command successful.");
FTPD_CommandPort(&bufr[5]);
rtems_ftpd_send_reply(200, "PORT command successful.");
rtems_ftpd_command_port(&bufr[5]);
}
else if (!strncmp("RETR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandRetrieve(fname);
rtems_ftpd_command_retrieve(fname);
}
else if (!strncmp("STOR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandStore(fname);
rtems_ftpd_command_store(fname);
}
else if (!strncmp("LIST", bufr, 4))
{
if (bufr[5] == '\n')
{
FTPD_CommandList(".");
rtems_ftpd_command_list(".");
}
else
{
sscanf(&bufr[5], "%254s", fname);
FTPD_CommandList(fname);
rtems_ftpd_command_list(fname);
}
}
else if (!strncmp("USER", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("SYST", bufr, 4))
{
FTPD_SendReply(240, "RTEMS");
rtems_ftpd_send_reply(240, "RTEMS");
}
else if (!strncmp("TYPE", bufr, 4))
{
if (bufr[5] == 'I')
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(200, "Type set to I.");
rtems_ftpd_send_reply(200, "Type set to I.");
}
else if (bufr[5] == 'A')
{
info->xfer_mode = TYPE_A;
FTPD_SendReply(200, "Type set to A.");
rtems_ftpd_send_reply(200, "Type set to A.");
}
else
{
info->xfer_mode = TYPE_I;
FTPD_SendReply(504, "Type not implemented. Set to I.");
rtems_ftpd_send_reply(504, "Type not implemented. Set to I.");
}
}
else if (!strncmp("PASS", bufr, 4))
{
FTPD_SendReply(230, "User logged in.");
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("DELE", bufr, 4))
{
sscanf(&bufr[4], "%254s", fname);
if (unlink(fname) == 0)
{
FTPD_SendReply(257, "DELE successful.");
rtems_ftpd_send_reply(257, "DELE successful.");
}
else
{
FTPD_SendReply(550, "DELE failed.");
rtems_ftpd_send_reply(550, "DELE failed.");
}
}
else if (!strncmp("SITE CHMOD", bufr, 10))
@@ -764,11 +745,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[11], "%o %254s", &mask, fname);
if (chmod(fname, (mode_t)mask) == 0)
{
FTPD_SendReply(257, "CHMOD successful.");
rtems_ftpd_send_reply(257, "CHMOD successful.");
}
else
{
FTPD_SendReply(550, "CHMOD failed.");
rtems_ftpd_send_reply(550, "CHMOD failed.");
}
}
else if (!strncmp("RMD", bufr, 3))
@@ -776,11 +757,11 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (rmdir(fname) == 0)
{
FTPD_SendReply(257, "RMD successful.");
rtems_ftpd_send_reply(257, "RMD successful.");
}
else
{
FTPD_SendReply(550, "RMD failed.");
rtems_ftpd_send_reply(550, "RMD failed.");
}
}
else if (!strncmp("MKD", bufr, 3))
@@ -788,33 +769,34 @@ FTPD_ParseCommand(char *bufr)
sscanf(&bufr[4], "%254s", fname);
if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
{
FTPD_SendReply(257, "MKD successful.");
rtems_ftpd_send_reply(257, "MKD successful.");
}
else
{
FTPD_SendReply(550, "MKD failed.");
rtems_ftpd_send_reply(550, "MKD failed.");
}
}
else if (!strncmp("CWD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
FTPD_CWD(fname);
rtems_ftpd_CWD(fname);
}
else if (!strncmp("PWD", bufr, 3))
{
char *cwd = getcwd(0, 0);
sprintf(bufr, "\"%s\" is the current directory.", cwd);
FTPD_SendReply(250, bufr);
rtems_ftpd_send_reply(250, bufr);
free(cwd);
}
else
{
FTPD_SendReply(500, "Unrecognized/unsupported command.");
rtems_ftpd_send_reply(500, "Unrecognized/unsupported command.");
}
}
/**************************************************************************
* Function: FTPD_Session *
* Function: rtems_ftpd_session *
**************************************************************************
* Description: *
* *
@@ -827,7 +809,7 @@ FTPD_ParseCommand(char *bufr)
* *
* Inputs: *
* *
* rtems_task_argument arg - The FTPD_Daemon task passes the socket *
* rtems_task_argument arg - The daemon task passes the socket *
* which serves as the control connection. *
* *
* Output: *
@@ -839,7 +821,7 @@ FTPD_ParseCommand(char *bufr)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Session(rtems_task_argument arg)
rtems_ftpd_session(rtems_task_argument arg)
{
char cmd[256];
rtems_status_code sc;
@@ -849,7 +831,7 @@ FTPD_Session(rtems_task_argument arg)
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
FTPD_SendReply(220, "Erithacus FTP server (Version 1.0) ready.");
rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE);
/***********************************************************************
* Set initial directory to "/".
@@ -858,7 +840,7 @@ FTPD_Session(rtems_task_argument arg)
info->xfer_mode = TYPE_A;
while (1)
{
if (recv(info->ctrl_sock, cmd, 256, 0) == -1)
if (fgets(cmd, 256, info->ctrl_fp) == NULL)
{
syslog(LOG_INFO, "ftpd: Connection aborted.");
break;
@@ -866,16 +848,16 @@ FTPD_Session(rtems_task_argument arg)
if (!strncmp("QUIT", cmd, 4))
{
FTPD_SendReply(221, "Goodbye.");
rtems_ftpd_send_reply(221, "Goodbye.");
break;
}
else
{
FTPD_ParseCommand(cmd);
rtems_ftpd_parse_command(cmd);
}
}
if (close(info->ctrl_sock) < 0)
if (fclose(info->ctrl_fp) != 0)
{
syslog(LOG_ERR, "ftpd: Could not close session.");
}
@@ -895,7 +877,7 @@ FTPD_Session(rtems_task_argument arg)
/**************************************************************************
* Function: FTPD_Daemon *
* Function: rtems_ftpd_daemon *
**************************************************************************
* Description: *
* *
@@ -918,7 +900,7 @@ FTPD_Session(rtems_task_argument arg)
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
FTPD_Daemon()
rtems_ftpd_daemon()
{
int s;
int s1;
@@ -941,7 +923,7 @@ FTPD_Daemon()
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = FTPD_CONTROL_PORT;
localAddr.sin_port = htons(rtems_ftpd_configuration.port);
localAddr.sin_addr.s_addr = INADDR_ANY;
memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero));
if (bind(s, (struct sockaddr *)&localAddr,
@@ -1002,21 +984,28 @@ FTPD_Daemon()
/********************************************************************
* Send the socket on to the new session.
*******************************************************************/
info->ctrl_sock = s1;
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, FTPD_Session, 0);
if (sc != RTEMS_SUCCESSFUL)
if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
syslog(LOG_ERR, "ftpd: fdopen() on socket failed.");
close(s1);
}
else
{
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, rtems_ftpd_session, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
}
}
}
}
/**************************************************************************
* Function: FTPD_Start *
* Function: rtems_ftpd_start *
**************************************************************************
* Description: *
* *
@@ -1031,21 +1020,33 @@ FTPD_Daemon()
* *
* Output: *
* *
* none *
* int - RTEMS_SUCCESSFUL on successful start of the daemon. *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
void
FTPD_Start(rtems_task_priority priority)
int
rtems_initialize_ftpd()
{
rtems_status_code sc;
rtems_id tid;
if (rtems_ftpd_configuration.port == 0)
{
rtems_ftpd_configuration.port = FTPD_CONTROL_PORT;
}
/***********************************************************************
* Default FTPD priority.
**********************************************************************/
if (rtems_ftpd_configuration.priority == 0)
{
rtems_ftpd_configuration.priority = 40;
}
sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
priority, 8*1024,
rtems_ftpd_configuration.priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
@@ -1054,14 +1055,18 @@ FTPD_Start(rtems_task_priority priority)
{
syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
sc = rtems_task_start(tid, FTPD_Daemon, 0);
sc = rtems_task_start(tid, rtems_ftpd_daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
syslog(LOG_INFO, "ftpd: FTP daemon started.");
return(RTEMS_SUCCESSFUL);
}

View File

@@ -10,17 +10,33 @@
#define FTPD_CONTROL_PORT 21
typedef int (*rtems_ftpd_hookfunction)(unsigned char *, unsigned long);
struct rtems_ftpd_hook
{
char *filename;
rtems_ftpd_hookfunction hook_function;
};
struct rtems_ftpd_configuration
{
rtems_task_priority priority; /* FTPD task priority */
unsigned long max_hook_filesize; /* Maximum buffersize */
/* for hooks */
int port; /* Well-known port */
struct rtems_ftpd_hook *hooks; /* List of hooks */
};
/*
* Reply codes.
*/
#define PRELIM 1 /* positive preliminary */
#define COMPLETE 2 /* positive completion */
#define CONTINUE 3 /* positive intermediate */
#define TRANSIENT 4 /* transient negative completion */
#define ERROR 5 /* permanent negative completion */
void rtems_ftpd_sTart(rtems_task_priority priority);
int rtems_initialize_ftpd();
#endif /* __FTPD_H__ */