Compare commits

...

36 Commits

Author SHA1 Message Date
Ugo
646404da3a ops: deprecated old logs functions 2025-06-01 22:06:28 +01:00
Ugo
74d319f6bb feat: moved threadReuseFunctions 2025-06-01 16:02:12 +01:00
Ugo
e8894937a3 fix: thread_join always executed 2025-05-31 17:14:48 +01:00
Ugo
b8a37c88ec feat: Normalized logs 2025-05-31 14:48:13 +01:00
Ugo
e84a649ebd feat: improved client compatibility 226 response 2025-05-31 01:16:07 +01:00
Ugo
6159ba6268 fix: improved client compatibility for LIST/NLIST commands 2025-05-29 20:02:01 +01:00
Ugo
48b4430c17 fix: client compatibility, RETR, STOR, APPE ops 2025-05-27 17:33:12 +01:00
Ugo
de7ff6a710 default config 2025-05-27 14:05:25 +01:00
Ugo
a35737d02a fix: using my_printf instead of printf 2025-05-27 13:37:40 +01:00
Ugo
94f7b75d6a feat: reuse ssl sessions if available 2025-05-27 13:35:09 +01:00
Ugo
d3be2eafde refactoring: splitted functions in data channels and more 2025-05-27 12:09:25 +01:00
Ugo
bd17059c41 ops: Open SSL v3 changes 2025-05-26 21:07:47 +01:00
Ugo
2f62192b6c feat: some refactoring and adjustments 2025-05-26 20:54:08 +01:00
Ugo
cdc4e4adc9 fix: pasv port chosen after availability checks 2025-05-26 20:24:13 +01:00
Ugo
5b6919a7b1 fix: more robust passive connection handling 2025-05-26 19:14:54 +01:00
Ugo
b926a26b22 refactoring: split ftp functions per data channel 2025-05-26 14:04:47 +01:00
Ugo
358c409996 refactor: code refactoring and cleaning 2025-05-23 22:20:23 +01:00
Ugo
5d95b42456 refactor: changing code structure 2025-05-23 22:03:41 +01:00
Ugo
e4ea93a280 fix: thread cleanup always called 2025-05-20 21:48:23 +01:00
Ugo
7869d55f95 config: changed default parameters and refactoring 2025-01-31 23:46:35 +00:00
root
4565a14d2c CWD / command fix 2024-09-29 21:28:41 +02:00
root
6db29a0f33 Adding ip type in port command 2024-07-29 22:28:22 +02:00
root
a2de9b1a7c Removed debug define 2024-06-06 21:10:10 +02:00
root
90f44e3a98 Possible memory leak fix 2024-05-12 14:15:48 +02:00
root
ec5c155ccb Updated version 2024-05-06 21:50:20 +02:00
root
63251ca3e4 FEAT updated 2024-05-06 21:35:11 +02:00
root
509910642d Disable ipv6 with makefile ok 2024-05-06 20:28:39 +02:00
root
2f355d91d8 ipv6 ok 2024-05-06 19:09:23 +02:00
root
8302e82366 Testing EPRT 2024-05-06 18:47:19 +02:00
root
998b720fa5 working ipv6 2024-05-06 15:52:59 +02:00
root
89e64c2ddc Ipv6 seems okay 2024-05-06 15:44:31 +02:00
root
5778081be9 Check if ipv4 or ipv6 2024-05-06 15:37:19 +02:00
root
8f78c9e7f1 Working on ipv6 2024-05-06 14:53:02 +02:00
root
38887ed633 Working on ipv6 2024-05-06 14:49:02 +02:00
root
4c0b19e6d6 working on ipv6 preliminary implementation okay 2024-05-06 14:33:35 +02:00
root
d0191ca20d Working on ipv6 implementation 2024-05-06 12:48:44 +02:00
35 changed files with 2383 additions and 2071 deletions

View File

@ -8,6 +8,11 @@ CC=gcc
OUTPATH=./build/ OUTPATH=./build/
SOURCE_MODULES_PATH=./library/ SOURCE_MODULES_PATH=./library/
#uncommend next lines to enable printf
ENABLE_PRINTF=
#uncommend next lines to enable printf
#ENABLE_PRINTF=-D ENABLE_PRINTF -D ENABLE_PRINTF_ERROR
#FOR DEBUG PURPOSE #FOR DEBUG PURPOSE
#CFLAGSTEMP=-c -Wall -I. -g -O0 #CFLAGSTEMP=-c -Wall -I. -g -O0
@ -16,7 +21,7 @@ ENDFLAG=
#ENDFLAG=-static #ENDFLAG=-static
#FOR RELEASE #FOR RELEASE
CFLAGSTEMP=-c -Wall -I. CFLAGSTEMP=-c -Wall -Wno-unused-variable -Wno-unused-but-set-variable -I.
OPTIMIZATION=-O3 OPTIMIZATION=-O3
HEADERS=-I HEADERS=-I
@ -33,13 +38,17 @@ ENABLE_OPENSSL_SUPPORT=
#ENABLE_OPENSSL_SUPPORT=-D OPENSSL_ENABLED #ENABLE_OPENSSL_SUPPORT=-D OPENSSL_ENABLED
#LIBS=-lpthread -lssl -lcrypto #LIBS=-lpthread -lssl -lcrypto
ENABLE_IPV6_SUPPORT=
#TO ENABLE IPV6 support uncomment next line
ENABLE_IPV6_SUPPORT=-D IPV6_ENABLED
ENABLE_PAM_SUPPORT= ENABLE_PAM_SUPPORT=
PAM_AUTH_LIB= PAM_AUTH_LIB=
#TO ENABLE PAM AUTH UNCOMMENT NEXT TWO LINES #TO ENABLE PAM AUTH UNCOMMENT NEXT TWO LINES
#ENABLE_PAM_SUPPORT= -D PAM_SUPPORT_ENABLED #ENABLE_PAM_SUPPORT= -D PAM_SUPPORT_ENABLED
#PAM_AUTH_LIB= -lpam #PAM_AUTH_LIB= -lpam
CFLAGS=$(CFLAGSTEMP) $(ENABLE_LARGE_FILE_SUPPORT) $(ENABLE_OPENSSL_SUPPORT) $(ENABLE_PAM_SUPPORT) CFLAGS=$(CFLAGSTEMP) $(ENABLE_LARGE_FILE_SUPPORT) $(ENABLE_OPENSSL_SUPPORT) $(ENABLE_IPV6_SUPPORT) $(ENABLE_PAM_SUPPORT) $(ENABLE_PRINTF)
all: $(BUILDFILES) all: $(BUILDFILES)
@ -53,8 +62,15 @@ start:
end: end:
@echo Build process end @echo Build process end
uFTP: uFTP.c fileManagement.o configRead.o logFunctions.o ftpCommandElaborate.o ftpData.o ftpServer.o daemon.o signals.o connection.o openSsl.o dynamicMemory.o errorHandling.o auth.o log.o uFTP: uFTP.c fileManagement.o configRead.o ftpCommandElaborate.o \
@$(CC) $(ENABLE_LARGE_FILE_SUPPORT) $(ENABLE_OPENSSL_SUPPORT) uFTP.c $(LIBPATH)dynamicVectors.o $(LIBPATH)fileManagement.o $(LIBPATH)configRead.o $(LIBPATH)logFunctions.o $(LIBPATH)ftpCommandElaborate.o $(LIBPATH)ftpData.o $(LIBPATH)ftpServer.o $(LIBPATH)daemon.o $(LIBPATH)signals.o $(LIBPATH)connection.o $(LIBPATH)openSsl.o $(LIBPATH)dynamicMemory.o $(LIBPATH)errorHandling.o $(LIBPATH)auth.o $(LIBPATH)log.o -o $(OUTPATH)uFTP $(LIBS) $(PAM_AUTH_LIB) $(ENDFLAG) ftpData.o ftpServer.o daemon.o signals.o connection.o openSsl.o \
dynamicMemory.o errorHandling.o auth.o log.o controlChannel.o dataChannel.o serverHelpers.o
@$(CC) $(ENABLE_LARGE_FILE_SUPPORT) $(ENABLE_OPENSSL_SUPPORT) uFTP.c \
$(LIBPATH)dynamicVectors.o $(LIBPATH)fileManagement.o $(LIBPATH)configRead.o \
$(LIBPATH)ftpCommandElaborate.o $(LIBPATH)ftpData.o $(LIBPATH)ftpServer.o $(LIBPATH)daemon.o $(LIBPATH)signals.o \
$(LIBPATH)connection.o $(LIBPATH)openSsl.o $(LIBPATH)dynamicMemory.o $(LIBPATH)errorHandling.o $(LIBPATH)auth.o \
$(LIBPATH)log.o $(LIBPATH)controlChannel.o $(LIBPATH)dataChannel.o $(LIBPATH)serverHelpers.o \
-o $(OUTPATH)uFTP $(LIBS) $(PAM_AUTH_LIB) $(ENDFLAG)
daemon.o: daemon.o:
@$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)daemon.c -o $(LIBPATH)daemon.o @$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)daemon.c -o $(LIBPATH)daemon.o
@ -83,14 +99,14 @@ fileManagement.o:
signals.o: signals.o:
@$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)signals.c -o $(LIBPATH)signals.o @$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)signals.c -o $(LIBPATH)signals.o
connection.o: connection.o: log.o
@$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)connection.c -o $(LIBPATH)connection.o @$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)connection.c -o $(LIBPATH)connection.o
log.o: log.o:
@$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)log.c -o $(LIBPATH)log.o @$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)log.c -o $(LIBPATH)log.o
logFunctions.o: serverHelpers.o:
@$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)logFunctions.c -o $(LIBPATH)logFunctions.o @$(CC) $(CFLAGS) $(SOURCE_MODULES_PATH)serverHelpers.c -o $(LIBPATH)serverHelpers.o
ftpCommandElaborate.o: ftpCommandElaborate.o:
@$(CC) $(CFLAGS) ftpCommandElaborate.c -o $(LIBPATH)ftpCommandElaborate.o @$(CC) $(CFLAGS) ftpCommandElaborate.c -o $(LIBPATH)ftpCommandElaborate.o
@ -98,7 +114,13 @@ ftpCommandElaborate.o:
ftpData.o: ftpData.o:
@$(CC) $(CFLAGS) ftpData.c -o $(LIBPATH)ftpData.o @$(CC) $(CFLAGS) ftpData.c -o $(LIBPATH)ftpData.o
ftpServer.o: openSsl.o controlChannel.o:
@$(CC) $(CFLAGS) ./controlChannel/controlChannel.c -o $(LIBPATH)controlChannel.o
dataChannel.o:
@$(CC) $(CFLAGS) ./dataChannel/dataChannel.c -o $(LIBPATH)dataChannel.o
ftpServer.o: openSsl.o controlChannel.o dataChannel.o
@$(CC) $(CFLAGS) ftpServer.c -o $(LIBPATH)ftpServer.o @$(CC) $(CFLAGS) ftpServer.c -o $(LIBPATH)ftpServer.o
clean: clean:

View File

@ -1,128 +0,0 @@
#
# There exist several targets which are by default empty and which can be
# used for execution of your targets. These targets are usually executed
# before and after some main targets. They are:
#
# .build-pre: called before 'build' target
# .build-post: called after 'build' target
# .clean-pre: called before 'clean' target
# .clean-post: called after 'clean' target
# .clobber-pre: called before 'clobber' target
# .clobber-post: called after 'clobber' target
# .all-pre: called before 'all' target
# .all-post: called after 'all' target
# .help-pre: called before 'help' target
# .help-post: called after 'help' target
#
# Targets beginning with '.' are not intended to be called on their own.
#
# Main targets can be executed directly, and they are:
#
# build build a specific configuration
# clean remove built files from a configuration
# clobber remove all built files
# all build all configurations
# help print help mesage
#
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
# .help-impl are implemented in nbproject/makefile-impl.mk.
#
# Available make variables:
#
# CND_BASEDIR base directory for relative paths
# CND_DISTDIR default top distribution directory (build artifacts)
# CND_BUILDDIR default top build directory (object files, ...)
# CONF name of current configuration
# CND_PLATFORM_${CONF} platform name (current configuration)
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
#
# NOCDDL
# Environment
MKDIR=mkdir
CP=cp
CCADMIN=CCadmin
# build
build: .build-post
.build-pre:
# Add your pre 'build' code here...
.build-post: .build-impl
# Add your post 'build' code here...
# clean
clean: .clean-post
.clean-pre:
# Add your pre 'clean' code here...
.clean-post: .clean-impl
# Add your post 'clean' code here...
# clobber
clobber: .clobber-post
.clobber-pre:
# Add your pre 'clobber' code here...
.clobber-post: .clobber-impl
# Add your post 'clobber' code here...
# all
all: .all-post
.all-pre:
# Add your pre 'all' code here...
.all-post: .all-impl
# Add your post 'all' code here...
# build tests
build-tests: .build-tests-post
.build-tests-pre:
# Add your pre 'build-tests' code here...
.build-tests-post: .build-tests-impl
# Add your post 'build-tests' code here...
# run tests
test: .test-post
.test-pre: build-tests
# Add your pre 'test' code here...
.test-post: .test-impl
# Add your post 'test' code here...
# help
help: .help-post
.help-pre:
# Add your pre 'help' code here...
.help-post: .help-impl
# Add your post 'help' code here...
# include project implementation makefile
include nbproject/Makefile-impl.mk
# include project make variables
include nbproject/Makefile-variables.mk

View File

@ -1,6 +1,6 @@
cd .. cd ..
make clean make clean
make make -j 8
cd build cd build
sudo killall uFTP sudo killall uFTP
./uFTP ./uFTP

View File

@ -7,5 +7,5 @@ cp build/uFTP /var/www/html/uftpserver.com/downloads/binaries/latest/armhf/uFTP
make clean make clean
make CC=musl-gcc ENDFLAG=-static make CC=musl-gcc ENDFLAG=-static
cp build/uFTP /var/www/html/uftpserver.com/downloads/binaries/latest/x64/uFTP cp build/uFTP /var/www/html/uftpserver.com/downloads/binaries/latest/x64/uFTP
cp uftpd.cfg /var/www/html/uftpserver.com/downloads/configuration_sample/uftpd.cfg
cd build cd build

View File

@ -0,0 +1,325 @@
/*
* The MIT License
*
* Copyright 2018 Ugo Cirmignani.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <errno.h>
/* FTP LIBS */
#include "library/fileManagement.h"
#include "library/configRead.h"
#include "library/signals.h"
#include "library/openSsl.h"
#include "library/connection.h"
#include "library/dynamicMemory.h"
#include "library/errorHandling.h"
#include "library/daemon.h"
#include "library/log.h"
#include "ftpServer.h"
#include "ftpData.h"
#include "ftpCommandsElaborate.h"
#include "debugHelper.h"
#include "controlChannel.h"
/* Private function definition */
static int processCommand(int processingElement, ftpDataType *ftpData);
static void memoryDebug(ftpDataType *ftpData);
void evaluateControlChannel(ftpDataType *ftpData)
{
int returnCode = 0;
//Update watchdog timer
updateWatchDogTime((int)time(NULL));
//debug memory usage
memoryDebug(ftpData);
/* waits for socket activity, if no activity then checks for client socket timeouts */
if (selectWait(ftpData) == 0)
{
checkClientConnectionTimeout(ftpData);
flushLoginWrongTriesData(ftpData);
}
/*Main loop handle client commands */
for (int processingSock = 0; processingSock < ftpData->ftpParameters.maxClients; processingSock++)
{
/* close the connection if quit flag has been set */
if (ftpData->clients[processingSock].closeTheClient == 1)
{
closeClient(ftpData, processingSock);
continue;
}
/* Check if there are client pending connections, accept the connection if possible otherwise reject */
if ((returnCode = evaluateClientSocketConnection(ftpData)) == 1)
{
break;
}
/* no data to check client is not connected, continue to check other clients */
if (isClientConnected(ftpData, processingSock) == 0)
{
/* socket is not conneted */
continue;
}
if (FD_ISSET(ftpData->clients[processingSock].socketDescriptor, &ftpData->connectionData.rset) ||
FD_ISSET(ftpData->clients[processingSock].socketDescriptor, &ftpData->connectionData.eset))
{
#ifdef OPENSSL_ENABLED
if (ftpData->clients[processingSock].tlsIsNegotiating == 1)
{
returnCode = SSL_accept(ftpData->clients[processingSock].ssl);
if (returnCode <= 0)
{
//my_printf("\nSSL NOT YET ACCEPTED: %d", returnCode);
ftpData->clients[processingSock].tlsIsEnabled = 0;
ftpData->clients[processingSock].tlsIsNegotiating = 1;
if ( ((int)time(NULL) - ftpData->clients[processingSock].tlsNegotiatingTimeStart) > TLS_NEGOTIATING_TIMEOUT )
{
ftpData->clients[processingSock].closeTheClient = 1;
LOGF("%sTLS timeout closing the client time:%lld, start time: %lld..", LOG_DEBUG_PREFIX, (int)time(NULL), ftpData->clients[processingSock].tlsNegotiatingTimeStart);
//my_printf("\nTLS timeout closing the client time:%lld, start time: %lld..", (int)time(NULL), ftpData->clients[processingSock].tlsNegotiatingTimeStart);
}
}
else
{
//my_printf("\nSSL ACCEPTED");
ftpData->clients[processingSock].tlsIsEnabled = 1;
ftpData->clients[processingSock].tlsIsNegotiating = 0;
}
continue;
}
#endif
if (ftpData->clients[processingSock].tlsIsEnabled == 1)
{
#ifdef OPENSSL_ENABLED
ftpData->clients[processingSock].bufferIndex = SSL_read(ftpData->clients[processingSock].ssl, ftpData->clients[processingSock].buffer, CLIENT_BUFFER_STRING_SIZE);
#endif
}
else
{
ftpData->clients[processingSock].bufferIndex = read(ftpData->clients[processingSock].socketDescriptor, ftpData->clients[processingSock].buffer, CLIENT_BUFFER_STRING_SIZE);
}
//The client is not connected anymore
if ((ftpData->clients[processingSock].bufferIndex) == 0)
{
closeClient(ftpData, processingSock);
}
//Some commands has been received
if (ftpData->clients[processingSock].bufferIndex > 0)
{
int i = 0;
int commandProcessStatus = 0;
for (i = 0; i < ftpData->clients[processingSock].bufferIndex; i++)
{
if (ftpData->clients[processingSock].commandIndex < CLIENT_COMMAND_STRING_SIZE)
{
if (ftpData->clients[processingSock].buffer[i] != '\r' && ftpData->clients[processingSock].buffer[i] != '\n')
{
ftpData->clients[processingSock].theCommandReceived[ftpData->clients[processingSock].commandIndex++] = ftpData->clients[processingSock].buffer[i];
}
if (ftpData->clients[processingSock].buffer[i] == '\n')
{
ftpData->clients[processingSock].socketCommandReceived = 1;
//my_printf("\n Processing the command: %s", ftpData->clients[processingSock].theCommandReceived);
commandProcessStatus = processCommand(processingSock, ftpData);
//Echo unrecognized commands
if (commandProcessStatus == FTP_COMMAND_NOT_RECONIZED)
{
int returnCode = 0;
returnCode = socketPrintf(ftpData, processingSock, "s", "500 Unknown command\r\n");
if (returnCode < 0)
{
ftpData->clients[processingSock].closeTheClient = 1;
LOG_ERROR("socketPrintf");
}
my_printf("\n COMMAND NOT SUPPORTED ********* %s", ftpData->clients[processingSock].buffer);
LOGF("%sCommand not supported: %s", LOG_DEBUG_PREFIX, ftpData->clients[processingSock].buffer);
}
else if (commandProcessStatus == FTP_COMMAND_PROCESSED)
{
ftpData->clients[processingSock].lastActivityTimeStamp = (int)time(NULL);
}
else if (commandProcessStatus == FTP_COMMAND_PROCESSED_WRITE_ERROR)
{
ftpData->clients[processingSock].closeTheClient = 1;
LOG_ERROR("ftp command processed error");
my_printf("\n Write error WARNING!");
}
}
}
else
{
//Command overflow can't be processed
int returnCode;
ftpData->clients[processingSock].commandIndex = 0;
memset(ftpData->clients[processingSock].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1);
returnCode = socketPrintf(ftpData, processingSock, "s", "500 Unknown command\r\n");
if (returnCode <= 0)
{
ftpData->clients[processingSock].closeTheClient = 1;
LOG_ERROR("socketPrintf");
}
my_printf("\n Command too long closing the client.");
break;
}
}
memset(ftpData->clients[processingSock].buffer, 0, CLIENT_BUFFER_STRING_SIZE+1);
}
}
}
}
/* Private static functions */
static void memoryDebug(ftpDataType *ftpData)
{
my_printf("\nUsed memory : %lld", DYNMEM_GetTotalMemory());
for (int memCount = 0; memCount < ftpData->ftpParameters.maxClients; memCount++)
{
if (ftpData->clients[memCount].memoryTable != NULL)
{
my_printf("\nftpData->clients[%d].memoryTable = %s", memCount, ftpData->clients[memCount].memoryTable->theName);
}
if (ftpData->clients[memCount].workerData.memoryTable != NULL)
{
my_printf("\nftpData->clients[%d].workerData.memoryTable = %s", memCount, ftpData->clients[memCount].workerData.memoryTable->theName);
}
if (ftpData->clients[memCount].workerData.directoryInfo.memoryTable != NULL)
{
my_printf("\nftpData->clients[%d].workerData.directoryInfo.memoryTable = %s", memCount, ftpData->clients[memCount].workerData.directoryInfo.memoryTable->theName);
}
}
}
static int processCommand(int processingElement, ftpDataType *ftpData)
{
//command handler structure
static CommandMapEntry commandMap[] = {
{"USER", parseCommandUser},
{"PASS", parseCommandPass},
{"SITE", parseCommandSite},
{"AUTH TLS", parseCommandAuth},
{"PROT", parseCommandProt},
{"PBSZ", parseCommandPbsz},
{"CCC", parseCommandCcc},
{"PWD", parseCommandPwd},
{"XPWD", parseCommandPwd},
{"SYST", parseCommandSyst},
{"FEAT", parseCommandFeat},
{"TYPE I", parseCommandTypeI},
{"TYPE A", parseCommandTypeI},
{"STRU F", parseCommandStruF},
{"MODE S", parseCommandModeS},
{"EPSV", parseCommandEpsv},
{"PASV", parseCommandPasv},
{"PORT", parseCommandPort},
{"EPRT", parseCommandEprt},
{"LIST", parseCommandList},
{"STAT", parseCommandStat},
{"CDUP", parseCommandCdup},
{"XCUP", parseCommandCdup},
{"CWD ..", parseCommandCdup},
{"CWD", parseCommandCwd},
{"REST", parseCommandRest},
{"RETR", parseCommandRetr},
{"STOR", parseCommandStor},
{"MKD", parseCommandMkd},
{"XMKD", parseCommandMkd},
{"ABOR", parseCommandAbor},
{"DELE", parseCommandDele},
{"OPTS", parseCommandOpts},
{"MDTM", parseCommandMdtm},
{"NLST", parseCommandNlst},
{"QUIT", parseCommandQuit},
{"RMD", parseCommandRmd},
{"XRMD", parseCommandRmd},
{"RNFR", parseCommandRnfr},
{"RNTO", parseCommandRnto},
{"SIZE", parseCommandSize},
{"APPE", parseCommandAppe},
{"NOOP", parseCommandNoop},
{"ACCT", parseCommandAcct}
};
#define COMMAND_MAP_SIZE (sizeof(commandMap) / sizeof(CommandMapEntry))
int toReturn = 0;
//printTimeStamp();
my_printf("\nCommand received from (%d): %s", processingElement, ftpData->clients[processingElement].theCommandReceived);
cleanDynamicStringDataType(&ftpData->clients[processingElement].ftpCommand.commandArgs, 0, ftpData->clients[processingElement].memoryTable);
cleanDynamicStringDataType(&ftpData->clients[processingElement].ftpCommand.commandOps, 0, ftpData->clients[processingElement].memoryTable);
if (ftpData->clients[processingElement].login.userLoggedIn == 0 &&
(IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "USER") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "PASS") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "QUIT") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "PBSZ") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "PROT") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "CCC") &&
IS_NOT_CMD(ftpData->clients[processingElement].theCommandReceived, "AUTH TLS")))
{
toReturn = notLoggedInMessage(ftpData, processingElement);
ftpData->clients[processingElement].commandIndex = 0;
memset(ftpData->clients[processingElement].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1);
return 1;
}
for (int i = 0; i < COMMAND_MAP_SIZE; ++i)
{
if (IS_CMD(ftpData->clients[processingElement].theCommandReceived, commandMap[i].command))
{
my_printf("\n%s COMMAND RECEIVED", commandMap[i].command);
toReturn = commandMap[i].handler(ftpData, processingElement);
break;
}
}
ftpData->clients[processingElement].commandIndex = 0;
memset(ftpData->clients[processingElement].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1);
return toReturn;
}

