Servidor FTP · 7 min read · Dec 17, 2025
PostgreSQL e Proftpd
Então você quer configurar um servidor ftp, precisa de funcionalidades avançadas e não sabe a quem recorrer? Experimente o proftpd.
Parte 1: Configurando o proftpd com um backend postgresql
Este tutorial é muito específico, vou cobrir apenas o proftpd, e apenas na medida em que ele se torne operacional com o Postgres. Assume-se um entendimento básico de proftpd e Postgres. Este tutorial fará com que você configure o proftpd rapidamente e o utilize um banco de dados; se esse banco de dados tiver triggers, as possibilidades dessa configuração são quase infinitas.
Obtendo Proftpd
Primeiro, você precisará do proftpd, estarei usando o Dapper do Ubuntu; há um meta-pacote preparado graças a Francesco Paolo Lovergine intitulado “proftpd-pgsql,” que configurará uma cópia do proftpd compilada com os seguintes módulos. Como nota lateral, enquanto o proftpd vem com os mods, o arquivo de configuração é o padrão do proftpd. Eu recomendo fortemente que você consulte a documentação do mod_sql, que embora seja inferior, ainda é útil – a documentação no site do proftpd é muito antiga, use estas em vez disso: Link para a documentação. Além disso, fique atento à versão, o proftpd agora está na 1.3, embora eu esteja usando a 1.2.10 – a versão usada no Dapper.
Os mods compilados nesta versão do proftpd são os seguintes
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.cVá em frente e emita o comando para obter o proftpd-pgsql:
apt-get install proftpd-pgsqlConfigurando Permissões.
Para meu propósito, (lembre-se, eu sou o centro do universo) tudo o que eu precisava era de uma estrutura unidimensional, porque os grupos são armazenados em um nível diferente em vez de permissões unix. Portanto, todos os arquivos devem entrar com permissões estáticas – eu só me importo com o proprietário e o grupo do proprietário. Meu plano era fazer com que o usuário padrão do proftpd, ftp, pertencesse ao seu próprio grupo apropriadamente nomeado que eu iria criar – ‘ftp’. Eu então faria o Postgres um membro desse grupo, veja a parte 2 para a razão. Eu precisava que ambos fossem membros do mesmo grupo, e precisava que a pasta chroot do proftpd fosse 775, para que todo o grupo pudesse adicionar (mover) arquivos, eu também fiz a pasta ser de propriedade do usuário ‘ftp’, com grupo ‘ftp’. Eu consegui isso com o seguinte script.
groupadd ftp
usermod -G ftp ftp
usermod -G ftp,postgres postgres
chown ftp:ftp ./ftp_directory/
chmod 775 ./ftp_directory/Configurando Postgres
Agora, vamos preparar nossas tabelas sql. Eu projeto utilizando esquemas, e é para isso que serve o prefixo ‘ftp.’ nas tabelas. Coloquei todas as minhas tabelas em um esquema ftp, há uma coisa que vale a pena notar, fui extremamente restritivo nas permissões para este projeto, porque não tenho certeza de quão seguro o mod_sql é. Ao fazer isso, criei um usuário especial, chamado proftp, para o proftpd no meu banco de dados (que mais aplicações utilizam do que o proftpd), esse usuário é restrito a seleções na auth_table e inserções na tabela file_log. Eu altamente sugiro que você adote alguma forma dessa política. No mínimo, isso previne algum grau de devastadores ataques de injeção sql ou vazamentos de informações no caso de o código do mod_sql não ser tão seguro quanto gostaríamos de pensar. Uma rápida pesquisa no google revela um problema de segurança anterior com a base de código do mod_sql. Cada consulta que o mod_sql envia ao db é anexada com uma cláusula “LIMIT 1”, e com o mod_delay também configurado por padrão, considero isso suficiente para este projeto.
Meu script de inicialização sql é o seguinte.
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;Conecte-se ao seu banco de dados e execute isso com:
\i script_nameou, você pode usar enviar ‘–file script_name’ para psql como um argumento de linha de comando.
Aqueles em bancos de dados menores (usando este tutorial com mysql), você pode querer substituir text por varchar; mas, devido ao design do Postgres, não há vantagem nisso.
Configurando proftpd
Esta parte é complicada e varia ligeiramente se você estiver usando 1.3 – mais uma vez, este tutorial é para 1.2.10.
Adicionei esta parte ao meu arquivo de configuração padrão do proftpd, localizado em /etc/proftpd.conf:
AuthOrder mod_sql.c
SQLAuthTypes Plaintext Empty
SQLAuthenticate users
SQLConnectInfo proftpd@localhost proftp dealermadeftp
SQLDefaultUID 110 # MUDE PARA O UID DOS SEUS USUÁRIOS FTP ENCONTRADO EM /etc/passwd
SQLDefaultGID 1001 # MUDE PARA O GID DOS SEUS USUÁRIOS FTP, ENCONTRADO EM /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 => --Nada,
# %f => abs_path
# %J => file
# %h => dns_remote, %V => dns_local
# %a => remote_ip, %L => local_ip
# %t => localtime
# %T => transfer_time- As variáveis do template estão comentadas e são apenas para sua própria referência. Um breve resumo da configuração é o seguinte:
- Aqui definimos o AuthOrder, para mod_sql.c, ativando assim o mod_sql.
- Eu selecionei usar senhas em texto simples, ou no caso de eu não atribuir uma, permitir senhas vazias. (Mais tarde implementarei um trigger para SHA1 as senhas no banco de dados.)
- Em seguida, configurei SQLAuthenticate para usuários, escolhi não usar grupos para este projeto, se você precisar de grupos, mais informações podem ser encontradas nessas tabelas em: Este site para documentação sobre grupos.
- SQLConnectInfo é o dsn no formato “banco_de_dados@host usuário senha,”
- SQLDefaultUID, SQLDefaultGID, SQLDefaultHomedir, configuram o padrão, deixando a maioria das minhas colunas como NULL, raramente vou substituir isso.
- RequireValidShell também está definido como off, se você configurá-lo como on, e fornecer um shell inválido, você falhará na autenticação.
- O SQLUserInfo corresponde às tabelas do Postgres, é um mapeamento literal, novamente o “ftp.” especifica o esquema para a tabela de autenticação.
- SQLNegativeCache, armazena em cache falhas de autenticação,
- SQLLogFile para registro detalhado enquanto configura seu servidor. Eu desativarei quando for para produção.
- SQLLog especifica qual ação ftp você gostaria de registrar, porque meus usuários só podem fazer upload, eu só registro STOR, o formato é ‘ftpaction query_to_execute’.
- SQLNamedQuery Verifique a sintaxe na documentação para uma melhor explicação, o formato que uso é ‘qryname FREEFORM custom_query_here’, faço isso principalmente porque desejo capturar muitas das variáveis de template do proftpd, há outras sintaxes mais simples.
É isso. Se tudo correr conforme o planejado, você deve estar funcionando. Agora, quando alguém faz upload de um arquivo, este deve ser o resultado:
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)Parte II: Além de ‘funcionando’
… Mas funcionando nunca é o suficiente, certo? Vamos prosseguir para responder à seguinte pergunta postada na faq de configuração do proftpd:
Posso rotacionar arquivos de um diretório de upload após o upload?
E a resposta, você com certeza pode. Eu vou realizar isso através de um procedimento armazenado, assim os arquivos são movidos da maneira certa – em tempo real – sem um daemon.
Você primeiro precisará instalar untrusted plperlu no sistema, isso pode ser feito com
apt-get install postgresql-plperl-8.1Em seguida, você precisa instalar plperlu no banco de dados
createlang plperlu your_database_hereEm seguida, precisamos criar um rápido script perl trigger, que será acionado em cada inserção na nossa tabela 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()
;Este script sql pode ser instalado da mesma forma que o anterior, (aquele usado para criar as tabelas)
Receba novas postagens na sua caixa de entrada
Sem spam. Cancele a assinatura a qualquer momento.