44 public $errors = array();
113 public $ldapcharset =
'UTF-8';
149 if (!empty($conf->global->LDAP_SERVER_HOST)) {
150 $this->server[] = $conf->global->LDAP_SERVER_HOST;
152 if (!empty($conf->global->LDAP_SERVER_HOST_SLAVE)) {
153 $this->server[] = $conf->global->LDAP_SERVER_HOST_SLAVE;
196 global $dolibarr_main_auth_ldap_debug;
201 $this->connectedServer =
'';
203 $ldapdebug = ((empty($dolibarr_main_auth_ldap_debug) || $dolibarr_main_auth_ldap_debug ==
"false") ?
false :
true);
206 dol_syslog(get_class($this).
"::connect_bind");
207 print
"DEBUG: connect_bind<br>\n";
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);
217 if (!function_exists(
"ldap_connect")) {
218 $this->error =
'LDAPFunctionsNotAvailableOnPHP';
219 dol_syslog(get_class($this).
"::connect_bind ".$this->error, LOG_WARNING);
223 if (empty($this->error)) {
225 foreach ($this->server as $host) {
233 if ($this->
serverPing($host, $this->serverPort) ===
true) {
235 dol_syslog(get_class($this).
"::connect_bind serverPing true, we try ldap_connect to ".$host);
237 $this->connection = ldap_connect($host, $this->serverPort);
239 if (preg_match(
'/^ldaps/i', $host)) {
243 dol_syslog(get_class($this).
"::connect_bind serverPing false, we try ldap_connect to ".$host);
245 $this->connection = ldap_connect($host, $this->serverPort);
251 if (is_resource($this->connection) || is_object($this->connection)) {
253 dol_syslog(get_class($this).
"::connect_bind this->connection is ok", LOG_DEBUG);
257 if (!empty($conf->global->LDAP_SERVER_USE_TLS)) {
263 $resulttls = ldap_start_tls($this->connection);
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);
274 ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0);
277 if ($this->serverType ==
"activedirectory") {
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);
284 $this->connectedServer = $host;
287 $this->error = ldap_errno($this->connection).
' '.ldap_error($this->connection);
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);
297 $this->connectedServer = $host;
300 $this->error = ldap_errno($this->connection).
' '.ldap_error($this->connection);
305 dol_syslog(get_class($this).
"::connect_bind try bind anonymously on ".$host, LOG_DEBUG);
310 $this->connectedServer = $host;
313 $this->error = ldap_errno($this->connection).
' '.ldap_error($this->connection);
326 $return = $connected;
327 dol_syslog(get_class($this).
"::connect_bind return=".$return, LOG_DEBUG);
329 $this->error =
'Failed to connect to LDAP'.($this->error ?
': '.$this->error :
'');
331 dol_syslog(get_class($this).
"::connect_bind return=".$return.
' - '.$this->error, LOG_WARNING);
358 if (!$this->result = @ldap_bind($this->connection)) {
359 $this->ldapErrorCode = ldap_errno($this->connection);
360 $this->ldapErrorText = ldap_error($this->connection);
380 if (!$this->result = @ldap_bind($this->connection, $bindDn, $pass)) {
381 $this->ldapErrorCode = ldap_errno($this->connection);
382 $this->ldapErrorText = ldap_error($this->connection);
398 $this->result =
true;
399 if (is_resource($this->connection) || is_object($this->connection)) {
400 $this->result = @ldap_unbind($this->connection);
418 $version = @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
430 $ldapsetversion = ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
431 return $ldapsetversion;
442 $ldapreferrals = ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
443 return $ldapreferrals;
458 dol_syslog(get_class($this).
"::add dn=".
$dn.
" info=".json_encode($info));
461 if (!$this->connection) {
462 $this->error =
"NotConnected";
466 $this->error =
"NotConnected";
472 foreach ($info as $key => $val) {
473 if (!is_array($val)) {
481 $result = @ldap_add($this->connection,
$dn, $info);
484 dol_syslog(get_class($this).
"::add successfull", LOG_DEBUG);
487 $this->ldapErrorCode = @ldap_errno($this->connection);
488 $this->ldapErrorText = @ldap_error($this->connection);
490 dol_syslog(get_class($this).
"::add failed: ".$this->error, LOG_ERR);
506 dol_syslog(get_class($this).
"::modify dn=".
$dn.
" info=".join(
',', $info));
509 if (!$this->connection) {
510 $this->error =
"NotConnected";
514 $this->error =
"NotConnected";
520 foreach ($info as $key => $val) {
521 if (!is_array($val)) {
531 if ($this->serverType ==
"activedirectory") {
535 if (isset($info[
'unicodePwd'])) {
536 $info[
'unicodePwd'] = mb_convert_encoding(
"\"".$info[
'unicodePwd'].
"\"",
"UTF-16LE",
"UTF-8");
539 $result = @ldap_modify($this->connection,
$dn, $info);
542 dol_syslog(get_class($this).
"::modify successfull", LOG_DEBUG);
545 $this->error = @ldap_error($this->connection);
546 dol_syslog(get_class($this).
"::modify failed: ".$this->error, LOG_ERR);
562 public function rename(
$dn, $newrdn, $newparent, $user, $deleteoldrdn =
true)
564 dol_syslog(get_class($this).
"::modify dn=".
$dn.
" newrdn=".$newrdn.
" newparent=".$newparent.
" deleteoldrdn=".($deleteoldrdn ? 1 : 0));
567 if (!$this->connection) {
568 $this->error =
"NotConnected";
572 $this->error =
"NotConnected";
582 $result = @ldap_rename($this->connection,
$dn, $newrdn, $newparent, $deleteoldrdn);
585 dol_syslog(get_class($this).
"::rename successfull", LOG_DEBUG);
588 $this->error = @ldap_error($this->connection);
589 dol_syslog(get_class($this).
"::rename failed: ".$this->error, LOG_ERR);
606 public function update(
$dn, $info, $user, $olddn, $newrdn =
false, $newparent =
false)
608 dol_syslog(get_class($this).
"::update dn=".
$dn.
" olddn=".$olddn);
611 if (!$this->connection) {
612 $this->error =
"NotConnected";
616 $this->error =
"NotConnected";
620 if (!$olddn || $olddn !=
$dn) {
621 if (!empty($olddn) && !empty($newrdn) && !empty($newparent) && $this->ldapProtocolVersion ===
'3') {
623 $result = $this->
rename($olddn, $newrdn, $newparent, $user,
true);
629 $result = $this->
delete($olddn);
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);
643 dol_syslog(get_class($this).
"::update done successfully");
656 public function delete(
$dn)
658 dol_syslog(get_class($this).
"::delete Delete LDAP entry dn=".
$dn);
661 if (!$this->connection) {
662 $this->error =
"NotConnected";
666 $this->error =
"NotConnected";
673 $result = @ldap_delete($this->connection,
$dn);
695 if (preg_match(
'/^ldap/', $this->server[0])) {
696 $target =
"-H ".join(
',', $this->server);
698 $target =
"-h ".join(
',', $this->server).
" -p ".$this->serverPort;
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";
706 $content .=
"dn: ".$dn.
"\n";
707 foreach ($info as $key => $value) {
708 if (!is_array($value)) {
709 $content .=
"$key: $value\n";
711 foreach ($value as $valuevalue) {
712 $content .=
"$key: $valuevalue\n";
736 $outputfile = $conf->ldap->dir_temp.
'/ldapinput.in';
737 $fp = fopen($outputfile,
"w");
739 fputs($fp, $content);
741 if (!empty($conf->global->MAIN_UMASK)) {
742 @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
761 if (preg_match(
'/^ldaps:\/\/([^\/]+)\/?$/', $host, $regs)) {
763 $host =
'ssl://'.$regs[1];
764 } elseif (preg_match(
'/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) {
773 $errno = $errstr = 0;
782 $op = @fsockopen($host, $port, $errno, $errstr, $timeout);
807 dol_syslog(get_class($this).
"::addAttribute dn=".
$dn.
" info=".join(
',', $info));
810 if (!$this->connection) {
811 $this->error =
"NotConnected";
815 $this->error =
"NotConnected";
821 foreach ($info as $key => $val) {
822 if (!is_array($val)) {
830 $result = @ldap_mod_add($this->connection,
$dn, $info);
833 dol_syslog(get_class($this).
"::add_attribute successfull", LOG_DEBUG);
836 $this->error = @ldap_error($this->connection);
837 dol_syslog(get_class($this).
"::add_attribute failed: ".$this->error, LOG_ERR);
853 dol_syslog(get_class($this).
"::updateAttribute dn=".
$dn.
" info=".join(
',', $info));
856 if (!$this->connection) {
857 $this->error =
"NotConnected";
861 $this->error =
"NotConnected";
867 foreach ($info as $key => $val) {
868 if (!is_array($val)) {
876 $result = @ldap_mod_replace($this->connection,
$dn, $info);
879 dol_syslog(get_class($this).
"::updateAttribute successfull", LOG_DEBUG);
882 $this->error = @ldap_error($this->connection);
883 dol_syslog(get_class($this).
"::updateAttribute failed: ".$this->error, LOG_ERR);
899 dol_syslog(get_class($this).
"::deleteAttribute dn=".
$dn.
" info=".join(
',', $info));
902 if (!$this->connection) {
903 $this->error =
"NotConnected";
907 $this->error =
"NotConnected";
913 foreach ($info as $key => $val) {
914 if (!is_array($val)) {
922 $result = @ldap_mod_del($this->connection,
$dn, $info);
925 dol_syslog(get_class($this).
"::deleteAttribute successfull", LOG_DEBUG);
928 $this->error = @ldap_error($this->connection);
929 dol_syslog(get_class($this).
"::deleteAttribute failed: ".$this->error, LOG_ERR);
944 if (!$this->connection) {
945 $this->error =
"NotConnected";
949 $this->error =
"NotConnected";
953 $search = @ldap_search($this->connection,
$dn, $filter);
956 $entry = @ldap_first_entry($this->connection, $search);
959 $this->ldapErrorCode = -1;
960 $this->ldapErrorText =
"Couldn't find entry";
965 if (!($values = ldap_get_attributes($this->connection, $entry))) {
966 $this->ldapErrorCode = ldap_errno($this->connection);
967 $this->ldapErrorText = ldap_error($this->connection);
984 $attributes = array();
985 $attributes[0] = $attribute;
988 $this->result = @ldap_search($this->connection, $this->people, $filterrecord, $attributes);
994 $entry = ldap_first_entry($this->connection, $this->result);
997 $this->ldapErrorCode = -1;
998 $this->ldapErrorText =
"Couldn't find user";
1003 if (!$values = @ldap_get_values($this->connection, $entry, $attribute)) {
1004 $this->ldapErrorCode = ldap_errno($this->connection);
1005 $this->ldapErrorText = ldap_error($this->connection);
1025 public function getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter = 0, $attributeAsArray = array())
1027 $fulllist = array();
1029 dol_syslog(get_class($this).
"::getRecords search=".$search.
" userDn=".$userDn.
" useridentifier=".$useridentifier.
" attributeArray=array(".join(
',', $attributeArray).
") activefilter=".$activefilter);
1032 if ($this->serverType ==
"activedirectory") {
1033 $this->
bindauth($this->searchUser, $this->searchPassword);
1034 dol_syslog(get_class($this).
"::bindauth serverType=activedirectory searchUser=".$this->searchUser);
1038 if (!empty($activefilter)) {
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.
')';
1047 $filter =
'('.ldap_escape($useridentifier,
'', LDAP_ESCAPE_FILTER).
'=*)';
1050 $filter =
'('.ldap_escape($useridentifier,
'', LDAP_ESCAPE_FILTER).
'='.ldap_escape($search,
'', LDAP_ESCAPE_FILTER).
')';
1053 if (is_array($attributeArray)) {
1055 $attributeArray = array_values($attributeArray);
1056 dol_syslog(get_class($this).
"::getRecords connection=".$this->connectedServer.
":".$this->serverPort.
" userDn=".$userDn.
" filter=".$filter.
" attributeArray=(".join(
',', $attributeArray).
")");
1058 $this->result = @ldap_search($this->connection, $userDn, $filter, $attributeArray);
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);
1064 if (!$this->result) {
1065 $this->error =
'LDAP search failed: '.ldap_errno($this->connection).
" ".ldap_error($this->connection);
1069 $info = @ldap_get_entries($this->connection, $this->result);
1075 for ($i = 0; $i < $info[
"count"]; $i++) {
1076 $recordid = $this->
convToOutputCharset($info[$i][strtolower($useridentifier)][0], $this->ldapcharset);
1079 $fulllist[$recordid][$useridentifier] = $recordid;
1082 $num = count($attributeArray);
1083 for ($j = 0; $j < $num; $j++) {
1084 $keyattributelower = strtolower($attributeArray[$j]);
1088 if ($this->serverType ==
"activedirectory" && $keyattributelower ==
"objectsid") {
1090 $fulllist[$recordid][$attributeArray[$j]] = $objectsid;
1092 if (in_array($attributeArray[$j], $attributeAsArray) && is_array($info[$i][$keyattributelower])) {
1093 $valueTab = array();
1094 foreach ($info[$i][$keyattributelower] as $key => $value) {
1097 $fulllist[$recordid][$attributeArray[$j]] = $valueTab;
1099 $fulllist[$recordid][$attributeArray[$j]] = $this->
convToOutputCharset($info[$i][$keyattributelower][0], $this->ldapcharset);
1120 for ($x =
dol_strlen($hex) - 2; $x >= 0; $x = $x - 2) {
1121 $result .= substr($hex, $x, 2);
1136 $criteria =
'('.$this->getUserIdentifier().
'='.$ldapUser.
')';
1137 $justthese = array(
"objectsid");
1140 if ($this->serverType ==
"activedirectory") {
1141 $this->
bindauth($this->searchUser, $this->searchPassword);
1148 $ldapSearchResult = @ldap_search($this->connection, $searchDN, $criteria, $justthese);
1150 if (!$ldapSearchResult) {
1151 $this->error = ldap_errno($this->connection).
" ".ldap_error($this->connection);
1155 $entry = ldap_first_entry($this->connection, $ldapSearchResult);
1168 $ldapBinary = ldap_get_values_len($this->connection, $entry,
"objectsid");
1172 $this->error = ldap_errno($this->connection).
" ".ldap_error($this->connection);
1186 $hex_sid = bin2hex($binsid);
1187 $rev = hexdec(substr($hex_sid, 0, 2));
1188 $subcount = hexdec(substr($hex_sid, 2, 2));
1189 $auth = hexdec(substr($hex_sid, 4, 12));
1191 for ($x = 0; $x < $subcount; $x++) {
1211 dol_syslog(get_class($this).
"::search checkDn=".$checkDn.
" filter=".$filter);
1217 if ($this->serverType ==
"activedirectory") {
1218 $this->
bindauth($this->searchUser, $this->searchPassword);
1221 $this->result = @ldap_search($this->connection, $checkDn, $filter);
1223 $result = @ldap_get_entries($this->connection, $this->result);
1225 $this->error = ldap_errno($this->connection).
" ".ldap_error($this->connection);
1228 ldap_free_result($this->result);
1247 if ($this->serverType ==
"activedirectory") {
1248 $this->
bindauth($this->searchUser, $this->searchPassword);
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);
1263 dol_syslog(
'Ldap::fetch search returns but found no records');
1267 $this->error = ldap_errno($this->connection).
" ".ldap_error($this->connection);
1268 dol_syslog(get_class($this).
"::fetch search fails");
1282 $this->error = ldap_errno($this->connection).
" ".ldap_error($this->connection);
1295 if (isset(
$result[0][
"pwdlastset"][0])) {
1298 $this->pwdlastset = -1;
1300 if (!$this->
name && !$this->login) {
1301 $this->pwdlastset = -1;
1306 $domain = str_replace(
'dc=',
'', $this->domain);
1312 $this->ldapUserDN =
$result[0][
'dn'];
1314 ldap_free_result($this->result);
1329 if ($this->serverType ==
"activedirectory") {
1330 return $this->attr_sambalogin;
1332 return $this->attr_login;
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,
1364 "HOMEDIR_REQUIRED" => 8,
1365 "ACCOUNTDISABLE" => 2,
1372 foreach ($flags as $flag => $val) {
1373 if ($uacf >= $val) {
1375 $retval[$val] = $flag;
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"
1402 while (list($sat, $val) = each($stypes)) {
1403 if ($samtype == $sat) {
1408 if (empty($retval)) {
1409 $retval =
"UNKNOWN_TYPE_".$samtype;
1425 $dateLargeInt = $value;
1426 $secsAfterADEpoch = $dateLargeInt / (10000000);
1427 $ADToUnixConvertor = ((1970 - 1601) * 365.242190) * 86400;
1428 $unixTimeStamp = intval($secsAfterADEpoch - $ADToUnixConvertor);
1429 return $unixTimeStamp;
1443 if ($pagecodefrom ==
'ISO-8859-1' && $conf->file->character_set_client ==
'UTF-8') {
1444 $str = utf8_encode($str);
1446 if ($pagecodefrom ==
'UTF-8' && $conf->file->character_set_client ==
'ISO-8859-1') {
1447 $str = utf8_decode($str);
1462 if ($pagecodeto ==
'ISO-8859-1' && $conf->file->character_set_client ==
'UTF-8') {
1463 $str = utf8_decode($str);
1465 if ($pagecodeto ==
'UTF-8' && $conf->file->character_set_client ==
'ISO-8859-1') {
1466 $str = utf8_encode($str);
1482 if (empty($keygroup)) {
1483 $keygroup =
'LDAP_KEY_GROUPS';
1486 $search =
'('.$conf->global->$keygroup.
'=*)';
1491 for ($i = 0; $i < $c; $i++) {
1492 $gids[] =
$result[$i][
'gidnumber'][0];
1496 return $gids[0] + 1;