Pull to refresh

Pure-FTPD с хранением пользователей в БД MYSQL

Reading time10 min
Views4.1K
image
Ранее не однократно приходилось настраивать FTP-сервер (делов то на несколько минут) и как то исторически сложилось, что безоговорочным кандидатом был ProFtpd. Поскольку в плане безопасности у этого товарища не так давно были проблемы, решил попробовать что-то другое, и не пожалел

Мой выбор остановился на замечательном FTP-сервере Pure-FTPd.
После инсталяции вы получите следующий набор функций:

  • Управление скоростью Download и Upload для каждого пользователя
  • Выбор UID и GUID для пользователя
  • Доступность ftp для пользователя только с указанных айпи адресов
  • Включение и отключение учетных записей пользователей


В качестве ОС используется FreeBSD. И так поехали! Предполагается, что у вас установлена и настроена СУБД MySql. Устанавливаем Pure-FTPd c портов (предварительно их обновив)
cd /usr/ports/ftp/pure-ftpd
make install clean

Я выбирал следующие опции

После инсталяции создаем конфиги из файлов по умолчанию
cd /usr/local/etc/
cp pureftpd-mysql.conf.sample pureftpd-mysql.conf
cp pure-ftpd.conf.sample pure-ftpd.conf

Редактируем главный конфигурационный файл
pure-ftpd.conf
# Chroot`ить всех пользователей в их папках
ChrootEveryone yes

# Если в предыдущей опции было выбрано «no», то члены следующей
# группы не будут chroot`ится. Всё остальные — будут. Если Вы не хотите
# chroot`ить всех, то просто раскоментируйте ChrootEveryone и TrustedGID.
# TrustedGID 100

# Включить «фичи» совместимости, для кривых клиентов
BrokenClientsCompatibility no

# Максимальное число одновременных юзеров
MaxClientsNumber 50

# Работать в фоне (демоном)
Daemonize yes

# Максимальное число одновременных соединений с одного IP
MaxClientsPerIP 8

# Если вы хотите логировать все команды клиентов, то в этом
# пункте должно быть «yes». Если необходимо логгировать также
# ответы сервера, то просто продублируйте этот пункт.
VerboseLog no

# Показывать или нет файлы, начинающиеся с точки, даже когда клиент
# явно не говорит что это надо делать, опцией "-a".
DisplayDotFiles yes

# Не разрешать аутентифицированных юзеров — этот FTP
# только для анонимных клиентов.
AnonymousOnly no

# Запретить анонимоусов — FTP тока для регистрованных юзеров.
NoAnonymous no

# Средства syslog (auth, authpriv, daemon, ftp, security, user, local*)
# Дефолт — «ftp». «none» — отключает логирование.
SyslogFacility ftp

# Показывать какие-то куки? (Display fortune cookies)
# FortunesFile /usr/share/fortune/zippy

# Не резольвить имена хостов в логах. Логи становятся менее информативными,
# но и ресурсов требуется меньше. «yes» — имеет смысл ставить на очень
# загруженных серверах, или при неработающем DNS.
DontResolve yes

# Максимальное время простоя (по окончании рвётся коннект), в минутах
# (default = 15 minutes)
MaxIdleTime 15

# Файл конфигурации LDAP (смотрите README.LDAP)
# LDAPConfigFile /etc/pureftpd-ldap.conf

# Файл конфигурации MySQL (смотрите README.MySQL)
MySQLConfigFile /usr/local/etc/pureftpd-mysql.conf

# Файл конфигурации Postgres (смотрите README.PGSQL)
# PGSQLConfigFile /etc/pureftpd-pgsql.conf

# база данных юзеров PureDB (смотрите README.Virtual-Users)
# PureDB /etc/pureftpd.pdb

# путь к сокету pure-authd (смотрите README.Authentication-Modules)
# ExtAuth /var/run/ftpd.sock

# Если нужно подключить PAM аутентификацию раскомментируйте
# следующую линию
# PAMAuthentication yes

# Если нужна системная, Unix аутентификация (/etc/passwd),
# раскомментируйте следующую линию
# UnixAuthentication yes

