From e82f3f21bff1cf021e036ce3e67d5cc12eb41ebe Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 4 Feb 2012 21:02:45 +0000 Subject: Add the beginnings of an FTP server git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4368 42af7a65-404d-4744-a932-0658087f49c3 --- apps/ChangeLog.txt | 4 + apps/examples/ftpd/ftpd_main.c | 72 + apps/include/netutils/ftpd.h | 187 ++ apps/netutils/ftpd/ftpd.c | 4523 ++++++++++++++++++++++++++++++++++++++++ apps/netutils/ftpd/ftpd.h | 204 ++ 5 files changed, 4990 insertions(+) create mode 100755 apps/examples/ftpd/ftpd_main.c create mode 100755 apps/include/netutils/ftpd.h create mode 100755 apps/netutils/ftpd/ftpd.c create mode 100755 apps/netutils/ftpd/ftpd.h (limited to 'apps') diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 543fea929..78011ef84 100755 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -180,4 +180,8 @@ * apps/system/readline: Moved the old nuttx/lib/stdio/lib_fgets.c here and renamed it as readline(). The old fgets was simplied and the overloaded readline functionality was removed. + * apps/netutils/ftpd: Add an FTPD server (does not even compile on initial + checkin). + * apps/examples/ftpd: Add a test for the FTPD server (untest on initial + check-in). diff --git a/apps/examples/ftpd/ftpd_main.c b/apps/examples/ftpd/ftpd_main.c new file mode 100755 index 000000000..b5f81f975 --- /dev/null +++ b/apps/examples/ftpd/ftpd_main.c @@ -0,0 +1,72 @@ +#include "ftpd.h" + +struct fptd_account_s +{ + uint8_t flags; + FAR const char *user; + FAR const char *password; + FAR const char *home; +} + +static const struct fptd_account_s g_ftpdaccounts[] = +{ + { FTPD_ACCOUNTFLAG_SYSTEM, "root", "abc123", NULL) }, + { FTPD_ACCOUNTFLAG_GUEST, "ftp", NULL, NULL }, + { FTPD_ACCOUNTFLAG_GUEST, "anonymous", NULL, NULL }, +}; +#define NACCOUNTS (sizeof(g_ftpdaccounts) / sizeof(struct fptd_account_s)) + +static void ftpd_accounts(FTPD_SESSION handle) +{ + FAR onst struct fptd_account_s *account; + int i; + + for (i = 0; i < NACCOUNTS; i++) + { + account = &g_ftpdaccounts[i]; + ftpd_add_user(handle, account->flags, account->user, account->password, account->home); + } +} + +int ftpd_main(int s_argc, char **s_argv) +{ + FTPD_SESSION handle; + int ret; + + /* Bring up the network */ + + ret = ftpd_netinit(); + if (ret < 0) + { + ndbg("Failed to initialize the network\n"); + return EXIT_FAILURE; + } + + /* Open FTPD */ + + handle = ftpd_open(); + if (!handle) + { + ndbg("Failed to open FTPD\n"); + return EXIT_FAILURE; + } + + /* Configure acounts */ + + (void)ftpd_accounts(handle); + + /* Then drive the FTPD server */ + + while (g_ftpd_break == 0) + { + (void)ftpd_run(handle, 1000); + } + + /* Close the FTPD server and exit */ + + ftpd_close(handle); + return EXIT_SUCCESS; +} + +/* vim: set expandtab: */ +/* End of source */ diff --git a/apps/include/netutils/ftpd.h b/apps/include/netutils/ftpd.h new file mode 100755 index 000000000..870b5cf94 --- /dev/null +++ b/apps/include/netutils/ftpd.h @@ -0,0 +1,187 @@ +/**************************************************************************** + * apps/include/netutils/ftpd.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_INCLUDE_NETUTILS_FTPD_H +#define __APPS_INCLUDE_NETUTILS_FTPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifdef CONFIG_DISABLE_PTHREAD +# error "pthread support is required (CONFIG_DISABLE_PTHREAD=n)" +#endif + +#ifndef CONFIG_FTPD_VENDORID +# define CONFIG_FTPD_VENDORID "NuttX" +#endif + +#ifndef CONFIG_FTPD_SERVERID +# define CONFIG_FTPD_SERVERID "NuttX FTP Server" +#endif + +#ifndef CONFIG_FTPD_CMDBUFFERSIZE +# define CONFIG_FTPD_CMDBUFFERSIZE 512 +#endif + +#ifndef CONFIG_FTPD_DATABUFFERSIZE +# define CONFIG_FTPD_DATABUFFERSIZE 2048 +#endif + +#ifndef CONFIG_FTPD_WORKERSTACKSIZE +# define CONFIG_FTPD_WORKERSTACKSIZE 2048 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This "handle" describes the FTP session */ + +typedef FAR void *FTPD_SESSION; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpd_open + * + * Description: + * Create an instance of the FTPD server and return a handle that can be + * used to run the server. + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL handle is returned that can be used to reference + * the server instance. + * + ****************************************************************************/ + +EXTERN FTPD_SESSION ftpd_open(void); + +/**************************************************************************** + * Name: ftpd_adduser + * + * Description: + * Add one FTP user. + * + * Input Parameters: + * handle - A handle previously returned by ftpd_open + * accountflags - The characteristics of this user (see FTPD_ACCOUNTFLAGS_* + * defintiions. + * user - The user login name. May be NULL indicating that no login is + * required. + * passwd - The user password. May be NULL indicating that no password + * is required. + * home - The user home directory. May be NULL. + * + * Returned Value: + * Zero is returned on success. A negated errno value is return on + * failure. + * + ****************************************************************************/ + +EXTERN int ftpd_adduser(FTPD_SESSION handle, uint8_t accountflags, + FAR const char *user, FAR const char *passwd, + FAR const char *home); + +/**************************************************************************** + * Name: ftpd_session + * + * Description: + * Execute the FTPD server. This thread does not return until either (1) + * the timeout expires with no connection, (2) some other error occurs, or + * (2) a connection was accepted and an FTP worker thread was started to + * service the session. Each call to ftpd_session creates on session. + * + * Input Parameters: + * handle - A handle previously returned by ftpd_open + * timeout - A time in milliseconds to wait for a connection. If this + * time elapses with no connected, the -ETIMEDOUT error will be returned. + * + * Returned Value: + * Zero is returned if the FTP worker was started. On failure, a negated + * errno value is returned to indicate why the servier terminated. + * -ETIMEDOUT indicates that the user-provided timeout elapsed with no + * connection. + * + ****************************************************************************/ + +EXTERN int ftpd_session(FTPD_SESSION handle, int timeout); + +/**************************************************************************** + * Name: ftpd_close + * + * Description: + * Close and destroy the handle created by ftpd_open. + * + * Input Parameters: + * handle - A handle previously returned by ftpd_open + * + * Returned Value: + * None + * + ****************************************************************************/ + +EXTERN void ftpd_close(FTPD_SESSION handle); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __APPS_INCLUDE_NETUTILS_FTPD_H */ diff --git a/apps/netutils/ftpd/ftpd.c b/apps/netutils/ftpd/ftpd.c new file mode 100755 index 000000000..fa15afeec --- /dev/null +++ b/apps/netutils/ftpd/ftpd.c @@ -0,0 +1,4523 @@ +/**************************************************************************** + * apps/n etutils/ftpd.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Includes original code as well as logic adapted from hwport_ftpd, written + * by Jaehyuk Cho which is released under a BSD license. + * + * Copyright (C) HWPORT.COM. All rights reserved. + * Author: JAEHYUK CHO + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include + +#include "ftpd.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* Account functions */ + +static FAR struct ftpd_account_s *ftpd_account_new(FAR const char *user, + uint8_t accountflags); +static void ftpd_account_free(FAR struct ftpd_account_s *account); +static int ftpd_account_setpassord(FAR struct ftpd_account_s *account, + FAR const char *passwd); +static int ftpd_account_add(FAR struct ftpd_server_s *server, + FAR struct ftpd_account_s *account); +static int ftpd_account_sethome(FAR struct ftpd_account_s *account, + FAR const char *home); +static FAR struct ftpd_account_s * + ftpd_account_search_user(FAR struct ftpd_session_s *session, + FAR const char *user, FAR struct ftpd_account_s **dupaccount); +static FAR struct ftpd_account_s * + ftpd_account_login(FAR struct ftpd_session_s *session, + FAR const char *user, FAR const char *passwd); + +/* Parsing functions */ + +static FAR char *ftpd_strtok(bool skipspace, FAR const char *delimiters, + FAR char **str); +static FAR char *ftpd_strtok_alloc(bool skipspace, + FAR const char *delimiters, FAR const char **str); +static int ftpd_patternmatch(FAR const char *pattern, FAR const char *str); + +/* Socket helpers */ + +static int ftpd_getprotocol(FAR const char *protocol) +static int ftpd_rxpoll(int sd, int timeout); +static int ftpd_txpoll(int sd, int timeout); +static int ftpd_accept(int sd, FAR void *addr, FAR socklen_t *addrlen, + int timeout); +static ssize_t ftpd_recv(int sd, FAR void *data, size_t size, int timeout); +static ssize_t ftpd_send(int sd, FAR const void *data, size_t size, + int timeout); +static ssize_t ftpd_response(int sd, int timeout, FAR const char *fmt, ...); + +static int ftpd_dataopen(FAR struct ftpd_session_s *session); +static int ftpd_dataclose(FAR struct ftpd_session_s *session); +static FAR struct ftpd_server_s *ftpd_openserver(int port); + +/* Path helpers */ + +static int ftpd_pathignore(FAR struct ftpd_pathnode_s *currpath); +static void ftpd_nodefree(FAR struct ftpd_pathnode_s *node); +static FAR struct ftpd_pathnode_s *ftpd_path2node(FAR const char *path); +static FAR char *ftpd_node2path(FAR struct ftpd_pathnode_s *node, + bool strip); +static FAR struct ftpd_pathnode_s * + ftpd_nodeappend(FAR struct ftpd_pathnode_s *head, + FAR struct ftpd_pathnode_s *node, bool override); +static int ftpd_getpath(FAR struct ftpd_session_s *session, + FAR const char *chdirectory, FAR char **abspath, + FAR char **workpath); + +/* Commmand helpers */ + +static int ftpd_changedir(FAR struct ftpd_session_s *session, + FAR char *rempath); +static off_t ftpd_offsatoi(FAR const char *filename, off_t offset); +static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype); +static uint8_t ftpd_listoption(FAR char **param); +static int ftpd_listbuffer(FAR struct ftpd_session_s *session, + FAR char *path, FAR struct stat *st, FAR char *buffer, + size_t buflen, unsigned int opton); +static int fptd_listscan(FAR struct ftpd_session_s *session, + FAR char *path, unsigned int opton); +static int ftpd_list(FAR struct ftpd_session_s *session, + unsigned int opton); + +/* Command handlers */ + +static int ftpd_command_user(FAR struct ftpd_session_s *session); +static int ftpd_command_pass(FAR struct ftpd_session_s *session); +static int ftpd_command_syst(FAR struct ftpd_session_s *session); +static int ftpd_command_type(FAR struct ftpd_session_s *session); +static int ftpd_command_mode(FAR struct ftpd_session_s *session); +static int ftpd_command_abor(FAR struct ftpd_session_s *session); +static int ftpd_command_quit(FAR struct ftpd_session_s *session); +static int ftpd_command_noop(FAR struct ftpd_session_s *session); +static int ftpd_command_port(FAR struct ftpd_session_s *session); +static int ftpd_command_eprt(FAR struct ftpd_session_s *session); +static int ftpd_command_pwd(FAR struct ftpd_session_s *session); +static int ftpd_command_cwd(FAR struct ftpd_session_s *session); +static int ftpd_command_cdup(FAR struct ftpd_session_s *session); +static int ftpd_command_rmd(FAR struct ftpd_session_s *session); +static int ftpd_command_mkd(FAR struct ftpd_session_s *session); +static int ftpd_command_dele(FAR struct ftpd_session_s *session); +static int ftpd_command_pasv(FAR struct ftpd_session_s *session); +static int ftpd_command_epsv(FAR struct ftpd_session_s *session); +static int ftpd_command_list(FAR struct ftpd_session_s *session); +static int ftpd_command_nlst(FAR struct ftpd_session_s *session); +static int ftpd_command_acct(FAR struct ftpd_session_s *session); +static int ftpd_command_size(FAR struct ftpd_session_s *session); +static int ftpd_command_stru(FAR struct ftpd_session_s *session); +static int ftpd_command_rnfr(FAR struct ftpd_session_s *session); +static int ftpd_command_rnto(FAR struct ftpd_session_s *session); +static int ftpd_command_retr(FAR struct ftpd_session_s *session); +static int ftpd_command_stor(FAR struct ftpd_session_s *session); +static int ftpd_command_appe(FAR struct ftpd_session_s *session); +static int ftpd_command_rest(FAR struct ftpd_session_s *session); +static int ftpd_command_mdtm(FAR struct ftpd_session_s *session); +static int ftpd_command_opts(FAR struct ftpd_session_s *session); +static int ftpd_command_site(FAR struct ftpd_session_s *session); +static int ftpd_command_help(FAR struct ftpd_session_s *session); + +static int ftpd_command(FAR struct ftpd_session_s *session); + +/* Worker thread */ + +static int ftpd_startworker(pthread_startroutine_t handler, FAR void *arg, + size_t stacksize); +static void ftpd_freesession(FAR struct ftpd_session_s *session); +static void ftpd_workersetup(FAR struct ftpd_session_s *session); +static FAR void *ftpd_worker(FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct ftpd_cmd_s g_ftpdcmdtab[] = +{ + {"USER", ftpd_command_user, 0}, /* USER */ + {"PASS", ftpd_command_pass, 0}, /* PASS */ + {"SYST", ftpd_command_syst, FTPD_CMDFLAG_LOGIN}, /* SYST */ + {"TYPE", ftpd_command_type, FTPD_CMDFLAG_LOGIN}, /* TYPE */ + {"MODE", ftpd_command_mode, FTPD_CMDFLAG_LOGIN}, /* MODE */ + {"ABOR", ftpd_command_abor, FTPD_CMDFLAG_LOGIN}, /* ABOR */ + {"QUIT", ftpd_command_quit, 0}, /* QUIT */ + {"NOOP", ftpd_command_noop, FTPD_CMDFLAG_LOGIN}, /* NOOP */ + {"PORT", ftpd_command_port, FTPD_CMDFLAG_LOGIN}, /* PORT */ + {"EPRT", ftpd_command_eprt, FTPD_CMDFLAG_LOGIN}, /* EPRT */ + {"PWD" , ftpd_command_pwd , FTPD_CMDFLAG_LOGIN}, /* PWD */ + {"XPWD", ftpd_command_pwd , FTPD_CMDFLAG_LOGIN}, /* XPWD */ + {"CWD" , ftpd_command_cwd , FTPD_CMDFLAG_LOGIN}, /* CWD */ + {"XCWD", ftpd_command_cwd , FTPD_CMDFLAG_LOGIN}, /* XCWD */ + {"CDUP", ftpd_command_cdup, FTPD_CMDFLAG_LOGIN}, /* CDUP */ + {"XCUP", ftpd_command_cdup, FTPD_CMDFLAG_LOGIN}, /* XCUP */ + {"RMD" , ftpd_command_rmd , FTPD_CMDFLAG_LOGIN}, /* RMD */ + {"XRMD", ftpd_command_rmd , FTPD_CMDFLAG_LOGIN}, /* XRMD */ + {"MKD" , ftpd_command_mkd , FTPD_CMDFLAG_LOGIN}, /* MKD */ + {"XMKD", ftpd_command_mkd , FTPD_CMDFLAG_LOGIN}, /* XMKD */ + {"DELE", ftpd_command_dele, FTPD_CMDFLAG_LOGIN}, /* DELE */ + {"PASV", ftpd_command_pasv, FTPD_CMDFLAG_LOGIN}, /* PASV */ + {"EPSV", ftpd_command_epsv, FTPD_CMDFLAG_LOGIN}, /* EPSV OR EPSV ALL */ + {"LPSV", ftpd_command_epsv, FTPD_CMDFLAG_LOGIN}, /* LPSV ??? */ + {"LIST", ftpd_command_list, FTPD_CMDFLAG_LOGIN}, /* LIST [ ] */ + {"NLST", ftpd_command_nlst, FTPD_CMDFLAG_LOGIN}, /* NLST [ ] */ + {"ACCT", ftpd_command_acct, FTPD_CMDFLAG_LOGIN}, /* ACCT */ + {"SIZE", ftpd_command_size, FTPD_CMDFLAG_LOGIN}, /* SIZE */ + {"STRU", ftpd_command_stru, FTPD_CMDFLAG_LOGIN}, /* STRU */ + {"RNFR", ftpd_command_rnfr, FTPD_CMDFLAG_LOGIN}, /* RNFR */ + {"RNTO", ftpd_command_rnto, FTPD_CMDFLAG_LOGIN}, /* RNTO */ + {"RETR", ftpd_command_retr, FTPD_CMDFLAG_LOGIN}, /* RETR */ + {"STOR", ftpd_command_stor, FTPD_CMDFLAG_LOGIN}, /* STOR */ + {"APPE", ftpd_command_appe, FTPD_CMDFLAG_LOGIN}, /* APPE */ + {"REST", ftpd_command_rest, FTPD_CMDFLAG_LOGIN}, /* REST */ + {"MDTM", ftpd_command_mdtm, FTPD_CMDFLAG_LOGIN}, /* MDTM */ + {"OPTS", ftpd_command_opts, FTPD_CMDFLAG_LOGIN}, /* OPTS