Serveur FTP · 7 min read · Dec 17, 2025

PostgreSQL et Proftpd

Alors vous voulez configurer un serveur ftp, vous avez besoin de fonctionnalités avancées et vous ne savez pas où vous tourner ? Essayez proftpd.

Partie 1 : Configuration de proftpd avec un backend postgresql

Ce tutoriel est très spécifique, je vais couvrir uniquement proftpd, et seulement dans la mesure où le rendre opérationnel avec Postgres. Une compréhension de base de proftpd et de Postgres est supposée. Ce tutoriel vous permettra de faire fonctionner proftpd assez rapidement, et de l’utiliser avec une base de données, si cette base de données a des déclencheurs, les possibilités de cette configuration sont presque infinies.

Obtenir Proftpd

Tout d’abord, vous aurez besoin de proftpd, j’utiliserai Dapper d’Ubuntu ; il existe un méta-paquet préparé grâce à Francesco Paolo Lovergine intitulé “proftpd-pgsql,” qui mettra en place une copie de proftpd compilée avec les modules suivants. En passant, bien que proftpd soit livré avec les mods, le fichier de configuration est le modèle standard de proftpd. Je vous recommande vivement de consulter la documentation de mod_sql, qui bien que médiocre est tout de même utile – les docs sur le site de proftpd sont très anciennes, utilisez plutôt celles-ci : Lien vers la documentation. De plus, faites attention à la version, proftpd est maintenant à 1.3, bien que j’utiliserai 1.2.10 – la version utilisée dans Dapper.

Les mods compilés dans cette version de proftpd sont les suivants

  mod_core.c  
  mod_xfer.c  
  mod_auth_unix.c  
  mod_auth_file.c  
  mod_auth.c  
  mod_ls.c  
  mod_log.c  
  mod_site.c  
  mod_auth_pam.c  
  mod_quotatab.c  
  mod_sql.c  
  mod_sql_postgres.c  
  mod_quotatab_sql.c  
  mod_ratio.c  
  mod_tls.c  
  mod_rewrite.c  
  mod_radius.c  
  mod_wrap.c  
  mod_quotatab_file.c  
  mod_delay.c  
  mod_readme.c  
  mod_ifsession.c  
  mod_cap.c

Allez-y et émettez la commande pour obtenir proftpd-pgsql :

apt-get install proftpd-pgsql

Configuration des permissions.

Pour mon besoin, (rappelez-vous, je suis le centre de l’univers) tout ce dont j’avais besoin était une structure unidimensionnelle, car les groupes sont stockés à un niveau différent plutôt qu’avec les permissions unix. Ainsi, tous les fichiers devraient arriver avec des permissions statiques – je ne me soucie que du propriétaire et du groupe du propriétaire. Mon plan était de faire en sorte que l’utilisateur par défaut de proftpd, ftp, appartienne à son propre groupe nommé de manière appropriée que j’allais créer – ‘ftp’. J’allais ensuite faire de Postgres un membre de ce groupe, voir la partie 2 pour la raison. J’avais besoin que les deux soient membres du même groupe, et j’avais besoin que le dossier chroot de proftpd soit 775, afin que tout le groupe puisse ajouter (déplacer) des fichiers, j’ai également fait en sorte que le dossier soit possédé par l’utilisateur ‘ftp’, avec le groupe ‘ftp’. J’ai accompli cela avec le script suivant.

groupadd ftp
usermod -G ftp ftp
usermod -G ftp,postgres postgres
chown ftp:ftp ./ftp_directory/
chmod 775 ./ftp_directory/

Configuration de Postgres

