[Kroupware] /openpkg...

Tassilo Erlewein kroupware@mail.kde.org
Wed, 27 Nov 2002 16:04:22 +0100


--------------Boundary-00=_AVP89J1SSKQ1I3JHKQO2
Content-Type: text/plain;
  charset="iso-8859-15"
Content-Transfer-Encoding: quoted-printable

Am Mittwoch, 27. November 2002 11:49 schrieb Lutz Badenheuer:
> Hi Tassilo,
>
> I've had a short look at kolab.ldif and discovered that there are
> several "config-dir:"-Attributes which contain /openpkg pathes.
> Shouldn't we use /kolab?

Yes, you're right. That setting needs to be chosen according to
your openpkg prefix.

BTW we have already fixed the installation procedure for the beta,=20
now the ldap entries are generated during rpm install.

the beta looks good but we're fighting with some nasty perl habits.
It seems the openpkg perl behaves differently from "regular" packages.

Could anybody provide me code snippets which successfully use
IO::Select to block on a tcp socket ?

Any of you used Convert::ASN1 ?

another thing is non-blocking IO on a fifo ...

(code examples would be nice, the O'Reilly stuff doesn't seem to work for=
 me)

I have attached the two supposedly buggy perl programs.
The beta very much depends on that stuff to get running and I would appre=
ciate=20
every help I could get.

Thanks in advance & best regards

Tassilo

ps: please don't mix this stuff with the alpha you probably have=20
installed...


--------------Boundary-00=_AVP89J1SSKQ1I3JHKQO2
Content-Type: text/plain;
  charset="iso-8859-15";
  name="kolab"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="kolab"

#!/kolab/bin/perl 

# (c) 2002 Tassilo Erlewein <tassilo.erlewein@erfrakon.de>
# (c) 2002 Martin Konold <martin.konold@erfrakon.de>
# (c) 2002 Achim Frank <achim.frank@erfrakon.de>

# kolab Version 0.91
# create unix configuration files from data source (files or LDAP) 
# and templates

use strict;

use IO::Select;
use IO::Socket;
use IO::File;
use Convert::ASN1 qw(:io);
use Net::LDAP::ASN qw(LDAPRequest LDAPResponse LDAPResult);
use Net::LDAP::Constant;
use Data::Dumper;
use POSIX qw(setuid setgid fcntl F_GETFL F_SETFL);
use Sys::Syslog qw(:DEFAULT setlogsock);

setlogsock('unix');

sub my_syslog {
  openlog("kolab[$$]");
  syslog("info", $_[0]);
  closelog;
  #system("logger -t \"kolab[$$]\" \"$_[0]\"");
}

sub PROTOCOLOP_BINDREQUEST   	() { 0x00 }
sub PROTOCOLOP_BINDRESPONSE  	() { 0x01 }
sub PROTOCOLOP_UNBINDREQUEST 	() { 0x02 }
sub PROTOCOLOP_SEARCHREQUEST 	() { 0x03 }
sub PROTOCOLOP_SEARCHRESENTRY  	() { 0x04 }
sub PROTOCOLOP_SEARCHRESDONE  	() { 0x05 }
sub PROTOCOLOP_SEARCHRESREF  	() { 0x06 }
sub PROTOCOLOP_MODIFYREQUEST  	() { 0x07 }
sub PROTOCOLOP_MODIFYRESPONSE  	() { 0x08 }
sub PROTOCOLOP_ADDREQUEST  	() { 0x09 }
sub PROTOCOLOP_ADDRESPONSE  	() { 0x10 }
sub PROTOCOLOP_DELREQUEST  	() { 0x11 }
sub PROTOCOLOP_DELRESPONSE  	() { 0x12 }
sub PROTOCOLOP_MODDNREQUEST  	() { 0x13 }
sub PROTOCOLOP_MODDNRESPONSE  	() { 0x14 }
sub PROTOCOLOP_COMPAREREQUEST  	() { 0x15 }
sub PROTOCOLOP_COMPARERESPONSE  () { 0x16 }
sub PROTOCOLOP_ABANDONREQUEST  	() { 0x17 }
sub PROTOCOLOP_EXTENDEDREQ  	() { 0x18 }
sub PROTOCOLOP_EXTENDEDRESP  	() { 0x19 }

