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.
--- /dev/null
+
+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;
+
--- /dev/null
+dovecot=/usr/sbin/dovecot
+dovecot_config=/etc/dovecot/dovecot.conf
+init_script=dovecot
+pid_file=/var/run/dovecot/master.pid
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);
+ @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
}
- elsif (/^\s*(#?)\s*}\s*$/ && $section) {
- # End of a section
- $section->{'eline'} = $lnum;
+ $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;
- 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);
+ 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++;
}
- close(CONF);
+ $lnum++;
}
-return \@get_config_cache;
+return @rv;
}
# find(name, &config, [disabled-mode], [sectionname], [sectionvalue])
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) {
}
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)) {
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,
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,
'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,
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'}." {");
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);
+ }
}
}
{
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 {
{
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;
}
return ( "dotlock", "fcntl", "flock", $forindex ? ( ) : ( "lockf" ) );
}
+# 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
# 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 {
$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");
$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");
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" ]);
[ 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,
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",
# 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");
# 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");
}
&flush_file_lines();
-&unlock_file($config{'dovecot_config'});
+&unlock_dovecot_files($conf);
&webmin_log("login");
&redirect("");
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) {
}
&flush_file_lines();
-&unlock_file($config{'dovecot_config'});
+&unlock_dovecot_files($conf);
&webmin_log("mail");
&redirect("");
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";
}
&flush_file_lines();
-&unlock_file($config{'dovecot_config'});
+&unlock_dovecot_files($conf);
&webmin_log("net");
&redirect("");
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'});
$in{'plain'} ? $in{'plain'} : undef);
&flush_file_lines();
-&unlock_file($config{'dovecot_config'});
+&unlock_dovecot_files($conf);
&webmin_log("ssl");
&redirect("");