From 443a058db4ee8032221da84823f39f411796ff63 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 30 Apr 2018 11:07:05 +0200 Subject: Use network services from RTEMS Close #3419. --- freebsd/include/arpa/ftp.h | 107 -- libbsd.py | 15 - rtemsbsd/ftpd/ftpd-init.c | 39 - rtemsbsd/ftpd/ftpd.c | 2171 -------------------------------------- rtemsbsd/ftpfs/ftpfs.c | 1428 ------------------------- rtemsbsd/include/rtems/ftpd.h | 80 -- rtemsbsd/include/rtems/ftpfs.h | 159 --- rtemsbsd/include/rtems/telnetd.h | 115 -- rtemsbsd/telnetd/check_passwd.c | 107 -- rtemsbsd/telnetd/des.c | 879 --------------- rtemsbsd/telnetd/passwd.h | 25 - rtemsbsd/telnetd/pty.c | 660 ------------ rtemsbsd/telnetd/telnetd-init.c | 33 - rtemsbsd/telnetd/telnetd.c | 517 --------- waf_libbsd.py | 2 +- 15 files changed, 1 insertion(+), 6336 deletions(-) delete mode 100644 freebsd/include/arpa/ftp.h delete mode 100644 rtemsbsd/ftpd/ftpd-init.c delete mode 100644 rtemsbsd/ftpd/ftpd.c delete mode 100644 rtemsbsd/ftpfs/ftpfs.c delete mode 100644 rtemsbsd/include/rtems/ftpd.h delete mode 100644 rtemsbsd/include/rtems/ftpfs.h delete mode 100644 rtemsbsd/include/rtems/telnetd.h delete mode 100644 rtemsbsd/telnetd/check_passwd.c delete mode 100644 rtemsbsd/telnetd/des.c delete mode 100644 rtemsbsd/telnetd/passwd.h delete mode 100644 rtemsbsd/telnetd/pty.c delete mode 100644 rtemsbsd/telnetd/telnetd-init.c delete mode 100644 rtemsbsd/telnetd/telnetd.c diff --git a/freebsd/include/arpa/ftp.h b/freebsd/include/arpa/ftp.h deleted file mode 100644 index 081c037e..00000000 --- a/freebsd/include/arpa/ftp.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 1983, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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 of the University 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 REGENTS 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 REGENTS 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. - * - * @(#)ftp.h 8.1 (Berkeley) 6/2/93 - * - * $FreeBSD$ - */ - -#ifndef _ARPA_FTP_H_ -#define _ARPA_FTP_H_ - -/* Definitions for FTP; see RFC-765. */ - -/* - * 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 */ - -/* - * Type codes - */ -#define TYPE_A 1 /* ASCII */ -#define TYPE_E 2 /* EBCDIC */ -#define TYPE_I 3 /* image */ -#define TYPE_L 4 /* local byte size */ - -#ifdef FTP_NAMES -char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" }; -#endif - -/* - * Form codes - */ -#define FORM_N 1 /* non-print */ -#define FORM_T 2 /* telnet format effectors */ -#define FORM_C 3 /* carriage control (ASA) */ -#ifdef FTP_NAMES -char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; -#endif - -/* - * Structure codes - */ -#define STRU_F 1 /* file (no record structure) */ -#define STRU_R 2 /* record structure */ -#define STRU_P 3 /* page structure */ -#ifdef FTP_NAMES -char *strunames[] = {"0", "File", "Record", "Page" }; -#endif - -/* - * Mode types - */ -#define MODE_S 1 /* stream */ -#define MODE_B 2 /* block */ -#define MODE_C 3 /* compressed */ -#ifdef FTP_NAMES -char *modenames[] = {"0", "Stream", "Block", "Compressed" }; -#endif - -/* - * Record Tokens - */ -#define REC_ESC '\377' /* Record-mode Escape */ -#define REC_EOR '\001' /* Record-mode End-of-Record */ -#define REC_EOF '\002' /* Record-mode End-of-File */ - -/* - * Block Header - */ -#define BLK_EOR 0x80 /* Block is End-of-Record */ -#define BLK_EOF 0x40 /* Block is End-of-File */ -#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */ -#define BLK_RESTART 0x10 /* Block is Restart Marker */ - -#define BLK_BYTECOUNT 2 /* Bytes in this block */ - -#endif /* !_FTP_H_ */ diff --git a/libbsd.py b/libbsd.py index a256594e..586703fd 100644 --- a/libbsd.py +++ b/libbsd.py @@ -278,10 +278,7 @@ class rtems(builder.Module): 'rtems/rtems-program-socket.c', 'rtems/rtems-routes.c', 'rtems/syslog.c', - 'ftpd/ftpd.c', - 'ftpd/ftpd-init.c', 'ftpd/ftpd-service.c', - 'ftpfs/ftpfs.c', 'mdns/mdns.c', 'mdns/mdns-hostname-default.c', 'nfsclient/mount_prot_xdr.c', @@ -318,22 +315,11 @@ class rtems(builder.Module): 'sys/fs/devfs/devfs_devs.c', 'sys/net/if_ppp.c', 'sys/net/ppp_tty.c', - 'telnetd/check_passwd.c', - 'telnetd/des.c', - 'telnetd/pty.c', - 'telnetd/telnetd.c', - 'telnetd/telnetd-init.c', 'telnetd/telnetd-service.c', 'sys/dev/tsec/if_tsec_nexus.c', ], mm.generator['source']() ) - self.addRTEMSSourceFiles( - [ - 'debugger/rtems-debugger-remote-tcp.c', - ], - mm.generator['source-if-header']('rtems/rtems-debugger.h') - ) self.addFile(mm.generator['file']('rtems/rtems-kernel-kvm-symbols.c', mm.generator['rtems-path'](), mm.generator['no-convert'](), @@ -2440,7 +2426,6 @@ class user_space(builder.Module): 'contrib/libxo/libxo/xo_wcwidth.h', 'sbin/pfctl/pfctl.h', 'sbin/pfctl/pfctl_parser.h', - 'include/arpa/ftp.h', 'include/arpa/nameser_compat.h', 'include/arpa/nameser.h', 'include/db.h', diff --git a/rtemsbsd/ftpd/ftpd-init.c b/rtemsbsd/ftpd/ftpd-init.c deleted file mode 100644 index 2741a633..00000000 --- a/rtemsbsd/ftpd/ftpd-init.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * FTP Server Daemon - * - * Submitted by: Jake Janovetz - * - * Changed by: Sergei Organov (OSV) - * Arnout Vandecappelle (AV) - * Sebastien Bourdeauducq (MM) - */ - -/************************************************************************* - * ftpd-init.c - ************************************************************************* - * Description: - * - * This file contains the legacy daemon initialisation. - * - *************************************************************************/ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -/* Configuration table */ -extern struct rtems_ftpd_configuration rtems_ftpd_configuration; - -/* - * rtems_initialize_ftpd - * - * Call the FTPD start function. - */ -int -rtems_initialize_ftpd(void) -{ - rtems_ftpd_configuration.verbose = true; - return rtems_ftpd_start(&rtems_ftpd_configuration); -} diff --git a/rtemsbsd/ftpd/ftpd.c b/rtemsbsd/ftpd/ftpd.c deleted file mode 100644 index 77e9d535..00000000 --- a/rtemsbsd/ftpd/ftpd.c +++ /dev/null @@ -1,2171 +0,0 @@ -/* FIXME: 1. Parse command is a hack. We can do better. - * 2. OSV: hooks support seems to be bad, as it requires storing of - * entire input file in memory. Seem to be better to change it to - * something more reasonable, like having - * 'hook_write(void const *buf, int count)' routine that will be - * called multiple times while file is being received. - * 3. OSV: Remove hack with "/dev/null"? - * - * FTP Server Daemon - * - * Submitted by: Jake Janovetz - * - * Changed by: Sergei Organov (OSV) - * Arnout Vandecappelle (AV) - * Sebastien Bourdeauducq (MM) - * - * - * Changes: - * - * 2010-12-02 Sebastien Bourdeauducq - * - * * Support spaces in filenames - * - * 2010-04-29 Arnout Vandecappelle (Essensium/Mind) - * - * * Added USER/PASS authentication. - * - * 2001-01-31 Sergei Organov - * - * * Hacks with current dir and root dir removed in favor of new libio - * support for task-local current and root directories. - * - * 2001-01-30 Sergei Organov - * - * * Bug in `close_data_socket()' introduced by previous change fixed. - * * `command_pasv()' changed to set timeout on socket we are listening on - * and code fixed to don't close socket twice on error. - * * `serr()' changed to clear `errno'. - * * `data_socket()' changed to clear `errno' before `bind()'. - * * `session()' changed to clear `errno' before processing session. - * - * 2001-01-29 Sergei Organov - * - * * `close_data_socket()' fixed to close both active and passive sockets - * * Initialize info->data_socket to -1 in `daemon()' - * * Initialize `fname' to empty string in `exec_command()' - * - * 2001-01-22 Sergei Organov - * - * * Timeouts on sockets implemented. 'idle' field added to - * configuration. No timeout by default to keep backward compatibility. - * Note: SITE IDLE command not implemented yet. - * * Basic global access control implemented. 'access' field added to - * configuration. No access limitations by default to keep backward - * compatibility. - * - * 2001-01-17 Sergei Organov - * - * * Anchor data socket for active mode (using self IP and port 20.) - * * Fixed default data port support (still not tested). - * * Don't allow IP address different from originating host in - * PORT command to improve security. - * * Fixed bug in MDTM command. - * * Check for correctness of parsing of argument in command_port(). - * * Fixed squeeze_path() to don't allow names like 'NAME/smth' where - * 'NAME' is not a directory. - * * Command parsing a little bit improved: command names are now - * converted to upper-case to be more compatible with RFC (command - * names are not case-sensitive.) - * * Reformat comments so that they have RTEMS look-and-feel. - * - * 2001-01-16 Sergei Organov - * - * * Fixed DELE, SITE CHMOD, RMD, MKD broken by previous changes - * * True ASCII mode implemented (doesn't work for hooks and /dev/null) - * * Passive mode implemented, PASV command added. - * * Default port for data connection could be used (untested, can't find - * ftp client that doesn't send PORT command) - * * SYST reply changed to UNIX, as former RTEMS isn't registered name. - * * Reply codes reviewed and fixed. - * - * 2001-01-08 Sergei Organov - * - * * use pool of pre-created threads to handle sessions - * * LIST output now similar to what "/bin/ls -al" would output, thus - * FTP clients could parse it. - * * LIST NAME now works (both for files and directories) - * * keep track of CWD for every session separately - * * ability to specify root directory name in configuration table - * * options sent in commands are ignored, thus LIST -al FILE works - * * added support for NLST, CDUP and MDTM commands - * * buffers are allocated on stack instead of heap where possible - * * drop using of task notepad to pass parameters - use function - * arguments instead - * * various bug-fixes, e.g., use of PF_INET in socket() instead of - * AF_INET, use snprintf() instead of sprintf() everywhere for safety, - * etc. - */ - -/************************************************************************* - * 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 'hooks' to make it usable in situations where files - * are not used/necessary. Once the server is started, it runs - * forever. - * - * - * Organization: - * - * The FTP daemon is started upon boot along with a (configurable) - * number of tasks to handle sessions. It runs all the time and - * waits for connections on the known FTP port (21). When - * a connection is made, it wakes-up a 'session' task. That - * session then interacts with the remote host. When the session - * is complete, the session task goes to sleep. The daemon still - * runs, however. - * - * - * 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. - * NLST xxx - Sends a file list to the client. - * 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. - * CDUP - Change to upper 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). - * MDTM xxx - Send file modification date/time to the client. - * xxx = filename. - * PASV - Use passive mode data connection. - * - * - * The public routines contained in this file are: - * - * rtems_initialize_ftpd - Initializes and starts the server daemon, - * then returns to its caller. - * - *------------------------------------------------------------------------ - * Jake Janovetz - * University of Illinois - * 1406 West Green Street - * Urbana IL 61801 - ************************************************************************* - * Change History: - * 12/01/97 - Creation (JWJ) - * 2001-01-08 - Changes by OSV - * 2010-04-29 - Authentication added by AV - *************************************************************************/ - -/************************************************************************* - * 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 accepted - * 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. - *************************************************************************/ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#ifdef __GNUC__ -/* change to #if 1 to disable syslog entirely */ -#if 0 -#undef syslog -#define syslog(a, b, ...) while(0){} -#endif -#endif - -#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready." - -#define FTPD_SYSTYPE "UNIX Type: L8" - -/* Seem to be unused */ -#if 0 -#define FTPD_WELCOME_MESSAGE \ - "Welcome to the RTEMS FTP server.\n" \ - "\n" \ - "Login accepted.\n" -#endif - -/* Event to be used by session tasks for waiting */ -enum -{ - FTPD_RTEMS_EVENT = RTEMS_EVENT_1 -}; - -/* Configuration table */ -static struct rtems_ftpd_configuration* ftpd_config; - -/* this is not prototyped in strict ansi mode */ -FILE *fdopen (int fildes, const char *mode); - -/*SessionInfo structure. - * - * The following structure is allocated for each session. - */ -typedef struct -{ - struct sockaddr_in ctrl_addr; /* Control connection self address */ - struct sockaddr_in data_addr; /* Data address set by PORT command */ - struct sockaddr_in def_addr; /* Default address for data */ - int use_default; /* 1 - use default address for data */ - FILE *ctrl_fp; /* File pointer for control connection */ - int ctrl_socket; /* Socket for ctrl connection */ - int pasv_socket; /* Socket for PASV connection */ - int data_socket; /* Socket for data connection */ - int idle; /* Timeout in seconds */ - int xfer_mode; /* Transfer mode (ASCII/binary) */ - rtems_id tid; /* Task id */ - char *user; /* user name (0 if not supplied) */ - char *pass; /* password (0 if not supplied) */ - bool auth; /* true if user/pass was valid, false if not or not supplied */ -} FTPD_SessionInfo_t; - - -/* - * TaskPool structure. - */ -typedef struct -{ - FTPD_SessionInfo_t *info; - FTPD_SessionInfo_t **queue; - int count; - int head; - int tail; - rtems_id mutex; - rtems_id sem; -} FTPD_TaskPool_t; - -/* - * Task pool instance. - */ -static FTPD_TaskPool_t task_pool; - -/* - * Root directory - */ - -static char const* ftpd_root = "/"; - -/* - * Default idle timeout for sockets in seconds. - */ -static int ftpd_timeout = 0; - -/* - * Global access flags. - */ -static int ftpd_access = 0; - -/* - * serr - * - * Return error string corresponding to current 'errno'. - * - */ -static char const* -serr(void) -{ - int err = errno; - errno = 0; - return strerror(err); -} - -/* - * Utility routines for access control. - * - */ - -static int -can_read(void) -{ - return (ftpd_access & FTPD_NO_READ) == 0; -} - -static int -can_write(void) -{ - return (ftpd_access & FTPD_NO_WRITE) == 0; -} - -/* - * Task pool management routines - * - */ - - -/* - * task_pool_done - * - * Cleanup task pool. - * - * Input parameters: - * count - number of entries in task pool to cleanup - * - * Output parameters: - * NONE - * - */ -static void -task_pool_done(int count) -{ - int i; - for(i = 0; i < count; ++i) - rtems_task_delete(task_pool.info[i].tid); - if(task_pool.info) - free(task_pool.info); - if(task_pool.queue) - free(task_pool.queue); - if(task_pool.mutex != (rtems_id)-1) - rtems_semaphore_delete(task_pool.mutex); - if(task_pool.sem != (rtems_id)-1) - rtems_semaphore_delete(task_pool.sem); - task_pool.info = 0; - task_pool.queue = 0; - task_pool.count = 0; - task_pool.sem = -1; - task_pool.mutex = -1; -} - -/* - * task_pool_init - * - * Initialize task pool. - * - * Input parameters: - * count - number of entries in task pool to create - * priority - priority tasks are started with - * - * Output parameters: - * returns 1 on success, 0 on failure. - * - */ -static void session(rtems_task_argument arg); /* Forward declare */ - -static int -task_pool_init(int count, rtems_task_priority priority) -{ - int i; - rtems_status_code sc; - char id = 'a'; - - task_pool.count = 0; - task_pool.head = task_pool.tail = 0; - task_pool.mutex = (rtems_id)-1; - task_pool.sem = (rtems_id)-1; - - sc = rtems_semaphore_create( - rtems_build_name('F', 'T', 'P', 'M'), - 1, - RTEMS_DEFAULT_ATTRIBUTES - | RTEMS_BINARY_SEMAPHORE - | RTEMS_INHERIT_PRIORITY - | RTEMS_PRIORITY, - RTEMS_NO_PRIORITY, - &task_pool.mutex); - - if(sc == RTEMS_SUCCESSFUL) - sc = rtems_semaphore_create( - rtems_build_name('F', 'T', 'P', 'S'), - count, - RTEMS_DEFAULT_ATTRIBUTES, - RTEMS_NO_PRIORITY, - &task_pool.sem); - - if(sc != RTEMS_SUCCESSFUL) { - task_pool_done(0); - syslog(LOG_ERR, "ftpd: Can not create semaphores"); - return 0; - } - - task_pool.info = (FTPD_SessionInfo_t*) - malloc(sizeof(FTPD_SessionInfo_t) * count); - task_pool.queue = (FTPD_SessionInfo_t**) - malloc(sizeof(FTPD_SessionInfo_t*) * count); - if (NULL == task_pool.info || NULL == task_pool.queue) - { - task_pool_done(0); - syslog(LOG_ERR, "ftpd: Not enough memory"); - return 0; - } - - for(i = 0; i < count; ++i) - { - FTPD_SessionInfo_t *info = &task_pool.info[i]; - sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id), - priority, FTPD_STACKSIZE, - RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | - RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), - RTEMS_FLOATING_POINT | RTEMS_LOCAL, - &info->tid); - if (sc == RTEMS_SUCCESSFUL) - { - sc = rtems_task_start( - info->tid, session, (rtems_task_argument)info); - if (sc != RTEMS_SUCCESSFUL) - task_pool_done(i); - } - else - task_pool_done(i + 1); - if (sc != RTEMS_SUCCESSFUL) - { - syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s", - rtems_status_text(sc)); - return 0; - } - task_pool.queue[i] = task_pool.info + i; - if (++id > 'z') - id = 'a'; - } - task_pool.count = count; - return 1; -} - -/* - * task_pool_obtain - * - * Obtain free task from task pool. - * - * Input parameters: - * NONE - * - * Output parameters: - * returns pointer to the corresponding SessionInfo structure on success, - * NULL if there are no free tasks in the pool. - * - */ -static FTPD_SessionInfo_t* -task_pool_obtain(void) -{ - FTPD_SessionInfo_t* info = 0; - rtems_status_code sc; - sc = rtems_semaphore_obtain(task_pool.sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); - if (sc == RTEMS_SUCCESSFUL) - { - rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - info = task_pool.queue[task_pool.head]; - if(++task_pool.head >= task_pool.count) - task_pool.head = 0; - rtems_semaphore_release(task_pool.mutex); - } - return info; -} - -/* - * task_pool_release - * - * Return task obtained by 'obtain()' back to the task pool. - * - * Input parameters: - * info - pointer to corresponding SessionInfo structure. - * - * Output parameters: - * NONE - * - */ -static void -task_pool_release(FTPD_SessionInfo_t* info) -{ - rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - task_pool.queue[task_pool.tail] = info; - if(++task_pool.tail >= task_pool.count) - task_pool.tail = 0; - rtems_semaphore_release(task_pool.mutex); - rtems_semaphore_release(task_pool.sem); -} - -/* - * End of task pool routines - */ - -/* - * Function: send_reply - * - * - * This procedure sends a reply to the client via the control - * connection. - * - * - * Input parameters: - * code - 3-digit reply code. - * text - Reply text. - * - * Output parameters: - * NONE - */ -static void -send_reply(FTPD_SessionInfo_t *info, int code, char *text) -{ - text = text != NULL ? text : ""; - fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text); - fflush(info->ctrl_fp); -} - - -/* - * close_socket - * - * Close socket. - * - * Input parameters: - * s - socket descriptor. - * seconds - number of seconds the timeout should be, - * if >= 0 - infinite timeout (no timeout). - * - * Output parameters: - * returns 1 on success, 0 on failure. - */ -static int -set_socket_timeout(int s, int seconds) -{ - int res = 0; - struct timeval tv; - int len = sizeof(tv); - - if(seconds < 0) - seconds = 0; - tv.tv_usec = 0; - tv.tv_sec = seconds; - if(0 != setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, len)) - syslog(LOG_ERR, "ftpd: Can't set send timeout on socket: %s.", serr()); - else if(0 != setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, len)) - syslog(LOG_ERR, "ftpd: Can't set receive timeout on socket: %s.", serr()); - else - res = 1; - return res; -} - -/* - * close_socket - * - * Close socket. - * - * Input parameters: - * s - socket descriptor to be closed. - * - * Output parameters: - * returns 1 on success, 0 on failure - */ -static int -close_socket(int s) -{ - if (0 <= s) - { - if (0 != close(s)) - { - shutdown(s, 2); - if (0 != close(s)) - return 0; - } - } - return 1; -} - -/* - * data_socket - * - * Create data socket for session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * returns socket descriptor, or -1 if failure - * - */ -static int -data_socket(FTPD_SessionInfo_t *info) -{ - int s = info->pasv_socket; - if(0 > s) - { - int on = 1; - s = socket(PF_INET, SOCK_STREAM, 0); - if(0 > s) - send_reply(info, 425, "Can't create data socket."); - else if(0 > setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - { - close_socket(s); - s = -1; - } - else - { - struct sockaddr_in data_source; - int tries; - - /* anchor socket to avoid multi-homing problems */ - data_source = info->ctrl_addr; - data_source.sin_port = htons(20); /* ftp-data port */ - for(tries = 1; tries < 10; ++tries) - { - errno = 0; - if(bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) - break; - if (errno != EADDRINUSE) - tries = 10; - else - rtems_task_wake_after(tries * 10); - } - if(tries >= 10) - { - send_reply(info, 425, "Can't bind data socket."); - close_socket(s); - s = -1; - } - else - { - struct sockaddr_in *data_dest = - (info->use_default) ? &info->def_addr : &info->data_addr; - if(0 > connect(s, (struct sockaddr *)data_dest, sizeof(*data_dest))) - { - send_reply(info, 425, "Can't connect data socket."); - close_socket(s); - s = -1; - } - } - } - } - info->data_socket = s; - info->use_default = 1; - if(s >= 0) - set_socket_timeout(s, info->idle); - return s; -} - -/* - * close_data_socket - * - * Close data socket for session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -close_data_socket(FTPD_SessionInfo_t *info) -{ - /* As at most one data socket could be open simultaneously and in some cases - data_socket == pasv_socket, we select socket to close, then close it. */ - int s = info->data_socket; - if(0 > s) - s = info->pasv_socket; - if(!close_socket(s)) - syslog(LOG_ERR, "ftpd: Error closing data socket."); - info->data_socket = -1; - info->pasv_socket = -1; - info->use_default = 1; -} - -/* - * close_stream - * - * Close control stream of session. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -close_stream(FTPD_SessionInfo_t* info) -{ - if (NULL != info->ctrl_fp) - { - if (0 != fclose(info->ctrl_fp)) - { - syslog(LOG_ERR, "ftpd: Could not close control stream: %s", serr()); - } - else - info->ctrl_socket = -1; - } - - if (!close_socket(info->ctrl_socket)) - syslog(LOG_ERR, "ftpd: Could not close control socket: %s", serr()); - - info->ctrl_fp = NULL; - info->ctrl_socket = -1; -} - - -/* - * send_mode_reply - * - * Sends BINARY/ASCII reply string depending on current transfer mode. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - * - */ -static void -send_mode_reply(FTPD_SessionInfo_t *info) -{ - if(info->xfer_mode == TYPE_I) - send_reply(info, 150, "Opening BINARY mode data connection."); - else - send_reply(info, 150, "Opening ASCII mode data connection."); -} - -/* - * command_retrieve - * - * Perform the "RETR" command (send file to client). - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *filename - source filename. - * - * Output parameters: - * NONE - * - */ -static void -command_retrieve(FTPD_SessionInfo_t *info, char const *filename) -{ - int s = -1; - int fd = -1; - char buf[FTPD_DATASIZE]; - struct stat stat_buf; - int res = 0; - - if(!can_read() || !info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - if (0 > (fd = open(filename, O_RDONLY))) - { - send_reply(info, 550, "Error opening file."); - return; - } - - if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) - { - if (-1 != fd) - close(fd); - send_reply(info, 550, "Is a directory."); - return; - } - - send_mode_reply(info); - - s = data_socket(info); - - if (0 <= s) - { - int n = -1; - - if(info->xfer_mode == TYPE_I) - { - while ((n = read(fd, buf, FTPD_DATASIZE)) > 0) - { - if(send(s, buf, n, 0) != n) - break; - sched_yield(); - } - } - else if (info->xfer_mode == TYPE_A) - { - int rest = 0; - while (rest == 0 && (n = read(fd, buf, FTPD_DATASIZE)) > 0) - { - char const* e = buf; - char const* b; - int i; - rest = n; - do - { - char lf = '\0'; - - b = e; - for(i = 0; i < rest; ++i, ++e) - { - if(*e == '\n') - { - lf = '\n'; - break; - } - } - if(send(s, b, i, 0) != i) - break; - if(lf == '\n') - { - if(send(s, "\r\n", 2, 0) != 2) - break; - ++e; - ++i; - } - } - while((rest -= i) > 0); - sched_yield(); - } - } - - if (0 == n) - { - if (0 == close(fd)) - { - fd = -1; - res = 1; - } - } - } - - if (-1 != fd) - close(fd); - - if (0 == res) - send_reply(info, 451, "File read error."); - else - send_reply(info, 226, "Transfer complete."); - - close_data_socket(info); - - return; -} - - -/* - * discard - * - * Analog of `write' routine that just discards passed data - * - * Input parameters: - * fd - file descriptor (ignored) - * buf - data to write (ignored) - * count - number of bytes in `buf' - * - * Output parameters: - * returns `count' - * - */ -static ssize_t -discard(int fd, void const* buf, size_t count) -{ - (void)fd; - (void)buf; - return count; -} - -/* - * command_store - * - * Performs the "STOR" command (receive data from client). - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *filename - Destination filename. - * - * Output parameters: - * NONE - */ -static void -command_store(FTPD_SessionInfo_t *info, char const *filename) -{ - int s; - int n; - unsigned long size = 0; - struct rtems_ftpd_hook *usehook = NULL; - char buf[FTPD_DATASIZE]; - int res = 1; - int bare_lfs = 0; - int null = 0; - typedef ssize_t (*WriteProc)(int, void const*, size_t); - WriteProc wrt = &write; - - if(!can_write() || !info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - send_mode_reply(info); - - s = data_socket(info); - if(0 > s) - return; - - null = !strcmp("/dev/null", filename); - if (null) - { - /* File "/dev/null" just throws data away. - * FIXME: this is hack. Using `/dev/null' filesystem entry would be - * better. - */ - wrt = &discard; - } - - if (!null && ftpd_config->hooks != NULL) - { - - /* Search our list of hooks to see if we need to do something special. */ - struct rtems_ftpd_hook *hook; - int i; - - i = 0; - hook = &ftpd_config->hooks[i++]; - while (hook->filename != NULL) - { - if (!strcmp(hook->filename, filename)) - { - usehook = hook; - break; - } - hook = &ftpd_config->hooks[i++]; - } - } - - if (usehook != NULL) - { - /* - * OSV: FIXME: Small buffer could be used and hook routine - * called multiple times instead. Alternatively, the support could be - * removed entirely in favor of configuring RTEMS pseudo-device with - * given name. - */ - - char *bigBufr; - size_t filesize = ftpd_config->max_hook_filesize + 1; - - /* - * Allocate space for our "file". - */ - bigBufr = (char *)malloc(filesize); - if (bigBufr == NULL) - { - send_reply(info, 451, "Local resource failure: malloc."); - close_data_socket(info); - return; - } - - /* - * Retrieve the file into our buffer space. - */ - size = 0; - while ((n = recv(s, bigBufr + size, filesize - size, 0)) > 0) - { - size += n; - } - if (size >= filesize) - { - send_reply(info, 451, "File too long: buffer size exceeded."); - free(bigBufr); - close_data_socket(info); - return; - } - - /* - * Call our hook. - */ - res = (usehook->hook_function)(bigBufr, size) == 0; - free(bigBufr); - if(!res) - { - send_reply(info, 451, "File processing failed."); - close_data_socket(info); - return; - } - } - else - { - /* Data transfer to regular file or /dev/null. */ - int fd = 0; - - if(!null) - fd = creat(filename, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - if (0 > fd) - { - send_reply(info, 550, "Error creating file."); - close_data_socket(info); - return; - } - - if(info->xfer_mode == TYPE_I) - { - while ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) - { - if (wrt(fd, buf, n) != n) - { - res = 0; - break; - } - sched_yield(); - } - } - else if(info->xfer_mode == TYPE_A) - { - int rest = 0; - int pended_cr = 0; - while (res && rest == 0 && (n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) - { - char const* e = buf; - char const* b; - int i; - - rest = n; - if(pended_cr && *e != '\n') - { - char const lf = '\r'; - pended_cr = 0; - if(wrt(fd, &lf, 1) != 1) - { - res = 0; - break; - } - } - do - { - int count; - int sub = 0; - - b = e; - for(i = 0; i < rest; ++i, ++e) - { - int pcr = pended_cr; - pended_cr = 0; - if(*e == '\r') - { - pended_cr = 1; - } - else if(*e == '\n') - { - if(pcr) - { - sub = 2; - ++i; - ++e; - break; - } - ++bare_lfs; - } - } - if(res == 0) - break; - count = i - sub - pended_cr; - if(count > 0 && wrt(fd, b, count) != count) - { - res = 0; - break; - } - if(sub == 2 && wrt(fd, e - 1, 1) != 1) - res = 0; - } - while((rest -= i) > 0); - sched_yield(); - } - } - - if (0 > close(fd) || res == 0) - { - send_reply(info, 452, "Error writing file."); - close_data_socket(info); - return; - } - } - - if (bare_lfs > 0) - { - snprintf(buf, FTPD_BUFSIZE, - "Transfer complete. WARNING! %d bare linefeeds received in ASCII mode.", - bare_lfs); - send_reply(info, 226, buf); - } - else - send_reply(info, 226, "Transfer complete."); - close_data_socket(info); - -} - - -/* - * send_dirline - * - * Sends one line of LIST command reply corresponding to single file. - * - * Input parameters: - * s - socket descriptor to send data to - * wide - if 0, send only file name. If not 0, send 'stat' info as well in - * "ls -l" format. - * curTime - current time - * path - path to be prepended to what is given by 'add' - * add - path to be appended to what is given by 'path', the resulting path - * is then passed to 'stat()' routine - * name - file name to be reported in output - * buf - buffer for temporary data - * - * Output parameters: - * returns 0 on failure, 1 on success - * - */ -static int -send_dirline(int s, int wide, time_t curTime, char const* path, - char const* add, char const* fname, char* buf) -{ - if(wide) - { - struct stat stat_buf; - - int plen = strlen(path); - int alen = strlen(add); - if(plen == 0) - { - buf[plen++] = '/'; - buf[plen] = '\0'; - } - else - { - strcpy(buf, path); - if(alen > 0 && buf[plen - 1] != '/') - { - buf[plen++] = '/'; - if(plen >= FTPD_BUFSIZE) - return 0; - buf[plen] = '\0'; - } - } - if(plen + alen >= FTPD_BUFSIZE) - return 0; - strcpy(buf + plen, add); - - if (stat(buf, &stat_buf) == 0) - { - int len; - struct tm bt; - time_t tf = stat_buf.st_mtime; - enum { SIZE = 80 }; - time_t SIX_MONTHS = (365L*24L*60L*60L)/2L; - char timeBuf[SIZE]; - gmtime_r(&tf, &bt); - if(curTime > tf + SIX_MONTHS || tf > curTime + SIX_MONTHS) - strftime (timeBuf, SIZE, "%b %d %Y", &bt); - else - strftime (timeBuf, SIZE, "%b %d %H:%M", &bt); - - len = snprintf(buf, FTPD_BUFSIZE, - "%c%c%c%c%c%c%c%c%c%c 1 %5d %5d %11u %s %s\r\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, - timeBuf, - fname - ); - - if(send(s, buf, len, 0) != len) - return 0; - } - } - else - { - int len = snprintf(buf, FTPD_BUFSIZE, "%s\r\n", fname); - if(send(s, buf, len, 0) != len) - return 0; - } - return 1; -} - -/* - * command_list - * - * Send file list to client. - * - * Input parameters: - * info - corresponding SessionInfo structure - * char *fname - File (or directory) to list. - * - * Output parameters: - * NONE - */ -static void -command_list(FTPD_SessionInfo_t *info, char const *fname, int wide) -{ - int s; - DIR *dirp = 0; - struct dirent *dp = 0; - struct stat stat_buf; - char buf[FTPD_BUFSIZE]; - time_t curTime; - int sc = 1; - - if(!info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - send_reply(info, 150, "Opening ASCII mode data connection for LIST."); - - s = data_socket(info); - if(0 > s) - { - syslog(LOG_ERR, "ftpd: Error connecting to data socket."); - return; - } - - if(fname[0] == '\0') - fname = "."; - - if (0 > stat(fname, &stat_buf)) - { - snprintf(buf, FTPD_BUFSIZE, - "%s: No such file or directory.\r\n", fname); - send(s, buf, strlen(buf), 0); - } - else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(fname)))) - { - snprintf(buf, FTPD_BUFSIZE, - "%s: Can not open directory.\r\n", fname); - send(s, buf, strlen(buf), 0); - } - else - { - time(&curTime); - if(!dirp && *fname) - sc = sc && send_dirline(s, wide, curTime, fname, "", fname, buf); - else { - /* FIXME: need "." and ".." only when '-a' option is given */ - sc = sc && send_dirline(s, wide, curTime, fname, "", ".", buf); - sc = sc && send_dirline(s, wide, curTime, fname, - (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf); - while (sc && (dp = readdir(dirp)) != NULL) - sc = sc && - send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf); - } - } - - if(dirp) - closedir(dirp); - close_data_socket(info); - - if(sc) - send_reply(info, 226, "Transfer complete."); - else - send_reply(info, 426, "Connection aborted."); -} - - -/* - * command_cwd - * - * Change current working directory. - * - * Input parameters: - * info - corresponding SessionInfo structure - * dir - directory name passed in CWD command - * - * Output parameters: - * NONE - * - */ -static void -command_cwd(FTPD_SessionInfo_t *info, char *dir) -{ - if(!info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - if(chdir(dir) == 0) - send_reply(info, 250, "CWD command successful."); - else - send_reply(info, 550, "CWD command failed."); -} - - -/* - * command_pwd - * - * Send current working directory to client. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * NONE - */ -static void -command_pwd(FTPD_SessionInfo_t *info) -{ - char buf[FTPD_BUFSIZE]; - char const* cwd; - errno = 0; - buf[0] = '"'; - - if(!info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - cwd = getcwd(buf + 1, FTPD_BUFSIZE - 4); - if(cwd) - { - int len = strlen(cwd); - static char const txt[] = "\" is the current directory."; - int size = sizeof(txt); - if(len + size + 1 >= FTPD_BUFSIZE) - size = FTPD_BUFSIZE - len - 2; - memcpy(buf + len + 1, txt, size); - buf[len + size] = '\0'; - send_reply(info, 250, buf); - } - else { - snprintf(buf, FTPD_BUFSIZE, "Error: %s.", serr()); - send_reply(info, 452, buf); - } -} - -/* - * command_mdtm - * - * Handle FTP MDTM command (send file modification time to client)/ - * - * Input parameters: - * info - corresponding SessionInfo structure - * fname - file name passed in MDTM command - * - * Output parameters: - * info->cwd is set to new CWD value. - */ -static void -command_mdtm(FTPD_SessionInfo_t *info, char const* fname) -{ - struct stat stbuf; - char buf[FTPD_BUFSIZE]; - - if(!info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - if (0 > stat(fname, &stbuf)) - { - snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); - send_reply(info, 550, buf); - } - else - { - struct tm *t = gmtime(&stbuf.st_mtime); - snprintf(buf, FTPD_BUFSIZE, "%04d%02d%02d%02d%02d%02d", - 1900 + t->tm_year, - t->tm_mon+1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); - send_reply(info, 213, buf); - } -} - -static void -command_size(FTPD_SessionInfo_t *info, char const* fname) -{ - struct stat stbuf; - char buf[FTPD_BUFSIZE]; - - if(!info->auth) - { - send_reply(info, 550, "Access denied."); - return; - } - - if (info->xfer_mode != TYPE_I || 0 > stat(fname, &stbuf) || stbuf.st_size < 0) - { - send_reply(info, 550, "Could not get file size."); - } - else - { - snprintf(buf, FTPD_BUFSIZE, "%" PRIuMAX, (uintmax_t) stbuf.st_size); - send_reply(info, 213, buf); - } -} - -/* - * command_port - * - * This procedure fills address for data connection given the IP address and - * port of the remote machine. - * - * Input parameters: - * info - corresponding SessionInfo structure - * args - arguments to the "PORT" command. - * - * Output parameters: - * info->data_addr is set according to arguments of the PORT command. - * info->use_default is set to 0 on success, 1 on failure. - */ -static void -command_port(FTPD_SessionInfo_t *info, char const *args) -{ - enum { NUM_FIELDS = 6 }; - unsigned int a[NUM_FIELDS]; - int n; - - close_data_socket(info); - - n = sscanf(args, "%u,%u,%u,%u,%u,%u", a+0, a+1, a+2, a+3, a+4, a+5); - if(NUM_FIELDS == n) - { - int i; - union { - uint8_t b[NUM_FIELDS]; - struct { - uint32_t ip; - uint16_t port; - } u ; - } ip_info; - - for(i = 0; i < NUM_FIELDS; ++i) - { - if(a[i] > 255) - break; - ip_info.b[i] = (uint8_t)a[i]; - } - - if(i == NUM_FIELDS) - { - /* Note: while it contradicts with RFC959, we don't allow PORT command - * to specify IP address different than those of the originating client - * for the sake of safety. */ - if (ip_info.u.ip == info->def_addr.sin_addr.s_addr) - { - info->data_addr.sin_addr.s_addr = ip_info.u.ip; - info->data_addr.sin_port = ip_info.u.port; - info->data_addr.sin_family = AF_INET; - memset(info->data_addr.sin_zero, 0, sizeof(info->data_addr.sin_zero)); - - info->use_default = 0; - send_reply(info, 200, "PORT command successful."); - return; /* success */ - } - else - { - send_reply(info, 425, "Address doesn't match peer's IP."); - return; - } - } - } - send_reply(info, 501, "Syntax error."); -} - - -/* - * command_pasv - * - * Handle FTP PASV command. - * Open socket, listen for and accept connection on it. - * - * Input parameters: - * info - corresponding SessionInfo structure - * - * Output parameters: - * info->pasv_socket is set to the descriptor of the data socket - */ -static void -command_pasv(FTPD_SessionInfo_t *info) -{ - int s = -1; - int err = 1; - - close_data_socket(info); - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) - syslog(LOG_ERR, "ftpd: Error creating PASV socket: %s", serr()); - else - { - struct sockaddr_in addr; - socklen_t addrLen = sizeof(addr); - - addr = info->ctrl_addr; - addr.sin_port = htons(0); - - if (0 > bind(s, (struct sockaddr *)&addr, addrLen)) - syslog(LOG_ERR, "ftpd: Error binding PASV socket: %s", serr()); - else if (0 > listen(s, 1)) - syslog(LOG_ERR, "ftpd: Error listening on PASV socket: %s", serr()); - else if(set_socket_timeout(s, info->idle)) - { - char buf[FTPD_BUFSIZE]; - unsigned char const *ip, *p; - - getsockname(s, (struct sockaddr *)&addr, &addrLen); - ip = (unsigned char const*)&(addr.sin_addr); - p = (unsigned char const*)&(addr.sin_port); - snprintf(buf, FTPD_BUFSIZE, "Entering passive mode (%u,%u,%u,%u,%u,%u).", - ip[0], ip[1], ip[2], ip[3], p[0], p[1]); - send_reply(info, 227, buf); - - info->pasv_socket = accept(s, (struct sockaddr *)&addr, &addrLen); - if (0 > info->pasv_socket) - syslog(LOG_ERR, "ftpd: Error accepting PASV connection: %s", serr()); - else - { - close_socket(s); - s = -1; - err = 0; - } - } - } - if(err) - { - /* (OSV) The note is from FreeBSD FTPD. - * Note: a response of 425 is not mentioned as a possible response to - * the PASV command in RFC959. However, it has been blessed as a - * legitimate response by Jon Postel in a telephone conversation - * with Rick Adams on 25 Jan 89. */ - send_reply(info, 425, "Can't open passive connection."); - close_socket(s); - } -} - - -/* - * skip_options - * - * Utility routine to skip options (if any) from input command. - * - * Input parameters: - * p - pointer to pointer to command - * - * Output parameters: - * p - is changed to point to first non-option argument - */ -static void -skip_options(char **p) -{ - char* buf = *p; - char* last = NULL; - while(1) { - while(isspace((unsigned char)*buf)) - ++buf; - if(*buf == '-') { - if(*++buf == '-') { /* `--' should terminate options */ - if(isspace((unsigned char)*++buf)) { - last = buf; - do ++buf; - while(isspace((unsigned char)*buf)); - break; - } - } - while(*buf && !isspace((unsigned char)*buf)) - ++buf; - last = buf; - } - else - break; - } - if(last) - *last = '\0'; - *p = buf; -} - -/* - * split_command - * - * Split command into command itself, options, and arguments. Command itself - * is converted to upper case. - * - * Input parameters: - * buf - initial command string - * - * Output parameter: - * buf - is modified by inserting '\0' at ends of split entities - * cmd - upper-cased command code - * opts - string containing all the options - * args - string containing all the arguments - */ -static void -split_command(char *buf, char **cmd, char **opts, char **args) -{ - char* eoc; - char* p = buf; - while(isspace((unsigned char)*p)) - ++p; - *cmd = p; - while(*p && !isspace((unsigned char)*p)) - { - *p = toupper((unsigned char)*p); - ++p; - } - eoc = p; - if(*p) - *p++ = '\0'; - while(isspace((unsigned char)*p)) - ++p; - *opts = p; - skip_options(&p); - *args = p; - if(*opts == p) - *opts = eoc; - while(*p && *p != '\r' && *p != '\n') - ++p; - if(*p) - *p++ = '\0'; -} - -/* - * exec_command - * - * Parse and execute FTP command. - * - * FIXME: This section is somewhat of a hack. We should have a better - * way to parse commands. - * - * Input parameters: - * info - corresponding SessionInfo structure - * cmd - command to be executed (upper-case) - * args - arguments of the command - * - * Output parameters: - * NONE - */ -static void -exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args) -{ - char fname[FTPD_BUFSIZE]; - int wrong_command = 0; - - fname[0] = '\0'; - - if (!strcmp("PORT", cmd)) - { - command_port(info, args); - } - else if (!strcmp("PASV", cmd)) - { - command_pasv(info); - } - else if (!strcmp("RETR", cmd)) - { - strncpy(fname, args, 254); - command_retrieve(info, fname); - } - else if (!strcmp("STOR", cmd)) - { - strncpy(fname, args, 254); - command_store(info, fname); - } - else if (!strcmp("LIST", cmd)) - { - strncpy(fname, args, 254); - command_list(info, fname, 1); - } - else if (!strcmp("NLST", cmd)) - { - strncpy(fname, args, 254); - command_list(info, fname, 0); - } - else if (!strcmp("MDTM", cmd)) - { - strncpy(fname, args, 254); - command_mdtm(info, fname); - } - else if (!strcmp("SIZE", cmd)) - { - strncpy(fname, args, 254); - command_size(info, fname); - } - else if (!strcmp("SYST", cmd)) - { - send_reply(info, 215, FTPD_SYSTYPE); - } - else if (!strcmp("TYPE", cmd)) - { - if (args[0] == 'I') - { - info->xfer_mode = TYPE_I; - send_reply(info, 200, "Type set to I."); - } - else if (args[0] == 'A') - { - info->xfer_mode = TYPE_A; - send_reply(info, 200, "Type set to A."); - } - else - { - info->xfer_mode = TYPE_I; - send_reply(info, 504, "Type not implemented. Set to I."); - } - } - else if (!strcmp("USER", cmd)) - { - sscanf(args, "%254s", fname); - if (info->user) - free(info->user); - if (info->pass) - free(info->pass); - info->pass = NULL; - info->user = strdup(fname); - if (ftpd_config->login && - !ftpd_config->login(info->user, NULL)) { - info->auth = false; - send_reply(info, 331, "User name okay, need password."); - } else { - info->auth = true; - send_reply(info, 230, "User logged in."); - } - } - else if (!strcmp("PASS", cmd)) - { - sscanf(args, "%254s", fname); - if (info->pass) - free(info->pass); - info->pass = strdup(fname); - if (!info->user) { - send_reply(info, 332, "Need account to log in"); - } else { - if (ftpd_config->login && - !ftpd_config->login(info->user, info->pass)) { - info->auth = false; - send_reply(info, 530, "Not logged in."); - } else { - info->auth = true; - send_reply(info, 230, "User logged in."); - } - } - } - else if (!strcmp("DELE", cmd)) - { - if(!can_write() || !info->auth) - { - send_reply(info, 550, "Access denied."); - } - else if ( - strncpy(fname, args, 254) && - unlink(fname) == 0) - { - send_reply(info, 257, "DELE successful."); - } - else - { - send_reply(info, 550, "DELE failed."); - } - } - else if (!strcmp("SITE", cmd)) - { - char* opts; - split_command(args, &cmd, &opts, &args); - if(!strcmp("CHMOD", cmd)) - { - int mask; - - if(!can_write() || !info->auth) - { - send_reply(info, 550, "Access denied."); - } - else { - char *c; - c = strchr(args, ' '); - if((c != NULL) && (sscanf(args, "%o", &mask) == 1) && strncpy(fname, c+1, 254) - && (chmod(fname, (mode_t)mask) == 0)) - send_reply(info, 257, "CHMOD successful."); - else - send_reply(info, 550, "CHMOD failed."); - } - } - else - wrong_command = 1; - } - else if (!strcmp("RMD", cmd)) - { - if(!can_write() || !info->auth) - { - send_reply(info, 550, "Access denied."); - } - else if ( - strncpy(fname, args, 254) && - rmdir(fname) == 0) - { - send_reply(info, 257, "RMD successful."); - } - else - { - send_reply(info, 550, "RMD failed."); - } - } - else if (!strcmp("MKD", cmd)) - { - if(!can_write() || !info->auth) - { - send_reply(info, 550, "Access denied."); - } - else if ( - strncpy(fname, args, 254) && - mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) - { - send_reply(info, 257, "MKD successful."); - } - else - { - send_reply(info, 550, "MKD failed."); - } - } - else if (!strcmp("CWD", cmd)) - { - strncpy(fname, args, 254); - command_cwd(info, fname); - } - else if (!strcmp("CDUP", cmd)) - { - command_cwd(info, ".."); - } - else if (!strcmp("PWD", cmd)) - { - command_pwd(info); - } - else - wrong_command = 1; - - if(wrong_command) - send_reply(info, 500, "Command not understood."); -} - - -/* - * session - * - * This task handles single session. It is waked up 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. - * - * Input parameters: - * arg - pointer to corresponding SessionInfo. - * - * Output parameters: - * NONE - */ -static void -session(rtems_task_argument arg) -{ - FTPD_SessionInfo_t *const info = (FTPD_SessionInfo_t *)arg; - int chroot_made = 0; - - rtems_libio_set_private_env(); - - /* chroot() can fail here because the directory may not exist yet. */ - chroot_made = chroot(ftpd_root) == 0; - - while(1) - { - rtems_event_set set; - int rv; - - rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, - &set); - - chroot_made = chroot_made || chroot(ftpd_root) == 0; - - rv = chroot_made ? chdir("/") : -1; - - errno = 0; - - if (rv == 0) - { - send_reply(info, 220, FTPD_SERVER_MESSAGE); - - while (1) - { - char buf[FTPD_BUFSIZE]; - char *cmd, *opts, *args; - - if (fgets(buf, FTPD_BUFSIZE, info->ctrl_fp) == NULL) - { - syslog(LOG_INFO, "ftpd: Connection aborted."); - break; - } - - split_command(buf, &cmd, &opts, &args); - - if (!strcmp("QUIT", cmd)) - { - send_reply(info, 221, "Goodbye."); - break; - } - else - { - exec_command(info, cmd, args); - } - } - } - else - { - send_reply(info, 421, "Service not available, closing control connection."); - } - - /* - * Go back to the root directory. A use case is to release a current - * directory in a mounted file system on dynamic media, e.g. USB stick. - * The return value can be ignored since the next session will try do the - * operation again and an error check is performed in this case. - */ - chdir("/"); - - /* Close connection and put ourselves back into the task pool. */ - close_data_socket(info); - close_stream(info); - free(info->user); - free(info->pass); - task_pool_release(info); - } -} - - -/* - * ftpd_daemon - * - * This task runs forever. It waits for service requests on the FTP port - * (port 21 by default). When a request is received, it opens a new session - * to handle those requests until the connection is closed. - * - * Input parameters: - * NONE - * - * Output parameters: - * NONE - */ -static void -ftpd_daemon(rtems_task_argument args __attribute__((unused))) -{ - int s; - socklen_t addrLen; - struct sockaddr_in addr; - FTPD_SessionInfo_t *info = NULL; - - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) - syslog(LOG_ERR, "ftpd: Error creating socket: %s", serr()); - - addr.sin_family = AF_INET; - addr.sin_port = htons(ftpd_config->port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); - - if (0 > bind(s, (struct sockaddr *)&addr, sizeof(addr))) - syslog(LOG_ERR, "ftpd: Error binding control socket: %s", serr()); - else if (0 > listen(s, 1)) - syslog(LOG_ERR, "ftpd: Error listening on control socket: %s", serr()); - else while (1) - { - int ss; - addrLen = sizeof(addr); - ss = accept(s, (struct sockaddr *)&addr, &addrLen); - if (0 > ss) - syslog(LOG_ERR, "ftpd: Error accepting control connection: %s", serr()); - else if(!set_socket_timeout(ss, ftpd_timeout)) - close_socket(ss); - else - { - info = task_pool_obtain(); - if (NULL == info) - { - close_socket(ss); - } - else - { - info->ctrl_socket = ss; - if ((info->ctrl_fp = fdopen(info->ctrl_socket, "r+")) == NULL) - { - syslog(LOG_ERR, "ftpd: fdopen() on socket failed: %s", serr()); - close_stream(info); - task_pool_release(info); - } - else - { - /* Initialize corresponding SessionInfo structure */ - info->def_addr = addr; - if(0 > getsockname(ss, (struct sockaddr *)&addr, &addrLen)) - { - syslog(LOG_ERR, "ftpd: getsockname(): %s", serr()); - close_stream(info); - task_pool_release(info); - } - else - { - info->use_default = 1; - info->ctrl_addr = addr; - info->pasv_socket = -1; - info->data_socket = -1; - info->xfer_mode = TYPE_A; - info->data_addr.sin_port = - htons(ntohs(info->ctrl_addr.sin_port) - 1); - info->idle = ftpd_timeout; - info->user = NULL; - info->pass = NULL; - if (ftpd_config->login) - info->auth = false; - else - info->auth = true; - /* Wakeup the session task. The task will call task_pool_release - after it closes connection. */ - rtems_event_send(info->tid, FTPD_RTEMS_EVENT); - } - } - } - } - } - rtems_task_delete(RTEMS_SELF); -} - - -/* - * rtems_ftpd_start - * - * 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. - * - * - * Input parameters: - * config: constant initial setup. - * Output parameters: - * returns RTEMS_SUCCESSFUL on successful start of the daemon. - */ -int -rtems_ftpd_start(const struct rtems_ftpd_configuration* config) -{ - rtems_status_code sc; - rtems_id tid; - rtems_task_priority priority; - int count; - - if (ftpd_config != NULL) - return RTEMS_RESOURCE_IN_USE; - - ftpd_config = malloc(sizeof(*ftpd_config)); - if (ftpd_config == NULL) - return RTEMS_NO_MEMORY; - - *ftpd_config = *config; - - if (ftpd_config->port == 0) - { - ftpd_config->port = FTPD_CONTROL_PORT; - } - - if (ftpd_config->priority == 0) - { - ftpd_config->priority = 40; - } - priority = ftpd_config->priority; - - ftpd_timeout = ftpd_config->idle; - if (ftpd_timeout < 0) - ftpd_timeout = 0; - ftpd_config->idle = ftpd_timeout; - - ftpd_access = ftpd_config->access; - - ftpd_root = "/"; - if (ftpd_config->root && ftpd_config->root[0] == '/' ) - ftpd_root = ftpd_config->root; - - ftpd_config->root = ftpd_root; - - if (ftpd_config->tasks_count <= 0) - ftpd_config->tasks_count = 1; - count = ftpd_config->tasks_count; - - if (!task_pool_init(count, priority)) - { - syslog(LOG_ERR, "ftpd: Could not initialize task pool."); - return RTEMS_UNSATISFIED; - } - - sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), - priority, RTEMS_MINIMUM_STACK_SIZE, - RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | - RTEMS_INTERRUPT_LEVEL(0), - RTEMS_FLOATING_POINT | RTEMS_LOCAL, - &tid); - - if (sc == RTEMS_SUCCESSFUL) - { - sc = rtems_task_start(tid, ftpd_daemon, 0); - if (sc != RTEMS_SUCCESSFUL) - rtems_task_delete(tid); - } - - if (sc != RTEMS_SUCCESSFUL) - { - task_pool_done(count); - syslog(LOG_ERR, "ftpd: Could not create/start FTP daemon: %s", - rtems_status_text(sc)); - return RTEMS_UNSATISFIED; - } - - if (ftpd_config->verbose) - syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", - count, ((count > 1) ? "s" : "")); - - return RTEMS_SUCCESSFUL; -} diff --git a/rtemsbsd/ftpfs/ftpfs.c b/rtemsbsd/ftpfs/ftpfs.c deleted file mode 100644 index e016caeb..00000000 --- a/rtemsbsd/ftpfs/ftpfs.c +++ /dev/null @@ -1,1428 +0,0 @@ -/** - * @file - * - * File Transfer Protocol file system (FTP client). - */ - -/* - * Copyright (c) 2009-2012 embedded brains GmbH. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * (c) Copyright 2002 - * Thomas Doerfler - * IMD Ingenieurbuero fuer Microcomputertechnik - * Herbststr. 8 - * 82178 Puchheim, Germany - * - * - * This code has been created after closly inspecting "tftpdriver.c" from Eric - * Norum. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef DEBUG - #define DEBUG_PRINTF(...) printf(__VA_ARGS__) -#else - #define DEBUG_PRINTF(...) -#endif - -/** - * Connection entry for each open file stream. - */ -typedef struct { - off_t file_size; - - /** - * Control connection socket. - */ - int ctrl_socket; - - uint32_t client_address; - - /** - * Data transfer socket. - */ - int data_socket; - - /** - * Current index into the reply buffer. - */ - size_t reply_current; - - /** - * End index of the reply buffer. - */ - size_t reply_end; - - /** - * Buffer for relpy data. - */ - char reply_buffer [128]; - - /** - * End of file flag. - */ - bool eof; - - bool write; - - /** - * Indicates if we should do a SIZE command. - * - * The first call to the rtems_ftpfs_fstat() handler is issued by the path - * evaluation to check for access permission. For this case we avoid the - * SIZE command. - */ - bool do_size_command; - - ino_t ino; - - const char *user; - - const char *password; - - const char *hostname; - - const char *filename; - - char buffer []; -} rtems_ftpfs_entry; - -/** - * Mount entry for each file system instance. - */ -typedef struct { - /** - * Verbose mode enabled or disabled. - */ - bool verbose; - - /** - * Timeout value - */ - struct timeval timeout; - - /** - * Inode counter. - */ - ino_t ino; -} rtems_ftpfs_mount_entry; - -static const rtems_filesystem_operations_table rtems_ftpfs_ops; - -static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers; - -static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers; - -static bool rtems_ftpfs_use_timeout(const struct timeval *to) -{ - return to->tv_sec != 0 || to->tv_usec != 0; -} - -static int rtems_ftpfs_set_connection_timeout( - int socket, - const struct timeval *to -) -{ - if (rtems_ftpfs_use_timeout(to)) { - int rv = 0; - - rv = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, to, sizeof(*to)); - if (rv != 0) { - return EIO; - } - - rv = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, to, sizeof(*to)); - if (rv != 0) { - return EIO; - } - } - - return 0; -} - -static rtems_status_code rtems_ftpfs_do_ioctl( - const char *mount_point, - ioctl_command_t req, - ... -) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - int rv = 0; - int fd = 0; - va_list ap; - - if (mount_point == NULL) { - mount_point = RTEMS_FTPFS_MOUNT_POINT_DEFAULT; - } - - fd = open(mount_point, O_RDWR); - if (fd < 0) { - return RTEMS_INVALID_NAME; - } - - va_start(ap, req); - rv = ioctl(fd, req, va_arg(ap, void *)); - va_end(ap); - if (rv != 0) { - sc = RTEMS_INVALID_NUMBER; - } - - rv = close(fd); - if (rv != 0 && sc == RTEMS_SUCCESSFUL) { - sc = RTEMS_IO_ERROR; - } - - return sc; -} - -rtems_status_code rtems_ftpfs_get_verbose(const char *mount_point, bool *verbose) -{ - return rtems_ftpfs_do_ioctl( - mount_point, - RTEMS_FTPFS_IOCTL_GET_VERBOSE, - verbose - ); -} - -rtems_status_code rtems_ftpfs_set_verbose(const char *mount_point, bool verbose) -{ - return rtems_ftpfs_do_ioctl( - mount_point, - RTEMS_FTPFS_IOCTL_SET_VERBOSE, - &verbose - ); -} - -rtems_status_code rtems_ftpfs_get_timeout( - const char *mount_point, - struct timeval *timeout -) -{ - return rtems_ftpfs_do_ioctl( - mount_point, - RTEMS_FTPFS_IOCTL_GET_TIMEOUT, - timeout - ); -} - -rtems_status_code rtems_ftpfs_set_timeout( - const char *mount_point, - const struct timeval *timeout -) -{ - return rtems_ftpfs_do_ioctl( - mount_point, - RTEMS_FTPFS_IOCTL_SET_TIMEOUT, - timeout - ); -} - -typedef void (*rtems_ftpfs_reply_parser)( - const char * /* reply fragment */, - size_t /* reply fragment length */, - void * /* parser argument */ -); - -typedef enum { - RTEMS_FTPFS_REPLY_START, - RTEMS_FTPFS_REPLY_SINGLE_LINE, - RTEMS_FTPFS_REPLY_DONE, - RTEMS_FTPFS_REPLY_MULTI_LINE, - RTEMS_FTPFS_REPLY_MULTI_LINE_START -} rtems_ftpfs_reply_state; - -typedef enum { - RTEMS_FTPFS_REPLY_ERROR = 0, - RTEMS_FTPFS_REPLY_1 = '1', - RTEMS_FTPFS_REPLY_2 = '2', - RTEMS_FTPFS_REPLY_3 = '3', - RTEMS_FTPFS_REPLY_4 = '4', - RTEMS_FTPFS_REPLY_5 = '5' -} rtems_ftpfs_reply; - -#define RTEMS_FTPFS_REPLY_SIZE 3 - -static bool rtems_ftpfs_is_reply_code_valid(unsigned char *reply) -{ - return isdigit(reply [0]) && isdigit(reply [1]) && isdigit(reply [2]); -} - -static rtems_ftpfs_reply rtems_ftpfs_get_reply( - rtems_ftpfs_entry *e, - rtems_ftpfs_reply_parser parser, - void *parser_arg, - bool verbose -) -{ - rtems_ftpfs_reply_state state = RTEMS_FTPFS_REPLY_START; - unsigned char reply_code [RTEMS_FTPFS_REPLY_SIZE] = { 'a', 'a', 'a' }; - size_t reply_code_index = 0; - - while (state != RTEMS_FTPFS_REPLY_DONE) { - char *buf = NULL; - size_t i = 0; - size_t n = 0; - - /* Receive reply fragment from socket */ - if (e->reply_current == e->reply_end) { - ssize_t rv = 0; - - e->reply_current = 0; - e->reply_end = 0; - - rv = recv( - e->ctrl_socket, - &e->reply_buffer [0], - sizeof(e->reply_buffer), - 0 - ); - - if (rv > 0) { - e->reply_end = (size_t) rv; - } else { - return RTEMS_FTPFS_REPLY_ERROR; - } - } - - buf = &e->reply_buffer [e->reply_current]; - n = e->reply_end - e->reply_current; - - /* Invoke parser if necessary */ - if (parser != NULL) { - parser(buf, n, parser_arg); - } - - /* Parse reply fragment */ - for (i = 0; i < n && state != RTEMS_FTPFS_REPLY_DONE; ++i) { - char c = buf [i]; - - switch (state) { - case RTEMS_FTPFS_REPLY_START: - if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) { - reply_code [reply_code_index] = c; - ++reply_code_index; - } else if (rtems_ftpfs_is_reply_code_valid(reply_code)) { - if (c == '-') { - state = RTEMS_FTPFS_REPLY_MULTI_LINE; - } else { - state = RTEMS_FTPFS_REPLY_SINGLE_LINE; - } - } else { - return RTEMS_FTPFS_REPLY_ERROR; - } - break; - case RTEMS_FTPFS_REPLY_SINGLE_LINE: - if (c == '\n') { - state = RTEMS_FTPFS_REPLY_DONE; - } - break; - case RTEMS_FTPFS_REPLY_MULTI_LINE: - if (c == '\n') { - state = RTEMS_FTPFS_REPLY_MULTI_LINE_START; - reply_code_index = 0; - } - break; - case RTEMS_FTPFS_REPLY_MULTI_LINE_START: - if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) { - if (reply_code [reply_code_index] == c) { - ++reply_code_index; - } else { - state = RTEMS_FTPFS_REPLY_MULTI_LINE; - } - } else { - if (c == ' ') { - state = RTEMS_FTPFS_REPLY_SINGLE_LINE; - } else { - state = RTEMS_FTPFS_REPLY_MULTI_LINE; - } - } - break; - default: - return RTEMS_FTPFS_REPLY_ERROR; - } - } - - /* Be verbose if necessary */ - if (verbose) { - write(STDERR_FILENO, buf, i); - } - - /* Update reply index */ - e->reply_current += i; - } - - return reply_code [0]; -} - -static rtems_ftpfs_reply rtems_ftpfs_send_command_with_parser( - rtems_ftpfs_entry *e, - const char *cmd, - const char *arg, - rtems_ftpfs_reply_parser parser, - void *parser_arg, - bool verbose -) -{ - rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; - size_t cmd_len = strlen(cmd); - size_t arg_len = arg != NULL ? strlen(arg) : 0; - size_t len = cmd_len + arg_len + 2; - char *buf = malloc(len); - - if (buf != NULL) { - ssize_t n = 0; - char *buf_arg = buf + cmd_len; - char *buf_eol = buf_arg + arg_len; - - memcpy(buf, cmd, cmd_len); - memcpy(buf_arg, arg, arg_len); - buf_eol [0] = '\r'; - buf_eol [1] = '\n'; - - /* Send */ - n = send(e->ctrl_socket, buf, len, 0); - if (n == (ssize_t) len) { - if (verbose) { - write(STDERR_FILENO, buf, len); - } - - /* Reply */ - reply = rtems_ftpfs_get_reply(e, parser, parser_arg, verbose); - } - - free(buf); - } - - return reply; -} - -static rtems_ftpfs_reply rtems_ftpfs_send_command( - rtems_ftpfs_entry *e, - const char *cmd, - const char *arg, - bool verbose -) -{ - return rtems_ftpfs_send_command_with_parser( - e, - cmd, - arg, - NULL, - NULL, - verbose - ); -} - -typedef enum { - STATE_USER_NAME, - STATE_START_PASSWORD, - STATE_START_HOST_NAME, - STATE_START_HOST_NAME_OR_PATH, - STATE_START_PATH, - STATE_PASSWORD, - STATE_HOST_NAME, - STATE_DONE, - STATE_INVALID -} split_state; - -static int rtems_ftpfs_split_names ( - char *s, - const char **user, - const char **password, - const char **hostname, - const char **path -) -{ - split_state state = STATE_USER_NAME; - size_t len = strlen(s); - size_t i = 0; - - *user = s; - - for (i = 0; i < len; ++i) { - char c = s [i]; - - switch (state) { - case STATE_USER_NAME: - if (c == ':') { - state = STATE_START_PASSWORD; - s [i] = '\0'; - } else if (c == '@') { - state = STATE_START_HOST_NAME; - s [i] = '\0'; - } else if (c == '/') { - state = STATE_START_HOST_NAME_OR_PATH; - s [i] = '\0'; - } - break; - case STATE_START_PASSWORD: - state = STATE_PASSWORD; - *password = &s [i]; - --i; - break; - case STATE_START_HOST_NAME: - state = STATE_HOST_NAME; - *hostname = &s [i]; - --i; - break; - case STATE_START_HOST_NAME_OR_PATH: - if (c == '@') { - state = STATE_START_HOST_NAME; - } else { - state = STATE_DONE; - *path = &s [i]; - goto done; - } - break; - case STATE_START_PATH: - state = STATE_DONE; - *path = &s [i]; - goto done; - case STATE_PASSWORD: - if (c == '@') { - state = STATE_START_HOST_NAME; - s [i] = '\0'; - } else if (c == '/') { - state = STATE_START_HOST_NAME_OR_PATH; - s [i] = '\0'; - } - break; - case STATE_HOST_NAME: - if (c == '/') { - state = STATE_START_PATH; - s [i] = '\0'; - } - break; - default: - state = STATE_INVALID; - goto done; - } - } - -done: - - /* This is a special case with no username and password */ - if (*hostname == NULL) { - *hostname = &s [0]; - *user = "anonymous"; - *password = *user; - } - - /* If we have no password use the user name */ - if (*password == NULL) { - *password = *user; - } - - return state == STATE_DONE ? 0 : ENOENT; -} - -static socklen_t rtems_ftpfs_create_address( - struct sockaddr_in *sa, - unsigned long address, - unsigned short port -) -{ - memset(sa, 0, sizeof(*sa)); - - sa->sin_family = AF_INET; - sa->sin_addr.s_addr = address; - sa->sin_port = port; - sa->sin_len = sizeof(*sa); - - return sizeof(*sa); -} - -static int rtems_ftpfs_close_data_connection( - rtems_ftpfs_entry *e, - bool verbose, - bool error -) -{ - int eno = 0; - - /* Close data connection if necessary */ - if (e->data_socket >= 0) { - int rv = close(e->data_socket); - - e->data_socket = -1; - if (rv != 0) { - eno = EIO; - } - - /* For write connections we have to obtain the transfer reply */ - if (e->write && !error) { - rtems_ftpfs_reply reply = - rtems_ftpfs_get_reply(e, NULL, NULL, verbose); - - if (reply != RTEMS_FTPFS_REPLY_2) { - eno = EIO; - } - } - } - - return eno; -} - -static int rtems_ftpfs_open_ctrl_connection( - rtems_ftpfs_entry *e, - bool verbose, - const struct timeval *timeout -) -{ - int rv = 0; - int eno = 0; - rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; - struct in_addr address = { .s_addr = 0 }; - struct sockaddr_in sa; - socklen_t size = 0; - - /* Create the socket for the control connection */ - e->ctrl_socket = socket(AF_INET, SOCK_STREAM, 0); - if (e->ctrl_socket < 0) { - return ENOMEM; - } - - /* Set up the server address from the hostname */ - if (inet_aton(e->hostname, &address) == 0) { - /* Try to get the address by name */ - struct hostent *he = gethostbyname(e->hostname); - - if (he != NULL) { - memcpy(&address, he->h_addr, sizeof(address)); - } else { - return ENOENT; - } - } - rtems_ftpfs_create_address(&sa, address.s_addr, htons(RTEMS_FTPFS_CTRL_PORT)); - DEBUG_PRINTF("server = %s\n", inet_ntoa(sa.sin_addr)); - - /* Open control connection */ - rv = connect( - e->ctrl_socket, - (struct sockaddr *) &sa, - sizeof(sa) - ); - if (rv != 0) { - return ENOENT; - } - - /* Set control connection timeout */ - eno = rtems_ftpfs_set_connection_timeout(e->ctrl_socket, timeout); - if (eno != 0) { - return eno; - } - - /* Get client address */ - size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); - rv = getsockname( - e->ctrl_socket, - (struct sockaddr *) &sa, - &size - ); - if (rv != 0) { - return ENOMEM; - } - e->client_address = ntohl(sa.sin_addr.s_addr); - DEBUG_PRINTF("client = %s\n", inet_ntoa(sa.sin_addr)); - - /* Now we should get a welcome message from the server */ - reply = rtems_ftpfs_get_reply(e, NULL, NULL, verbose); - if (reply != RTEMS_FTPFS_REPLY_2) { - return ENOENT; - } - - /* Send USER command */ - reply = rtems_ftpfs_send_command(e, "USER ", e->user, verbose); - if (reply == RTEMS_FTPFS_REPLY_3) { - /* Send PASS command */ - reply = rtems_ftpfs_send_command(e, "PASS ", e->password, verbose); - if (reply != RTEMS_FTPFS_REPLY_2) { - return EACCES; - } - - /* TODO: Some server may require an account */ - } else if (reply != RTEMS_FTPFS_REPLY_2) { - return EACCES; - } - - /* Send TYPE command to set binary mode for all data transfers */ - reply = rtems_ftpfs_send_command(e, "TYPE I", NULL, verbose); - if (reply != RTEMS_FTPFS_REPLY_2) { - return EIO; - } - - return 0; -} - -static int rtems_ftpfs_open_data_connection_active( - rtems_ftpfs_entry *e, - const char *file_command, - bool verbose, - const struct timeval *timeout -) -{ - int rv = 0; - int eno = 0; - rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; - struct sockaddr_in sa; - socklen_t size = 0; - int port_socket = -1; - char port_command [] = "PORT 000,000,000,000,000,000"; - uint16_t data_port = 0; - - /* Create port socket to establish a data data connection */ - port_socket = socket(AF_INET, SOCK_STREAM, 0); - if (port_socket < 0) { - eno = ENOMEM; - goto cleanup; - } - - /* Bind port socket */ - rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); - rv = bind( - port_socket, - (struct sockaddr *) &sa, - sizeof(sa) - ); - if (rv != 0) { - eno = EBUSY; - goto cleanup; - } - - /* Get port number for data socket */ - size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); - rv = getsockname( - port_socket, - (struct sockaddr *) &sa, - &size - ); - if (rv != 0) { - eno = ENOMEM; - goto cleanup; - } - data_port = ntohs(sa.sin_port); - - /* Send PORT command to set data connection port for server */ - snprintf( - port_command, - sizeof(port_command), - "PORT %lu,%lu,%lu,%lu,%lu,%lu", - (e->client_address >> 24) & 0xffUL, - (e->client_address >> 16) & 0xffUL, - (e->client_address >> 8) & 0xffUL, - (e->client_address >> 0) & 0xffUL, - (data_port >> 8) & 0xffUL, - (data_port >> 0) & 0xffUL - ); - reply = rtems_ftpfs_send_command(e, port_command, NULL, verbose); - if (reply != RTEMS_FTPFS_REPLY_2) { - eno = ENOTSUP; - goto cleanup; - } - - /* Listen on port socket for incoming data connections */ - rv = listen(port_socket, 1); - if (rv != 0) { - eno = EBUSY; - goto cleanup; - } - - /* Send RETR or STOR command with filename */ - reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose); - if (reply != RTEMS_FTPFS_REPLY_1) { - eno = EIO; - goto cleanup; - } - - /* Wait for connect on data connection if necessary */ - if (rtems_ftpfs_use_timeout(timeout)) { - struct timeval to = *timeout; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(port_socket, &fds); - - rv = select(port_socket + 1, &fds, NULL, NULL, &to); - if (rv <= 0) { - eno = EIO; - goto cleanup; - } - } - - /* Accept data connection */ - size = sizeof(sa); - e->data_socket = accept( - port_socket, - (struct sockaddr *) &sa, - &size - ); - if (e->data_socket < 0) { - eno = EIO; - goto cleanup; - } - -cleanup: - - /* Close port socket if necessary */ - if (port_socket >= 0) { - rv = close(port_socket); - if (rv != 0) { - eno = EIO; - } - } - - return eno; -} - -typedef enum { - RTEMS_FTPFS_PASV_START = 0, - RTEMS_FTPFS_PASV_JUNK, - RTEMS_FTPFS_PASV_DATA, - RTEMS_FTPFS_PASV_DONE -} rtems_ftpfs_pasv_state; - -typedef struct { - rtems_ftpfs_pasv_state state; - size_t index; - uint8_t data [6]; -} rtems_ftpfs_pasv_entry; - -static void rtems_ftpfs_pasv_parser( - const char* buf, - size_t len, - void *arg -) -{ - rtems_ftpfs_pasv_entry *pe = arg; - size_t i = 0; - - for (i = 0; i < len; ++i) { - int c = buf [i]; - - switch (pe->state) { - case RTEMS_FTPFS_PASV_START: - if (!isdigit(c)) { - pe->state = RTEMS_FTPFS_PASV_JUNK; - pe->index = 0; - } - break; - case RTEMS_FTPFS_PASV_JUNK: - if (isdigit(c)) { - pe->state = RTEMS_FTPFS_PASV_DATA; - pe->data [pe->index] = (uint8_t) (c - '0'); - } - break; - case RTEMS_FTPFS_PASV_DATA: - if (isdigit(c)) { - pe->data [pe->index] = - (uint8_t) (pe->data [pe->index] * 10 + c - '0'); - } else if (c == ',') { - ++pe->index; - if (pe->index < sizeof(pe->data)) { - pe->data [pe->index] = 0; - } else { - pe->state = RTEMS_FTPFS_PASV_DONE; - } - } else { - pe->state = RTEMS_FTPFS_PASV_DONE; - } - break; - default: - return; - } - } -} - -static int rtems_ftpfs_open_data_connection_passive( - rtems_ftpfs_entry *e, - const char *file_command, - bool verbose, - const struct timeval *timeout -) -{ - int rv = 0; - rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; - struct sockaddr_in sa; - uint32_t data_address = 0; - uint16_t data_port = 0; - rtems_ftpfs_pasv_entry pe; - - memset(&pe, 0, sizeof(pe)); - - /* Send PASV command */ - reply = rtems_ftpfs_send_command_with_parser( - e, - "PASV", - NULL, - rtems_ftpfs_pasv_parser, - &pe, - verbose - ); - if (reply != RTEMS_FTPFS_REPLY_2) { - return ENOTSUP; - } - data_address = ((uint32_t)(pe.data [0]) << 24) - + ((uint32_t)(pe.data [1]) << 16) - + ((uint32_t)(pe.data [2]) << 8) - + ((uint32_t)(pe.data [3])); - data_port = (uint16_t) ((pe.data [4] << 8) + pe.data [5]); - rtems_ftpfs_create_address(&sa, htonl(data_address), htons(data_port)); - DEBUG_PRINTF( - "server data = %s:%u\n", - inet_ntoa(sa.sin_addr), - (unsigned) ntohs(sa.sin_port) - ); - - /* Create data socket */ - e->data_socket = socket(AF_INET, SOCK_STREAM, 0); - if (e->data_socket < 0) { - return ENOMEM; - } - - /* Open data connection */ - rv = connect( - e->data_socket, - (struct sockaddr *) &sa, - sizeof(sa) - ); - if (rv != 0) { - return EIO; - } - - /* Send RETR or STOR command with filename */ - reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose); - if (reply != RTEMS_FTPFS_REPLY_1) { - return EIO; - } - - return 0; -} - -typedef enum { - RTEMS_FTPFS_SIZE_START = 0, - RTEMS_FTPFS_SIZE_SPACE, - RTEMS_FTPFS_SIZE_NUMBER, - RTEMS_FTPFS_SIZE_NL -} rtems_ftpfs_size_state; - -typedef struct { - rtems_ftpfs_size_state state; - size_t index; - off_t size; -} rtems_ftpfs_size_entry; - -static void rtems_ftpfs_size_parser( - const char* buf, - size_t len, - void *arg -) -{ - rtems_ftpfs_size_entry *se = arg; - size_t i = 0; - - for (i = 0; se->size >= 0 && i < len; ++i, ++se->index) { - int c = buf [i]; - - switch (se->state) { - case RTEMS_FTPFS_SIZE_START: - if (se->index == 2) { - se->state = RTEMS_FTPFS_SIZE_SPACE; - } - break; - case RTEMS_FTPFS_SIZE_SPACE: - if (c == ' ') { - se->state = RTEMS_FTPFS_SIZE_NUMBER; - } else { - se->size = -1; - } - break; - case RTEMS_FTPFS_SIZE_NUMBER: - if (isdigit(c)) { - se->size = 10 * se->size + c - '0'; - } else if (c == '\r') { - se->state = RTEMS_FTPFS_SIZE_NL; - } else { - se->size = -1; - } - break; - case RTEMS_FTPFS_SIZE_NL: - if (c != '\n') { - se->size = -1; - } - break; - default: - se->size = -1; - break; - } - } -} - -static void rtems_ftpfs_get_file_size(rtems_ftpfs_entry *e, bool verbose) -{ - if (e->file_size < 0) { - if (e->write) { - e->file_size = 0; - } else { - rtems_ftpfs_size_entry se; - rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; - - memset(&se, 0, sizeof(se)); - - reply = rtems_ftpfs_send_command_with_parser( - e, - "SIZE ", - e->filename, - rtems_ftpfs_size_parser, - &se, - verbose - ); - if (reply == RTEMS_FTPFS_REPLY_2 && se.size >= 0) { - e->file_size = se.size; - } else { - e->file_size = 0; - } - } - } -} - -static int rtems_ftpfs_open( - rtems_libio_t *iop, - const char *path, - int oflag, - mode_t mode -) -{ - int eno = 0; - rtems_ftpfs_entry *e = iop->pathinfo.node_access; - rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; - bool verbose = me->verbose; - const struct timeval *timeout = &me->timeout; - - e->write = (iop->flags & LIBIO_FLAGS_WRITE) != 0; - - /* Check for either read-only or write-only flags */ - if ( - (iop->flags & LIBIO_FLAGS_WRITE) != 0 - && (iop->flags & LIBIO_FLAGS_READ) != 0 - ) { - eno = ENOTSUP; - } - - if (eno == 0) { - rtems_ftpfs_get_file_size(e, verbose); - } - - if (eno == 0) { - const char *file_command = e->write ? "STOR " : "RETR "; - - /* Open passive data connection */ - eno = rtems_ftpfs_open_data_connection_passive( - e, - file_command, - verbose, - timeout - ); - if (eno == ENOTSUP) { - /* Open active data connection */ - eno = rtems_ftpfs_open_data_connection_active( - e, - file_command, - verbose, - timeout - ); - } - } - - /* Set data connection timeout */ - if (eno == 0) { - eno = rtems_ftpfs_set_connection_timeout(e->data_socket, timeout); - } - - if (eno == 0) { - return 0; - } else { - rtems_ftpfs_close_data_connection(e, verbose, true); - - rtems_set_errno_and_return_minus_one(eno); - } -} - -static ssize_t rtems_ftpfs_read( - rtems_libio_t *iop, - void *buffer, - size_t count -) -{ - rtems_ftpfs_entry *e = iop->pathinfo.node_access; - const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; - bool verbose = me->verbose; - char *in = buffer; - size_t todo = count; - - if (e->eof) { - return 0; - } - - while (todo > 0) { - ssize_t rv = recv(e->data_socket, in, todo, 0); - - if (rv <= 0) { - if (rv == 0) { - rtems_ftpfs_reply reply = - rtems_ftpfs_get_reply(e, NULL, NULL, verbose); - - if (reply == RTEMS_FTPFS_REPLY_2) { - e->eof = true; - break; - } - } - - rtems_set_errno_and_return_minus_one(EIO); - } - - in += rv; - todo -= (size_t) rv; - } - - return (ssize_t) (count - todo); -} - -static ssize_t rtems_ftpfs_write( - rtems_libio_t *iop, - const void *buffer, - size_t count -) -{ - rtems_ftpfs_entry *e = iop->pathinfo.node_access; - const char *out = buffer; - size_t todo = count; - - while (todo > 0) { - ssize_t rv = send(e->data_socket, out, todo, 0); - - if (rv <= 0) { - if (rv == 0) { - break; - } else { - rtems_set_errno_and_return_minus_one(EIO); - } - } - - out += rv; - todo -= (size_t) rv; - - e->file_size += rv; - } - - return (ssize_t) (count - todo); -} - -static int rtems_ftpfs_close(rtems_libio_t *iop) -{ - rtems_ftpfs_entry *e = iop->pathinfo.node_access; - const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; - int eno = rtems_ftpfs_close_data_connection(e, me->verbose, false); - - if (eno == 0) { - return 0; - } else { - rtems_set_errno_and_return_minus_one(eno); - } -} - -/* Dummy version to let fopen(*,"w") work properly */ -static int rtems_ftpfs_ftruncate(rtems_libio_t *iop, off_t count) -{ - return 0; -} - -static void rtems_ftpfs_eval_path( - rtems_filesystem_eval_path_context_t *self -) -{ - int eno = 0; - - rtems_filesystem_eval_path_eat_delimiter(self); - - if (rtems_filesystem_eval_path_has_path(self)) { - const char *path = rtems_filesystem_eval_path_get_path(self); - size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self); - rtems_ftpfs_entry *e = calloc(1, sizeof(*e) + pathlen + 1); - - rtems_filesystem_eval_path_clear_path(self); - - if (e != NULL) { - memcpy(e->buffer, path, pathlen); - - eno = rtems_ftpfs_split_names( - e->buffer, - &e->user, - &e->password, - &e->hostname, - &e->filename - ); - - DEBUG_PRINTF( - "user = '%s', password = '%s', filename = '%s'\n", - e->user, - e->password, - e->filename - ); - - if (eno == 0) { - rtems_filesystem_location_info_t *currentloc = - rtems_filesystem_eval_path_get_currentloc(self); - rtems_ftpfs_mount_entry *me = currentloc->mt_entry->fs_info; - - rtems_libio_lock(); - ++me->ino; - e->ino = me->ino; - rtems_libio_unlock(); - - e->file_size = -1; - e->ctrl_socket = -1; - - eno = rtems_ftpfs_open_ctrl_connection( - e, - me->verbose, - &me->timeout - ); - if (eno == 0) { - currentloc->node_access = e; - currentloc->handlers = &rtems_ftpfs_handlers; - } - } - - if (eno != 0) { - free(e); - } - } else { - eno = ENOMEM; - } - } - - if (eno != 0) { - rtems_filesystem_eval_path_error(self, eno); - } -} - -static void rtems_ftpfs_free_node(const rtems_filesystem_location_info_t *loc) -{ - rtems_ftpfs_entry *e = loc->node_access; - - /* The root node handler has no entry */ - if (e != NULL) { - const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info; - - /* Close control connection if necessary */ - if (e->ctrl_socket >= 0) { - rtems_ftpfs_send_command(e, "QUIT", NULL, me->verbose); - - close(e->ctrl_socket); - } - - free(e); - } -} - -int rtems_ftpfs_initialize( - rtems_filesystem_mount_table_entry_t *e, - const void *d -) -{ - rtems_ftpfs_mount_entry *me = calloc(1, sizeof(*me)); - - /* Mount entry for FTP file system instance */ - e->fs_info = me; - if (e->fs_info == NULL) { - rtems_set_errno_and_return_minus_one(ENOMEM); - } - me->verbose = false; - me->timeout.tv_sec = 0; - me->timeout.tv_usec = 0; - - /* Set handler and oparations table */ - e->mt_fs_root->location.handlers = &rtems_ftpfs_root_handlers; - e->ops = &rtems_ftpfs_ops; - - /* We maintain no real file system nodes, so there is no real root */ - e->mt_fs_root->location.node_access = NULL; - - return 0; -} - -static void rtems_ftpfs_unmount_me( - rtems_filesystem_mount_table_entry_t *e -) -{ - free(e->fs_info); -} - -static int rtems_ftpfs_ioctl( - rtems_libio_t *iop, - uint32_t command, - void *arg -) -{ - rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; - bool *verbose = arg; - struct timeval *timeout = arg; - - if (arg == NULL) { - rtems_set_errno_and_return_minus_one(EINVAL); - } - - switch (command) { - case RTEMS_FTPFS_IOCTL_GET_VERBOSE: - *verbose = me->verbose; - break; - case RTEMS_FTPFS_IOCTL_SET_VERBOSE: - me->verbose = *verbose; - break; - case RTEMS_FTPFS_IOCTL_GET_TIMEOUT: - *timeout = me->timeout; - break; - case RTEMS_FTPFS_IOCTL_SET_TIMEOUT: - me->timeout = *timeout; - break; - default: - rtems_set_errno_and_return_minus_one(EINVAL); - } - - return 0; -} - -/* - * The stat() support is intended only for the cp shell command. Each request - * will return that we have a regular file with read, write and execute - * permissions for every one. The node index uses a global counter to support - * a remote to remote copy. This is not a very sophisticated method. - */ -static int rtems_ftpfs_fstat( - const rtems_filesystem_location_info_t *loc, - struct stat *st -) -{ - int eno = 0; - rtems_ftpfs_entry *e = loc->node_access; - - /* FIXME */ - st->st_ino = e->ino; - st->st_dev = rtems_filesystem_make_dev_t(0xcc494cd6U, 0x1d970b4dU); - - st->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; - - if (e->do_size_command) { - const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info; - - rtems_ftpfs_get_file_size(e, me->verbose); - st->st_size = e->file_size; - } else { - e->do_size_command = true; - } - - if (eno == 0) { - return 0; - } else { - rtems_set_errno_and_return_minus_one(eno); - } -} - -static void rtems_ftpfs_lock_or_unlock( - const rtems_filesystem_mount_table_entry_t *mt_entry -) -{ - /* Do nothing */ -} - -static const rtems_filesystem_operations_table rtems_ftpfs_ops = { - .lock_h = rtems_ftpfs_lock_or_unlock, - .unlock_h = rtems_ftpfs_lock_or_unlock, - .eval_path_h = rtems_ftpfs_eval_path, - .link_h = rtems_filesystem_default_link, - .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal, - .mknod_h = rtems_filesystem_default_mknod, - .rmnod_h = rtems_filesystem_default_rmnod, - .fchmod_h = rtems_filesystem_default_fchmod, - .chown_h = rtems_filesystem_default_chown, - .clonenod_h = rtems_filesystem_default_clonenode, - .freenod_h = rtems_ftpfs_free_node, - .mount_h = rtems_filesystem_default_mount, - .unmount_h = rtems_filesystem_default_unmount, - .fsunmount_me_h = rtems_ftpfs_unmount_me, - .utime_h = rtems_filesystem_default_utime, - .symlink_h = rtems_filesystem_default_symlink, - .readlink_h = rtems_filesystem_default_readlink, - .rename_h = rtems_filesystem_default_rename, - .statvfs_h = rtems_filesystem_default_statvfs -}; - -static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers = { - .open_h = rtems_ftpfs_open, - .close_h = rtems_ftpfs_close, - .read_h = rtems_ftpfs_read, - .write_h = rtems_ftpfs_write, - .ioctl_h = rtems_filesystem_default_ioctl, - .lseek_h = rtems_filesystem_default_lseek, - .fstat_h = rtems_ftpfs_fstat, - .ftruncate_h = rtems_ftpfs_ftruncate, - .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fcntl_h = rtems_filesystem_default_fcntl, - .kqfilter_h = rtems_filesystem_default_kqfilter, - .poll_h = rtems_filesystem_default_poll, - .readv_h = rtems_filesystem_default_readv, - .writev_h = rtems_filesystem_default_writev -}; - -static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers = { - .open_h = rtems_filesystem_default_open, - .close_h = rtems_filesystem_default_close, - .read_h = rtems_filesystem_default_read, - .write_h = rtems_filesystem_default_write, - .ioctl_h = rtems_ftpfs_ioctl, - .lseek_h = rtems_filesystem_default_lseek, - .fstat_h = rtems_filesystem_default_fstat, - .ftruncate_h = rtems_filesystem_default_ftruncate, - .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fcntl_h = rtems_filesystem_default_fcntl, - .kqfilter_h = rtems_filesystem_default_kqfilter, - .poll_h = rtems_filesystem_default_poll, - .readv_h = rtems_filesystem_default_readv, - .writev_h = rtems_filesystem_default_writev -}; diff --git a/rtemsbsd/include/rtems/ftpd.h b/rtemsbsd/include/rtems/ftpd.h deleted file mode 100644 index b57880d1..00000000 --- a/rtemsbsd/include/rtems/ftpd.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * FTP Server Information - */ - -#ifndef _RTEMS_FTPD_H -#define _RTEMS_FTPD_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define FTPD_CONTROL_PORT 21 - -/* Various buffer sizes */ -enum { - FTPD_BUFSIZE = 256, /* Size for temporary buffers */ - FTPD_DATASIZE = 4 * 1024, /* Size for file transfer buffers */ - FTPD_STACKSIZE = RTEMS_MINIMUM_STACK_SIZE + FTPD_DATASIZE /* Tasks stack size */ -}; - -/* FTPD access control flags */ -enum -{ - FTPD_NO_WRITE = 0x1, - FTPD_NO_READ = 0x2, - FTPD_NO_RW = FTPD_NO_WRITE | FTPD_NO_READ -}; - -typedef int (*rtems_ftpd_hookfunction)(char *, size_t); - -#include - -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 */ - char const *root; /* Root for FTPD or 0 for / */ - int tasks_count; /* Max. connections */ - int idle; /* Idle timeout in seoconds - or 0 for no (inf) timeout */ - int access; /* 0 - r/w, 1 - read-only, - 2 - write-only, - 3 - browse-only */ - rtems_shell_login_check_t login; /* Login check or 0 to ignore - user/passwd. */ - bool verbose; /* Say hello! */ -}; - -/* - * 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 */ - -/* - * Initialise with the global table. - * - * Note, use rc.conf, this function will be removed at some point. - */ -int rtems_initialize_ftpd(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _RTEMS_FTPD_H */ diff --git a/rtemsbsd/include/rtems/ftpfs.h b/rtemsbsd/include/rtems/ftpfs.h deleted file mode 100644 index c1f615b8..00000000 --- a/rtemsbsd/include/rtems/ftpfs.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file - * - * @brief File Transfer Protocol file system (FTP client). - */ - -/* - * Copyright (c) 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * (c) Copyright 2002 - * Thomas Doerfler - * IMD Ingenieurbuero fuer Microcomputertechnik - * Herbststr. 8 - * 82178 Puchheim, Germany - * - * - * Modified by Sebastian Huber . - * - * This code has been created after closly inspecting "tftpdriver.c" from Eric - * Norum. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifndef _RTEMS_FTPFS_H -#define _RTEMS_FTPFS_H - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup rtems_ftpfs File Transfer Protocol File System - * - * @brief The FTP file system (FTP client) can be used to transfer files from - * or to remote hosts. - * - * You can mount the FTP file system with a call to mount() or - * mount_and_make_target_path() with the @ref RTEMS_FILESYSTEM_TYPE_FTPFS file - * system type. - * - * You have to add @ref CONFIGURE_FILESYSTEM_FTPFS to your application - * configuration. - * - * You can open files either read-only or write-only. A seek is not allowed. - * A close terminates the control and data connections. - * - * To open a file @c file.txt in the directory @c dir (relative to home - * directory of the server) on a server named @c host using the user name - * @c user and the password @c pw you must specify the following path: - * /FTP/user:pw@@host/dir/file.txt. - * - * If the server is the default server specified in BOOTP, it can be ommitted: - * /FTP/user:pw/dir/file.txt. - * - * The user name will be used for the password if it is ommitted: - * /FTP/user@@host/dir/file.txt. - * - * For the data transfer passive (= default) and active (= fallback) mode are - * supported. - */ -/**@{**/ - -/** - * @brief Well-known port number for FTP control connection. - */ -#define RTEMS_FTPFS_CTRL_PORT 21 - -/** - * @brief Default mount point for FTP file system. - */ -#define RTEMS_FTPFS_MOUNT_POINT_DEFAULT "/FTP" - -/** - * @brief FTP file system IO control requests. - */ -typedef enum { - RTEMS_FTPFS_IOCTL_GET_VERBOSE = _IOR( 'd', 1, bool *), - RTEMS_FTPFS_IOCTL_SET_VERBOSE = _IOW( 'd', 1, bool *), - RTEMS_FTPFS_IOCTL_GET_TIMEOUT = _IOR( 'd', 2, struct timeval *), - RTEMS_FTPFS_IOCTL_SET_TIMEOUT = _IOW( 'd', 2, struct timeval *) -} rtems_ftpfs_ioctl_numbers; - -/** - * @brief Returns in @a verbose if the verbose mode is enabled or disabled for - * the file system at @a mount_point. - * - * If @a mount_point is @c NULL the default mount point - * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used. - */ -rtems_status_code rtems_ftpfs_get_verbose( const char *mount_point, bool *verbose); - -/** - * @brief Enables or disables the verbose mode if @a verbose is @c true or - * @c false respectively for the file system at @a mount_point. - * - * In the enabled verbose mode the commands and replies of the FTP control - * connections will be printed to standard error. - * - * If @a mount_point is @c NULL the default mount point - * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used. - */ -rtems_status_code rtems_ftpfs_set_verbose( const char *mount_point, bool verbose); - -/** - * @brief Returns the current timeout value in @a timeout for the file system - * at @a mount_point. - * - * If @a mount_point is @c NULL the default mount point - * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used. - */ -rtems_status_code rtems_ftpfs_get_timeout( - const char *mount_point, - struct timeval *timeout -); - -/** - * @brief Sets the timeout value to @a timeout for the file system at - * @a mount_point. - * - * The timeout value will be used during connection establishment of active - * data connections. It will be also used for send and receive operations on - * data and control connections. - * - * If @a mount_point is @c NULL the default mount point - * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used. - */ -rtems_status_code rtems_ftpfs_set_timeout( - const char *mount_point, - const struct timeval *timeout -); - -/** @} */ - -/** - * @brief Do not call directly, use mount(). - */ -int rtems_ftpfs_initialize( - rtems_filesystem_mount_table_entry_t *mt_entry, - const void *data -); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/rtemsbsd/include/rtems/telnetd.h b/rtemsbsd/include/rtems/telnetd.h deleted file mode 100644 index 3919d80f..00000000 --- a/rtemsbsd/include/rtems/telnetd.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Original Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es) - * May 2001 - * Reworked by Till Straumann and .h overhauled by Joel Sherrill. - * - * Copyright (c) 2009 embedded brains GmbH and others. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifndef _RTEMS_TELNETD_H -#define _RTEMS_TELNETD_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -bool rtems_telnetd_login_check( - const char *user, - const char *passphrase -); - -/** - * @brief Telnet command type. - */ -typedef void (*rtems_telnetd_command)( - char * /* device name */, - void * /* arg */ -); - -/** - * @brief Telnet configuration structure. - */ -typedef struct { - /** - * @brief Function invoked for each Telnet connection. - * - * The first parameter contains the device name. The second parameter - * contains the argument pointer of this configuration table. - */ - rtems_telnetd_command command; - - /** - * @brief Argument for command function. - */ - void *arg; - - /** - * @brief Task priority. - * - * If this parameter is equal to zero, then the priority of network task is - * used or 100 if this priority is less than two. - */ - rtems_task_priority priority; - - /** - * @brief Task stack size. - */ - size_t stack_size; - - /** - * @brief Login check function. - * - * Method used for login checks. Use @c NULL to disable a login check. - */ - rtems_shell_login_check_t login_check; - - /** - * @brief Keep standard IO of the caller. - * - * Telnet takes over the standard input, output and error associated with - * task, if this parameter is set to @c true. In this case, it will @b not - * listen on any sockets. When this parameter is @c false, Telnet will - * create other tasks for the shell which listen on sockets. - */ - bool keep_stdio; -} rtems_telnetd_config_table; - -/** - * @brief Start the Telnet subsystem with the provided configuration. - */ -rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config); - -/** - * @brief Telnet configuration. - * - * The application must provide this configuration table. It is used by - * rtems_telnetd_initialize() to configure the Telnet subsystem. Do not modify - * the entries after the intialization since it is used internally. - */ -extern rtems_telnetd_config_table rtems_telnetd_config; - -/** - * @brief Initializes the Telnet subsystem. - * - * Uses the application provided @ref rtems_telnetd_config configuration table. - */ -rtems_status_code rtems_telnetd_initialize(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/rtemsbsd/telnetd/check_passwd.c b/rtemsbsd/telnetd/check_passwd.c deleted file mode 100644 index 9e3f2c98..00000000 --- a/rtemsbsd/telnetd/check_passwd.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann , 2003-2007 - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - * - * Copyright (c) 2009 embedded brains GmbH and others. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "passwd.h" - -char *__des_crypt_r( const char *, const char *, char *, int); - -/** - * @brief Standard Telnet login check that uses DES to encrypt the passphrase. - * - * Takes a @a passphrase, encrypts it and compares it to the encrypted - * passphrase in the @c TELNETD_PASSWD environment variable. No password is - * required if @c TELNETD_PASSWD is unset. The argument @a user is ignored. - */ -bool rtems_telnetd_login_check( - const char *user, - const char *passphrase -) -{ - char *pw = getenv( "TELNETD_PASSWD"); - char cryptbuf [21]; - char salt [3]; - - if (pw == NULL || strlen( pw) == 0) { - #ifdef TELNETD_DEFAULT_PASSWD - pw = TELNETD_DEFAULT_PASSWD; - #else - return true; - #endif - } - - strncpy( salt, pw, 2); - salt [2] = '\0'; - - return strcmp( - __des_crypt_r( passphrase, salt, cryptbuf, sizeof( cryptbuf)), - pw - ) == 0; -} diff --git a/rtemsbsd/telnetd/des.c b/rtemsbsd/telnetd/des.c deleted file mode 100644 index 542e8968..00000000 --- a/rtemsbsd/telnetd/des.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * FreeSec: libcrypt for NetBSD - * - * Copyright (c) 1994 David Burren - * All rights reserved. - * - * Ported to RTEMS and made reentrant by Till Straumann, 9/2003 - * - * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet - * this file should now *only* export crypt(), in order to make - * binaries of libcrypt exportable from the USA - * - * Adapted for FreeBSD-4.0 by Mark R V Murray - * this file should now *only* export crypt_des(), in order to make - * a module that can be optionally included in libcrypt. - * - * 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 of the author nor the names of other contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * This is an original implementation of the DES and the crypt(3) interfaces - * by David Burren . - * - * An excellent reference on the underlying algorithm (and related - * algorithms) is: - * - * B. Schneier, Applied Cryptography: protocols, algorithms, - * and source code in C, John Wiley & Sons, 1994. - * - * Note that in that book's description of DES the lookups for the initial, - * pbox, and final permutations are inverted (this has been brought to the - * attention of the author). A list of errata for this book has been - * posted to the sci.crypt newsgroup by the author and is available for FTP. - * - * ARCHITECTURE ASSUMPTIONS: - * It is assumed that the 8-byte arrays passed by reference can be - * addressed as arrays of u_int32_t's (ie. the CPU is not picky about - * alignment). - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define __FORCE_GLIBC -#include -#include -#include -#include -#ifndef __rtems__ -#include -#include -#endif -#include -#include - -#define REENTRANT -/* Re-entrantify me -- all this junk needs to be in - * struct crypt_data to make this really reentrant... */ - -/* TS; not really - only the stuff in Des_Context */ -static struct fixed1 { -u_char inv_key_perm[64]; -u_char inv_comp_perm[56]; -u_char u_sbox[8][64]; -u_char un_pbox[32]; -} des1_f; -static struct fixed2 { -u_int32_t ip_maskl[8][256], ip_maskr[8][256]; -} des2_f; -static struct fixed3 { -u_int32_t fp_maskl[8][256], fp_maskr[8][256]; -} des3_f; -static struct fixed4 { -u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; -u_int32_t comp_maskl[8][128], comp_maskr[8][128]; -} des4_f; - -#define inv_key_perm des1_f.inv_key_perm -#define inv_comp_perm des1_f.inv_comp_perm -#define u_sbox des1_f.u_sbox -#define un_pbox des1_f.un_pbox -#define ip_maskl des2_f.ip_maskl -#define ip_maskr des2_f.ip_maskr -#define fp_maskl des3_f.fp_maskl -#define fp_maskr des3_f.fp_maskr -#define key_perm_maskl des4_f.key_perm_maskl -#define key_perm_maskr des4_f.key_perm_maskr -#define comp_maskl des4_f.comp_maskl -#define comp_maskr des4_f.comp_maskr - -/* These need to be maintained per-process */ -struct Des_Context { -u_int32_t en_keysl[16], en_keysr[16]; -u_int32_t de_keysl[16], de_keysr[16]; -u_int32_t saltbits; -u_int32_t old_salt; -u_int32_t old_rawkey0, old_rawkey1; -}; - -#ifndef REENTRANT -static struct Des_Context single; -#endif - -#define en_keysl des_ctx->en_keysl -#define en_keysr des_ctx->en_keysr -#define de_keysl des_ctx->de_keysl -#define de_keysr des_ctx->de_keysr -#define saltbits des_ctx->saltbits -#define old_salt des_ctx->old_salt -#define old_rawkey0 des_ctx->old_rawkey0 -#define old_rawkey1 des_ctx->old_rawkey1 - -/* Static stuff that stays resident and doesn't change after - * being initialized, and therefore doesn't need to be made - * reentrant. */ -static u_char init_perm[64], final_perm[64]; -static u_char m_sbox[4][4096]; -static u_int32_t psbox[4][256]; - - - - -/* A pile of data */ -static const u_char ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static const u_char IP[64] = { - 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 -}; - -static const u_char key_perm[56] = { - 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, - 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 -}; - -static const u_char key_shifts[16] = { - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 -}; - -static const u_char comp_perm[48] = { - 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 -}; - -/* - * No E box is used, as it's replaced by some ANDs, shifts, and ORs. - */ - -static const u_char sbox[8][64] = { - { - 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, - 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, - 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, - 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 - }, - { - 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, - 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, - 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, - 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 - }, - { - 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, - 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, - 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, - 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 - }, - { - 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, - 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, - 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, - 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 - }, - { - 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, - 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, - 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, - 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 - }, - { - 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, - 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, - 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, - 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 - }, - { - 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, - 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, - 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, - 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 - }, - { - 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, - 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, - 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, - 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 - } -}; - -static const u_char pbox[32] = { - 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, - 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 -}; - -static const u_int32_t bits32[32] = -{ - 0x80000000, 0x40000000, 0x20000000, 0x10000000, - 0x08000000, 0x04000000, 0x02000000, 0x01000000, - 0x00800000, 0x00400000, 0x00200000, 0x00100000, - 0x00080000, 0x00040000, 0x00020000, 0x00010000, - 0x00008000, 0x00004000, 0x00002000, 0x00001000, - 0x00000800, 0x00000400, 0x00000200, 0x00000100, - 0x00000080, 0x00000040, 0x00000020, 0x00000010, - 0x00000008, 0x00000004, 0x00000002, 0x00000001 -}; - -static const u_char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; -static const u_int32_t *bits28, *bits24; - - -static int -ascii_to_bin(char ch) -{ - if (ch > 'z') - return(0); - if (ch >= 'a') - return(ch - 'a' + 38); - if (ch > 'Z') - return(0); - if (ch >= 'A') - return(ch - 'A' + 12); - if (ch > '9') - return(0); - if (ch >= '.') - return(ch - '.'); - return(0); -} - -struct Des_Context * -des_ctx_init(void) -{ -struct Des_Context *des_ctx; -#ifdef REENTRANT - des_ctx = malloc(sizeof(*des_ctx)); -#else - des_ctx = &single; -#endif - old_rawkey0 = old_rawkey1 = 0L; - saltbits = 0L; - old_salt = 0L; - - return des_ctx; -} - -static void -des_init(void) -{ - int i, j, b, k, inbit, obit; - u_int32_t *p, *il, *ir, *fl, *fr; - static int des_initialised = 0; - - if (des_initialised==1) - return; - -#ifndef REENTRANT - des_ctx_init(); -#endif - - bits24 = (bits28 = bits32 + 4) + 4; - - /* - * Invert the S-boxes, reordering the input bits. - */ - for (i = 0; i < 8; i++) - for (j = 0; j < 64; j++) { - b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); - u_sbox[i][j] = sbox[i][b]; - } - - /* - * Convert the inverted S-boxes into 4 arrays of 8 bits. - * Each will handle 12 bits of the S-box input. - */ - for (b = 0; b < 4; b++) - for (i = 0; i < 64; i++) - for (j = 0; j < 64; j++) - m_sbox[b][(i << 6) | j] = - (u_char)((u_sbox[(b << 1)][i] << 4) | - u_sbox[(b << 1) + 1][j]); - - /* - * Set up the initial & final permutations into a useful form, and - * initialise the inverted key permutation. - */ - for (i = 0; i < 64; i++) { - init_perm[final_perm[i] = IP[i] - 1] = (u_char)i; - inv_key_perm[i] = 255; - } - - /* - * Invert the key permutation and initialise the inverted key - * compression permutation. - */ - for (i = 0; i < 56; i++) { - inv_key_perm[key_perm[i] - 1] = (u_char)i; - inv_comp_perm[i] = 255; - } - - /* - * Invert the key compression permutation. - */ - for (i = 0; i < 48; i++) { - inv_comp_perm[comp_perm[i] - 1] = (u_char)i; - } - - /* - * Set up the OR-mask arrays for the initial and final permutations, - * and for the key initial and compression permutations. - */ - for (k = 0; k < 8; k++) { - for (i = 0; i < 256; i++) { - *(il = &ip_maskl[k][i]) = 0L; - *(ir = &ip_maskr[k][i]) = 0L; - *(fl = &fp_maskl[k][i]) = 0L; - *(fr = &fp_maskr[k][i]) = 0L; - for (j = 0; j < 8; j++) { - inbit = 8 * k + j; - if (i & bits8[j]) { - if ((obit = init_perm[inbit]) < 32) - *il |= bits32[obit]; - else - *ir |= bits32[obit-32]; - if ((obit = final_perm[inbit]) < 32) - *fl |= bits32[obit]; - else - *fr |= bits32[obit - 32]; - } - } - } - for (i = 0; i < 128; i++) { - *(il = &key_perm_maskl[k][i]) = 0L; - *(ir = &key_perm_maskr[k][i]) = 0L; - for (j = 0; j < 7; j++) { - inbit = 8 * k + j; - if (i & bits8[j + 1]) { - if ((obit = inv_key_perm[inbit]) == 255) - continue; - if (obit < 28) - *il |= bits28[obit]; - else - *ir |= bits28[obit - 28]; - } - } - *(il = &comp_maskl[k][i]) = 0L; - *(ir = &comp_maskr[k][i]) = 0L; - for (j = 0; j < 7; j++) { - inbit = 7 * k + j; - if (i & bits8[j + 1]) { - if ((obit=inv_comp_perm[inbit]) == 255) - continue; - if (obit < 24) - *il |= bits24[obit]; - else - *ir |= bits24[obit - 24]; - } - } - } - } - - /* - * Invert the P-box permutation, and convert into OR-masks for - * handling the output of the S-box arrays setup above. - */ - for (i = 0; i < 32; i++) - un_pbox[pbox[i] - 1] = (u_char)i; - - for (b = 0; b < 4; b++) - for (i = 0; i < 256; i++) { - *(p = &psbox[b][i]) = 0L; - for (j = 0; j < 8; j++) { - if (i & bits8[j]) - *p |= bits32[un_pbox[8 * b + j]]; - } - } - - des_initialised = 1; -} - - -static void -setup_salt(long salt, struct Des_Context *des_ctx) -{ - u_int32_t obit, saltbit; - int i; - - if (salt == old_salt) - return; - old_salt = salt; - - saltbits = 0L; - saltbit = 1; - obit = 0x800000; - for (i = 0; i < 24; i++) { - if (salt & saltbit) - saltbits |= obit; - saltbit <<= 1; - obit >>= 1; - } -} - - -static int -des_setkey(const char *key, struct Des_Context *des_ctx) -{ - u_int32_t k0, k1, rawkey0, rawkey1; - int shifts, round; - - des_init(); - - rawkey0 = ntohl(*(const u_int32_t *) key); - rawkey1 = ntohl(*(const u_int32_t *) (key + 4)); - - if ((rawkey0 | rawkey1) - && rawkey0 == old_rawkey0 - && rawkey1 == old_rawkey1) { - /* - * Already setup for this key. - * This optimisation fails on a zero key (which is weak and - * has bad parity anyway) in order to simplify the starting - * conditions. - */ - return(0); - } - old_rawkey0 = rawkey0; - old_rawkey1 = rawkey1; - - /* - * Do key permutation and split into two 28-bit subkeys. - */ - k0 = key_perm_maskl[0][rawkey0 >> 25] - | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] - | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] - | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] - | key_perm_maskl[4][rawkey1 >> 25] - | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] - | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] - | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; - k1 = key_perm_maskr[0][rawkey0 >> 25] - | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] - | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] - | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] - | key_perm_maskr[4][rawkey1 >> 25] - | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] - | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] - | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; - /* - * Rotate subkeys and do compression permutation. - */ - shifts = 0; - for (round = 0; round < 16; round++) { - u_int32_t t0, t1; - - shifts += key_shifts[round]; - - t0 = (k0 << shifts) | (k0 >> (28 - shifts)); - t1 = (k1 << shifts) | (k1 >> (28 - shifts)); - - de_keysl[15 - round] = - en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] - | comp_maskl[1][(t0 >> 14) & 0x7f] - | comp_maskl[2][(t0 >> 7) & 0x7f] - | comp_maskl[3][t0 & 0x7f] - | comp_maskl[4][(t1 >> 21) & 0x7f] - | comp_maskl[5][(t1 >> 14) & 0x7f] - | comp_maskl[6][(t1 >> 7) & 0x7f] - | comp_maskl[7][t1 & 0x7f]; - - de_keysr[15 - round] = - en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] - | comp_maskr[1][(t0 >> 14) & 0x7f] - | comp_maskr[2][(t0 >> 7) & 0x7f] - | comp_maskr[3][t0 & 0x7f] - | comp_maskr[4][(t1 >> 21) & 0x7f] - | comp_maskr[5][(t1 >> 14) & 0x7f] - | comp_maskr[6][(t1 >> 7) & 0x7f] - | comp_maskr[7][t1 & 0x7f]; - } - return(0); -} - - -static int -do_des( u_int32_t l_in, u_int32_t r_in, u_int32_t *l_out, u_int32_t *r_out, int count, struct Des_Context *des_ctx) -{ - /* - * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. - */ - u_int32_t l, r, *kl, *kr, *kl1, *kr1; - u_int32_t f, r48l, r48r; - int round; - - if (count == 0) { - return(1); - } else if (count > 0) { - /* - * Encrypting - */ - kl1 = en_keysl; - kr1 = en_keysr; - } else { - /* - * Decrypting - */ - count = -count; - kl1 = de_keysl; - kr1 = de_keysr; - } - - /* - * Do initial permutation (IP). - */ - l = ip_maskl[0][l_in >> 24] - | ip_maskl[1][(l_in >> 16) & 0xff] - | ip_maskl[2][(l_in >> 8) & 0xff] - | ip_maskl[3][l_in & 0xff] - | ip_maskl[4][r_in >> 24] - | ip_maskl[5][(r_in >> 16) & 0xff] - | ip_maskl[6][(r_in >> 8) & 0xff] - | ip_maskl[7][r_in & 0xff]; - r = ip_maskr[0][l_in >> 24] - | ip_maskr[1][(l_in >> 16) & 0xff] - | ip_maskr[2][(l_in >> 8) & 0xff] - | ip_maskr[3][l_in & 0xff] - | ip_maskr[4][r_in >> 24] - | ip_maskr[5][(r_in >> 16) & 0xff] - | ip_maskr[6][(r_in >> 8) & 0xff] - | ip_maskr[7][r_in & 0xff]; - - while (count--) { - /* - * Do each round. - */ - kl = kl1; - kr = kr1; - round = 16; - while (round--) { - /* - * Expand R to 48 bits (simulate the E-box). - */ - r48l = ((r & 0x00000001) << 23) - | ((r & 0xf8000000) >> 9) - | ((r & 0x1f800000) >> 11) - | ((r & 0x01f80000) >> 13) - | ((r & 0x001f8000) >> 15); - - r48r = ((r & 0x0001f800) << 7) - | ((r & 0x00001f80) << 5) - | ((r & 0x000001f8) << 3) - | ((r & 0x0000001f) << 1) - | ((r & 0x80000000) >> 31); - /* - * Do salting for crypt() and friends, and - * XOR with the permuted key. - */ - f = (r48l ^ r48r) & saltbits; - r48l ^= f ^ *kl++; - r48r ^= f ^ *kr++; - /* - * Do sbox lookups (which shrink it back to 32 bits) - * and do the pbox permutation at the same time. - */ - f = psbox[0][m_sbox[0][r48l >> 12]] - | psbox[1][m_sbox[1][r48l & 0xfff]] - | psbox[2][m_sbox[2][r48r >> 12]] - | psbox[3][m_sbox[3][r48r & 0xfff]]; - /* - * Now that we've permuted things, complete f(). - */ - f ^= l; - l = r; - r = f; - } - r = l; - l = f; - } - /* - * Do final permutation (inverse of IP). - */ - *l_out = fp_maskl[0][l >> 24] - | fp_maskl[1][(l >> 16) & 0xff] - | fp_maskl[2][(l >> 8) & 0xff] - | fp_maskl[3][l & 0xff] - | fp_maskl[4][r >> 24] - | fp_maskl[5][(r >> 16) & 0xff] - | fp_maskl[6][(r >> 8) & 0xff] - | fp_maskl[7][r & 0xff]; - *r_out = fp_maskr[0][l >> 24] - | fp_maskr[1][(l >> 16) & 0xff] - | fp_maskr[2][(l >> 8) & 0xff] - | fp_maskr[3][l & 0xff] - | fp_maskr[4][r >> 24] - | fp_maskr[5][(r >> 16) & 0xff] - | fp_maskr[6][(r >> 8) & 0xff] - | fp_maskr[7][r & 0xff]; - return(0); -} - - -#if 0 -static int -des_cipher(const char *in, char *out, u_int32_t salt, int count) -{ - u_int32_t l_out, r_out, rawl, rawr; - int retval; - union { - u_int32_t *ui32; - const char *c; - } trans; - - des_init(); - - setup_salt(salt); - - trans.c = in; - rawl = ntohl(*trans.ui32++); - rawr = ntohl(*trans.ui32); - - retval = do_des(rawl, rawr, &l_out, &r_out, count); - - trans.c = out; - *trans.ui32++ = htonl(l_out); - *trans.ui32 = htonl(r_out); - return(retval); -} -#endif - - -#ifndef REENTRANT -void -setkey(const char *key) -{ - int i, j; - u_int32_t packed_keys[2]; - u_char *p; - - p = (u_char *) packed_keys; - - for (i = 0; i < 8; i++) { - p[i] = 0; - for (j = 0; j < 8; j++) - if (*key++ & 1) - p[i] |= bits8[j]; - } - des_setkey(p, &single); -} -#endif - - -#ifndef REENTRANT -void -encrypt(char *block, int flag) -{ - u_int32_t io[2]; - u_char *p; - int i, j; - - des_init(); - - setup_salt(0L, &single); - p = block; - for (i = 0; i < 2; i++) { - io[i] = 0L; - for (j = 0; j < 32; j++) - if (*p++ & 1) - io[i] |= bits32[j]; - } - do_des(io[0], io[1], io, io + 1, flag ? -1 : 1, &single); - for (i = 0; i < 2; i++) - for (j = 0; j < 32; j++) - block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0; -} - -#endif - -char * -__des_crypt_r(const char *key, const char *setting, char *output, int sz) -{ - char *rval = 0; - struct Des_Context *des_ctx; - u_int32_t count, salt, l, r0, r1, keybuf[2]; - u_char *p, *q; - - if (sz < 21) - return NULL; - - des_init(); - des_ctx = des_ctx_init(); - - /* - * Copy the key, shifting each character up by one bit - * and padding with zeros. - */ - q = (u_char *)keybuf; - while (q - (u_char *)keybuf - 8) { - *q++ = *key << 1; - if (*(q - 1)) - key++; - } - if (des_setkey((char *)keybuf, des_ctx)) - goto bailout; - -#if 0 - if (*setting == _PASSWORD_EFMT1) { - int i; - /* - * "new"-style: - * setting - underscore, 4 bytes of count, 4 bytes of salt - * key - unlimited characters - */ - for (i = 1, count = 0L; i < 5; i++) - count |= ascii_to_bin(setting[i]) << ((i - 1) * 6); - - for (i = 5, salt = 0L; i < 9; i++) - salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6); - - while (*key) { - /* - * Encrypt the key with itself. - */ - if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1)) - goto bailout; - /* - * And XOR with the next 8 characters of the key. - */ - q = (u_char *)keybuf; - while (q - (u_char *)keybuf - 8 && *key) - *q++ ^= *key++ << 1; - - if (des_setkey((char *)keybuf)) - goto bailout; - } - strncpy(output, setting, 9); - - /* - * Double check that we weren't given a short setting. - * If we were, the above code will probably have created - * wierd values for count and salt, but we don't really care. - * Just make sure the output string doesn't have an extra - * NUL in it. - */ - output[9] = '\0'; - p = (u_char *)output + strlen(output); - } else -#endif - { - /* - * "old"-style: - * setting - 2 bytes of salt - * key - up to 8 characters - */ - count = 25; - - salt = (ascii_to_bin(setting[1]) << 6) - | ascii_to_bin(setting[0]); - - output[0] = setting[0]; - /* - * If the encrypted password that the salt was extracted from - * is only 1 character long, the salt will be corrupted. We - * need to ensure that the output string doesn't have an extra - * NUL in it! - */ - output[1] = setting[1] ? setting[1] : output[0]; - - p = (u_char *)output + 2; - } - setup_salt(salt, des_ctx); - /* - * Do it. - */ - if (do_des(0L, 0L, &r0, &r1, (int)count, des_ctx)) - goto bailout; - /* - * Now encode the result... - */ - l = (r0 >> 8); - *p++ = ascii64[(l >> 18) & 0x3f]; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - - l = (r0 << 16) | ((r1 >> 16) & 0xffff); - *p++ = ascii64[(l >> 18) & 0x3f]; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - - l = r1 << 2; - *p++ = ascii64[(l >> 12) & 0x3f]; - *p++ = ascii64[(l >> 6) & 0x3f]; - *p++ = ascii64[l & 0x3f]; - *p = 0; - - rval = output; -bailout: - free(des_ctx); - return rval; -} - -char * -__des_crypt(const char *key, const char *setting) -{ - static char output[21]; - return __des_crypt_r(key, setting, output, sizeof(output)); -} - - -#ifdef DEBUG - -void -des_snap(void **pf, void **pd) -{ - uint8* pfc; - *pf = malloc(sizeof(struct fixed1) + sizeof(struct fixed2) + sizeof(struct fixed3) + sizeof(struct fixed4)); - pfc = *pf; - memcpy(pfc, &des1_f, sizeof(des1_f)); - pfc += sizeof(des1_f); - memcpy(pfc, &des2_f, sizeof(des2_f)); - pfc += sizeof(des2_f); - memcpy(pfc, &des3_f, sizeof(des3_f)); - pfc += sizeof(des3_f); - memcpy(pfc, &des4_f, sizeof(des4_f)); -// *pd = malloc(sizeof(struct Des_Context)); -// memcpy(*pd, &des_ctx, sizeof(des_ctx)); -} - -void -des_check(void *pf, void *pd) -{ - uint8* pfc1, pfc2, pfc3, pfc4; - pfc1 = pf; - pfc2 = pfc1 + sizeof(des1_f); - pfc3 = pfc2 + sizeof(des2_f); - pfc4 = pfc3 + sizeof(des3_f); - printf("Fixed: do%s differ"/*", Context: do%s differ"*/"\n", - (memcmp(pfc1, &des1_f, sizeof(des1_f)) || - memcmp(pfc2, &des2_f, sizeof(des2_f)) || - memcmp(pfc3, &des4_f, sizeof(des3_f)) || - memcmp(pfc4, &des4_f, sizeof(des4_f))) ? "" : "nt"); -} - -#endif diff --git a/rtemsbsd/telnetd/passwd.h b/rtemsbsd/telnetd/passwd.h deleted file mode 100644 index 8d5c299a..00000000 --- a/rtemsbsd/telnetd/passwd.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Define a default password for telnetd here. - * NOTES: - * - this can be overridden at run-time by setting - * the "TELNETD_PASSWD" environment variable. - * As soon as that variable is set, the new password - * is effective - no need to restart telnetd. - * - this must be set to an _encrypted_ password, NOT - * the cleartext. Use the 'genpw' utility to generate - * a password string: - * - * 1) Compile 'genpw.c' for the HOST, i.e. - * cc -o genpw genpw.c -lcrypt - * 1) delete an old password definition from this file. - * 2) run './genpw >> passwd.h'. This will append - * a new definition to this file. - * - * - if no password is defined here, no authentication - * is needed, i.e. telnet is open to the world. - * - * T. Straumann - */ - -/* #undef TELNETD_DEFAULT_PASSWD */ -/* Default password: 'rtems' */ -#define TELNETD_DEFAULT_PASSWD "tduDcyLX12owo" diff --git a/rtemsbsd/telnetd/pty.c b/rtemsbsd/telnetd/pty.c deleted file mode 100644 index 727e5ebf..00000000 --- a/rtemsbsd/telnetd/pty.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * /dev/ptyXX (Support for pseudo-terminals) - * - * Original Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es) - * May 2001 - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Till Straumann - * - * - converted into a loadable module - * - NAWS support / ioctls for querying/setting the window - * size added. - * - don't delete the running task when the connection - * is closed. Rather let 'read()' return a 0 count so - * they may cleanup. Some magic hack works around termios - * limitation. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define DEBUG_WH (1<<0) -#define DEBUG_DETAIL (1<<1) - -/* #define DEBUG DEBUG_WH */ - -/*-----------------------------------------*/ -#include -#include -#include -#include -#include -#include -#include -#include -/*-----------------------------------------*/ -#include -#include -#include -#include -#include -/*-----------------------------------------*/ -#define IAC_ESC 255 -#define IAC_DONT 254 -#define IAC_DO 253 -#define IAC_WONT 252 -#define IAC_WILL 251 -#define IAC_SB 250 -#define IAC_GA 249 -#define IAC_EL 248 -#define IAC_EC 247 -#define IAC_AYT 246 -#define IAC_AO 245 -#define IAC_IP 244 -#define IAC_BRK 243 -#define IAC_DMARK 242 -#define IAC_NOP 241 -#define IAC_SE 240 -#define IAC_EOR 239 - -#define SB_MAX 16 - -extern int rtems_telnetd_maximum_ptys; - -struct pty_tt; -typedef struct pty_tt pty_t; - -struct pty_tt { - char *devname; - struct rtems_termios_tty *ttyp; - tcflag_t c_cflag; - int opened; - int socket; - int last_cr; - unsigned iac_mode; - unsigned char sb_buf[SB_MAX]; - int sb_ind; - int width; - int height; -}; - - -static int telnet_pty_inited=FALSE; -static pty_t *telnet_ptys; - -static rtems_device_major_number pty_major; - -static -int send_iac(int minor,unsigned char mode,unsigned char option) -{ - unsigned char buf[3]; - - buf[0]=IAC_ESC; - buf[1]=mode; - buf[2]=option; - return write(telnet_ptys[minor].socket,buf,sizeof(buf)); -} - -/* This procedure returns the devname for a pty slot free. - * If not slot availiable (field socket>=0) - * then the socket argument is closed - */ - -char * telnet_get_pty(int socket) -{ - int ndx; - - if (telnet_pty_inited) { -#if 0 - if ( rtems_telnetd_maximum_ptys < 5 ) - rtems_telnetd_maximum_ptys = 5; - - telnet_ptys = malloc( rtems_telnetd_maximum_ptys * sizeof (pty_t) ); -#endif - if ( !telnet_ptys ) { - return NULL; - } - - for (ndx=0;ndxsb_buf[0]) { - case 31: /* NAWS */ - pty->width = (pty->sb_buf[1]<<8) + pty->sb_buf[2]; - pty->height = (pty->sb_buf[3]<<8) + pty->sb_buf[4]; -#if DEBUG & DEBUG_WH - fprintf(stderr, - "Setting width/height to %ix%i\n", - pty->width, - pty->height); -#endif - break; - default: - break; - } - return 0; -} - -static int read_pty(int minor) -{ /* Characters written to the client side*/ - unsigned char value; - unsigned int omod; - int count; - int result; - pty_t *pty=telnet_ptys+minor; - - count=read(pty->socket,&value,sizeof(value)); - if (count<0) - return -1; - - if (count<1) { - /* Unfortunately, there is no way of passing an EOF - * condition through the termios driver. Hence, we - * resort to an ugly hack. Setting cindex>ccount - * causes the termios driver to return a read count - * of '0' which is what we want here. We leave - * 'errno' untouched. - */ - pty->ttyp->cindex=pty->ttyp->ccount+1; - return pty->ttyp->termios.c_cc[VEOF]; - }; - - omod=pty->iac_mode; - pty->iac_mode=0; - switch(omod & 0xff) { - case IAC_ESC: - switch(value) { - case IAC_ESC : - /* in case this is an ESC ESC sequence in SB mode */ - pty->iac_mode = omod>>8; - return IAC_ESC; - case IAC_DONT: - case IAC_DO : - case IAC_WONT: - case IAC_WILL: - pty->iac_mode=value; - return -1; - case IAC_SB : -#if DEBUG & DEBUG_DETAIL - printk("SB\n"); -#endif - pty->iac_mode=value; - pty->sb_ind=0; - return -100; - case IAC_GA : - return -1; - case IAC_EL : - return 0x03; /* Ctrl-C*/ - case IAC_EC : - return '\b'; - case IAC_AYT : - write(pty->socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP)); - return -1; - case IAC_AO : - return -1; - case IAC_IP : - write(pty->socket,IAC_IP_RSP,strlen(IAC_IP_RSP)); - return -1; - case IAC_BRK : - write(pty->socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP)); - return -1; - case IAC_DMARK: - return -2; - case IAC_NOP : - return -1; - case IAC_SE : -#if DEBUG & DEBUG_DETAIL - { - int i; - printk("SE"); - for (i=0; isb_ind; i++) - printk(" %02x",pty->sb_buf[i]); - printk("\n"); - } -#endif - handleSB(pty); - return -101; - case IAC_EOR : - return -102; - default : - return -1; - }; - break; - - case IAC_SB: - pty->iac_mode=omod; - if (IAC_ESC==value) { - pty->iac_mode=(omod<<8)|value; - } else { - if (pty->sb_ind < SB_MAX) - pty->sb_buf[pty->sb_ind++]=value; - } - return -1; - - case IAC_WILL: - if (value==34){ - send_iac(minor,IAC_DONT, 34); /*LINEMODE*/ - send_iac(minor,IAC_DO , 1); /*ECHO */ - } else if (value==31) { - send_iac(minor,IAC_DO , 31); /*NAWS */ -#if DEBUG & DEBUG_DETAIL - printk("replied DO NAWS\n"); -#endif - } else { - send_iac(minor,IAC_DONT,value); - } - return -1; - case IAC_DONT: - return -1; - case IAC_DO : - if (value==3) { - send_iac(minor,IAC_WILL, 3); /* GO AHEAD*/ - } else if (value==1) { - send_iac(minor,IAC_WILL, 1); /* ECHO */ - } else { - send_iac(minor,IAC_WONT,value); - }; - return -1; - case IAC_WONT: - if (value==1) { - send_iac(minor,IAC_WILL, 1); - } else { /* ECHO */ - send_iac(minor,IAC_WONT,value); - } - return -1; - default: - if (value==IAC_ESC) { - pty->iac_mode=value; - return -1; - } else { - result=value; - if ( 0 - /* map CRLF to CR for symmetry */ - || ((value=='\n') && pty->last_cr) - /* map telnet CRNUL to CR down here */ - || ((value==0) && pty->last_cr) - ) result=-1; - pty->last_cr=(value=='\r'); - return result; - }; - }; - /* should never get here but keep compiler happy */ - return -1; -} - -/*-----------------------------------------------------------*/ -static int ptySetAttributes(int minor,const struct termios *t); -static int ptyPollInitialize(int major,int minor,void * arg) ; -static int ptyShutdown(int major,int minor,void * arg) ; -static ssize_t ptyPollWrite(int minor, const char * buf, size_t len) ; -static int ptyPollRead(int minor) ; -static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ; -/*-----------------------------------------------------------*/ -/* Set the 'Hardware' */ -/*-----------------------------------------------------------*/ -static int -ptySetAttributes(int minor,const struct termios *t) { - if (minorc_cflag; - } else { - return -1; - }; - return 0; -} -/*-----------------------------------------------------------*/ -static int -ptyPollInitialize(int major,int minor,void * arg) { - rtems_libio_open_close_args_t * args = (rtems_libio_open_close_args_t*)arg; - struct termios t; - if (minoriop->data1; - telnet_ptys[minor].iac_mode=0; - telnet_ptys[minor].sb_ind=0; - telnet_ptys[minor].width=0; - telnet_ptys[minor].height=0; - t.c_cflag=B9600|CS8;/* termios default */ - return ptySetAttributes(minor,&t); - } else { - return -1; - } -} -/*-----------------------------------------------------------*/ -static int -ptyShutdown(int major,int minor,void * arg) { - if (minor=0) close(telnet_ptys[minor].socket); - telnet_ptys[minor].socket=-1; - chown(telnet_ptys[minor].devname,2,0); - } else { - return -1; - } - return 0; -} -/*-----------------------------------------------------------*/ -/* Write Characters into pty device */ -/*-----------------------------------------------------------*/ -static ssize_t -ptyPollWrite(int minor, const char * buf, size_t len) { - size_t count; - if (minorbuffer; - pty_t *p = &telnet_ptys[minor]; - - switch (args->command) { - - case TIOCGWINSZ: - - wp->ws_row = p->height; - wp->ws_col = p->width; - args->ioctl_return=0; -#if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), returning %ix%i\n", - wp->ws_col, - wp->ws_row); -#endif - - return RTEMS_SUCCESSFUL; - - case TIOCSWINSZ: -#if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), setting %ix%i\n", - wp->ws_col, - wp->ws_row); -#endif - - p->height = wp->ws_row; - p->width = wp->ws_col; - args->ioctl_return=0; - - return RTEMS_SUCCESSFUL; - - default: - - break; - } - - return rtems_termios_ioctl(arg); -} - -static rtems_driver_address_table drvPty = { - my_pty_initialize, - my_pty_open, - my_pty_close, - my_pty_read, - my_pty_write, - my_pty_control -}; - -/*-----------------------------------------------------------*/ -static const rtems_termios_callbacks pty_poll_callbacks = { - ptyPollInitialize, /* FirstOpen */ - ptyShutdown, /* LastClose */ - ptyPollRead, /* PollRead */ - ptyPollWrite, /* Write */ - ptySetAttributes, /* setAttributes */ - NULL, /* stopRemoteTX */ - NULL, /* StartRemoteTX */ - 0 /* outputUsesInterrupts */ -}; -/*-----------------------------------------------------------*/ -static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) { - return &pty_poll_callbacks; -} -/*-----------------------------------------------------------*/ - -static int pty_do_initialize(void) -{ - if ( !telnet_pty_inited ) { - if (RTEMS_SUCCESSFUL==rtems_io_register_driver(0, &drvPty, &pty_major)) - telnet_pty_inited=TRUE; - else - fprintf(stderr,"WARNING: registering the PTY driver FAILED\n"); - } - return telnet_pty_inited; -} - -int telnet_pty_initialize(void) -{ - return pty_do_initialize(); -} - -int telnet_pty_finalize(void) -{ - return pty_do_finalize(); -} diff --git a/rtemsbsd/telnetd/telnetd-init.c b/rtemsbsd/telnetd/telnetd-init.c deleted file mode 100644 index e723def0..00000000 --- a/rtemsbsd/telnetd/telnetd-init.c +++ /dev/null @@ -1,33 +0,0 @@ -/***********************************************************/ -/* - * - * The telnet DAEMON - * - * Author: 17,may 2001 - * - * WORK: fernando.ruiz@ctv.es - * HOME: correo@fernando-ruiz.com - * - * Copyright (c) 2009 embedded brains GmbH and others. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -rtems_status_code rtems_telnetd_initialize(void) -{ - return rtems_telnetd_start(&rtems_telnetd_config); -} diff --git a/rtemsbsd/telnetd/telnetd.c b/rtemsbsd/telnetd/telnetd.c deleted file mode 100644 index 7fe603fa..00000000 --- a/rtemsbsd/telnetd/telnetd.c +++ /dev/null @@ -1,517 +0,0 @@ -/***********************************************************/ -/* - * - * The telnet DAEMON - * - * Author: 17,may 2001 - * - * WORK: fernando.ruiz@ctv.es - * HOME: correo@fernando-ruiz.com - * - * After start the net you can start this daemon. - * It uses the previously inited pseudo-terminales (pty.c) - * getting a new terminal with getpty(). This function - * gives a terminal name passing a opened socket like parameter. - * - * With register_telnetd() you add a new command in the shell to start - * this daemon interactively. (Login in /dev/console of course) - * - * Sorry but OOB is not still implemented. (This is the first version) - * - * Till Straumann - * - made the 'shell' interface more generic, i.e. it is now - * possible to have 'telnetd' run an arbitrary 'shell' - * program. - * - * Copyright (c) 2009 embedded brains GmbH and others. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define PARANOIA - -extern char *telnet_get_pty(int socket); -extern int telnet_pty_initialize(void); - -struct shell_args { - char *devname; - void *arg; - char peername[16]; - char delete_myself; -}; - -typedef union uni_sa { - struct sockaddr_in sin; - struct sockaddr sa; -} uni_sa; - -static int sockpeername(int sock, char *buf, int bufsz); - -rtems_id telnetd_dflt_spawn( - const char *name, - unsigned priority, - unsigned stackSize, - void (*fn)(void*), - void *fnarg -); - -/***********************************************************/ -static rtems_telnetd_config_table* telnetd_config; -static rtems_id telnetd_task_id; - -/* - * chrisj: this variable was global and with no declared interface in a header - * file and with no means to set it so I have stopped it being global; - * if this breaks any user they will have be to provide a formal - * interface to get this change reverted. - */ -static const rtems_id (*telnetd_spawn_task)( - const char *, - unsigned, - unsigned, - void (*)(void*), - void * -) = telnetd_dflt_spawn; - -static char *grab_a_Connection( - int des_socket, - uni_sa *srv, - char *peername, - int sz -) -{ - char *rval = 0; - socklen_t size_adr = sizeof(srv->sin); - int acp_sock; - - acp_sock = accept(des_socket,&srv->sa,&size_adr); - - if (acp_sock<0) { - perror("telnetd:accept"); - goto bailout; - }; - - if ( !(rval=telnet_get_pty(acp_sock)) ) { - syslog( LOG_DAEMON | LOG_ERR, "telnetd: unable to obtain PTY"); - /* NOTE: failing 'do_get_pty()' closed the socket */ - goto bailout; - } - - if (sockpeername(acp_sock, peername, sz)) - strncpy(peername, "", sz); - -#ifdef PARANOIA - syslog(LOG_DAEMON | LOG_INFO, - "telnetd: accepted connection from %s on %s", - peername, - rval); -#endif - -bailout: - - return rval; -} - - -static void release_a_Connection(char *devname, char *peername, FILE **pstd, int n) -{ - -#ifdef PARANOIA - syslog( LOG_DAEMON | LOG_INFO, - "telnetd: releasing connection from %s on %s", - peername, - devname ); -#endif - - while (--n>=0) - if (pstd[n]) fclose(pstd[n]); - -} - -static int sockpeername(int sock, char *buf, int bufsz) -{ - uni_sa peer; - int rval = sock < 0; - socklen_t len = sizeof(peer.sin); - - if ( !rval ) - rval = getpeername(sock, &peer.sa, &len); - - if ( !rval ) - rval = !inet_ntop( AF_INET, &peer.sin.sin_addr, buf, bufsz ); - - return rval; -} - -static void -spawned_shell(void *arg); - -/***********************************************************/ -static void -rtems_task_telnetd(void *task_argument) -{ - int des_socket; - uni_sa srv; - char *devname; - char peername[16]; - int i=1; - int size_adr; - struct shell_args *arg = NULL; - - if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { - perror("telnetd:socket"); - telnetd_task_id = RTEMS_ID_NONE; - rtems_task_delete(RTEMS_SELF); - }; - setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); - - memset(&srv,0,sizeof(srv)); - srv.sin.sin_family=AF_INET; - srv.sin.sin_port=htons(23); - size_adr=sizeof(srv.sin); - if ((bind(des_socket,&srv.sa,size_adr))<0) { - perror("telnetd:bind"); - close(des_socket); - telnetd_task_id = RTEMS_ID_NONE; - rtems_task_delete(RTEMS_SELF); - }; - if ((listen(des_socket,5))<0) { - perror("telnetd:listen"); - close(des_socket); - telnetd_task_id = RTEMS_ID_NONE; - rtems_task_delete(RTEMS_SELF); - }; - - /* we don't redirect stdio as this probably - * was started from the console anyway .. - */ - do { - if (telnetd_config->keep_stdio) { - bool start = true; - char device_name [32]; - - ttyname_r( 1, device_name, sizeof( device_name)); - if (telnetd_config->login_check != NULL) { - start = rtems_shell_login_prompt( - stdin, - stderr, - device_name, - telnetd_config->login_check - ); - } - if (start) { - telnetd_config->command( device_name, arg->arg); - } else { - syslog( - LOG_AUTHPRIV | LOG_WARNING, - "telnetd: to many wrong passwords entered from %s", - device_name - ); - } - } else { - devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); - - if ( !devname ) { - /* if something went wrong, sleep for some time */ - sleep(10); - continue; - } - - arg = malloc( sizeof(*arg) ); - - arg->devname = devname; - arg->arg = telnetd_config->arg; - strncpy(arg->peername, peername, sizeof(arg->peername)); - - telnetd_task_id = telnetd_spawn_task( - devname, - telnetd_config->priority, - telnetd_config->stack_size, - spawned_shell, - arg - ); - if (telnetd_task_id == RTEMS_ID_NONE) { - FILE *dummy; - - if ( telnetd_spawn_task != telnetd_dflt_spawn ) { - fprintf(stderr,"Telnetd: Unable to spawn child task\n"); - } - - /* hmm - the pty driver slot can only be - * released by opening and subsequently - * closing the PTY - this also closes - * the underlying socket. So we mock up - * a stream... - */ - - if ( !(dummy=fopen(devname,"r+")) ) - perror("Unable to dummy open the pty, losing a slot :-("); - release_a_Connection(devname, peername, &dummy, 1); - free(arg); - sleep(2); /* don't accept connections too fast */ - } - } - } while(1); - - /* TODO: how to free the connection semaphore? But then - - * stopping the daemon is probably only needed during - * development/debugging. - * Finalizer code should collect all the connection semaphore - * counts and eventually clean up... - */ - close(des_socket); - telnetd_task_id = RTEMS_ID_NONE; -} - -rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config) -{ - if (telnetd_config != NULL) { - fprintf(stderr, "telnetd already started\n"); - return RTEMS_RESOURCE_IN_USE; - } - - if (config->command == NULL) { - fprintf(stderr, "telnetd setup with invalid command\n"); - return RTEMS_IO_ERROR; - } - - telnetd_config = calloc(1, sizeof(*telnetd_config)); - if (telnetd_config == NULL) { - fprintf(stderr, "telnetd cannot alloc telnetd config table\n"); - return RTEMS_NO_MEMORY; - } - - - if ( !telnet_pty_initialize() ) { - fprintf(stderr, "telnetd cannot initialize PTY driver\n"); - free(telnetd_config); - telnetd_config = NULL; - return RTEMS_IO_ERROR; - } - - *telnetd_config = *config; - - /* Check priority */ - if (telnetd_config->priority < 2) { - telnetd_config->priority = 100; - } - - /* Check stack size */ - if (telnetd_config->stack_size <= 0) { - telnetd_config->stack_size = (size_t)32 * 1024; - } - - /* Spawn task */ - telnetd_task_id = telnetd_spawn_task( - "TNTD", - telnetd_config->priority, - telnetd_config->stack_size, - rtems_task_telnetd, - 0 - ); - if (telnetd_task_id == RTEMS_ID_NONE) { - free(telnetd_config); - telnetd_config = NULL; - return RTEMS_IO_ERROR; - } - - /* Print status */ - if (!telnetd_config->keep_stdio) { - fprintf( - stderr, - "telnetd started with stacksize = %u and priority = %d\n", - (unsigned) telnetd_config->stack_size, - (unsigned) telnetd_config->priority - ); - } - - return RTEMS_SUCCESSFUL; -} - -/* utility wrapper */ -static void -spawned_shell(void *targ) -{ - rtems_status_code sc; - FILE *nstd[3]={0}; - FILE *ostd[3]={ stdin, stdout, stderr }; - int i=0; - struct shell_args *arg = targ; - bool login_failed = false; - bool start = true; - - sc=rtems_libio_set_private_env(); - - /* newlib hack/workaround. Before we change stdin/out/err we must make - * sure the internal data are initialized (fileno(stdout) has this sideeffect). - * This should probably be done from RTEMS' libc support layer... - * (T.S., newlibc-1.13; 2005/10) - */ - - fileno(stdout); - - if (RTEMS_SUCCESSFUL != sc) { - rtems_error(sc,"rtems_libio_set_private_env"); - goto cleanup; - } - - /* redirect stdio */ - for (i=0; i<3; i++) { - if ( !(nstd[i]=fopen(arg->devname,"r+")) ) { - perror("unable to open stdio"); - goto cleanup; - } - } - - stdin = nstd[0]; - stdout = nstd[1]; - stderr = nstd[2]; - - #if 0 - printk("STDOUT is now %x (%x) (FD %i/%i)\n", - stdout,nstd[1],fileno(stdout),fileno(nstd[1])); - printf("hello\n"); - write(fileno(stdout),"hellofd\n",8); - #endif - - /* call their routine */ - if (telnetd_config->login_check != NULL) { - start = rtems_shell_login_prompt( - stdin, - stderr, - arg->devname, - telnetd_config->login_check - ); - login_failed = !start; - } - if (start) { - telnetd_config->command( arg->devname, arg->arg); - } - - stdin = ostd[0]; - stdout = ostd[1]; - stderr = ostd[2]; - - if (login_failed) { - syslog( - LOG_AUTHPRIV | LOG_WARNING, - "telnetd: to many wrong passwords entered from %s", - arg->peername - ); - } - -cleanup: - release_a_Connection(arg->devname, arg->peername, nstd, i); - free(arg); -} - -struct wrap_delete_args { - void (*t)(void *); - void *a; -}; - -static rtems_task -wrap_delete(rtems_task_argument arg) -{ - struct wrap_delete_args *pwa = (struct wrap_delete_args *)arg; - register void (*t)(void *) = pwa->t; - register void *a = pwa->a; - - /* free argument before calling function (which may never return if - * they choose to delete themselves) - */ - free(pwa); - t(a); - rtems_task_delete(RTEMS_SELF); -} - -rtems_id -telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg) -{ - rtems_status_code sc; - rtems_id task_id = RTEMS_ID_NONE; - char nm[4] = {'X','X','X','X' }; - struct wrap_delete_args *pwa = malloc(sizeof(*pwa)); - - strncpy(nm, name, 4); - - if ( !pwa ) { - perror("Telnetd: no memory\n"); - return RTEMS_ID_NONE; - } - - pwa->t = fn; - pwa->a = fnarg; - - if ((sc=rtems_task_create( - rtems_build_name(nm[0], nm[1], nm[2], nm[3]), - (rtems_task_priority)priority, - stackSize, - RTEMS_DEFAULT_MODES, - RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, - &task_id)) || - (sc=rtems_task_start( - task_id, - wrap_delete, - (rtems_task_argument)pwa))) { - free(pwa); - rtems_error(sc,"Telnetd: spawning task failed"); - return RTEMS_ID_NONE; - } - return task_id; -} - -/* convenience routines for CEXP (retrieve stdio descriptors - * from reent structure) - */ -#ifdef stdin -static __inline__ FILE * -_stdin(void) { return stdin; } -#undef stdin -FILE *stdin(void) { return _stdin(); } -#endif -#ifdef stdout -static __inline__ FILE * -_stdout(void) { return stdout; } -#undef stdout -FILE *stdout(void) { return _stdout(); } -#endif -#ifdef stderr -static __inline__ FILE * -_stderr(void) { return stderr; } -#undef stderr -FILE *stderr(void) { return _stderr(); } -#endif - -/* MUST NOT USE stdin & friends below here !!!!!!!!!!!!! */ diff --git a/waf_libbsd.py b/waf_libbsd.py index 54a60a78..fd89c394 100644 --- a/waf_libbsd.py +++ b/waf_libbsd.py @@ -477,5 +477,5 @@ class Builder(builder.ModuleManager): includes = includes, source = test_sources, use = ['bsd'], - lib = ['m', 'z'], + lib = ['ftpfs', 'ftpd', 'telnetd', 'bsd', 'm', 'z'], install_path = None) -- cgit v1.2.3