system("echo $$ > /kolab/var/kolab/kolab.pid");
my $uid = (getpwnam("nobody"))[2];
my $gid = (getgrnam("nogroup"))[2];
setuid($uid);
setgid($gid);
my $fifo = "/kolab/var/kolab/fifo";
my $server_port = 9999;
my $server = IO::Socket::INET->new(
    LocalPort => $server_port, Proto => "tcp", Type => SOCK_STREAM, LocalAddr => "127.0.0.1", Listen => 10)
    || die "Couldn't be a tcp server on port $server_port : $@\n";

my_syslog("kolab started");

sub do_notify
{
   if (! -e $fifo) { return; }
   my $fd = IO::File->new($fifo, "w") || return;
   my $flags = '';
#   fcntl($fd, F_GETFL, $flags) || die "Couldn't get flags for $fd : $!\n";
#   $flags |= O_NONBLOCK;
#   fcntl($fd, F_SETFL, $flags) || die "Couldn't set flags for $fd: $!\n";
   my $select = IO::Select->new($fd);
   if ($select->can_write) { print $fd "ping"; }
#   print $fd "ping";
   my_syslog("kolab_buildconfig notified");
   undef $fd;
}

sub debug
{
   #my $a = shift;
   #print "$a\n";
   #my_syslog($a);
}

sub debug_response
{ 
   #my $p = shift;
   #$Data::Dumper::Indent=1;
   #$Data::Dumper::Quotekeys=0;
   #print Dumper($LDAPResponse->decode($p));
}

sub debug_request
{
   #my $p = shift;
   #$Data::Dumper::Indent=1;
   #$Data::Dumper::Quotekeys=0;
   #print Dumper($LDAPRequest->decode($p));
}



sub get_request_type
{
   my $op = shift;
   if ($op->{bindRequest}) { return "bindRequest"; }
   if ($op->{unbindRequest}) { return "unbindRequest"; }
   if ($op->{addRequest}) { return "addRequest"; }
   if ($op->{delRequest}) { return "delRequest"; }
   if ($op->{modifyRequest}) { return "modifyRequest"; }
   if ($op->{modDNRequest}) { return "modDNRequest"; }
   if ($op->{searchRequest}) { return "searchRequest"; }
   if ($op->{compareRequest}) { return "compareRequest"; }
   if ($op->{abandonRequest}) { return "abandonRequest"; }
   if ($op->{extendedRequest}) { return "extendedRequest"; }
   return "";
}


sub bind_response
{
   my $req = shift;
   debug("got bind request");
   my $pdu = $LDAPResponse->encode(
                messageID => $req->{messageID},
                protocolOp => {
                   choiceID => PROTOCOLOP_BINDRESPONSE,
                   bindResponse => {
                      resultCode => Net::LDAP::Constant::LDAP_SUCCESS,
                      matchedDN => $req->{bindRequest}{name},
                      errorMessage => "",
                      serverSaslCreds => "" }}) || die $LDAPResponse->error;
   return $pdu;
}

sub add_response
{
   my $req = shift;
   debug("got add request");
   my $pdu = $LDAPResponse->encode(
                messageID => $req->{messageID},
                protocolOp => {
                   choiceID => PROTOCOLOP_ADDRESPONSE,
                   addResponse => {
                      resultCode => Net::LDAP::Constant::LDAP_SUCCESS,
                      matchedDN => $req->{addRequest}{objectName},
                      errorMessage => "" }}) || die $LDAPResponse->error;
   return $pdu;
}