View File

@ -0,0 +1,16 @@
#ifndef CTRL_CHANNEL_H
#define CTRL_CHANNEL_H
#include "ftpData.h"
typedef int (*CommandHandler)(struct FtpDataType*, int);
typedef struct {
const char* command;
CommandHandler handler;
} CommandMapEntry;
void evaluateControlChannel(ftpDataType *ftpData);
#endif /* DATA_CHANNEL_H */

523
dataChannel/dataChannel.c Normal file
View File

@ -0,0 +1,523 @@
/*
* The MIT License
*
* Copyright 2018 Ugo Cirmignani.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <errno.h>
/* FTP LIBS */
#include "library/fileManagement.h"
#include "library/configRead.h"
#include "library/signals.h"
#include "library/openSsl.h"
#include "library/connection.h"
#include "library/dynamicMemory.h"
#include "library/errorHandling.h"
#include "library/daemon.h"
#include "library/log.h"
#include "ftpServer.h"
#include "ftpData.h"
#include "ftpCommandsElaborate.h"
#include "debugHelper.h"
#include "dataChannel.h"
static int acceptConnection(cleanUpWorkerArgs *args);
static int processStorAppe(cleanUpWorkerArgs *args);
static int processListNlst(cleanUpWorkerArgs *args);
static int processRetr(cleanUpWorkerArgs *args);
void workerCleanup(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode = 0;
//my_printf("\nWorker %d cleanup", theSocketId);
#ifdef OPENSSL_ENABLED
int error;
error = fcntl(ftpData->clients[theSocketId].workerData.socketConnection, F_SETFL, O_NONBLOCK);
if (ftpData->clients[theSocketId].dataChannelIsTls == 1)
{
if(ftpData->clients[theSocketId].workerData.passiveModeOn == 1)
{
//my_printf("\nSSL worker Shutdown 1");
returnCode = SSL_shutdown(ftpData->clients[theSocketId].workerData.serverSsl);
//my_printf("\nnSSL worker Shutdown 1 return code : %d", returnCode);
if (!returnCode)
{
shutdown(ftpData->clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData->clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
//my_printf("\nSSL worker Shutdown 2");
returnCode = SSL_shutdown(ftpData->clients[theSocketId].workerData.serverSsl);
//my_printf("\nnSSL worker Shutdown 2 return code : %d", returnCode);
}
}
if(ftpData->clients[theSocketId].workerData.activeModeOn == 1)
{
returnCode = SSL_shutdown(ftpData->clients[theSocketId].workerData.clientSsl);
if (!returnCode)
{
shutdown(ftpData->clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData->clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
returnCode = SSL_shutdown(ftpData->clients[theSocketId].workerData.clientSsl);
}
}
}
#endif
shutdown(ftpData->clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData->clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
returnCode = close(ftpData->clients[theSocketId].workerData.socketConnection);
returnCode = close(ftpData->clients[theSocketId].workerData.passiveListeningSocket);
if (ftpData->clients[theSocketId].workerData.commandProcessed)
{
returnCode = socketPrintf(ftpData, theSocketId, "s", ftpData->clients[theSocketId].workerData.theCommandResponse);
if (returnCode <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("socketPrintf");
my_printf("\n Closing the client 10");
}
}
resetWorkerData(ftpData, theSocketId, 0);
DYNMEM_free(args, &ftpData->clients[theSocketId].workerData.memoryTable);
if (ftpData->clients[theSocketId].workerData.memoryTable != NULL)
DYNMEM_dump(ftpData->clients[theSocketId].workerData.memoryTable);//my_printf("\nMemory table element label: %s", ftpData->clients[theSocketId].workerData.memoryTable->theName);
}
static int processStorAppe(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode = 0;
if (compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "APPE", strlen("APPE")) == 1)
{
#ifdef LARGE_FILE_SUPPORT_ENABLED
//#warning LARGE FILE SUPPORT IS ENABLED!
ftpData->clients[theSocketId].workerData.theStorFile = fopen64(ftpData->clients[theSocketId].fileToStor.text, "ab");
#endif
#ifndef LARGE_FILE_SUPPORT_ENABLED
#warning LARGE FILE SUPPORT IS NOT ENABLED!
ftpData->clients[theSocketId].workerData.theStorFile = fopen(ftpData->clients[theSocketId].fileToStor.text, "ab");
#endif
}
else
{
#ifdef LARGE_FILE_SUPPORT_ENABLED
//#warning LARGE FILE SUPPORT IS ENABLED!
ftpData->clients[theSocketId].workerData.theStorFile = fopen64(ftpData->clients[theSocketId].fileToStor.text, "wb");
#endif
#ifndef LARGE_FILE_SUPPORT_ENABLED
#warning LARGE FILE SUPPORT IS NOT ENABLED!
ftpData->clients[theSocketId].workerData.theStorFile = fopen(ftpData->clients[theSocketId].fileToStor.text, "wb");
#endif
}
if (ftpData->clients[theSocketId].workerData.theStorFile == NULL)
{
returnCode = socketPrintf(ftpData, theSocketId, "s", "553 Unable to write the file\r\n");
if (returnCode <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("socketPrintf");
my_printf("\n Closing the client 6");
return -1;
}
return -1;
}
while(1)
{
if (ftpData->clients[theSocketId].dataChannelIsTls != 1)
{
ftpData->clients[theSocketId].workerData.bufferIndex = read(ftpData->clients[theSocketId].workerData.socketConnection, ftpData->clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
}
else if (ftpData->clients[theSocketId].dataChannelIsTls == 1)
{
#ifdef OPENSSL_ENABLED
if (ftpData->clients[theSocketId].workerData.passiveModeOn == 1)
ftpData->clients[theSocketId].workerData.bufferIndex = SSL_read(ftpData->clients[theSocketId].workerData.serverSsl, ftpData->clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
else if(ftpData->clients[theSocketId].workerData.activeModeOn == 1)
ftpData->clients[theSocketId].workerData.bufferIndex = SSL_read(ftpData->clients[theSocketId].workerData.clientSsl, ftpData->clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
#endif
}
else
{
my_printf("\nError state");
}
if (ftpData->clients[theSocketId].workerData.bufferIndex == 0)
{
break;
}
else if (ftpData->clients[theSocketId].workerData.bufferIndex > 0)
{
fwrite(ftpData->clients[theSocketId].workerData.buffer, ftpData->clients[theSocketId].workerData.bufferIndex, 1, ftpData->clients[theSocketId].workerData.theStorFile);
usleep(100);
ftpData->clients[theSocketId].lastActivityTimeStamp = (int)time(NULL);
}
else if (ftpData->clients[theSocketId].workerData.bufferIndex < 0)
{
break;
}
}
int theReturnCode;
theReturnCode = fclose(ftpData->clients[theSocketId].workerData.theStorFile);
ftpData->clients[theSocketId].workerData.theStorFile = NULL;
if (ftpData->clients[theSocketId].login.ownerShip.ownerShipSet == 1)
{
FILE_doChownFromUidGid(ftpData->clients[theSocketId].fileToStor.text, ftpData->clients[theSocketId].login.ownerShip.uid, ftpData->clients[theSocketId].login.ownerShip.gid);
}
ftpData->clients[theSocketId].workerData.commandProcessed = 1;
snprintf(ftpData->clients[theSocketId].workerData.theCommandResponse, STRING_SZ_SMALL, "226 file stor ok\r\n");
return 1;
}
static int acceptConnection(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode;
//Passive data connection mode
if (ftpData->clients[theSocketId].workerData.passiveModeOn == 1)
{
int tries = 30;
while (tries > 0)
{
setRandomicPort(ftpData, theSocketId);
ftpData->clients[theSocketId].workerData.passiveListeningSocket = createPassiveSocket(ftpData->clients[theSocketId].workerData.connectionPort);
if (ftpData->clients[theSocketId].workerData.passiveListeningSocket != -1)
{
break;
}
tries--;
}
if (ftpData->clients[theSocketId].workerData.passiveListeningSocket == -1)
{
ftpData->clients[theSocketId].closeTheClient = 1;
my_printf("\n Closing the client 1");
return -1;
}
if (ftpData->clients[theSocketId].workerData.socketIsConnected == 0)
{
if (ftpData->clients[theSocketId].workerData.passiveModeOn == 1 && ftpData->clients[theSocketId].workerData.extendedPassiveModeOn == 0)
{
if(strnlen(ftpData->ftpParameters.natIpAddress, STRING_SZ_SMALL) > 0)
{
my_printf("\n Using nat ip: %s", ftpData->ftpParameters.natIpAddress);
returnCode = socketPrintf(ftpData, theSocketId, "sssdsds", "227 Entering Passive Mode (", ftpData->ftpParameters.natIpAddress, ",", (ftpData->clients[theSocketId].workerData.connectionPort / 256), ",", (ftpData->clients[theSocketId].workerData.connectionPort % 256), ")\r\n");
}
else
{
my_printf("\n Using server ip: %s", ftpData->ftpParameters.natIpAddress);
returnCode = socketPrintf(ftpData, theSocketId, "sdsdsdsdsdsds", "227 Entering Passive Mode (", ftpData->clients[theSocketId].serverIpV4AddressInteger[0], ",", ftpData->clients[theSocketId].serverIpV4AddressInteger[1], ",", ftpData->clients[theSocketId].serverIpV4AddressInteger[2], ",", ftpData->clients[theSocketId].serverIpV4AddressInteger[3], ",", (ftpData->clients[theSocketId].workerData.connectionPort / 256), ",", (ftpData->clients[theSocketId].workerData.connectionPort % 256), ")\r\n");
}
}
else if (ftpData->clients[theSocketId].workerData.passiveModeOn == 1 && ftpData->clients[theSocketId].workerData.extendedPassiveModeOn == 1)
{
returnCode = socketPrintf(ftpData, theSocketId, "sds", "229 Entering Extended Passive Mode (|||", ftpData->clients[theSocketId].workerData.connectionPort, "|)\r\n");
}
else
{
returnCode = -1;
my_printfError("\nUnknown passive state, should be PASV or EPSV");
perror("Unknown passive state, should be PASV or EPSV");
}
ftpData->clients[theSocketId].workerData.socketIsReadyForConnection = 1;
if (returnCode <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("socketPrintf");
my_printf("\n Closing the client 2");
return -1;
}
//Wait for sockets
if ((ftpData->clients[theSocketId].workerData.socketConnection = accept(ftpData->clients[theSocketId].workerData.passiveListeningSocket, 0, 0))!=-1)
{
ftpData->clients[theSocketId].workerData.socketIsConnected = 1;
#ifdef OPENSSL_ENABLED
if (ftpData->clients[theSocketId].dataChannelIsTls == 1)
{
if (acceptSSLConnection(theSocketId, ftpData) < 0)
{
my_printf("\nSSL_Accept failed");
return -1;
}
}
#endif
}
else
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("Socket error");
my_printf("\n Closing the client 3");
return -1;
}
}
else
my_printf("\n Socket already connected");
}
else if (ftpData->clients[theSocketId].workerData.activeModeOn == 1)
{
my_printf("\n ----------------- CREATING ACTIVE SOCKET --------------!");
if (ftpData->clients[theSocketId].workerData.addressType == 1)
ftpData->clients[theSocketId].workerData.socketConnection = createActiveSocket(ftpData->clients[theSocketId].workerData.connectionPort, ftpData->clients[theSocketId].workerData.activeIpAddress);
#ifdef IPV6_ENABLED
else if (ftpData->clients[theSocketId].workerData.addressType == 2)
ftpData->clients[theSocketId].workerData.socketConnection = createActiveSocketV6(ftpData->clients[theSocketId].workerData.connectionPort, ftpData->clients[theSocketId].workerData.activeIpAddress);
#endif
#ifdef OPENSSL_ENABLED
if (ftpData->clients[theSocketId].dataChannelIsTls == 1)
{
returnCode = SSL_set_fd(ftpData->clients[theSocketId].workerData.clientSsl, ftpData->clients[theSocketId].workerData.socketConnection);
if (returnCode == 0)
{
my_printf("\nSSL ERRORS ON WORKER SSL_set_fd");
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("SSL ERRORS ON WORKER SSL_set_fd");
}
//SSL_set_connect_state(ftpData->clients[theSocketId].workerData.clientSsl);
returnCode = SSL_connect(ftpData->clients[theSocketId].workerData.clientSsl);
if (returnCode <= 0)
{
my_printf("\nSSL ERRORS ON WORKER %d error code: %d", returnCode, SSL_get_error(ftpData->clients[theSocketId].workerData.clientSsl, returnCode));
ERR_print_errors_fp(stderr);
}
else
{
//my_printf("\nSSL ACCEPTED ON WORKER");
}
}
#endif
if (ftpData->clients[theSocketId].workerData.socketConnection < 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("Socket error");
my_printf("\n Closing the client 4");
return -1;
}
returnCode = socketPrintf(ftpData, theSocketId, "s", "200 connection accepted\r\n");
ftpData->clients[theSocketId].workerData.socketIsReadyForConnection = 1;
if (returnCode <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("socketPrintf");
my_printf("\n Closing the client 5");
return -1;
}
ftpData->clients[theSocketId].workerData.socketIsConnected = 1;
}
return 1;
}
static int processRetr(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode = 0;
long long int writenSize = 0, writeReturn = 0;
writenSize = writeRetrFile(ftpData, theSocketId, ftpData->clients[theSocketId].workerData.retrRestartAtByte, ftpData->clients[theSocketId].workerData.theStorFile);
ftpData->clients[theSocketId].workerData.retrRestartAtByte = 0;
if (writenSize <= -1)
{
writeReturn = socketPrintf(ftpData, theSocketId, "s", "550 unable to open the file for reading\r\n");
if (writeReturn <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("socketPrintf");
my_printf("\n Closing the client 12");
return -1;
}
return -1;
}
ftpData->clients[theSocketId].workerData.commandProcessed = 1;
snprintf(ftpData->clients[theSocketId].workerData.theCommandResponse, STRING_SZ_SMALL, "226-File successfully transferred\r\n226 done\r\n");
return 1;
}
static int processListNlst(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode = 0;
int theFiles = 0, theCommandType = 0;
if (compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "LIST", strlen("LIST")) == 1)
theCommandType = COMMAND_TYPE_LIST;
else if (compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "NLST", strlen("NLST")) == 1)
theCommandType = COMMAND_TYPE_NLST;
returnCode = writeListDataInfoToSocket(ftpData, theSocketId, &theFiles, theCommandType, &ftpData->clients[theSocketId].workerData.memoryTable);
if (returnCode <= 0)
{
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("writeListDataInfoToSocket");
my_printf("\n Closing the client 9");
return -1;
}
ftpData->clients[theSocketId].workerData.commandProcessed = 1;
snprintf(ftpData->clients[theSocketId].workerData.theCommandResponse, STRING_SZ_SMALL, "226 %d matches total\r\n", theFiles);
return 1;
}
void *connectionWorkerHandle(cleanUpWorkerArgs *args)
{
ftpDataType *ftpData = args->ftpData;
int theSocketId = args->socketId;
int returnCode = 0;
// Enable cancellation for this thread
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
pthread_cleanup_push(workerCleanup, args);
ftpData->clients[theSocketId].workerData.threadIsAlive = 1;
ftpData->clients[theSocketId].workerData.threadHasBeenCreated = 1;
int returnCode;
my_printf("\n ----------------- WORKER CREATED --------------!");
// deal with connections
if (acceptConnection(args) != 1)
{
my_printf("\n Connection error on the worker, exit from thread.");
goto data_channel_exit;
}
//Endless loop ftp process
while (1)
{
if (ftpData->clients[theSocketId].workerData.socketIsConnected > 0)
{
my_printf("\nWorker %d is waiting for commands!", theSocketId);
//Conditional lock on tconditionVariablehread actions
pthread_mutex_lock(&ftpData->clients[theSocketId].conditionMutex);
while (ftpData->clients[theSocketId].workerData.commandReceived == 0)
{
pthread_cond_wait(&ftpData->clients[theSocketId].conditionVariable, &ftpData->clients[theSocketId].conditionMutex);
}
pthread_mutex_unlock(&ftpData->clients[theSocketId].conditionMutex);
if (ftpData->clients[theSocketId].workerData.commandReceived == 1 &&
(compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "STOR", strlen("STOR")) == 1 ||
compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "APPE", strlen("APPE")) == 1) &&
ftpData->clients[theSocketId].fileToStor.textLen > 0)
{
if (processStorAppe(args) != 1)
{
my_printf("\nWorker %d errors on STOR APPE!", theSocketId);
}
break;
}
else if (ftpData->clients[theSocketId].workerData.commandReceived == 1 &&
( (compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "LIST", strlen("LIST")) == 1)
|| (compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "NLST", strlen("NLST")) == 1)))
{
if (processListNlst(args) != 1)
{
my_printf("\nWorker %d errors on LIST NLST!", theSocketId);
}
break;
}
else if (ftpData->clients[theSocketId].workerData.commandReceived == 1 &&
compareStringCaseInsensitive(ftpData->clients[theSocketId].workerData.theCommandReceived, "RETR", strlen("RETR")) == 1)
{
if (processRetr(args) != 1)
{
my_printf("\nWorker %d errors on RETR!", theSocketId);
}
break;
}
break;
}
else
{
break;
}
}
data_channel_exit:
pthread_cleanup_pop(1);
pthread_exit((void *)1);
}

