dolibarr  17.0.4
ldap.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
4  * Copyright (C) 2005-2021 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2006-2021 Laurent Destailleur <eldy@users.sourceforge.net>
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 3 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, see <https://www.gnu.org/licenses/>.
19  * or see https://www.gnu.org/
20  */
21 
34 class Ldap
35 {
39  public $error = '';
40 
44  public $errors = array();
45 
49  public $server = array();
50 
55 
59  public $dn;
63  public $serverType;
71  public $domain;
76  public $searchUser;
85  public $people;
89  public $groups;
98 
99 
100  //Fetch user
101  public $name;
102  public $firstname;
103  public $login;
104  public $phone;
105  public $skype;
106  public $fax;
107  public $mail;
108  public $mobile;
109 
110  public $uacf;
111  public $pwdlastset;
112 
113  public $ldapcharset = 'UTF-8'; // LDAP should be UTF-8 encoded
114 
115 
119  public $connection;
123  public $result;
124 
128  const SYNCHRO_NONE = 0;
129 
134 
139 
140 
144  public function __construct()
145  {
146  global $conf;
147 
148  // Server
149  if (!empty($conf->global->LDAP_SERVER_HOST)) {
150  $this->server[] = $conf->global->LDAP_SERVER_HOST;
151  }
152  if (!empty($conf->global->LDAP_SERVER_HOST_SLAVE)) {
153  $this->server[] = $conf->global->LDAP_SERVER_HOST_SLAVE;
154  }
155  $this->serverPort = getDolGlobalInt('LDAP_SERVER_PORT', 389);
156  $this->ldapProtocolVersion = getDolGlobalString('LDAP_SERVER_PROTOCOLVERSION');
157  $this->dn = getDolGlobalString('LDAP_SERVER_DN');
158  $this->serverType = getDolGlobalString('LDAP_SERVER_TYPE');
159 
160  $this->domain = getDolGlobalString('LDAP_SERVER_DN');
161  $this->searchUser = getDolGlobalString('LDAP_ADMIN_DN');
162  $this->searchPassword = getDolGlobalString('LDAP_ADMIN_PASS');
163  $this->people = getDolGlobalString('LDAP_USER_DN');
164  $this->groups = getDolGlobalString('LDAP_GROUP_DN');
165 
166  $this->filter = getDolGlobalString('LDAP_FILTER_CONNECTION'); // Filter on user
167  $this->filtergroup = getDolGlobalString('LDAP_GROUP_FILTER'); // Filter on groups
168  $this->filtermember = getDolGlobalString('LDAP_MEMBER_FILTER'); // Filter on member
169 
170  // Users
171  $this->attr_login = getDolGlobalString('LDAP_FIELD_LOGIN'); //unix
172  $this->attr_sambalogin = getDolGlobalString('LDAP_FIELD_LOGIN_SAMBA'); //samba, activedirectory
173  $this->attr_name = getDolGlobalString('LDAP_FIELD_NAME');
174  $this->attr_firstname = getDolGlobalString('LDAP_FIELD_FIRSTNAME');
175  $this->attr_mail = getDolGlobalString('LDAP_FIELD_MAIL');
176  $this->attr_phone = getDolGlobalString('LDAP_FIELD_PHONE');
177  $this->attr_skype = getDolGlobalString('LDAP_FIELD_SKYPE');
178  $this->attr_fax = getDolGlobalString('LDAP_FIELD_FAX');
179  $this->attr_mobile = getDolGlobalString('LDAP_FIELD_MOBILE');
180  }
181 
182  // Connection handling methods -------------------------------------------
183 
184  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
192  public function connect_bind()
193  {
194  // phpcs:enable
195  global $conf;
196  global $dolibarr_main_auth_ldap_debug;
197 
198  $connected = 0;
199  $this->bind = 0;
200  $this->error = 0;
201  $this->connectedServer = '';
202 
203  $ldapdebug = ((empty($dolibarr_main_auth_ldap_debug) || $dolibarr_main_auth_ldap_debug == "false") ? false : true);
204 
205  if ($ldapdebug) {
206  dol_syslog(get_class($this)."::connect_bind");
207  print "DEBUG: connect_bind<br>\n";
208  }
209 
210  // Check parameters
211  if (count($this->server) == 0 || empty($this->server[0])) {
212  $this->error = 'LDAP setup (file conf.php) is not complete';
213  dol_syslog(get_class($this)."::connect_bind ".$this->error, LOG_WARNING);
214  return -1;
215  }
216 
217  if (!function_exists("ldap_connect")) {
218  $this->error = 'LDAPFunctionsNotAvailableOnPHP';
219  dol_syslog(get_class($this)."::connect_bind ".$this->error, LOG_WARNING);
220  $return = -1;
221  }
222 
223  if (empty($this->error)) {
224  // Loop on each ldap server
225  foreach ($this->server as $host) {
226  if ($connected) {
227  break;
228  }
229  if (empty($host)) {
230  continue;
231  }
232 
233  if ($this->serverPing($host, $this->serverPort) === true) {
234  if ($ldapdebug) {
235  dol_syslog(get_class($this)."::connect_bind serverPing true, we try ldap_connect to ".$host);
236  }
237  $this->connection = ldap_connect($host, $this->serverPort);
238  } else {
239  if (preg_match('/^ldaps/i', $host)) {
240  // With host = ldaps://server, the serverPing to ssl://server sometimes fails, even if the ldap_connect succeed, so
241  // we test this case and continue in such a case even if serverPing fails.
242  if ($ldapdebug) {
243  dol_syslog(get_class($this)."::connect_bind serverPing false, we try ldap_connect to ".$host);
244  }
245  $this->connection = ldap_connect($host, $this->serverPort);
246  } else {
247  continue;
248  }
249  }
250 
251  if (is_resource($this->connection) || is_object($this->connection)) {
252  if ($ldapdebug) {
253  dol_syslog(get_class($this)."::connect_bind this->connection is ok", LOG_DEBUG);
254  }
255 
256  // Upgrade connexion to TLS, if requested by the configuration
257  if (!empty($conf->global->LDAP_SERVER_USE_TLS)) {
258  // For test/debug
259  //ldap_set_option($this->connection, LDAP_OPT_DEBUG_LEVEL, 7);
260  //ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
261  //ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
262 
263  $resulttls = ldap_start_tls($this->connection);
264  if (!$resulttls) {
265  dol_syslog(get_class($this)."::connect_bind failed to start tls", LOG_WARNING);
266  $this->error = 'ldap_start_tls Failed to start TLS '.ldap_errno($this->connection).' '.ldap_error($this->connection);
267  $connected = 0;
268  $this->unbind();
269  }
270  }
271 
272  // Execute the ldap_set_option here (after connect and before bind)
273  $this->setVersion();
274  ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0); // no limit here. should return true.
275 
276 
277  if ($this->serverType == "activedirectory") {
278  $result = $this->setReferrals();
279  dol_syslog(get_class($this)."::connect_bind try bindauth for activedirectory on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
280  $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
281  if ($this->result) {
282  $this->bind = $this->result;
283  $connected = 2;
284  $this->connectedServer = $host;
285  break;
286  } else {
287  $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
288  }
289  } else {
290  // Try in auth mode
291  if ($this->searchUser && $this->searchPassword) {
292  dol_syslog(get_class($this)."::connect_bind try bindauth on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
293  $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
294  if ($this->result) {
295  $this->bind = $this->result;
296  $connected = 2;
297  $this->connectedServer = $host;
298  break;
299  } else {
300  $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
301  }
302  }
303  // Try in anonymous
304  if (!$this->bind) {
305  dol_syslog(get_class($this)."::connect_bind try bind anonymously on ".$host, LOG_DEBUG);
306  $result = $this->bind();
307  if ($result) {
308  $this->bind = $this->result;
309  $connected = 1;
310  $this->connectedServer = $host;
311  break;
312  } else {
313  $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
314  }
315  }
316  }
317  }
318 
319  if (!$connected) {
320  $this->unbind();
321  }
322  } // End loop on each server
323  }
324 
325  if ($connected) {
326  $return = $connected;
327  dol_syslog(get_class($this)."::connect_bind return=".$return, LOG_DEBUG);
328  } else {
329  $this->error = 'Failed to connect to LDAP'.($this->error ? ': '.$this->error : '');
330  $return = -1;
331  dol_syslog(get_class($this)."::connect_bind return=".$return.' - '.$this->error, LOG_WARNING);
332  }
333 
334  return $return;
335  }
336 
345  public function close()
346  {
347  return $this->unbind();
348  }
349 
356  public function bind()
357  {
358  if (!$this->result = @ldap_bind($this->connection)) {
359  $this->ldapErrorCode = ldap_errno($this->connection);
360  $this->ldapErrorText = ldap_error($this->connection);
361  $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
362  return false;
363  } else {
364  return true;
365  }
366  }
367 
378  public function bindauth($bindDn, $pass)
379  {
380  if (!$this->result = @ldap_bind($this->connection, $bindDn, $pass)) {
381  $this->ldapErrorCode = ldap_errno($this->connection);
382  $this->ldapErrorText = ldap_error($this->connection);
383  $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
384  return false;
385  } else {
386  return true;
387  }
388  }
389 
396  public function unbind()
397  {
398  $this->result = true;
399  if (is_resource($this->connection) || is_object($this->connection)) {
400  $this->result = @ldap_unbind($this->connection);
401  }
402  if ($this->result) {
403  return true;
404  } else {
405  return false;
406  }
407  }
408 
409 
415  public function getVersion()
416  {
417  $version = 0;
418  $version = @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
419  return $version;
420  }
421 
427  public function setVersion()
428  {
429  // LDAP_OPT_PROTOCOL_VERSION est une constante qui vaut 17
430  $ldapsetversion = ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
431  return $ldapsetversion;
432  }
433 
439  public function setReferrals()
440  {
441  // LDAP_OPT_REFERRALS est une constante qui vaut ?
442  $ldapreferrals = ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
443  return $ldapreferrals;
444  }
445 
446 
456  public function add($dn, $info, $user)
457  {
458  dol_syslog(get_class($this)."::add dn=".$dn." info=".json_encode($info));
459 
460  // Check parameters
461  if (!$this->connection) {
462  $this->error = "NotConnected";
463  return -2;
464  }
465  if (!$this->bind) {
466  $this->error = "NotConnected";
467  return -3;
468  }
469 
470  // Encode to LDAP page code
471  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
472  foreach ($info as $key => $val) {
473  if (!is_array($val)) {
474  $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
475  }
476  }
477 
478  $this->dump($dn, $info);
479 
480  //print_r($info);
481  $result = @ldap_add($this->connection, $dn, $info);
482 
483  if ($result) {
484  dol_syslog(get_class($this)."::add successfull", LOG_DEBUG);
485  return 1;
486  } else {
487  $this->ldapErrorCode = @ldap_errno($this->connection);
488  $this->ldapErrorText = @ldap_error($this->connection);
489  $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
490  dol_syslog(get_class($this)."::add failed: ".$this->error, LOG_ERR);
491  return -1;
492  }
493  }
494 
504  public function modify($dn, $info, $user)
505  {
506  dol_syslog(get_class($this)."::modify dn=".$dn." info=".join(',', $info));
507 
508  // Check parameters
509  if (!$this->connection) {
510  $this->error = "NotConnected";
511  return -2;
512  }
513  if (!$this->bind) {
514  $this->error = "NotConnected";
515  return -3;
516  }
517 
518  // Encode to LDAP page code
519  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
520  foreach ($info as $key => $val) {
521  if (!is_array($val)) {
522  $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
523  }
524  }
525 
526  $this->dump($dn, $info);
527 
528  //print_r($info);
529 
530  // For better compatibility with Samba4 AD
531  if ($this->serverType == "activedirectory") {
532  unset($info['cn']); // To avoid error : Operation not allowed on RDN (Code 67)
533 
534  // To avoid error : LDAP Error: 53 (Unwilling to perform)
535  if (isset($info['unicodePwd'])) {
536  $info['unicodePwd'] = mb_convert_encoding("\"".$info['unicodePwd']."\"", "UTF-16LE", "UTF-8");
537  }
538  }
539  $result = @ldap_modify($this->connection, $dn, $info);
540 
541  if ($result) {
542  dol_syslog(get_class($this)."::modify successfull", LOG_DEBUG);
543  return 1;
544  } else {
545  $this->error = @ldap_error($this->connection);
546  dol_syslog(get_class($this)."::modify failed: ".$this->error, LOG_ERR);
547  return -1;
548  }
549  }
550 
562  public function rename($dn, $newrdn, $newparent, $user, $deleteoldrdn = true)
563  {
564  dol_syslog(get_class($this)."::modify dn=".$dn." newrdn=".$newrdn." newparent=".$newparent." deleteoldrdn=".($deleteoldrdn ? 1 : 0));
565 
566  // Check parameters
567  if (!$this->connection) {
568  $this->error = "NotConnected";
569  return -2;
570  }
571  if (!$this->bind) {
572  $this->error = "NotConnected";
573  return -3;
574  }
575 
576  // Encode to LDAP page code
577  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
578  $newrdn = $this->convFromOutputCharset($newrdn, $this->ldapcharset);
579  $newparent = $this->convFromOutputCharset($newparent, $this->ldapcharset);
580 
581  //print_r($info);
582  $result = @ldap_rename($this->connection, $dn, $newrdn, $newparent, $deleteoldrdn);
583 
584  if ($result) {
585  dol_syslog(get_class($this)."::rename successfull", LOG_DEBUG);
586  return 1;
587  } else {
588  $this->error = @ldap_error($this->connection);
589  dol_syslog(get_class($this)."::rename failed: ".$this->error, LOG_ERR);
590  return -1;
591  }
592  }
593 
606  public function update($dn, $info, $user, $olddn, $newrdn = false, $newparent = false)
607  {
608  dol_syslog(get_class($this)."::update dn=".$dn." olddn=".$olddn);
609 
610  // Check parameters
611  if (!$this->connection) {
612  $this->error = "NotConnected";
613  return -2;
614  }
615  if (!$this->bind) {
616  $this->error = "NotConnected";
617  return -3;
618  }
619 
620  if (!$olddn || $olddn != $dn) {
621  if (!empty($olddn) && !empty($newrdn) && !empty($newparent) && $this->ldapProtocolVersion === '3') {
622  // This function currently only works with LDAPv3
623  $result = $this->rename($olddn, $newrdn, $newparent, $user, true);
624  $result = $this->modify($dn, $info, $user); // We force "modify" for avoid some fields not modify
625  } else {
626  // If change we make is rename the key of LDAP record, we create new one and if ok, we delete old one.
627  $result = $this->add($dn, $info, $user);
628  if ($result > 0 && $olddn && $olddn != $dn) {
629  $result = $this->delete($olddn); // If add fails, we do not try to delete old one
630  }
631  }
632  } else {
633  //$result = $this->delete($olddn);
634  $result = $this->add($dn, $info, $user); // If record has been deleted from LDAP, we recreate it. We ignore error if it already exists.
635  $result = $this->modify($dn, $info, $user); // We use add/modify instead of delete/add when olddn is received
636  }
637  if ($result <= 0) {
638  $this->error = ldap_error($this->connection).' (Code '.ldap_errno($this->connection).") ".$this->error;
639  dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
640  //print_r($info);
641  return -1;
642  } else {
643  dol_syslog(get_class($this)."::update done successfully");
644  return 1;
645  }
646  }
647 
648 
656  public function delete($dn)
657  {
658  dol_syslog(get_class($this)."::delete Delete LDAP entry dn=".$dn);
659 
660  // Check parameters
661  if (!$this->connection) {
662  $this->error = "NotConnected";
663  return -2;
664  }
665  if (!$this->bind) {
666  $this->error = "NotConnected";
667  return -3;
668  }
669 
670  // Encode to LDAP page code
671  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
672 
673  $result = @ldap_delete($this->connection, $dn);
674 
675  if ($result) {
676  return 1;
677  }
678  return -1;
679  }
680 
681  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
689  public function dump_content($dn, $info)
690  {
691  // phpcs:enable
692  $content = '';
693 
694  // Create file content
695  if (preg_match('/^ldap/', $this->server[0])) {
696  $target = "-H ".join(',', $this->server);
697  } else {
698  $target = "-h ".join(',', $this->server)." -p ".$this->serverPort;
699  }
700  $content .= "# ldapadd $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
701  $content .= "# ldapmodify $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
702  $content .= "# ldapdelete $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
703  if (in_array('localhost', $this->server)) {
704  $content .= "# If commands fails to connect, try without -h and -p\n";
705  }
706  $content .= "dn: ".$dn."\n";
707  foreach ($info as $key => $value) {
708  if (!is_array($value)) {
709  $content .= "$key: $value\n";
710  } else {
711  foreach ($value as $valuevalue) {
712  $content .= "$key: $valuevalue\n";
713  }
714  }
715  }
716  return $content;
717  }
718 
726  public function dump($dn, $info)
727  {
728  global $conf;
729 
730  // Create content
731  $content = $this->dump_content($dn, $info);
732 
733  //Create file
734  $result = dol_mkdir($conf->ldap->dir_temp);
735 
736  $outputfile = $conf->ldap->dir_temp.'/ldapinput.in';
737  $fp = fopen($outputfile, "w");
738  if ($fp) {
739  fputs($fp, $content);
740  fclose($fp);
741  if (!empty($conf->global->MAIN_UMASK)) {
742  @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
743  }
744  return 1;
745  } else {
746  return -1;
747  }
748  }
749 
758  public function serverPing($host, $port = 389, $timeout = 1)
759  {
760  $regs = array();
761  if (preg_match('/^ldaps:\/\/([^\/]+)\/?$/', $host, $regs)) {
762  // Replace ldaps:// by ssl://
763  $host = 'ssl://'.$regs[1];
764  } elseif (preg_match('/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) {
765  // Remove ldap://
766  $host = $regs[1];
767  }
768 
769  //var_dump($newhostforstream); var_dump($host); var_dump($port);
770  //$host = 'ssl://ldap.test.local:636';
771  //$port = 636;
772 
773  $errno = $errstr = 0;
774  /*
775  if ($methodtochecktcpconnect == 'socket') {
776  Try to use socket_create() method.
777  Method that use stream_context_create() works only on registered listed in stream stream_get_wrappers(): http, https, ftp, ...
778  }
779  */
780 
781  // Use the method fsockopen to test tcp connect. No way to ignore ssl certificate errors with this method !
782  $op = @fsockopen($host, $port, $errno, $errstr, $timeout);
783 
784  //var_dump($op);
785  if (!$op) {
786  return false; //DC is N/A
787  } else {
788  fclose($op); //explicitly close open socket connection
789  return true; //DC is up & running, we can safely connect with ldap_connect
790  }
791  }
792 
793 
794  // Attribute methods -----------------------------------------------------
795 
805  public function addAttribute($dn, $info, $user)
806  {
807  dol_syslog(get_class($this)."::addAttribute dn=".$dn." info=".join(',', $info));
808 
809  // Check parameters
810  if (!$this->connection) {
811  $this->error = "NotConnected";
812  return -2;
813  }
814  if (!$this->bind) {
815  $this->error = "NotConnected";
816  return -3;
817  }
818 
819  // Encode to LDAP page code
820  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
821  foreach ($info as $key => $val) {
822  if (!is_array($val)) {
823  $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
824  }
825  }
826 
827  $this->dump($dn, $info);
828 
829  //print_r($info);
830  $result = @ldap_mod_add($this->connection, $dn, $info);
831 
832  if ($result) {
833  dol_syslog(get_class($this)."::add_attribute successfull", LOG_DEBUG);
834  return 1;
835  } else {
836  $this->error = @ldap_error($this->connection);
837  dol_syslog(get_class($this)."::add_attribute failed: ".$this->error, LOG_ERR);
838  return -1;
839  }
840  }
841 
851  public function updateAttribute($dn, $info, $user)
852  {
853  dol_syslog(get_class($this)."::updateAttribute dn=".$dn." info=".join(',', $info));
854 
855  // Check parameters
856  if (!$this->connection) {
857  $this->error = "NotConnected";
858  return -2;
859  }
860  if (!$this->bind) {
861  $this->error = "NotConnected";
862  return -3;
863  }
864 
865  // Encode to LDAP page code
866  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
867  foreach ($info as $key => $val) {
868  if (!is_array($val)) {
869  $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
870  }
871  }
872 
873  $this->dump($dn, $info);
874 
875  //print_r($info);
876  $result = @ldap_mod_replace($this->connection, $dn, $info);
877 
878  if ($result) {
879  dol_syslog(get_class($this)."::updateAttribute successfull", LOG_DEBUG);
880  return 1;
881  } else {
882  $this->error = @ldap_error($this->connection);
883  dol_syslog(get_class($this)."::updateAttribute failed: ".$this->error, LOG_ERR);
884  return -1;
885  }
886  }
887 
897  public function deleteAttribute($dn, $info, $user)
898  {
899  dol_syslog(get_class($this)."::deleteAttribute dn=".$dn." info=".join(',', $info));
900 
901  // Check parameters
902  if (!$this->connection) {
903  $this->error = "NotConnected";
904  return -2;
905  }
906  if (!$this->bind) {
907  $this->error = "NotConnected";
908  return -3;
909  }
910 
911  // Encode to LDAP page code
912  $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
913  foreach ($info as $key => $val) {
914  if (!is_array($val)) {
915  $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
916  }
917  }
918 
919  $this->dump($dn, $info);
920 
921  //print_r($info);
922  $result = @ldap_mod_del($this->connection, $dn, $info);
923 
924  if ($result) {
925  dol_syslog(get_class($this)."::deleteAttribute successfull", LOG_DEBUG);
926  return 1;
927  } else {
928  $this->error = @ldap_error($this->connection);
929  dol_syslog(get_class($this)."::deleteAttribute failed: ".$this->error, LOG_ERR);
930  return -1;
931  }
932  }
933 
941  public function getAttribute($dn, $filter)
942  {
943  // Check parameters
944  if (!$this->connection) {
945  $this->error = "NotConnected";
946  return -2;
947  }
948  if (!$this->bind) {
949  $this->error = "NotConnected";
950  return -3;
951  }
952 
953  $search = @ldap_search($this->connection, $dn, $filter);
954 
955  // Only one entry should ever be returned
956  $entry = @ldap_first_entry($this->connection, $search);
957 
958  if (!$entry) {
959  $this->ldapErrorCode = -1;
960  $this->ldapErrorText = "Couldn't find entry";
961  return 0; // Couldn't find entry...
962  }
963 
964  // Get values
965  if (!($values = ldap_get_attributes($this->connection, $entry))) {
966  $this->ldapErrorCode = ldap_errno($this->connection);
967  $this->ldapErrorText = ldap_error($this->connection);
968  return 0; // No matching attributes
969  }
970 
971  // Return an array containing the attributes.
972  return $values;
973  }
974 
982  public function getAttributeValues($filterrecord, $attribute)
983  {
984  $attributes = array();
985  $attributes[0] = $attribute;
986 
987  // We need to search for this user in order to get their entry.
988  $this->result = @ldap_search($this->connection, $this->people, $filterrecord, $attributes);
989 
990  // Pourquoi cette ligne ?
991  //$info = ldap_get_entries($this->connection, $this->result);
992 
993  // Only one entry should ever be returned (no user will have the same uid)
994  $entry = ldap_first_entry($this->connection, $this->result);
995 
996  if (!$entry) {
997  $this->ldapErrorCode = -1;
998  $this->ldapErrorText = "Couldn't find user";
999  return false; // Couldn't find the user...
1000  }
1001 
1002  // Get values
1003  if (!$values = @ldap_get_values($this->connection, $entry, $attribute)) {
1004  $this->ldapErrorCode = ldap_errno($this->connection);
1005  $this->ldapErrorText = ldap_error($this->connection);
1006  return false; // No matching attributes
1007  }
1008 
1009  // Return an array containing the attributes.
1010  return $values;
1011  }
1012 
1025  public function getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter = 0, $attributeAsArray = array())
1026  {
1027  $fulllist = array();
1028 
1029  dol_syslog(get_class($this)."::getRecords search=".$search." userDn=".$userDn." useridentifier=".$useridentifier." attributeArray=array(".join(',', $attributeArray).") activefilter=".$activefilter);
1030 
1031  // if the directory is AD, then bind first with the search user first
1032  if ($this->serverType == "activedirectory") {
1033  $this->bindauth($this->searchUser, $this->searchPassword);
1034  dol_syslog(get_class($this)."::bindauth serverType=activedirectory searchUser=".$this->searchUser);
1035  }
1036 
1037  // Define filter
1038  if (!empty($activefilter)) { // Use a predefined trusted filter (defined into setup by admin).
1039  if (((string) $activefilter == '1' || (string) $activefilter == 'user') && $this->filter) {
1040  $filter = '('.$this->filter.')';
1041  } elseif (((string) $activefilter == 'group') && $this->filtergroup ) {
1042  $filter = '('.$this->filtergroup.')';
1043  } elseif (((string) $activefilter == 'member') && $this->filter) {
1044  $filter = '('.$this->filtermember.')';
1045  } else {
1046  // If this->filter/this->filtergroup is empty, make fiter on * (all)
1047  $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'=*)';
1048  }
1049  } else { // Use a filter forged using the $search value
1050  $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'='.ldap_escape($search, '', LDAP_ESCAPE_FILTER).')';
1051  }
1052 
1053  if (is_array($attributeArray)) {
1054  // Return list with required fields
1055  $attributeArray = array_values($attributeArray); // This is to force to have index reordered from 0 (not make ldap_search fails)
1056  dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter." attributeArray=(".join(',', $attributeArray).")");
1057  //var_dump($attributeArray);
1058  $this->result = @ldap_search($this->connection, $userDn, $filter, $attributeArray);
1059  } else {
1060  // Return list with fields selected by default
1061  dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter);
1062  $this->result = @ldap_search($this->connection, $userDn, $filter);
1063  }
1064  if (!$this->result) {
1065  $this->error = 'LDAP search failed: '.ldap_errno($this->connection)." ".ldap_error($this->connection);
1066  return -1;
1067  }
1068 
1069  $info = @ldap_get_entries($this->connection, $this->result);
1070 
1071  // Warning: Dans info, les noms d'attributs sont en minuscule meme si passe
1072  // a ldap_search en majuscule !!!
1073  //print_r($info);
1074 
1075  for ($i = 0; $i < $info["count"]; $i++) {
1076  $recordid = $this->convToOutputCharset($info[$i][strtolower($useridentifier)][0], $this->ldapcharset);
1077  if ($recordid) {
1078  //print "Found record with key $useridentifier=".$recordid."<br>\n";
1079  $fulllist[$recordid][$useridentifier] = $recordid;
1080 
1081  // Add to the array for each attribute in my list
1082  $num = count($attributeArray);
1083  for ($j = 0; $j < $num; $j++) {
1084  $keyattributelower = strtolower($attributeArray[$j]);
1085  //print " Param ".$attributeArray[$j]."=".$info[$i][$keyattributelower][0]."<br>\n";
1086 
1087  //permet de recuperer le SID avec Active Directory
1088  if ($this->serverType == "activedirectory" && $keyattributelower == "objectsid") {
1089  $objectsid = $this->getObjectSid($recordid);
1090  $fulllist[$recordid][$attributeArray[$j]] = $objectsid;
1091  } else {
1092  if (in_array($attributeArray[$j], $attributeAsArray) && is_array($info[$i][$keyattributelower])) {
1093  $valueTab = array();
1094  foreach ($info[$i][$keyattributelower] as $key => $value) {
1095  $valueTab[$key] = $this->convToOutputCharset($value, $this->ldapcharset);
1096  }
1097  $fulllist[$recordid][$attributeArray[$j]] = $valueTab;
1098  } else {
1099  $fulllist[$recordid][$attributeArray[$j]] = $this->convToOutputCharset($info[$i][$keyattributelower][0], $this->ldapcharset);
1100  }
1101  }
1102  }
1103  }
1104  }
1105 
1106  asort($fulllist);
1107  return $fulllist;
1108  }
1109 
1117  public function littleEndian($hex)
1118  {
1119  $result = '';
1120  for ($x = dol_strlen($hex) - 2; $x >= 0; $x = $x - 2) {
1121  $result .= substr($hex, $x, 2);
1122  }
1123  return $result;
1124  }
1125 
1126 
1134  public function getObjectSid($ldapUser)
1135  {
1136  $criteria = '('.$this->getUserIdentifier().'='.$ldapUser.')';
1137  $justthese = array("objectsid");
1138 
1139  // if the directory is AD, then bind first with the search user first
1140  if ($this->serverType == "activedirectory") {
1141  $this->bindauth($this->searchUser, $this->searchPassword);
1142  }
1143 
1144  $i = 0;
1145  $searchDN = $this->people;
1146 
1147  while ($i <= 2) {
1148  $ldapSearchResult = @ldap_search($this->connection, $searchDN, $criteria, $justthese);
1149 
1150  if (!$ldapSearchResult) {
1151  $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1152  return -1;
1153  }
1154 
1155  $entry = ldap_first_entry($this->connection, $ldapSearchResult);
1156 
1157  if (!$entry) {
1158  // Si pas de resultat on cherche dans le domaine
1159  $searchDN = $this->domain;
1160  $i++;
1161  } else {
1162  $i++;
1163  $i++;
1164  }
1165  }
1166 
1167  if ($entry) {
1168  $ldapBinary = ldap_get_values_len($this->connection, $entry, "objectsid");
1169  $SIDText = $this->binSIDtoText($ldapBinary[0]);
1170  return $SIDText;
1171  } else {
1172  $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1173  return '?';
1174  }
1175  }
1176 
1184  public function binSIDtoText($binsid)
1185  {
1186  $hex_sid = bin2hex($binsid);
1187  $rev = hexdec(substr($hex_sid, 0, 2)); // Get revision-part of SID
1188  $subcount = hexdec(substr($hex_sid, 2, 2)); // Get count of sub-auth entries
1189  $auth = hexdec(substr($hex_sid, 4, 12)); // SECURITY_NT_AUTHORITY
1190  $result = "$rev-$auth";
1191  for ($x = 0; $x < $subcount; $x++) {
1192  $result .= "-".hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); // get all SECURITY_NT_AUTHORITY
1193  }
1194  return $result;
1195  }
1196 
1197 
1209  public function search($checkDn, $filter)
1210  {
1211  dol_syslog(get_class($this)."::search checkDn=".$checkDn." filter=".$filter);
1212 
1213  $checkDn = $this->convFromOutputCharset($checkDn, $this->ldapcharset);
1214  $filter = $this->convFromOutputCharset($filter, $this->ldapcharset);
1215 
1216  // if the directory is AD, then bind first with the search user first
1217  if ($this->serverType == "activedirectory") {
1218  $this->bindauth($this->searchUser, $this->searchPassword);
1219  }
1220 
1221  $this->result = @ldap_search($this->connection, $checkDn, $filter);
1222 
1223  $result = @ldap_get_entries($this->connection, $this->result);
1224  if (!$result) {
1225  $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1226  return -1;
1227  } else {
1228  ldap_free_result($this->result);
1229  return $result;
1230  }
1231  }
1232 
1233 
1242  public function fetch($user, $filter)
1243  {
1244  // Perform the search and get the entry handles
1245 
1246  // if the directory is AD, then bind first with the search user first
1247  if ($this->serverType == "activedirectory") {
1248  $this->bindauth($this->searchUser, $this->searchPassword);
1249  }
1250 
1251  $searchDN = $this->people; // TODO Why searching in people then domain ?
1252 
1253  $result = '';
1254  $i = 0;
1255  while ($i <= 2) {
1256  dol_syslog(get_class($this)."::fetch search with searchDN=".$searchDN." filter=".$filter);
1257  $this->result = @ldap_search($this->connection, $searchDN, $filter);
1258  if ($this->result) {
1259  $result = @ldap_get_entries($this->connection, $this->result);
1260  if ($result['count'] > 0) {
1261  dol_syslog('Ldap::fetch search found '.$result['count'].' records');
1262  } else {
1263  dol_syslog('Ldap::fetch search returns but found no records');
1264  }
1265  //var_dump($result);exit;
1266  } else {
1267  $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1268  dol_syslog(get_class($this)."::fetch search fails");
1269  return -1;
1270  }
1271 
1272  if (!$result) {
1273  // Si pas de resultat on cherche dans le domaine
1274  $searchDN = $this->domain;
1275  $i++;
1276  } else {
1277  break;
1278  }
1279  }
1280 
1281  if (!$result) {
1282  $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1283  return -1;
1284  } else {
1285  $this->name = $this->convToOutputCharset($result[0][$this->attr_name][0], $this->ldapcharset);
1286  $this->firstname = $this->convToOutputCharset($result[0][$this->attr_firstname][0], $this->ldapcharset);
1287  $this->login = $this->convToOutputCharset($result[0][$this->attr_login][0], $this->ldapcharset);
1288  $this->phone = $this->convToOutputCharset($result[0][$this->attr_phone][0], $this->ldapcharset);
1289  $this->skype = $this->convToOutputCharset($result[0][$this->attr_skype][0], $this->ldapcharset);
1290  $this->fax = $this->convToOutputCharset($result[0][$this->attr_fax][0], $this->ldapcharset);
1291  $this->mail = $this->convToOutputCharset($result[0][$this->attr_mail][0], $this->ldapcharset);
1292  $this->mobile = $this->convToOutputCharset($result[0][$this->attr_mobile][0], $this->ldapcharset);
1293 
1294  $this->uacf = $this->parseUACF($this->convToOutputCharset($result[0]["useraccountcontrol"][0], $this->ldapcharset));
1295  if (isset($result[0]["pwdlastset"][0])) { // If expiration on password exists
1296  $this->pwdlastset = ($result[0]["pwdlastset"][0] != 0) ? $this->convert_time($this->convToOutputCharset($result[0]["pwdlastset"][0], $this->ldapcharset)) : 0;
1297  } else {
1298  $this->pwdlastset = -1;
1299  }
1300  if (!$this->name && !$this->login) {
1301  $this->pwdlastset = -1;
1302  }
1303  $this->badpwdtime = $this->convert_time($this->convToOutputCharset($result[0]["badpasswordtime"][0], $this->ldapcharset));
1304 
1305  // FQDN domain
1306  $domain = str_replace('dc=', '', $this->domain);
1307  $domain = str_replace(',', '.', $domain);
1308  $this->domainFQDN = $domain;
1309 
1310  // Set ldapUserDn (each user can have a different dn)
1311  //var_dump($result[0]);exit;
1312  $this->ldapUserDN = $result[0]['dn'];
1313 
1314  ldap_free_result($this->result);
1315  return 1;
1316  }
1317  }
1318 
1319 
1320  // helper methods
1321 
1327  public function getUserIdentifier()
1328  {
1329  if ($this->serverType == "activedirectory") {
1330  return $this->attr_sambalogin;
1331  } else {
1332  return $this->attr_login;
1333  }
1334  }
1335 
1342  public function parseUACF($uacf)
1343  {
1344  //All flags array
1345  $flags = array(
1346  "TRUSTED_TO_AUTH_FOR_DELEGATION" => 16777216,
1347  "PASSWORD_EXPIRED" => 8388608,
1348  "DONT_REQ_PREAUTH" => 4194304,
1349  "USE_DES_KEY_ONLY" => 2097152,
1350  "NOT_DELEGATED" => 1048576,
1351  "TRUSTED_FOR_DELEGATION" => 524288,
1352  "SMARTCARD_REQUIRED" => 262144,
1353  "MNS_LOGON_ACCOUNT" => 131072,
1354  "DONT_EXPIRE_PASSWORD" => 65536,
1355  "SERVER_TRUST_ACCOUNT" => 8192,
1356  "WORKSTATION_TRUST_ACCOUNT" => 4096,
1357  "INTERDOMAIN_TRUST_ACCOUNT" => 2048,
1358  "NORMAL_ACCOUNT" => 512,
1359  "TEMP_DUPLICATE_ACCOUNT" => 256,
1360  "ENCRYPTED_TEXT_PWD_ALLOWED" => 128,
1361  "PASSWD_CANT_CHANGE" => 64,
1362  "PASSWD_NOTREQD" => 32,
1363  "LOCKOUT" => 16,
1364  "HOMEDIR_REQUIRED" => 8,
1365  "ACCOUNTDISABLE" => 2,
1366  "SCRIPT" => 1
1367  );
1368 
1369  //Parse flags to text
1370  $retval = array();
1371  //while (list($flag, $val) = each($flags)) {
1372  foreach ($flags as $flag => $val) {
1373  if ($uacf >= $val) {
1374  $uacf -= $val;
1375  $retval[$val] = $flag;
1376  }
1377  }
1378 
1379  //Return human friendly flags
1380  return($retval);
1381  }
1382 
1389  public function parseSAT($samtype)
1390  {
1391  $stypes = array(
1392  805306368 => "NORMAL_ACCOUNT",
1393  805306369 => "WORKSTATION_TRUST",
1394  805306370 => "INTERDOMAIN_TRUST",
1395  268435456 => "SECURITY_GLOBAL_GROUP",
1396  268435457 => "DISTRIBUTION_GROUP",
1397  536870912 => "SECURITY_LOCAL_GROUP",
1398  536870913 => "DISTRIBUTION_LOCAL_GROUP"
1399  );
1400 
1401  $retval = "";
1402  while (list($sat, $val) = each($stypes)) {
1403  if ($samtype == $sat) {
1404  $retval = $val;
1405  break;
1406  }
1407  }
1408  if (empty($retval)) {
1409  $retval = "UNKNOWN_TYPE_".$samtype;
1410  }
1411 
1412  return($retval);
1413  }
1414 
1415  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1422  public function convert_time($value)
1423  {
1424  // phpcs:enable
1425  $dateLargeInt = $value; // nano secondes depuis 1601 !!!!
1426  $secsAfterADEpoch = $dateLargeInt / (10000000); // secondes depuis le 1 jan 1601
1427  $ADToUnixConvertor = ((1970 - 1601) * 365.242190) * 86400; // UNIX start date - AD start date * jours * secondes
1428  $unixTimeStamp = intval($secsAfterADEpoch - $ADToUnixConvertor); // Unix time stamp
1429  return $unixTimeStamp;
1430  }
1431 
1432 
1440  private function convToOutputCharset($str, $pagecodefrom = 'UTF-8')
1441  {
1442  global $conf;
1443  if ($pagecodefrom == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1444  $str = utf8_encode($str);
1445  }
1446  if ($pagecodefrom == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1447  $str = utf8_decode($str);
1448  }
1449  return $str;
1450  }
1451 
1459  public function convFromOutputCharset($str, $pagecodeto = 'UTF-8')
1460  {
1461  global $conf;
1462  if ($pagecodeto == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1463  $str = utf8_decode($str);
1464  }
1465  if ($pagecodeto == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1466  $str = utf8_encode($str);
1467  }
1468  return $str;
1469  }
1470 
1471 
1478  public function getNextGroupGid($keygroup = 'LDAP_KEY_GROUPS')
1479  {
1480  global $conf;
1481 
1482  if (empty($keygroup)) {
1483  $keygroup = 'LDAP_KEY_GROUPS';
1484  }
1485 
1486  $search = '('.$conf->global->$keygroup.'=*)';
1487  $result = $this->search($this->groups, $search);
1488  if ($result) {
1489  $c = $result['count'];
1490  $gids = array();
1491  for ($i = 0; $i < $c; $i++) {
1492  $gids[] = $result[$i]['gidnumber'][0];
1493  }
1494  rsort($gids);
1495 
1496  return $gids[0] + 1;
1497  }
1498 
1499  return 0;
1500  }
1501 }
Class to manage LDAP features.
Definition: ldap.class.php:35
add($dn, $info, $user)
Add a LDAP entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:456
connect_bind()
Connect and bind Use this->server, this->serverPort, this->ldapProtocolVersion, this->serverType,...
Definition: ldap.class.php:192
$ldapErrorCode
Code erreur retourne par le serveur Ldap.
Definition: ldap.class.php:93
modify($dn, $info, $user)
Modify a LDAP entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:504
deleteAttribute($dn, $info, $user)
Delete a LDAP attribute in entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:897
$connection
The internal LDAP connection handle.
Definition: ldap.class.php:119
setVersion()
Change ldap protocol version to use.
Definition: ldap.class.php:427
convToOutputCharset($str, $pagecodefrom='UTF-8')
Convert a string into output/memory charset.
$server
Tableau des serveurs (IP addresses ou nom d'hotes)
Definition: ldap.class.php:49
littleEndian($hex)
Converts a little-endian hex-number to one, that 'hexdec' can convert Required by Active Directory.
fetch($user, $filter)
Load all attribute of a LDAP user.
getObjectSid($ldapUser)
Recupere le SID de l'utilisateur Required by Active Directory.
updateAttribute($dn, $info, $user)
Update a LDAP attribute in entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:851
update($dn, $info, $user, $olddn, $newrdn=false, $newparent=false)
Modify a LDAP entry (to use if dn != olddn) Ldap object connect and bind must have been done.
Definition: ldap.class.php:606
$ldapErrorText
Message texte de l'erreur.
Definition: ldap.class.php:97
getUserIdentifier()
Returns the correct user identifier to use, based on the ldap server type.
getAttribute($dn, $filter)
Returns an array containing attributes and values for first record.
Definition: ldap.class.php:941
$searchPassword
Mot de passe de l'administrateur Active Directory ne supporte pas les connexions anonymes.
Definition: ldap.class.php:81
close()
Simply closes the connection set up earlier.
Definition: ldap.class.php:345
$ldapProtocolVersion
Version du protocole ldap.
Definition: ldap.class.php:67
parseSAT($samtype)
SamAccountType value to text.
rename($dn, $newrdn, $newparent, $user, $deleteoldrdn=true)
Rename a LDAP entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:562
getNextGroupGid($keygroup='LDAP_KEY_GROUPS')
Return available value of group GID.
$serverType
type de serveur, actuellement OpenLdap et Active Directory
Definition: ldap.class.php:63
binSIDtoText($binsid)
Returns the textual SID Indispensable pour Active Directory.
setReferrals()
changement du referrals.
Definition: ldap.class.php:439
$domain
Server DN.
Definition: ldap.class.php:71
search($checkDn, $filter)
Fonction de recherche avec filtre this->connection doit etre defini donc la methode bind ou bindauth ...
getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter=0, $attributeAsArray=array())
Returns an array containing a details or list of LDAP record(s).
getVersion()
Verification de la version du serveur ldap.
Definition: ldap.class.php:415
convert_time($value)
Convertit le temps ActiveDirectory en Unix timestamp.
$searchUser
User administrateur Ldap Active Directory ne supporte pas les connexions anonymes.
Definition: ldap.class.php:76
const SYNCHRO_NONE
No Ldap synchronization.
Definition: ldap.class.php:128
$connectedServer
Current connected server.
Definition: ldap.class.php:54
$groups
DN des groupes.
Definition: ldap.class.php:89
dump_content($dn, $info)
Build a LDAP message.
Definition: ldap.class.php:689
getAttributeValues($filterrecord, $attribute)
Returns an array containing values for an attribute and for first record matching filterrecord.
Definition: ldap.class.php:982
parseUACF($uacf)
UserAccountControl Flgs to more human understandable form...
__construct()
Constructor.
Definition: ldap.class.php:144
const SYNCHRO_LDAP_TO_DOLIBARR
Ldap to Dolibarr synchronization.
Definition: ldap.class.php:138
convFromOutputCharset($str, $pagecodeto='UTF-8')
Convert a string from output/memory charset.
$people
DN des utilisateurs.
Definition: ldap.class.php:85
serverPing($host, $port=389, $timeout=1)
Ping a server before ldap_connect for avoid waiting.
Definition: ldap.class.php:758
bind()
Anonymously binds to the connection.
Definition: ldap.class.php:356
unbind()
Unbind of LDAP server (close connection).
Definition: ldap.class.php:396
bindauth($bindDn, $pass)
Binds as an authenticated user, which usually allows for write access.
Definition: ldap.class.php:378
$result
Result of any connections etc.
Definition: ldap.class.php:123
dump($dn, $info)
Dump a LDAP message to ldapinput.in file.
Definition: ldap.class.php:726
addAttribute($dn, $info, $user)
Add a LDAP attribute in entry Ldap object connect and bind must have been done.
Definition: ldap.class.php:805
const SYNCHRO_DOLIBARR_TO_LDAP
Dolibarr to Ldap synchronization.
Definition: ldap.class.php:133
$dn
Base DN (e.g.
Definition: ldap.class.php:59
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:122