Code

Updated department handling for the rootDSE entry.
[gosa.git] / gosa-core / include / class_userinfo.inc
index 77015dad2290a8992a921968fd50cb3281efdf62..4045821ba85e0d5311ce31f6360678db2e522c6c 100644 (file)
@@ -1,21 +1,23 @@
 <?php
 /*
-   This code is part of GOsa (https://gosa.gonicus.de)
-   Copyright (C) 2003-2005  Cajus Pollmeier
-
-   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This code is part of GOsa (http://www.gosa-project.org)
+ * Copyright (C) 2003-2008 GONICUS GmbH
+ *
+ * ID: $$Id$$
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 class userinfo
@@ -175,32 +177,133 @@ class userinfo
 
   function get_category_permissions($dn, $category)
   {
+    /* If we are forced to skip ACLs checks for the current user 
+        then return all permissions.
+     */
+    if($this->ignore_acl_for_current_user()){
+      return("rwcdm");
+    }
+
     /* Get list of objectClasses and get the permissions for it */
     $acl= "";
     if (isset($this->ocMapping[$category])){
       foreach($this->ocMapping[$category] as $oc){
         $acl.= $this->get_permissions($dn, $category."/".$oc);
       }
+    }else{
+      trigger_error("ACL request for an invalid category (".$category.").");
     }
 
     return ($acl);
   }
 
+  
+  /*! \brief Check if the given object (dn) is copyable
+      @param  String The object dn 
+      @param  String The acl  category (e.g. users) 
+      @param  String The acl  class (e.g. user) 
+      @return Boolean   TRUE if the given object is copyable else FALSE 
+  */
+  function is_copyable($dn, $object, $class)
+  {
+    return(preg_match("/r/",$this->has_complete_category_acls($dn, $object)));
+  }
+
+
+  /*! \brief Check if the given object (dn) is cutable
+      @param  String The object dn 
+      @param  String The acl  category (e.g. users) 
+      @param  String The acl  class (e.g. user) 
+      @return Boolean   TRUE if the given object is cutable else FALSE 
+  */
+  function is_cutable($dn, $object, $class)
+  {
+    $remove = preg_match("/d/",$this->get_permissions($dn,$object."/".$class));
+    $read   = preg_match("/r/",$this->has_complete_category_acls($dn, $object));
+    return($remove && $read);
+  }
+
+
+  /*! \brief  Checks if we are allowed to paste an object to the given destination ($dn)
+      @param  String The destination dn 
+      @param  String The acl  category (e.g. users) 
+      @param  String The acl  class (e.g. user) 
+      @return Boolean   TRUE if we are allowed to paste an object.
+  */
+  function is_pasteable($dn, $object)
+  {
+    return(preg_match("/w/",$this->has_complete_category_acls($dn, $object)));
+  }
+
+
+  /*! \brief  Checks if we are allowed to restore a snapshot for the given dn.
+      @param  String The destination dn 
+      @param  String The acl  category (e.g. users) 
+      @return Boolean   TRUE if we are allowed to restore a snapshot.
+  */
+  function allow_snapshot_restore($dn, $object)
+  {
+    if(!is_array($object)){
+      $object = array($object);
+    }
+    $r = $w = $c = TRUE;
+    foreach($object as $category){
+      $w &= preg_match("/w/",$this->has_complete_category_acls($dn, $category));
+      $c &= preg_match("/c/",$this->has_complete_category_acls($dn, $category));
+      $r &= preg_match("/r/",$this->has_complete_category_acls($dn, $category));
+#     print_a(array($category => array($r.$w.$c)));
+    }
+    return($r && $w ); 
+  }  
+
+
+  /*! \brief  Checks if we are allowed to create a snapshot of the given dn.
+      @param  String The source dn 
+      @param  String The acl category (e.g. users) 
+      @return Boolean   TRUE if we are allowed to restore a snapshot.
+  */
+  function allow_snapshot_create($dn, $object)
+  {
+    if(!is_array($object)){
+      $object = array($object);
+    }
+    $r = $w = $c = TRUE;
+    foreach($object as $category){
+      $w &= preg_match("/w/",$this->has_complete_category_acls($dn, $category));
+      $c &= preg_match("/c/",$this->has_complete_category_acls($dn, $category));
+      $r &= preg_match("/r/",$this->has_complete_category_acls($dn, $category));
+#      print_a(array($category => array($r.$w.$c)));
+    }
+    return($r) ; 
+  }  
+
 
   function get_permissions($dn, $object, $attribute= "", $skip_write= FALSE)
   {
+    /* If we are forced to skip ACLs checks for the current user 
+        then return all permissions.
+     */
+    if($this->ignore_acl_for_current_user()){
+      return("rwcdm");
+    }
+
     /* Push cache answer? */
-    if (isset($_SESSION['ACL_CACHE']["$dn+$object+$attribute"])){
+    $ACL_CACHE = &session::get('ACL_CACHE');
+    if (isset($ACL_CACHE["$dn+$object+$attribute"])){
 
       /* Remove write if needed */
       if ($skip_write){
-        $ret = preg_replace('/w/', '', $_SESSION['ACL_CACHE']["$dn+$object+$attribute"]);
+        $ret = preg_replace('/w/', '', $ACL_CACHE["$dn+$object+$attribute"]);
       }else{
-        $ret = $_SESSION['ACL_CACHE']["$dn+$object+$attribute"];
+        $ret = $ACL_CACHE["$dn+$object+$attribute"];
       } 
       return($ret);
     }
 
+    /* Get ldap object, for later filter checks 
+     */
+    $ldap = $this->config->get_ldap_link();
+
     $acl= array("r" => "", "w" => "", "c" => "", "d" => "", "m" => "", "a" => "");
 
     /* Build dn array */
@@ -212,13 +315,16 @@ class userinfo
     foreach ($path as $element){
 
       /* Clean potential ACLs for each level */
-      $acl= $this->cleanACL($acl);
+      if(in_array($cpath,$this->config->departments)){
+        $acl= $this->cleanACL($acl);
+      }
 
       if ($cpath == ""){
         $cpath= $element;
       } else {
         $cpath= $element.','.$cpath;
       }
+
       if (isset($this->ACL[$cpath])){
 
         /* Inspect this ACL, place the result into ACL */
@@ -235,6 +341,43 @@ class userinfo
             continue;
           }
 
+          /* With user filter */
+          if (isset($subacl['filter']) && !empty($subacl['filter'])){
+            $sdn = preg_replace("/^[^,]*+,/","",$dn);
+            $ldap->cd($sdn);
+            $ldap->ls($subacl['filter'],$sdn);
+            if(!$ldap->count()){
+              continue;
+            }else{
+              $found = FALSE; 
+              while($attrs = $ldap->fetch()){
+                if($attrs['dn'] == $dn){
+                  $found = TRUE;
+                  break;
+                }
+              }
+              if(!$found){
+                continue;
+              }
+            }
+          }
+
+          /* Self ACLs? 
+           */
+          if(isset($subacl['acl'][$object][0]) && preg_match("/s/",$subacl['acl'][$object][0]) && $dn != $this->dn){
+            continue;
+          }
+
+          /* If attribute is "", we want to know, if we've *any* permissions here... 
+              Merge global class ACLs [0] with attributes specific ACLs [attribute].
+           */
+          if ($attribute == "" && isset($subacl['acl'][$object])){
+            foreach($subacl['acl'][$object] as $attr => $dummy){
+              $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attr]);
+            }
+            continue;
+          }
+
           /* Per attribute ACL? */
           if (isset($subacl['acl'][$object][$attribute])){
             $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attribute]);
