dnl dnl поддержка клиентской SMTP Auth (список) dnl dnl NO - не использовать SMTP Auth dnl PLAIN - использовать PLAIN SMTP Auth dnl LOGIN - использовать LOGIN SMTP Auth dnl CRAM-MD5 - использовать CRAM-MD5 SMTP Auth dnl OAUTH2 - использовать OAuth2 SMTP Auth dnl только для exim 4.95 и выше, т. к. нужен патч для поддержки SNI dnl define(`confSMTP_AUTH_CLIENT', `NO')dnl dnl dnl данные аутентификации указываются в файле CONFDIR/smtpauthdb в виде трех колонок, dnl разделенных двоеточиями: dnl host:login:password dnl dnl пример: dnl mail.server:clientname:secret dnl *:defaultclientname:defaultsecret dnl dnl при необходимости использовать логины и пароли в зависимости от адреса отправителя: dnl NO - не использовать логины и пароли в зависимости от адреса отправителя dnl YES - использовать логины и пароли в зависимости от адреса отправителя dnl define(`confSMTP_AUTH_CLIENT_PER_SENDER', `NO')dnl dnl dnl пример: dnl mail.server<@>sender_address1:clientname1:secret1 dnl mail.server<@>sender_address2:clientname2:secret2 dnl mail.server:clientname:secret dnl dnl при необходимости использования другого разделителя его нужно указать в confSMTP_AUTH_CLIENT_SEPARATOR: dnl define(`confSMTP_AUTH_CLIENT_SEPARATOR', `|')dnl dnl dnl пример: dnl mail.server:clientname|secret dnl ifdef(`confSMTP_AUTH_CLIENT_PER_SENDER', `', `define(`confSMTP_AUTH_CLIENT_PER_SENDER', `NO')')dnl ifelse(len(X`'confSMTP_AUTH_CLIENT_PER_SENDER), `1', `define(`confSMTP_AUTH_CLIENT_PER_SENDER', `NO')')dnl ifelse(SECTION, `MAIN', `dnl ifelse(confSMTP_AUTH_CLIENT_PER_SENDER, `NO', `dnl hostlist hosts_try_auth = lsearch,ret=key;CONFDIR/smtpauthdb ', `dnl hostlist hosts_try_auth = ${sg{${sg{${sg{${sg{${readfile{CONFDIR/smtpauthdb}}}{\N(?sm)^[ \t]*(#[^\n]*)?\n\N}{}}}{\N(<@>.+)?:[^\n]+\N}{}}}{\n}{:}}}{\N:$\N}{}} ') dnl ifelse(confSMTP_AUTH_CLIENT_PER_SENDER, `NO', `') ') ifelse(SECTION, `AUTHENTICATORS', `dnl ifdef(`confSMTP_AUTH_CLIENT_SEPARATOR', `', `define(`confSMTP_AUTH_CLIENT_SEPARATOR', `:')')dnl ifelse(len(X`'confSMTP_AUTH_CLIENT_SEPARATOR), `1', `define(`confSMTP_AUTH_CLIENT_SEPARATOR', `:')')dnl ifelse(confSMTP_AUTH_CLIENT_PER_SENDER, `NO', `dnl define(`_confSMTP_AUTH_CLIENT_LOOKUP_', `${lookup{$host}lsearch*{CONFDIR/smtpauthdb}{$value}fail}')dnl ', `dnl define(`_confSMTP_AUTH_CLIENT_LOOKUP_', `${lookup{$host<@>$sender_address}lsearch*{CONFDIR/smtpauthdb}{$value}{${lookup{$host}lsearch*{CONFDIR/smtpauthdb}{$value}fail}}}')dnl ') dnl ifelse(confSMTP_AUTH_CLIENT_PER_SENDER, `NO', `') ifelse_strstr(confSMTP_AUTH_CLIENT, `PLAIN', `dnl client_auth_plain: driver = plaintext public_name = PLAIN client_condition = ${if eq{_confSMTP_AUTH_CLIENT_LOOKUP_}{}{no}{yes}} client_send = "^${extract{1}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}}^${extract{2}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}}" ') ifelse_strstr(confSMTP_AUTH_CLIENT, `LOGIN', `dnl client_auth_login: driver = plaintext public_name = LOGIN client_condition = ${if eq{_confSMTP_AUTH_CLIENT_LOOKUP_}{}{no}{yes}} client_send = ": ${extract{1}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}} : ${extract{2}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}}" ') ifelse_strstr(confSMTP_AUTH_CLIENT, `CRAM-MD5', `dnl client_cram_md5: driver = cram_md5 public_name = CRAM-MD5 client_condition = ${if eq{_confSMTP_AUTH_CLIENT_LOOKUP_}{}{no}{yes}} client_name = ${extract{1}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}} client_secret = ${extract{2}{confSMTP_AUTH_CLIENT_SEPARATOR}{_confSMTP_AUTH_CLIENT_LOOKUP_}} ') ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTH2', `dnl client_oauth2: driver = plaintext public_name = XOAUTH2 client_condition = ${lookup{$host<@>$sender_address<@>oauth2}lsearch*{CONFDIR/smtpauthdb}{yes}{no}} # client_send = ${lookup{$host<@>$sender_address<@>oauth2}lsearch*{CONFDIR/smtpauthdb}{${acl{acl_expand}{$value}}}fail} client_send = "<\n ${lookup{$host<@>$sender_address<@>oauth2}lsearch*{CONFDIR/smtpauthdb}{${expand:$value}}fail}" ') ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTHBEARER', `dnl client_oauthbearer: driver = plaintext public_name = OAUTHBEARER client_condition = ${lookup{$host<@>$sender_address<@>oauthbearer}lsearch*{CONFDIR/smtpauthdb}{yes}{no}} # client_send = ${lookup{$host<@>$sender_address<@>oauthbearer}lsearch*{CONFDIR/smtpauthdb}{${acl{acl_expand}{$value}}}fail} client_send = "<\n ${lookup{$host<@>$sender_address<@>oauthbearer}lsearch*{CONFDIR/smtpauthdb}{${expand:$value}}fail}" ') ') dnl ifelse(SECTION, `AUTHENTICATORS', `') ifelse(SECTION, `ACLS_ADDITIONAL', `dnl define(`_OAUTH_TOKENS_', `NO')dnl ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTH2', `define(`_OAUTH_TOKENS_', `YES')') ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTHBEARER', `define(`_OAUTH_TOKENS_', `YES')') ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTH2', `dnl dnl exim -be ${acl{acl_get_google_oauth2_refresh_token}{USER@gmail.com}{CODE}{REDIRECT_URI}} acl_get_google_oauth2_refresh_token: # acl_arg1 - sender address # acl_arg2 - authorization code # acl_arg3 - redirect URI accept condition = ${if eq{$acl_arg2}{}{yes}{no}} log_message = Google OAuth2 get refresh token for user $acl_arg1: authorization code expected accept condition = ${if eq{$acl_arg3}{}{yes}{no}} log_message = Google OAuth2 get refresh token for user $acl_arg1: redirect URI expected warn set acl_m_now = $tod_epoch warn set acl_m_oauth2_data = ${lookup mysql{SELECT * FROM mail.oauth2_google_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 client secret for user $acl_arg1 not found warn set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&grant_type=authorization_code&code=$acl_arg2&redirect_uri=$acl_arg3 set acl_m_oauth2_token_response = set acl_m_oauth2_token_response = ${readsocket{inet:oauth2.googleapis.com:443}{POST https://oauth2.googleapis.com/token HTTP/1.0\r\nHost: oauth2.googleapis.com\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=oauth2.googleapis.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: socket failure accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: empty response received warn set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: empty response body accept \ # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: response body is not a JSON warn set acl_m_oauth2_refresh_token_new = ${extract jsons{refresh_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} accept condition = ${if eq{$acl_m_oauth2_refresh_token_new}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent refresh_token accept condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent expires_in accept condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Google OAuth2 refresh token for user $acl_arg1 getting: expires_in is not a number warn set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_google_tokens SET \ refresh_token="${quote_mysql:$acl_m_oauth2_refresh_token_new}", \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}", \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}) \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} acl_get_google_oauth2_access_token: # acl_arg1 - sender address warn set acl_m_now = $tod_epoch set acl_m_oauth2_data = set acl_m_oauth2_token_response = set acl_m_oauth2_data = ${lookup mysql{SELECT *, UNIX_TIMESTAMP(access_token_expires_at) as access_token_expires_at_unixtime FROM mail.oauth2_google_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 client secret for user $acl_arg1 not found accept condition = ${if eq{${extract{refresh_token}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Google OAuth2 refresh token for user $acl_arg1 not found warn set acl_m_oauth2_access_token = ${extract{access_token}{$acl_m_oauth2_data}} set acl_m_oauth2_access_token = ${if eq{${extract{access_token_expires_at}{$acl_m_oauth2_data}}}{}{}{$acl_m_oauth2_access_token}} condition = ${if <{${extract{access_token_expires_at_unixtime}{$acl_m_oauth2_data}}}{$tod_epoch}{yes}{no}} set acl_m_oauth2_access_token = log_message = Google OAuth2 access token for user $acl_arg1 expired. Try to refresh warn condition = ${if eq{$acl_m_oauth2_access_token}{}{no}{yes}} log_message = Google OAuth2 access token for user $acl_arg1: cached access token found warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&grant_type=refresh_token&refresh_token=${extract{refresh_token}{$acl_m_oauth2_data}} set acl_m_oauth2_token_response = ${readsocket{inet:oauth2.googleapis.com:443}{POST https://oauth2.googleapis.com/token HTTP/1.0\r\nHost: oauth2.googleapis.com\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=oauth2.googleapis.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: socket failure accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: empty response received warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: empty response body accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: response body is not a JSON warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent expires_in accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Google OAuth2 access token for user $acl_arg1 refreshing: expires_in is not a number warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token = $acl_m_oauth2_access_token_new set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_google_tokens SET \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}), \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}" \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} accept message = $acl_m_oauth2_access_token dnl exim -be ${acl{acl_get_ms_oauth2_refresh_token}{USER@DOMAIN}{CODE}{REDIRECT_URI}} acl_get_ms_oauth2_refresh_token: # acl_arg1 - sender address # acl_arg2 - authorization code # acl_arg3 - redirect URI accept condition = ${if eq{$acl_arg2}{}{yes}{no}} log_message = Microsoft OAuth2 get refresh token for user $acl_arg1: authorization code expected accept condition = ${if eq{$acl_arg3}{}{yes}{no}} log_message = Microsoft OAuth2 get refresh token for user $acl_arg1: redirect URI expected warn set acl_m_now = $tod_epoch warn set acl_m_oauth2_data = ${lookup mysql{SELECT * FROM mail.oauth2_ms_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{tenant_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 tenant ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 client secret for user $acl_arg1 not found warn set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&client_info=1&grant_type=authorization_code&code=$acl_arg2&scope=https://outlook.office.com/SMTP.Send+offline_access+openid+profile&redirect_uri=$acl_arg3 set acl_m_oauth2_token_response = set acl_m_oauth2_token_response = ${readsocket{inet:login.microsoftonline.com:443}{POST https://login.microsoftonline.com/${extract{tenant_id}{$acl_m_oauth2_data}}/oauth2/v2.0/token HTTP/1.0\r\nHost: login.microsoftonline.com\r\nAccept: application/json\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=login.microsoftonline.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: socket failure accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: empty response received warn set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: empty response body accept \ # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: response body is not a JSON warn set acl_m_oauth2_refresh_token_new = ${extract jsons{refresh_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} accept condition = ${if eq{$acl_m_oauth2_refresh_token_new}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent refresh_token accept condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent expires_in accept condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 getting: expires_in is not a number warn set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_ms_tokens SET \ refresh_token="${quote_mysql:$acl_m_oauth2_refresh_token_new}", \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}", \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}) \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} acl_get_ms_oauth2_access_token: # acl_arg1 - sender address warn set acl_m_now = $tod_epoch set acl_m_oauth2_data = set acl_m_oauth2_token_response = set acl_m_oauth2_data = ${lookup mysql{SELECT *, UNIX_TIMESTAMP(access_token_expires_at) as access_token_expires_at_unixtime FROM mail.oauth2_ms_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{tenant_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 tenant ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 client secret for user $acl_arg1 not found accept condition = ${if eq{${extract{refresh_token}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Microsoft OAuth2 refresh token for user $acl_arg1 not found warn set acl_m_oauth2_access_token = ${extract{access_token}{$acl_m_oauth2_data}} set acl_m_oauth2_access_token = ${if eq{${extract{access_token_expires_at}{$acl_m_oauth2_data}}}{}{}{$acl_m_oauth2_access_token}} condition = ${if <{${extract{access_token_expires_at_unixtime}{$acl_m_oauth2_data}}}{$tod_epoch}{yes}{no}} set acl_m_oauth2_access_token = log_message = Microsoft OAuth2 access token for user $acl_arg1 expired. Try to refresh warn condition = ${if eq{$acl_m_oauth2_access_token}{}{no}{yes}} log_message = Microsoft OAuth2 access token for user $acl_arg1: cached access token found warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&client_info=1&grant_type=refresh_token&refresh_token=${extract{refresh_token}{$acl_m_oauth2_data}}&scope=https://outlook.office.com/SMTP.Send+offline_access+openid+profile set acl_m_oauth2_token_response = ${readsocket{inet:login.microsoftonline.com:443}{POST https://login.microsoftonline.com/${extract{tenant_id}{$acl_m_oauth2_data}}/oauth2/v2.0/token HTTP/1.0\r\nHost: login.microsoftonline.com\r\nAccept: application/json\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=login.microsoftonline.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: socket failure accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: empty response received warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: empty response body accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: response body is not a JSON warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} set acl_m_oauth2_refresh_token_new = ${extract jsons{refresh_token}{$acl_m_oauth2_token_response}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent expires_in accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: expires_in is not a number accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_refresh_token_new}{}{yes}{no}} log_message = Microsoft OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent refresh_token warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token = $acl_m_oauth2_access_token_new set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_ms_tokens SET \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}), \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}", \ refresh_token="${quote_mysql:$acl_m_oauth2_refresh_token_new}" \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} accept message = $acl_m_oauth2_access_token dnl exim -be ${acl{acl_get_yahoo_oauth2_refresh_token}{USER@yahoo.com}{CODE}{REDIRECT_URI}} acl_get_yahoo_oauth2_refresh_token: # acl_arg1 - sender address # acl_arg2 - authorization code # acl_arg3 - redirect URI accept condition = ${if eq{$acl_arg2}{}{yes}{no}} log_message = Yahoo OAuth2 get refresh token for user $acl_arg1: authorization code expected accept condition = ${if eq{$acl_arg3}{}{yes}{no}} log_message = YAhoo OAuth2 get refresh token for user $acl_arg1: redirect URI expected warn set acl_m_now = $tod_epoch warn set acl_m_oauth2_data = ${lookup mysql{SELECT * FROM mail.oauth2_yahoo_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 client secret for user $acl_arg1 not found warn set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&grant_type=authorization_code&code=$acl_arg2&redirect_uri=$acl_arg3 set acl_m_oauth2_token_response = set acl_m_oauth2_token_response = ${readsocket{inet:api.login.yahoo.com:443}{POST https://api.login.yahoo.com/oauth2/get_token HTTP/1.0\r\nHost: api.login.yahoo.com\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=api.login.yahoo.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: socket failure accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: empty response received warn set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: empty response body accept \ # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: response body is not a JSON warn set acl_m_oauth2_refresh_token_new = ${extract jsons{refresh_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} accept condition = ${if eq{$acl_m_oauth2_refresh_token_new}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent refresh_token accept condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: empty or unexistent expires_in accept condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 getting: expires_in is not a number warn set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_yahoo_tokens SET \ refresh_token="${quote_mysql:$acl_m_oauth2_refresh_token_new}", \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}", \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}) \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} acl_get_yahoo_oauth2_access_token: # acl_arg1 - sender address warn set acl_m_now = $tod_epoch set acl_m_oauth2_data = set acl_m_oauth2_token_response = set acl_m_oauth2_data = ${lookup mysql{SELECT *, UNIX_TIMESTAMP(access_token_expires_at) as access_token_expires_at_unixtime FROM mail.oauth2_yahoo_tokens WHERE sender_address="${quote_mysql:$acl_arg1}";}{$value}fail} accept condition = ${if eq{${extract{sender_address}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 data for user $acl_arg1 not found accept condition = ${if eq{${extract{client_id}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 client ID for user $acl_arg1 not found accept condition = ${if eq{${extract{client_secret}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 client secret for user $acl_arg1 not found accept condition = ${if eq{${extract{refresh_token}{$acl_m_oauth2_data}}}{}{yes}{no}} log_message = Yahoo OAuth2 refresh token for user $acl_arg1 not found warn set acl_m_oauth2_access_token = ${extract{access_token}{$acl_m_oauth2_data}} set acl_m_oauth2_access_token = ${if eq{${extract{access_token_expires_at}{$acl_m_oauth2_data}}}{}{}{$acl_m_oauth2_access_token}} condition = ${if <{${extract{access_token_expires_at_unixtime}{$acl_m_oauth2_data}}}{$tod_epoch}{yes}{no}} set acl_m_oauth2_access_token = log_message = Yahoo OAuth2 access token for user $acl_arg1 expired. Try to refresh warn condition = ${if eq{$acl_m_oauth2_access_token}{}{no}{yes}} log_message = Yahoo OAuth2 access token for user $acl_arg1: cached access token found warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m0 = client_id=${extract{client_id}{$acl_m_oauth2_data}}&client_secret=${extract{client_secret}{$acl_m_oauth2_data}}&grant_type=refresh_token&refresh_token=${extract{refresh_token}{$acl_m_oauth2_data}} set acl_m_oauth2_token_response = ${readsocket{inet:api.login.yahoo.com:443}{POST https://api.login.yahoo.com/oauth2/get_token HTTP/1.0\r\nHost: api.login.yahoo.com\r\nContent-Length: ${strlen:$acl_m0}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\n\r\n$acl_m0}{20s:tls=yes:sni=api.login.yahoo.com}{\n}{socket failure}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{socket failure}{yes}{no}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: socket failure accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: empty response received warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_token_response = ${sg{$acl_m_oauth2_token_response}{\N^(.+\r?\n)+?\r?\n\N}{}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_token_response}{}{yes}{no}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: empty response body accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} # condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{(.*\n)*.*\}$\N}{no}{yes}} condition = ${if match{$acl_m_oauth2_token_response}{\N^[\s\r\n]*\{[\s\r\n]*("[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))?([\s\r\n]*,[\s\r\n]*[\s\r\n]*"[A-Za-z\d_]+"[\s\r\n]*:[\s\r\n]*(\d+|".*?"))*[\s\r\n]*\}$\N}{no}{yes}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: response body is not a JSON warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token_new = ${extract jsons{access_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_expires_in_new = ${extract json{expires_in}{$acl_m_oauth2_token_response}} set acl_m_oauth2_refresh_token_new = ${extract jsons{refresh_token}{$acl_m_oauth2_token_response}} set acl_m_oauth2_refresh_token_new = ${if eq{$acl_m_oauth2_refresh_token_new}{}{${extract{refresh_token}{$acl_m_oauth2_data}}}{$acl_m_oauth2_refresh_token_new}} accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_access_token_new}{}{yes}{no}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent access_token accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if eq{$acl_m_oauth2_expires_in_new}{}{yes}{no}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: empty or unexistent expires_in accept condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} condition = ${if match{$acl_m_oauth2_expires_in_new}{\N^\d+$\N}{no}{yes}} log_message = Yahoo OAuth2 access token for user $acl_arg1 refreshing: expires_in is not a number warn condition = ${if eq{$acl_m_oauth2_access_token}{}{yes}{no}} set acl_m_oauth2_access_token = $acl_m_oauth2_access_token_new set acl_m0 = ${lookup mysql{\ UPDATE mail.oauth2_yahoo_tokens SET \ access_token_expires_at=FROM_UNIXTIME(${eval:$tod_epoch + $acl_m_oauth2_expires_in_new - 60}), \ access_token="${quote_mysql:$acl_m_oauth2_access_token_new}", \ refresh_token="${quote_mysql:$acl_m_oauth2_refresh_token_new}" \ WHERE sender_address="${quote_mysql:$acl_arg1}"\ }{$value}fail} accept message = $acl_m_oauth2_access_token acl_get_google_oauth2_data: # acl_arg1 - sender address warn set acl_m_oauth2_access_token = ${acl{acl_get_google_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ user=$acl_arg1\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} acl_get_ms_oauth2_data: # acl_arg1 - sender address warn set acl_m_oauth2_access_token = ${acl{acl_get_ms_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ user=$acl_arg1\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} acl_get_yahoo_oauth2_data: # acl_arg1 - sender address warn set acl_m_oauth2_access_token = ${acl{acl_get_yahoo_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ user=$acl_arg1\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} ') dnl ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTH2', `') ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTHBEARER', `dnl acl_get_google_oauthbearer_data: # acl_arg1 - sender address # acl_arg2 - server address # acl_arg3 - server port warn set acl_m_oauth2_access_token = ${acl{acl_get_google_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ n,a=$acl_arg1,\x01host=$acl_arg2\x01port=$acl_arg3\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} acl_get_ms_oauthbearer_data: # acl_arg1 - sender address # acl_arg2 - server address # acl_arg3 - server port warn set acl_m_oauth2_access_token = ${acl{acl_get_ms_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ n,a=$acl_arg1,\x01host=$acl_arg2\x01port=$acl_arg3\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} acl_get_yahoo_oauthbearer_data: # acl_arg1 - sender address # acl_arg2 - server address # acl_arg3 - server port warn set acl_m_oauth2_access_token = ${acl{acl_get_yahoo_oauth2_access_token}{$acl_arg1}} accept message = ${if eq{$acl_m_oauth2_access_token}{}{}{\ n,a=$acl_arg1,\x01host=$acl_arg2\x01port=$acl_arg3\x01auth=Bearer $acl_m_oauth2_access_token\x01\x01\ }} ') dnl ifelse_strstr(confSMTP_AUTH_CLIENT, `OAUTHBEARER', `') ') dnl ifelse(SECTION, `ACLS_ADDITIONAL', `')