# Пожалуйста, отметтьте, что LDAPConfigFile, MySQLConfigFile,
# PAMAuthentication и UnixAuthentication могут использоваться только
# один раз, но они могут использоваться вместе. Например, если вы
# используете MySQLConfigFile, затем UnixAuthentication, то идёт запрос
# к MySQL. Если в БД такой пользователь не найден, то пробуется
# системный пользователь в /etc/passwd и /etc/shadow. Если SQL
# аутентификация неудачна по причине неправильного пароля, то происходит
# остановка дальнейшего поиска пользователя. Методы аутентификации
# будут ипользоваться в порядке в которм они заданы

# Пределы рекурсии команды 'ls'. Первй аргумент — максимально число файлов,
# которое будет показано. Второе — максимальное число подкаталогов
LimitRecursion 10000 8

# Имеют ли право анонимоусы создвать новые директории?
AnonymousCanCreateDirs no

# Если система загружена более, чем указанное тут значение, то
# анонимоусы не могут что-либо скачивать
MaxLoad 4

# Диапазон портов для пассивного соединения. Если у вас файрволл рубает
# стандартный диапазон
# PassivePortRange 30000 50000

# Принудительный IP адрес в PASV/EPSV/SPSV ответах. — для NAT.
# Символические имена хостов такде приняты для шлюзов с динамическим IP
# ForcePassiveIP 192.168.0.1

# Соотношение upload/download для анонимоусов.
# AnonymousRatio 1 10

# Соотношение upload/download для всех юзеров.
# Эта директива не перекрывает предыдущую.
# UserRatio 1 10

# Запретить скачку файлов владельцем которых является «ftp», т.е.
# файлы были загружены но не одобрены местным (локальным) админом.
AntiWarez yes

# IP адрес/порт на которых слушаем (дефолт = все IP и порт 21).
#Bind 192.168.254.254,21

# Максимальная скорость для анонимоусов в KB/s
# AnonymousBandwidth 8

# Максимальная скорость для всех юзеров (включая анонимов) в KB/s
# Используйте AnonymousBandwidth или UserBandwidth, использовать оба,
# не имеет смысла.
# UserBandwidth 8

# Маска для создаваемых файлов. <umask для файлов>:<umask для директорий>.
# 177:077 — если вы параноик :)
# umask — это такое число, при вычитании которого из максимума (777) и
# получается нужная маска. т.е. для случая ниже маски будут, соответствено:
# 644 для файлов, и 755 для директорий
Umask 133:022

# Минимальный UID с которым юзер будет пущен.
# (В родном варианте тут было 100. Я поставил тыщщу)
MinUID 1000

# Разрешить передачу FXP для авторизованных юзеров.
AllowUserFXP no

# Разрешить передачу FXP для анонимоусов и не-анонимоусов
AllowAnonymousFXP no

# Пользователи не могут удалять и изменять файлы начинающиеся на точку('.')
# даже если они их владельцы. Если TrustedGID включена, эта группа имеет
# доступ к этим файлам.
ProhibitDotFilesWrite no

# Запретить чтение файлов начинающихся с точки
ProhibitDotFilesRead no

# Никогда не перезаписывать файлы. Когда имя, для закачиваемго файла уже
# существует, он будет автоматически переименован в file.1, file.2, file.3,…
AutoRename no

# Запретить анонимным юзерам загружать новые файлы (no = аплоад разрешён)
AnonymousCantUpload no

# Только подключения к этому IP адресу могут быть не анонимными. Вы
# можете использовать эту директиву чтобы использовать несколько IP
# для анонимного FTP, и оставить приватный, зафаерволленый IP для
# удалённого администрирования. также вы можете разрешить нероутабельный
# локальный IP (типа 10.x.x.x) для аутентификации и оставить публичный
# (для анонимоусов) FTP-сервер на другом IP.
#TrustedIP 10.1.1.1

# Если вы хотите чтобы PID добавлялся в каждую линию лога,
# то раскомемнтируйте следующую линию.
#LogPID yes

