Страница 1 из 1

Exim и ограничения при отправке почты

Добавлено: 2008-06-16 10:18:51
wein72
Доброго времени суток!

Вот возникла задачка такая: есть почтовый сервер с mta exim (база юзеров в mysql), на нём необходимо сделать так, чтобы одни пользователи могли отсылать почту куда угодно, а другие - лишь в пределах локального домена. Всё усложняется тем, что только часть клиентов находится в одной локальной сети с сервером. Остальные цепляются к нему с инета с одного фиксированного ip-адреса.
Идея такая: в таблице users, где хранятся данные об акаунтах, я создал ещё одно доп. поле relay. Полагается сделать так, чтобы почту отправлять во внешний мир могли только пользователи, для которых relay=1.
Собственно вопрос: откуда плясать? Мануалы читал, но что-то просветление не настало :(
Пробовал в acl_check_rcpt завязать при помощи endpass дополнительное условие к accept autenthicated, но что-то не попёрло, либо я lookup неправильно построил, либо идея в корне не верна была :-)
В общем, научите как надо, люди добрые! Заранее благодарствую.

С уважением, Алексей.

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-16 10:29:08
dikens3
Ты всё верно мыслишь, только недоконца.

1. Определиться, как отличать всех своих пользователей. (Лучше наверное аутентификацией абсолютно для всех, и пускай бегают как хотят)
2. Разрешить отправку почты куда угодно аутентифицированным у которых relay = 1.

Всё.

Кратко acl_smtp_rcpt выглядит так:

Код: Выделить всё

acl_check_rcpt:

# Принимаем почту пришедшую не по TCP/IP, localhost имеется ввиду
  accept  hosts = :

# Принимаем аутентифицированных для внешних доменов
  accept    authenticated = *
            !domains       = +local_domains
            + тут проверка на relay = 1

# Принимаем письма для нашего домена
  accept    domains       = +local_domains
            endpass
            message       = "Unknown user"
            verify        = recipient

# Остальных прибиваем
  deny     message       = relay not permitted

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-16 10:59:27
wein72
1. Определиться, как отличать всех своих пользователей. (Лучше наверное аутентификацией абсолютно для всех, и пускай бегают как хотят)
Ну так я и думаю примерно. Т.е. аутентификация для всех абсолютно, а после проверка на relay=1 из базы
2. Разрешить отправку почты куда угодно аутентифицированным у которых relay = 1.
а вот тут вопрос: а что будет с аутентифицированными, у которых relay<>1? ;-) они по идее должны иметь право слать почту только адресатам из локального домена

Мой alc сейчас выглядит вот так (это в принципе дефолтовый конфиг из virtual exim):

Код: Выделить всё

acl_check_rcpt:

  accept  hosts = :

  # Include Vexim specific rcpt ACLs
  .include /usr/local/exim/vexim-acl-check-rcpt.conf
  #  тут ничего особенного, лишь список dns blacklists

  deny    local_parts   = ^.*[@%!/|] : ^\\.
  accept  local_parts   = postmaster
          domains       = +local_domains
  accept  domains       = +local_domains
          endpass
          verify        = recipient
  accept  domains       = +relay_to_domains
          endpass
          verify        = recipient
  accept  hosts         = +relay_from_hosts

# вот тут я экспериментировал, пробуя различные условия, раскоментируя различные комбинации, но в итоге ничего не заработало :-(

#  accept  authenticated = *
#  endpass 
#  accept  condition = ${lookup mysql{SELECT username FROM users WHERE relay = 1}{yes}{no}}
#  accept  condition     = ${if match{lookup mysql{select relay from users where username="$sender_address"}}{1}{yes}{no}}
#  accept  condition     = ${lookup mysql {SELECT relay FROM users WHERE username=$sender_address}{1}{yes}{no}}
#  endpass
#  accept  authenticated = *
#  endpass
#  accept  condition     = ${if match{lookup mysql{select relay from users where username="$sender_address"}}={"1"}{yes}{no}}
#  accept  condition     = ${if eq {${lookup mysql{select relay from users where username="$sender_address"}{"1"}{yes}{no}}
#  endpass

  accept  authenticated = *  
  deny    message       = relay not permitted
