From 14b65713bd9da75f1f79a6740cb2944bc7d725b1 Mon Sep 17 00:00:00 2001
From: Thibault Dockx <thibault.dockx@fusiondirectory.org>
Date: Tue, 31 Jan 2023 11:41:24 +0000
Subject: [PATCH] :sparkles: Feat(Core) - Removes Perl script setup.

Removes the perl fusiondirectory-setup.
It exists in PHP within Tool repo.
---
 contrib/bin/fusiondirectory-setup | 2332 -----------------------------
 1 file changed, 2332 deletions(-)
 delete mode 100644 contrib/bin/fusiondirectory-setup

diff --git a/contrib/bin/fusiondirectory-setup b/contrib/bin/fusiondirectory-setup
deleted file mode 100644
index c240f003f..000000000
--- a/contrib/bin/fusiondirectory-setup
+++ /dev/null
@@ -1,2332 +0,0 @@
-#!/usr/bin/perl
-
-########################################################################
-#
-#  fusiondirectory-setup
-#
-#  Manage fusiondirectory installs from the command line
-#
-#  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
-#  Copyright (C) 2011-2018  FusionDirectory
-#
-#  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 of the License, 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 should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-########################################################################
-
-use strict;
-use warnings;
-use 5.008;
-
-# used to manage files
-use Path::Class;
-
-# used for checking config dirs rights (make the translation for lstat output)
-use Fcntl ':mode';
-
-# used to handle ldap connections
-use Net::LDAP;
-
-# used to base64 encode
-use MIME::Base64;
-
-# used to generate {SSHA} password (for LDAP)
-use Digest::SHA;
-use Crypt::CBC;
-use Bytes::Random::Secure qw(random_string_from);
-
-# used to uncompress tar.gz
-use Archive::Extract;
-
-# used to copy files
-use File::Copy::Recursive qw(rcopy);
-
-#XML parser
-use XML::Twig;
-
-# To hide password input
-use Term::ReadKey;
-
-use Data::Dumper;
-
-# fd's directory and class.cache file's path declaration
-my %vars = (
- fd_home          => "/var/www/fusiondirectory",
- fd_cache         => "/var/cache/fusiondirectory",
- fd_config_dir    => "/etc/fusiondirectory",
- fd_smarty_path   => "/usr/share/php/smarty3/Smarty.class.php",
- fd_spool_dir     => "/var/spool/fusiondirectory",
- ldap_conf        => "/etc/ldap/ldap.conf",
- config_file      => "fusiondirectory.conf",
- secrets_file     => "fusiondirectory.secrets",
- locale_dir       => "locale",
- class_cache      => "class.cache",
- locale_cache_dir => "locale",
- tmp_dir          => "tmp",
- fai_log_dir      => "fai",
- template_dir     => "template"
-);
-
-my ($fd_config,$fd_secrets,$locale_dir,$class_cache,$locale_cache_dir,$tmp_dir,$fai_log_dir,$template_dir);
-
-my (@root_config_dirs,@apache_config_dirs,@config_dirs);
-
-my @plugin_types = qw(addons admin personal);
-my $yes_flag = 0;
-
-my %classes_hash_result = ();
-my %i18n_hash_result = ();
-
-my $configrdn   = "cn=config,ou=fusiondirectory";
-my $userrdn     = "ou=people";
-my $aclrolerdn  = "ou=aclroles";
-my $grouprdn    = "ou=groups";
-my $systemrdn   = "ou=systems";
-my $dnsrdn      = "ou=dns";
-my $dhcprdn     = "ou=dhcp";
-my $workstationrdn  = "ou=workstations,ou=systems";
-my $winstationrdn   = "ou=computers,ou=systems";
-
-#################################################################################################################################################
-
-# ask a question send as parameter, and return true if the answer is "yes"
-sub ask_yn_question {
-  return 1 if ($yes_flag);
-  my ($question) = @_;
-  print ( "$question [Yes/No]?\n" );
-
-  while ( my $input = <STDIN> ) {
-    # remove the \n at the end of $input
-    chomp $input;
-
-    # if user's answer is "yes"
-    if ( lc($input) eq "yes" || lc($input) eq "y") {
-      return 1;
-    # else if he answer "no"
-    } elsif ( lc($input) eq "no" || lc($input) eq "n") {
-      return 0;
-    }
-  }
-}
-
-# function that ask for an user input and do some checks
-sub ask_user_input {
- my ($thing_to_ask, $default_answer, $hide_input) = @_;
- my $answer;
-
- if (defined $default_answer) {
-   $thing_to_ask .= " [$default_answer]";
- }
- print $thing_to_ask.":\n";
-
- if (defined $hide_input && $hide_input) {
-   ReadMode('noecho');
- }
-
- do
- {
-   if ($answer = <STDIN>) {
-     chomp $answer;
-     $answer =~ s/^\s+|\s+$//g;
-   } else {
-     $answer = "";
-   }
- } while (($answer eq "") && (not defined $default_answer));
-
- ReadMode('restore');
-
- if ($answer eq "") {
-   return $default_answer;
- }
- return $answer;
-}
-
-# Die on all LDAP error except for «No such object»
-sub die_on_ldap_errors
-{
-  my ($mesg) = @_;
-  if (($mesg->code != 0) && ($mesg->code != 32)) {
-    die $mesg->error;
-  }
-}
-
-{
-  my $indice = 0;
-  sub find_free_role_dn {
-    my ($ldap,$base,$prefix) = @_;
-    my ($cn,$dn,$mesg);
-    do {
-      $cn = $prefix.'-'.$indice;
-      $dn = "cn=$cn,$aclrolerdn,$base";
-      $indice++;
-      $mesg = $ldap->search(
-        base    => "$dn",
-        scope   => 'base',
-        filter  => '(objectClass=*)'
-      );
-      die_on_ldap_errors($mesg);
-    } while ($mesg->count);
-    return $cn;
-  }
-}
-
-sub create_role {
-  my ($ldap,$base,$cn,$acl) = @_;
-  my %role = (
-    'cn'              => "$cn",
-    'objectclass'     => [ 'top', 'gosaRole' ],
-    'gosaAclTemplate' => "0:$acl"
-  );
-
-  if (!branch_exists($ldap, "$aclrolerdn,$base")) {
-    create_branch($ldap, $base, $aclrolerdn);
-  }
-
-  my $role_dn = "cn=$cn,$aclrolerdn,$base";
-  # Add the administator role object
-  my @options = %role;
-  my $role_add = $ldap->add( $role_dn, attr => \@options );
-  # send a warning if the ldap's admin's add didn't gone well
-  $role_add->code && die "\n! failed to add LDAP's $role_dn entry - ".$role_add->error_name.": ".$role_add->error_text;
-  return $role_dn;
-}
-
-###################################################### Password encryption #########################################################################
-
-sub cred_encrypt {
-  my ($input, $password) = @_;
-  my $cipher = Crypt::CBC->new(
-                -key    =>  $password,
-                -cipher => 'Rijndael',
-                -salt   => 1,
-                -header => 'salt',
-              ) || die "Couldn't create CBC object";
-  return $cipher->encrypt_hex($input);
-}
-
-sub cred_decrypt {
-  my ($input, $password) = @_;
-  my $cipher = Crypt::CBC->new(
-                -key    =>  $password,
-                -cipher => 'Rijndael',
-                -salt   => 1,
-                -header => 'salt',
-              ) || die "Couldn't create CBC object";
-  return $cipher->decrypt_hex($input);
-}
-
-sub get_random_string {
-  my ($size) = @_;
-  $size = 32 if !$size;
-  my @chars = ("A".."Z", "a".."z", '.', '/', 0..9);
-  return random_string_from(join('', @chars), $size);
-}
-
-sub encrypt_passwords {
-  if (!-e $fd_config) {
-    die "Cannot find a valid configuration file ($fd_config)!\n";
-  }
-  if (-e $fd_secrets) {
-    die "There's already a file '$fd_secrets'. Cannot convert your existing fusiondirectory.conf - aborted\n";
-  }
-  print "Starting password encryption\n";
-  print "* generating random master key\n";
-  my $master_key = get_random_string();
-  print "* creating '$fd_secrets'\n";
-  my $fp_file = file($fd_secrets);
-  my $fp = $fp_file->openw() or die "! Unable to open '$fd_secrets' in write mode\n";
-  $fp->print("RequestHeader set FDKEY $master_key\n");
-  $fp->close or die "! Can't close '$fd_secrets'\n";
-  chmod 0600, $fd_secrets or die "! Unable to change '$fd_secrets' rights\n";
-  my $root_uid = getpwnam("root");
-  my $root_gid = getgrnam("root");
-  chown $root_uid,$root_gid,$fd_secrets or die "! Unable to change '$fd_secrets' owner\n";
-
-  # Move original fusiondirectory.conf out of the way and make it unreadable for the web user
-  print "* creating backup in '$fd_config.orig'\n";
-  rcopy($fd_config, "$fd_config.orig");
-  chmod 0600, "$fd_config.orig" or die "! Unable to change '$fd_config.orig' rights\n";
-  chown $root_uid,$root_gid,"$fd_config.orig" or die "! Unable to change '$fd_config.orig' owner\n";
-
-  print "* loading '$fd_config'\n";
-  my $twig = XML::Twig->new();    # create the twig
-  $twig->parsefile($fd_config); # build it
-  # Locate all passwords inside the fusiondirectory.conf
-  my @locs = $twig->root->first_child('main')->children('location');
-  foreach my $loc (@locs) {
-    my $ref = $loc->first_child('referral');
-    print "* encrypting FusionDirectory password for: ".$ref->{'att'}->{'adminDn'}."\n";
-    $ref->set_att('adminPassword' => cred_encrypt($ref->{'att'}->{'adminPassword'}, $master_key));
-  }
-
-  # Save
-  print "* saving modified '$fd_config'\n";
-  $twig->print_to_file($fd_config, pretty_print => 'indented') or die "Cannot write modified $fd_config - aborted\n";
-  print "OK\n\n";
-
-  # Print reminder
-  print "
-Please adapt your http fusiondirectory declaration to include the newly
-created $fd_secrets.
-
-Example:
-
-# Include FusionDirectory to your web service
-Alias /fusiondirectory $vars{fd_home}/html
-
-<Directory $vars{fd_home}/html>
-  # Include the secrects file
-  include $fd_secrets
-</Directory>
-
-
-Please reload your httpd configuration after you've modified anything.\n";
-}
-
-sub show_passwords {
-  if (!-e $fd_config) {
-    die "Cannot find a valid configuration file ($fd_config)!\n";
-  }
-  my $secret;
-  if (-e $fd_secrets) {
-    open(my $secrets, q{<}, $fd_secrets) || die ("Could not open $fd_secrets");
-    while(<$secrets>) {
-      if ($_ =~ m/RequestHeader set FDKEY ([^ \n]+)\n/) {
-        $secret = $1;
-        last;
-      }
-    }
-    close($secrets);
-  }
-
-  my $locations = get_locations_from_config_file();
-
-  while ( my($key,$location) = each %$locations ) {
-    my ($uri,$base);
-    if ($location->{'base'} ne '') {
-      $uri  = $location->{'uri'};
-      $base = $location->{'base'};
-    } elsif ($location->{'uri'} =~ qr|^(.*)/([^/]+)$|) {
-      # Format from FD<1.3
-      $uri  = $1;
-      $base = $2;
-    } else {
-      die '"'.$location->{'uri'}.'" does not contain any base!';
-    }
-    my $bind_pwd = $location->{'bind_pwd'};
-    if (defined $secret) {
-      $bind_pwd = cred_decrypt($bind_pwd, $secret);
-    }
-    printf("Location \"%s\":\n", $key);
-    printf(" %-15s%s\n", 'URI',           $uri);
-    printf(" %-15s%s\n", 'Base',          $base);
-    printf(" %-15s%s\n", 'Bind DN',       $location->{'bind_dn'});
-    printf(" %-15s%s\n", 'Bind password', $bind_pwd);
-    printf(" %-15s%s\n", 'TLS',           $location->{'tls'});
-  }
-}
-
-####################################################### class.cache update #########################################################################
-
-# function that scan recursivly a directory to find .inc and . php
-# then return a hash with class => path to the class file
-sub get_classes {
-
-    my ($path) = @_;
-
-    # if this function has been called without a parameter
-    die ("! function get_classes called without parameter\n") if ( !defined($path) );
-
-    # create a "dir" object with the path
-    my $dir = dir ($path) or die ("! Can't open $path\n");
-
-    my $contrib_dir = dir($vars{fd_home},"contrib");
-    if ("$dir" eq "$contrib_dir") {
-        return;
-    }
-
-    # create an array with the content of $dir
-    my @dir_files = $dir->children;
-
-    foreach my $file (@dir_files) {
-        # recursive call if $file is a directory
-        if ( -d $file ) {
-            get_classes($file);
-            next;
-        }
-
-        # only process if $file is a .inc or a .php file
-        if ( ( $file =~ /.*\.inc$/ ) && ( $file !~ /.*smarty.*/ ) ) {
-          # put the entire content of the file pointed by $file in $data
-          my @lines = $file->slurp;
-
-          # modifing $file, to contains relative path, not complete one
-          $file =~ s/^$vars{fd_home}//;
-
-          foreach my $line ( @lines ) {
-            # remove \n from the end of each line
-            chomp $line;
-
-            # process for lines beginning with "class", and extracting the 2nd word (the class name)
-            if ( $line =~ /^(abstract )?class\s*(\w+).*/ ) {
-              # adding the values (class name and file path) to the hash
-              $classes_hash_result{$2} = $file;
-            }
-
-            # process for lines beginning with "interface", and extracting the 2nd word (the interface name)
-            if ( $line =~ /^interface\s*(\w+).*/ ) {
-              # adding the values (class name and file path) to the hash
-              $classes_hash_result{$1} = $file;
-            }
-          }
-        }
-    }
-    return %classes_hash_result;
-}
-
-# call get_classes and create /var/cache/fusiondirectory/class.cache
-sub rescan_classes {
-
-  # hash that will contain the result of the "get_classes" function
-  my %get_classes_result = get_classes ($vars{fd_home});
-
-  # create a "file" object with the $class_cache path
-  my $file_class = file ($class_cache);
-
-  # create the handler (write mode) for the file previoulsy created
-  my $fhw = $file_class->openw() or die ("! Unable to open $class_cache in write mode\n");
-
-  # first lines of class.cache
-  $fhw->print ("<?php\n\t\$class_mapping= array(\n");
-
-  # for each $key/$value, writting a new line to $class_cache
-  while ( my($key,$value) = each %get_classes_result ) {
-    $fhw->print ("\t\t\"$key\" => \"$value\",\n");
-  }
-
-  # last line of classe.cache
-  $fhw->print ("\t);\n?>");
-
-  $fhw->close or die ("! Can't close $class_cache\n");
-}
-
-###################################################### Internalisation's update ####################################################################################
-
-# function that create .mo files with .po for each language
-sub get_i18n {
-
-    my ($path) = @_;
-
-    # if this function has been called without a parameter
-    die ("! function get_i18n called without parameter" ) if ( !defined($path) );
-
-    # create a "dir" object
-    my $dir = dir ($path) or die ("! Can't open $path\n");
-
-    # create an array with the content of $dir
-    my @dir_files = $dir->children;
-
-    foreach my $file (@dir_files) {
-      # recursive call if $file is a directory
-      if (-d $file) {
-        %i18n_hash_result = get_i18n ($file);
-        next;
-      }
-
-      # if the file's directory is ???/language/fusiondirectory.po
-      if ($file =~ qr{^.*/(\w+)/fusiondirectory.po$}) {
-        # push the file's path in the language (fr/en/es/it...) array (wich is inside the hash pointed by $ref_result
-        push @{$i18n_hash_result{$1}}, $file;
-      }
-    }
-  return %i18n_hash_result;
-}
-
-# call get_i18n with the FusionDirectory's locales's directory and the hash that will contain the result in parameter
-sub rescan_i18n {
-
-  # hash that will contain the result of the "get_i18n" function
-  my %get_i18n_result = get_i18n ($locale_dir);
-
-  while ( my ($lang, $files) = each %get_i18n_result ) {
-
-    # directory wich will contain the .mo file for each language
-    my $lang_cache_dir = dir ("$locale_cache_dir/$lang/LC_MESSAGES");
-
-    # if $lang_cache_dir doesn't already exists, creating it
-    if ( !-d $lang_cache_dir ) {
-      $lang_cache_dir->mkpath or die ("! Can't create $locale_cache_dir/$lang/LC_MESSAGES");
-    }
-
-    # glue .po files's names
-    my $po_files = join(" ", @{$files});
-    chomp $po_files;
-
-    # merging .po files
-    system ( "msgcat --use-first ".$po_files.">".$lang_cache_dir."/fusiondirectory.po" ) and die ("! Unable to merge .po files for $lang with msgcat, is it already installed?\n");
-
-    # compiling .po files in .mo files
-    system ( "msgfmt -o $lang_cache_dir/fusiondirectory.mo $lang_cache_dir/fusiondirectory.po && rm $lang_cache_dir/fusiondirectory.po" ) and die ("! Unable to compile .mo files with msgfmt, is it already installed?\n");
-  }
-}
-
-############################################################# Directories checking ###################################################################################
-
-#get the apache user group name
-sub get_apache_group {
-  my $apache_group = "";
-
-  # try to identify the running distribution, if it's not debian or rehat like, script ask for user input
-  if (-e "/etc/debian_version") {
-    $apache_group = "www-data";
-  } elsif ((-e "/etc/redhat-release") || (-e "/etc/mageia-release")) {
-    $apache_group = "apache";
-  } elsif (-e "/etc/SuSE-release") {
-    $apache_group = "www";
-  } elsif (-e "/etc/arch-release") {
-    $apache_group = "http";
-  } else {
-    print ("! Looks like you are not a Debian, Suse, Redhat or Mageia, I don't know your distribution !\n");
-    $apache_group = ask_user_input ("What is your apache group?");
-  }
-  return $apache_group;
-}
-
-#check the rights of a directory or file, creates missing directory if needed
-sub check_rights {
-  my ($dir,$user,$group,$rights,$create) = @_;
-  my $user_uid = getpwnam ( $user );
-  my $group_gid = getgrnam ( $group );
-
-  # if the current dir exists
-  if (-e $dir) {
-    print("$dir exists...\n");
-    # retrieve dir's informations
-    my @lstat = lstat ($dir);
-
-    # extract the owner and the group of the directory
-    my $dir_owner = getpwuid ( $lstat[4] );
-    my $dir_group = getgrgid ( $lstat[5] );
-
-    # extract the dir's rights
-    my $dir_rights = S_IMODE( $lstat[2] );
-
-    if ( ($dir_owner ne $user) || ($dir_group ne $group) || ($dir_rights ne $rights) ) {
-      if ( ask_yn_question ("$dir is not set properly, do you want to fix it ?: ") ) {
-        chown ($user_uid,$group_gid,$dir) or die ("! Unable to change $dir owner\n") if ( ($dir_owner ne $user) || ($dir_group ne $group) );
-        chmod ( $rights, $dir ) or die ("! Unable to change $dir rights\n") if ($dir_rights ne $rights);
-      } else {
-        print ("Skipping...\n");
-      }
-    } else {
-      print("Rights on $dir are correct\n");
-    }
-  } elsif ($create) {
-
-    if ( ask_yn_question("Directory $dir doesn't exist, do you want to create it ?: ") ) {
-      my $conf_dir = dir ($dir);
-
-      # create the directory, and change the rights
-      $conf_dir->mkpath (0,$rights);
-      chmod ($rights, $dir);
-      chown ($user_uid,$group_gid,$dir) or die ("Unable to change $dir rights\n");
-
-    } else {
-      print ( "Skipping...\n" );
-    }
-  } else {
-    return 0;
-  }
-  return 1;
-}
-
-# function that check FusionDirectory's directories
-sub check_directories {
-  my $apache_group = get_apache_group();
-
-  # for each config directory
-  foreach my $dir (@config_dirs) {
-
-      # if $dir is one of the dirs that remains to root
-      if ( grep (/.*$dir.*/, @root_config_dirs) ) {
-        check_rights($dir,"root","root",oct(755),1);
-
-      # else if $dir is one of the dirs that remains to apache's user group, and the dir's owner is not root or the group is not the apache's user group, modifying owner
-      } elsif ( grep ( /.*$dir.*/, @apache_config_dirs) ) {
-        check_rights($dir,"root",$apache_group,oct(770),1);
-      }
-  }
-}
-
-# function that check FusionDirectory's config file
-sub check_config {
-  my $apache_group = get_apache_group();
-
-  # check config file
-  check_rights($fd_config,"root",$apache_group,oct(640),0) or die 'The config file does not exist!';
-}
-
-############################################################# Change install directories #################################################################################
-
-sub write_vars {
-  my $filecontent = <<eof;
-<?php
-require_once('variables_common.inc');
-
-/*! \\file
- * Define common locations and variables
- * Generated by fusiondirectory-setup */
-
-if (!defined("CONFIG_DIR")) {
-  define ("CONFIG_DIR", "$vars{fd_config_dir}/"); /* FusionDirectory etc path */
-}
-
-/* Allow setting the config file in the apache configuration
-    e.g.  SetEnv CONFIG_FILE fusiondirectory.conf 1.0
- */
-if (!defined("CONFIG_FILE")) {
-  define ("CONFIG_FILE", "$vars{config_file}"); /* FusionDirectory filename */
-}
-
-/* Path for smarty3 libraries */
-define("SMARTY", "$vars{fd_smarty_path}");
-
-/* Smarty compile dir */
-define ("SPOOL_DIR", "$vars{fd_spool_dir}/"); /* FusionDirectory spool directory */
-
-/* Global cache dir */
-define ("CACHE_DIR", "$vars{fd_cache}/"); /* FusionDirectory var directory */
-
-/* Global locale cache dir */
-define ("LOCALE_DIR", "$locale_cache_dir/"); /* FusionDirectory locale directory */
-
-/* Global tmp dir */
-define ("TEMP_DIR", "$tmp_dir/"); /* FusionDirectory tmp directory */
-
-/* Directory containing the configuration template */
-define ("CONFIG_TEMPLATE_DIR", "$template_dir/"); /* FusionDirectory template directory */
-
-/* Directory containing the fai logs */
-define ("FAI_LOG_DIR", "$fai_log_dir/"); /* FusionDirectory fai directory */
-
-/* Directory containing the supann files */
-define ("SUPANN_DIR", "$vars{fd_config_dir}/supann/"); /* FusionDirectory supann template directory */
-
-/* name of the class.cache file */
-define("CLASS_CACHE", "$vars{class_cache}"); /* name of the class cache */
-?>
-eof
-
-  my $variables_path = "$vars{fd_home}/include/variables.inc";
-  my $variables_file = file ($variables_path);
-  my $vars_file = $variables_file->openw() or die ("! Unable to open $variables_path in write mode\n");
-  $vars_file->print($filecontent);
-  $vars_file->close or die ("! Can't close $variables_file\n");
-}
-
-############################################################# LDAP conformity check #################################################################################
-
-# function that add the FusionDirectory's admin account
-# return nothing is it a problem?
-sub add_ldap_admin {
-  my ($base, $ldap, $admindns, $people_entries, $roles) = @_;
-
-  # Get the configuration to know which attribute must be used in the dn
-  my $mesg = $ldap->search(
-    base => "$configrdn,$base",
-    filter => '(objectClass=fusionDirectoryConf)',
-    scope => 'base',
-    attrs => ['fdAccountPrimaryAttribute', 'fdForcePasswordDefaultHash', 'fdPasswordDefaultHash']
-  );
-  $mesg->code && die $mesg->error;
-  my $attr;
-  if ($mesg->count <= 0) {
-    print "Could not find configuration object, using default value\n";
-    $attr = 'uid';
-  } elsif (($mesg->entries)[0]->exists('fdAccountPrimaryAttribute')) {
-    $attr = ($mesg->entries)[0]->get_value('fdAccountPrimaryAttribute');
-  } else {
-    $attr = 'uid';
-  }
-  if ($mesg->count > 0) {
-    if (($mesg->entries)[0]->exists('fdForcePasswordDefaultHash') && ($mesg->entries)[0]->exists('fdPasswordDefaultHash')) {
-      if ((($mesg->entries)[0]->get_value('fdForcePasswordDefaultHash') eq 'TRUE') &&
-          (($mesg->entries)[0]->get_value('fdPasswordDefaultHash') ne 'ssha')) {
-        warn "Warning: Administrator password will be hashed with ssha instead of forced default ".($mesg->entries)[0]->get_value('fdPasswordDefaultHash')."\n";
-      }
-    }
-  }
-
-  my $fd_admin_uid = ask_user_input ("Please enter a login for FusionDirectory's admin", "fd-admin");
-  # Does this user exist?
-  my $dn = "";
-  foreach my $entry (@$people_entries) {
-    my $mesg = $ldap->search(
-      base => "$entry",
-      filter => "(&(objectClass=inetOrgPerson)(uid=$fd_admin_uid))",
-      attrs => ['uid']
-    );
-    $mesg->code && die $mesg->error;
-    if ($mesg->count) {
-      print "User $fd_admin_uid already existing, adding admin acl to it\n";
-      $dn = ($mesg->entries)[0]->dn;
-      last;
-    }
-  }
-
-  if ($dn eq "") {
-    my $fd_admin_pwd = ask_user_input ("Please enter FusionDirectory's admin password", undef, 1);
-    my $fd_admin_pwd_confirm = ask_user_input ("Please enter it again", undef, 1);
-
-    # while the confirmation password is not the same than the first one
-    while ( ($fd_admin_pwd_confirm ne $fd_admin_pwd) && ($fd_admin_pwd_confirm ne "quit" ) ) {
-      $fd_admin_pwd_confirm = ask_user_input ("! Inputs don't match, try again or type 'quit' to end this function");
-    }
-    return -1 if ($fd_admin_pwd_confirm eq "quit");
-
-    my $ctx = Digest::SHA->new(1);
-    my $salt = get_random_string(8);
-    $ctx->add($fd_admin_pwd);
-    $ctx->add($salt);
-    my $hashedPasswd = '{SSHA}'.encode_base64($ctx->digest.$salt, '');
-    my %obj = (
-      'cn'  =>  'System Administrator',
-      'sn'  =>  'Administrator',
-      'uid' =>  $fd_admin_uid,
-      'givenname'     =>  'System',
-      'objectclass'   =>  [ 'top', 'person', 'organizationalPerson', 'inetOrgPerson' ],
-      'userPassword'  =>  $hashedPasswd
-    );
-    if (not defined $obj{$attr}) {
-      print "Error : invalid account primary attribute $attr, using uid\n";
-      $attr = 'uid';
-    }
-    $dn = "$attr=".$obj{$attr}.",$userrdn,$base";
-
-    # Add the administator user object
-    my @options = %obj;
-    my $admin_add = $ldap->add( $dn, attr => \@options );
-    # send a warning if the ldap's admin's add didn't gone well
-    $admin_add->code && die "\n! failed to add LDAP's $dn entry - ".$admin_add->error_name.": ".$admin_add->error_text;
-  }
-
-  # Create admin role if not existing
-  my $role;
-  if (scalar @$roles == 0) {
-    my $role_dn = create_role($ldap,$base,'admin','all;cmdrw');
-    $role = encode_base64($role_dn, '');
-  } else {
-    $role = shift(@$roles);
-  }
-
-  # Add the assignment that make him an administrator
-  my $acls = $ldap->search (
-    base    => "$base",
-    scope   => 'base',
-    filter  => "(objectClass=*)",
-    attrs   => ['objectClass', 'gosaAclEntry']
-  );
-  $acls->code && die "\n! failed to search acls in '$base' - ".$acls->error_name.": ".$acls->error_text;
-  ($acls->count == 0) && die "\n! failed to search acls in '$base' - base not found";
-  my $oclass = ($acls->entries)[0]->get_value("objectClass", asref => 1);
-  # Add admin acl
-  my $newacl = ["0:subtree:$role:".encode_base64($dn, '')];
-  if (not (grep $_ eq 'gosaAcl', @$oclass)) {
-    push (@$oclass, 'gosaAcl');
-  } else {
-    my $acl = ($acls->entries)[0]->get_value("gosaAclEntry", asref => 1);
-    my $i = 1;
-    if (defined $acl) {
-      foreach my $line (@$acl) {
-        # Reorder existing non-admin acls
-        $line =~ s/^\d+:/$i:/;
-        push (@$newacl, $line);
-        $i++;
-      }
-    }
-  }
-  my $result = $ldap->modify (
-    $base,
-    replace => {
-      'objectClass'   => $oclass,
-      'gosaAclEntry'  => $newacl
-    }
-  );
-  $result->code && warn "\n! failed to add ACL for admin on '$base' - ".$result->error_name.": ".$result->error_text;
-}
-
-sub get_locations_from_config_file
-{
-  my $twig = XML::Twig->new();
-  $twig->safe_parsefile($fd_config) or die("There is an error in $fd_config XML code: ".(split /\n/, $@)[1]."\n");
-  my @locs = $twig->root->first_child('main')->children('location');
-  my %locations = ();
-  foreach my $loc (@locs) {
-    $loc->lc_attnames();
-    my $ref = $loc->first_child('referral');
-    # Ignore case
-    $ref->lc_attnames();
-    $locations{$loc->{'att'}->{'name'}} = {
-      'tls'       => 0,
-      'uri'       => $ref->{'att'}->{'uri'},
-      'base'      => ($ref->{'att'}->{'base'} or $loc->{'att'}->{'base'} or ''),
-      'bind_dn'   => $ref->{'att'}->{'admindn'},
-      'bind_pwd'  => $ref->{'att'}->{'adminpassword'}
-    };
-    if (defined $loc->{'att'}->{'ldaptls'} and $loc->{'att'}->{'ldaptls'} =~ m/true/i) {
-      $locations{$loc->{'att'}->{'name'}}->{'tls'} = 1
-    }
-  }
-  return \%locations;
-}
-
-# function that initiate the ldap connexion, and bind as the ldap's admin
-sub get_ldap_connexion {
-  my %hash_result = ();
-  my $bind_dn = "";
-  my $bind_pwd = "";
-  my $uri = "";
-  my $base = "";
-  my $tls = 0;
-
-  # read ldap's server's info from /etc/fusiondirectory/fusiondirectory.conf
-  if (-e $fd_config) {
-    my $locations = get_locations_from_config_file();
-
-    my ($location) = keys(%$locations);
-    if (scalar(keys(%$locations)) > 1) {
-      my $question = "There are several locations in your config file, which one should be used : (".join(',',keys(%$locations)).")";
-      my $answer;
-      do {
-        $answer = ask_user_input ($question, $location);
-      } while (not exists($locations->{$answer}));
-      $location = $answer;
-    }
-
-    if ($locations->{$location}->{'base'} ne '') {
-      $uri  = $locations->{$location}->{'uri'};
-      $base = $locations->{$location}->{'base'};
-    } elsif ($locations->{$location}->{'uri'} =~ qr|^(.*)/([^/]+)$|) {
-      # Format from FD<1.3
-      $uri  = $1;
-      $base = $2;
-    } else {
-      die '"'.$locations->{$location}->{'uri'}.'" does not contain any base!';
-    }
-    $bind_dn  = $locations->{$location}->{'bind_dn'};
-    $bind_pwd = $locations->{$location}->{'bind_pwd'};
-    $tls      = $locations->{$location}->{'tls'};
-
-  # if can't find fusiondirectory.conf
-  } else {
-
-    if ( ask_yn_question ("Can't find fusiondirectory.conf, do you want to specify LDAP's information yourself ?: ") ) {
-      $uri = ask_user_input ("LDAP server's URI");
-      $base = ask_user_input ("Search base");
-      $hash_result{base} = $base;
-
-      $bind_dn = ask_user_input ("Bind DN");
-      $bind_pwd = ask_user_input("Bind password", undef, 1);
-    } else {
-      return;
-    }
-  }
-
-  # ldap connection
-  my $ldap = Net::LDAP->new ($uri) or die ("! Can't contact LDAP server $uri\n");
-
-  $hash_result{ldap} = $ldap;
-  $hash_result{base} = $base;
-
-  # bind to the LDAP server
-  if (-e $fd_secrets) {
-    open(my $secrets, q{<}, $fd_secrets) || die ("Could not open $fd_secrets");
-    my $key = "";
-    while(<$secrets>) {
-      if ($_ =~ m/RequestHeader set FDKEY ([^ \n]+)\n/) {
-        $key = $1;
-        last;
-      }
-    }
-    close($secrets);
-    $bind_pwd = cred_decrypt($bind_pwd, $key);
-  }
-
-  if ($tls) {
-    # Read LDAP config file
-    open (my $ldapconf, q{<}, $vars{ldap_conf}) or die ("! Failed to open ldap config file '$vars{ldap_conf}': $!\n");
-
-    my %tls_options = (
-      'REQCERT'   => 'require',
-      'CERT'      => '',
-      'KEY'       => '',
-      'CACERTDIR' => '',
-      'CACERT'    => '',
-    );
-    # Scan LDAP config
-    while (<$ldapconf>) {
-      /^\s*(#|$)/ && next;
-      chomp;
-      if (m/^TLS_(REQCERT|CERT|KEY|CACERTDIR|CACERT)\s+(.*)\s*$/i) {
-        $tls_options{uc $1} = $2;
-      }
-    }
-    close($ldapconf);
-
-    $ldap->start_tls(
-      verify      => $tls_options{'REQCERT'},
-      clientcert  => $tls_options{'CERT'},
-      clientkey   => $tls_options{'KEY'},
-      capath      => $tls_options{'CACERTDIR'},
-      cafile      => $tls_options{'CACERT'}
-    );
-  }
-
-  my $bind = $ldap->bind ($bind_dn, password => $bind_pwd);
-
-  # send a warning if the bind didn't gone well
-  $bind->code && die ("! Failed to bind to LDAP server: ", $bind->error."\n");
-
-  return %hash_result;
-}
-
-# function that check if there is an admin
-sub check_admin {
-  my ($base, $ldap, $people_entries) = @_;
-
-  # search for FusionDirectory's admin account
-
-  # search for admin role
-  my $admin_roles = $ldap->search (
-    base => "$base",
-    filter => "(&(objectClass=gosaRole)(gosaAclTemplate=*:all;cmdrw))",
-    attrs => ['gosaAclTemplate']
-  );
-  $admin_roles->code && die $admin_roles->error;
-  my @dns = ();
-  my @roles = ();
-  my $count = 0;
-  while (my $entry = $admin_roles->shift_entry) {
-    my $role_dn64 = encode_base64($entry->dn, '');
-    push @roles, $role_dn64;
-    print ("Role ".$entry->dn." is an admin ACL role\n");
-    # Search for base-wide assignments
-    my $assignments = $ldap->search (
-      base    => "$base",
-      scope   => 'base',
-      filter  => "(&(objectClass=gosaAcl)(gosaAclEntry=*:subtree:$role_dn64:*))",
-      attrs   => ['gosaAclEntry']
-    );
-    $assignments->code && die $assignments->error;
-    while (my $assignment = $assignments->shift_entry) {
-      my $acl = $assignment->get_value("gosaAclEntry", asref => 1);
-      foreach my $line (@$acl) {
-        if ($line =~ m/^.:subtree:\Q$role_dn64\E/) {
-          my @parts = split(':',$line,4);
-          my @members = split(",",$parts[3]);
-          foreach my $member (@members) {
-            # Is this an existing user?
-            my $dn = decode_base64($member);
-            my $member_node = $ldap->search(
-              base    => $dn,
-              scope   => 'base',
-              filter  => "(objectClass=inetOrgPerson)"
-            );
-            if ($member_node->count == 1) {
-              print ("$dn is a valid admin\n");
-              return;
-            }
-            # Is this a group?
-            $member_node = $ldap->search(
-              base    => $dn,
-              scope   => 'base',
-              filter  => "(objectClass=posixGroup)",
-              attrs   => ['memberUid']
-            );
-            if ($member_node->count == 1) {
-              # Find group members
-              my $member_entry  = $member_node->shift_entry;
-              my $memberUids    = $member_entry->get_value("memberUid", asref => 1);
-              my $filter = '(&(objectClass=inetOrgPerson)(|(uid='.join(')(uid=', @$memberUids).')))';
-              my $group_members = $ldap->search(
-                base    => $base,
-                filter  => $filter,
-              );
-              $group_members->code && die $group_members->error;
-              if (my $group_member_entry = $group_members->shift_entry) {
-                print ($group_member_entry->dn." is a valid admin\n");
-                return;
-              }
-            } else {
-              push @dns, $dn;
-            }
-          }
-        }
-      }
-    }
-    $count++;
-  }
-  if ($count < 1) {
-    print ("! There is no admin ACL role\n");
-  }
-  foreach my $dn (@dns) {
-    print ("! $dn is supposed to be admin but does not exist\n");
-  }
-  if (ask_yn_question("No valid admin account found, do you want to create it ?")) {
-    return add_ldap_admin($base, $ldap, \@dns, $people_entries, \@roles);
-  }
-}
-
-sub create_branch {
-  my ($ldap, $base, $ou) = @_;
-  $ou =~ m/^ou=([^,]*),?$/ or die "Can’t create branch of unknown type $ou\n";
-  my $branch_add = $ldap->add( "$ou,$base",
-    attr => [
-      'ou'  => $1,
-      'objectClass' =>  'organizationalUnit'
-      ]
-  );
-
-  $branch_add->code && die "! failed to add LDAP's $ou,$base branch: ".$branch_add->error."\n";
-}
-
-sub branch_exists {
-  my ($ldap, $branch) = @_;
-
-  # search for branch
-  my $branch_mesg = $ldap->search (base => $branch, filter => '(objectClass=*)', scope => 'base');
-  if ($branch_mesg->code == 32) {
-    return 0;
-  }
-  $branch_mesg->code && die $branch_mesg->error;
-
-  my @entries = $branch_mesg->entries;
-  return (defined ($entries[0]));
-}
-
-# function that check LDAP configuration
-sub check_ldap {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $admin_add = "";
-
-  # Collect existing people branches (even if main one may not exists);
-  my $people = $ldap->search (base => $base, filter => $userrdn);
-  $people->code && die $people->error;
-  my @people_entries = $people->entries;
-  @people_entries = map {$_->dn} @people_entries;
-
-  # if people branch exists
-  if ( branch_exists($ldap, "$userrdn,$base") ) {
-    check_admin($base, $ldap, \@people_entries);
-
-  # if ou=people doesn't exist
-  } else {
-    print ( "! $userrdn,$base not found in your LDAP directory\n" );
-
-    # if user's answer is "yes", creating ou=people branch
-    if ( ask_yn_question("Do you want to create it ?: ") ) {
-      create_branch($ldap, $base, $userrdn);
-      push @people_entries, "$userrdn,$base";
-      check_admin($base, $ldap, \@people_entries);
-    } else {
-      print ("Skipping...\n");
-    }
-  }
-
-  # if groups branch does not exist
-  if (!branch_exists($ldap, "$grouprdn,$base")) {
-    print ("! $grouprdn,$base not found in your LDAP directory\n");
-
-    # if user's answer is "yes", creating groups branch
-    if ( ask_yn_question("Do you want to create it ?: ") ) {
-      create_branch($ldap, $base, $grouprdn);
-    } else {
-      print ("Skipping...\n");
-    }
-  }
-
-  # search for workstations and object groups
-  my $faiclasses = $ldap->search (base => "$base",
-                                  filter => "(&(FAIclass=*)(!(objectClass~=FAIprofile)))" );
-  $faiclasses->code && die $faiclasses->error;
-  my @faiclass_entries = $faiclasses->entries;
-  foreach my $entry (@faiclass_entries) {
-    my $faiclass = $entry->get_value('FAIclass');
-    my (@profiles) = split(' ',$faiclass);
-    if (scalar @profiles > 2) {
-      print "! System or group ".$entry->get_value('cn')." have more than one FAI profile : ".$faiclass."\n";
-    } elsif (scalar @profiles < 2) {
-      print "! System or group ".$entry->get_value('cn')." have no release set in its FAIclass : ".$faiclass."\n";
-    }
-  }
-
-  # search for old config dn
-  if (branch_exists($ldap, "cn=fusiondirectory,ou=configs,$base")) {
-    print ("! There is a configuration in cn=fusiondirectory,ou=configs,$base in your LDAP directory\n");
-    print ("! The correct configuration dn is now cn=config,ou=fusiondirectory,$base\n");
-    print ("! FusionDirectory will not read your configuration at its current dn\n");
-
-    if ( ask_yn_question("Do you want to move and rename this entry? ") ) {
-      if (!branch_exists($ldap, "ou=fusiondirectory,$base")) {
-        create_branch($ldap, $base, 'ou=fusiondirectory');
-      }
-      my $result = $ldap->moddn (
-        "cn=fusiondirectory,ou=configs,$base",
-        newrdn        => 'cn=config',
-        deleteoldrdn  => '1',
-        newsuperior   => "ou=fusiondirectory,$base"
-      );
-      $result->code && die "Migration of configuration entry failed, LDAP error: ".$result->error."\n";
-    } else {
-      print ("Skipping...\n");
-    }
-  }
-
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# function that checks for duplicate uid or gid numbers
-sub check_id_numbers {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $ldap = $hash_ldap_param{ldap};
-  my $base = $hash_ldap_param{base};
-
-  check_id_numbers_generic($ldap, $base, 'posixAccount','uidNumber','users');
-
-  check_id_numbers_generic($ldap, $base, 'posixGroup','gidNumber','groups');
-}
-
-sub check_id_numbers_generic {
-  my ($ldap, $base, $objectClass, $attribute, $type) = @_;
-
-  my $mesg = $ldap->search(
-    filter  => "(&(objectClass=$objectClass)($attribute=*))",
-    base    => $base,
-    attrs   => [$attribute]
-  );
-  $mesg->code && die $mesg->error;
-
-  my @entries = $mesg->entries;
-
-  my %tmp = ();
-
-  foreach my $entry (@entries) {
-    if (not defined $tmp{$entry->get_value($attribute)}) {
-      $tmp{$entry->get_value($attribute)} = ();
-    }
-    push @{$tmp{$entry->get_value($attribute)}}, $entry->dn();
-  }
-
-  my $dups = 0;
-  while (my ($id, $dns) = each %tmp) {
-    if (scalar(@$dns) > 1) {
-      $dups = 1;
-      print "The following $type use the same $attribute $id:\n";
-      foreach my $dn (@$dns) {
-        print "\t$dn\n";
-      }
-    }
-  }
-  if ($dups == 0) {
-    print "There are no duplicate ${attribute}s\n";
-  }
-}
-
-# function that create a directory and copy plugin files in it
-sub create_and_copy_plugin_dir {
-  my ($plugin_dir,$dest_dir) = @_;
-  if ( -e $plugin_dir ){
-    my $dir = dir ($dest_dir);
-    $dir->mkpath() or warn ("! Unable to make ".$dest_dir."\n") if ( !-e $dest_dir);
-    my $files_dirs_copied = rcopy($plugin_dir."/*", $dest_dir);
-  }
-}
-
-# function that install all the FD's plugins from a directory
-sub install_plugins {
-  # ask for the plugins archive
-  my $plugins_archive = ask_user_input ("Where is your plugins archive or folder?");
-  die ("! ".$plugins_archive." doesn't exist") if (!-e $plugins_archive);
-
-  my $dir;
-  if (-d $plugins_archive) {
-    $dir = dir ($plugins_archive);
-  } else {
-    # check the archive format
-    $plugins_archive =~ /^.*\/(.*).tar.gz$/;
-    my $name = $1 or die ("! Unknown archive $plugins_archive");
-
-    # where the extract files will go
-    my $tmp_plugins_dir = "/tmp";
-
-    print ("Installing plugins into $vars{fd_home}, please wait...\n");
-
-    # extract the plugins archive
-    my $archive = Archive::Extract->new (archive => $plugins_archive);
-    my $extract = $archive->extract( to => "$tmp_plugins_dir" ) or die ("! Unable to extract $plugins_archive\n");
-
-    $dir = dir ($tmp_plugins_dir."/".$name);
-  }
-
-  # List non-hidden children, grep directories, and sort by name
-  my @plugins =
-    sort {$a->basename cmp $b->basename}
-    grep {$_->is_dir}
-    $dir->children(no_hidden => 1);
-
-  print "Available plugins:\n";
-
-  my $i = 1;
-  foreach my $plugin_path (@plugins) {
-    print $i++.":".$plugin_path->basename."\n";
-  }
-
-  my $user_input = ask_user_input("Which plugins do you want to install (use \"all\" to install all plugins)?");
-  my @plugins_to_install = split(/\s/, $user_input);
-
-  chdir ($dir) or die ("! Unable to move to $dir\n");
-
-  $i = 0;
-  foreach my $plugin_path (@plugins) {
-    $i++;
-
-    my $plugin = $plugin_path->basename;
-
-    if (grep {($_ eq "all") or ($_ eq $i) or ($_ eq $plugin)} @plugins_to_install) {
-      print "Installing plugin $plugin\n";
-    } else {
-      next;
-    }
-
-    # copy addons into plugins
-    create_and_copy_plugin_dir($plugin_path."/addons/", $vars{fd_home}."/plugins/addons/");
-
-    # copy admin into plugins
-    create_and_copy_plugin_dir($plugin_path."/admin/", $vars{fd_home}."/plugins/admin/");
-
-    # copy config into plugins
-    create_and_copy_plugin_dir($plugin_path."/config/", $vars{fd_home}."/plugins/config/");
-
-    # copy personal into plugins
-    create_and_copy_plugin_dir($plugin_path."/personal/", $vars{fd_home}."/plugins/personal/");
-
-    # copy extra HTML and images
-    create_and_copy_plugin_dir($plugin_path."/html/", $vars{fd_home}."/html/");
-
-    # copy extra theme templates
-    create_and_copy_plugin_dir($plugin_path."/ihtml/", $vars{fd_home}."/ihtml/");
-
-    # copy includes
-    create_and_copy_plugin_dir($plugin_path."/include/", $vars{fd_home}."/include/");
-
-    # copy ldap schema
-    create_and_copy_plugin_dir($plugin_path."/contrib/openldap/", $vars{fd_home}."/contrib/openldap/");
-
-    # copy etc files
-    create_and_copy_plugin_dir($plugin_path."/contrib/etc/", $vars{fd_config_dir}."/".$plugin."/");
-
-    # copy doc
-    create_and_copy_plugin_dir($plugin_path."/contrib/doc/", $vars{fd_home}."/contrib/doc/");
-
-    # copy the locales
-    create_and_copy_plugin_dir($plugin_path."/locale/", $vars{fd_home}."/locale/plugins/".$plugin."/locale/");
-  }
-
-  #finally update FusionDirectory's class.cache and locales
-  rescan_classes();
-  rescan_i18n();
-}
-
-# function that add object classes to people branch users
-sub migrate_users {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $mesg = $ldap->search(
-     filter => '(&'.
-        '(|'.
-          '(objectClass=posixAccount)'.
-          '(objectClass=person)'.
-          '(objectClass=OpenLDAPperson)'.
-        ')'.
-        '(!(objectClass=ipHost))'.
-        '(!(objectClass=inetOrgPerson))'.
-        '(uid=*)'.
-      ')',
-    base   => $base
-  );
-  $mesg->code && die $mesg->error;
-
-  if ($mesg->count > 0) {
-    print ("The following users are missing objectClasses:\n");
-
-    my @entries = $mesg->entries;
-
-    foreach my $entry (@entries) {
-      print $entry->dn()."\n";
-    }
-
-    if (ask_yn_question("Add the inetOrgPerson objectClass to all these entries?")) {
-      foreach my $entry (@entries) {
-        $mesg = $ldap->modify($entry->dn(), add => { "objectClass" => ["person","organizationalPerson","inetOrgPerson"]});
-        $mesg->code && print $mesg->error."\n";
-      }
-    }
-  }
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# function that moves DHCP configurations from systems to ou=dhcp
-sub migrate_dhcp {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  # Search for DHCP configurations
-  my $mesg = $ldap->search(
-    base => "$base",
-    filter => "(objectClass=dhcpService)",
-    attrs => ['cn']
-  );
-  $mesg->code && die $mesg->error;
-
-  my @entries = $mesg->entries;
-
-  print "There are ".$mesg->count." DHCP configurations in the LDAP\n";
-
-  my @baddns  = ();
-
-  foreach my $entry (@entries) {
-    if ($entry->dn() !~ m/$dhcprdn/) {
-      if (scalar(@baddns) == 0) {
-        print "The following are not in the DHCP branch ($dhcprdn):\n";
-      }
-      print $entry->dn()."\n";
-      push @baddns, $entry->dn();
-    }
-  }
-
-  if (scalar(@baddns) == 0) {
-    print "They all already are in the DHCP branch ($dhcprdn):\n";
-  } else {
-    if (ask_yn_question("Move these entries to the DHCP branch ($dhcprdn)?")) {
-      foreach my $entrydn (@baddns) {
-        $entrydn =~ m/^([^,]+),(cn=([^,]+),.*$systemrdn,(.+))$/ or die "Could not parse dn ".$entrydn."\n";
-        my $rdn = $1;
-        my $systemdn = $2;
-        my $systemcn = $3;
-        my $entrybase = $4;
-        if (!branch_exists($ldap, "$dhcprdn,$entrybase")) {
-          create_branch($ldap, $entrybase, $dhcprdn);
-        }
-        my $result = $ldap->moddn (
-          $entrydn,
-          newrdn        => "$rdn-$systemcn",
-          deleteoldrdn  => '1',
-          newsuperior   => "$dhcprdn,$entrybase"
-        );
-        $result->code && die "Migration of DHCP configuration entry failed, LDAP error: ".$result->error."\n";
-
-        my $configDn = "$rdn-$systemcn,$dhcprdn,$entrybase";
-
-        # Add DHCP service on server
-        $mesg = $ldap->search(
-          base    => $systemdn,
-          scope   => 'base',
-          filter  => '(objectClass=*)'
-        );
-        $mesg->code && die $mesg->error;
-        my $system_entry = $mesg->shift_entry;
-        $system_entry->get_value('objectClass');
-        my @classes = $system_entry->get_value('objectClass');
-        if (grep {$_ eq 'dhcpServer'} @classes) {
-          $result = $ldap->modify (
-            "$systemdn",
-            replace => {
-              'dhcpServiceDN' => $configDn,
-            }
-          );
-        } else {
-          $result = $ldap->modify (
-            "$systemdn",
-            replace => {
-              'dhcpServiceDN' => $configDn,
-            },
-            add => {
-              'objectClass' => 'dhcpServer'
-            }
-          );
-        }
-        $result->code && print "Could not add DHCP service on $systemdn, LDAP error: ".$result->error."\nYou'll need to activate it yourself\n";
-      }
-    }
-  }
-}
-
-sub delete_gosa_locks {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  # Search for old formatted ACLs
-  my $mesg = $ldap->search(
-    base => "$base",
-    filter => "(objectClass=gosaLockEntry)",
-    attrs => ['dn']
-  );
-  $mesg->code && die $mesg->error;
-
-  my @entries = $mesg->entries;
-
-  foreach my $entry (@entries) {
-    $mesg = $ldap->delete($entry);
-    if ($mesg->code) {
-      print "Failed to delete lock '".$entry->dn."': ".$mesg->error."\n";
-    } else {
-      print "Deleted lock '".$entry->dn."'\n";
-    }
-  }
-}
-
-# Get LDAP attributes which have been deprecated
-sub get_deprecated {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $schema_info = $ldap->schema();
-
-  my @attributes      = $schema_info->all_attributes();
-  my @obsolete_attrs  = ();
-  foreach my $attribute (@attributes) {
-    if ($attribute->{'obsolete'}) {
-      push @obsolete_attrs, $attribute;
-    }
-  }
-
-  my @ocs               = $schema_info->all_objectclasses();
-  my @obsolete_classes  = ();
-  foreach my $oc (@ocs) {
-    if ($oc->{'obsolete'}) {
-      push @obsolete_classes, $oc;
-    }
-  }
-
-  return (\@obsolete_attrs, \@obsolete_classes);
-}
-
-# function that migrates systems from FD<1.1 to FD>=1.1
-sub migrate_systems {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my @oldOCs = ('gotoWorkstation',  'goServer', 'gotoTerminal', 'gotoDevice');
-  my @newOCs = ('fdWorkstation',    'fdServer', 'fdTerminal',   'device');
-  foreach my $i (0 .. $#oldOCs) {
-    my $oldOC = $oldOCs[$i];
-    my $newOC = $newOCs[$i];
-
-    my $mesg = $ldap->search(
-      filter => "(objectClass=$oldOC)",
-      base   => $base
-    );
-    $mesg->code && die $mesg->error;
-
-    if ($mesg->count > 0) {
-      print ("The following systems are using the obsolete $oldOC objectClass:\n");
-
-      my @entries = $mesg->entries;
-
-      foreach my $entry (@entries) {
-        print $entry->dn()."\n";
-      }
-
-      if (ask_yn_question("Migrate these entries to $newOC objectClass?")) {
-        foreach my $entry (@entries) {
-          my $tmprdn = "cn=".$entry->get_value('cn')."+ipHostNumber=".$entry->get_value('ipHostNumber');
-          my $newrdn = "cn=".$entry->get_value('cn');
-          my $dn_old = $entry->dn();
-          my $dn_new = $entry->dn();
-          $dn_new =~ s/^[^,]+,/$tmprdn,/;
-          $entry->dn($dn_new);
-          my @replace = ('ieee802Device', 'ipHost', $newOC);
-          my @classes = $entry->get_value('objectClass');
-          foreach my $class (@classes) {
-            if (($class ne $oldOC) && ($class ne 'GOhard')) {
-              push(@replace, "$class");
-            }
-          }
-          $entry->replace("objectClass" => \@replace);
-          if ($entry->exists('gotoMode')) {
-            my $gotoMode = $entry->get_value('gotoMode');
-            if ($gotoMode eq 'locked') {
-              $entry->add('fdMode' => 'locked');
-            } else {
-              $entry->add('fdMode' => 'unlocked');
-            }
-            $entry->delete('gotoMode');
-          }
-          if ($entry->exists('argonautLdap2zoneAllowNotify')) {
-            $entry->delete('argonautLdap2zoneAllowNotify');
-          }
-          $mesg = $ldap->add($entry);
-          if ($mesg->code) {
-            print $entry->dn().": ".$mesg->error."\n";
-            next;
-          }
-          undef @replace;
-          $mesg = $ldap->delete($dn_old);
-          if ($mesg->code) {
-            print $entry->dn().": ".$mesg->error."\n";
-            next;
-          }
-          $mesg = $ldap->moddn($dn_new, newrdn => $newrdn);
-          if ($mesg->code) {
-            print $entry->dn().": ".$mesg->error."\n";
-            next;
-          }
-        }
-      }
-    } else {
-      print "Found no system using $oldOC\n";
-    }
-  }
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# function that migrates winstations from FD<1.1 to FD>=1.1
-sub migrate_winstations
-{
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $mesg = $ldap->search(
-    filter => "(&(!(objectClass=fdWorkstation))(!(objectClass=inetOrgPerson))(!(objectClass=posixGroup))(uid=*\$)(objectClass=sambaSamAccount))",
-    base   => $base
-  );
-  $mesg->code && die $mesg->error;
-
-  if ($mesg->count > 0) {
-    print ("The following winstations are not using the new fdWorkstation objectClass:\n");
-
-    my @entries = $mesg->entries;
-
-    foreach my $entry (@entries) {
-      print $entry->dn()."\n";
-    }
-
-    if (ask_yn_question("Migrate these entries to fdWorkstation objectClass?")) {
-      foreach my $entry (@entries) {
-        my $cn = $entry->get_value('cn');
-        $cn =~ s/\$$//;
-        $entry->replace('cn' => $cn);
-        my $newrdn = "cn=".$cn;
-        my $dn_old = $entry->dn();
-        my $entrybase;
-        if ($dn_old =~ m/^[^,]+,$winstationrdn,(.+)$/) {
-          $entrybase = $1;
-        } elsif ($dn_old =~ m/^[^,]+,.*$systemrdn,(.+)$/) {
-          $entrybase = $1;
-        } elsif ($dn_old =~ m/^[^,]+,.*$winstationrdn,(.+)$/) {
-          $entrybase = $1;
-        } else {
-          die "Could not parse dn ".$dn_old."\n";
-        }
-        if (!branch_exists($ldap, "$workstationrdn,$entrybase")) {
-          if ($workstationrdn =~ m/^([^,]+),([^,]+)$/) {
-            if (!branch_exists($ldap, "$2,$entrybase")) {
-              create_branch($ldap, $entrybase, $2);
-            }
-            create_branch($ldap, "$2,$entrybase", $1);
-          } else {
-            create_branch($ldap, $entrybase, $workstationrdn);
-          }
-        }
-        my $dn_new = "$newrdn,$workstationrdn,$entrybase";
-        $entry->dn($dn_new);
-        my @replace = ('fdWorkstation');
-        my @classes = $entry->get_value('objectClass');
-        foreach my $class (@classes) {
-          if ($class ne 'account') {
-            push(@replace, "$class");
-          }
-        }
-        $entry->replace("objectClass" => \@replace);
-        $entry->add('fdMode' => 'unlocked');
-        $mesg = $ldap->add($entry);
-        if ($mesg->code) {
-          print $entry->dn().": ".$mesg->error."\n";
-          next;
-        }
-        undef @replace;
-        $mesg = $ldap->delete($dn_old);
-        if ($mesg->code) {
-          print $entry->dn().": ".$mesg->error."\n";
-          next;
-        }
-      }
-    }
-  } else {
-    print "Found no winstation to migrate\n";
-  }
-}
-
-# function that migrates phones from FD<1.1 to FD>=1.1
-sub migrate_phones {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $mesg = $ldap->search(
-    filter => '(&(objectClass=fdPhone)(objectClass=device))',
-    base   => $base
-  );
-  $mesg->code && die $mesg->error;
-
-  if ($mesg->count > 0) {
-    print ("The following phones are still using the device objectClass:\n");
-
-    my @entries = $mesg->entries;
-
-    foreach my $entry (@entries) {
-      print $entry->dn()."\n";
-    }
-
-    if (ask_yn_question("Migrate these entries to fdPhone objectClass?")) {
-      foreach my $entry (@entries) {
-        my $tmprdn = "cn=".$entry->get_value('cn')."+objectClass=fdPhone";
-        my $newrdn = "cn=".$entry->get_value('cn');
-        my $dn_old = $entry->dn();
-        my $dn_new = $entry->dn();
-        $dn_new =~ s/^[^,]+,/$tmprdn,/;
-        $entry->dn($dn_new);
-        my @replace = ();
-        my @classes = $entry->get_value('objectClass');
-        foreach my $class (@classes) {
-          if ($class ne 'device') {
-            push(@replace, "$class");
-          }
-        }
-        $entry->replace("objectClass" => \@replace);
-        $mesg = $ldap->add($entry);
-        if ($mesg->code) {
-          print $entry->dn().": ".$mesg->error."\n";
-          next;
-        }
-        undef @replace;
-        $mesg = $ldap->delete($dn_old);
-        if ($mesg->code) {
-          print $entry->dn().": ".$mesg->error."\n";
-          next;
-        }
-        $mesg = $ldap->moddn($dn_new, newrdn => $newrdn);
-        if ($mesg->code) {
-          print $entry->dn().": ".$mesg->error."\n";
-          next;
-        }
-      }
-    }
-  }
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# function that migrates interfaces from FD<1.4 to FD>=1.4
-sub migrate_interfaces {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my @entriesToMigrate  = ();
-  my @entriesToIgnore   = ();
-
-  my @systemOCs = ('fdWorkstation', 'fdServer', 'fdTerminal', 'fdPrinter', 'fdPhone', 'fdMobilePhone', 'device');
-
-  my $mesg = $ldap->search(
-    filter  => "(&(|(objectClass=".join(')(objectClass=', @systemOCs)."))(|(ipHostNumber=*)(macAddress=*)))",
-    base    => $base
-  );
-  $mesg->code && die $mesg->error;
-
-  my @entries = $mesg->entries;
-
-  foreach my $entry (@entries) {
-    my $mesg2 = $ldap->search(
-      filter  => "(objectClass=fdNetworkInterface)",
-      base    => $entry->dn,
-      scope   => "one"
-    );
-    $mesg2->code && die $mesg2->error;
-    if ($mesg2->count == 0) {
-      my @macs  = $entry->get_value('macAddress');
-      if (scalar(@macs) > 1) {
-        push @entriesToIgnore, $entry;
-        next;
-      }
-      push @entriesToMigrate, $entry;
-    }
-  }
-
-  if (scalar(@entriesToMigrate) > 0) {
-    print "\nThe following systems are missing an interface node and can be migrated automatically:\n\n";
-    foreach my $entry (@entriesToMigrate) {
-      my @macs  = $entry->get_value('macAddress');
-      my @ips   = $entry->get_value('ipHostNumber');
-      print $entry->dn;
-      if (scalar(@macs) > 0) {
-        print " with MAC ".join(', ', @macs);
-      } else {
-        print " with no MAC";
-      }
-      if (scalar(@ips) > 0) {
-        print " and IP ".join(', ', @ips)."\n";
-      } else {
-        print " and no IP\n";
-      }
-    }
-    print "\n";
-
-    if (ask_yn_question("Migrate these systems by adding an interface node")) {
-      my $interface_cn = ask_user_input ("Please enter the name for interfaces created by this migration", "eth0");
-      my $count = 0;
-      foreach my $entry (@entriesToMigrate) {
-        my @macs  = $entry->get_value('macAddress');
-        my @ips   = $entry->get_value('ipHostNumber');
-        my %interface = (
-          'cn'            => $interface_cn,
-          'objectClass'   => 'fdNetworkInterface',
-        );
-
-        if (scalar(@macs) > 0) {
-          $interface{'macAddress'} = \@macs;
-        }
-
-        if (scalar(@ips) > 0) {
-          $interface{'ipHostNumber'} = \@ips;
-        }
-
-        my @options = %interface;
-        my $interface_add = $ldap->add( "cn=$interface_cn,".$entry->dn, attr => \@options );
-
-        $interface_add->code && die "! failed to add interface: ".$interface_add->error."\n";
-        $count++;
-      }
-      print $count." entries migrated\n";
-    }
-  }
-
-  if (scalar(@entriesToIgnore) > 0) {
-    print "\nThe following systems are missing interfaces nodes but cannot be migrated because they have several MAC addresses:\n\n";
-    foreach my $entry (@entriesToIgnore) {
-      my @macs  = $entry->get_value('macAddress');
-      my @ips   = $entry->get_value('ipHostNumber');
-      print $entry->dn;
-      if (scalar(@macs) > 0) {
-        print " with MAC ".join(', ', @macs);
-      } else {
-        print " with no MAC";
-      }
-      if (scalar(@ips) > 0) {
-        print " and IP ".join(', ', @ips)."\n";
-      } else {
-        print " and no IP\n";
-      }
-    }
-    print "\n";
-    print "Please edit them by hand in FusionDirectory to add interfaces\n";
-  }
-
-  if ((scalar(@entriesToMigrate) == 0) and (scalar(@entriesToIgnore) == 0)) {
-    print "\nNo systems are missing interfaces, nothing to do\n"
-  }
-
-  print "\n";
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# function that removes SupAnn root information from FD<1.4
-sub remove_supann_root {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $mesg = $ldap->search(
-    filter  => '(&(objectClass=supannOrg)(objectClass=eduOrg))',
-    base    => $base,
-    scope   => 'one'
-  );
-  $mesg->code && die $mesg->error;
-
-  if ($mesg->count > 0) {
-    print ("There is an outdated SupAnn establishement stored under root node:\n");
-
-    my @entries = $mesg->entries;
-
-    foreach my $entry (@entries) {
-      print $entry->dn()."\n";
-    }
-
-    print ("You should remove this entry and check the 'Root establishment' checkbox\n");
-    print (" in FusionDirectory to save it in the root node instead.\n");
-
-    if (ask_yn_question("Remove this entry?")) {
-      foreach my $entry (@entries) {
-        $mesg = $ldap->delete($entry);
-        if ($mesg->code) {
-          print "Failed to delete entry '".$entry->dn."': ".$mesg->error."\n";
-        } else {
-          print "Deleted entry '".$entry->dn."'\n";
-        }
-      }
-    }
-  } else {
-    print ("There is no outdated SupAnn establishement stored under root node.\n");
-  }
-
-  # unbind to the LDAP server
-  my $unbind = $ldap->unbind;
-  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
-}
-
-# List LDAP attributes which have been deprecated
-sub list_deprecated {
-  my ($obsolete_attrs, $obsolete_classes) = get_deprecated();
-
-  print "Deprecated attributes:\n";
-  foreach my $attribute (@$obsolete_attrs) {
-    printf(" %-30s\t%-60s\t- %s\n", $attribute->{'name'}, '('.$attribute->{'desc'}.')', $attribute->{'oid'});
-  }
-
-  print "Deprecated objectClasses:\n";
-  foreach my $oc (@$obsolete_classes) {
-    printf(" %-30s\t%-60s\t- %s\n", $oc->{'name'}, '('.$oc->{'desc'}.')', $oc->{'oid'});
-  }
-}
-
-# List LDAP entries using attributes which have been deprecated
-sub check_deprecated {
-  my ($obsolete_attrs, $obsolete_classes) = get_deprecated();
-
-  my $filterAttrs   = '(|'.join('', (map{ '('.$_->{'name'}.'=*)' } @$obsolete_attrs)).')';
-
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $entries = $ldap->search(
-    base    => "$base",
-    filter  => "$filterAttrs",
-  );
-  $entries->code && die $entries->error;
-
-  if ($entries->count > 0) {
-    while (my $entry = $entries->shift_entry) {
-      print $entry->dn." contains an obsolete attribute\n";
-    }
-  } else {
-    print "There are no entries in the LDAP using obsolete attributes\n";
-  }
-
-  my $useobsoletes = 0;
-  foreach my $class (@$obsolete_classes) {
-    $entries = $ldap->search(
-      base    => "$base",
-      filter  => '(objectClass='.$class->{'name'}.')',
-    );
-    $entries->code && die $entries->error;
-
-    if ($entries->count > 0) {
-      $useobsoletes = 1;
-      while (my $entry = $entries->shift_entry) {
-        print $entry->dn." uses the obsolete object class ".$class->{'name'}."\n";
-      }
-    }
-  }
-
-  if (!$useobsoletes) {
-    print "There are no entries in the LDAP using obsolete classes\n";
-  }
-}
-
-# Print a LDIF file removing attributes which have been deprecated
-sub ldif_deprecated {
-  my ($obsolete_attrs, $obsolete_classes) = get_deprecated();
-
-  my $filterAttrs   = '(|'.join('', (map{ '('.$_->{'name'}.'=*)' } @$obsolete_attrs)).')';
-  my $filterClasses = '(|'.join('', (map{ '(objectClass='.$_->{'name'}.')' } @$obsolete_classes)).')';
-
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $entries = $ldap->search(
-    base    => "$base",
-    filter  => "$filterAttrs",
-  );
-  $entries->code && die $entries->error;
-
-  if ($entries->count > 0) {
-    while (my $entry = $entries->shift_entry) {
-      print 'dn:'.$entry->dn."\n";
-      print "changetype:modify\n";
-      foreach my $attr (@$obsolete_attrs) {
-        if ($entry->exists($attr->{'name'})) {
-          print "delete:".$attr->{'name'}."\n-\n";
-        }
-      }
-      print "\n";
-    }
-  } else {
-    print "# There are no entries in the LDAP using obsolete attributes\n";
-  }
-
-  $entries = $ldap->search(
-    base    => "$base",
-    filter  => "$filterClasses",
-  );
-  $entries->code && die $entries->error;
-
-  if ($entries->count > 0) {
-    print "# WARNING: There are entries in the LDAP using obsolete classes, you need to edit them manually\n";
-  } else {
-    print "# There are no entries in the LDAP using obsolete classes\n";
-  }
-}
-
-# Read FD config in the LDAP
-sub read_ldap_config {
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $mesg = $ldap->search (base => "$configrdn,$base", filter => '(objectClass=fusionDirectoryConf)', scope => 'base');
-  die_on_ldap_errors($mesg);
-
-  if ($mesg->count > 0) {
-    if (($mesg->entries)[0]->exists('fdUserRDN')) {
-      $userrdn = ($mesg->entries)[0]->get_value('fdUserRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdOGroupRDN')) {
-      $grouprdn = ($mesg->entries)[0]->get_value('fdOGroupRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdAclRoleRDN')) {
-      $aclrolerdn = ($mesg->entries)[0]->get_value('fdAclRoleRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdSystemRDN')) {
-      $systemrdn = ($mesg->entries)[0]->get_value('fdSystemRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdDnsRDN')) {
-      $dnsrdn = ($mesg->entries)[0]->get_value('fdDnsRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdDhcpRDN')) {
-      $dhcprdn = ($mesg->entries)[0]->get_value('fdDhcpRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdWorkstationRDN')) {
-      $workstationrdn = ($mesg->entries)[0]->get_value('fdWorkstationRDN');
-    }
-    if (($mesg->entries)[0]->exists('fdSambaMachineAccountRDN')) {
-      $winstationrdn = ($mesg->entries)[0]->get_value('fdSambaMachineAccountRDN');
-    }
-  }
-
-  return ($mesg->entries)[0];
-}
-
-sub show_ldap_config {
-  my $config_node = read_ldap_config();
-  $config_node->dump();
-}
-
-sub set_config_var {
-  my ($var, $value) = @_;
-  if (!($var =~ m/^fd/)) {
-    $var = "fd$var";
-  }
-
-  print "Setting configuration var $var to $value\n";
-
-  # initiate the LDAP connexion
-  my %hash_ldap_param = get_ldap_connexion();
-
-  # LDAP's connection's parameters
-  my $base = $hash_ldap_param{base};
-  my $ldap = $hash_ldap_param{ldap};
-
-  my $result = $ldap->modify (
-    "$configrdn,$base",
-    replace => {
-      $var  => $value
-    }
-  );
-  $result->code && warn "! failed to set value for '".$var."' - ".$result->error_name.": ".$result->error_text;
-}
-
-sub show_version {
-  my $variables_common_path = "$vars{fd_home}/include/variables_common.inc";
-  if (-e $variables_common_path) {
-    open(my $vars, q{<}, $variables_common_path) || die ("Could not open $variables_common_path");
-    while(<$vars>) {
-      if ($_ =~ m/^define \(["']FD_VERSION["'], "([^"]+)"\);/) {
-        print "FusionDirectory version is $1\n";
-        last;
-      }
-    }
-    close($vars);
-  } else {
-    print "File $variables_common_path does not exist, can’t find out FusionDirectory version\n";
-  }
-}
-
-# function that set useful vars based on user specified folders and files
-sub set_vars {
-  $fd_config        = $vars{fd_config_dir}."/".$vars{config_file};
-  $fd_secrets       = $vars{fd_config_dir}."/".$vars{secrets_file};
-  $locale_dir       = $vars{fd_home}."/".$vars{locale_dir};
-  $class_cache      = $vars{fd_cache}."/".$vars{class_cache};
-  $locale_cache_dir = $vars{fd_cache}."/".$vars{locale_cache_dir};
-  $tmp_dir          = $vars{fd_cache}."/".$vars{tmp_dir};
-  $fai_log_dir      = $vars{fd_cache}."/".$vars{fai_log_dir};
-  $template_dir     = $vars{fd_cache}."/".$vars{template_dir};
-  my $supann_dir    = $vars{fd_cache}."/supann";
-
-  @root_config_dirs   = ( $vars{fd_home}, $vars{fd_config_dir} );
-  @apache_config_dirs = ( $vars{fd_spool_dir}, $vars{fd_cache}, $tmp_dir, $fai_log_dir,
-                          $template_dir );
-  @config_dirs = ( @root_config_dirs, @apache_config_dirs );
-}
-
-# function that list variables that can be modified by the user
-sub list_vars {
-  while ( my ($key, $value) = each(%vars) ) {
-    print "$key\t[$value]"."\n";
-  }
-}
-
-#################### main function #####################
-#die if the user is not root
-die ("! You have to run this script as root\n") if ($<!=0);
-
-  my @vars_keys = keys %vars;
-
-  # $commands{<cli-option>} = [<description>, <function>, <needs-ldap-config>];
-  my %commands = ();
-  $commands{"--update-cache"}         = ["Updating class.cache",                          \&rescan_classes];
-  $commands{"--update-locales"}       = ["Updating translations",                         \&rescan_i18n];
-  $commands{"--check-directories"}    = ["Checking FusionDirectory's directories",        \&check_directories];
-  $commands{"--check-config"}         = ["Checking FusionDirectory's config file",        \&check_config];
-  $commands{"--check-ldap"}           = ["Checking your LDAP tree",                       \&check_ldap, 1];
-  $commands{"--check-ids"}            = ["Checking for duplicate uid or gid numbers",     \&check_id_numbers, 1];
-  $commands{"--migrate-users"}        = ["Migrating your users",                          \&migrate_users, 1];
-  $commands{"--migrate-phones"}       = ["Migrating your phones from FD < 1.1",           \&migrate_phones, 1];
-  $commands{"--migrate-systems"}      = ["Migrating your systems from FD < 1.1",          \&migrate_systems, 1];
-  $commands{"--migrate-winstations"}  = ["Migrating your winstations from FD < 1.1",      \&migrate_winstations, 1];
-  $commands{"--migrate-dhcp"}         = ["Migrating DHCP configurations for FD >= 1.0.17",\&migrate_dhcp, 1];
-  $commands{"--migrate-interfaces"}   = ["Migrating your systems from FD < 1.4",          \&migrate_interfaces, 1];
-  $commands{"--remove-supann-root"}   = ["Remove SupAnn root establishment from FD < 1.4",\&remove_supann_root, 1];
-  $commands{"--delete-gosa-locks"}    = ["Delete lock tokens using old gosaLockEntry class", \&delete_gosa_locks];
-  $commands{"--install-plugins"}      = ["Installing FusionDirectory's plugins",          \&install_plugins];
-  $commands{"--encrypt-passwords"}    = ["Encrypt passwords in fusiondirectory.conf",     \&encrypt_passwords];
-  $commands{"--show-passwords"}       = ["Show passwords from fusiondirectory.conf",      \&show_passwords];
-  $commands{"--show-version"}         = ["Show FusionDirectory version from variables_common.inc", \&show_version];
-  $commands{"--list-vars"}            = ["List possible vars to give --set",              \&list_vars];
-  $commands{"--write-vars"}           = ["Choose FusionDirectory Directories",            \&write_vars];
-  $commands{"--set-VAR=value"}        = ["Set the variable VAR to value see --list-vars", \&die]; # Won't be called because it contains uppercase
-  $commands{"--list-deprecated"}      = ["List deprecated attributes and objectclasses",  \&list_deprecated];
-  $commands{"--check-deprecated"}     = ["List LDAP entries using deprecated attributes or objectclasses", \&check_deprecated];
-  $commands{"--ldif-deprecated"}      = ["# Print an LDIF removing deprecated attributes",\&ldif_deprecated];
-  $commands{"--show-config"}          = ["Show an LDAP dump of the FusionDirectory configuration", \&show_ldap_config];
-  $commands{"--set-config-VAR=value"} = ["Set the value in LDAP of a configuration field",\&set_config_var];
-
-  my $usage = 0;
-
-  set_vars();
-
-  foreach my $arg ( @ARGV ) {
-    if (( $arg =~ m/^--set-(.*)=(.*)$/ ) && (grep {$_ eq lc($1)} @vars_keys)) {
-      $vars{lc($1)} = $2;
-      print "Setting ".lc($1)." to $2\n";
-      set_vars();
-    } elsif ( $arg =~ m/^--set-config-(.*)=(.*)$/ ) {
-      set_config_var($1, $2);
-    } elsif ( defined $commands { lc ( $arg ) } ) {
-      my @command = @{ $commands{ $arg } };
-      if ((defined $command[2]) && $command[2]) {
-        read_ldap_config();
-      }
-      print( $command[0]."\n" );
-      $command[1]();
-    } elsif ( ( lc($arg) eq "--help" ) || ( lc($arg) eq "-h" ) ) {
-      print ( "\nCommands:\n" );
-      while ( my ( $key,$value ) = each %commands ) {
-        print ( "$key\t".$value->[0]."\n" );
-      }
-      print ("--yes\t\t\tAlways answer yes to yes/no questions\n");
-      print ("--help\t\t\tShows this help\n\n");
-
-    } elsif (( lc($arg) eq "--yes" ) || ( lc($arg) eq "-y" )) {
-      $yes_flag = 1;
-    } else {
-      print ("\nInvalid argument\n\n");
-      $usage = 1;
-    }
-  }
-
-  if( $usage || ( @ARGV <= 0 ) ) {
-    print ( "Usage : $0 [--yes]" );
-    foreach my $command ( keys ( %commands )) {
-      print ( " [$command]" );
-    }
-    print "\n\n";
-  }
-exit 0;
-
-__END__
-
-=head1 NAME
-
-fusiondirectory-setup - FusionDirectory configuration management tool
-
-=head1 DESCRIPTION
-
-This script is designed to perform multiple checks on your FusionDirectory/LDAP architecture, and fix usual misconfiguration.
-Some extra features allow you to install FusionDirectory's plugins, and change destinations directories.
-
-=head2 Options
-
-=over 4
-
-=item --update-cache
-
-This option update the /var/cache/fusiondirectory/class.cache file. Which contain PHP classes used in FusionDirectory, and their location.
-
-=item --update-locales
-
-This option update internalization, by generating a new .mo locales file for each language, with every .po files it found.
-Needs I<msgcat> and I<msgfmt> to be installed.
-
-=item --check-directories
-
-This option perform a check on all FusionDirectory's files or directories.
-
-=item --check-config
-
-This option perform a check on FusionDirectory's config file.
-
-=item --check-ldap
-
-This option check your LDAP tree. Looking for admin account, and groups or people branch. If one of those doesn't exist, the script will ask you what to do.
-
-=item --check-ids
-
-This option check your LDAP tree for duplicate uidNumber or gidNumber among users and groups.
-
-=item --migrate-users
-
-This option add FusionDirectory attributes to the people branch.
-
-=item --migrate-phones
-
-This option removes device objectClass for phones as fdPhones is now structural since FD 1.1.
-
-=item --migrate-systems
-
-This option replace old systems objectClasses by new objectClasses from FD 1.1.
-
-=item --migrate-winstations
-
-This option replace old winstations objectClasses by new objectClasses from FD 1.1.
-
-=item --migrate-dhcp
-
-This option moves DHCP configurations from systems branch to DHCP branch, which is necessary for FusionDirectory 1.0.17 and above.
-
-=item --migrate-interfaces
-
-This option creates interfaces objects for old systems from FD < 1.4.
-
-=item --delete-gosa-locks
-
-This option will delete old GOsa style lock tokens from 1.0.15 or older
-
-=item --install-plugins
-
-This option will install the plugin from a tar.gz of the plugin. This option is intended for people wanting to install from the sources.
-
-=item --encrypt-passwords
-
-This option will encrypt the password inside your fusiondirectory.conf file, it need the headers module to be activated in your apache to work.
-
-=item --show-passwords
-
-This option will show the passwords inside your fusiondirectory.conf file as clear text (even if they are encrypted).
-
-=item --show-version
-
-This option will parse the file variables_common.inc of FusionDirectory to find out which version of FusionDirectory is installed.
-
-=item --list_vars
-
-This option will list the variables you can change to install FusionDirectory on another set of directories. This option is intended for people wanting to install from the sources.
-
-=item --write-vars
-
-This option will write back the variables.inc file with the updated variables and is only useful with --set-VAR=variable and for people installing from sources.
-
-=item --set-VAR=variable
-
-This option will change the variable for the FusionDirectory installation. it is only useful with --install-directories and for people installing from sources.
-
-=item --list-deprecated
-
-This option will list the deprecated attributes and objectclasses still in your schemas and no longer used by FusionDirectory.
-
-=item --check-deprecated
-
-This option will list the dn of LDAP entries using deprecated attributes or objectclasses and no longer used by FusionDirectory.
-
-=item --ldif-deprecated
-
-This option will print an LDIF to allow you to remove deprecated attributes from you ldap server. Be careful and check before applying.
-
-=item --show-config
-
-This option will print a dump of the FusionDirectory configuration LDAP node.
-
-=item --set-config-VAR=value
-
-This option sets the value of a configuration field in the LDAP. The value needs to be in the correct LDAP format.
-You cannot set multivalued field with this. The var name can be provided with or without the fd prefix.
-
-=item --yes
-
-This flag will answer "yes" to every yes/no question asked by the script
-
-=back
-
-=head1 EXAMPLE
-
- benoit@catbert$ fusiondirectory-setup --update-cache --update-locales
-
- Update FusionDirectory class cache and update localization
-
- benoit@catbert$ fusiondirectory-setup --list-vars
- List possible vars to give --set
-locale_cache_dir	[locale]
-config_file     	[fusiondirectory.conf]
-fd_cache        	[/var/cache/fusiondirectory]
-fd_smarty_path  	[/usr/share/php/smarty3/Smarty.class.php]
-fd_spool_dir    	[/var/spool/fusiondirectory]
-fai_log_dir     	[fai]
-tmp_dir         	[tmp]
-secrets_file    	[fusiondirectory.secrets]
-template_dir    	[template]
-locale_dir      	[locale]
-class_cache     	[class.cache]
-fd_config_dir   	[/etc/fusiondirectory]
-fd_home         	[/var/www/fusiondirectory]
-
-
- benoit@catbert$ fusiondirectory-setup --set-class_cache=class.cache --write-vars
-
- update the class.cache name and write back the variables.inc file
-
-=head1 BUGS
-
-Please report any bugs, or post any suggestions, to the fusiondirectory mailing list fusiondirectory-users or to
-<https://gitlab.fusiondirectory.org/fusiondirectory/fd/issues/new>
-
-=head1 AUTHORS
-
-Benjamin Carpentier
-
-Come Bernigaud
-
-=head1 LICENCE AND COPYRIGHT
-
-This code is part of FusionDirectory (http://www.fusiondirectory.org/)
-
-=over 2
-
-=item Copyright (C) 2011-2018  FusionDirectory
-
-=back
-
-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.
-
-=cut
-- 
GitLab