Maintenant, nous allons préparer nos tables sql. Je conçois en utilisant des schémas, et c’est ce que le préfixe ‘ftp.’ sur les tables est pour. J’ai mis toutes mes tables dans un schéma ftp, il y a une chose à noter, j’ai été extrêmement restrictif sur les permissions pour ce projet, car je ne suis pas sûr de la sécurité de mod_sql. Ce faisant, j’ai créé un utilisateur spécial, nommé proftp, pour proftpd dans ma base de données (qui est utilisée par plus d’applications que proftpd), cet utilisateur est restreint aux sélections sur la auth_table, et aux insertions sur la table file_log. Je vous recommande fortement d’adopter une forme de cette politique. Au minimum, cela empêche un certain degré d’attaques par injection sql dévastatrices ou de fuites d’informations dans le cas où le code de mod_sql n’est pas aussi sécurisé que nous aimerions le penser. Une rapide recherche sur Google révèle un problème de sécurité précédent avec le code de mod_sql. Chaque requête que mod_sql envoie à la base de données est appendue avec une clause “LIMIT 1”, et avec mod_delay également configuré par défaut, je trouve cela suffisant pour ce projet.

Mon script d’initialisation sql est le suivant.

ALTER USER proftp UNENCRYPTED PASSWORD 'dealermadeftp';
CREATE SCHEMA ftp;
GRANT USAGE ON SCHEMA ftp TO proftp;

CREATE TABLE ftp.users (
        pkid      serial      PRIMARY KEY,
        userid    text        NOT NULL UNIQUE,
        passwd    text,
        uid       int,
        gid       int,
        homedir   text,
        shell     text
);
GRANT SELECT ON ftp.users TO proftp;
INSERT INTO ftp.users ( userid, passwd ) VALUES ( 'ecarroll', 'adm1n' );
INSERT INTO ftp.users ( userid, passwd ) VALUES ( 'jgallagher', 'adm1n' );

CREATE TABLE ftp.file_log (
        pkid               serial      PRIMARY KEY,
        userid             text        REFERENCES ftp.users(userid),
        abs_path           text,
        file               text,
        dns                text,
        time_transaction   text,
        ts_in              timestamp with time zone   NOT NULL DEFAULT CURRENT_TIMESTAMP
);
GRANT INSERT ON ftp.file_log TO proftp;
GRANT UPDATE ON TABLE ftp.file_log_pkid_seq TO proftp;

Connectez-vous à votre base de données et exécutez cela avec :

\i script_name

ou, vous pouvez envoyer ‘–file script_name’ à psql en tant qu’argument de ligne de commande.

Ceux sur des bases de données moins performantes (utilisant ce tutoriel avec mysql), vous voudrez peut-être remplacer text par varchar ; mais, en raison de la conception de Postgres, il n’y a aucun avantage à cela.

Configuration de proftpd

Cette partie est délicate et varie légèrement si vous utilisez 1.3 – encore une fois, ce tutoriel est pour 1.2.10.

J’ai ajouté cette partie à mon fichier de configuration par défaut de proftpd, situé à /etc/proftpd.conf :

AuthOrder            mod_sql.c
SQLAuthTypes         Plaintext Empty
SQLAuthenticate      users
SQLConnectInfo       proftpd@localhost proftp dealermadeftp

SQLDefaultUID        110   # CHANGEZ POUR LE UID DE VOS UTILISATEURS FTP TROUVÉ DANS /etc/passwd
SQLDefaultGID        1001  # CHANGEZ POUR LE GID DE VOS UTILISATEURS FTP, TROUVÉ DANS /etc/groups
SQLDefaultHomedir    /home/ftp
RequireValidShell    off

SQLUserInfo          ftp.users userid passwd uid gid homedir shell

SQLNegativeCache     off
SQLLogFile           /var/log/proftpd-sql
SQLLog               STOR newfile
SQLNamedQuery        newfile FREEFORM "INSERT INTO ftp.file_log(userid,abs_path,file,dns,time_transaction) VALUES ('%U','%f','%J','%V','%T')"