15
dataChannel/dataChannel.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef DATA_CHANNEL_H
#define DATA_CHANNEL_H
#include "ftpData.h"
typedef struct {
ftpDataType *ftpData;
int socketId;
} cleanUpWorkerArgs;
void workerCleanup(cleanUpWorkerArgs *args);
void *connectionWorkerHandle(cleanUpWorkerArgs *args);
#endif /* DATA_CHANNEL_H */

View File

@ -1,9 +1,5 @@
#ifndef ENABLE_PRINTF_MODULE #ifndef ENABLE_PRINTF_MODULE
// Uncomment next line to enable debug printf
// #define ENABLE_PRINTF
// #define ENABLE_PRINTF_ERROR
#define CURRENT_FILE __FILE__ #define CURRENT_FILE __FILE__
#define CURRENT_LINE __LINE__ #define CURRENT_LINE __LINE__
#define CURRENT_FUNC __func__ #define CURRENT_FUNC __func__

0
debug_defines.h Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@ -90,7 +90,7 @@ int parseCommandOpts(ftpDataType * data, int socketId);
int parseCommandRnfr(ftpDataType * data, int socketId); int parseCommandRnfr(ftpDataType * data, int socketId);
int parseCommandRnto(ftpDataType * data, int socketId); int parseCommandRnto(ftpDataType * data, int socketId);
int parseCommandAcct(ftpDataType * data, int socketId); int parseCommandAcct(ftpDataType * data, int socketId);
int parseCommandEprt(ftpDataType *data, int socketId);
long long int writeRetrFile(ftpDataType * data, int theSocketId, long long int startFrom, FILE *retrFP); long long int writeRetrFile(ftpDataType * data, int theSocketId, long long int startFrom, FILE *retrFP);
char *getFtpCommandArg(char * theCommand, char *theCommandString, int skipArgs); char *getFtpCommandArg(char * theCommand, char *theCommandString, int skipArgs);

139
ftpData.c
View File