# Создавать дополнительный лог-файл с логом в формате типа «apache»:
# fw.c9x.org — jedi [13/Dec/1975:19:36:39] «GET /icap.tar.bz2» 200 21808
# Этот лог-файл может быть обработан программами для
# анализа логов апача.
# AltLog clf:/var/log/pureftpd.log

# Создавать дополнительный лог-файл в формате оптимизированном для
# статистических отчётов (х.з. как это. Надо будет посмотреть)
# AltLog stats:/var/log/pureftpd.log

# Создавать ещё один лог с переданными файлами в стандарте W3C
# (совместим с многими коммерческими анализаторами)
# AltLog w3c:/var/log/pureftpd.log

# Отключить команду CHMOD. Пользователи не смогут менять разрешения
# на файлы.
#NoChmod yes

# Позволить юзерам закачивать но не удалять файлы.
#KeepAllFiles yes

# Автоматически создавать домашнюю директорию пользователя,
# если она отсутствует
#CreateHomeDir yes

# Включить виртуальную квоту. Первое число — максимальное число файлов.
# Второе число — максимальный размер, в мегабайтах.
# Так 1000:10 ограничивает каждого пользователя 1000 файлов и 10-ю мегами.
#Quota 1000:10

# Если pure-ftpd скомпилен с поддержкой standalone режима, вы можете изменить
# местоположение pid-файла. Дефолтовое положение — /var/run/pure-ftpd.pid
#PIDFile /var/run/pure-ftpd.pid

# Если pure-ftpd скомпилен с поддержкой pure-uploadscript,
# то этот пункт позволяет писать информацию о новых загруженных
# файлах в /var/run/pure-ftpd.upload.pipe так что pure-uploadscript может
# прочесть их и обработать загруженный файл.
#CallUploadScript yes

# Эта опция полезна на серверах, гда позволен аплоад анонимоусам.
# Если /var/ftp находится в отдельном разделе /var, это позволяет
# сохранить свободное место и защитить файлы логов. Когда процент
# заполнения больше чем указанный тут, аплоад автоматом запрещается.
MaxDiskUsage 99

# Установите 'yes' в этой опции если хотите разрешить юзерам
# переименовывать файлы.
#NoRename yes

# Включить 'customer proof': какая-то ошибка, типа 'chmod 0 public_html',
# при совместной работе, чтоль… Короче это не баг а фича… :) И чтобы
# тупые клиенты не напрягали ваш саппорт надо поставить 'yes' в этом
# пункте. Если клиенты имеют немного знаний по Unix то эта фича
# бесполезна. Если у Вас хостинг — включите её.
# (перевод почти дословный — но про что речь я так и не понял...)
CustomerProof yes

# Число параллельных процессов. Работает тока если сервер был
# скомпилен с опцией '--with-peruserlimits' (тут чё-то про то, что
# в большинстве бинарных дистрибов так оно и есть).
# Формат:<максимум сессий на юзера>:<максимум сеансов анонимоусов>
# Например, 3:20 значит что аутентифичированный юзер может иметь три
# активных сеанса. А на всех анонимов — максимум 20 сеансов.
#PerUserLimits 3:20

# Когда загружен файл на сервер, и есть предыдущая версия (с тем же именем),
# то старый файл не будет ни удалён ни усечён. Загрузка будет произведена
# во временный файл и по окончании загрузки будет произведено атомарное
# переключение к новой версии файла. Например, при загрузке большого PHP
# сценария, апач будет работать со старой версией до полной загрузки
# и немедленно переключится на новый как тока он будет полностью передан
# Эта опция несовместима с виртуальными квотами.
#NoTruncate yes

# Эта опция может принимать три значения:
# 0 — отключить SSL/TLS шифрование (по-умолчанию).
# 1 — принимать и шифрованные и обычные подключения.
# 2 — отклонять подключения которые не используют SSL/TLS,
# включая анонимные соединения.
# Не раскомментируйте это вслепую. Проверьте, что:
# 1) Сервер скомпилен с поддержкой SSL/TLS (--with-tls),
# 2) Положен валидный сертификат,
# 3) Только совместимые клиенты залогинятся.
# TLS 1

