I am not responsible if your devices send you back in time, explodes, implodes, bricks or flies into space from the use of any software I put up.


Sunday, February 26, 2012

Configuring Pure-FTPd with TLS on OpenWRT

This is a simple guide to configuring Pure-FTPd on OpenWRT which is available on the TP-Link WR1043ND OpenWRT Image I compiled.
Pure-FTPd is a secure FTP Server by www.pureftpd.org
Configuring OpenWRT is more like configuring a barebones Linux Terminal Server than many other commercial Routers. There is NO LuCI GUI for Pure-FTPd.
The reason why I chose Pure-Pure-FTPd is
  • Offers Optional TLS Encryption on OpenWRT
  • Not a very big FTP Server
First, you have to login via an SSH Client to your OpenWRT Router and get use to it if you are going to leverage on the Power and Flexibility on OpenWRT (If you custom compile OpenWRT without LuCI GUI you get to save even more flash memory!).

You can use any SSH Client, in Windows I recommend PuTTY while on Linux the built-in SSH will do. To learn how to login via CLI and edit files please go through the previous postings.

Pure-FTPd uses a few configuration files to set itself up.
Originally Pure-FTPd is designed to run without config files. Just run the binary with the correct switches it should set itself up but in OpenWRT it is designed to read the config file to set itself up.

To see the full switches on Pure-FTPd on OpenWRT simply cat the initialization scripts.

The initialization script is located in /etc/init.d/pure-ftpd

Run cat /etc/init.d/pure-ftpd  and you should see the following:
#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2011 OpenWrt.org


# TODO: allow multiple instance to run with different pid-files

# XXX: pure-ftpd changes it's name to 'pure-ftpd (SERVER) ...'

