Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> программы —> ProFTP+PgSQL

Установка и настройка ProFTP + PgSQL

Автор: DNK.


            proftpd с хранением пользователей и логов в PgSQL

Многие сисадмины предпочитают использовать бд postgreSQL для хранения
данных и логов.Вот и все отличие данной статьи от статьи уважаемого автора lissyara
proftp+mysql.Ну разве что немного расширена конфигурация.

1)Устанавливаем PostgreSQL
Root>cd /usr/ports/databases/postgresql82-server/
Root>make install clean


2)Настраиваем и запускаем
Root>su – pgsql
$>initdb

Root> echo postgresql_enable="YES" >> /etc/rc.conf
Root>/usr/local/etc/rc.d/postgresql start

3)Создадим юзера ftp и разрешим ему создавать БД
Root>adduser ftp
Root>su – pgsql
$>createuser ftp


4)Создадим БД proftp и таблицы в ней
   Root>su – ftp
   ftp>createdb proftp
   ftp>psql proftp

#таблица для хранения юзеров и накопительной информации

CREATE TABLE users (id serial PRIMARY KEY,username varchar(20),password varchar
(20),groupname varchar(24),uid int,gid int,homedir varchar(70),shell varchar
(20),last_login varchar(30),login_count int,last_error_login varchar
(30),login_error_count int);

#Таблица лога “кто и что делал”

CREATE TABLE worklog (id serial PRIMARY KEY,date varchar(30),user_name varchar
(20),file_and_path text,bytes int8,send_time varchar(9),client_ip varchar
(15),client_name text,client_command varchar(5));

#Таблица лога ошибок

CREATE TABLE errorlog (id serial PRIMARY KEY,date varchar(30),user_name varchar
(20),file_and_path text,bytes int8,send_time varchar(9),client_ip varchar
(15),client_name text,client_command varchar(5));

#Создадим тестового пользователя

insert INTO users VALUES (1,'test','123','ftp',1010,1010,
'/var/ftp','sbin/sh','0',0,'0',0);
insert INTO users VALUES (2,'test1','345','ftp',1010,1010,
'/var/ftp/test1','/sbin/sh','0',0,'0',0);

   Psql>exit
   Root>mkdir /var/ftp
   Root>mkdir /var/ftp/test1
   Roott>chown –R 1010:1010 /var/ftp


5)Ставим из портов:
Root>cd /usr/ports/ftp/proftpd/
Root>make config


[ ] IPV6        Use IPv6
[ ] LDAP        Use LDAP
[ ] MYSQL       Use MySQL
[X] POSTGRESQL  Use Postgres
[ ] OPENSSL     Include mod_tls
[X] QUOTA       Include mod_quota
[ ] IFSESSION   Include mod_ifsession
[X] README      Include mod_readme
[X] RATIO       Include mod_ratio
[X] REWRITE     Include mod_rewrite
[X] WRAP        Include mod_wrap
[ ] RADIUS      Include mod_radius

root>make install clean

После инсталляции правим конфиг /usr/local/etc/proftpd.conf:

------------------------------------------------------------------
# имя сервера - показывается коннектящимся клиентам
ServerName                      "FTP server DNK"
# тип сервера standalone/inetd - сам или через inetd
ServerType                      standalone
# смысл следующей директивы такой: если клиент коннектится не на имя
# а на IP или на виртуальный хост, не описанный в конфиге, то при
# установке в `off` он получит отлуп, если же установлено `on` то
# он будет обслужен `сервером по-умолчанию`
DefaultServer                   on
# файло где хранится инфа о сессиях
#ScoreboardFile         /var/run/proftpd.scoreboard
# порт на котором работает сервер
Port                            21
# e-mail администратора (по идее для каждого ВиртуалХоста его можно
# поставить разный - но я делаю один сервер без извращений с
# виртуальными хостами)
ServerAdmin             admin@dnk.ua
# Маска с которой создаются новые файлы (не совсем маска - маска получается
# из этого значения, путём его вычитания из 777 - т.е. в даном случае получится
# маска 755)
Umask                           022
# Максимальное число `детей` (работает только в standalohe режиме)
# необходимо для защиты от атак типа `отказ в обслуживании` да и
# от перегрузки сервера поможет
MaxInstances                    30
CommandBufferSize       512
# Юзер от которого работает сервер
# группа, под которой работает сервер
User                            ftp
Group                           ftp
# Normally, we want files to be overwriteable.
AllowOverwrite          on
# Директории
<Directory ~>
AllowOverwrite          on
<Limit Write>
AllowAll
</Limit>
<Limit READ>
AllowAll
</Limit>
</Directory>
<Limit SITE_CHMOD>
  DenyAll
