void FtpClient_OnCmdRmd(FtpClient *pClient, const char *pDir) { if (FileSystem_DeleteDir(&pClient->m_kContext, pDir) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else FtpClient_Send(pClient, 250, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); }
void FtpClient_OnCmdPass( FtpClient* pClient, const char* pPass ) { if( (AUTHSTATE_PASSWORD == pClient->m_eAuthState) && !strcmp(pPass,pClient->m_pServer->m_Password) ) { // password matches, allow login FtpClient_Send(pClient,230,"User logged in."); pClient->m_eAuthState = AUTHSTATE_VALID; } else { // password didn't match, or we had no valid login if( AUTHSTATE_INVALID != pClient->m_eAuthState ) { FtpClient_Send(pClient,530, pClient->m_pMessages[FTPMSG_LOGIN_INCORRECT] ); // disconnect client if more than 3 attempts to login has been made pClient->m_iAuthAttempt++; if( pClient->m_iAuthAttempt > 3 ) FtpServer_OnClientDisconnect( pClient->m_pServer, pClient ); pClient->m_eAuthState = AUTHSTATE_INVALID; } else FtpClient_Send( pClient, 503, pClient->m_pMessages[FTPMSG_LOGIN_WITH_USER_FIRST] ); } }
void FtpClient_OnCmdRnto(FtpClient *pClient, const char *newName) { if (FileSystem_Rename(&pClient->m_kContext, buffer, newName) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else FtpClient_Send(pClient, 250, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); }
void FtpClient_OnCmdCwd(FtpClient *pClient, const char *pPath) { if (FileSystem_ChangeDir(&pClient->m_kContext, pPath) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else FtpClient_Send(pClient, 250, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); }
void FtpClient_OnDataComplete( FtpClient* pClient, int iReturnCode, const char* pMessage ) { assert( pClient ); if( pMessage && iReturnCode > 0 ) { FtpClient_Send( pClient, iReturnCode, pMessage ); } else { switch( pClient->m_eDataAction ) { case DATAACTION_APPE: case DATAACTION_NLST: case DATAACTION_LIST: case DATAACTION_RETR: case DATAACTION_STOR: FtpClient_Send( pClient, 226, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL] ); break; default: break; } } // thanks to clients implemented incorrectly, we must close the connection after completed transfer FtpClient_OnDataCleanup(pClient); }
void FtpClient_OnCmdType(FtpClient *pClient, const char *pType) { if ((tolower(*pType) == 'i') || (tolower(*pType) == 'a')) FtpClient_Send(pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_ILLEGAL_COMMAND]); }
void FtpClient_OnCmdMode(FtpClient *pClient, const char *pMode) { // only stream-mode supported if (tolower(*pMode) == 's') FtpClient_Send(pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); }
void FtpClient_OnCmdStru(FtpClient *pClient, const char *pStructure) { // only file-structure supported if (tolower(*pStructure) == 'f') FtpClient_Send(pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); }
void FtpClient_OnSiteUmount(struct FtpClient *pClient, const char *pMountPoint) { // unmount filesystem if (FileSystem_UnmountDevice(&(pClient->m_kContext), pMountPoint) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else FtpClient_Send(pClient, 214, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); }
void FtpClient_OnSiteSync(struct FtpClient *pClient, const char *pDeviceName) { // sync data with filesystem if (FileSystem_SyncDevice(&(pClient->m_kContext), pDeviceName) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else FtpClient_Send(pClient, 214, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); }
void FtpClient_OnCmdRest(FtpClient *pClient, int iMarker) { if (iMarker < 0) { pClient->m_iRestartMarker = 0; FtpClient_Send(pClient, 501, pClient->m_pMessages[FTPMSG_INVALID_RESTART_MARKER]); } else { pClient->m_iRestartMarker = iMarker; FtpClient_Send(pClient, 350, pClient->m_pMessages[FTPMSG_RESTART_MARKER_SET]); } }
void FtpClient_OnCmdSize(FtpClient *pClient, const char *pFile) { int size = FileSystem_GetFileSize(&(pClient->m_kContext), pFile); if (size < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COULD_NOT_GET_FILESIZE]); else { itoa(buffer, size); FtpClient_Send(pClient, 213, buffer); } }
void FtpClient_OnCmdQuit(FtpClient *pClient) { assert(pClient); FtpClient_Send(pClient, 221, pClient->m_pMessages[FTPMSG_GOODBYE]); FtpServer_OnClientDisconnect(pClient->m_pServer, pClient); }
void FtpClient_OnCmdRnfr(FtpClient *pClient, const char *name) { int iMarker = pClient->m_iRestartMarker; pClient->m_iRestartMarker = 0; // check if file/dir exists that is to be renamed if ((FileSystem_OpenFile(&pClient->m_kContext, name, FM_READ, iMarker)) && (FileSystem_OpenDir(&pClient->m_kContext, name)) < 0) FtpClient_Send(pClient, 550, pClient->m_pMessages[FTPMSG_COMMAND_FAILED]); else { // get just the name not the path FileSystem_BuildPath(buffer, pClient->m_kContext.m_Path, name); if (NULL != (name = FileSystem_ClassifyPath(&pClient->m_kContext, buffer))) strcpy(buffer, name); FtpClient_Send(pClient, 350, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); } }
void FtpClient_OnCmdUser(FtpClient *pClient, const char *pUser) { assert(pClient); if (!strcmp(pUser, "anonymous") && pClient->m_pServer->m_iAnonymous) { // anonymous login, user authenticated pClient->m_eAuthState = AUTHSTATE_VALID; FtpClient_Send(pClient, 230, pClient->m_pMessages[FTPMSG_USER_LOGGED_IN]); } else { // allow password check pClient->m_eAuthState = !strcmp(pUser, pClient->m_pServer->m_Username) ? AUTHSTATE_PASSWORD : AUTHSTATE_FAKEPASS; FtpClient_Send(pClient, 331, pClient->m_pMessages[FTPMSG_PASSWORD_REQUIRED_FOR_USER]); // after this line, username is destroyed } }
void FtpClient_OnDataConnected( FtpClient* pClient ) { assert( pClient ); switch( pClient->m_eDataAction ) { case DATAACTION_LIST: case DATAACTION_NLST: { pClient->m_eDataMode = DATAMODE_WRITE; pClient->m_eConnState = CONNSTATE_RUNNING; FtpClient_Send( pClient, 150, pClient->m_pMessages[FTPMSG_OPENING_ASCII_CONNECTION] ); } break; case DATAACTION_RETR: { pClient->m_eDataMode = DATAMODE_WRITE; pClient->m_eConnState = CONNSTATE_RUNNING; FtpClient_Send( pClient, 150, pClient->m_pMessages[FTPMSG_OPENING_BINARY_CONNECTION] ); } break; case DATAACTION_APPE: case DATAACTION_STOR: { pClient->m_eDataMode = DATAMODE_READ; pClient->m_eConnState = CONNSTATE_RUNNING; FtpClient_Send( pClient, 150, pClient->m_pMessages[FTPMSG_OPENING_BINARY_CONNECTION] ); } break; // something has gone wrong, but we have an open socket here, keep it for re-use (some clients support it) default: { pClient->m_eDataMode = DATAMODE_IDLE; pClient->m_eConnState = CONNSTATE_RUNNING; } break; } pClient->m_uiDataBufferSize = sizeof(buffer); pClient->m_uiDataOffset = 0; }
void FtpClient_OnCmdPort(FtpClient *pClient, int *ip, int port) { assert(pClient); if (port >= 1024) { // TODO: validate IP? pClient->m_iRemoteAddress[0] = ip[0]; pClient->m_iRemoteAddress[1] = ip[1]; pClient->m_iRemoteAddress[2] = ip[2]; pClient->m_iRemoteAddress[3] = ip[3]; pClient->m_iRemotePort = port; FtpClient_Send(pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL]); } else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_ILLEGAL_COMMAND]); }
void FtpClient_OnCmdPwd(FtpClient *pClient) { char *buf2 = buffer; *(buf2++) = '\"'; *(buf2) = '\0'; strcat(buf2, pClient->m_kContext.m_Path); buf2 = buf2 + strlen(buf2); *(buf2++) = '\"'; *(buf2) = '\0'; FtpClient_Send(pClient, 257, buffer); }
void FtpClient_OnCmdAppe(FtpClient *pClient, const char *pFile) { assert(pClient); if (FileSystem_OpenFile(&pClient->m_kContext, pFile, FM_WRITE, -1) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_CREATE_FILE]); return; } pClient->m_eDataAction = DATAACTION_APPE; FtpClient_HandleDataConnect(pClient); }
void FtpClient_OnCmdSyst(FtpClient *pClient) { assert(pClient); // TODO: is this proper? /* UNIX-style LIST format */ FtpClient_Send(pClient, 215, "UNIX Type: L8"); /* MS-style LIST format: To use uncomment this format after commenting out UNIX-style LIST format and making changes in FtpClient.c's FtpClient_OnDataWrite FtpClient_Send( pClient, 215, "Windows_NT version 5.0" ); */ }
void FtpClient_OnCmdRetr(FtpClient *pClient, const char *pFile) { int iMarker = pClient->m_iRestartMarker; pClient->m_iRestartMarker = 0; if (FileSystem_OpenFile(&pClient->m_kContext, pFile, FM_READ, iMarker) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_FILE_NOT_FOUND]); return; } pClient->m_eDataAction = DATAACTION_RETR; FtpClient_HandleDataConnect(pClient); }
void FtpClient_OnCmdStor(FtpClient *pClient, const char *pFile) { int iMarker = pClient->m_iRestartMarker; pClient->m_iRestartMarker = 0; if (FileSystem_OpenFile(&pClient->m_kContext, pFile, FM_WRITE, iMarker) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_CREATE_FILE]); return; } pClient->m_eDataAction = DATAACTION_STOR; FtpClient_HandleDataConnect(pClient); }
void FtpClient_OnCmdList(struct FtpClient *pClient, const char *pPath, int iNamesOnly) { assert(pClient); if (iNamesOnly) pClient->m_eDataAction = DATAACTION_NLST; else pClient->m_eDataAction = DATAACTION_LIST; // attempt to open directory if (FileSystem_OpenDir(&pClient->m_kContext, pPath) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_UNABLE_TO_OPEN_DIRECTORY]); return; } FtpClient_HandleDataConnect(pClient); }
void FtpClient_OnCmdPasv(FtpClient *pClient) { struct sockaddr_in sa; socklen_t sl; int s; unsigned int addr; unsigned short port; char *buf; assert(pClient); FtpClient_OnDataCleanup(pClient); // get socket address we will listen to sl = sizeof(sa); if (getsockname(pClient->m_iControlSocket, (struct sockaddr *)&sa, &sl) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_ENTER_PASSIVE_MODE]); return; } sa.sin_port = 0; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { disconnect(s); FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_ENTER_PASSIVE_MODE]); return; } if (bind(s, (struct sockaddr *)&sa, sl) < 0) { disconnect(s); FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_ENTER_PASSIVE_MODE]); return; } if (listen(s, 1) < 0) { disconnect(s); FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_ENTER_PASSIVE_MODE]); return; } // report back sl = sizeof(sa); if (getsockname(s, (struct sockaddr *)&sa, &sl) < 0) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_COULD_NOT_ENTER_PASSIVE_MODE]); return; } // store socket and flag us as listening pClient->m_iDataSocket = s; pClient->m_eConnState = CONNSTATE_LISTEN; // generate reply addr = htonl(sa.sin_addr.s_addr); port = htons(sa.sin_port); buf = buffer; strcpy(buf, pClient->m_pMessages[FTPMSG_ENTERING_PASSIVE_MODE]); strcat(buf, " ("); itoa(buf + strlen(buf), (addr >> 24) & 0xff); strcat(buf, ","); itoa(buf + strlen(buf), (addr >> 16) & 0xff); strcat(buf, ","); itoa(buf + strlen(buf), (addr >> 8) & 0xff); strcat(buf, ","); itoa(buf + strlen(buf), (addr)&0xff); strcat(buf, ","); itoa(buf + strlen(buf), port >> 8); strcat(buf, ","); itoa(buf + strlen(buf), port & 0xff); strcat(buf, ")."); /* sprintf( buffer, "Entering passive mode (%d,%d,%d,%d,%d,%d).", (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8)&0xff, addr&0xff, port>>8,port&0xff ); */ FtpClient_Send(pClient, 227, buffer); }
void FtpClient_OnCommand( FtpClient* pClient, const char* pString ) { char* c; assert( pClient ); strcpy(buffer,pString); c = strtok(buffer," "); if(c) { int i; unsigned int result = 0; for( i = 0; *c && i < 4; i++ ) result = (result<<8)|tolower(*(c++)); // if user has not logged in, we only allow a small subset of commands if( pClient->m_eAuthState != AUTHSTATE_VALID ) { switch( result ) { // USER <name> case FTPCMD_USER: { char* user = strtok(NULL,""); if(user) FtpClient_OnCmdUser(pClient,user); else FtpClient_Send( pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS] ); } break; // PASS <password> case FTPCMD_PASS: { char* pass = strtok(NULL,""); if(pass) FtpClient_OnCmdPass(pClient,pass); else FtpClient_Send( pClient, 530, pClient->m_pMessages[FTPMSG_LOGIN_INCORRECT] ); } break; // QUIT case FTPCMD_QUIT: { FtpClient_OnCmdQuit(pClient); } break; case FTPCMD_NOOP: FtpClient_Send( pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL] ); break; } return; } switch( result ) { case FTPCMD_USER: case FTPCMD_PASS: { FtpClient_Send( pClient, 503, pClient->m_pMessages[FTPMSG_ALREADY_AUTHENTICATED] ); } break; // PASV case FTPCMD_PASV: { FtpClient_OnCmdPasv(pClient); } break; // PORT a0,a1,a2,a3,p0,p1 case FTPCMD_PORT: { int i; int ip[4]; int port = 0; for( i = 0; i < 6; i++ ) { char* val = strtok(NULL,","); if(!val) break; if( i >= 0 && i < 4 ) { ip[i] = strtol(val,NULL,10); } else if( 4 == i ) { port = strtol(val,NULL,10)*256; } else if( 5 == i ) { port += strtol(val,NULL,10); } } if(6 == i) FtpClient_OnCmdPort(pClient,ip,port); else FtpClient_Send( pClient, 501, pClient->m_pMessages[FTPMSG_ILLEGAL_COMMAND] ); } break; // QUIT case FTPCMD_QUIT: { FtpClient_OnCmdQuit(pClient); } break; // SYST case FTPCMD_SYST: { FtpClient_OnCmdSyst(pClient); } break; // LIST case FTPCMD_LIST: { char* path = strtok(NULL,""); if(path) FtpClient_OnCmdList(pClient,path,0); else FtpClient_OnCmdList(pClient,"",0); } break; // NLST case FTPCMD_NLST: { char* path = strtok(NULL,""); if(path) FtpClient_OnCmdList(pClient,path,1); else FtpClient_OnCmdList(pClient,"",1); } break; // these all share the same setup case FTPCMD_TYPE: case FTPCMD_RETR: case FTPCMD_STOR: case FTPCMD_APPE: case FTPCMD_CWD: case FTPCMD_XCWD: case FTPCMD_DELE: case FTPCMD_MKD: case FTPCMD_XMKD: case FTPCMD_RMD: case FTPCMD_XRMD: case FTPCMD_RNFR: case FTPCMD_RNTO: case FTPCMD_SITE: case FTPCMD_MODE: case FTPCMD_STRU: case FTPCMD_SIZE: { char* arg = strtok(NULL,""); if( arg ) { switch( result ) { case FTPCMD_TYPE: FtpClient_OnCmdType(pClient,arg); break; case FTPCMD_RETR: FtpClient_OnCmdRetr(pClient,arg); break; case FTPCMD_STOR: FtpClient_OnCmdStor(pClient,arg); break; case FTPCMD_APPE: FtpClient_OnCmdAppe(pClient,arg); break; case FTPCMD_CWD: case FTPCMD_XCWD: FtpClient_OnCmdCwd(pClient,arg); break; case FTPCMD_DELE: FtpClient_OnCmdDele(pClient,arg); break; case FTPCMD_MKD: case FTPCMD_XMKD: FtpClient_OnCmdMkd(pClient,arg); break; case FTPCMD_RMD: case FTPCMD_XRMD: FtpClient_OnCmdRmd(pClient,arg); break; case FTPCMD_RNFR: FtpClient_OnCmdRnfr(pClient,arg); break; case FTPCMD_RNTO: FtpClient_OnCmdRnto(pClient,arg); break; case FTPCMD_SITE: FtpClient_OnCmdSite(pClient,arg); break; case FTPCMD_MODE: FtpClient_OnCmdMode(pClient,arg); break; case FTPCMD_STRU: FtpClient_OnCmdStru(pClient,arg); break; case FTPCMD_SIZE: FtpClient_OnCmdSize(pClient,arg); break; } } else FtpClient_Send( pClient, 501, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS] ); } break; // TYPE <type> case FTPCMD_PWD: case FTPCMD_XPWD: { FtpClient_OnCmdPwd(pClient); } break; case FTPCMD_CDUP: { FtpClient_OnCmdCwd(pClient,".."); } break; case FTPCMD_REST: { char* marker = strtok(NULL,""); if(marker) { char* c = marker; while(*c) { if((*c < '0')||(*c > '9')) break; c++; } if(!*c) FtpClient_OnCmdRest( pClient, (!*c) ? strtol( marker, NULL, 10 ) : -1 ); } else FtpClient_Send( pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS] ); } break; case FTPCMD_NOOP: FtpClient_Send( pClient, 200, pClient->m_pMessages[FTPMSG_COMMAND_SUCCESSFUL] ); break; default: FtpClient_Send( pClient, 500, pClient->m_pMessages[FTPMSG_NOT_UNDERSTOOD] ); break; } } else FtpClient_Send( pClient, 500, pClient->m_pMessages[FTPMSG_NOT_UNDERSTOOD] ); }
void FtpClient_OnCmdSite(FtpClient *pClient, const char *pCmd) { char *c; // copy command to clean buffer strcpy(buffer, pCmd); c = strtok(buffer, " "); if (c) { int i = 0; unsigned int result = 0; for (i = 0; *c && i < 4; i++) result = (result << 8) | tolower(*(c++)); switch (result) { #ifndef LINUX // SITE MNT <device> <file> case SITECMD_MNT: { char *mount_point; char *mount_file; // get mount point mount_point = strtok(NULL, " "); if (!mount_point || !strlen(mount_point)) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS]); break; } // get mount source mount_file = strtok(NULL, ""); if (!mount_file || !strlen(mount_file)) { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS]); break; } FtpClient_OnSiteMount(pClient, mount_point, mount_file); } break; // SITE UMNT <device> case SITECMD_UMNT: { char *mount_point = strtok(NULL, ""); if (mount_point) FtpClient_OnSiteUmount(pClient, mount_point); else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS]); } break; // SITE SYNC <device> case SITECMD_SYNC: { char *devname = strtok(NULL, ""); if (devname) FtpClient_OnSiteSync(pClient, devname); else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_REQUIRES_PARAMETERS]); } break; #endif default: { FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_NOT_SUPPORTED]); } break; } } else FtpClient_Send(pClient, 500, pClient->m_pMessages[FTPMSG_NOT_UNDERSTOOD]); }
void FtpClient_OnConnect( FtpClient* pClient ) { FtpClient_Send( pClient, 220, pClient->m_pMessages[FTPMSG_SERVER_READY] ); }