diff --git a/add-ftp-account.sh b/add-ftp-account.sh new file mode 100755 index 0000000..20e8280 --- /dev/null +++ b/add-ftp-account.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +#------------------------------------------- +# $1 = User name +# $2 = Password +# $3 = Home directory +#------------------------------------------- + +if [ "$#" -ne 3 ]; then + echo "Illegal number of parameters" + echo "Usage:" + echo " $0 " + echo + echo "Example:" + echo " ./add-ftp-account.sh user_name password user_home_dir" + echo + exit 1 +fi + +conf="conf/ftp.conf" +perm="elrwm" + +#--CREATE NEW USER ACCOUNT +if [ -z "$( grep "name: $1" $conf )" ]; then + echo "" >> $conf + echo " - name: $1" >> $conf + echo " dir: $3" >> $conf + echo " password: $2" >> $conf + echo " permission: $perm" >> $conf + echo "Created new FTP account $1 having permission $perm" +else + echo "The user $1 already exists: ABORT !!!" + exit -1 +fi + +#--CREATE HOME DIR +if [ ! -d $3 ]; then + mkdir $3 + chown www-data:www-data $3 + chmod -R g+w $3 + chmod g+s $3 + echo "Created new home dir: $3" +fi + +#echo "HOMEs:" +#echo "$( ls -l $3/.. )" + +#--RESTART easyftp DAEMON TO ENABLE NEW ACCOUNT +daemon_restart="zdaemon -C conf/zdaemon.conf restart" +read -p "Do you want to restart EASYFTP daemon now ? ('Yes' or 'No')" response +if [ "${response^^}" == "YES" ]; then + $daemon_restart +else + echo + echo "ATTENTION:" + echo "Remember to restart daemon manually to apply config changes:" + echo " $daemon_restart" +fi + +echo "Done!" + diff --git a/app/main.py b/app/main.py index 34486f8..0a35945 100644 --- a/app/main.py +++ b/app/main.py @@ -4,6 +4,8 @@ import os import yaml +import logging +import pyftpdlib.log from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler @@ -19,24 +21,41 @@ def read_conf(config_file=os.path.join(this_dir, '../conf/ftp.conf')): class CustomHandler(FTPHandler): + my_log = logging.getLogger('CustomHandler') + def on_file_received(self, file): import os + self.my_log.debug("Rename " + os.path.basename(file) + " to original file name") head, tail = list(path.split(file))[0], list(path.split(file))[1] - os.rename(path.join(head, tail), path.join(head, tail[4:])) + os.rename(path.join(head, tail), path.join(head, tail[4:-1])) pass - + + #Rob: it seems doesn't exist ! def on_incomplete_received(self, file): import os + self.my_log.warn("on_incomplete_received('" + os.path.basename(file) + "')") os.remove(file) - def ftp_STOR(self, file, mode='w'): + import os + self.my_log.debug("Rename " + os.path.basename(file) + " useing temp file name .in.xxx.") head, tail = list(path.split(file))[0], list(path.split(file))[1] - file = path.join(head, ".in." + tail) - + file = path.join(head, ".in." + tail + ".") return FTPHandler.ftp_STOR(self, file, mode) + def on_incomplete_file_received(self, file): + import os + self.my_log.warn("Remove partially uploaded file " + os.path.basename(file)) + # remove partially uploaded file + #This happens on connection interrupted but not when Ctrl+C is pressed on FTP client (rob) + os.remove(file) + #Rob: added by me + def on_incomplete_file_sent(self, file): + import os + self.my_log.warn("Remove partially downloaded file " + os.path.basename(file)) + # remove partially downloaded files + os.remove(file) def get_server(conf=None): @@ -53,7 +72,8 @@ def get_server(conf=None): # Instantiate FTP handler class handler = CustomHandler handler.authorizer = authorizer - + handler.log_prefix = '[%(username)s@%(remote_ip)s:%(remote_port)s]' + # Define a customized banner (string returned when client connects) handler.banner = "simpleftp ready!" @@ -68,6 +88,7 @@ def get_server(conf=None): address = (server.get('address', ''), server.get('port', '2121')) server = FTPServer(address, handler) + pyftpdlib.log.LEVEL = log_level # set a limit for connections # server.max_cons = 256 @@ -78,5 +99,20 @@ def get_server(conf=None): return server if __name__ == '__main__': - server = get_server(read_conf()) + conf = read_conf() + log_level = logging.DEBUG + if conf.get('log').get('level').upper() == 'INFO': + log_level = logging.INFO + elif conf.get('log').get('level').upper() == 'WARN': + log_level = logging.WARN + elif conf.get('log').get('level').upper() == 'ERROR': + log_level = logging.ERROR + + logging.basicConfig(level=log_level, + format='%(asctime)s %(levelname)-5s %(name)-13s %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + filename='/var/log/pyftpd.log', + filemode='a') + + server = get_server(conf) server.serve_forever() diff --git a/conf/ftp-example.conf b/conf/ftp-example.conf index 430e9a0..39576ab 100644 --- a/conf/ftp-example.conf +++ b/conf/ftp-example.conf @@ -1,3 +1,6 @@ +log: + level: INFO + users: - name: luca dir: /Users/luca @@ -16,4 +19,4 @@ server: # masquerade_address: 8.8.8.8 passive_ports: start: 60000 - end: 65535 \ No newline at end of file + end: 65535 diff --git a/conf/zdaemon.conf b/conf/zdaemon.conf index e71218e..0ba7fc7 100644 --- a/conf/zdaemon.conf +++ b/conf/zdaemon.conf @@ -1,6 +1,12 @@ daemon on - program python ./app/main.py - socket-name ./socket/ftpserver.sock - transcript ./log/ftpserver.log - \ No newline at end of file + program ./easyftp.sh + socket-name socket/ftpserver.sock + #transcript log/ftpserver.log + + + + + path log/easyftp.log + + diff --git a/easyftp.sh b/easyftp.sh new file mode 100755 index 0000000..d3dea57 --- /dev/null +++ b/easyftp.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# This script is the EasyFTP launcher + +python app/main.py +