Compare commits

...

22 Commits

Author SHA1 Message Date
Deon George
d4cae5065b Updated version to 1.2.6.3 2021-12-12 13:35:51 +11:00
Deon George
386d6ab83b Fix syntax error created by a0de69b - thanks to Bert Van de Poel for testing this and identifying the error 2021-12-12 13:25:28 +11:00
Deon George
1d26d435c2 Special character issue in password - closes #104 2021-12-10 16:14:04 +11:00
Deon George
a0de69bd58 foreach error in lib_ldap_pla.php:checkUniqueAttrs when uidpool is turned on - closes #20 2021-12-10 16:05:01 +11:00
EtienneBarbier
a8c9abe22b Add option to list available password types - closes #143 2021-12-10 15:56:58 +11:00
Bert Van de Poel
1c7340ce48 Correct incorrent mixing of tabs and spaces.
All code (including code originating from the blowfish PR) now correctly use tabs. Spaces are only used for alignment in comments where necessary.
2021-12-10 15:18:26 +11:00
Bert Van de Poel
24ce5d5833 Replace salt function with a more modern, cryptographically secure pseudo-random method
Set minimum PHP version to 7.0.0 for random_bytes
2021-12-10 15:18:18 +11:00
Bert Van de Poel
fe3798f8ec Modernize sha1 and md5 password hash and check functions: remove unnecessary pack, no longer use very old fallbacks, and use random_salt 2021-12-10 15:18:09 +11:00
Bert Van de Poel
1a09e4ff3c Modernize sha512 hash code: replace openssl_digest with the generic hash function, remove check no longer necessary in minimum version 2021-12-10 15:18:01 +11:00
Bert Van de Poel
bc1691f5d2 Add hash support for ssha512 2021-12-10 15:17:54 +11:00
Bert Van de Poel
54bb4743aa Add hash support for salted and non-salted sha256 and sha384 (therefore adding full support for all hashes in the sha2 openLDAP module) 2021-12-10 15:17:43 +11:00
Franky Van Liedekerke
46cc4a1b13 Take into account empty arguments
If no argument is given to the function call, don't try to pass an empty array as some php functions don't allow arguments (like the time function)
2021-12-10 15:09:18 +11:00
Maarten
45aa1e5208 Added script comment for the Autofill A flag 2021-12-10 15:06:36 +11:00
Maarten
02b047c1f5 Bug fix: typo in regex 2021-12-10 15:06:36 +11:00
Maarten
6d4aff8733 Added optional delimiter to /K autofill function 2021-12-10 15:06:36 +11:00
Scott Shambarger
00683b3ea7 Added TLS client certificate support
Adds configuration for TLS client certificates to secure TLS connection
(requires PHP 7.1+ to use).
Updates use of ldap_set_option to report errors if settings fail.
Modifies connection logic to fail if connection preparation fails
(eg. to avoid connections over insecure links if requested TLS fails).
2021-12-10 15:02:31 +11:00
Scott Shambarger
da69ebf06a Added SASL EXTERNAL authentication support
New auth_type 'sasl_external'.  Login is hard coded as 'external'
2021-12-10 14:59:02 +11:00
Deon George
a8fe6f3274 Revert part of 0b657471 to fix #105 - Problem with member select list to goun 2020-09-23 10:13:11 +10:00
Deon George
0c334f0385 Fix for issue #103 - hexdec() causes an deprecation notice when invalid chars are used 2020-09-19 17:09:29 +10:00
Deon George
9fac4b415a Release 1.2.6 2020-09-19 13:45:09 +10:00
Nic Bernstein
f4c8c3d31e SF Bug #1008 getContainerPath doesn't properly traverse to baseDN and back & #1009 - return_ldap_hash should not return container object in result set 2020-08-31 08:49:02 +10:00
Andy Beefeater
e45e71fd08 SF Feature #356 - HTMLTree icons formatting 2020-08-31 08:48:49 +10:00
13 changed files with 423 additions and 183 deletions

View File

@ -5,7 +5,7 @@ For install instructions in non-English languages, see the wiki:
phpLDAPadmin requires the following:
a. A web server (Apache, IIS, etc).
b. PHP 5.5.0 or newer (with LDAP support)
b. PHP 7.0.0 or newer (with LDAP support)
* To install

View File

@ -1 +1 @@
RELEASE-1.2.5
RELEASE-1.2.6.3

View File