Вот как условие прописать правильно - я заступорился честно говоря :(

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-16 12:22:09
dikens3
Вот как условие прописать правильно - я заступорился честно говоря
Я делаю так.
1. Составляю сами запросы (Они у меня в отдельном файле):

Код: Выделить всё

# Полная квота почтового ящика
MYSQL_QUOTA             = SELECT `quota-max` FROM users WHERE username='${quote_mysql:$local_part}' LIMIT 1
DEFAULT_QUOTA_LIMIT     = 25M

# Системные пользователи, им почту посылать нельзя
MYSQL_SYSTEM_USERS      = SELECT dst_username FROM aliases WHERE dst_username='${quote_mysql:$local_part}' AND active='S' LIMIT 1

# Список доменов
MYSQL_DOMAINS           = SELECT domain FROM domains WHERE domain='${quote_mysql:$domain}' AND active='Y' LIMIT 1

# Список алиасов
MYSQL_ALIASES           = SELECT recipient FROM aliases WHERE dst_username='${quote_mysql:$local_part}' AND active!='N' LIMIT 1
2. Далее в acl_smtp_rcpt я выполняю запрос и загоняю результат в переменную:

Код: Выделить всё

set acl_m19  = ${lookup mysql{MYSQL_SYSTEM_USERS}}
3. И затем работаю с этой переменной.

Код: Выделить всё

condition     = ${if eq{$acl_m19}{1}{yes}{no}}
4. В итоге у тебя получается примерно следующее:

Код: Выделить всё

# Принимаем аутентифицированных для внешних доменов
  accept    authenticated = *
            !domains       = +local_domains
            set acl_m19  = ${lookup mysql{MYSQL_RELAY_USERS}}
            condition     = ${if eq{$acl_m19}{1}{yes}{no}}
Желательно именно в таком порядке, чтобы зря базу mysql не гонять. Только для аутентифицированных и при отправке во внешний мир произойдёт запрос к базе и значение отправится в acl_m19, которое и будет сравниваться с 1 (единицей).
а вот тут вопрос: а что будет с аутентифицированными, у которых relay<>1? ;-) они по идее должны иметь право слать почту только адресатам из локального домена
Просто блок (который я привёл чёть выше) несработает и действие перейдёт к следующему блоку, в котором произойдёт приём письма для твоего домена.

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-17 6:45:52
wein72
В итоге у тебя получается примерно следующее:

Код: Выделить всё

# Принимаем аутентифицированных для внешних доменов
  accept    authenticated = *
            !domains       = +local_domains
            set acl_m19  = ${lookup mysql{MYSQL_RELAY_USERS}}
            condition     = ${if eq{$acl_m19}{1}{yes}{no}}
Желательно именно в таком порядке, чтобы зря базу mysql не гонять. Только для аутентифицированных и при отправке во внешний мир произойдёт запрос к базе и значение отправится в acl_m19, которое и будет сравниваться с 1 (единицей).
Ну общую мыслю я понял вроде твою. Только теперь бы ещё запрос сформировать правильно :-) Вот смотри, таблица users, в ней поле relay (0 или 1). Как будет выглядеть запрос для MYSQL_RELAY_USERS примерно?

Кстати, нагрузка на базу не критична в моем случае :-) Тама 10-15 юзеров всего в почте и сервак мощный весьма.

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-17 8:59:13
dikens3

Код: Выделить всё

MYSQL_RELAY_USERS = select relay from users where user = '${quote_mysql:$local_part}' LIMIT 1
примерно так, только потребуется ещё одно поле, в котором содержатся имена пользователей без домена? Я его назвал user.

Для составления запроса требуется 2-а поля. relay + то, в котором хранятся пользователи + как именно хранятся пользователи (с доменом или без)

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-17 12:07:14
wein72
dikens3 писал(а):

Код: Выделить всё

MYSQL_RELAY_USERS = select relay from users where user = '${quote_mysql:$local_part}' LIMIT 1
примерно так, только потребуется ещё одно поле, в котором содержатся имена пользователей без домена? Я его назвал user.
Ну у меня есть такое поле по умолчанию, называется localpart.
Для составления запроса требуется 2-а поля. relay + то, в котором хранятся пользователи + как именно хранятся пользователи (с доменом или без)
А это так принципиально как они хранятся? У меня есть там 2 поля: localpart и username. В первом только имена без доменов, во втором - полное имя с доменом соответственно.
Получается для моего случая необходимо добавить в конфиг следующее:

Код: Выделить всё

MYSQL_RELAY_USERS = select relay from users where localpart = '${quote_mysql:$local_part}' LIMIT 1 
# или всё же тут вместо localpart использовать username?

# ну и добавить в конец acl
accept    authenticated = *
            !domains       = +local_domains
            set acl_m19  = ${lookup mysql{MYSQL_RELAY_USERS}}
            condition     = ${if eq{$acl_m19}{1}{yes}{no}}
Примерно так?

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-17 14:04:09
dikens3
Не в конец, а в начало. Млин ну думай уже, вверху всё описано очень доходчиво. Перечитай и подумай.

