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.
---- Changes since 1.430 ----
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,66 +14,92 @@ use WebminCore;
sub get_config
{
if (!scalar(@get_config_cache)) {
@get_config_cache = ( );
local $lnum = 0;
local ($section, @sections);
open(CONF, $config{'dovecot_config'});
while(<CONF>) {
s/\r|\n//g;
if (/^\s*(#?)\s*([a-z0-9\_]+)\s*(\S*)\s*\{\s*$/) {
# Start of a section .. add this as a value too
local $oldsection = $section;
if ($section) {
push(@sections, $section); # save old
}
$section = { 'name' => $2,
'value' => $3,
'enabled' => !$1,
'section' => 1,
'members' => [ ],
'indent' => scalar(@sections),
'line' => $lnum,
'eline' => $lnum };
if ($oldsection) {
$section->{'sectionname'} =
$oldsection->{'name'};
$section->{'sectionvalue'} =
$oldsection->{'value'};
}
push(@get_config_cache, $section);
}
elsif (/^\s*(#?)\s*}\s*$/ && $section) {
# End of a section
$section->{'eline'} = $lnum;
$section->{'eline'} = $lnum;
if (@sections) {
$section = pop(@sections);
}
else {
$section = undef;
}
}
elsif (/^\s*(#?)([a-z0-9\_]+)\s+=\s*(.*)/) {
# A directive inside a section
local $dir = { 'name' => $2,
'value' => $3,
'enabled' => !$1,
'line' => $lnum };
if ($section) {
$dir->{'sectionname'} = $section->{'name'};
$dir->{'sectionvalue'} = $section->{'value'};
push(@{$section->{'members'}}, $dir);
$section->{'eline'} = $lnum;
}
push(@get_config_cache, $dir);
}
$lnum++;
}
close(CONF);
@get_config_cache = &read_config_file($config{'dovecot_config'});
}
return \@get_config_cache;
}
# 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;
if (/^\s*(#?)\s*([a-z0-9\_]+)\s*(\S*)\s*\{\s*$/) {
# Start of a section .. add this as a value too
local $oldsection = $section;
if ($section) {
push(@sections, $section); # save old
}
$section = { 'name' => $2,
'value' => $3,
'enabled' => !$1,
'section' => 1,
'members' => [ ],
'indent' => scalar(@sections),
'line' => $lnum,
'eline' => $lnum,
'file' => $file, };
if ($oldsection) {
$section->{'sectionname'} =
$oldsection->{'name'};
$section->{'sectionvalue'} =
$oldsection->{'value'};
}
push(@rv, $section);
}
elsif (/^\s*(#?)\s*}\s*$/ && $section) {
# End of a section
$section->{'eline'} = $lnum;
$section->{'eline'} = $lnum;
if (@sections) {
$section = pop(@sections);
}
else {
$section = undef;
}
}
elsif (/^\s*(#?)([a-z0-9\_]+)\s+=\s*(.*)/) {
# A directive inside a section
local $dir = { 'name' => $2,
'value' => $3,
'enabled' => !$1,
'line' => $lnum,
'file' => $file, };
if ($section) {
$dir->{'sectionname'} = $section->{'name'};
$dir->{'sectionvalue'} = $section->{'value'};
push(@{$section->{'members'}}, $dir);
$section->{'eline'} = $lnum;
}
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++;
}
return @rv;
}
# find(name, &config, [disabled-mode], [sectionname], [sectionvalue])
# Mode 0=enabled, 1=disabled, 2=both
sub find
@ -126,7 +152,6 @@ return wantarray ? @rv : $rv[0];
sub save_directive
{
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 $newline = ref($name) ? "$name->{'name'} = $value" : "$name = $value";
if ($sname) {
@ -134,13 +159,15 @@ if ($sname) {
}
if ($dir && defined($value)) {
# Updating some directive
local $lref = &read_file_lines($dir->{'file'});
$lref->[$dir->{'line'}] = $newline;
$dir->{'value'} = $value;
}
elsif ($dir && !defined($value)) {
# Deleting some directive
local $lref = &read_file_lines($dir->{'file'});
splice(@$lref, $dir->{'line'}, 1);
&renumber($conf, $dir->{'line'}, -1);
&renumber($conf, $dir->{'line'}, $dir->{'file'}, -1);
@$conf = grep { $_ ne $dir } @$conf;
}
elsif (!$dir && defined($value)) {
@ -148,8 +175,9 @@ elsif (!$dir && defined($value)) {
local $cmt = &find($name, $conf, 1, $sname, $svalue);
if ($cmt) {
# After comment
local $lref = &read_file_lines($cmt->{'file'});
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,
'value' => $value,
'line' => $cmt->{'line'}+1,
@ -161,9 +189,10 @@ elsif (!$dir && defined($value)) {
local @insect = grep { $_->{'sectionname'} eq $sname &&
$_->{'sectionvalue'} eq $svalue } @$conf;
@insect || &error("Failed to find section $sname $svalue !");
local $lref = &read_file_lines($insect[$#insect]->{'file'});
local $line = $insect[$#insect]->{'line'}+1;
splice(@$lref, $line, 0, $newline);
&renumber($conf, $line, 1);
&renumber($conf, $line, $insect[$#insect]->{'file'}, 1);
push(@$conf, { 'name' => $name,
'value' => $value,
'line' => $line,
@ -171,7 +200,8 @@ elsif (!$dir && defined($value)) {
'sectionvalue' => $svalue });
}
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(@$conf, { 'name' => $name,
'value' => $value,
@ -187,7 +217,7 @@ elsif (!$dir && defined($value)) {
sub save_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 @newlines;
push(@newlines, $indent.$section->{'name'}." ".$section->{'value'}." {");
@ -197,17 +227,20 @@ foreach my $m (@{$section->{'members'}}) {
push(@newlines, $indent."}");
local $oldlen = $section->{'eline'} - $section->{'line'} + 1;
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;
}
# renumber(&conf, line, offset)
# renumber(&conf, line, file, offset)
sub renumber
{
local ($conf, $line, $offset) = @_;
local ($conf, $line, $file, $offset) = @_;
foreach my $c (@$conf) {
$c->{'line'} += $offset if ($c->{'line'} >= $line);
$c->{'eline'} += $offset if ($c->{'eline'} >= $line);
if ($c->{'file'} eq $file) {
$c->{'line'} += $offset if ($c->{'line'} >= $line);
$c->{'eline'} += $offset if ($c->{'eline'} >= $line);
}
}
}
@ -244,7 +277,7 @@ sub stop_dovecot
{
local $script = &get_initscript();
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;
}
else {
@ -265,7 +298,7 @@ sub start_dovecot
{
local $script = &get_initscript();
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;
}
@ -323,5 +356,28 @@ local ($forindex) = @_;
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..)
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));
}
else {
@ -46,6 +46,12 @@ elsif ($usec = &find_section("userdb", $conf, undef, "auth", "default")) {
$args = &find_value("args", $conf, undef, "userdb", $usec->{'value'});
$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 {
# Version 1.0 format
$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);
$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 {
# Version 1.0 format
$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);
# 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'},
&ui_opt_textbox("cert", $cert, 40, &getdef("ssl_cert_file")), 3,
[ 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'},
&ui_opt_textbox("key", $key, 40, &getdef("ssl_key_file")), 3,
[ undef, "nowrap" ]);
@ -26,7 +38,13 @@ print &ui_table_row($text{'ssl_pass'},
[ undef, "nowrap" ]);
# 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'},
&ui_opt_textbox("ca", $ca, 40,
&getdef("ssl_ca_file", [ [ "", $text{'ssl_none'} ] ])), 3,

View File

@ -4,8 +4,8 @@
require './dovecot-lib.pl';
&ReadParse();
&error_setup($text{'login_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config();
&lock_dovecot_files($conf);
# Allowed and default realm
&save_directive($conf, "auth_realms",
@ -67,6 +67,12 @@ elsif (&find("auth_userdb", $conf, 2)) {
# Version 0.99 format
&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 {
# Version 1.0 format
&save_directive($conf, "userdb", $userdb, "auth", "default");
@ -133,6 +139,12 @@ elsif (&find("auth_passdb", $conf, 2)) {
# Version 0.99 format
&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 {
# Version 1.0 format
&save_directive($conf, "passdb", $passdb, "auth", "default");
@ -177,7 +189,7 @@ if (&find("login_processes_count", $conf, 2)) {
}
&flush_file_lines();
&unlock_file($config{'dovecot_config'});
&unlock_dovecot_files($conf);
&webmin_log("login");
&redirect("");

View File

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

View File

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

View File

@ -4,18 +4,45 @@
require './dovecot-lib.pl';
&ReadParse();
&error_setup($text{'ssl_err'});
&lock_file($config{'dovecot_config'});
$conf = &get_config();
&lock_dovecot_files($conf);
# Save SSL cert and key
$in{'cert_def'} || -r $in{'cert'} || &error($text{'ssl_ecert'});
$in{'key_def'} || -r $in{'key'} || &error($text{'ssl_ekey'});
&save_directive($conf, "ssl_cert_file", $in{'cert_def'} ? undef : $in{'cert'});
&save_directive($conf, "ssl_key_file", $in{'key_def'} ? undef : $in{'key'});
$in{'cert_def'} || -r $in{'cert'} || $in{'cert'} =~ /^[<>\|]/ ||
&error($text{'ssl_ecert'});
if (&find_value("ssl_cert", $conf, 2)) {
$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
$in{'ca_def'} || -r $in{'ca'} || &error($text{'ssl_eca'});
&save_directive($conf, "ssl_ca_file", $in{'ca_def'} ? undef : $in{'ca'});
$in{'ca_def'} || -r $in{'ca'} || $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
$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);
&flush_file_lines();
&unlock_file($config{'dovecot_config'});
&unlock_dovecot_files($conf);
&webmin_log("ssl");
&redirect("");