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 foreach($plist as $class => $plInfo){
37 if(isset($plInfo['plCategory']) && is_array($plInfo['plCategory'])){
38 foreach($plInfo['plCategory'] as $category => $desc){
39 if(!is_numeric($category)){
40 $map[$category] = $desc['description'];
41 }
42 }
43 }
44 }
45 foreach($plist as $class => $plInfo){
46 if(isset($plInfo['plCategory']) && is_array($plInfo['plCategory'])){
47 foreach($plInfo['plCategory'] as $category => $desc){
48 if(!is_numeric($category)){
49 $map[$category."/".$class] = $map[$category]." - ".$plInfo['plDescription'];
50 }else{
51 $map[$desc."/".$class] = $map[$desc]." - ".$plInfo['plDescription'];
52 }
53 }
55 }
56 }
57 session::set('aclConverter::classMapping', $map);
58 }
59 $this->classMapping = session::get('aclConverter::classMapping');
61 // Define ACL type translations
62 $this->aclTypes= array("reset" => _("Reset ACLs"),
63 "one" => _("One level"),
64 "base" => _("Current object"),
65 "sub" => _("Complete subtree"),
66 "psub" => _("Complete subtree (permanent)"),
67 "role" => _("Use ACL defined in role"));
69 // Enforce to reload acl result
70 $this->renderedList = "";
71 }
74 function reload()
75 {
76 // Go through all ACLs and get those matching the objects dn.
77 $ui = get_userinfo();
78 $ui->reset_acl_cache();
79 $ui->loadACL();
81 // Get ACL category for the current object.
82 if(isset($this->parent->acl_category) && !empty($this->parent->acl_category)){
83 $this->acl_category = preg_replace("/\/$/","",$this->parent->acl_category);
84 }
86 foreach($ui->allACLs as $dn => $acls){
87 if(preg_match("/".preg_quote($dn,'/')."$/i", $this->dn)){
89 // Foreach dn there is a collection of ACLs indexed by their priority
90 foreach($acls as $prio => $acl){
91 if($acl['type'] == "reset"){
92 $this->affectingACLs[$dn][$prio] = $acl;
93 continue;
94 }else{
96 // Only get those entries with a relevant acl-category
97 foreach($acl['acl'] as $category => $attributes){
98 if(preg_match("/^all($|\/)/", $category) ||
99 preg_match("/^".$this->acl_category."($|\/)/", $category)){
100 $this->affectingACLs[$dn][$prio] = $acl;
101 continue;
102 }
103 }
104 }
105 }
106 }
107 }
108 }
112 /*! \brief Create a human readable HTML result
113 */
114 function getReadableACL()
115 {
116 if(isset($_POST['aclTarget'])){
117 $d = get_post('aclTarget');
118 if(isset($this->userMap[$d])){
119 $this->validateDn = $this->userMap[$d]['dn'];
120 $this->validateUid = $this->userMap[$d]['uid'][0];
121 $this->renderedList = "";
122 }
123 }
125 if(empty($this->renderedList)){
127 $this->reload();
129 // Autocompleter template
130 $autocompleter ="
131 <input class='filter_textfield' placeholder='"._("Enter another user name")."...'
132 id='aclTarget' name='aclTarget' type='text' value=''
133 onChange=\"\$('aclTargetSubmit').focus();\">
135 <div id='autocomplete' class='autocomplete'></div>
136 <script type='text/javascript'>
137 new Ajax.Autocompleter(
138 'aclTarget',
139 'autocomplete',
140 'autocomplete.php',
141 { minChars: 3, frequency: 0.5 });
142 </script>
143 ".image("images/lists/submit.png","aclTargetSubmit");
145 // Base template - each entry start with this
146 $tpl =
147 "\n <tr class='acl-viewer-head %s'>".
148 "\n <td style='width:20px'>%s</td>".
149 "\n <td colspan=2><b>%s</b><div class='right'>%s</div></td>".
150 "\n </tr>".
151 "\n %s";
153 // If the acl consists of a user-object-filter then this template is used.
154 $filter_tpl =
155 "\n <tr class='%s'>".
156 "\n <td></td>".
157 "\n <td><b>"._("Filter")."</b></td>".
158 "\n <td><ul class='acl-viewer-items'><li>%s</li></ul></td>".
159 "\n </tr>";
161 // Used to display ACL owner of type "group"
162 $gmem_tpl =
163 "\n <tr class='%s'>".
164 "\n <td></td>".
165 "\n <td><b>"._("Groups")."</b></td>".
166 "\n <td><ul class='acl-viewer-items'>%s</ul></td>".
167 "\n </tr>";
169 // Used to display ACL owner of type "user"
170 $umem_tpl =
171 "\n <tr class='%s'>".
172 "\n <td></td>".
173 "\n <td><b>"._("Users")."</b></td>".
174 "\n <td><ul class='acl-viewer-items'>%s</ul></td>".
175 "\n </tr>";
177 // Used to display the acl contents, except 'reset' and 'role'
178 $acl_tpl =
179 "\n <tr class='%s'>".
180 "\n <td></td>".
181 "\n <td><b>"._("Acls")."</b></td>".
182 "\n <td><ul class='acl-viewer-items'>%s</ul></td>".
183 "\n </tr>";
186 $user = "<h3>".sprintf(_("List of effective ACLs for '%s'"), $this->validateUid)."</h3>";
187 $str = "<table summary='"._("Object permissions")."'>";
188 $str .= " <tr><td>".$user."</td><td>".$autocompleter."</td></tr>";
189 $str .= "</table>";
190 $str .= "<div class='acl-viewer-container'>";
191 $str .= "<table summary='"._("Object permissions")."' cellpadding='0' cellspacing='0' class='acl-viewer'>";
192 $ldap = $this->config->get_ldap_link();
193 $ldap->cd($this->config->current['BASE']);
194 $ui = get_userinfo();
195 foreach($this->affectingACLs as $dn => $acls){
196 foreach($acls as $acl){
198 // Prepare entry icon (department or element?)
199 $image = (isset($this->config->idepartments[$dn]))? "images/select_department.png":"images/lists/element.png";
201 // The acl type (sub,psub,reset...)
202 $aclType = $this->aclTypes[$acl['type']];
204 // Does the filter match for current object?
205 $filter ="";
206 $match = TRUE;
207 if(!empty($acl['filter'])){
208 $match = $ldap->object_match_filter($this->dn,$acl['filter']);
209 $filter= $acl['filter'];
210 if(!$match){
211 $filter= "<span>".$filter."</span>";
212 }
213 }
215 // Check membership
216 $gmem = $umem = "";
217 $users = $groups = array();
218 $found = FALSE;
219 foreach($acl['members'] as $type => $name){
221 // Check if we're part of the members
222 if(preg_match("/^U:/", $type)){
223 if(preg_match("/^U:".preg_quote($this->validateDn,'/')."/", $type)){
224 $users[] = $name;
225 $found = TRUE;
226 continue;
227 }
228 $users[] = "<span>".$name."</span>";
229 }
231 // Check if we're part of the group members
232 if(preg_match("/^G/", $type)){
233 if($type == "G:*"){
234 $found = TRUE;
235 $groups[] = $name;
236 continue;
237 }
238 if(preg_match("/^G:/", $type)){
239 $gdn = preg_replace("/^G:/","",$type);
240 $ldap->cat($gdn,array('memberUid'));
241 if($ldap->count()){
242 $attrs = $ldap->fetch();
243 if(isset($attrs['memberUid']) && in_array($this->validateUid, $attrs['memberUid'])){
244 $found = TRUE;
245 $groups[] = $name;
246 continue;
247 }
248 }
249 }
251 // Mark groups that doesn't match
252 $groups[] = "<span>".$name."</span>";
253 }
254 }
256 // Build up ACL definition list
257 $defs ="";
258 if($acl['type']!='reset'){
259 foreach($acl['acl'] as $type => $acl){
260 if(isset($this->classMapping[$type])){
261 $defs .= "<li>".$this->classMapping[$type].": ".$this->aclToString($acl)."</li>";
262 }else{
263 $defs .= "<li>".$type.": ".$this->aclToString($acl)."</li>";
264 }
265 }
266 }
268 // Display the acl block in a special color if its not matching
269 $class="";
270 if(!$found || !$match){
271 $class = "acl-viewer-blocked";
272 }
273 if(!empty($filter)) $filter =sprintf($filter_tpl,$class,$filter);
274 if(!empty($defs)) $defs = sprintf($acl_tpl,$class,$defs);
275 if(count($users)) $umem = sprintf($umem_tpl,$class,"<li>".implode($users,'</li><li>')."</li>");
276 if(count($groups)) $gmem = sprintf($gmem_tpl,$class,"<li>".implode($groups,'</li><li>')."</li>");
277 $str.= sprintf($tpl,$class, image($image), $dn, $aclType, $filter.$gmem.$umem.$defs);
278 }
279 }
280 $str .= "</table>";
281 $str .= "</div>";
282 $this->renderedList = $str;
283 }
284 return($this->renderedList);
285 }
287 function aclToString($acls)
288 {
289 $str ="<ul class='acl-category-list'>";
290 foreach($acls as $name => $acl){
291 if($name == "0") $name = _("All");
292 $str .= "<li><i>".$name.":</i> ";
293 $str .= "<ul class='acl-list'>";
294 if(preg_match("/s/", $acl)){
295 $str.="<li><u>"._("Restrict changes to user's own object").'</u></li>';
296 }
297 if(preg_match("/r/", $acl)) $str.="<li>"._("read").'</li>';
298 if(preg_match("/w/", $acl)) $str.="<li>"._("write").'</li>';
299 if(preg_match("/c/", $acl)) $str.="<li>"._("create").'</li>';
300 if(preg_match("/d/", $acl)) $str.="<li>"._("remove").'</li>';
301 if(preg_match("/m/", $acl)) $str.="<li>"._("move").'</li>';
302 $str.= "</ul>";
303 }
304 return($str."</ul>");
305 }
307 function processAutocomplete()
308 {
309 $ldap = $this->config->get_ldap_link();
310 $ldap->cd($this->config->current['BASE']);
311 $ldap->search("(&(objectClass=gosaAccount)(|(sn=*".get_post('aclTarget')."*)".
312 "(uid=*".get_post('aclTarget')."*)(givenName=*".get_post('aclTarget')."*)))",
313 array('uid','dn','sn','givenName'));
314 echo "<ul>";
315 while($attrs = $ldap->fetch()){
316 $display = $attrs['givenName'][0]." ".$attrs['sn'][0]." [".$attrs['uid'][0]."]";
317 echo "<li>{$display}</li>";
318 $this->userMap[$display] = $attrs;
319 }
320 echo "</ul>";
321 }
322 }
324 ?>