Changeset 85676 in vbox for trunk/src/VBox
- Timestamp:
- Aug 10, 2020 4:18:47 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/ftp-server.cpp
r85674 r85676 2 2 /** @file 3 3 * Generic FTP server (RFC 959) implementation. 4 * 4 5 * 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 * 29 7 * Known limitations so far: 30 8 * - UTF-8 support only. … … 37 15 * - No proxy support. 38 16 * - 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. 39 38 */ 40 39 … … 158 157 } while (0) 159 158 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 *********************************************************************************************************************************/ 160 218 /** Supported FTP server command IDs. 161 219 * Alphabetically, named after their official command names. */ 162 typedef enum RTFTPSERVER _CMD220 typedef enum RTFTPSERVERCMD 163 221 { 164 222 /** Invalid command, do not use. Always must come first. */ 165 RTFTPSERVER _CMD_INVALID = 0,223 RTFTPSERVERCMD_INVALID = 0, 166 224 /** Aborts the current command on the server. */ 167 RTFTPSERVER _CMD_ABOR,225 RTFTPSERVERCMD_ABOR, 168 226 /** Changes the current working directory. */ 169 RTFTPSERVER _CMD_CDUP,227 RTFTPSERVERCMD_CDUP, 170 228 /** Changes the current working directory. */ 171 RTFTPSERVER _CMD_CWD,229 RTFTPSERVERCMD_CWD, 172 230 /** Reports features supported by the server. */ 173 RTFTPSERVER _CMD_FEAT,231 RTFTPSERVERCMD_FEAT, 174 232 /** Lists a directory. */ 175 RTFTPSERVER _CMD_LIST,233 RTFTPSERVERCMD_LIST, 176 234 /** Sets the transfer mode. */ 177 RTFTPSERVER _CMD_MODE,235 RTFTPSERVERCMD_MODE, 178 236 /** Sends a nop ("no operation") to the server. */ 179 RTFTPSERVER _CMD_NOOP,237 RTFTPSERVERCMD_NOOP, 180 238 /** Sets the password for authentication. */ 181 RTFTPSERVER _CMD_PASS,239 RTFTPSERVERCMD_PASS, 182 240 /** Sets the port to use for the data connection. */ 183 RTFTPSERVER _CMD_PORT,241 RTFTPSERVERCMD_PORT, 184 242 /** Gets the current working directory. */ 185 RTFTPSERVER _CMD_PWD,243 RTFTPSERVERCMD_PWD, 186 244 /** Get options. Needed in conjunction with the FEAT command. */ 187 RTFTPSERVER _CMD_OPTS,245 RTFTPSERVERCMD_OPTS, 188 246 /** Terminates the session (connection). */ 189 RTFTPSERVER _CMD_QUIT,247 RTFTPSERVERCMD_QUIT, 190 248 /** Retrieves a specific file. */ 191 RTFTPSERVER _CMD_RETR,249 RTFTPSERVERCMD_RETR, 192 250 /** Retrieves the size of a file. */ 193 RTFTPSERVER _CMD_SIZE,251 RTFTPSERVERCMD_SIZE, 194 252 /** Retrieves the current status of a transfer. */ 195 RTFTPSERVER _CMD_STAT,253 RTFTPSERVERCMD_STAT, 196 254 /** Sets the structure type to use. */ 197 RTFTPSERVER _CMD_STRU,255 RTFTPSERVERCMD_STRU, 198 256 /** Gets the server's OS info. */ 199 RTFTPSERVER _CMD_SYST,257 RTFTPSERVERCMD_SYST, 200 258 /** Sets the (data) representation type. */ 201 RTFTPSERVER _CMD_TYPE,259 RTFTPSERVERCMD_TYPE, 202 260 /** Sets the user name for authentication. */ 203 RTFTPSERVER _CMD_USER,261 RTFTPSERVERCMD_USER, 204 262 /** End marker. */ 205 RTFTPSERVER _CMD_END,263 RTFTPSERVERCMD_END, 206 264 /** The usual 32-bit hack. */ 207 RTFTPSERVER _CMD_32BIT_HACK = 0x7fffffff208 } RTFTPSERVER _CMD;265 RTFTPSERVERCMD_32BIT_HACK = 0x7fffffff 266 } RTFTPSERVERCMD; 209 267 210 268 struct RTFTPSERVERCLIENT; … … 272 330 typedef FNRTFTPSERVERCMD *PFNRTFTPSERVERCMD; 273 331 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 330 332 331 333 /********************************************************************************************************************************* 332 * Defined Constants And Macros*334 * Internal Functions * 333 335 *********************************************************************************************************************************/ 334 335 336 static int rtFtpServerDataConnOpen(PRTFTPSERVERDATACONN pDataConn, PRTNETADDRIPV4 pAddr, uint16_t uPort); 336 337 static int rtFtpServerDataConnClose(PRTFTPSERVERDATACONN pDataConn); … … 370 371 * Structure for maintaining a single command entry for the command table. 371 372 */ 372 typedef struct RTFTPSERVER _CMD_ENTRY373 typedef struct RTFTPSERVERCMD_ENTRY 373 374 { 374 375 /** 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]; 378 381 /** Whether the commands needs a logged in (valid) user. */ 379 bool fNeedsUser;382 bool fNeedsUser; 380 383 /** Function pointer invoked to handle the command. */ 381 PFNRTFTPSERVERCMD pfnCmd;382 } RTFTPSERVER _CMD_ENTRY;384 PFNRTFTPSERVERCMD pfnCmd; 385 } RTFTPSERVERCMD_ENTRY; 383 386 /** Pointer to a command entry. */ 384 typedef RTFTPSERVER_CMD_ENTRY *PRTFTPSERVER_CMD_ENTRY; 385 387 typedef RTFTPSERVERCMD_ENTRY *PRTFTPSERVERCMD_ENTRY; 388 389 390 391 /********************************************************************************************************************************* 392 * Global Variables * 393 *********************************************************************************************************************************/ 386 394 /** 387 395 * Table of handled commands. 388 396 */ 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 }397 static 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 } 411 419 }; 412 420 … … 2287 2295 static int rtFtpServerProcessCommands(PRTFTPSERVERCLIENT pClient, char *pcszCmd, size_t cbCmd) 2288 2296 { 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'. */ 2289 2300 /* Make sure to terminate the string in any case. */ 2290 2301 pcszCmd[RT_MIN(RTFTPSERVER_MAX_CMD_LEN, cbCmd)] = '\0'; … … 2295 2306 /* First, terminate string by finding the command end marker (telnet style). */ 2296 2307 /** @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? */ 2297 2309 char *pszCmdEnd = RTStrIStr(pcszCmd, "\r\n"); 2298 2310 if (pszCmdEnd) … … 2317 2329 for (; i < RT_ELEMENTS(g_aCmdMap); i++) 2318 2330 { 2319 const RTFTPSERVER _CMD_ENTRY *pCmdEntry = &g_aCmdMap[i];2331 const RTFTPSERVERCMD_ENTRY *pCmdEntry = &g_aCmdMap[i]; 2320 2332 2321 2333 if (!RTStrICmp(papszArgs[0], pCmdEntry->szCmd)) … … 2367 2379 } 2368 2380 2369 const bool fDisconnect = g_aCmdMap[i].enmCmd == RTFTPSERVER _CMD_QUIT2381 const bool fDisconnect = g_aCmdMap[i].enmCmd == RTFTPSERVERCMD_QUIT 2370 2382 || pClient->State.cFailedLoginAttempts >= 3; /** @todo Make this dynamic. */ 2371 2383 if (fDisconnect) … … 2398 2410 * @returns VBox status code. 2399 2411 * @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). 2400 2416 */ 2401 2417 static int rtFtpServerProcessCommands(PRTFTPSERVERCLIENT pClient) … … 2419 2435 } 2420 2436 } 2437 else if (rc == VERR_TIMEOUT) 2438 rc = VINF_SUCCESS; 2421 2439 else 2422 { 2423 if (rc == VERR_TIMEOUT) 2424 rc = VINF_SUCCESS; 2425 2426 if (RT_FAILURE(rc)) 2427 break; 2428 } 2440 break; 2429 2441 2430 2442 /*
Note:
See TracChangeset
for help on using the changeset viewer.