1 <?php
3 class aclResolver
4 {
5 private $classMapping = array();
6 private $aclTypes = array();
7 private $affectingACLs = array();
9 private $renderedList = "";
11 // The users 'dn' and 'uid' used to verify the collected acls
12 private $validateDn;
13 private $validateUid;
14 private $acl_category;
15 private $parent;
17 // Used for the autocompleter
18 private $userMap;
20 function __construct($config, $dn, $parent)
21 {
22 $this->config = &$config;
23 $this->dn = $dn;
24 $this->parent = $parent;
26 // Replace this with a user defined one later.
27 $ui = get_userinfo();
28 $this->validateUid = $ui->uid;
29 $this->validateDn = $ui->dn;
31 // Build class mapping - only once, will not change during session.
32 if(!session::is_set('aclConverter::classMapping')){
33 $tmp= session::global_get('plist');
34 $plist= $tmp->info;
35 $map = array();
36 $map['all']= _("All categories");
37 foreach($plist as $class => $plInfo){
38 if(isset($plInfo['plCategory']) && is_array($plInfo['plCategory'])){
39 foreach($plInfo['plCategory'] as $category => $desc){
40 if(!is_numeric($category)){
41 $map[$category] = $desc['description'];
42 }
43 }
44 }
45 }
46 foreach($plist as $class => $plInfo){
47 if(isset($plInfo['plCategory']) && is_array($plInfo['plCategory'])){
48 foreach($plInfo['plCategory'] as $category => $desc){
49 if(!is_numeric($category)){
50 $map[$category."/".$class] = $map[$category]." - ".$plInfo['plDescription'];
51 }else{
52 $map[$desc."/".$class] = $map[$desc]." - ".$plInfo['plDescription'];
53 }
54 }
56 }
57 }
58 session::set('aclConverter::classMapping', $map);
59 }
60 $this->classMapping = session::get('aclConverter::classMapping');
62 // Define ACL type translations
63 $this->aclTypes= array("reset" => _("Reset ACLs"),
64 "one" => _("One level"),
65 "base" => _("Current object"),
66 "sub" => _("Complete subtree"),
67 "psub" => _("Complete subtree (permanent)"),
68 "role" => _("Use ACL defined in role"));
70 // Enforce to reload acl result
71 $this->renderedList = "";
72 }
75 function reload()
76 {
77 // Go through all ACLs and get those matching the objects dn.
78 $ui = get_userinfo();
79 $ui->reset_acl_cache();
80 $ui->loadACL();
82 // Get ACL category for the current object.
83 if(isset($this->parent->acl_category) && !empty($this->parent->acl_category)){
84 $this->acl_category = preg_replace("/\/$/","",$this->parent->acl_category);
85 }
87 foreach($ui->allACLs as $dn => $acls){
88 if(preg_match("/".preg_quote($dn,'/')."$/i", $this->dn)){
90 // Foreach dn there is a collection of ACLs indexed by their priority
91 foreach($acls as $prio => $acl){
92 if($acl['type'] == "reset"){
93 $this->affectingACLs[$dn][$prio] = $acl;
94 continue;
95 }else{
97 // Only get those entries with a relevant acl-category
98 foreach($acl['acl'] as $category => $attributes){
99 if(preg_match("/^all($|\/)/", $category) ||
100 preg_match("/^".$this->acl_category."($|\/)/", $category)){
101 $this->affectingACLs[$dn][$prio] = $acl;
102 continue;
103 }
104 }
105 }
106 }
107 }
108 }
109 }
113 /*! \brief Create a human readable HTML result
114 */
115 function getReadableACL()
116 {
117 if(isset($_POST['aclTarget'])){
118 $d = get_post('aclTarget');
119 if(isset($this->userMap[$d])){
120 $this->validateDn = $this->userMap[$d]['dn'];
121 $this->validateUid = $this->userMap[$d]['uid'][0];
122 $this->renderedList = "";
123 }
124 }
126 if(empty($this->renderedList)){
128 $this->reload();
130 // Autocompleter template
131 $autocompleter ="
132 <input class='filter_textfield' placeholder='"._("Search")."...'
133 id='aclTarget' name='aclTarget' type='text' value=''
134 onChange=\"\$('aclTargetSubmit').focus();\">
136 <div id='autocomplete' class='autocomplete'></div>
137 <script type='text/javascript'>
138 new Ajax.Autocompleter(
139 'aclTarget',
140 'autocomplete',
141 'autocomplete.php',
142 { minChars: 3, frequency: 0.5 });
143 </script>
144 ".image("images/lists/submit.png","aclTargetSubmit");
146 // Base template - each entry start with this
147 $tpl =
148 "\n <tr class='acl-viewer-head %s'>".
149 "\n <td>%s</td>".
150 "\n <td colspan=2><b>%s</b> - %s</td>".
151 "\n </tr>".
152 "\n %s".
153 "\n <tr>".
154 "\n <td colspan=3><hr></td>".
155 "\n </tr>";
157 // If the acl consists of a user-object-filter then this template is used.
158 $filter_tpl =
159 "\n <tr class='%s'>".
160 "\n <td></td>".
161 "\n <td><b>"._("Filter")."</b></td>".
162 "\n <td><ul><li>%s</li></ul></td>".
163 "\n </tr>";
165 // Used to display ACL owner of type "group"
166 $gmem_tpl =
167 "\n <tr class='%s'>".
168 "\n <td></td>".
169 "\n <td><b>"._("Group members")."</b></td>".
170 "\n <td><ul>%s</ul></td>".
171 "\n </tr>";
173 // Used to display ACL owner of type "user"
174 $umem_tpl =
175 "\n <tr class='%s'>".
176 "\n <td></td>".
177 "\n <td><b>"._("Members")."</b></td>".
178 "\n <td><ul>%s</ul></td>".
179 "\n </tr>";
181 // Used to display the acl contents, except 'reset' and 'role'
182 $acl_tpl =
183 "\n <tr class='%s'>".
184 "\n <td></td>".
185 "\n <td><b>"._("Acls")."</b></td>".
186 "\n <td><ul>%s</ul></td>".
187 "\n </tr>";
190 $user = sprintf(_("ACL from the viewpoint of user '%s'"), "<b>".$this->validateUid."</b>");
191 $str = "<table summary='"._("Object permissions")."'>";
192 $str .= " <tr><td>".$user."</td><td>".$autocompleter."</td></tr>";
193 $str .= "</table>";
194 $str .= "<table summary='"._("Object permissions")."' class='acl-viewer'>";
195 $ldap = $this->config->get_ldap_link();
196 $ldap->cd($this->config->current['BASE']);
197 $ui = get_userinfo();
198 foreach($this->affectingACLs as $dn => $acls){
199 foreach($acls as $acl){
201 // Prepare entry icon (department or element?)
202 $image = (isset($this->config->idepartments[$dn]))? "images/select_department.png":"images/lists/element.png";
204 // The acl type (sub,psub,reset...)
205 $aclType = $this->aclTypes[$acl['type']];
207 // Does the filter match for current object?
208 $filter ="";
209 $match = TRUE;
210 if(!empty($acl['filter'])){
211 $match = $ldap->object_match_filter($this->dn,$acl['filter']);
212 $filter= $acl['filter'];
213 if(!$match){
214 $filter= "<span>".$filter."</span>";
215 }
216 }
218 // Check membership
219 $gmem = $umem = "";
220 $users = $groups = array();
221 $gfound = $ufound = FALSE;
222 foreach($acl['members'] as $type => $name){
224 // Check if we're part of the members
225 if(preg_match("/^U:/", $type)){
226 if(preg_match("/^U:".preg_quote($this->validateDn,'/')."/", $type)){
227 $users[] = $name;
228 $ufound = TRUE;
229 continue;
230 }
231 $users[] = "<span>".$name."</span>";
232 }
234 // Check if we're part of the group members
235 if(preg_match("/^G/", $type)){
236 if($type == "G:*"){
237 $gfound = TRUE;
238 $groups[] = $name;
239 continue;
240 }
241 if(preg_match("/^G:/", $type)){
242 $gdn = preg_replace("/^G:/","",$type);
243 $ldap->cat($gdn,array('memberUid'));
244 if($ldap->count()){
245 $attrs = $ldap->fetch();
246 if(isset($attrs['memberUid']) && in_array($this->validateUid, $attrs['memberUid'])){
247 $gfound = TRUE;
248 $groups[] = $name;
249 }
250 }
251 continue;
252 }
254 // Group member doesn't mactch
255 $groups[] = "<span>".$name."</span>";
256 }
257 }
258 if(!count($groups)) $gfound = TRUE;
259 if(!count($users)) $ufound = TRUE;
261 // Build up ACL definition list
262 $defs ="";
263 if($acl['type']!='reset'){
264 foreach($acl['acl'] as $type => $acl){
265 if(isset($this->classMapping[$type])){
266 $defs .= "<li>".$this->classMapping[$type].": ".$this->aclToString($acl)."</li>";
267 }else{
268 $defs .= "<li>".$type.": ".$this->aclToString($acl)."</li>";
269 }
270 }
271 }
273 // Display the acl block in a special color if its not matching
274 $class="";
275 if(!($gfound || $ufound) || !$match){
276 $class = "acl-viewer-blocked";
277 }
279 if(!empty($filter)) $filter =sprintf($filter_tpl,$class,$filter);
280 if(!empty($defs)) $defs = sprintf($acl_tpl,$class,$defs);
281 if(count($users)) $umem = sprintf($umem_tpl,$class,"<li>".implode($users,'</li><li>')."</li>");
282 if(count($groups)) $gmem = sprintf($gmem_tpl,$class,"<li>".implode($groups,'</li><li>')."</li>");
283 $str.= sprintf($tpl,$class, image($image), $dn, $aclType, $filter.$gmem.$umem.$defs);
284 }
285 }
286 $str .= "</table>";
287 $this->renderedList = $str;
288 }
289 return($this->renderedList);
290 }
292 function aclToString($acls)
293 {
294 $str ="<ul>";
295 foreach($acls as $name => $acl){
296 if($name == "0") $name = _("All");
297 $str .= "<li>".$name;
298 $str .= "<ul>";
299 if(preg_match("/s/", $acl)){
300 $str.="<li><u>"._("Grant permission to owner").'</u></li>';
301 }
302 if(preg_match("/r/", $acl)) $str.="<li>"._("read").'</li>';
303 if(preg_match("/w/", $acl)) $str.="<li>"._("write").'</li>';
304 if(preg_match("/c/", $acl)) $str.="<li>"._("Create").'</li>';
305 if(preg_match("/d/", $acl)) $str.="<li>"._("Remove").'</li>';
306 if(preg_match("/m/", $acl)) $str.="<li>"._("Move").'</li>';
307 $str.= "</ul>";
308 }
309 return($str."</ul>");
310 }
312 function processAutocomplete()
313 {
314 $ldap = $this->config->get_ldap_link();
315 $ldap->cd($this->config->current['BASE']);
316 $ldap->search("(&(objectClass=gosaAccount)(|(sn=*".get_post('aclTarget')."*)".
317 "(uid=*".get_post('aclTarget')."*)(givenName=*".get_post('aclTarget')."*)))",
318 array('uid','dn','sn','givenName'));
319 echo "<ul>";
320 while($attrs = $ldap->fetch()){
321 $display = $attrs['givenName'][0]." ".$attrs['sn'][0]." [".$attrs['uid'][0]."]";
322 echo "<li>{$display}</li>";
323 $this->userMap[$display] = $attrs;
324 }
325 echo "</ul>";
326 }
327 }
329 ?>