# Список шифров, которые будут приняты для SSL / TLS соединений 
# Префикс -S: чтобы полностью отключить SSL, но не TLS.
# TLSCipherSuite HIGH:MEDIUM:+TLSv1:!SSLv2:+SSLv3

# Слушается тока IPv4 адрес в режиме standalone (т.е. IPv6 отключен)
# По дефолту, IPv4 и IPv6 включены.
IPV4Only yes

# Слушается тока IPv6 адрес в режиме standalone (т.е. IPv4 отключен)
# По дефолту, IPv4 и IPv6 включены.
# IPV6Only yes

# Поддержка UTF-8 для имён файлов (RFC 2640)
# Определите кодировку для файловой системы сервера и, опционально,
# дефолтовую кодировку для клиентов, которые не юзают UTF-8.
# Работает тока если pure-ftpd скомпилен с '--with-rfc2640'
FileSystemCharset utf-8
ClientCharset cp1251

а так же конфиг для работы Pure-FTPd с БД MySql
pure-ftpd.conf
# Конфиг MySQL для pureftpd

# Опционально: Имя или IP MySQL-сервера. Не задавать этот
# пункт, если используется локальный unix сокет.
#MYSQLServer 127.0.0.1

# Опционально: Порт на котором висит MySQL. Не задавать этот
# пункт, если используется локальный unix сокет.
#MYSQLPort 3306

# Опционально: Задаётся имя сокета mysql.sock если MySQL на этом же хосте.
MYSQLSocket /tmp/mysql.sock

# Обязательно: юзер, которым лезем в БД.
MYSQLUser pure-ftpd

# Обязательно: пароль пользователя, от которого лезем в MySQL.
MYSQLPassword pure-ftpd

# Обязательно: БД с которой работаем.
MYSQLDatabase pureftpd

# Обязательно: как сохранён пароль в БД
# Возможные значения: «cleartext», «crypt», «md5» и «password»
# («password» = MySQL password() функции)
# Можно использовать «any» чтобы попробовать «crypt», «md5» и «password»
MYSQLCrypt cleartext

# В последующих директивах части строк заменены, до
# выполнения запроса:
#
# \L заменяется именем пользователя, что логинится.
# \I заменяется IP адресом сервера, на который лезет юзер
# \P заменяется номером порта с которым соединился юзер.
# \R заменяется IP адресом юзера.
# \D заменяется IP адресом юзера, в виде long decimal number
# (например, 192.168.254.1 == 3232300545).
#
# Можно настругать относительно сложные квери к БД, используя
# этот набор переменных. Если используется одна БД на несколько серверов,
# то "\I" позволяет определить, на тот ли сервер ломится юзер.

# Кверя на получение пароля из БД:
MYSQLGetPW SELECT `password` FROM `users` WHERE `user`="\L" AND `active`='1'

# Кверя на получение системного имени пользователя, или UID
MYSQLGetUID SELECT `uid` FROM `users` WHERE `user`="\L"

# Опционально: default UID — вместо квери на его извлечение MYSQLGetUID
#MYSQLDefaultUID 1000

# Запрос к БД на получение имени группы или gid
MYSQLGetGID SELECT `gid` FROM `users` WHERE `user`="\L"

# Опционально: default GID — вместо запроса MYSQLGetGID
#MYSQLDefaultGID 1000

# Запрос на получения хомяка
MYSQLGetDir SELECT `home` FROM `users` WHERE `user`="\L"

# Опционально: Запрос на максимальное число файлов у юзера
# (интересно — какой в этом глубокий смысл? Чтобы inode на
# сервере не первели чтоль? :))
#Должен быть скомпилен с `virtual quotas support`.
MySQLGetQTAFS SELECT `QuotaFiles` FROM `users` WHERE `user`="\L"

# Опционально: запрос на квоту (использование диска)
# Число, в мегабайтах.
# Pure-FTPd должен быть скомпилен с `virtual quotas support`.
MySQLGetQTASZ SELECT `QuotaSize` FROM `users` WHERE `user`="\L"