</Limit>
#########################################################################
#Если нужен анонимный вход - раскоментируй
#########################################################################
#<Anonymous ~ftp>
#   User                                users
#   Group                               users
  ### We want clients to be able to login with "anonymous" as well as "ftp"
  # UserAlias                   anonymous ftp
  ### 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
  # DisplayFirstChdir           .message
  ### Limit WRITE everywhere in the anonymous chroot
  # <Limit WRITE>
  #   DenyAll
  # </Limit>
#</Anonymous>
#===========================================================================
# Тип авторизации (на самом деле - в каком виде хрянятся
# пароли в БД - в данном случае - открытым текстом)
# Чтобы пароль хранились в закодированном виде
# вместо Plaintext ставим Crypt
SQLAuthTypes            Plaintext
# Кого и как аутентифицируем - on - всех и вся :)
# Но - если поставить `on` то он ломится в БД за группами.
# мне группы никчему. Посему поставил `users`
SQLAuthenticate         users
# инфа для соединения с PgSQL сервером:
# имя_базы_данных@хост_где_PgSQL:порт имя_пользователя пароль
SQLConnectInfo          proftp@localhost ftp
# в каком порядке вернёт поля запрос - первое поле, это
# имя таблицы, где лежат пользователи
SQLUserInfo             users username password uid gid homedir shell
# должен ли быть у юзера (для того, чтобы он мог коннектится),
# `реальный` shell описанный в /etc/shells
RequireValidShell off
# лог файл работы с SQL (после проверки работоспособности – закоментировать)
SQLLogFile      /var/log/proftpd.log
# Записываем удачные логины в БД.
SQLLog          PASS            counter_login

SQLNamedQuery   counter_login   UPDATE "\
        last_login=date_trunc ( 'seconds' ,\
        timestamp without time zone 'now' ),\
        login_count=login_count+1 WHERE \
        username='%u'" users

# пишем неудачные логины в БД
SQLLog          ERR_PASS        counter_err

SQLNamedQuery   counter_err     UPDATE "\
        last_error_login=date_trunc ( 'seconds' ,\
        timestamp without time zone\'now' ), \
        login_error_count=login_error_count+1 WHERE \
        username='%U'" users

# логируем что сохраняет и тащщит с сервера:
# переменные
# %u - имя пользователя (с которым залогинился)
# %f - полный путь и имя файла который был скачан
# %b - число байт, которые были скачаны
# %h - имя клиента (из DNS), если не удалось разрешить - IP
# %a - IP-адрес клиента
# %m - имя команды полученной от клиента (RETR/STOR)
# %T - время (секунд) ушедшее на передачу файла клиенту
SQLLog          DELE,RETR,STOR,         log_work

SQLNamedQuery  log_work FREEFORM "\
INSERT INTO worklog (\
         date,\
         user_name,\
         file_and_path,\
         bytes,\
         send_time,\
         client_ip,\
         client_name,\
         client_command) \
VALUES(\
date_trunc ( 'seconds' , timestamp without time zone 'now' ),\
'%u','%f','%b','%T','%a','%h','%m')"


# записываем ошибки при сохранении и чтении файлов
# (в одну строку не влезли - но работает и в таком виде :))

SQLLOG    ERR_RETR,ERR_STOR,ERR_DELE,ERR_RMD,ERR_RNTO log_error
SQLNamedQuery  log_error FREEFORM "\
INSERT INTO errorlog (\
         date,\
         user_name,\
         file_and_path,\
         bytes,\
         send_time,\
         client_ip,\
         client_name,\
         client_command) \
VALUES(\
date_trunc ( 'seconds' , timestamp without time zone 'now' ),\
'%u','%f','%b','%T','%a','%h','%m')"
# если вылезет проблема, типа тормозов при подключении
# (в момент установления коннекта `задумывается` на 10-20 секунд)
# то раскомментируйте следующие две строки
#UseReverseDNS     off
#IdentLookups      off

# ВСЕ пользователи по ftp ограниченны
# своей домашней директорией
DefaultRoot     ~

# у меня хитрее сделано - себе я разрешил шариться по всему серверу
# а остальных за`chroot`ил. Если, например, надо чтобы пользователи
# могли по серверу шариться а анонимоусы нет, то надо указать !users
# также можно указать определённую группу.
#DefaultRoot             ~       !ftp
MaxClients 55 "Слишком много соединений с сервером"
MaxClientsPerHost 24 "%m клиента уже подключены с Вашего хоста, 
больше не разрешено"
MaxLoginAttempts 3 "Слишком много попыток войти"
AccessDenyMsg "ATTENTION!!! ALL CONNECTIONS LOGED"
AccessGrantMsg "Now upload/download files"
DisplayGoAway "Go Away"