@ -42,6 +42,8 @@
#include "library/dynamicMemory.h" #include "library/dynamicMemory.h"
#include "debugHelper.h" #include "debugHelper.h"
#include "library/log.h"
static int is_prefix(const char *str, const char *prefix); static int is_prefix(const char *str, const char *prefix);
static char *my_realpath(const char *path, char *resolved_path); static char *my_realpath(const char *path, char *resolved_path);
@ -60,7 +62,7 @@ static char *my_realpath(const char *path, char *resolved_path)
else else
{ {
my_printfError("getcwd"); my_printfError("getcwd");
addLog("getcwd error ", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("getcwd");
return NULL; return NULL;
} }
@ -224,13 +226,13 @@ int getSafePath(dynamicStringDataType *safePath, char *theDirectoryName, loginDa
else else
{ {
my_printfError("\nPath check error: %s check if is in: %s",loginData->homePath.text, real_path); my_printfError("\nPath check error: %s check if is in: %s",loginData->homePath.text, real_path);
addLog("Path check error ", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOGF("%sPath check error: %s check if is in: %s", LOG_DEBUG_PREFIX, loginData->homePath.text, real_path);
return 0; return 0;
} }
} }
else else
{ {
addLog("Realpath error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOGF("%sRealpath error: %s", LOG_DEBUG_PREFIX, theDirectoryName);
my_printfError("\nRealpath error input %s", theDirectoryName); my_printfError("\nRealpath error input %s", theDirectoryName);
my_printfError("\ntheDirectoryToCheck error input %s", theDirectoryToCheck); my_printfError("\ntheDirectoryToCheck error input %s", theDirectoryToCheck);
return 0; return 0;
@ -255,28 +257,45 @@ void appendToDynamicStringDataType(dynamicStringDataType *dynamicString, char *t
void setRandomicPort(ftpDataType *data, int socketPosition) void setRandomicPort(ftpDataType *data, int socketPosition)
{ {
unsigned short int randomicPort = 5000; unsigned short int randomicPort;
int i = 0; int maxAttempts = data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin +1;
int attempt = 0;
int conflict;
randomicPort = data->ftpParameters.connectionPortMin + (rand()%(data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin)); while (attempt++ < maxAttempts)
{
// Generate a random port in range
randomicPort = data->ftpParameters.connectionPortMin +
(rand() % (data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin + 1));
while (i < data->ftpParameters.maxClients) // Check against other clients
{ conflict = 0;
if (randomicPort == data->clients[i].workerData.connectionPort) for (int i = 0; i < data->ftpParameters.maxClients; ++i)
{ {
randomicPort = data->ftpParameters.connectionPortMin + (rand()%(data->ftpParameters.connectionPortMax - data->ftpParameters.connectionPortMin)); if (i != socketPosition &&
i = 0; data->clients[i].workerData.connectionPort == randomicPort)
} {
else conflict = 1;
{ break;
i++; }
} }
}
data->clients[socketPosition].workerData.connectionPort = randomicPort; if (conflict)
continue;
my_printf("\n data->clients[%d].workerData.connectionPort = %d", socketPosition, data->clients[socketPosition].workerData.connectionPort); // Check if port is in use on the system
if (!isPortInUse(randomicPort))
{
data->clients[socketPosition].workerData.connectionPort = randomicPort;
my_printf("\n data->clients[%d].workerData.connectionPort = %d",
socketPosition, randomicPort);
return;
}
}
// If were here, we failed to find a port
LOG_ERROR("Failed to find available random port");
data->clients[socketPosition].workerData.connectionPort = 0;
} }
int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumber, int commandType, DYNMEM_MemoryTable_DataType **memoryTable) int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumber, int commandType, DYNMEM_MemoryTable_DataType **memoryTable)
@ -299,6 +318,11 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
returnCode = socketWorkerPrintf(ftpData, clientId, "sds", "total ", fileAndFoldersCount ,"\r\n"); returnCode = socketWorkerPrintf(ftpData, clientId, "sds", "total ", fileAndFoldersCount ,"\r\n");
if (returnCode <= 0) if (returnCode <= 0)
{ {
for (x = 0; x < fileAndFoldersCount; x++)
DYNMEM_free (fileList[x], memoryTable);
DYNMEM_free (fileList, memoryTable);
return -1; return -1;
} }
} }
@ -344,6 +368,7 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
if (data.isDirectory == 0 && data.isFile == 0 && data.isLink == 0) if (data.isDirectory == 0 && data.isFile == 0 && data.isLink == 0)
{ {
DYNMEM_free (fileList[i], memoryTable);
continue; continue;
} }
@ -368,7 +393,7 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
my_printf("\n ********************** void inode permission string"); my_printf("\n ********************** void inode permission string");
} }
if (data.isLink = 1 && if (data.isLink == 1 &&
data.inodePermissionString != NULL && data.inodePermissionString != NULL &&
strlen(data.inodePermissionString) > 0 && strlen(data.inodePermissionString) > 0 &&
data.inodePermissionString[0] == 'l') data.inodePermissionString[0] == 'l')
@ -382,6 +407,7 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
FILE_AppendToString(&data.finalStringPath, " -> ", memoryTable); FILE_AppendToString(&data.finalStringPath, " -> ", memoryTable);
FILE_AppendToString(&data.finalStringPath, data.linkPath, memoryTable); FILE_AppendToString(&data.finalStringPath, data.linkPath, memoryTable);
} }
} }
memset(data.lastModifiedDataString, 0, LIST_DATA_TYPE_MODIFIED_DATA_STR_SIZE); memset(data.lastModifiedDataString, 0, LIST_DATA_TYPE_MODIFIED_DATA_STR_SIZE);
@ -390,7 +416,6 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
localtime_r(&data.lastModifiedData, &newtime); localtime_r(&data.lastModifiedData, &newtime);
strftime(data.lastModifiedDataString, LIST_DATA_TYPE_MODIFIED_DATA_STR_SIZE, "%b %d %Y", &newtime); strftime(data.lastModifiedDataString, LIST_DATA_TYPE_MODIFIED_DATA_STR_SIZE, "%b %d %Y", &newtime);
switch (commandType) switch (commandType)
{ {
case COMMAND_TYPE_LIST: case COMMAND_TYPE_LIST:
@ -492,7 +517,6 @@ int writeListDataInfoToSocket(ftpDataType *ftpData, int clientId, int *filesNumb
DYNMEM_free (fileList, memoryTable); DYNMEM_free (fileList, memoryTable);
return -1; return -1;
} }
} }
if (fileList != NULL) if (fileList != NULL)
@ -635,8 +659,7 @@ void getListDataInfo(char * thePath, DYNV_VectorGenericDataType *directoryInfo,
void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector) void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector)
{ {
int i; for (int i = 0; i < theVector->Size; i++)
for (i = 0; i < theVector->Size; i++)
{ {
ftpListDataType *data = (ftpListDataType *)theVector->Data[i]; ftpListDataType *data = (ftpListDataType *)theVector->Data[i];
@ -667,20 +690,6 @@ void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector)
} }
} }
void cancelWorker(ftpDataType *data, int clientId)
{
void *pReturn;
addLog("Cancelling thread because is busy", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
int returnCode = pthread_cancel(data->clients[clientId].workerData.workerThread);
if (returnCode != 0)
{
addLog("Cancelling thread ERROR", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
returnCode = pthread_join(data->clients[clientId].workerData.workerThread, &pReturn);
data->clients[clientId].workerData.threadHasBeenCreated = 0;
}
void resetWorkerData(ftpDataType *data, int clientId, int isInitialization) void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
{ {
my_printf("\nReset of worker id: %d", clientId); my_printf("\nReset of worker id: %d", clientId);
@ -698,11 +707,12 @@ void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
data->clients[clientId].workerData.activeModeOn = 0; data->clients[clientId].workerData.activeModeOn = 0;
data->clients[clientId].workerData.extendedPassiveModeOn = 0; data->clients[clientId].workerData.extendedPassiveModeOn = 0;
data->clients[clientId].workerData.activeIpAddressIndex = 0; data->clients[clientId].workerData.activeIpAddressIndex = 0;
data->clients[clientId].workerData.threadHasBeenCreated = 0; data->clients[clientId].workerData.commandProcessed = 0;
memset(data->clients[clientId].workerData.buffer, 0, CLIENT_BUFFER_STRING_SIZE+1); memset(data->clients[clientId].workerData.buffer, 0, CLIENT_BUFFER_STRING_SIZE+1);
memset(data->clients[clientId].workerData.activeIpAddress, 0, CLIENT_BUFFER_STRING_SIZE); memset(data->clients[clientId].workerData.activeIpAddress, 0, CLIENT_BUFFER_STRING_SIZE);
memset(data->clients[clientId].workerData.theCommandReceived, 0, CLIENT_BUFFER_STRING_SIZE+1); memset(data->clients[clientId].workerData.theCommandReceived, 0, CLIENT_BUFFER_STRING_SIZE+1);
memset(data->clients[clientId].workerData.theCommandResponse, 0, STRING_SZ_SMALL+1);
cleanDynamicStringDataType(&data->clients[clientId].workerData.ftpCommand.commandArgs, isInitialization, &data->clients[clientId].workerData.memoryTable); cleanDynamicStringDataType(&data->clients[clientId].workerData.ftpCommand.commandArgs, isInitialization, &data->clients[clientId].workerData.memoryTable);
cleanDynamicStringDataType(&data->clients[clientId].workerData.ftpCommand.commandOps, isInitialization, &data->clients[clientId].workerData.memoryTable); cleanDynamicStringDataType(&data->clients[clientId].workerData.ftpCommand.commandOps, isInitialization, &data->clients[clientId].workerData.memoryTable);
@ -724,14 +734,12 @@ void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
data->clients[clientId].workerData.serverSsl = NULL; data->clients[clientId].workerData.serverSsl = NULL;
} }
if (data->clients[clientId].workerData.clientSsl != NULL) if (data->clients[clientId].workerData.clientSsl != NULL)
{ {
SSL_free(data->clients[clientId].workerData.clientSsl); SSL_free(data->clients[clientId].workerData.clientSsl);
data->clients[clientId].workerData.clientSsl = NULL; data->clients[clientId].workerData.clientSsl = NULL;
} }
#endif #endif
} }
else else
@ -752,33 +760,30 @@ void resetWorkerData(ftpDataType *data, int clientId, int isInitialization)
DYNMEM_free(lastToDestroy, &data->clients[clientId].workerData.memoryTable); DYNMEM_free(lastToDestroy, &data->clients[clientId].workerData.memoryTable);
} }
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
data->clients[clientId].workerData.serverSsl = SSL_new(data->serverCtx); data->clients[clientId].workerData.serverSsl = SSL_new(data->serverCtx);
data->clients[clientId].workerData.clientSsl = SSL_new(data->clientCtx); data->clients[clientId].workerData.clientSsl = SSL_new(data->serverCtx);
#endif #endif
} }
void resetClientData(ftpDataType *data, int clientId, int isInitialization) void resetClientData(ftpDataType *data, int clientId, int isInitialization)
{ {
if (isInitialization != 1) if (isInitialization != 1)
{ {
if (data->clients[clientId].workerData.threadIsAlive == 1)
{
cancelWorker(data, clientId);
}
pthread_mutex_destroy(&data->clients[clientId].conditionMutex); handleThreadReuse(data, clientId);
pthread_cond_destroy(&data->clients[clientId].conditionVariable);
pthread_mutex_destroy(&data->clients[clientId].conditionMutex);
pthread_cond_destroy(&data->clients[clientId].conditionVariable);
pthread_mutex_destroy(&data->clients[clientId].writeMutex);
pthread_mutex_destroy(&data->clients[clientId].writeMutex); #ifdef OPENSSL_ENABLED
if (data->clients[clientId].ssl != NULL)
#ifdef OPENSSL_ENABLED {
if (data->clients[clientId].ssl != NULL) SSL_free(data->clients[clientId].ssl);
{ data->clients[clientId].ssl = NULL;
SSL_free(data->clients[clientId].ssl); }
data->clients[clientId].ssl = NULL; #endif
}
#endif
} }
@ -811,10 +816,6 @@ void resetClientData(ftpDataType *data, int clientId, int isInitialization)
data->clients[clientId].closeTheClient = 0; data->clients[clientId].closeTheClient = 0;
data->clients[clientId].sockaddr_in_size = sizeof(struct sockaddr_in); data->clients[clientId].sockaddr_in_size = sizeof(struct sockaddr_in);
data->clients[clientId].sockaddr_in_server_size = sizeof(struct sockaddr_in); data->clients[clientId].sockaddr_in_server_size = sizeof(struct sockaddr_in);
data->clients[clientId].serverIpAddressInteger[0] = 0;
data->clients[clientId].serverIpAddressInteger[1] = 0;
data->clients[clientId].serverIpAddressInteger[2] = 0;
data->clients[clientId].serverIpAddressInteger[3] = 0;
memset(&data->clients[clientId].client_sockaddr_in, 0, data->clients[clientId].sockaddr_in_size); memset(&data->clients[clientId].client_sockaddr_in, 0, data->clients[clientId].sockaddr_in_size);
@ -839,7 +840,6 @@ void resetClientData(ftpDataType *data, int clientId, int isInitialization)
data->clients[clientId].lastActivityTimeStamp = 0; data->clients[clientId].lastActivityTimeStamp = 0;
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
//data->clients[clientId].workerData.ssl = SSL_new(data->ctx);
data->clients[clientId].ssl = SSL_new(data->serverCtx); data->clients[clientId].ssl = SSL_new(data->serverCtx);
#endif #endif
@ -849,8 +849,8 @@ void resetClientData(ftpDataType *data, int clientId, int isInitialization)
int compareStringCaseInsensitive(char * stringIn, char * stringRef, int stringLenght) int compareStringCaseInsensitive(char * stringIn, char * stringRef, int stringLenght)
{ {
int i = 0; int i = 0;
char * alfaLowerCase = "qwertyuiopasdfghjklzxcvbnm ."; char *alfaLowerCase = "qwertyuiopasdfghjklzxcvbnm .";
char * alfaUpperCase = "QWERTYUIOPASDFGHJKLZXCVBNM ."; char *alfaUpperCase = "QWERTYUIOPASDFGHJKLZXCVBNM .";
int stringInIndex; int stringInIndex;
int stringRefIndex; int stringRefIndex;
@ -888,8 +888,7 @@ int compareStringCaseInsensitive(char * stringIn, char * stringRef, int stringLe
int isCharInString(char *theString, int stringLen, char theChar) int isCharInString(char *theString, int stringLen, char theChar)
{ {
int i; for (int i = 0; i < stringLen; i++)
for (i = 0; i < stringLen; i++)
{ {
if (theString[i] == theChar) if (theString[i] == theChar)
{ {

View File

@ -54,6 +54,10 @@
#define COMMAND_TYPE_STAT 2 #define COMMAND_TYPE_STAT 2
#define WRONG_PASSWORD_ALLOWED_RETRY_TIME 60 #define WRONG_PASSWORD_ALLOWED_RETRY_TIME 60
#define IS_CMD(str, cmd) (compareStringCaseInsensitive(str, cmd, strlen(cmd)) == 1)
#define IS_NOT_CMD(str, cmd) (compareStringCaseInsensitive(str, cmd, strlen(cmd)) != 1)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -87,7 +91,7 @@ struct usersParameters
struct ftpParameters struct ftpParameters
{ {
int ftpIpAddress[4]; int ftpIpAddressV4[4];
int port; int port;
int maxClients; int maxClients;
int daemonModeOn; int daemonModeOn;
@ -150,6 +154,7 @@ struct workerData
int threadIsAlive; int threadIsAlive;
int threadHasBeenCreated; int threadHasBeenCreated;
int connectionPort; int connectionPort;
int addressType;
int passiveModeOn; int passiveModeOn;
int extendedPassiveModeOn; int extendedPassiveModeOn;
int activeModeOn; int activeModeOn;
@ -169,6 +174,9 @@ struct workerData
char theCommandReceived[CLIENT_COMMAND_STRING_SIZE+1]; char theCommandReceived[CLIENT_COMMAND_STRING_SIZE+1];
int commandReceived; int commandReceived;
int commandProcessed;
char theCommandResponse[STRING_SZ_SMALL+1];
long long int retrRestartAtByte; long long int retrRestartAtByte;
/* The PASV thread will wait the signal before start */ /* The PASV thread will wait the signal before start */
@ -184,6 +192,7 @@ struct clientData
SSL *ssl; SSL *ssl;
#endif #endif
int isIpV6;
int tlsIsEnabled; int tlsIsEnabled;
int tlsIsNegotiating; int tlsIsNegotiating;
unsigned long long int tlsNegotiatingTimeStart; unsigned long long int tlsNegotiatingTimeStart;
@ -214,15 +223,20 @@ struct clientData
loginDataType login; loginDataType login;
workerDataType workerData; workerDataType workerData;
int sockaddr_in_size, sockaddr_in_server_size; socklen_t sockaddr_in_size, sockaddr_in_server_size;
#ifdef IPV6_ENABLED
struct sockaddr_in6 client_sockaddr_in, server_sockaddr_in;
#else
struct sockaddr_in client_sockaddr_in, server_sockaddr_in; struct sockaddr_in client_sockaddr_in, server_sockaddr_in;
#endif
int clientPort; int clientPort;
char clientIpAddress[INET_ADDRSTRLEN]; char clientIpAddress[INET6_ADDRSTRLEN];
int serverPort; int serverPort;
char serverIpAddress[INET_ADDRSTRLEN]; char serverIpAddress[INET6_ADDRSTRLEN];
int serverIpAddressInteger[4]; int serverIpV4AddressInteger[4];
ftpCommandDataType ftpCommand; ftpCommandDataType ftpCommand;
int closeTheClient; int closeTheClient;
@ -252,7 +266,6 @@ struct ftpData
{ {
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
SSL_CTX *serverCtx; SSL_CTX *serverCtx;
SSL_CTX *clientCtx;
#endif #endif
int connectedClients; int connectedClients;
@ -301,7 +314,6 @@ int searchInLoginFailsVector(void *loginFailsVector, void *element);
void deleteLoginFailsData(void *element); void deleteLoginFailsData(void *element);
void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector); void deleteListDataInfoVector(DYNV_VectorGenericDataType *theVector);
void resetWorkerData(ftpDataType *data, int clientId, int isInitialization); void resetWorkerData(ftpDataType *data, int clientId, int isInitialization);
void cancelWorker(ftpDataType *data, int clientId);
void resetClientData(ftpDataType *data, int clientId, int isInitialization); void resetClientData(ftpDataType *data, int clientId, int isInitialization);
int compareStringCaseInsensitive(char *stringIn, char* stringRef, int stringLenght); int compareStringCaseInsensitive(char *stringIn, char* stringRef, int stringLenght);
int isCharInString(char *theString, int stringLen, char theChar); int isCharInString(char *theString, int stringLen, char theChar);

View File

@ -37,7 +37,6 @@
/* FTP LIBS */ /* FTP LIBS */
#include "library/fileManagement.h" #include "library/fileManagement.h"
#include "library/logFunctions.h"
#include "library/configRead.h" #include "library/configRead.h"
#include "library/signals.h" #include "library/signals.h"
#include "library/openSsl.h" #include "library/openSsl.h"
@ -51,477 +50,17 @@
#include "ftpData.h" #include "ftpData.h"
#include "ftpCommandsElaborate.h" #include "ftpCommandsElaborate.h"
#include "debugHelper.h" #include "debugHelper.h"
#include "controlChannel/controlChannel.h"
ftpDataType ftpData; ftpDataType ftpData;
pthread_t watchDogThread; pthread_t watchDogThread;
static int processCommand(int processingElement); void initFtpServer(void)
void workerCleanup(void *socketId)
{ {
int theSocketId = *(int *)socketId; int returnCode = 0;
int returnCode = 0;
//my_printf("\nWorker %d cleanup", theSocketId);
#ifdef OPENSSL_ENABLED
int error;
error = fcntl(ftpData.clients[theSocketId].workerData.socketConnection, F_SETFL, O_NONBLOCK);
if (ftpData.clients[theSocketId].dataChannelIsTls == 1)
{
if(ftpData.clients[theSocketId].workerData.passiveModeOn == 1)
{
//my_printf("\nSSL worker Shutdown 1");
returnCode = SSL_shutdown(ftpData.clients[theSocketId].workerData.serverSsl);
//my_printf("\nnSSL worker Shutdown 1 return code : %d", returnCode);
if (!returnCode)
{
shutdown(ftpData.clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData.clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
//my_printf("\nSSL worker Shutdown 2");
returnCode = SSL_shutdown(ftpData.clients[theSocketId].workerData.serverSsl);
//my_printf("\nnSSL worker Shutdown 2 return code : %d", returnCode);
}
}
if(ftpData.clients[theSocketId].workerData.activeModeOn == 1)
{
returnCode = SSL_shutdown(ftpData.clients[theSocketId].workerData.clientSsl);
if (!returnCode)
{
shutdown(ftpData.clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData.clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
returnCode = SSL_shutdown(ftpData.clients[theSocketId].workerData.clientSsl);
}
}
}
#endif
shutdown(ftpData.clients[theSocketId].workerData.socketConnection, SHUT_RDWR);
shutdown(ftpData.clients[theSocketId].workerData.passiveListeningSocket, SHUT_RDWR);
returnCode = close(ftpData.clients[theSocketId].workerData.socketConnection);
returnCode = close(ftpData.clients[theSocketId].workerData.passiveListeningSocket);
resetWorkerData(&ftpData, theSocketId, 0);
// my_printf("\nWorker cleaned!");
//my_printf("\nWorker memory table :%lld", ftpData.clients[theSocketId].workerData.memoryTable);
if (ftpData.clients[theSocketId].workerData.memoryTable != NULL)
;//my_printf("\nMemory table element label: %s", ftpData.clients[theSocketId].workerData.memoryTable->theName);
else
;//my_printf("\nNo data to print");
}
void *connectionWorkerHandle(void * socketId)
{
int theSocketId = *(int *)socketId;
// Enable cancellation for this thread
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_cleanup_push(workerCleanup, (void *) &theSocketId);
ftpData.clients[theSocketId].workerData.threadIsAlive = 1;
ftpData.clients[theSocketId].workerData.threadHasBeenCreated = 1;
int returnCode;
my_printf("\nWORKER CREATED!");
//Passive data connection mode
if (ftpData.clients[theSocketId].workerData.passiveModeOn == 1)
{
int tries = 30;
while (tries > 0)
{
setRandomicPort(&ftpData, theSocketId);
ftpData.clients[theSocketId].workerData.passiveListeningSocket = createPassiveSocket(ftpData.clients[theSocketId].workerData.connectionPort);
if (ftpData.clients[theSocketId].workerData.passiveListeningSocket != -1)
{
break;
}
tries--;
}
if (ftpData.clients[theSocketId].workerData.passiveListeningSocket == -1)
{
ftpData.clients[theSocketId].closeTheClient = 1;
my_printf("\n Closing the client 1");
pthread_exit(NULL);
}
if (ftpData.clients[theSocketId].workerData.socketIsConnected == 0)
{
if (ftpData.clients[theSocketId].workerData.passiveModeOn == 1 && ftpData.clients[theSocketId].workerData.extendedPassiveModeOn == 0)
{
if(strnlen(ftpData.ftpParameters.natIpAddress, STRING_SZ_SMALL) > 0)
{
my_printf("\n Using nat ip: %s", ftpData.ftpParameters.natIpAddress);
returnCode = socketPrintf(&ftpData, theSocketId, "sssdsds", "227 Entering Passive Mode (", ftpData.ftpParameters.natIpAddress, ",", (ftpData.clients[theSocketId].workerData.connectionPort / 256), ",", (ftpData.clients[theSocketId].workerData.connectionPort % 256), ")\r\n");
}
else
{
my_printf("\n Using server ip: %s", ftpData.ftpParameters.natIpAddress);
returnCode = socketPrintf(&ftpData, theSocketId, "sdsdsdsdsdsds", "227 Entering Passive Mode (", ftpData.clients[theSocketId].serverIpAddressInteger[0], ",", ftpData.clients[theSocketId].serverIpAddressInteger[1], ",", ftpData.clients[theSocketId].serverIpAddressInteger[2], ",", ftpData.clients[theSocketId].serverIpAddressInteger[3], ",", (ftpData.clients[theSocketId].workerData.connectionPort / 256), ",", (ftpData.clients[theSocketId].workerData.connectionPort % 256), ")\r\n");
}
}
else if (ftpData.clients[theSocketId].workerData.passiveModeOn == 1 && ftpData.clients[theSocketId].workerData.extendedPassiveModeOn == 1)
{
returnCode = socketPrintf(&ftpData, theSocketId, "sds", "229 Entering Extended Passive Mode (|||", ftpData.clients[theSocketId].workerData.connectionPort, "|)\r\n");
}
else
{
returnCode = -1;
my_printfError("\nUnknown passive state, should be PASV or EPSV");
perror("Unknown passive state, should be PASV or EPSV");
}
ftpData.clients[theSocketId].workerData.socketIsReadyForConnection = 1;
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 2");
pthread_exit(NULL);
}
//Wait for sockets
if ((ftpData.clients[theSocketId].workerData.socketConnection = accept(ftpData.clients[theSocketId].workerData.passiveListeningSocket, 0, 0))!=-1)
{
ftpData.clients[theSocketId].workerData.socketIsConnected = 1;
#ifdef OPENSSL_ENABLED
if (ftpData.clients[theSocketId].dataChannelIsTls == 1)
{
returnCode = SSL_set_fd(ftpData.clients[theSocketId].workerData.serverSsl, ftpData.clients[theSocketId].workerData.socketConnection);
if (returnCode == 0)
{
my_printf("\nSSL ERRORS ON WORKER SSL_set_fd");
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
returnCode = SSL_accept(ftpData.clients[theSocketId].workerData.serverSsl);
if (returnCode <= 0)
{
my_printf("\nSSL ERRORS ON WORKER");
ERR_print_errors_fp(stderr);
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
else
{
//my_printf("\nSSL ACCEPTED ON WORKER");
}
}
#endif
}
else
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 3");
pthread_exit(NULL);
}
}
else
my_printf("\n Socket already connected");
}
else if (ftpData.clients[theSocketId].workerData.activeModeOn == 1)
{
ftpData.clients[theSocketId].workerData.socketConnection = createActiveSocket(ftpData.clients[theSocketId].workerData.connectionPort, ftpData.clients[theSocketId].workerData.activeIpAddress);
#ifdef OPENSSL_ENABLED
if (ftpData.clients[theSocketId].dataChannelIsTls == 1)
{
returnCode = SSL_set_fd(ftpData.clients[theSocketId].workerData.clientSsl, ftpData.clients[theSocketId].workerData.socketConnection);
if (returnCode == 0)
{
my_printf("\nSSL ERRORS ON WORKER SSL_set_fd");
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
//SSL_set_connect_state(ftpData.clients[theSocketId].workerData.clientSsl);
returnCode = SSL_connect(ftpData.clients[theSocketId].workerData.clientSsl);
if (returnCode <= 0)
{
my_printf("\nSSL ERRORS ON WORKER %d error code: %d", returnCode, SSL_get_error(ftpData.clients[theSocketId].workerData.clientSsl, returnCode));
ERR_print_errors_fp(stderr);
}
else
{
//my_printf("\nSSL ACCEPTED ON WORKER");
}
}
#endif
if (ftpData.clients[theSocketId].workerData.socketConnection < 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 4");
pthread_exit(NULL);
}
returnCode = socketPrintf(&ftpData, theSocketId, "s", "200 connection accepted\r\n");
ftpData.clients[theSocketId].workerData.socketIsReadyForConnection = 1;
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 5");
pthread_exit(NULL);
}
ftpData.clients[theSocketId].workerData.socketIsConnected = 1;
}
//my_printf("\nftpData.clients[theSocketId].workerData.socketIsConnected = %d", ftpData.clients[theSocketId].workerData.socketIsConnected);
//Endless loop ftp process
while (1)
{
if (ftpData.clients[theSocketId].workerData.socketIsConnected > 0)
{
my_printf("\nWorker %d is waiting for commands!", theSocketId);
//Conditional lock on tconditionVariablehread actions
pthread_mutex_lock(&ftpData.clients[theSocketId].conditionMutex);
while (ftpData.clients[theSocketId].workerData.commandReceived == 0)
{
pthread_cond_wait(&ftpData.clients[theSocketId].conditionVariable, &ftpData.clients[theSocketId].conditionMutex);
}
pthread_mutex_unlock(&ftpData.clients[theSocketId].conditionMutex);
if (ftpData.clients[theSocketId].workerData.commandReceived == 1 &&
(compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "STOR", strlen("STOR")) == 1 || compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "APPE", strlen("APPE")) == 1) &&
ftpData.clients[theSocketId].fileToStor.textLen > 0)
{
if (compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "APPE", strlen("APPE")) == 1)
{
#ifdef LARGE_FILE_SUPPORT_ENABLED
//#warning LARGE FILE SUPPORT IS ENABLED!
ftpData.clients[theSocketId].workerData.theStorFile = fopen64(ftpData.clients[theSocketId].fileToStor.text, "ab");
#endif
#ifndef LARGE_FILE_SUPPORT_ENABLED
#warning LARGE FILE SUPPORT IS NOT ENABLED!
ftpData.clients[theSocketId].workerData.theStorFile = fopen(ftpData.clients[theSocketId].fileToStor.text, "ab");
#endif
}
else
{
#ifdef LARGE_FILE_SUPPORT_ENABLED
//#warning LARGE FILE SUPPORT IS ENABLED!
ftpData.clients[theSocketId].workerData.theStorFile = fopen64(ftpData.clients[theSocketId].fileToStor.text, "wb");
#endif
#ifndef LARGE_FILE_SUPPORT_ENABLED
#warning LARGE FILE SUPPORT IS NOT ENABLED!
ftpData.clients[theSocketId].workerData.theStorFile = fopen(ftpData.clients[theSocketId].fileToStor.text, "wb");
#endif
}
if (ftpData.clients[theSocketId].workerData.theStorFile == NULL)
{
returnCode = socketPrintf(&ftpData, theSocketId, "s", "553 Unable to write the file\r\n");
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 6");
pthread_exit(NULL);
}
break;
}
returnCode = socketPrintf(&ftpData, theSocketId, "s", "150 Accepted data connection\r\n");
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 7");
pthread_exit(NULL);
}
while(1)
{
if (ftpData.clients[theSocketId].dataChannelIsTls != 1)
{
ftpData.clients[theSocketId].workerData.bufferIndex = read(ftpData.clients[theSocketId].workerData.socketConnection, ftpData.clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
}
else if (ftpData.clients[theSocketId].dataChannelIsTls == 1)
{
#ifdef OPENSSL_ENABLED
if (ftpData.clients[theSocketId].workerData.passiveModeOn == 1)
ftpData.clients[theSocketId].workerData.bufferIndex = SSL_read(ftpData.clients[theSocketId].workerData.serverSsl, ftpData.clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
else if(ftpData.clients[theSocketId].workerData.activeModeOn == 1)
ftpData.clients[theSocketId].workerData.bufferIndex = SSL_read(ftpData.clients[theSocketId].workerData.clientSsl, ftpData.clients[theSocketId].workerData.buffer, CLIENT_BUFFER_STRING_SIZE);
#endif
}
else
{
my_printf("\nError state");
}
if (ftpData.clients[theSocketId].workerData.bufferIndex == 0)
{
break;
}
else if (ftpData.clients[theSocketId].workerData.bufferIndex > 0)
{
fwrite(ftpData.clients[theSocketId].workerData.buffer, ftpData.clients[theSocketId].workerData.bufferIndex, 1, ftpData.clients[theSocketId].workerData.theStorFile);
usleep(100);
}
else if (ftpData.clients[theSocketId].workerData.bufferIndex < 0)
{
break;
}
}
int theReturnCode;
theReturnCode = fclose(ftpData.clients[theSocketId].workerData.theStorFile);
ftpData.clients[theSocketId].workerData.theStorFile = NULL;
if (ftpData.clients[theSocketId].login.ownerShip.ownerShipSet == 1)
{
FILE_doChownFromUidGid(ftpData.clients[theSocketId].fileToStor.text, ftpData.clients[theSocketId].login.ownerShip.uid, ftpData.clients[theSocketId].login.ownerShip.gid);
}
returnCode = socketPrintf(&ftpData, theSocketId, "s", "226 file stor ok\r\n");
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 8");
pthread_exit(NULL);
}
break;
}
else if (ftpData.clients[theSocketId].workerData.commandReceived == 1 &&
( (compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "LIST", strlen("LIST")) == 1)
|| (compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "NLST", strlen("NLST")) == 1))
)
{
int theFiles = 0, theCommandType = 0;
if (compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "LIST", strlen("LIST")) == 1)
theCommandType = COMMAND_TYPE_LIST;
else if (compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "NLST", strlen("NLST")) == 1)
theCommandType = COMMAND_TYPE_NLST;
returnCode = socketPrintf(&ftpData, theSocketId, "s", "150 Accepted data connection\r\n");
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 8");
pthread_exit(NULL);
}
returnCode = writeListDataInfoToSocket(&ftpData, theSocketId, &theFiles, theCommandType, &ftpData.clients[theSocketId].workerData.memoryTable);
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 9");
pthread_exit(NULL);
}
returnCode = socketPrintf(&ftpData, theSocketId, "sds", "226 ", theFiles, " matches total\r\n");
if (returnCode <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 10");
pthread_exit(NULL);
}
break;
}
else if (ftpData.clients[theSocketId].workerData.commandReceived == 1 &&
compareStringCaseInsensitive(ftpData.clients[theSocketId].workerData.theCommandReceived, "RETR", strlen("RETR")) == 1)
{
long long int writenSize = 0, writeReturn = 0;
writeReturn = socketPrintf(&ftpData, theSocketId, "s", "150 Accepted data connection\r\n");
if (writeReturn <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 11");
pthread_exit(NULL);
}
writenSize = writeRetrFile(&ftpData, theSocketId, ftpData.clients[theSocketId].workerData.retrRestartAtByte, ftpData.clients[theSocketId].workerData.theStorFile);
ftpData.clients[theSocketId].workerData.retrRestartAtByte = 0;
if (writenSize <= -1)
{
writeReturn = socketPrintf(&ftpData, theSocketId, "s", "550 unable to open the file for reading\r\n");
if (writeReturn <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 12");
pthread_exit(NULL);
}
break;
}
writeReturn = socketPrintf(&ftpData, theSocketId, "s", "226-File successfully transferred\r\n226 done\r\n");
if (writeReturn <= 0)
{
ftpData.clients[theSocketId].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Closing the client 13");
pthread_exit(NULL);
}
break;
}
break;
}
else
{
break;
}
}
pthread_exit((void *)1);
pthread_cleanup_pop(0);
pthread_exit((void *)2);
return NULL;
}
void runFtpServer(void)
{
printf("\nHello uFTP server %s starting..\n", UFTP_SERVER_VERSION); printf("\nHello uFTP server %s starting..\n", UFTP_SERVER_VERSION);
/* Needed for Select*/
static int processingSock = 0, returnCode = 0;
/* Handle signals */ /* Handle signals */
signalHandlerInstall(); signalHandlerInstall();
@ -544,6 +83,7 @@ void runFtpServer(void)
//Socket main creator //Socket main creator
ftpData.connectionData.theMainSocket = createSocket(&ftpData); ftpData.connectionData.theMainSocket = createSocket(&ftpData);
printf("\nuFTP server starting.."); printf("\nuFTP server starting..");
/* init fd set needed for select */ /* init fd set needed for select */
@ -556,445 +96,36 @@ void runFtpServer(void)
if(returnCode != 0) if(returnCode != 0)
{ {
my_printf("pthread_create WatchDog Error %d", returnCode); my_printf("pthread_create WatchDog Error %d", returnCode);
addLog("Pthead create error restarting the server", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("Pthead create error restarting the server");
exit(0); exit(0);
} }
//Endless loop ftp process
while (1)
{
//Update watchdog timer
updateWatchDogTime((int)time(NULL));
/*
my_printf("\nUsed memory : %lld", DYNMEM_GetTotalMemory());
int memCount = 0;
for (memCount = 0; memCount < ftpData.ftpParameters.maxClients; memCount++)
{
if (ftpData.clients[memCount].memoryTable != NULL)
{
my_printf("\nftpData.clients[%d].memoryTable = %s", memCount, ftpData.clients[memCount].memoryTable->theName);
}
if (ftpData.clients[memCount].workerData.memoryTable != NULL)
{
my_printf("\nftpData.clients[%d].workerData.memoryTable = %s", memCount, ftpData.clients[memCount].workerData.memoryTable->theName);
}
if (ftpData.clients[memCount].workerData.directoryInfo.memoryTable != NULL)
{
my_printf("\nftpData.clients[%d].workerData.directoryInfo.memoryTable = %s", memCount, ftpData.clients[memCount].workerData.directoryInfo.memoryTable->theName);
}
}
*/
/* waits for socket activity, if no activity then checks for client socket timeouts */
if (selectWait(&ftpData) == 0)
{
checkClientConnectionTimeout(&ftpData);
flushLoginWrongTriesData(&ftpData);
}
/*Main loop handle client commands */
for (processingSock = 0; processingSock < ftpData.ftpParameters.maxClients; processingSock++)
{
/* close the connection if quit flag has been set */
if (ftpData.clients[processingSock].closeTheClient == 1)
{
closeClient(&ftpData, processingSock);
continue;
}
/* Check if there are client pending connections, accept the connection if possible otherwise reject */
if ((returnCode = evaluateClientSocketConnection(&ftpData)) == 1)
{
break;
}
/* no data to check client is not connected, continue to check other clients */
if (isClientConnected(&ftpData, processingSock) == 0)
{
/* socket is not conneted */
continue;
}
if (FD_ISSET(ftpData.clients[processingSock].socketDescriptor, &ftpData.connectionData.rset) ||
FD_ISSET(ftpData.clients[processingSock].socketDescriptor, &ftpData.connectionData.eset))
{
#ifdef OPENSSL_ENABLED
if (ftpData.clients[processingSock].tlsIsNegotiating == 1)
{
returnCode = SSL_accept(ftpData.clients[processingSock].ssl);
if (returnCode <= 0)
{
//my_printf("\nSSL NOT YET ACCEPTED: %d", returnCode);
ftpData.clients[processingSock].tlsIsEnabled = 0;
ftpData.clients[processingSock].tlsIsNegotiating = 1;
if ( ((int)time(NULL) - ftpData.clients[processingSock].tlsNegotiatingTimeStart) > TLS_NEGOTIATING_TIMEOUT )
{
ftpData.clients[processingSock].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
//my_printf("\nTLS timeout closing the client time:%lld, start time: %lld..", (int)time(NULL), ftpData.clients[processingSock].tlsNegotiatingTimeStart);
}
}
else
{
//my_printf("\nSSL ACCEPTED");
ftpData.clients[processingSock].tlsIsEnabled = 1;
ftpData.clients[processingSock].tlsIsNegotiating = 0;
}
continue;
}
#endif
if (ftpData.clients[processingSock].tlsIsEnabled == 1)
{
#ifdef OPENSSL_ENABLED
ftpData.clients[processingSock].bufferIndex = SSL_read(ftpData.clients[processingSock].ssl, ftpData.clients[processingSock].buffer, CLIENT_BUFFER_STRING_SIZE);
#endif
}
else
{
ftpData.clients[processingSock].bufferIndex = read(ftpData.clients[processingSock].socketDescriptor, ftpData.clients[processingSock].buffer, CLIENT_BUFFER_STRING_SIZE);
}
//The client is not connected anymore
if ((ftpData.clients[processingSock].bufferIndex) == 0)
{
//addLog("Client not connected anymore", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
closeClient(&ftpData, processingSock);
}
//Debug print errors
if (ftpData.clients[processingSock].bufferIndex < 0)
{
//ftpData.clients[processingSock].closeTheClient = 1;
//addLog("Socket write error ", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
//my_printfError("\n1 Errno = %d", errno);
continue;
}
//Some commands has been received
if (ftpData.clients[processingSock].bufferIndex > 0)
{
int i = 0;
int commandProcessStatus = 0;
for (i = 0; i < ftpData.clients[processingSock].bufferIndex; i++)
{
if (ftpData.clients[processingSock].commandIndex < CLIENT_COMMAND_STRING_SIZE)
{
if (ftpData.clients[processingSock].buffer[i] != '\r' && ftpData.clients[processingSock].buffer[i] != '\n')
{
ftpData.clients[processingSock].theCommandReceived[ftpData.clients[processingSock].commandIndex++] = ftpData.clients[processingSock].buffer[i];
}
if (ftpData.clients[processingSock].buffer[i] == '\n')
{
ftpData.clients[processingSock].socketCommandReceived = 1;
//my_printf("\n Processing the command: %s", ftpData.clients[processingSock].theCommandReceived);
commandProcessStatus = processCommand(processingSock);
//Echo unrecognized commands
if (commandProcessStatus == FTP_COMMAND_NOT_RECONIZED)
{
int returnCode = 0;
returnCode = socketPrintf(&ftpData, processingSock, "s", "500 Unknown command\r\n");
if (returnCode < 0)
{
ftpData.clients[processingSock].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
my_printf("\n COMMAND NOT SUPPORTED ********* %s", ftpData.clients[processingSock].buffer);
}
else if (commandProcessStatus == FTP_COMMAND_PROCESSED)
{
ftpData.clients[processingSock].lastActivityTimeStamp = (int)time(NULL);
}
else if (commandProcessStatus == FTP_COMMAND_PROCESSED_WRITE_ERROR)
{
ftpData.clients[processingSock].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
my_printf("\n Write error WARNING!");
}
}
}
else
{
//Command overflow can't be processed
int returnCode;
ftpData.clients[processingSock].commandIndex = 0;
memset(ftpData.clients[processingSock].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1);
returnCode = socketPrintf(&ftpData, processingSock, "s", "500 Unknown command\r\n");
if (returnCode <= 0)
{
ftpData.clients[processingSock].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
}
my_printf("\n Command too long closing the client.");
break;
}
}
usleep(100);
memset(ftpData.clients[processingSock].buffer, 0, CLIENT_BUFFER_STRING_SIZE+1);
}
}
}
}
//Server Close
shutdown(ftpData.connectionData.theMainSocket, SHUT_RDWR);
close(ftpData.connectionData.theMainSocket);
return;
} }
static int processCommand(int processingElement) void runFtpServer(void)
{ {
int toReturn = 0; initFtpServer();
//printTimeStamp();
my_printf ("\nCommand received from (%d): %s", processingElement, ftpData.clients[processingElement].theCommandReceived);
cleanDynamicStringDataType(&ftpData.clients[processingElement].ftpCommand.commandArgs, 0, &ftpData.clients[processingElement].memoryTable); //Endless loop ftp process
cleanDynamicStringDataType(&ftpData.clients[processingElement].ftpCommand.commandOps, 0, &ftpData.clients[processingElement].memoryTable); while (1)
if (ftpData.clients[processingElement].login.userLoggedIn == 0 &&
(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "USER", strlen("USER")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PASS", strlen("PASS")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "QUIT", strlen("QUIT")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PBSZ", strlen("PBSZ")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PROT", strlen("PROT")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "CCC", strlen("CCC")) != 1 &&
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "AUTH", strlen("AUTH")) != 1))
{
toReturn = notLoggedInMessage(&ftpData, processingElement);
ftpData.clients[processingElement].commandIndex = 0;
memset(ftpData.clients[processingElement].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1);
return 1;
}
//Process Command
if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "USER", strlen("USER")) == 1)
{ {
//my_printf("\nUSER COMMAND RECEIVED"); evaluateControlChannel(&ftpData);
toReturn = parseCommandUser(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PASS", strlen("PASS")) == 1)
{
//my_printf("\nPASS COMMAND RECEIVED");
toReturn = parseCommandPass(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "SITE", strlen("SITE")) == 1)
{
//my_printf("\nSITE COMMAND RECEIVED");
toReturn = parseCommandSite(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "AUTH", strlen("AUTH")) == 1)
{
//my_printf("\nAUTH COMMAND RECEIVED");
toReturn = parseCommandAuth(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PROT", strlen("PROT")) == 1)
{
//my_printf("\nPROT COMMAND RECEIVED");
toReturn = parseCommandProt(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PBSZ", strlen("PBSZ")) == 1)
{
//my_printf("\nPBSZ COMMAND RECEIVED");
toReturn = parseCommandPbsz(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "CCC", strlen("CCC")) == 1)
{
//my_printf("\nCCC COMMAND RECEIVED");
toReturn = parseCommandCcc(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PWD", strlen("PWD")) == 1 ||
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "XPWD", strlen("XPWD")) == 1)
{
// XPWD
//my_printf("\nPWD COMMAND RECEIVED");
toReturn = parseCommandPwd(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "SYST", strlen("SYST")) == 1)
{
//my_printf("\nSYST COMMAND RECEIVED");
toReturn = parseCommandSyst(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "FEAT", strlen("FEAT")) == 1)
{
//my_printf("\nFEAT COMMAND RECEIVED");
toReturn = parseCommandFeat(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "TYPE I", strlen("TYPE I")) == 1)
{
//my_printf("\nTYPE I COMMAND RECEIVED");
toReturn = parseCommandTypeI(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "STRU F", strlen("STRU F")) == 1)
{
//my_printf("\nTYPE I COMMAND RECEIVED");
toReturn = parseCommandStruF(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "MODE S", strlen("MODE S")) == 1)
{
//my_printf("\nMODE S COMMAND RECEIVED");
toReturn = parseCommandModeS(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "TYPE A", strlen("TYPE A")) == 1)
{
//my_printf("\nTYPE A COMMAND RECEIVED");
toReturn = parseCommandTypeI(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "EPSV", strlen("EPSV")) == 1)
{
my_printf("\nEPSV COMMAND RECEIVED");
toReturn = parseCommandEpsv(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PASV", strlen("PASV")) == 1)
{
my_printf("\nPASV COMMAND RECEIVED");
toReturn = parseCommandPasv(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "PORT", strlen("PORT")) == 1)
{
//my_printf("\nPORT COMMAND RECEIVED");
toReturn = parseCommandPort(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "LIST", strlen("LIST")) == 1)
{
//my_printf("\nLIST COMMAND RECEIVED");
toReturn = parseCommandList(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "STAT", strlen("STAT")) == 1)
{
my_printf("\nSTAT COMMAND RECEIVED");
toReturn = parseCommandStat(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "CDUP", strlen("CDUP")) == 1 ||
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "XCUP", strlen("XCUP")) == 1 ||
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "CWD ..", strlen("CWD ..")) == 1)
{
//my_printf("\nCDUP COMMAND RECEIVED");
toReturn = parseCommandCdup(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "CWD", strlen("CWD")) == 1)
{
//my_printf("\nCWD COMMAND RECEIVED");
toReturn = parseCommandCwd(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "REST", strlen("REST")) == 1)
{
//my_printf("\nREST COMMAND RECEIVED");
toReturn = parseCommandRest(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "RETR", strlen("RETR")) == 1)
{
//my_printf("\nRETR COMMAND RECEIVED");
toReturn = parseCommandRetr(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "STOR", strlen("STOR")) == 1)
{
//my_printf("\nSTOR COMMAND RECEIVED");
toReturn = parseCommandStor(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "MKD", strlen("MKD")) == 1 ||
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "XMKD", strlen("XMKD")) == 1)
{
//my_printf("\nMKD command received");
toReturn = parseCommandMkd(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "ABOR", strlen("ABOR")) == 1)
{
//my_printf("\nABOR command received");
toReturn = parseCommandAbor(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "DELE", strlen("DELE")) == 1)
{
//my_printf("\nDELE comman200 OKd received");
toReturn = parseCommandDele(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "OPTS", strlen("OPTS")) == 1)
{
//my_printf("\nOPTS command received");
toReturn = parseCommandOpts(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "MDTM", strlen("MDTM")) == 1)
{
my_printf("\nMTDM command received");
toReturn = parseCommandMdtm(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "NLST", strlen("NLST")) == 1)
{
// my_printf("\nNLST command received");
toReturn = parseCommandNlst(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "QUIT", strlen("QUIT")) == 1)
{
//my_printf("\nQUIT command received");
toReturn = parseCommandQuit(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "RMD", strlen("RMD")) == 1 ||
compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "XRMD", strlen("XRMD")) == 1)
{
// XRMD
// my_printf("\nRMD command received");
toReturn = parseCommandRmd(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "RNFR", strlen("RNFR")) == 1)
{
// my_printf("\nRNFR command received");
toReturn = parseCommandRnfr(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "RNTO", strlen("RNTO")) == 1)
{
// my_printf("\nRNTO command received");
toReturn = parseCommandRnto(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "SIZE", strlen("SIZE")) == 1)
{
//my_printf("\nSIZE command received");
toReturn = parseCommandSize(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "APPE", strlen("APPE")) == 1)
{
// my_printf("\nAPPE command received");
toReturn = parseCommandAppe(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "NOOP", strlen("NOOP")) == 1)
{
//my_printf("\nNOOP command received");
toReturn = parseCommandNoop(&ftpData, processingElement);
}
else if(compareStringCaseInsensitive(ftpData.clients[processingElement].theCommandReceived, "ACCT", strlen("ACCT")) == 1)
{
//my_printf("\nNOOP command received");
toReturn = parseCommandAcct(&ftpData, processingElement);
}
else
{
; //Parse unsupported command not needed
} }
ftpData.clients[processingElement].commandIndex = 0; //Server Close
memset(ftpData.clients[processingElement].theCommandReceived, 0, CLIENT_COMMAND_STRING_SIZE+1); shutdown(ftpData.connectionData.theMainSocket, SHUT_RDWR);
return toReturn; close(ftpData.connectionData.theMainSocket);
return;
} }
void deallocateMemory(void) void deallocateMemory(void)
{ {
int i = 0; int i = 0;
// my_printf("\n Deallocating the memory.. "); my_printf("\nDeallocating server memory ..");
// my_printf("\nDYNMEM_freeAll called"); my_printf("\nDYNMEM_freeAll called");
// my_printf("\nElement size: %ld", ftpData.generalDynamicMemoryTable->size); my_printf("\nMemory Table size: %ld", ftpData.generalDynamicMemoryTable->size);
// my_printf("\nElement address: %ld", (long int) ftpData.generalDynamicMemoryTable->address); my_printf("\nMemory Table: %ld", (long int) ftpData.generalDynamicMemoryTable->address);
// my_printf("\nElement nextElement: %ld",(long int) ftpData.generalDynamicMemoryTable->nextElement); my_printf("\nMemory Table: %ld",(long int) ftpData.generalDynamicMemoryTable->nextElement);
// my_printf("\nElement previousElement: %ld",(long int) ftpData.generalDynamicMemoryTable->previousElement); my_printf("\nMemory Table: %ld",(long int) ftpData.generalDynamicMemoryTable->previousElement);
for (i = 0; i < ftpData.ftpParameters.maxClients; i++) for (i = 0; i < ftpData.ftpParameters.maxClients; i++)
{ {
@ -1006,9 +137,9 @@ void deallocateMemory(void)
DYNMEM_freeAll(&ftpData.ftpParameters.usersVector.memoryTable); DYNMEM_freeAll(&ftpData.ftpParameters.usersVector.memoryTable);
DYNMEM_freeAll(&ftpData.generalDynamicMemoryTable); DYNMEM_freeAll(&ftpData.generalDynamicMemoryTable);
//my_printf("\n\nUsed memory at end: %lld", DYNMEM_GetTotalMemory()); my_printf("\n\nUsed memory at end: %lld", DYNMEM_GetTotalMemory());
my_printf("\n ftpData.generalDynamicMemoryTable = %ld", ftpData.generalDynamicMemoryTable);
//my_printf("\n ftpData.generalDynamicMemoryTable = %ld", ftpData.generalDynamicMemoryTable);
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
SSL_CTX_free(ftpData.serverCtx); SSL_CTX_free(ftpData.serverCtx);
cleanupOpenssl(); cleanupOpenssl();

View File

@ -27,12 +27,10 @@
#define FTPSERVER_H #define FTPSERVER_H
#define MAX_FTP_CLIENTS 10 #define MAX_FTP_CLIENTS 10
#define UFTP_SERVER_VERSION "v2.6.0 stable" #define UFTP_SERVER_VERSION "v4.0.0 stable"
void initFtpServer(void);
void runFtpServer(void); void runFtpServer(void);
void *connectionWorkerHandle(void * socketId);
void workerCleanup(void *socketId);
void signal_callback_handler(int signum); void signal_callback_handler(int signum);
void deallocateMemory(void); void deallocateMemory(void);

View File

@ -1,79 +0,0 @@
/*
* The MIT License
*
* Copyright 2018 Ugo Cirmignani.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
USER <SP> <username> <CRLF>
PASS <SP> <password> <CRLF>
ACCT <SP> <account-information> <CRLF>
CWD <SP> <pathname> <CRLF>
CDUP <CRLF>
SMNT <SP> <pathname> <CRLF>
QUIT <CRLF>
REIN <CRLF>
PORT <SP> <host-port> <CRLF>
PASV <CRLF>
TYPE <SP> <type-code> <CRLF>
STRU <SP> <structure-code> <CRLF>
MODE <SP> <mode-code> <CRLF>
RETR <SP> <pathname> <CRLF>
STOR <SP> <pathname> <CRLF>
STOU <CRLF>
APPE <SP> <pathname> <CRLF>
ALLO <SP> <decimal-integer>
[<SP> R <SP> <decimal-integer>] <CRLF>
REST <SP> <marker> <CRLF>
RNFR <SP> <pathname> <CRLF>
RNTO <SP> <pathname> <CRLF>
ABOR <CRLF>
DELE <SP> <pathname> <CRLF>
RMD <SP> <pathname> <CRLF>
MKD <SP> <pathname> <CRLF>
PWD <CRLF>
LIST [<SP> <pathname>] <CRLF>
NLST [<SP> <pathname>] <CRLF>
SITE <SP> <string> <CRLF>
SYST <CRLF>
STAT [<SP> <pathname>] <CRLF>
HELP [<SP> <string>] <CRLF>
NOOP <CRLF>
*/
#ifndef FTPSPECS_H
#define FTPSPECS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* FTPSPECS_H */

View File

@ -143,9 +143,7 @@ void initFtpData(ftpDataType *ftpData)
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
initOpenssl(); initOpenssl();
ftpData->serverCtx = createServerContext(); ftpData->serverCtx = createServerContext();
ftpData->clientCtx = createClientContext();
configureContext(ftpData->serverCtx, ftpData->ftpParameters.certificatePath, ftpData->ftpParameters.privateCertificatePath); configureContext(ftpData->serverCtx, ftpData->ftpParameters.certificatePath, ftpData->ftpParameters.privateCertificatePath);
configureClientContext(ftpData->clientCtx, ftpData->ftpParameters.certificatePath, ftpData->ftpParameters.privateCertificatePath);
#endif #endif
ftpData->connectedClients = 0; ftpData->connectedClients = 0;
@ -528,7 +526,7 @@ static int parseConfigurationFile(ftpParameters_DataType *ftpParameters, DYNV_Ve
searchIndex = searchParameter("SERVER_IP", parametersVector); searchIndex = searchParameter("SERVER_IP", parametersVector);
if (searchIndex != -1) if (searchIndex != -1)
{ {
strncpy(&ftpParameters->natIpAddress, ((parameter_DataType *) parametersVector->Data[searchIndex])->value, STRING_SZ_SMALL); strncpy(ftpParameters->natIpAddress, ((parameter_DataType *) parametersVector->Data[searchIndex])->value, STRING_SZ_SMALL);
my_printf("\n SERVER_IP parameter:%s", ftpParameters->natIpAddress); my_printf("\n SERVER_IP parameter:%s", ftpParameters->natIpAddress);
} }
else else
@ -552,10 +550,10 @@ static int parseConfigurationFile(ftpParameters_DataType *ftpParameters, DYNV_Ve
searchIndex = searchParameter("FTP_SERVER_IP", parametersVector); searchIndex = searchParameter("FTP_SERVER_IP", parametersVector);
if (searchIndex != -1) if (searchIndex != -1)
{ {
sscanf (((parameter_DataType *) parametersVector->Data[searchIndex])->value,"%d.%d.%d.%d", &ftpParameters->ftpIpAddress[0], sscanf (((parameter_DataType *) parametersVector->Data[searchIndex])->value,"%d.%d.%d.%d", &ftpParameters->ftpIpAddressV4[0],
&ftpParameters->ftpIpAddress[1], &ftpParameters->ftpIpAddressV4[1],
&ftpParameters->ftpIpAddress[2], &ftpParameters->ftpIpAddressV4[2],
&ftpParameters->ftpIpAddress[3]); &ftpParameters->ftpIpAddressV4[3]);
//my_printf("\nFTP_SERVER_IP value: %d.%d.%d.%d", ftpParameters->ftpIpAddress[0], //my_printf("\nFTP_SERVER_IP value: %d.%d.%d.%d", ftpParameters->ftpIpAddress[0],
// ftpParameters->ftpIpAddress[1], // ftpParameters->ftpIpAddress[1],
// ftpParameters->ftpIpAddress[2], // ftpParameters->ftpIpAddress[2],
@ -563,10 +561,10 @@ static int parseConfigurationFile(ftpParameters_DataType *ftpParameters, DYNV_Ve
} }
else else
{ {
ftpParameters->ftpIpAddress[0] = 127; ftpParameters->ftpIpAddressV4[0] = 127;
ftpParameters->ftpIpAddress[1] = 0; ftpParameters->ftpIpAddressV4[1] = 0;
ftpParameters->ftpIpAddress[2] = 0; ftpParameters->ftpIpAddressV4[2] = 0;
ftpParameters->ftpIpAddress[3] = 1; ftpParameters->ftpIpAddressV4[3] = 1;
//my_printf("\nFTP_SERVER_IP parameter not found in the configuration file, listening on all available networks"); //my_printf("\nFTP_SERVER_IP parameter not found in the configuration file, listening on all available networks");
} }

View File

@ -40,6 +40,23 @@
#include "../debugHelper.h" #include "../debugHelper.h"
#include "../ftpData.h" #include "../ftpData.h"
#include "connection.h" #include "connection.h"
#include "log.h"
#include "debug_defines.h"
static int is_ipv4_mapped_ipv6(const char *ip);
int is_ipv4_mapped_ipv6(const char *ip) {
size_t prefix_len = strlen("::ffff:");
// Check if the address starts with the mapped address prefix
if (strncmp(ip, "::ffff:", prefix_len) != 0) {
return 0;
}
// Check if the remaining part is a valid IPv4 address using existing logic
return 1;
}
int socketPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...) int socketPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...)
{ {
@ -343,6 +360,226 @@ int getMaximumSocketFd(int mainSocket, ftpDataType * ftpData)
return toReturn; return toReturn;
} }
#ifdef IPV6_ENABLED
int isPortInUse(int port) {
int sockfd;
struct sockaddr_in6 addr;
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
return 1; // Assume port is in use if we can't create a socket
}
int reuse = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
addr.sin6_addr = in6addr_any;
int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
close(sockfd); // Always close after test
if (result == 0) {
return 0; // Port is free
} else if (errno == EADDRINUSE) {
return 1; // Port is in use
} else {
perror("bind");
return 1; // Other error, treat as in-use
}
}
int createSocket(ftpDataType * ftpData)
{
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
int sock = -1, errorCode = -1;
struct sockaddr_in6 serveraddr;
//Socket creation IPV6
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
{
perror("socket() failed");
LOG_ERROR("Socket creation failed");
return -1;
}
//No blocking socket
errorCode = fcntl(sock, F_SETFL, O_NONBLOCK);
int reuse = 1;
#ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed");
LOG_ERROR("socketopt failed");
}
#endif
reuse = 1;
#ifdef SO_REUSEPORT
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed");
LOG_ERROR("setsocket error");
}
#endif
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin6_family = AF_INET6;
serveraddr.sin6_port = htons(ftpData->ftpParameters.port);
serveraddr.sin6_addr = in6addr_any;
if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
close(sock);
perror("bind() failed");
LOG_ERROR("bind failed");
return -1;
}
//Number of client allowed
errorCode = listen(sock, ftpData->ftpParameters.maxClients + 1);
if (errorCode < 0)
{
LOG_ERROR("listen error");
if (sock != -1)
{
close(sock);
}
return -1;
}
return sock;
}
int createPassiveSocket(int port)
{
int sock, returnCode;
struct sockaddr_in6 serveraddr;
int max_retries = 12; // number of bind retries
int retry_delay_sec = 1; // delay between retries
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
{
perror("socket() failed");
LOG_ERROR("socket failed");
return -1;
}
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin6_family = AF_INET6;
serveraddr.sin6_port = htons(port);
serveraddr.sin6_addr = in6addr_any;
int reuse = 1;
#ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed");
LOG_ERROR("setsocketerror");
}
#endif
#ifdef SO_REUSEPORT
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEPORT) failed");
my_printfError("setsockopt(SO_REUSEPORT) failed");
LOG_ERROR("setsocketerror");
}
#endif
// Retry bind if fails with EADDRINUSE
for (int i = 0; i < max_retries; i++)
{
returnCode = bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (returnCode == 0)
{
if(i > 0)
printf("\n Success After: %d attempts", i);
break;
}
if (errno == EADDRINUSE)
{
my_printf("Bind failed with EADDRINUSE on port: %d, retrying %d/%d...\n",port, i + 1, max_retries);
sleep(retry_delay_sec); // wait before retrying
}
else
{
// Other bind errors: fail immediately
perror("bind() failed");
LOG_ERROR("bind failed");
close(sock);
return -1;
}
}
if (returnCode != 0)
{
my_printf("Bind failed after %d retries, errno=%d\n", max_retries, errno);
LOGF("%sBind failed after %d retries, errno=%d\n", LOG_ERROR_PREFIX, max_retries, errno);
close(sock);
return -1;
}
// Listen
returnCode = listen(sock, 1);
if (returnCode == -1)
{
LOG_ERROR("listen failed");
my_printf("\nCould not listen %d errno = %d", sock, errno);
if (sock != -1)
close(sock);
return -1;
}
return sock;
}
#else
int isPortInUse(int port) {
int sockfd;
struct sockaddr_in addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
return 1; // Assume port is in use if we can't create a socket
}
int reuse = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
close(sockfd); // Always close after test
if (result == 0) {
return 0; // Port is free
} else if (errno == EADDRINUSE) {
return 1; // Port is in use
} else {
perror("bind");
return 1; // Other error, treat as in-use
}
}
int createSocket(ftpDataType * ftpData) int createSocket(ftpDataType * ftpData)
{ {
//my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port); //my_printf("\nCreating main socket on port %d", ftpData->ftpParameters.port);
@ -369,7 +606,7 @@ int createSocket(ftpDataType * ftpData)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("socketopt failed", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("socketopt failed");
} }
#endif #endif
@ -379,7 +616,7 @@ int createSocket(ftpDataType * ftpData)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("setsocket error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("setsocket error");
} }
#endif #endif
//Bind socket //Bind socket
@ -409,82 +646,162 @@ int createSocket(ftpDataType * ftpData)
int createPassiveSocket(int port) int createPassiveSocket(int port)
{ {
int sock, returnCode; int sock, returnCode;
struct sockaddr_in temp; struct sockaddr_in serveraddr;
int max_retries = 12; // number of bind retries
int retry_delay_sec = 1; // delay between retries
//Socket creation if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
sock = socket(AF_INET, SOCK_STREAM, 0); {
if (sock == -1) perror("socket() failed");
{ LOG_ERROR("socket failed");
return -1; return -1;
} }
temp.sin_family = AF_INET; memset(&serveraddr, 0, sizeof(serveraddr));
temp.sin_addr.s_addr = INADDR_ANY; serveraddr.sin_family = AF_INET;
temp.sin_port = htons(port); serveraddr.sin_port = htons(port);
serveraddr.sin_addr.s_addr = INADDR_ANY;
int reuse = 1;
#ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed");
LOG_ERROR("setsocketerror");
}
#endif
#ifdef SO_REUSEPORT
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
{
perror("setsockopt(SO_REUSEPORT) failed");
my_printfError("setsockopt(SO_REUSEPORT) failed");
LOG_ERROR("setsocketerror");
}
#endif
// Retry bind if it fails with EADDRINUSE
for (int i = 0; i < max_retries; i++)
{
returnCode = bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (returnCode == 0)
{
if (i > 0)
printf("\n Success After: %d attempts", i);
break;
}
if (errno == EADDRINUSE)
{
my_printf("Bind failed with EADDRINUSE on port: %d, retrying %d/%d...\n", port, i + 1, max_retries);
sleep(retry_delay_sec);
}
else
{
perror("bind() failed");
LOG_ERROR("bind failed");
close(sock);
return -1;
}
}
if (returnCode != 0)
{
my_printf("bind failed after %d retries, errno=%d\n", max_retries, errno);
LOGF("%sbind failed after %d retries, errno=%d\n", LOG_ERROR_PREFIX, max_retries, errno);
close(sock);
return -1;
}
// Start listening
returnCode = listen(sock, 1);
if (returnCode == -1)
{
LOG_ERROR("listen failed");
my_printf("\nCould not listen %d errno = %d", sock, errno);
close(sock);
return -1;
}
return sock;
}
#endif
#ifdef IPV6_ENABLED
int createActiveSocketV6(int port, char *ipAddress)
{
int sockfd;
struct sockaddr_in6 serv_addr6;
struct sockaddr *serv_addr_any;
// Creating socket
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
{
my_printfError("Socket creation failed");
LOG_ERROR("Socket creation failed");
return -1;
}
int reuse = 1; int reuse = 1;
#ifdef SO_REUSEADDR #ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("setsocketerror", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("set socket error");
} }
#endif #endif
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("set socket error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("setsockopt error");
} }
#endif #endif
//Bind socket // Prepare the sockaddr structure
returnCode = bind(sock,(struct sockaddr*) &temp,sizeof(temp)); if (inet_pton(AF_INET6, ipAddress, &serv_addr6.sin6_addr) == 1)
{
serv_addr6.sin6_family = AF_INET6;
serv_addr6.sin6_port = htons(port);
serv_addr_any = (struct sockaddr *)&serv_addr6;
}
else
{
my_printfError("Invalid ip address");
LOG_ERROR("Invalid ip address");
return -1;
}
if (returnCode == -1) // Connect to server
{ if (connect(sockfd, serv_addr_any, sizeof(serv_addr6)) < 0)
my_printf("\n Could not bind %d errno = %d", sock, errno); {
my_printfError("Connection failed");
LOG_ERROR("Connection failed");
return -1;
}
if (sock != -1) return sockfd;
{
close(sock);
}
return returnCode;
}
//Number of client allowed
returnCode = listen(sock, 1);
if (returnCode == -1)
{
my_printf("\n Could not listen %d errno = %d", sock, errno);
if (sock != -1)
{
close(sock);
}
return returnCode;
}
return sock;
} }
#endif
int createActiveSocket(int port, char *ipAddress) int createActiveSocket(int port, char *ipAddress)
{ {
int sockfd; int sockfd;
struct sockaddr_in serv_addr; struct sockaddr_in serv_addr;
//my_printf("\n Connection socket is going to start ip: %s:%d \n", ipAddress, port); my_printf("\n Connection socket is going to start ip: %s:%d \n", ipAddress, port);
memset(&serv_addr, 0, sizeof(struct sockaddr_in)); memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port); serv_addr.sin_port = htons(port);
if(inet_pton(AF_INET, ipAddress, &serv_addr.sin_addr)<=0) if(inet_pton(AF_INET, ipAddress, &serv_addr.sin_addr)<=0)
{ {
my_printf("\n inet_pton error occured\n"); my_printf("\n inet_pton error occured at address: %s:%d\n", ipAddress, port);
return -1; return -1;
} }
@ -505,7 +822,7 @@ int createActiveSocket(int port, char *ipAddress)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("set socket error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("set socket error");
} }
#endif #endif
@ -514,7 +831,7 @@ int createActiveSocket(int port, char *ipAddress)
{ {
perror("setsockopt(SO_REUSEADDR) failed"); perror("setsockopt(SO_REUSEADDR) failed");
my_printfError("setsockopt(SO_REUSEADDR) failed"); my_printfError("setsockopt(SO_REUSEADDR) failed");
addLog("setsockopt error", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("setsockopt error");
} }
#endif #endif
@ -623,7 +940,7 @@ void closeClient(ftpDataType * ftpData, int processingSocket)
if (ftpData->clients[processingSocket].workerData.threadIsAlive == 1) if (ftpData->clients[processingSocket].workerData.threadIsAlive == 1)
{ {
cancelWorker(ftpData, processingSocket); handleThreadReuse(ftpData, processingSocket);
} }
FD_CLR(ftpData->clients[processingSocket].socketDescriptor, &ftpData->connectionData.rsetAll); FD_CLR(ftpData->clients[processingSocket].socketDescriptor, &ftpData->connectionData.rsetAll);
@ -654,7 +971,7 @@ void checkClientConnectionTimeout(ftpDataType * ftpData)
(int)time(NULL) - ftpData->clients[processingSock].lastActivityTimeStamp > ftpData->ftpParameters.maximumIdleInactivity) (int)time(NULL) - ftpData->clients[processingSock].lastActivityTimeStamp > ftpData->ftpParameters.maximumIdleInactivity)
{ {
ftpData->clients[processingSock].closeTheClient = 1; ftpData->clients[processingSock].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_DEBUG("timeout, closing the connection for inactivity");
} }
} }
} }
@ -713,6 +1030,139 @@ int getAvailableClientSocketIndex(ftpDataType * ftpData)
return -1; return -1;
} }
#ifdef IPV6_ENABLED
#warning IPV6 IS ENABLED
int evaluateClientSocketConnection(ftpDataType * ftpData)
{
char str[INET6_ADDRSTRLEN];
if (FD_ISSET(ftpData->connectionData.theMainSocket, &ftpData->connectionData.rset))
{
int availableSocketIndex;
if ((availableSocketIndex = getAvailableClientSocketIndex(ftpData)) != -1) //get available socket
{
if ((ftpData->clients[availableSocketIndex].socketDescriptor = accept(ftpData->connectionData.theMainSocket, (struct sockaddr *)&ftpData->clients[availableSocketIndex].client_sockaddr_in, (socklen_t*)&ftpData->clients[availableSocketIndex].sockaddr_in_size)) !=- 1)
{
int error, numberOfConnectionFromSameIp, i;
numberOfConnectionFromSameIp = 0;
ftpData->connectedClients++;
ftpData->clients[availableSocketIndex].socketIsConnected = 1;
error = fcntl(ftpData->clients[availableSocketIndex].socketDescriptor, F_SETFL, O_NONBLOCK);
fdAdd(ftpData, availableSocketIndex);
// - - //
ftpData->clients[availableSocketIndex].sockaddr_in_server_size = sizeof(ftpData->clients[availableSocketIndex].server_sockaddr_in);
ftpData->clients[availableSocketIndex].sockaddr_in_size = sizeof(ftpData->clients[availableSocketIndex].client_sockaddr_in);
getpeername(ftpData->clients[availableSocketIndex].socketDescriptor, (struct sockaddr *)&ftpData->clients[availableSocketIndex].client_sockaddr_in, &ftpData->clients[availableSocketIndex].sockaddr_in_size);
if(inet_ntop(AF_INET6, &ftpData->clients[availableSocketIndex].client_sockaddr_in.sin6_addr, ftpData->clients[availableSocketIndex].clientIpAddress, sizeof(ftpData->clients[availableSocketIndex].clientIpAddress)))
{
ftpData->clients[availableSocketIndex].clientPort = (int) ntohs(ftpData->clients[availableSocketIndex].client_sockaddr_in.sin6_port);
}
getsockname(ftpData->clients[availableSocketIndex].socketDescriptor, (struct sockaddr *)&ftpData->clients[availableSocketIndex].server_sockaddr_in, &ftpData->clients[availableSocketIndex].sockaddr_in_server_size);
if(inet_ntop(AF_INET6, &ftpData->clients[availableSocketIndex].server_sockaddr_in.sin6_addr, ftpData->clients[availableSocketIndex].serverIpAddress, sizeof(ftpData->clients[availableSocketIndex].serverIpAddress)))
{
;
}
if (is_ipv4_mapped_ipv6(ftpData->clients[availableSocketIndex].clientIpAddress))
{
sscanf (ftpData->clients[availableSocketIndex].serverIpAddress,"::ffff:%d.%d.%d.%d", &ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[0],
&ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[1],
&ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[2],
&ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[3]);
}
else
{
;
}
// Check if it's an IPv4-mapped address
if (is_ipv4_mapped_ipv6(ftpData->clients[availableSocketIndex].clientIpAddress))
{
ftpData->clients[availableSocketIndex].isIpV6 = 0;
}
else
{
ftpData->clients[availableSocketIndex].isIpV6 = 1;
}
ftpData->clients[availableSocketIndex].connectionTimeStamp = (int)time(NULL);
ftpData->clients[availableSocketIndex].lastActivityTimeStamp = (int)time(NULL);
for (i = 0; i <ftpData->ftpParameters.maxClients; i++)
{
if (i == availableSocketIndex)
{
continue;
}
if (strcmp(ftpData->clients[availableSocketIndex].clientIpAddress, ftpData->clients[i].clientIpAddress) == 0) {
numberOfConnectionFromSameIp++;
}
}
if (ftpData->ftpParameters.maximumConnectionsPerIp > 0 &&
numberOfConnectionFromSameIp >= ftpData->ftpParameters.maximumConnectionsPerIp)
{
int theReturnCode = socketPrintf(ftpData, availableSocketIndex, "sss", "530 too many connection from your ip address ", ftpData->clients[availableSocketIndex].clientIpAddress, " \r\n");
ftpData->clients[availableSocketIndex].closeTheClient = 1;
LOGF("%stoo many connection from ip address: %s maximum allowed: %d", LOG_SECURITY_PREFIX, ftpData->clients[availableSocketIndex].clientIpAddress, ftpData->ftpParameters.maximumConnectionsPerIp);
}
else
{
int returnCode = socketPrintf(ftpData, availableSocketIndex, "s", ftpData->welcomeMessage);
if (returnCode <= 0)
{
ftpData->clients[availableSocketIndex].closeTheClient = 1;
LOG_ERROR("socketPrintf");
}
}
return 1;
}
else
{
//Errors while accepting, socket will be closed
ftpData->clients[availableSocketIndex].closeTheClient = 1;
LOG_ERROR("Errors while accepting, socket will be closed");
//my_printf("\n2 Errno = %d", errno);
return 1;
}
}
else
{
int socketRefuseFd;
struct sockaddr_in6 socketRefuse_sockaddr_in;
socklen_t socketRefuse_in_size = sizeof(socketRefuse_sockaddr_in);
if ((socketRefuseFd = accept(ftpData->connectionData.theMainSocket, (struct sockaddr *)&socketRefuse_sockaddr_in, &socketRefuse_in_size))!=-1)
{
int theReturnCode = 0;
char *messageToWrite = "10068 Server reached the maximum number of connection, please try later.\r\n";
write(socketRefuseFd, messageToWrite, strlen(messageToWrite));
shutdown(socketRefuseFd, SHUT_RDWR);
theReturnCode = close(socketRefuseFd);
}
return 0;
}
}
else
{
//No new socket
return 0;
}
}
#else
int evaluateClientSocketConnection(ftpDataType * ftpData) int evaluateClientSocketConnection(ftpDataType * ftpData)
{ {
if (FD_ISSET(ftpData->connectionData.theMainSocket, &ftpData->connectionData.rset)) if (FD_ISSET(ftpData->connectionData.theMainSocket, &ftpData->connectionData.rset))
@ -739,10 +1189,10 @@ int evaluateClientSocketConnection(ftpDataType * ftpData)
//my_printf("\n Server IP: %s", ftpData->clients[availableSocketIndex].serverIpAddress); //my_printf("\n Server IP: %s", ftpData->clients[availableSocketIndex].serverIpAddress);
//my_printf("Server: New client connected with id: %d", availableSocketIndex); //my_printf("Server: New client connected with id: %d", availableSocketIndex);
//my_printf("\nServer: Clients connected: %d", ftpData->connectedClients); //my_printf("\nServer: Clients connected: %d", ftpData->connectedClients);
sscanf (ftpData->clients[availableSocketIndex].serverIpAddress,"%d.%d.%d.%d", &ftpData->clients[availableSocketIndex].serverIpAddressInteger[0], sscanf (ftpData->clients[availableSocketIndex].serverIpAddress,"%d.%d.%d.%d", &ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[0],
&ftpData->clients[availableSocketIndex].serverIpAddressInteger[1], &ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[1],
&ftpData->clients[availableSocketIndex].serverIpAddressInteger[2], &ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[2],
&ftpData->clients[availableSocketIndex].serverIpAddressInteger[3]); &ftpData->clients[availableSocketIndex].serverIpV4AddressInteger[3]);
inet_ntop(AF_INET, inet_ntop(AF_INET,
&(ftpData->clients[availableSocketIndex].client_sockaddr_in.sin_addr), &(ftpData->clients[availableSocketIndex].client_sockaddr_in.sin_addr),
@ -771,7 +1221,8 @@ int evaluateClientSocketConnection(ftpDataType * ftpData)
{ {
int theReturnCode = socketPrintf(ftpData, availableSocketIndex, "sss", "530 too many connection from your ip address ", ftpData->clients[availableSocketIndex].clientIpAddress, " \r\n"); int theReturnCode = socketPrintf(ftpData, availableSocketIndex, "sss", "530 too many connection from your ip address ", ftpData->clients[availableSocketIndex].clientIpAddress, " \r\n");
ftpData->clients[availableSocketIndex].closeTheClient = 1; ftpData->clients[availableSocketIndex].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); char
LOGF("%sToo many connection from %s max per ip is %d", LOG_SECURITY_PREFIX, ftpData->clients[availableSocketIndex].clientIpAddress, ftpData->ftpParameters.maximumConnectionsPerIp);
} }
else else
{ {
@ -779,7 +1230,7 @@ int evaluateClientSocketConnection(ftpDataType * ftpData)
if (returnCode <= 0) if (returnCode <= 0)
{ {
ftpData->clients[availableSocketIndex].closeTheClient = 1; ftpData->clients[availableSocketIndex].closeTheClient = 1;
addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("socketPrintf");
} }
} }
@ -789,7 +1240,7 @@ int evaluateClientSocketConnection(ftpDataType * ftpData)
{ {
//Errors while accepting, socket will be closed //Errors while accepting, socket will be closed
ftpData->clients[availableSocketIndex].closeTheClient = 1; ftpData->clients[availableSocketIndex].closeTheClient = 1;
//addLog("Closing the client", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_ERROR("Errors while accepting, socket will be closed");
//my_printf("\n2 Errno = %d", errno); //my_printf("\n2 Errno = %d", errno);
return 1; return 1;
} }
@ -817,3 +1268,118 @@ int evaluateClientSocketConnection(ftpDataType * ftpData)
return 0; return 0;
} }
} }
#endif
#ifdef OPENSSL_ENABLED
int acceptSSLConnection(int theSocketId, ftpDataType * ftpData)
{
SSL *ssl = ftpData->clients[theSocketId].workerData.serverSsl;
int sockfd = ftpData->clients[theSocketId].workerData.socketConnection;
my_printf("\nSSL SSL_set_fd start");
int rc = SSL_set_fd(ssl, sockfd);
if (rc == 0)
{
my_printf("\nSSL ERRORS ON SSL_set_fd");
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("Closing client SSL_set_fd");
return -1;
}
my_printf("\nSSL SSL_set_fd end");
int flags = fcntl(sockfd, F_GETFL, 0);
if (flags == -1)
{
perror("fcntl get flags");
ftpData->clients[theSocketId].closeTheClient = 1;
return -1;
}
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
{
perror("fcntl set nonblocking");
ftpData->clients[theSocketId].closeTheClient = 1;
return -1;
}
my_printf("\nSSL accept start");
// Reuse the session from control connection
SSL_SESSION *session = SSL_get_session(ftpData->clients[theSocketId].ssl);
if (session != NULL)
{
unsigned int len;
const unsigned char *id = SSL_SESSION_get_id(session, &len);
my_printf("Trying to reuse SSL Session ID: ");
for (unsigned int i = 0; i < len; i++) {
my_printf("\n%02X", id[i]);
}
my_printf("\n");
SSL_set_session(ssl, session);
} else {
my_printf("\nNo session available for reuse. Accepting fresh handshake.\n");
}
SSL_set_accept_state(ssl);
int max_attempts = 500; // 500*10ms = 5 sec timeout
while (max_attempts--)
{
rc = SSL_accept(ssl);
if (rc == 1)
{
my_printf("\n------------------------------------------- SSL_accept success");
break;
}
int err = SSL_get_error(ssl, rc);
//my_printf("\nSSL_accept err: %d\n", err);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
{
usleep(10000); // 10 ms
//my_printf("\nSSL_accept waiting ...");
continue;
}
else
{
my_printf("\n-------------------------------------------SSL_accept failed:");
ERR_print_errors_fp(stderr);
ftpData->clients[theSocketId].closeTheClient = 1;
LOG_ERROR("Closing client SSL_accept");
return -1;
}
}
if (max_attempts <= 0)
{
my_printf("\nSSL_accept timeout");
ftpData->clients[theSocketId].closeTheClient = 1;
return -1;
}
if (SSL_session_reused(ssl)) {
my_printf("\n**** FTPS data connection reused control TLS session.\n");
} else {
my_printf("\n**** FTPS data connection did NOT reuse TLS session.\n");
}
if (fcntl(sockfd, F_SETFL, flags) == -1)
{
perror("fcntl set blocking");
ftpData->clients[theSocketId].closeTheClient = 1;
return -1;
}
return 1;
}
#endif