# Опционально: Отношения. Запросы на соотношение download/upload.
# Дол; ен быть скомпилен с этой функцией.
MySQLGetRatioUL SELECT `ULRatio` FROM `users` WHERE `user`="\L"
MySQLGetRatioDL SELECT `DLRatio` FROM `users` WHERE `user`="\L"

# Опционально: Ширина канала для юзера. Сервер должен быть
# скомпилен с такой опцией. Значение в KB/s.
MySQLGetBandwidthUL SELECT `ULBandwidth` FROM `users` WHERE `user`="\L"
MySQLGetBandwidthDL SELECT `DLBandwidth` FROM users WHERE `user`="\L"

# Выпускать юзера из хомяка (~). Никогда не делайте этого, если:
# 1) Вы точно знаете что делаете.
# 2) Совпадают реальные и виртуальные юзеры.
#MySQLForceTildeExpansion 1

# Если Вы обновили таблицы до транзакционных (Gemini,
# BerkeleyDB, Innobase...), можно включить транзакции SQL
# Оставьте закомменченым, если используются MyISAM базы данных,
# или старая версия MySQL (< 3.23.x).
#MySQLTransactions On

Далее создаем саму БД (pureftpd) и таблицу с пользователями (users)
CREATE TABLE `users` (
  `User` varchar(50) NOT NULL DEFAULT '',
  `Password` varchar(250) DEFAULT '',
  `Uid` int(11) DEFAULT '10000',
  `Gid` int(11) DEFAULT '10000',
  `Dir` varchar(250) DEFAULT '',
  `QuotaFiles` int(11) DEFAULT NULL,
  `QuotaSize` int(11) DEFAULT '0',
  `ULRatio` int(11) DEFAULT '0',
  `DLRation` int(11) DEFAULT NULL,
  `ULBandwidth` int(11) DEFAULT '0',
  `DLBandwidth` int(11) DEFAULT '0',
  `Comment` tinytext,
  `active` int(11) DEFAULT '0',
  PRIMARY KEY (`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Добавляем в /etc/rc.conf
pureftpd_enable="YES"

и запускаем наш FTP-сервер
/usr/local/etc/rc.d/pure-ftpd start
Starting pureftpd.
Running: /usr/local/sbin/pure-ftpd -g/var/run/pure-ftpd.pid -A -c50 -B -C10 -D -fftp -I15 -lmysql:/usr/local/etc/pureftpd-mysql.conf -L10000:8 -m4 -s -U133:022 -u80 -k99 -Z -8utf-8 -9cp1251

На этом казалось бы все. Осталось завести пользователя в таблицу users (указать логин, пароль, домашнюю директорию) и пробовать подключаться. Но мне не давал покоя вопрос ограничения доступа пользователю по его IP адресу. В классическом случае добавляется поле ip в таблицу пользователей, и sql-запрос для MYSQLGetPW в pureftpd-mysql.conf принимает следующий вид

SELECT Password FROM users WHERE User='\L' AND ip='\R' 

Но мне он не подходит. Во первых для каждого пользователя нужно задать IP-адрес, с которого он будут подключатся, во вторых можно задать только один единственный IP. В реальной жизни, нужно выполнить привязку к IP'шнику только определенным пользователям, и возможность задать n-ое число IP-адресов для одного пользователя.

Синтаксис MySql'я включает в себя функции потока управления программой, среди которых нам нужна функция IF

Создаем таблицу IP
CREATE TABLE `ip` (
  `user` varchar(200) DEFAULT NULL,
  `ip` varchar(16) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Приводим sql-запрос для MYSQLGetPW к следующему виду:
 SELECT IF((SELECT COUNT(`user`) FROM ip WHERE user='\L')=0,
(SELECT Password FROM users WHERE User='\L'),
(SELECT users.Password FROM users,ip WHERE users.User='\L' AND ip.ip='\R' AND ip.user='\L'))

В конечном результате, все пользователи, для которых не заданы записи в таблице IP будут проходить авторизацию без проверки на IP-адрес, а для тех юзеров, которые прописаны в таблице IP будет выполнятся проверка с какого IP-адреса они пробуют подключиться, причем можно задать неограниченное число IP-адресов для одного логина
Tags:
Hubs:
+2
Comments5

Articles