9ceefc964318b6a2d37c606be882ca94e8ab27cf
1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2003-2005 Cajus Pollmeier
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 class userinfo
22 {
23 var $dn;
24 var $ip;
25 var $username;
26 var $cn;
27 var $uid;
28 var $gidNumber= -1;
29 var $language= "";
30 var $config;
31 var $gosaUnitTag= "";
32 var $subtreeACL= array();
33 var $ACL= array();
34 var $ocMapping= array();
35 var $groups= array();
36 var $result_cache =array();
38 /* get acl's an put them into the userinfo object
39 attr subtreeACL (userdn:components, userdn:component1#sub1#sub2,component2,...) */
40 function userinfo($config, $userdn){
41 $this->config= $config;
42 $ldap= $this->config->get_ldap_link();
43 $ldap->cat($userdn,array('sn', 'givenName', 'uid', 'gidNumber', 'preferredLanguage', 'gosaUnitTag'));
44 $attrs= $ldap->fetch();
46 if (isset($attrs['givenName'][0]) && isset($attrs['sn'][0])){
47 $this->cn= $attrs['givenName'][0]." ".$attrs['sn'][0];
48 } else {
49 $this->cn= $attrs['uid'][0];
50 }
51 if (isset($attrs['gidNumber'][0])){
52 $this->gidNumber= $attrs['gidNumber'][0];
53 }
55 /* Assign user language */
56 if (isset($attrs['preferredLanguage'][0])){
57 $this->language= $attrs['preferredLanguage'][0];
58 }
60 if (isset($attrs['gosaUnitTag'][0])){
61 $this->gosaUnitTag= $attrs['gosaUnitTag'][0];
62 }
64 $this->dn= $userdn;
65 $this->uid= $attrs['uid'][0];
66 $this->ip= $_SERVER['REMOTE_ADDR'];
67 }
70 function loadACL()
71 {
72 $this->ACL= array();
73 $this->groups= array();
74 $this->result_cache =array();
75 $ldap= $this->config->get_ldap_link();
76 $ldap->cd($this->config->current['BASE']);
78 /* Get member groups... */
79 $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->uid."))", array('dn'));
80 while ($attrs= $ldap->fetch()){
81 $this->groups[$attrs['dn']]= $attrs['dn'];
82 }
84 /* Crawl through ACLs and move relevant to the tree */
85 $ldap->search("(objectClass=gosaACL)", array('dn', 'gosaAclEntry'));
86 $aclp= array();
87 $aclc= array();
88 while ($attrs= $ldap->fetch()){
90 /* Insert links in ACL array */
91 $aclp[$attrs['dn']]= substr_count($attrs['dn'], ',');
92 $aclc[$attrs['dn']]= array();
93 $ol= array();
94 for($i= 0; $i<$attrs['gosaAclEntry']['count']; $i++){
95 $ol= array_merge($ol, @acl::explodeAcl($attrs['gosaAclEntry'][$i]));
96 }
97 $aclc[$attrs['dn']]= $ol;
98 }
100 /* ACL's read, sort for tree depth */
101 asort($aclp);
103 /* Sort in tree order */
104 foreach ($aclp as $dn => $acl){
105 /* Check if we need to keep this ACL */
106 foreach($aclc[$dn] as $idx => $type){
107 $interresting= FALSE;
109 /* No members? This is good for all users... */
110 if (!count($type['members'])){
111 $interresting= TRUE;
112 } else {
114 /* Inspect members... */
115 foreach ($type['members'] as $grp => $grpdsc){
116 /* Some group inside the members that is relevant for us? */
117 if (in_array_ics(preg_replace('/^G:/', '', $grp), $this->groups)){
118 $interresting= TRUE;
119 }
121 /* User inside the members? */
122 if (preg_replace('/^U:/', '', $grp) == $this->dn){
123 $interresting= TRUE;
124 }
125 }
126 }
128 if ($interresting){
129 if (!isset($this->ACL[$dn])){
130 $this->ACL[$dn]= array();
131 }
132 $this->ACL[$dn][$idx]= $type;
133 }
134 }
136 }
137 }
140 function get_category_permissions($dn, $category)
141 {
142 /* Get list of objectClasses and get the permissions for it */
143 $acl= "";
144 if (isset($this->ocMapping[$category])){
145 foreach($this->ocMapping[$category] as $oc){
146 $acl.= $this->get_permissions($dn, $category."/".$oc);
147 }
148 }
150 return ($acl);
151 }
154 function get_permissions($dn, $object, $attribute= "", $skip_write= FALSE)
155 {
156 $acl= array("r" => "", "w" => "", "c" => "", "d" => "", "m" => "", "a" => "");
158 /* Build dn array */
159 $path= split(',', $dn);
160 $path= array_reverse($path);
162 /* Walk along the path to evaluate the acl */
163 $cpath= "";
164 foreach ($path as $element){
166 /* Clean potential ACLs for each level */
167 $acl= $this->cleanACL($acl);
169 if ($cpath == ""){
170 $cpath= $element;
171 } else {
172 $cpath= $element.','.$cpath;
173 }
174 if (isset($this->ACL[$cpath])){
176 /* Inspect this ACL, place the result into ACL */
177 foreach ($this->ACL[$cpath] as $subacl){
179 /* Reset? Just clean the ACL and turn over to the next one... */
180 if ($subacl['type'] == 'reset'){
181 $acl= $this->cleanACL($acl, TRUE);
182 continue;
183 }
185 if($subacl['type'] == "role") {
186 echo "role skipped";
187 continue;
188 }
190 /* Per attribute ACL? */
191 if (isset($subacl['acl'][$object][$attribute])){
192 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attribute]);
193 continue;
194 }
196 /* Per object ACL? */
197 if (isset($subacl['acl'][$object][0])){
198 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][0]);
199 continue;
200 }
202 /* Global ACL? */
203 if (isset($subacl['acl']['all'][0])){
204 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']['all'][0]);
205 continue;
206 }
208 /* If attribute is "", we want to know, if we've *any* permissions here... */
209 if ($attribute == "" && isset($subacl['acl'][$object])){
210 foreach($subacl['acl'][$object] as $attr => $dummy){
211 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attr]);
212 }
213 continue;
214 }
216 }
217 }
218 }
220 /* Assemble string */
221 $ret= "";
222 foreach ($acl as $key => $value){
223 if ($value != ""){
224 $ret.= $key;
225 }
226 }
228 /* Remove write if needed */
229 if ($skip_write){
230 $ret= preg_replace('/w/', '', $ret);
231 }
233 return ($ret);
234 }
237 /* Extract all departments that are accessible (direct or 'on the way' to an
238 accessible department) */
239 function get_module_departments($module)
240 {
241 global $plist;
243 $objects= array();
244 $deps= array();
246 /* Extract all relevant objects for this module from plist */
247 foreach ($plist->info as $object => $info){
248 if (!isset($info['plCategory'])){
249 continue;
250 }
251 foreach ($info['plCategory'] as $idx => $data){
252 if (preg_match('/^[0-9]+$/', $idx)){
253 if ($data == $module){
254 $objects[$object]= $object;
255 }
256 } else {
257 if ($idx == $module){
258 $objects[$object]= $object;
259 }
260 }
261 }
262 }
264 /* For all gosaDepartments */
265 foreach ($this->config->departments as $dn){
266 $acl= array("r" => "", "w" => "", "c" => "", "d" => "", "m" => "", "a" => "");
268 /* Build dn array */
269 $path= split(',', $dn);
270 $path= array_reverse($path);
272 /* Walk along the path to evaluate the acl */
273 $cpath= "";
274 foreach ($path as $element){
276 /* Clean potential ACLs for each level */
277 $acl= $this->cleanACL($acl);
279 if ($cpath == ""){
280 $cpath= $element;
281 } else {
282 $cpath= $element.','.$cpath;
283 }
284 if (isset($this->ACL[$cpath])){
286 /* Inspect this ACL, place the result into ACL */
287 foreach ($this->ACL[$cpath] as $subacl){
289 /* Reset? Just clean the ACL and turn over to the next one... */
290 if ($subacl['type'] == 'reset'){
291 $acl= $this->cleanACL($acl, TRUE);
292 continue;
293 }
295 if($subacl['type'] == 'role'){
296 echo "role skipped";
297 continue;
298 }
300 /* Per object ACL? */
301 foreach ($objects as $object){
302 if (isset($subacl['acl']["$module/$object"])){
303 foreach($subacl['acl']["$module/$object"] as $attribute => $dcl){
304 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["$module/$object"][$attribute]);
305 }
306 }
307 }
309 /* Global ACL? */
310 if (isset($subacl['acl']["$module/all"][0])){
311 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["$module/all"][0]);
312 continue;
313 }
315 /* Global ACL? */
316 if (isset($subacl['acl']["all"][0])){
317 $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']["all"][0]);
318 continue;
319 }
320 }
321 }
322 }
324 /* Add department, if we have (some) permissions for the required module */
325 foreach ($acl as $val){
326 if ($val != ""){
327 $deps[]= $dn;
328 break;
329 }
330 }
331 }
333 return ($deps);
334 }
337 function mergeACL($acl, $type, $newACL)
338 {
339 if(preg_match("/w/",$newACL) && !preg_match("/r/",$newACL)){
340 $newACL .= "r";
341 }
342 foreach(str_split($newACL) as $char){
344 /* Ignore invalid characters */
345 if (!preg_match('/[rwcdm]/', $char)){
346 continue;
347 }
349 /* Skip permanent and subtree entries */
350 if (preg_match('/[sp]/', $acl[$char])){
351 continue;
352 }
354 switch ($type){
355 case 'psub':
356 $acl[$char]= 'p';
357 break;
359 case 'sub':
360 $acl[$char]= 's';
361 break;
363 case 'one':
364 $acl[$char]= 1;
365 break;
367 case 'base':
368 if ($acl[$char] != 1){
369 $acl[$char]= 0;
370 }
371 break;
372 }
373 }
375 return ($acl);
376 }
379 function cleanACL($acl, $reset= FALSE)
380 {
381 foreach ($acl as $key => $value){
383 /* Reset removes everything but 'p' */
384 if ($reset && $value != 'p'){
385 $acl[$key]= "";
386 continue;
387 }
389 /* Decrease tree level */
390 if (preg_match('/^[0-9]+$/', $value)){
391 if ($value > 0){
392 $acl[$key]= $value - 1;
393 } else {
394 $acl[$key]= "";
395 }
396 }
397 }
399 return ($acl);
400 }
403 /* #FIXME This could be logical wrong or could be optimized in the future
404 Return combined acls for a given category.
405 All acls will be combined like boolean AND
406 As example ('rwcdm' + 'rcd' + 'wrm'= 'r')
408 Results will be cached in $this->result_cache.
409 $this->result_cache will be resetted if load_acls is called.
410 */
411 function has_complete_category_acls($dn,$category)
412 {
413 $acl = "rwcdm";
414 $types = "rwcdm";
417 if(!is_string($category)){
418 trigger_error("category must be string");
419 $acl = "";
420 }else{
421 if(!isset($this->result_cache['has_complete_category_acls'][$dn][$category])) {
422 if (isset($this->ocMapping[$category])){
423 foreach($this->ocMapping[$category] as $oc){
425 /* Skip objectClass '0' (e.g. users/0) get_permissions will ever return '' ?? */
426 if($oc == "0") continue;
427 $tmp = $this->get_permissions($dn, $category."/".$oc);
428 for($i = 0 ; $i < strlen($types); $i++) {
429 if(!preg_match("/".$types[$i]."/",$tmp)){
430 $acl = preg_replace("/".$types[$i]."/","",$acl);
431 }
432 }
433 }
434 }else{
435 trigger_error("Invalid type of category ".$category);
436 $acl = "";
437 }
438 $this->result_cache['has_complete_category_acls'][$dn][$category] = $acl;
439 }else{
440 $acl = $this->result_cache['has_complete_category_acls'][$dn][$category];
441 }
442 }
443 return($acl);
444 }
445 }
447 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
448 ?>