View File

@ -36,6 +36,15 @@ int getMaximumSocketFd(int mainSocket, ftpDataType * data);
int createSocket(ftpDataType * ftpData); int createSocket(ftpDataType * ftpData);
int createPassiveSocket(int port); int createPassiveSocket(int port);
int createActiveSocket(int port, char *ipAddress); int createActiveSocket(int port, char *ipAddress);
#ifdef IPV6_ENABLED
int createActiveSocketV6(int port, char *ipAddress);
#endif
#ifdef OPENSSL_ENABLED
int acceptSSLConnection(int theSocketId, ftpDataType * ftpData);
#endif
void fdInit(ftpDataType * ftpData); void fdInit(ftpDataType * ftpData);
void fdAdd(ftpDataType * ftpData, int index); void fdAdd(ftpDataType * ftpData, int index);
void fdRemove(ftpDataType * ftpData, int index); void fdRemove(ftpDataType * ftpData, int index);
@ -51,7 +60,6 @@ int evaluateClientSocketConnection(ftpDataType * ftpData);
int socketPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...); int socketPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...);
int socketWorkerPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...); int socketWorkerPrintf(ftpDataType * ftpData, int clientId, const char *__restrict __fmt, ...);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -37,7 +37,10 @@ void DYNMEM_Init(void)
unsigned long long int DYNMEM_GetTotalMemory(void) unsigned long long int DYNMEM_GetTotalMemory(void)
{ {
return theTotalMemory; pthread_mutex_lock(&memoryCountMutex);
unsigned long long int mem = theTotalMemory;
pthread_mutex_unlock(&memoryCountMutex);
return mem;
} }
unsigned long long int DYNMEM_IncreaseMemoryCounter(unsigned long long int theSize) unsigned long long int DYNMEM_IncreaseMemoryCounter(unsigned long long int theSize)
@ -79,7 +82,8 @@ void *DYNMEM_malloc(size_t bytes, DYNMEM_MemoryTable_DataType **memoryListHead,
newItem->size = bytes; newItem->size = bytes;
newItem->nextElement = NULL; newItem->nextElement = NULL;
newItem->previousElement = NULL; newItem->previousElement = NULL;
strncpy(newItem->theName, theName, 20); strncpy(newItem->theName, theName, sizeof(newItem->theName) - 1);
newItem->theName[sizeof(newItem->theName) - 1] = '\0';
if( (*memoryListHead) != NULL) if( (*memoryListHead) != NULL)
{ {
@ -140,7 +144,6 @@ void *DYNMEM_realloc(void *theMemoryAddress, size_t bytes, DYNMEM_MemoryTable_Da
//strcpy(theData, "NOOOOOOOOOOOOOOOO"); //strcpy(theData, "NOOOOOOOOOOOOOOOO");
report_error_q("Unable to reallocate memory not previously allocated",__FILE__,__LINE__, 0); report_error_q("Unable to reallocate memory not previously allocated",__FILE__,__LINE__, 0);
free(newMemory);
// Report this as an error // Report this as an error
return NULL; return NULL;
} }
@ -238,3 +241,27 @@ void DYNMEM_freeAll(DYNMEM_MemoryTable_DataType **memoryListHead)
(*memoryListHead) = temp; (*memoryListHead) = temp;
} }
} }
void DYNMEM_dump(DYNMEM_MemoryTable_DataType *memoryListHead)
{
int count = 0;
unsigned long long int total = 0;
my_printf("\n==== DYNMEM Memory Dump ====\n");
for (DYNMEM_MemoryTable_DataType *current = memoryListHead; current != NULL; current = current->nextElement)
{
my_printf("Block %d:\n", count + 1);
my_printf(" Address : %p\n", current->address);
my_printf(" Size : %zu bytes\n", current->size);
my_printf(" Label : %s\n", current->theName);
my_printf(" Block MetaSize: %zu bytes\n", sizeof(DYNMEM_MemoryTable_DataType));
total += current->size + sizeof(DYNMEM_MemoryTable_DataType);
count++;
}
my_printf("\nTotal blocks : %d\n", count);
my_printf("Total memory used : %llu bytes (including metadata)\n", total);
my_printf("Global counter : %llu bytes\n", DYNMEM_GetTotalMemory());
my_printf("=============================\n");
}