#Возможно определить с каких ip соединения допустимы или запрещены
#UseHostsAllowFile /etc/proftpd.allow
#UseHostsDenyFile /etc/proftpd.deny

# Установим ограничения по времени
#TimeoutIdle 180
#TimeoutLogin 120
#TimeoutNoTransfer 360
#TimeoutStalled 640

# Логи
SyslogLevel notice
UseReverseDNS off
#TransferLog /var/log/proftpd-tranfer.log
#SystemLog /var/log/proftpd-error.log
#ExtendedLog /var/log/proftpd-extended.log read,write

#Для кодировки win-cp1251
#(корректо отображается вин кодировка, а не кракозябры)
LangEngine on
#UseEncoding UTF-8 CP1251
UseEncoding KOI8-R CP1251

#Для корректного отображения времени
TimesGMT  off 
SetEnv TZ :/etc/localtime

-----------------------------------------------------------------

6) Запускаемся
   Root>echo proftpd_enable=
YES >> /etc/rc.conf
   Root>/usr/local/etc/rc.d/proftpd start

7)Для ленивых скриптик на Perl для добавления пользователя

Для запуска скрипта (от root) необходимо установить из портов
/usr/ports/database/p5-DBI и /usr/ports/database/p5-DBD-Pg



-------------------------------------------------------------------
#!/usr/bin/perl
use DBI;
#данные о БД и пользователе
$dbname='proftp';
$user='ftp';
$passwd='';
#шаблон для нового пользователя
$username='';
$password='';
$groupname='ftp';
$uid=1010;
$gid=1010;
$homedir='/var/ftp';
$shell='/bin/sh';

L1:
print "Username=>";$s=<STDIN>;chomp($s);
if($s eq ""){goto L1;}else{$username=$s;}
L2:
print "Password=>";$s=<STDIN>;chomp($s);
if($s eq ""){goto L2;}else{$password=$s;}
print "Groupname (default $groupname)=>";$s=<STDIN>;chomp($s);
if($s ne ""){$groupname=$s;}
print "UID (default $uid)=>";$s=<STDIN>;chomp($s);
if($s ne ""){$uid=$s;}
print "GID (default $gid)=>";$s=<STDIN>;chomp($s);
if($s ne ""){$gid=$s;}
print "Homedir (default $homedir)=>";$s=<STDIN>;chomp($s);
if($s ne ""){$homedir=$s;}
print "Shell (default $shell)=>";$s=<STDIN>;chomp($s);
if($s ne ""){$shell=$s;}

print "\n\n\n=========================================\n";
print "Username=$username\nPassword=$password\nGroupname=$groupname\n
        UID=$uid\nGID=$gid\nDir=$homedir\nShell=$shell\n";
print "=========================================\n";
print "Insert (default 'y')?=>";$s=<STDIN>;chomp($s);
if($s eq ""){$s='y';}
if($s eq 'y' or $s eq 'Y')
{
$dbh=DBI->connect("DBI:Pg:dbname='$dbname'","$user","$passwd");
$sth=$dbh->prepare("insert into users (username,password,groupname,
        uid,gid,homedir,shell,last_login,login_count,last_error_login,
        login_error_count) 
values('$username','$password','$groupname',$uid,
$gid,'$homedir','$shell','',0,'',0)");
$sth->execute();$sth->finish();$dbh->disconnect();print "SUCCESS\n";
}

@a=`su - $user -c ' /usr/local/bin/psql proftp -c "select * from users;"'`;
print @a;

Логи сохраняются в таком виде :

# psql proftp
Welcome to psql 8.2.5, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

proftp=# \d
                     Список отношений
 Схема  |       Имя       |        Тип         | Владелец
--------+-----------------+--------------------+----------
 public | errorlog        | таблица            | ftp
 public | errorlog_id_seq | последовательность | ftp
 public | users           | таблица            | ftp
 public | users_id_seq    | последовательность | ftp
 public | worklog         | таблица            | ftp
 public | worklog_id_seq  | последовательность | ftp
(6 rows)

proftp=# SELECT * from worklog;
 id |        date         | user_name |             file_and_path             |
  bytes   | send_time |  client_ip   | client_name  | client_command
----+---------------------+-----------+--------------------------------------
+----------+-----------+--------------+--------------+----------------
  1 | 2008-07-31 06:45:57 | test      | /var/ftp/VirtualBox-1.6.0-Win_x86.msi| 
22353408 | 27.678    | 192.168.1.83 | 192.168.1.83 | STOR
  2 | 2008-07-31 06:46:05 | test      | /var/ftp/VirtualBox-1.6.0-Win_x86.msi|
   0 | 0.0       | 192.168.1.83 | 192.168.1.83 | DELE
(2 rows)

proftp=# SELECT * from users;
 id | username | password | groupname | uid  | gid  | homedir  |  shell   |
last_login      | login_count | last_error_login | login_error_count
----+----------+----------+-----------+------+------+----------+----------
+---------------------+-------------+------------------+------------------
  1 | test     | 123      | ftp       | 1010 | 1010 | /var/ftp | /sbin/sh | 
2008-07-31 06:45:10 |           3 | 0                |                 0
(1 запись)

proftp=#



размещено: 2008-07-30,
последнее обновление: 2014-12-16,
автор: DNK


Den, 2008-08-28 в 6:29:53

установил postgreql 8.3 и наверное тут есть пара неточностей
вместо этого
>>Root>su – pgsql
>>$>initdb
стартовал так
Root>/usr/local/etc/rc.d/postgresql initdb
и тут наверное опечатка, не сразу увидел :) а настраивал копипастом
>>Root> echo posgresql_enable="YES" >> /etc/rc.conf
Root> echo posgtresql_enable="YES" >> /etc/rc.conf

DNK, 2008-08-28 в 12:40:32

Спасибо за замечание по опечатке,
действительно нужно вводить postgresql_enable. По поводу инициализации (первоначальной) БД : все-таки нужно чтобы постгрес работал от юзера pgsql а не от рута, поэтому правильней инициализировать БД от pgsql через initdb.
Обратите внимание что в логи пишется : кто залил,удалил или СКАЧАЛ файл - если регистрация скачивающего не нужна, уберите в строке
SQLLog   DELE,RETR,STOR,         log_work
параметр RETR.

Den, 2008-08-29 в 7:39:50

вот выдержка из стартового скрипта, от рута база не инициализируется

postgresql_initdb()
{
   su -l -c ${postgresql_class} ${postgresql_user} -c "exec ${prefix}/bin/initdb ${postgresql_initdb_flags} -D ${postgresql_data}"
}

ermak, 2008-11-30 в 12:58:22

Всем привет!
У меня почему то не пищется в таблицы логов.
Хотя авторизует нормально.
В чем трабл?

DNK, 2008-12-04 в 11:33:38

Проверь конфиг

ermak, 2008-12-04 в 16:06:47

2 DIK Все разрулил!
Спасибо тебе за статью!
И еще вопрос: В errorlog я как понимаю пишется то что не удалось скачать? прервалось по ошибке?
Я прав или нет?

DNK, 2008-12-19 в 17:20:03

да пишется все что не смогло произойти а хотелось :)

chdd29, 2009-01-29 в 18:26:22

для работы с русскими именами
/usr/local/etc/proftpd.conf
CharsetLocal KOI8-R
CharsetRemote CP1251

DNK, 2009-02-16 в 15:02:48

По поводу кодировки замечание правильное.Спасибо.

garison, 2009-03-11 в 11:17:36

перекодировку правильно так указывать
UseEncoding koi8-r cp1251
такая проблема в /var/log пишет тарабаршину а в логах базы postgres таблица worklog логов операции с фаилами на русском вообше ниче нету, на англиском они есть

chdd29, 2009-03-12 в 20:02:01

Впрос, а как теперь раздать квоты без создавания юзера, как например ограничит ту же папку test1 не более 100mb?

unknownDaemon, 2010-02-07 в 15:50:58

Статья хорошая, но, внесу свою ложку ;-)
1) Хранить пароли в открытом виде - плохая идея, а потому:
cd work/postgresql-8.4.2/contrib/
gmake && gmake install
su -l pgsql
psql proftpd < /usr/local/share/postgresql/contrib/pgcrypto.sql
SET
CREATE FUNCTION
CREATE FUNCTION
....
CREATE FUNCTION

Потом читать тут(например): http://www.postgresql.org/docs/8.3/static/pgcrypto.html

Потом делать что-то в роде:
[пример для blf]
insert INTO users VALUES (1,'test'crypt('password', gen_salt('bf')),,'ftp',1010,1010,'/var/ftp','/sbin/\
sh','0',0,'0',0);
[пример для md5]
insert INTO users VALUES (1,'test'crypt('password', gen_salt('md5')),,'ftp',1010,1010,'/var/ftp','/sbin/\
sh','0',0,'0',0);

