diff --git a/zmldapsync/zmldapsync.pl b/zmldapsync/zmldapsync.pl index 201cfa7..0ed14fd 100755 --- a/zmldapsync/zmldapsync.pl +++ b/zmldapsync/zmldapsync.pl @@ -16,7 +16,6 @@ use Email::MIME; use Email::Sender::Simple qw(sendmail); use Email::Sender::Transport::Sendmail; use utf8; -use Data::Dumper; # This is needed for Email::Sender::Simple # See https://rt.cpan.org/Public/Bug/Display.html?id=76533 @@ -114,8 +113,8 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { } else { handle_error( $domain, - 'Zimbra domain lookup', - "Domain $domain doesn't exist in Zimbra" + 'Zimbra domain lookup', + "Domain $domain doesn't exist in Zimbra" ); next DOMAIN; } @@ -143,8 +142,8 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { } else { handle_error( $domain, - 'Domain external auth check', - "domain $domain must be configured for LDAP or AD authentication first" + 'Domain external auth check', + "domain $domain must be configured for LDAP or AD authentication first" ); next DOMAIN; } @@ -197,7 +196,7 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { } log_verbose( "Trying to connect to " . - join( ' or ', @{ $conf->{domains}->{$domain}->{ldap}->{servers} } ) ); + join( ' or ', @{ $conf->{domains}->{$domain}->{ldap}->{servers} } ) ); my $ext_ldap = Net::LDAP->new( [ @{ $conf->{domains}->{$domain}->{ldap}->{servers} } ] ); if ( not $ext_ldap ) { @@ -248,8 +247,8 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { if ( $zim_aliases_search->code ) { handle_error( $domain, - 'Zimbra user and distribution lists alias lookup', - $zim_aliases_search->error + 'Zimbra user and distribution lists alias lookup', + $zim_aliases_search->error ); next DOMAIN; } @@ -257,10 +256,12 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { $zim_aliases->{$domain_alias} = ldap2hashref( $zim_aliases_search, 'uid' ); } - log_verbose( "Searching for potential users in " . - $conf->{domains}->{$domain}->{users}->{base} . - " matching filter " . - $conf->{domains}->{$domain}->{users}->{filter} ); + log_verbose( + "Searching for potential users in " . + $conf->{domains}->{$domain}->{users}->{base} . + " matching filter " . + $conf->{domains}->{$domain}->{users}->{filter} + ); # List of attributes to fetch from LDAP # First, we want all the attributes which are mapped to Zimbra fields @@ -291,8 +292,10 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { next DOMAIN; } - log_verbose( "Found " . scalar $ext_user_search->entries . - " users in external LDAP" ); + log_verbose( + "Found " . scalar $ext_user_search->entries . + " users in external LDAP" + ); log_verbose( "Searching for users in Zimbra" ); @@ -301,14 +304,18 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { base => 'ou=people,' . $domain_entry->{dn}, filter => '(&(objectClass=zimbraAccount)(!(zimbraIsSystemAccount=TRUE))(!(zimbraIsSystemResource=TRUE)))', attrs => [ - ( map { $conf->{domains}->{$domain}->{users}->{attr_map}->{$_} } - keys %{$conf->{domains}->{$domain}->{users}->{attr_map}} ), - ( 'uid', - 'zimbraAccountStatus', - 'zimbraAuthLdapExternalDn', - 'zimbraMailAlias', - 'mail', - 'zimbraNotes' ) + ( + map { $conf->{domains}->{$domain}->{users}->{attr_map}->{$_} } + keys %{$conf->{domains}->{$domain}->{users}->{attr_map}} + ), + ( + 'uid', + 'zimbraAccountStatus', + 'zimbraAuthLdapExternalDn', + 'zimbraMailAlias', + 'mail', + 'zimbraNotes' + ) ] ); if ( $zim_user_search->code ) { @@ -320,8 +327,10 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { next DOMAIN; } - log_verbose( "Found " . scalar $zim_user_search->entries . - " users in Zimbra" ); + log_verbose( + "Found " . scalar $zim_user_search->entries . + " users in Zimbra" + ); log_verbose( "Comparing the accounts" ); @@ -359,7 +368,7 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { # Except for sn which is mandatory in Zimbra log_verbose( "Attribute $attr for user $user removed from LDAP, removing it from Zimbra"); $attrs .= '-' . $conf->{domains}->{$domain}->{users}->{attr_map}->{$attr} . " " . - zim_attr_value( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} ); + zim_attr_value( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} ); } elsif ( ( $conf->{domains}->{$domain}->{users}->{attr_map}->{$attr} ne 'sn' and $ext_users->{$user}->{$attr} ne ( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} || '' ) @@ -369,11 +378,13 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { $ext_users->{$user}->{$attr} ne ( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} || '' ) ) { $attrs .= " " . $conf->{domains}->{$domain}->{users}->{attr_map}->{$attr} . " " . - zim_attr_value( $ext_users->{$user}->{$attr} ); - log_verbose( "Attribute $attr for user $user changed from " . - ( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} || 'an empty value' ). - " to " . - $ext_users->{$user}->{$attr} ); + zim_attr_value( $ext_users->{$user}->{$attr} ); + log_verbose( + "Attribute $attr for user $user changed from " . + ( $zim_users->{$user}->{$conf->{domains}->{$domain}->{users}->{attr_map}->{$attr}} || 'an empty value' ). + " to " . + $ext_users->{$user}->{$attr} + ); } } @@ -412,7 +423,7 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { not defined $ext_users->{$user}->{$conf->{domains}->{$domain}->{users}->{$mail_attr}} ); push @ext_aliases, ref $ext_users->{$user}->{$conf->{domains}->{$domain}->{users}->{$mail_attr}} eq 'ARRAY' ? @{ $ext_users->{$user}->{$conf->{domains}->{$domain}->{users}->{$mail_attr}} } : - $ext_users->{$user}->{$conf->{domains}->{$domain}->{users}->{$mail_attr}}; + $ext_users->{$user}->{$conf->{domains}->{$domain}->{users}->{$mail_attr}}; } @ext_aliases = uniq( sort @ext_aliases ); @@ -435,17 +446,23 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { foreach my $alias ( @{ $alias_diff->deleted } ) { my ( $al, $dom ) = split /\@/, $alias; - next if ( not defined $zim_aliases->{$dom} or - not defined $zim_aliases->{$dom}->{$al} ); - log_verbose( "Removing LDAP alias $alias from user $user " . - "as it doesn't exist in LDAP anymore" ); + next if ( + not defined $zim_aliases->{$dom} or + not defined $zim_aliases->{$dom}->{$al} + ); + log_verbose( + "Removing LDAP alias $alias from user $user " . + "as it doesn't exist in LDAP anymore" + ); send_zmprov_cmd( "removeAccountAlias $user\@$domain $alias" ); } my $note = $sync_from_ldap . "|LDAP_Aliases=" . join(',', @ext_aliases); if ( $note ne ($zim_users->{$user}->{zimbraNotes} || '') ) { - send_zmprov_cmd( "modifyAccount $user\@$domain zimbraNotes " . - zim_attr_value( $note ) ); + send_zmprov_cmd( + "modifyAccount $user\@$domain zimbraNotes " . + zim_attr_value( $note ) + ); } } @@ -458,8 +475,10 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { $zim_users->{$user}->{zimbraNotes} =~ m/^$sync_from_ldap/ and defined $zim_users->{$user}->{zimbraAccountStatus} and $zim_users->{$user}->{zimbraAccountStatus} =~ m/^active|lockout$/ ) { - log_verbose( "User $user doesn't exist in external LDAP anymore, " . - "locking it in Zimbra" ); + log_verbose( + "User $user doesn't exist in external LDAP anymore, " . + "locking it in Zimbra" + ); send_zmprov_cmd( "modifyAccount $user\@$domain zimbraAccountStatus locked" ); } } @@ -467,10 +486,11 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { # Now, we try to sync groups in external LDAP into distribution lists in Zimbra if ( defined $conf->{domains}->{$domain}->{groups} ) { - log_verbose( "Searching for potential groups in " . - $conf->{domains}->{$domain}->{groups}->{base} . - " matching filter " . - $conf->{domains}->{$domain}->{groups}->{filter} + log_verbose( + "Searching for potential groups in " . + $conf->{domains}->{$domain}->{groups}->{base} . + " matching filter " . + $conf->{domains}->{$domain}->{groups}->{filter} ); $fetch_attrs = [ keys %{$conf->{domains}->{$domain}->{groups}->{attr_map}} ]; @@ -492,8 +512,10 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { next DOMAIN; } - log_verbose( "Found " . scalar $ext_group_search->entries . - " groups in external LDAP" ); + log_verbose( + "Found " . scalar $ext_group_search->entries . + " groups in external LDAP" + ); log_verbose( "Searching for distribution lists in Zimbra" ); @@ -506,26 +528,28 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { keys %{$conf->{domains}->{$domain}->{groups}->{attr_map}} ), ( 'uid', - 'zimbraDistributionListSubscriptionPolicy', - 'zimbraDistributionListUnsubscriptionPolicy', + 'zimbraDistributionListSubscriptionPolicy', + 'zimbraDistributionListUnsubscriptionPolicy', 'zimbraMailForwardingAddress', - 'zimbraNotes', - 'zimbraMailStatus', - 'mail' + 'zimbraNotes', + 'zimbraMailStatus', + 'mail' ) ] ); if ( $zim_dl_search->code ) { handle_error( $domain, - 'Zimbra distribution lists lookup', - $zim_dl_search->error + 'Zimbra distribution lists lookup', + $zim_dl_search->error ); next DOMAIN; } - log_verbose( "Found " . scalar $zim_dl_search->entries . - " distribution list(s) in Zimbra" ); + log_verbose( + "Found " . scalar $zim_dl_search->entries . + " distribution list(s) in Zimbra" + ); log_verbose( "Comparing groups with distribution lists" ); my @single = keys %{$conf->{domains}->{$domain}->{groups}->{attr_map}}; @@ -570,8 +594,10 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { # Attr exists in both but doesn't match $attrs .= " " . ( $conf->{domains}->{$domain}->{groups}->{attr_map}->{$attr} || '' ) . " " . zim_attr_value( $ext_groups->{$group}->{$attr} ); - log_verbose( "Attribute $attr for group $group changed from " . ( $ext_groups->{$group}->{$attr} || 'an empty value' ) . " to " . - ( $zim_dl->{$group}->{$conf->{domains}->{$domain}->{groups}->{attr_map}->{$attr}} || 'an empty value' ) ); + log_verbose( + "Attribute $attr for group $group changed from " . ( $ext_groups->{$group}->{$attr} || 'an empty value' ) . " to " . + ( $zim_dl->{$group}->{$conf->{domains}->{$domain}->{groups}->{attr_map}->{$attr}} || 'an empty value' ) + ); } } @@ -587,7 +613,7 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { # If the group in LDAP has a mail defined, enable mail delivery in Zimbra. Else, disable it my $mail_status = ( defined $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{mail_attr}} ) ? - 'enabled' : 'disabled'; + 'enabled' : 'disabled'; if ( not defined $zim_dl->{$group}->{zimbraMailStatus} or $zim_dl->{$group}->{zimbraMailStatus} ne $mail_status ) { $attrs .= " zimbraMailStatus $mail_status"; @@ -660,7 +686,7 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { not defined $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{$mail_attr}} ); push @ext_aliases, ref $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{$mail_attr}} eq 'ARRAY' ? @{ $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{$mail_attr}} } : - $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{$mail_attr}}; + $ext_groups->{$group}->{$conf->{domains}->{$domain}->{groups}->{$mail_attr}}; } @ext_aliases = uniq( sort @ext_aliases ); foreach my $alias ( @ext_aliases ) { @@ -686,18 +712,24 @@ DOMAIN: foreach my $domain ( keys %{$conf->{domains}} ) { my $note = $sync_from_ldap . "|LDAP_Aliases=" . join(',', @ext_aliases); if ( $note ne ($zim_dl->{$group}->{zimbraNotes} || '') ) { - send_zmprov_cmd( "modifyDistributionList $group\@$domain zimbraNotes " . - zim_attr_value( $note ) ); + send_zmprov_cmd( + "modifyDistributionList $group\@$domain zimbraNotes " . + zim_attr_value( $note ) + ); } } # Now, look at all the distribution list which were created from LDAP but doesn't exist anymore in LDAP foreach my $dl ( keys %{$zim_dl} ) { - next if ( not defined $zim_dl->{$dl}->{zimbraNotes} or - $zim_dl->{$dl}->{zimbraNotes} !~ m/^$sync_from_ldap/ ); + next if ( + not defined $zim_dl->{$dl}->{zimbraNotes} or + $zim_dl->{$dl}->{zimbraNotes} !~ m/^$sync_from_ldap/ + ); next if ( defined $ext_groups->{$dl} ); - log_verbose( "Group $dl doesn't exist in LDAP anymore, " . - "removing the corresponding distribution list" ); + log_verbose( + "Group $dl doesn't exist in LDAP anymore, " . + "removing the corresponding distribution list" + ); send_zmprov_cmd( "deleteDistributionList $dl\@$domain" ); } }