2011-01-20 15:56:30 +00:00
/* FEATHERY FTP-Server
* Copyright ( C ) 2005 - 2010 Andreas Martin ( andreas . martin @ linuxmail . org )
* < https : //sourceforge.net/projects/feathery>
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
DECLARATIVE SPECIFICATIONS
5.1 . MINIMUM IMPLEMENTATION
In order to make FTP workable without needless error messages , the
following minimum implementation is required for all servers :
TYPE - ASCII Non - print
MODE - Stream
STRUCTURE - File , Record
COMMANDS - USER , QUIT , PORT ,
TYPE , MODE , STRU ,
for the default values
RETR , STOR ,
NOOP .
The default values for transfer parameters are :
TYPE - ASCII Non - print
MODE - Stream
STRU - File
All hosts must accept the above as the standard defaults .
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include "ftpTypes.h"
# include "ftpConfig.h"
# include "ftp.h"
# include "ftpIfc.h"
2010-12-31 08:21:26 +00:00
# include "ftpMessages.h"
2011-01-20 15:56:30 +00:00
LOCAL uint8_t scratchBuf [ LEN_SCRATCHBUF ] ;
int ftpSendMsg ( msgmode_E mode , int sessionId , int ret , const char * msg )
{
int sentlen = 0 ;
2013-12-22 23:58:12 -08:00
int len = ( int ) strlen ( msg ) ;
2011-01-20 15:56:30 +00:00
char buf [ 6 ] ;
if ( mode = = MSG_QUOTE )
{
2012-10-19 01:31:20 +00:00
snprintf ( ( char * ) buf , 6 , " %03d \" " , ret ) ;
2011-01-20 15:56:30 +00:00
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , buf , 5 ) ;
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , msg , len ) ;
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , " \" \r \n " , 3 ) ;
}
else
{
2012-10-19 01:31:20 +00:00
snprintf ( ( char * ) buf , 6 , " %03d " , ret ) ;
2011-01-20 15:56:30 +00:00
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , buf , 4 ) ;
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , msg , len ) ;
sentlen + = ftpSend ( ftpGetSession ( sessionId ) - > ctrlSocket , " \r \n " , 2 ) ;
}
if ( VERBOSE_MODE_ENABLED ) printf ( " %02d <-- %s%s \n " , sessionId , buf , msg ) ;
return sentlen ;
}
int ftpExecTransmission ( int sessionId )
{
int finished = FALSE ;
2013-12-22 23:58:12 -08:00
size_t len ;
2011-01-20 15:56:30 +00:00
ftpSession_S * pSession = ftpGetSession ( sessionId ) ;
transmission_S * pTrans = & pSession - > activeTrans ;
int rxLen ;
pSession - > timeLastCmd = ftpGetUnixTime ( ) ;
switch ( pTrans - > op )
{
case OP_RETR :
len = ftpReadFile ( scratchBuf , 1 , LEN_SCRATCHBUF , pTrans - > fsHandle ) ;
if ( len > 0 )
{
2013-12-22 23:58:12 -08:00
pTrans - > fileSize - = ( uint32_t ) len ;
if ( ftpSend ( pTrans - > dataSocket , scratchBuf , ( int ) len ) )
2011-01-20 15:56:30 +00:00
{
ftpSendMsg ( MSG_NORMAL , sessionId , 426 , ftpMsg000 ) ;
finished = TRUE ;
}
}
else
{
2013-12-23 00:05:07 -08:00
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR in ftpExecTransmission ftpReadFile returned = %d for sessionId = %d \n " , ( int ) len , sessionId ) ;
2011-01-20 15:56:30 +00:00
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg001 ) ;
finished = TRUE ;
}
if ( pTrans - > fileSize = = 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 226 , ftpMsg002 ) ;
finished = TRUE ;
}
break ;
case OP_STOR :
rxLen = 0 ;
do
{
len = ftpReceive ( pTrans - > dataSocket , & scratchBuf [ rxLen ] , LEN_SCRATCHBUF - rxLen ) ;
2013-12-24 22:27:44 -08:00
if ( len < 1 ) {
2011-01-20 15:56:30 +00:00
int errorNumber = getLastSocketError ( ) ;
const char * errText = getLastSocketErrorText ( & errorNumber ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " ftpExecTransmission ERROR ON RECEIVE for socket = %d, data len = %d, error = %d [%s] \n " , pTrans - > dataSocket , ( LEN_SCRATCHBUF - rxLen ) , errorNumber , errText ) ;
break ;
}
2013-12-22 23:58:12 -08:00
rxLen + = ( int ) len ;
2011-01-20 15:56:30 +00:00
} while ( rxLen < LEN_SCRATCHBUF ) ;
if ( rxLen > 0 )
{
2013-12-22 23:58:12 -08:00
size_t res = ftpWriteFile ( scratchBuf , 1 , rxLen , pTrans - > fsHandle ) ;
2013-12-23 00:05:07 -08:00
if ( res ! = ( size_t ) rxLen )
2011-01-20 15:56:30 +00:00
{
2013-12-23 00:05:07 -08:00
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR in ftpExecTransmission ftpWriteFile returned = %d for sessionId = %d \n " , ( int ) res , sessionId ) ;
2011-01-20 15:56:30 +00:00
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg001 ) ;
finished = TRUE ;
}
}
2013-12-24 22:27:44 -08:00
if ( len < 1 )
2011-01-20 15:56:30 +00:00
{
ftpSendMsg ( MSG_NORMAL , sessionId , 226 , ftpMsg003 ) ;
finished = TRUE ;
}
break ;
case OP_LIST :
break ;
default :
return - 1 ;
}
if ( finished )
{
ftpCloseTransmission ( sessionId ) ;
return 1 ;
2011-01-06 00:52:00 +00:00
}
2011-01-20 15:56:30 +00:00
else
{
return 0 ;
}
}
LOCAL int ftpCmdUser ( int sessionId , const char * args , int len )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 331 , ftpMsg004 ) ;
ftpGetSession ( sessionId ) - > userId = ftpFindAccount ( args ) ;
return 0 ;
}
LOCAL int ftpCmdPass ( int sessionId , const char * args , int len )
{
if ( ! ftpCheckPassword ( ftpGetSession ( sessionId ) - > userId , args ) )
{
ftpAuthSession ( sessionId ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 230 , ftpMsg005 ) ;
}
else
{
ftpGetSession ( sessionId ) - > userId = 0 ;
ftpSendMsg ( MSG_NORMAL , sessionId , 530 , ftpMsg006 ) ;
}
return 0 ;
}
LOCAL int ftpCmdSyst ( int sessionId , const char * args , int len )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 215 , " UNIX Type: L8 " ) ;
return 0 ;
}
LOCAL int ftpCmdPort ( int sessionId , const char * args , int len )
{
2013-11-19 06:14:06 +00:00
//char clientIp[16]="";
2013-02-04 08:30:43 +00:00
uint16_t clientPort = 0 ;
2011-01-20 15:56:30 +00:00
int commaCnt = 0 ;
int n ;
char * p ;
for ( n = 0 ; args [ n ] ! = ' \0 ' ; n + + )
{
if ( commaCnt < = 3 ) // Ip-Adresse
{
if ( args [ n ] = = ' , ' )
{
commaCnt + + ;
2013-11-19 06:14:06 +00:00
// if(commaCnt < 4)
// clientIp[n] = '.';
// else
// clientIp[n] = '\0';
2011-01-20 15:56:30 +00:00
}
2013-11-19 06:14:06 +00:00
// else
// clientIp[n] = args[n];
2011-01-20 15:56:30 +00:00
}
else // Port-Nummer
{
p = ( char * ) & args [ n ] ;
clientPort = ( uint16_t ) ( strtoul ( p , & p , 0 ) < < 8 ) ;
p + + ;
clientPort | = strtoul ( p , & p , 0 ) ;
break ;
}
}
if ( ftpGetSession ( sessionId ) - > passiveDataSocket > = 0 )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdPort about to Close socket = %d for sessionId = %d \n " , ftpGetSession ( sessionId ) - > passiveDataSocket , sessionId ) ;
ftpUntrackSocket ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
ftpCloseSocket ( & ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
ftpGetSession ( sessionId ) - > passiveDataSocket = - 1 ;
}
//ftpGetSession(sessionId)->passiveDataSocket = -1;
ftpGetSession ( sessionId ) - > remoteDataPort = clientPort ;
ftpGetSession ( sessionId ) - > passive = FALSE ;
ftpSendMsg ( MSG_NORMAL , sessionId , 200 , ftpMsg007 ) ;
return 0 ;
}
LOCAL int ftpCmdNoop ( int sessionId , const char * args , int len )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 200 , ftpMsg008 ) ;
return 0 ;
}
LOCAL int ftpCmdQuit ( int sessionId , const char * args , int len )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 221 , ftpMsg009 ) ;
return - 1 ;
}
LOCAL int ftpCmdAbor ( int sessionId , const char * args , int len )
{
ftpCloseTransmission ( sessionId ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 226 , ftpMsg040 ) ;
return 0 ;
}
# define ALL 0x80
# define LIST 1
# define NLST 2
# define MLST 4
# define MLSD 8
LOCAL int sendListing ( socket_t dataSocket , int sessionId , const char * path , int format )
{
void * dir ;
const char monName [ 12 ] [ 4 ] = {
" Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec "
} ;
dir = ftpOpenDir ( path ) ;
if ( dir )
{
2011-12-02 16:07:59 +00:00
const char * dirEntry = NULL ;
int len = 0 ;
2011-01-20 15:56:30 +00:00
int err = 0 ;
ftpTime_S currTime = { 0 } ;
ftpPathInfo_S fileInfo ;
2011-12-02 16:07:59 +00:00
int haveAnySuccessfulFiles = 0 ;
2011-01-20 15:56:30 +00:00
ftpGetLocalTime ( & currTime ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 150 , ftpMsg010 ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In sendListing about to read dir contents [%s] for sessionId = %d, dataSocket = %d \n " , path , sessionId , dataSocket ) ;
2010-12-29 01:10:53 +00:00
2010-12-29 16:28:46 +00:00
haveAnySuccessfulFiles = 0 ;
2011-01-20 15:56:30 +00:00
while ( ( dirEntry = ftpReadDir ( dir ) ) ! = NULL )
2010-12-29 01:10:53 +00:00
{
2010-12-29 16:28:46 +00:00
const char * realPath = ftpGetRealPath ( sessionId , dirEntry , FALSE ) ;
2010-12-29 01:10:53 +00:00
int statResult = ftpStat ( realPath , & fileInfo ) ;
2010-12-31 08:21:26 +00:00
2011-01-20 15:56:30 +00:00
if ( VERBOSE_MODE_ENABLED ) printf ( " ftpGetRealPath() returned [%s] stat() = %d \n " , realPath , statResult ) ;
if ( statResult = = 0 )
{
if ( ( format & ALL ) = = 0 )
{
if ( dirEntry [ 0 ] = = ' . ' )
continue ;
}
if ( format & LIST )
{
switch ( fileInfo . type )
{
default :
case TYPE_FILE :
scratchBuf [ 0 ] = ' - ' ;
break ;
case TYPE_DIR :
scratchBuf [ 0 ] = ' d ' ;
break ;
case TYPE_LINK :
scratchBuf [ 0 ] = ' l ' ;
break ;
}
if ( currTime . year = = fileInfo . mTime . year )
{
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) & scratchBuf [ 1 ] , LEN_SCRATCHBUF - 1 , " rwxrwxrwx %4u %-8s %-8s %8u %s %02d %02d:%02d %s \r \n " ,
2011-01-20 15:56:30 +00:00
fileInfo . links ,
fileInfo . user ,
fileInfo . group ,
fileInfo . size ,
monName [ fileInfo . mTime . month - 1 ] ,
fileInfo . mTime . day ,
fileInfo . mTime . hour ,
fileInfo . mTime . minute ,
dirEntry ) ;
}
else
{
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) & scratchBuf [ 1 ] , LEN_SCRATCHBUF - 1 , " rwxrwxrwx %4u %-8s %-8s %8u %s %02d %5d %s \r \n " ,
2011-01-20 15:56:30 +00:00
fileInfo . links ,
fileInfo . user ,
fileInfo . group ,
fileInfo . size ,
monName [ fileInfo . mTime . month - 1 ] ,
fileInfo . mTime . day ,
fileInfo . mTime . year ,
dirEntry ) ;
}
2010-12-29 01:10:53 +00:00
ftpSend ( dataSocket , scratchBuf , len + 1 ) ;
2011-01-20 15:56:30 +00:00
haveAnySuccessfulFiles = 1 ;
}
else if ( format & NLST )
{
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " %s \r \n " , dirEntry ) ;
2010-12-29 01:10:53 +00:00
ftpSend ( dataSocket , scratchBuf , len ) ;
2011-01-20 15:56:30 +00:00
haveAnySuccessfulFiles = 1 ;
}
else if ( format & MLSD )
{
if ( ! strcmp ( " .. " , dirEntry ) )
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " Type=pdir " ) ;
2011-01-20 15:56:30 +00:00
else
{
switch ( fileInfo . type )
{
default :
case TYPE_FILE :
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " Type=file " ) ;
2011-01-20 15:56:30 +00:00
break ;
case TYPE_DIR :
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " Type=dir " ) ;
2011-01-20 15:56:30 +00:00
break ;
case TYPE_LINK :
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " Type=OS.unix=slink " ) ;
2011-01-20 15:56:30 +00:00
break ;
}
}
2010-12-29 01:10:53 +00:00
ftpSend ( dataSocket , scratchBuf , len ) ;
2012-10-19 01:31:20 +00:00
len = snprintf ( ( char * ) scratchBuf , LEN_SCRATCHBUF , " ;Size=%u;Modify=%04d%02d%02d%02d%02d%02d;Perm=r; %s \r \n " ,
2011-01-20 15:56:30 +00:00
fileInfo . size ,
fileInfo . mTime . year ,
fileInfo . mTime . month ,
fileInfo . mTime . day ,
fileInfo . mTime . hour ,
fileInfo . mTime . minute ,
fileInfo . mTime . second ,
dirEntry ) ;
ftpSend ( dataSocket , scratchBuf , len ) ;
haveAnySuccessfulFiles = 1 ;
}
}
else
{
err = 1 ;
//break;
}
}
ftpCloseDir ( dir ) ;
if ( err & & haveAnySuccessfulFiles = = 0 )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR in sendListing err = %d, path = [%s] for sessionId = %d, dataSocket = %d \n " , err , path , sessionId , dataSocket ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg039 ) ;
}
else
{
ftpSendMsg ( MSG_NORMAL , sessionId , 226 , ftpMsg013 ) ;
}
}
else
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR opendir [%s] returned errno: %#x for sessionId = %d, dataSocket = %d \n " , path , errno , sessionId , dataSocket ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg038 ) ;
}
return 0 ;
}
LOCAL int ftpCmdList ( int sessionId , const char * args , int len )
{
const char * realPath ;
socket_t s ;
//#### Funktioniert nicht wenn Pfad übergeben wird
/* if(args[0] != '\0')
{
if ( args [ 0 ] ! = ' - ' )
realPath = ftpGetRealPath ( sessionId , args ) ;
}
else */
realPath = ftpGetRealPath ( sessionId , ftpGetSession ( sessionId ) - > workingDir , TRUE ) ;
if ( ftpGetSession ( sessionId ) - > passive = = FALSE )
{
s = ftpEstablishDataConnection ( FALSE , & ftpGetSession ( sessionId ) - > remoteIp , & ftpGetSession ( sessionId ) - > remoteDataPort , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg011 ) ;
return 1 ;
}
}
else
{
s = ftpAcceptDataConnection ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
}
sendListing ( s , sessionId , realPath , LIST ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdList about to Close socket = %d for sessionId = %d \n " , s , sessionId ) ;
ftpUntrackSocket ( s ) ;
ftpCloseSocket ( & s ) ;
return 0 ;
}
LOCAL int ftpCmdNlst ( int sessionId , const char * args , int len )
{
//#### -List kann auch Argumente haben
const char * realPath ;
socket_t s ;
/* if(pfad übergeben)
realPath = ftpGetRealPath ( sessionId , args ) ;
else */
realPath = ftpGetRealPath ( sessionId , ftpGetSession ( sessionId ) - > workingDir , TRUE ) ;
if ( ftpGetSession ( sessionId ) - > passive = = FALSE )
{
s = ftpEstablishDataConnection ( FALSE , & ftpGetSession ( sessionId ) - > remoteIp , & ftpGetSession ( sessionId ) - > remoteDataPort , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg011 ) ;
return 1 ;
}
}
else
{
s = ftpAcceptDataConnection ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
}
sendListing ( s , sessionId , realPath , NLST ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdNlst about to Close socket = %d for sessionId = %d \n " , s , sessionId ) ;
ftpUntrackSocket ( s ) ;
ftpCloseSocket ( & s ) ;
return 0 ;
}
LOCAL int ftpCmdRetr ( int sessionId , const char * args , int len )
{
ftpPathInfo_S fileInfo ;
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
socket_t s ;
void * fp ;
int statResult = 0 ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdRetr args [%s] realPath [%s] \n " , args , realPath ) ;
2010-12-29 07:35:31 +00:00
2010-12-29 16:28:46 +00:00
statResult = ftpStat ( realPath , & fileInfo ) ;
2011-01-20 15:56:30 +00:00
if ( VERBOSE_MODE_ENABLED ) printf ( " stat() = %d fileInfo.type = %d \n " , statResult , fileInfo . type ) ;
if ( statResult | | ( fileInfo . type ! = TYPE_FILE ) ) // file accessible?
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR In ftpCmdRetr [file not available] args [%s] realPath [%s] \n " , args , realPath ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg032 ) ;
return 2 ;
}
2011-11-29 05:07:18 +00:00
if ( ftpIsClientAllowedToGetFile ! = NULL ) {
if ( ftpIsClientAllowedToGetFile ( ftpGetSession ( sessionId ) - > remoteIp , ftpFindAccountById ( ftpGetSession ( sessionId ) - > userId ) , realPath ) ! = 1 ) {
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR In ftpCmdRetr FILE DISALLOWED By MGserver [file not available] args [%s] realPath [%s] \n " , args , realPath ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg032 ) ;
return 2 ;
}
}
2011-01-20 15:56:30 +00:00
if ( ftpGetSession ( sessionId ) - > passive = = FALSE )
{
s = ftpEstablishDataConnection ( FALSE , & ftpGetSession ( sessionId ) - > remoteIp , & ftpGetSession ( sessionId ) - > remoteDataPort , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg011 ) ;
return 1 ;
}
}
else
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdRetr about accept passive data connection, args [%s] realPath [%s] \n " , args , realPath ) ;
s = ftpAcceptDataConnection ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( s < 0 )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR In ftpCmdRetr failed to accept data connection, args [%s] realPath [%s] \n " , args , realPath ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
}
ftpSendMsg ( MSG_NORMAL , sessionId , 150 , ftpMsg014 ) ;
fp = ftpOpenFile ( realPath , " rb " ) ;
if ( fp )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdRetr opened realPath [%s] [%p] for sessionId = %d for socket = %d \n " , realPath , fp , sessionId , s ) ;
ftpOpenTransmission ( sessionId , OP_RETR , fp , s , fileInfo . size ) ;
ftpExecTransmission ( sessionId ) ;
}
else
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR in ftpCmdRetr could not open realPath [%s] for sessionId = %d for socket = %d \n " , realPath , sessionId , s ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg015 ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdRetr about to Close socket = %d for sessionId = %d \n " , s , sessionId ) ;
ftpUntrackSocket ( s ) ;
ftpCloseSocket ( & s ) ;
}
return 0 ;
}
LOCAL int ftpCmdStor ( int sessionId , const char * args , int len )
{
socket_t s ;
void * fp ;
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
if ( ftpGetSession ( sessionId ) - > passive = = FALSE )
{
s = ftpEstablishDataConnection ( FALSE , & ftpGetSession ( sessionId ) - > remoteIp , & ftpGetSession ( sessionId ) - > remoteDataPort , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg011 ) ;
return 1 ;
}
}
else
{
s = ftpAcceptDataConnection ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
}
ftpSendMsg ( MSG_NORMAL , sessionId , 150 , ftpMsg016 ) ;
fp = ftpOpenFile ( realPath , " wb " ) ;
if ( fp )
{
ftpOpenTransmission ( sessionId , OP_STOR , fp , s , 0 ) ;
ftpExecTransmission ( sessionId ) ;
}
else
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR in ftpCmdStor could not open realPath [%s] \n " , realPath ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 451 , ftpMsg015 ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdStor about to Close socket = %d for sessionId = %d \n " , s , sessionId ) ;
ftpUntrackSocket ( s ) ;
ftpCloseSocket ( & s ) ;
}
return 0 ;
}
LOCAL int ftpCmdDele ( int sessionId , const char * args , int len )
{
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
if ( ftpRemoveFile ( realPath ) )
ftpSendMsg ( MSG_NORMAL , sessionId , 450 , ftpMsg018 ) ;
else
ftpSendMsg ( MSG_NORMAL , sessionId , 250 , ftpMsg019 ) ;
return 0 ;
}
LOCAL int ftpCmdMkd ( int sessionId , const char * args , int len )
{
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
if ( ftpMakeDir ( realPath ) )
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg020 ) ;
else
ftpSendMsg ( MSG_NORMAL , sessionId , 250 , ftpMsg021 ) ;
return 0 ;
}
LOCAL int ftpCmdRmd ( int sessionId , const char * args , int len )
{
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
if ( ftpRemoveDir ( realPath ) )
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg022 ) ;
else
ftpSendMsg ( MSG_NORMAL , sessionId , 250 , ftpMsg023 ) ;
return 0 ;
}
LOCAL int ftpCmdPwd ( int sessionId , const char * args , int len )
{
if ( ftpGetSession ( sessionId ) - > workingDir [ 0 ] )
ftpSendMsg ( MSG_QUOTE , sessionId , 257 , ftpGetSession ( sessionId ) - > workingDir ) ;
else
ftpSendMsg ( MSG_QUOTE , sessionId , 257 , " / " ) ;
return 0 ;
}
LOCAL int ftpCmdCwd ( int sessionId , const char * args , int len )
{
if ( ftpChangeDir ( sessionId , args ) = = 0 )
ftpSendMsg ( MSG_NORMAL , sessionId , 250 , ftpMsg024 ) ;
else
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg025 ) ;
return 0 ;
}
LOCAL int ftpCmdType ( int sessionId , const char * args , int len )
{
switch ( args [ 0 ] )
{
case ' I ' :
case ' i ' :
ftpSendMsg ( MSG_NORMAL , sessionId , 200 , ftpMsg026 ) ;
ftpGetSession ( sessionId ) - > binary = TRUE ;
break ;
case ' A ' :
case ' a ' :
ftpSendMsg ( MSG_NORMAL , sessionId , 200 , ftpMsg027 ) ;
ftpGetSession ( sessionId ) - > binary = FALSE ;
break ;
default :
ftpSendMsg ( MSG_NORMAL , sessionId , 504 , ftpMsg028 ) ;
2012-09-22 20:13:57 +00:00
break ;
2011-01-20 15:56:30 +00:00
}
return 0 ;
}
LOCAL int ftpCmdPasv ( int sessionId , const char * args , int len )
{
uint16_t port ;
uint32_t ip ;
char str [ 50 ] ;
socket_t s ;
uint32_t remoteFTPServerIp ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdPasv sessionId = %d, ftpGetSession(sessionId)->passiveDataSocket = %d \n " , sessionId , ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( ftpGetSession ( sessionId ) - > passiveDataSocket < = 0 )
{
//if(VERBOSE_MODE_ENABLED) printf("In ftpCmdPasv about to Close socket = %d for sessionId = %d\n",ftpGetSession(sessionId)->passiveDataSocket,sessionId);
//ftpUntrackSocket(ftpGetSession(sessionId)->passiveDataSocket);
//ftpCloseSocket(&ftpGetSession(sessionId)->passiveDataSocket);
2011-01-17 07:19:32 +00:00
//}
2011-01-20 15:56:30 +00:00
//ftpGetSession(sessionId)->passiveDataSocket = -1;
s = ftpEstablishDataConnection ( TRUE , & ip , & port , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
ftpGetSession ( sessionId ) - > passiveDataSocket = s ;
ftpGetSession ( sessionId ) - > passiveIp = ip ;
ftpGetSession ( sessionId ) - > passivePort = port ;
}
else
{
s = ftpGetSession ( sessionId ) - > passiveDataSocket ;
ip = ftpGetSession ( sessionId ) - > passiveIp ;
port = ftpGetSession ( sessionId ) - > passivePort ;
2011-01-17 07:19:32 +00:00
}
2010-12-30 15:56:02 +00:00
2011-01-17 07:19:32 +00:00
//if(VERBOSE_MODE_ENABLED) printf("In ftpCmdPasv sessionId = %d, client IP = %u, remote IP = %u, port = %d, ftpAddUPNPPortForward = %p, ftpRemoveUPNPPortForward = %p using listener socket = %d\n",
2011-01-20 15:56:30 +00:00
// sessionId, ftpGetSession(sessionId)->remoteIp, ftpFindExternalFTPServerIp(ftpGetSession(sessionId)->remoteIp), port,ftpAddUPNPPortForward,ftpRemoveUPNPPortForward,s);
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdPasv sessionId = %d, client IP = %u, remote IP = %u, port = %d, using listener socket = %d \n " ,
sessionId , ftpGetSession ( sessionId ) - > remoteIp , ftpFindExternalFTPServerIp ( ftpGetSession ( sessionId ) - > remoteIp ) , port , s ) ;
2010-12-30 18:51:25 +00:00
2011-01-02 09:33:37 +00:00
if ( ftpAddUPNPPortForward ! = NULL & & ftpFindExternalFTPServerIp ( ftpGetSession ( sessionId ) - > remoteIp ) ! = 0 )
2010-12-30 15:56:02 +00:00
{
ftpGetSession ( sessionId ) - > remoteFTPServerPassivePort = port ;
2011-01-02 09:33:37 +00:00
2011-01-20 15:56:30 +00:00
//if(VERBOSE_MODE_ENABLED) printf("In ftpCmdPasv sessionId = %d, adding UPNP port forward\n", sessionId);
2011-01-06 00:52:00 +00:00
//ftpAddUPNPPortForward(port, port);
2010-12-30 15:56:02 +00:00
2010-12-30 16:05:47 +00:00
remoteFTPServerIp = ftpFindExternalFTPServerIp ( ftpGetSession ( sessionId ) - > remoteIp ) ;
2010-12-30 15:56:02 +00:00
2012-10-19 01:31:20 +00:00
snprintf ( str , 50 , " %s (%d,%d,%d,%d,%d,%d) " ,
2011-01-20 15:56:30 +00:00
ftpMsg029 ,
( remoteFTPServerIp > > 24 ) & 0xFF ,
( remoteFTPServerIp > > 16 ) & 0xFF ,
( remoteFTPServerIp > > 8 ) & 0xFF ,
remoteFTPServerIp & 0xFF ,
( port > > 8 ) & 0xFF ,
2010-12-30 15:56:02 +00:00
port & 0xFF ) ;
2010-12-30 18:51:25 +00:00
2011-01-20 15:56:30 +00:00
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdPasv sessionId = %d, str [%s] \n " , sessionId , str ) ;
2010-12-30 18:51:25 +00:00
2010-12-30 15:56:02 +00:00
}
else
{
2012-10-19 01:31:20 +00:00
snprintf ( str , 50 , " %s (%d,%d,%d,%d,%d,%d) " ,
2011-01-20 15:56:30 +00:00
ftpMsg029 ,
( ip > > 24 ) & 0xFF ,
( ip > > 16 ) & 0xFF ,
( ip > > 8 ) & 0xFF ,
ip & 0xFF ,
( port > > 8 ) & 0xFF ,
2010-12-30 15:56:02 +00:00
port & 0xFF ) ;
}
2011-01-20 15:56:30 +00:00
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdPasv sessionId = %d, ftpGetSession(sessionId)->passiveDataSocket = %d SENDING 227 to client \n " , sessionId , ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 227 , str ) ;
ftpGetSession ( sessionId ) - > passive = TRUE ;
return 0 ;
}
LOCAL int ftpCmdCdup ( int sessionId , const char * args , int len )
{
return ftpCmdCwd ( sessionId , " .. " , 2 ) ;
}
LOCAL int ftpCmdStru ( int sessionId , const char * args , int len )
{
switch ( args [ 0 ] )
{
case ' F ' :
case ' f ' :
ftpSendMsg ( MSG_NORMAL , sessionId , 200 , ftpMsg030 ) ;
break ;
default :
ftpSendMsg ( MSG_NORMAL , sessionId , 504 , ftpMsg031 ) ;
2012-09-22 20:13:57 +00:00
break ;
2011-01-20 15:56:30 +00:00
}
return 0 ;
}
# if RFC3659
LOCAL int ftpCmdSize ( int sessionId , const char * args , int len )
{
int ret ;
char str [ 12 ] ;
ftpPathInfo_S fileInfo ;
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
ret = ftpStat ( realPath , & fileInfo ) ;
if ( ret )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg032 ) ;
return 2 ;
}
2012-10-19 01:31:20 +00:00
snprintf ( str , 12 , " %d " , fileInfo . size ) ;
2011-01-20 15:56:30 +00:00
ftpSendMsg ( MSG_NORMAL , sessionId , 213 , str ) ;
return 0 ;
}
LOCAL int ftpCmdMdtm ( int sessionId , const char * args , int len )
{
int ret ;
char str [ 15 ] ;
ftpPathInfo_S fileInfo ;
const char * realPath = ftpGetRealPath ( sessionId , args , TRUE ) ;
ret = ftpStat ( realPath , & fileInfo ) ;
if ( ret )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg032 ) ;
return 2 ;
}
2012-10-19 01:31:20 +00:00
snprintf ( str , 15 , " %04d%02d%02d%02d%02d%02d " , fileInfo . mTime . year ,
2011-01-20 15:56:30 +00:00
fileInfo . mTime . month ,
fileInfo . mTime . day ,
fileInfo . mTime . hour ,
fileInfo . mTime . minute ,
fileInfo . mTime . second ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 213 , str ) ;
return 0 ;
}
LOCAL int ftpCmdMlst ( int sessionId , const char * args , int len )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , " MLST command not implemented " ) ;
return 0 ;
}
/*LOCAL int ftpCmdMlsd(int sessionId, const char* args, int len)
{
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , " MLSD command not implemented " ) ;
return 0 ;
} */
LOCAL int ftpCmdMlsd ( int sessionId , const char * args , int len )
{
const char * realPath ;
socket_t s ;
//#### Funktioniert nicht wenn Pfad übergeben wird
/* if(args[0] != '\0')
{
if ( args [ 0 ] ! = ' - ' )
realPath = ftpGetRealPath ( sessionId , args ) ;
}
else */
realPath = ftpGetRealPath ( sessionId , ftpGetSession ( sessionId ) - > workingDir , TRUE ) ;
if ( ftpGetSession ( sessionId ) - > passive = = FALSE )
{
s = ftpEstablishDataConnection ( FALSE , & ftpGetSession ( sessionId ) - > remoteIp , & ftpGetSession ( sessionId ) - > remoteDataPort , sessionId ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg011 ) ;
return 1 ;
}
}
else
{
s = ftpAcceptDataConnection ( ftpGetSession ( sessionId ) - > passiveDataSocket ) ;
if ( s < 0 )
{
ftpSendMsg ( MSG_NORMAL , sessionId , 425 , ftpMsg012 ) ;
return 1 ;
}
}
sendListing ( s , sessionId , realPath , MLSD ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " In ftpCmdMlsd about to Close socket = %d for sessionId = %d \n " , s , sessionId ) ;
ftpUntrackSocket ( s ) ;
ftpCloseSocket ( & s ) ;
return 0 ;
}
# endif
typedef struct
{
char cmdToken [ 5 ] ; ///< command-string
int tokLen ; ///< len of cmdToken
int neededRights ; ///< required access rights for executing the command
int needLogin ; ///< if TRUE, command needs successful authentication via USER and PASS
int reportFeat ; ///< if TRUE, command is reported via FEAT
int duringTransfer ; ///< if TRUE, command can be executed during a file transfer
int ( * handler ) ( int , const char * , int ) ; ///< handler function
} ftpCommand_S ;
static const ftpCommand_S cmds [ ] = {
{ " USER " , 4 , 0 , FALSE , FALSE , FALSE , ftpCmdUser } ,
{ " PASS " , 4 , 0 , FALSE , FALSE , FALSE , ftpCmdPass } ,
{ " SYST " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdSyst } ,
{ " PORT " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdPort } ,
{ " NOOP " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdNoop } ,
{ " QUIT " , 4 , 0 , FALSE , FALSE , TRUE , ftpCmdQuit } ,
{ " ABOR " , 4 , 0 , FALSE , FALSE , TRUE , ftpCmdAbor } ,
{ " LIST " , 4 , FTP_ACC_LS , TRUE , FALSE , FALSE , ftpCmdList } ,
{ " NLST " , 4 , FTP_ACC_LS , TRUE , FALSE , FALSE , ftpCmdNlst } ,
{ " PWD " , 3 , FTP_ACC_RD , TRUE , FALSE , FALSE , ftpCmdPwd } ,
{ " XPWD " , 4 , FTP_ACC_DIR , TRUE , FALSE , FALSE , ftpCmdPwd } ,
{ " TYPE " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdType } ,
{ " PASV " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdPasv } ,
{ " CWD " , 3 , FTP_ACC_DIR , TRUE , FALSE , FALSE , ftpCmdCwd } ,
{ " CDUP " , 4 , FTP_ACC_DIR , TRUE , FALSE , FALSE , ftpCmdCdup } ,
{ " STRU " , 4 , 0 , TRUE , FALSE , FALSE , ftpCmdStru } ,
{ " RETR " , 4 , FTP_ACC_RD , TRUE , FALSE , FALSE , ftpCmdRetr } ,
{ " STOR " , 4 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdStor } ,
{ " DELE " , 4 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdDele } ,
{ " MKD " , 3 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdMkd } ,
{ " XMKD " , 4 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdMkd } ,
{ " RMD " , 3 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdRmd } ,
{ " XRMD " , 4 , FTP_ACC_WR , TRUE , FALSE , FALSE , ftpCmdRmd } ,
# if RFC3659
{ " SIZE " , 4 , FTP_ACC_RD , TRUE , TRUE , FALSE , ftpCmdSize } ,
{ " MDTM " , 4 , FTP_ACC_RD , TRUE , TRUE , FALSE , ftpCmdMdtm } ,
{ " MLST " , 4 , FTP_ACC_RD , TRUE , TRUE , FALSE , ftpCmdMlst } ,
{ " MLSD " , 4 , FTP_ACC_LS , TRUE , TRUE , FALSE , ftpCmdMlsd }
# endif
} ;
int execFtpCmd ( int sessionId , const char * cmd , int cmdlen )
{
int n ;
int ret = 0 ;
ftpSession_S * pSession = ftpGetSession ( sessionId ) ;
//if(VERBOSE_MODE_ENABLED) printf("In execFtpCmd ARRAY_SIZE(cmds) = %lu for sessionId = %d\n",ARRAY_SIZE(cmds),sessionId);
if ( VERBOSE_MODE_ENABLED ) printf ( " In execFtpCmd cmd [%s] for sessionId = %d \n " , cmd , sessionId ) ;
2013-11-19 06:14:06 +00:00
for ( n = 0 ; n < ( int ) ARRAY_SIZE ( cmds ) ; n + + )
2011-01-20 15:56:30 +00:00
{
if ( ! strncmp ( cmds [ n ] . cmdToken , cmd , cmds [ n ] . tokLen ) )
{
int i = cmds [ n ] . tokLen ;
if ( cmds [ n ] . needLogin )
{
if ( ( pSession - > userId = = 0 ) | | ( pSession - > authenticated = = FALSE ) )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In execFtpCmd User NOT loggedin for sessionId = %d \n " , sessionId ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 530 , ftpMsg033 ) ;
return 0 ;
}
if ( ftpCheckAccRights ( pSession - > userId , cmds [ n ] . neededRights ) )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In execFtpCmd User has no ACCESS for sessionId = %d \n " , sessionId ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 550 , ftpMsg034 ) ;
return 0 ;
}
}
if ( ( pSession - > activeTrans . op ! = OP_NOP ) ) // transfer in progress?
{
if ( cmds [ n ] . duringTransfer = = FALSE ) // command during transfer allowed?
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In execFtpCmd got command during transfer, discarding for sessionId = %d \n " , sessionId ) ;
return 0 ; // no => silently discard command
}
}
while ( cmd [ i ] ! = ' \0 ' )
{
if ( ( cmd [ i ] ! = ' ' ) & & ( cmd [ i ] ! = ' \t ' ) )
break ;
i + + ;
}
if ( VERBOSE_MODE_ENABLED ) printf ( " About to execute cmds[n].cmdToken [%s] command [%s] for sessionId = %d \n " , cmds [ n ] . cmdToken , & cmd [ i ] , sessionId ) ;
2013-12-22 23:58:12 -08:00
ret = cmds [ n ] . handler ( sessionId , & cmd [ i ] , ( int ) strlen ( & cmd [ i ] ) ) ; // execute command
2011-01-20 15:56:30 +00:00
if ( VERBOSE_MODE_ENABLED ) printf ( " Executed cmds[n].cmdToken [%s] command [%s] ret = %d for sessionId = %d \n " , cmds [ n ] . cmdToken , & cmd [ i ] , ret , sessionId ) ;
pSession - > timeLastCmd = ftpGetUnixTime ( ) ;
return ret ;
}
else
{
//if(VERBOSE_MODE_ENABLED) printf("In execFtpCmd SKIPPED COMMAND cmds[n].cmdToken = [%s] n = %d for sessionId = %d\n",cmds[n].cmdToken,n,sessionId);
}
}
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR UNKNOWN COMMAND cmd [%s] for sessionId = %d \n " , cmd , sessionId ) ;
ftpSendMsg ( MSG_NORMAL , sessionId , 500 , cmd ) ; // reject unknown commands
pSession - > timeLastCmd = ftpGetUnixTime ( ) ;
return ret ;
}
void ftpParseCmd ( int sessionId )
{
ftpSession_S * pSession ;
int len ;
socket_t ctrlSocket ;
pSession = ftpGetSession ( sessionId ) ;
len = pSession - > rxBufWriteIdx ;
ctrlSocket = pSession - > ctrlSocket ;
if ( ( pSession - > rxBuf [ len - 1 ] = = ' \n ' ) & &
( pSession - > rxBuf [ len - 2 ] = = ' \r ' ) ) // command correctly terminated?
{
2011-12-02 16:07:59 +00:00
int c = 0 ;
2011-01-20 15:56:30 +00:00
pSession - > rxBuf [ len - 2 ] = ' \0 ' ;
pSession - > rxBufWriteIdx = 0 ;
for ( c = 0 ; c < len ; c + + ) // convert command token to uppercase
{
if ( isspace ( pSession - > rxBuf [ c ] ) )
break ;
pSession - > rxBuf [ c ] = toupper ( pSession - > rxBuf [ c ] ) ;
}
if ( VERBOSE_MODE_ENABLED ) printf ( " %02d --> %s for socket: %d \n " , sessionId , pSession - > rxBuf , ctrlSocket ) ;
if ( execFtpCmd ( sessionId , pSession - > rxBuf , len - 2 ) = = - 1 )
{
if ( VERBOSE_MODE_ENABLED ) printf ( " In execFtpCmd command triggered close for socket: %d! \n " , ctrlSocket ) ;
ftpUntrackSocket ( ctrlSocket ) ;
ftpCloseSession ( sessionId ) ;
}
}
else
{
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR In execFtpCmd problem with parsing string [%s] for socket: %d! \n " , pSession - > rxBuf , ctrlSocket ) ;
}
if ( pSession - > rxBufWriteIdx > = LEN_RXBUF ) // overflow of receive buffer?
{
pSession - > rxBufWriteIdx = 0 ;
ftpSendMsg ( MSG_NORMAL , sessionId , 500 , ftpMsg035 ) ;
if ( VERBOSE_MODE_ENABLED ) printf ( " ERROR: Receive buffer overflow. Received data discarded. \n " ) ;
}
}