From cvs at kolab.org Fri Oct 10 16:20:04 2008 From: cvs at kolab.org (cvs@kolab.org) Date: Fri, 10 Oct 2008 16:20:04 +0200 (CEST) Subject: gunnar: server/perl-kolab/bin - New directory Message-ID: <20081010142004.2C2E8600BA9@lists.intevation.de> Author: gunnar Update of /kolabrepository/server/perl-kolab/bin In directory doto:/tmp/cvs-serv20182/bin Log Message: Directory /kolabrepository/server/perl-kolab/bin added to the repository From cvs at kolab.org Fri Oct 10 16:20:10 2008 From: cvs at kolab.org (cvs@kolab.org) Date: Fri, 10 Oct 2008 16:20:10 +0200 (CEST) Subject: gunnar: server/perl-kolab/data - New directory Message-ID: <20081010142010.5E5C9600BAF@lists.intevation.de> Author: gunnar Update of /kolabrepository/server/perl-kolab/data In directory doto:/tmp/cvs-serv20220/data Log Message: Directory /kolabrepository/server/perl-kolab/data added to the repository From cvs at kolab.org Fri Oct 10 16:22:06 2008 From: cvs at kolab.org (cvs@kolab.org) Date: Fri, 10 Oct 2008 16:22:06 +0200 (CEST) Subject: gunnar: server/perl-kolab/data quotawarning.txt,NONE,1.1 Message-ID: <20081010142206.C1D15600BAF@lists.intevation.de> Author: gunnar Update of /kolabrepository/server/perl-kolab/data In directory doto:/tmp/cvs-serv20319/data Added Files: quotawarning.txt Log Message: Merge all perl tools into the perl-kolab package. --- NEW FILE: quotawarning.txt --- [This is an automatically generated message.] The mailbox for is % full, please clean it up. The size of the mailbox is currently KB out of a total allowed KB. [Dies ist eine automatisch generierte Nachricht] Das Postfach für ist zu % gefüllt. Bitte räumen Sie es auf. Das Postfach belegt zurzeit KB von erlaubten KB. From cvs at kolab.org Fri Oct 10 16:22:07 2008 From: cvs at kolab.org (cvs@kolab.org) Date: Fri, 10 Oct 2008 16:22:07 +0200 (CEST) Subject: gunnar: server/perl-kolab/lib/Kolab Conf.pm,NONE,1.1 Message-ID: <20081010142207.0431A600BAF@lists.intevation.de> Author: gunnar Update of /kolabrepository/server/perl-kolab/lib/Kolab In directory doto:/tmp/cvs-serv20319/lib/Kolab Added Files: Conf.pm Log Message: Merge all perl tools into the perl-kolab package. --- NEW FILE: Conf.pm --- 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 . ## ## $Revision: 1.1 $ 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 =