Dovecot 2.0 support

This commit is contained in:
Jamie Cameron
2011-03-26 11:40:51 -07:00
parent a089ae573b
commit d58220f68a
10 changed files with 262 additions and 88 deletions

View File

@ -17,3 +17,5 @@ The locking methods for mailboxes and index files can be configured on the Mail
Added fields for setting the index and control files locations. Added fields for setting the index and control files locations.
---- Changes since 1.430 ---- ---- Changes since 1.430 ----
Added fields to the SSL page for an optional CA certificate file and private key password. Added fields to the SSL page for an optional CA certificate file and private key password.
---- Changes since 1.530 ----
Added support for Dovecot 2.0, which renames many configuration directives and splits up the config using include files.

43
dovecot/backup_config.pl Executable file
View File

@ -0,0 +1,43 @@
do 'dovecot-lib.pl';
# backup_config_files()
# Returns files and directories that can be backed up
sub backup_config_files
{
return ( $config{'dovecot_config'} );
}
# pre_backup(&files)
# Called before the files are actually read
sub pre_backup
{
return undef;
}
# post_backup(&files)
# Called after the files are actually read
sub post_backup
{
return undef;
}
# pre_restore(&files)
# Called before the files are restored from a backup
sub pre_restore
{
return undef;
}
# post_restore(&files)
# Called after the files are restored from a backup
sub post_restore
{
if (&is_dovecot_running()) {
return &apply_configuration();
}
return undef;
}
1;

View File

@ -0,0 +1,4 @@
dovecot=/usr/sbin/dovecot
dovecot_config=/etc/dovecot/dovecot.conf
init_script=dovecot
pid_file=/var/run/dovecot/master.pid

View File