View File

@ -26,6 +26,6 @@ void *DYNMEM_malloc(size_t bytes, DYNMEM_MemoryTable_DataType ** memoryListHead,
void *DYNMEM_realloc(void *theMemoryAddress, size_t bytes, DYNMEM_MemoryTable_DataType **memoryListHead); void *DYNMEM_realloc(void *theMemoryAddress, size_t bytes, DYNMEM_MemoryTable_DataType **memoryListHead);
void DYNMEM_free(void *f_address, DYNMEM_MemoryTable_DataType ** memoryListHead); void DYNMEM_free(void *f_address, DYNMEM_MemoryTable_DataType ** memoryListHead);
void DYNMEM_freeAll(DYNMEM_MemoryTable_DataType ** memoryListHead); void DYNMEM_freeAll(DYNMEM_MemoryTable_DataType ** memoryListHead);
void DYNMEM_dump(DYNMEM_MemoryTable_DataType *memoryListHead);
#endif /* LIBRARY_DYNAMICMEMORY_H_ */ #endif /* LIBRARY_DYNAMICMEMORY_H_ */

View File

@ -204,7 +204,7 @@ int FILE_IsLink( char* path)
} }
/* Check if a file is valid */ /* Check if a file is valid */
int FILE_IsFile(const char *TheFileName, int checkExist) int FILE_IsFile(char *TheFileName, int checkExist)
{ {
FILE *TheFile; FILE *TheFile;
@ -257,23 +257,23 @@ void FILE_GetDirectoryInodeList(char * DirectoryInodeName, char *** InodeList, i
// //
if ((dir->d_name[0] == '.' && dir->d_name[1] == '.' && strnlen(dir->d_name, 3) == 2) && (commandOps == NULL || commandOps[0] != 'a')) if ((dir->d_name[0] == '.' && dir->d_name[1] == '.' && strnlen(dir->d_name, 3) == 2) && (commandOps == NULL || commandOps[0] != 'a'))
continue; continue;
//Skips all files and dir starting with . //Skips all files and dir starting with .
if ((dir->d_name[0] == '.' && commandOps == NULL) || (dir->d_name[0] == '.' && commandOps[0] != 'a' && commandOps[0] != 'A')) if ((dir->d_name[0] == '.' && commandOps == NULL) || (dir->d_name[0] == '.' && commandOps[0] != 'a' && commandOps[0] != 'A'))
continue; continue;
char *thePathToCheck[PATH_MAX]; char thePathToCheck[PATH_MAX];
memset(thePathToCheck, 0, PATH_MAX); memset(thePathToCheck, 0, PATH_MAX);
strcpy(thePathToCheck, DirectoryInodeName); strcpy(thePathToCheck, DirectoryInodeName);
strcat(thePathToCheck, "/"); strcat(thePathToCheck, "/");
strcat(thePathToCheck, dir->d_name); strcat(thePathToCheck, dir->d_name);
printf("\n ************* thePathToCheck = %s", thePathToCheck);
if (checkIfInodeExist == 1 && FILE_CheckIfLinkExist(thePathToCheck) == 0) if (checkIfInodeExist == 1 && FILE_CheckIfLinkExist(thePathToCheck) == 0)
{ {
printf("--> Not valid!");
continue; continue;
} }
@ -341,7 +341,7 @@ int FILE_GetDirectoryInodeCount(char * DirectoryInodeName)
continue; continue;
if ( dir->d_name[0] == '.' && dir->d_name[1] == '.' && strnlen(dir->d_name, 3) == 2) if ( dir->d_name[0] == '.' && dir->d_name[1] == '.' && strnlen(dir->d_name, 3) == 2)
continue; continue;
FileAndFolderIndex++; FileAndFolderIndex++;
@ -749,8 +749,7 @@ char * FILE_GetGroupOwner(char *fileName, DYNMEM_MemoryTable_DataType **memoryTa
return toReturn; return toReturn;
} }
void FILE_AppendStringToFile(char *fileName, char *theString)
char * FILE_AppendStringToFile(char *fileName, char *theString)
{ {
FILE *fp = fopen(fileName, "a"); FILE *fp = fopen(fileName, "a");
if (fp == NULL) if (fp == NULL)
@ -758,7 +757,7 @@ char * FILE_AppendStringToFile(char *fileName, char *theString)
my_printfError("\nError while opening file %s.", fileName); my_printfError("\nError while opening file %s.", fileName);
} }
fprintf(fp, "\n%s", theString); fprintf(fp, "\n%s", theString);
fclose(fp); fclose(fp);
} }

