Sophie

Sophie

distrib > Mageia > 5 > i586 > media > core-release > by-pkgid > c031e6b4ec62ed509c3c4c8e7bf7c57d > files > 10

fusiondirectory-plugin-asterisk-1.0.8.1-5.mga5.noarch.rpm

#!/usr/bin/perl

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 {CRYPT} password (for LDAP)
use Crypt::PasswdMD5;
use Crypt::CBC;

# used to uncompress tar.gz
use Archive::Extract;

# used to copy files
use File::Copy::Recursive qw(rcopy);

#XML parser
use XML::Twig;

# 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_dir    => "/usr/share/php/smarty3",
 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 $oupeople  = "people";
my $peopleou  = "ou=$oupeople";
my $ouroles   = "aclroles";
my $rolesou   = "ou=$ouroles";

#################################################################################################################################################

# 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) = @_;
 my $answer;

 if (defined $default_answer) {
   $thing_to_ask .= " [$default_answer]";
 }
 print $thing_to_ask.":\n";

 do
 {
   $answer = <STDIN>;
   chomp $answer;
   $answer =~ s/^\s+|\s+$//g;
 } while (($answer eq "") && (not defined $default_answer));

 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,$rolesou,$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, "$rolesou,$base")) {
    create_branch($ldap, $base, $ouroles);
  }

  my $role_dn = "cn=$cn,$rolesou,$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);
  my $string;
  $string .= $chars[rand @chars] for 1..$size;
  return $string;
}

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 location declaration to include the newly
created $fd_secrets.

Example:

Alias /fusiondirectory /usr/share/fusiondirectory/html

<Location /fusiondirectory>
  php_admin_flag engine on
  php_admin_flag register_globals off
  php_admin_flag allow_call_time_pass_reference off
  php_admin_flag expose_php off
  php_admin_flag zend.ze1_compatibility_mode off
  php_admin_flag register_long_arrays off
  php_admin_value upload_tmp_dir /var/spool/fusiondirectory/
  php_admin_value session.cookie_lifetime 0
  include /etc/fusiondirectory/fusiondirectory.secrets
</Location>


Please reload your httpd configuration after you've modified anything.\n";
}

####################################################### 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;

            # only process for lines beginning with "class", and extracting the 2nd word (the class name)
            if ( $line =~ /^class\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_user {
  my $apache_user = "";

  # 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_user = "www-data";
  } elsif ((-e "/etc/redhat-release") || (-e "/etc/mageia-release")) {
    $apache_user = "apache";
  } else {
    print ("! Looks like you are not a Debian, Redhat or Mageia, I don't know your distribution !\n");
    $apache_user = ask_user_input ("Who is your apache user ?");
  }
  return $apache_user;
}

#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 ("Skiping...\n");
      }
    } else {
      print("Rights on $dir are correct\n");
    }
  } elsif ($create) {

    if ( ask_yn_question("Directory $dir doesn't exists, 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 ( "Skiping...\n" );
    }
  } else {
    return 0;
  }
  return 1;
}

# function that check FusionDirectory's directories
sub check_directories {
  my $apache_user = get_apache_user();

  # 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",0755,1);

      # else if $dir is one of the dirs that remains to apache's user, and the dir's owner is not root or the group is not the apache's user, modifying owner
      } elsif ( grep ( /.*$dir.*/, @apache_config_dirs) ) {
        check_rights($dir,"root",$apache_user,0770,1);
      }
  }
}

# function that check FusionDirectory's config file
sub check_config {
  my $apache_user = get_apache_user();

  # check config file
  check_rights($fd_config,"root",$apache_user,0640,0) or die 'The config file does not exists!';
}

############################################################# 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_dir}");

