Installation

Il vous faut tout d'abord installer vsftpd. Il est possible d'installer le package vsftpd avec yum, mais il est préférable d'utiliser le groupe FTP Server fourni par yum. Pour dire vrai je ne sait pas la réelle différence puisque le seul package proposé dans ce groupe est vsftpd, mais cela pourrait changer, et c'est peut-être cela qui permet d'avoir le user FTP et le groupe FTP automatiquement. Donc nous tapons en root :

# yum groupinstall "FTP Server"

Une fois l'installation faite, pour que le serveur démarre automatiquement au démarrage (attention il faut être dans l'environnement root, donc su - ) :

# chkconfig vsftpd on

Pour démarrer , redémarrer et stopper le service, ce sera respectivement (toujours en su -) :

# service vsftpd start
# service vsftpd restart
# service vsftpd stop

Normalement votre système doit déja avoir un utilisateur ftp et un groupe ftp. Si ce n'est pas le cas, créez les avec groupadd et useradd.

Configuration

Le fichier de configuration de vsftpd se trouve dans le répertoire /etc/vsftpd et se nomme : vsftpd.conf

Rendons nous d'abord dans le dossier pour y faire du ménage, en root :

# cd /etc/vsftpd

La première chose à faire est de sauvegarder le fichier de configuration original (je repars d'un fichier vide ensuite) :

# mv vsftpd.conf vsftpd.conf.default

Nous créons ensuite un dossier qui contiendra les configuration spécifiques à chaque utilisateur :

# mkdir vsftpd_user_conf

Enfin il est temps que je dise deux mots sur deux fichiers présents dans ce répertoire :

ftpusers et user_list

En fait ces deux fichiers ont la même vocation : interdire des utilisateurs. En effet il contiennent tous les deux une liste d'utilisateurs pour lesquels le server ftp refusera toute connexion. Pourquoi deux fichiers (au contenu identique) ? Le premier (ftpusers) est utilisé via PAM dans la configuration par défaut faite sur Fedora et CentOS. A la connexion d'un utilisateur, PAM vient lire ce fichier et si le login est dans ce fichier, la connexion est refusée. Le second (user_list) est utilisé directement par vsftpd. Il peut avoir deux usages : soit seuls les utilisateurs contenus dans ce fichier ont le droit de se connecter, soit au contraire, si un utilisateur se connectant fait partie de ce fichier, il sera alors refusé. La seconde solution correspond à la même que celle utilisée via PAM. Je me fiche d'avoir une liste d'utilisateurs autorisés, puisque je les gererais avec ma liste d'utilisateurs virtuels. Il est donc inutile d'avoir ces deux systèmes d'interdiction. Mon choix pourrait être de suivre la configuration par défaut faite par CentOS et Fedora, c'est à dire utiliser PAM (dans la configuration par défaut d'ailleurs, le fichier user_list n'est pas utilisé), et donc supprimer le fichier user_list alors inutile. Et pourtant ce n'est pas la solution que j'ai retenue. En effet il y a une petite différence dans la façon de rejeter les utilisateurs. Imaginons que "root" fasse partie des deux fichiers (ce qui est le cas en fait). Si root se connecte, le système PAM ne va pas réagir, et le mot de passe sera demandé. A partir de la, même si ce dernier est correct, PAM va refuser la connexion car "root" est présent dans le fichier ftpusers. Vsftpd va lui réagir différemment. Lorsque le login sera demandé, et que l'utilisateur tapera "root", si celui-ci est dans le fichier "user_list", il coupe directement la connexion, sans même demander le mot de passe. C'est une subtilité, mais je préfère ce comportement. Je vais donc utiliser le fichier user_list plutôt que ftpusers. On supprime donc ce dernier (n'étant pas utilisé, vous pouvez tout a fait le conserver et sauter cette étape, au cas où vous voudriez vous en servir ensuite. Notez cependant que son contenu est par défaut le même que user_list)  :

# rm ftpusers

Nous verrons plus loin la configuration de PAM pour ne plus qu'il aille chercher dans ce fichier. A vous de rentrer les logins que vous ne souhaitez pas voir se connecter dans user_list en plus ce ceux par défaut. Cela sera pratique pour désactiver un utilisateur virtuel, plutôt que de supprimer puis recrééer son compte.

Venons en maintenant au fichier de configuration à proprement parlé :

# vi vsftpd.conf

Vous êtes dans un fichier vide, puisque nous avons renommé celui par défaut. Vous trouverez tous les paramêtres possibles du fichier de config dans la page de man (man vsftpd.conf) où à cette adresse.

Je vous donne directement mon fichier de configuration, que je pense assez documenté. Si vous avez des questions ou des suggestions, n'hésitez pas à en faire part dans les commentaires :

# http://vsftpd.beasts.org/vsftpd_conf.html ou "man vsftpd.conf"

# Port d'ecoute
listen_port=21

# Banniere de bienvenue
ftpd_banner=Bienvenue sur mon ftp perso

# Fichier de config PAM
pam_service_name=vsftpd

# Mode "standalone"
listen=YES

# Je ne veux pas de connexion anonymes
anonymous_enable=NO

# On autorise les connexion des utilisateurs locaux. C'est indispensable
# pour que les utilisateurs virtuels (mappes sur un utilisateur local)
# puissent se connecter (les "vrai" utilisateurs locaux sont ensuite desactives
# avec le fichier user_list
local_enable=YES

# Fichier de users
userlist_file=/etc/vsftpd/user_list
# Chargement de la liste userlist_file
userlist_enable=YES
# On refuse les utilisateur de la liste
userlist_deny=YES

# trop restrictif, un utilisateur virtuel pourra ainsi telecharger un fichier meme s'il n'est pas world readable
anon_world_readable_only=NO

# Refus des commandes influant sur le systeme de fichier (STOR, DELE, RNFR, RNTO, MKD, RMD, APPE and SITE)
write_enable=NO

# Refus des droits d'ecriture pour les anonyme (et donc utilisateurs virtuels) par défaut
# les autorisations seront donnees au cas par cas :
# pas d'upload
anon_upload_enable=NO
# pas de creation de repertoire
anon_mkdir_write_enable=NO
# pas de creation, suppression, renommage de repertoire ...
anon_other_write_enable=NO

# On fait en sorte que les utilisateurs "guest" (non-anonymes) soient mappés sur le compte local "ftp"
guest_enable=YES
guest_username=ftp

# chroot des utilisateurs
chroot_local_user=YES

# Nombre maximum de connexion simultannees
max_clients=50

# Nombre maxeimum de connexion venant de la meme IP
max_per_ip=4

# Dossier de configuration specifique de sutilisateurs
user_config_dir=/etc/vsftpd/vsftpd_user_conf

# On active le log
xferlog_enable=YES

Voila pour la configuration. Pour faire un petit résumé court :

  • On écoute sur le port 21
  • On est en standalone
  • On refuse les utilisateurs anonymes
  • On accepte les utilisateurs système et les utilsiateurs virtuels
  • Les utilisateurs virtuels sont mappés sur le user "ftp"
  • Les utilisateurs n'ont aucun droit d'écriture par défaut
  • Ils sont chrootés dans /var/ftp
  • vsftpd_user_conf sera le dossier pour les config d'utilisateurs virtuels
  • user_list contiendra la liste des utilisateurs refusés (pour lesquels on ne demandera même pas le mot de passe)

Pensez à ouvrir les ports 20 et 21 de votre pare-feu, et à faire une redirection de port si vous êtes derrière un routeur. Si vous avez changé les valeurs de ces ports dans le fichier de configuration, modifiez vos pare-feu et routage en conséquence. Pour plus de sécurité, on réduit les droits sur le fichier de configuration :

# chmod 600 /etc/vsftpd/vsftpd.conf

Utilisateurs virtuels

Il est temps maintenant de créer la base contenant nos utilisateurs virtuels. Comme je l'ai dis celle-ci sera au format berkeley. Nous partirons d'un fichier texte simple, comprenant les logins et les mots de passe, puis nous utiliserons une commande pour transformer ce fichier en format db. Le format du fichier est simplissime, un mot par ligne, et on écrit dans l'ordre le login, le pass, le login, le pass etc ... Je vais créer une base contenant deux utilisateurs :

  • titi dont le mot de passe est passtiti
  • toto dont le mot de passe est passtoto

Rendez vous dans /etc/vsftpd et en root créez un fichier nommé login.txt :

# cd /etc/vsftpd/
# vi login.txt

Et voici le ce que contiendra le fichier :

titi
passtiti
toto
passtoto

Nous allons maintenant créer le fichier db à partir de celui-ci. Pour cela nous devons utiliser la commande db_load, fournie par le package db4-utils. Si ce package n'est pas installé, faites le de cette façon :

# yum install db4-utils

Une fois cela fait, toujours depuis le dossier /etc/vsftpd, en root tapez :

# db_load -T -t hash -f login.txt login.db

Nous verrons plus loin que l'on peut intégrer cette commande à un script pour regénérer plus facilement la base. Nous disposons maintenant d'un fichier /etc/vsftpd/login.db. Pour plus de sécurité, on réduit les droits sur les fichiers utilisateurs :

# chmod 600 login.*

PAM

Notre base d'utilisateurs étant créée, configurons PAM pour qu'il l'utilise. Comme apache (par exemple), PAM utilise pour sa configuration un dossier /etc/pam.d/ comportant les fichiers de configuration des services qui l'utilise. Un fichier /etc/pam.d/vsftpd existe déja, mais comme je l'expliquais plus haut, je ne l'utilise pas dans son intégralité. Voici donc le contenu complet que ce fichier doit avoir (et rien de plus) :

#%PAM-1.0
auth sufficient pam_unix.so
account sufficient pam_unix.so
auth       required     /lib/security/pam_userdb.so db=/etc/vsftpd/login
account    required     /lib/security/pam_userdb.so db=/etc/vsftpd/login

Les lignes 2 et 3 permettent la connexion des utilisateusr système, les 4 et 5 la connexion des utilisateurs virtuels placés dans notre base.

ATTENTION, les utilisateurs utilisant uen distribution 64 bits doivent utiliser /lib64/ et non /lib/.

On peut relancer notre serveur (en su -) :

# service vsftpd restart

Voilà notre serveur prêt à l'emploi.

ATTRIBUTION / PERSONNALISATION DES DROITS

Testons notre serveur

ftp localhost

Entrez comme user "titi" et pass "passtiti". La connexion doit être OK.

Placez un fichier dans /var/ftp/ et reconnectez vous. Une fois connecté, tapez la commande "ls". Vous devez voir votre fichier.

Tout cela est bien gentil, mais perso si je créé des comptes, c'est pour avoir des droits différents pour chacun, et surtout que chacun ai son propre répertoire (qui peut être un sous répertoire du local_root, ou pourquoi pas un autre). Vous avez vu que dans la configuration, nous utilisons la directive "user_config_dir=/etc/vsftpd/vsftpd_user_conf". Ce dossier nous permet de stocker dans des fichiers séparés des configurations spécifiques à chaque utilisateur. Dans ces fichiers, on entre des paramètres (les mêmes que ceux du fichier de configuration) qui seront prioritaires par rapport au fichier de configuration principal. Généralement, on y modifie le local_root, et les droits d'écriture. On y met un fichier par utilisateur, et le fichier porte le même nom que le login de l'utilisateur auquel il fait référence. Créons un dossier "titi" dans /var/ftp, changeons le de propriétaire puis modifions le local_root et les droits d'écriture pour cet utilisateur :

# mkdir /var/ftp/titi
# chown ftp:ftp /var/ftp/titi
# echo "local_root=titi" > /etc/vsftpd/vsftpd_user_conf/titi
# echo "write_enable=YES" >> /etc/vsftpd/vsftpd_user_conf/titi
# echo "anon_upload_enable=YES" >> /etc/vsftpd/vsftpd_user_conf/titi
# echo "anon_mkdir_write_enable=YES" >> /etc/vsftpd/vsftpd_user_conf/titi
# echo "anon_other_write_enable=YES" >> /etc/vsftpd/vsftpd_user_conf/titi

Nottez que l'on aurait pû mettre un répertoire absolu pour le local_root, par exemple /var/www/html/le_site_de_titi, mais en s'assurant que l'utilisateur ftp ai les droits adéquats sur ce dossier.

Reconnectez vous avec l'utilisateur titi, il vous ai maintenant possible de déposer des fichiers.

Reportez vous à la page de man pour les détails sur les paramètres de configuration.

Il est possible que parfois lorsque vous vous connectiez, vous aillez cette erreur :

500 OOPS: reading non-root config file

Cela intervient si l'utilisateur n'a pas de fichier spécifique dans vsftpd_user_conf (même vide). Il semble que ce soit un bug. Si vous avez ce souci, créez un fichier pour cet utilisateur. Nous verrons ensuite que l'on peut faire cela automatiquement.

Edit : MarbolanGos nous indique dans les commentaires de ce billet qu'une autre erreur peut survenir :

500 OOPS: cannot change directory:<repertoire>

Dans ce cas, voilà la solution (en root) :

/usr/sbin/setsebool -P ftp_home_dir 1

Se simplifier la vie

La commande pour générer le fichier db à partir du txt est lourde a retenir, et de plus il est intéressant de pouvoir générer un fichier de configuration spécifique vide pour chaque utilisateur pour ne pas avoir d'erreur. Voici un petit script (surement optimisable) appellé txt2db.sh faisant cela pour vous. Il regénère le fichier db, et créé un fichier de config vide s'il n'existe pas. Vous trouverez ce fichier en pièce jointe à ce billet. En voici le contenu :

#!/bin/sh
if [ $# = "2" ]; then
        rm -f $2
        db_load -T -t hash -f $1 $2
        chmod 600 /etc/vsftpd/login.*
        echo "Base cree"
        lignes=$(cat $1)
        nb=1
        for ligne in $lignes
        do
                if [ $(($nb%2)) -ne 0  ];
                then
                        if [ ! -e vsftpd_user_conf/$ligne ];
                        then
                                touch /etc/vsftpd/vsftpd_user_conf/$ligne
                                echo "fichier $ligne cree"
                        fi
                fi
                nb=$(($nb+1))
        done
else
        echo "Il faut donner le fichier d'entree et le fichier de sortie"
fi

et son utilisation :

# cd /etc/vsftpd/
# chmod +x txt2db.sh (à ne faire que la première fois)
# ./txt2db.sh login.txt login.db

Ce script lie les lignes du login.txt et pour chaque login, vérifie si un fichier de conf existe. Si ce n'est pas le cas il en créé un vide. Auparavant il génère le fichier db.

L'autre soucis est que si vous supprimez un utilisateur du login.txt, il restera toujours le fichier spécifique de configuration. Voici un script appellé "cleanconf.sh" qui supprime tous les fichiers spécifiques n'ayant pas de login associé. Vous le trouverez aussi en pièce jointe. Son contenu :

fichiers=$(ls /etc/vsftpd/vsftpd_user_conf)
users=""
lignes=$(cat /etc/vsftpd/login.txt)
nb=1
for ligne in $lignes
do
        if [ $(($nb%2)) -ne 0  ];
        then
                users="$users $ligne"
        fi
        nb=$(($nb+1))
done
for conf in $fichiers
do
        found=0
        for user in $users
        do
                if [ $conf = $user ];
                then
                        found="1"
                fi
        done
        if [ $found != "1" ];
        then
                rm -f vsftpd_user_conf/$conf
                echo "Fichier $conf supprime"
        fi
done

Son utilisation :

# chmod +x cleanconf.sh
# ./cleanconf.sh

Voila qui nous simplifiera un peu la vie.

Conclusion

Voila un petit serveur FTP prêt, avec une gestion facile d'utilisateurs virtuels. Il est de plus pour chaque utilsiateur possible de modifier chaque valeur de la configuration principale, ce qui rend la gestion des utilisateurs virtuels très souple. Pour plus de sécurité, il est possible de faire du FTP over SSH.

J'ai définitivement adopté vsftpd, très légé, dispo de base, et si vite mis en place. La gestion est aussi très aisée (n'oubliez pas que vous pouvez stocker cos utilsiateurs dans chaque type de stockage supporté par PAM), et le principe de configuration détaillée pour les utilisateurs virtuels permet des réglages fins.

Cependant comparé à pureftpd, il me manque encore certaines petites choses, pas indispensables mais qui étaient sympa. Je ne sais pas encore si vsftpd permet ces choses. Il permettait notemment de voir les transferts actifs, et de limiter en bande passante et surtout en horraires les utilisateurs.

En espérant que cet article donnera un coup de main.

Fabien