VirtualBox

Changeset 82702 in vbox for trunk


Ignore:
Timestamp:
Jan 9, 2020 4:18:28 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/FTP: Made authentication workflow more flexible. bugref:9437

Location:
trunk
Files:
2 edited

Legend:

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

    r82699 r82702  
    108108    /** Service ready for new user. */
    109109    RTFTPSERVER_REPLY_READY_FOR_NEW_USER             = 220,
     110    /** Service is closing control connection. */
     111    RTFTPSERVER_REPLY_CLOSING_CTRL_CONN              = 221,
    110112    /** Closing data connection. */
    111113    RTFTPSERVER_REPLY_CLOSING_DATA_CONN              = 226,
     
    137139typedef struct RTFTPSERVERCLIENTSTATE
    138140{
     141    /** User name. */
     142    char         *pszUser;
     143    /** Number of failed login attempts. */
     144    uint8_t       cFailedLoginAttempts;
    139145    /** Timestamp (in ms) of last command issued by the client. */
    140146    uint64_t      tsLastCmdMs;
  • trunk/src/VBox/Runtime/generic/ftp-server.cpp

    r82699 r82702  
    195195static FNRTFTPSERVERCMD rtFtpServerHandleMODE;
    196196static FNRTFTPSERVERCMD rtFtpServerHandleNOOP;
     197static FNRTFTPSERVERCMD rtFtpServerHandlePASS;
    197198static FNRTFTPSERVERCMD rtFtpServerHandlePORT;
    198199static FNRTFTPSERVERCMD rtFtpServerHandlePWD;
     
    203204static FNRTFTPSERVERCMD rtFtpServerHandleSYST;
    204205static FNRTFTPSERVERCMD rtFtpServerHandleTYPE;
     206static FNRTFTPSERVERCMD rtFtpServerHandleUSER;
    205207
    206208/**
     
    228230    { RTFTPSERVER_CMD_MODE,     "MODE",         rtFtpServerHandleMODE },
    229231    { RTFTPSERVER_CMD_NOOP,     "NOOP",         rtFtpServerHandleNOOP },
     232    { RTFTPSERVER_CMD_PASS,     "PASS",         rtFtpServerHandlePASS },
    230233    { RTFTPSERVER_CMD_PORT,     "PORT",         rtFtpServerHandlePORT },
    231234    { RTFTPSERVER_CMD_PWD,      "PWD",          rtFtpServerHandlePWD  },
     
    236239    { RTFTPSERVER_CMD_SYST,     "SYST",         rtFtpServerHandleSYST },
    237240    { RTFTPSERVER_CMD_TYPE,     "TYPE",         rtFtpServerHandleTYPE },
     241    { RTFTPSERVER_CMD_USER,     "USER",         rtFtpServerHandleUSER },
    238242    { RTFTPSERVER_CMD_LAST,     "",             NULL }
    239243};
     
    370374}
    371375
     376static int rtFtpServerHandlePASS(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     377{
     378    if (cArgs != 1)
     379        return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);
     380
     381    const char *pcszPassword = apcszArgs[0];
     382    AssertPtrReturn(pcszPassword, VERR_INVALID_PARAMETER);
     383
     384    int rc = rtFtpServerAuthenticate(pClient, pClient->State.pszUser, pcszPassword);
     385    if (RT_SUCCESS(rc))
     386    {
     387        rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_LOGGED_IN_PROCEED);
     388    }
     389    else
     390    {
     391        pClient->State.cFailedLoginAttempts++;
     392
     393        int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_NOT_LOGGED_IN);
     394        if (RT_SUCCESS(rc))
     395            rc = rc2;
     396    }
     397
     398    return rc;
     399}
     400
    372401static int rtFtpServerHandlePORT(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    373402{
     
    451480}
    452481
     482static int rtFtpServerHandleUSER(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     483{
     484    if (cArgs != 1)
     485        return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);
     486
     487    const char *pcszUser = apcszArgs[0];
     488    AssertPtrReturn(pcszUser, VERR_INVALID_PARAMETER);
     489
     490    if (pClient->State.pszUser)
     491    {
     492        RTStrFree(pClient->State.pszUser);
     493        pClient->State.pszUser = NULL;
     494    }
     495
     496    int rc = rtFtpServerLookupUser(pClient, pcszUser);
     497    if (RT_SUCCESS(rc))
     498    {
     499        pClient->State.pszUser = RTStrDup(pcszUser);
     500        AssertPtrReturn(pClient->State.pszUser, VERR_NO_MEMORY);
     501
     502        rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_USERNAME_OKAY_NEED_PASSWORD);
     503    }
     504    else
     505    {
     506        pClient->State.cFailedLoginAttempts++;
     507
     508        int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_NOT_LOGGED_IN);
     509        if (RT_SUCCESS(rc))
     510            rc = rc2;
     511    }
     512
     513    return rc;
     514}
     515
    453516
    454517/*********************************************************************************************************************************
    455518*   Internal server functions                                                                                                    *
    456519*********************************************************************************************************************************/
    457 
    458 /**
    459  * Handles the client's login procedure.
    460  *
    461  * @returns VBox status code.
    462  * @param   pClient             Client to handle login procedure for.
    463  */
    464 static int rtFtpServerDoLogin(PRTFTPSERVERCLIENT pClient)
    465 {
    466     LogFlowFuncEnter();
    467 
    468     /* Send welcome message. */
    469     int rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_READY_FOR_NEW_USER);
    470     if (RT_SUCCESS(rc))
    471     {
    472         size_t cbRead;
    473 
    474         char szUser[64];
    475         rc = RTTcpRead(pClient->hSocket, szUser, sizeof(szUser), &cbRead);
    476         if (RT_SUCCESS(rc))
    477         {
    478             rc = rtFtpServerLookupUser(pClient, szUser);
    479             if (RT_SUCCESS(rc))
    480             {
    481                 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_USERNAME_OKAY_NEED_PASSWORD);
    482                 if (RT_SUCCESS(rc))
    483                 {
    484                     char szPass[64];
    485                     rc = RTTcpRead(pClient->hSocket, szPass, sizeof(szPass), &cbRead);
    486                     {
    487                         if (RT_SUCCESS(rc))
    488                         {
    489                             rc = rtFtpServerAuthenticate(pClient, szUser, szPass);
    490                             if (RT_SUCCESS(rc))
    491                             {
    492                                 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_LOGGED_IN_PROCEED);
    493                             }
    494                         }
    495                     }
    496                 }
    497             }
    498         }
    499     }
    500 
    501     if (RT_FAILURE(rc))
    502     {
    503         int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_NOT_LOGGED_IN);
    504         if (RT_SUCCESS(rc))
    505             rc = rc2;
    506     }
    507 
    508     return rc;
    509 }
    510520
    511521/**
     
    582592                *pszCmdEnd = '\0';
    583593
    584             /* Second, determine if there is any parameters following. */
    585             char *pszCmdParms = RTStrIStr(szCmd, " ");
    586             if (pszCmdParms)
    587                 pszCmdParms++;
    588 
    589594            uint8_t cArgs     = 0;
    590595            char  **papszArgs = NULL;
    591             rc = rtFtpServerCmdArgsParse(pszCmdParms, &cArgs, &papszArgs);
    592             if (RT_SUCCESS(rc))
     596            rc = rtFtpServerCmdArgsParse(szCmd, &cArgs, &papszArgs);
     597            if (   RT_SUCCESS(rc)
     598                && cArgs) /* At least the actual command (without args) must be present. */
    593599            {
    594600                unsigned i = 0;
    595601                for (; i < RT_ELEMENTS(g_aCmdMap); i++)
    596602                {
    597                     if (!RTStrICmp(szCmd, g_aCmdMap[i].szCmd))
     603                    if (!RTStrICmp(papszArgs[0], g_aCmdMap[i].szCmd))
    598604                    {
    599605                        /* Save timestamp of last command sent. */
    600606                        pClient->State.tsLastCmdMs = RTTimeMilliTS();
    601607
    602                         rc = g_aCmdMap[i].pfnCmd(pClient, cArgs, papszArgs);
     608                        rc = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL);
    603609                        break;
    604610                    }
     
    614620                }
    615621
    616                 if (g_aCmdMap[i].enmCmd == RTFTPSERVER_CMD_QUIT)
     622                const bool fDisconnect =    g_aCmdMap[i].enmCmd == RTFTPSERVER_CMD_QUIT
     623                                         || pClient->State.cFailedLoginAttempts >= 3; /** @todo Make this dynamic. */
     624                if (fDisconnect)
    617625                {
     626                    int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_CLOSING_CTRL_CONN);
     627                    if (RT_SUCCESS(rc))
     628                        rc = rc2;
     629
    618630                    RTFTPSERVER_HANDLE_CALLBACK_RET(pfnOnUserDisconnect);
    619631                    break;
     
    645657static void rtFtpServerClientStateReset(PRTFTPSERVERCLIENTSTATE pState)
    646658{
     659    RTStrFree(pState->pszUser);
     660    pState->pszUser = NULL;
     661
    647662    pState->tsLastCmdMs = RTTimeMilliTS();
    648663}
     
    668683    rtFtpServerClientStateReset(&Client.State);
    669684
    670     int rc = rtFtpServerDoLogin(&Client);
     685    /* Send welcome message. */
     686    int rc = rtFtpServerSendReplyRc(&Client, RTFTPSERVER_REPLY_READY_FOR_NEW_USER);
    671687    if (RT_SUCCESS(rc))
    672688    {
     
    677693        ASMAtomicDecU32(&pThis->cClients);
    678694    }
     695
     696    rtFtpServerClientStateReset(&Client.State);
    679697
    680698    return 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