diff --git a/postfix/CHANGELOG b/postfix/CHANGELOG
index ffcf89b13..7ae390a24 100644
--- a/postfix/CHANGELOG
+++ b/postfix/CHANGELOG
@@ -41,3 +41,6 @@ Added Module Config options for stop, start and reload commands.
Allow map files are now checked when listing and editing virtusers and other map types.
---- Changes since 1.360 ----
Added the new SMTP Authentication And Encryption page for setting SASL and TLS related options.
+---- Changes since 1.370 ----
+Added a popup window for selecting a map source, rather than having to type in something like hash:/etc/postfix/virtual . This source can be an LDAP or MySQL database on Postfix systems that support it, which will trigger the automatic creation of a configuration file if needed.
+Maps in MySQL and LDAP databases can be viewed and edited in the same way that those in regular files are, if the appropriate Perl modules are installed (DBI and DBD::mysql for MySQL, or Net::LDAP for LDAP). This also applies to email aliases.
diff --git a/postfix/config.info b/postfix/config.info
index 51feb59f0..f30976951 100644
--- a/postfix/config.info
+++ b/postfix/config.info
@@ -27,8 +27,17 @@ start_cmd=Command to start Postfix,3,Use control command
stop_cmd=Command to stop Postfix,3,Use control command
reload_cmd=Command to apply Postfix configuration,3,Use control command
-line3=LDAP options,11
+line3=MySQL options,11
+mysql_host=MySQL server for editing maps,3,Same as Postfix configuration
+mysql_user=MySQL login for editing maps,3,Same as Postfix configuration
+mysql_pass=MySQL password for editing maps,3,Same as Postfix configuration
+
+line4=LDAP options,11
+ldap_host=LDAP server for editing maps,3,Same as Postfix configuration
+ldap_user=LDAP login for editing maps,3,Same as Postfix configuration
+ldap_pass=LDAP password for editing maps,3,Same as Postfix configuration
ldap_class=Object classes for maps,3,Default (top)
ldap_attrs=Other LDAP attributes for maps
(In fieldname: value format),9,40,3,\t
ldap_id=Key attribute for map objects,3,Default (cn)
ldap_doms=Create separate DN for each domain?,1,1-Yes,0-No
+
diff --git a/postfix/lang/en b/postfix/lang/en
index 2fa22f4e1..f5e0a33bf 100644
--- a/postfix/lang/en
+++ b/postfix/lang/en
@@ -756,6 +756,7 @@ log_stop=Stopped Postfix server
log_start=Started Postfix server
log_delqs=Deleted $1 messages from mail queue
log_flushq=Flushed mail queue
+log_backend=Updated configuration file for map $1
sasl_title=SMTP Authentication And Encryption
opts_smtpd_sasl_auth_enable=Enable SASL SMTP authentication?
diff --git a/postfix/log_parser.pl b/postfix/log_parser.pl
index 1fcf2e507..27b1b9a43 100644
--- a/postfix/log_parser.pl
+++ b/postfix/log_parser.pl
@@ -19,6 +19,9 @@ elsif ($action eq 'manual') {
elsif ($action eq 'delqs') {
return &text('log_delqs', $object);
}
+elsif ($action eq 'backend') {
+ return &text('log_backend', $object);
+ }
else {
return $text{'log_'.$action};
}
diff --git a/postfix/map_chooser_save.cgi b/postfix/map_chooser_save.cgi
index 317174316..6b307202c 100644
--- a/postfix/map_chooser_save.cgi
+++ b/postfix/map_chooser_save.cgi
@@ -217,7 +217,18 @@ for($i=0; defined($t = $in{"type_".$i}); $i++) {
@maps || &error($text{'chooser_enone'});
# Write out mysql and LDAP files
-&flush_file_lines(&unique(@files));
+@files = &unique(@files);
+@newfiles = map { !-r $_ } @files;
+foreach $f (@files) {
+ &lock_file($f);
+ }
+&flush_file_lines(@files);
+foreach $f (@newfiles) {
+ &set_ownership_permissions(undef, undef, 0700, $f);
+ }
+foreach $f (@files) {
+ &unlock_file($f);
+ }
# Create final string for map
$str = join(",", @maps);
@@ -230,5 +241,8 @@ window.close();
EOF
+if (@files) {
+ &webmin_log("backend", undef, $in{'map_name'});
+ }
&popup_footer();
diff --git a/postfix/postfix-lib.pl b/postfix/postfix-lib.pl
index debb8f910..7aa9499b3 100644
--- a/postfix/postfix-lib.pl
+++ b/postfix/postfix-lib.pl
@@ -673,8 +673,8 @@ sub regenerate_any_table
{
next unless $map;
if ($map->[0] eq "hash" || $map->[0] eq "regexp") {
- local $out = &backquote_logged("$config{'postfix_lookup_table_command'} -c $config_dir $map 2>&1");
- if ($?) { &error(&text('regenerate_table_efailed', $map, $out)); }
+ local $out = &backquote_logged("$config{'postfix_lookup_table_command'} -c $config_dir $map->[1] 2>&1");
+ if ($?) { &error(&text('regenerate_table_efailed', $map->[1], $out)); }
}
}
}
@@ -925,7 +925,8 @@ sub create_mapping
my @maps_files = $_[2] ? (map { [ "hash", $_ ] } @{$_[2]}) :
$_[3] ? &get_maps_types_files($_[3]) :
&get_maps_types_files(&get_real_value($_[0]));
-my ($maps_type, $maps_file) = @{$maps_files[0]};
+my $last_map = $maps_files[$#maps_files];
+my ($maps_type, $maps_file) = @$last_map;
if ($maps_type eq "hash" || $maps_type eq "regexp") {
# Adding to a regular file
local $lref = &read_file_lines($maps_file);
@@ -1860,11 +1861,18 @@ EOF
if ($@) {
return &text('mysql_edriver', "DBD::$driver");
}
-local @hosts = split(/\s+/, $conf->{'hosts'});
-local $dbistr = "database=$conf->{'dbname'}";
-$dbistr .= ";host=$hosts[0]" if (@hosts);
-local $dbh = $drh->connect($dbistr,
- $conf->{'user'}, $conf->{'password'}, { });
+local @hosts = split(/\s+/, $config{'mysql_hosts'} || $conf->{'hosts'});
+@hosts = ( undef ) if (!@hosts); # Localhost only
+local $dbh;
+foreach my $host (@hosts) {
+ local $dbistr = "database=$conf->{'dbname'}";
+ $dbistr .= ";host=$host" if ($host);
+ $dbh = $drh->connect($dbistr,
+ $config{'mysql_user'} || $conf->{'user'},
+ $config{'mysql_pass'} || $conf->{'password'},
+ { });
+ last if ($dbh);
+ }
$dbh || return &text('mysql_elogin',
"$conf->{'dbname'}", $drh->errstr)."\n";
return $dbh;
@@ -1885,26 +1893,60 @@ eval "use Net::LDAP";
if ($@) {
return &text('ldap_eldapmod', "Net::LDAP");
}
-local $port = $conf->{'server_port'} || 389;
-local @servers = split(/\s+/, $conf->{'server_host'} || "localhost");
-local $ldap = Net::LDAP->new($servers[0], port => $port);
-if (!$ldap) {
- return &text('ldap_eldap', "$servers[0]", $port);
- }
-if ($conf->{'start_tls'} eq 'yes') {
- $ldap->start_tls;
- }
-if ($conf->{'bind'} eq 'yes') {
- local $mesg = $ldap->bind(dn => $conf->{'bind_dn'},
- password => $conf->{'bind_pw'});
- if (!$mesg || $mesg->code) {
- return &text('ldap_eldaplogin', "$servers[0]",
- "$conf->{'bind_dn'}",
- $mesg ? $mesg->error : "Unknown error");
+local @servers = split(/\s+/, $config{'ldap_host'} ||
+ $conf->{'server_host'} || "localhost");
+local ($ldap, $lasterr);
+foreach my $server (@servers) {
+ local ($host, $port, $tls);
+ if ($server =~ /^(\S+):(\d+)$/) {
+ # Host and port
+ ($host, $port) = ($1, $2);
+ $tls = $conf->{'start_tls'} eq 'yes';
}
+ elsif ($server =~ /^(ldap|ldaps):\/\/(\S+)(:(\d+))?/) {
+ # LDAP URL
+ $host = $2;
+ $port = $4 || $conf->{'server_port'} || 389;
+ $tls = $1 eq "ldaps";
+ }
+ else {
+ # Host only
+ $host = $server;
+ $port = $conf->{'server_port'} || 389;
+ $tls = $conf->{'start_tls'} eq 'yes';
+ }
+ $ldap = Net::LDAP->new($server, port => $port);
+ if (!$ldap) {
+ $lasterr = &text('ldap_eldap', "$server", $port);
+ next;
+ }
+ if ($tls) {
+ $ldap->start_tls;
+ }
+ if ($conf->{'bind'} eq 'yes' || $config{'ldap_user'}) {
+ local $mesg = $ldap->bind(
+ dn => $config{'ldap_user'} || $conf->{'bind_dn'},
+ password => $config{'ldap_pass'} || $conf->{'bind_pw'});
+ if (!$mesg || $mesg->code) {
+ $lasterr = &text('ldap_eldaplogin',
+ "$server",
+ "".($config{'ldap_user'} ||
+ $conf->{'bind_dn'})."",
+ $mesg ? $mesg->error : "Unknown error");
+ $ldap = undef;
+ next;
+ }
+ }
+ last if ($ldap);
+ }
+if ($ldap) {
+ # Connected OK
+ $connect_ldap_db_cache = $ldap;
+ return $ldap;
+ }
+else {
+ return $lasterr;
}
-$connect_ldap_db_cache = $ldap;
-return $ldap;
}
# mysql_value_to_conf(value)