sub del_response
{
   my $req = shift;
   debug("got del request");
   my $pdu = $LDAPResponse->encode(
                messageID => $req->{messageID},
                protocolOp => {
                   choiceID => PROTOCOLOP_DELRESPONSE,
                   delResponse => {
                      resultCode => Net::LDAP::Constant::LDAP_SUCCESS,
                      matchedDN => $req->{delRequest},
                      errorMessage => "" }}) || die $LDAPResponse->error;
   return $pdu;
}

sub mod_response
{   
   my $req = shift;
   debug("got mod request");
   my $pdu = $LDAPResponse->encode(
                messageID => $req->{messageID},
                protocolOp => {
                   choiceID => PROTOCOLOP_MODIFYRESPONSE,
                   modifyResponse => {
                      resultCode => Net::LDAP::Constant::LDAP_SUCCESS,
                      matchedDN => $req->{modifyRequest}{object},
                      errorMessage => "" }}) || die $LDAPResponse->error;
   return $pdu;
}

sub moddn_response
{
   my $req = shift;
   debug("got moddn request");
   my $pdu = $LDAPResponse->encode(
                messageID => $req->{messageID},
                protocolOp => {
                   choiceID => PROTOCOLOP_MODDNRESPONSE,
                   modDNResponse => {
                      resultCode => Net::LDAP::Constant::LDAP_SUCCESS,
                      matchedDN => $req->{modDNRequest}{entry},
                      errorMessage => "" }}) || die $LDAPResponse->error;
   return $pdu;
}


my $conn;
my $request;
my $response;
my $pdu;
my $notify;


while ($conn = $server->accept()) {
 
   my_syslog("incoming connection");
   my $select = IO::Select->new($conn);

   my_syslog("waiting for incoming LDAP updates");
   while ($conn) {

      undef $pdu;
      my $ready;
      my $offset = 0;
      for( $ready = 1 ; $ready ; $ready = $select->can_read(1)) {
         $offset = asn_read($conn, $pdu, $offset);
         defined($offset) or $offset = 0;
      }

#      while (!($select->can_read)) { sleep 1; };
#      asn_recv($conn,$pdu,0);

      if ($pdu) { 
         $notify = 0;
         debug_request($pdu); 
         $request = $LDAPRequest->decode($pdu) || die $LDAPRequest->error;
         $_ = get_request_type($request);
         undef $pdu;
         debug("got $_");

         SWITCH: {
            if (/bindRequest/) { $pdu = bind_response($request); last SWITCH; }
            if (/addRequest/) { $pdu = add_response($request); $notify = 1; last SWITCH; }
            if (/delRequest/) { $pdu = del_response($request); $notify = 1; last SWITCH; }
            if (/modifyRequest/) { $pdu = mod_response($request); $notify = 1; last SWITCH; }
            if (/modDNRequest/) { $pdu = moddn_response($request); $notify = 1; last SWITCH; }

            if (/unbindRequest/) {
               debug("Got unbindRequest");
            } else {
               debug("Unhandled Request!");
            #$pdu = $LDAPResult->encode(
            #          resultCode => Net::LDAP::Constant::LDAP_PROTOCOL_ERROR, 
            #          matchedDN => '', errorMessage => "Invald Request received")
            #   || die $LDAPRequest->error;
            #asn_send($conn,$pdu,0);
            #undef $pdu;
            }
            #$select->remove($conn);
            $conn->close;
            undef $conn;
         } # SWITCH
      } # if pdu

      if ($pdu) {
         #asn_send($conn,$pdu,0);
         syswrite($conn, $pdu, length($pdu));
	 if ($notify) { do_notify; }
         debug_response($pdu);
         $response = $LDAPResponse->decode($pdu) || die $LDAPResponse->error;
      }

      sleep 1;

   } # while conn
}
$server->close;
exit 0;

--------------Boundary-00=_AVP89J1SSKQ1I3JHKQO2
Content-Type: text/plain;
  charset="iso-8859-15";
  name="kolab_buildconfig"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="kolab_buildconfig"

#!/kolab/bin/perl 