/* 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 => "$base",
    filter => "(&(objectClass=fusionDirectoryConf)(cn=fusiondirectory))",
    attrs => ['fdAccountPrimaryAttribute']
  );
  $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';
  }

  my $fd_admin_uid = ask_user_input ("Please enter a login for FusionDirectory's admin", "fd-admin");
  # Does this user exists?
  my $dn = "";
  foreach my $entry (@$people_entries) {
    my $mesg = $ldap->search(
      base => "$entry",
      filter => "(&(objectClass=gosaAccount)(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");
    my $fd_admin_pwd_confirm = ask_user_input ("Please enter it again");

    # 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 %obj = (
      'cn'  =>  'System Administrator',
      'sn'  =>  'Administrator',
      'uid' =>  $fd_admin_uid,
      'givenname'     =>  'System',
      'objectclass'   =>  [ 'top', 'person', 'gosaAccount', 'organizationalPerson', 'inetOrgPerson' ],
      'userPassword'  => "{CRYPT}".unix_md5_crypt($fd_admin_pwd)
    );
    if (not defined $obj{$attr}) {
      print "Error : invalid account primary attribute $attr, using uid\n";
      $attr = 'uid';
    }
    $dn = "$attr=".$obj{$attr}.",$peopleou,$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;
  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;
}

# 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 $twig = XML::Twig->new();    # create the twig
    $twig->parsefile($fd_config); # build it
    my @locs = $twig->root->first_child('main')->children('location');
    my %locations = ();
    foreach my $loc (@locs) {
      my $ref = $loc->first_child('referral');
      $locations{$loc->{'att'}->{'name'}} = {
        'tls'       => 0,
        'uri'       => $ref->{'att'}->{'URI'},
        '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
      }
    }

    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}->{'uri'} =~ qr|^(.*)/([^/]+)$|) {
      $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 informations 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");
    } 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(SECRETS, $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 (LDAPCONF,$vars{ldap_conf}) or die ("! Failed to open ldap config file '$vars{ldap_conf}': $!\n");

    my %tls_options = (
      'REQCERT'   => 'require',
      'CERT'      => '',
      'KEY'       => '',
      'CACERTDIR' => ''
    );
    # Scan LDAP config
    while (<LDAPCONF>) {
      /^\s*(#|$)/ && next;
      chomp;
      if (m/^TLS_(REQCERT|CERT|KEY|CACERTDIR)\s+(.*)\s*$/) {
        $tls_options{$1} = $2;
      }
    }
    close(LDAPCONF);

    $ldap->start_tls(
      verify      => $tls_options{'REQCERT'},
      clientcert  => $tls_options{'CERT'},
      clientkey   => $tls_options{'KEY'},
      capath      => $tls_options{'CACERTDIR'}
    );
  }

  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);
          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=gosaAccount)"
            );
            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=gosaAccount)(|(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 exists\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) = @_;
  my $branch_add = $ldap->add( "ou=$ou,$base",
    attr => [
      'ou'  => $ou,
      'objectClass' =>  'organizationalUnit'
      ]
  );

  $branch_add->code && die "! failed to add LDAP's ou=$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 => $peopleou);
  $people->code && die $people->error;
  my @people_entries = $people->entries;
  @people_entries = map {$_->dn} @people_entries;

  # if ou=people exists
  if ( branch_exists($ldap, "$peopleou,$base") ) {
    check_admin($base, $ldap, \@people_entries);

  # if ou=people doesn't exists
  } else {
    print ( "! $peopleou,$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, $oupeople);
      push @people_entries, "$peopleou,$base";
      check_admin($base, $ldap, \@people_entries);
    } else {
      print ("Skiping...\n");
    }
  }

  # if ou=groups does not exist
  if (!branch_exists($ldap, "ou=groups,$base")) {
    print ("! ou=groups,$base not found in your LDAP directory\n");

    # if user's answer is "yes", creating ou=groups branch
    if ( ask_yn_question("Do you want to create it ?: ") ) {
      create_branch($ldap, $base, 'groups');
    } else {
      print ("skiping...\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";
    }
  }

  # unbind to the LDAP server
  my $unbind = $ldap->unbind;
  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
}

# function that migrate old FAI repos
sub migrate_repo {

  # 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 FAI repository server
  my $fai_repo = $ldap->search (base => $base, filter => "(&(FAIrepository=*)(objectClass=FAIrepositoryServer))");
  $fai_repo->code && die $fai_repo->error;

  # stock search's results
  my @fai_entries = $fai_repo->entries;

  foreach my $repoServer (@fai_entries) {
    # retrieve the FAIrepository from the LDAP object
    my $ref_FAIrepo = $repoServer->get_value('fairepository', asref=>1);
    my @repos;

    # foreach FAIrepository of the LDAP object
    foreach my $repo (@{$ref_FAIrepo}) {
      my (@items) = split('\|',$repo);
      # Unless the FAIrepository has already been migrated
      if (scalar @items < 5) {
        print "modifying $repo\n";
        push @repos, $repo."|install|local|i386";
      } elsif (scalar @items < 6) {
        print "repository $repo seems malformed\n";
        push @repos, $repo;
      } elsif (scalar @items < 7) {
        print "modifying $repo\n";
        push @repos, $repo."|i386";
      } else {
        print "keeping $repo\n";
        push @repos, $repo;
      }
    }
    my $modify = $ldap->modify ($repoServer->dn, replace => [ FAIrepository => \@repos]);
    $modify->code && warn "! Unable to modify FAI repositories for ".$repoServer->dn." : ".$modify->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 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 {
 say ("This option is not available for RPM setups - Please use the official RPMs");

  }

  #finally update FusionDirectory's class.cache and locales
  rescan_classes();
  rescan_i18n();

# function that add object classes to people branch users
sub migrate_users {
  my $scope="one";

  # 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};

  print ("Add FusionDirectory attributes for the following users from $peopleou,$base\n");
  print ("---------------------------------------------\n");

  my $mesg = $ldap->search(
    filter => "(|(!(objectClass~=gosaAccount))(!(objectClass~=organizationalPerson))(!(objectClass~=Person)))",
    base   => "$peopleou,$base",
    scope  => $scope
  );
  $mesg->code && die $mesg->error;
  my @entries = $mesg->entries;

  foreach my $entry (@entries) {
    $mesg = $ldap->modify($entry->dn(), add => { "ObjectClass" => "gosaAccount"});
    $mesg = $ldap->modify($entry->dn(), add => { "ObjectClass" => "organizationalPerson"});
    $mesg = $ldap->modify($entry->dn(), add => { "ObjectClass" => "Person"});
    print $entry->dn();
    print "\n";
  }
  # unbind to the LDAP server
  my $unbind = $ldap->unbind;
  $unbind->code && warn "! Unable to unbind from LDAP server: ", $unbind->error."\n";
}

sub migrate_acls {
  # 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 => "(gosaAclEntry=*)",
    attrs => ['gosaAclEntry']
  );
  $mesg->code && die $mesg->error;

  while (my $entry = $mesg->shift_entry) {
    my $acls = $entry->get_value('gosaAclEntry', asref => 1);
    my @nacls = ();
    my $old_formats = 0;
    ACL: foreach my $acl (@$acls) {
      my $old_format = 0;
      my ($index,$scope,$part1,$part2,$filter);
      if ($acl =~ m/:(p?sub|role):/) {
        $old_format = 1;
        ($index,$scope,$part1,$part2,$filter) = split(':', $acl);
      } elsif ($acl !~ m/:subtree:/) {
        # With one or base scope we can't know, we have to check other parts
        ($index,$scope,$part1,$part2,$filter) = split(':', $acl);
        my $dn = decode_base64($part1);
        $mesg = $ldap->search(
          base    => "$dn",
          scope   => 'base',
          filter  => '(objectClass=gosaRole)'
        );
        die_on_ldap_errors($mesg);
        if ($mesg->count == 0) {
          $old_format = 1;
        }
      }
      if ($old_format) {
        $old_formats = 1;
        print "$acl needs migration\n";
        my ($role_dn, $members);
        if ($scope eq 'role') {
          $role_dn = decode_base64($part1);
          $members = $part2;
          # Find scope in role
          $mesg = $ldap->search(
            base    => $role_dn,
            scope   => 'base',
            filter  => '(objectClass=gosaRole)'
          );
          die_on_ldap_errors($mesg);
          if (my $role_entry = $mesg->shift_entry) {
            my $acl_templates = $role_entry->get_value('gosaAclTemplate', asref => 1);
            my $scope = '';
            foreach my $acl_template (@$acl_templates) {
              my ($t_index,$t_scope,$t_acl) = split(':',$acl_template);
              if ($scope eq '') {
                $scope = $t_scope;
              } elsif ($scope ne $t_scope) {
                print "We don't know how to migrate role $role_dn as it contains several scopes\n";
                push @nacls, $acl;
                next ACL;
              }
            }
            push @nacls, "$index:$scope:".encode_base64($role_dn).":$members";
          } else {
            # Removing invalid ACL
            print "Removing acl as associated role $role_dn does not exists\n";
            next ACL;
          }
        } else {
          my $cn = find_free_role_dn($ldap,$base,'migrated-acl');
          $role_dn = create_role($ldap,$base,$cn,$part2);
          $members = $part1;
          if ($scope =~ m/sub$/) {
            $scope = 'subtree';
          }
          push @nacls, "$index:$scope:".encode_base64($role_dn).":$members";
        }
      } else {
        push @nacls, $acl;
      }
    }
    if ($old_formats) {
      @nacls = sort @nacls;
      my $i = 0;
      map { s/^[0-9]*:/$i:/; $i++ } @nacls; # Re-index acls
      my $result = $ldap->modify (
        $entry->dn,
        replace => {
          'gosaAclEntry'  => \@nacls
        }
      );
      $result->code && warn "\n! failed to migrate ACL for '".$entry->dn."' - ".$result->error_name.": ".$result->error_text;
      print "Migrated acls for '".$entry->dn."'\n";
    }
  }

  # Search for old formatted ACL roles
  $mesg = $ldap->search(
    base => "$base",
    filter => "(gosaAclTemplate=*:*:*)",
    attrs => ['gosaAclTemplate']
  );
  $mesg->code && die $mesg->error;
  ROLE: while (my $role_entry = $mesg->shift_entry) {
    my $acl_templates = $role_entry->get_value('gosaAclTemplate', asref => 1);
    my $scope = '';
    my @ntemplates = ();
    foreach my $acl_template (@$acl_templates) {
      my ($t_index,$t_scope,$t_acl) = split(':',$acl_template);
      if ($scope eq '') {
        $scope = $t_scope;
      } elsif ($scope ne $t_scope) {
        print "We don't know how to migrate role '".$role_entry->dn."' as it contains several scopes\n";
        next ROLE;
      }
      push @ntemplates, $t_index.':'.$t_acl;
    }
    my $result = $ldap->modify (
      $role_entry->dn,
      replace => {
        'gosaAclTemplate'  => \@ntemplates
      }
    );
    $result->code && warn "\n! failed to migrate ACL for '".$role_entry->dn."' - ".$result->error_name.": ".$result->error_text;
    print "Migrated role '".$role_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);
}

# 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)).')';
  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 $entry->dn." contains an obsolete attribute\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) {
    while (my $entry = $entries->shift_entry) {
      print $entry->dn." uses an obsolete object class\n";
    }
  } else {
    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)).')';

  # 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";
  }
}

# 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;

  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];
  $commands{"--migrate-repositories"} = ["Migrating your FAI repositories",               \&migrate_repo];
  $commands{"--migrate-users"}        = ["Migrating your users",                          \&migrate_users];
  $commands{"--migrate-acls"}         = ["Migrating your ACLs",                           \&migrate_acls];
  $commands{"--install-plugins"}      = ["Installing FusionDirectory's plugins",          \&install_plugins];
  $commands{"--encrypt-passwords"}    = ["Encrypt passwords in fusiondirectory.conf",     \&encrypt_passwords];
  $commands{"--write-vars"}           = ["Choose FusionDirectory Directories",            \&write_vars];
  $commands{"--list-vars"}            = ["List possible vars to give --set",              \&list_vars];
  $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{"--set-VAR=value"}        = ["Set the variable VAR to value see --list-vars", \&die]; # Won't be called because it contains uppercase

  my $usage = 0;

  set_vars();

  foreach my $arg ( @ARGV ) {
    if (( lc($arg) =~ m/^--set-(.*)=(.*)/ ) && (grep {$_ eq lc($1)} @vars_keys)) {
      $vars{lc($1)} = $2;
      print "Setting $1 to $2\n";
      set_vars();
    } elsif ( defined $commands { lc ( $arg ) } ) {
      my @command = @{ $commands{ $arg } };
      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 setup script

=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, changes destinations directories, and migrate your old FAIrepositories.

=head2 Options

=over 4

=item --update-cache

This option update the /var/cache/fusiondirectory/class.cache file. Wich 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 don't exists, the script will ask you what to do.

=item --migrate-repositories

This option check the fairepository object in your ldap tree and add the new option for FusionDirectory 1.0.2.

=item --migrate-users

This option add FusionDirectory attributes to the people branch.

=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 --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 --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 --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 --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_dir   	[/usr/share/php/smarty3]
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://forge.fusiondirectory.org/projects/fdirectory/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-2013  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