mail=# select * from maps limit 3; id | ldomain_id | mdomain_id | storage1 | storage2 ----+------------+------------+--------------------+--------------- 56 | 56 | 2 | storage-01.domain.ru | storage-02.domain.ru 57 | 57 | 2 | storage-02.domain.ru | storage-01.domain.ru 58 | 58 | 2 | storage-01.domain.ru | storage-02.domain.ru (3 )
psql -Upgsql template1 ctreate database mail; \q
CREATE TABLE mail ( "id" BIGSERIAL PRIMARY KEY, "mailbox" CHARACTER VARYING(32) not null, "password" CHARACTER VARYING(128), "ldomain_id" int NOT NULL, "mdomain_id" int NOT NULL, active BOOLEAN DEFAULT TRUE NOT NULL, CONSTRAINT "mail_ldomain_id_check" CHECK (("ldomain_id" > 0)) ); CREATE TABLE "ldomain" ( "id" BIGSERIAL PRIMARY KEY, "domain" CHARACTER VARYING(32) NOT NULL, "active" BOOLEAN DEFAULT TRUE NOT NULL, CONSTRAINT ldomain_k UNIQUE (domain) ); CREATE TABLE "mdomain" ( "id" BIGSERIAL PRIMARY KEY, "domain" CHARACTER VARYING(32) NOT NULL, "active" BOOLEAN DEFAULT TRUE NOT NULL, CONSTRAINT mdomain_k UNIQUE (domain) ); CREATE TABLE "maps" ( "id" SERIAL PRIMARY KEY, "ldomain_id" int NOT NULL, "mdomain_id" int NOT NULL, "storage1" CHARACTER VARYING(32) NOT NULL, "storage2" CHARACTER VARYING(32) NOT NULL, CONSTRAINT maps_ldomain_k UNIQUE (ldomain_id) );
/usr/local/etc/dovecot/dovecot.conf protocols = imap pop3 lmtp # Exim LMTP
/usr/local/etc/dovecot/dovecot-sql.conf.ext driver = pgsql connect = host=localhost dbname=mail user=mail password=password default_pass_scheme = MD5 iterate_query = \ SELECT mail.mailbox || '@' || ldomain.domain || '.' || mdomain.domain AS user \ FROM mail \ INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) \ INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) password_query = \ SELECT mail.mailbox || '@' || ldomain.domain || '.' || mdomain.domain AS mail, mail.password \ FROM mail \ INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) \ INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) \ WHERE mailbox = '%n' AND \ ldomain.domain || '.' || mdomain.domain = '%d' AND \ mail.active = true AND \ ldomain.active = 'true' user_query = \ SELECT '/usr/mail/' || ldomain.domain || '.' || mdomain.domain || '/' || mail.mailbox AS home \ FROM mail \ INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) \ INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) \ WHERE mail.mailbox = '%n' AND \ ldomain.domain || '.' || mdomain.domain = '%d'
/usr/local/etc/dovecot/conf.d/10-auth.conf auth_username_format = %Lu # mail@ldomain.mdomain.ru !include auth-sql.conf.ext
/usr/local/etc/dovecot/conf.d/10-mail.conf mail_location = maildir:/usr/mail/%d/%n/Maildir # /usr/mail/ 2- / 3- //
#mailrsync.pl storage-01.domain.ru storage-02.domain.ru
#!/usr/local/bin/perl use DBI; use threads; use Net::Nslookup; use Sys::Hostname; @host = split('\.',hostname); $dbn="mail"; $dbuser="mail"; $dbpass = "password" $curdata=`date +%Y-%m`; chop $curdata; $conn=DBI->connect("DBI:Pg:dbname=$dbn;host=localhost","$dbuser","$dbpass") or die "Cannot connect"; ($localhostname,$remotehost)=@ARGV; $mail_dir = "/usr/mail/"; sub domains { $q = "SELECT ldomain.domain,mdomain.domain,maps.storage1 FROM mail INNER JOIN ldomain on (mail.ldomain_id = ldomain.id) INNER JOIN mdomain on (mail.mdomain_id = mdomain.id) INNER JOIN maps on (maps.ldomain_id=ldomain.id) WHERE maps.storage1='".$localhostname."' AND mail.mailbox ='dir'"; $domain = $conn->prepare($q) or die "Can't prepare statement: $DBI::errstr"; $domain->execute(); while ( my @domain = $domain->fetchrow_array ) { @domains=(@domains,$domain[0].".".$domain[1]); } print "count of domains: ".($#domains + 1)."\n"; $dt = 2; # $count = ($#domains / $dt ); print "count: ".$count."\n"; $i1 = 0; for ($i2 = 0; $i2< $count; $i2++){ if ($dt > $#domains ){$dt = $#domains ;} print $dt."\n"; print "loop: ".$i2."\n"; foreach $item (@domains[$i1..$m]){ print "in \@domains: ".$mail_dir.$item."\n"; @stack = (@stack,$mail_dir.$item."/"); } push @threads,threads->create(\&sync,\@stack); $i1 = $dt+1; $dt = $dt + 2; @stack=(); } } sub sync { print "sync\n"; foreach $target (@stack){ system(`/usr/local/bin/rsync -H --delete-during -azz -e "/usr/bin/ssh -i /root/.ssh/dovecot_dsa" $target vmail\@$remotehost:$target`); print $target."\n"; } } domains(); foreach $thread (@threads) { $thread->join(); }
domainlist LOCAL_DOMAINS = \ ${lookup pgsql{\ SELECT ldomain.domain || '.' || mdomain.domain AS domainname \ FROM ldomain, mdomain,maps \ WHERE ldomain.domain || '.' || mdomain.domain = LOWER('${quote_pgsql:$domain}') \ AND ldomain.active = 'true' \ AND maps.storage1 = 'storage-01.domain.ru' \ AND maps.ldomain_id = ldomain.id}}
relay_from_hosts = localhost : smtp01.domain.ru : smtp02.domain.ru : mail.domain.ru
ROUTE_LIST = "${lookup pgsql{\ SELECT COALESCE(storage1,'') || ' : ' || COALESCE(storage2,'') \ FROM (\ SELECT storage1,storage2 \ FROM maps \ INNER JOIN ldomain ON ( maps.ldomain_id = ldomain.id ) \ INNER JOIN mdomain ON ( maps.mdomain_id = mdomain.id ) \ WHERE ldomain.domain || '.' || mdomain.domain = '${quote_pgsql:$domain}' \ UNION ALL \ SELECT storage1,storage2 \ FROM co_maps \ INNER JOIN co_domain ON ( co_maps.domain_id = co_domain.id ) \ WHERE co_domain.domain = '${quote_pgsql:$domain}') AS foo}}"
begin routers DATASTORE: driver = manualroute domains = DOMAINS transport = remote_smtp condition = MAILS route_list = * ROUTE_LIST no_more
cat /usr/local/etc/nginx/nginx.conf worker_processes 1; worker_rlimit_nofile 8192; pid /var/run/nginx.pid; error_log /var/log/nginx-error.log debug; error_log /var/log/nginx-error.log notice; error_log /var/log/nginx-error.log info; events { worker_connections 8192; multi_accept on; use kqueue; } mail { ssl_certificate /usr/local/etc/ssl/proxy.crt; ssl_certificate_key /usr/local/etc/ssl/proxy.key; ssl_session_timeout 5m; xclient off; auth_http storage-01.domain.ru:8185/auth; pop3_capabilities "LAST" "TOP" "USER" "PIPELINING" "UIDL" "RESP-CODES" "EXPIRE" "IMPLEMENTATION"; imap_capabilities "IMAP4" "IMAP4rev1" "UIDPLUS" "IDLE" "LITERAL+" "QUOTA" "LIST-EXTENDED"; smtp_capabilities "SIZE 52428800" "8BITMIME" "PIPELINING" "STARTTLS" "HELP"; server { smtp_auth login plain; listen 25; protocol smtp; proxy on; starttls on; } server { smtp_auth login plain; listen 587; protocol smtp; proxy on; starttls on; } server { listen 110; protocol pop3; proxy on; starttls on; } server { listen 995; protocol pop3; proxy on; starttls on; } server { listen 143; protocol imap; proxy on; starttls on; } server { listen 993; protocol imap; proxy on; starttls on; } }
auth_http storage-01.domain.ru:8185/auth;
"Auth-Status", "OK"; "Auth-Server", "storage-01.domain.ru"; "Auth-Port", "143";
worker_processes 4; worker_rlimit_nofile 8192; error_log /var/log/nginx-error.log info; events { worker_connections 8192; multi_accept on; } http { perl_modules perl/lib; perl_require mailauth.pm; perl_require Digest.pm; access_log off; server { listen 8185; ssl_certificate /usr/local/etc/ssl/storage-01.crt; ssl_certificate_key /usr/local/etc/ssl/storage-01.key; ssl_session_timeout 5m; location /auth { perl mailauth::handler; proxy_set_header X-Real-IP $remote_addr; } } }
package mailauth; use nginx; use DBI; use Net::Nslookup; use Digest::MD5 qw(md5_hex); $pg_user = "mail"; $pg_pass = "password"; $passhost = "localhost"; $mapshost = "localhost"; our $auth_ok; $protocol_ports->{'pop3'}=110; $protocol_ports->{'imap'}=143; $protocol_ports->{'smtp'}=25; $protocol_ports->{'smtpssl'}=465; sub handler { $r = shift; $Passdbh=DBI->connect("DBI:Pg:dbname=mail;host=$passhost","$pg_user","$pg_pass"); if (!$Passdbh) { $r->header_out("Auth-Status", "OK") ; $r->header_out("Auth-Server", '0.0.0.0'); $r->header_out("Auth-Port", $protocol_ports->{$r->header_in("Auth-Protocol")}); $r->send_http_header("text/html"); return OK; exit; }; $Mapsdbh=DBI->connect("DBI:Pg:dbname=mail;host=$mapshost","$pg_user","$pg_pass"); $auth_ok=0; $mailbox = $r->header_in("Auth-User"); our $get_pass_from_db=$Passdbh->prepare("SELECT password FROM mail INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) WHERE mail.mailbox || '\@' || ldomain.domain || '.' || mdomain.domain = ? "); $get_pass_from_db->execute($mailbox); @row=$get_pass_from_db->fetchrow_array(); $passfromDB=@row[0]; $md5passFromConnect = md5_hex($r->header_in("Auth-Pass")); if ( $passfromDB eq $md5passFromConnect ){ $auth_ok=1; } if ($auth_ok==1){ @domain = split('\@',$mailbox); $get_server_from_maps = $Mapsdbh->prepare( "SELECT storage1 FROM maps INNER JOIN ldomain ON ( maps.ldomain_id = ldomain.id ) \ INNER JOIN mdomain ON ( maps.mdomain_id = mdomain.id ) \ WHERE ldomain.domain || '.' || mdomain.domain = ? " ); $get_server_from_maps->execute(@domain[1]); @row=$get_server_from_maps->fetchrow_array(); $server_from_maps = nslookup(host => $row[0], type => "A"); $r->header_out("Auth-Status", "OK") ; $r->header_out("Auth-Server", $server_from_maps); $r->header_out("Auth-Port", $protocol_ports->{$r->header_in("Auth-Protocol")}); } else { $r->header_out("mail:", $r->header_in("Auth-User")); $r->header_out("Auth-Status", "Invalid login or password") ; } $r->send_http_header("text/html"); return OK; } sub db_fail { $r->header_out("Auth-Status", "OK") ; $r->header_out("Auth-Server", '127.0.0.1'); $r->send_http_header("text/html"); } 1; __END__
Source: https://habr.com/ru/post/324538/
All Articles