From 6d0e13c3bd56e1f158bb8691e6ca244b160616d1 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 16 Mar 1999 01:51:53 +0000 Subject: Added ftpd server from Jake Janovetz . --- cpukit/ftpd/ftpd.c | 1067 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cpukit/ftpd/ftpd.h | 26 ++ 2 files changed, 1093 insertions(+) create mode 100644 cpukit/ftpd/ftpd.c create mode 100644 cpukit/ftpd/ftpd.h (limited to 'cpukit/ftpd') diff --git a/cpukit/ftpd/ftpd.c b/cpukit/ftpd/ftpd.c new file mode 100644 index 0000000000..121a5b7762 --- /dev/null +++ b/cpukit/ftpd/ftpd.c @@ -0,0 +1,1067 @@ +/* + * FTP Server Daemon + * + * Submitted by: Jake Janovetz + * + * $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. * + * * + * Organization: * + * * + * The FTP daemon is started upon boot. It runs all the time * + * and waits for connections on the known FTP port (21). When * + * a connection is made, it starts a 'session' task. That * + * session then interacts with the remote host. When the session * + * 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: * + * * + * RETR xxx - Sends a file from the client. * + * STOR xxx - Receives a file from the client. xxx = filename. * + * LIST xxx - Sends a file list to the client. * + * (LIST xxx isn't working yet...) * + * USER - Does nothing. * + * PASS - Does nothing. * + * SYST - Replies with the system type (`RTEMS'). * + * DELE xxx - Delete file xxx. * + * MKD xxx - Create directory xxx. * + * RMD xxx - Remove directory xxx. * + * PWD - Print working directory. * + * CWD xxx - Change working directory. * + * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx. * + * PORT a,b,c,d,x,y - Setup for a data port to IP address a.b.c.d * + * and port (x*256 + y). * + * * + * * + * * + * The public routines contained in this file are: * + * * + * 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. * + * * + * * + *------------------------------------------------------------------------* + * * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ftpd.h" +#include "untar.h" + + +/************************************************************************** + * Meanings of first and second digits of reply codes: + * + * Reply: Description: + *-------- -------------- + * 1yz Positive preliminary reply. The action is being started but + * expect another reply before sending another command. + * 2yz Positive completion reply. A new command can be sent. + * 3yz Positive intermediate reply. The command has been accpeted + * but another command must be sent. + * 4yz Transient negative completion reply. The requested action did + * not take place, but the error condition is temporary so the + * command can be reissued later. + * 5yz Permanent negative completion reply. The command was not + * accepted and should not be retried. + *------------------------------------------------------------------------- + * x0z Syntax errors. + * x1z Information. + * x2z Connections. Replies referring to the control or data + * connections. + * x3z Authentication and accounting. Replies for the login or + * accounting commands. + * x4z Unspecified. + * x5z Filesystem status. + *************************************************************************/ + + +/************************************************************************** + * 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. + * + * The following structure is allocated for each session. The pointer + * to this structure is contained in the tasks notepad entry. + *************************************************************************/ +typedef struct +{ + struct sockaddr_in data_addr; /* Data address for PORT commands */ + int ctrl_sock; /* Control connection socker */ + char cwd[255]; /* Current working directory */ + /* Login -- future use -- */ + int xfer_mode; /* Transfer mode (ASCII/binary) */ +} FTPD_SessionInfo_t; + + +#define FTPD_WELCOME_MESSAGE \ + "Welcome to the RTEMS FTP server.\n" \ + "\n" \ + "Login accepted.\n" + + +/************************************************************************** + * Function: FTPD_SendReply * + ************************************************************************** + * Description: * + * * + * This procedure sends a reply to the client via the control * + * connection. * + * * + * * + * Inputs: * + * * + * int code - The 3-digit reply code. * + * char *text - Reply text. * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_SendReply(int code, char *text) +{ + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + char str[80]; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + /*********************************************************************** + * code must be a 3-digit number. + **********************************************************************/ + if ((code < 100) || (code > 999)) + { + syslog(LOG_ERR, "ftpd: Code not 3-digits."); + return; + } + + /*********************************************************************** + * If a text reply exists, add it to the reply data. + **********************************************************************/ + if (text != NULL) + { + sprintf(str, "%d %.70s\r\n", code, text); + } + else + { + sprintf(str, "%d\r\n", code); + } + send(info->ctrl_sock, str, strlen(str), 0); +} + + +/************************************************************************** + * Function: FTPD_CommandRetrieve * + ************************************************************************** + * Description: * + * * + * This performs the "RETR" command. A data connection must already * + * be open (via the "PORT" command.) Here, we send the data to the * + * connection. * + * * + * * + * Inputs: * + * * + * char *filename - Source filename. * + * * + * Output: * + * * + * int - 0 for reply sent. * + * 1 for no reply sent. * + * * + ************************************************************************** + * Change History: * + * 04/29/98 - Creation (JWJ) * + *************************************************************************/ +static int +FTPD_CommandRetrieve(char *filename) +{ + int s; + int n; + + FILE *fp; + unsigned char *bufr; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + + if ((fp = fopen(filename, "r")) == NULL) + { + FTPD_SendReply(450, "Error opening file."); + return(0); + } + + bufr = (unsigned char *)malloc(BUFSIZ); + if (bufr == NULL) + { + FTPD_SendReply(440, "Server error - malloc fail."); + fclose(fp); + return(0); + } + + /*********************************************************************** + * Connect to the data connection (PORT made in an earlier PORT call). + **********************************************************************/ + FTPD_SendReply(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."); + free(bufr); + fclose(fp); + close(s); + return(1); + } + + /*********************************************************************** + * Send the data over the ether. + **********************************************************************/ + while ((n = fread(bufr, 1, BUFSIZ, fp)) != 0) + { + send(s, bufr, n, 0); + } + + if (feof(fp)) + { + FTPD_SendReply(210, "File sent successfully."); + } + else + { + FTPD_SendReply(450, "Retrieve failed."); + } + + if (close(s) != 0) + { + syslog(LOG_ERR, "ftpd: Error closing data socket"); + } + + free(bufr); + fclose(fp); + return(0); +} + + +/************************************************************************** + * Function: FTPD_CommandStore * + ************************************************************************** + * Description: * + * * + * This performs the "STOR" command. A data connection must already * + * be open (via the "PORT" command.) Here, we get the data from the * + * connection and figure out what to do with it. * + * * + * * + * Inputs: * + * * + * char *filename - Destination filename. * + * * + * Output: * + * * + * int - 0 for success. * + * 1 for failure. * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static int +FTPD_CommandStore(char *filename) +{ + char *bufr; + char *bigBufr; + int s; + int n; + unsigned long size = 0; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + bufr = (char *)malloc(BUFSIZ * sizeof(char)); + if (bufr == NULL) + { + FTPD_SendReply(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."); + + 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); + } + + + /*********************************************************************** + * File: "/dev/null" just throws the data away. + **********************************************************************/ + if (!strncmp("/dev/null", filename, 9)) + { + while ((n = read(s, bufr, BUFSIZ)) > 0); + } + else + { + /*********************************************************************** + * Retrieve the file into our buffer space. + **********************************************************************/ + size = 0; + while ((n = read(s, bufr, BUFSIZ)) > 0) + { + if (size + n > FTPD_MAX_RECEIVESIZE) + { + FTPD_SendReply(440, "Server error - Buffer size exceeded."); + free(bufr); + free(bigBufr); + close(s); + return(1); + } + memcpy(&bigBufr[size], bufr, n); + size += n; + } + } + free(bufr); + 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) + { + FTPD_SendReply(440, "Could not open file."); + free(bigBufr); + return(1); + } + + n = 0; + written = 0; + while (nBUFSIZ)?(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."); + } + else + { + FTPD_SendReply(440, "Error during write."); + free(bigBufr); + return(1); + } + } + + free(bigBufr); + return(0); +} + + +/************************************************************************** + * Function: FTPD_CommandList * + ************************************************************************** + * Description: * + * * + * Sends a file list through a data connection. The data * + * connection must have already been opened with the "PORT" command. * + * * + * * + * Inputs: * + * * + * char *fname - File (or directory) to list. * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_CommandList(char *fname) +{ + int s; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + DIR *dirp; + struct dirent *dp; + char dirline[255]; + struct stat stat_buf; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + FTPD_SendReply(150, "ASCII data connection for LIST."); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (connect(s, (struct sockaddr *)&info->data_addr, + sizeof(struct sockaddr)) < 0) + { + syslog(LOG_ERR, "ftpd: Error connecting to data socket."); + return; + } + + if ((dirp = opendir(fname)) == NULL) + { + sprintf(dirline, "%s: No such file or directory.%s\n", + fname, (info->xfer_mode==TYPE_A)?("\r"):("")); + send(s, dirline, strlen(dirline), 0); + close(s); + FTPD_SendReply(226, "Transfer complete."); + return; + } + while ((dp = readdir(dirp)) != NULL) + { + if (stat(dp->d_name, &stat_buf) == 0) + { + sprintf(dirline, "%c%c%c%c%c%c%c%c%c%c %5d %5d %11d %s%s\n", + (S_ISLNK(stat_buf.st_mode)?('l'): + (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), + (stat_buf.st_mode & S_IRUSR)?('r'):('-'), + (stat_buf.st_mode & S_IWUSR)?('w'):('-'), + (stat_buf.st_mode & S_IXUSR)?('x'):('-'), + (stat_buf.st_mode & S_IRGRP)?('r'):('-'), + (stat_buf.st_mode & S_IWGRP)?('w'):('-'), + (stat_buf.st_mode & S_IXGRP)?('x'):('-'), + (stat_buf.st_mode & S_IROTH)?('r'):('-'), + (stat_buf.st_mode & S_IWOTH)?('w'):('-'), + (stat_buf.st_mode & S_IXOTH)?('x'):('-'), + (int)stat_buf.st_uid, + (int)stat_buf.st_gid, + (int)stat_buf.st_size, + dp->d_name, + (info->xfer_mode==TYPE_A)?("\r"):("")); + send(s, dirline, strlen(dirline), 0); + } + } + closedir(dirp); + + close(s); + FTPD_SendReply(226, "Transfer complete."); +} + + +/* + * Cheesy way to change directories + */ +static void +FTPD_CWD(char *dir) +{ + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + if (chdir(dir) == 0) + { + FTPD_SendReply(250, "CWD command successful."); + } + else + { + FTPD_SendReply(550, "CWD command failed."); + } +} + + +/************************************************************************** + * Function: FTPD_CommandPort * + ************************************************************************** + * Description: * + * * + * This procedure opens up a data port given the IP address of the * + * remote machine and the port on the remote machine. This connection * + * will then be used to transfer data between the hosts. * + * * + * * + * Inputs: * + * * + * char *bufr - Arguments to the "PORT" command. * + * * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_CommandPort(char *bufr) +{ + char *ip; + char *port; + int ip0, ip1, ip2, ip3, port0, port1; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); + ip = (char *)&(info->data_addr.sin_addr); + ip[0] = ip0 & 0xff; + ip[1] = ip1 & 0xff; + ip[2] = ip2 & 0xff; + ip[3] = ip3 & 0xff; + port = (char *)&(info->data_addr.sin_port); + port[0] = port0 & 0xff; + port[1] = port1 & 0xff; + info->data_addr.sin_family = AF_INET; +} + + +/************************************************************************** + * Function: FTPD_ParseCommand * + ************************************************************************** + * Description: * + * * + * Here, we parse the commands that have come through the control * + * connection. * + * * + * * + * Inputs: * + * * + * char *bufr - Pointer to the buffer which contains the command * + * text. * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_ParseCommand(char *bufr) +{ + char fname[255]; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + if (!strncmp("PORT", bufr, 4)) + { + FTPD_SendReply(200, "PORT command successful."); + FTPD_CommandPort(&bufr[5]); + } + else if (!strncmp("RETR", bufr, 4)) + { + sscanf(&bufr[5], "%254s", fname); + FTPD_CommandRetrieve(fname); + } + else if (!strncmp("STOR", bufr, 4)) + { + sscanf(&bufr[5], "%254s", fname); + FTPD_CommandStore(fname); + } + else if (!strncmp("LIST", bufr, 4)) + { + if (bufr[5] == '\n') + { + FTPD_CommandList("."); + } + else + { + sscanf(&bufr[5], "%254s", fname); + FTPD_CommandList(fname); + } + } + else if (!strncmp("USER", bufr, 4)) + { + FTPD_SendReply(230, "User logged in."); + } + else if (!strncmp("SYST", bufr, 4)) + { + FTPD_SendReply(240, "RTEMS"); + } + else if (!strncmp("TYPE", bufr, 4)) + { + if (bufr[5] == 'I') + { + info->xfer_mode = TYPE_I; + FTPD_SendReply(200, "Type set to I."); + } + else if (bufr[5] == 'A') + { + info->xfer_mode = TYPE_A; + FTPD_SendReply(200, "Type set to A."); + } + else + { + info->xfer_mode = TYPE_I; + FTPD_SendReply(504, "Type not implemented. Set to I."); + } + } + else if (!strncmp("PASS", bufr, 4)) + { + FTPD_SendReply(230, "User logged in."); + } + else if (!strncmp("DELE", bufr, 4)) + { + sscanf(&bufr[4], "%254s", fname); + if (unlink(fname) == 0) + { + FTPD_SendReply(257, "DELE successful."); + } + else + { + FTPD_SendReply(550, "DELE failed."); + } + } + else if (!strncmp("SITE CHMOD", bufr, 10)) + { + int mask; + + sscanf(&bufr[11], "%o %254s", &mask, fname); + if (chmod(fname, (mode_t)mask) == 0) + { + FTPD_SendReply(257, "CHMOD successful."); + } + else + { + FTPD_SendReply(550, "CHMOD failed."); + } + } + else if (!strncmp("RMD", bufr, 3)) + { + sscanf(&bufr[4], "%254s", fname); + if (rmdir(fname) == 0) + { + FTPD_SendReply(257, "RMD successful."); + } + else + { + FTPD_SendReply(550, "RMD failed."); + } + } + else if (!strncmp("MKD", bufr, 3)) + { + sscanf(&bufr[4], "%254s", fname); + if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) + { + FTPD_SendReply(257, "MKD successful."); + } + else + { + FTPD_SendReply(550, "MKD failed."); + } + } + else if (!strncmp("CWD", bufr, 3)) + { + sscanf(&bufr[4], "%254s", fname); + 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); + free(cwd); + } + else + { + FTPD_SendReply(500, "Unrecognized/unsupported command."); + } +} + +/************************************************************************** + * Function: FTPD_Session * + ************************************************************************** + * Description: * + * * + * This task is started when the FTP daemon gets a service request * + * from a remote machine. Here, we watch for commands that will * + * come through the "control" connection. These commands are then * + * parsed and executed until the connection is closed, either * + * unintentionally or intentionally with the "QUIT" command. * + * * + * * + * Inputs: * + * * + * rtems_task_argument arg - The FTPD_Daemon task passes the socket * + * which serves as the control connection. * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_Session(rtems_task_argument arg) +{ + char cmd[256]; + rtems_status_code sc; + FTPD_SessionInfo_t *info = NULL; + + + sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, + (rtems_unsigned32 *)&info); + + FTPD_SendReply(220, "Erithacus FTP server (Version 1.0) ready."); + + /*********************************************************************** + * Set initial directory to "/". + **********************************************************************/ + strcpy(info->cwd, "/"); + info->xfer_mode = TYPE_A; + while (1) + { + if (recv(info->ctrl_sock, cmd, 256, 0) == -1) + { + syslog(LOG_INFO, "ftpd: Connection aborted."); + break; + } + + if (!strncmp("QUIT", cmd, 4)) + { + FTPD_SendReply(221, "Goodbye."); + break; + } + else + { + FTPD_ParseCommand(cmd); + } + } + + if (close(info->ctrl_sock) < 0) + { + syslog(LOG_ERR, "ftpd: Could not close session."); + } + + + /* Least we can do is put the CWD back to /. */ + chdir("/"); + + /*********************************************************************** + * Free up the allocated SessionInfo struct and exit. + **********************************************************************/ + free(info); + sc = rtems_task_delete(RTEMS_SELF); + syslog(LOG_ERR, "ftpd: Task deletion failed: %s", + rtems_status_text(sc)); +} + + +/************************************************************************** + * Function: FTPD_Daemon * + ************************************************************************** + * Description: * + * * + * This task runs in the background forever. It waits for service * + * requests on the FTP port (port 21). When a request is received, * + * it opens a new session to handle those requests until the * + * connection is closed. * + * * + * * + * Inputs: * + * * + * none * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +static void +FTPD_Daemon() +{ + int s; + int s1; + int addrLen; + struct sockaddr_in remoteAddr; + struct sockaddr_in localAddr; + char sessionID; + rtems_task_priority priority; + rtems_status_code sc; + rtems_id tid; + FTPD_SessionInfo_t *info = NULL; + + + sessionID = 'a'; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + { + perror("Creating socket"); + } + + localAddr.sin_family = AF_INET; + localAddr.sin_port = FTPD_CONTROL_PORT; + localAddr.sin_addr.s_addr = INADDR_ANY; + memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero)); + if (bind(s, (struct sockaddr *)&localAddr, + sizeof(localAddr)) < 0) + { + perror("Binding control socket"); + } + + if (listen(s, 2) < 0) + { + perror("Listening on control socket"); + } + + while (1) + { + /******************************************************************** + * Allocate a SessionInfo structure for the session task. + *******************************************************************/ + info = (FTPD_SessionInfo_t *)malloc(sizeof(FTPD_SessionInfo_t)); + if (info == NULL) + { + syslog(LOG_ERR, "ftpd: Could not allocate session info struct."); + rtems_panic("Malloc fail."); + } + + /******************************************************************** + * Accept on the socket and start the session task. + *******************************************************************/ + addrLen = sizeof(remoteAddr); + s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrLen); + if (s1 < 0) + { + perror("Accepting control connection"); + } + + rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); + sc = rtems_task_create(rtems_build_name('F', 'T', 'P', sessionID), + priority, 8*1024, + RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | + RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), + RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, + &tid); + if (sc != RTEMS_SUCCESSFUL) + { + syslog(LOG_ERR, "ftpd: Could not create FTPD session: %s", + rtems_status_text(sc)); + } + + if (sessionID == 'z') + { + sessionID = 'a'; + } + else + { + sessionID++; + } + + /******************************************************************** + * 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) + { + syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s", + rtems_status_text(sc)); + } + } +} + + +/************************************************************************** + * Function: FTPD_Start * + ************************************************************************** + * Description: * + * * + * Here, we start the FTPD task which waits for FTP requests and * + * services them. This procedure returns to its caller once the * + * task is started. * + * * + * * + * Inputs: * + * * + * rtems_task_priority priority - Priority to assign to this task. * + * * + * Output: * + * * + * none * + * * + ************************************************************************** + * Change History: * + * 12/01/97 - Creation (JWJ) * + *************************************************************************/ +void +FTPD_Start(rtems_task_priority priority) +{ + rtems_status_code sc; + rtems_id tid; + + + sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), + priority, 8*1024, + RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | + RTEMS_INTERRUPT_LEVEL(0), + RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, + &tid); + if (sc != RTEMS_SUCCESSFUL) + { + syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s", + rtems_status_text(sc)); + } + + sc = rtems_task_start(tid, FTPD_Daemon, 0); + if (sc != RTEMS_SUCCESSFUL) + { + syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s", + rtems_status_text(sc)); + } + + syslog(LOG_INFO, "ftpd: FTP daemon started."); +} diff --git a/cpukit/ftpd/ftpd.h b/cpukit/ftpd/ftpd.h new file mode 100644 index 0000000000..56bae5a043 --- /dev/null +++ b/cpukit/ftpd/ftpd.h @@ -0,0 +1,26 @@ +/* + * FTP Server Information + * + * $Id$ + */ + +#ifndef __FTPD_H__ +#define __FTPD_H__ + + +#define FTPD_CONTROL_PORT 21 + +/* + * 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); + +#endif /* __FTPD_H__ */ + -- cgit v1.2.3