View File

@ -58,7 +58,7 @@
long long int FILE_GetFileSize(FILE *theFilePointer); long long int FILE_GetFileSize(FILE *theFilePointer);
long int FILE_GetAvailableSpace(const char* ThePath); long int FILE_GetAvailableSpace(const char* ThePath);
long long int FILE_GetFileSizeFromPath(char *TheFileName); long long int FILE_GetFileSizeFromPath(char *TheFileName);
int FILE_IsFile(const char *theFileName, int checkExist); int FILE_IsFile(char *theFileName, int checkExist);
int FILE_IsDirectory (char *directory_path, int checkExist); int FILE_IsDirectory (char *directory_path, int checkExist);
int FILE_IsLink (char *directory_path); int FILE_IsLink (char *directory_path);
void FILE_GetDirectoryInodeList(char * DirectoryInodeName, char *** InodeList, int * filesandfolders, int recursive, char* commandOps, int checkIfInodeExist, DYNMEM_MemoryTable_DataType ** memoryTable); void FILE_GetDirectoryInodeList(char * DirectoryInodeName, char *** InodeList, int * filesandfolders, int recursive, char* commandOps, int checkIfInodeExist, DYNMEM_MemoryTable_DataType ** memoryTable);
@ -71,7 +71,7 @@
char * FILE_GetListPermissionsString(char *file, DYNMEM_MemoryTable_DataType ** memoryTable); char * FILE_GetListPermissionsString(char *file, DYNMEM_MemoryTable_DataType ** memoryTable);
char * FILE_GetOwner(char *fileName, DYNMEM_MemoryTable_DataType ** memoryTable); char * FILE_GetOwner(char *fileName, DYNMEM_MemoryTable_DataType ** memoryTable);
char * FILE_GetGroupOwner(char *fileName, DYNMEM_MemoryTable_DataType ** memoryTable); char * FILE_GetGroupOwner(char *fileName, DYNMEM_MemoryTable_DataType ** memoryTable);
char * FILE_AppendStringToFile(char *fileName, char *theString); void FILE_AppendStringToFile(char *fileName, char *theString);
time_t FILE_GetLastModifiedData(char *path); time_t FILE_GetLastModifiedData(char *path);
void FILE_AppendToString(char ** sourceString, char *theString, DYNMEM_MemoryTable_DataType ** memoryTable); void FILE_AppendToString(char ** sourceString, char *theString, DYNMEM_MemoryTable_DataType ** memoryTable);
void FILE_DirectoryToParent(char ** sourceString, DYNMEM_MemoryTable_DataType ** memoryTable); void FILE_DirectoryToParent(char ** sourceString, DYNMEM_MemoryTable_DataType ** memoryTable);

View File

@ -1,308 +1,170 @@
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <time.h> #include <time.h>
#include <semaphore.h> #include <semaphore.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <ctype.h> #include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <stdarg.h>
#include "log.h" #include "log.h"
#include "../debugHelper.h" #include "../debugHelper.h"
#include "dynamicVectors.h" #include "dynamicVectors.h"
#include "fileManagement.h" #include "fileManagement.h"
#define LOG_LINE_SIZE 1024 + PATH_MAX #define LOG_LINE_SIZE (1024 + PATH_MAX)
#define LOG_FILENAME_PREFIX "uftpLog_" #define LOG_FILENAME_PREFIX "uftpLog_"
#define MAX_FILENAME_LENGTH 256
static void logThread(void * arg); static void* logThread(void* arg);
static int deleteOldLogs(const char* folderPath, int daysToKeep);
static long long getDateNumeric(const char* str);
static DYNV_VectorString_DataType logQueue; static DYNV_VectorString_DataType logQueue;
static DYNV_VectorString_DataType workerQueue; static DYNV_VectorString_DataType workerQueue;
static sem_t logsem; // Semaphore for controlling log to write
static pthread_t pLogThread; static sem_t logSem;
static pthread_mutex_t mutex; static pthread_t logThreadId;
static pthread_mutex_t logMutex = PTHREAD_MUTEX_INITIALIZER;
static int logFilesNumber; static int maxLogFiles = 0;
static char logFolder[PATH_MAX]; static char logFolder[PATH_MAX] = {0};
#define MAX_FILENAME_LENGTH 256 // Convert YYYY-MM-DD to comparable numeric
static long long getDateNumeric(const char* str) {
if (strlen(str) != 10 || str[4] != '-' || str[7] != '-') return 0;
char year[5] = {0}, month[3] = {0}, day[3] = {0};
strncpy(year, str, 4);
strncpy(month, str + 5, 2);
strncpy(day, str + 8, 2);
static long long is_date_format(const char* str); return atoll(year) * 365 + (atoll(month) - 1) * 31 + atoll(day);
static int delete_old_logs(const char* folder_path, int days_to_keep); }
static long long is_date_format(const char* str) static int deleteOldLogs(const char* folderPath, int daysToKeep) {
{ DIR* dir = opendir(folderPath);
char year[5]; if (!dir) {
char month[3]; perror("opendir");
char day[3]; return -1;
}
memset(year, 0, 5); time_t now = time(NULL);
memset(month, 0, 3); struct tm* today = localtime(&now);
memset(day, 0, 3); char todayStr[11];
strftime(todayStr, sizeof(todayStr), "%Y-%m-%d", today);
long long todayNumeric = getDateNumeric(todayStr);
if (strlen(str) != 10 || str[4] != '-' || str[7] != '-') struct dirent* entry;
{ char filePath[PATH_MAX];
struct stat fileStat;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type != DT_REG) continue;
if (strncmp(entry->d_name, LOG_FILENAME_PREFIX, strlen(LOG_FILENAME_PREFIX)) != 0) continue;
snprintf(filePath, sizeof(filePath), "%s%s", folderPath, entry->d_name);
if (stat(filePath, &fileStat) != 0) continue;
long long fileDate = getDateNumeric(entry->d_name + strlen(LOG_FILENAME_PREFIX));
if (fileDate > 0 && (fileDate + daysToKeep < todayNumeric)) {
my_printf("\nRemoving old log file: %s", filePath);
remove(filePath);
}
}
closedir(dir);
return 0; return 0;
}
// Check for valid digits in year, month, and day components
for (int i = 0; i < 4; i++)
{
if (!isdigit(str[i])) {
return 0;
}
year[i] = str[i];
}
for (int i = 5; i < 7; i++) {
if (!isdigit(str[i])) {
return 0;
}
}
for (int i = 8; i < 10; i++) {
if (!isdigit(str[i])) {
return 0;
}
}
month[0] = str[5];
month[1] = str[6];
day[0] = str[8];
day[1] = str[9];
return atoll(year)*365+(atoll(month)-1)*31+atoll(day);
} }
static int delete_old_logs(const char* folder_path, int days_to_keep) static void* logThread(void* arg) {
{ int lastDay = -1;
unsigned long long n_of_day_file;
unsigned long long n_of_day_today;
struct stat statbuf; while (1) {
DIR* dir; sem_wait(&logSem);
struct dirent* entry;
char full_path[PATH_MAX];
dir = opendir(folder_path);
if (dir == NULL)
{
perror("opendir");
return 1;
}
time_t now = time(NULL);
struct tm *info = localtime(&now);
char timeToday[11];
if (strftime(timeToday, sizeof(timeToday), "%Y-%m-%d", info) == 0)
{
my_printfError("strftime error");
return;
}
n_of_day_today = is_date_format(timeToday);
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue; // Skip . and .. entries
}
snprintf(full_path, sizeof(full_path), "%s%s", folder_path, entry->d_name);
if (stat(full_path, &statbuf) == -1)
{
perror("stat");
continue;
}
if (!S_ISREG(statbuf.st_mode))
{
continue; // Not a regular file
}
if (strncmp(entry->d_name, LOG_FILENAME_PREFIX, strlen(LOG_FILENAME_PREFIX)) != 0)
{
continue; // Not a log file
}
n_of_day_file = is_date_format(entry->d_name + strlen(LOG_FILENAME_PREFIX));
if (!n_of_day_file)
{
continue; // Invalid date format
}
if (n_of_day_file+days_to_keep < n_of_day_today)
{
my_printf("\nRemoving old log file: %s", full_path);
// File is older than specified days
if (remove(full_path) == -1)
{
perror("remove");
continue;
}
}
}
closedir(dir);
return 0;
}
// STATIC SECTION
static void logThread(void * arg)
{
int lastDay;
while(1)
{
if (sem_wait(&logsem) == 0)
{
char theLogFilename[PATH_MAX];
int day = 0;
// write the logs to the file
time_t now = time(NULL); time_t now = time(NULL);
struct tm *info = localtime(&now); struct tm* tm_now = localtime(&now);
char logName[50];
char dayString[50];
memset(theLogFilename, 0, PATH_MAX); char dateStr[11], logFilePath[PATH_MAX];
strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", tm_now);
snprintf(logFilePath, sizeof(logFilePath), "%s%s%s", logFolder, LOG_FILENAME_PREFIX, dateStr);
if (strftime(dayString, sizeof(dayString), "%d", info) == 0) int currentDay = tm_now->tm_mday;
{ if (currentDay != lastDay) {
my_printfError("strftime error"); deleteOldLogs(logFolder, maxLogFiles);
return; lastDay = currentDay;
} }
day = atoi(dayString); pthread_mutex_lock(&logMutex);
for (int i = 0; i < logQueue.Size; ++i) {
if (day != lastDay) workerQueue.PushBack(&workerQueue, logQueue.Data[i], strnlen(logQueue.Data[i], LOG_LINE_SIZE));
{
delete_old_logs(logFolder, logFilesNumber);
lastDay = day;
} }
while (logQueue.Size > 0) logQueue.PopBack(&logQueue);
pthread_mutex_unlock(&logMutex);
if (strftime(logName, sizeof(logName), LOG_FILENAME_PREFIX"%Y-%m-%d", info) == 0) for (int i = 0; i < workerQueue.Size; ++i) {
{ FILE_AppendStringToFile(logFilePath, workerQueue.Data[i]);
my_printfError("strftime error");
return;
}
strncpy(theLogFilename, logFolder, PATH_MAX);
strncat(theLogFilename, logName, PATH_MAX);
// Fill the worker queue
pthread_mutex_lock(&mutex);
for(int i = 0; i <logQueue.Size; i++)
{
workerQueue.PushBack(&workerQueue, logQueue.Data[i], strnlen(logQueue.Data[i], LOG_LINE_SIZE));
}
// empty the log vector
while (logQueue.Size > 0)
{
logQueue.PopBack(&logQueue);
}
// Release the mutex to let the log queue be available
pthread_mutex_unlock(&mutex);
for(int i = 0; i <workerQueue.Size; i++)
{
FILE_AppendStringToFile(theLogFilename, workerQueue.Data[i]);
my_printf("\n Log at %d : %s", i, workerQueue.Data[i]);
}
// empty the log vector
while (workerQueue.Size > 0)
{
workerQueue.PopBack(&workerQueue);
} }
while (workerQueue.Size > 0) workerQueue.PopBack(&workerQueue);
} }
}
} }
int logInit(char * folder, int numberOfLogFiles) int logInit(const char* folder, int numberOfLogFiles) {
{ if (numberOfLogFiles <= 0 || !folder) return -1;
int returnCode;
my_printf("\n Init logging system..");
logFilesNumber = numberOfLogFiles; maxLogFiles = numberOfLogFiles;
snprintf(logFolder, sizeof(logFolder), "%s", folder);
if (logFilesNumber <= 0)
return;
delete_old_logs(folder, numberOfLogFiles);
DYNV_VectorString_Init(&logQueue); DYNV_VectorString_Init(&logQueue);
DYNV_VectorString_Init(&workerQueue); DYNV_VectorString_Init(&workerQueue);
sem_init(&logsem, 0, 0); // Initialize semaphore with number of printers sem_init(&logSem, 0, 0);
// Initialize the mutex if (pthread_create(&logThreadId, NULL, logThread, NULL) != 0) {
pthread_mutex_init(&mutex, NULL); LOG_ERROR("Failed to create log thread");
return -1;
returnCode = pthread_create(&pLogThread, NULL, &logThread, NULL);
if (returnCode != 0)
{
addLog("Pthead create error restarting the server", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
exit(0);
return 0;
} }
//addLog("Log init ", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); deleteOldLogs(logFolder, maxLogFiles);
my_printf("\nLog system initialized in folder: %s", logFolder);
memset(logFolder, 0, PATH_MAX);
strncpy(logFolder, folder, PATH_MAX);
my_printf("\n Log init LogFolder: %s ", logFolder);
return 1; return 1;
} }
void addLog(char* logString, char * currFile, int currLine, char * currFunction) void logMessage(const char* message, const char* file, int line, const char* function) {
{ if (maxLogFiles <= 0 || !message) return;
if (logFilesNumber <= 0)
return;
char theLogString[LOG_LINE_SIZE];
char debugInfo[LOG_LINE_SIZE];
memset(theLogString, 0, LOG_LINE_SIZE);
memset(debugInfo, 0, LOG_LINE_SIZE);
char logEntry[LOG_LINE_SIZE] = {0};
time_t now = time(NULL); time_t now = time(NULL);
struct tm *info = localtime(&now); struct tm* tm_now = localtime(&now);
if (strftime(theLogString, sizeof(theLogString), "%Y-%m-%d_%H:%M: ", info) == 0) strftime(logEntry, sizeof(logEntry), "%Y-%m-%d_%H:%M:%S: ", tm_now);
{ strncat(logEntry, message, LOG_LINE_SIZE - strlen(logEntry) - 1);
my_printfError("strftime error");
return;
}
snprintf(debugInfo, LOG_LINE_SIZE, " - File %s at line %d - fun %s() ", currFile, currLine, currFunction); char metaInfo[256];
strncat(theLogString, logString, LOG_LINE_SIZE); snprintf(metaInfo, sizeof(metaInfo), " - File %s at line %d - fun %s()", file, line, function);
strncat(theLogString, debugInfo, LOG_LINE_SIZE); strncat(logEntry, metaInfo, LOG_LINE_SIZE - strlen(logEntry) - 1);
pthread_mutex_lock(&logMutex);
// Acquire the mutex lock before accessing count logQueue.PushBack(&logQueue, logEntry, strlen(logEntry));
pthread_mutex_lock(&mutex); pthread_mutex_unlock(&logMutex);
//Add a string to the log sem_post(&logSem);
logQueue.PushBack(&logQueue, theLogString, strnlen(theLogString, LOG_LINE_SIZE));
// Acquire the mutex lock before accessing count
//Count log available
sem_post(&logsem);
pthread_mutex_unlock(&mutex);
} }
// printf-style log function
void logMessagef(const char* file, int line, const char* function, const char* fmt, ...) {
if (maxLogFiles <= 0 || !fmt) return;
char messageBuffer[LOG_LINE_SIZE] = {0};
va_list args;
va_start(args, fmt);
vsnprintf(messageBuffer, sizeof(messageBuffer), fmt, args);
va_end(args);
logMessage(messageBuffer, file, line, function);
}