# (c) 2002 Tassilo Erlewein <tassilo.erlewein@erfrakon.de>
# (c) 2002 Martin Konold <martin.konold@erfrakon.de>
# (c) 2002 Achim Frank <achim.frank@erfrakon.de>

# kolab_buildconfig Version 0.91
# create unix configuration files from LDAP and templates
# this needs to run as user root

use strict;
use vars qw($opt_v $opt_o $opt_l);

use URI;
use IO::File;
use IO::Select;
use Net::LDAP;
use File::Copy;
use Getopt::Std;
use Cyrus::IMAP::Admin;
use Sys::Syslog qw(:DEFAULT setlogsock);
setlogsock('unix');

sub my_syslog {
  openlog("kolab_buildconfig[$$]");
  syslog("info", $_[0]);
  closelog();
  #system("logger -t \"kolab_buildconfig[$$]\" \"$_[0]\"");
}

my %configdata;         # hash to hold all config data, either from config file, or from LDAP
my $kolab_prefix = "/kolab";
my $kolab_config = $kolab_prefix."/etc/kolab/kolab.conf";
my $kolab_fifo = $kolab_prefix."/var/kolab/fifo";

system("echo $$ > /kolab/var/kolab/kolab_buildconfig.pid");

my $fd = IO::File->new($kolab_config, "r")
   || die "could not open $kolab_config";
my %kolab_config;
foreach (<$fd>) {
   if (/(.*) : (.*)/) {
      $kolab_config{$1} = $2;
   }
}
undef $fd;
$configdata{'bind_dn'} = $kolab_config{'bind_dn'} || die "could not read bind_dn from $kolab_config";
$configdata{'bind_pw'} = $kolab_config{'bind_pw'} || die "could not read bind_pw from $kolab_config";
$configdata{'ldap_uri'} = $kolab_config{'ldap_uri'} || die "could not read ldap_uri from $kolab_config";
$configdata{'base_dn'} = $kolab_config{'base_dn'} || die "could not read base_dn from $kolab_config";

my_syslog("starting kolab_buildconfig script");

my $postmap="$kolab_prefix/sbin/postmap";    	# inserted at installation time (rpm spec file)

# get command line options
getopts('vol:');
if (defined($opt_l)) { $configdata{'ldap_uri'} = $opt_l; }

# we will often trim strings and kill leading and trailing whitespace
sub trim {
  my $string = $_[0];
  $string =~ s/^\s+//g;
  $string =~ s/\s+$//g;
  chomp $string;
  return $string;
}

# build ( <template name> , <new config file name> )
sub build {
   $opt_v && print "creating new $_[1] from $_[0]\n";
   my $template = IO::File->new($_[0], "r") || die "could not open $_[0]";
   my $config = IO::File->new($_[1], "w+") || die "could not open $_[1]";
   while (<$template>) {
      if (/\@{3}(\S+)\@{3}/) {
         if ($configdata{$1}) {
      	    s/\@{3}(\S+)\@{3}/$configdata{$1}/g;
         } else {
            my_syslog("no replacement for substitute $1");
	    s/\@{3}(\S+)\@{3}//g;
         }
      }
      print $config $_;
   }
   $template->close;
   $config->close;
   system("chown kolab:kolab $_[1]");
}


if (!$opt_o) {
   $opt_v && print "creating new fifo\n";
   system("rm -f $kolab_fifo");
   system("mkfifo $kolab_fifo");
}


sub wait_fifo
{
   $opt_o && return;
   my_syslog("blocking on fifo ...\n");
   my $buf;
   my $fd = IO::File->new($kolab_fifo, "r") || die "could not open $kolab_fifo";
   my $select = IO::Select->new($fd) || die "could not initialize select interface";
   $select->can_read;
   sleep 1;
   while ($select->can_read(1) && $fd->read($buf,1024) > 0) {}
   undef $fd;
   return 0;
}

