mistserver/lib/ftp.cpp
2012-08-23 12:06:26 +02:00

399 lines
14 KiB
C++

#include "ftp.h"
FTP::User::User( Socket::Connection NewConnection ) {
Conn = NewConnection;
USER = "";
PASS = "";
MODE = MODE_STREAM;
STRU = STRU_FILE;
TYPE = TYPE_ASCII_NONPRINT;
PORT = 20;
RNFR = "";
MyDir = Filesystem::Directory( "", FTPBasePath );
MyDir.SetPermissions( "", Filesystem::P_LIST );
MyDir.SetPermissions( "Unconverted", Filesystem::P_LIST | Filesystem::P_DELE | Filesystem::P_RNFT | Filesystem::P_STOR | Filesystem::P_RETR );
MyDir.SetPermissions( "Converted", Filesystem::P_LIST | Filesystem::P_DELE | Filesystem::P_RNFT | Filesystem::P_RETR );
MyDir.SetPermissions( "OnDemand", Filesystem::P_LIST | Filesystem::P_RETR );
MyDir.SetPermissions( "Live", Filesystem::P_LIST );
MyDir.SetVisibility( "Converted", Filesystem::S_INACTIVE );
MyDir.SetVisibility( "OnDemand", Filesystem::S_ACTIVE );
JSON::Value MyConfig = JSON::fromFile( "/tmp/mist/streamlist" );
fprintf( stderr, "Streamamount: %d\n", MyConfig["streams"].size() );
for( JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++ ) {
std::string ThisStream = (*it).second["channel"]["URL"].toString();
ThisStream.erase( ThisStream.begin() );
ThisStream.erase( ThisStream.end() - 1 );
while( ThisStream.find( '/' ) != std::string::npos ) {
ThisStream.erase(0,ThisStream.find('/')+1);
}
ActiveStreams.push_back( ThisStream );
fprintf( stderr, "\t%s\n", ThisStream.c_str() );
}
}
FTP::User::~User( ) { }
int FTP::User::ParseCommand( std::string Command ) {
Commands ThisCmd = CMD_NOCMD;
if( Command.substr(0,4) == "NOOP" ) { ThisCmd = CMD_NOOP; Command.erase(0,5); }
if( Command.substr(0,4) == "USER" ) { ThisCmd = CMD_USER; Command.erase(0,5); }
if( Command.substr(0,4) == "PASS" ) { ThisCmd = CMD_PASS; Command.erase(0,5); }
if( Command.substr(0,4) == "QUIT" ) { ThisCmd = CMD_QUIT; Command.erase(0,5); }
if( Command.substr(0,4) == "PORT" ) { ThisCmd = CMD_PORT; Command.erase(0,5); }
if( Command.substr(0,4) == "RETR" ) { ThisCmd = CMD_RETR; Command.erase(0,5); }
if( Command.substr(0,4) == "STOR" ) { ThisCmd = CMD_STOR; Command.erase(0,5); }
if( Command.substr(0,4) == "TYPE" ) { ThisCmd = CMD_TYPE; Command.erase(0,5); }
if( Command.substr(0,4) == "MODE" ) { ThisCmd = CMD_MODE; Command.erase(0,5); }
if( Command.substr(0,4) == "STRU" ) { ThisCmd = CMD_STRU; Command.erase(0,5); }
if( Command.substr(0,4) == "EPSV" ) { ThisCmd = CMD_EPSV; Command.erase(0,5); }
if( Command.substr(0,4) == "PASV" ) { ThisCmd = CMD_PASV; Command.erase(0,5); }
if( Command.substr(0,4) == "LIST" ) { ThisCmd = CMD_LIST; Command.erase(0,5); }
if( Command.substr(0,4) == "CDUP" ) { ThisCmd = CMD_CDUP; Command.erase(0,5); }
if( Command.substr(0,4) == "DELE" ) { ThisCmd = CMD_DELE; Command.erase(0,5); }
if( Command.substr(0,4) == "RNFR" ) { ThisCmd = CMD_RNFR; Command.erase(0,5); }
if( Command.substr(0,4) == "RNTO" ) { ThisCmd = CMD_RNTO; Command.erase(0,5); }
if( Command.substr(0,3) == "PWD" ) { ThisCmd = CMD_PWD; Command.erase(0,4); }
if( Command.substr(0,3) == "CWD" ) { ThisCmd = CMD_CWD; Command.erase(0,4); }
if( Command.substr(0,3) == "RMD" ) { ThisCmd = CMD_RMD; Command.erase(0,4); }
if( Command.substr(0,3) == "MKD" ) { ThisCmd = CMD_MKD; Command.erase(0,4); }
if( ThisCmd != CMD_RNTO ) { RNFR = ""; }
switch( ThisCmd ) {
case CMD_NOOP: {
return 200;//Command okay.
break;
}
case CMD_USER: {
USER = "";
PASS = "";
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
USER = ThisCmd;
return 331;//User name okay, need password.
break;
}
case CMD_PASS: {
if( USER == "" ) { return 503; }//Bad sequence of commands
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
PASS = ThisCmd;
if( !LoggedIn( ) ) {
USER = "";
PASS ="";
return 530;//Not logged in.
}
return 230;
break;
}
case CMD_LIST: {
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if( Connected.connected() ) {
Conn.write( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.write( "150 File status okay; about to open data connection.\n" );
}
while( !Connected.connected() ) {
Connected = Passive.accept();
}
fprintf( stderr, "Sending LIST information\n" );
Connected.write( MyDir.LIST( ActiveStreams ) );
Connected.close( );
return 226;
break;
}
case CMD_QUIT: {
return 221;//Service closing control connection. Logged out if appropriate.
break;
}
case CMD_PORT: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
PORT = atoi( Command.c_str() );
return 200;//Command okay.
break;
}
case CMD_EPSV: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
MyPassivePort = (rand() % 9999);
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort,"0.0.0.0",true);
return 229;
break;
}
case CMD_PASV: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
MyPassivePort = (rand() % 9999) + 49152;
std::cout << ":" << MyPassivePort << "\n";
Passive = Socket::Server(MyPassivePort,"0.0.0.0",true);
return 227;
break;
}
case CMD_RETR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_RETR ) ) { return 550; }//Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if( Connected.connected() ) {
Conn.write( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.write( "150 File status okay; about to open data connection.\n" );
}
while( !Connected.connected() ) {
Connected = Passive.accept();
}
fprintf( stderr, "Sending RETR information\n" );
Connected.write( MyDir.RETR( Command ) );
Connected.close();
return 226;
break;
}
case CMD_STOR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_STOR ) ) { return 550; }//Access denied.
std::cout << "Listening on :" << MyPassivePort << "\n";
Socket::Connection Connected = Passive.accept();
if( Connected.connected() ) {
Conn.write( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.write( "150 File status okay; about to open data connection.\n" );
}
while( !Connected.connected() ) {
Connected = Passive.accept();
}
fprintf( stderr, "Reading STOR information\n" );
std::string Buffer;
while( Connected.spool() ) { }
Buffer = Connected.Received();
MyDir.STOR( Command, Buffer );
return 250;
break;
}
case CMD_TYPE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 && Command.size() != 3 ) { return 501; }//Syntax error in parameters or arguments.
switch( Command[0] ) {
case 'A': {
if( Command.size() > 1 ) {
if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
}
TYPE = TYPE_ASCII_NONPRINT;
break;
}
case 'I': {
if( Command.size() > 1 ) {
if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
}
TYPE = TYPE_IMAGE_NONPRINT;
break;
}
default: {
return 504;//Command not implemented for that parameter.
break;
}
}
return 200;//Command okay.
break;
}
case CMD_MODE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
if( Command[0] != 'S' ) { return 504; }//Command not implemented for that parameter.
MODE = MODE_STREAM;
return 200;//Command okay.
break;
}
case CMD_STRU: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
switch( Command[0] ) {
case 'F': {
STRU = STRU_FILE;
break;
}
case 'R': {
STRU = STRU_RECORD;
break;
}
default: {
return 504;//Command not implemented for that parameter.
break;
}
}
return 200;//Command okay.
break;
}
case CMD_PWD: {
if( !LoggedIn( ) ) { return 550; }//Not logged in.
if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
return 2570;//257 -- 0 to indicate PWD over MKD
break;
}
case CMD_CWD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
Filesystem::Directory TmpDir = MyDir;
if( TmpDir.CWD( Command ) ) {
if( TmpDir.IsDir( ) ) {
MyDir = TmpDir;
return 250;
}
}
return 550;
break;
}
case CMD_CDUP: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
Filesystem::Directory TmpDir = MyDir;
if( TmpDir.CDUP( ) ) {
if( TmpDir.IsDir( ) ) {
MyDir = TmpDir;
return 250;
}
}
return 550;
break;
}
case CMD_DELE: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.DELE( Command ) ) { return 550; }
return 250;
break;
}
case CMD_RMD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_RMD ) ) { return 550; }
if( !MyDir.DELE( Command ) ) { return 550; }
return 250;
break;
}
case CMD_MKD: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( !MyDir.HasPermission( Filesystem::P_MKD ) ) { return 550; }
if( !MyDir.MKD( Command ) ) { return 550; }
return 2571;
break;
}
case CMD_RNFR: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
RNFR = Command;
return 350;//Awaiting further information
}
case CMD_RNTO: {
if( !LoggedIn( ) ) { return 530; }//Not logged in.
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
if( RNFR == "" ) { return 503; } //Bad sequence of commands
if( !MyDir.Rename( RNFR, Command ) ) { return 550; }
return 250;
}
default: {
return 502;//Command not implemented.
break;
}
}
}
bool FTP::User::LoggedIn( ) {
if( USER == "" || PASS == "" ) { return false; }
return true;
}
std::string FTP::User::NumToMsg( int MsgNum ) {
std::string Result;
switch( MsgNum ) {
case 200: {
Result = "200 Message okay.\n";
break;
}
case 221: {
Result = "221 Service closing control connection. Logged out if appropriate.\n";
break;
}
case 226: {
Result = "226 Closing data connection.\n";
break;
}
case 227: {
std::stringstream sstr;
sstr << "227 Entering passive mode (0,0,0,0,";
sstr << (MyPassivePort >> 8) % 256;
sstr << ",";
sstr << MyPassivePort % 256;
sstr << ").\n";
Result = sstr.str();
break;
}
case 229: {
std::stringstream sstr;
sstr << "229 Entering extended passive mode (|||";
sstr << MyPassivePort;
sstr << "|).\n";
Result = sstr.str();
break;
}
case 230: {
Result = "230 User logged in, proceed.\n";
break;
}
case 250: {
Result = "250 Requested file action okay, completed.\n";
break;
}
case 2570: {//PWD
Result = "257 \"" + MyDir.PWD( ) + "\" selected as PWD\n";
break;
}
case 2571: {//MKD
Result = "257 \"" + MyDir.PWD( ) + "\" created\n";
break;
}
case 331: {
Result = "331 User name okay, need password.\n";
break;
}
case 350: {
Result = "350 Requested file action pending further information\n";
break;
}
case 501: {
Result = "501 Syntax error in parameters or arguments.\n";
break;
}
case 502: {
Result = "502 Command not implemented.\n";
break;
}
case 503: {
Result = "503 Bad sequence of commands.\n";
break;
}
case 504: {
Result = "504 Command not implemented for that parameter.\n";
break;
}
case 530: {
Result = "530 Not logged in.\n";
break;
}
case 550: {
Result = "550 Requested action not taken.\n";
break;
}
default: {
Result = "Error msg not implemented?\n";
break;
}
}
return Result;
}