ProFTPD, MySQL et Quota
Cet article a été publié sur Lea Linux
Le support des quotas n'est que partiel : si l'upload d'un fichier entraine le dépassement d'un quota, le fichier sera uploadé jusqu'à la fin puis supprimé sans que l'utilisateur en soit informé.
Introduction
Au début, j'utilisais le serveur ProFTPD avec la configuration
d'origine (ou presque), donc sur la base de l'authentification unix. J'ai eu besoin de modifier
regulièrement les comptes FTP. Ajouter et supprimer les utlisateurs (compte linux) devînt vite lourd. Je me suis donc penché sur le support MySQL de ProFTPD et je vous propose mes explications.
Le fait d'utiliser l'authentification de ProFTPD par base de
données vous permet, par exemple, de faire
une page php de configuration ou d'administrer facilement vos comptes ftp
via l'interface Web PHPMyAdmin.
Prérequis
Je vous conseille de lire d'abord le tutoriel de DuF : Introduction à proftpd
Il vous faut un système avec un serveur MySQL installé
avec si possible un serveur web et PHPMyAdmin
pour faciliter l'administration de la BD.
Rmq : Ce document peut aussi convenir à la
configuration du support PostGreSQL.
Installation
- Soit vous installez ProFTPD à partir de package. (Soyez sur que
le package va installer le support MySQL)
- Soit à partir des sources.
Sous Debian (apt)
Il suffit de taper en tant que
root :
#apt-get install proftpd-mysql
A partir des sources
Téléchargez les sources en allant sur le site de proftpd pour obtenir la version
la plus récente.
Décompressez-les et lancez la compilation :
tar jxvf proftpd-version.tar.bz2
cd proftpd-version
./configure\
--with-modules=mod_sql:mod_sql_mysql:mod_quotatab:mod_quotatab_sql\
--with-includes=/usr/include/mysql\
--with-libraries=/usr/lib
make
Et en tant que root : make install
Configuration
La base de données
Entrez dans l'interface de la base de données :
- si vous n'avez jamais modifier les utilisateurs de la base :
mysql -u root
- sinon (avec un utilisateur/pwd ayant le droit de modifier la base):
mysql -u utilisateur -p
Il faut tout d'abord créer la base de données (ex :
proftpd) et les tables qu'elle contient.
CREATE DATABASE `proftpd`;
USE proftpd;
--
-- Table structure for table `ftpgroup`
--
CREATE TABLE `ftpgroup` (
`groupname` varchar(16) NOT NULL default '',
`gid` smallint(6) NOT NULL default '5500',
`members` varchar(16) NOT NULL default '',
KEY `groupname` (`groupname`)
) TYPE=MyISAM COMMENT='Table des groupes ProFTPD';
--
-- Table structure for table `ftpquotalimits`
--
CREATE TABLE `ftpquotalimits` (
`name` varchar(30) default NULL,
`quota_type` enum('user','group','class','all') NOT NULL default 'user',
`par_session` enum('false','true') NOT NULL default 'false',
`limit_type` enum('soft','hard') NOT NULL default 'soft',
`bytes_up_limit` float NOT NULL default '0',
`bytes_down_limit` float NOT NULL default '0',
`bytes_transfer_limit` float NOT NULL default '0',
`files_up_limit` int(10) unsigned NOT NULL default '0',
`files_down_limit` int(10) unsigned NOT NULL default '0',
`files_transfer_limit` int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM COMMENT='Table des quotas ProFTPD';
--
-- Table structure for table `ftpquotatotal`
--
CREATE TABLE `ftpquotatotal` (
`name` varchar(30) NOT NULL default '',
`quota_type` enum('user','group','class','all') NOT NULL default
'user',
`bytes_up_total` float NOT NULL default '0',
`bytes_down_total` float NOT NULL default '0',
`bytes_transfer_total` float NOT NULL default '0',
`files_up_total` int(10) unsigned NOT NULL default '0',
`files_down_total` int(10) unsigned NOT NULL default '0',
`files_transfer_total` int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM COMMENT='Table des compteurs des quotas ProFTPD';
--
-- Table structure for table `ftpuser`
--
CREATE TABLE `ftpuser` (
`id` int(10) unsigned NOT NULL auto_increment,
`userid` varchar(32) NOT NULL default '',
`passwd` varchar(32) NOT NULL default '',
`uid` smallint(6) NOT NULL default '5500',
`gid` smallint(6) NOT NULL default '5500',
`homedir` varchar(255) NOT NULL default '',
`shell` varchar(16) NOT NULL default '/bin/false',
`count` int(11) NOT NULL default '0',
`accessed` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`LoginAllowed` enum('true','false') NOT NULL default 'true',
PRIMARY KEY (`id`)
) TYPE=MyISAM COMMENT='Table des utlisateurs ProFTPD';
Ensuite il faut créer un nouvel utilisateur (ex : proftpd) avec
un mot de passe (ex : password) qui a seulement les droits de lire les
données de la base proftpd:
GRANT USAGE ON proftpd.* TO
'proftpd'@'localhost'
IDENTIFIED BY 'password' WITH GRANT OPTION;
Attention : Si votre serveur MySQL n'est sur la
même machine que ProFTPD remplacer localhost par le nom de la
machine (du serveur MySQL) ou par *
Configuration de ProFTPD
Editez le fichier /etc/proftpd.conf.
# Configuration de base
# =====================
ServerName "Mon serveur FTP"
ServerType standalone
ServerIdent on "Bienvenue sur mon ftp. Veuillez-vous
identifiez"
DeferWelcome on
ServerAdmin "ftp_admin@mydomain.com"
MultilineRFC2228 on
DefaultServer on
ShowSymlinks on
AllowOverwrite on
TimeoutNoTransfer 600
TimeoutStalled 600
TimeoutIdle 1200
ListOptions "-l"
Defaultroot ~
DenyFilter \*.*/
Port 21
# A configurer selon sa connection
# ================================
MaxInstances 6
MaxLoginAttempts 3
MaxClientsPerUser 10
MaxClientsPerHost 2
MaxHostsPerUser 4
MaxClients 6 "Limite a 6 utilisateurs"
# ProFTPD est excecuté avec des droits réduits
# ============================================
User nobody
Group nogroup
Umask 022
AllowStoreRestart on
AllowRetrieveRestart on
# Mod MySQL
# =========
# Les mots de passe sont crypté ds la base avec la fct ENCRYPT
(MySQL)
SQLAuthTypes Crypt
SQLAuthenticate users* groups*
# Modifiez cette ligne selon l'utilisateur et le mot de passe
définit plutôt
SQLConnectInfo proftpd@localhost proftpd password
# On donne à ProFTPD le nom des colonnes de la table usertable
SQLUserInfo ftpuser userid passwd uid gid homedir shell
SQLUserWhereClause "LoginAllowed = 'true'"
# On donne à ProFTPD le nom des colonnes de la table
"grouptable"
SQLGroupInfo ftpgroup groupname gid members
# Créer le repertoire home de l'utilisateur si il n'existe pas
SQLHomedirOnDemand on
# Met à jour les compteurs à chaque connection d'un
utilisateur
SQLLog PASS updatecount
SQLNamedQuery updatecount UPDATE "count=count+1, accessed=now() WHERE
userid='%u'" ftpuser
#Met à jour les compteurs à chaque upload ou download d'un
utilisateur
SQLLog STOR,DELE modified
SQLNamedQuery modified UPDATE "modified=now() WHERE userid='%u'"
ftpuser
# Mod quota
# =========
QuotaEngine on
QuotaDirectoryTally on
QuotaDisplayUnits Mb
QuotaShowQuotas on
# Définit les requêtes SQL pour que ProFTPd recupere les
infos sur les quotas
SQLNamedQuery get-quota-limit SELECT "name, quota_type, par_session,
limit_type, bytes_up_limit, bytes_down_limit, bytes_transfer_limit,
files_up_limit, files_down_limit, files_transfer_limit FROM ftpquotalimits
WHERE name = '%{0}' AND quota_type = '%{1}'"
SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_up_total,
bytes_down_total, bytes_transfer_total, files_up_total, files_down_total,
files_transfer_total FROM ftpquotatotal WHERE name = '%{0}' AND quota_type =
'%{1}'"
SQLNamedQuery update-quota-tally UPDATE "bytes_up_total = bytes_up_total +
%{0}, bytes_down_total = bytes_down_total + %{1}, bytes_transfer_total =
bytes_transfer_total + %{2}, files_up_total = files_up_total + %{3},
files_down_total = files_down_total + %{4}, files_transfer_total = files_transfer_total
+ %{5} WHERE name = '%{6}' AND quota_type = '%{7}'" ftpquotatotal
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4},
%{5}, %{6}, %{7}" ftpquotatotal
QuotaLimitTable sql:/get-quota-limit
QuotaTallyTable
sql:/get-quota-tally/update-quota-tally/insert-quota-tally
RootLogin off
RequireValidShell off
# Gestion des logs
# ================
# Enregistre les requêtes SQL dans /var/log/proftpd/mysql.log
SQLLogFile /var/log/proftpd/mysql.log
# Enregistre les authentifications
LogFormat auth "%v [%P] %h %t \"%r\" %s"
ExtendedLog /var/log/proftpd/auth.log AUTH auth
# Enregistre les accès aux fichiers
LogFormat write "%h %l %u %t \"%r\" %s %b"
ExtendedLog /var/log/proftpd/access.log WRITE,READ write
# Recupère le nom à partir de l'ip de la machine de
l'utilisateur ( resolution DNS )
IdentLookups on
Maintenant vous pouvez redémarrez le serveur ProFTPd pour
appliquer la configuration :
/etc/init.d/proftpd restart
Utilisation
Maintenant que la configuration est faite, nous allons voir comment gérer les utilisateurs à travers la base de données.
Je vous conseille d'utiliser PHPMyAdmin pour ceux qui ne connaissent pas le langage SQL.
Gestion des utilisateurs
Ajout d'un utilisateur
Création de l'utilisateur 'test' avec un mot de passe 'pwd'. Cet
utilisateur a accès au repertoire '/home/ftp/test' avec les droits
de l'utilisateur (UID) 5500, et de groupe (GID) 5500, sans shell
('/bin/false').
La valeur 'LoginAllowed' est mise à 'true' pour autoriser la
connection de cet utilisateur, à 'false' pour l'interdire.
INSERT INTO `ftpuser` ( `id`, `userid`, `passwd`, `uid`,
`gid`, `homedir`, `shell`, `count`, `accessed` , `modified`,
`LoginAllowed` )
VALUES ('', 'test', ENCRYPT('pwd'), '5500', '5500', '/home/ftp/test',
'/bin/false', '', '', '', 'true'
);
'count' représente le nombre d'authentifications
effectués par cet utilisateur,
'accessed' la date du dernier accès et
'modified' la date de
la dernière écriture.
Suppression d'un utilisateur
Suppression de l'utilisateur 'test'
DELETE FROM `ftpuser` WHERE `userid`='test';
DELETE FROM `ftpgroup` WHERE `members`='test';
Gestion des groupes
Affecter un utilisateur à un groupe
Affecte l'utilisateur 'test' au groupe 'group_test' avec les droits de groupe (GID) du groupe 5500
INSERT INTO `ftpgroup` ( `groupname` , `gid` , `members` )
VALUES ('group_test', '5500', 'test');
Enlever un utilisateur d'un groupe
Enlève l'utilisateur 'test' du groupe 'group_test'
DELETE FROM `ftpgroup` WHERE `members`='test';
Gestion des quotas
La table 'ftpquotalimits' contient la description des quotas.
La table 'ftpquotatotal' contient les statistiques d'utilisation correspondant aux règles des quotas défini dans la table 'ftpquotalimits'. Cette table permet à ProFTPd de gérer les quotas.
Ajouter une règles de quotas
Executer la requête suivante :
INSERT INTO `ftpquotalimits` ( `name`, `quota_type`, `par_session`, `limit_type`, `bytes_up_limit`, `bytes_down_limit`, `bytes_transfer_limit`, `files_up_limit`, `files_down_limit`, `files_transfer_limit` )
VALUES ( 'NOM' , 'TYPE', 'SESSION', 'LIMIT_TYPE', 'B_UP', 'B_DOWN', 'B_TRANS', 'F_UP', 'F_DOWN', 'F_TRANS');
où
- NOM : nom de l'utilisateur, du groupe ou de la règle selon la valeur de TYPE.
- TYPE : 'user' si le quota s'applique à un utilisateur, 'group' à un groupe, 'class' à une classe (ici inutile), 'all' à tous les utilisateurs.
- SESSION : 'true' si les quotas doivent être remis à zéro à chaque nouvelle session, 'false' sinon. ('false' est conseillé).
- LIMIT_TYPE : 'soft' pour une mesure logicielle de la taille, 'hard' pour une mesure hardware.
- B_UP : taille (en Mbytes) autorisé à être uploadé sur le serveur.
- B_DOWN : taille (en Mbytes) autorisé à être downloadé à partir du serveur.
- B_TRANS : taille (en Mbytes) autorisé à transféré à sur et à partir du serveur (upload+download).
- F_UP : nombre de fichiers autorisé à être uploadé sur le serveur.
- F_DOWN : nombre de fichiers autorisé à être downloadé à partir du serveur.
- F_TRANS : nombre de fichiers autorisé à transféré à sur et à partir du serveur (upload+download).
Pour définir un quota illimité à un des champs, mettez une valeur négative ou nulle
Attention : Les quotas de type 'all', 'class' ou 'group' ne définissent pas un quota pour chaque utilisateur mais un quota partagé par tous les utlisateurs concernés par cette règle.
Réinitialiser les quotas
Il suffit de supprimer l'entrée (ligne) correspondant à la règle devant être réinitialisé. Par exemple :
DELETE FROM `ftpquotatotal` WHERE `name`='test' AND `quota_type`='user';
Si vous voulez réinitialiser tous les quotas, par exemple tous les mois, faîtes une tâche cron se connectant sur le serveur et executant la requête suivante :
TRUNCATE TABLE `ftpquotatotal`;
Et voilà, c'est terminé... Vous avez plus qu'à tester ;-)