my $ldap;
my $ldapuri;
my $key;
my $value;
my $section="";
my $ldapobject;
my $mesg;

my %config_files = (
 	"$kolab_prefix/etc/kolab/session_vars.php.template" => "$kolab_prefix/var/kolab/www/admin/include/session_vars.php",
 	"$kolab_prefix/etc/kolab/main.cf.template" => "$kolab_prefix/etc/postfix/main.cf",
 	"$kolab_prefix/etc/kolab/master.cf.template" => "$kolab_prefix/etc/postfix/master.cf",
        "$kolab_prefix/etc/kolab/saslauthd.conf.template" => "$kolab_prefix/etc/saslauthd.conf",
      	"$kolab_prefix/etc/kolab/imapd.conf.template" => "$kolab_prefix/etc/imapd/imapd.conf",
	"$kolab_prefix/etc/kolab/httpd.conf.template" => "$kolab_prefix/etc/apache/apache.conf",
	"$kolab_prefix/etc/kolab/legacy.conf.template" => "$kolab_prefix/etc/apache/legacy.conf",
	"$kolab_prefix/etc/kolab/php.ini.template" => "$kolab_prefix/etc/apache/php.ini",
	"$kolab_prefix/etc/kolab/proftpd.conf.template" => "$kolab_prefix/etc/proftpd/proftpd.conf",
	"$kolab_prefix/etc/kolab/proftpd.passwd.template" => "$kolab_prefix/etc/proftpd/proftpd.passwd",
	"$kolab_prefix/etc/kolab/slapd.conf.template" => "$kolab_prefix/etc/openldap/slapd.conf",	
	"$kolab_prefix/etc/kolab/proftpd.group.template" => "$kolab_prefix/etc/proftpd/proftpd.group", 
	"$kolab_prefix/etc/kolab/imapd.group.template" => "$kolab_prefix/etc/imapd/imapd.group",
	"$kolab_prefix/etc/kolab/transport.template" => "$kolab_prefix/etc/postfix/transport",
	"$kolab_prefix/etc/kolab/monit.conf.template" => "$kolab_prefix/etc/monit/monit.conf",
	"$kolab_prefix/etc/kolab/canonical.template" => "$kolab_prefix/etc/postfix/canonical" );

