mistserver/lib/ftp.cpp

567 lines
14 KiB
C++

#include "ftp.h"
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials){
Conn = NewConnection;
MyPassivePort = 0;
USER = "";
PASS = "";
MODE = MODE_STREAM;
STRU = STRU_FILE;
TYPE = TYPE_ASCII_NONPRINT;
PORT = 20;
RNFR = "";
AllCredentials = Credentials;
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");
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);
}
}
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 = Command;
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 = Command;
if ( !LoggedIn()){
USER = "";
PASS = "";
return 530; //Not logged in.
}
return 230;
break;
}
case CMD_LIST: {
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
}else{
Conn.Send("150 File status okay; about to open data connection.\n");
}
while ( !Connected.connected()){
Connected = Passive.accept();
}
std::string tmpstr = MyDir.LIST(ActiveStreams);
Connected.Send(tmpstr);
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);
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;
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.
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
}else{
Conn.Send("150 File status okay; about to open data connection.\n");
}
while ( !Connected.connected()){
Connected = Passive.accept();
}
std::string tmpstr = MyDir.RETR(Command);
Connected.Send(tmpstr);
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.
Socket::Connection Connected = Passive.accept();
if (Connected.connected()){
Conn.Send("125 Data connection already open; transfer starting.\n");
}else{
Conn.Send("150 File status okay; about to open data connection.\n");
}
while ( !Connected.connected()){
Connected = Passive.accept();
}
std::string Buffer;
while (Connected.spool()){
}
/// \todo Comment me back in. ^_^
//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;
}
if ( !AllCredentials.size()){
return true;
}
if ((AllCredentials.find(USER) != AllCredentials.end()) && AllCredentials[USER] == PASS){
return true;
}
return false;
}
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;
}