А вообще смотрите табличку на странице в приведенной ссылке...
ЗЫ И не говорите после, что в мускуле есть "крутая" функция PASSWORD из коробки.

ЗЗЫ contrib - это стандартный набор расширений postgresql, который может расширятся и вами по желанию

Удачи!

unknownDaemon, 2010-02-07 в 15:59:55

Для копипастеров: я в инсёрте запятую пропустил ;-)

unknownDaemon, 2010-03-02 в 14:47:22

Афтар, ну поправь статью что ли ;-) Некошерно в открытом виде хранить пасы, несекьюрно. Ежели чего не понятно - рисуй мыло - объясню... В мною приведенном примере юзается blowfish соответственно в конфиге парметр: "SQLAuthTypes" должен быть выставлен в Crypt, при поможи озвученной подключеной libcrypt из контриба можно юзать еще один тип аутидентификации, а именно: "OpenSSL"
Для инфы, если интересно:
http://markmail.org/message/kkbg4tywqnqih5hr
http://www.proftpd.org/docs/directives/linked/config_ref_SQLAuthTypes.html

Гость, 2010-03-30 в 18:57:30

что то не получается авторизоваться используя crypt.
пароли сгенерировал, а авторизация не проходит на фтп.

unknownDaemon, 2010-04-01 в 19:49:16

2 Гость - по подробней плиз,
1) сами функции криптовые в базу доавил?
2) пароли криптанул?
3) метод SQLAuthTypes, в конфиге Proftpd выставил?

Как бы эта...  у меня все работает...

unknownDaemon, 2010-04-01 в 20:06:14

В реале я использую blf(blowfish) -

во-первых за то что оно от системы(в логин.конф у меня тоже он выставлен по дефолту, надеюсь и у Вас ;-) ибо md5 безнадежно протух) и является ни чем иным, как системная Unix crypt(3)

во-вторых потому-что шибко стойкий...

итого:
а) в конфиге фтп сервера:
SQLAuthTypes    Crypt

b) пожалуй момент, который я прежде упустил: так как "оно" становится длиннее - длинна и тип поля для пароля меняются(возможно потому у тебя и трабла... ;-) ), вот скрипт создания таблички:
— Table: users

— DROP TABLE users;

CREATE TABLE users
(
 id serial NOT NULL,
 username character varying(20),
 "password" character varying(70),
 groupname character varying(24),
 uid integer,
 gid integer,
 homedir character varying(70),
 shell character varying(20),
 last_login character varying(30),
 login_count integer,
 last_error_login character varying(30),
 login_error_count integer,
 CONSTRAINT users_pkey PRIMARY KEY (id)
)
WITH (
 OIDS=FALSE
);
ALTER TABLE users OWNER TO proftp;


c) функция добавления сего добра в поле:
crypt('my_super_password', gen_salt('bf'))



truebest, 2010-05-02 в 15:47:42

220 ProFTPD 1.3.3 Server (FTP server DNK) [::ffff:127.0.0.1]

У кого так и в бд не пишутся логи, либо правим бд поля шире делаем либо отключаем в конфиге ipv6

UseIPv6    off

DNK, 2010-06-24 в 12:50:40

Немного дополнил статью :
1) показал как менять кодировку
2) показал как хранить пароли в зашифрованном
виде

DNK, 2010-06-24 в 13:35:23

Да :))
У кого возникает проблема с отображением
времени - смотрите конец конфига

balas, 2010-07-01 в 17:43:24

Доброго времени суток!
В этой строке:
login_error_count=err_login_count+1 WHERE \
скорей всего должно быть так:
login_error_count=login_error_count+1 WHERE \
У меня ошибочные логины не записывались без этого, а потом и вообще весь proftpd отказался работать после очередного обновления.

DNK, 2010-07-02 в 10:00:14

Спачибо за замечание.Исправил.К стати я не пользуюсь записью ошибочных логинов, это скорее отладочная информация.По поводу обновления : прекрасно работаеи под freeBSD 8.0 последняя версия proftp.Если есть проблемы , опиши и с логами в личку скинь, помогу.Постараюсь дописать в статью интерфейс администрирования (у нас он навороченный, нужно урезать) , если это кому-то будет интересно.

balas, 2010-07-02 в 11:18:28

Нет-нет, все работает! Я имел ввиду, что раньше с этой ошибкой в конфиге программа работала (просто ошибочные логины не писала в базу), а после какого-то обновления, стала ругаться и не запускаться, пока я не исправил.



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0558 секунд
Из них PHP: 47%; SQL: 53%; Число SQL-запросов: 77 шт.
Исходный размер: 57465; Сжатая: 14112