An error occurred while loading the file. Please try again.
-
Côme Chilliet authored
We cannot pass arguments by reference through ldapMultiplexer issue #2895
Unverifiedf787f099
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2003-2010 Cajus Pollmeier
Copyright (C) 2003 Alejandro Escanero Blanco <aescanero@chaosdimension.org>
Copyright (C) 1998 Eric Kilfoil <eric@ipass.net>
Copyright (C) 2011-2016 FusionDirectory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*!
* \file class_ldap.inc
* Source code for Class LDAP
*/
/*!
* \brief This class contains all ldap function needed to make
* ldap operations easy
*/
class LDAP
{
var $hascon = FALSE;
var $reconnect = FALSE;
var $tls = FALSE;
/* connection identifier */
var $cid;
var $hasres = [];
var $sr = [];
var $re = [];
var $basedn = "";
/* 0 if we are fetching the first entry, otherwise 1 */
var $start = [];
/* Any error messages to be returned can be put here */
var $error = "";
var $srp = 0;
/* Information read from slapd.oc.conf */
var $objectClasses = [];
/* the dn for the bind */
var $binddn = "";
/* the dn's password for the bind */
var $bindpw = "";
var $hostname = "";
var $follow_referral = FALSE;
var $referrals = [];
/* 0, empty or negative values will disable this check */
var $max_ldap_query_time = 0;
/*!
* \brief Create a LDAP connection
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
*
* \param string $binddn Bind of the DN
*
* \param string $bindpw Bind
*
* \param string $hostname The hostname
*
* \param boolean $follow_referral FALSE
*
* \param boolean $tls FALSE
*/
function __construct ($binddn, $bindpw, $hostname, $follow_referral = FALSE, $tls = FALSE)
{
global $config;
$this->follow_referral = $follow_referral;
$this->tls = $tls;
$this->binddn = $binddn;
$this->bindpw = $bindpw;
$this->hostname = $hostname;
/* Check if MAX_LDAP_QUERY_TIME is defined */
if (is_object($config) && ($config->get_cfg_value("ldapMaxQueryTime") != "")) {
$str = $config->get_cfg_value("ldapMaxQueryTime");
$this->max_ldap_query_time = (float)($str);
}
$this->connect();
}
/*!
* \brief Get the search ressource
*
* \return increase srp
*/
function getSearchResource ()
{
$this->sr[$this->srp] = NULL;
$this->start[$this->srp] = 0;
$this->hasres[$this->srp] = FALSE;
return $this->srp++;
}
/*!
* \brief Function to fix problematic characters in DN's that are used for search requests. I.e. member=....
*
* \param string $dn The DN
*/
static function prepare4filter ($dn)
{
trigger_error('deprecated, use ldap_escape_f instead');
return ldap_escape_f($dn);
}
/*!
* \brief Error text that must be returned for invalid user or password
*
* This is useful to make sure the same error text is shown whether a user exists or not, when the password is not correct.
*/
static function invalidCredentialsError (): string
{
return _(ldap_err2str(49));
}
/*!
* \brief Create a connection to LDAP server
*
* The string $error containts result of the connection
*/
function connect ()
{
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
$this->hascon = FALSE;
$this->reconnect = FALSE;
if ($this->cid = @ldap_connect($this->hostname)) {
@ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
if ($this->follow_referral) {
@ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
@ldap_set_rebind_proc($this->cid, [&$this, 'rebind']);
}
if ($this->tls) {
@ldap_start_tls($this->cid);
}
$this->error = 'No Error';
if (function_exists('ldap_bind_ext')) {
/* PHP>=7.3 */
$serverctrls = [];
if (class_available('ppolicyAccount')) {
$serverctrls = [['oid' => LDAP_CONTROL_PASSWORDPOLICYREQUEST]];
}
$result = @ldap_bind_ext($this->cid, $this->binddn, $this->bindpw, $serverctrls);
if (@ldap_parse_result($this->cid, $result, $errcode, $matcheddn, $errmsg, $referrals, $ctrls)) {
if (isset($ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error'])) {
$this->hascon = FALSE;
switch ($ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error']) {
case 0:
/* passwordExpired - password has expired and must be reset */
$this->error = _('It seems your user password has expired. Please use <a href="recovery.php">password recovery</a> to change it.');
break;
case 1:
/* accountLocked */
$this->error = _('Account locked. Please contact your system administrator!');
break;
case 2:
/* changeAfterReset - password must be changed before the user will be allowed to perform any other operation */
$this->error = 'changeAfterReset';
break;
case 3:
/* passwordModNotAllowed */
case 4:
/* mustSupplyOldPassword */
case 5:
/* insufficientPasswordQuality */
case 6:
/* passwordTooShort */
case 7:
/* passwordTooYoung */
case 8:
/* passwordInHistory */
default:
$this->error = sprintf(_('Unexpected ppolicy error "%s", please contact the administrator'), $ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error']);
break;
}
// Note: Also available: expire, grace
} else {
$this->hascon = ($errcode == 0);
if ($errcode == 49) {
$this->error = static::invalidCredentialsError();
} elseif (empty($errmsg)) {
$this->error = ldap_err2str($errcode);
} else {
$this->error = $errmsg;
}
}
} else {
$this->error = 'Parsing of LDAP result from bind failed';
$this->hascon = FALSE;
}
} elseif (@ldap_bind($this->cid, $this->binddn, $this->bindpw)) {
$this->error = 'Success';
$this->hascon = TRUE;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} else {
if ($this->reconnect) {
if ($this->error != 'Success') {
$this->error = static::invalidCredentialsError();
}
} else {
$this->error = static::invalidCredentialsError();
}
}
} else {
$this->error = 'Could not connect to LDAP server';
}
}
/*!
* \brief Rebind
*/
function rebind ($ldap, $referral)
{
$credentials = $this->get_credentials($referral);
if (@ldap_bind($ldap, $credentials['ADMINDN'], $credentials['ADMINPASSWORD'])) {
$this->error = "Success";
$this->hascon = TRUE;
$this->reconnect = TRUE;
return 0;
} else {
$this->error = "Could not bind to " . $credentials['ADMINDN'];
return NULL;
}
}
/*!
* \brief Reconnect to LDAP server
*/
function reconnect ()
{
if ($this->reconnect) {
$this->unbind();
}
}
/*!
* \brief Unbind to LDAP server
*/
function unbind ()
{
@ldap_unbind($this->cid);
$this->cid = NULL;
}
/*!
* \brief Disconnect to LDAP server
*/
function disconnect ()
{
if ($this->hascon) {
@ldap_close($this->cid);
$this->hascon = FALSE;
}
}
/*!
* \brief Change directory
*
* \param string $dir The new directory
*/
function cd ($dir)
{
if ($dir == '..') {
$this->basedn = $this->getParentDir();
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
} else {
$this->basedn = $dir;
}
}
/*!
* \brief Accessor of the parent directory of the basedn
*
* \param string $basedn The basedn which we want the parent directory
*
* \return String, the parent directory
*/
function getParentDir ($basedn = '')
{
if ($basedn == '') {
$basedn = $this->basedn;
}
return preg_replace("/[^,]*[,]*[ ]*(.*)/", "$1", $basedn);
}
/*!
* \brief Search about filter
*
* \param integer $srp srp
*
* \param string $filter The filter
*
* \param array $attrs
*
* \param string $scope Scope of the search: subtree/base/one
*/
function search ($srp, $filter, $attrs = [], $scope = 'subtree', array $controls = NULL)
{
if ($this->hascon) {
if ($this->reconnect) {
$this->connect();
}
$startTime = microtime(TRUE);
$this->clearResult($srp);
switch (strtolower($scope)) {
case 'base':
if (isset($controls)) {
$this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
} else {
$this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs);
}
break;
case 'one':
if (isset($controls)) {
$this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
} else {
$this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs);
}
break;
case 'subtree':
default:
if (isset($controls)) {
$this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
} else {
$this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs);
}
break;
}
$this->error = @ldap_error($this->cid);
$this->resetResult($srp);
$this->hasres[$srp] = TRUE;
/* Check if query took longer as specified in max_ldap_query_time */
$diff = microtime(TRUE) - $startTime;
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
if ($this->max_ldap_query_time && ($diff > $this->max_ldap_query_time)) {
msg_dialog::display(_("Performance warning"), sprintf(_("LDAP performance is poor: last query took about %.2fs!"), $diff), WARNING_DIALOG);
}
$this->log("LDAP operation: time=".$diff." operation=search('".$this->basedn."', '$filter')");
return $this->sr[$srp];
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Parse last result
*
* \param integer $srp srp
*
*/
function parse_result ($srp): array
{
if ($this->hascon && $this->hasres[$srp]) {
if (ldap_parse_result($this->cid, $this->sr[$srp], $errcode, $matcheddn, $errmsg, $referrals, $controls)) {
return [$errcode, $matcheddn, $errmsg, $referrals, $controls];
} else {
throw new FusionDirectoryException(_('Parsing LDAP result failed'));
}
} else {
throw new FusionDirectoryException(_('No LDAP result to parse'));
}
}
/*
* \brief List
*
* \param integer $srp
*
* \param string $filter Initialized at "(objectclass=*)"
*
* \param string $basedn Empty string
*
* \param array $attrs
*/
function ls ($srp, $filter = "(objectclass=*)", $basedn = "", $attrs = ["*"])
{
trigger_error('deprecated');
$this->cd($basedn);
return $this->search($srp, $filter, $attrs, 'one');
}
/*
* \brief Concatenate
*
* \param integer $srp
*
* \param string $dn The DN
*
* \param array $attrs
*
* \param string $filter Initialized at "(objectclass=*)"
*/
function cat ($srp, $dn, $attrs = ["*"], $filter = "(objectclass=*)")
{
if ($this->hascon) {
if ($this->reconnect) {
$this->connect();
}
$this->clearResult($srp);
$this->sr[$srp] = @ldap_read($this->cid, $dn, $filter, $attrs);
$this->error = @ldap_error($this->cid);
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
$this->resetResult($srp);
$this->hasres[$srp] = TRUE;
return $this->sr[$srp];
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Search object from a filter
*
* \param string $dn The DN
*
* \param string $filter The filter of the research
*/
function object_match_filter ($dn, $filter)
{
if ($this->hascon) {
if ($this->reconnect) {
$this->connect();
}
$res = @ldap_read($this->cid, $dn, $filter, ["objectClass"]);
return @ldap_count_entries($this->cid, $res);
} else {
$this->error = "Could not connect to LDAP server";
return FALSE;
}
}
/*!
* \brief Set a size limit
*
* \param $size The limit
*/
function set_size_limit ($size)
{
/* Ignore zero settings */
if ($size == 0) {
@ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
}
if ($this->hascon) {
@ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
} else {
$this->error = "Could not connect to LDAP server";
}
}
/*!
* \brief Fetch
*
* \param integer $srp
*/
function fetch ($srp)
{
$att = [];
if ($this->hascon) {
if ($this->hasres[$srp]) {
if ($this->start[$srp] == 0) {
if ($this->sr[$srp]) {
$this->start[$srp] = 1;
$this->re[$srp] = @ldap_first_entry($this->cid, $this->sr[$srp]);
} else {
return [];
}
} else {
$this->re[$srp] = @ldap_next_entry($this->cid, $this->re[$srp]);
}
if ($this->re[$srp]) {
$att = @ldap_get_attributes($this->cid, $this->re[$srp]);
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
$att['dn'] = trim(@ldap_get_dn($this->cid, $this->re[$srp]));
}
$this->error = @ldap_error($this->cid);
if (!isset($att)) {
$att = [];
}
return $att;
} else {
$this->error = "Perform a fetch with no search";
return "";
}
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Reset the result
*
* \param integer $srp Value to be reset
*/
function resetResult ($srp)
{
$this->start[$srp] = 0;
}
/*!
* \brief Clear a result
*
* \param integer $srp The result to clear
*/
function clearResult ($srp)
{
if ($this->hasres[$srp]) {
$this->hasres[$srp] = FALSE;
@ldap_free_result($this->sr[$srp]);
}
}
/*!
* \brief Accessor of the DN
*
* \param $srp srp
*/
function getDN ($srp)
{
if ($this->hascon) {
if ($this->hasres[$srp]) {
if (!$this->re[$srp]) {
$this->error = "Perform a Fetch with no valid Result";
} else {
$rv = @ldap_get_dn($this->cid, $this->re[$srp]);
$this->error = @ldap_error($this->cid);
return trim($rv);
}
} else {
$this->error = "Perform a Fetch with no Search";
return "";
}
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Return the numbers of entries
*
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
* \param $srp srp
*/
function count ($srp)
{
if ($this->hascon) {
if ($this->hasres[$srp]) {
$rv = @ldap_count_entries($this->cid, $this->sr[$srp]);
$this->error = @ldap_error($this->cid);
return $rv;
} else {
$this->error = "Perform a Fetch with no Search";
return "";
}
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Remove
*
* \param string $attrs Empty string
*
* \param string $dn Empty string
*/
function rm ($attrs = "", $dn = "")
{
if ($this->hascon) {
if ($this->reconnect) {
$this->connect();
}
if ($dn == '') {
$dn = $this->basedn;
}
$r = ldap_mod_del($this->cid, $dn, $attrs);
$this->error = @ldap_error($this->cid);
return $r;
} else {
$this->error = 'Could not connect to LDAP server';
return '';
}
}
function mod_add ($attrs = "", $dn = "")
{
if ($this->hascon) {
if ($this->reconnect) {
$this->connect();
}
if ($dn == "") {
$dn = $this->basedn;
}
$r = @ldap_mod_add($this->cid, $dn, $attrs);
$this->error = @ldap_error($this->cid);
return $r;
} else {
$this->error = "Could not connect to LDAP server";
return "";
}
}
/*!
* \brief Remove directory
*
* \param string $deletedn The DN to be deleted
*/