append_bool() {
        local section="$1"
        local option="$2"
        local value="$3"
        local _val
        config_get_bool _val "$section" "$option" '0'
        [ "$_val" -gt 0 ] && append args "$3"

append_string() {
        local section="$1"
        local option="$2"
        local value="$3"
        local _val
        config_get _val "$section" "$option"
        [ -n "$_val" ] && append args "$3 $_val"

start_instance() {
        local section="$1"

        config_get_bool enabled "$section" 'enabled' '1'
        [ $enabled -gt 0 ] || return 1

        append_string "$section" trustedgid "-a"
        append_string "$section" syslogfacility "-f"
        append_string "$section" fortunesfile "-F"
        append_string "$section" maxidletime "-I"
        append_string "$section" maxdiskusagepct "-k"
        append_string "$section" limitrecursion "-L"
        append_string "$section" anonymouscancreate "-M"
        append_string "$section" maxload "-m"
        append_string "$section" quota "-n"
        append_string "$section" altlog "-O"
        append_string "$section" passiveportrange "-p"
        append_string "$section" forcepassiveip "-P"
        append_string "$section" anonymousratio "-q"
        append_string "$section" userratio "-Q"
        append_string "$section" anonymousbandwidth "-t"
        append_string "$section" userbandwidth "-T"
        append_string "$section" minuid "-u"
        append_string "$section" trustedip "-V"
        append_string "$section" tls "-Y"
        append_string "$section" tlsciphersuite "-J"

        append_bool "$section" uploadscript "-o"
        append_bool "$section" natmode "-N"
        append_bool "$section" autorename "-r"
        append_bool "$section" nochmod "-R"
        append_bool "$section" antiwarez "-s"
        append_bool "$section" allowuserfxp "-w"
        append_bool "$section" allowanonymousfxp "-W"
        append_bool "$section" prohibitdotfileswrite "-x"
        append_bool "$section" prohibitdotfilesread "-X"
        append_bool "$section" allowdotfiles "-z"
        append_bool "$section" customerproof "-Z"
        append_bool "$section" anonymouscantupload "-i"
        append_bool "$section" createhomedir "-j"
        append_bool "$section" keepallfiles "-K"
        append_bool "$section" norename "-G"
        append_bool "$section" dontresolve "-H"
        append_bool "$section" verboselog "-d"
        append_bool "$section" displaydotfiles "-D"
        append_bool "$section" anonymousonly "-e"
        append_bool "$section" brokenclientscompatibility "-b"
        append_bool "$section" notruncate "-0"
        append_bool "$section" logpid "-1"
        append_bool "$section" ipv4only "-4"
        append_bool "$section" ipv6only "-6"

        append_string "$section" bind "-S"
        append_string "$section" login "-l"

        append_bool "$section" noanonymous "-E"
        append_bool "$section" chrooteveryone "-A"
        append_string "$section" maxclientsperip "-c"
        append_string "$section" maxclientsnumber "-C"
        append_string "$section" peruserlimits "-y"
        append_string "$section" umask "-U"

        append_string "$section" port "-S"
        append_string "$section" authentication "-l"

        service_start /usr/sbin/pure-ftpd -B $args

start() {
        config_load "pure-ftpd"
        config_foreach start_instance "pure-ftpd"

stop() {
        service_stop /usr/sbin/pure-ftpd
From what you can read you can tell the initialization scripts translates switches like "-k" into human readable config options and all the available switches are shown above.

To control Pure-FTPd the commands are as follow
Syntax: /etc/init.d/pure-ftpd [command]

Available commands:
        start   Start the service
        stop    Stop the service
        restart Restart the service
        reload  Reload configuration files (or restart if that fails)
        enable  Enable service autostart
        disable Disable service autostart
Eg: To start Pure-FTPd run
/etc/init.d/pure-ftpd start

It is that simple so CLI isn't really as difficult as most imagine.

Pure-FTPd also uses 2 database file as access-control lists they are located at
(This is like your UNIX passwd file except it is for Pure-FTPd it contains user accounts, shell etc)
(It is Pure-FTPd database file I like to think of it as your UNIX shadow file)

First you add a system user and system group as a default account on UNIX that Pure-FTPd will create virtual user from.
addgroup pure_ftpd_grp #or any othername as you want

adduser -H -G pure_ftpd_grp pure_ftpd_user #adds user to previously created group - change groupname accordingly, afterwards you will be asked for password for user (-H indicates that I don't want to assign home directory - if you want to you need to change -H to -h /homedirectory)
For me I assign the home directory to the directory I want to be logging from FTP.
FTP will fail if the directory change permission is not correct so you need to set it to the right directory.

Next you add the virtual user to Pure-FTPd Access Control

pure-pw useradd FTP_LOGIN -u pure_ftpd_user -d /ftp_directory #change FTP_LOGIN, pure_ftpd_user and /ftp_directory as you wish (pure_ftpd_user is same as you created in previous step). I set the same directory as above.

To see the Pure-FTPd accounts use the commands
pure-pw useradd <login> [-f <passwd file>] -u <uid> [-g <gid>]
                -D/-d <home directory> [-c <gecos>]
                [-t <download bandwidth>] [-T <upload bandwidth>]
                [-n <max number of files>] [-N <max Mbytes>]
                [-q <upload ratio>] [-Q <download ratio>]
                [-r <allow client ip>/<mask>] [-R <deny client ip>/<mask>]
                [-i <allow local ip>/<mask>] [-I <deny local ip>/<mask>]
                [-y <max number of concurrent sessions>]
                [-z <hhmm>-<hhmm>] [-m]

pure-pw usermod <login> -f <passwd file> -u <uid> [-g <gid>]
                -D/-d <home directory> -[c <gecos>]
                [-t <download bandwidth>] [-T <upload bandwidth>]
                [-n <max number of files>] [-N <max Mbytes>]
                [-q <upload ratio>] [-Q <download ratio>]
                [-r <allow client ip>/<mask>] [-R <deny client ip>/<mask>]
                [-i <allow local ip>/<mask>] [-I <deny local ip>/<mask>]
                [-y <max number of concurrent sessions>]
                [-z <hhmm>-<hhmm>] [-m]

pure-pw userdel <login> [-f <passwd file>] [-m]

pure-pw passwd  <login> [-f <passwd file>] [-m]

pure-pw show    <login> [-f <passwd file>]

pure-pw mkdb    [<puredb database file> [-f <passwd file>]]
                [-F <puredb file>]

pure-pw list    [-f <passwd file>]

-d <home directory> : chroot user (recommended)
-D <home directory> : don't chroot user
-<option> '' : set this option to unlimited
-m : also update the /etc/pureftpd.pdb database
For a 1:10 ratio, use -q 1 -Q 10
To allow access only between 9 am and 6 pm, use -z 0900-1800
Every time you modify the FTP Accounts you need to run pure-pw mkdb to apply the changes.

Now we edit the Pure-FTPd config file at /etc/config/pure-ftpd

vi /etc/config/pure-ftpd

I will provide you a sample so you don't have to read about all the options and what are they used for.

config pure-ftpd
        option port             '21'
        option noanonymous      '1'
        option chrooteveryone   '1'
        option maxclientsperip  '20'
        option maxclientsnumber '40'
        option umask            '133:022'
        option authentication   'unix'
        option enabled          '1'
        option passiveportrange '1985:2000'
        option tls              '1'
        option daemonize        '1'
        option authentication   'puredb:/etc/pureftpd.pdb'
        option prohibitdotfileswrite '1'
        option prohibitdotfilesread '1'
        option userbandwidth '50:50'
#       option natmode '1'
#       option brokenclientscompatibility' '1'
Basically this runs pure-ftpd on Port 21 with passive ports from 1985-2000 with anonymous login disabled, tls set on optional (if client request it will provide if not just unencrypted communication).
The default directory is chrooted which means user cannot change from their default directory to /.
The # comments out lines, it should only be enabled if there are incompatibilities with the firewalls and clients. After you get good at FTP you might want to tweak the bandwidth and number of connections and other advance settings for more performance.

Next we will do TLS encryption

You have to generate a self-signed certification using OpenSSL, you should do it on the PC and copy the certificate to the router unless you are a masochist to want to do it on a 400MHZ MIPS Processor.

To generate the certificate run on your PC (with OpenSSL installed) run 
openssl req -x509 -days 365 -nodes -newkey rsa:1024 -keyout [Destination Directory]/pure-ftpd.pem -out [Destination Directory]/pure-ftpd.pem

You can use days to specify how long before the self-signed certificate expire.

This will create a certificate file called pure-ftpd.pem for TLS in the destination directory.
Note the destination directory has to be the SAME.

Pure-FTPd reads the TLS certificate in /etc/ssl/private so we make a directory there as is it is not created by default

mkdir -p /etc/ssl/private

Then we Upload the file to the router to the directory we created.You should have /etc/ssl/private/pure-ftpd.pem This is location where Pure-FTPd will try to find a certificate to use for TLS communication if any.

Then we change the file permission

chmod 600 /etc/ssl/private/pure-ftpd.pem
Finally we have to open the ports on the firewall to allow FTP communication.
Note there are 2 types of ports we need to open FTP Active Ports and Passive Ports.
We do it via LuCI GUI, go to Network -> Firewall -> Traffic Rules and Add the following Ruleset

Save and Apply.

Finally we restart Pure-FTPd so it will relaunch with the correct settings.
/etc/init.d/pureftpd restart

So now you need an FTP Client. On Web Browsers like Firefox there is a client built in by default.
To utilise TLS encryption you have to use better clients, I recommend FileZilla.
You specify TLS in the Connection Options.
You have to get a Dynamic DNS address to reverse lookup your Router's external IP Address.
There are free and paid options for home users free is usually good enough.
AFRAID @ http://freedns.afraid.org/ is a good Free Dynamic DNS Address Provider(Funny name though =) ).
It allows numerous domains for you to choose from.

Again DDNS Updating Scripts is built into my 3.25 Kernel Trunk Router's Image by default but I will not be writing about setting up Dynamic DNS records (I modified the DDNS scripts to support HTTPS (by skipping checks) default OpenWRT DDNS does not have that).

You should be able to login to your FTP Server from everywhere on Earth from the Internet in both Active and Passive Modes provided your workplace does not block FTP ports if so simply change port 21 to one of the unblock ports.

Hopefully my guide is simple enough for you to understand how to setup an FTP server on OpenWRT.


rich said...

Thanks you for guide manager to get pure_ftpd working with ssl and i can login but only to root / I have configure pure-pw useradd FTP_LOGIN -u pure_ftpd_user -d /mnt/home

/mnt/home is my usb hdd but still only login to root / and not my usb hdd

Thanks for taking the time to make this guide

Best Regards

Admin said...

You need to
1)Create a user on OpenWRT for Pure-FTPd to use and home directory set to /mnt/home
2)Create a Pure-FTPd account using the user above also set the home directory to /mnt/home/

Troubleshooting tips:
Use FileZilla to login and note the error messages if any to pinpoint the configuration faults. FileZilla logs errors.

rich said...

Hi Admin thanks for the help but still having problems I created a user for openwrt but when I enter my username & Password & login the hole thing is blank with no setting or menu just empty space and if i try to log in to the server using FileZilla I get Response: 421 Home directory not available - aborting
Error: Could not connect to server

I think the reason for the missing home dir is due to nothing in the user page don't understand what happened I added the new user to the /etc/passwd :1000:65534:users:/home/user:/bin/ash


Best Regards

rich said...

Hi Admin,

I can login via ssh but I can not login as a superuser

Best Regards

Admin said...

Copy the syntax from other users in /etc/passwd

Your :1000:65534:users:/home/user:/bin/ash means that the default login directory is /home/user which is wrong because OpenWRT doesn't have this directory at all.
You have to change it to something else.
For super user the line should read as this

Admin said...

Let me further explain the problem:
UNIX by default automatically set /home/username as the default login directory if you didn't specify any home directory. BUT in OpenWRT there is no /home/ directory so it is not pointing to any valid directory so you cannot login at all, therefore you must change the default login directory to something valid.

For super user there is a problem:
The developers set it to
which is wrong it should be

rich said...

Hi Admin,

Thanks for your post but still having problems made a new user

I can in to the webinterface but the page is still white and blank I can login via ssh but still no root user even after I added root:x:0:0:root:/root:/bin/ash
could you please make a guide for this action because I cant see were I am going wrong.
or is there a way in this version to add your usb harddrive partition to be used as root this would increase my storage space too let say 90GB or install all the root /tmp folders to your usb hdd

Best Regards

rich said...

Hi Admin,

I can now upload & download from my pure_ftpd user to my usb hdd but upload & download is very slow 45kbs up & 45kbs down is there any way to speed this up on dd-wrt I was getting 1.8mb up & 2.5mb down

Thanks for all your help

Admin said...

If you want to do a reset you can check openwrt website how to do it.

Did you edit the /etc/config/wireless to add noscan, HT40 etc?

Can you remove all your password and any info you want to keep private then backup all your config file using LuCI and attach it so I can take a look.

Admin said...

Also OpenWRT comes with all function enabled go to the system menu and disable unused function this will speed up performance. Do not disable important function like network!

rich said...

Hi Admin,

speed issue all sorted now I am getting 1.4mb upload & 1.6mb download with encryption enabled with out encrypt I get 3.7mb upload & 5,4mb download is there any way of monitoring users in realtime
and how do I upload the backup to you


Admin said...

OpenWRT LuCI has a backup tab use it to generate the archive.
The archive is a tar.gz of your config files very cool.
It will detect the modified config files and back it up.
You can also add path to files you want to backup.
This is a very nice function of backing up your Router's entire config.

rich said...

Hi Admin,

Thanks for all the help but facing one more problem do you have any easy guides for setting up a DMZ mode I need to port am IP address through DMZ mode


Admin said...

I am afraid you have to use OpenWRT wikipages to search for yourself as I have no experience of setting up dmz on OpenWRT but it is there.

rich said...

Thanks Admin,

For replying