while (1) {

   $opt_o || my_syslog("entering endless loop");

   wait_fifo;

   $opt_o || my_syslog("run config action");

   $ldapuri = URI->new($configdata{'ldap_uri'}) || die "error: could not parse given uri";
   $ldap = Net::LDAP->new($ldapuri->host, port=> $ldapuri->port) || die "could not connect ldap server";
   $ldap->bind($configdata{'bind_dn'}, password=> $configdata{'bind_pw'}) || die "could not bind to ldap";

   $mesg = $ldap->search(base=> "k=kolab,".$configdata{'base_dn'}, scope=> 'exact', filter=> "(objectclass=*)");
   $ldapobject = $mesg->pop_entry;
   foreach my $attr ($ldapobject->attributes) {
      $configdata{$attr} = $ldapobject->get_value($attr);
   }
   my $salt = substr $configdata{'proftpd-userPassword'}, 0, 2;
   $configdata{'proftpd-userPassword'} = crypt($configdata{'proftpd-userPassword'}, $salt);

   if ($opt_o) { $configdata{'ldap_uri'} =~ s/7777/389/g; }
   my $dummy = URI->new($configdata{'ldap_uri'});
   $configdata{'ldap_ip'} = $dummy->host;
   $configdata{'ldap_port'} = $dummy->port; 

   $configdata{'legacy-mode'} = "";
   if ($configdata{'apache-http'} =~ /true/i) {
      $configdata{'legacy-mode'} = "Include \"$kolab_prefix/etc/apache/legacy.conf\"";
   } 

   foreach $key (keys %config_files) {
      build($key, $config_files{$key});
   }

   # put together the transport map for postfix
   my $transport = IO::File->new("$kolab_prefix/etc/postfix/transport", "a")
        || die "could not write to postfix transport map";
   $mesg = $ldap->search(base=> "k=kolab,".$configdata{'base_dn'}, scope=> 'sub', filter=> "(objectclass=*)")
        || my_syslog("could not find any transport table entries in ldap");
   if ($mesg->code <= 0) {
      foreach $ldapobject ($mesg->entries) {
         my $routes = $ldapobject->get_value('postfix-transport', asref => 1);
         foreach (@$routes) {
            $_=trim($_);
            defined($opt_v) && print "adding smtp route '$_'\n";
            print $transport $_."\n";
         }
      }
   }
   $transport->close;
   system("$postmap $kolab_prefix/etc/postfix/transport");


   undef $ldapobject;

   my $cyrustemplate = IO::File->new("$kolab_prefix/etc/kolab/cyrus.conf.template","r") 
      || die "could not open imapd cyrus.conf template";
   my $configname = "$kolab_prefix/etc/imapd/cyrus.conf";
   $opt_v && printf "creating new $configname from cyrus.conf.template\n";
   my $cyrusconf = IO::File->new($configname,"w") || die "could not open $configname";
   while (<$cyrustemplate>) {
      if (/\@{3}cyrus-imap\@{3}/ && ($configdata{"cyrus-imap"} =~ /true/i)) {
         $_ = "imap cmd=\"imapd listen=\"143\" prefork=0\n";
      }
      elsif (/\@{3}cyrus-pop3\@{3}/ && ($configdata{"cyrus-pop3"} =~ /true/i)) {
         $_ = "pop3 cmd=\"pop3d listen=\"110\" prefork=0\n";
      }
      elsif (/\@{3}cyrus-imaps\@{3}/ && ($configdata{"cyrus-imaps"} =~ /true/i)) {
         $_ = "imaps cmd=\"imapd -s listen=\"993\" prefork=0\n";
      }
      elsif (/\@{3}cyrus-pop3s\@{3}/ && ($configdata{"cyrus-pop3s"} =~ /true/i)) {
         $_ = "pop3s cmd=\"pop3d -s listen=\"995\" prefork=0\n";
      }
      elsif (/\@{3}cyrus-sieve\@{3}/ && ($configdata{"cyrus-sieve"} =~ /true/i)) {
         $_ = "sieve cmd=\"timsieved listen=\"2000\" prefork=0";
      }
      print $cyrusconf $_;
   }
   $cyrustemplate->close;
   $cyrusconf->close;


   # collect group information from LDAP
   my $confname = "$kolab_prefix/etc/imapd/imapd.group";
   my $groupconf = IO::File->new($confname, "a") 
      	|| die "could not write to $confname";
   my $count = 60000;
   $mesg = $ldap->search(base=> $configdata{'base_dn'}, scope=> 'sub', filter=> '(objectclass=groupofnames)') 
	|| die "could not query LDAP for group information";
   if ($mesg->code > 0) {
      $opt_v && print "warning: could not find groups in LDAP tree\n"; 
   } else {
      foreach $ldapobject ($mesg->entries) {
         my $group = $ldapobject->get_value('cn').":*:$count:";
         my $userlist = $ldapobject->get_value('uid', asref => 1);
         foreach (@$userlist) { $group .= "$_,"; }
         $group =~ s/,$/\n/g;
         print $groupconf $group;
         $opt_v && print "added group $group"; 
         $count++;
      }
   }
   undef $ldapobject;
   $groupconf->close;

   $opt_o && exit(0);

   # trigger server config reload
   system("$kolab_prefix/bin/monit -c $kolab_prefix/etc/monit/monit.conf restart slapd &");
   system("$kolab_prefix/bin/monit -c $kolab_prefix/etc/monit/monit.conf restart saslauthd &");
   system("kill -HUP `cat $kolab_prefix/var/proftpd/proftpd.pid`");
   system("kill -HUP `cat $kolab_prefix/var/apache/run/apache.pid`");
   system("kill _HUP `cat $kolab_prefix/var/postfix/pid/master.pid`");
   system("kill -HUP `cat $kolab_prefix/var/imapd/imapd.pid`");

   # open admin channel to local Cyrus IMAP daemon   
   my $cyrus = Cyrus::IMAP::Admin->new('localhost') 
	|| die "could not connect to Cyrus IMAP daemon";
   $cyrus->authenticate('User' => 'manager', 'Password' => $configdata{'bind_pw'}) 
	|| die "could not authenticate with Cyrus IMAP daemon ($cyrus->{'error'})";

   # get LDAP user data for checking the mailboxes
   $mesg = $ldap->search(base=> $configdata{'base_dn'}, scope=> 'sub', filter=> '(uid=*)') 
	|| die "could not query LDAP for all uid's";
   if ($mesg->code > 0) {
      $opt_v && print "warning: could not find uid's in LDAP tree\n"; 
   } else {
      foreach $ldapobject ($mesg->entries) {
         my $uid = $ldapobject->get_value('uid');
         $uid = trim($uid);
         my $cyruid = "user.".$uid;
         my $deleteflag = $ldapobject->get_value('deleteflag');
         if (defined($deleteflag) && ($deleteflag =~ /true/i)) {
            $opt_v && print "removing mailbox $cyruid\n"; 
            $cyrus->setaclmailbox($cyruid, 'manager', 'c') 
		|| my_syslog("could not reset acl to delete imap user $cyruid");
            $cyrus->deletemailbox($cyruid) || my_syslog("could not delete imap user $cyruid");
            next;
         }
         my $mailbox = ($cyrus->listmailbox($cyruid))[0];
         if (($uid ne "manager") && !defined($mailbox)) {
            $opt_v && print "create mailbox for user $cyruid\n"; 
            $cyrus->createmailbox($cyruid) 
		|| die "could not create Cyrus mailbox for $cyruid ($cyrus->{'error'})";
         }
         my $quota = $ldapobject->get_value('userquota');
         if (defined($quota) && ($quota > 0)) {
            (my $root, my %quota) = $cyrus->quotaroot($cyruid);
            my $setquota = $quota{'STORAGE'}[1];
            if (!defined($setquota) || ($setquota != $quota)) {
               $opt_v && print "resetting quota for user $cyruid to $quota\n"; 
               $cyrus->setquota($cyruid, 'STORAGE', $quota) 
		|| die "could not set quota for $cyruid ($cyrus->{'error'})";
            }
         }
      }
   }

   # get shared folder configuration and check it against Cyrus
   $mesg = $ldap->search(base=> $configdata{'base_dn'}, scope=> 'sub', filter=> '(objectclass=sharedfolder)') 
	|| die "could not qeury LDAP for sharedfolder configuration";
   if ($mesg->code > 0) {
      $opt_v && print "warning: could not find shared folders in LDAP tree\n"; 
   } else {
      foreach $ldapobject ($mesg->entries) {
         my $folder = $ldapobject->get_value('cn');
         my $deleteflag = $ldapobject->get_value('deleteflag');
         $folder = trim($folder);
         my $cyrfolder = "user.".$folder;
         if (defined($deleteflag) && ($deleteflag =~ /true/i)) {
            $opt_v && print "removing shared folder $cyrfolder\n"; 
            $cyrus->setacl($cyrfolder, 'manager', 'c') 
		|| my_syslog("could not reset acl to delete imap $cyrfolder"); 
            $cyrus->delete($cyrfolder) 
		|| my_syslog("could not delete imap folder $cyrfolder");
            next;
         }
         my $fo = ($cyrus->list($cyrfolder))[0];
         if (!defined($fo)) {
            $opt_v && print "create folder: $cyrfolder\n"; 
            $cyrus->create($cyrfolder) 
		|| die "could not create Cyrus shared folder for $cyrfolder ($cyrus->{'error'})";
         }
         my $quota = $ldapobject->get_value('userquota');
         if (defined($quota) && ($quota > 0)) {
            (my $root, my %quota) = $cyrus->quotaroot($cyrfolder);
            my $setquota = $quota{'STORAGE'}[1];
            if (!defined($setquota) || ($setquota != $quota)) {
               $opt_v && print "resetting quota for shared folder $cyrfolder to $quota\n"; 
               $cyrus->setquota($cyrfolder, 'STORAGE', $quota) 
		|| die "could not set quota for folder $cyrfolder ($cyrus->{'error'})";
            }
         }
         # first reset current acl
         my @acl = `$kolab_prefix/etc/kolab/workaround.sh $cyrfolder $configdata{'bind_pw'} | sed -e /localhost/d`;
         foreach (@acl) {
            $_ = trim($_);
            (my $user, ) = split / /;
            $opt_v && print "remove acl $user from folder $cyrfolder\n";
            $cyrus->deleteacl($cyrfolder, $user) 
		|| my_syslog("could not remove acl from imap folder $cyrfolder ($cyrus->{'error'})");
         }
         #my %acl = $cyrus->listacl($folder) || print "imap folder $folder seems to not have acl\n";
         #foreach my $acl (keys %acl) {
         #   defined($opt_v) && print "remove acl $acl from folder $folder\n";
         #   $cyrus->deleteacl($folder, $acl) || print "could not remove acl from imap folder $folder ($cyrus->{'error'})\n";
         #}
         my $acls = $ldapobject->get_value('acl', asref => 1);
         foreach (@$acls) {
            (my $user, my $acl) = split (/ /,$_,2);
            $user = trim($user);
            $acl = trim($acl);
            $opt_v && print "set $cyrfolder acl to $user $acl\n"; 
            $cyrus->setacl($cyrfolder, $user, $acl); 
         }
      }
   } 

   # remove all LDAP objects marked for deletion
   $mesg = $ldap->search(base=> $configdata{'base_dn'}, scope=> 'sub', filter=> '(deleteflag=true)') 
   	|| my_syslog("could not query LDAP for to be deleted objects");
   if ($mesg->code <= 0) {
      foreach $ldapobject ($mesg->entries) {
         my $dn = $ldapobject->dn;
         $opt_v && print "removing $dn from ldap\n"; 
         $mesg = $ldap->delete($dn) || my_syslog("could not delete $dn");
      }
   }
   
   # find all aliases and put together the canonical map for postfix
   $confname = "$kolab_prefix/etc/postfix/canonical";
   $opt_v && print "appending ldap data to postfix canonical\n";
   my $canonical = IO::File->new($confname, "a") || die "could not write to $confname";
   $mesg = $ldap->search(base=> $configdata{'base_dn'}, scope=> 'sub', filter=> '(alias=*)'); 
   if ($mesg->code <= 0) {
      foreach $ldapobject ($mesg->entries) {
         my $mail = $ldapobject->get_value('mail');
         if (defined($mail)) {
            $mail = trim($mail);
            my $aliases = $ldapobject->get_value('alias', asref => 1);
            foreach (@$aliases) {
               $_ = trim($_);
               my $rule = $_."  ".$mail;
               defined($opt_v) && print "adding canonical entry '$rule'\n";
               print $canonical $rule."\n";
            }
         }   
      }
   } elsif ($opt_v) { print "warning: could not find any aliases in ldap\n"; }
   $canonical->close;
   system("$postmap $confname"); 

   $ldap->unbind;

} # while (1)

exit 0;

--------------Boundary-00=_AVP89J1SSKQ1I3JHKQO2
Content-Type: text/plain;
  charset="iso-8859-15";
  name="kolab.conf"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="kolab.conf"

base_dn : dc=dumbo
bind_dn : cn=manager,dc=dumbo
bind_pw : ZVFvrB9iy.O3I
ldap_uri : ldap://127.0.0.1:389

--------------Boundary-00=_AVP89J1SSKQ1I3JHKQO2--