VirtualBox

Ignore:
Timestamp:
Jan 8, 2020 4:19:35 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/FTP: First connections (via Linux ftp client) are working now. bugref:9437

File:
1 edited

Legend:

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

    r82665 r82673  
    4444#include <iprt/ftp.h>
    4545#include <iprt/mem.h>
     46#include <iprt/log.h>
    4647#include <iprt/poll.h>
    4748#include <iprt/socket.h>
    4849#include <iprt/string.h>
     50#include <iprt/system.h>
    4951#include <iprt/tcp.h>
    5052
     
    102104    RTFTPSERVER_CMD_CWD,
    103105    /** Lists a directory. */
    104     RTFTPSERVER_CMD_LS,
     106    RTFTPSERVER_CMD_LIST,
     107    /** Sets the transfer mode. */
     108    RTFTPSERVER_CMD_MODE,
    105109    /** Sends a nop ("no operation") to the server. */
    106110    RTFTPSERVER_CMD_NOOP,
    107111    /** Sets the password for authentication. */
    108112    RTFTPSERVER_CMD_PASS,
     113    /** Sets the port to use for the data connection. */
     114    RTFTPSERVER_CMD_PORT,
    109115    /** Gets the current working directory. */
    110116    RTFTPSERVER_CMD_PWD,
     
    117123    /** Retrieves the current status of a transfer. */
    118124    RTFTPSERVER_CMD_STAT,
     125    /** Gets the server's OS info. */
     126    RTFTPSERVER_CMD_SYST,
    119127    /** Sets the (data) representation type. */
    120128    RTFTPSERVER_CMD_TYPE,
    121129    /** Sets the user name for authentication. */
    122130    RTFTPSERVER_CMD_USER,
     131    /** End marker. */
     132    RTFTPSERVER_CMD_LAST,
    123133    /** The usual 32-bit hack. */
    124134    RTFTPSERVER_CMD_32BIT_HACK = 0x7fffffff
     
    138148typedef RTFTPSERVERCLIENTSTATE *PRTFTPSERVERCLIENTSTATE;
    139149
    140 
    141 static int rtFTPServerSendReply(PRTFTPSERVERCLIENTSTATE pClient, RTFTPSERVER_REPLY enmReply)
    142 {
    143     RT_NOREF(enmReply);
    144 
    145     RTTcpWrite(pClient->hSocket, "hello\n", sizeof("hello\n") - 1);
    146 
    147     int rc =  0;
    148     RT_NOREF(rc);
     150typedef DECLCALLBACK(int) FNRTFTPSERVERCMD(PRTFTPSERVERCLIENTSTATE pClient);
     151/** Pointer to a FNRTFTPSERVERCMD(). */
     152typedef FNRTFTPSERVERCMD *PFNRTFTPSERVERCMD;
     153
     154static FNRTFTPSERVERCMD rtFTPServerHandleSYST;
     155
     156typedef struct RTFTPSERVER_CMD_ENTRY
     157{
     158    RTFTPSERVER_CMD    enmCmd;
     159    char               szCmd[RTFTPSERVER_MAX_CMD_LEN];
     160    PFNRTFTPSERVERCMD  pfnCmd;
     161} RTFTPSERVER_CMD_ENTRY;
     162
     163const RTFTPSERVER_CMD_ENTRY g_aCmdMap[] =
     164{
     165    { RTFTPSERVER_CMD_SYST,     "SYST",         rtFTPServerHandleSYST },
     166    { RTFTPSERVER_CMD_LAST,     "",             NULL }
     167};
     168
     169
     170static int rtFTPServerSendReplyRc(PRTFTPSERVERCLIENTSTATE pClient, RTFTPSERVER_REPLY enmReply)
     171{
     172    char szReply[32];
     173    RTStrPrintf2(szReply, sizeof(szReply), "%RU32\r\n", enmReply);
     174
     175    return RTTcpWrite(pClient->hSocket, szReply, strlen(szReply) + 1);
     176}
     177
     178static int rtFTPServerSendReplyStr(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszStr)
     179{
     180    char *pszReply;
     181    int rc = RTStrAPrintf(&pszReply, "%s\r\n", pcszStr);
     182    if (RT_SUCCESS(rc))
     183    {
     184        rc = RTTcpWrite(pClient->hSocket, pszReply, strlen(pszReply) + 1);
     185        RTStrFree(pszReply);
     186        return rc;
     187    }
     188
     189    return VERR_NO_MEMORY;
     190}
     191
     192static int rtFTPServerLookupUser(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszUser)
     193{
     194    RT_NOREF(pClient, pcszUser);
     195
     196    LogFunc(("User='%s'\n", pcszUser));
     197
     198    return VINF_SUCCESS; /** @todo Implement lookup. */
     199}
     200
     201static int rtFTPServerAuthenticate(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszUser, const char *pcszPassword)
     202{
     203    RT_NOREF(pClient, pcszUser, pcszPassword);
     204
     205    LogFunc(("User='%s', Password='%s'\n", pcszUser, pcszPassword));
     206
     207    return VINF_SUCCESS; /** @todo Implement authentication. */
     208}
     209
     210static int rtFTPServerHandleSYST(PRTFTPSERVERCLIENTSTATE pClient)
     211{
     212    char szOSInfo[64];
     213    int rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSInfo, sizeof(szOSInfo));
     214    if (RT_SUCCESS(rc))
     215        rc = rtFTPServerSendReplyStr(pClient, szOSInfo);
    149216
    150217    return rc;
     
    153220static int rtFTPServerDoLogin(PRTFTPSERVERCLIENTSTATE pClient)
    154221{
    155     int rc = rtFTPServerSendReply(pClient, RTFTPSERVER_REPLY_READY_FOR_NEW_USER);
     222    LogFlowFuncEnter();
     223
     224    /* Send welcome message. */
     225    int rc = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_READY_FOR_NEW_USER);
     226    if (RT_SUCCESS(rc))
     227    {
     228        size_t cbRead;
     229
     230        char szUser[64];
     231        rc = RTTcpRead(pClient->hSocket, szUser, sizeof(szUser), &cbRead);
     232        if (RT_SUCCESS(rc))
     233        {
     234            rc = rtFTPServerLookupUser(pClient, szUser);
     235            if (RT_SUCCESS(rc))
     236            {
     237                rc = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_USERNAME_OKAY_NEED_PASSWORD);
     238                if (RT_SUCCESS(rc))
     239                {
     240                    char szPass[64];
     241                    rc = RTTcpRead(pClient->hSocket, szPass, sizeof(szPass), &cbRead);
     242                    {
     243                        if (RT_SUCCESS(rc))
     244                        {
     245                            rc = rtFTPServerAuthenticate(pClient, szUser, szPass);
     246                            if (RT_SUCCESS(rc))
     247                            {
     248                                rc = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_LOGGED_IN_PROCEED);
     249                            }
     250                        }
     251                    }
     252                }
     253            }
     254        }
     255    }
     256
     257    if (RT_FAILURE(rc))
     258    {
     259        int rc2 = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_NOT_LOGGED_IN);
     260        if (RT_SUCCESS(rc))
     261            rc = rc2;
     262    }
     263
     264    return rc;
     265}
     266
     267static int rtFTPServerProcessCommands(PRTFTPSERVERCLIENTSTATE pClient)
     268{
     269    int rc;
     270
     271    for (;;)
     272    {
     273        size_t cbRead;
     274        char   szCmd[RTFTPSERVER_MAX_CMD_LEN];
     275        rc = RTTcpRead(pClient->hSocket, szCmd, sizeof(szCmd), &cbRead);
     276        if (   RT_SUCCESS(rc)
     277            && strlen(szCmd))
     278        {
     279            /* A tiny bit of sanitation. */
     280            RTStrStripL(szCmd);
     281
     282            /* First, terminate string by finding the command end marker (telnet style). */
     283            /** @todo Not sure if this is entirely correct and/or needs tweaking; good enough for now as it seems. */
     284            char *pszCmdEnd = RTStrIStr(szCmd, "\r\n");
     285            if (pszCmdEnd)
     286                *pszCmdEnd = '\0';
     287
     288            /* Second, determine if there is any parameters following. */
     289            char *pszCmdParms = RTStrIStr(szCmd, " ");
     290            /* pszCmdParms can be NULL if command has not parameters. */
     291            RT_NOREF(pszCmdParms);
     292
     293            unsigned i = 0;
     294            for (; i < RT_ELEMENTS(g_aCmdMap); i++)
     295            {
     296                if (!RTStrICmp(szCmd, g_aCmdMap[i].szCmd))
     297                {
     298                    rc = g_aCmdMap[i].pfnCmd(pClient);
     299                    break;
     300                }
     301            }
     302
     303            if (i == RT_ELEMENTS(g_aCmdMap))
     304            {
     305                int rc2 = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL);
     306                if (RT_SUCCESS(rc))
     307                    rc = rc2;
     308            }
     309        }
     310        else
     311        {
     312            int rc2 = rtFTPServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_RECOGNIZED);
     313            if (RT_SUCCESS(rc))
     314                rc = rc2;
     315        }
     316    }
    156317
    157318    return rc;
     
    170331
    171332    int rc = rtFTPServerDoLogin(&ClientState);
     333    if (RT_SUCCESS(rc))
     334        rc = rtFTPServerProcessCommands(&ClientState);
    172335
    173336    return rc;
     
    187350    if (pThis)
    188351    {
     352        pThis->u32Magic = RTFTPSERVER_MAGIC;
     353
    189354        rc = RTTcpServerCreate(pcszAddress, uPort, RTTHREADTYPE_DEFAULT, "ftpsrv",
    190355                               rtFTPServerThread, pThis /* pvUser */, &pThis->pTCPServer);
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