VirtualBox

Changeset 82715 in vbox


Ignore:
Timestamp:
Jan 10, 2020 2:04:36 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/FTP: More protocol handling and callback work. bugref:9437

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/ftp.h

    r82702 r82715  
    175175    /** Size (in bytes) of user data pointing at. Optional and can be 0. */
    176176    size_t cbUser;
     177    /**
     178     * Callback which gets invoked when a user connected.
     179     *
     180     * @returns VBox status code.
     181     * @param   pcszUser        User name.
     182     */
    177183    DECLCALLBACKMEMBER(int,  pfnOnUserConnect)(PRTFTPCALLBACKDATA pData, const char *pcszUser);
     184    /**
     185     * Callback which gets invoked when a user tries to authenticate with a password.
     186     *
     187     * @returns VBox status code.
     188     * @param   pcszUser        User name to authenticate.
     189     * @param   pcszPassword    Password to authenticate with.
     190     */
    178191    DECLCALLBACKMEMBER(int,  pfnOnUserAuthenticate)(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword);
     192    /**
     193     * Callback which gets invoked when a user disconnected.
     194     *
     195     * @returns VBox status code.
     196     * @param   pcszUser        User name which disconnected.
     197     */
    179198    DECLCALLBACKMEMBER(int,  pfnOnUserDisconnect)(PRTFTPCALLBACKDATA pData);
     199    /**
     200     * Callback which gets invoked when setting the current working directory.
     201     *
     202     * @returns VBox status code.
     203     * @param   pcszCWD         Current working directory to set.
     204     */
    180205    DECLCALLBACKMEMBER(int,  pfnOnPathSetCurrent)(PRTFTPCALLBACKDATA pData, const char *pcszCWD);
     206    /**
     207     * Callback which gets invoked when a client wants to retrieve the current working directory.
     208     *
     209     * @returns VBox status code.
     210     * @param   pszPWD          Where to store the current working directory.
     211     * @param   cbPWD           Size of buffer in bytes.
     212     */
    181213    DECLCALLBACKMEMBER(int,  pfnOnPathGetCurrent)(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD);
    182     DECLCALLBACKMEMBER(int,  pfnOnList)(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData);
     214    /**
     215     * Callback which gets invoked when the client wants to move up a directory (relative to the current working directory).
     216     *
     217     * @returns VBox status code.
     218     */
     219    DECLCALLBACKMEMBER(int,  pfnOnPathUp)(PRTFTPCALLBACKDATA pData);
     220    /**
     221     * Callback which gets invoked when the client wants to list a directory or file.
     222     *
     223     * @param   pcszPath        Path of file / directory to list. Optional. If NULL, the current directory will be listed.
     224     * @param   ppvData         Where to return the listing data. Must be free'd by the caller.
     225     * @param   pcbvData        Where to return the listing data size in bytes.
     226     * @returns VBox status code.
     227     */
     228    DECLCALLBACKMEMBER(int,  pfnOnList)(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvData, size_t *pcbData);
    183229} RTFTPSERVERCALLBACKS;
    184230/** Pointer to a FTP server callback data table. */
  • trunk/src/VBox/Runtime/generic/ftp-server.cpp

    r82702 r82715  
    4040*********************************************************************************************************************************/
    4141#define LOG_GROUP RTLOGGROUP_FTP
     42#include <iprt/ftp.h>
     43#include "internal/iprt.h"
     44#include "internal/magics.h"
     45
    4246#include <iprt/asm.h>
    4347#include <iprt/assert.h>
    4448#include <iprt/errcore.h>
    45 #include <iprt/ftp.h>
    4649#include <iprt/getopt.h>
    4750#include <iprt/mem.h>
     
    5356#include <iprt/system.h>
    5457#include <iprt/tcp.h>
    55 
    56 #include "internal/magics.h"
    5758
    5859
     
    172173            return pCallbacks->a_Name(&Data); \
    173174        } \
     175        else \
     176            return VERR_NOT_IMPLEMENTED; \
     177    } while (0)
     178
     179/** Handles a FTP server callback with no arguments and sets rc accordingly. */
     180#define RTFTPSERVER_HANDLE_CALLBACK(a_Name) \
     181    do \
     182    { \
     183        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     184        if (pCallbacks->a_Name) \
     185        { \
     186            RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \
     187            rc = pCallbacks->a_Name(&Data); \
     188        } \
     189        else \
     190            rc = VERR_NOT_IMPLEMENTED; \
     191    } while (0)
     192
     193/** Handles a FTP server callback with arguments and sets rc accordingly. */
     194#define RTFTPSERVER_HANDLE_CALLBACK_VA(a_Name, ...) \
     195    do \
     196    { \
     197        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     198        if (pCallbacks->a_Name) \
     199        { \
     200            RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \
     201            rc = pCallbacks->a_Name(&Data, __VA_ARGS__); \
     202        } \
     203        else \
     204            rc = VERR_NOT_IMPLEMENTED; \
    174205    } while (0)
    175206
     
    184215            return pCallbacks->a_Name(&Data, __VA_ARGS__); \
    185216        } \
     217        else \
     218            return VERR_NOT_IMPLEMENTED; \
    186219    } while (0)
    187220
     
    323356
    324357    /** @todo Anything to do here? */
    325     return VINF_SUCCESS;
     358    return VERR_NOT_IMPLEMENTED;
    326359}
    327360
    328361static int rtFtpServerHandleCDUP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     362{
     363    RT_NOREF(cArgs, apcszArgs);
     364
     365    int rc;
     366
     367    RTFTPSERVER_HANDLE_CALLBACK(pfnOnPathUp);
     368
     369    if (RT_SUCCESS(rc))
     370        return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY);
     371
     372    return rc;
     373}
     374
     375static int rtFtpServerHandleCWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     376{
     377    if (cArgs != 1)
     378        return VERR_INVALID_PARAMETER;
     379
     380    int rc;
     381
     382    RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathSetCurrent, apcszArgs[0]);
     383
     384    if (RT_SUCCESS(rc))
     385        return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY);
     386
     387    return rc;
     388}
     389
     390static int rtFtpServerHandleLIST(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     391{
     392    RT_NOREF(cArgs, apcszArgs);
     393
     394    int rc;
     395
     396    void   *pvData = NULL;
     397    size_t  cbData = 0;
     398
     399    /* The first argument might indicate a directory to list. */
     400    RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnList,
     401                                     cArgs == 1
     402                                   ? apcszArgs[0] : NULL, &pvData, &cbData);
     403
     404    if (RT_SUCCESS(rc))
     405    {
     406        RTMemFree(pvData);
     407    }
     408
     409    return rc;
     410}
     411
     412static int rtFtpServerHandleMODE(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    329413{
    330414    RT_NOREF(pClient, cArgs, apcszArgs);
     
    334418}
    335419
    336 static int rtFtpServerHandleCWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    337 {
    338     AssertPtrReturn(apcszArgs, VERR_INVALID_POINTER);
    339 
    340     if (cArgs != 1)
    341         return VERR_INVALID_PARAMETER;
    342 
    343     RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnPathSetCurrent, apcszArgs[0]);
    344 
    345     return VERR_NOT_IMPLEMENTED;
    346 }
    347 
    348 static int rtFtpServerHandleLIST(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     420static int rtFtpServerHandleNOOP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    349421{
    350422    RT_NOREF(cArgs, apcszArgs);
    351423
    352     void   *pvData = NULL;
    353     size_t  cbData = 0;
    354 
    355     RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnList, &pvData, &cbData);
    356 
    357     return VERR_NOT_IMPLEMENTED;
    358 }
    359 
    360 static int rtFtpServerHandleMODE(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    361 {
    362     RT_NOREF(pClient, cArgs, apcszArgs);
    363 
    364     /** @todo Anything to do here? */
    365     return VINF_SUCCESS;
    366 }
    367 
    368 static int rtFtpServerHandleNOOP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    369 {
    370     RT_NOREF(pClient, cArgs, apcszArgs);
    371 
    372     /* Nothing to do here. */
    373     return VINF_SUCCESS;
     424    /* Save timestamp of last command sent. */
     425    pClient->State.tsLastCmdMs = RTTimeMilliTS();
     426
     427    return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY);
    374428}
    375429
     
    404458
    405459    /** @todo Anything to do here? */
    406     return VINF_SUCCESS;
     460    return VERR_NOT_IMPLEMENTED;
    407461}
    408462
     
    411465    RT_NOREF(cArgs, apcszArgs);
    412466
    413 #if 0
    414     char *pszReply;
    415     int rc = RTStrAPrintf(&pszReply, "%s\r\n", pClient->szCWD);
    416     if (RT_SUCCESS(rc))
    417     {
    418         rc = RTTcpWrite(pClient->hSocket, pszReply, strlen(pszReply) + 1);
    419         RTStrFree(pszReply);
    420         return rc;
    421     }
    422 
    423     return VERR_NO_MEMORY;
    424 #endif
    425 
    426     RT_NOREF(pClient);
    427     return 0;
     467    int rc;
     468
     469    char szPWD[RTPATH_MAX];
     470
     471    RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathGetCurrent, szPWD, sizeof(szPWD));
     472
     473    if (RT_SUCCESS(rc))
     474       rc = rtFtpServerSendReplyStr(pClient, szPWD);
     475
     476    return rc;
    428477}
    429478
     
    433482
    434483    /** @todo Anything to do here? */
    435     return VINF_SUCCESS;
     484    return VERR_NOT_IMPLEMENTED;
    436485}
    437486
     
    441490
    442491    /** @todo Anything to do here? */
    443     return VINF_SUCCESS;
     492    return VERR_NOT_IMPLEMENTED;
    444493}
    445494
     
    449498
    450499    /** @todo Anything to do here? */
    451     return VINF_SUCCESS;
     500    return VERR_NOT_IMPLEMENTED;
    452501}
    453502
     
    457506
    458507    /** @todo Anything to do here? */
    459     return VINF_SUCCESS;
     508    return VERR_NOT_IMPLEMENTED;
    460509}
    461510
     
    477526
    478527    /** @todo Anything to do here? */
    479     return VINF_SUCCESS;
     528    return VERR_NOT_IMPLEMENTED;
    480529}
    481530
     
    483532{
    484533    if (cArgs != 1)
    485         return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);
     534        return VERR_INVALID_PARAMETER;
    486535
    487536    const char *pcszUser = apcszArgs[0];
     
    591640            if (pszCmdEnd)
    592641                *pszCmdEnd = '\0';
     642
     643            int rcCmd = VINF_SUCCESS;
    593644
    594645            uint8_t cArgs     = 0;
     
    606657                        pClient->State.tsLastCmdMs = RTTimeMilliTS();
    607658
    608                         rc = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL);
     659                        rcCmd = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL);
    609660                        break;
    610661                    }
     
    618669                    if (RT_SUCCESS(rc))
    619670                        rc = rc2;
     671
     672                    continue;
    620673                }
    621674
     
    630683                    RTFTPSERVER_HANDLE_CALLBACK_RET(pfnOnUserDisconnect);
    631684                    break;
     685                }
     686
     687                switch (rcCmd)
     688                {
     689                    case VERR_INVALID_PARAMETER:
     690                        RT_FALL_THROUGH();
     691                    case VERR_INVALID_POINTER:
     692                        rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);
     693                        break;
     694
     695                    case VERR_NOT_IMPLEMENTED:
     696                        rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL);
     697                        break;
     698
     699                    default:
     700                        break;
    632701                }
    633702            }
     
    717786        rc = RTTcpServerCreate(pcszAddress, uPort, RTTHREADTYPE_DEFAULT, "ftpsrv",
    718787                               rtFtpServerClientThread, pThis /* pvUser */, &pThis->pTCPServer);
     788        if (RT_SUCCESS(rc))
     789        {
     790            *phFTPServer = (RTFTPSERVER)pThis;
     791        }
    719792    }
    720793    else
  • trunk/src/VBox/Runtime/tools/RTFTPServer.cpp

    r82699 r82715  
    2323 * You may elect to license modified versions of this file under the
    2424 * terms and conditions of either the GPL or the CDDL or both.
     25 */
     26
     27/*
     28 * Use this setup to best see what's going on:
     29 *
     30 *    VBOX_LOG=rt_ftp=~0
     31 *    VBOX_LOG_DEST="nofile stderr"
     32 *    VBOX_LOG_FLAGS="unbuffered enabled thread msprog"
     33 *
    2534 */
    2635
     
    5463
    5564/*********************************************************************************************************************************
     65*   Definitations                                                                                                                *
     66*********************************************************************************************************************************/
     67typedef struct FTPSERVERDATA
     68{
     69    char szRootDir[RTPATH_MAX];
     70    char szCWD[RTPATH_MAX];
     71} FTPSERVERDATA;
     72typedef FTPSERVERDATA *PFTPSERVERDATA;
     73
     74
     75/*********************************************************************************************************************************
    5676*   Global Variables                                                                                                             *
    5777*********************************************************************************************************************************/
    5878/** Set by the signal handler when the FTP server shall be terminated. */
    5979static volatile bool  g_fCanceled  = false;
    60 static char          *g_pszRootDir = NULL;
     80static FTPSERVERDATA  g_FTPServerData;
    6181
    6282
     
    150170    RT_NOREF(pData, pcszUser);
    151171
    152     RTPrintf("User '%s' connected", pcszUser);
     172    RTPrintf("User '%s' connected\n", pcszUser);
    153173
    154174    return VINF_SUCCESS;
     
    159179    RT_NOREF(pData, pcszUser, pcszPassword);
    160180
    161     RTPrintf("Authenticating user '%s' ...", pcszUser);
     181    RTPrintf("Authenticating user '%s' ...\n", pcszUser);
    162182
    163183    return VINF_SUCCESS;
     
    168188    RT_NOREF(pData);
    169189
    170     RTPrintf("User disconnected");
     190    RTPrintf("User disconnected\n");
    171191
    172192    return VINF_SUCCESS;
     
    175195static DECLCALLBACK(int) onPathSetCurrent(PRTFTPCALLBACKDATA pData, const char *pcszCWD)
    176196{
    177     RT_NOREF(pData, pcszCWD);
     197    PFTPSERVERDATA pThis = (PFTPSERVERDATA)pData->pvUser;
     198    Assert(pData->cbUser == sizeof(FTPSERVERDATA));
    178199
    179200    RTPrintf("Setting current directory to '%s'\n", pcszCWD);
    180201
    181     return VINF_SUCCESS;
     202    /** @todo BUGBUG Santiy checks! */
     203
     204    return RTStrCopy(pThis->szCWD, sizeof(pThis->szCWD), pcszCWD);
    182205}
    183206
    184207static DECLCALLBACK(int) onPathGetCurrent(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD)
    185208{
    186     RT_NOREF(pData, pszPWD, cbPWD);
    187 
    188     return VINF_SUCCESS;
    189 }
    190 
    191 static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData)
    192 {
    193     RT_NOREF(pData, ppvData, pcbData);
     209    PFTPSERVERDATA pThis = (PFTPSERVERDATA)pData->pvUser;
     210    Assert(pData->cbUser == sizeof(FTPSERVERDATA));
     211
     212    RTPrintf("Current directory is: '%s'\n", pThis->szCWD);
     213
     214    RTStrPrintf(pszPWD, cbPWD, "%s", pThis->szCWD);
     215
     216    return VINF_SUCCESS;
     217}
     218
     219static DECLCALLBACK(int) onPathUp(PRTFTPCALLBACKDATA pData)
     220{
     221    RT_NOREF(pData);
     222
     223    return VINF_SUCCESS;
     224}
     225
     226static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvData, size_t *pcbData)
     227{
     228    RT_NOREF(pData, pcszPath, ppvData, pcbData);
    194229
    195230    return VINF_SUCCESS;
     
    203238
    204239    /* Use some sane defaults. */
    205     char     szAddress[64]         = "localhost";
    206     uint16_t uPort                 = 2121;
     240    char     szAddress[64] = "localhost";
     241    uint16_t uPort         = 2121;
     242
     243    RT_ZERO(g_FTPServerData);
    207244
    208245    /*
     
    238275
    239276            case 'r':
    240                 g_pszRootDir = RTStrDup(ValueUnion.psz);
     277                RTStrCopy(g_FTPServerData.szRootDir, sizeof(g_FTPServerData.szRootDir), ValueUnion.psz);
    241278                break;
    242279
     
    273310    }
    274311
    275     if (!g_pszRootDir)
    276     {
    277         char szRootDir[RTPATH_MAX];
    278 
     312    if (!strlen(g_FTPServerData.szRootDir))
     313    {
    279314        /* By default use the current directory as serving root directory. */
    280         rc = RTPathGetCurrent(szRootDir, sizeof(szRootDir));
     315        rc = RTPathGetCurrent(g_FTPServerData.szRootDir, sizeof(g_FTPServerData.szRootDir));
    281316        if (RT_FAILURE(rc))
    282317            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Retrieving current directory failed: %Rrc", rc);
    283 
    284         g_pszRootDir = RTStrDup(szRootDir);
    285         if (!g_pszRootDir)
    286             return RTMsgErrorExit(RTEXITCODE_FAILURE, "Allocating current directory failed");
    287     }
     318    }
     319
     320    /* Initialize CWD. */
     321    RTStrPrintf2(g_FTPServerData.szCWD, sizeof(g_FTPServerData.szCWD), "/");
    288322
    289323    /* Install signal handler. */
     
    296330        RTFTPSERVERCALLBACKS Callbacks;
    297331        RT_ZERO(Callbacks);
     332
     333        Callbacks.pvUser                = &g_FTPServerData;
     334        Callbacks.cbUser                = sizeof(g_FTPServerData);
     335
    298336        Callbacks.pfnOnUserConnect      = onUserConnect;
    299337        Callbacks.pfnOnUserAuthenticate = onUserAuthenticate;
     
    301339        Callbacks.pfnOnPathSetCurrent   = onPathSetCurrent;
    302340        Callbacks.pfnOnPathGetCurrent   = onPathGetCurrent;
     341        Callbacks.pfnOnPathUp           = onPathUp;
     342        Callbacks.pfnOnList             = onList;
    303343        Callbacks.pfnOnList             = onList;
    304344
     
    308348        {
    309349            RTPrintf("Starting FTP server at %s:%RU16 ...\n", szAddress, uPort);
    310             RTPrintf("Root directory is '%s'\n", g_pszRootDir);
     350            RTPrintf("Root directory is '%s'\n", g_FTPServerData.szRootDir);
    311351
    312352            RTPrintf("Running FTP server ...\n");
     
    336376    }
    337377
    338     RTStrFree(g_pszRootDir);
    339 
    340378    /* Set rcExit on failure in case we forgot to do so before. */
    341379    if (RT_FAILURE(rc))
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