View File

@ -25,7 +25,20 @@
#ifndef LOG_H #ifndef LOG_H
#define LOG_H #define LOG_H
int logInit(char * folder, int numberOfLogFiles); #define LOG_INFO_PREFIX "[INFO] "
void addLog(char* logString, char * currFile, int currLine, char * currFunction); #define LOG_DEBUG_PREFIX "[DEBUG] "
#define LOG_ERROR_PREFIX "[ERROR] "
#define LOG_SECURITY_PREFIX "[SECURITY] "
#define LOG(msg) logMessage(msg, __FILE__, __LINE__, __func__)
#define LOG_INFO(msg) logMessage(LOG_INFO_PREFIX msg, __FILE__, __LINE__, __func__)
#define LOG_DEBUG(msg) logMessage(LOG_DEBUG_PREFIX msg, __FILE__, __LINE__, __func__)
#define LOG_ERROR(msg) logMessage(LOG_ERROR_PREFIX msg, __FILE__, __LINE__, __func__)
#define LOG_SECURITY(msg) logMessage(LOG_SECURITY_PREFIX msg, __FILE__, __LINE__, __func__)
#define LOGF(fmt, ...) logMessagef(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
int logInit(const char* folder, int numberOfLogFiles);
void logMessage(const char* message, const char* file, int line, const char* function);
void logMessagef(const char* file, int line, const char* function, const char* fmt, ...);
#endif #endif

View File

@ -1,50 +0,0 @@
/*
* The MIT License
*
* Copyright 2018 Ugo Cirmignani.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <time.h>
#include "logFunctions.h"
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include "../debugHelper.h"
void printTimeStamp(void)
{
// time_t ltime; calendar time
// ltime=time(NULL); get current cal time
// my_printf("\n\n %s -->",asctime( localtime(&ltime) ) );
}
void makeTimeout(struct timespec *tsp, long seconds)
{
struct timeval now;
/* get the current time */
gettimeofday(&now, NULL);
tsp->tv_sec = now.tv_sec;
tsp->tv_nsec = now.tv_usec * 1000; /* usec to nsec */
/* add the offset to get timeout value */
tsp->tv_sec += seconds;
}

View File

@ -21,6 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
/*
* The MIT License
* Copyright 2018 Ugo Cirmignani.
* [license text unchanged...]
*/
#ifdef OPENSSL_ENABLED #ifdef OPENSSL_ENABLED
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -29,204 +35,161 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/conf.h>
#include "openSsl.h" #include "openSsl.h"
#include "fileManagement.h" #include "fileManagement.h"
#include "../debugHelper.h" #include "../debugHelper.h"
#include "log.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define NEED_OPENSSL_THREADING 1
#else
#define NEED_OPENSSL_THREADING 0
#endif
#if NEED_OPENSSL_THREADING
#define MUTEX_TYPE pthread_mutex_t #define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) #define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
#define THREAD_ID pthread_self() #define THREAD_ID pthread_self()
/* This array will store all of the mutexes available to OpenSSL. */
static MUTEX_TYPE *mutex_buf = NULL; static MUTEX_TYPE *mutex_buf = NULL;
#endif
void initOpenssl() void initOpenssl()
{ {
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ #if NEED_OPENSSL_THREADING
SSL_load_error_strings(); /* Bring in and register error messages */
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_library_init();
thread_setup(); thread_setup();
#endif
// No longer needed in OpenSSL >= 1.1.0
// OpenSSL_add_all_algorithms();
// SSL_load_error_strings();
// ERR_load_BIO_strings();
// ERR_load_crypto_strings();
// SSL_library_init();
} }
void cleanupOpenssl() void cleanupOpenssl()
{ {
thread_cleanup(); #if NEED_OPENSSL_THREADING
EVP_cleanup(); thread_cleanup();
#endif
// Deprecated in OpenSSL >= 1.1.0
// EVP_cleanup();
} }
SSL_CTX *createServerContext() SSL_CTX *createServerContext()
{ {
const SSL_METHOD *method; const SSL_METHOD *method = TLS_server_method();
SSL_CTX *ctx; SSL_CTX *ctx = SSL_CTX_new(method);
if (!ctx) {
method = TLS_server_method(); perror("Unable to create server SSL context");
ERR_print_errors_fp(stderr);
ctx = SSL_CTX_new(method); exit(EXIT_FAILURE);
if (!ctx)
{
perror("Unable to create server SSL context");
ERR_print_errors_fp(stderr);
exit(0);
}
return ctx;
}
SSL_CTX *createClientContext(void)
{
const SSL_METHOD *method;
SSL_CTX *ctx;
method = TLS_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
//SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
//SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE| SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
//SSL_CTX_set_ecdh_auto(ctx, 1);
if (ctx == NULL)
{
perror("Unable to create server SSL context");
my_printfError("Unable to create server SSL context");
addLog("Unable to create server SSL context", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC);
ERR_print_errors_fp(stderr);
abort();
exit(0);
} }
return ctx; return ctx;
} }
void configureClientContext(SSL_CTX *ctx, char *certificatePath, char* privateCertificatePath) void configureContext(SSL_CTX *ctx, const char *certPath, const char *keyPath)
{/*
if (FILE_IsFile(certificatePath) != 1)
{
my_printf("\ncertificate file: %s not found!", certificatePath);
exit(0);
}
if (FILE_IsFile(privateCertificatePath) != 1)
{
my_printf("\ncertificate file: %s not found!", privateCertificatePath);
exit(0);
}
Set the key and cert
if (SSL_CTX_use_certificate_file(ctx, certificatePath, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
if (SSL_CTX_use_PrivateKey_file(ctx, privateCertificatePath, SSL_FILETYPE_PEM) <= 0 ) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
} */
}
void configureContext(SSL_CTX *ctx, char *certificatePath, char* privateCertificatePath)
{ {
if (FILE_IsFile(certificatePath, 1) != 1) if (!FILE_IsFile(certPath, 1)) {
{ my_printf("\nCertificate file not found: %s", certPath);
my_printf("\ncertificate file: %s not found!", certificatePath); exit(EXIT_FAILURE);
exit(0); }
}
if (FILE_IsFile(privateCertificatePath, 1) != 1) if (!FILE_IsFile(keyPath, 1)) {
{ my_printf("\nPrivate key file not found: %s", keyPath);
my_printf("\ncertificate file: %s not found!", privateCertificatePath); exit(EXIT_FAILURE);
exit(0); }
}
SSL_CTX_set_ecdh_auto(ctx, 1); // Removed SSL_CTX_set_ecdh_auto (no-op since OpenSSL 1.1.0)
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!MD5");
/* Set the key and cert */ if (SSL_CTX_use_certificate_file(ctx, certPath, SSL_FILETYPE_PEM) <= 0) {
if (SSL_CTX_use_certificate_file(ctx, certificatePath, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (SSL_CTX_use_PrivateKey_file(ctx, privateCertificatePath, SSL_FILETYPE_PEM) <= 0 ) { if (SSL_CTX_use_PrivateKey_file(ctx, keyPath, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Enable session cache on server side
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
} }
void ShowCerts(SSL *ssl)
void ShowCerts(SSL* ssl) {
{ X509 *cert; X509 *cert = SSL_get_peer_certificate(ssl);
char *line; if (cert) {
char *line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
my_printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
my_printf("Subject: %s\n", line); my_printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */ free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
my_printf("Issuer: %s\n", line); my_printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */ free(line);
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
my_printf("No certificates.\n");
}
X509_free(cert);
} else {
my_printf("No certificates.\n");
}
}
void handle_error(const char *file, int lineno, const char *msg) void handle_error(const char *file, int lineno, const char *msg)
{ {
fprintf(stderr, "** %s:%d %s\n", file, lineno, msg); fprintf(stderr, "** %s:%d %s\n", file, lineno, msg);
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
/* exit(-1); */
} }
#if NEED_OPENSSL_THREADING
static void locking_function(int mode, int n, const char *file, int line) static void locking_function(int mode, int n, const char *file, int line)
{ {
if(mode & CRYPTO_LOCK) if (mode & CRYPTO_LOCK)
MUTEX_LOCK(mutex_buf[n]); MUTEX_LOCK(mutex_buf[n]);
else else
MUTEX_UNLOCK(mutex_buf[n]); MUTEX_UNLOCK(mutex_buf[n]);
} }
static unsigned long id_function(void) static unsigned long id_function(void)
{ {
return ((unsigned long)THREAD_ID); return (unsigned long)THREAD_ID;
} }
int thread_setup(void) int thread_setup(void)
{ {
int i; int i;
mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
if (!mutex_buf) return 0;
mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE)); for (i = 0; i < CRYPTO_num_locks(); i++)
if(!mutex_buf) MUTEX_SETUP(mutex_buf[i]);
return 0;
for(i = 0; i < CRYPTO_num_locks(); i++) CRYPTO_set_id_callback(id_function);
MUTEX_SETUP(mutex_buf[i]); CRYPTO_set_locking_callback(locking_function);
CRYPTO_set_id_callback(id_function); return 1;
CRYPTO_set_locking_callback(locking_function);
return 1;
} }
int thread_cleanup(void) int thread_cleanup(void)
{ {
int i; int i;
if (!mutex_buf) return 0;
if(!mutex_buf) CRYPTO_set_id_callback(NULL);
return 0; CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL); for (i = 0; i < CRYPTO_num_locks(); i++)
for(i = 0; i < CRYPTO_num_locks(); i++) MUTEX_CLEANUP(mutex_buf[i]);
MUTEX_CLEANUP(mutex_buf[i]);
free(mutex_buf); free(mutex_buf);
mutex_buf = NULL; mutex_buf = NULL;
return 1; return 1;
} }
#endif
#endif #endif

View File

@ -40,9 +40,7 @@ int thread_cleanup(void);
int thread_setup(void); int thread_setup(void);
void handle_error(const char *file, int lineno, const char *msg); void handle_error(const char *file, int lineno, const char *msg);
SSL_CTX *createServerContext(); SSL_CTX *createServerContext();
SSL_CTX *createClientContext(); void configureContext(SSL_CTX *ctx, const char *certificatePath, const char* privateCertificatePath);
void configureContext(SSL_CTX *ctx, char *certificatePath, char* privateCertificatePath);
void configureClientContext(SSL_CTX *ctx, char *certificatePath, char* privateCertificatePath);
void ShowCerts(SSL* ssl); void ShowCerts(SSL* ssl);
#ifdef __cplusplus #ifdef __cplusplus
} }

67
library/serverHelpers.c Normal file
View File

@ -0,0 +1,67 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <limits.h>
#include "../ftpData.h"
#include "../ftpServer.h"
#include "library/fileManagement.h"
#include "library/configRead.h"
#include "library/openSsl.h"
#include "library/connection.h"
#include "library/dynamicMemory.h"
#include "library/auth.h"
#include "library/serverHelpers.h"
#include "dataChannel/dataChannel.h"
#include "ftpCommandsElaborate.h"
#include "debugHelper.h"
#include "library/log.h"
int handleThreadReuse(ftpDataType *data, int socketId)
{
void *pReturn;
int returnCode = 0;
if (data->clients[socketId].workerData.threadHasBeenCreated == 1)
{
if (data->clients[socketId].workerData.threadIsAlive == 1)
{
cancelWorker(data, socketId);
}
returnCode = pthread_join(data->clients[socketId].workerData.workerThread, &pReturn);
my_printf("\njoin thread status %d", returnCode);
if (returnCode != 0)
{
LOGF("%sJoining thread error: %d", LOG_ERROR_PREFIX, returnCode);
}
data->clients[socketId].workerData.threadHasBeenCreated = 0;
}
return returnCode;
}
void cancelWorker(ftpDataType *data, int clientId)
{
LOG_DEBUG("Cancelling thread because it is busy");
int returnCode = pthread_cancel(data->clients[clientId].workerData.workerThread);
if (returnCode != 0) {
LOGF("%sCancel thread error: %d", LOG_ERROR_PREFIX, returnCode);
}
}

20
library/logFunctions.h → library/serverHelpers.h Executable file → Normal file
View File

@ -22,20 +22,10 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef LOGFUNCTIONS_H #ifndef SERVER_HELPERS_H
#define LOGFUNCTIONS_H #define SERVER_HELPERS_H
#ifdef __cplusplus int handleThreadReuse(ftpDataType *data, int socketId);
extern "C" { void cancelWorker(ftpDataType *data, int clientId);
#endif
void printTimeStamp(void);
void makeTimeout(struct timespec *tsp, long minutes);
#ifdef __cplusplus
}
#endif
#endif /* LOGFUNCTIONS_H */
#endif

View File

@ -30,6 +30,7 @@
#include "../ftpServer.h" #include "../ftpServer.h"
#include "../debugHelper.h" #include "../debugHelper.h"
#include "log.h"
static void ignore_sigpipe(void); static void ignore_sigpipe(void);
@ -56,7 +57,7 @@ static void ignore_sigpipe(void)
{ {
perror("Could not ignore the SIGPIPE signal"); perror("Could not ignore the SIGPIPE signal");
my_printfError("Could not ignore the SIGPIPE signal"); my_printfError("Could not ignore the SIGPIPE signal");
addLog("Could not ignore the SIGPIPE signal", CURRENT_FILE, CURRENT_LINE, CURRENT_FUNC); LOG_INFO("Could not ignore the SIGPIPE signal");
exit(0); exit(0);
} }
} }

View File

@ -2,7 +2,8 @@
#OPENSSL TEST COMMANDS #OPENSSL TEST COMMANDS
#Required packages to compile with TLS #Required packages to compile with TLS
sudo apt-get install libssl-devù sudo apt-get install libssl-dev
#Required packages to compile with PAM #Required packages to compile with PAM
sudo apt-get install libpam0g-dev sudo apt-get install libpam0g-dev
@ -12,8 +13,6 @@ openssl rsa -in key.pem -out newkey.pem
handle SIGPIPE nostop noprint pass handle SIGPIPE nostop noprint pass
thread apply all where thread apply all where
#Testing ssl #Testing ssl
openssl s_client -starttls ftp -connect 192.168.1.237:21 openssl s_client -starttls ftp -connect 192.168.1.237:21
sudo openssl s_server -key key.pem -cert cert.pem -accept 123 sudo openssl s_server -key key.pem -cert cert.pem -accept 123
@ -23,3 +22,7 @@ PASS password
PROT P PROT P
PORT 192,168,1,237,0,123 PORT 192,168,1,237,0,123
LIST LIST
PASV EXAMPLE:
openssl s_client -connect localhost:10000

2
uFTP.c
View File

@ -25,12 +25,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "ftpServer.h" #include "ftpServer.h"
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
runFtpServer(); runFtpServer();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,67 +1,68 @@
#FTP CONFIGURATION SAMPLE "/etc/uftpd.cfg" # FTP CONFIGURATION SAMPLE "/etc/uftpd.cfg"
####################################################### #######################################################
# UFTP SERVER SETTINGS # # UFTP SERVER SETTINGS #
####################################################### #######################################################
#MAXIMUM ALLOWED CONNECTIONS ON THE SERVER # NOTES:
MAXIMUM_ALLOWED_FTP_CONNECTION = 30 # restart uFTP to apply the configuration after changing parameters
#TCP/IP PORT SETTINGS (DEFAULT 21) # Maximum allowed FTP connections on the server
MAXIMUM_ALLOWED_FTP_CONNECTION = 50
# TCP/IP port settings (default: 21)
FTP_PORT = 21 FTP_PORT = 21
#Allow only one server instance (true or false) # Allow only one server instance (true or false)
SINGLE_INSTANCE = true SINGLE_INSTANCE = true
#Run in background, daemon mode ok # Run in background daemon mode (true or false)
DAEMON_MODE = true DAEMON_MODE = true
# Folder where to save the logs, use the same format below, the folder must terminate with / # Folder where logs are saved; must end with a '/'
LOG_FOLDER = /var/log/ LOG_FOLDER = /var/log/
# Maximum number of logs to keep, if 0 log functionality is disabled # Maximum number of logs to keep; set to 0 to disable logging
MAXIMUM_LOG_FILES = 0 MAXIMUM_LOG_FILES = 0
# Idle timeout in seconds, client are disconnected for inactivity after the # Idle timeout in seconds; clients are disconnected after this period of inactivity; set to 0 to disable
# specified amount of time in seconds, set to 0 to disable # some clients may fail if the timeout is too high https://github.com/kingk85/uFTP/issues/29
IDLE_MAX_TIMEOUT = 3600 IDLE_MAX_TIMEOUT = 330
#MAX CONNECTIONS PER IP # Maximum connections per IP address; set to 0 to disable
#LIMIT THE MAXIMUM NUMBER OF CONNECTION FOR EACH IP ADDRESS
# 0 TO DISABLE
MAX_CONNECTION_NUMBER_PER_IP = 10 MAX_CONNECTION_NUMBER_PER_IP = 10
#MAX LOGIN TRY PER IP # Maximum login attempts per IP (anti bruteforce feature); IP will be blocked for 5 minutes after exceeding this number of failed login attempts; set to 0 to disable
#THE IP ADDRESS WILL BE BLOCKED FOR 5 MINUTES AFTER WRONG LOGIN USERNAME AND PASSWORD
#0 TO DISABLE
MAX_CONNECTION_TRY_PER_IP = 10 MAX_CONNECTION_TRY_PER_IP = 10
#USE THE SERVER IP PARAMETER IF THE FTP SERVER IS UNDER NAT # Server IP address for NAT configurations; use commas instead of periods (e.g., 192,168,1,1); leave commented or blank if not used
#SERVER IP SHOULD BE SET TO ROUTER IP IN THIS CASE
#IF NOT IN USE LEAVE IT COMMENTED OR BLANK
#USE , instad of . eg: 192,168,1,1
#SERVER_IP = 192,168,1,1 #SERVER_IP = 192,168,1,1
#TLS CERTIFICATE FILE PATH # TLS certificate file paths
CERTIFICATE_PATH=/etc/uFTP/cert.pem CERTIFICATE_PATH=/etc/uFTP/cert.pem
PRIVATE_CERTIFICATE_PATH=/etc/uFTP/key.pem PRIVATE_CERTIFICATE_PATH=/etc/uFTP/key.pem
#Enable system authentication based on /etc/passwd # Enable system authentication based on /etc/passwd and /etc/shadow (true or false)
#and /etc/shadow
ENABLE_PAM_AUTH = false ENABLE_PAM_AUTH = false
# Force usage of the TLS # Force usage of TLS; if enabled, only TLS connections are allowed (true or false)
# If enabled, only TLS connections will be allowed
FORCE_TLS = false FORCE_TLS = false
# # Random port range for passive FTP connections
# Random port for passive FTP connections range
#
RANDOM_PORT_START = 10000 RANDOM_PORT_START = 10000
RANDOM_PORT_END = 50000 RANDOM_PORT_END = 50000
#USERS #######################################################
#START FROM USER 0 TO XXX # USER SETTINGS #
#######################################################
# Define users with the following parameters:
# USER_<n> = username
# PASSWORD_<n> = password
# HOME_<n> = home directory
# GROUP_NAME_OWNER_<n> = group ownership for new files (optional)
# USER_NAME_OWNER_<n> = user ownership for new files (optional)
USER_0 = username USER_0 = username
PASSWORD_0 = password PASSWORD_0 = password
HOME_0 = / HOME_0 = /
@ -78,7 +79,7 @@ USER_2 = anotherUsername
PASSWORD_2 = anotherPassowrd PASSWORD_2 = anotherPassowrd
HOME_2 = / HOME_2 = /
#blocked user that are not allowed to login # Blocked users who are not allowed to log in
BLOCK_USER_0 = user1 BLOCK_USER_0 = user1
BLOCK_USER_1 = user2 BLOCK_USER_1 = user2
BLOCK_USER_2 = user3 BLOCK_USER_2 = user3