/**************************************************************************** * apps/netutils/ftpd/ftpd.c * * Copyright (C) 2012, 2015, 2020 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 #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_FTPD_LOGIN_PASSWD #include "fsutils/passwd.h" #endif #include "netutils/ftpd.h" #include "ftpd.h" /**************************************************************************** * 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_setpassword(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); static bool 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); /* Socket helpers */ 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, ...) printf_like(3, 4); 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, sa_family_t family); /* 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 *path, FAR char **abspath, FAR char **workpath); /* Command helpers */ static int ftpd_changedir(FAR struct ftpd_session_s *session, FAR const 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