Installazione di ProFtpd in Debian con gestione Virtual Users in MySQL
Introduzione
Supponiamo quindi di avere una situazione del genere:
- /var/www/esempio.it/www
e di voler creare utenti virtuali, senza accesso alla console:
- esempio_it
che possano accedere via FTP solo alle directory del loro sito web.
Installazione di ProFTPD
La scelta sul server FTP da utilizzare è caduta su ProFTPD, che ora dobbiamo configurare in modo opportuno per avere due utenti distinti che gestiscano i due siti. Per fare ciò creeremo due login FTP virtuali, con l’ausilio di un database dedicato su MySQL.
- Installiamo innanzitutto ProFTPD con il supporto per MySQL:
sudo apt-get install proftpd-basic proftpd-mod-mysql
- Per aumentare il tempo massimo prima che una connessione FTP vada in timeout per mancanza di attività possiamo e aumentare il valore della direttiva TimeoutNoTransfer:
sed -i -e 's/TimeoutNoTransfer.*600/TimeoutNoTransfer 1200/' /etc/proftpd/proftpd.conf
- Consiglio inoltre di aggiungere le seguenti direttive:
echo "AllowStoreRestart on" >> /etc/proftpd/proftpd.conf echo "DeleteAbortedStores off" >> /etc/proftpd/proftpd.conf echo "AllowRetrieveRestart on" >> /etc/proftpd/proftpd.conf
- Ora dobbiamo creare il database per ProFTPD, entrando in MySQL col comando:
mysql -u root -p
- Creeremo un database chiamato
proftpde un utente MySQL chiamatoproftpd, che sarà in seguito utilizzato da ProFTPD per connettersi al database server:
CREATE DATABASE proftpd; GRANT SELECT, INSERT, UPDATE, DELETE ON proftpd.* TO 'proftpd'@'localhost' IDENTIFIED BY 'password'; GRANT SELECT, INSERT, UPDATE, DELETE ON proftpd.* TO 'proftpd'@'localhost.localdomain' IDENTIFIED BY 'password'; FLUSH PRIVILEGES;
- Ovviamente sostituite la stringa
passwordcon la password che volete assegnare al vostro utente MySQL.
- Già che siamo collegati alla shell di MySQL ne approfittiamo per creare anche tutte le tabelle che ci servono:
USE proftpd;
CREATE TABLE ftpgroup (
groupname varchar(16) NOT NULL default '',
gid smallint(6) NOT NULL default '2001',
members varchar(16) NOT NULL default '',
KEY groupname (groupname)
) COMMENT='ProFTP group table';
CREATE TABLE ftpquotalimits (
name varchar(30) default NULL,
quota_type enum('user','group','class','all') NOT NULL default 'user',
per_session enum('false','true') NOT NULL default 'false',
limit_type enum('soft','hard') NOT NULL default 'soft',
bytes_in_avail bigint(20) unsigned NOT NULL default '0',
bytes_out_avail bigint(20) unsigned NOT NULL default '0',
bytes_xfer_avail bigint(20) unsigned NOT NULL default '0',
files_in_avail int(10) unsigned NOT NULL default '0',
files_out_avail int(10) unsigned NOT NULL default '0',
files_xfer_avail int(10) unsigned NOT NULL default '0'
);
CREATE TABLE ftpquotatallies (
name varchar(30) NOT NULL default '',
quota_type enum('user','group','class','all') NOT NULL default 'user',
bytes_in_used bigint(20) unsigned NOT NULL default '0',
bytes_out_used bigint(20) unsigned NOT NULL default '0',
bytes_xfer_used bigint(20) unsigned NOT NULL default '0',
files_in_used int(10) unsigned NOT NULL default '0',
files_out_used int(10) unsigned NOT NULL default '0',
files_xfer_used int(10) unsigned NOT NULL default '0'
);
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 '2001',
gid smallint(6) NOT NULL default '2001',
homedir varchar(255) NOT NULL default '',
shell varchar(16) NOT NULL default '/sbin/nologin',
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',
PRIMARY KEY (id),
UNIQUE KEY userid (userid)
) COMMENT='ProFTP user table';
quit;
Configurazione di ProFTPD
La configurazione di ProFTPD per utilizzare MySQL come backend comporta la modifica di alcuni file:
/etc/proftpd/modules.conf
Abilitiamo i moduli seguenti:
sed -i -e 's/#LoadModule mod_sql.c/LoadModule mod_sql.c/' /etc/proftpd/modules.conf sed -i -e 's/#LoadModule mod_sql_mysql.c/LoadModule mod_sql_mysql.c/' /etc/proftpd/modules.conf sed -i -e 's/#LoadModule mod_quotatab_sql.c/LoadModule mod_quotatab_sql.c/' /etc/proftpd/modules.conf
/etc/proftpd/proftpd.conf
- Decommentiamo la linea
Include /etc/proftpd/sql.conf:
sed -i -e 's_#Include /etc/proftpd/sql.conf_Include /etc/proftpd/sql.conf_' /etc/proftpd/proftpd.conf
- Cambiamo la linea:
sed -i -e 's/^# AuthOrder.*/AuthOrder mod_sql.c/' /etc/proftpd/proftpd.conf
/etc/proftpd/sql.conf
- Di questo file, in particolare, notiamo la riga
SQLConnectInfo(in cui vanno inseriti i parametri di connessione al database)che, se utilizziamo un database MySQL configurato come descritto in precedenza, va scritta così:
- CAMBIARE LA PASSWORD:
cat <<EOFile > /etc/proftpd/sql.conf
#
# Proftpd sample configuration for SQL-based authentication.
#
# (This is not to be used if you prefer a PAM-based SQL authentication)
#
#<IfModule mod_sql.c>
#
# Choose a SQL backend among MySQL or PostgreSQL.
# Both modules are loaded in default configuration, so you have to specify the backend
# or comment out the unused module in /etc/proftpd/modules.conf.
# Use 'mysql' or 'postgres' as possible values.
#
#SQLBackend mysql
#
#SQLEngine on
#SQLAuthenticate on
#
# Use both a crypted or plaintext password
#SQLAuthTypes Crypt Plaintext
#
# Use a backend-crypted or a crypted password
#SQLAuthTypes Backend Crypt
#
# Connection
#SQLConnectInfo proftpd@localhost proftpd password
#
# Describes both users/groups tables
#
#SQLUserInfo users userid passwd uid gid homedir shell
#SQLGroupInfo groups groupname gid members
#
#
#</IfModule>
<IfModule mod_sql.c>
DefaultRoot ~
SQLBackend mysql
SQLAuthTypes Crypt Plaintext
SQLAuthenticate users groups
SQLConnectInfo proftpd@localhost proftpd password
SQLUserInfo ftpuser userid passwd uid gid homedir shell
SQLGroupInfo ftpgroup groupname gid members
SQLMinID 100
CreateHome on
SQLLog PASS updatecount
SQLNamedQuery updatecount UPDATE "count=count+1, accessed=now() WHERE userid='%u'" ftpuser
SQLLog STOR,DELE modified
SQLNamedQuery modified UPDATE "modified=now() WHERE userid='%u'" ftpuser
QuotaEngine on
QuotaDirectoryTally on
QuotaDisplayUnits Mb
QuotaShowQuotas on
SQLNamedQuery get-quota-limit SELECT "name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail FROM ftpquotalimits WHERE name = '%{0}' AND quota_type = '%{1}'"
SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used, bytes_out_used, bytes_xfer_used, files_in_used, files_out_used, files_xfer_used FROM ftpquotatallies WHERE name = '%{0}' AND quota_type = '%{1}'"
SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used = files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name = '%{6}' AND quota_type = '%{7}'" ftpquotatallies
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" ftpquotatallies
QuotaLimitTable sql:/get-quota-limit
QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally
RootLogin off
RequireValidShell off
</IfModule>
EOFile
- Controllate che SQLMinID sia superiore all'id dello user FTP
- Controllate di aver inserito la corretta password di connessione a MySQL e riavviate il servizio FTP
/etc/init.d/proftpd restart
Creazione degli utenti FTP
Giunti fino a qui, dobbiamo ora inserire gli utenti virtuali FTP nel database MySQL.
Nell’inserimento vero e proprio degli utenti nel database proftpd in MySQL, dobbiamo prestare attenzione ad indicare la home directory su cui verrà rimbalzato l’utente che si autentica su ProFTPD. Creeremo:
- un gruppo chiamato ftp;
- un utente chiamato example_com con password passwordcom e home directory
/var/www/example.com/www; - un utente chiamato example_it con password passwordit e home directory
/var/www/example.it/www.
- Verifica l'id del gruppo ftp:
id ftp uid=110(ftp) gid=118(ftp) groups=118(ftp)
- Verifica id users:
id www-exacom uid=999(www-exacom) gid=999(www-exacom) groups=999(www-exacom)
id www-exait uid=998(www-exait) gid=998(www-exait) groups=998(www-exait)
Dobbiamo creare questi userid
username uid gid example_com 110 999 example_it 110 998
Perchè i files dovranno avere permission
filename ftp example_com filename ftp example_it
- Colleghiamoci alla shell di MySQL:
mysql -u root -p
- impartiamo le seguenti istruzioni:
USE proftpd;
INSERT INTO `ftpgroup` (`groupname`, `gid`, `members`) VALUES ('example_com', 999, 'example_com');
INSERT INTO `ftpgroup` (`groupname`, `gid`, `members`) VALUES ('example_it', 998, 'example_it');
INSERT INTO ftpuser (userid, passwd, uid, gid, homedir, shell, count, accessed, modified) VALUES
('example_com', ENCRYPT('passwordcom'), 110, 999, '/var/www/example.com/www', '/sbin/nologin', 0, '', '');
INSERT INTO ftpuser (userid, passwd, uid, gid, homedir, shell, count, accessed, modified) VALUES
('example_it', ENCRYPT('passwordit'), 110, 999, '/var/www/example.it/www', '/sbin/nologin', 0, '', '');
#INSERT INTO `ftpquotalimits` (`name`, `quota_type`, `per_session`, `limit_type`, `bytes_in_avail`, `bytes_out_avail`, `bytes_xfer_avail`, `files_in_avail`, `files_out_avail`, `files_xfer_avail`) VALUES ('esempio-it', 'user', 'true', 'hard', 15728640, 0, 0, 0, 0, 0);
#INSERT INTO `ftpquotalimits` (`name`, `quota_type`, `per_session`, `limit_type`, `bytes_in_avail`, `bytes_out_avail`, `bytes_xfer_avail`, `files_in_avail`, `files_out_avail`, `files_xfer_avail`) VALUES ('esempio-org', 'user', 'true', 'hard', 15728640, 0, 0, 0, 0, 0);
quit;
- Si noti che insieme agli utenti NON sono state create due regole per lo spazio su disco, con una quota impostata a 15MB.
Da notare che per inserire la password è stata usata la funzione di MySQL ENCRYPT, che utilizza la chiamata di sistema crypt() presente sul sistema operativo, quindi di fatto utilizza lo stesso metodo di cifratura utilizzato da Linux per cifrare le password degli utenti di sistema.
Descrizione campi
- Le tabelle; quelle che ci interessano nella creazione e nella gestione degli utenti sono però solo due:
- ftpquotalimits
- ftpuser
Vediamone il contenuto.
ftpuser
I campi da riempire sono i seguenti (i restanti campi sono utilizzati da ProFTPD e/o da MySQL, quindi non riempiteli!):
- userid: il nome dell'utente FTP virtuale (es: esempio-it)
- passwd: la password dell'utente
- uid: il valore userid dell'utente di sistema ftp creato in precedenza (2001)
- gid: il valore groupid dell'utente di sistema ftp creato in precedenza (2001)
- homedir: il percorso della home directory dell'utente FTP virtuale (
/var/www/www.esempio.it). Se non esiste sarà creata al momento della connessione. L'utente virtuale sarà chrooted in questa directory e non potrà uscirne - shell: la shell di sistema assegnata all'utente. Dato che non vogliamo permettere accesso al server, lasciamo il valore di default
ftpquotalimits
I campi da riempire sono i seguenti (i restanti campi sono utilizzati da ProFTPD e/o da MySQL, quindi non riempiteli!):
- name: il nome dell'utente FTP virtuale (es: esempio-it)
- quota_type: user o group. Normalmente useremo user
- per_session: true o false. true significa che la quota limite è valida per una singola sessione: se l'utente effettua un logout e un nuovo login la quota si azzera. false significa che l'utente ha a disposizione la quota stabilita
- limit_type: hard o soft. Un hard quota limit non permette eccezioni, mentre un soft quota limit può temporaneamente essere superato. Normalmente viene usato hard
- bytes_in_avail: limite di upload in bytes. 0 significa senza limite
- bytes_out_avail: limite di download in bytes. 0 significa senza limite
- bytes_xfer_avail: limite di transfer bytes. È la quantità massima di bytes che un utente può uploadare o downloadare. 0 significa senza limite
- files_in_avail: numero limite di file uploadabili. 0 significa senza limite
- files_out_avail: numero limite di file scaricabili. 0 significa senza limite
- files_xfer_avail: numero limite di file trasferibili. 0 significa senza limite
Altre tabelle
La tabella ftpquotatallies è utilizzata da Proftpd per gestire le quotas e non va modificata.
Impostazione dei permessi corretti
Ora rimangono da impostare i permessi sulle directory dei due siti web, per far sì che gli utenti FTP possano scrivere al loro interno, dando l’autorizzazione in scrittura all’utente ftpuser creato in precedenza:
# chown -R ftpuser:www-data /var/www/www.esempio.it # chown -R ftpuser:www-data /var/www/www.esempio.org # chmod -R 775 /var/www/www.esempio.it # chmod -R 775 /var/www/www.esempio.org
Test di connessione
Aprite il vostro client FTP preferito e connettetevi al vostro server utilizzando le credenziali seguenti:
- Host: ftp.esempio.it
- Utente: esempio-it
- Password: passwordit
- Porta: 21
Provate a caricare un file e controllate eventuali messaggi di errore.
Una volta completato l'upload, fate login come root sulla console del server e spostatevi nella DocumentRoot del sito www.esempio.it:
# cd /var/www/www.esempio.it # ls -la
Dovreste trovare listato anche il file che avete appena caricato.
FTP anonimo
È possibile creare anche un account ftp anonimo, cioè un account ftp che chiunque possa usare senza una password, in questo modo.
Creiamo innanzitutto un utente, un gruppo di sistema e una home directory:
# mkdir /var/www/anonymous_ftp # groupadd -g 2002 anonymous_ftp # useradd -u 2002 -s /bin/false -d /var/www/anonymous_ftp -m -c "Anonymous FTP User" -g anonymous_ftp anonymous_ftp
Poi creiamo la directory /home/anonymous_ftp/incoming dove gli utenti anonimi potranno caricare i file:
# mkdir /var/www/anonymous_ftp/incoming # chown anonymous_ftp:nogroup /var/www/anonymous_ftp/incoming
Infine apriamo il file di configurazione /etc/proftpd/proftpd.conf e aggiungiamo le direttive:
# vi /etc/proftpd/proftpd.conf
[...]
<Anonymous /var/www/anonymous_ftp>
User anonymous_ftp
Group nogroup
# We want clients to be able to login with "anonymous" as well as "ftp"
UserAlias anonymous anonymous_ftp
# Cosmetic changes, all files belongs to ftp user
DirFakeUser on anonymous_ftp
DirFakeGroup on anonymous_ftp
RequireValidShell off
# Limit the maximum number of anonymous logins
MaxClients 10
# We want 'welcome.msg' displayed at login, and '.message' displayed
# in each newly chdired directory.
DisplayLogin welcome.msg
DisplayChdir .message
# Limit WRITE everywhere in the anonymous chroot
<Directory *>
<Limit WRITE>
DenyAll
</Limit>
</Directory>
# Uncomment this if you're brave.
<Directory incoming>
# Umask 022 is a good standard umask to prevent new files and dirs
# (second parm) from being group and world writable.
Umask 022 022
<Limit READ WRITE>
DenyAll
</Limit>
<Limit STOR>
AllowAll
</Limit>
</Directory>
</Anonymous>
Riavviamo il servizio:
# /etc/init.d/proftpd restart
e verifichiamo che gli utenti anonimi possano ora effettuare il login.
L'impostazione data prevede che gli utenti anonimi possano:
- scaricare i file messi in
/var/www/anonymous_ftp - caricare i file nella directory
/var/www/anonymous_ftp/incoming
Una volta che un file è stato caricato, nessuno può leggerlo o scaricarlo prima che un amministratore lo sposti nella directory /var/www/anonymous_ftp per renderlo disponibile a tutti.
Configurazione del Firewall
Se il server FTP è protetto da un firewall iptables occorre abilitare la direttiva PassivePorts:
# nano /etc/proftpd/proftdp.conf
in questo modo:
PassivePorts 60000 65000
In questo modo abbiamo istruito ProFTPD a utilizzare uno specifico range di porte dinamiche per le transazioni FTP. Lo stesso range va abilitato nello script del nostro firewall:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 60000:65000 -j ACCEPT
Un riavvio del demone FTP e dello script del firewall completerà l'opera.