PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/plugins/acl/admin.php

http://github.com/splitbrain/dokuwiki
PHP | 858 lines | 576 code | 94 blank | 188 comment | 174 complexity | f83b2df1cf4dfe10ac8ec819d233bffc MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * ACL administration functions
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Andreas Gohr <andi@splitbrain.org>
  7. * @author Anika Henke <anika@selfthinker.org> (concepts)
  8. * @author Frank Schubert <frank@schokilade.de> (old version)
  9. */
  10. /**
  11. * All DokuWiki plugins to extend the admin function
  12. * need to inherit from this class
  13. */
  14. class admin_plugin_acl extends DokuWiki_Admin_Plugin
  15. {
  16. public $acl = null;
  17. protected $ns = null;
  18. /**
  19. * The currently selected item, associative array with id and type.
  20. * Populated from (in this order):
  21. * $_REQUEST['current_ns']
  22. * $_REQUEST['current_id']
  23. * $ns
  24. * $ID
  25. */
  26. protected $current_item = null;
  27. protected $who = '';
  28. protected $usersgroups = array();
  29. protected $specials = array();
  30. /**
  31. * return prompt for admin menu
  32. */
  33. public function getMenuText($language)
  34. {
  35. return $this->getLang('admin_acl');
  36. }
  37. /**
  38. * return sort order for position in admin menu
  39. */
  40. public function getMenuSort()
  41. {
  42. return 1;
  43. }
  44. /**
  45. * handle user request
  46. *
  47. * Initializes internal vars and handles modifications
  48. *
  49. * @author Andreas Gohr <andi@splitbrain.org>
  50. */
  51. public function handle()
  52. {
  53. global $AUTH_ACL;
  54. global $ID;
  55. global $auth;
  56. global $config_cascade;
  57. global $INPUT;
  58. // fresh 1:1 copy without replacements
  59. $AUTH_ACL = file($config_cascade['acl']['default']);
  60. // namespace given?
  61. if ($INPUT->str('ns') == '*') {
  62. $this->ns = '*';
  63. } else {
  64. $this->ns = cleanID($INPUT->str('ns'));
  65. }
  66. if ($INPUT->str('current_ns')) {
  67. $this->current_item = array('id' => cleanID($INPUT->str('current_ns')), 'type' => 'd');
  68. } elseif ($INPUT->str('current_id')) {
  69. $this->current_item = array('id' => cleanID($INPUT->str('current_id')), 'type' => 'f');
  70. } elseif ($this->ns) {
  71. $this->current_item = array('id' => $this->ns, 'type' => 'd');
  72. } else {
  73. $this->current_item = array('id' => $ID, 'type' => 'f');
  74. }
  75. // user or group choosen?
  76. $who = trim($INPUT->str('acl_w'));
  77. if ($INPUT->str('acl_t') == '__g__' && $who) {
  78. $this->who = '@'.ltrim($auth->cleanGroup($who), '@');
  79. } elseif ($INPUT->str('acl_t') == '__u__' && $who) {
  80. $this->who = ltrim($who, '@');
  81. if ($this->who != '%USER%' && $this->who != '%GROUP%') { #keep wildcard as is
  82. $this->who = $auth->cleanUser($this->who);
  83. }
  84. } elseif ($INPUT->str('acl_t') &&
  85. $INPUT->str('acl_t') != '__u__' &&
  86. $INPUT->str('acl_t') != '__g__') {
  87. $this->who = $INPUT->str('acl_t');
  88. } elseif ($who) {
  89. $this->who = $who;
  90. }
  91. // handle modifications
  92. if ($INPUT->has('cmd') && checkSecurityToken()) {
  93. $cmd = $INPUT->extract('cmd')->str('cmd');
  94. // scope for modifications
  95. if ($this->ns) {
  96. if ($this->ns == '*') {
  97. $scope = '*';
  98. } else {
  99. $scope = $this->ns.':*';
  100. }
  101. } else {
  102. $scope = $ID;
  103. }
  104. if ($cmd == 'save' && $scope && $this->who && $INPUT->has('acl')) {
  105. // handle additions or single modifications
  106. $this->deleteACL($scope, $this->who);
  107. $this->addOrUpdateACL($scope, $this->who, $INPUT->int('acl'));
  108. } elseif ($cmd == 'del' && $scope && $this->who) {
  109. // handle single deletions
  110. $this->deleteACL($scope, $this->who);
  111. } elseif ($cmd == 'update') {
  112. $acl = $INPUT->arr('acl');
  113. // handle update of the whole file
  114. foreach ($INPUT->arr('del') as $where => $names) {
  115. // remove all rules marked for deletion
  116. foreach ($names as $who)
  117. unset($acl[$where][$who]);
  118. }
  119. // prepare lines
  120. $lines = array();
  121. // keep header
  122. foreach ($AUTH_ACL as $line) {
  123. if ($line[0] == '#') {
  124. $lines[] = $line;
  125. } else {
  126. break;
  127. }
  128. }
  129. // re-add all rules
  130. foreach ($acl as $where => $opt) {
  131. foreach ($opt as $who => $perm) {
  132. if ($who[0]=='@') {
  133. if ($who!='@ALL') {
  134. $who = '@'.ltrim($auth->cleanGroup($who), '@');
  135. }
  136. } elseif ($who != '%USER%' && $who != '%GROUP%') { #keep wildcard as is
  137. $who = $auth->cleanUser($who);
  138. }
  139. $who = auth_nameencode($who, true);
  140. $lines[] = "$where\t$who\t$perm\n";
  141. }
  142. }
  143. // save it
  144. io_saveFile($config_cascade['acl']['default'], join('', $lines));
  145. }
  146. // reload ACL config
  147. $AUTH_ACL = file($config_cascade['acl']['default']);
  148. }
  149. // initialize ACL array
  150. $this->initAclConfig();
  151. }
  152. /**
  153. * ACL Output function
  154. *
  155. * print a table with all significant permissions for the
  156. * current id
  157. *
  158. * @author Frank Schubert <frank@schokilade.de>
  159. * @author Andreas Gohr <andi@splitbrain.org>
  160. */
  161. public function html()
  162. {
  163. echo '<div id="acl_manager">'.NL;
  164. echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL;
  165. echo '<div class="level1">'.NL;
  166. echo '<div id="acl__tree">'.NL;
  167. $this->makeExplorer();
  168. echo '</div>'.NL;
  169. echo '<div id="acl__detail">'.NL;
  170. $this->printDetail();
  171. echo '</div>'.NL;
  172. echo '</div>'.NL;
  173. echo '<div class="clearer"></div>';
  174. echo '<h2>'.$this->getLang('current').'</h2>'.NL;
  175. echo '<div class="level2">'.NL;
  176. $this->printAclTable();
  177. echo '</div>'.NL;
  178. echo '<div class="footnotes"><div class="fn">'.NL;
  179. echo '<sup><a id="fn__1" class="fn_bot" href="#fnt__1">1)</a></sup>'.NL;
  180. echo '<div class="content">'.$this->getLang('p_include').'</div>';
  181. echo '</div></div>';
  182. echo '</div>'.NL;
  183. }
  184. /**
  185. * returns array with set options for building links
  186. *
  187. * @author Andreas Gohr <andi@splitbrain.org>
  188. */
  189. protected function getLinkOptions($addopts = null)
  190. {
  191. $opts = array(
  192. 'do'=>'admin',
  193. 'page'=>'acl',
  194. );
  195. if ($this->ns) $opts['ns'] = $this->ns;
  196. if ($this->who) $opts['acl_w'] = $this->who;
  197. if (is_null($addopts)) return $opts;
  198. return array_merge($opts, $addopts);
  199. }
  200. /**
  201. * Display a tree menu to select a page or namespace
  202. *
  203. * @author Andreas Gohr <andi@splitbrain.org>
  204. */
  205. protected function makeExplorer()
  206. {
  207. global $conf;
  208. global $ID;
  209. global $lang;
  210. $ns = $this->ns;
  211. if (empty($ns)) {
  212. $ns = dirname(str_replace(':', '/', $ID));
  213. if ($ns == '.') $ns ='';
  214. } elseif ($ns == '*') {
  215. $ns ='';
  216. }
  217. $ns = utf8_encodeFN(str_replace(':', '/', $ns));
  218. $data = $this->makeTree($ns);
  219. // wrap a list with the root level around the other namespaces
  220. array_unshift($data, array( 'level' => 0, 'id' => '*', 'type' => 'd',
  221. 'open' =>'true', 'label' => '['.$lang['mediaroot'].']'));
  222. echo html_buildlist(
  223. $data,
  224. 'acl',
  225. array($this, 'makeTreeItem'),
  226. array($this, 'makeListItem')
  227. );
  228. }
  229. /**
  230. * get a combined list of media and page files
  231. *
  232. * also called via AJAX
  233. *
  234. * @param string $folder an already converted filesystem folder of the current namespace
  235. * @param string $limit limit the search to this folder
  236. * @return array
  237. */
  238. public function makeTree($folder, $limit = '')
  239. {
  240. global $conf;
  241. // read tree structure from pages and media
  242. $data = array();
  243. search($data, $conf['datadir'], 'search_index', array('ns' => $folder), $limit);
  244. $media = array();
  245. search($media, $conf['mediadir'], 'search_index', array('ns' => $folder, 'nofiles' => true), $limit);
  246. $data = array_merge($data, $media);
  247. unset($media);
  248. // combine by sorting and removing duplicates
  249. usort($data, array($this, 'treeSort'));
  250. $count = count($data);
  251. if ($count>0) for ($i=1; $i<$count; $i++) {
  252. if ($data[$i-1]['id'] == $data[$i]['id'] && $data[$i-1]['type'] == $data[$i]['type']) {
  253. unset($data[$i]);
  254. $i++; // duplicate found, next $i can't be a duplicate, so skip forward one
  255. }
  256. }
  257. return $data;
  258. }
  259. /**
  260. * usort callback
  261. *
  262. * Sorts the combined trees of media and page files
  263. */
  264. public function treeSort($a, $b)
  265. {
  266. // handle the trivial cases first
  267. if ($a['id'] == '') return -1;
  268. if ($b['id'] == '') return 1;
  269. // split up the id into parts
  270. $a_ids = explode(':', $a['id']);
  271. $b_ids = explode(':', $b['id']);
  272. // now loop through the parts
  273. while (count($a_ids) && count($b_ids)) {
  274. // compare each level from upper to lower
  275. // until a non-equal component is found
  276. $cur_result = strcmp(array_shift($a_ids), array_shift($b_ids));
  277. if ($cur_result) {
  278. // if one of the components is the last component and is a file
  279. // and the other one is either of a deeper level or a directory,
  280. // the file has to come after the deeper level or directory
  281. if (empty($a_ids) && $a['type'] == 'f' && (count($b_ids) || $b['type'] == 'd')) return 1;
  282. if (empty($b_ids) && $b['type'] == 'f' && (count($a_ids) || $a['type'] == 'd')) return -1;
  283. return $cur_result;
  284. }
  285. }
  286. // The two ids seem to be equal. One of them might however refer
  287. // to a page, one to a namespace, the namespace needs to be first.
  288. if (empty($a_ids) && empty($b_ids)) {
  289. if ($a['type'] == $b['type']) return 0;
  290. if ($a['type'] == 'f') return 1;
  291. return -1;
  292. }
  293. // Now the empty part is either a page in the parent namespace
  294. // that obviously needs to be after the namespace
  295. // Or it is the namespace that contains the other part and should be
  296. // before that other part.
  297. if (empty($a_ids)) return ($a['type'] == 'd') ? -1 : 1;
  298. if (empty($b_ids)) return ($b['type'] == 'd') ? 1 : -1;
  299. return 0; //shouldn't happen
  300. }
  301. /**
  302. * Display the current ACL for selected where/who combination with
  303. * selectors and modification form
  304. *
  305. * @author Andreas Gohr <andi@splitbrain.org>
  306. */
  307. protected function printDetail()
  308. {
  309. global $ID;
  310. echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
  311. echo '<div id="acl__user">';
  312. echo $this->getLang('acl_perms').' ';
  313. $inl = $this->makeSelect();
  314. echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who, '@'))).'" />'.NL;
  315. echo '<button type="submit">'.$this->getLang('btn_select').'</button>'.NL;
  316. echo '</div>'.NL;
  317. echo '<div id="acl__info">';
  318. $this->printInfo();
  319. echo '</div>';
  320. echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
  321. echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
  322. echo '<input type="hidden" name="do" value="admin" />'.NL;
  323. echo '<input type="hidden" name="page" value="acl" />'.NL;
  324. echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL;
  325. echo '</div></form>'.NL;
  326. }
  327. /**
  328. * Print info and editor
  329. *
  330. * also loaded via Ajax
  331. */
  332. public function printInfo()
  333. {
  334. global $ID;
  335. if ($this->who) {
  336. $current = $this->getExactPermisson();
  337. // explain current permissions
  338. $this->printExplanation($current);
  339. // load editor
  340. $this->printAclEditor($current);
  341. } else {
  342. echo '<p>';
  343. if ($this->ns) {
  344. printf($this->getLang('p_choose_ns'), hsc($this->ns));
  345. } else {
  346. printf($this->getLang('p_choose_id'), hsc($ID));
  347. }
  348. echo '</p>';
  349. echo $this->locale_xhtml('help');
  350. }
  351. }
  352. /**
  353. * Display the ACL editor
  354. *
  355. * @author Andreas Gohr <andi@splitbrain.org>
  356. */
  357. protected function printAclEditor($current)
  358. {
  359. global $lang;
  360. echo '<fieldset>';
  361. if (is_null($current)) {
  362. echo '<legend>'.$this->getLang('acl_new').'</legend>';
  363. } else {
  364. echo '<legend>'.$this->getLang('acl_mod').'</legend>';
  365. }
  366. echo $this->makeCheckboxes($current, empty($this->ns), 'acl');
  367. if (is_null($current)) {
  368. echo '<button type="submit" name="cmd[save]">'.$lang['btn_save'].'</button>'.NL;
  369. } else {
  370. echo '<button type="submit" name="cmd[save]">'.$lang['btn_update'].'</button>'.NL;
  371. echo '<button type="submit" name="cmd[del]">'.$lang['btn_delete'].'</button>'.NL;
  372. }
  373. echo '</fieldset>';
  374. }
  375. /**
  376. * Explain the currently set permissions in plain english/$lang
  377. *
  378. * @author Andreas Gohr <andi@splitbrain.org>
  379. */
  380. protected function printExplanation($current)
  381. {
  382. global $ID;
  383. global $auth;
  384. $who = $this->who;
  385. $ns = $this->ns;
  386. // prepare where to check
  387. if ($ns) {
  388. if ($ns == '*') {
  389. $check='*';
  390. } else {
  391. $check=$ns.':*';
  392. }
  393. } else {
  394. $check = $ID;
  395. }
  396. // prepare who to check
  397. if ($who[0] == '@') {
  398. $user = '';
  399. $groups = array(ltrim($who, '@'));
  400. } else {
  401. $user = $who;
  402. $info = $auth->getUserData($user);
  403. if ($info === false) {
  404. $groups = array();
  405. } else {
  406. $groups = $info['grps'];
  407. }
  408. }
  409. // check the permissions
  410. $perm = auth_aclcheck($check, $user, $groups);
  411. // build array of named permissions
  412. $names = array();
  413. if ($perm) {
  414. if ($ns) {
  415. if ($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16');
  416. if ($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8');
  417. if ($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4');
  418. }
  419. if ($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2');
  420. if ($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1');
  421. $names = array_reverse($names);
  422. } else {
  423. $names[] = $this->getLang('acl_perm0');
  424. }
  425. // print permission explanation
  426. echo '<p>';
  427. if ($user) {
  428. if ($ns) {
  429. printf($this->getLang('p_user_ns'), hsc($who), hsc($ns), join(', ', $names));
  430. } else {
  431. printf($this->getLang('p_user_id'), hsc($who), hsc($ID), join(', ', $names));
  432. }
  433. } else {
  434. if ($ns) {
  435. printf($this->getLang('p_group_ns'), hsc(ltrim($who, '@')), hsc($ns), join(', ', $names));
  436. } else {
  437. printf($this->getLang('p_group_id'), hsc(ltrim($who, '@')), hsc($ID), join(', ', $names));
  438. }
  439. }
  440. echo '</p>';
  441. // add note if admin
  442. if ($perm == AUTH_ADMIN) {
  443. echo '<p>'.$this->getLang('p_isadmin').'</p>';
  444. } elseif (is_null($current)) {
  445. echo '<p>'.$this->getLang('p_inherited').'</p>';
  446. }
  447. }
  448. /**
  449. * Item formatter for the tree view
  450. *
  451. * User function for html_buildlist()
  452. *
  453. * @author Andreas Gohr <andi@splitbrain.org>
  454. */
  455. public function makeTreeItem($item)
  456. {
  457. $ret = '';
  458. // what to display
  459. if (!empty($item['label'])) {
  460. $base = $item['label'];
  461. } else {
  462. $base = ':'.$item['id'];
  463. $base = substr($base, strrpos($base, ':')+1);
  464. }
  465. // highlight?
  466. if (($item['type']== $this->current_item['type'] && $item['id'] == $this->current_item['id'])) {
  467. $cl = ' cur';
  468. } else {
  469. $cl = '';
  470. }
  471. // namespace or page?
  472. if ($item['type']=='d') {
  473. if ($item['open']) {
  474. $img = DOKU_BASE.'lib/images/minus.gif';
  475. $alt = '−';
  476. } else {
  477. $img = DOKU_BASE.'lib/images/plus.gif';
  478. $alt = '+';
  479. }
  480. $ret .= '<img src="'.$img.'" alt="'.$alt.'" />';
  481. $ret .= '<a href="'.
  482. wl('', $this->getLinkOptions(array('ns'=> $item['id'], 'sectok'=>getSecurityToken()))).
  483. '" class="idx_dir'.$cl.'">';
  484. $ret .= $base;
  485. $ret .= '</a>';
  486. } else {
  487. $ret .= '<a href="'.
  488. wl('', $this->getLinkOptions(array('id'=> $item['id'], 'ns'=>'', 'sectok'=>getSecurityToken()))).
  489. '" class="wikilink1'.$cl.'">';
  490. $ret .= noNS($item['id']);
  491. $ret .= '</a>';
  492. }
  493. return $ret;
  494. }
  495. /**
  496. * List Item formatter
  497. *
  498. * @param array $item
  499. * @return string
  500. */
  501. public function makeListItem($item)
  502. {
  503. return '<li class="level' . $item['level'] . ' ' .
  504. ($item['open'] ? 'open' : 'closed') . '">';
  505. }
  506. /**
  507. * Get current ACL settings as multidim array
  508. *
  509. * @author Andreas Gohr <andi@splitbrain.org>
  510. */
  511. public function initAclConfig()
  512. {
  513. global $AUTH_ACL;
  514. global $conf;
  515. $acl_config=array();
  516. $usersgroups = array();
  517. // get special users and groups
  518. $this->specials[] = '@ALL';
  519. $this->specials[] = '@'.$conf['defaultgroup'];
  520. if ($conf['manager'] != '!!not set!!') {
  521. $this->specials = array_merge(
  522. $this->specials,
  523. array_map(
  524. 'trim',
  525. explode(',', $conf['manager'])
  526. )
  527. );
  528. }
  529. $this->specials = array_filter($this->specials);
  530. $this->specials = array_unique($this->specials);
  531. sort($this->specials);
  532. foreach ($AUTH_ACL as $line) {
  533. $line = trim(preg_replace('/#.*$/', '', $line)); //ignore comments
  534. if (!$line) continue;
  535. $acl = preg_split('/[ \t]+/', $line);
  536. //0 is pagename, 1 is user, 2 is acl
  537. $acl[1] = rawurldecode($acl[1]);
  538. $acl_config[$acl[0]][$acl[1]] = $acl[2];
  539. // store non-special users and groups for later selection dialog
  540. $ug = $acl[1];
  541. if (in_array($ug, $this->specials)) continue;
  542. $usersgroups[] = $ug;
  543. }
  544. $usersgroups = array_unique($usersgroups);
  545. sort($usersgroups);
  546. ksort($acl_config);
  547. $this->acl = $acl_config;
  548. $this->usersgroups = $usersgroups;
  549. }
  550. /**
  551. * Display all currently set permissions in a table
  552. *
  553. * @author Andreas Gohr <andi@splitbrain.org>
  554. */
  555. protected function printAclTable()
  556. {
  557. global $lang;
  558. global $ID;
  559. echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
  560. if ($this->ns) {
  561. echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
  562. } else {
  563. echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
  564. }
  565. echo '<input type="hidden" name="acl_w" value="'.hsc($this->who).'" />'.NL;
  566. echo '<input type="hidden" name="do" value="admin" />'.NL;
  567. echo '<input type="hidden" name="page" value="acl" />'.NL;
  568. echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL;
  569. echo '<div class="table">';
  570. echo '<table class="inline">';
  571. echo '<tr>';
  572. echo '<th>'.$this->getLang('where').'</th>';
  573. echo '<th>'.$this->getLang('who').'</th>';
  574. echo '<th>'.$this->getLang('perm').'<sup><a id="fnt__1" class="fn_top" href="#fn__1">1)</a></sup></th>';
  575. echo '<th>'.$lang['btn_delete'].'</th>';
  576. echo '</tr>';
  577. foreach ($this->acl as $where => $set) {
  578. foreach ($set as $who => $perm) {
  579. echo '<tr>';
  580. echo '<td>';
  581. if (substr($where, -1) == '*') {
  582. echo '<span class="aclns">'.hsc($where).'</span>';
  583. $ispage = false;
  584. } else {
  585. echo '<span class="aclpage">'.hsc($where).'</span>';
  586. $ispage = true;
  587. }
  588. echo '</td>';
  589. echo '<td>';
  590. if ($who[0] == '@') {
  591. echo '<span class="aclgroup">'.hsc($who).'</span>';
  592. } else {
  593. echo '<span class="acluser">'.hsc($who).'</span>';
  594. }
  595. echo '</td>';
  596. echo '<td>';
  597. echo $this->makeCheckboxes($perm, $ispage, 'acl['.$where.']['.$who.']');
  598. echo '</td>';
  599. echo '<td class="check">';
  600. echo '<input type="checkbox" name="del['.hsc($where).'][]" value="'.hsc($who).'" />';
  601. echo '</td>';
  602. echo '</tr>';
  603. }
  604. }
  605. echo '<tr>';
  606. echo '<th class="action" colspan="4">';
  607. echo '<button type="submit" name="cmd[update]">'.$lang['btn_update'].'</button>';
  608. echo '</th>';
  609. echo '</tr>';
  610. echo '</table>';
  611. echo '</div>';
  612. echo '</div></form>'.NL;
  613. }
  614. /**
  615. * Returns the permission which were set for exactly the given user/group
  616. * and page/namespace. Returns null if no exact match is available
  617. *
  618. * @author Andreas Gohr <andi@splitbrain.org>
  619. */
  620. protected function getExactPermisson()
  621. {
  622. global $ID;
  623. if ($this->ns) {
  624. if ($this->ns == '*') {
  625. $check = '*';
  626. } else {
  627. $check = $this->ns.':*';
  628. }
  629. } else {
  630. $check = $ID;
  631. }
  632. if (isset($this->acl[$check][$this->who])) {
  633. return $this->acl[$check][$this->who];
  634. } else {
  635. return null;
  636. }
  637. }
  638. /**
  639. * adds new acl-entry to conf/acl.auth.php
  640. *
  641. * @author Frank Schubert <frank@schokilade.de>
  642. */
  643. public function addOrUpdateACL($acl_scope, $acl_user, $acl_level)
  644. {
  645. global $config_cascade;
  646. // first make sure we won't end up with 2 lines matching this user and scope. See issue #1115
  647. $this->deleteACL($acl_scope, $acl_user);
  648. $acl_user = auth_nameencode($acl_user, true);
  649. // max level for pagenames is edit
  650. if (strpos($acl_scope, '*') === false) {
  651. if ($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
  652. }
  653. $new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
  654. return io_saveFile($config_cascade['acl']['default'], $new_acl, true);
  655. }
  656. /**
  657. * remove acl-entry from conf/acl.auth.php
  658. *
  659. * @author Frank Schubert <frank@schokilade.de>
  660. */
  661. public function deleteACL($acl_scope, $acl_user)
  662. {
  663. global $config_cascade;
  664. $acl_user = auth_nameencode($acl_user, true);
  665. $acl_pattern = '^'.preg_quote($acl_scope, '/').'[ \t]+'.$acl_user.'[ \t]+[0-8].*$';
  666. return io_deleteFromFile($config_cascade['acl']['default'], "/$acl_pattern/", true);
  667. }
  668. /**
  669. * print the permission radio boxes
  670. *
  671. * @author Frank Schubert <frank@schokilade.de>
  672. * @author Andreas Gohr <andi@splitbrain.org>
  673. */
  674. protected function makeCheckboxes($setperm, $ispage, $name)
  675. {
  676. global $lang;
  677. static $label = 0; //number labels
  678. $ret = '';
  679. if ($ispage && $setperm > AUTH_EDIT) $setperm = AUTH_EDIT;
  680. foreach (array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm) {
  681. $label += 1;
  682. //general checkbox attributes
  683. $atts = array( 'type' => 'radio',
  684. 'id' => 'pbox'.$label,
  685. 'name' => $name,
  686. 'value' => $perm );
  687. //dynamic attributes
  688. if (!is_null($setperm) && $setperm == $perm) $atts['checked'] = 'checked';
  689. if ($ispage && $perm > AUTH_EDIT) {
  690. $atts['disabled'] = 'disabled';
  691. $class = ' class="disabled"';
  692. } else {
  693. $class = '';
  694. }
  695. //build code
  696. $ret .= '<label for="pbox'.$label.'"'.$class.'>';
  697. $ret .= '<input '.buildAttributes($atts).' />&#160;';
  698. $ret .= $this->getLang('acl_perm'.$perm);
  699. $ret .= '</label>'.NL;
  700. }
  701. return $ret;
  702. }
  703. /**
  704. * Print a user/group selector (reusing already used users and groups)
  705. *
  706. * @author Andreas Gohr <andi@splitbrain.org>
  707. */
  708. protected function makeSelect()
  709. {
  710. $inlist = false;
  711. $usel = '';
  712. $gsel = '';
  713. if ($this->who &&
  714. !in_array($this->who, $this->usersgroups) &&
  715. !in_array($this->who, $this->specials)) {
  716. if ($this->who[0] == '@') {
  717. $gsel = ' selected="selected"';
  718. } else {
  719. $usel = ' selected="selected"';
  720. }
  721. } else {
  722. $inlist = true;
  723. }
  724. echo '<select name="acl_t" class="edit">'.NL;
  725. echo ' <option value="__g__" class="aclgroup"'.$gsel.'>'.$this->getLang('acl_group').'</option>'.NL;
  726. echo ' <option value="__u__" class="acluser"'.$usel.'>'.$this->getLang('acl_user').'</option>'.NL;
  727. if (!empty($this->specials)) {
  728. echo ' <optgroup label="&#160;">'.NL;
  729. foreach ($this->specials as $ug) {
  730. if ($ug == $this->who) {
  731. $sel = ' selected="selected"';
  732. $inlist = true;
  733. } else {
  734. $sel = '';
  735. }
  736. if ($ug[0] == '@') {
  737. echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
  738. } else {
  739. echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
  740. }
  741. }
  742. echo ' </optgroup>'.NL;
  743. }
  744. if (!empty($this->usersgroups)) {
  745. echo ' <optgroup label="&#160;">'.NL;
  746. foreach ($this->usersgroups as $ug) {
  747. if ($ug == $this->who) {
  748. $sel = ' selected="selected"';
  749. $inlist = true;
  750. } else {
  751. $sel = '';
  752. }
  753. if ($ug[0] == '@') {
  754. echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
  755. } else {
  756. echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
  757. }
  758. }
  759. echo ' </optgroup>'.NL;
  760. }
  761. echo '</select>'.NL;
  762. return $inlist;
  763. }
  764. }