@ -71,6 +71,31 @@
environments. */
# $config->custom->password['no_random_crypt_salt'] = true;
/* If you want to restrict password available types (encryption algorithms)
Should be subset of:
array(
''=>'clear',
'bcrypt'=>'bcrypt',
'blowfish'=>'blowfish',
'crypt'=>'crypt',
'ext_des'=>'ext_des',
'md5'=>'md5',
'k5key'=>'k5key',
'md5crypt'=>'md5crypt',
'sha'=>'sha',
'smd5'=>'smd5',
'ssha'=>'ssha',
'sha256'=>'sha256',
'ssha256'=>'ssha256',
'sha384'=>'sha384',
'ssha384'=>'ssha384',
'sha512'=>'sha512',
'ssha512'=>'ssha512',
'sha256crypt'=>'sha256crypt',
'sha512crypt'=>'sha512crypt',
)*/
# $config->custom->password['available_types'] = array(''=>'clear','md5'=>'md5');
/* PHP script timeout control. If php runs longer than this many seconds then
PHP will stop with an Maximum Execution time error. Increase this value from
the default if queries to your LDAP server are slow. The default is either
@ -173,6 +198,10 @@ $config->custom->commands['script'] = array(
// $config->custom->appearance['tree_width'] = null;
# $config->custom->appearance['tree_width'] = 250;
/* Number of tree command icons to show, 0 = show all icons on 1 row. */
// $config->custom->appearance['tree_icons'] = 0;
# $config->custom->appearance['tree_icons'] = 4;
/* Confirm create and update operations, allowing you to review the changes
and optionally skip attributes during the create/update operation. */
// $config->custom->confirm['create'] = true;
@ -243,7 +272,6 @@ $config->custom->appearance['friendly_attrs'] = array(
/* Attribute that is added to the group member attribute. */
// $config->custom->modify_member['attr'] = 'dn';
/* For Posix attributes */
// $config->custom->modify_member['posixattr'] = 'uid';
// $config->custom->modify_member['posixfilter'] = '(uid=*)';
@ -311,6 +339,7 @@ $servers->setValue('server','name','My LDAP Server');
login will be required to use phpLDAPadmin for this server.
5. 'sasl': login will be taken from the webserver's kerberos authentication.
Currently only GSSAPI has been tested (using mod_auth_kerb).
6. 'sasl_external': login will be taken from SASL external mechanism.
Choose wisely to protect your authentication information appropriately for
your situation. If you choose 'cookie', your cookie contents will be
@ -335,6 +364,22 @@ $servers->setValue('server','name','My LDAP Server');
/* Use TLS (Transport Layer Security) to connect to the LDAP server. */
// $servers->setValue('server','tls',false);
/* TLS Certificate Authority file (overrides ldap.conf, PHP 7.1+) */
// $servers->setValue('server','tls_cacert',null);
# $servers->setValue('server','tls_cacert','/etc/openldap/certs/ca.crt');
/* TLS Certificate Authority hashed directory (overrides ldap.conf, PHP 7.1+) */
// $servers->setValue('server','tls_cacertdir',null);
# $servers->setValue('server','tls_cacertdir','/etc/openldap/certs');
/* TLS Client Certificate file (PHP 7.1+) */
// $servers->setValue('server','tls_cert',null);
# $servers->setValue('server','tls_cert','/etc/pki/tls/certs/ldap_user.crt');
/* TLS Client Certificate Key file (PHP 7.1+) */
// $servers->setValue('server','tls_key',null);
# $servers->setValue('server','tls_key','/etc/pki/tls/private/ldap_user.key');
/************************************
* SASL Authentication *
************************************/
@ -352,6 +397,9 @@ $servers->setValue('server','name','My LDAP Server');
NOTE: auth_type must be simple auth compatible (ie not sasl) */
# $servers->setValue('sasl','mech','PLAIN');
/* SASL EXTERNAL support... really a different auth_type */
# $servers->setValue('login','auth_type','sasl_external');
/* SASL authentication realm name */
// $servers->setValue('sasl','realm','');
# $servers->setValue('sasl','realm','EXAMPLE.COM');

View File

@ -20,6 +20,7 @@ if ($pass) {
$user = array();
$user['login'] = get_request('login');
$user['password'] = get_request('login_pass');
$user['password'] = html_entity_decode($user['password'], ENT_QUOTES);
if ($user['login'] && !strlen($user['password'])) {
system_message(array(

View File

@ -65,7 +65,7 @@ for ($i=0;$i<count($possible_values);$i++) {
if (preg_match("/^".$request['attr']."$/i",$_SESSION[APPCONFIG]->getValue('modify_member','posixgroupattr')))
$possible_members[$i] = $possible_values[$i][$_SESSION[APPCONFIG]->getValue('modify_member','posixattr')][0];
else
$possible_members[$i] = $possible_values[$i][$_SESSION[APPCONFIG]->getValue('modify_member','attr')][0];
$possible_members[$i] = $possible_values[$i][$_SESSION[APPCONFIG]->getValue('modify_member','attr')];
}
# Show only user that are not already in group.

View File

@ -136,6 +136,7 @@ class HTMLTree extends Tree {
case 'config':
case 'proxy':
case 'sasl':
case 'sasl_external':
break;
default:
@ -184,10 +185,15 @@ class HTMLTree extends Tree {
$links = '';
$i = 0;
$icons = $_SESSION[APPCONFIG]->getValue('appearance','tree_icons');
if (is_array($_SESSION[APPCONFIG]->getValue('menu','session')))
foreach ($_SESSION[APPCONFIG]->getValue('menu','session') as $link => $title) {
if ($this->get_menu_item($link))
$links .= sprintf('<td class="server_links">%s</td>',$this->get_menu_item($link));
if ($icons && ++$i%$icons == 0)
$links .= '</tr><tr>';
}
# Finally add our logout link.
@ -329,7 +335,7 @@ class HTMLTree extends Tree {
$server = $this->getServer();
$href = sprintf('cmd.php?cmd=logout&server_id=%s',$server->getIndex());
if (! $_SESSION[APPCONFIG]->isCommandAvailable('script','logout') || in_array($server->getAuthType(),array('config','http','proxy','sasl')))
if (! $_SESSION[APPCONFIG]->isCommandAvailable('script','logout') || in_array($server->getAuthType(),array('config','http','proxy','sasl','sasl_external')))
return '';
else
return sprintf('<a href="%s" title="%s"><img src="%s/%s" alt="%s" /><br />%s</a>',

View File

@ -1123,10 +1123,11 @@ class Template extends xmlTemplate {
switch ($command) {
/*
autoFill:string
string is a literal string, and may contain many fields like %attr|start-end/flags%
string is a literal string, and may contain many fields like %attr|start-end/flags|additionalcontrolchar%
to substitute values read from other fields.
|start-end is optional, but must be present if the k flag is used.
/flags is optional.
|additionalcontrolchar is optional.
flags may be:
T: Read display text from selection item (drop-down list), otherwise, read the value of the field
@ -1141,8 +1142,11 @@ class Template extends xmlTemplate {
The string read will be split into fields, using : as a delimiter
"start" indicates which field number to pass through.
K: The string read will be split into fields, using ' ' as a delimiter "start" indicates which field number to pass through.
If additionalcontrolchar is given, it will be used as delimiter (e.g. this allows for splitting e-mail addresses
into domain and domain-local part).
l: Make the result lower case.
U: Make the result upper case.
A: Remap special characters to their corresponding ASCII value
*/
case 'autoFill':
if (! preg_match('/;/',$arg)) {
@ -1155,8 +1159,8 @@ class Template extends xmlTemplate {
}
list($attr,$string) = preg_split('(([^,]+);(.*))',$arg,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
preg_match_all('/%(\w+)(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?%/U',$string,$matchall);
//print"<PRE>";print_r($matchall); //0 = highlevel match, 1 = attr, 2 = subst, 3 = mod
preg_match_all('/%(\w+)(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U',$string,$matchall);
//print"<PRE>";print_r($matchall); //0 = highlevel match, 1 = attr, 2 = subst, 3 = mod, 4 = delimiter
if (! isset($attribute->js['autoFill']))
$attribute->js['autoFill'] = '';
@ -1183,6 +1187,7 @@ class Template extends xmlTemplate {
$match_attr = strtolower($matchall[1][$index]);
$match_subst = $matchall[2][$index];
$match_mod = $matchall[3][$index];
$match_delim = $matchall[4][$index];
$substrarray = array();
@ -1226,7 +1231,13 @@ class Template extends xmlTemplate {
} else {
$tok_idx = '0';
}
$attribute->js['autoFill'] .= sprintf(" %s = %s.split(' ')[%s];\n",$match_attr,$match_attr,$tok_idx);
if ($match_delim == '') {
$delimiter = ' ';
} else {
$delimiter = preg_quote($match_delim);
}
$attribute->js['autoFill'] .= sprintf(" %s = %s.split('%s')[%s];\n",$match_attr,$match_attr,$delimiter,$tok_idx);
} else {
preg_match_all('/([0-9]*)-([0-9]*)/',trim($match_subst),$substrarray);
@ -1251,13 +1262,13 @@ class Template extends xmlTemplate {
# Matchfor only entry without modifiers.
$formula = preg_replace('/^%('.$match_attr.')%$/U','$1 + \'\'',$formula);
# Matchfor only entry with modifiers.
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?%$/U','$1 + \'\'',$formula);
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','$1 + \'\'',$formula);
# Matchfor begining entry.
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?%/U','$1 + \'',$formula);
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','$1 + \'',$formula);
# Matchfor ending entry.
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?%$/U','\' + $1 ',$formula);
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','\' + $1 ',$formula);
# Match for entries not at begin/end.
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[:lTUA]+)?%/U','\' + $1 + \'',$formula);
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','\' + $1 + \'',$formula);
$attribute->js['autoFill'] .= "\n";
}

View File

@ -139,16 +139,23 @@ class TemplateRender extends PageRender {
return;
}
$function_args = explode(',',$args[0]);
if (function_exists($function))
$vals = call_user_func_array($function,$function_args);
if (!empty($args[0]))
$function_args = explode(',',$args[0]);
else
$function_args = '';
if (function_exists($function)) {
if (empty($function_args))
$vals = call_user_func($function);
else
$vals = call_user_func_array($function,$function_args);
} else {
system_message(array(
'title'=>_('Function doesnt exist'),
'body'=>sprintf('%s (<b>%s</b>)',_('An attempt was made to call a function that doesnt exist'),$function),
'type'=>'warn'));
}
break;
@ -264,6 +271,9 @@ class TemplateRender extends PageRender {
*
* * arg 8 (for MultiList)
* - size of displayed list (default: 10 lines)
*
* * arg 9
* - if whether to include parent in sub query TRUE|FALSE
*/
case 'MultiList':
case 'PickList':
@ -322,6 +332,9 @@ class TemplateRender extends PageRender {
$vals = array();
foreach ($picklistvalues as $key => $values) {
if (! empty($args[9]) && $container == $key)
continue;
$display = $args[3];
foreach ($matchall[1] as $key => $arg) {

View File

@ -8,7 +8,7 @@
*/
/** The minimum version of PHP required to run phpLDAPadmin. */
define('REQUIRED_PHP_VERSION','5.5.0');
define('REQUIRED_PHP_VERSION','7.0.0');
/**
* The config class contains all our configuration settings for a session.
@ -261,6 +261,10 @@ class Config {
'desc'=>'LDAP search filter for the tree entries',
'default'=>'(objectClass=*)');
$this->default->appearance['tree_icons'] = array(
'desc'=>'Number of Tree Icons to display on a row',
'default'=>0);
# PLA will not display the header and footer parts in minimal mode.
$this->default->appearance['minimalMode'] = array(
'desc'=>'Minimal mode hides header and footer parts',
@ -550,6 +554,30 @@ class Config {
'desc'=>'Disable random salt for crypt()',
'default'=>false);
$this->default->password['available_types'] = array(
'desc'=>'List of available password types used for encryption',
'default'=>array(
''=>'clear',
'bcrypt'=>'bcrypt',
'blowfish'=>'blowfish',
'crypt'=>'crypt',
'ext_des'=>'ext_des',
'md5'=>'md5',
'k5key'=>'k5key',
'md5crypt'=>'md5crypt',
'sha'=>'sha',
'smd5'=>'smd5',
'ssha'=>'ssha',
'sha256'=>'sha256',
'ssha256'=>'ssha256',
'sha384'=>'sha384',
'ssha384'=>'ssha384',
'sha512'=>'sha512',
'ssha512'=>'ssha512',
'sha256crypt'=>'sha256crypt',
'sha512crypt'=>'sha512crypt',
));
/** Search display
* By default, when searching you may display a list or a table of results.
* Set this to 'table' to see table formatted results.

View File

@ -139,6 +139,7 @@ abstract class DS {
case 'proxy':
case 'session':
case 'sasl':
case 'sasl_external':
return $this->getValue('login','auth_type');
default:
@ -194,6 +195,8 @@ abstract class DS {
else
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['name']);
case 'sasl_external':
return 'external';
default:
die(sprintf('Error: %s hasnt been configured for auth_type %s',__METHOD__,$this->getAuthType()));
}
@ -215,6 +218,7 @@ abstract class DS {
return true;
case 'config':
case 'sasl_external':
return true;
case 'proxy':
@ -274,6 +278,8 @@ abstract class DS {
else
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['pass']);
case 'sasl_external':
return '';
default:
die(sprintf('Error: %s hasnt been configured for auth_type %s',__METHOD__,$this->getAuthType()));
}
@ -400,6 +406,7 @@ abstract class DS {
set_cookie($method.'-PASS','',time()-3600,'/');
case 'config':
case 'sasl_external':
return true;
case 'http':

View File

@ -54,6 +54,22 @@ class ldap extends DS {
'desc'=>'Connect using TLS',
'default'=>false);
$this->default->server['tls_cacert'] = array(
'desc'=>'TLS Certificate Authority',
'default'=>null);
$this->default->server['tls_cacertdir'] = array(
'desc'=>'TLS Certificate Authority Directory',
'default'=>null);
$this->default->server['tls_cert'] = array(
'desc'=>'TLS Client Certificate',
'default'=>null);
$this->default->server['tls_key'] = array(
'desc'=>'TLS Client Certificate Key',
'default'=>null);
# Login Details
$this->default->login['attr'] = array(
'desc'=>'Attribute to use to find the users DN',
@ -110,6 +126,35 @@ class ldap extends DS {
'default'=>null);
}
/**
* Set LDAP option with error checking...
*
* @param resource Connection resource
* @param string Name of option to set
* @param mixed Option value
* @return boolean false if error
*/
private function setLdapOption($resource, $option, $value) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',16,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (! defined($option)) {
system_message(array(
'title'=>sprintf('%s',_('Undefined LDAP option')),
'body'=>sprintf('<b>%s</b>: %s <b>%s</b>',_('Error'),_('Required LDAP option not defined'),$option),
'type'=>'error'));
return false;
}
if (! @ldap_set_option($resource,constant($option),$value)) {
system_message(array(
'title'=>sprintf('%s',_('Failed to set LDAP option')),
'body'=>sprintf('<b>%s</b>: %s <b>%s</b>',_('Error'),_('Failed to set LDAP option'),$option),
'type'=>'error'));
return false;
}
return true;
}
/**
* Required ABSTRACT functions
*/
@ -164,6 +209,7 @@ class ldap extends DS {
else
$resource = ldap_connect($this->getValue('server','host'));
$this->noconnect = false;
$CACHE[$this->index][$method] = $resource;
if (DEBUG_ENABLED)
@ -174,12 +220,14 @@ class ldap extends DS {
debug_dump_backtrace('UNHANDLED, $resource is not a resource',1);
# Go with LDAP version 3 if possible (needed for renaming and Novell schema fetching)
ldap_set_option($resource,LDAP_OPT_PROTOCOL_VERSION,3);
if (! $this->setLdapOption($resource,'LDAP_OPT_PROTOCOL_VERSION',3))
$this->noconnect = true;
/* Disabling this makes it possible to browse the tree for Active Directory, and seems
* to not affect other LDAP servers (tested with OpenLDAP) as phpLDAPadmin explicitly
* specifies deref behavior for each ldap_search operation. */
ldap_set_option($resource,LDAP_OPT_REFERRALS,0);
elseif (! $this->setLdapOption($resource,'LDAP_OPT_REFERRALS',0))
$this->noconnect = true;
/* Enabling manageDsaIt to be able to browse through glued entries
* 2.16.840.1.113730.3.4.2 : "ManageDsaIT Control" "RFC 3296" "The client may provide
@ -187,14 +235,18 @@ class ldap extends DS {
* to manage objects within the DSA (server) Information Tree. The control causes
* Directory-specific entries (DSEs), regardless of type, to be treated as normal entries
* allowing clients to interrogate and update these entries using LDAP operations." */
ldap_set_option($resource,LDAP_OPT_SERVER_CONTROLS,array(array('oid'=>'2.16.840.1.113730.3.4.2')));
elseif (! $this->setLdapOption($resource,'LDAP_OPT_SERVER_CONTROLS',array(array('oid'=>'2.16.840.1.113730.3.4.2'))))
$this->noconnect = true;
# Try to fire up TLS is specified in the config
if ($this->isTLSEnabled())
$this->startTLS($resource);
if ($this->isTLSEnabled() && !$this->noconnect)
if(! $this->startTLS($resource))
$this->noconnect = true;
# If SASL has been configured for binding, then start it now.
if ($this->isSASLEnabled())
if ($this->noconnect)
$bind['result'] = false;
elseif ($this->isSASLEnabled())
$bind['result'] = $this->startSASL($resource,$method,$bind['id'],$bind['pass']);
# Normal bind...
@ -211,17 +263,16 @@ class ldap extends DS {
if (DEBUG_ENABLED)
debug_log('Leaving with FALSE, bind FAILed',16,0,__FILE__,__LINE__,__METHOD__);
$this->noconnect = true;
system_message(array(
'title'=>sprintf('%s %s',_('Unable to connect to LDAP server'),$this->getName()),
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
'type'=>'error'));
if (! $this->noconnect) {
$this->noconnect = true;
system_message(array(
'title'=>sprintf('%s %s',_('Unable to connect to LDAP server'),$this->getName()),
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
'type'=>'error'));
}
$CACHE[$this->index][$method] = null;
} else {
$this->noconnect = false;
# If this is a proxy session, we need to switch to the proxy user
if ($this->isProxyEnabled() && $bind['id'] && $method != 'anon')
@ -570,10 +621,41 @@ class ldap extends DS {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (! $this->getValue('server','tls') || (function_exists('ldap_start_tls') && ! @ldap_start_tls($resource))) {
// LDAP_OPT_X_TLS_ options must be set globally ($res = null)
// until LDAP_OPT_X_TLS_NEWCTX is exported,
// NOTE: new values will require php-fpm or other stateful
// php servers to be restarted, and are global for all php
// users in the process pool!
$val = $this->getValue('server','tls_cacert');
if (! empty($val))
if (! $this->setLdapOption(null, 'LDAP_OPT_X_TLS_CACERTFILE', $val))
return false;
$val = $this->getValue('server','tls_cacertdir');
if (! empty($val))
if (! $this->setLdapOption(null, 'LDAP_OPT_X_TLS_CACERTDIR', $val))
return false;
$val = $this->getValue('server','tls_cert');
if (! empty($val))
if (! $this->setLdapOption(null, 'LDAP_OPT_X_TLS_CERTFILE', $val))
return false;
$val = $this->getValue('server','tls_key');
if (! empty($val))
if (! $this->setLdapOption(null, 'LDAP_OPT_X_TLS_KEYFILE', $val))
return false;
if (! @ldap_start_tls($resource)) {
$diag_error='';
ldap_get_option($resource, LDAP_OPT_DIAGNOSTIC_MESSAGE, $diag_error);
if (! empty($diag_error)) {
$diag_error = '<br>'.$diag_error;
}
$error = ldap_error($resource);
system_message(array(
'title'=>sprintf('%s (%s)',_('Could not start TLS.'),$this->getName()),
'body'=>sprintf('<b>%s</b>: %s',_('Error'),_('Could not start TLS. Please check your LDAP server configuration.')),
'body'=>sprintf('<b>%s</b>: %s %s%s',_('Error'),_('Could not start TLS.'),$error,$diag_error),
'type'=>'error'));
return false;
@ -590,6 +672,8 @@ class ldap extends DS {
* $servers->setValue('login','auth_type','sasl');
* OR
* $servers->setValue('sasl','mech','PLAIN');
* OR
* $servers->setValue('login','auth_type','sasl_external');
* </code>
*
* @return boolean
@ -598,7 +682,7 @@ class ldap extends DS {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (! in_array($this->getValue('login','auth_type'), array('sasl'))) {
if (! in_array($this->getValue('login','auth_type'), array('sasl','sasl_external'))) {
// check if SASL mech uses login from other auth_types
if (! in_array(strtolower($this->getValue('sasl', 'mech')), array('plain')))
return false;
@ -630,6 +714,13 @@ class ldap extends DS {
if ($method == 'anon')
return false;
# EXTERNAL mech is really a different authType
if ($this->getAuthType() == 'sasl_external') {
return @ldap_sasl_bind($resource,NULL,NULL,
'EXTERNAL',NULL,NULL,
$this->getValue('sasl','props'));
}
# At the moment, we have only implemented GSSAPI and PLAIN
if (! in_array(strtolower($this->getValue('sasl','mech')),array('gssapi','plain'))) {
system_message(array(
@ -783,7 +874,7 @@ class ldap extends DS {
'value'=>sprintf('dn:%s',$dn),
'iscritical' => true);
if (! ldap_set_option($resource,LDAP_OPT_SERVER_CONTROLS,array($ctrl))) {
if (! @ldap_set_option($resource,LDAP_OPT_SERVER_CONTROLS,array($ctrl))) {
system_message(array(
'title'=>sprintf('%s %s',_('Unable to start proxy connection'),$this->getName()),
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
@ -939,7 +1030,7 @@ class ldap extends DS {
$dn = $this->getContainer($dn);
if ($dn == $top)
break;
continue;
} elseif($value)
$dn = sprintf('%s,%s',$value,$dn);
@ -1146,12 +1237,12 @@ class ldap extends DS {
if (is_array($dn)) {
$a = array();
foreach ($dn as $key => $rdn) {
$a[$key] = preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', function($m) { return chr(hexdec('${m[1]}')); }, $rdn);
$a[$key] = preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', function($m) { return chr(hexdec($m[1])); }, $rdn);
}
return $a;
} else {
return preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', function($m) { return chr(hexdec('${m[1]}')); }, $dn);
return preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', function($m) { return chr(hexdec($m[1])); }, $dn);
}
}

View File

@ -599,10 +599,16 @@ class ldap_pla extends ldap {
# Build our search filter to double check each attribute.
$query['filter'] = '(|';
foreach ($checkattrs as $attr)
foreach ($checkattrs as $attr) {
if (!is_array($attrs[$attr])) {
$val = $attrs[$attr];
$query['filter'] .= sprintf('(%s=%s)',$attr,$val);
continue;
}
foreach ($attrs[$attr] as $val)
if ($val)
$query['filter'] .= sprintf('(%s=%s)',$attr,$val);
}
$query['filter'] .= ')';
$query['attrs'] = $checkattrs;

View File

@ -687,16 +687,16 @@ function get_request($attr,$type='POST',$die=false,$default=null,$preventXSS=tru
* Return valor escape XSS.
*/
function preventXSS($data){
if (gettype($data) == 'array') {
foreach ($data as $key => $value) {
if (gettype($value) == 'array')
$data[$key] = preventXSS($value);
else
$data[$key] = htmlspecialchars($value);
}
return $data;
}
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
if (gettype($data) == 'array') {
foreach ($data as $key => $value) {
if (gettype($value) == 'array')
$data[$key] = preventXSS($value);
else
$data[$key] = htmlspecialchars($value);
}
return $data;
}
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
/*
@ -1298,29 +1298,29 @@ function is_url_string($str) {
/**
* Compares 2 DNs. If they are equivelant, returns 0, otherwise,
* returns their sorting order (similar to strcmp()):
* Returns < 0 if dn1 is less than dn2.
* Returns > 0 if dn1 is greater than dn2.
* Returns < 0 if dn1 is less than dn2.
* Returns > 0 if dn1 is greater than dn2.
*
* The comparison is performed starting with the top-most element
* of the DN. Thus, the following list:
* <code>
* ou=people,dc=example,dc=com
* cn=Admin,ou=People,dc=example,dc=com
* cn=Joe,ou=people,dc=example,dc=com
* dc=example,dc=com
* cn=Fred,ou=people,dc=example,dc=org
* cn=Dave,ou=people,dc=example,dc=org
* </code>
* <code>
* ou=people,dc=example,dc=com
* cn=Admin,ou=People,dc=example,dc=com
* cn=Joe,ou=people,dc=example,dc=com
* dc=example,dc=com
* cn=Fred,ou=people,dc=example,dc=org
* cn=Dave,ou=people,dc=example,dc=org
* </code>
* Will be sorted thus using usort( $list, "pla_compare_dns" ):
* <code>
* dc=com
* dc=example,dc=com
* ou=people,dc=example,dc=com
* cn=Admin,ou=People,dc=example,dc=com
* cn=Joe,ou=people,dc=example,dc=com
* cn=Dave,ou=people,dc=example,dc=org
* cn=Fred,ou=people,dc=example,dc=org
* </code>
* <code>
* dc=com
* dc=example,dc=com
* ou=people,dc=example,dc=com
* cn=Admin,ou=People,dc=example,dc=com
* cn=Joe,ou=people,dc=example,dc=com
* cn=Dave,ou=people,dc=example,dc=org
* cn=Fred,ou=people,dc=example,dc=org
* </code>
*
* @param string The first of two DNs to compare
* @param string The second of two DNs to compare
@ -1828,15 +1828,9 @@ function random_salt($length) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
$possible = '0123456789'.
'abcdefghijklmnopqrstuvwxyz'.
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
'./';
$str = '';
mt_srand((double)microtime() * 1000000);
while (strlen($str) < $length)
$str .= substr($possible,(rand()%strlen($possible)),1);
$str = bin2hex(random_bytes(ceil($length/2)));
if ($length % 2 == 1)
return substr($str, 0, -1);
return $str;
}
@ -2154,22 +2148,7 @@ function password_types() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
return array(
''=>'clear',
'bcrypt'=>'bcrypt',
'blowfish'=>'blowfish',
'crypt'=>'crypt',
'ext_des'=>'ext_des',
'md5'=>'md5',
'k5key'=>'k5key',
'md5crypt'=>'md5crypt',
'sha'=>'sha',
'smd5'=>'smd5',
'ssha'=>'ssha',
'sha512'=>'sha512',
'sha256crypt'=>'sha256crypt',
'sha512crypt'=>'sha512crypt',
);
return $_SESSION[APPCONFIG]->getValue('password', 'available_types');
}
/**
@ -2225,7 +2204,7 @@ function pla_password_hash($password_clear,$enc_type) {
break;
case 'md5':
$new_value = sprintf('{MD5}%s',base64_encode(pack('H*',md5($password_clear))));
$new_value = sprintf('{MD5}%s',base64_encode(md5($password_clear, true)));
break;
case 'md5crypt':
@ -2237,60 +2216,65 @@ function pla_password_hash($password_clear,$enc_type) {
break;
case 'sha':
# Use php 4.3.0+ sha1 function, if it is available.
if (function_exists('sha1'))
$new_value = sprintf('{SHA}%s',base64_encode(pack('H*',sha1($password_clear))));
elseif (function_exists('mhash'))
$new_value = sprintf('{SHA}%s',base64_encode(mhash(MHASH_SHA1,$password_clear)));
else
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
$new_value = sprintf('{SHA}%s',base64_encode(sha1($password_clear, true)));
break;
case 'ssha':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double)microtime()*1000000);
$salt = mhash_keygen_s2k(MHASH_SHA1,$password_clear,substr(pack('h*',md5(mt_rand())),0,8),4);
$new_value = sprintf('{SSHA}%s',base64_encode(mhash(MHASH_SHA1,$password_clear.$salt).$salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'),'error','index.php');
}
$salt = hex2bin(random_salt(8));
$new_value = sprintf('{SSHA}%s',base64_encode(sha1($password_clear.$salt, true).$salt));
break;
case 'bcrypt':
$options = [
'cost' => 8,
];
#Checking if password_hash() function is available.
if (function_exists('password_hash'))
$new_value = sprintf('{BCRYPT}%s',base64_encode(password_hash($password_clear, PASSWORD_BCRYPT, $options)));
else
error(_('Your PHP install does not have the password_hash() function. Cannot do BCRYPT hashes.'),'error','index.php');
case 'bcrypt':
$options = [
'cost' => 8,
];
#Checking if password_hash() function is available.
if (function_exists('password_hash'))
$new_value = sprintf('{BCRYPT}%s',base64_encode(password_hash($password_clear, PASSWORD_BCRYPT, $options)));
else
error(_('Your PHP install does not have the password_hash() function. Cannot do BCRYPT hashes.'),'error','index.php');
break;
break;
case 'smd5':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double)microtime()*1000000);
$salt = mhash_keygen_s2k(MHASH_MD5,$password_clear,substr(pack('h*',md5(mt_rand())),0,8),4);
$new_value = sprintf('{SMD5}%s',base64_encode(mhash(MHASH_MD5,$password_clear.$salt).$salt));
$salt = hex2bin(random_salt(8));
$new_value = sprintf('{SMD5}%s',base64_encode(md5($password_clear.$salt, true).$salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'),'error','index.php');
}
break;
case 'sha256':
$new_value = sprintf('{SHA256}%s', base64_encode(hash('sha256', $password_clear, true)));
break;
case 'ssha256':
$salt = hex2bin(random_salt(8));
$new_value = sprintf('{SSHA256}%s', base64_encode(hash('sha256', $password_clear.$salt, true).$salt));
break;
case 'sha384':
$new_value = sprintf('{SHA384}%s', base64_encode(hash('sha384', $password_clear, true)));
break;
case 'ssha384':
$salt = hex2bin(random_salt(8));
$new_value = sprintf('{SSHA384}%s', base64_encode(hash('sha384', $password_clear.$salt, true).$salt));
break;
case 'sha512':
if (function_exists('openssl_digest') && function_exists('base64_encode')) {
$new_value = sprintf('{SHA512}%s', base64_encode(openssl_digest($password_clear, 'sha512', true)));
$new_value = sprintf('{SHA512}%s', base64_encode(hash('sha512', $password_clear, true)));
} else {
error(_('Your PHP install doest not have the openssl_digest() or base64_encode() function. Cannot do SHA512 hashes. '),'error','index.php');
}
break;
case 'ssha512':
$salt = hex2bin(random_salt(8));
$new_value = sprintf('{SSHA512}%s', base64_encode(hash('sha512', $password_clear.$salt, true).$salt));
break;
@ -2325,7 +2309,7 @@ function pla_password_hash($password_clear,$enc_type) {
* @return Boolean True if the clear password matches the hash, and false otherwise.
*/
function password_check($cryptedpassword,$plainpassword,$attribute='userpassword') {
$plainpassword = htmlspecialchars_decode($plainpassword);
$plainpassword = htmlspecialchars_decode($plainpassword);
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -2360,58 +2344,46 @@ function password_check($cryptedpassword,$plainpassword,$attribute='userpassword
switch($cypher) {
# SSHA crypted passwords
case 'ssha':
# Check php mhash support before using it
if (function_exists('mhash')) {
$hash = base64_decode($cryptedpassword);
$hash = base64_decode($cryptedpassword);
# OpenLDAP uses a 4 byte salt, SunDS uses an 8 byte salt - both from char 20.
$salt = substr($hash,20);
$new_hash = base64_encode(mhash(MHASH_SHA1,$plainpassword.$salt).$salt);
# OpenLDAP uses a 4 byte salt, SunDS uses an 8 byte salt - both from char 20.
$salt = substr($hash,20);
$new_hash = base64_encode(sha1($plainpassword.$salt, true).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
} else {
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
}
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
break;
#BCRYPT hashed passwords
case 'bcrypt':
# Check php password_verify support before using it
if (function_exists('password_verify')) {
$hash = base64_decode($cryptedpassword);
if (password_verify($plainpassword, $hash)) {
return true;
} else {
return false;
}
#BCRYPT hashed passwords
case 'bcrypt':
# Check php password_verify support before using it
if (function_exists('password_verify')) {
$hash = base64_decode($cryptedpassword);
if (password_verify($plainpassword, $hash)) {
return true;
} else {
return false;
}
} else {
error(_('Your PHP install does not have the password_verify() function. Cannot do Bcrypt hashes.'),'error','index.php');
}
} else {
error(_('Your PHP install does not have the password_verify() function. Cannot do Bcrypt hashes.'),'error','index.php');
}
break;
break;
# Salted MD5
case 'smd5':
# Check php mhash support before using it
if (function_exists('mhash')) {
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,16);
$new_hash = base64_encode(mhash(MHASH_MD5,$plainpassword.$salt).$salt);
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,16);
$new_hash = base64_encode(md5($plainpassword.$salt).$salt, true);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
} else {
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
}
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
break;
@ -2489,6 +2461,50 @@ function password_check($cryptedpassword,$plainpassword,$attribute='userpassword
break;
# SHA256 crypted passwords
case 'sha256':
if (strcasecmp(pla_password_hash($plainpassword,'sha256'),'{SHA256}'.$cryptedpassword) == 0)
return true;
else
return false;
break;
# Salted SHA256 crypted passwords
case 'ssha256':
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,64);
$new_hash = base64_encode(hash('sha256', $plainpassword.$salt, true).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
break;
# SHA384 crypted passwords
case 'sha384':
if (strcasecmp(pla_password_hash($plainpassword,'sha384'),'{SHA384}'.$cryptedpassword) == 0)
return true;
else
return false;
break;
# Salted SHA384 crypted passwords
case 'ssha384':
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,64);
$new_hash = base64_encode(hash('sha384', $plainpassword.$salt, true).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
break;
# SHA512 crypted passwords
case 'sha512':
if (strcasecmp(pla_password_hash($plainpassword,'sha512'),'{SHA512}'.$cryptedpassword) == 0)
@ -2498,6 +2514,19 @@ function password_check($cryptedpassword,$plainpassword,$attribute='userpassword
break;
# Salted SHA512 crypted passwords
case 'ssha512':
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,64);
$new_hash = base64_encode(hash('sha512', $plainpassword.$salt, true).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
break;
# No crypt is given assume plaintext passwords are used
default:
if ($plainpassword == $cryptedpassword)
@ -3262,7 +3291,7 @@ function IsRobot($gResponse){
$options = array(
'http' => array (
'method' => 'POST','header' =>
'Content-Type: application/x-www-form-urlencoded',
'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($data)
)
);