P.S. Mysql запрос верный. (можно проверить руками зайдя в mysql)

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-25 14:11:40
wein72
dikens3 писал(а):Не в конец, а в начало. Млин ну думай уже, вверху всё описано очень доходчиво. Перечитай и подумай.
Перечитал. Подумал. Что-то не хочет всё равно :st: При таком раскладе говорит что релей закрыт в любом случае, независимо от значения поля relay.

Получил я вот такой конфиг:

Код: Выделить всё

#добавил к прочим запросам вот этот
RELAY_USERS = SELECT relay FROM users WHERE localpart = '${quote_mysql:$local_part}' LIMIT 1
#тут localpart - имя пользователя без домена, есть в таблице такое отдельным полем
Запрос верный видимо, проверял в мускле - похоже возвращает как надо всё:

Код: Выделить всё

mysql> SELECT relay FROM users WHERE localpart = 'test' LIMIT 1;
+-------+
| relay |
+-------+
| 1     |
+-------+
1 row in set (0.00 sec)
Это для пользователя test, у которого relay=1.

ACL выглядел вот так:

Код: Выделить всё

acl_check_rcpt:

  accept  hosts = :

  # Include Vexim specific rcpt ACLs
  .include /usr/local/exim/vexim-acl-check-rcpt.conf

  deny    local_parts   = ^.*[@%!/|] : ^\\.
  accept  local_parts   = postmaster
          domains       = +local_domains
  accept  authenticated = *
	  !domains = +local_domains
	  set acl_m19  = ${lookup mysql{RELAY_USERS}}
	  condition = ${if eq{$acl_m19}{1}{yes}{no}}
  accept  domains       = +local_domains
          endpass
          verify        = recipient
  accept  domains       = +relay_to_domains
          endpass
          verify        = recipient
  accept  hosts         = +relay_from_hosts
  deny    message       = relay not permitted
В include ничего кроме списка dns-блэклистов нету.

Где что я опять делаю не так? :(

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-25 14:56:35
dikens3
Лог где?

Скорее всего пользователь не аутентифицировался.

Есть ещё например такое действие logwrite = :panic: $acl_m19

Использовать так:

Код: Выделить всё

  accept  authenticated = *
     !domains = +local_domains
     set acl_m19  = ${lookup mysql{RELAY_USERS}}
     logwrite = :panic: "значение m19: $acl_m19"
     condition = ${if eq{$acl_m19}{1}{yes}{no}}
Как только дойдёт до logwrite в paniclog будет переменная $acl_m19

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-26 9:04:08
wein72
dikens3 писал(а):Лог где?

Скорее всего пользователь не аутентифицировался.
Естественно не аутентифицировался ибо сообщает:

Код: Выделить всё

2008-06-26 10:26:28 H=(admin) [192.168.1.10] F=<test@xx.ru> rejected RCPT <wein72@gm__l.com>: relay not permitted
Есть ещё например такое действие logwrite = :panic: $acl_m19
Да, похоже переменная пустая :(

Код: Выделить всё

2008-06-26 10:26:28 "value of m19: "

Т.е. видимо затык где-то тут:

Код: Выделить всё

RELAY_USERS = SELECT relay FROM users WHERE localpart = '${quote_mysql:$local_part}' LIMIT 1
Получается что если запрос вида:

Код: Выделить всё

mysql> SELECT relay FROM users WHERE localpart = 'test' LIMIT 1;
возвращает то, что надо, то грабли где-то в этой части?

Код: Выделить всё

localpart = '${quote_mysql:$local_part}' LIMIT 1
Точно запрос то верный тогда? У меня localpart - это имя пользователя БЕЗ доменной части.

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-26 10:07:16
dikens3
зафискируй весь запрос и всё узнаешь.

Код: Выделить всё

accept  authenticated = *
        !domains = +local_domains
        logwrite = :panic: "Мой запрос будет: RELAY_USERS"
        set acl_m19  = ${lookup mysql{RELAY_USERS}}
        condition = ${if eq{$acl_m19}{1}{yes}{no}}
Потом то, что будет в логе выполни руками в mysql.

Re: Exim и ограничения при отправке почты

Добавлено: 2008-06-26 11:07:13
wein72
Всё заработало!
Правильный запрос к базе выглядит так:

Код: Выделить всё

RELAY_USERS = SELECT relay FROM users WHERE username = '${quote_mysql:$authenticated_id}' LIMIT 1
Надо отметить, что username - это полное имя пользователя С ДОМЕНОМ.
Ну и сам ACL в принципе без изменений, первым условием идёт:

Код: Выделить всё

  accept  authenticated = *
	  !domains = +local_domains
	  set acl_m19  = ${lookup mysql{RELAY_USERS}}
	  condition = ${if eq{$acl_m19}{1}{yes}{no}}
Моё огромное человеческое спасибо товарисчу dikens3!