VirtualBox

Changeset 85676 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Aug 10, 2020 4:18:47 PM (4 years ago)
Author:
vboxsync
Message:

IPRT/ftp-server.cpp: some nits and todos. bugref:9437

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/ftp-server.cpp

    r85674 r85676  
    22/** @file
    33 * Generic FTP server (RFC 959) implementation.
     4 *
    45 * Partly also implements RFC 3659 (Extensions to FTP, for "SIZE", ++).
    5  */
    6 
    7 /*
    8  * Copyright (C) 2020 Oracle Corporation
    9  *
    10  * This file is part of VirtualBox Open Source Edition (OSE), as
    11  * available from http://www.virtualbox.org. This file is free software;
    12  * you can redistribute it and/or modify it under the terms of the GNU
    13  * General Public License (GPL) as published by the Free Software
    14  * Foundation, in version 2 as it comes in the "COPYING" file of the
    15  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    16  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    17  *
    18  * The contents of this file may alternatively be used under the terms
    19  * of the Common Development and Distribution License Version 1.0
    20  * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
    21  * VirtualBox OSE distribution, in which case the provisions of the
    22  * CDDL are applicable instead of those of the GPL.
    23  *
    24  * You may elect to license modified versions of this file under the
    25  * terms and conditions of either the GPL or the CDDL or both.
    26  */
    27 
    28 /**
     6 *
    297 * Known limitations so far:
    308 * - UTF-8 support only.
     
    3715 * - No proxy support.
    3816 * - No FXP support.
     17 */
     18
     19/*
     20 * Copyright (C) 2020 Oracle Corporation
     21 *
     22 * This file is part of VirtualBox Open Source Edition (OSE), as
     23 * available from http://www.virtualbox.org. This file is free software;
     24 * you can redistribute it and/or modify it under the terms of the GNU
     25 * General Public License (GPL) as published by the Free Software
     26 * Foundation, in version 2 as it comes in the "COPYING" file of the
     27 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     28 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     29 *
     30 * The contents of this file may alternatively be used under the terms
     31 * of the Common Development and Distribution License Version 1.0
     32 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
     33 * VirtualBox OSE distribution, in which case the provisions of the
     34 * CDDL are applicable instead of those of the GPL.
     35 *
     36 * You may elect to license modified versions of this file under the
     37 * terms and conditions of either the GPL or the CDDL or both.
    3938 */
    4039
     
    158157    } while (0)
    159158
     159
     160/** Handles a FTP server callback with no arguments and returns. */
     161#define RTFTPSERVER_HANDLE_CALLBACK_RET(a_Name) \
     162    do \
     163    { \
     164        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     165        if (pCallbacks->a_Name) \
     166        { \
     167            RTFTPCALLBACKDATA Data = { &pClient->State }; \
     168            return pCallbacks->a_Name(&Data); \
     169        } \
     170        return VERR_NOT_IMPLEMENTED; \
     171    } while (0)
     172
     173/** Handles a FTP server callback with no arguments and sets rc accordingly. */
     174#define RTFTPSERVER_HANDLE_CALLBACK(a_Name) \
     175    do \
     176    { \
     177        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     178        if (pCallbacks->a_Name) \
     179        { \
     180            RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
     181            rc = pCallbacks->a_Name(&Data); \
     182        } \
     183        else \
     184            rc = VERR_NOT_IMPLEMENTED; \
     185    } while (0)
     186
     187/** Handles a FTP server callback with arguments and sets rc accordingly. */
     188#define RTFTPSERVER_HANDLE_CALLBACK_VA(a_Name, ...) \
     189    do \
     190    { \
     191        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     192        if (pCallbacks->a_Name) \
     193        { \
     194            RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
     195            rc = pCallbacks->a_Name(&Data, __VA_ARGS__); \
     196        } \
     197        else \
     198            rc = VERR_NOT_IMPLEMENTED; \
     199    } while (0)
     200
     201/** Handles a FTP server callback with arguments and returns. */
     202#define RTFTPSERVER_HANDLE_CALLBACK_VA_RET(a_Name, ...) \
     203    do \
     204    { \
     205        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     206        if (pCallbacks->a_Name) \
     207        { \
     208            RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
     209            return pCallbacks->a_Name(&Data, __VA_ARGS__); \
     210        } \
     211        return VERR_NOT_IMPLEMENTED; \
     212    } while (0)
     213
     214
     215/*********************************************************************************************************************************
     216*   Structures and Typedefs                                                                                                      *
     217*********************************************************************************************************************************/
    160218/** Supported FTP server command IDs.
    161219 *  Alphabetically, named after their official command names. */
    162 typedef enum RTFTPSERVER_CMD
     220typedef enum RTFTPSERVERCMD
    163221{
    164222    /** Invalid command, do not use. Always must come first. */
    165     RTFTPSERVER_CMD_INVALID = 0,
     223    RTFTPSERVERCMD_INVALID = 0,
    166224    /** Aborts the current command on the server. */
    167     RTFTPSERVER_CMD_ABOR,
     225    RTFTPSERVERCMD_ABOR,
    168226    /** Changes the current working directory. */
    169     RTFTPSERVER_CMD_CDUP,
     227    RTFTPSERVERCMD_CDUP,
    170228    /** Changes the current working directory. */
    171     RTFTPSERVER_CMD_CWD,
     229    RTFTPSERVERCMD_CWD,
    172230    /** Reports features supported by the server. */
    173     RTFTPSERVER_CMD_FEAT,
     231    RTFTPSERVERCMD_FEAT,
    174232    /** Lists a directory. */
    175     RTFTPSERVER_CMD_LIST,
     233    RTFTPSERVERCMD_LIST,
    176234    /** Sets the transfer mode. */
    177     RTFTPSERVER_CMD_MODE,
     235    RTFTPSERVERCMD_MODE,
    178236    /** Sends a nop ("no operation") to the server. */
    179     RTFTPSERVER_CMD_NOOP,
     237    RTFTPSERVERCMD_NOOP,
    180238    /** Sets the password for authentication. */
    181     RTFTPSERVER_CMD_PASS,
     239    RTFTPSERVERCMD_PASS,
    182240    /** Sets the port to use for the data connection. */
    183     RTFTPSERVER_CMD_PORT,
     241    RTFTPSERVERCMD_PORT,
    184242    /** Gets the current working directory. */
    185     RTFTPSERVER_CMD_PWD,
     243    RTFTPSERVERCMD_PWD,
    186244    /** Get options. Needed in conjunction with the FEAT command. */
    187     RTFTPSERVER_CMD_OPTS,
     245    RTFTPSERVERCMD_OPTS,
    188246    /** Terminates the session (connection). */
    189     RTFTPSERVER_CMD_QUIT,
     247    RTFTPSERVERCMD_QUIT,
    190248    /** Retrieves a specific file. */
    191     RTFTPSERVER_CMD_RETR,
     249    RTFTPSERVERCMD_RETR,
    192250    /** Retrieves the size of a file. */
    193     RTFTPSERVER_CMD_SIZE,
     251    RTFTPSERVERCMD_SIZE,
    194252    /** Retrieves the current status of a transfer. */
    195     RTFTPSERVER_CMD_STAT,
     253    RTFTPSERVERCMD_STAT,
    196254    /** Sets the structure type to use. */
    197     RTFTPSERVER_CMD_STRU,
     255    RTFTPSERVERCMD_STRU,
    198256    /** Gets the server's OS info. */
    199     RTFTPSERVER_CMD_SYST,
     257    RTFTPSERVERCMD_SYST,
    200258    /** Sets the (data) representation type. */
    201     RTFTPSERVER_CMD_TYPE,
     259    RTFTPSERVERCMD_TYPE,
    202260    /** Sets the user name for authentication. */
    203     RTFTPSERVER_CMD_USER,
     261    RTFTPSERVERCMD_USER,
    204262    /** End marker. */
    205     RTFTPSERVER_CMD_END,
     263    RTFTPSERVERCMD_END,
    206264    /** The usual 32-bit hack. */
    207     RTFTPSERVER_CMD_32BIT_HACK = 0x7fffffff
    208 } RTFTPSERVER_CMD;
     265    RTFTPSERVERCMD_32BIT_HACK = 0x7fffffff
     266} RTFTPSERVERCMD;
    209267
    210268struct RTFTPSERVERCLIENT;
     
    272330typedef FNRTFTPSERVERCMD *PFNRTFTPSERVERCMD;
    273331
    274 /** Handles a FTP server callback with no arguments and returns. */
    275 #define RTFTPSERVER_HANDLE_CALLBACK_RET(a_Name) \
    276     do \
    277     { \
    278         PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
    279         if (pCallbacks->a_Name) \
    280         { \
    281             RTFTPCALLBACKDATA Data = { &pClient->State }; \
    282             return pCallbacks->a_Name(&Data); \
    283         } \
    284         else \
    285             return VERR_NOT_IMPLEMENTED; \
    286     } while (0)
    287 
    288 /** Handles a FTP server callback with no arguments and sets rc accordingly. */
    289 #define RTFTPSERVER_HANDLE_CALLBACK(a_Name) \
    290     do \
    291     { \
    292         PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
    293         if (pCallbacks->a_Name) \
    294         { \
    295             RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
    296             rc = pCallbacks->a_Name(&Data); \
    297         } \
    298         else \
    299             rc = VERR_NOT_IMPLEMENTED; \
    300     } while (0)
    301 
    302 /** Handles a FTP server callback with arguments and sets rc accordingly. */
    303 #define RTFTPSERVER_HANDLE_CALLBACK_VA(a_Name, ...) \
    304     do \
    305     { \
    306         PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
    307         if (pCallbacks->a_Name) \
    308         { \
    309             RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
    310             rc = pCallbacks->a_Name(&Data, __VA_ARGS__); \
    311         } \
    312         else \
    313             rc = VERR_NOT_IMPLEMENTED; \
    314     } while (0)
    315 
    316 /** Handles a FTP server callback with arguments and returns. */
    317 #define RTFTPSERVER_HANDLE_CALLBACK_VA_RET(a_Name, ...) \
    318     do \
    319     { \
    320         PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
    321         if (pCallbacks->a_Name) \
    322         { \
    323             RTFTPCALLBACKDATA Data = { &pClient->State, pClient->pServer->pvUser, pClient->pServer->cbUser }; \
    324             return pCallbacks->a_Name(&Data, __VA_ARGS__); \
    325         } \
    326         else \
    327             return VERR_NOT_IMPLEMENTED; \
    328     } while (0)
    329 
    330332
    331333/*********************************************************************************************************************************
    332 *   Defined Constants And Macros                                                                                                 *
     334*   Internal Functions                                                                                                           *
    333335*********************************************************************************************************************************/
    334 
    335336static int  rtFtpServerDataConnOpen(PRTFTPSERVERDATACONN pDataConn, PRTNETADDRIPV4 pAddr, uint16_t uPort);
    336337static int  rtFtpServerDataConnClose(PRTFTPSERVERDATACONN pDataConn);
     
    370371 * Structure for maintaining a single command entry for the command table.
    371372 */
    372 typedef struct RTFTPSERVER_CMD_ENTRY
     373typedef struct RTFTPSERVERCMD_ENTRY
    373374{
    374375    /** Command ID. */
    375     RTFTPSERVER_CMD    enmCmd;
    376     /** Command represented as ASCII string. */
    377     char               szCmd[RTFTPSERVER_MAX_CMD_LEN];
     376    RTFTPSERVERCMD      enmCmd;
     377    /** Command represented as ASCII string.
     378     * @todo r=bird: It's a waste to use 64 byte here when all supported commands
     379     *       are 3 or 4 chars + terminator.  For (64-bit) alignment reasons,  */
     380    char                szCmd[RTFTPSERVER_MAX_CMD_LEN];
    378381    /** Whether the commands needs a logged in (valid) user. */
    379     bool               fNeedsUser;
     382    bool                fNeedsUser;
    380383    /** Function pointer invoked to handle the command. */
    381     PFNRTFTPSERVERCMD  pfnCmd;
    382 } RTFTPSERVER_CMD_ENTRY;
     384    PFNRTFTPSERVERCMD   pfnCmd;
     385} RTFTPSERVERCMD_ENTRY;
    383386/** Pointer to a command entry. */
    384 typedef RTFTPSERVER_CMD_ENTRY *PRTFTPSERVER_CMD_ENTRY;
    385 
     387typedef RTFTPSERVERCMD_ENTRY *PRTFTPSERVERCMD_ENTRY;
     388
     389
     390
     391/*********************************************************************************************************************************
     392*   Global Variables                                                                                                             *
     393*********************************************************************************************************************************/
    386394/**
    387395 * Table of handled commands.
    388396 */
    389 const RTFTPSERVER_CMD_ENTRY g_aCmdMap[] =
    390 {
    391     { RTFTPSERVER_CMD_ABOR,     "ABOR", true,  rtFtpServerHandleABOR },
    392     { RTFTPSERVER_CMD_CDUP,     "CDUP", true,  rtFtpServerHandleCDUP },
    393     { RTFTPSERVER_CMD_CWD,      "CWD",  true,  rtFtpServerHandleCWD  },
    394     { RTFTPSERVER_CMD_FEAT,     "FEAT", false, rtFtpServerHandleFEAT },
    395     { RTFTPSERVER_CMD_LIST,     "LIST", true,  rtFtpServerHandleLIST },
    396     { RTFTPSERVER_CMD_MODE,     "MODE", true,  rtFtpServerHandleMODE },
    397     { RTFTPSERVER_CMD_NOOP,     "NOOP", true,  rtFtpServerHandleNOOP },
    398     { RTFTPSERVER_CMD_PASS,     "PASS", false, rtFtpServerHandlePASS },
    399     { RTFTPSERVER_CMD_PORT,     "PORT", true,  rtFtpServerHandlePORT },
    400     { RTFTPSERVER_CMD_PWD,      "PWD",  true,  rtFtpServerHandlePWD  },
    401     { RTFTPSERVER_CMD_OPTS,     "OPTS", false, rtFtpServerHandleOPTS },
    402     { RTFTPSERVER_CMD_QUIT,     "QUIT", false, rtFtpServerHandleQUIT },
    403     { RTFTPSERVER_CMD_RETR,     "RETR", true,  rtFtpServerHandleRETR },
    404     { RTFTPSERVER_CMD_SIZE,     "SIZE", true,  rtFtpServerHandleSIZE },
    405     { RTFTPSERVER_CMD_STAT,     "STAT", true,  rtFtpServerHandleSTAT },
    406     { RTFTPSERVER_CMD_STRU,     "STRU", true,  rtFtpServerHandleSTRU },
    407     { RTFTPSERVER_CMD_SYST,     "SYST", false, rtFtpServerHandleSYST },
    408     { RTFTPSERVER_CMD_TYPE,     "TYPE", true,  rtFtpServerHandleTYPE },
    409     { RTFTPSERVER_CMD_USER,     "USER", false, rtFtpServerHandleUSER },
    410     { RTFTPSERVER_CMD_END,      "",     false, NULL }
     397static const RTFTPSERVERCMD_ENTRY g_aCmdMap[] =
     398{
     399    { RTFTPSERVERCMD_ABOR,      "ABOR", true,  rtFtpServerHandleABOR },
     400    { RTFTPSERVERCMD_CDUP,      "CDUP", true,  rtFtpServerHandleCDUP },
     401    { RTFTPSERVERCMD_CWD,       "CWD",  true,  rtFtpServerHandleCWD  },
     402    { RTFTPSERVERCMD_FEAT,      "FEAT", false, rtFtpServerHandleFEAT },
     403    { RTFTPSERVERCMD_LIST,      "LIST", true,  rtFtpServerHandleLIST },
     404    { RTFTPSERVERCMD_MODE,      "MODE", true,  rtFtpServerHandleMODE },
     405    { RTFTPSERVERCMD_NOOP,      "NOOP", true,  rtFtpServerHandleNOOP },
     406    { RTFTPSERVERCMD_PASS,      "PASS", false, rtFtpServerHandlePASS },
     407    { RTFTPSERVERCMD_PORT,      "PORT", true,  rtFtpServerHandlePORT },
     408    { RTFTPSERVERCMD_PWD,       "PWD",  true,  rtFtpServerHandlePWD  },
     409    { RTFTPSERVERCMD_OPTS,      "OPTS", false, rtFtpServerHandleOPTS },
     410    { RTFTPSERVERCMD_QUIT,      "QUIT", false, rtFtpServerHandleQUIT },
     411    { RTFTPSERVERCMD_RETR,      "RETR", true,  rtFtpServerHandleRETR },
     412    { RTFTPSERVERCMD_SIZE,      "SIZE", true,  rtFtpServerHandleSIZE },
     413    { RTFTPSERVERCMD_STAT,      "STAT", true,  rtFtpServerHandleSTAT },
     414    { RTFTPSERVERCMD_STRU,      "STRU", true,  rtFtpServerHandleSTRU },
     415    { RTFTPSERVERCMD_SYST,      "SYST", false, rtFtpServerHandleSYST },
     416    { RTFTPSERVERCMD_TYPE,      "TYPE", true,  rtFtpServerHandleTYPE },
     417    { RTFTPSERVERCMD_USER,      "USER", false, rtFtpServerHandleUSER },
     418    { RTFTPSERVERCMD_END,       "",     false, NULL }
    411419};
    412420
     
    22872295static int rtFtpServerProcessCommands(PRTFTPSERVERCLIENT pClient, char *pcszCmd, size_t cbCmd)
    22882296{
     2297    /** @todo r=bird: pcszCmd is a misnomer, it is _clearly_ not const as you
     2298     * modify it all over the place!  Please do _not_use 'c' to mean 'const', it
     2299     * means 'count of'. */
    22892300    /* Make sure to terminate the string in any case. */
    22902301    pcszCmd[RT_MIN(RTFTPSERVER_MAX_CMD_LEN, cbCmd)] = '\0';
     
    22952306    /* First, terminate string by finding the command end marker (telnet style). */
    22962307    /** @todo Not sure if this is entirely correct and/or needs tweaking; good enough for now as it seems. */
     2308    /** @todo r=bird: Why are you using the case-insensitive version here? */
    22972309    char *pszCmdEnd = RTStrIStr(pcszCmd, "\r\n");
    22982310    if (pszCmdEnd)
     
    23172329        for (; i < RT_ELEMENTS(g_aCmdMap); i++)
    23182330        {
    2319             const RTFTPSERVER_CMD_ENTRY *pCmdEntry = &g_aCmdMap[i];
     2331            const RTFTPSERVERCMD_ENTRY *pCmdEntry = &g_aCmdMap[i];
    23202332
    23212333            if (!RTStrICmp(papszArgs[0], pCmdEntry->szCmd))
     
    23672379        }
    23682380
    2369         const bool fDisconnect =    g_aCmdMap[i].enmCmd == RTFTPSERVER_CMD_QUIT
     2381        const bool fDisconnect =    g_aCmdMap[i].enmCmd == RTFTPSERVERCMD_QUIT
    23702382                                 || pClient->State.cFailedLoginAttempts >= 3; /** @todo Make this dynamic. */
    23712383        if (fDisconnect)
     
    23982410 * @returns VBox status code.
    23992411 * @param   pClient             Client to process commands for.
     2412 *
     2413 * @todo r=bird: There are two rtFtpServerProcessCommands functions. Please
     2414 *       don't use C++ overloading in C code, it's unnecessary and confusing
     2415 *       (even in C++ code, see init() methods in the API).
    24002416 */
    24012417static int rtFtpServerProcessCommands(PRTFTPSERVERCLIENT pClient)
     
    24192435            }
    24202436        }
     2437        else if (rc == VERR_TIMEOUT)
     2438            rc = VINF_SUCCESS;
    24212439        else
    2422         {
    2423             if (rc == VERR_TIMEOUT)
    2424                 rc = VINF_SUCCESS;
    2425 
    2426             if (RT_FAILURE(rc))
    2427                 break;
    2428         }
     2440            break;
    24292441
    24302442        /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette