From c90f52db11944d60de1c2308fdecdf1b225de552 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come@opensides.be>
Date: Tue, 7 Aug 2018 14:56:46 +0200
Subject: [PATCH] :ambulance: fix(core) Fix create_missing_trees to be able to
 snapshot in locality, amond other things

Changed code so that common department classes are hardcoded to speed up
 process and avoid weird classes like residentialPerson instead of
 locality.
Also fixed code so that MUST attributes from all classes of the
 hierarchy are filled whether autodetection is used or not.

issue #5861
---
 include/class_ldap.inc | 140 +++++++++++++++++++++--------------------
 1 file changed, 73 insertions(+), 67 deletions(-)

diff --git a/include/class_ldap.inc b/include/class_ldap.inc
index 7c218cb3d..ad22fcfa1 100644
--- a/include/class_ldap.inc
+++ b/include/class_ldap.inc
@@ -733,7 +733,7 @@ class LDAP
     $real_path = substr($target, 0, strlen($target) - strlen($this->basedn) - 1);
 
     if ($target == $this->basedn) {
-      $l = array("dummy");
+      $l = array('dummy');
     } else {
       $l = array_reverse(ldap_explode_dn($real_path, 0));
     }
@@ -744,111 +744,117 @@ class LDAP
     $classes = $this->get_objectclasses();
 
     foreach ($l as $part) {
-      if ($part != "dummy") {
+      if ($part != 'dummy') {
         $cdn = "$part,$cdn";
       }
 
       /* Ignore referrals */
       if ($ignoreReferralBases) {
-        $found = FALSE;
         foreach ($this->referrals as $ref) {
           if ($ref['BASE'] == $cdn) {
-            $found = TRUE;
-            break;
+            continue 2;
           }
         }
-        if ($found) {
-          continue;
-        }
       }
 
       $this->cat ($srp, $cdn);
       $attrs = $this->fetch($srp);
 
       /* Create missing entry? */
-      if (!count($attrs)) {
-        $type   = preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
-        $param  = preg_replace('/^[^=]+=([^,]+).*$/', '\\1', $cdn);
-        $param  = preg_replace(array('/\\\\,/','/\\\\"/'), array(',','"'), $param);
+      if (count($attrs)) {
+        continue;
+      }
 
-        $na = array();
+      $type   = preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
+      $param  = preg_replace('/^[^=]+=([^,]+).*$/', '\\1', $cdn);
+      $param  = preg_replace(array('/\\\\,/','/\\\\"/'), array(',','"'), $param);
 
-        /* Automatic or traditional? */
-        if (count($classes)) {
+      $attrs = array($type => $param);
+
+      /* Hardcoded classes */
+      switch ($type) {
+        case 'ou':
+          $attrs['objectClass']  = array('organizationalUnit');
+          break;
+        case 'd':
+          $attrs['objectClass']  = array('domain');
+          break;
+        case 'dc':
+          $attrs['objectClass']  = array('dcObject');
+          break;
+        case 'o':
+          $attrs['objectClass']  = array('organization');
+          break;
+        case 'l':
+          $attrs['objectClass']  = array('locality');
+          break;
+        case 'c':
+          $attrs['objectClass']  = array('country');
+          break;
+        default:
+          /* Fallback to autodetection of objectClass */
+          if (!count($classes)) {
+            msg_dialog::display(_('Internal error'), sprintf(_('Cannot automatically create subtrees with RDN "%s": not supported'), $type), FATAL_ERROR_DIALOG);
+            exit();
+          }
           /* Get name of first matching objectClass */
-          $ocname = "";
+          $attrs['objectClass']  = array();
           foreach ($classes as $class) {
             if (isset($class['MUST']) && in_array($type, $class['MUST'])) {
-
-              /* Look for first classes that is structural... */
+              /* Look for first class that is structural... */
               if (isset($class['STRUCTURAL'])) {
-                $ocname = $class['NAME'];
+                $attrs['objectClass'] = array($class['NAME']);
                 break;
               }
 
-              /* Look for classes that are auxiliary... */
-              if (isset($class['AUXILIARY'])) {
-                $ocname = $class['NAME'];
+              /* Look for class that is auxiliary... */
+              if (empty($attrs['objectClass']) && isset($class['AUXILIARY'])) {
+                $attrs['objectClass'] = array($class['NAME']);
               }
+            } elseif (empty($attrs['objectClass']) && isset($class['MAY']) && in_array($type, $class['MAY'])) {
+              /* Better than nothing */
+              $attrs['objectClass'] = array($class['NAME']);
             }
           }
 
           /* Bail out, if we've nothing to do... */
-          if ($ocname == '') {
+          if (empty($attrs['objectClass'])) {
             msg_dialog::display(_('Internal error'), sprintf(_('Cannot automatically create subtrees with RDN "%s": no object class found!'), $type), FATAL_ERROR_DIALOG);
             exit();
           }
+      }
 
-          /* Assemble_entry */
-          $na['objectClass'] = array($ocname);
-          if (isset($classes[$ocname]['AUXILIARY'])) {
-            $na['objectClass'][] = $classes[$ocname]['SUP'];
-          }
-          if ($type == 'dc') {
-            /* This is bad actually, but - tell me a better way? */
-            $na['objectClass'][]  = 'organization';
-            $na['o']              = $param;
-          }
-          $na[$type] = $param;
+      $ocname = $attrs['objectClass'][0];
+      while (isset($classes[$ocname]['SUP']) && ($classes[$ocname]['SUP'] != 'top')) {
+        $ocname                 = $classes[$ocname]['SUP'];
+        $attrs['objectClass'][] = $ocname;
+      }
 
-          // Fill in MUST values - but do not overwrite existing ones.
-          if (is_array($classes[$ocname]['MUST'])) {
-            foreach ($classes[$ocname]['MUST'] as $attr) {
-              if (isset($na[$attr]) && !empty($na[$attr])) {
-                continue;
-              }
-              $na[$attr] = 'filled';
+      if (isset($classes[$ocname]['AUXILIARY'])) {
+        /* AUXILIARY class, we have to add a STRUCTURAL one */
+        $attrs['objectClass'][] = 'organization';
+      }
+
+      foreach ($attrs['objectClass'] as $ocname) {
+        // Fill in MUST values - but do not overwrite existing ones.
+        if (is_array($classes[$ocname]['MUST'])) {
+          foreach ($classes[$ocname]['MUST'] as $attr) {
+            if (empty($attrs[$attr])) {
+              $attrs[$attr] = $param;
             }
           }
-        } else {
-          /* Use alternative add... */
-          switch ($type) {
-            case 'ou':
-              $na['objectClass']  = 'organizationalUnit';
-              $na['ou']           = $param;
-              break;
-            case 'dc':
-              $na['objectClass']  = array('dcObject', 'top', 'organization');
-              $na['dc']           = $param;
-              $na['o']            = $param;
-              break;
-            default:
-              msg_dialog::display(_('Internal error'), sprintf(_('Cannot automatically create subtrees with RDN "%s": not supported'), $type), FATAL_ERROR_DIALOG);
-              exit();
-          }
-
         }
-        $this->cd($cdn);
-        $this->add($na);
+      }
+      $this->cd($cdn);
+      $this->add($attrs);
 
-        if (!$this->success()) {
-          @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $cdn, 'dn');
-          @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $na, 'Content');
-          @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->get_error(), 'LDAP error');
+      if (!$this->success()) {
+        @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $cdn, 'dn');
+        @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $attrs, 'Content');
+        @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->get_error(), 'LDAP error');
 
-          msg_dialog::display(_('LDAP error'), msgPool::ldaperror($this->get_error(), $cdn, LDAP_ADD, get_class()), LDAP_ERROR);
-          return FALSE;
-        }
+        msg_dialog::display(_('LDAP error'), msgPool::ldaperror($this->get_error(), $cdn, LDAP_ADD, get_class()), LDAP_ERROR);
+        return FALSE;
       }
     }
 
-- 
GitLab