#!/usr/bin/perl
# 
# ***** BEGIN LICENSE BLOCK *****
# Zimbra Collaboration Suite Server
# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc.
#
# 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,
# version 2 of the License.
#
# 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 should have received a copy of the GNU General Public License along with this program.
# If not, see <https://www.gnu.org/licenses/>.
# ***** END LICENSE BLOCK *****
# 

use strict;
use lib "/opt/zimbra/common/lib/perl5";
use Zimbra::Util::Common;
use File::Grep qw (fgrep);
use File::Path;
use Net::LDAP;
use Net::LDAP::LDIF;
use Net::LDAP::Entry;
use Crypt::SaltedHash;
use MIME::Base64;

my $source_config_dir = "/opt/zimbra/common/etc/openldap";
my $config_dir = "/opt/zimbra/conf";
my $ldap_config_dir="/opt/zimbra/data/ldap/config/cn\=config";

my $zimbra_user=getLocalConfig("zimbra_user");
my $zimbra_ldap_userdn = getLocalConfig("zimbra_ldap_userdn");
my $zimbra_ldap_password = getLocalConfig("zimbra_ldap_password");
my $ldap_root_password = getLocalConfig("ldap_root_password");
my $ldap_master_url = getLocalConfig("ldap_master_url");
my $ldap_is_master = getLocalConfig("ldap_is_master");
my $ldap_starttls_supported = getLocalConfig("ldap_starttls_supported");
my $zimbra_tmp_directory = getLocalConfig("zimbra_tmp_directory");

if (!-d $zimbra_tmp_directory) {
  File::Path::mkpath("$zimbra_tmp_directory");
}

# Get the SHA password.
my $ctx = Crypt::SaltedHash->new(algorithm => 'SHA-512', salt_len => '8');
$ctx->add("$ldap_root_password");
my $root_ssha_password = $ctx->generate;

$ctx = Crypt::SaltedHash->new(algorithm => 'SHA-512', salt_len => '8');
$ctx->add("$zimbra_ldap_password");
my $zimbra_ssha_password = $ctx->generate;

# Update cn=config
my $infile="$ldap_config_dir/olcDatabase\=\{0\}config.ldif";
my $outfile="$zimbra_tmp_directory/olcDatabase\=\{0\}config.ldif.$$";
my $mime_root_passwd=MIME::Base64::encode($root_ssha_password,"");
chomp ($mime_root_passwd);

open(IN,"<$infile");
open(OUT,">$outfile");
while (<IN>) {
  if ($_ =~ /^olcRootPW/) {
    $_ =~ s|^olcRootPW.*|olcRootPW:: $mime_root_passwd|;
    print OUT $_;
  } else {
    print OUT $_;
  }
}
close IN;
close OUT;
if ( -s $outfile ) {
  my $rc=0xffff & system("/bin/mv -f $outfile $infile");
  if ($rc != 0) {
    print "Warning: failed to write $infile\n";
  }
  qx(chown $zimbra_user:$zimbra_user $infile); 
  qx(chmod 600 $infile);
} else {
  print "Warning: Failed to update root password.\n";
}

# Update zimbra.ldif
unlink("${config_dir}/zimbra.ldif");

$infile = "$source_config_dir/zimbra/zimbra.ldif";
$outfile = "$config_dir/zimbra.ldif";
my $ldifin = Net::LDAP::LDIF->new( "$infile", "r", onerror => 'undef' );
my $ldifout = Net::LDAP::LDIF->new("$outfile", "w", onerror => 'undef' );
while( not $ldifin->eof()) {
  my $entry = $ldifin->read_entry ( );
  if ( $ldifin->error ( ) ) {
    print "Error msg: ", $ldifin->error ( ), "\n";
    print "Error lines:\n", $ldifin->error_lines ( ), "\n";
  } elsif ( $entry ) {
      if ($entry->dn() eq "uid=zimbra,cn=admins,cn=zimbra") {
        $entry->replace (
          userPassword => "${zimbra_ssha_password}",
        );
      }
    $ldifout->write($entry);
  }
}
$ldifin->done ( );
$ldifout->done ( );

exit 0;

sub getLocalConfig {
  my $key = shift;

  return $main::loaded{lc}{$key}
    if (exists $main::loaded{lc}{$key});

  my $val = qx(/opt/zimbra/bin/zmlocalconfig -x -s -m nokey ${key} 2> /dev/null);
  chomp $val;
  $main::loaded{lc}{$key} = $val;
  return $val;
}