@ -14,11 +14,27 @@ use WebminCore;
sub get_config sub get_config
{ {
if (!scalar(@get_config_cache)) { if (!scalar(@get_config_cache)) {
@get_config_cache = ( ); @get_config_cache = &read_config_file($config{'dovecot_config'});
local $lnum = 0; }
local ($section, @sections); return \@get_config_cache;
open(CONF, $config{'dovecot_config'}); }
while(<CONF>) {
# read_config_file(filename)
# Convert a file into a list od directives
sub read_config_file
{
local ($file) = @_;
local $filedir = $file;
$filedir =~ s/\/[^\/]+$//;
local $lnum = 0;
local ($section, @sections);
open(CONF, $file);
local @lines = <CONF>;
close(CONF);
local $_;
local @rv;
local $section;
foreach (@lines) {
s/\r|\n//g; s/\r|\n//g;
if (/^\s*(#?)\s*([a-z0-9\_]+)\s*(\S*)\s*\{\s*$/) { if (/^\s*(#?)\s*([a-z0-9\_]+)\s*(\S*)\s*\{\s*$/) {
# Start of a section .. add this as a value too # Start of a section .. add this as a value too
@ -33,14 +49,15 @@ if (!scalar(@get_config_cache)) {
'members' => [ ], 'members' => [ ],
'indent' => scalar(@sections), 'indent' => scalar(@sections),
'line' => $lnum, 'line' => $lnum,
'eline' => $lnum }; 'eline' => $lnum,
'file' => $file, };
if ($oldsection) { if ($oldsection) {
$section->{'sectionname'} = $section->{'sectionname'} =
$oldsection->{'name'}; $oldsection->{'name'};
$section->{'sectionvalue'} = $section->{'sectionvalue'} =
$oldsection->{'value'}; $oldsection->{'value'};
} }
push(@get_config_cache, $section); push(@rv, $section);
} }
elsif (/^\s*(#?)\s*}\s*$/ && $section) { elsif (/^\s*(#?)\s*}\s*$/ && $section) {
# End of a section # End of a section
@ -58,20 +75,29 @@ if (!scalar(@get_config_cache)) {
local $dir = { 'name' => $2, local $dir = { 'name' => $2,
'value' => $3, 'value' => $3,
'enabled' => !$1, 'enabled' => !$1,
'line' => $lnum }; 'line' => $lnum,
'file' => $file, };
if ($section) { if ($section) {
$dir->{'sectionname'} = $section->{'name'}; $dir->{'sectionname'} = $section->{'name'};
$dir->{'sectionvalue'} = $section->{'value'}; $dir->{'sectionvalue'} = $section->{'value'};
push(@{$section->{'members'}}, $dir); push(@{$section->{'members'}}, $dir);
$section->{'eline'} = $lnum; $section->{'eline'} = $lnum;
} }
push(@get_config_cache, $dir); push(@rv, $dir);
}
elsif (/^\s*!(include|include_try)\s+(\S+)/) {
# Include file(s)
local $glob = $2;
if ($glob !~ /^\//) {
$glob = $filedir."/".$glob;
}
foreach my $i (glob($glob)) {
push(@rv, &read_config_file($i));
}
} }
$lnum++; $lnum++;
} }
close(CONF); return @rv;
}
return \@get_config_cache;
} }
# find(name, &config, [disabled-mode], [sectionname], [sectionvalue]) # find(name, &config, [disabled-mode], [sectionname], [sectionvalue])
@ -126,7 +152,6 @@ return wantarray ? @rv : $rv[0];
sub save_directive sub save_directive
{ {
local ($conf, $name, $value, $sname, $svalue) = @_; local ($conf, $name, $value, $sname, $svalue) = @_;
local $lref = &read_file_lines($config{'dovecot_config'});
local $dir = ref($name) ? $name : &find($name, $conf, 0, $sname, $svalue); local $dir = ref($name) ? $name : &find($name, $conf, 0, $sname, $svalue);
local $newline = ref($name) ? "$name->{'name'} = $value" : "$name = $value"; local $newline = ref($name) ? "$name->{'name'} = $value" : "$name = $value";
if ($sname) { if ($sname) {
@ -134,13 +159,15 @@ if ($sname) {
} }
if ($dir && defined($value)) { if ($dir && defined($value)) {
# Updating some directive # Updating some directive
local $lref = &read_file_lines($dir->{'file'});
$lref->[$dir->{'line'}] = $newline; $lref->[$dir->{'line'}] = $newline;
$dir->{'value'} = $value; $dir->{'value'} = $value;
} }
elsif ($dir && !defined($value)) { elsif ($dir && !defined($value)) {
# Deleting some directive # Deleting some directive
local $lref = &read_file_lines($dir->{'file'});
splice(@$lref, $dir->{'line'}, 1); splice(@$lref, $dir->{'line'}, 1);
&renumber($conf, $dir->{'line'}, -1); &renumber($conf, $dir->{'line'}, $dir->{'file'}, -1);
@$conf = grep { $_ ne $dir } @$conf; @$conf = grep { $_ ne $dir } @$conf;
} }
elsif (!$dir && defined($value)) { elsif (!$dir && defined($value)) {
@ -148,8 +175,9 @@ elsif (!$dir && defined($value)) {
local $cmt = &find($name, $conf, 1, $sname, $svalue); local $cmt = &find($name, $conf, 1, $sname, $svalue);
if ($cmt) { if ($cmt) {
# After comment # After comment
local $lref = &read_file_lines($cmt->{'file'});
splice(@$lref, $cmt->{'line'}+1, 0, $newline); splice(@$lref, $cmt->{'line'}+1, 0, $newline);
&renumber($conf, $cmt->{'line'}+1, 1); &renumber($conf, $cmt->{'line'}+1, $cmt->{'file'}, 1);
push(@$conf, { 'name' => $name, push(@$conf, { 'name' => $name,
'value' => $value, 'value' => $value,
'line' => $cmt->{'line'}+1, 'line' => $cmt->{'line'}+1,
@ -161,9 +189,10 @@ elsif (!$dir && defined($value)) {
local @insect = grep { $_->{'sectionname'} eq $sname && local @insect = grep { $_->{'sectionname'} eq $sname &&
$_->{'sectionvalue'} eq $svalue } @$conf; $_->{'sectionvalue'} eq $svalue } @$conf;
@insect || &error("Failed to find section $sname $svalue !"); @insect || &error("Failed to find section $sname $svalue !");
local $lref = &read_file_lines($insect[$#insect]->{'file'});
local $line = $insect[$#insect]->{'line'}+1; local $line = $insect[$#insect]->{'line'}+1;
splice(@$lref, $line, 0, $newline); splice(@$lref, $line, 0, $newline);
&renumber($conf, $line, 1); &renumber($conf, $line, $insect[$#insect]->{'file'}, 1);
push(@$conf, { 'name' => $name, push(@$conf, { 'name' => $name,
'value' => $value, 'value' => $value,
'line' => $line, 'line' => $line,
@ -171,7 +200,8 @@ elsif (!$dir && defined($value)) {
'sectionvalue' => $svalue }); 'sectionvalue' => $svalue });
} }
else { else {
# Need to put at end # Need to put at end of main config
local $lref = &read_file_lines($config{'dovecot_config'});
push(@$lref, $newline); push(@$lref, $newline);
push(@$conf, { 'name' => $name, push(@$conf, { 'name' => $name,
'value' => $value, 'value' => $value,
@ -187,7 +217,7 @@ elsif (!$dir && defined($value)) {
sub save_section sub save_section
{ {
local ($conf, $section) = @_; local ($conf, $section) = @_;
local $lref = &read_file_lines($config{'dovecot_config'}); local $lref = &read_file_lines($section->{'file'});
local $indent = " " x $section->{'indent'}; local $indent = " " x $section->{'indent'};
local @newlines; local @newlines;
push(@newlines, $indent.$section->{'name'}." ".$section->{'value'}." {"); push(@newlines, $indent.$section->{'name'}." ".$section->{'value'}." {");
@ -197,18 +227,21 @@ foreach my $m (@{$section->{'members'}}) {
push(@newlines, $indent."}"); push(@newlines, $indent."}");
local $oldlen = $section->{'eline'} - $section->{'line'} + 1; local $oldlen = $section->{'eline'} - $section->{'line'} + 1;
splice(@$lref, $section->{'line'}, $oldlen, @newlines); splice(@$lref, $section->{'line'}, $oldlen, @newlines);
&renumber($conf, $section->{'eline'}, scalar(@newlines)-$oldlen); &renumber($conf, $section->{'eline'}, $section->{'file'},
scalar(@newlines)-$oldlen);
$section->{'eline'} = $section->{'line'} + scalar(@newlines) - 1; $section->{'eline'} = $section->{'line'} + scalar(@newlines) - 1;
} }
# renumber(&conf, line, offset) # renumber(&conf, line, file, offset)
sub renumber sub renumber
{ {
local ($conf, $line, $offset) = @_; local ($conf, $line, $file, $offset) = @_;
foreach my $c (@$conf) { foreach my $c (@$conf) {
if ($c->{'file'} eq $file) {
$c->{'line'} += $offset if ($c->{'line'} >= $line); $c->{'line'} += $offset if ($c->{'line'} >= $line);
$c->{'eline'} += $offset if ($c->{'eline'} >= $line); $c->{'eline'} += $offset if ($c->{'eline'} >= $line);
} }
}
} }
# is_dovecot_running() # is_dovecot_running()
@ -244,7 +277,7 @@ sub stop_dovecot
{ {
local $script = &get_initscript(); local $script = &get_initscript();
if ($script) { if ($script) {
local $out = &backquote_logged("$script stop 2>&1"); local $out = &backquote_logged("$script stop 2>&1 </dev/null");
return $? ? "<pre>$out</pre>" : undef; return $? ? "<pre>$out</pre>" : undef;
} }
else { else {
@ -265,7 +298,7 @@ sub start_dovecot
{ {
local $script = &get_initscript(); local $script = &get_initscript();
local $cmd = $script ? "$script start" : $config{'dovecot'}; local $cmd = $script ? "$script start" : $config{'dovecot'};
local $out = &backquote_logged("$cmd 2>&1"); local $out = &backquote_logged("$cmd 2>&1 </dev/null");
return $? ? "<pre>$out</pre>" : undef; return $? ? "<pre>$out</pre>" : undef;
} }
@ -323,5 +356,28 @@ local ($forindex) = @_;
return ( "dotlock", "fcntl", "flock", $forindex ? ( ) : ( "lockf" ) ); return ( "dotlock", "fcntl", "flock", $forindex ? ( ) : ( "lockf" ) );
} }
1; # lock_dovecot_files([&conf])
# Lock all files in the Dovecot config
sub lock_dovecot_files
{
local ($conf) = @_;
$conf ||= &get_config();
foreach my $f (&unique(map { $_->{'file'} } @$conf)) {
&lock_file($f);
}
}
# unlock_dovecot_files([&conf])
# Release lock on all files
sub unlock_dovecot_files
{
local ($conf) = @_;
$conf ||= &get_config();
foreach my $f (reverse(&unique(map { $_->{'file'} } @$conf))) {
&unlock_file($f);
}
}
1;
r

View File

@ -20,7 +20,7 @@ print &ui_table_row($text{'login_realm'},
# Authentication mechanisms (MD5, etc..) # Authentication mechanisms (MD5, etc..)
if (&find("auth_mechanisms", $conf, 2)) { if (&find("auth_mechanisms", $conf, 2)) {
# Version 0.99 format # Version 0.99 and 2.0 format
@mechs = split(/\s+/, &find_value("auth_mechanisms", $conf)); @mechs = split(/\s+/, &find_value("auth_mechanisms", $conf));
} }
else { else {
@ -46,6 +46,12 @@ elsif ($usec = &find_section("userdb", $conf, undef, "auth", "default")) {
$args = &find_value("args", $conf, undef, "userdb", $usec->{'value'}); $args = &find_value("args", $conf, undef, "userdb", $usec->{'value'});
$userdb .= " $args" if ($args); $userdb .= " $args" if ($args);
} }
elsif (&find_value("driver", $conf, 2, "userdb")) {
# Version 2.0 format
$userdb = &find_value("driver", $conf, undef, "userdb");
$args = &find_value("args", $conf, undef, "userdb");
$userdb .= " ".$args if ($args);
}
else { else {
# Version 1.0 format # Version 1.0 format
$userdb = &find_value("userdb", $conf, undef, "auth", "default"); $userdb = &find_value("userdb", $conf, undef, "auth", "default");
@ -113,6 +119,12 @@ elsif ($psec = &find_section("passdb", $conf, undef, "auth", "default")) {
$passdb .= " $args" if ($args); $passdb .= " $args" if ($args);
$alpha_opts = 1; $alpha_opts = 1;
} }
elsif (&find_value("driver", $conf, 2, "passdb")) {
# Version 2.0 format
$passdb = &find_value("driver", $conf, undef, "passdb");
$args = &find_value("args", $conf, undef, "passdb");
$passdb .= " ".$args if ($args);
}
else { else {
# Version 1.0 format # Version 1.0 format
$passdb = &find_value("passdb", $conf, undef, "auth", "default"); $passdb = &find_value("passdb", $conf, undef, "auth", "default");

View File

@ -9,12 +9,24 @@ print &ui_form_start("save_ssl.cgi", "post");
print &ui_table_start($text{'ssl_header'}, "width=100%", 4); print &ui_table_start($text{'ssl_header'}, "width=100%", 4);
# SSL cert and key files # SSL cert and key files
$cert = &find_value("ssl_cert_file", $conf); if (&find_value("ssl_cert", $conf, 2)) {
$cert = &find_value("ssl_cert", $conf);
$cert =~ s/^<//;
}
else {
$cert = &find_value("ssl_cert_file", $conf);
}
print &ui_table_row($text{'ssl_cert'}, print &ui_table_row($text{'ssl_cert'},
&ui_opt_textbox("cert", $cert, 40, &getdef("ssl_cert_file")), 3, &ui_opt_textbox("cert", $cert, 40, &getdef("ssl_cert_file")), 3,
[ undef, "nowrap" ]); [ undef, "nowrap" ]);
$key = &find_value("ssl_key_file", $conf); if (&find_value("ssl_key", $conf, 2)) {
$key = &find_value("ssl_key", $conf);
$key =~ s/^<//;
}
else {
$key = &find_value("ssl_key_file", $conf);
}
print &ui_table_row($text{'ssl_key'}, print &ui_table_row($text{'ssl_key'},
&ui_opt_textbox("key", $key, 40, &getdef("ssl_key_file")), 3, &ui_opt_textbox("key", $key, 40, &getdef("ssl_key_file")), 3,
[ undef, "nowrap" ]); [ undef, "nowrap" ]);
@ -26,7 +38,13 @@ print &ui_table_row($text{'ssl_pass'},
[ undef, "nowrap" ]); [ undef, "nowrap" ]);
# SSL CA file # SSL CA file
$ca = &find_value("ssl_ca_file", $conf); if (&find_value("ssl_ca", $conf, 2)) {
$ca = &find_value("ssl_ca", $conf);
$ca =~ s/^<//;
}
else {
$ca = &find_value("ssl_ca_file", $conf);
}
print &ui_table_row($text{'ssl_ca'}, print &ui_table_row($text{'ssl_ca'},
&ui_opt_textbox("ca", $ca, 40, &ui_opt_textbox("ca", $ca, 40,
&getdef("ssl_ca_file", [ [ "", $text{'ssl_none'} ] ])), 3, &getdef("ssl_ca_file", [ [ "", $text{'ssl_none'} ] ])), 3,

View File

@ -4,8 +4,8 @@
require './dovecot-lib.pl'; require './dovecot-lib.pl';
&ReadParse(); &ReadParse();
&error_setup($text{'login_err'}); &error_setup($text{'login_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config(); $conf = &get_config();
&lock_dovecot_files($conf);
# Allowed and default realm # Allowed and default realm
&save_directive($conf, "auth_realms", &save_directive($conf, "auth_realms",
@ -67,6 +67,12 @@ elsif (&find("auth_userdb", $conf, 2)) {
# Version 0.99 format # Version 0.99 format
&save_directive($conf, "auth_userdb", $userdb); &save_directive($conf, "auth_userdb", $userdb);
} }
elsif (&find_value("driver", $conf, 2, "userdb")) {
# Version 2.0 format
$args = $userdb =~ s/\s+(\S.*)$// ? $1 : undef;
&save_directive($conf, "driver", $userdb, "userdb");
&save_directive($conf, "args", $args, "userdb");
}
else { else {
# Version 1.0 format # Version 1.0 format
&save_directive($conf, "userdb", $userdb, "auth", "default"); &save_directive($conf, "userdb", $userdb, "auth", "default");
@ -133,6 +139,12 @@ elsif (&find("auth_passdb", $conf, 2)) {
# Version 0.99 format # Version 0.99 format
&save_directive($conf, "auth_passdb", $passdb); &save_directive($conf, "auth_passdb", $passdb);
} }
elsif (&find_value("driver", $conf, 2, "passdb")) {
# Version 2.0 format
$args = $passdb =~ s/\s+(\S.*)$// ? $1 : undef;
&save_directive($conf, "driver", $passdb, "passdb");
&save_directive($conf, "args", $args, "passdb");
}
else { else {
# Version 1.0 format # Version 1.0 format
&save_directive($conf, "passdb", $passdb, "auth", "default"); &save_directive($conf, "passdb", $passdb, "auth", "default");
@ -177,7 +189,7 @@ if (&find("login_processes_count", $conf, 2)) {
} }
&flush_file_lines(); &flush_file_lines();
&unlock_file($config{'dovecot_config'}); &unlock_dovecot_files($conf);
&webmin_log("login"); &webmin_log("login");
&redirect(""); &redirect("");

View File

@ -4,8 +4,8 @@
require './dovecot-lib.pl'; require './dovecot-lib.pl';
&ReadParse(); &ReadParse();
&error_setup($text{'mail_err'}); &error_setup($text{'mail_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config(); $conf = &get_config();
&lock_dovecot_files($conf);
# Mail file location # Mail file location
if ($in{'envmode'} == 4) { if ($in{'envmode'} == 4) {
@ -100,7 +100,7 @@ foreach $l ("mbox_read_locks", "mbox_write_locks") {
} }
&flush_file_lines(); &flush_file_lines();
&unlock_file($config{'dovecot_config'}); &unlock_dovecot_files($conf);
&webmin_log("mail"); &webmin_log("mail");
&redirect(""); &redirect("");

View File

@ -4,8 +4,8 @@
require './dovecot-lib.pl'; require './dovecot-lib.pl';
&ReadParse(); &ReadParse();
&error_setup($text{'net_err'}); &error_setup($text{'net_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config(); $conf = &get_config();
&lock_dovecot_files($conf);
&save_directive($conf, "protocols", join(" ", split(/\0/, $in{'protocols'}))); &save_directive($conf, "protocols", join(" ", split(/\0/, $in{'protocols'})));
$sslopt = &find("ssl_disable", $conf, 2) ? "ssl_disable" : "ssl"; $sslopt = &find("ssl_disable", $conf, 2) ? "ssl_disable" : "ssl";
@ -31,7 +31,7 @@ foreach $l (@listens) {
} }
&flush_file_lines(); &flush_file_lines();
&unlock_file($config{'dovecot_config'}); &unlock_dovecot_files($conf);
&webmin_log("net"); &webmin_log("net");
&redirect(""); &redirect("");

View File

@ -4,18 +4,45 @@
require './dovecot-lib.pl'; require './dovecot-lib.pl';
&ReadParse(); &ReadParse();
&error_setup($text{'ssl_err'}); &error_setup($text{'ssl_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config(); $conf = &get_config();
&lock_dovecot_files($conf);
# Save SSL cert and key # Save SSL cert and key
$in{'cert_def'} || -r $in{'cert'} || &error($text{'ssl_ecert'}); $in{'cert_def'} || -r $in{'cert'} || $in{'cert'} =~ /^[<>\|]/ ||
$in{'key_def'} || -r $in{'key'} || &error($text{'ssl_ekey'}); &error($text{'ssl_ecert'});
&save_directive($conf, "ssl_cert_file", $in{'cert_def'} ? undef : $in{'cert'}); if (&find_value("ssl_cert", $conf, 2)) {
&save_directive($conf, "ssl_key_file", $in{'key_def'} ? undef : $in{'key'}); $in{'cert'} = "<".$in{'cert'} if ($in{'cert'} =~ /^\//);
&save_directive($conf, "ssl_cert",
$in{'cert_def'} ? undef : $in{'cert'});
}
else {
&save_directive($conf, "ssl_cert_file",
$in{'cert_def'} ? undef : $in{'cert'});
}
$in{'key_def'} || -r $in{'key'} || $in{'key'} =~ /^[<>\|]/ ||
&error($text{'ssl_ekey'});
if (&find_value("ssl_key", $conf, 2)) {
$in{'key'} = "<".$in{'key'} if ($in{'key'} =~ /^\//);
&save_directive($conf, "ssl_key",
$in{'key_def'} ? undef : $in{'key'});
}
else {
&save_directive($conf, "ssl_key_file",
$in{'key_def'} ? undef : $in{'key'});
}
# Save SSL CA cert # Save SSL CA cert
$in{'ca_def'} || -r $in{'ca'} || &error($text{'ssl_eca'}); $in{'ca_def'} || -r $in{'ca'} || $in{'ca'} =~ /^[<>\|]/ ||
&save_directive($conf, "ssl_ca_file", $in{'ca_def'} ? undef : $in{'ca'}); &error($text{'ssl_eca'});
if (&find_value("ssl_ca", $conf, 2)) {
$in{'ca'} = "<".$in{'ca'} if ($in{'ca'} =~ /^\//);
&save_directive($conf, "ssl_ca",
$in{'ca_def'} ? undef : $in{'ca'});
}
else {
&save_directive($conf, "ssl_ca_file",
$in{'ca_def'} ? undef : $in{'ca'});
}
# Save SSL key password # Save SSL key password
$in{'pass_def'} || $in{'pass'} =~ /\S/ || &error($text{'ssl_epass'}); $in{'pass_def'} || $in{'pass'} =~ /\S/ || &error($text{'ssl_epass'});
@ -30,7 +57,7 @@ $in{'regen_def'} || $in{'regen'} =~ /^\d+$/ || &error($text{'ssl_eregen'});
$in{'plain'} ? $in{'plain'} : undef); $in{'plain'} ? $in{'plain'} : undef);
&flush_file_lines(); &flush_file_lines();
&unlock_file($config{'dovecot_config'}); &unlock_dovecot_files($conf);
&webmin_log("ssl"); &webmin_log("ssl");
&redirect(""); &redirect("");