- Timestamp:
- Jan 9, 2020 4:18:28 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/ftp.h
r82699 r82702 108 108 /** Service ready for new user. */ 109 109 RTFTPSERVER_REPLY_READY_FOR_NEW_USER = 220, 110 /** Service is closing control connection. */ 111 RTFTPSERVER_REPLY_CLOSING_CTRL_CONN = 221, 110 112 /** Closing data connection. */ 111 113 RTFTPSERVER_REPLY_CLOSING_DATA_CONN = 226, … … 137 139 typedef struct RTFTPSERVERCLIENTSTATE 138 140 { 141 /** User name. */ 142 char *pszUser; 143 /** Number of failed login attempts. */ 144 uint8_t cFailedLoginAttempts; 139 145 /** Timestamp (in ms) of last command issued by the client. */ 140 146 uint64_t tsLastCmdMs; -
trunk/src/VBox/Runtime/generic/ftp-server.cpp
r82699 r82702 195 195 static FNRTFTPSERVERCMD rtFtpServerHandleMODE; 196 196 static FNRTFTPSERVERCMD rtFtpServerHandleNOOP; 197 static FNRTFTPSERVERCMD rtFtpServerHandlePASS; 197 198 static FNRTFTPSERVERCMD rtFtpServerHandlePORT; 198 199 static FNRTFTPSERVERCMD rtFtpServerHandlePWD; … … 203 204 static FNRTFTPSERVERCMD rtFtpServerHandleSYST; 204 205 static FNRTFTPSERVERCMD rtFtpServerHandleTYPE; 206 static FNRTFTPSERVERCMD rtFtpServerHandleUSER; 205 207 206 208 /** … … 228 230 { RTFTPSERVER_CMD_MODE, "MODE", rtFtpServerHandleMODE }, 229 231 { RTFTPSERVER_CMD_NOOP, "NOOP", rtFtpServerHandleNOOP }, 232 { RTFTPSERVER_CMD_PASS, "PASS", rtFtpServerHandlePASS }, 230 233 { RTFTPSERVER_CMD_PORT, "PORT", rtFtpServerHandlePORT }, 231 234 { RTFTPSERVER_CMD_PWD, "PWD", rtFtpServerHandlePWD }, … … 236 239 { RTFTPSERVER_CMD_SYST, "SYST", rtFtpServerHandleSYST }, 237 240 { RTFTPSERVER_CMD_TYPE, "TYPE", rtFtpServerHandleTYPE }, 241 { RTFTPSERVER_CMD_USER, "USER", rtFtpServerHandleUSER }, 238 242 { RTFTPSERVER_CMD_LAST, "", NULL } 239 243 }; … … 370 374 } 371 375 376 static 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 372 401 static int rtFtpServerHandlePORT(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 373 402 { … … 451 480 } 452 481 482 static 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 453 516 454 517 /********************************************************************************************************************************* 455 518 * Internal server functions * 456 519 *********************************************************************************************************************************/ 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 }510 520 511 521 /** … … 582 592 *pszCmdEnd = '\0'; 583 593 584 /* Second, determine if there is any parameters following. */585 char *pszCmdParms = RTStrIStr(szCmd, " ");586 if (pszCmdParms)587 pszCmdParms++;588 589 594 uint8_t cArgs = 0; 590 595 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. */ 593 599 { 594 600 unsigned i = 0; 595 601 for (; i < RT_ELEMENTS(g_aCmdMap); i++) 596 602 { 597 if (!RTStrICmp( szCmd, g_aCmdMap[i].szCmd))603 if (!RTStrICmp(papszArgs[0], g_aCmdMap[i].szCmd)) 598 604 { 599 605 /* Save timestamp of last command sent. */ 600 606 pClient->State.tsLastCmdMs = RTTimeMilliTS(); 601 607 602 rc = g_aCmdMap[i].pfnCmd(pClient, cArgs , papszArgs);608 rc = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL); 603 609 break; 604 610 } … … 614 620 } 615 621 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) 617 625 { 626 int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_CLOSING_CTRL_CONN); 627 if (RT_SUCCESS(rc)) 628 rc = rc2; 629 618 630 RTFTPSERVER_HANDLE_CALLBACK_RET(pfnOnUserDisconnect); 619 631 break; … … 645 657 static void rtFtpServerClientStateReset(PRTFTPSERVERCLIENTSTATE pState) 646 658 { 659 RTStrFree(pState->pszUser); 660 pState->pszUser = NULL; 661 647 662 pState->tsLastCmdMs = RTTimeMilliTS(); 648 663 } … … 668 683 rtFtpServerClientStateReset(&Client.State); 669 684 670 int rc = rtFtpServerDoLogin(&Client); 685 /* Send welcome message. */ 686 int rc = rtFtpServerSendReplyRc(&Client, RTFTPSERVER_REPLY_READY_FOR_NEW_USER); 671 687 if (RT_SUCCESS(rc)) 672 688 { … … 677 693 ASMAtomicDecU32(&pThis->cClients); 678 694 } 695 696 rtFtpServerClientStateReset(&Client.State); 679 697 680 698 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.