diff --git a/bin/ldap-schema-manager b/bin/ldap-schema-manager
new file mode 100755
index 0000000000000000000000000000000000000000..aa90126911218f9ef5e4a38723f3314d436bb765
--- /dev/null
+++ b/bin/ldap-schema-manager
@@ -0,0 +1,444 @@
+#!/usr/bin/perl
+
+########################################################################
+#
+# ldap-schema-manager
+#
+# Manipulate, insert and update schemas into the ldap server
+#
+#  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
+#  Copyright (C) 2011-2017  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;
+
+my $ldap_host_options = '-Y EXTERNAL -H ldapi:///';
+my $path              = "/etc/ldap/schema/";
+my $full_cmd          = "";
+my $schema2ldif       = "schema2ldif";
+
+my $listschemas = 0;
+my $modify      = 0;
+my $schemalist  = 0;
+my $yes_flag    = 0;
+my $pathunset   = 1;
+my $continue    = 0;
+my @schemas     = ();
+my @gen_files   = ();
+my $delete_ldif = 1;
+foreach my $arg ( @ARGV ) {
+  if (not defined $ldap_host_options) {
+    $ldap_host_options = $arg;
+  } elsif ((lc($arg) eq '-i') || (lc($arg) eq '--insert')) {
+    if ($schemalist) {
+      usage();
+    }
+    $schemalist = 1;
+  } elsif ((lc($arg) eq '-l') || (lc($arg) eq '--list')) {
+    $listschemas = 1;
+  } elsif ((lc($arg) eq '-c') || (lc($arg) eq '--continue')) {
+    $continue = 1;
+  } elsif ((lc($arg) eq '-e') || (lc($arg) eq '--empty')) {
+    if ($schemalist) {
+      usage();
+    }
+    $modify = 2;
+    $schemalist = 1;
+  } elsif ((lc($arg) eq '-m') || (lc($arg) eq '--modify')) {
+    if ($schemalist) {
+      usage();
+    }
+    $modify = 1;
+    $schemalist = 1;
+  } elsif ((lc($arg) eq '-o') || (lc($arg) eq '--options')) {
+    undef $ldap_host_options;
+  } elsif ((lc($arg) eq '-n') || (lc($arg) eq '--nodelete')) {
+    $delete_ldif = 0;
+  } elsif ((lc($arg) eq '-y') || (lc($arg) eq '--yes')) {
+    $yes_flag = 1;
+  } elsif ((lc($arg) eq '-h') || (lc($arg) eq '--help')) {
+    usage();
+  } elsif ($schemalist) {
+    if ($arg !~ m|/|) {
+      # add path prefix if not a path
+      $arg = $path.$arg;
+    }
+    if ($arg =~ /^(.*)\.ldif$/) {
+      # ignore ".ldif" if it is there
+      push @schemas, $1;
+    } elsif ($arg =~ /^(.*)\.schema$/) {
+      if (system("$schema2ldif $arg > $1.ldif") == 0) {
+        push @schemas, $1;
+        push @gen_files, $1;
+      } else {
+        push @gen_files, $1;
+        die_with_error("Something went wrong while trying to convert $arg to ldif\n");
+      }
+    } else {
+      push @schemas, $arg;
+    }
+  } elsif ($pathunset) {
+    $path = $arg;
+    if ($path !~ m|/$|) {
+      # add path prefix if not a path
+      $path = $path."/";
+    }
+    $pathunset = 0;
+  } else {
+    usage();
+  }
+}
+
+# if --options is used with no value
+usage () if (not defined $ldap_host_options);
+
+# die if user is not "root"
+die_with_error ("! You have to run this script as root\n") if ($<!=0);
+
+my $add_cmd         = "ldapadd $ldap_host_options -f ";
+my $mod_cmd         = "ldapmodify $ldap_host_options -f ";
+my $ldapsearch      = "ldapsearch $ldap_host_options ";
+my $search_cmd      = $ldapsearch." -b \"cn=schema,cn=config\" cn={*}";
+my $list_cmd        = $search_cmd."* cn 2>/dev/null";
+my $cnconfig_cmd    = $ldapsearch." -b \"cn=config\" cn=config dn 2>/dev/null | grep dn:";
+
+if ($listschemas) {
+  list_schemas();
+  exit 0;
+}
+
+# die if the path doesn't exists
+die_with_error ("! $path doesn't seems to exists\n") if (!-e $path);
+
+#die if we are not in cn=config
+my $cnconfig = `$cnconfig_cmd`;
+if (!($cnconfig =~ m/^dn:\s*cn=config$/)) {
+  die_with_error ("! This tool is only intended to be with with a cn=config backend, cn=config could not be found in the LDAP");
+}
+
+if (scalar(@schemas) == 0) {
+  usage("Missing schema list\n");
+}
+
+if ($modify == 2) {
+  unless (ask_yn_question("Are you sure you want to empty schema(s) ".join(", ",@schemas)."?"))
+  {
+    die_with_error("Aborting…\n");
+  }
+}
+
+$continue++; # activating continue feature only for insertions
+
+foreach my $schema (@schemas) {
+  my $schema_name = "";
+  my $ldif_file;
+
+  if ($modify < 2) {
+    # Searching schema name in ldif file first line.
+    open $ldif_file, q{<}, $schema.".ldif" or die "Could not open $schema.ldif file : $!\n";
+    my $dn = "";
+    while ($dn eq "") {
+      chomp($dn = <$ldif_file>);
+    }
+    if ($dn =~ /^dn: cn=([^,]+),/) {
+      $schema_name = $1;
+    }
+    close($ldif_file);
+  }
+
+  # Fallback on file name
+  if ($schema_name eq "") {
+    $schema_name = $schema;
+    $schema_name =~ s|^.*/||;
+  }
+
+  insert_schema($schema, $schema_name);
+}
+
+remove_ldifs();
+
+sub insert_schema
+{
+  my($schema, $schema_name) = @_;
+  my $schema_file;
+  my $update_file;
+  my $empty_file;
+
+  $full_cmd = $search_cmd.$schema_name." cn";
+  print ("\n");
+  my $search = `$full_cmd`;
+
+  if ($search !~ /# numEntries: 1/m) {
+    if ($modify) {
+      print "$schema_name does not exists in the LDAP, skipping…\n";
+    } else {
+      # if the schema doesn't already exists in the LDAP server, adding it
+      $full_cmd = $add_cmd.$schema.".ldif";
+      print "executing '$full_cmd'\n";
+      if (system ($full_cmd) != 0) {
+        die_with_error ("Insertion failed!\n");
+      }
+    }
+  } else {
+    if ($modify) {
+      if ($search !~ m/dn: ([^,]+),cn=schema,cn=config/) {
+        print "Could not parse existing dn for $schema_name, skipping…\n";
+        return;
+      }
+      my $dn_part = $1;
+      # if the schema already exists in the LDAP server, modify it
+      if ($modify == 1) {
+        open($schema_file, q{<}, $schema.".ldif") or die_with_error('Could not open '."<".$schema.".ldif: $!");
+        open($update_file, q{>}, $schema."_update.ldif") or die_with_error('Could not open '.">".$schema."_update.ldif: $!");
+        push @gen_files, $schema."_update";
+        my $attrs   = 0;
+        my $classes = 0;
+        while (<$schema_file>) {
+          next if m/^#/; # remove comments
+          chomp;
+          next if m/^$/; # remove empty lines
+          if (m/^dn: cn=([^,]+),cn=schema,cn=config$/) {
+            print $update_file "dn: $dn_part,cn=schema,cn=config\n";
+            print $update_file "changetype: modify\n";
+            next;
+          }
+          if (!m/^olcAttributeTypes:/ && !m/^olcObjectClasses:/ && !m/^ /) {
+            #skip cn, objectClass, …
+            next;
+          }
+
+          if (!$attrs && $classes) {
+            die "Malformed schema\n";
+          }
+
+          if (!$attrs && m/^olcAttributeTypes:/) {
+            $attrs = 1;
+            print $update_file "replace: olcAttributeTypes\n";
+          }
+          if (!$classes && m/^olcObjectClasses:/) {
+            $classes = 1;
+            print $update_file "-\n";
+            print $update_file "replace: olcObjectClasses\n";
+          }
+
+          print $update_file $_;
+          print $update_file "\n";
+        }
+        close $schema_file;
+        close $update_file;
+      } else { # Emptying schema
+        open($empty_file,  q{>}, $schema."_update.ldif") or die_with_error('Could not open '.">".$schema."_update.ldif: $!");
+        push @gen_files, $schema."_update";
+        print $empty_file "dn: $dn_part,cn=schema,cn=config\n";
+        print $empty_file "changetype: modify\n";
+        print $empty_file "delete: olcAttributeTypes\n";
+        print $empty_file "-\n";
+        print $empty_file "delete: olcObjectClasses\n";
+        print $empty_file "-\n";
+        close $empty_file;
+      }
+      $full_cmd = $mod_cmd.$schema."_update.ldif";
+      print "executing '$full_cmd'\n";
+      if (system ($full_cmd) != 0) {
+        die_with_error ("Insertion failed!\n");
+      }
+    } else {
+      print "$schema_name already exists in the LDAP, skipping…\n";
+    }
+  }
+}
+
+sub remove_ldifs
+{
+  if ($delete_ldif) {
+    foreach my $file (@gen_files) {
+      unlink "$file.ldif" or print "Could not delete $file.ldif\n";
+    }
+  }
+}
+
+sub die_with_error
+{
+  my ($error) = @_;
+  if ($continue == 2) {
+    print "Error: $error\nContinuing…\n";
+  } else {
+    remove_ldifs();
+    die $error;
+  }
+}
+
+sub list_schemas
+{
+  my @schemas = `$list_cmd`;
+  foreach my $schema (@schemas) {
+    if ($schema =~ m/cn:\s*{[0-9]+}(.*)$/) {
+      print "$1\n";
+    }
+  }
+}
+
+# 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;
+    }
+  }
+}
+
+sub usage
+{
+  (@_) && print STDERR "\n@_\n\n";
+
+  print STDERR << "EOF";
+ usage: $0 [-y] [-n] [-c] [-o options] [path] [-h|-l|-i schema1 schema2|-m schema1 schema2|-e schema1 schema2]
+
+  -h, --help      : this (help) message
+  path            : where to find the schemas
+  -i, --insert    : specify the schemas to insert
+  -l, --list      : list inserted schemas
+  -m, --modify    : modify exising inserted schemas
+  -e, --empty     : empty exising inserted schemas (do not remove them)
+  -n, --nodelete  : do not delete generated ldifs at the end
+  -o, --options   : set ldap options used (default is -Y EXTERNAL -H ldapi:///)
+  -c, --continue  : continue on error(s)
+  -y, --yes       : answer yes to all questions
+
+EOF
+  exit -1;
+}
+
+exit 0;
+
+=head1 NAME
+
+ldap-schema-manager - insert schema needed by FusionDirectory into the ldap server
+
+=head1 SYNOPSIS
+
+ldap-schema-manager [-y] [-n] [-c] [-o options] [path] [-h|-l|-i schema1 schema2|-m schema1 schema2|-e schema1 schema2]
+
+=head1 DESCRIPTION
+
+This program will list, insert, empty or modify the ldap schemas into the ldap server.
+If a schema is not listed as a path, it will be searched for in the provided path, or in /etc/ldap/schema/ if no path has been provided. To insert schemas from working directory prepend them with "./".
+Schema with no extension is assumed to be .ldif. Specify .schema if you want the tool to autoconvert the schema to ldif file. See the examples for more information
+
+=head2 Options
+
+=over 6
+
+=item -i
+
+This option insert the given list of schemas
+
+=item -m
+
+This option insert the given list of schemas, replacing already inserted versions of those schemas
+
+=item -e
+
+This option empty the given list of schemas, removing attributes and objectClasses from those.
+This is useful because you cannot delete a schema without restarting slapd.
+
+=item -l
+
+This option list inserted schemas
+
+=item -n
+
+This option will make generated ldifs file to not be deleted after execution. Might be useful to understand errors.
+
+=item -c
+
+This option make the program continue even if an error occur
+
+=item -y
+
+This option answer yes to all questions. The only question right now is the confirmation one when you ask to empty a schema.
+
+=item -o
+
+This option allow you to specify specifics options to give to ldap commands such as ldapmodify,
+but beware that you will not be able to see things like password prompts as the output of these commands is piped.
+
+=back
+
+=head1 EXAMPLES
+
+ admin@ldapserver$ ldap-schema-manager -i /etc/ldap/otherschema/myschema.ldif
+   Insert the schema /etc/ldap/otherschema/myschema.ldif
+
+ admin@ldapserver$ ldap-schema-manager -i /etc/ldap/otherschema/myschema.schema
+   Convert /etc/ldap/otherschema/myschema.schema to ldif and insert it
+
+ admin@ldapserver$ ldap-schema-manager -i myschema
+   Insert the schema myschema.ldif from default directory (/etc/ldap/schema/)
+
+ admin@ldapserver$ ldap-schema-manager -i myschema.schema
+   Insert the schema myschema.schema from default directory (/etc/ldap/schema/)
+
+ admin@ldapserver$ ldap-schema-manager -m /etc/ldap/otherschema/myschema.schema
+   Convert /etc/ldap/otherschema/myschema.schema to ldif and replace the existing schema by this one
+
+ admin@ldapserver$ ldap-schema-manager -e myschema
+   Empty the schema myschema
+
+ admin@ldapserver$ ldap-schema-manager -o "-H ldap://my.ldap.com -ZZ -D 'cn=admin,cn=config' -w password -x" -l
+   Connect to another ldap server and list schemas
+
+=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 AUTHOR
+
+Come Bernigaud
+
+=head1 LICENCE AND COPYRIGHT
+
+This code is part of FusionDirectory <http://www.fusiondirectory.org>
+
+=over 1
+
+=item Copyright (C) 2011-2017 FusionDirectory Project
+
+=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