dolibarr 25.0.0-alpha
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 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
7 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
8 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 * or see https://www.gnu.org/
23 */
24
39class Ldap
40{
44 public $error = '';
45
49 public $errors = array();
50
54 public $server = array();
55
59 public $connectedServer;
60
64 public $serverPort;
65
70 public $dn;
75 public $serverType;
80 public $ldapProtocolVersion;
85 public $domain;
86
90 public $domainFQDN;
91
95 public $bind;
96
101 public $searchUser;
106 public $searchPassword;
107
111 public $people;
112
116 public $groups;
117
121 public $ldapErrorCode;
122
126 public $ldapErrorText;
127
131 public $filter;
132
136 public $filtergroup;
137
141 public $filtermember;
142
146 public $attr_login;
147
151 public $attr_sambalogin;
152
156 public $attr_name;
157
161 public $attr_firstname;
162
166 public $attr_mail;
167
171 public $attr_phone;
172
176 public $attr_fax;
177
181 public $attr_mobile;
182
186 public $badpwdtime;
187
191 public $ldapUserDN;
192
196 public $name;
197
201 public $firstname;
202
206 public $login;
207
211 public $phone;
212
216 public $fax;
217
221 public $mail;
222
226 public $mobile;
227
231 public $uacf;
232
236 public $pwdlastset;
237
242 public $ldapcharset = 'UTF-8';
243
248 public $connection;
249
253 public $result;
254
258 const SYNCHRO_NONE = 0;
259
263 const SYNCHRO_DOLIBARR_TO_LDAP = 1;
264
268 const SYNCHRO_LDAP_TO_DOLIBARR = 2;
269
273 public function __construct()
274 {
275
276 // Server
277 if (getDolGlobalString('LDAP_SERVER_HOST')) {
278 $this->server[] = getDolGlobalString('LDAP_SERVER_HOST');
279 }
280 if (getDolGlobalString('LDAP_SERVER_HOST_SLAVE')) {
281 $this->server[] = getDolGlobalString('LDAP_SERVER_HOST_SLAVE');
282 }
283 $this->serverPort = getDolGlobalInt('LDAP_SERVER_PORT', 389);
284 $this->ldapProtocolVersion = getDolGlobalString('LDAP_SERVER_PROTOCOLVERSION');
285 $this->dn = getDolGlobalString('LDAP_SERVER_DN');
286 $this->serverType = getDolGlobalString('LDAP_SERVER_TYPE');
287
288 $this->domain = getDolGlobalString('LDAP_SERVER_DN');
289 $this->searchUser = getDolGlobalString('LDAP_ADMIN_DN');
290 $this->searchPassword = getDolGlobalString('LDAP_ADMIN_PASS');
291 $this->people = getDolGlobalString('LDAP_USER_DN');
292 $this->groups = getDolGlobalString('LDAP_GROUP_DN');
293
294 $this->filter = getDolGlobalString('LDAP_FILTER_CONNECTION'); // Filter on user
295 $this->filtergroup = getDolGlobalString('LDAP_GROUP_FILTER'); // Filter on groups
296 $this->filtermember = getDolGlobalString('LDAP_MEMBER_FILTER'); // Filter on member
297
298 // Users
299 $this->attr_login = getDolGlobalString('LDAP_FIELD_LOGIN'); //unix
300 $this->attr_sambalogin = getDolGlobalString('LDAP_FIELD_LOGIN_SAMBA'); //samba, activedirectory
301 $this->attr_name = getDolGlobalString('LDAP_FIELD_NAME');
302 $this->attr_firstname = getDolGlobalString('LDAP_FIELD_FIRSTNAME');
303 $this->attr_mail = getDolGlobalString('LDAP_FIELD_MAIL');
304 $this->attr_phone = getDolGlobalString('LDAP_FIELD_PHONE');
305 $this->attr_fax = getDolGlobalString('LDAP_FIELD_FAX');
306 $this->attr_mobile = getDolGlobalString('LDAP_FIELD_MOBILE');
307 }
308
309 // Connection handling methods -------------------------------------------
310
318 public function connectBind()
319 {
320 global $dolibarr_main_auth_ldap_debug;
321
322 $connected = 0;
323 $this->bind = false;
324 $this->error = '';
325 $this->connectedServer = '';
326
327 $ldapdebug = !((empty($dolibarr_main_auth_ldap_debug) || $dolibarr_main_auth_ldap_debug == "false"));
328
329 if ($ldapdebug) {
330 dol_syslog(get_class($this)."::connectBind");
331 print "DEBUG: connectBind<br>\n";
332 }
333
334 // Check parameters
335 if (count($this->server) == 0 || empty($this->server[0])) {
336 $this->error = 'LDAP setup (file conf.php) is not complete';
337 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
338 return -1;
339 }
340
341 if (!function_exists("ldap_connect")) {
342 $this->error = 'LDAPFunctionsNotAvailableOnPHP';
343 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
344 return -1;
345 }
346
347 if (empty($this->error)) {
348 // Loop on each ldap server
349 foreach ($this->server as $host) {
350 if ($connected) { // @phpstan-ignore if.alwaysFalse
351 break;
352 }
353 if (empty($host)) {
354 continue;
355 }
356
357 if ($this->serverPing($host, $this->serverPort)) {
358 if ($ldapdebug) {
359 dol_syslog(get_class($this)."::connectBind serverPing true, we try ldap_connect to ".$host, LOG_DEBUG);
360 }
361 if (version_compare(PHP_VERSION, '8.3.0', '>=')) {
362 // Since PHP 8.3, ldap_connect() expects a single URI argument. A scheme-less
363 // host (ex: localhost, 192.168.0.2) must be turned into a valid ldap:// URI,
364 // otherwise the host is parsed as the URI scheme and the later bind fails.
365 $uri = preg_match('/^ldaps?:\/\//i', $host) ? $host : 'ldap://'.$host.':'.$this->serverPort;
366 $this->connection = ldap_connect($uri);
367 } else {
368 $this->connection = ldap_connect($host, $this->serverPort);
369 }
370 } else {
371 if (preg_match('/^ldaps/i', $host)) {
372 // With host = ldaps://server, the serverPing to ssl://server sometimes fails, even if the ldap_connect succeed, so
373 // we test this case and continue in such a case even if serverPing fails.
374 if ($ldapdebug) {
375 dol_syslog(get_class($this)."::connectBind serverPing false, we try ldap_connect to ".$host, LOG_DEBUG);
376 }
377 if (version_compare(PHP_VERSION, '8.3.0', '>=')) {
378 $uri = preg_match('/^ldaps?:\/\//i', $host) ? $host : 'ldap://'.$host.':'.$this->serverPort;
379 $this->connection = ldap_connect($uri);
380 } else {
381 $this->connection = ldap_connect($host, $this->serverPort);
382 }
383 } else {
384 if ($ldapdebug) {
385 dol_syslog(get_class($this)."::connectBind serverPing false, no ldap_connect ".$host, LOG_DEBUG);
386 }
387 continue;
388 }
389 }
390
391 if ($this->connection !== false) {
392 if ($ldapdebug) {
393 dol_syslog(get_class($this)."::connectBind this->connection is ok", LOG_DEBUG);
394 }
395
396 // Upgrade connection to TLS, if requested by the configuration
397 if (getDolGlobalString('LDAP_SERVER_USE_TLS')) {
398 // For test/debug
399 //ldap_set_option($this->connection, LDAP_OPT_DEBUG_LEVEL, 7);
400 //ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
401 //ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
402
403 $resulttls = ldap_start_tls($this->connection);
404 if (!$resulttls) {
405 dol_syslog(get_class($this)."::connectBind failed to start tls", LOG_WARNING);
406 $this->error = 'ldap_start_tls Failed to start TLS '.ldap_errno($this->connection).' '.ldap_error($this->connection);
407 $connected = 0;
408 $this->unbind();
409 }
410 }
411
412 // Execute the ldap_set_option here (after connect and before bind)
413 $this->setVersion();
414 $this->setSizeLimit();
415
416 if ($this->serverType == "activedirectory") {
417 $result = $this->setReferrals();
418 dol_syslog(get_class($this)."::connectBind try bindauth for activedirectory on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
419 $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
420 if ($this->result) {
421 $this->bind = $this->result;
422 $connected = 2;
423 $this->connectedServer = $host;
424 break;
425 } else {
426 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
427 }
428 } else {
429 // Try in auth mode
430 if ($this->searchUser && $this->searchPassword) {
431 dol_syslog(get_class($this)."::connectBind try bindauth on ".$host." user=".$this->searchUser." password=".preg_replace('/./', '*', $this->searchPassword), LOG_DEBUG);
432 $this->result = $this->bindauth($this->searchUser, $this->searchPassword);
433 if ($this->result) {
434 $this->bind = $this->result;
435 $connected = 2;
436 $this->connectedServer = $host;
437 break;
438 } else {
439 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
440 }
441 }
442 // Try in anonymous
443 if (!$this->bind) { // @phpstan-ignore booleanNot.alwaysTrue
444 dol_syslog(get_class($this)."::connectBind try bind anonymously on ".$host, LOG_DEBUG);
445 $result = $this->bind();
446 if ($result) {
447 $this->bind = $this->result;
448 $connected = 1;
449 $this->connectedServer = $host;
450 break;
451 } else {
452 $this->error = ldap_errno($this->connection).' '.ldap_error($this->connection);
453 }
454 }
455 }
456 }
457
458 if (!$connected) { // @phpstan-ignore booleanNot.alwaysTrue
459 $this->unbind();
460 }
461 } // End loop on each server
462 }
463
464 if ($connected) {
465 dol_syslog(get_class($this)."::connectBind ".$connected, LOG_DEBUG);
466 return $connected;
467 } else {
468 $this->error = 'Failed to connect to LDAP'.($this->error ? ': '.$this->error : '');
469 dol_syslog(get_class($this)."::connectBind ".$this->error, LOG_WARNING);
470 return -1;
471 }
472 }
473
482 public function close()
483 {
484 return $this->unbind();
485 }
486
493 public function bind()
494 {
495 if (!$this->result = @ldap_bind($this->connection)) {
496 $this->ldapErrorCode = ldap_errno($this->connection);
497 $this->ldapErrorText = ldap_error($this->connection);
498 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
499 return false;
500 } else {
501 return true;
502 }
503 }
504
515 public function bindauth($bindDn, $pass)
516 {
517 if (!$this->result = @ldap_bind($this->connection, $bindDn, $pass)) {
518 $this->ldapErrorCode = ldap_errno($this->connection);
519 $this->ldapErrorText = ldap_error($this->connection);
520 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
521 return false;
522 } else {
523 return true;
524 }
525 }
526
533 public function unbind()
534 {
535 $this->result = true;
536 if (version_compare(PHP_VERSION, '8.1.0', '>=')) {
537 if (is_object($this->connection)) {
538 try {
539 $this->result = ldap_unbind($this->connection);
540 } catch (Throwable $exception) {
541 $this->error = 'Failed to unbind LDAP connection: '.$exception;
542 $this->result = false;
543 dol_syslog(get_class($this).'::unbind - '.$this->error, LOG_WARNING);
544 }
545 }
546 } else {
547 if ($this->connection !== false) {
548 // @phan-suppress-next-line PhanTypeMismatchArgumentInternalReal PhanTypeSuspiciousIndirectVariable
549 $this->result = @ldap_unbind($this->connection);
550 }
551 }
552 if ($this->result) {
553 return true;
554 } else {
555 return false;
556 }
557 }
558
559
565 public function getVersion()
566 {
567 @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
568 return $version;
569 }
570
577 public function setVersion()
578 {
579 return ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
580 }
581
587 public function setSizeLimit()
588 {
589 return ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0);
590 }
591
598 public function setReferrals()
599 {
600 return ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
601 }
602
603
613 public function add($dn, $info, $user)
614 {
615 dol_syslog(get_class($this)."::add dn=".$dn." info=".print_r($info, true));
616
617 // Check parameters
618 if (!$this->connection) {
619 $this->error = "NotConnected";
620 return -2;
621 }
622 if (!$this->bind) {
623 $this->error = "NotConnected";
624 return -3;
625 }
626
627 // Encode to LDAP page code
628 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
629 foreach ($info as $key => $val) {
630 if (!is_array($val)) {
631 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
632 }
633 }
634
635 $this->dump($dn, $info);
636
637 //print_r($info);
638 $result = @ldap_add($this->connection, $dn, $info);
639
640 if ($result) {
641 dol_syslog(get_class($this)."::add successful", LOG_DEBUG);
642 return 1;
643 } else {
644 $this->ldapErrorCode = @ldap_errno($this->connection);
645 $this->ldapErrorText = @ldap_error($this->connection);
646 $this->error = $this->ldapErrorCode." ".$this->ldapErrorText;
647 dol_syslog(get_class($this)."::add failed: ".$this->error, LOG_ERR);
648 return -1;
649 }
650 }
651
661 public function modify($dn, $info, $user)
662 {
663 dol_syslog(get_class($this)."::modify dn=".$dn." info=".print_r($info, true));
664
665 // Check parameters
666 if (!$this->connection) {
667 $this->error = "NotConnected";
668 return -2;
669 }
670 if (!$this->bind) {
671 $this->error = "NotConnected";
672 return -3;
673 }
674
675 // Encode to LDAP page code
676 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
677 foreach ($info as $key => $val) {
678 if (!is_array($val)) {
679 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
680 }
681 }
682
683 $this->dump($dn, $info);
684
685 //print_r($info);
686
687 // For better compatibility with Samba4 AD
688 if ($this->serverType == "activedirectory") {
689 unset($info['cn']); // To avoid error : Operation not allowed on RDN (Code 67)
690
691 // To avoid error : LDAP Error: 53 (Unwilling to perform)
692 if (isset($info['unicodePwd'])) {
693 $info['unicodePwd'] = mb_convert_encoding("\"".$info['unicodePwd']."\"", "UTF-16LE", "UTF-8");
694 }
695 }
696 $result = @ldap_mod_replace($this->connection, $dn, $info);
697
698 if ($result) {
699 dol_syslog(get_class($this)."::modify successful", LOG_DEBUG);
700 return 1;
701 } else {
702 $this->error = @ldap_error($this->connection);
703 dol_syslog(get_class($this)."::modify failed: ".$this->error, LOG_ERR);
704 return -1;
705 }
706 }
707
719 public function rename($dn, $newrdn, $newparent, $user, $deleteoldrdn = true)
720 {
721 dol_syslog(get_class($this)."::modify dn=".$dn." newrdn=".$newrdn." newparent=".$newparent." deleteoldrdn=".($deleteoldrdn ? 1 : 0));
722
723 // Check parameters
724 if (!$this->connection) {
725 $this->error = "NotConnected";
726 return -2;
727 }
728 if (!$this->bind) {
729 $this->error = "NotConnected";
730 return -3;
731 }
732
733 // Encode to LDAP page code
734 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
735 $newrdn = $this->convFromOutputCharset($newrdn, $this->ldapcharset);
736 $newparent = $this->convFromOutputCharset($newparent, $this->ldapcharset);
737
738 //print_r($info);
739 $result = @ldap_rename($this->connection, $dn, $newrdn, $newparent, $deleteoldrdn);
740
741 if ($result) {
742 dol_syslog(get_class($this)."::rename successful", LOG_DEBUG);
743 return 1;
744 } else {
745 $this->error = @ldap_error($this->connection);
746 dol_syslog(get_class($this)."::rename failed: ".$this->error, LOG_ERR);
747 return -1;
748 }
749 }
750
763 public function update($dn, $info, $user, $olddn, $newrdn = '', $newparent = '')
764 {
765 dol_syslog(get_class($this)."::update dn=".$dn." olddn=".$olddn);
766
767 // Check parameters
768 if (!$this->connection) {
769 $this->error = "NotConnected";
770 return -2;
771 }
772 if (!$this->bind) {
773 $this->error = "NotConnected";
774 return -3;
775 }
776
777 if (!$olddn || $olddn != $dn) {
778 if (!empty($olddn) && !empty($newrdn) && !empty($newparent) && $this->ldapProtocolVersion === '3') {
779 // This function currently only works with LDAPv3
780 $result = $this->rename($olddn, $newrdn, $newparent, $user, true);
781 $result = $this->modify($dn, $info, $user); // We force "modify" for avoid some fields not modify
782 } else {
783 // If change we make is rename the key of LDAP record, we create new one and if ok, we delete old one.
784 $result = $this->add($dn, $info, $user);
785 if ($result > 0 && $olddn && $olddn != $dn) {
786 $result = $this->delete($olddn); // If add fails, we do not try to delete old one
787 }
788 }
789 } else {
790 //$result = $this->delete($olddn);
791 $result = $this->add($dn, $info, $user); // If record has been deleted from LDAP, we recreate it. We ignore error if it already exists.
792 $result = $this->modify($dn, $info, $user); // We use add/modify instead of delete/add when olddn is received
793 }
794 if ($result <= 0) {
795 $this->error = ldap_error($this->connection).' (Code '.ldap_errno($this->connection).") ".$this->error;
796 dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
797 //print_r($info);
798 return -1;
799 } else {
800 dol_syslog(get_class($this)."::update done successfully");
801 return 1;
802 }
803 }
804
805
813 public function delete($dn)
814 {
815 dol_syslog(get_class($this)."::delete Delete LDAP entry dn=".$dn);
816
817 // Check parameters
818 if (!$this->connection) {
819 $this->error = "NotConnected";
820 return -2;
821 }
822 if (!$this->bind) {
823 $this->error = "NotConnected";
824 return -3;
825 }
826
827 // Encode to LDAP page code
828 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
829
830 $result = @ldap_delete($this->connection, $dn);
831
832 if ($result) {
833 return 1;
834 }
835 return -1;
836 }
837
845 public function dumpContent($dn, $info)
846 {
847 $content = '';
848
849 // Create file content
850 if (preg_match('/^ldap/', $this->server[0])) {
851 $target = "-H ".implode(',', $this->server);
852 } else {
853 $target = "-h ".implode(',', $this->server)." -p ".$this->serverPort;
854 }
855 $content .= "# ldapadd $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
856 $content .= "# ldapmodify $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
857 $content .= "# ldapdelete $target -c -v -D ".$this->searchUser." -W -f ldapinput.in\n";
858 if (in_array('localhost', $this->server)) {
859 $content .= "# If commands fails to connect, try without -h and -p\n";
860 }
861 $content .= "dn: ".$dn."\n";
862 foreach ($info as $key => $value) {
863 if (!is_array($value)) {
864 $content .= "$key: $value\n";
865 } else {
866 foreach ($value as $valuevalue) {
867 $content .= "$key: $valuevalue\n";
868 }
869 }
870 }
871 return $content;
872 }
873
881 public function dump($dn, $info)
882 {
883 global $conf;
884 $ldapDirTemp = $conf->ldap->dir_temp;
885 // Create content
886 $content = $this->dumpContent($dn, $info);
887
888 //Create directory & file
889 $result = dol_mkdir($ldapDirTemp);
890 if ($result != 0) {
891 $outputfile = $ldapDirTemp.'/ldapinput.in';
892 $fp = fopen($outputfile, "w");
893 if ($fp) {
894 fwrite($fp, $content);
895 fclose($fp);
896 dolChmod($outputfile);
897 return 1;
898 } else {
899 return -1;
900 }
901 } else {
902 return -1;
903 }
904 }
905
914 public function serverPing($host, $port = 389, $timeout = 1)
915 {
916 $regs = array();
917 if (preg_match('/^ldaps:\/\/([^\/]+)\/?$/', $host, $regs)) {
918 // Replace ldaps:// by ssl://
919 $host = 'ssl://'.$regs[1];
920 } elseif (preg_match('/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) {
921 // Remove ldap://
922 $host = $regs[1];
923 }
924
925 //var_dump($newhostforstream); var_dump($host); var_dump($port);
926 //$host = 'ssl://ldap.test.local:636';
927 //$port = 636;
928
929 $errno = $errstr = 0;
930 /*
931 if ($methodtochecktcpconnect == 'socket') {
932 Try to use socket_create() method.
933 Method that use stream_context_create() works only on registered listed in stream stream_get_wrappers(): http, https, ftp, ...
934 }
935 */
936
937 // Use the method fsockopen to test tcp connect. No way to ignore ssl certificate errors with this method !
938 $op = @fsockopen($host, $port, $errno, $errstr, $timeout);
939
940 //var_dump($op);
941 if (!$op) {
942 return false; //DC is N/A
943 } else {
944 fclose($op); //explicitly close open socket connection
945 return true; //DC is up & running, we can safely connect with ldap_connect
946 }
947 }
948
949
950 // Attribute methods -----------------------------------------------------
951
961 public function addAttribute($dn, $info, $user)
962 {
963 dol_syslog(get_class($this)."::addAttribute dn=".$dn." info=".implode(',', $info));
964
965 // Check parameters
966 if (!$this->connection) {
967 $this->error = "NotConnected";
968 return -2;
969 }
970 if (!$this->bind) {
971 $this->error = "NotConnected";
972 return -3;
973 }
974
975 // Encode to LDAP page code
976 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
977 foreach ($info as $key => $val) {
978 if (!is_array($val)) {
979 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
980 }
981 }
982
983 $this->dump($dn, $info);
984
985 //print_r($info);
986 $result = @ldap_mod_add($this->connection, $dn, $info);
987
988 if ($result) {
989 dol_syslog(get_class($this)."::add_attribute successful", LOG_DEBUG);
990 return 1;
991 } else {
992 $this->error = @ldap_error($this->connection);
993 dol_syslog(get_class($this)."::add_attribute failed: ".$this->error, LOG_ERR);
994 return -1;
995 }
996 }
997
1007 public function updateAttribute($dn, $info, $user)
1008 {
1009 dol_syslog(get_class($this)."::updateAttribute dn=".$dn." info=".implode(',', $info));
1010
1011 // Check parameters
1012 if (!$this->connection) {
1013 $this->error = "NotConnected";
1014 return -2;
1015 }
1016 if (!$this->bind) {
1017 $this->error = "NotConnected";
1018 return -3;
1019 }
1020
1021 // Encode to LDAP page code
1022 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
1023 foreach ($info as $key => $val) {
1024 if (!is_array($val)) {
1025 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
1026 }
1027 }
1028
1029 $this->dump($dn, $info);
1030
1031 //print_r($info);
1032 $result = @ldap_mod_replace($this->connection, $dn, $info);
1033
1034 if ($result) {
1035 dol_syslog(get_class($this)."::updateAttribute successful", LOG_DEBUG);
1036 return 1;
1037 } else {
1038 $this->error = @ldap_error($this->connection);
1039 dol_syslog(get_class($this)."::updateAttribute failed: ".$this->error, LOG_ERR);
1040 return -1;
1041 }
1042 }
1043
1053 public function deleteAttribute($dn, $info, $user)
1054 {
1055 dol_syslog(get_class($this)."::deleteAttribute dn=".$dn." info=".implode(',', $info));
1056
1057 // Check parameters
1058 if (!$this->connection) {
1059 $this->error = "NotConnected";
1060 return -2;
1061 }
1062 if (!$this->bind) {
1063 $this->error = "NotConnected";
1064 return -3;
1065 }
1066
1067 // Encode to LDAP page code
1068 $dn = $this->convFromOutputCharset($dn, $this->ldapcharset);
1069 foreach ($info as $key => $val) {
1070 if (!is_array($val)) {
1071 $info[$key] = $this->convFromOutputCharset($val, $this->ldapcharset);
1072 }
1073 }
1074
1075 $this->dump($dn, $info);
1076
1077 //print_r($info);
1078 $result = @ldap_mod_del($this->connection, $dn, $info);
1079
1080 if ($result) {
1081 dol_syslog(get_class($this)."::deleteAttribute successful", LOG_DEBUG);
1082 return 1;
1083 } else {
1084 $this->error = @ldap_error($this->connection);
1085 dol_syslog(get_class($this)."::deleteAttribute failed: ".$this->error, LOG_ERR);
1086 return -1;
1087 }
1088 }
1089
1099 public function getAttribute($dn, $filter)
1100 {
1101 // Check parameters
1102 if (!$this->connection) {
1103 $this->error = "NotConnected";
1104 return -2;
1105 }
1106 if (!$this->bind) {
1107 $this->error = "NotConnected";
1108 return -3;
1109 }
1110
1111 // Honor the admin-configured user search filter (LDAP_FILTER_CONNECTION)
1112 // so an identifier match outside the configured scope does not leak
1113 // attributes for an unrelated LDAP user (see #37120).
1114 if (!empty($this->filter) && !preg_match('/^\s*\‍(\s*&\s*\‍(/', $filter)) {
1115 $filter = '(&(' . $this->filter . ')' . $filter . ')';
1116 }
1117
1118 $search = @ldap_search($this->connection, $dn, $filter);
1119
1120 // Only one entry should ever be returned
1121 $entry = @ldap_first_entry($this->connection, $search);
1122
1123 if (!$entry) {
1124 $this->ldapErrorCode = -1;
1125 $this->ldapErrorText = "Couldn't find entry";
1126 return 0; // Couldn't find entry...
1127 }
1128
1129 // Get values
1130 if (!($values = ldap_get_attributes($this->connection, $entry))) {
1131 $this->ldapErrorCode = ldap_errno($this->connection);
1132 $this->ldapErrorText = ldap_error($this->connection);
1133 return 0; // No matching attributes
1134 }
1135
1136 // Return an array containing the attributes.
1137 return $values;
1138 }
1139
1147 public function getAttributeValues($filterrecord, $attribute)
1148 {
1149 $attributes = array();
1150 $attributes[0] = $attribute;
1151
1152 // We need to search for this user in order to get their entry.
1153 $this->result = @ldap_search($this->connection, $this->people, $filterrecord, $attributes);
1154
1155 // What is this line for ?
1156 //$info = ldap_get_entries($this->connection, $this->result);
1157
1158 // Only one entry should ever be returned (no user will have the same uid)
1159 $entry = ldap_first_entry($this->connection, $this->result);
1160
1161 if (!$entry) {
1162 $this->ldapErrorCode = -1;
1163 $this->ldapErrorText = "Couldn't find user";
1164 return false; // Couldn't find the user...
1165 }
1166
1167 // Get values
1168 if (!$values = @ldap_get_values_len($this->connection, $entry, $attribute)) {
1169 $this->ldapErrorCode = ldap_errno($this->connection);
1170 $this->ldapErrorText = ldap_error($this->connection);
1171 return false; // No matching attributes
1172 }
1173
1174 // Return an array containing the attributes.
1175 return $values;
1176 }
1177
1190 public function getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter = 0, $attributeAsArray = array())
1191 {
1192 $fulllist = array();
1193
1194 dol_syslog(get_class($this)."::getRecords search=".$search." userDn=".$userDn." useridentifier=".$useridentifier." attributeArray=array(".implode(',', $attributeArray).") activefilter=".$activefilter);
1195
1196 // if the directory is AD, then bind first with the search user first
1197 if ($this->serverType == "activedirectory") {
1198 $this->bindauth($this->searchUser, $this->searchPassword);
1199 dol_syslog(get_class($this)."::bindauth serverType=activedirectory searchUser=".$this->searchUser);
1200 }
1201
1202 // Define filter
1203 if (!empty($activefilter)) { // Use a predefined trusted filter (defined into setup by admin).
1204 if (((string) $activefilter == '1' || (string) $activefilter == 'user') && $this->filter) {
1205 $filter = '('.$this->filter.')';
1206 } elseif (((string) $activefilter == 'group') && $this->filtergroup) {
1207 $filter = '('.$this->filtergroup.')';
1208 } elseif (((string) $activefilter == 'member') && $this->filter) {
1209 $filter = '('.$this->filtermember.')';
1210 } else {
1211 // If this->filter/this->filtergroup is empty, make filter on * (all)
1212 $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'=*)';
1213 }
1214 } else { // Use a filter forged using the $search value
1215 $filter = '('.ldap_escape($useridentifier, '', LDAP_ESCAPE_FILTER).'='.ldap_escape($search, '', LDAP_ESCAPE_FILTER).')';
1216 }
1217
1218 if (is_array($attributeArray)) {
1219 // Return list with required fields
1220 $attributeArray = array_values($attributeArray); // This is to force to have index reordered from 0 (not make ldap_search fails)
1221 dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter." attributeArray=(".implode(',', $attributeArray).")");
1222 //var_dump($attributeArray);
1223 $this->result = @ldap_search($this->connection, $userDn, $filter, $attributeArray);
1224 } else {
1225 // Return list with fields selected by default
1226 dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter);
1227 $this->result = @ldap_search($this->connection, $userDn, $filter);
1228 }
1229 if (!$this->result) {
1230 $this->error = 'LDAP search failed: '.ldap_errno($this->connection)." ".ldap_error($this->connection);
1231 return -1;
1232 }
1233
1234 $info = @ldap_get_entries($this->connection, $this->result);
1235
1236 // Warning: Dans info, les noms d'attributs sont en minuscule meme si passe
1237 // a ldap_search en majuscule !!!
1238 //print_r($info);
1239
1240 for ($i = 0; $i < $info["count"]; $i++) {
1241 $recordid = $this->convToOutputCharset($info[$i][strtolower($useridentifier)][0], $this->ldapcharset);
1242 if ($recordid) {
1243 //print "Found record with key $useridentifier=".$recordid."<br>\n";
1244 $fulllist[$recordid][$useridentifier] = $recordid;
1245
1246 // Add to the array for each attribute in my list
1247 $num = count($attributeArray);
1248 for ($j = 0; $j < $num; $j++) {
1249 $keyattributelower = strtolower($attributeArray[$j]);
1250 //print " Param ".$attributeArray[$j]."=".$info[$i][$keyattributelower][0]."<br>\n";
1251
1252 // Enables getting the SID using Active Directory
1253 if ($this->serverType == "activedirectory" && $keyattributelower == "objectsid") {
1254 $objectsid = $this->getObjectSid($recordid);
1255 $fulllist[$recordid][$attributeArray[$j]] = $objectsid;
1256 } else {
1257 if (in_array($attributeArray[$j], $attributeAsArray) && is_array($info[$i][$keyattributelower])) {
1258 $valueTab = array();
1259 foreach ($info[$i][$keyattributelower] as $key => $value) {
1260 $valueTab[$key] = $this->convToOutputCharset($value, $this->ldapcharset);
1261 }
1262 $fulllist[$recordid][$attributeArray[$j]] = $valueTab;
1263 } else {
1264 $fulllist[$recordid][$attributeArray[$j]] = $this->convToOutputCharset($info[$i][$keyattributelower][0], $this->ldapcharset);
1265 }
1266 }
1267 }
1268 }
1269 }
1270
1271 asort($fulllist);
1272 return $fulllist;
1273 }
1274
1282 public function littleEndian($hex)
1283 {
1284 $result = '';
1285 for ($x = dol_strlen($hex) - 2; $x >= 0; $x -= 2) {
1286 $result .= substr($hex, $x, 2);
1287 }
1288 return $result;
1289 }
1290
1291
1299 public function getObjectSid($ldapUser)
1300 {
1301 $criteria = '('.$this->getUserIdentifier().'='.$ldapUser.')';
1302 $justthese = array("objectsid");
1303
1304 // if the directory is AD, then bind first with the search user first
1305 if ($this->serverType == "activedirectory") {
1306 $this->bindauth($this->searchUser, $this->searchPassword);
1307 }
1308
1309 $i = 0;
1310 $entry = null;
1311 $searchDN = $this->people;
1312
1313 while ($i <= 2) {
1314 $ldapSearchResult = @ldap_search($this->connection, $searchDN, $criteria, $justthese);
1315
1316 if (!$ldapSearchResult) {
1317 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1318 return -1;
1319 }
1320
1321 $entry = ldap_first_entry($this->connection, $ldapSearchResult);
1322
1323 if (!$entry) {
1324 // Si pas de resultat on cherche dans le domaine
1325 $searchDN = $this->domain;
1326 $i++;
1327 } else {
1328 $i++;
1329 $i++;
1330 }
1331 }
1332
1333 if ($entry) {
1334 $ldapBinary = ldap_get_values_len($this->connection, $entry, "objectsid");
1335 $SIDText = $this->binSIDtoText($ldapBinary[0]);
1336 return $SIDText;
1337 } else {
1338 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1339 return -1;
1340 }
1341 }
1342
1350 public function binSIDtoText($binsid)
1351 {
1352 $hex_sid = bin2hex($binsid);
1353 $rev = hexdec(substr($hex_sid, 0, 2)); // Get revision-part of SID
1354 $subcount = hexdec(substr($hex_sid, 2, 2)); // Get count of sub-auth entries
1355 $auth = hexdec(substr($hex_sid, 4, 12)); // SECURITY_NT_AUTHORITY
1356 $result = "$rev-$auth";
1357 for ($x = 0; $x < $subcount; $x++) {
1358 $result .= "-".hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8))); // get all SECURITY_NT_AUTHORITY
1359 }
1360 return $result;
1361 }
1362
1363
1377 public function search($checkDn, $filter)
1378 {
1379 dol_syslog(get_class($this)."::search checkDn=".$checkDn." filter=".$filter);
1380
1381 $checkDn = $this->convFromOutputCharset($checkDn, $this->ldapcharset);
1382 $filter = $this->convFromOutputCharset($filter, $this->ldapcharset);
1383
1384 // if the directory is AD, then bind first with the search user first
1385 if ($this->serverType == "activedirectory") {
1386 $this->bindauth($this->searchUser, $this->searchPassword);
1387 }
1388
1389 $this->result = @ldap_search($this->connection, $checkDn, $filter);
1390
1391 $result = @ldap_get_entries($this->connection, $this->result);
1392 if (!$result) {
1393 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1394 return -1;
1395 } else {
1396 ldap_free_result($this->result);
1397 return $result;
1398 }
1399 }
1400
1401
1410 public function fetch($user, $filter)
1411 {
1412 // Perform the search and get the entry handles
1413
1414 // if the directory is AD, then bind first with the search user first
1415 if ($this->serverType == "activedirectory") {
1416 $this->bindauth($this->searchUser, $this->searchPassword);
1417 }
1418
1419 $searchDN = $this->people; // TODO Why searching in people then domain ?
1420
1421 $result = '';
1422 $i = 0;
1423 while ($i <= 2) {
1424 dol_syslog(get_class($this)."::fetch search with searchDN=".$searchDN." filter=".$filter);
1425 $this->result = @ldap_search($this->connection, $searchDN, $filter);
1426 if ($this->result) {
1427 $result = @ldap_get_entries($this->connection, $this->result);
1428 if ($result['count'] > 0) {
1429 dol_syslog('Ldap::fetch search found '.$result['count'].' records');
1430 } else {
1431 dol_syslog('Ldap::fetch search returns but found no records');
1432 }
1433 //var_dump($result);exit;
1434 } else {
1435 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1436 dol_syslog(get_class($this)."::fetch search fails");
1437 return -1;
1438 }
1439
1440 if (!$result) {
1441 // Si pas de resultat on cherche dans le domaine
1442 $searchDN = $this->domain;
1443 $i++;
1444 } else {
1445 break;
1446 }
1447 }
1448
1449 if (!$result) {
1450 $this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
1451 return -1;
1452 } else {
1453 $this->name = $this->convToOutputCharset($result[0][$this->attr_name][0], $this->ldapcharset);
1454 $this->firstname = $this->convToOutputCharset($result[0][$this->attr_firstname][0], $this->ldapcharset);
1455 $this->login = $this->convToOutputCharset($result[0][$this->attr_login][0], $this->ldapcharset);
1456 $this->phone = $this->convToOutputCharset($result[0][$this->attr_phone][0], $this->ldapcharset);
1457 $this->fax = $this->convToOutputCharset($result[0][$this->attr_fax][0], $this->ldapcharset);
1458 $this->mail = $this->convToOutputCharset($result[0][$this->attr_mail][0], $this->ldapcharset);
1459 $this->mobile = $this->convToOutputCharset($result[0][$this->attr_mobile][0], $this->ldapcharset);
1460
1461 $this->uacf = $this->parseUACF($this->convToOutputCharset($result[0]["useraccountcontrol"][0], $this->ldapcharset));
1462 if (isset($result[0]["pwdlastset"][0])) { // If expiration on password exists
1463 $this->pwdlastset = ($result[0]["pwdlastset"][0] != 0) ? $this->convertTime($this->convToOutputCharset($result[0]["pwdlastset"][0], $this->ldapcharset)) : 0;
1464 } else {
1465 $this->pwdlastset = -1;
1466 }
1467 if (!$this->name && !$this->login) {
1468 $this->pwdlastset = -1;
1469 }
1470 $this->badpwdtime = $this->convertTime($this->convToOutputCharset($result[0]["badpasswordtime"][0], $this->ldapcharset));
1471
1472 // FQDN domain
1473 $domain = str_replace('dc=', '', $this->domain);
1474 $domain = str_replace(',', '.', $domain);
1475 $this->domainFQDN = $domain;
1476
1477 // Set ldapUserDn (each user can have a different dn)
1478 //var_dump($result[0]);exit;
1479 $this->ldapUserDN = $result[0]['dn'];
1480
1481 ldap_free_result($this->result);
1482 return 1;
1483 }
1484 }
1485
1486
1487 // helper methods
1488
1494 public function getUserIdentifier()
1495 {
1496 if ($this->serverType == "activedirectory") {
1497 return $this->attr_sambalogin;
1498 } else {
1499 return $this->attr_login;
1500 }
1501 }
1502
1509 public function parseUACF($uacf)
1510 {
1511 //All flags array
1512 $flags = array(
1513 "TRUSTED_TO_AUTH_FOR_DELEGATION" => 16777216,
1514 "PASSWORD_EXPIRED" => 8388608,
1515 "DONT_REQ_PREAUTH" => 4194304,
1516 "USE_DES_KEY_ONLY" => 2097152,
1517 "NOT_DELEGATED" => 1048576,
1518 "TRUSTED_FOR_DELEGATION" => 524288,
1519 "SMARTCARD_REQUIRED" => 262144,
1520 "MNS_LOGON_ACCOUNT" => 131072,
1521 "DONT_EXPIRE_PASSWORD" => 65536,
1522 "SERVER_TRUST_ACCOUNT" => 8192,
1523 "WORKSTATION_TRUST_ACCOUNT" => 4096,
1524 "INTERDOMAIN_TRUST_ACCOUNT" => 2048,
1525 "NORMAL_ACCOUNT" => 512,
1526 "TEMP_DUPLICATE_ACCOUNT" => 256,
1527 "ENCRYPTED_TEXT_PWD_ALLOWED" => 128,
1528 "PASSWD_CANT_CHANGE" => 64,
1529 "PASSWD_NOTREQD" => 32,
1530 "LOCKOUT" => 16,
1531 "HOMEDIR_REQUIRED" => 8,
1532 "ACCOUNTDISABLE" => 2,
1533 "SCRIPT" => 1
1534 );
1535
1536 //Parse flags to text
1537 $retval = array();
1538 //while (list($flag, $val) = each($flags)) {
1539 foreach ($flags as $flag => $val) {
1540 if ($uacf >= $val) {
1541 $uacf -= $val;
1542 $retval[$val] = $flag;
1543 }
1544 }
1545
1546 //Return human friendly flags
1547 return $retval;
1548 }
1549
1556 public function parseSAT($samtype)
1557 {
1558 $stypes = array(
1559 805306368 => "NORMAL_ACCOUNT",
1560 805306369 => "WORKSTATION_TRUST",
1561 805306370 => "INTERDOMAIN_TRUST",
1562 268435456 => "SECURITY_GLOBAL_GROUP",
1563 268435457 => "DISTRIBUTION_GROUP",
1564 536870912 => "SECURITY_LOCAL_GROUP",
1565 536870913 => "DISTRIBUTION_LOCAL_GROUP"
1566 );
1567
1568 $retval = "";
1569 foreach ($stypes as $sat => $val) {
1570 if ($samtype == $sat) {
1571 $retval = $val;
1572 break;
1573 }
1574 }
1575 if (empty($retval)) {
1576 $retval = "UNKNOWN_TYPE_".$samtype;
1577 }
1578
1579 return $retval;
1580 }
1581
1588 public function convertTime($value)
1589 {
1590 $dateLargeInt = $value; // nano secondes since the year 1601 !!!!
1591 if (PHP_INT_SIZE < 8) {
1592 // 32 bit platform
1593 $secsAfterADEpoch = (float) $dateLargeInt / (10000000.); // seconds since 1 jan 1601
1594 } else {
1595 // At least 64 bit platform
1596 $secsAfterADEpoch = (int) $dateLargeInt / (10000000); // seconds since 1 jan 1601
1597 }
1598 $ADToUnixConvertor = ((1970 - 1601) * 365.242190) * 86400; // UNIX start date - AD start date * days * seconds
1599 $unixTimeStamp = intval($secsAfterADEpoch - $ADToUnixConvertor); // Unix time stamp
1600 return $unixTimeStamp;
1601 }
1602
1603
1611 private function convToOutputCharset($str, $pagecodefrom = 'UTF-8')
1612 {
1613 global $conf;
1614 if ($pagecodefrom == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1615 $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');
1616 }
1617 if ($pagecodefrom == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1618 $str = mb_convert_encoding($str, 'ISO-8859-1');
1619 }
1620 return $str;
1621 }
1622
1630 public function convFromOutputCharset($str, $pagecodeto = 'UTF-8')
1631 {
1632 global $conf;
1633 if ($pagecodeto == 'ISO-8859-1' && $conf->file->character_set_client == 'UTF-8') {
1634 $str = mb_convert_encoding($str, 'ISO-8859-1');
1635 }
1636 if ($pagecodeto == 'UTF-8' && $conf->file->character_set_client == 'ISO-8859-1') {
1637 $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');
1638 }
1639 return $str;
1640 }
1641
1642
1649 public function getNextGroupGid($keygroup = 'LDAP_KEY_GROUPS')
1650 {
1651
1652 if (empty($keygroup)) {
1653 $keygroup = 'LDAP_KEY_GROUPS';
1654 }
1655
1656 $search = '(' . getDolGlobalString($keygroup).'=*)';
1657 $result = $this->search($this->groups, $search);
1658 if ($result) {
1659 $c = $result['count'];
1660 $gids = array();
1661 for ($i = 0; $i < $c; $i++) {
1662 $gids[] = (int) $result[$i]['gidnumber'][0];
1663 }
1664 rsort($gids);
1665
1666 return $gids[0] + 1;
1667 }
1668
1669 return 0;
1670 }
1671}
$c
Definition line.php:334
Class to manage LDAP features.
add($dn, $info, $user)
Add an LDAP entry LDAP object connect and bind must have been done.
convertTime($value)
Converts ActiveDirectory time to Unix timestamp.
modify($dn, $info, $user)
Modify an LDAP entry LDAP object connect and bind must have been done.
deleteAttribute($dn, $info, $user)
Delete an LDAP attribute in entry LDAP object connect and bind must have been done.
setVersion()
Set LDAP protocol version.
convToOutputCharset($str, $pagecodefrom='UTF-8')
Convert a string into output/memory charset.
littleEndian($hex)
Converts a little-endian hex-number to one, that 'hexdec' can convert Required by Active Directory.
fetch($user, $filter)
Load all attributes of an LDAP user.
update($dn, $info, $user, $olddn, $newrdn='', $newparent='')
Modify an LDAP entry (to use if dn != olddn) LDAP object connect and bind must have been done.
getObjectSid($ldapUser)
Gets LDAP user SID.
updateAttribute($dn, $info, $user)
Update an LDAP attribute in entry LDAP object connect and bind must have been done.
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.
close()
Simply closes the connection set up earlier.
parseSAT($samtype)
SamAccountType value to text.
rename($dn, $newrdn, $newparent, $user, $deleteoldrdn=true)
Rename an LDAP entry LDAP object connect and bind must have been done.
getNextGroupGid($keygroup='LDAP_KEY_GROUPS')
Return available value of group GID.
setSizeLimit()
Set LDAP size limit.
binSIDtoText($binsid)
Returns the textual SID Required by Active Directory.
connectBind()
Connect and bind Use this->server, this->serverPort, this->ldapProtocolVersion, this->serverType,...
setReferrals()
Set LDAP referrals.
search($checkDn, $filter)
Search method with filter this->connection must be defined.
getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter=0, $attributeAsArray=array())
Returns an array containing a details or list of LDAP record(s).
getVersion()
Verify LDAP server version.
dumpContent($dn, $info)
Build an LDAP message.
getAttributeValues($filterrecord, $attribute)
Returns an array containing values for an attribute and for first record matching filterrecord.
parseUACF($uacf)
UserAccountControl Flags to more human understandable form...
__construct()
Constructor.
convFromOutputCharset($str, $pagecodeto='UTF-8')
Convert a string from output/memory charset.
serverPing($host, $port=389, $timeout=1)
Ping a server before ldap_connect for avoid waiting.
bind()
Anonymously binds to the connection.
unbind()
Unbind of LDAP server (close connection).
bindauth($bindDn, $pass)
Binds as an authenticated user, which usually allows for write access.
dump($dn, $info)
Dump an LDAP message to ldapinput.in file.
addAttribute($dn, $info, $user)
Add an LDAP attribute in entry LDAP object connect and bind must have been done.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a 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:133