summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Wrobel <wrobel@pardus.de>2008-10-10 14:22:04 (GMT)
committerGunnar Wrobel <wrobel@pardus.de>2008-10-10 14:22:04 (GMT)
commit4ed87f9f9489856fdad3f1c9b4d680dbcfe0b558 (patch)
tree9a09563956a782aa7babef6d0e8725b546948067
parentbabd6a6d986f227a40bb0f658935215086309745 (diff)
downloadperl-Kolab-4ed87f9f9489856fdad3f1c9b4d680dbcfe0b558.tar.gz
Merge all perl tools into the perl-kolab package.
-rw-r--r--AUTHORS8
-rw-r--r--ChangeLog134
-rw-r--r--MANIFEST1
-rw-r--r--lib/Kolab/Conf.pm901
-rw-r--r--perl-kolab.spec10
5 files changed, 1046 insertions, 8 deletions
diff --git a/AUTHORS b/AUTHORS
index e7b0f80..3abb4b9 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,11 +8,11 @@ Portions based on work by the following people:
(c) 2003 Tassilo Erlewein <tassilo.erlewein@erfrakon.de>
(c) 2003 Achim Frank <achim.frank@erfrakon.de>
(c) 2004 Stephan Buys <s.buys@codefusion.co.za>
- (c) 2005 - 2006 Richard Bos <richard@radoeka.nl>
- (c) 2005 - 2006 Marcus Hwe <suse-tux@gmx.de>
+ (c) 2005 - 2008 Richard Bos <richard@radoeka.nl>
+ (c) 2005 - 2008 Marcus Hwe <suse-tux@gmx.de>
(c) 2004 - 2006 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
(c) 2007 - 2008 Thomas Arendsen Hein <thomas@intevation.de>
- (c) 2006 - 2007 Gunnar Wrobel <wrobel@pardus.de>
+ (c) 2006 - 2008 Gunnar Wrobel <wrobel@pardus.de>
(c) 2003 - 2007 Martin Konold <martin.konold@erfrakon.de>
@@ -20,7 +20,7 @@ Portions based on work by the following companies:
(c) 2004 - 2006 Klaraelvdalens Datakonsult AB
(c) 2007 - 2008 Intevation GmbH
- (c) 2006 - 2007 p@rdus
+ (c) 2006 - 2008 p@rdus
(c) 2003 - 2007 erfrakon Partnerschaftsgesellschaft
diff --git a/ChangeLog b/ChangeLog
index 8d21661..4f38b0d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,79 @@
+2008-10-03 Gunnar Wrobel <p@rdus.de>
+
+ * bin/kolabquotawarn.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolabpasswd.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolab_bootstrap.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolabd.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolabcheckperm.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolabquotareport.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * bin/kolab_smtpdpolicy.in: Moved script from kolabd package into
+ perl-kolab.
+
+ * Makefile.PL: Added routines for script installations.
+
+2008-09-09 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: updated to improve readability
+
+2008-09-08 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: added code to include warnings in a configuration
+ file, by replacing the macro @@@warning@@@ in the config file.
+ See kolab/issue1671
+
+2008-09-06 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm:
+ - changed if {}; if {}, etc into if {}; elsif {}, etc.
+ Added a warning for incorrect keys in the META section
+ of a template file.
+ - Added support to define the comment character in the
+ META part of a template file
+
+2008-09-01 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: allow different spacing (multiple spaces or tabs)
+ instead of only 1 space in the @@@if conditionals.
+
+2008-08-29 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: added code to support the conditional:
+ @@@if exists( /full/path/to/file )@@@ as proposed by Thomas in
+ kolab/issue3006
+
+2008-08-27 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: removed code specific for slapd.conf
+ See kolab/issue3005
+
+2008-08-20 Richard Bos <richard@radoeka.nl>
+
+ * lib/Kolab/Conf.pm: added function bootstrapConfig to create config
+ files needed during kolab bootstrapping, see kolab/issue1755
+
2008-08-14 Richard Bos <richard@radoeka.nl>
- * lib/Kolab.pm: add syncrepl support, see kolab/issue1755
+ * lib/Kolab.pm: add syncrepl support, see kolab/issue1755
+
+2008-08-09 Richard Bos <richard@radoeka.nl>
+
+ * Kolab-Conf/Conf.pm.in: added syncrepl support (see kolab/issue1755)
2008-07-17 Richard Bos <richard@radoeka.nl>
- * lib/Kolab/LDAP/Backend/syncrepl.pm: add kolab/issue1755
+ * lib/Kolab/LDAP/Backend/syncrepl.pm: add kolab/issue1755
* MANIFEST: added the file lib/Kolab/LDAP/Backend/syncrepl.pm
* lib/Kolab.pm: added supported backend types
@@ -66,6 +135,28 @@
* lib/Kolab/LDAP.pm: Fix synchronization of mailboxes with newer perl.
kolab/issue2411 (perl error in LDAP.pm)
+2008-01-07 Thomas Arendsen Hein <thomas@intevation.de>
+
+ * bin/kolabconf.in: Added missing newlines in kolabconf -h.
+
+2008-01-02 Marcus Hüwe <suse-tux@gmx.de>
+
+ * Makefile.PL:
+
+ Fixed build for older versions of ExtUtils::MakeMaker.
+
+2008-01-01 Marcus Hüwe <suse-tux@gmx.de>
+
+ * bin/kolabconf.in:
+
+ Removed superfluous print statement.
+
+2007-12-07 Gunnar Wrobel <p@rdus.de>
+
+ * Makefile.PL (MY::postamble):
+
+ Fix the install location for kolabconf for the newest MakeMaker.
+
2007-11-28 Gunnar Wrobel <p@rdus.de>
* lib/Kolab/LDAP.pm (syncDomains, createObject):
@@ -85,8 +176,32 @@
* lib/Kolab.pm: kolab/issue934 (Remove FTP FreeBusy Service (proftpd))
+ * lib/Kolab/Conf.pm: kolab/issue934 (Remove FTP FreeBusy Service (proftpd))
+
+2007-09-06 Gunnar Wrobel <p@rdus.de>
+
+ * Conf.pm:
+
+ Allowed config variable replacement within the META section of
+ the templates. This reduces our dependence on the dist_conf
+ mechanism and we can use variables from kolab.globals
+ instead. Now add on packages can install their own templates.
+
+ Whitespace cleanup.
+
+2007-08-07 Gunnar Wrobel <p@rdus.de>
+
+ * Conf.pm:
+
+ Fixed kolab/issue1879 (kolabconf poor error message in buildCyrusConfig)
+ https://intevation.de/roundup/kolab/issue1879
+
2007-08-01 Gunnar Wrobel <p@rdus.de>
+ Created the kolabconf package by moving kolabconf and the
+ Conf.pm perl module into one package. The package is now a
+ clean perl package.
+
Converted the perl-kolab package into a standard perl library.
2007-07-31 Gunnar Wrobel <p@rdus.de>
@@ -136,12 +251,24 @@
* Makefile.am: added Makefile dependencies
+2007-01-06 Joergen Fjeld <jhf@linpro.no>
+
+ * Kolab-Conf/Conf.pm.in (build):
+
+ Patch applied by Martin Konold:
+
+ - fixes order of domains see also https://intevation.de/roundup/kolab/issue1550
+
2006-12-04 Gunnar Wrobel <wrobel@pardus.de>
* Kolab-Conf/Conf.pm.in (build): Only print "No configuration
variable corresponding to `$1' exists" in case we are NOT skipping
the section.
+ * Kolab-Conf/Conf.pm.in (build): Only print "No configuration
+ variable corresponding to `$1' exists" in case we are NOT skipping
+ the section.
+
2006-03-20 Marcus Hüwe <suse-tux@gmx.de>
Patch commited by Richard Bos
* Kolab-Conf/Conf.pm.in: introduce a new variable phpinit_dir for the
@@ -157,6 +284,8 @@
Added dist_conf file check. If dist_conf file specified with
--with-dist is not present fail configure.
* perl-kolab.spec.in: replaced --enable-dist with --with-dist
+ * Kolab-Conf/Conf.pm.in: introduce a new variable phpinit_dir for the
+ directory that holds the php.ini file to be used.
2006-01-14 Richard Bos <richard@radoeka.nl>
* Kolab/Kolab.pm.in: check for valid uid/gid values with perl define
@@ -248,4 +377,3 @@
Kolab-LDAP-Backend-slurpd/Makefile.PL,
Kolab-DirServ/Makefile.PL,
Kolab-LDAP-Backend-dirservd/Makefile.PL: are removed
-
diff --git a/MANIFEST b/MANIFEST
index 99dfa1e..ae2254e 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -2,6 +2,7 @@ AUTHORS
ChangeLog
INSTALL
lib/Kolab.pm
+lib/Kolab/Conf.pm
lib/Kolab/Cyrus.pm
lib/Kolab/LDAP.pm
lib/Kolab/LDAP/Backend.pm
diff --git a/lib/Kolab/Conf.pm b/lib/Kolab/Conf.pm
new file mode 100644
index 0000000..003d938
--- /dev/null
+++ b/lib/Kolab/Conf.pm
@@ -0,0 +1,901 @@
+package Kolab::Conf;
+
+## COPYRIGHT
+## ---------
+##
+## See AUTHORS file
+##
+##
+## LICENSE
+## -------
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You can view the GNU General Public License, online, at the GNU
+## Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
+##
+## $Revision$
+
+use 5.008;
+use strict;
+use warnings;
+
+use IO::File;
+use File::Copy;
+use File::Temp;
+use File::stat;
+use Kolab;
+use Kolab::Util;
+use Kolab::LDAP;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+our %EXPORT_TAGS = (
+ 'all' => [ qw(
+ &buildPostfixTransportMap
+ &buildCyrusGroups
+ &buildLDAPReplicas
+ &rebuildTemplates
+ &checkPermissions
+ ) ]
+ );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+
+);
+
+my %templates = ();
+my %ownership = ();
+my %permissions = ();
+my %templatehaschanged = ();
+my %haschanged = ();
+my %commentchar = ();
+
+sub fixup {
+ my $file = shift;
+ my $ownership = shift;
+ my $perm = shift;
+
+ (my $owner, my $group) = split(/:/, $ownership, 2);
+ my $uid = (getpwnam($owner))[2];
+ my $gid = (getgrnam($group))[2];
+ Kolab::log('T', sprintf("Changing permissions of %s to 0%o", $file, $perm ), KOLAB_DEBUG );
+ if( chmod($perm, $file) != 1 ) {
+ Kolab::log('T', "Unable to change permissions of `$file' to ".sprintf("0%o",$perm) . ": $!", KOLAB_ERROR);
+ exit(1);
+ }
+ Kolab::log('T', "Changing owner of $file to $owner:$group ($uid:$gid)", KOLAB_DEBUG );
+ if( chown($uid,$gid,$file) != 1 ) {
+ Kolab::log('T', "Unable to change ownership of `$file' to $uid:$gid: $!", KOLAB_ERROR);
+ exit(1);
+ }
+}
+
+sub printWarning {
+
+ my $stream = shift;
+ my $templateFile = shift;
+ my $cc = shift;
+
+ $templateFile = "" if (!defined $templateFile);
+ $cc = "#" if (!defined $cc);
+
+ # Different warnings during bootstrapping and regular configuration
+# $Kolab::config{"bootstrap_config"} = "true";
+ if ((defined $Kolab::config{"bootstrap_config"}) &&
+ ($Kolab::config{"bootstrap_config"} eq "true")) {
+
+ print $stream "$cc=================================================================\n";
+ print $stream "$cc This is a preliminary version of this configuration file and\n";
+ print $stream "$cc only used for bootstrapping. If you see this warning in your\n";
+ print $stream "$cc configuration after bootstrapping the Kolab Server\n";
+ print $stream "$cc SOMETHING WENT VERY WRONG !!!\n";
+ print $stream "$cc=================================================================\n";
+
+ } else {
+
+ print $stream "$cc=================================================================\n";
+ print $stream "$cc THIS FILE IS AUTOMATICALLY WRITTEN BY THE KOLAB CONFIG BACKEND.\n";
+ print $stream "$cc MANUAL CHANGES ARE LOST UNLESS MADE IN THE TEMPLATE FILE:\n";
+ print $stream "$cc\n";
+ print $stream "$cc $templateFile\n";
+ print $stream "$cc\n";
+ print $stream "$cc Changes can be activated by running ".$Kolab::config{'kolabconf_script'}."\n";
+ print $stream "$cc=================================================================\n";
+
+ }
+}
+
+sub build {
+ my $tmpl = shift;
+ my $cfg = shift;
+ my $owner = shift;
+ my $perm = shift;
+ my $cchr = shift; # comment character
+
+ my $oldcfg = $cfg . '.old';
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ my %special_templates = (
+ "$templatedir/transport.template" => 1,
+ "$templatedir/virtual.template" => 1,
+ "$templatedir/imapd.group.template" => 1,
+ "$templatedir/slapd.access.template" => 1,
+ "$templatedir/slapd.replicas.template" => 1
+ );
+
+ my $oldmask = umask 077;
+ copy($cfg, $oldcfg);
+ #chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $oldcfg);
+ # To avoid warnings, the backup files must be owned by root
+ chown(0, 0, $oldcfg);
+ umask $oldmask;
+ #chmod(0600, $oldcfg) if ($oldcfg =~ /openldap/);
+
+ Kolab::log('T', "Creating new configuration file `$cfg' from template `$tmpl'", KOLAB_DEBUG );
+ #print STDERR "Creating new configuration file `$cfg' from template `$tmpl'\n";
+
+ my $template;
+ if (!($template = IO::File->new($tmpl, 'r'))) {
+ Kolab::log('T', "Unable to open template file `$tmpl': $!", KOLAB_ERROR);
+ # Error, fail gracefully
+ return;
+ }
+ my $config;
+ if (!($config = new File::Temp( TEMPLATE => 'tmpXXXXX',
+ DIR => $Kolab::config{"kolabdir"},
+ SUFFIX => '.kolabtmp',
+ UNLINK => 0 ))) {
+ Kolab::log('T', "Unable to open configuration file `$cfg': $!", KOLAB_ERROR);
+ exit(1);
+ }
+
+ #Kolab::log('T', "Using temporary file '".$config->filename."'", KOLAB_DEBUG );
+
+ my $skip = 0;
+ my $keep = 0;
+ while (<$template>) {
+ #Eat the meta data sections
+ if (/^KOLAB_META_START$/) {
+ my $found_end;
+ while (!$found_end) {
+ $_ = <$template>;
+ $found_end = /^KOLAB_META_END$/;
+ }
+ $_ = <$template>;
+ }
+
+ if (/\@{3}if\s+exists\(\s*(\S+?)\s*\)\@{3}/) {
+ # @@@if exists(/full/path/to/file)@@@
+ # also possible: @@@if exists( /full/path/to/file )@@@
+ if (-f $1) {
+ # Keep text if searched file or symbolic link exists.
+ $keep = 1;
+ } else {
+ # Skip text
+ $skip++;
+ $keep = 0;
+ }
+ } elsif (/\@{3}if\s+(\S+?)\@{3}/) {
+ # @@@if some_variable@@@
+ # The some_variable is a key in the $Kolab::config hash and has
+ # its value set to either 'false' or 'true'
+ if ($Kolab::config{$1} && lc($Kolab::config{$1}) ne "false" ) {
+ # Keep text
+ $keep = 1;
+ } else {
+ # Skip text
+ $skip++;
+ $keep = 0;
+ }
+ s/\@{3}if (\S+?)\@{3}\n?//;
+ } elsif (/\@{3}else\@{3}/) {
+ if( $keep == 0 ) {
+ # Now keep
+ $keep = 1;
+ $skip--;
+ } else {
+ # Now skip
+ $keep = 0;
+ $skip++;
+ }
+ s/\@{3}else\@{3}\n?//;
+
+ } elsif (/\@{3}endif\@{3}/) {
+ ($skip > 0) && $skip--;
+ s/\@{3}endif\@{3}\n?//;
+
+ } elsif (/\@{3}warning\@{3}/) {
+
+ printWarning($config, $tmpl, $cchr);
+
+ } else {
+ while (/\@{3}([^\s\@]+?)(\|(.+?)\((.*)\))?\@{3}/) {
+ my $attr = $1;
+ my $fct = $3;
+ my $args = $4;
+ #print STDERR "attr=\"$attr\", fct=\"$fct\", args=\"$args\"\n";
+ if ($Kolab::config{$attr}) {
+ my $val = "";
+ if( !$fct ) {
+ if (ref $Kolab::config{$attr} eq "ARRAY") {
+ $val = $Kolab::config{$attr}->[0];
+ } else {
+ $val = $Kolab::config{$attr};
+ }
+ } else {
+ # Modifier functions
+ SWITCH: {
+ # Join function
+ $fct eq 'join' && do {
+ if (ref $Kolab::config{$attr} eq "ARRAY") {
+ my @vals = @{$Kolab::config{$attr}} ;
+ # We want to make sure subdomain.domain.tld comes before domain.tld
+ my @length_sorted_vals = sort {length $b cmp length $a} @vals;
+ $val = join ($args, @length_sorted_vals) ;
+ } else {
+ $val = $Kolab::config{$attr};
+ }
+ last SWITCH;
+ };
+ # Quote function
+ $fct eq 'quote' && do {
+ # slapd.conf compatible quoting
+ $val = $Kolab::config{$attr};
+ $val =~ s/"/\"/g;
+ $val = '"'.$val.'"';
+ last SWITCH;
+ }
+ }
+ }
+ s/\@{3}([^\s\@]+?)(\|.+?)?\@{3}/$val/;
+ last if ( $val eq "\@\@\@$attr\@\@\@" ); # prevent endless loop
+ } else {
+ # Only warn the user in case we are not skipping the section
+ ($skip == 0) && Kolab::log('T', "No configuration variable corresponding to `$1' exists", KOLAB_WARN);
+ s/\@{3}([^\s\@]+?)\@{3}//;
+ }
+ }
+ ($skip == 0) && print $config $_;
+ }
+ }
+
+ $template->close;
+ $config->close;
+
+ move($config->filename, $cfg) || Kolab::log('T', "Error moving configfile to $cfg, error: $!", KOLAB_ERROR );
+ fixup( $cfg, $owner, $perm );
+ #chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $cfg);
+ #chmod(0600, $cfg) if ($cfg =~ /openldap/);
+
+ if (-f $oldcfg && !defined $special_templates{$tmpl} ) {
+ my $rc = `diff -q $cfg $oldcfg`;
+ chomp($rc);
+ if ($rc) {
+ if ($cfg =~ /postfix/) {
+ $haschanged{'postfix'} = 1;
+ } elsif ($cfg =~ /saslauthd/) {
+ $haschanged{'saslauthd'} = 1;
+ } elsif ($cfg =~ /apache/) {
+ $haschanged{'apache'} = 1;
+ } elsif ($cfg =~ /openldap/) {
+ $haschanged{'slapd'} = 1;
+ } elsif ($cfg =~ /imapd/) {
+ $haschanged{'imapd'} = 1;
+ } elsif ($cfg =~ /amavisd/) {
+ $haschanged{'amavisd'} = 1;
+ } elsif ($cfg =~ /clamav/) {
+ $haschanged{'clamav'} = 1;
+#} elsif ($cfg =~ /example/) {
+ } else {
+ Kolab::log('T', "`$cfg' change detected ", KOLAB_DEBUG );
+ $templatehaschanged{$tmpl} = 1;
+ }
+
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG );
+ }
+ }
+
+ Kolab::log('T', "Finished creating configuration file `$cfg'", KOLAB_DEBUG );
+}
+
+sub buildPostfixTransportMap
+{
+ buildPostfixMap( 'transport' );
+}
+
+sub buildPostfixVirtualMap
+{
+ buildPostfixMap( 'virtual' );
+}
+
+sub buildPostfixMap
+{
+ my $map = shift;
+ Kolab::log('T', "Building Postfix $map map", KOLAB_DEBUG);
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ my $keytemplate = "$templatedir/$map.template";
+ my $cfg = $templates{$keytemplate};
+ my $oldcfg = $cfg . '.old';
+
+ #my $oldmask = umask 077;
+ #copy($cfg, $oldcfg);
+ #chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $oldcfg);
+ #umask $oldmask;
+ #delete $templates{$keytemplate};
+
+ my $transport;
+ if (!($transport = IO::File->new($cfg, 'a'))) {
+ Kolab::log('T', "Unable to create Postfix $map map: $!", KOLAB_ERROR);
+ exit(1);
+ }
+
+ my $ldap = Kolab::LDAP::create(
+ $Kolab::config{'ldap_ip'},
+ $Kolab::config{'ldap_port'},
+ $Kolab::config{'bind_dn'},
+ $Kolab::config{'bind_pw'}
+ );
+
+ my $mesg = $ldap->search(
+ base => 'k=kolab,'.$Kolab::config{'base_dn'},
+ scope => 'base',
+ filter => '(objectclass=*)'
+ );
+ if ($mesg->code) {
+ Kolab::log('T', "Unable to locate Postfix $map map entries in LDAP", KOLAB_ERROR);
+ exit(1);
+ }
+
+ my $ldapobject;
+ if ($mesg->code <= 0) {
+ foreach $ldapobject ($mesg->entries) {
+ my $routes = $ldapobject->get_value("postfix-$map", asref => 1);
+ foreach (@$routes) {
+ $_ = trim($_);
+ Kolab::log('T', "Adding entry `$_' to $map");
+ print $transport $_ . "\n";
+ }
+ }
+ } else {
+ Kolab::log('T', "No Postfix $map map entries found");
+ }
+
+ Kolab::LDAP::destroy($ldap);
+ $transport->close;
+
+ # FIXME: bad way of doing things...
+ #system("chown root:root @emailserver_confdir@/*");
+ fixup( $cfg, $ownership{$cfg}, $permissions{$cfg});
+ system("$Kolab::config{'postmapping'}/$map");
+
+ if (-f $oldcfg) {
+ my $rc = `diff -q $cfg $oldcfg`;
+ chomp($rc);
+ if ($rc) {
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'postfix'} = 1;
+ }
+ } else {
+ $haschanged{'postfix'} = 1;
+ }
+
+ Kolab::log('T', 'Finished building Postfix $map map', KOLAB_DEBUG);
+}
+
+sub buildCyrusGroups
+{
+ Kolab::log('T', 'Building Cyrus groups', KOLAB_DEBUG);
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ my $keytemplate = "$templatedir/imapd.group.template";
+ my $cfg = $templates{$keytemplate};
+ my $oldcfg = $cfg . '.old';
+ #delete $templates{$keytemplate};
+
+ #my $oldmask = umask 077;
+ #copy($cfg, $oldcfg);
+ #chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $oldcfg);
+ #umask $oldmask;
+
+ my $groupconf;
+ if (!($groupconf = IO::File->new($cfg, 'a'))) {
+ Kolab::log('T', "Unable to open configuration file `$cfg': $!", KOLAB_ERROR);
+ exit(1);
+ }
+
+ my $ldap = Kolab::LDAP::create(
+ $Kolab::config{'ldap_ip'},
+ $Kolab::config{'ldap_port'},
+ $Kolab::config{'bind_dn'},
+ $Kolab::config{'bind_pw'}
+ );
+
+ my $mesg = $ldap->search(
+ base => $Kolab::config{'base_dn'},
+ scope => 'sub',
+ filter => '(&(mail=*)(objectclass=kolabgroupofnames))'
+ );
+ if ($mesg->code) {
+ Kolab::log('T', 'Unable to locate Cyrus groups in LDAP', KOLAB_ERROR);
+ exit(1);
+ }
+
+ my $ldapobject;
+ my $count = 60000;
+ if ($mesg->code <= 0) {
+ foreach $ldapobject ($mesg->entries) {
+ #my $group = $ldapobject->get_value('cn') . '@'.join('.',reverse(@dn)) . ":*:$count:";
+ my $group = lc($ldapobject->get_value('mail')).":*:$count:";
+ my $userlist = $ldapobject->get_value('member', asref => 1);
+ foreach (@$userlist) {
+ my $uid = $_;
+ my $umesg = $ldap->search( base => $uid,
+ scope => 'base',
+ filter => '(objectClass=*)' );
+ if ( $umesg && $umesg->code() <= 0 && $umesg->count() == 1 ) {
+ my $mail;
+ ($mail = $umesg->entry(0)->get_value('mail')) or
+ ($mail = $umesg->entry(0)->get_value('uid'));
+ $group .= lc($mail).',';
+ }
+ }
+ $group =~ s/,$//;
+ print $groupconf $group . "\n";
+ Kolab::log('T', "Adding cyrus group `$group'");
+ $count++;
+ }
+ } else {
+ Kolab::log('T', 'No Cyrus groups found');
+ }
+
+ $groupconf->close;
+ Kolab::LDAP::destroy($ldap);
+
+ fixup( $cfg, $ownership{$cfg}, $permissions{$cfg});
+
+ Kolab::log('T', 'Finished building Cyrus groups', KOLAB_DEBUG );
+}
+
+sub buildLDAPAccess
+{
+ Kolab::log('T', 'Building LDAP access file', KOLAB_DEBUG);
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ my $keytemplate = "$templatedir/slapd.access.template";
+ my $cfg = $templates{$keytemplate};
+ my $oldcfg = $cfg . '.old';
+
+ my $access;
+ if (!($access = IO::File->new($cfg, 'a'))) {
+ Kolab::log('T', "Unable to open configuration file `$cfg': $!", KOLAB_ERROR);
+ exit(1);
+ }
+
+my $global_acl = <<'EOS';
+# Domain specific access
+access to filter=(&(objectClass=kolabInetOrgPerson)(mail=*@@@@domain@@@)(|(!(alias=*))(alias=*@@@@domain@@@)))
+ by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" write
+ by * break
+
+access to filter=(&(objectClass=kolabGroupOfNames)(mail=*@@@@domain@@@))
+ by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" write
+ by * break
+
+access to filter=(&(objectClass=kolabSharedFolder)(cn=*@@@@domain@@@))
+ by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" write
+ by * break
+
+EOS
+
+my $dom_acl1 = << 'EOS';
+# Access to domain groups
+access to dn.children="cn=domains,cn=internal,@@@base_dn@@@"
+ by group/kolabGroupOfNames="cn=admin,cn=internal,@@@base_dn@@@" write
+ by group/kolabGroupOfNames="cn=maintainer,cn=internal,@@@base_dn@@@" write
+ by dn="cn=nobody,cn=internal,@@@base_dn@@@" read
+EOS
+
+my $dom_acl2 = << 'EOS';
+ by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" read
+EOS
+
+my $dom_acl3 = << 'EOS';
+ by * search stop
+EOS
+
+ my $str;
+ my $domain;
+ my @domains;
+ if( ref($Kolab::config{'postfix-mydestination'}) eq 'ARRAY' ) {
+ @domains = @{$Kolab::config{'postfix-mydestination'}};
+ } else {
+ @domains =( $Kolab::config{'postfix-mydestination'} );
+ }
+
+ ($str = $dom_acl1) =~ s/\@{3}base_dn\@{3}/$Kolab::config{'base_dn'}/g;
+ print $access $str;
+
+ foreach $domain (@domains) {
+ ($str = $dom_acl2) =~ s/\@{3}domain\@{3}/$domain/g;
+ $str =~ s/\@{3}base_dn\@{3}/$Kolab::config{'base_dn'}/g;
+ print $access $str;
+ }
+
+ ($str = $dom_acl3) =~ s/\@{3}base_dn\@{3}/$Kolab::config{'base_dn'}/g;
+ print $access $str;
+
+ foreach $domain (@domains) {
+ ($str = $global_acl) =~ s/\@{3}domain\@{3}/$domain/g;
+ $str =~ s/\@{3}base_dn\@{3}/$Kolab::config{'base_dn'}/g;
+ print $access $str;
+ Kolab::log('T', "Adding acl for domain '$str'");
+ }
+
+ $access->close;
+
+ if (-f $oldcfg) {
+ my $rc = `diff -q $cfg $oldcfg`;
+ chomp($rc);
+ if ($rc) {
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'slapd'} = 1;
+ }
+ } else {
+ $haschanged{'slapd'} = 1;
+ }
+
+ fixup( $cfg, $ownership{$cfg}, $permissions{$cfg});
+
+ Kolab::log('T', 'Finished building LDAP access file', KOLAB_DEBUG );
+}
+
+sub buildLDAPReplicas
+{
+ Kolab::log('T', 'Building LDAP replicas', KOLAB_DEBUG);
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ my $keytemplate = "$templatedir/slapd.replicas.template";
+ my $cfg = $templates{$keytemplate};
+ my $oldcfg = $cfg . '.old';
+
+ my $repl;
+ if (!($repl = IO::File->new($cfg, 'a'))) {
+ Kolab::log('T', "Unable to open configuration file `$cfg': $!", KOLAB_ERROR);
+ exit(1);
+ }
+
+ # directory_mode syncrepl is supported from openldap-2.3.x and beyond
+ if ($Kolab::config{'directory_mode'} eq "syncrepl") {
+
+ if ( $Kolab::config{'is_master'} eq "false" ) {
+ # Output a syncrepl statement for database synchronisation
+ print $repl "syncrepl rid=0 \n"
+ ." provider=".$Kolab::config{"ldap_master_uri"}."\n"
+ ." type=refreshAndPersist\n"
+ ." searchbase=\"".$Kolab::config{'base_dn'}."\"\n"
+ ." scope=sub\n"
+ ." schemachecking=on\n"
+ ." binddn=\"".$Kolab::config{"bind_dn"}."\"\n"
+ ." credentials=\"".$Kolab::config{"bind_pw"}."\"\n"
+ ." bindmethod=simple\n";
+ }
+
+ } else {
+
+ if( $Kolab::config{'is_master'} eq "true" ) {
+ # Master setup
+ my @kh;
+ if( ref $Kolab::config{'kolabhost'} eq 'ARRAY' ) {
+ @kh = @{$Kolab::config{'kolabhost'}};
+ } else {
+ @kh = ( $Kolab::config{'kolabhost'} );
+ }
+ for my $h ( @kh ) {
+ next if lc($h) eq lc($Kolab::config{'fqdnhostname'});
+ print $repl "replica uri=ldaps://$h\n"
+ ." binddn=\"".$Kolab::config{'bind_dn'}."\"\n"
+ ." bindmethod=simple credentials=".$Kolab::config{'bind_pw'}."\n\n";
+ }
+ } else {
+ # Slave setup
+ # Output an update dn statement instead
+ print $repl "updatedn ".$Kolab::config{'bind_dn'}."\n";
+ print $repl "updateref ".$Kolab::config{'ldap_master_uri'}."\n";
+ }
+ }
+
+ $repl->close;
+
+ fixup( $cfg, $ownership{$cfg}, $permissions{$cfg});
+
+ if (-f $oldcfg) {
+ my $rc = `diff -q $cfg $oldcfg`;
+ chomp($rc);
+ if ($rc) {
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'slapd'} = 1;
+ }
+ } else {
+ $haschanged{'slapd'} = 1;
+ }
+
+ Kolab::log('T', 'Finished building LDAP replicas', KOLAB_DEBUG);
+}
+
+sub replaceMetaVar
+{
+ my $var = shift;
+
+ while ($var =~ /\@{3}([^\s\@]+?)\@{3}/) {
+ my $attr = $1;
+ if ($Kolab::config{$attr}) {
+ my $val = $Kolab::config{$attr};
+ $var =~ s/\@{3}([^\s\@]+?)\@{3}/$val/;
+ } else {
+ Kolab::log('T', "No configuration variable corresponding to `$1' exists", KOLAB_WARN);
+ }
+ }
+ return $var;
+}
+
+
+sub loadMetaTemplates
+{
+ my $templatedir = shift;
+ my ($tref, $pref, $oref, $cmdref, $ccharref) = @_;
+
+ Kolab::log('T', 'Collecting template files', KOLAB_DEBUG );
+ opendir(DIR, $templatedir) or Kolab::log('T', 'Given templatedir $templatedir does not exist!', KOLAB_ERROR );
+ my @metatemplates = grep { /\.template$/ } readdir (DIR);
+ closedir(DIR);
+
+ foreach my $template (@metatemplates) {
+ my $runonchange = undef;
+ my $commentchar = undef;
+ #Open each file and check for the META
+ if (open (TEMPLATE, "$templatedir/$template" )) {
+ my $line = <TEMPLATE>;
+ if ($line =~ /^KOLAB_META_START$/) {
+ Kolab::log('T', 'Processing META template :'.$template, KOLAB_DEBUG );
+ my ($found_end, $target, $permissions, $ownership);
+ while (<TEMPLATE>) {
+ $line = $_;
+
+ if (!$found_end) {
+ $found_end = $line =~ /^KOLAB_META_END$/;
+ if (!$found_end && $line) {
+ my ($key,$value) = split(/=/,$line);
+ chomp($value);
+ Kolab::log('T', 'META Key: '.$key.' Value: '.$value, KOLAB_DEBUG );
+ if ($key =~ /^TARGET$/) {
+ $target = replaceMetaVar($value);
+ Kolab::log('T', 'META Target '.$target, KOLAB_DEBUG );
+ } elsif ($key =~ /^PERMISSIONS$/) {
+ $permissions = replaceMetaVar($value);
+ Kolab::log('T', 'META Permissions '.$permissions, KOLAB_DEBUG );
+ } elsif ($key =~ /^OWNERSHIP$/) {
+ $ownership = replaceMetaVar($value);
+ Kolab::log('T', 'META Ownership '.$ownership, KOLAB_DEBUG );
+ } elsif ($key =~ /^RUNONCHANGE$/) {
+ $runonchange = replaceMetaVar($value);
+ Kolab::log('T', 'META Cmd to execute '.$runonchange, KOLAB_DEBUG );
+ } elsif ($key =~ /^COMMENT_CHAR$/) {
+ $commentchar = replaceMetaVar($value);
+ Kolab::log('T', 'META CommentChar to use: '.$commentchar, KOLAB_DEBUG );
+ } else {
+ Kolab::log('T', 'incorrect META key "'.$key.'" in: '.$template, KOLAB_WARN );
+ }
+ }
+ }
+ }
+ if ($found_end && $target && $permissions && $ownership) {
+ Kolab::log('T', 'All mandatory fields populated in '.$template, KOLAB_DEBUG );
+ $$tref{$templatedir . "/" . $template} = $target;
+ $$oref{$target} = $ownership;
+ $permissions = oct($permissions);
+ $$pref{$target} = $permissions;
+ my $runcmdtemplate = $templatedir."/".$template;
+ $$cmdref{$runcmdtemplate} = $runonchange if (defined $runonchange);
+ $$ccharref{$target} = $commentchar if (defined $commentchar);
+ }
+
+ }
+ } else {
+ Kolab::log('T', 'Could not open template file: '. $template, KOLAB_WARN);
+ }
+ }
+
+}
+
+sub rebuildTemplates
+{
+ my $key;
+ my $value;
+ my $section="";
+ my %runonchange;
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ Kolab::log('T', 'Regenerating configuration files', KOLAB_DEBUG );
+
+ Kolab::log('T', 'Loading meta-template data', KOLAB_DEBUG );
+ loadMetaTemplates( $templatedir, \%templates, \%permissions, \%ownership, \%runonchange, \%commentchar );
+
+ my $cfg;
+ my $tpl;
+ foreach $tpl (keys %templates) {
+ $cfg = $templates{$tpl};
+ #print STDOUT "Rebuilding $tpl => $cfg\n";
+ build($tpl, $cfg, $ownership{$cfg}, $permissions{$cfg}, $commentchar{$cfg});
+ }
+
+ buildPostfixTransportMap;
+ buildPostfixVirtualMap;
+ buildLDAPAccess;
+ buildLDAPReplicas;
+ buildCyrusGroups;
+
+ Kolab::log('T', 'Finished regenerating configuration files', KOLAB_DEBUG );
+
+ foreach $key (keys %runonchange) {
+ if (defined $templatehaschanged{$key})
+ {
+ Kolab::log('T', 'Actioning RUNONCHANGE for $key', KOLAB_DEBUG );
+ my $cmd = $runonchange{$key};
+ system($cmd);
+ Kolab::log('T', 'Executing command', KOLAB_DEBUG );
+ }
+ }
+}
+
+sub bootstrapConfig
+{
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ # FIXME: it would be better if the templates can be given as an
+ # argument to this function.
+ my @templ = ("$templatedir/slapd.access.template",
+ "$templatedir/slapd.conf.template",
+ "$templatedir/slapd.replicas.template");
+
+ my %runonchange;
+
+ loadMetaTemplates( $templatedir, \%templates, \%permissions, \%ownership, \%runonchange, \%commentchar );
+
+ my $cfg;
+ my $out;
+ foreach my $tpl (@templ) {
+ $cfg = $templates{$tpl};
+ # print STDOUT "Rebuilding $tpl => $cfg\n";
+ build($tpl, $cfg, $ownership{$cfg}, $permissions{$cfg}, $commentchar{$cfg});
+ }
+}
+
+sub checkPermissions {
+ my $key;
+ my $value;
+
+ my $templatedir = $Kolab::config{"templatedir"};
+
+ Kolab::log('T', 'Checking generated config file permissions and ownership', KOLAB_DEBUG );
+
+ loadMetaTemplates( $templatedir, \%templates, \%permissions, \%ownership );
+
+ my $ok = 1;
+
+ foreach $key (keys %templates) {
+ my $tpl = $templates{$key};
+
+ if (-r $tpl) {
+ my $st = stat($tpl);
+ my $owner = getpwuid($st->uid).':'.getgrgid($st->gid);
+ if( ( ($st->mode & 07777) != $permissions{$tpl}) ||
+ ($owner ne $ownership{$tpl}) ) {
+ my $str = 'File '.$tpl.' has the wrong persmissions/owner. Found '
+ .sprintf("%lo", $st->mode&07777).' '.$owner.', expected '
+ .sprintf("%lo",$permissions{$tpl}).' '.$ownership{$tpl};
+ print( "$str\n" );
+ Kolab::log('T', $str, KOLAB_ERROR );
+ $ok = 0;
+ }
+ } else {
+ my $str = "File $tpl does not exist";
+ print "$str\n";
+ Kolab::log('T', "$str", KOLAB_ERROR );
+ }
+ }
+ return $ok;
+}
+
+sub reload
+{
+ if ($haschanged{'slapd'}) {
+ &Kolab::log('K', 'Restarting OpenLDAP...');
+ system("$Kolab::config{'KOLABRC'} rc openldap restart &");
+ }
+
+ if ($haschanged{'saslauthd'}) {
+ &Kolab::log('K', 'Restarting SASLAuthd...');
+ system("$Kolab::config{'KOLABRC'} rc sasl stop; sleep 1; $Kolab::config{sbindir}/saslauthd -a ldap -n 5");
+ }
+
+ if ($haschanged{'apache'}) {
+ &Kolab::log('K', 'Reloading Apache...');
+ system("$Kolab::config{sbindir}/apachectl graceful");
+ }
+
+ if ($haschanged{'postfix'}) {
+ &Kolab::log('K', 'Reloading Postfix...');
+ system("$Kolab::config{sbindir}/postfix reload");
+ }
+
+ if ($haschanged{'imapd'}) {
+ &Kolab::log('K', 'Restarting imapd...');
+ # Would it be enough with a reload here? /steffen
+ system("$Kolab::config{'KOLABRC'} rc imapd restart");
+ }
+
+ if ($haschanged{'amavisd'}) {
+ &Kolab::log('K', 'Restarting amavisd...');
+ system("$Kolab::config{'KOLABRC'} rc amavisd restart");
+ }
+
+ if ($haschanged{'clamav'}) {
+ &Kolab::log('K', 'Restarting clamav...');
+ system("$Kolab::config{'KOLABRC'} rc clamav restart");
+ }
+
+ %Kolab::Conf::haschanged = ();
+
+ &Kolab::log('K', 'Reload finished');
+}
+
+1;
+__END__
+=head1 NAME
+
+Kolab::Conf - Perl extension for Kolab template generation
+
+=head1 ABSTRACT
+
+ Kolab::Conf handles the generation of template files, used by
+ kolabconf.
+
+=head1 COPYRIGHT AND AUTHORS
+
+Stuart Bingë and others (see AUTHORS file)
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You can view the GNU General Public License, online, at the GNU
+Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
+
+=cut
diff --git a/perl-kolab.spec b/perl-kolab.spec
index 870f601..0c2e7a7 100644
--- a/perl-kolab.spec
+++ b/perl-kolab.spec
@@ -72,8 +72,16 @@ AutoReqProv: no
%install
%{l_prefix}/bin/perl-openpkg prepare
- %{l_prefix}/bin/perl-openpkg -d %{SOURCE0} configure build install
+ %{l_prefix}/bin/perl-openpkg -d %{SOURCE0} -A "--config \"%{l_prefix}/etc/kolab\" --bin \"%{l_prefix}/bin\"" configure build install
%{l_prefix}/bin/perl-openpkg -F perl-openpkg-files fixate cleanup
+ mkdir -p $RPM_BUILD_ROOT/%{l_prefix}/sbin
+ mv $RPM_BUILD_ROOT/%{l_prefix}/bin/kolabd $RPM_BUILD_ROOT/%{l_prefix}/sbin/kolabd
+ mv $RPM_BUILD_ROOT/%{l_prefix}/bin/kolabcheckperm $RPM_BUILD_ROOT/%{l_prefix}/sbin/kolabcheckperm
+ chmod 744 $RPM_BUILD_ROOT/%{l_prefix}/sbin/kolabd
+ chmod 744 $RPM_BUILD_ROOT/%{l_prefix}/sbin/kolabcheckperm
+ mkdir -p $RPM_BUILD_ROOT/%{l_prefix}/etc/kolab
+ cp $RPM_BUILD_DIR/%{V_package}-%{V_version}/%{V_package}-%{V_source_tag}/data/quotawarning.txt $RPM_BUILD_ROOT/%{l_prefix}/etc/kolab
+ sed -i -e 's#/bin/kolabd#/sbin/kolabd#' -e 's#/bin/kolabcheckperm#/sbin/kolabcheckperm#' perl-openpkg-files
%{l_rpmtool} files -v -ofiles -r$RPM_BUILD_ROOT %{l_files_std} `cat perl-openpkg-files`
%files -f files