@@ -252,28 +395,26 @@ class userinfo
             $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']['all'][0]);
             continue;
           }
-
-          /* If attribute is "", we want to know, if we've *any* permissions here... */
-          if ($attribute == "" && isset($subacl['acl'][$object])){
-            foreach($subacl['acl'][$object] as $attr => $dummy){
-              $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attr]);
-            }
-            continue;
-          }
-
         }
       }
     }
 
+    /* If the requested ACL is for a container object, then alter 
+        ACLs by applying cleanACL a last time.
+     */
+    if(in_array($dn,$this->config->departments)){
+      $acl = $this->cleanACL($acl);
+    }
+
     /* Assemble string */
     $ret= "";
     foreach ($acl as $key => $value){
-      if ($value != ""){
+      if ($value !== ""){
         $ret.= $key;
       }
     }
 
-    $_SESSION['ACL_CACHE']["$dn+$object+$attribute"]= $ret;
+    $ACL_CACHE["$dn+$object+$attribute"]= $ret;
 
     /* Remove write if needed */
     if ($skip_write){
@@ -285,11 +426,20 @@ class userinfo
 
   /* Extract all departments that are accessible (direct or 'on the way' to an
      accessible department) */
-  function get_module_departments($module)
+  function get_module_departments($module, $skip_self_acls = FALSE )
   {
+    
+    /* If we are forced to skip ACLs checks for the current user 
+        then return all departments as valid.
+     */
+    if($this->ignore_acl_for_current_user()){
+      return(array_keys($this->config->idepartments));
+    }
+
     /* Use cached results if possilbe */
-    if(isset($_SESSION['ACL_CACHE']['MODULE_DEPARTMENTS'][serialize($module)])){
-      return($_SESSION['ACL_CACHE']['MODULE_DEPARTMENTS'][serialize($module)]);
+    $ACL_CACHE = session::get('ACL_CACHE');
+    if(isset($ACL_CACHE['MODULE_DEPARTMENTS'][serialize($module)])){
+      return($ACL_CACHE['MODULE_DEPARTMENTS'][serialize($module)]);
     }
 
     global $plist;
@@ -315,76 +465,63 @@ class userinfo
       }
     }
 
-    /* For all gosaDepartments */
-    foreach ($this->config->departments as $dn){
-      $acl= array("r" => "", "w" => "", "c" => "", "d" => "", "m" => "", "a" => "");
-
-      /* Build dn array */
-      $path= split(',', $dn);
-      $path= array_reverse($path);
-
-      /* Walk along the path to evaluate the acl */
-      $cpath= "";
-      foreach ($path as $element){
-
-        /* Clean potential ACLs for each level */
-        $acl= $this->cleanACL($acl);
-
-        if ($cpath == ""){
-          $cpath= $element;
-        } else {
-          $cpath= $element.','.$cpath;
-        }
-        if (isset($this->ACL[$cpath])){
-
-          /* Inspect this ACL, place the result into ACL */
-          foreach ($this->ACL[$cpath] as $subacl){
-
-            /* Reset? Just clean the ACL and turn over to the next one... */
-            if ($subacl['type'] == 'reset'){
-              $acl= $this->cleanACL($acl, TRUE);
-              continue;
-            }
-    
-            if($subacl['type'] == 'role'){
-              echo "role skipped";
-              continue;
-            }
-
-            /* Per object ACL? */
-            foreach ($objects as $object){
-              if (isset($subacl['acl']["$module/$object"])){
-                foreach($subacl['acl']["$module/$object"] as $attribute => $dcl){
-                  $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["$module/$object"][$attribute]);
-                }
+    /* Search for per object ACLs. 
+     */
+    $this->config->get_departments();
+    $this->config->make_idepartments();
+
+    foreach($this->ACL as $dn => $infos){
+      foreach($infos as $info){
+        $found = FALSE;
+        foreach($info['acl'] as $cat => $data){
+
+          /* Skip self acls? */
+          if($skip_self_acls && isset($data['0']) && preg_match("//s",$data['0'])) continue;
+
+          if(is_array($module)){
+            foreach($module as $mod){
+              if(preg_match("/^".normalizePreg($mod)."/",$cat)){
+                $found =TRUE;
+                break;
               }
             }
-
-            /* Global ACL? */
-            if (isset($subacl['acl']["$module/all"][0])){
-              $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["$module/all"][0]);
-              continue;
+          }else{
+            if(preg_match("/^".normalizePreg($module)."/",$cat)){
+              $found =TRUE;
+              break;
             }
+          }
+        } 
 
-            /* Global ACL? */
-            if (isset($subacl['acl']["all"][0])){
-              $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["all"][0]);
-              continue;
-            }
+        if($found && !isset($this->config->idepartments[$dn])){
+          while(!isset($this->config->idepartments[$dn]) && preg_match("/,/",$dn)){
+            $dn = preg_replace("/^[^,]+,/","",$dn);
+          }
+          if(isset($this->config->idepartments[$dn])){
+            $deps[] = $dn;
           }
         }
       }
+    }
 
-      /* Add department, if we have (some) permissions for the required module */
-      foreach ($acl as $val){
-        if ($val != ""){
-          $deps[]= $dn;
-          break;
+    /* For all gosaDepartments */
+    foreach ($this->config->departments as $dn){
+      if(!is_array($module)){
+        $module = array($module);
+      }
+      $acl = "";
+      foreach($module as $mod){
+        if(preg_match("/\//",$mod)){
+          $acl.=  $this->get_permissions($dn,$mod);
+        }else{
+          $acl.=  $this->get_category_permissions($dn,$mod);
         }
       }
+      if($acl !== "") $deps[] = $dn;
     }
-
-    $_SESSION['ACL_CACHE']['MODULE_DEPARTMENTS'][serialize($module)] = $deps;
+  
+    $ACL_CACHE = &session::get('ACL_CACHE');
+    $ACL_CACHE['MODULE_DEPARTMENTS'][serialize($module)] = $deps;
     return ($deps);
   }
 
@@ -497,6 +634,16 @@ class userinfo
     }
     return($acl);
   }
+
+  /*! \brief  Returns TRUE if the current user is configured in IGNORE_ACL=".." in your gosa.conf 
+      @param  Return Boolean TRUE if we have to skip ACL checks else FALSE.
+   */ 
+  function ignore_acl_for_current_user()
+  {
+    return(isset($this->config->current['IGNORE_ACL']) && $this->config->current['IGNORE_ACL'] == $this->dn);
+  }
+
 }
 
 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: