Серверы FTP · 6 min read · Dec 17, 2025

PostgreSQL и Proftpd

Итак, вы хотите настроить ftp-сервер, вам нужна расширенная функциональность, и вы не знаете, к кому обратиться? Попробуйте proftpd.

Часть 1: Настройка proftpd с использованием PostgreSQL в качестве бэкенда

Этот учебник очень узкоспециализированный, я собираюсь рассмотреть только proftpd и только в той мере, чтобы сделать его работоспособным с Postgres. Предполагается базовое понимание proftpd и Postgres. Этот учебник поможет вам быстро запустить proftpd и использовать базу данных, если эта база данных имеет триггеры, возможности этой конфигурации практически безграничны.

Получение Proftpd

Сначала вам понадобится proftpd, я буду использовать Dapper от Ubuntu; есть мета-пакет, подготовленный благодаря Франческо Паоло Ловерджине, под названием “proftpd-pgsql”, который установит копию proftpd, скомпилированную с следующими модулями. В качестве примечания, хотя proftpd поставляется с модулями, конфигурационный файл является стандартным шаблоном proftpd. Я настоятельно рекомендую вам ознакомиться с документацией mod_sql, которая, хотя и не идеальна, все же полезна — документация на сайте proftpd очень старая, используйте вместо этого: Ссылка на документацию. Также будьте осторожны с версией, proftpd сейчас на 1.3, хотя я буду использовать 1.2.10 — версия, используемая в Dapper.

Список модулей, скомпилированных в эту версию proftpd:

  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

Продолжайте и выполните команду для установки proftpd-pgsql:

apt-get install proftpd-pgsql

Настройка прав доступа.

Для моих целей (помните, я — центр вселенной) все, что мне нужно, это одноразовая структура, потому что группы хранятся на другом уровне, а не в unix-правах. Поэтому все файлы должны приходить со статическими правами — меня интересует только владелец и группа владельца. Мой план заключался в том, чтобы сделать пользователя по умолчанию proftpd, ftp, членом своей собственной, удачно названной группы, которую я собирался создать — ‘ftp’. Затем я собирался сделать Postgres членом этой группы, смотрите часть 2 для объяснения. Мне нужно было, чтобы оба были членами одной группы, и мне нужно было, чтобы папка chroot proftpd имела права 775, чтобы вся группа могла добавлять (перемещать) файлы, я также сделал папку владельцем пользователя ‘ftp’ с группой ‘ftp’. Я достиг этого с помощью следующего скрипта.

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

Настройка Postgres

Теперь мы собираемся подготовить наши sql таблицы. Я проектирую, используя схемы, и именно для этого предназначен префикс ‘ftp.’ в таблицах. Я поместил все свои таблицы в схему ftp, есть одна вещь, которую стоит отметить, я был крайне ограничительным в отношении прав доступа для этого проекта, потому что я не уверен, насколько безопасен mod_sql. В результате я создал специального пользователя, по имени proftp, для proftpd в своей базе данных (которую используют больше приложений, чем proftpd), этот пользователь ограничен выборками из auth_table и вставками в таблицу file_log. Я настойчиво рекомендую вам принять какую-либо форму этой политики. По крайней мере, это предотвращает некоторую степень разрушительных атак SQL-инъекций или утечек информации в случае, если код mod_sql не так безопасен, как нам хотелось бы думать. Быстрый поиск в Google показывает предыдущую проблему безопасности с кодовой базой mod_sql. Каждый запрос, который mod_sql отправляет в базу данных, дополнен условием “LIMIT 1”, и с mod_delay, также настроенным по умолчанию, я считаю это достаточным для этого проекта.

Мой sql инициализационный скрипт выглядит следующим образом.

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;

Подключитесь к вашей базе данных и выполните это с:

\i script_name

или вы можете использовать отправку ‘–file script_name’ в psql в качестве аргумента командной строки.

Тем, кто использует менее мощные базы данных (используя этот учебник с mysql), возможно, стоит заменить text на varchar; но, из-за дизайна Postgres, в этом нет преимущества.

Настройка proftpd

Эта часть сложная и немного отличается, если вы используете 1.3 — еще раз, этот учебник предназначен для 1.2.10.

Я добавил эту часть в свой стандартный конфигурационный файл proftpd, расположенный по адресу /etc/proftpd.conf:

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

SQLDefaultUID        110   # ИЗМЕНИТЕ ДЛЯ UID ВАШИХ FTP-ПОЛЬЗОВАТЕЛЕЙ, НАЙДЕННЫХ В /etc/passwd
SQLDefaultGID        1001  # ИЗМЕНИТЕ ДЛЯ GID ВАШИХ FTP-ПОЛЬЗОВАТЕЛЕЙ, НАЙДЕННЫХ В /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 => --Ничего,
# %f => abs_path
# %J => file
# %h => dns_remote, %V => dns_local
# %a => remote_ip, %L => local_ip
# %t => localtime
# %T => transfer_time
  • Шаблонные переменные прокомментированы и предназначены только для вашего собственного справки. Краткий обзор конфигурации:
  1. Здесь мы устанавливаем AuthOrder на mod_sql.c, что, в свою очередь, включает mod_sql.
  2. Я выбрал использовать пароли в открытом виде или, в случае, если я не назначу один, разрешить пустые пароли. (Позже я реализую триггер для SHA1 паролей в базе данных.)
  3. Затем я устанавливаю SQLAuthenticate на users, я решил не использовать группы для этого проекта, если вам нужны группы, больше информации можно найти в этих таблицах на: Этот сайт для документации по группам.
  4. SQLConnectInfo — это DSN в формате “database@host user password,”.
  5. SQLDefaultUID, SQLDefaultGID, SQLDefaultHomedir настраивают значения по умолчанию, оставляя большинство моих столбцов NULL, я редко переопределяю это.
  6. RequireValidShell также установлен на off, если вы установите его на on и введете недопустимую оболочку, вы не пройдете аутентификацию.
  7. SQLUserInfo соответствует таблицам Postgres, это буквальное сопоставление, снова “ftp.” указывает на схему для таблицы аутентификации.
  8. SQLNegativeCache кэширует неудачи аутентификации,
  9. SQLLogFile для подробного ведения журнала во время настройки вашего сервера. Я отключу это, когда перейду в продакшн.
  10. SQLLog указывает, какое действие FTP вы хотите записать, поскольку мои пользователи могут только загружать, я записываю только STOR, формат — ‘ftpaction query_to_execute’.
  11. SQLNamedQuery Проверьте синтаксис в документации для лучшего объяснения, формат, который я использую, — ‘qryname FREEFORM custom_query_here’, я делаю это в основном потому, что хочу захватить много шаблонных переменных proftpd, есть другие более простые синтаксисы.

Вот и все. Если все пойдет по плану, вы должны быть готовы к работе. Теперь, когда кто-то загружает файл, это должно быть результатом:

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 row)

Часть II: За пределами ‘работы’

… Но работа никогда не бывает достаточной, верно? Давайте перейдем к ответу на следующий вопрос, размещенный в FAQ по конфигурации для proftpd:
Могу ли я перемещать файлы из каталога загрузки после загрузки?

И ответ: конечно, можете. Я достигну этого с помощью хранимой процедуры, чтобы файлы перемещались правильным образом — на лету — без демона.

Сначала вам нужно установить untrusted plperlu на систему, это можно сделать с помощью

apt-get install postgresql-plperl-8.1

Затем вам нужно установить plperlu в базу данных

createlang plperlu your_database_here

Далее нам нужно создать быстрый триггер на perl-скрипт, который будет срабатывать при каждой вставке в нашу таблицу 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()
;

Этот sql-скрипт можно установить так же, как и предыдущий (тот, который использовался для создания таблиц)

Share: X/Twitter LinkedIn

Get new posts in your inbox

No spam. Unsubscribe anytime.