FusionDirectory
class_config.inc
Go to the documentation of this file.
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2003-2010 Cajus Pollmeier
5  Copyright (C) 2011-2017 FusionDirectory
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 
31 class config
32 {
33  /* XML parser */
34  var $parser;
35  var $config_found = FALSE;
36  var $tags = [];
37  var $level = 0;
38  var $currentLocation = '';
39 
43  var $current = [];
44 
45  /* Link to LDAP-server */
46  protected $ldapLink = NULL;
47  var $referrals = [];
48 
49  /*
50  * \brief Configuration data
51  *
52  * - $data['SERVERS'] contains server informations.
53  */
54  var $data = [
55  'LOCATIONS' => [],
56  'SERVERS' => [],
57  'MAIN' => [],
58  ];
59  var $basedir = '';
60 
61  /* Keep a copy of the current department list */
62  protected $departmentList;
63  protected $departmentTree;
64  protected $departmentInfo;
65 
66  var $filename = '';
67  var $last_modified = 0;
68 
76  function __construct ($filename, $basedir = '')
77  {
78  $this->basedir = $basedir;
79 
80  /* Parse config file directly? */
81  if ($filename != '') {
82  $this->parse($filename);
83  }
84  }
85 
93  function check_and_reload ($force = FALSE)
94  {
95  /* Check if class_location.inc has changed, this is the case
96  if we have installed or removed plugins. */
97  $tmp = stat(CACHE_DIR.'/'.CLASS_CACHE);
98  if (session::is_set('class_location.inc:timestamp')
99  && ($tmp['mtime'] != session::get('class_location.inc:timestamp'))) {
100  session::un_set('plist');
101  }
102  session::set('class_location.inc:timestamp', $tmp['mtime']);
103 
104  if (($this->filename != '') && ((filemtime($this->filename) != $this->last_modified) || $force)) {
105  $this->config_found = FALSE;
106  $this->tags = [];
107  $this->level = 0;
108  $this->currentLocation = '';
109 
110  $this->parse($this->filename);
111  $this->set_current($this->current['NAME']);
112  }
113  }
114 
123  function parse ($filename)
124  {
125  $this->last_modified = filemtime($filename);
126  $this->filename = $filename;
127  $fh = fopen($filename, 'r');
128  $xmldata = fread($fh, 100000);
129  fclose($fh);
130  $this->parse_data($xmldata);
131  }
132 
133  function parse_data ($xmldata)
134  {
135  $this->data = [
136  'LOCATIONS' => [],
137  'SERVERS' => [],
138  'MAIN' => [],
139  ];
140 
141  $this->parser = xml_parser_create();
142  xml_set_object($this->parser, $this);
143  xml_set_element_handler($this->parser, "tag_open", "tag_close");
144 
145  if (!xml_parse($this->parser, chop($xmldata))) {
146  $msg = sprintf(_('XML error in fusiondirectory.conf: %s at line %d'),
147  xml_error_string(xml_get_error_code($this->parser)),
148  xml_get_current_line_number($this->parser));
149  throw new FatalError(htmlescape($msg));
150  }
151  xml_parser_free($this->parser);
152  }
153 
163  function tag_open ($parser, $tag, $attrs)
164  {
165  /* Save last and current tag for reference */
166  $this->tags[$this->level] = $tag;
167  $this->level++;
168 
169  /* Trigger on CONF section */
170  if ($tag == 'CONF') {
171  $this->config_found = TRUE;
172  }
173 
174  /* Return if we're not in config section */
175  if (!$this->config_found) {
176  return;
177  }
178 
179  /* yes/no to true/false and upper case TRUE to true and so on*/
180  foreach ($attrs as $name => $value) {
181  if (preg_match("/^(true|yes)$/i", $value)) {
182  $attrs[$name] = "TRUE";
183  } elseif (preg_match("/^(false|no)$/i", $value)) {
184  $attrs[$name] = "FALSE";
185  }
186  }
187 
188  /* Look through attributes */
189  switch ($this->tags[$this->level - 1]) {
190  /* Handle location */
191  case 'LOCATION':
192  if ($this->tags[$this->level - 2] == 'MAIN') {
193  $attrs['NAME'] = preg_replace('/[<>"\']/', '', $attrs['NAME']);
194 
195  $this->currentLocation = $attrs['NAME'];
196 
197  /* Add location elements */
198  $this->data['LOCATIONS'][$attrs['NAME']] = $attrs;
199  }
200  break;
201 
202  /* Handle referral tags */
203  case 'REFERRAL':
204  if ($this->tags[$this->level - 2] == 'LOCATION') {
205  if (isset($attrs['BASE'])) {
206  $server = $attrs['URI'];
207  } elseif (isset($this->data['LOCATIONS'][$this->currentLocation]['BASE'])) {
208  /* Fallback on location base */
209  $server = $attrs['URI'];
210  $attrs['BASE'] = $this->data['LOCATIONS'][$this->currentLocation]['BASE'];
211  } else {
212  /* Format from FD<1.3 */
213  $server = preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $attrs['URI']);
214  $attrs['BASE'] = preg_replace('!^[^:]+://[^/]+/(.*)$!', '\\1', $attrs['URI']);
215  $attrs['URI'] = $server;
216  }
217 
218  /* Add location elements */
219  if (!isset($this->data['LOCATIONS'][$this->currentLocation]['REFERRAL'])) {
220  $this->data['LOCATIONS'][$this->currentLocation]['REFERRAL'] = [];
221  }
222 
223  $this->data['LOCATIONS'][$this->currentLocation]['REFERRAL'][$server] = $attrs;
224  }
225  break;
226 
227  /* Load main parameters */
228  case 'MAIN':
229  $this->data['MAIN'] = array_merge($this->data['MAIN'], $attrs);
230  break;
231 
232  /* Ignore other tags */
233  default:
234  break;
235  }
236  }
237 
245  function tag_close ($parser, $tag)
246  {
247  /* Close config section */
248  if ($tag == 'CONF') {
249  $this->config_found = FALSE;
250  }
251  $this->level--;
252  }
253 
264  function get_credentials ($creds)
265  {
266  if (isset($_SERVER['HTTP_FDKEY'])) {
267  if (!session::is_set('HTTP_FDKEY_CACHE')) {
268  session::set('HTTP_FDKEY_CACHE', []);
269  }
270  $cache = session::get('HTTP_FDKEY_CACHE');
271  if (!isset($cache[$creds])) {
272  try {
273  $cache[$creds] = cred_decrypt($creds, $_SERVER['HTTP_FDKEY']);
274  session::set('HTTP_FDKEY_CACHE', $cache);
275  } catch (FusionDirectoryException $e) {
276  $msg = nl2br(htmlescape(sprintf(
277  _('It seems you are trying to decode something which is not encoded : %s'."\n".
278  'Please check you are not using a fusiondirectory.secrets file while your passwords are not encrypted.'),
279  $e->getMessage()
280  )));
281  throw new FatalError($msg);
282  }
283  }
284  return $cache[$creds];
285  }
286  return $creds;
287  }
288 
307  function get_ldap_link (bool $sizelimit = FALSE): ldapMultiplexer
308  {
309  global $ui;
310 
311  if (($this->ldapLink === NULL) || ($this->ldapLink->cid === FALSE)) {
312  /* Build new connection */
313  $this->ldapLink = LDAP::init($this->current['SERVER'], $this->current['BASE'],
314  $this->current['ADMINDN'], $this->get_credentials($this->current['ADMINPASSWORD']));
315 
316  /* Check for connection */
317  if (is_null($this->ldapLink) || (is_int($this->ldapLink) && $this->ldapLink == 0)) {
318  throw new FatalError(htmlescape(_('Cannot bind to LDAP. Please contact the system administrator.')));
319  }
320 
321  /* Move referrals */
322  if (!isset($this->current['REFERRAL'])) {
323  $this->ldapLink->referrals = [];
324  } else {
325  $this->ldapLink->referrals = $this->current['REFERRAL'];
326  }
327  }
328 
329  $obj = new ldapMultiplexer($this->ldapLink);
330  if ($sizelimit) {
331  $obj->set_size_limit($ui->getSizeLimitHandler()->getSizeLimit());
332  } else {
333  $obj->set_size_limit(0);
334  }
335  return $obj;
336  }
337 
343  function set_current ($name)
344  {
345  global $ui;
346 
347  if (!isset($this->data['LOCATIONS'][$name])) {
348  throw new FatalError(htmlescape(sprintf(_('Location "%s" could not be found in the configuration file'), $name)));
349  }
350  $this->current = $this->data['LOCATIONS'][$name];
351 
352  if (isset($this->current['INITIAL_BASE']) && isset($ui)) {
353  $ui->setCurrentBase($this->current['INITIAL_BASE']);
354  }
355 
356  /* Sort referrals, if present */
357  if (isset($this->current['REFERRAL'])) {
358  $servers = [];
359  foreach ($this->current['REFERRAL'] as $server => $ref) {
360  $servers[$server] = strlen($ref['BASE']);
361  }
362  asort($servers);
363  reset($servers);
364 
365  /* SERVER not defined? Load the one with the shortest base */
366  if (!isset($this->current['SERVER'])) {
367  $this->current['SERVER'] = key($servers);
368  }
369  }
370 
371 
372  /* Parse LDAP referral informations */
373  if (!isset($this->current['ADMINDN']) || !isset($this->current['ADMINPASSWORD'])) {
374  $this->current['BASE'] = $this->current['REFERRAL'][$this->current['SERVER']]['BASE'];
375  $this->current['ADMINDN'] = $this->current['REFERRAL'][$this->current['SERVER']]['ADMINDN'];
376  $this->current['ADMINPASSWORD'] = $this->current['REFERRAL'][$this->current['SERVER']]['ADMINPASSWORD'];
377  }
378 
379  /* Load in-ldap configuration */
380  $this->load_inldap_config();
381 
382  /* Parse management config */
383  $this->loadManagementConfig();
384 
385  $debugLevel = $this->get_cfg_value('DEBUGLEVEL');
386  if ($debugLevel & DEBUG_CONFIG) {
387  /* Value from LDAP can't activate DEBUG_CONFIG */
388  $debugLevel -= DEBUG_CONFIG;
389  }
390  if (isset($this->data['MAIN']['DEBUGLEVEL'])) {
391  $debugLevel |= $this->data['MAIN']['DEBUGLEVEL'];
392  }
393  session::set('DEBUGLEVEL', $debugLevel);
394 
395  IconTheme::loadThemes('themes');
396 
397  timezone::setDefaultTimezoneFromConfig();
398 
399  Language::init();
400  }
401 
402  /* Check that configuration is in LDAP, check that no plugin got installed since last configuration update */
403  function checkLdapConfig ($forceReload = FALSE)
404  {
405  global $ui;
406  $dn = CONFIGRDN.$this->current['BASE'];
407 
408  if (!$forceReload) {
409  $ldap = $this->get_ldap_link();
410  $ldap->cat($dn, ['fusionConfigMd5']);
411  if (($attrs = $ldap->fetch()) && isset($attrs['fusionConfigMd5'][0])
412  && ($attrs['fusionConfigMd5'][0] == md5_file(CACHE_DIR.'/'.CLASS_CACHE))) {
413  return;
414  }
415  }
416 
417  Lock::add($dn);
418  $config_plugin = objects::open($dn, 'configuration');
419  $config_plugin->update();
420  $config_plugin->save();
422  }
423 
424  function load_inldap_config ()
425  {
426  $ldap = $this->get_ldap_link();
427  $ldap->cat(CONFIGRDN.$this->current['BASE']);
428  if ($attrs = $ldap->fetch()) {
429  for ($i = 0; $i < $attrs['count']; $i++) {
430  $key = $attrs[$i];
431  if (preg_match('/^fdTabHook$/i', $key)) {
432  for ($j = 0; $j < $attrs[$key]['count']; ++$j) {
433  $parts = explode('|', $attrs[$key][$j], 3);
434  $class = strtoupper($parts[0]);
435  $mode = strtoupper($parts[1]);
436  $cmd = $parts[2];
437  if (!isset($cmd[0]) || ($cmd[0] == '#')) {
438  /* Ignore commented out and empty triggers */
439  continue;
440  }
441  if (!isset($this->data['HOOKS'][$class])) {
442  $this->data['HOOKS'][$class] = ['CLASS' => $parts[0]];
443  }
444  if (!isset($this->data['HOOKS'][$class][$mode])) {
445  $this->data['HOOKS'][$class][$mode] = [];
446  }
447  $this->data['HOOKS'][$class][$mode][] = $cmd;
448  }
449  } elseif (preg_match('/^fd/', $key)) {
450  if (isset($attrs[$key]['count']) && ($attrs[$key]['count'] > 1)) {
451  $value = $attrs[$key];
452  unset($value['count']);
453  } else {
454  $value = $attrs[$key][0];
455  }
456  $key = strtoupper(preg_replace('/^fd/', '', $key));
457  $this->current[$key] = $value;
458  }
459  }
460  }
461  }
462 
466  private function loadManagementConfig ()
467  {
468  if (isset($this->current['MANAGEMENTCONFIG'])) {
469  if (!is_array($this->current['MANAGEMENTCONFIG'])) {
470  $this->current['MANAGEMENTCONFIG'] = [$this->current['MANAGEMENTCONFIG']];
471  }
472  $value = [];
473  foreach ($this->current['MANAGEMENTCONFIG'] as $config) {
474  list($class, $json) = explode(':', $config, 2);
475  $value[$class] = $json;
476  }
477  $this->current['MANAGEMENTCONFIG'] = $value;
478  }
479  if (isset($this->current['MANAGEMENTUSERCONFIG'])) {
480  if (!is_array($this->current['MANAGEMENTUSERCONFIG'])) {
481  $this->current['MANAGEMENTUSERCONFIG'] = [$this->current['MANAGEMENTUSERCONFIG']];
482  }
483  $value = [];
484  foreach ($this->current['MANAGEMENTUSERCONFIG'] as $config) {
485  list($user, $class, $json) = explode(':', $config, 3);
486  $value[$user][$class] = $json;
487  }
488  $this->current['MANAGEMENTUSERCONFIG'] = $value;
489  }
490  }
491 
495  public function updateManagementConfig (string $managementClass, $managementConfig, bool $userConfig = FALSE): array
496  {
497  global $ui;
498 
499  $changes = [];
500  if ($userConfig) {
501  if (!isset($this->current['MANAGEMENTUSERCONFIG'][$ui->dn])) {
502  $this->current['MANAGEMENTUSERCONFIG'][$ui->dn] = [];
503  }
504  $currentConfig =& $this->current['MANAGEMENTUSERCONFIG'][$ui->dn];
505  $attrib = 'fdManagementUserConfig';
506  $prefix = $ui->dn.':'.$managementClass;
507  } else {
508  if (!isset($this->current['MANAGEMENTCONFIG'])) {
509  $this->current['MANAGEMENTCONFIG'] = [];
510  }
511  $currentConfig =& $this->current['MANAGEMENTCONFIG'];
512  $attrib = 'fdManagementConfig';
513  $prefix = $managementClass;
514  }
515 
516  if ($managementConfig !== NULL) {
517  $managementConfig = json_encode($managementConfig);
518  }
519 
520  if (isset($currentConfig[$managementClass])) {
521  /* If there already was a config for this class, remove it */
522  if ($currentConfig[$managementClass] === $managementConfig) {
523  /* Unless it's the same one and we've got nothing to do */
524  return [];
525  }
526  $changes[] = [
527  'attrib' => $attrib,
528  'modtype' => LDAP_MODIFY_BATCH_REMOVE,
529  'values' => [$prefix.':'.$currentConfig[$managementClass]],
530  ];
531  }
532 
533  if ($managementConfig !== NULL) {
534  /* Add the new one, if any */
535  $changes[] = [
536  'attrib' => $attrib,
537  'modtype' => LDAP_MODIFY_BATCH_ADD,
538  'values' => [$prefix.':'.$managementConfig],
539  ];
540  }
541  $ldap = $this->get_ldap_link();
542  $ldap->cd(CONFIGRDN.$this->current['BASE']);
543  if (!$ldap->modify_batch($changes)) {
544  return [$ldap->get_error()];
545  }
546 
547  if ($managementConfig !== NULL) {
548  $currentConfig[$managementClass] = $managementConfig;
549  } else {
550  unset($currentConfig[$managementClass]);
551  }
552 
553  return [];
554  }
555 
559  public function hasManagementConfig (string $managementClass, bool $userConfig = FALSE): bool
560  {
561  global $ui;
562 
563  if ($userConfig) {
564  return isset($this->current['MANAGEMENTUSERCONFIG'][$ui->dn][$managementClass]);
565  } else {
566  return isset($this->current['MANAGEMENTCONFIG'][$managementClass]);
567  }
568  }
569 
573  public function getManagementConfig ($managementClass)
574  {
575  global $ui;
576 
577  if (isset($this->current['MANAGEMENTUSERCONFIG'][$ui->dn][$managementClass])) {
578  return json_decode($this->current['MANAGEMENTUSERCONFIG'][$ui->dn][$managementClass], TRUE);
579  } elseif (isset($this->current['MANAGEMENTCONFIG'][$managementClass])) {
580  return json_decode($this->current['MANAGEMENTCONFIG'][$managementClass], TRUE);
581  } else {
582  return NULL;
583  }
584  }
585 
586  function getDepartmentList (): array
587  {
588  if (!isset($this->departmentList)) {
589  $this->storeDepartmentList();
590  }
591  return $this->departmentList;
592  }
593 
594  function getDepartmentTree (): array
595  {
596  if (!isset($this->departmentTree)) {
597  $this->storeDepartmentTree();
598  }
599  return $this->departmentTree;
600  }
601 
602  function getDepartmentInfo (): array
603  {
604  if (!isset($this->departmentInfo)) {
605  $this->storeDepartmentList();
606  }
607  return $this->departmentInfo;
608  }
609 
610  function resetDepartmentCache ()
611  {
612  unset($this->departmentList);
613  unset($this->departmentTree);
614  unset($this->departmentInfo);
615  }
616 
620  protected function storeDepartmentList ()
621  {
622  /* Initialize result hash */
623  $result = ['/' => $this->current['BASE']];
624 
625  $this->departmentInfo = [];
626 
627  /* Get all department types from department Management, to be able detect the department type.
628  -It is possible that different department types have the same name,
629  in this case we have to mark the department name to be able to differentiate.
630  (e.g l=Name or o=Name)
631  */
632  $types = departmentManagement::getDepartmentTypes();
633 
634  /* Create a list of attributes to fetch */
635  $filter = '';
636  $ldap_values = ['objectClass', 'description'];
637  foreach ($types as $type) {
638  $i = objects::infos($type);
639  $filter .= $i['filter'];
640  /* Add type main attr to fetched attributes list */
641  $ldap_values[] = $i['mainAttr'];
642  }
643  $filter = '(|'.$filter.')';
644 
645  /* Get list of department objects */
646  $ldap = $this->get_ldap_link();
647  $ldap->cd($this->current['BASE']);
648  $ldap->search($filter, $ldap_values);
649  while ($attrs = $ldap->fetch()) {
650 
651  /* Detect department type */
652  $oc = NULL;
653  foreach ($types as $type) {
654  if (objects::isOfType($attrs, $type)) {
655  $oc = $type;
656  break;
657  }
658  }
659 
660  /* Unknown department type -> skip */
661  if ($oc == NULL) {
662  continue;
663  }
664 
665  $dn = $attrs['dn'];
666  $infos = objects::infos($oc);
667  $this->departmentInfo[$dn] = [
668  'img' => $infos['icon'],
669  'description' => (isset($attrs['description'][0]) ? $attrs['description'][0] : ''),
670  'name' => $attrs[$infos['mainAttr']][0]
671  ];
672 
673  /* Only assign non-root departments */
674  if ($dn != $result['/']) {
675  $c_dn = convert_department_dn($dn).' ('.$infos['mainAttr'].')';
676  $result[$c_dn] = $dn;
677  }
678  }
679 
680  $this->departmentList = $result;
681  }
682 
686  protected function storeDepartmentTree ()
687  {
688  if (!isset($this->departmentList)) {
689  $this->storeDepartmentList();
690  }
691 
692  $base = $this->current['BASE'];
693  $qbase = preg_quote($base, '/');
694 
695  $arr = [];
696 
697  /* Create multidimensional array, with all departments. */
698  foreach ($this->departmentList as $val) {
699 
700  /* Split dn into single department pieces */
701  $elements = array_reverse(explode(',', preg_replace("/$qbase$/", '', $val)));
702 
703  /* Add last ou element of current dn to our array */
704  $last = &$arr;
705  foreach ($elements as $key => $ele) {
706  /* skip empty */
707  if (empty($ele)) {
708  continue;
709  }
710 
711  /* Extract department name */
712  $elestr = trim(preg_replace('/^[^=]*+=/', '', $ele), ',');
713  $nameA = trim(preg_replace('/=.*$/', '', $ele), ',');
714  if ($nameA != 'ou') {
715  $nameA = " ($nameA)";
716  } else {
717  $nameA = '';
718  }
719 
720  /* Add to array */
721  if ($key == (count($elements) - 1)) {
722  $last[$elestr.$nameA]['ENTRY'] = $val;
723  }
724 
725  /* Set next array appending position */
726  $last = &$last[$elestr.$nameA]['SUB'];
727  }
728  }
729 
730  /* Add base entry */
731  $ret = [
732  '/' => [
733  'ENTRY' => $base,
734  'SUB' => $arr,
735  ]
736  ];
737  $this->departmentTree = $this->generateDepartmentArray($ret, -1, 28);
738  }
739 
740  /*
741  * \brief Creates display friendly output from make_idepartments
742  *
743  * \param $arr arr
744  *
745  * \param int $depth initialized at -1
746  *
747  * \param int $max_size initialized at 256
748  */
749  protected function generateDepartmentArray ($arr, $depth, $max_size)
750  {
751  $ret = [];
752  $depth++;
753 
754  /* Walk through array */
755  ksort($arr);
756  foreach ($arr as $name => $entries) {
757  /* Fix name, if it contains a replace tag */
758  $name = preg_replace('/\\\\,/', ',', $name);
759 
760  /* Check if current name is too long, then cut it */
761  if (mb_strlen($name, 'UTF-8') > $max_size) {
762  $name = mb_substr($name, 0, ($max_size - 3), 'UTF-8')." ...";
763  }
764 
765  /* Append the name to the list */
766  if (isset($entries['ENTRY'])) {
767  $a = "";
768  for ($i = 0; $i < $depth; $i++) {
769  $a .= ".";
770  }
771  $ret[$entries['ENTRY']] = $a."&nbsp;".$name;
772  }
773 
774  /* recursive add of subdepartments */
775  if (!empty($entries['SUB'])) {
776  $ret = array_merge($ret, $this->generateDepartmentArray($entries['SUB'], $depth, $max_size));
777  }
778  }
779 
780  return $ret;
781  }
782 
797  function searchHooks ($class, $value)
798  {
799  $class = strtoupper($class);
800  $value = strtoupper($value);
801  return (isset($this->data['HOOKS'][$class][$value]) ? $this->data['HOOKS'][$class][$value] : []);
802  }
803 
821  function get_cfg_value ($name, $default = '')
822  {
823  $name = strtoupper($name);
824  $res = $default;
825 
826  /* Check if we have a current value for $name */
827  if (isset($this->current[$name])) {
828  $res = $this->current[$name];
829  } elseif (isset($this->data['MAIN'][$name])) {
830  /* Check if we have a global value for $name */
831  $res = $this->data['MAIN'][$name];
832  }
833 
834  if (is_array($default) && !is_array($res)) {
835  $res = [$res];
836  }
837 
838  return $res;
839  }
840 
855  {
856  $cfg_lifetime = $this->get_cfg_value('SESSIONLIFETIME', 0);
857  if ($cfg_lifetime > 0) {
858  $ini_lifetime = ini_get('session.gc_maxlifetime');
859  $deb_system = file_exists('/etc/debian_version');
860  return !($deb_system && ($ini_lifetime < $cfg_lifetime));
861  } else {
862  return TRUE;
863  }
864  }
865 
871  function snapshotEnabled ()
872  {
873  if ($this->get_cfg_value('enableSnapshots') != 'TRUE') {
874  return FALSE;
875  }
876 
877  /* Check if the snapshot_base is defined */
878  if ($this->get_cfg_value('snapshotBase') == '') {
879  /* Send message if not done already */
880  if (!session::is_set('snapshotFailMessageSend')) {
881  session::set('snapshotFailMessageSend', TRUE);
882  $error = new FusionDirectoryError(
883  htmlescape(sprintf(
884  _('The snapshot functionality is enabled, but the required variable "%s" is not set.'),
885  'snapshotBase'
886  ))
887  );
888  $error->display();
889  }
890  return FALSE;
891  }
892 
893  /* Check if gzcompress is available */
894  if (!is_callable('gzcompress')) {
895  /* Send message if not done already */
896  if (!session::is_set('snapshotFailMessageSend')) {
897  session::set('snapshotFailMessageSend', TRUE);
898  $error = new FusionDirectoryError(
899  htmlescape(sprintf(
900  _('The snapshot functionality is enabled, but the required compression module is missing. Please install "%s".'),
901  'php-zip / php-gzip'
902  ))
903  );
904  $error->display();
905  }
906  return FALSE;
907  }
908  return TRUE;
909  }
910 
911  function loadPlist (pluglist $plist)
912  {
913  $this->data['OBJECTS'] = [];
914  $this->data['SECTIONS'] = [];
915  $this->data['CATEGORIES'] = [];
916  $this->data['MENU'] = [];
917  $this->data['TABS'] = [];
918  foreach ($plist->info as $class => &$plInfo) {
919  if (isset($plInfo['plObjectType'])) {
920  $entry = ['CLASS' => $class,'NAME' => $plInfo['plShortName']];
921  if (isset($plInfo['plSubTabs'])) {
922  $entry['SUBTABS'] = strtoupper($plInfo['plSubTabs']);
923  }
924  foreach ($plInfo['plObjectType'] as $key => $value) {
925  if (is_numeric($key)) {
926  /* This is not the main tab */
927  $tabclass = strtoupper($value).'TABS';
928  if (($tabclass == 'GROUPTABS') && class_available('mixedGroup')) {
929  $tabclass = 'OGROUP-USERTABS';
930  }
931  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $tabclass, "Adding $class to tab list");
932  if (!isset($this->data['TABS'][$tabclass])) {
933  $this->data['TABS'][$tabclass] = [];
934  }
935  $this->data['TABS'][$tabclass][] = $entry;
936  } else {
937  /* This is the main tab */
938  if (isset($this->data['OBJECTS'][strtoupper($key)])) {
939  die("duplicated object type ".strtoupper($key)." in ".$this->data['OBJECTS'][strtoupper($key)]['mainTab']." and $class");
940  }
941  $tabclass = strtoupper($key)."TABS";
942  $value['tabGroup'] = $tabclass;
943  $value['mainTab'] = $class;
944  $value['templateActive'] = FALSE;
945  $value['snapshotActive'] = FALSE;
946  foreach (['ou', 'tabClass'] as $i) {
947  if (!isset($value[$i])) {
948  $value[$i] = NULL;
949  }
950  }
951  if (!isset($value['aclCategory'])) {
952  $value['aclCategory'] = $key;
953  }
954  if (isset($value['filter'])) {
955  if (!preg_match('/^\(.*\)$/', $value['filter'])) {
956  $value['filter'] = '('.$value['filter'].')';
957  }
958  } elseif (isset($plInfo['plFilter'])) {
959  $value['filter'] = $plInfo['plFilter'];
960  } else {
961  $value['filter'] = NULL;
962  }
963  if (!isset($value['mainAttr'])) {
964  $value['mainAttr'] = 'cn';
965  }
966  if (!isset($value['nameAttr'])) {
967  $value['nameAttr'] = $value['mainAttr'];
968  }
969  if (!isset($value['tabClass'])) {
970  $value['tabClass'] = 'simpleTabs';
971  }
972  $this->data['OBJECTS'][strtoupper($key)] = $value;
973  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $tabclass, "Adding $class as main tab of");
974  if (!isset($this->data['TABS'][$tabclass])) {
975  $this->data['TABS'][$tabclass] = [];
976  }
977  array_unshift($this->data['TABS'][$tabclass], $entry);
978  }
979  }
980  } elseif (class_available($class) && is_subclass_of($class, 'simpleService')) {
981  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $class, "Adding service");
982  if (!isset($this->data['TABS']['SERVERSERVICE'])) {
983  $this->data['TABS']['SERVERSERVICE'] = [];
984  }
985  $this->data['TABS']['SERVERSERVICE'][] = [
986  'CLASS' => $class,
987  'NAME' => $plInfo['plShortName']
988  ];
989  }
990  }
991  unset($plInfo);
992  $this->data['CATEGORIES']['all'] = [
993  'classes' => ['all'],
994  'description' => '*&nbsp;'._('All categories'),
995  'objectClass' => [],
996  ];
997  /* Extract categories definitions from object types */
998  foreach ($this->data['OBJECTS'] as $key => $infos) {
999  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $infos['aclCategory'], "ObjectType $key category");
1000  if (strtoupper($infos['aclCategory']) == $key) {
1001  $cat = $infos['aclCategory'];
1002  if (!isset($this->data['CATEGORIES'][$cat])) {
1003  $this->data['CATEGORIES'][$cat] = ['classes' => ['0']];
1004  }
1005  if (!isset($this->data['CATEGORIES'][$cat]['description'])) {
1006  $this->data['CATEGORIES'][$cat]['description'] = $infos['name'];
1007  preg_match_all('/objectClass=([^= \)\(]+)/', $infos['filter'], $m);
1008  $this->data['CATEGORIES'][$cat]['objectClass'] = $m[1];
1009  }
1010  }
1011  }
1012  /* Now that OBJECTS are filled, place tabs in categories */
1013  foreach ($plist->info as $class => &$plInfo) {
1014  $acl = [];
1015  /* Feed categories */
1016  if (isset($plInfo['plCategory'])) {
1017  /* Walk through supplied list and feed only translated categories */
1018  $acl = [];
1019  foreach ($plInfo['plCategory'] as $idx => $infos) {
1020  $cat = (is_numeric($idx) ? $infos : $idx);
1021  $acl[] = $cat;
1022  if (!isset($this->data['CATEGORIES'][$cat])) {
1023  $this->data['CATEGORIES'][$cat] = [ 'classes' => ['0'] ];
1024  }
1025  if (!empty($plInfo['plProvidedAcls'])) {
1026  $this->data['CATEGORIES'][$cat]['classes'][] = $class;
1027  }
1028  if (!is_numeric($idx)) {
1029  /* Non numeric index means -> base object containing more informations */
1030  $this->data['CATEGORIES'][$cat]['description'] = $infos['description'];
1031  if (!is_array($infos['objectClass'])) {
1032  $infos['objectClass'] = [$infos['objectClass']];
1033  }
1034  $this->data['CATEGORIES'][$cat]['objectClass'] = $infos['objectClass'];
1035  }
1036  }
1037  $plInfo['plCategory'] = $acl;
1038  }
1039  if (isset($plInfo['plObjectType'])) {
1040  foreach ($plInfo['plObjectType'] as $key => $value) {
1041  if (is_numeric($key)) {
1042  /* This is not the main tab */
1043  $obj = strtoupper($value);
1044  } else {
1045  /* This is the main tab */
1046  $obj = strtoupper($key);
1047  }
1048  if (strpos($obj, 'OGROUP-') === 0) {
1049  $obj = 'OGROUP';
1050  }
1051  /* if this is an existing objectType, not just a tab group */
1052  if (isset($this->data['OBJECTS'][$obj])) {
1053  $cat = $this->data['OBJECTS'][$obj]['aclCategory'];
1054  $acl[] = $cat;
1055 
1056  if (!empty($plInfo['plProvidedAcls'])) {
1057  $this->data['CATEGORIES'][$cat]['classes'][] = $class;
1058  }
1059  if (!in_array($cat, $plInfo['plCategory'])) {
1060  $plInfo['plCategory'][] = $cat;
1061  }
1062  }
1063  }
1064  }
1065  /* Read management info */
1066  if (isset($plInfo['plManages'])) {
1067  foreach ($plInfo['plManages'] as $type) {
1068  $obj = strtoupper($type);
1069  if (!isset($this->data['OBJECTS'][$obj])) {
1070  continue;
1071  }
1072  $cat = $this->data['OBJECTS'][$obj]['aclCategory'];
1073  $acl[] = $cat;
1074 
1075  if (!empty($plInfo['plProvidedAcls'])) {
1076  $this->data['CATEGORIES'][$cat]['classes'][] = $class;
1077  }
1078  if (!in_array($cat, $plInfo['plCategory'])) {
1079  $plInfo['plCategory'][] = $cat;
1080  }
1081 
1082  if (isset($this->data['OBJECTS'][$obj])) {
1083  $this->data['OBJECTS'][$obj]['management'] = $class;
1084  if (isset($class::$skipTemplates) && !$class::$skipTemplates) {
1085  $this->data['OBJECTS'][$obj]['templateActive'] = TRUE;
1086  $this->data['CATEGORIES'][$cat]['classes'][] = 'template';
1087  }
1088  if (isset($class::$skipSnapshots) && !$class::$skipSnapshots) {
1089  $this->data['OBJECTS'][$obj]['snapshotActive'] = TRUE;
1090  $this->data['CATEGORIES'][$cat]['classes'][] = 'SnapshotHandler';
1091  }
1092  if (class_available('archivedObject') && archivedObject::isArchiveActive($obj)) {
1093  $this->data['OBJECTS'][$obj]['archiveActive'] = TRUE;
1094  $this->data['CATEGORIES'][$cat]['classes'][] = 'archivedObject';
1095  }
1096  }
1097  }
1098  }
1099  logging::debug(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, join(',', array_unique($acl)), "Class $class categories");
1100  /* Feed menu */
1101  if (isset($plInfo['plSection'])) {
1102  $section = $plInfo['plSection'];
1103  if (!is_array($acl)) {
1104  $acl = [$acl];
1105  }
1106  if (!is_numeric(key($acl))) {
1107  $acl = array_keys($acl);
1108  }
1109  if (isset($plInfo['plSelfModify']) && $plInfo['plSelfModify']) {
1110  $acl[] = $acl[0].'/'.$class.':self';
1111  }
1112  $acl = join(',', array_unique($acl));
1113 
1114  if (is_array($section)) {
1115  $section = key($section);
1116  if (is_numeric($section)) {
1117  trigger_error("$class have wrong setting in plInfo/plSection");
1118  continue;
1119  }
1120  $this->data['SECTIONS'][$section] = array_change_key_case($plInfo['plSection'][$section], CASE_UPPER);
1121  }
1122  if (!isset($this->data['MENU'][$section])) {
1123  $this->data['MENU'][$section] = [];
1124  }
1125  $attrs = ['CLASS' => $class];
1126  if (!empty($acl)) {
1127  $attrs['ACL'] = $acl;
1128  }
1129  $this->data['MENU'][$section][] = $attrs;
1130  }
1131  if (isset($plInfo['plMenuProvider']) && $plInfo['plMenuProvider']) {
1132  list($sections, $entries) = $class::getMenuEntries();
1133  foreach ($sections as $section => $infos) {
1134  if (!isset($this->data['SECTIONS'][$section])) {
1135  $this->data['SECTIONS'][$section] = array_change_key_case($infos, CASE_UPPER);
1136  }
1137  if (!isset($this->data['MENU'][$section])) {
1138  $this->data['MENU'][$section] = [];
1139  }
1140  }
1141  foreach ($entries as $section => $section_entries) {
1142  foreach ($section_entries as $entry) {
1143  $this->data['MENU'][$section][] = $entry;
1144  }
1145  }
1146  }
1147  }
1148  unset($plInfo);
1149  ksort($this->data['CATEGORIES']);
1150  foreach ($this->data['CATEGORIES'] as $name => &$infos) {
1151  $infos['classes'] = array_unique($infos['classes']);
1152  if (!isset($infos['description'])) {
1153  $infos['description'] = $name;
1154  $infos['objectClass'] = [];
1155  }
1156  }
1157  unset($infos);
1158  $this->data['SECTIONS']['personal'] = ['NAME' => _('My account'), 'PRIORITY' => 60];
1159  $personal = [];
1160  foreach ($this->data['TABS']['USERTABS'] as $tab) {
1161  if ($plist->info[$tab['CLASS']]['plSelfModify']) {
1162  $personal[] = ['CLASS' => $tab['CLASS'], 'ACL' => 'user/'.$tab['CLASS'].':self'];
1163  }
1164  }
1165  if (!isset($this->data['MENU']['personal'])) {
1166  $this->data['MENU']['personal'] = $personal;
1167  } else {
1168  $this->data['MENU']['personal'] = array_merge($personal, $this->data['MENU']['personal']);
1169  }
1170  uasort($this->data['SECTIONS'],
1171  function ($a, $b)
1172  {
1173  if ($a['PRIORITY'] == $b['PRIORITY']) {
1174  return 0;
1175  }
1176  return (($a['PRIORITY'] < $b['PRIORITY']) ? -1 : 1);
1177  }
1178  );
1179  }
1180 }
const CACHE_DIR
Global cache dir.
Definition: variables.inc:55
cred_decrypt($input, $password)
Decrypt a string with RIJNDAEL_128.
Definition: functions.inc:1431
updateManagementConfig(string $managementClass, $managementConfig, bool $userConfig=FALSE)
Update the management config in the LDAP and the cache.
__construct($filename, $basedir='')
Class constructor of the config class.
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
const CLASS_CACHE
name of the class.cache file
Definition: variables.inc:85
hasManagementConfig(string $managementClass, bool $userConfig=FALSE)
Test if there is a stored management config.
static get($name)
Accessor of a session var.
set_current($name)
Set the current location.
This class contains all the function needed to make list of plugin and manage them.
get_ldap_link(bool $sizelimit=FALSE)
Get a LDAP link object.
const CONFIGRDN
FusionDirectory config object RDN.
tag_open($parser, $tag, $attrs)
Open xml tag when parsing the xml config.
static set($name, $value)
Set a value in a session.
static add($object, string $user=NULL)
Add a lock for object(s)
Definition: class_Lock.inc:47
static init($lang=NULL)
Initialize language configuration.
getManagementConfig($managementClass)
Returns the config for a management class, or NULL.
get_credentials($creds)
Get the password when needed from the config file.
static open(string $dn, string $type)
Create the tab object for the given dn.
static debug(int $level, int $line, string $function, string $file, $data, string $info='')
Debug output method.
Parent class for all exceptions thrown in FusionDirectory.
static deleteByObject($object)
Remove a lock for object(s)
Definition: class_Lock.inc:135
Fatal error class. Does not extend FusionDirectoryError.
static un_set($name)
Unset a session.
check_and_reload($force=FALSE)
Check and reload the configuration.
check_session_lifetime()
Check if session lifetime matches session.gc_maxlifetime.
static init(string $server, string $base, string $binddn='', string $pass='')
Initialize a LDAP connection.
Definition: class_ldap.inc:127
storeDepartmentTree()
Store the tree render for departments in $this->departmentTree.
const DEBUG_CONFIG
Parent class for all errors in FusionDirectory.
convert_department_dn($dn, $base=NULL)
Convert a department DN to a sub-directory style list.
Definition: functions.inc:349
$current
Store configuration for current location.
searchHooks($class, $value)
Search for hooks.
This class is responsible for parsing and querying the fusiondirectory configuration file...
static is_set($name)
Check if the name of the session is set.
snapshotEnabled()
Check if snapshot are enabled.
storeDepartmentList()
Store the departments from ldap in $this->departmentList.
tag_close($parser, $tag)
Close xml tag when parsing the xml config.
get_cfg_value($name, $default='')
Get a configuration value from the config.
class_available($name)
Checks if a class is available.
Definition: functions.inc:92
parse($filename)
Parse the given configuration file.