# %U => userid
# %D => --Rien,
# %f => abs_path
# %J => file
# %h => dns_remote, %V => dns_local
# %a => remote_ip, %L => local_ip
# %t => localtime
# %T => transfer_time
  • Les variables de modèle sont commentées et uniquement pour votre propre référence. Un bref aperçu de la configuration est le suivant :
  1. Ici, nous définissons l’AuthOrder, à mod_sql.c, activant ainsi mod_sql.
  2. J’ai choisi d’utiliser des mots de passe en texte clair, ou dans le cas où je n’en attribue pas, d’autoriser des mots de passe vides. ( Je vais plus tard mettre en œuvre un déclencheur pour SHA1 les mots de passe dans la base de données. )
  3. J’ai ensuite défini SQLAuthenticate sur users, j’ai choisi de ne pas utiliser de groupes pour ce projet, si vous avez besoin de groupes, plus d’informations peuvent être trouvées sur ces tables à : Ce site pour la documentation sur les groupes.
  4. SQLConnectInfo est le dsn au format “base_de_données@hôte utilisateur mot_de_passe,”
  5. SQLDefaultUID, SQLDefaultGID, SQLDefaultHomedir, configurent le défaut, laissant la majorité de mes colonnes à NULL, je vais rarement remplacer cela.
  6. RequireValidShell est également défini sur off, si vous le définissez sur on, et fournissez un shell invalide, vous échouerez à l’authentification.
  7. Le SQLUserInfo correspond aux tables Postgres, c’est un mappage littéral, encore une fois le “ftp.” spécifie le schéma pour la table d’authentification.
  8. SQLNegativeCache, met en cache les échecs d’authentification,
  9. SQLLogFile pour un journal détaillé lors de la configuration de votre serveur. Je vais désactiver cela lorsque je passerai en production.
  10. SQLLog spécifie quelle action ftp vous souhaitez enregistrer, car mes utilisateurs ne peuvent que télécharger, j’enregistre uniquement STOR, le format est ‘ftpaction requête_à_exécuter’.
  11. SQLNamedQuery Vérifiez la syntaxe dans la documentation à ce sujet pour une meilleure explication, le format que j’utilise est ‘qryname FREEFORM requête_personnalisée_ici’, je fais cela principalement parce que je souhaite capturer beaucoup des variables de modèle de proftpd, il existe d’autres syntaxes plus simples.

C’est tout. Si tout se passe comme prévu, vous devriez être opérationnel. Maintenant, quand quelqu’un télécharge un fichier, cela devrait être le résultat :

proftpd=# select * from ftp.file_log;
 pkid |  userid  |        abs_path        |     file      |  dns  | time_transaction |             ts_in 
------+----------+------------------------+---------------+-------+------------------+-------------------------------
    1 | ecarroll | /home/ftp/foo/testfile | /foo/testfile | AMD64 | 0.000            | 2006-06-11 20:49:12.623375-05
(1 ligne)

Partie II : Au-delà de ‘fonctionnel’

… Mais fonctionnel n’est jamais suffisant, n’est-ce pas ? Passons à répondre à la question suivante posée dans la faq de configuration pour proftpd :
Puis-je faire pivoter des fichiers d’un répertoire de téléchargement après le téléchargement ?

Et la réponse, vous le pouvez certainement. Je vais accomplir cela par le biais d’une procédure stockée, de cette façon les fichiers sont déplacés de la bonne manière – à la volée – sans un démon.

Vous devrez d’abord installer untrusted plperlu sur le système, cela peut être accompli avec

apt-get install postgresql-plperl-8.1

Ensuite, vous devez installer plperlu sur la base de données

createlang plperlu votre_base_de_données_ici

Ensuite, nous devons créer un déclencheur de script perl rapide, qui se déclenchera à chaque insertion dans notre table ftp_log

CREATE OR REPLACE FUNCTION ftp_file() RETURNS TRIGGER AS $$
        use warnings;
        use Cwd;
        use File::Basename;
        use File::Spec;
        use File::Copy;
        move (
                $_TD->{new}{abs_path},
                File::Spec->catfile( '/home/ftp/', basename($_TD->{new}{file}) )
        );
        return;
$$ LANGUAGE 'plperlu' VOLATILE;

CREATE TRIGGER ftp_file
        BEFORE INSERT
        ON ftp.file_log
        FOR EACH ROW
        EXECUTE PROCEDURE ftp_file()
;

Ce script sql peut être installé de la même manière que le précédent, (celui utilisé pour créer les tables)

Share: X/Twitter LinkedIn

Recevez de nouveaux articles dans votre boîte de réception.

Aucun spam. Désabonnez-vous à tout moment.