4395 lines
135 KiB
PHP
4395 lines
135 KiB
PHP
<?php
|
|
// $Header: /cvsroot/phpldapadmin/phpldapadmin/lib/functions.php,v 1.275.2.19 2005/11/27 06:59:24 wurley Exp $
|
|
|
|
/**
|
|
* A collection of functions used throughout phpLDAPadmin.
|
|
* @author The phpLDAPadmin development team
|
|
* @package phpLDAPadmin
|
|
*/
|
|
|
|
define('HTDOCDIR',sprintf('%s/',realpath(LIBDIR.'../htdocs/')));
|
|
define('LANGDIR',sprintf('%s/',realpath(LIBDIR.'../lang/')));
|
|
define('CONFDIR',sprintf('%s/',realpath(LIBDIR.'../config')));
|
|
define('TMPLDIR',sprintf('%s/',realpath(LIBDIR.'../templates/')));
|
|
define('DOCDIR',sprintf('%s/',realpath(LIBDIR.'../doc/')));
|
|
define('CSSDIR','css/');
|
|
define('JSDIR','js/');
|
|
|
|
/* Supplimental functions
|
|
* This list is a list of supplimental functions that are used throughout PLA. The
|
|
* order here IS important - so that files that refer to functions defined in other files
|
|
* need to be listed after those files.*/
|
|
$pla_function_files = array(
|
|
# Functions for talking to LDAP servers.
|
|
LIBDIR.'server_functions.php',
|
|
# Functions for sending syslog messages
|
|
LIBDIR.'syslog.php',
|
|
# The base English language strings
|
|
LANGDIR.'recoded/en.php',
|
|
# Functions for managing the session (pla_session_start(), etc.)
|
|
LIBDIR.'session_functions.php',
|
|
# Functions for reading the server schema
|
|
LIBDIR.'schema_functions.php',
|
|
# Functions that can be defined by the user (preEntryDelete(), postEntryDelete(), etc.)
|
|
LIBDIR.'custom_functions.php',
|
|
# Functions for template manipulation.
|
|
LIBDIR.'template_functions.php',
|
|
# Functions for hashing passwords with OpenSSL binary (only if mhash not present)
|
|
LIBDIR.'emuhash_functions.php',
|
|
# Functions for running various hooks
|
|
LIBDIR.'hooks.php',
|
|
# Functions for creating Samba passwords
|
|
LIBDIR.'createlm.php',
|
|
# Functions for timeout and automatic logout feature
|
|
LIBDIR.'timeout_functions.php'
|
|
);
|
|
|
|
/**
|
|
* Determines if an attribute's value can contain multiple lines. Attributes that fall
|
|
* in this multi-line category may be configured in config.php. Hence, this function
|
|
* accesses the global variable $config->custom->appearance['multi_line_attributes'];
|
|
*
|
|
* Usage example:
|
|
* <code>
|
|
* if( is_muli_line_attr( "postalAddress" ) )
|
|
* echo "<textarea name=\"postalAddress\"></textarea>";
|
|
* else
|
|
* echo "<input name=\"postalAddress\" type=\"text\">";
|
|
* </code>
|
|
*
|
|
* @param string $attr_name The name of the attribute of interestd (case insensivite)
|
|
* @param string $val (optional) The current value of the attribute (speeds up the
|
|
* process by searching for carriage returns already in the attribute value)
|
|
* @param int $server_id (optional) The ID of the server of interest. If specified,
|
|
* is_multi_line_attr() will read the schema from the server to determine if
|
|
* the attr is multi-line capable. (note that schema reads can be expensive,
|
|
* but that impact is lessened due to PLA's new caching mechanism)
|
|
* @return bool
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_multi_line_attr( $attr_name, $val=null, $server_id=null ) {
|
|
global $config, $ldapservers;
|
|
|
|
$multi_line_attributes = $config->GetValue('appearance','multi_line_attributes');
|
|
$multi_line_syntax_oids = $config->GetValue('appearance','multi_line_syntax_oids');
|
|
|
|
# Set default return
|
|
$return = false;
|
|
|
|
// First, check the optional val param for a \n or a \r
|
|
if (! is_null($val) && (false !== strpos($val,"\n") || false !== strpos($val,"\r")))
|
|
$return = true;
|
|
|
|
// Next, compare strictly by name first
|
|
else
|
|
foreach ($multi_line_attributes as $multi_line_attr_name)
|
|
if (strcasecmp($multi_line_attr_name,$attr_name) == 0) {
|
|
$return = true;
|
|
break;
|
|
}
|
|
|
|
// If unfound, compare by syntax OID
|
|
if (! $return && ! is_null($server_id)) {
|
|
$ldapserver = $ldapservers->Instance($server_id);
|
|
|
|
$schema_attr = $ldapserver->getSchemaAttribute($attr_name);
|
|
if ($schema_attr) {
|
|
$syntax_oid = $schema_attr->getSyntaxOID();
|
|
|
|
if ($syntax_oid)
|
|
foreach($multi_line_syntax_oids as $multi_line_syntax_oid)
|
|
if ($multi_line_syntax_oid == $syntax_oid) {
|
|
$return = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_multi_line_attr(): Entered with (%s,%s,%s), Returning (%s)',1,$attr_name,$val,$server_id,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Fetches the user setting for $view_deref from config.php. The returned value
|
|
* will be one of the four LDAP_DEREF_* constancts defined by the PHP LDAP API. If
|
|
* the user has failed to configure this setting or configured an inappropriate
|
|
* value, the constant DEFAULT_VIEW_DEREF_SETTING is returned.
|
|
*
|
|
* @return int
|
|
* @deprecated
|
|
*/
|
|
function get_view_deref_setting() {
|
|
global $config;
|
|
return $config->GetValue('deref','view');
|
|
}
|
|
|
|
/**
|
|
* Fetches whether the user has configured phpLDAPadmin to obfuscate passwords
|
|
* with "*********" when displaying them.
|
|
*
|
|
* This is configured in config.php thus:
|
|
* <code>
|
|
* $obfuscate_password_display = true;
|
|
* </code>
|
|
*
|
|
* @param string $enc Password encoding type
|
|
* @return bool
|
|
*/
|
|
function obfuscate_password_display($enc=null) {
|
|
global $config;
|
|
|
|
if ($config->GetValue('appearance','obfuscate_password_display'))
|
|
$return = true;
|
|
|
|
elseif (! $config->GetValue('appearance','show_clear_password') && (is_null($enc) || $enc == 'clear'))
|
|
$return = true;
|
|
|
|
else
|
|
$return = false;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('obfuscate_password_display(): Entered with (%s), Returning (%s)',1,$enc,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Returns an HTML-beautified version of a DN.
|
|
* Internally, this function makes use of pla_explode_dn() to break the
|
|
* the DN into its components. It then glues them back together with
|
|
* "pretty" HTML. The returned HTML is NOT to be used as a real DN, but
|
|
* simply displayed.
|
|
*
|
|
* @param string $dn The DN to pretty-print.
|
|
* @return string
|
|
*/
|
|
function pretty_print_dn( $dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pretty_print_dn(): Entered with (%s)',2,$dn);
|
|
|
|
$dn = pla_explode_dn( $dn );
|
|
foreach( $dn as $i => $element ) {
|
|
$element = htmlspecialchars($element);
|
|
$element = explode('=',$element,2);
|
|
$element = implode('<span style="color: blue; font-family: courier; font-weight: bold">=</span>',$element);
|
|
$dn[$i] = $element;
|
|
}
|
|
$dn = implode('<span style="color:red; font-family:courier; font-weight: bold;">,</span>',$dn);
|
|
|
|
return $dn;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the attribute specified is required to take as input a DN.
|
|
* Some examples include 'distinguishedName', 'member' and 'uniqueMember'.
|
|
* @param int $server_id The ID of the server of interest
|
|
* (required since this operation demands a schema lookup)
|
|
* @param string $attr_name The name of the attribute of interest (case insensitive)
|
|
* @return bool
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_dn_attr( $ldapserver, $attr_name ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_dn_attr(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr_name);
|
|
|
|
// Simple test first
|
|
$dn_attrs = array( "aliasedObjectName" );
|
|
foreach( $dn_attrs as $dn_attr )
|
|
if( 0 == strcasecmp( $attr_name, $dn_attr ) )
|
|
return true;
|
|
|
|
// Now look at the schema OID
|
|
$attr_schema = $ldapserver->getSchemaAttribute($attr_name);
|
|
if( ! $attr_schema )
|
|
return false;
|
|
|
|
$syntax_oid = $attr_schema->getSyntaxOID();
|
|
if( '1.3.6.1.4.1.1466.115.121.1.12' == $syntax_oid )
|
|
return true;
|
|
if( '1.3.6.1.4.1.1466.115.121.1.34' == $syntax_oid )
|
|
return true;
|
|
|
|
$syntaxes = $ldapserver->SchemaSyntaxes();
|
|
if (! isset($syntaxes[$syntax_oid]))
|
|
return false;
|
|
|
|
$syntax_desc = $syntaxes[ $syntax_oid ]->getDescription();
|
|
if( false !== strpos( strtolower($syntax_desc), 'distinguished name' ) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Given a string, this function returns true if the string has the format
|
|
* of a DN (ie, looks like "cn=Foo,dc=example,dc=com"). Returns false otherwise.
|
|
* The purpose of this function is so that developers can examine a string and
|
|
* know if it looks like a DN, and draw a hyperlink as needed.
|
|
*
|
|
* (See unit_test.php for test cases)
|
|
*
|
|
* @param string $attr The attribute to examine for "DNness"
|
|
* @see unit_test.php
|
|
* @return bool
|
|
*/
|
|
function is_dn_string($str) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_dn_string(): Entered with (%s)',2,$str);
|
|
|
|
/* Try to break the string into its component parts if it can be done
|
|
ie, "uid=Manager" "dc=example" and "dc=com" */
|
|
$parts = pla_explode_dn($str);
|
|
if (! is_array($parts) || ! count($parts))
|
|
return false;
|
|
|
|
/* Foreach of the "parts", look for an "=" character,
|
|
and make sure neither the left nor the right is empty */
|
|
foreach ($parts as $part) {
|
|
if (! strpos($part,"="))
|
|
return false;
|
|
|
|
$sub_parts = explode("=",$part,2);
|
|
$left = $sub_parts[0];
|
|
$right = $sub_parts[1];
|
|
|
|
if ( ! strlen(trim($left)) || ! strlen(trim($right)))
|
|
return false;
|
|
|
|
if (strpos($left,'#') !== false)
|
|
return false;
|
|
}
|
|
|
|
# We survived the above rigor. This is a bonified DN string.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get whether a string looks like an email address (user@example.com).
|
|
*
|
|
* @param string $str The string to analyze.
|
|
* @return bool Returns true if the specified string looks like
|
|
* an email address or false otherwise.
|
|
*/
|
|
function is_mail_string($str) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_mail_string(): Entered with (%s)',2,$str);
|
|
|
|
$mail_regex = "/^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*$/";
|
|
|
|
if (preg_match($mail_regex,$str))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get whether a string looks like a web URL (http://www.example.com/)
|
|
*
|
|
* @param string $str The string to analyze.
|
|
* @return bool Returns true if the specified string looks like
|
|
* a web URL or false otherwise.
|
|
*/
|
|
function is_url_string($str) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_url_string(): Entered with (%s)',2,$str);
|
|
|
|
$url_regex = '/(ftp|https?):\/\/+[\w\.\-\/\?\=\&]*\w+/';
|
|
|
|
if (preg_match($url_regex,$str))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Utility wrapper for setting cookies, which takes into consideration
|
|
* phpLDAPadmin configuration values. On success, true is returned. On
|
|
* failure, false is returned.
|
|
*
|
|
* @param string $name The name of the cookie to set.
|
|
* @param string $val The value of the cookie to set.
|
|
* @param int $expire (optional) The duration in seconds of this cookie. If unspecified, $cookie_time
|
|
* is used from config.php
|
|
* @param string $dir (optional) The directory value of this cookie (see php.net/setcookie)
|
|
*
|
|
* @see setcookie
|
|
* @return bool
|
|
*/
|
|
function pla_set_cookie( $name, $val, $expire=null, $dir=null ) {
|
|
global $config;
|
|
|
|
# Set default return
|
|
$return = false;
|
|
|
|
if ($expire == null) {
|
|
$cookie_time = $config->GetValue('session','cookie_time');
|
|
$expire = $cookie_time == 0 ? null : time() + $cookie_time;
|
|
}
|
|
|
|
if ($dir == null)
|
|
$dir = dirname( $_SERVER['PHP_SELF'] );
|
|
|
|
if (@setcookie($name,$val,$expire,$dir)) {
|
|
$_COOKIE[$name] = $val;
|
|
$return = true;
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_set_cookie(): Entered with (%s,%s,%s,%s), Returning (%s)',1,$name,$val,$expire,$dir,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Responsible for setting two cookies/session-vars to indicate that a user has logged in,
|
|
* one for the logged in DN and one for the logged in password.
|
|
*
|
|
* This function is only used if 'auth_type' is set to 'cookie' or 'session'. The values
|
|
* written have the name "pla_login_dn_X" and "pla_login_pass_X" where X is the
|
|
* ID of the server to which the user is attempting login.
|
|
*
|
|
* Note that as with all cookie/session operations this function must be called BEFORE
|
|
* any output is sent to the browser.
|
|
*
|
|
* On success, true is returned. On failure, false is returned.
|
|
*
|
|
* @param object $ldapserver The LDAPServer object of the server which the user hsa logged in.
|
|
* @param string $dn The DN with which the user has logged in.
|
|
* @param string $password The password of the user logged in.
|
|
* @param bool $anon_bind Indicates that this is an anonymous bind such that
|
|
* a password of "0" is stored.
|
|
* @return bool
|
|
* @see unset_login_dn
|
|
*/
|
|
function set_login_dn($ldapserver,$dn,$password,$anon_bind) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('set_login_dn(): Entered with (%s,%s,%s,%s)',2,$ldapserver->server_id,$dn,$password,$anon_bind);
|
|
|
|
if (! $ldapserver->auth_type)
|
|
return false;
|
|
|
|
switch ($ldapserver->auth_type) {
|
|
case 'cookie':
|
|
$cookie_dn_name = sprintf("pla_login_dn_%s",$ldapserver->server_id);
|
|
$cookie_pass_name = sprintf("pla_login_pass_%s",$ldapserver->server_id);
|
|
|
|
# we set the cookie password to 0 for anonymous binds.
|
|
if ($anon_bind) {
|
|
$dn = 'anonymous';
|
|
$password = '0';
|
|
}
|
|
|
|
$res1 = pla_set_cookie($cookie_dn_name,pla_blowfish_encrypt($dn));
|
|
$res2 = pla_set_cookie($cookie_pass_name,pla_blowfish_encrypt($password));
|
|
if ($res1 && $res2)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
break;
|
|
|
|
case 'session':
|
|
$sess_var_dn_name = sprintf("pla_login_dn_%s",$ldapserver->server_id);
|
|
$sess_var_pass_name = sprintf("pla_login_pass_%s",$ldapserver->server_id);
|
|
|
|
# we set the cookie password to 0 for anonymous binds.
|
|
if ($anon_bind) {
|
|
$dn = 'anonymous';
|
|
$password = '0';
|
|
}
|
|
|
|
$_SESSION[$sess_var_dn_name] = pla_blowfish_encrypt($dn);
|
|
$_SESSION[$sess_var_pass_name] = pla_blowfish_encrypt($password);
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
global $lang;
|
|
pla_error(sprintf($lang['unknown_auth_type'],htmlspecialchars($ldapserver->auth_type)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log a user out of the LDAP server.
|
|
*
|
|
* Removes the cookies/session-vars set by set_login_dn()
|
|
* after a user logs out using "auth_type" of "session" or "cookie".
|
|
* Returns true on success, false on failure.
|
|
*
|
|
* @param object $ldapserver The LDAPServer object of the server which the user hsa logged in.
|
|
* @return bool True on success, false on failure.
|
|
* @see set_login_dn
|
|
*/
|
|
function unset_login_dn( $ldapserver ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('unset_login_dn(): Entered with (%s)',2,$ldapserver->server_id);
|
|
|
|
if (! $ldapserver->auth_type)
|
|
return false;
|
|
|
|
switch ($ldapserver->auth_type) {
|
|
case 'cookie':
|
|
$logged_in_dn = get_logged_in_dn($ldapserver);
|
|
if (! $logged_in_dn)
|
|
return false;
|
|
|
|
$logged_in_pass = get_logged_in_pass($ldapserver);
|
|
$anon_bind = $logged_in_dn == 'anonymous' ? true : false;
|
|
|
|
# set cookie with expire time already passed to erase cookie from client
|
|
$expire = time()-3600;
|
|
$cookie_dn_name = sprintf("pla_login_dn_%s",$ldapserver->server_id);
|
|
$cookie_pass_name = sprintf("pla_login_pass_%s",$ldapserver->server_id);
|
|
|
|
if ($anon_bind) {
|
|
$res1 = pla_set_cookie($cookie_dn_name,'anonymous',$expire);
|
|
$res2 = pla_set_cookie($cookie_pass_name,'0',$expire);
|
|
|
|
} else {
|
|
$res1 = pla_set_cookie($cookie_dn_name,pla_blowfish_encrypt($logged_in_dn),$expire);
|
|
$res2 = pla_set_cookie($cookie_pass_name,pla_blowfish_encrypt($logged_in_pass),$expire);
|
|
}
|
|
|
|
# Need to unset the cookies too, since they are still set if further processing occurs (eg: Timeout)
|
|
unset($_COOKIE[$cookie_dn_name]);
|
|
unset($_COOKIE[$cookie_pass_name]);
|
|
|
|
if (! $res1 || ! $res2)
|
|
return false;
|
|
else
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'session':
|
|
# unset session variables
|
|
$session_var_dn_name = sprintf("pla_login_dn_%s",$ldapserver->server_id);
|
|
$session_var_pass_name = sprintf("pla_login_pass_%s",$ldapserver->server_id);
|
|
|
|
if (array_key_exists($session_var_dn_name,$_SESSION))
|
|
unset($_SESSION[$session_var_dn_name]);
|
|
|
|
if (array_key_exists($session_var_pass_name,$_SESSION))
|
|
unset($_SESSION[$session_var_pass_name]);
|
|
|
|
session_write_close();
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
global $lang;
|
|
pla_error(sprintf($lang['unknown_auth_type'],htmlspecialchars($auth_type)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a customized file for a server
|
|
* We don't need any caching, because it's done by PHP
|
|
*
|
|
* @param int $server_id The ID of the server
|
|
* @param string $filename The requested filename
|
|
*
|
|
* @return string The customized filename, if exists, or the standard one
|
|
*/
|
|
function get_custom_file($server_id,$filename,$path) {
|
|
global $ldapservers;
|
|
|
|
# Set default return
|
|
$return = $path.$filename;
|
|
|
|
$custom = $ldapservers->GetValue($server_id,'custom','pages_prefix');
|
|
if (! is_null($custom) && is_file(realpath($path.$custom.$filename)))
|
|
$return = $path.$custom.$filename;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_custom_file(): Entered with (%s,%s,%s), Returning (%s)',1,$server_id,$filename,$path,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Call a customized function
|
|
*
|
|
* @param int $server_id The ID of the server
|
|
* @param string $filename The requested function
|
|
*
|
|
* @return any The result of the called function
|
|
*/
|
|
function call_custom_function( $server_id, $function ) {
|
|
global $ldapservers;
|
|
|
|
# Set default return
|
|
$return = $function;
|
|
|
|
$custom = $ldapservers->GetValue($server_id,'custom','pages_prefix');
|
|
if (! is_null($custom) && function_exists($custom.$function))
|
|
$return = $custom.$filename;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_custom_file(): Entered with (%s,%s), Returning (%s)',1,$server_id,$function,$return);
|
|
|
|
return call_user_func($return );
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* 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>
|
|
* 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>
|
|
*
|
|
* @param string $dn1 The first of two DNs to compare
|
|
* @param string $dn2 The second of two DNs to compare
|
|
* @return int
|
|
*/
|
|
function pla_compare_dns($dn1,$dn2) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_compare_dns(): Entered with (%s,%s)',2,$dn1,$dn2);
|
|
|
|
# If they are obviously the same, return immediately
|
|
if (! strcasecmp($dn1,$dn2))
|
|
return 0;
|
|
|
|
$dn1_parts = pla_explode_dn(pla_reverse_dn($dn1));
|
|
$dn2_parts = pla_explode_dn(pla_reverse_dn($dn2));
|
|
assert(is_array($dn1_parts));
|
|
assert(is_array($dn2_parts));
|
|
|
|
# Foreach of the "parts" of the smaller DN
|
|
for ($i=0; $i < count($dn1_parts) && $i < count($dn2_parts); $i++) {
|
|
/* dnX_part is of the form: "cn=joe" or "cn = joe" or "dc=example"
|
|
ie, one part of a multi-part DN. */
|
|
$dn1_part = $dn1_parts[$i];
|
|
$dn2_part = $dn2_parts[$i];
|
|
|
|
/* Each "part" consists of two sub-parts:
|
|
1. the attribute (ie, "cn" or "o")
|
|
2. the value (ie, "joe" or "example") */
|
|
$dn1_sub_parts = explode('=',$dn1_part,2);
|
|
$dn2_sub_parts = explode('=',$dn2_part,2);
|
|
|
|
$dn1_sub_part_attr = trim($dn1_sub_parts[0]);
|
|
$dn2_sub_part_attr = trim($dn2_sub_parts[0]);
|
|
|
|
if (0 != ($cmp = strcasecmp($dn1_sub_part_attr,$dn2_sub_part_attr)))
|
|
return $cmp;
|
|
|
|
$dn1_sub_part_val = trim($dn1_sub_parts[1]);
|
|
$dn2_sub_part_val = trim($dn2_sub_parts[1]);
|
|
if (0 != ($cmp = strcasecmp($dn1_sub_part_val,$dn2_sub_part_val)))
|
|
return $cmp;
|
|
}
|
|
|
|
/* If we iterated through all entries in the smaller of the two DNs
|
|
(ie, the one with fewer parts), and the entries are different sized,
|
|
then, the smaller of the two must be "less than" than the larger. */
|
|
if (count($dn1_parts) > count($dn2_parts)) {
|
|
return 1;
|
|
|
|
} elseif (count($dn2_parts) > count($dn1_parts)) {
|
|
return -1;
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prunes off anything after the ";" in an attr name. This is useful for
|
|
* attributes that may have ";binary" appended to their names. With
|
|
* real_attr_name(), you can more easily fetch these attributes' schema
|
|
* with their "real" attribute name.
|
|
*
|
|
* @param string $attr_name The name of the attribute to examine.
|
|
* @return string
|
|
*/
|
|
function real_attr_name($attr_name) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('real_attr_name(): Entered with (%s)',2,$attr_name);
|
|
|
|
$attr_name = preg_replace('/;.*$/U','',$attr_name);
|
|
return $attr_name;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the user has configured PLA to show
|
|
* helpful hints with the $show_hints setting.
|
|
* This is configured in config.php thus:
|
|
* <code>
|
|
* $show_hints = true;
|
|
* </code>
|
|
*
|
|
* @return bool
|
|
* @deprecated
|
|
*/
|
|
function show_hints() {
|
|
global $config;
|
|
return $config->GetValue('appearance','show_hints');
|
|
}
|
|
|
|
/**
|
|
* Determines if the user has enabled auto uidNumbers for the specified server ID.
|
|
*
|
|
* @param int $server_id The id of the server of interest.
|
|
* @return bool True if auto uidNumbers are enabled, false otherwise.
|
|
*/
|
|
function auto_uid_numbers_enabled($server_id) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('auto_uid_numbers_enabled(): Entered with (%s)',2,$server_id);
|
|
|
|
global $ldapservers;
|
|
return $ldapservers->GetValue($server_id,'auto_number','enable');
|
|
}
|
|
|
|
/**
|
|
* For hosts who have 'enable_auto_uid_numbers' set to true, this function will
|
|
* get the next available uidNumber using the host's preferred mechanism
|
|
* (uidpool or search). The uidpool mechanism uses a user-configured entry in
|
|
* the LDAP server to store the last used uidNumber. This mechanism simply fetches
|
|
* and increments and returns that value. The search mechanism is more complicated
|
|
* and slow. It searches all entries that have uidNumber set, finds the smalles and
|
|
* "fills in the gaps" by incrementing the smallest uidNumber until an unused value
|
|
* is found. Both mechanisms do NOT prevent race conditions or toe-stomping, so
|
|
* care must be taken when actually creating the entry to check that the uidNumber
|
|
* returned here has not been used in the mean time. Note that the two different
|
|
* mechanisms may (will!) return different values as they use different algorithms
|
|
* to arrive at their result. Do not be alarmed if (when!) this is the case.
|
|
*
|
|
* Also note that both algorithms are susceptible to a race condition. If two admins
|
|
* are adding users simultaneously, the users may get identical uidNumbers with this
|
|
* function.
|
|
*
|
|
* See config.php.example for more notes on the two auto uidNumber mechanisms.
|
|
*
|
|
* @param object $ldapserver The LDAP Server Object of interest.
|
|
* @return int
|
|
*
|
|
* @todo take advantage of multiple connections with new LDAPServer object.
|
|
* @todo rename this function as its a generic get_next_number function now.
|
|
* @todo Must turn off auto_uid|gid in template if config is disabled.
|
|
*/
|
|
function get_next_uid_number($ldapserver,$startbase='',$type='uid') {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_next_uid_number(): Entered with (%s,%s,%s)',2,$ldapserver->server_id,$startbase,$type);
|
|
|
|
global $config,$ldapservers,$lang;
|
|
|
|
if (! $ldapservers->GetValue($ldapserver->server_id,'auto_number','enable'))
|
|
return false;
|
|
|
|
# Based on the configured mechanism, go get the next available uidNumber!
|
|
$mechanism = $ldapservers->GetValue($ldapserver->server_id,'auto_number','mechanism');
|
|
|
|
switch ($mechanism) {
|
|
|
|
// @todo: This is being deprecated - unless somebody wants it?
|
|
case 'uidpool' :
|
|
if( ! isset( $servers[ $ldapserver->server_id ][ 'auto_uid_number_uid_pool_dn' ] ) )
|
|
pla_error( sprintf( $lang['uidpool_not_set'], $ldapserver->name ) );
|
|
|
|
$uid_pool_dn = $servers[ $ldapserver->server_id ][ 'auto_uid_number_uid_pool_dn' ];
|
|
if( ! dn_exists( $ldapserver, $uid_pool_dn ) )
|
|
pla_error( sprintf( $lang['uidpool_not_exist'] , $uid_pool_dn ) );
|
|
|
|
$next_uid_number = get_object_attr( $ldapserver, $uid_pool_dn, 'uidNumber' );
|
|
$next_uid_number = intval( $next_uid_number[ 0 ] );
|
|
$next_uid_number++;
|
|
|
|
return $next_uid_number;
|
|
break;
|
|
|
|
case 'search' :
|
|
if (! $startbase) {
|
|
$base_dn = $ldapservers->GetValue($ldapserver->server_id,'auto_number','search_base');
|
|
if (is_null($base_dn))
|
|
pla_error( sprintf( $lang['specified_uidpool'] , $ldapserver->name ) );
|
|
|
|
} else {
|
|
$base_dn = $startbase;
|
|
}
|
|
$filter = "(|(uidNumber=*)(gidNumber=*))";
|
|
$results = array();
|
|
|
|
# Check see and use our alternate uid_dn and password if we have it.
|
|
if (! is_null($ldapservers->GetValue($ldapserver->server_id,'auto_number','dn')) &&
|
|
! is_null($ldapservers->GetValue($ldapserver->server_id,'auto_number','pass'))) {
|
|
|
|
$con = @ldap_connect($ldapserver->host,$ldapserver->port);
|
|
@ldap_set_option($con,LDAP_OPT_PROTOCOL_VERSION,3);
|
|
@ldap_set_option($con,LDAP_OPT_REFERRALS,0);
|
|
|
|
# Bind with the alternate ID.
|
|
$res = @ldap_bind($con,
|
|
$ldapservers->GetValue($ldapserver->server_id,'auto_number','dn'),
|
|
$ldapservers->GetValue($ldapserver->server_id,'auto_number','pass'));
|
|
|
|
if (! $res)
|
|
pla_error(sprintf($lang['auto_uid_invalid_credential'],$ldapserver->name));
|
|
|
|
$search = @ldap_search($con,$base_dn,$filter,array('uidNumber','gidNumber'),0,0,0,
|
|
$config->GetValue('deref','search'));
|
|
|
|
if (! $search)
|
|
pla_error(sprintf($lang['bad_auto_uid_search_base'],$ldapserver->name));
|
|
|
|
$search = @ldap_get_entries($con,$search);
|
|
$res = @ldap_unbind($con);
|
|
|
|
for ($i = 0;$i < $search['count']; $i++ ) {
|
|
$attrs = $search[$i];
|
|
$entry = array();
|
|
|
|
switch ($type) {
|
|
case 'uid' :
|
|
if (isset($attrs['uidnumber'])) {
|
|
$entry['dn'] = $attrs['dn'];
|
|
$entry['uniqnumber'] = $attrs['uidnumber'][0];
|
|
}
|
|
break;
|
|
|
|
case 'gid' :
|
|
if (isset($attrs['gidnumber'])) {
|
|
$entry['dn'] = $attrs['dn'];
|
|
$entry['uniqnumber'] = $attrs['gidnumber'][0];
|
|
}
|
|
break;
|
|
default :
|
|
pla_error(sprintf('Unknown type [%s] in search',$type));
|
|
}
|
|
$results[] = $entry;
|
|
}
|
|
|
|
} else {
|
|
$search = pla_ldap_search( $ldapserver, $filter, $base_dn, array('uidNumber','gidNumber'));
|
|
|
|
foreach ($search as $dn => $attrs) {
|
|
$entry = array();
|
|
|
|
switch ($type) {
|
|
case 'uid' :
|
|
if (isset($attrs['uidNumber'])) {
|
|
$entry['dn'] = $attrs['dn'];
|
|
$entry['uniqnumber'] = $attrs['uidNumber'];
|
|
}
|
|
break;
|
|
|
|
case 'gid' :
|
|
if (isset($attrs['gidNumber'])) {
|
|
$entry['dn'] = $attrs['dn'];
|
|
$entry['uniqnumber'] = $attrs['gidNumber'];
|
|
}
|
|
break;
|
|
default :
|
|
pla_error(sprintf('Unknown type [%s] in search',$type));
|
|
}
|
|
$results[] = $entry;
|
|
}
|
|
}
|
|
|
|
# construct a list of used numbers
|
|
$autonum = array();
|
|
foreach ($results as $result)
|
|
if (isset($result['uniqnumber']))
|
|
$autonum[] = $result['uniqnumber'];
|
|
|
|
$autonum = array_unique($autonum);
|
|
if (count($autonum) == 0)
|
|
return false;
|
|
|
|
sort($autonum);
|
|
foreach($autonum as $uid)
|
|
$uid_hash[$uid] = 1;
|
|
|
|
# start with the least existing autoNumber and add 1
|
|
if ($ldapservers->GetValue($ldapserver->server_id,'auto_number','min'))
|
|
$minNumber = $ldapservers->GetValue($ldapserver->server_id,'auto_number','min');
|
|
|
|
else
|
|
$minNumber = intval($autonum[0]) + 1;
|
|
|
|
# this loop terminates as soon as we encounter the next available minNumber
|
|
while (isset($uid_hash[$minNumber]))
|
|
$minNumber++;
|
|
|
|
return $minNumber;
|
|
|
|
break;
|
|
|
|
# No other cases allowed. The user has an error in the configuration
|
|
default :
|
|
pla_error( sprintf( $lang['auto_uid_invalid_value'] , $mechanism) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used to determine if the specified attribute is indeed a jpegPhoto. If the
|
|
* specified attribute is one that houses jpeg data, true is returned. Otherwise
|
|
* this function returns false.
|
|
*
|
|
* @param int $server_id The ID of the server hosuing the attribute of interest
|
|
* @param string $attr_name The name of the attribute to test.
|
|
* @return bool
|
|
* @see draw_jpeg_photos
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_jpeg_photo($ldapserver,$attr_name) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_jpeg_photo(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr_name);
|
|
|
|
# easy quick check
|
|
if (! strcasecmp($attr_name,'jpegPhoto') || ! strcasecmp($attr_name,'photo'))
|
|
return true;
|
|
|
|
# go to the schema and get the Syntax OID
|
|
$schema_attr = $ldapserver->getSchemaAttribute($attr_name);
|
|
if (! $schema_attr)
|
|
return false;
|
|
|
|
$oid = $schema_attr->getSyntaxOID();
|
|
$type = $schema_attr->getType();
|
|
|
|
if (! strcasecmp($type,'JPEG') || ($oid == '1.3.6.1.4.1.1466.115.121.1.28'))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Given an attribute name and server ID number, this function returns
|
|
* whether the attrbiute contains boolean data. This is useful for
|
|
* developers who wish to display the contents of a boolean attribute
|
|
* with a drop-down.
|
|
*
|
|
* @param int $server_id The ID of the server of interest (required since
|
|
* this action requires a schema lookup on the server)
|
|
* @param string $attr_name The name of the attribute to test.
|
|
* @return bool
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_attr_boolean($ldapserver,$attr_name) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_attr_boolean(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr_name);
|
|
|
|
$type = ($schema_attr = $ldapserver->getSchemaAttribute($attr_name)) ? $schema_attr->getType() : null;
|
|
|
|
if (! strcasecmp('boolean',$type ) ||
|
|
! strcasecmp('isCriticalSystemObject',$attr_name) ||
|
|
! strcasecmp('showInAdvancedViewOnly',$attr_name))
|
|
return true;
|
|
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Given an attribute name and server ID number, this function returns
|
|
* whether the attrbiute may contain binary data. This is useful for
|
|
* developers who wish to display the contents of an arbitrary attribute
|
|
* but don't want to dump binary data on the page.
|
|
*
|
|
* @param int $server_id The ID of the server of interest (required since
|
|
* this action requires a schema lookup on the server)
|
|
* @param string $attr_name The name of the attribute to test.
|
|
* @return bool
|
|
*
|
|
* @see is_jpeg_photo
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_attr_binary($ldapserver,$attr_name) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_attr_binary(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr_name);
|
|
|
|
$attr_name = strtolower($attr_name);
|
|
/**
|
|
* Determining if an attribute is binary can be an expensive operation.
|
|
* We cache the results for each attr name on each server in the $attr_cache
|
|
* to speed up subsequent calls. The $attr_cache looks like this:
|
|
*
|
|
* Array
|
|
* 0 => Array
|
|
* 'objectclass' => false
|
|
* 'cn' => false
|
|
* 'usercertificate' => true
|
|
* 1 => Array
|
|
* 'jpegphoto' => true
|
|
* 'cn' => false
|
|
*/
|
|
|
|
static $attr_cache;
|
|
if( isset( $attr_cache[ $ldapserver->server_id ][ $attr_name ] ) )
|
|
return $attr_cache[ $ldapserver->server_id ][ $attr_name ];
|
|
|
|
if( $attr_name == 'userpassword' ) {
|
|
$attr_cache[ $ldapserver->server_id ][ $attr_name ] = false;
|
|
return false;
|
|
}
|
|
|
|
// Quick check: If the attr name ends in ";binary", then it's binary.
|
|
if( 0 == strcasecmp( substr( $attr_name, strlen( $attr_name ) - 7 ), ";binary" ) ) {
|
|
$attr_cache[ $ldapserver->server_id ][ $attr_name ] = true;
|
|
return true;
|
|
}
|
|
|
|
// See what the server schema says about this attribute
|
|
$schema_attr = $ldapserver->getSchemaAttribute($attr_name);
|
|
if( ! $schema_attr ) {
|
|
|
|
// Strangely, some attributeTypes may not show up in the server
|
|
// schema. This behavior has been observed in MS Active Directory.
|
|
$type = null;
|
|
$syntax = null;
|
|
|
|
} else {
|
|
$type = $schema_attr->getType();
|
|
$syntax = $schema_attr->getSyntaxOID();
|
|
}
|
|
|
|
if( 0 == strcasecmp( $type, 'Certificate' ) ||
|
|
0 == strcasecmp( $type, 'Binary' ) ||
|
|
0 == strcasecmp( $attr_name, 'usercertificate' ) ||
|
|
0 == strcasecmp( $attr_name, 'usersmimecertificate' ) ||
|
|
0 == strcasecmp( $attr_name, 'networkaddress' ) ||
|
|
0 == strcasecmp( $attr_name, 'objectGUID' ) ||
|
|
0 == strcasecmp( $attr_name, 'objectSID' ) ||
|
|
$syntax == '1.3.6.1.4.1.1466.115.121.1.10' ||
|
|
$syntax == '1.3.6.1.4.1.1466.115.121.1.28' ||
|
|
$syntax == '1.3.6.1.4.1.1466.115.121.1.5' ||
|
|
$syntax == '1.3.6.1.4.1.1466.115.121.1.8' ||
|
|
$syntax == '1.3.6.1.4.1.1466.115.121.1.9' ) {
|
|
|
|
$attr_cache[ $ldapserver->server_id ][ $attr_name ] = true;
|
|
return true;
|
|
|
|
} else {
|
|
$attr_cache[ $ldapserver->server_id ][ $attr_name ] = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if the specified attribute is configured as read only
|
|
* in config.php with the $read_only_attrs array.
|
|
* Attributes are configured as read-only in config.php thus:
|
|
* <code>
|
|
* $read_only_attrs = array( "objectClass", "givenName" );
|
|
* </code>
|
|
*
|
|
* @param string $attr The name of the attribute to test.
|
|
* @return bool
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function is_attr_read_only( $ldapserver, $attr ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_attr_read_only(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr);
|
|
|
|
global $read_only_attrs, $read_only_except_dn;
|
|
|
|
$attr = trim( $attr );
|
|
if( '' === $attr )
|
|
return false;
|
|
if( ! isset( $read_only_attrs ) )
|
|
return false;
|
|
if( ! is_array( $read_only_attrs) )
|
|
return false;
|
|
|
|
// Is the user excluded?
|
|
if (isset($read_only_except_dn) && userIsMember($ldapserver, get_logged_in_dn( $ldapserver ),$read_only_except_dn))
|
|
return false;
|
|
|
|
foreach( $read_only_attrs as $attr_name )
|
|
if( 0 == strcasecmp( $attr, trim($attr_name) ) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the specified attribute is configured as hidden
|
|
* in config.php with the $hidden_attrs array or the $hidden_attrs_ro
|
|
* array.
|
|
* Attributes are configured as hidden in config.php thus:
|
|
* <code>
|
|
* $hidden_attrs = array( "objectClass", "givenName" );
|
|
* </code>
|
|
* or
|
|
* <code>
|
|
* $hidden_attrs_ro = array( "objectClass", "givenName", "shadowWarning",
|
|
* "shadowLastChange", "shadowMax", "shadowFlag",
|
|
* "shadowInactive", "shadowMin", "shadowExpire" );
|
|
* </code>
|
|
*
|
|
* @param string $attr The name of the attribute to test.
|
|
* @return bool
|
|
*/
|
|
function is_attr_hidden( $ldapserver, $attr ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_attr_hidden(): Entered with (%s,%s)',2,$ldapserver->server_id,$attr);
|
|
|
|
global $hidden_attrs, $hidden_attrs_ro, $hidden_except_dn;
|
|
|
|
$attr = trim( $attr );
|
|
if( '' === $attr )
|
|
return false;
|
|
if( ! isset( $hidden_attrs ) )
|
|
return false;
|
|
if( ! is_array( $hidden_attrs) )
|
|
return false;
|
|
|
|
if( ! isset( $hidden_attrs_ro ) )
|
|
$hidden_attrs_ro = $hidden_attrs;
|
|
if( ! is_array( $hidden_attrs_ro) )
|
|
$hidden_attrs_ro = $hidden_attrs;
|
|
|
|
// Is the user excluded?
|
|
if (isset($hidden_except_dn) && userIsMember($ldapserver, get_logged_in_dn( $ldapserver ),$hidden_except_dn))
|
|
return false;
|
|
|
|
if( $ldapserver->isReadOnly() ) {
|
|
foreach( $hidden_attrs_ro as $attr_name )
|
|
if( 0 == strcasecmp( $attr, trim($attr_name) ) )
|
|
return true;
|
|
|
|
} else {
|
|
foreach( $hidden_attrs as $attr_name )
|
|
if( 0 == strcasecmp( $attr, trim($attr_name) ) )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the specified server is configured to be displayed
|
|
* in read only mode. If a user has logged in via anonymous bind, and
|
|
* config.php specifies anonymous_bind_implies_read_only as true, then
|
|
* this also returns true. Servers can be configured read-only in
|
|
* config.php thus:
|
|
* <code>
|
|
* $server[$i]['read_only'] = true;
|
|
* </code>
|
|
*
|
|
* @param int $server_id The ID of the server of interest from the $servers array in config.php
|
|
* @return bool
|
|
* @deprecated
|
|
*/
|
|
function is_server_read_only( $server_id ) {
|
|
global $servers;
|
|
if( isset( $servers[$server_id]['read_only'] ) &&
|
|
$servers[$server_id]['read_only'] == true )
|
|
return true;
|
|
|
|
global $anonymous_bind_implies_read_only;
|
|
|
|
if( "anonymous" == get_logged_in_dn( $server_id ) &&
|
|
isset( $anonymous_bind_implies_read_only ) &&
|
|
$anonymous_bind_implies_read_only == true )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Given a DN and server ID, this function reads the DN's objectClasses and
|
|
* determines which icon best represents the entry. The results of this query
|
|
* are cached in a session variable so it is not run every time the tree
|
|
* browser changes, just when exposing new DNs that were not displayed
|
|
* previously. That means we can afford a little bit of inefficiency here
|
|
* in favor of coolness. :)
|
|
*
|
|
* This function returns a string like "country.png". All icon files are assumed
|
|
* to be contained in the /images/ directory of phpLDAPadmin.
|
|
*
|
|
* Developers are encouraged to add new icons to the images directory and modify
|
|
* this function as needed to suit their types of LDAP entries. If the modifications
|
|
* are general to an LDAP audience, the phpLDAPadmin team will gladly accept them
|
|
* as a patch.
|
|
*
|
|
* @param int $server_id The ID of the LDAP server housing the DN of interest.
|
|
* @param string $dn The DN of the entry whose icon you wish to fetch.
|
|
*
|
|
* @return string
|
|
*/
|
|
function get_icon( $ldapserver, $dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_icon(): Entered with (%s,%s)',2,$ldapserver->server_id,$dn);
|
|
|
|
// fetch and lowercase all the objectClasses in an array
|
|
$object_classes = get_object_attr( $ldapserver, $dn, 'objectClass', true );
|
|
|
|
if( $object_classes === null || $object_classes === false || ! is_array( $object_classes ) )
|
|
$object_classes = array();
|
|
|
|
foreach( $object_classes as $i => $class )
|
|
$object_classes[$i] = strtolower( $class );
|
|
|
|
$rdn = get_rdn( $dn );
|
|
$rdn_parts = explode( '=', $rdn, 2 );
|
|
$rdn_value = isset( $rdn_parts[0] ) ? $rdn_parts[0] : null;
|
|
$rdn_attr = isset( $rdn_parts[1] ) ? $rdn_parts[1] : null;
|
|
unset( $rdn_parts );
|
|
|
|
// return icon filename based upon objectClass value
|
|
if( in_array( 'sambaaccount', $object_classes ) &&
|
|
'$' == $rdn{ strlen($rdn) - 1 } )
|
|
return 'nt_machine.png';
|
|
|
|
if( in_array( 'sambaaccount', $object_classes ) )
|
|
return 'nt_user.png';
|
|
|
|
elseif( in_array( 'person', $object_classes ) ||
|
|
in_array( 'organizationalperson', $object_classes ) ||
|
|
in_array( 'inetorgperson', $object_classes ) ||
|
|
in_array( 'account', $object_classes ) ||
|
|
in_array( 'posixaccount', $object_classes ) )
|
|
|
|
return 'user.png';
|
|
|
|
elseif( in_array( 'organization', $object_classes ) )
|
|
return 'o.png';
|
|
|
|
elseif( in_array( 'organizationalunit', $object_classes ) )
|
|
return 'ou.png';
|
|
|
|
elseif( in_array( 'organizationalrole', $object_classes ) )
|
|
return 'uid.png';
|
|
|
|
elseif( in_array( 'dcobject', $object_classes ) ||
|
|
in_array( 'domainrelatedobject', $object_classes ) ||
|
|
in_array( 'domain', $object_classes ) ||
|
|
in_array( 'builtindomain', $object_classes ))
|
|
|
|
return 'dc.png';
|
|
|
|
elseif( in_array( 'alias', $object_classes ) )
|
|
return 'go.png';
|
|
|
|
elseif( in_array( 'room', $object_classes ) )
|
|
return 'door.png';
|
|
|
|
elseif( in_array( 'device', $object_classes ) )
|
|
return 'device.png';
|
|
|
|
elseif( in_array( 'document', $object_classes ) )
|
|
return 'document.png';
|
|
|
|
elseif( in_array( 'country', $object_classes ) ) {
|
|
$tmp = pla_explode_dn( $dn );
|
|
$cval = explode( '=', $tmp[0], 2 );
|
|
$cval = isset( $cval[1] ) ? $cval[1] : false;
|
|
if( $cval && false === strpos( $cval, ".." ) &&
|
|
file_exists( realpath( sprintf("./images/countries/%s.png",strtolower($cval)) ) ) )
|
|
|
|
return sprintf("countries/%s.png",strtolower($cval));
|
|
|
|
else
|
|
return 'country.png';
|
|
}
|
|
|
|
elseif( in_array( 'jammvirtualdomain', $object_classes ) )
|
|
return 'mail.png';
|
|
|
|
elseif( in_array( 'locality', $object_classes ) )
|
|
return 'locality.png';
|
|
|
|
elseif( in_array( 'posixgroup', $object_classes ) ||
|
|
in_array( 'groupofnames', $object_classes ) ||
|
|
in_array( 'group', $object_classes ) )
|
|
|
|
return 'ou.png';
|
|
|
|
elseif( in_array( 'applicationprocess', $object_classes ) )
|
|
return 'process.png';
|
|
|
|
elseif( in_array( 'groupofuniquenames', $object_classes ) )
|
|
return 'uniquegroup.png';
|
|
|
|
elseif( in_array( 'iphost', $object_classes ) )
|
|
return 'host.png';
|
|
|
|
elseif( in_array( 'nlsproductcontainer', $object_classes ) )
|
|
return 'n.png';
|
|
|
|
elseif( in_array( 'ndspkikeymaterial', $object_classes ) )
|
|
return 'lock.png';
|
|
|
|
elseif( in_array( 'server', $object_classes ) )
|
|
return 'server-small.png';
|
|
|
|
elseif( in_array( 'volume', $object_classes ) )
|
|
return 'hard-drive.png';
|
|
|
|
elseif( in_array( 'ndscatcatalog', $object_classes ) )
|
|
return 'catalog.png';
|
|
|
|
elseif( in_array( 'resource', $object_classes ) )
|
|
return 'n.png';
|
|
|
|
elseif( in_array( 'ldapgroup', $object_classes ) )
|
|
return 'ldap-server.png';
|
|
|
|
elseif( in_array( 'ldapserver', $object_classes ) )
|
|
return 'ldap-server.png';
|
|
|
|
elseif( in_array( 'nisserver', $object_classes ) )
|
|
return 'ldap-server.png';
|
|
|
|
elseif( in_array( 'rbscollection', $object_classes ) )
|
|
return 'ou.png';
|
|
|
|
elseif( in_array( 'dfsconfiguration', $object_classes ) )
|
|
return 'nt_machine.png';
|
|
|
|
elseif( in_array( 'applicationsettings', $object_classes ) )
|
|
return 'server-settings.png';
|
|
|
|
elseif( in_array( 'aspenalias', $object_classes ) )
|
|
return 'mail.png';
|
|
|
|
elseif( in_array( 'container', $object_classes ) )
|
|
return 'folder.png';
|
|
|
|
elseif( in_array( 'ipnetwork', $object_classes ) )
|
|
return 'network.png';
|
|
|
|
elseif( in_array( 'samserver', $object_classes ) )
|
|
return 'server-small.png';
|
|
|
|
elseif( in_array( 'lostandfound', $object_classes ) )
|
|
return 'find.png';
|
|
|
|
elseif( in_array( 'infrastructureupdate', $object_classes ) )
|
|
return 'server-small.png';
|
|
|
|
elseif( in_array( 'filelinktracking', $object_classes ) )
|
|
return 'files.png';
|
|
|
|
elseif( in_array( 'automountmap', $object_classes ) ||
|
|
in_array( 'automount', $object_classes ) )
|
|
|
|
return 'hard-drive.png';
|
|
|
|
elseif( 0 === strpos( $rdn_value, "ipsec" ) ||
|
|
0 == strcasecmp( $rdn_value, "IP Security" ) ||
|
|
0 == strcasecmp( $rdn_value, "MSRADIUSPRIVKEY Secret" ) ||
|
|
0 === strpos( $rdn_value, "BCKUPKEY_" ) )
|
|
|
|
return 'lock.png';
|
|
|
|
elseif( 0 == strcasecmp( $rdn_value, "MicrosoftDNS" ) )
|
|
return 'dc.png';
|
|
|
|
// Oh well, I don't know what it is. Use a generic icon.
|
|
else
|
|
return 'object.png';
|
|
}
|
|
|
|
/**
|
|
* Does the same thing as get_icon(), but it tries to fetch the icon name from the
|
|
* tree_icons session variable first. If not found, resorts to get_icon() and stores
|
|
* the icon nmae in the tree_icons session before returing the icon.
|
|
*
|
|
* @param int $server_id The ID of the server housing the DN of interest.
|
|
* @param string $dn The DN of the entry of interest.
|
|
*
|
|
* @return string
|
|
*
|
|
* @see get_icon
|
|
*/
|
|
function get_icon_use_cache( $ldapserver, $dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_icon_use_cache(): Entered with (%s,%s)',2,$ldapserver->server_id,$dn);
|
|
|
|
initialize_session_tree();
|
|
|
|
if( array_key_exists( 'tree_icons', $_SESSION ) ) {
|
|
if( array_key_exists( $ldapserver->server_id, $_SESSION['tree_icons'] ) &&
|
|
array_key_exists( $dn, $_SESSION['tree_icons'][$ldapserver->server_id] ) ) {
|
|
return $_SESSION['tree_icons'][ $ldapserver->server_id ][ $dn ];
|
|
|
|
} else {
|
|
$icon = get_icon( $ldapserver, $dn );
|
|
$_SESSION['tree_icons'][ $ldapserver->server_id ][ $dn ] = $icon;
|
|
return $icon;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given a server_id, returns whether or not we have enough information
|
|
* to authenticate against the server. For example, if the user specifies
|
|
* auth_type of 'cookie' in the config for that server, it checks the $_COOKIE array to
|
|
* see if the cookie username and password is set for the server. If the auth_type
|
|
* is 'session', the $_SESSION array is checked.
|
|
*
|
|
* There are three cases for this function depending on the auth_type configured for
|
|
* the specified server. If the auth_type is form or http, then get_logged_in_dn() is
|
|
* called to verify that the user has logged in. If the auth_type is config, then the
|
|
* $servers array in config.php is checked to ensure that the user has specified
|
|
* login information. In any case, if phpLDAPadmin has enough information to login
|
|
* to the server, true is returned. Otherwise false is returned.
|
|
*
|
|
* @param int $server_id
|
|
* @return bool
|
|
* @see get_logged_in_dn
|
|
* @deprecated
|
|
*/
|
|
function have_auth_info( $server_id )
|
|
{
|
|
global $servers, $ldapservers;
|
|
$ldapserver = $ldapservers->Instance($server_id);
|
|
|
|
$server = $servers[$server_id];
|
|
|
|
// For session or cookie auth_types, we check the session or cookie to see if a user has logged in.
|
|
if( isset( $server['auth_type'] ) && ( in_array( $server['auth_type'], array( 'session', 'cookie' ) ) ) ) {
|
|
// we don't look at get_logged_in_pass() cause it may be null for anonymous binds
|
|
// get_logged_in_dn() will never return null if someone is really logged in.
|
|
if( get_logged_in_dn( $ldapserver ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
// whether or not the login_dn or pass is specified, we return
|
|
// true here. (if they are blank, we do an anonymous bind anyway)
|
|
elseif( ! isset( $server['auth_type'] ) || $server['auth_type'] == 'config' ) {
|
|
return true;
|
|
}
|
|
else {
|
|
global $lang;
|
|
pla_error( sprintf( $lang['error_auth_type_config'],
|
|
htmlspecialchars( $server[ 'auth_type' ] ) ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetches the password of the currently logged in user (for auth_types "form" and "http" only)
|
|
* or false if the current login is anonymous.
|
|
*
|
|
* @param object $ldapserver The LDAPServer object of the server which the user hsa logged in.
|
|
* @return string
|
|
* @see have_auth_info
|
|
* @see get_logged_in_dn
|
|
*/
|
|
function get_logged_in_pass( $ldapserver ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_logged_in_pass(): Entered with (%s)',2,$ldapserver->server_id);
|
|
|
|
if (! $ldapserver->auth_type)
|
|
return false;
|
|
|
|
switch( $ldapserver->auth_type )
|
|
{
|
|
case 'cookie':
|
|
$cookie_name = sprintf('pla_login_pass_%s',$ldapserver->server_id);
|
|
$pass = isset( $_COOKIE[ $cookie_name ] ) ? $_COOKIE[ $cookie_name ] : false;
|
|
|
|
if( $pass == '0' )
|
|
return null;
|
|
else
|
|
return pla_blowfish_decrypt( $pass );
|
|
break;
|
|
|
|
case 'session':
|
|
$session_var_name = sprintf('pla_login_pass_%s',$ldapserver->server_id);
|
|
$pass = isset( $_SESSION[ $session_var_name ] ) ? $_SESSION[ $session_var_name ] : false;
|
|
|
|
if( $pass == '0' )
|
|
return null;
|
|
else
|
|
return pla_blowfish_decrypt ( $pass );
|
|
break;
|
|
|
|
case 'config':
|
|
return $ldapserver->login_pass;
|
|
break;
|
|
|
|
default:
|
|
global $lang;
|
|
pla_error( sprintf( $lang['unknown_auth_type'], htmlspecialchars( $ldapserver->auth_type ) ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the DN who is logged in currently to the given server, which may
|
|
* either be a DN or the string 'anonymous'. This applies only for auth_types
|
|
* "form" and "http".
|
|
*
|
|
* One place where this function is used is the tree viewer:
|
|
* After a user logs in, the text "Logged in as: " is displayed under the server
|
|
* name. This information is retrieved from this function.
|
|
*
|
|
* @param object $ldapserver The LDAPServer object of the server which the user hsa logged in.
|
|
* @return string
|
|
* @see have_auth_info
|
|
* @see get_logged_in_pass
|
|
*/
|
|
function get_logged_in_dn($ldapserver) {
|
|
# Set default return
|
|
$return = false;
|
|
|
|
if ($ldapserver->auth_type) {
|
|
switch ($ldapserver->auth_type) {
|
|
case 'cookie':
|
|
$cookie_name = sprintf('pla_login_dn_%s',$ldapserver->server_id);
|
|
|
|
if (isset($_COOKIE[$cookie_name]))
|
|
$return = pla_blowfish_decrypt($_COOKIE[$cookie_name]);
|
|
else
|
|
$return = false;
|
|
|
|
break;
|
|
|
|
case 'session':
|
|
$session_var_name = sprintf('pla_login_dn_%s',$ldapserver->server_id);
|
|
|
|
if (isset($_SESSION[$session_var_name]))
|
|
$return = pla_blowfish_decrypt($_SESSION[$session_var_name]);
|
|
else
|
|
$return = false;
|
|
|
|
break;
|
|
|
|
case 'config':
|
|
$return = $ldapserver->login_dn;
|
|
break;
|
|
|
|
default:
|
|
global $lang;
|
|
pla_error(sprintf($lang['unknown_auth_type'],htmlspecialchars($auth_type)));
|
|
}
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_logged_in_dn(): Entered with (%s), Returning (%s)',1,$ldapserver->server_id,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Appends a servers base to a "sub" dn or returns the base.
|
|
*
|
|
* @param string $base The baseDN to be added if the DN is relative
|
|
* @param string $sub_dn The DN to be made absolute
|
|
* @return string|null Returns null if both base is null and sub_dn is null or empty
|
|
*/
|
|
function expand_dn_with_base( $base,$sub_dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('expand_dn_with_base(): Entered with (%s,%s)',2,$base,$sub_dn);
|
|
|
|
$empty_str = ( is_null($sub_dn) || ( ( $len = strlen( trim( $sub_dn ) ) ) == 0 ) );
|
|
|
|
if ( $empty_str ) {
|
|
return $base;
|
|
|
|
} elseif ( $sub_dn[$len - 1] != ',' ) {
|
|
// If we have a string which doesn't need a base
|
|
return $sub_dn;
|
|
} else {
|
|
return $sub_dn . $base;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a list of child entries for an entry. Given a DN, this function fetches the list of DNs of
|
|
* child entries one level beneath the parent. For example, for the following tree:
|
|
*
|
|
* <code>
|
|
* dc=example,dc=com
|
|
* ou=People
|
|
* cn=Dave
|
|
* cn=Fred
|
|
* cn=Joe
|
|
* ou=More People
|
|
* cn=Mark
|
|
* cn=Bob
|
|
* </code>
|
|
*
|
|
* Calling <code>get_container_contents( $server_id, "ou=people,dc=example,dc=com" )</code>
|
|
* would return the following list:
|
|
*
|
|
* <code>
|
|
* cn=Dave
|
|
* cn=Fred
|
|
* cn=Joe
|
|
* ou=More People
|
|
* </code>
|
|
*
|
|
* @param object $ldapserver The LDAP Server Object housing the entry of interest
|
|
* @param string $dn The DN of the entry whose children to return.
|
|
* @param int $size_limit (optional) The maximum number of entries to return.
|
|
* If unspecified, no limit is applied to the number of entries in the returned.
|
|
* @param string $filter (optional) An LDAP filter to apply when fetching children, example: "(objectClass=inetOrgPerson)"
|
|
* @return array An array of DN strings listing the immediate children of the specified entry.
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function get_container_contents( $ldapserver, $dn, $size_limit=0, $filter='(objectClass=*)', $deref=LDAP_DEREF_ALWAYS ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_container_contents(): Entered with (%s,%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$dn,$size_limit,$filter,$deref);
|
|
|
|
$search = @ldap_list( $ldapserver->connect(), $dn, $filter, array( 'dn' ), 1, $size_limit, 0, $deref );
|
|
if( ! $search )
|
|
return array();
|
|
|
|
$search = ldap_get_entries( $ldapserver->connect(), $search );
|
|
|
|
$return = array();
|
|
for( $i=0; $i<$search['count']; $i++ ) {
|
|
$entry = $search[$i];
|
|
$dn = $entry['dn'];
|
|
$return[] = $dn;
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Builds the initial tree that is stored in the session variable 'tree'.
|
|
* Simply returns an array with an entry for each active server in
|
|
* config.php. The structure of the returned array is simple, and looks like
|
|
* this:
|
|
* <code>
|
|
* Array (
|
|
* 0 => Array ( )
|
|
* 1 => Array ( )
|
|
* )
|
|
* </code>
|
|
* This function is not meant as a user callable function, but rather a convenient,
|
|
* automated method for setting up the initial structure for the tree viewer.
|
|
*/
|
|
function build_initial_tree() {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('build_initial_tree(): Entered with ()',2);
|
|
|
|
global $ldapservers;
|
|
$return = array();
|
|
|
|
foreach ($ldapservers->GetServerList() as $id) {
|
|
if( $ldapservers->GetValue($id,'server','host') == '' )
|
|
continue;
|
|
|
|
$return[$id] = array();
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('build_initial_tree(): Returning (%s)',1,serialize($return));
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Builds the initial array that stores the icon-lookup for each server's DN in the tree browser. The returned
|
|
* array is then stored in the current session. The structure of the returned array is simple, and looks like
|
|
* this:
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [0] => Array
|
|
* (
|
|
* [dc=example,dc=com] => "dcobject.png"
|
|
* )
|
|
* [1] => Array
|
|
* (
|
|
* [o=Corporation] => "o.png"
|
|
* )
|
|
* )
|
|
* </code>
|
|
* This function is not meant as a user-callable function, but rather a convenient, automated method for
|
|
* setting up the initial data structure for the tree viewer's icon cache.
|
|
*/
|
|
function build_initial_tree_icons() {
|
|
global $ldapservers;
|
|
|
|
$return = array();
|
|
|
|
# initialize an empty array for each server
|
|
foreach ($ldapservers->GetServerList() as $id) {
|
|
if( $ldapservers->GetValue($id,'server','host') == '' )
|
|
continue;
|
|
|
|
$ldapserver = $ldapservers->Instance($id);
|
|
|
|
$return[$id] = array();
|
|
foreach ($ldapserver->getBaseDN() as $base_dn)
|
|
$return[$id][$base_dn] = get_icon($ldapserver,$base_dn);
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('build_initial_tree_icons(): Entered with (), Returning (%s)',1,serialize($return));
|
|
|
|
return $return;
|
|
}
|
|
|
|
/*
|
|
* Checks and fixes an initial session's tree cache if needed.
|
|
*
|
|
* This function is not meant as a user-callable function, but rather a convenient,
|
|
* automated method for checking the initial data structure of the session.
|
|
*/
|
|
function initialize_session_tree() {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('initialize_session_tree(): Entered with ()',2);
|
|
|
|
// From the PHP manual: If you use $_SESSION don't use
|
|
// session_register(), session_is_registered() or session_unregister()!
|
|
if( ! array_key_exists( 'tree', $_SESSION ) )
|
|
$_SESSION['tree'] = build_initial_tree();
|
|
if( ! array_key_exists( 'tree_icons', $_SESSION ) )
|
|
$_SESSION['tree_icons'] = build_initial_tree_icons();
|
|
|
|
// Make sure that the tree index is indeed well formed.
|
|
if( ! is_array( $_SESSION['tree'] ) )
|
|
$_SESSION['tree'] = build_initial_tree();
|
|
if( ! is_array( $_SESSION['tree_icons'] ) )
|
|
$_SESSION['tree_icons'] = build_initial_tree_icons();
|
|
}
|
|
|
|
/**
|
|
* Gets the operational attributes for an entry. Given a DN, this function fetches that entry's
|
|
* operational (ie, system or internal) attributes. These attributes include "createTimeStamp",
|
|
* "creatorsName", and any other attribute that the LDAP server sets automatically. The returned
|
|
* associative array is of this form:
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [creatorsName] => Array
|
|
* (
|
|
* [0] => "cn=Admin,dc=example,dc=com"
|
|
* )
|
|
* [createTimeStamp]=> Array
|
|
* (
|
|
* [0] => "10401040130"
|
|
* )
|
|
* [hasSubordinates] => Array
|
|
* (
|
|
* [0] => "FALSE"
|
|
* )
|
|
* )
|
|
* </code>
|
|
*
|
|
* @param object $ldapserver The LDAP Server Object of interest
|
|
* @param string $dn The DN of the entry whose interal attributes are desired.
|
|
* @param int $deref For aliases and referrals, this parameter specifies whether to
|
|
* follow references to the referenced DN or to fetch the attributes for
|
|
* the referencing DN. See http://php.net/ldap_search for the 4 valid
|
|
* options.
|
|
* @return array An associative array whose keys are attribute names and whose values
|
|
* are arrays of values for the aforementioned attribute.
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function get_entry_system_attrs( $ldapserver, $dn, $deref=LDAP_DEREF_NEVER ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_entry_system_attrs(): Entered with (%s,%s,%s)',2,$ldapserver->server_id,$dn,$deref);
|
|
|
|
$attrs = array( 'creatorsname', 'createtimestamp', 'modifiersname',
|
|
'structuralObjectClass', 'entryUUID', 'modifytimestamp',
|
|
'subschemaSubentry', 'hasSubordinates', '+' );
|
|
|
|
$search = @ldap_read( $ldapserver->connect(), $dn, '(objectClass=*)', $attrs, 0, 0, 0, $deref );
|
|
if( ! $search )
|
|
return false;
|
|
|
|
$entry = ldap_first_entry( $ldapserver->connect(), $search );
|
|
if (! $entry)
|
|
return false;
|
|
|
|
$attrs = ldap_get_attributes( $ldapserver->connect(), $entry );
|
|
if( ! $attrs )
|
|
return false;
|
|
|
|
if( ! isset( $attrs['count'] ) )
|
|
return false;
|
|
|
|
$count = $attrs['count'];
|
|
unset( $attrs['count'] );
|
|
$return_attrs = array();
|
|
|
|
for( $i=0; $i<$count; $i++ ) {
|
|
$attr_name = $attrs[$i];
|
|
unset( $attrs[$attr_name]['count'] );
|
|
$return_attrs[$attr_name] = $attrs[$attr_name];
|
|
}
|
|
|
|
return $return_attrs;
|
|
}
|
|
|
|
/**
|
|
* Gets the attributes/values of an entry. Returns an associative array whose
|
|
* keys are attribute value names and whose values are arrays of values for
|
|
* said attribute. Optionally, callers may specify true for the parameter
|
|
* $lower_case_attr_names to force all keys in the associate array (attribute
|
|
* names) to be lower case.
|
|
*
|
|
* Sample return value of <code>get_object_attrs( 0, "cn=Bob,ou=pepole,dc=example,dc=com" )</code>
|
|
*
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [objectClass] => Array
|
|
* (
|
|
* [0] => person
|
|
* [1] => top
|
|
* )
|
|
* [cn] => Array
|
|
* (
|
|
* [0] => Bob
|
|
* )
|
|
* [sn] => Array
|
|
* (
|
|
* [0] => Jones
|
|
* )
|
|
* [dn] => Array
|
|
* (
|
|
* [0] => cn=Bob,ou=pepole,dc=example,dc=com
|
|
* )
|
|
* )
|
|
* </code>
|
|
*
|
|
* @param object $ldapserver The LDAP Server Object of interest
|
|
* @param string $dn The distinguished name (DN) of the entry whose attributes/values to fetch.
|
|
* @param bool $lower_case_attr_names (optional) If true, all keys of the returned associative
|
|
* array will be lower case. Otherwise, they will be cased as the LDAP server returns
|
|
* them.
|
|
* @param int $deref For aliases and referrals, this parameter specifies whether to
|
|
* follow references to the referenced DN or to fetch the attributes for
|
|
* the referencing DN. See http://php.net/ldap_search for the 4 valid
|
|
* options.
|
|
* @return array
|
|
* @see get_entry_system_attrs
|
|
* @see get_object_attr
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function get_object_attrs( $ldapserver, $dn, $lower_case_attr_names=false, $deref=LDAP_DEREF_NEVER ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_object_attrs(): Entered with (%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$dn,$lower_case_attr_names,$deref);
|
|
|
|
$search = @ldap_read( $ldapserver->connect(), $dn, '(objectClass=*)', array( ), 0, 0, 0, $deref );
|
|
if( ! $search )
|
|
return false;
|
|
|
|
$entry = ldap_first_entry( $ldapserver->connect(), $search );
|
|
if( ! $entry )
|
|
return false;
|
|
|
|
$attrs = ldap_get_attributes( $ldapserver->connect(), $entry );
|
|
if( ! $attrs || $attrs['count'] == 0 )
|
|
return false;
|
|
|
|
$num_attrs = $attrs['count'];
|
|
unset( $attrs['count'] );
|
|
|
|
// strip numerical inices
|
|
for( $i=0; $i<$num_attrs; $i++ )
|
|
unset( $attrs[$i] );
|
|
|
|
$return_array = array();
|
|
foreach( $attrs as $attr => $vals ) {
|
|
if( $lower_case_attr_names )
|
|
$attr = strtolower( $attr );
|
|
|
|
if( is_attr_binary( $ldapserver, $attr ) )
|
|
$vals = ldap_get_values_len( $ldapserver->connect(), $entry, $attr );
|
|
|
|
unset( $vals['count'] );
|
|
$return_array[ $attr ] = $vals;
|
|
}
|
|
|
|
ksort( $return_array );
|
|
return $return_array;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the passed string $temp contains all printable
|
|
* ASCII characters. Otherwise (like if it contains binary data),
|
|
* returns false.
|
|
*/
|
|
function is_printable_str($temp) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_printable_str(): Entered with (%s)',2,$temp);
|
|
|
|
$len = strlen($temp);
|
|
|
|
for ($i=0; $i<$len; $i++) {
|
|
$ascii_val = ord( substr( $temp,$i,1 ) );
|
|
if( $ascii_val < 32 || $ascii_val > 126 )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Much like get_object_attrs(), but only returns the values for
|
|
* one attribute of an object. Example calls:
|
|
*
|
|
* <code>
|
|
* print_r( get_object_attr( 0, "cn=Bob,ou=people,dc=example,dc=com", "sn" ) );
|
|
* // prints:
|
|
* // Array
|
|
* // (
|
|
* // [0] => "Smith"
|
|
* // )
|
|
*
|
|
* print_r( get_object_attr( 0, "cn=Bob,ou=people,dc=example,dc=com", "objectClass" ) );
|
|
* // prints:
|
|
* // Array
|
|
* // (
|
|
* // [0] => "top"
|
|
* // [1] => "person"
|
|
* // )
|
|
* </code>
|
|
*
|
|
* @param int $server_id The ID of the server of interest
|
|
* @param string $dn The distinguished name (DN) of the entry whose attributes/values to fetch.
|
|
* @param string $attr The attribute whose value(s) to return (ie, "objectClass", "cn", "userPassword")
|
|
* @param bool $lower_case_attr_names (optional) If true, all keys of the returned associative
|
|
* array will be lower case. Otherwise, they will be cased as the LDAP server returns
|
|
* them.
|
|
* @param int $deref For aliases and referrals, this parameter specifies whether to
|
|
* follow references to the referenced DN or to fetch the attributes for
|
|
* the referencing DN. See http://php.net/ldap_search for the 4 valid
|
|
* options.
|
|
* @see get_object_attrs
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function get_object_attr( $ldapserver, $dn, $attr, $lower_case_attr_names=false, $deref=LDAP_DEREF_NEVER ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_object_attr(): Entered with (%s,%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$dn,$attr,$lower_case_attr_names,$deref);
|
|
|
|
if ($lower_case_attr_names)
|
|
$attr = strtolower( $attr );
|
|
|
|
$attrs = get_object_attrs( $ldapserver, $dn, $lower_case_attr_names, $deref );
|
|
if( isset( $attrs[$attr] ) )
|
|
return $attrs[$attr];
|
|
else
|
|
return false;
|
|
|
|
//echo "get_object_attr( $server_id, $dn, $attr )<br />";
|
|
|
|
/*
|
|
$search = @ldap_read( $ldapesrver->connect(), $dn, '(objectClass=*)', array( $attr ), 0, 0, 0, $deref );
|
|
if( ! $search )
|
|
return false;
|
|
|
|
$entry = ldap_first_entry( $ldapesrver->connect(), $search );
|
|
if( ! $entry )
|
|
return false;
|
|
|
|
$attrs = ldap_get_attributes( $ldapesrver->connect(), $entry );
|
|
if( ! $attrs || $attrs['count'] == 0 )
|
|
return false;
|
|
|
|
if( is_attr_binary( $ldapserver, $attr ) )
|
|
$vals = ldap_get_values_len( $ldapesrver->connect(), $entry, $attr );
|
|
else
|
|
$vals = ldap_get_values( $ldapesrver->connect(), $entry, $attr );
|
|
unset( $vals['count'] );
|
|
return $vals;
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* A handy ldap searching function very similar to PHP's ldap_search() with the
|
|
* following exceptions: Callers may specify a search scope and the return value
|
|
* is an array containing the search results rather than an LDAP result resource.
|
|
*
|
|
* Example usage:
|
|
* <code>
|
|
* $samba_users = ldap_search( 0, "(&(objectClass=sambaAccount)(objectClass=posixAccount))",
|
|
* "ou=People,dc=example,dc=com", array( "uid", "homeDirectory" ) );
|
|
* print_r( $samba_users );
|
|
* // prints (for example):
|
|
* // Array
|
|
* // (
|
|
* // [uid=jsmith,ou=People,dc=example,dc=com] => Array
|
|
* // (
|
|
* // [dn] => "uid=jsmith,ou=People,dc=example,dc=com"
|
|
* // [uid] => "jsmith"
|
|
* // [homeDirectory] => "\\server\jsmith"
|
|
* // )
|
|
* // [uid=byoung,ou=People,dc=example,dc=com] => Array
|
|
* // (
|
|
* // [dn] => "uid=byoung,ou=Samba,ou=People,dc=example,dc=com"
|
|
* // [uid] => "byoung"
|
|
* // [homeDirectory] => "\\server\byoung"
|
|
* // )
|
|
* // )
|
|
* </code>
|
|
*
|
|
* WARNING: This function will use a lot of memory on large searches since the entire result set is
|
|
* stored in a single array. For large searches, you should consider sing the less memory intensive
|
|
* PHP LDAP API directly (ldap_search(), ldap_next_entry(), ldap_next_attribute(), etc).
|
|
*
|
|
* @param int $server_id The ID of the server to search on.
|
|
* @param string $filter The LDAP filter to use when searching (example: "(objectClass=*)") (see RFC 2254)
|
|
* @param string $base_dn The DN of the base of search.
|
|
* @param array $attrs An array of attributes to include in the search result (example: array( "objectClass", "uid", "sn" )).
|
|
* @param string $scope The LDAP search scope. Must be one of "base", "one", or "sub". Standard LDAP search scope.
|
|
* @param bool $sort_results Specify false to not sort results by DN or true to have the
|
|
* returned array sorted by DN (uses ksort)
|
|
* @param int $deref When handling aliases or referrals, this specifies whether to follow referrals. Must be one of
|
|
* LDAP_DEREF_ALWAYS, LDAP_DEREF_NEVER, LDAP_DEREF_SEARCHING, or LDAP_DEREF_FINDING. See the PHP LDAP API for details.
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function pla_ldap_search( $ldapserver, $filter, $base_dn=null, $attrs=array(), $scope='sub', $sort_results=true, $deref=LDAP_DEREF_ALWAYS ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_ldap_search(): Entered with (%s,%s,%s,%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$filter,$base_dn,count($attrs),$scope,$sort_results,$deref);
|
|
|
|
if( is_null($base_dn)) {
|
|
foreach ($ldapserver->getBaseDN() as $baseDN) {
|
|
$base_dn = $baseDN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch( $scope ) {
|
|
case 'base':
|
|
$search = @ldap_read( $ldapserver->connect(false), $base_dn, $filter, $attrs, 0, 0, 0, $deref );
|
|
break;
|
|
case 'one':
|
|
$search = @ldap_list( $ldapserver->connect(false), $base_dn, $filter, $attrs, 0, 0, 0, $defef );
|
|
break;
|
|
case 'sub':
|
|
default:
|
|
$search = @ldap_search( $ldapserver->connect(false), $base_dn, $filter, $attrs, 0, 0, 0, $deref );
|
|
break;
|
|
}
|
|
|
|
if( ! $search )
|
|
return array();
|
|
|
|
$return = array();
|
|
|
|
//get the first entry identifier
|
|
if( $entry_id = ldap_first_entry($ldapserver->connect(false),$search) )
|
|
|
|
//iterate over the entries
|
|
while($entry_id) {
|
|
|
|
//get the distinguished name of the entry
|
|
$dn = ldap_get_dn($ldapserver->connect(false),$entry_id);
|
|
|
|
//get the attributes of the entry
|
|
$attrs = ldap_get_attributes($ldapserver->connect(false),$entry_id);
|
|
$return[$dn]['dn'] = $dn;
|
|
|
|
//get the first attribute of the entry
|
|
if($attr = ldap_first_attribute($ldapserver->connect(false),$entry_id,$attrs))
|
|
|
|
//iterate over the attributes
|
|
while($attr) {
|
|
if( is_attr_binary($ldapserver,$attr))
|
|
$values = ldap_get_values_len($ldapserver->connect(false),$entry_id,$attr);
|
|
else
|
|
$values = ldap_get_values($ldapserver->connect(false),$entry_id,$attr);
|
|
|
|
//get the number of values for this attribute
|
|
$count = $values['count'];
|
|
unset($values['count']);
|
|
if($count==1)
|
|
$return[$dn][$attr] = $values[0];
|
|
else
|
|
$return[$dn][$attr] = $values;
|
|
|
|
$attr = ldap_next_attribute($ldapserver->connect(false),$entry_id,$attrs);
|
|
}// end while attr
|
|
|
|
$entry_id = ldap_next_entry($ldapserver->connect(false),$entry_id);
|
|
|
|
} // end while entry_id
|
|
|
|
if( $sort_results && is_array( $return ) )
|
|
ksort( $return );
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Reads the query, checks all values and sets defaults.
|
|
*
|
|
* @param int $query_id The ID of the predefined query.
|
|
* @return array The fixed query or null on error
|
|
* @todo Fix base_dn processing and use getBaseDN()
|
|
* @todo expand_dn_with_base no longer knows what the base_dn is, so you need to pass it the base, need to fix this function.
|
|
*/
|
|
function get_cleaned_up_predefined_search( $query_id ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_cleaned_up_predefined_search(): Entered with (%s)',2,$query_id);
|
|
|
|
global $ldapservers,$queries;
|
|
|
|
if( ! isset( $queries[$query_id] ) )
|
|
return null;
|
|
|
|
$query = $queries[$query_id];
|
|
|
|
if( isset( $query['server'] ) && ( is_numeric( $query['server'] ) ) )
|
|
$server_id = $query['server'];
|
|
else $server_id = 0;
|
|
|
|
$ldapserver = $ldapservers->Instance($server_id);
|
|
|
|
$base = ( isset( $query['base'] ) ) ? $query['base'] : null;
|
|
// Multiple base strings mean we can't do this properly
|
|
// Could just take the first entry or return an array rather than a string
|
|
// Ignore for now
|
|
// $base = expand_dn_with_base( $ldapserver, $base );
|
|
|
|
if( isset( $query['filter'] ) && strlen( trim( $query['filter'] ) ) > 0 )
|
|
$filter = $query['filter'];
|
|
else
|
|
$filter = 'objectclass=*';
|
|
|
|
$scope = isset( $query['scope'] )
|
|
&& ( in_array( $query['scope'], array( 'base', 'sub', 'one' ) ) )
|
|
? $query['scope'] : 'sub';
|
|
|
|
if( isset( $query['attributes'] ) && strlen( trim( $query['filter'] ) ) > 0 )
|
|
$attrib = $query['attributes'];
|
|
else
|
|
$attrib = "dn, cn, sn, objectClass";
|
|
|
|
return array (
|
|
'server' => $server_id, 'base' => $base,
|
|
'filter' => $filter, 'scope' => $scope, 'attributes' => $attrib );
|
|
}
|
|
|
|
/**
|
|
* Checks the specified server id for sanity. Ensures that the server is indeed in the configured
|
|
* list and active. This is used by many many scripts to ensure that valid server ID values
|
|
* are passed in POST and GET.
|
|
* @deprecated
|
|
*/
|
|
function check_server_id( $server_id ) {
|
|
global $ldapservers;
|
|
|
|
$ldapserver = $ldapservers->Instance($server_id);
|
|
if(! isset( $ldapserver->host ) || $ldapserver->host == '' )
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Used to generate a random salt for crypt-style passwords. Salt strings are used
|
|
* to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses
|
|
* not only the user's password but also a randomly generated string. The string is
|
|
* stored as the first N characters of the hash for reference of hashing algorithms later.
|
|
*
|
|
* --- added 20021125 by bayu irawan <bayuir@divnet.telkom.co.id> ---
|
|
* --- ammended 20030625 by S C Rigler <srigler@houston.rr.com> ---
|
|
*
|
|
* @param int $length The length of the salt string to generate.
|
|
* @return string The generated salt string.
|
|
*/
|
|
function random_salt( $length ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('random_salt(): Entered with (%s)',2,$length);
|
|
|
|
$possible = '0123456789'.
|
|
'abcdefghijklmnopqrstuvwxyz'.
|
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
|
|
'./';
|
|
$str = "";
|
|
mt_srand((double)microtime() * 1000000);
|
|
|
|
while( strlen( $str ) < $length )
|
|
$str .= substr( $possible, ( rand() % strlen( $possible ) ), 1 );
|
|
|
|
/**
|
|
* Commented out following line because of problem
|
|
* with crypt function in update.php
|
|
* --- 20030625 by S C Rigler <srigler@houston.rr.com> ---
|
|
*/
|
|
//$str = "\$1\$".$str."\$";
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Given a DN string, this returns the 'RDN' portion of the string.
|
|
* For example. given 'cn=Manager,dc=example,dc=com', this function returns
|
|
* 'cn=Manager' (it is really the exact opposite of get_container()).
|
|
*
|
|
* @param string $dn The DN whose RDN to return.
|
|
* @param bool $include_attrs If true, include attributes in the RDN string.
|
|
* See http://php.net/ldap_explode_dn for details
|
|
*
|
|
* @return string The RDN
|
|
* @see get_container
|
|
*/
|
|
function get_rdn( $dn, $include_attrs=0 ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_rdn(): Entered with (%s,%s)',2,$dn,$include_attrs);
|
|
|
|
if( $dn == null )
|
|
return null;
|
|
$rdn = pla_explode_dn( $dn, $include_attrs );
|
|
if( 0 == count($rdn) )
|
|
return $dn;
|
|
if( ! isset( $rdn[0] ) )
|
|
return $dn;
|
|
$rdn = $rdn[0];
|
|
return $rdn;
|
|
}
|
|
|
|
/**
|
|
* Given a DN string, this returns the parent container portion of the string.
|
|
* For example. given 'cn=Manager,dc=example,dc=com', this function returns
|
|
* 'dc=example,dc=com'.
|
|
*
|
|
* @param string $dn The DN whose container string to return.
|
|
*
|
|
* @return string The container
|
|
* @see get_rdn
|
|
*/
|
|
function get_container( $dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_container(): Entered with (%s)',2,$dn);
|
|
|
|
$parts = pla_explode_dn( $dn );
|
|
if( count( $parts ) <= 1 )
|
|
return null;
|
|
$container = $parts[1];
|
|
for( $i=2; $i<count($parts); $i++ )
|
|
$container .= ',' . $parts[$i];
|
|
return $container;
|
|
}
|
|
|
|
/**
|
|
* Given a DN string, this returns the top container portion of the string.
|
|
* @param object $ldapserver The LDAPserver being used.
|
|
* @param string $dn The DN whose container string to return.
|
|
* @return string The container
|
|
* @see get_rdn
|
|
* @see get_container
|
|
* @todo: need to fix this, it should just produce the base_dn for the DN entered, not the top .
|
|
*/
|
|
function get_container_top($ldapserver,$dn) {
|
|
# First determine which base this DN belongs to.
|
|
foreach ($ldapserver->getBaseDN() as $base_dn) {
|
|
if (preg_match("/${base_dn}$/",$dn)) {
|
|
$return = $base_dn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
debug_log(sprintf('get_container_top(): Entered with (%s), Returning (%s)',$dn,$return),1);
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Given a DN string and a path like syntax, this returns the parent container portion of the string.
|
|
* @param object $ldapserver The LDAPserver being used.
|
|
* @param string $dn The DN whose container string to return.
|
|
* @param string $path Either '/', '.' or a series of '../'
|
|
* @return string The container
|
|
* @see get_rdn
|
|
* @see get_container
|
|
*/
|
|
function get_container_parent($ldapserver,$container,$path) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_container_parent(): Entered with (%s,%s)',2,$container,$path);
|
|
|
|
$top = get_container_top($ldapserver,$container);
|
|
|
|
if ($path == '/') {
|
|
return $top;
|
|
|
|
} elseif ($path == '.') {
|
|
return $container;
|
|
|
|
} else {
|
|
$parenttree = explode('/',$path);
|
|
|
|
foreach ($parenttree as $index => $value) {
|
|
if ($value == '..') {
|
|
if (get_container($container))
|
|
$container = get_container($container);
|
|
|
|
if ($container == $top)
|
|
break;
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $container;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given an LDAP error number, returns a verbose description of the error.
|
|
* This function parses ldap_error_codes.txt and looks up the specified
|
|
* ldap error number, and returns the verbose message defined in that file.
|
|
*
|
|
* @param string $err_no The hex error number (ie, "0x42") of the LDAP error of interest.
|
|
* @return array An associative array contianing the error title and description like so:
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [title] => "Invalid Credentials"
|
|
* [description] => "An invalid username and/or password was supplied to the LDAP server."
|
|
* )
|
|
* </code>
|
|
*/
|
|
function pla_verbose_error( $err_no ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_verbose_error(): Entered with (%s)',2,$err_no);
|
|
|
|
static $err_codes;
|
|
|
|
if( count($err_codes) <= 0 ) {
|
|
$err_codes_file = LIBDIR.'ldap_error_codes.txt';
|
|
|
|
if (! file_exists($err_codes_file) || ! is_readable($err_codes_file) || ! ($f = fopen($err_codes_file,'r')))
|
|
return false;
|
|
|
|
$contents = fread( $f, filesize( $err_codes_file ) );
|
|
fclose( $f );
|
|
$entries = array();
|
|
preg_match_all( "/0x[A-Fa-f0-9][A-Za-z0-9]\s+[0-9A-Za-z_]+\s+\"[^\"]*\"\n/",
|
|
$contents, $entries );
|
|
$err_codes = array();
|
|
foreach( $entries[0] as $e ) {
|
|
$entry = array();
|
|
preg_match( "/(0x[A-Za-z0-9][A-Za-z0-9])\s+([0-9A-Za-z_]+)\s+\"([^\"]*)\"/", $e, $entry );
|
|
$hex_code = isset( $entry[1] ) ? $entry[1] : null;
|
|
$title = isset( $entry[2] ) ? $entry[2] : null;
|
|
$desc = isset( $entry[3] ) ? $entry[3] : null;
|
|
$desc = preg_replace( "/\s+/", " ", $desc );
|
|
$err_codes[ "$hex_code" ] = array( 'title' => $title, 'desc' => $desc );
|
|
}
|
|
}
|
|
|
|
if( isset( $err_codes[ $err_no ] ) )
|
|
return $err_codes[ $err_no ];
|
|
else
|
|
return array( 'title' => null, 'desc' => null );
|
|
}
|
|
|
|
// @todo: describe this function
|
|
function support_oid_to_text($oid_id) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('support_oid_to_text(): Entered with (%s)',2,$oid_id);
|
|
|
|
static $oid;
|
|
|
|
if( count($oid) <= 0 ) {
|
|
$oid_codes_file = LIBDIR.'ldap_supported_oids.txt';
|
|
|
|
if(! file_exists($oid_codes_file) || ! is_readable($oid_codes_file) || ! ($f = fopen($oid_codes_file,'r')))
|
|
return false;
|
|
|
|
$contents = fread( $f, filesize( $oid_codes_file ) );
|
|
fclose( $f );
|
|
$entries = array();
|
|
preg_match_all( "/[0-9]\..+\s+\"[^\"]*\"\n/", $contents, $entries );
|
|
$err_codes = array();
|
|
foreach( $entries[0] as $e ) {
|
|
$entry = array();
|
|
preg_match( "/([0-9]\.([0-9]+\.)*[0-9]+)(\s+\"([^\"]*)\")?(\s+\"([^\"]*)\")?(\s+\"([^\"]*)\")?/", $e, $entry );
|
|
$oid_id_a = isset( $entry[1] ) ? $entry[1] : null;
|
|
|
|
if ($oid_id_a) {
|
|
$oid[$oid_id_a]['title'] = isset( $entry[4] ) ? $entry[4] : null;
|
|
$oid[$oid_id_a]['ref'] = isset( $entry[6] ) ? $entry[6] : null;
|
|
$desc = isset( $entry[8] ) ? $entry[8] : null;
|
|
$oid[$oid_id_a]['desc'] = preg_replace( "/\s+/", " ", $desc );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( isset( $oid[ $oid_id ] ) )
|
|
return $oid[ $oid_id ];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Prints an HTML-formatted error string. If you specify the optional
|
|
* parameters $ldap_err_msg and $ldap_err_no, this function will
|
|
* lookup the error number and display a verbose message in addition
|
|
* to the message you pass it.
|
|
*
|
|
* @param string $msg The error message to display.
|
|
* @param string $ldap_err_msg (optional) The error message supplied by the LDAP server
|
|
* @param string $ldap_err_no (optional) The hexadecimal error number string supplied by the LDAP server
|
|
* @param bool $fatal (optional) If true, phpLDAPadmin will terminate execution with the PHP die() function.
|
|
*
|
|
* @see die
|
|
* @see ldap_errno
|
|
* @see pla_verbose_error
|
|
*/
|
|
function pla_error( $msg, $ldap_err_msg=null, $ldap_err_no=-1, $fatal=true ) {
|
|
if (defined('DEBUG_ENABLED') && (DEBUG_ENABLED))
|
|
debug_log('pla_error(): Entered with (%s,%s,%s,%s)',2,$msg,$ldap_err_msg,$ldap_err_no,$fatal);
|
|
|
|
@include_once HTDOCDIR.'header.php';
|
|
global $lang, $config;
|
|
|
|
?>
|
|
<center>
|
|
<table class="error"><tr><td class="img"><img src="images/warning.png" /></td>
|
|
<td><center><h2><?php echo $lang['ferror_error'];?></h2></center>
|
|
<?php echo $msg; ?>
|
|
<br />
|
|
<br />
|
|
<?php
|
|
|
|
if (function_exists('syslog_err'))
|
|
syslog_err($msg);
|
|
|
|
if( $ldap_err_msg ) {
|
|
echo sprintf($lang['ldap_said'], htmlspecialchars( $ldap_err_msg ));
|
|
echo '<br />';
|
|
}
|
|
|
|
if( $ldap_err_no != -1 ) {
|
|
$ldap_err_no = ( '0x' . str_pad( dechex( $ldap_err_no ), 2, 0, STR_PAD_LEFT ) );
|
|
$verbose_error = pla_verbose_error( $ldap_err_no );
|
|
|
|
if( $verbose_error ) {
|
|
echo sprintf( $lang['ferror_number'], $ldap_err_no, $verbose_error['title']);
|
|
echo '<br />';
|
|
echo sprintf( $lang['ferror_discription'], $verbose_error['desc']);
|
|
} else {
|
|
echo sprintf($lang['ferror_number_short'], $ldap_err_no);
|
|
echo '<br />';
|
|
echo $lang['ferror_discription_short'];
|
|
}
|
|
|
|
if (function_exists('syslog_err'))
|
|
syslog_err(sprintf($lang['ferror_number_short'],$ldap_err_no));
|
|
}
|
|
?>
|
|
<br />
|
|
<!-- Commented out due to too many false bug reports. :)
|
|
<br />
|
|
<center>
|
|
<small>
|
|
<?php echo sprintf($lang['ferror_submit_bug'] , get_href( 'add_bug' ));?>
|
|
<?php
|
|
if( function_exists( "debug_print_backtrace" ) )
|
|
debug_print_backtrace();
|
|
?>
|
|
</small>
|
|
</center>
|
|
-->
|
|
</td></tr></table>
|
|
</center>
|
|
<?php
|
|
|
|
if( $fatal ) {
|
|
echo "</body>\n</html>";
|
|
die();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* phpLDAPadmin's custom error handling function. When a PHP error occurs,
|
|
* PHP will call this function rather than printing the typical PHP error string.
|
|
* This provides phpLDAPadmin the ability to format an error message more "pretty"
|
|
* and provide a link for users to submit a bug report. This function is not to
|
|
* be called by users. It is exclusively for the use of PHP internally. If this
|
|
* function is called by PHP from within a context where error handling has been
|
|
* disabled (ie, from within a function called with "@" prepended), then this
|
|
* function does nothing.
|
|
*
|
|
* @param int $errno The PHP error number that occurred (ie, E_ERROR, E_WARNING, E_PARSE, etc).
|
|
* @param string $errstr The PHP error string provided (ie, "Warning index "foo" is undefined)
|
|
* @param string $file The file in which the PHP error ocurred.
|
|
* @param int $lineno The line number on which the PHP error ocurred
|
|
*
|
|
* @see set_error_handler
|
|
*/
|
|
function pla_error_handler( $errno, $errstr, $file, $lineno ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_error_handler(): Entered with (%s,%s,%s,%s)',2,$errno,$errstr,$file,$lineno);
|
|
|
|
global $lang;
|
|
|
|
// error_reporting will be 0 if the error context occurred
|
|
// within a function call with '@' preprended (ie, @ldap_bind() );
|
|
// So, don't report errors if the caller has specifically
|
|
// disabled them with '@'
|
|
if( 0 == ini_get( 'error_reporting' ) || 0 == error_reporting() )
|
|
return;
|
|
|
|
$file = basename( $file );
|
|
$caller = basename( $_SERVER['PHP_SELF'] );
|
|
$errtype = "";
|
|
switch( $errno ) {
|
|
case E_STRICT: $errtype = "E_STRICT"; break;
|
|
case E_ERROR: $errtype = "E_ERROR"; break;
|
|
case E_WARNING: $errtype = "E_WARNING"; break;
|
|
case E_PARSE: $errtype = "E_PARSE"; break;
|
|
case E_NOTICE: $errtype = "E_NOTICE"; break;
|
|
case E_CORE_ERROR: $errtype = "E_CORE_ERROR"; break;
|
|
case E_CORE_WARNING: $errtype = "E_CORE_WARNING"; break;
|
|
case E_COMPILE_ERROR: $errtype = "E_COMPILE_ERROR"; break;
|
|
case E_COMPILE_WARNING: $errtype = "E_COMPILE_WARNING"; break;
|
|
case E_USER_ERROR: $errtype = "E_USER_ERROR"; break;
|
|
case E_USER_WARNING: $errtype = "E_USER_WARNING"; break;
|
|
case E_USER_NOTICE: $errtype = "E_USER_NOTICE"; break;
|
|
case E_ALL: $errtype = "E_ALL"; break;
|
|
default: $errtype = $lang['ferror_unrecognized_num'] . $errno;
|
|
}
|
|
|
|
$errstr = preg_replace("/\s+/"," ",$errstr);
|
|
if( $errno == E_NOTICE ) {
|
|
echo sprintf($lang['ferror_nonfatil_bug'], $errstr, $errtype, $file,
|
|
$lineno, $caller, pla_version(), phpversion(), php_sapi_name(),
|
|
$_SERVER['SERVER_SOFTWARE'], get_href('search_bug',"&summary_keyword=".htmlspecialchars($errstr)),get_href('add_bug'));
|
|
return;
|
|
}
|
|
|
|
$server = isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'undefined';
|
|
$phpself = isset( $_SERVER['PHP_SELF'] ) ? basename( $_SERVER['PHP_SELF'] ) : 'undefined';
|
|
pla_error( sprintf($lang['ferror_congrats_found_bug'], $errstr, $errtype, $file,
|
|
$lineno, $phpself, pla_version(),
|
|
phpversion(), php_sapi_name(), $server ));
|
|
}
|
|
|
|
/**
|
|
* Reads the friendly_attrs array as defined in config.php and lower-cases all
|
|
* the keys. Will return an empty array if the friendly_attrs array is not defined
|
|
* in config.php. This is simply used so we can more easily lookup user-friendly
|
|
* attributes configured by the admin.
|
|
*/
|
|
function process_friendly_attr_table() {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('process_friendly_attr_table(): Entered with ()',2);
|
|
|
|
// require 'config.php';
|
|
global $friendly_attrs;
|
|
$attrs_table = array();
|
|
if( isset( $friendly_attrs ) && is_array( $friendly_attrs ) )
|
|
foreach( $friendly_attrs as $old_name => $new_name )
|
|
$attrs_table[ strtolower( $old_name ) ] = $new_name;
|
|
else
|
|
return array();
|
|
|
|
return $attrs_table;
|
|
}
|
|
|
|
/**
|
|
* Show friendly attribute.
|
|
*/
|
|
function show_friendly_attribute($attr) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('show_friendly_attribute(): Entered with (%s)',2,$attr);
|
|
|
|
$friendly_attrs = process_friendly_attr_table();
|
|
|
|
if (isset($friendly_attrs[strtolower($attr)]))
|
|
$return = $friendly_attrs[strtolower($attr)];
|
|
else
|
|
$return = $attr;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('show_friendly_attribute(): Returning (%s)',1,$return);
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Gets whether an entry exists based on its DN. If the entry exists,
|
|
* returns true. Otherwise returns false.
|
|
*
|
|
* @param object $ldapserver The LDAP Server Object of interest
|
|
* @param string $dn The DN\of the entry of interest.
|
|
*
|
|
* @return bool
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function dn_exists($ldapserver,$dn) {
|
|
# Set default return
|
|
$return = false;
|
|
|
|
$search_result = @ldap_read($ldapserver->connect(false),$dn,'objectClass=*',array('dn'));
|
|
|
|
if ($search_result) {
|
|
$num_entries = ldap_count_entries($ldapserver->connect(false),$search_result);
|
|
|
|
if ($num_entries > 0)
|
|
$return = true;
|
|
else
|
|
$return = false;
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('dn_exists(): Entered with (%s,%s), Returning (%s)',1,$ldapserver->server_id,$dn,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Draw the jpegPhoto image(s) for an entry wrapped in HTML. Many options are available to
|
|
* specify how the images are to be displayed.
|
|
*
|
|
* Usage Examples:
|
|
* <code>
|
|
* draw_jpeg_photos( 0, "cn=Bob,ou=People,dc=example,dc=com", "jpegPhoto" true, false, "border: 1px; width: 150px" );
|
|
* draw_jpeg_photos( 1, "cn=Fred,ou=People,dc=example,dc=com" );
|
|
* </code>
|
|
*
|
|
* @param int $server_id The ID of the server of interest.
|
|
* @param string $dn The DN of the entry that contains the jpeg attribute you want to draw.
|
|
* @param string $attr_name The name of the attribute containing the jpeg data (usually 'jpegPhoto').
|
|
* @param bool $draw_delete_buttons If true, draws a button beneath the image titled 'Delete' allowing the user
|
|
* to delete the jpeg attribute by calling JavaScript function deleteAttribute() provided
|
|
* in the default modification template.
|
|
* @param bool $draw_bytes_and_size If true, draw text below the image indicating the byte size and dimensions.
|
|
* @param string $table_html_attrs Specifies optional CSS style attributes for the table tag.
|
|
*
|
|
* @return void
|
|
*/
|
|
function draw_jpeg_photos( $ldapserver, $dn, $attr_name='jpegPhoto', $draw_delete_buttons=false,
|
|
$draw_bytes_and_size=true, $table_html_attrs='align="left"', $img_html_attrs='' ) {
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('draw_jpeg_photos(): Entered with (%s,%s,%s,%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$dn,$attr_name,$draw_delete_buttons,
|
|
$draw_bytes_and_size,$table_html_attrs,$img_html_attrs);
|
|
|
|
global $config, $lang;
|
|
|
|
$fixed_width = false;
|
|
$fixed_height = false;
|
|
if (eregi(" width",$img_html_attrs) || eregi("^width",$img_html_attrs))
|
|
$fixed_width = true;
|
|
if (eregi(" height=",$img_html_attrs) || eregi("^height=",$img_html_attrs))
|
|
$fixed_height = true;
|
|
|
|
$search_result = ldap_read( $ldapserver->connect(), $dn, 'objectClass=*', array( $attr_name ) );
|
|
$entry = ldap_first_entry( $ldapserver->connect(), $search_result );
|
|
|
|
if (isset($table_html_attrs) && $table_html_attrs != "" )
|
|
echo "<table $table_html_attrs><td><center>\n\n";
|
|
|
|
// for each jpegPhoto in the entry, draw it (there may be only one, and that's okay)
|
|
$jpeg_data = @ldap_get_values_len( $ldapserver->connect(), $entry, $attr_name );
|
|
if( ! is_array( $jpeg_data ) ) {
|
|
printf( $lang['jpeg_unable_toget'], htmlspecialchars( $attr_name ));
|
|
return;
|
|
}
|
|
|
|
for( $i=0; $i<$jpeg_data['count']; $i++ ) {
|
|
// ensures that the photo is written to the specified jpeg['tmpdir']
|
|
$jpeg_temp_dir = realpath($config->GetValue('jpeg','tmpdir').'/');
|
|
if( ! is_writable( $jpeg_temp_dir ) )
|
|
pla_error( $lang['jpeg_dir_not_writable'] );
|
|
|
|
$jpeg_filename = tempnam($jpeg_temp_dir.'/', 'pla');
|
|
$outjpeg = @fopen($jpeg_filename, "wb");
|
|
if( ! $outjpeg )
|
|
pla_error( sprintf( $lang['jpeg_dir_not_writable_error'],$jpeg_temp_dir ));
|
|
fwrite($outjpeg, $jpeg_data[$i]);
|
|
fclose ($outjpeg);
|
|
|
|
$jpeg_data_size = filesize( $jpeg_filename );
|
|
if( $jpeg_data_size < 6 && $draw_delete_buttons ) {
|
|
echo $lang['jpeg_contains_errors'];
|
|
echo '<a href="javascript:deleteAttribute( \'' . $attr_name . '\' );" style="color:red; font-size: 75%">'. $lang['delete_photo'] .'</a>';
|
|
continue;
|
|
}
|
|
|
|
if( function_exists( 'getimagesize' ) ) {
|
|
$jpeg_dimensions = @getimagesize( $jpeg_filename );
|
|
$width = $jpeg_dimensions[0];
|
|
$height = $jpeg_dimensions[1];
|
|
|
|
} else {
|
|
$width = 0;
|
|
$height = 0;
|
|
}
|
|
|
|
if( $width > 300 ) {
|
|
$scale_factor = 300 / $width;
|
|
$img_width = 300;
|
|
$img_height = $height * $scale_factor;
|
|
|
|
} else {
|
|
$img_width = $width;
|
|
$img_height = $height;
|
|
}
|
|
|
|
print "<img ".
|
|
($fixed_width ? '' : "width=\"$img_width\" ").
|
|
($fixed_height ? '' : "height=\"$img_height\" ").
|
|
" $img_html_attrs src=\"view_jpeg_photo.php?file=" . basename($jpeg_filename) . "\" /><br />\n";
|
|
|
|
if( $draw_bytes_and_size ) {
|
|
echo "<small>" . number_format($jpeg_data_size) . " bytes. ";
|
|
echo "$width x $height pixels.<br /></small>\n\n";
|
|
}
|
|
|
|
if( $draw_delete_buttons ) { ?>
|
|
<!-- JavaScript function deleteJpegPhoto() to be defined later by calling script -->
|
|
<a href="javascript:deleteAttribute( '<?php echo $attr_name; ?>' );" style="color:red; font-size: 75%"><?php echo $lang['jpeg_delete'] ?></a>
|
|
<?php }
|
|
}
|
|
|
|
if (isset($table_html_attrs) && $table_html_attrs != "" )
|
|
echo "</center></td></table>\n\n";
|
|
|
|
// delete old jpeg files.
|
|
$jpegtmp_wildcard = "/^pla/";
|
|
$handle = opendir($jpeg_temp_dir);
|
|
while( ($file = readdir($handle) ) != false ) {
|
|
if( preg_match( $jpegtmp_wildcard, $file ) ) {
|
|
$file = "$jpeg_temp_dir/$file";
|
|
if ((time() - filemtime($file)) > $config->GetValue('jpeg','tmp_keep_time'))
|
|
@unlink( $file );
|
|
}
|
|
}
|
|
closedir($handle);
|
|
}
|
|
|
|
/**
|
|
* Hashes a password and returns the hash based on the specified enc_type.
|
|
*
|
|
* @param string $password_clear The password to hash in clear text.
|
|
* @param string $enc_type Standard LDAP encryption type which must be one of
|
|
* crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, or clear.
|
|
* @return string The hashed password.
|
|
*/
|
|
function password_hash( $password_clear, $enc_type ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('password_hash(): Entered with (%s,%s)',2,$password_clear,$enc_type);
|
|
|
|
global $lang;
|
|
|
|
$enc_type = strtolower( $enc_type );
|
|
|
|
switch( $enc_type ) {
|
|
case 'crypt':
|
|
$new_value = '{CRYPT}' . crypt( $password_clear, random_salt(2) );
|
|
break;
|
|
|
|
case 'ext_des':
|
|
// extended des crypt. see OpenBSD crypt man page.
|
|
if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 )
|
|
pla_error( $lang['install_not_support_ext_des'] );
|
|
|
|
$new_value = '{CRYPT}' . crypt( $password_clear, '_' . random_salt(8) );
|
|
break;
|
|
|
|
case 'md5crypt':
|
|
if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 )
|
|
pla_error( $lang['install_not_support_md5crypt'] );
|
|
|
|
$new_value = '{CRYPT}' . crypt( $password_clear , '$1$' . random_salt(9) );
|
|
break;
|
|
|
|
case 'blowfish':
|
|
if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 )
|
|
pla_error( $lang['install_not_support_blowfish'] );
|
|
|
|
// hardcoded to second blowfish version and set number of rounds
|
|
$new_value = '{CRYPT}' . crypt( $password_clear , '$2a$12$' . random_salt(13) );
|
|
break;
|
|
|
|
case 'md5':
|
|
$new_value = '{MD5}' . base64_encode( pack( 'H*' , md5( $password_clear) ) );
|
|
break;
|
|
|
|
case 'sha':
|
|
if( function_exists('sha1') ) {
|
|
// use php 4.3.0+ sha1 function, if it is available.
|
|
$new_value = '{SHA}' . base64_encode( pack( 'H*' , sha1( $password_clear) ) );
|
|
|
|
} elseif( function_exists( 'mhash' ) ) {
|
|
$new_value = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $password_clear) );
|
|
|
|
} else {
|
|
pla_error( $lang['install_no_mash'] );
|
|
}
|
|
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 = "{SSHA}".base64_encode( mhash( MHASH_SHA1, $password_clear.$salt ).$salt );
|
|
|
|
} else {
|
|
pla_error( $lang['install_no_mash'] );
|
|
}
|
|
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 = "{SMD5}".base64_encode( mhash( MHASH_MD5, $password_clear.$salt ).$salt );
|
|
|
|
} else {
|
|
pla_error( $lang['install_no_mash'] );
|
|
}
|
|
break;
|
|
|
|
case 'clear':
|
|
default:
|
|
$new_value = $password_clear;
|
|
}
|
|
|
|
return $new_value;
|
|
}
|
|
|
|
/**
|
|
* Given a clear-text password and a hash, this function determines if the clear-text password
|
|
* is the password that was used to generate the hash. This is handy to verify a user's password
|
|
* when all that is given is the hash and a "guess".
|
|
* @param String $hash The hash.
|
|
* @param String $clear The password in clear text to test.
|
|
* @return Boolean True if the clear password matches the hash, and false otherwise.
|
|
*/
|
|
function password_check( $cryptedpassword, $plainpassword ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('password_check(): Entered with (%s,%s)',2,$cryptedpassword,$plainpassword);
|
|
|
|
global $lang;
|
|
|
|
//echo "password_check( $cryptedpassword, $plainpassword )\n";
|
|
if( preg_match( "/{([^}]+)}(.*)/", $cryptedpassword, $cypher ) ) {
|
|
$cryptedpassword = $cypher[2];
|
|
$_cypher = strtolower($cypher[1]);
|
|
|
|
} else {
|
|
$_cypher = NULL;
|
|
}
|
|
|
|
switch( $_cypher ) {
|
|
// SSHA crypted passwords
|
|
case 'ssha':
|
|
// check php mhash support before using it
|
|
if( function_exists( 'mhash' ) ) {
|
|
$hash = base64_decode($cryptedpassword);
|
|
$salt = substr($hash, -4);
|
|
$new_hash = base64_encode( mhash( MHASH_SHA1, $plainpassword.$salt).$salt );
|
|
|
|
if( strcmp( $cryptedpassword, $new_hash ) == 0 )
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
} else {
|
|
pla_error( $lang['install_no_mash'] );
|
|
}
|
|
break;
|
|
|
|
// Salted MD5
|
|
case 'smd5':
|
|
// check php mhash support before using it
|
|
if( function_exists( 'mhash' ) ) {
|
|
$hash = base64_decode($cryptedpassword);
|
|
$salt = substr($hash, -4);
|
|
$new_hash = base64_encode( mhash( MHASH_MD5, $plainpassword.$salt).$salt );
|
|
|
|
if( strcmp( $cryptedpassword, $new_hash ) == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
} else {
|
|
pla_error( $lang['install_no_mash'] );
|
|
}
|
|
break;
|
|
|
|
// SHA crypted passwords
|
|
case 'sha':
|
|
if( strcasecmp( password_hash($plainpassword,'sha' ), "{SHA}".$cryptedpassword ) == 0 )
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
|
|
// MD5 crypted passwords
|
|
case 'md5':
|
|
if( strcasecmp( password_hash( $plainpassword,'md5' ), "{MD5}".$cryptedpassword ) == 0 )
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
|
|
// Crypt passwords
|
|
case 'crypt':
|
|
// Check if it's blowfish crypt
|
|
if( preg_match("/^\\$2+/",$cryptedpassword ) ) {
|
|
|
|
// make sure that web server supports blowfish crypt
|
|
if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 )
|
|
pla_error( $lang['install_not_support_blowfish'] );
|
|
|
|
list(,$version,$rounds,$salt_hash) = explode('$',$cryptedpassword);
|
|
|
|
if( crypt( $plainpassword, '$'. $version . '$' . $rounds . '$' .$salt_hash ) == $cryptedpassword )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Check if it's an crypted md5
|
|
elseif( strstr( $cryptedpassword, '$1$' ) ) {
|
|
|
|
// make sure that web server supports md5 crypt
|
|
if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 )
|
|
pla_error( $lang['install_not_support_md5crypt'] );
|
|
|
|
list(,$type,$salt,$hash) = explode('$',$cryptedpassword);
|
|
|
|
if( crypt( $plainpassword, '$1$' .$salt ) == $cryptedpassword )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Check if it's extended des crypt
|
|
elseif (strstr( $cryptedpassword, '_' ) ) {
|
|
|
|
// make sure that web server supports ext_des
|
|
if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 )
|
|
pla_error( $lang['install_not_support_ext_des'] );
|
|
|
|
if( crypt($plainpassword, $cryptedpassword ) == $cryptedpassword )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Password is plain crypt
|
|
else {
|
|
|
|
if( crypt($plainpassword, $cryptedpassword ) == $cryptedpassword )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
// No crypt is given assume plaintext passwords are used
|
|
default:
|
|
if( $plainpassword == $cryptedpassword )
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Detects password encryption type
|
|
*
|
|
* Returns crypto string listed in braces. If it is 'crypt' password,
|
|
* returns crypto detected in password hash. Function should detect
|
|
* md5crypt, blowfish and extended DES crypt. If function fails to detect
|
|
* encryption type, it returns NULL.
|
|
* @param string hashed password
|
|
* @return string
|
|
*/
|
|
function get_enc_type( $user_password ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_enc_type(): Entered with (%s)',2,$user_password);
|
|
|
|
/* Capture the stuff in the { } to determine if this is crypt, md5, etc. */
|
|
$enc_type = null;
|
|
|
|
if( preg_match( "/{([^}]+)}/", $user_password, $enc_type) )
|
|
$enc_type = strtolower( $enc_type[1] );
|
|
else
|
|
return null;
|
|
|
|
/* handle crypt types */
|
|
if( strcasecmp( $enc_type, 'crypt') == 0 ) {
|
|
|
|
if( preg_match( "/{[^}]+}\\$1\\$+/", $user_password) ) {
|
|
$enc_type = "md5crypt";
|
|
|
|
} elseif ( preg_match( "/{[^}]+}\\$2+/", $user_password) ) {
|
|
$enc_type = "blowfish";
|
|
|
|
} elseif ( preg_match( "/{[^}]+}_+/", $user_password) ) {
|
|
$enc_type = "ext_des";
|
|
}
|
|
|
|
/*
|
|
* No need to check for standard crypt,
|
|
* because enc_type is already equal to 'crypt'.
|
|
*/
|
|
}
|
|
return $enc_type;
|
|
}
|
|
|
|
/**
|
|
* Gets the default enc_type configured in config.php for the server indicated by $server_id;
|
|
* @param int $server_id The ID of the server of interest.
|
|
* @return String The enc_type, like 'sha', 'md5', 'ssha', 'md5crypt', for example.
|
|
*/
|
|
function get_default_hash($server_id) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_default_hash(): Entered with (%s)',2,$server_id);
|
|
|
|
global $ldapservers;
|
|
return $ldapservers->GetValue($server_id,'appearance','password_hash');
|
|
}
|
|
|
|
/**
|
|
* Returns the phpLDAPadmin version currently running. The version
|
|
* is read from the file named VERSION.
|
|
*
|
|
* @return string The current version as read from the VERSION file.
|
|
*/
|
|
function pla_version() {
|
|
$version_file = realpath('../VERSION');
|
|
if (! file_exists($version_file))
|
|
$return = 'UNKNOWN';
|
|
|
|
else {
|
|
$f = fopen($version_file,'r');
|
|
$version = trim(fread($f, filesize($version_file)));
|
|
fclose($f);
|
|
|
|
# We use cvs_prefix, because CVS will translate this on checkout otherwise.
|
|
$cvs_prefix = '\$Name:';
|
|
|
|
$return = preg_replace('/^'.$cvs_prefix.' RELEASE-([0-9_]+)\s*\$$/','$1',$version);
|
|
$return = preg_replace('/_/','.',$return);
|
|
|
|
# Check if we are a CVS copy.
|
|
if (preg_match('/^'.$cvs_prefix.'?\s*\$$/',$return))
|
|
$return = 'CVS';
|
|
|
|
# If return is still the same as version, then the tag is not one we expect.
|
|
elseif ($return == $version)
|
|
$return = 'UNKNOWN';
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_version(): Entered with (), Returning (%s)',2,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Draws an HTML browse button which, when clicked, pops up a DN chooser dialog.
|
|
* @param string $form_element The name of the form element to which this chooser
|
|
* dialog will publish the user's choice. The form element must be a member
|
|
* of a form with the "name" or "id" attribute set in the form tag, and the element
|
|
* must also define "name" or "id" for JavaScript to uniquely identify it.
|
|
* Example $form_element values may include "creation_form.container" or
|
|
* "edit_form.member_uid". See /templates/modification/default.php for example usage.
|
|
* @param bool $include_choose_text (optional) If true, the function draws the localized text "choose" to the right of the button.
|
|
*/
|
|
function draw_chooser_link( $form_element, $include_choose_text=true, $rdn="none" ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('draw_chooser_link(): Entered with (%s,%s,%s)',2,$form_element,$include_choose_text,$rdn);
|
|
|
|
global $lang;
|
|
|
|
if ($rdn == "none") {
|
|
$href = "javascript:dnChooserPopup('$form_element', '');";
|
|
|
|
} else {
|
|
$href = "javascript:dnChooserPopup('$form_element', '$rdn');";
|
|
}
|
|
|
|
$title = $lang['chooser_link_tooltip'];
|
|
|
|
printf('<nobr><a href="%s" title="%s"><img class="chooser" src="images/find.png" /></a>',$href,$title);
|
|
if ($include_choose_text)
|
|
printf('<span class="x-small"><a href="%s" title="%s">%s</a></span>',$href,$title,$lang['fbrowse']);
|
|
|
|
echo "</nobr>";
|
|
}
|
|
|
|
/**
|
|
* Explode a DN into an array of its RDN parts. This function is UTF-8 safe
|
|
* and replaces the buggy PHP ldap_explode_dn() which does not properly
|
|
* handle UTF-8 DNs and also causes segmentation faults with some inputs.
|
|
*
|
|
* @param string $dn The DN to explode.
|
|
* @param int $with_attriutes (optional) Whether to include attribute names (see http://php.net/ldap_explode_dn for details)
|
|
*
|
|
* @return array An array of RDN parts of this format:
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [0] => uid=ppratt
|
|
* [1] => ou=People
|
|
* [2] => dc=example
|
|
* [3] => dc=com
|
|
* )
|
|
* </code>
|
|
*/
|
|
function pla_explode_dn( $dn, $with_attributes=0 ) {
|
|
# replace "\," with the hexadecimal value for safe split
|
|
$var = preg_replace("/\\\,/","\\\\\\\\2C",$dn);
|
|
|
|
# split the dn
|
|
$result = explode(",",$var);
|
|
|
|
# translate hex code into ascii for display
|
|
foreach( $result as $key => $value )
|
|
$result[$key] = preg_replace("/\\\([0-9A-Fa-f]{2})/e", "''.chr(hexdec('\\1')).''", $value);
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_explode_dn(): Entered with (%s,%s), Returning (%s)',1,$dn,$with_attributes,serialize($result));
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Fetches the URL for the specified item. This is a convenience function for
|
|
* fetching project HREFs (like bugs)
|
|
*
|
|
* @param string $type One of "open_bugs", "add_bug", "donate", or "add_rfe"
|
|
* (rfe = request for enhancement)
|
|
* @return string The URL to the requested item.
|
|
*/
|
|
function get_href( $type, $extra_info='' ) {
|
|
$group_id = "61828";
|
|
$bug_atid = "498546";
|
|
$rfe_atid = "498549";
|
|
$forum_id = "34809";
|
|
|
|
switch( $type ) {
|
|
case 'open_bugs': return "https://sourceforge.net/tracker/?group_id=$group_id&atid=$bug_atid";
|
|
case 'add_bug': return "https://sourceforge.net/tracker/?func=add&group_id=$group_id&atid=$bug_atid";
|
|
case 'add_rfe': return "https://sourceforge.net/tracker/?func=add&group_id=$group_id&atid=$rfe_atid";
|
|
case 'forum': return "http://sourceforge.net/mailarchive/forum.php?forum_id=$forum_id";
|
|
case 'search_bug': return "https://sourceforge.net/tracker/?func=search&group_id=$group_id&atid=$bug_atid&set=custom&_status=100&_group=100&order=summary$extra_info";
|
|
case 'donate': return "donate.php";
|
|
case 'help': return "help.php";
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the current time as a double (including micro-seconds).
|
|
*
|
|
* @return double The current time in seconds since the beginning of the UNIX epoch (Midnight Jan. 1, 1970)
|
|
*/
|
|
function utime () {
|
|
$time = explode(' ',microtime());
|
|
$usec = (double)$time[0];
|
|
$sec = (double)$time[1];
|
|
return $sec + $usec;
|
|
}
|
|
|
|
/**
|
|
* Converts an array to a query-string with the option to exclude certain variables
|
|
* from the returned query string. This is convenient if callers want to convert the
|
|
* current GET query string or POST array into a string and replace certain
|
|
* variables with their own.
|
|
*
|
|
* @param array $array The associate array to convert whose form is such that the keys are the
|
|
* names of the variables and the values are said variables' values like this:
|
|
* <code>
|
|
* Array
|
|
* (
|
|
* [server_id] = 0,
|
|
* [dn] = "dc=example,dc=com",
|
|
* [attr] = "sn"
|
|
* )
|
|
* </code>
|
|
* This will produce a string like this: "server_id=0&dn=dc=example,dc=com&attr=sn"
|
|
* @param array $exclude_vars (optional) An array of variables to exclude in the resulting string
|
|
* @param bool $url_encode_ampersands (optional) By default, this function encodes all ampersand-separators
|
|
* as & but callers may dislabe this by specifying false here. For example, URLs on HTML
|
|
* pages should encode the ampersands but URLs in header( "Location: http://example.com" ) should
|
|
* not be encoded.
|
|
* @return string The string created from the array.
|
|
*/
|
|
function array_to_query_string( $array, $exclude_vars=array(), $url_encode_ampersands=true ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('array_to_query_string(): Entered with (%s,%s,%s)',2,
|
|
count($array),count($exclude_vars),$url_encode_ampersands);
|
|
|
|
if( ! is_array( $array ) )
|
|
return '';
|
|
if( ! $array )
|
|
return '';
|
|
$str = '';
|
|
$i=0;
|
|
foreach( $array as $name => $val ) {
|
|
if( ! in_array( $name, $exclude_vars ) ) {
|
|
if( $i>0 )
|
|
if( $url_encode_ampersands )
|
|
$str .= '&';
|
|
else
|
|
$str .= '&';
|
|
$str .= urlencode( $name ) . '=' . urlencode( $val );
|
|
$i++;
|
|
}
|
|
}
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Reverses a DN such that the top-level RDN is first and the bottom-level RDN is last
|
|
* For example:
|
|
* <code>
|
|
* cn=Brigham,ou=People,dc=example,dc=com
|
|
* </code>
|
|
* Becomes:
|
|
* <code>
|
|
* dc=com,dc=example,ou=People,cn=Brigham
|
|
* </code>
|
|
* This makes it possible to sort lists of DNs such that they are grouped by container.
|
|
*
|
|
* @param string $dn The DN to reverse
|
|
*
|
|
* @return string The reversed DN
|
|
*
|
|
* @see pla_compare_dns
|
|
*/
|
|
function pla_reverse_dn($dn) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_reverse_dn(): Entered with (%s)',2,$dn);
|
|
|
|
foreach (pla_explode_dn($dn) as $key => $branch) {
|
|
|
|
// pla_expode_dn returns the array with an extra count attribute, we can ignore that.
|
|
if ( $key === "count" ) continue;
|
|
|
|
if (isset($rev)) {
|
|
$rev = $branch.",".$rev;
|
|
} else {
|
|
$rev = $branch;
|
|
}
|
|
}
|
|
return $rev;
|
|
}
|
|
|
|
/**
|
|
* Determins if the specified attribute is contained in the $unique_attrs list
|
|
* configured in config.php.
|
|
* @return Bool True if the specified attribute is in the $unique_attrs list and false
|
|
* otherwise.
|
|
*/
|
|
function is_unique_attr( $attr_name ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_unique_attr(): Entered with (%s)',2,$attr_name);
|
|
|
|
global $unique_attrs;
|
|
if( isset( $unique_attrs ) && is_array( $unique_attrs ) ) {
|
|
foreach( $unique_attrs as $attr )
|
|
if( 0 === strcasecmp( $attr_name, $attr ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This function will check whether the value for an attribute being changed
|
|
* is already assigned to another DN.
|
|
*
|
|
* Inputs:
|
|
* @param object $ldapserver The LDAP Server Object of interest
|
|
* @param dn $dn DN that is being changed
|
|
* @param string $attr_name Attribute being changed
|
|
* @param string|array $new values New values for the attribute
|
|
*
|
|
* Returns the bad value, or null if all values are OK
|
|
* @todo Implement alternate conection with LDAPserver object
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function checkUniqueAttr( $ldapserver, $dn, $attr_name, $new_value ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('checkUniqueAttr(): Entered with (%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$dn,$attr_name,count($new_value));
|
|
|
|
global $ldapservers,$lang;
|
|
|
|
// Is this attribute in the unique_attrs list?
|
|
if ( is_unique_attr( $attr_name ) ) {
|
|
|
|
// Search the tree and make sure that attribute doesnt already exist to somebody else.
|
|
|
|
// Check see and use our alternate uid_dn and password if we have it.
|
|
$unique_attrs_dn = $ldapservers->GetValue($ldapserver->server_id,'unique_attrs','dn');
|
|
$unique_attrs_pass = $ldapservers->GetValue($ldapserver->server_id,'unique_attrs','pass');
|
|
$need_to_unbind = false;
|
|
|
|
if ( isset( $unique_attrs_dn ) && $unique_attrs_dn != '' && isset( $uniqe_attrs_pass ) )
|
|
{
|
|
$con = @ldap_connect( $ldapserver->host, $ldapserver->port );
|
|
|
|
@ldap_set_option( $con, LDAP_OPT_PROTOCOL_VERSION, 3 );
|
|
|
|
// Bind with the alternate ID.
|
|
$res = @ldap_bind( $con, $unuque_attrs_dn, $unique_attrs_pass );
|
|
|
|
if (! $res) pla_error( sprintf( $lang['unique_attrs_invalid_credential'] , $ldapserver->name ) );
|
|
|
|
$need_to_unbind = true;
|
|
|
|
} else {
|
|
$con = $ldapserver->connect();
|
|
}
|
|
|
|
// Build our search filter to double check each attribute.
|
|
$searchfilter = "(|";
|
|
|
|
if ( is_array( $new_value ) ) {
|
|
foreach ($new_value as $val) {
|
|
$searchfilter .= sprintf("($attr_name=%s)",clean_search_vals($val));
|
|
}
|
|
|
|
} elseif ( $new_value ) {
|
|
$searchfilter .= sprintf("($attr_name=%s)",clean_search_vals($new_value));
|
|
}
|
|
|
|
$searchfilter .= ")";
|
|
|
|
// Do we need a sanity check to just in case $new_value was null and hence the search string is bad?
|
|
|
|
foreach ($ldapserver->getBaseDN() as $base_dn) {
|
|
|
|
// Do the search
|
|
$search = @ldap_search( $con, $base_dn, $searchfilter, array('dn',$attr_name), 0, 0, 0, LDAP_DEREF_ALWAYS);
|
|
if (! $search)
|
|
continue;
|
|
|
|
$search = ldap_get_entries( $con, $search );
|
|
|
|
foreach ($search as $result) {
|
|
// Skip the count result and go to the array.
|
|
if (! is_array($result)) continue;
|
|
|
|
// If one of the attributes is owned to somebody else, then we may as well die here.
|
|
if ($result['dn'] != $dn) {
|
|
|
|
// Find which attribute matched.
|
|
foreach ($result[strtolower($attr_name)] as $attr) {
|
|
foreach ($new_value as $new_value_attr) {
|
|
if ($attr == $new_value_attr)
|
|
return $attr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $need_to_unbind ) {
|
|
$res = @ldap_unbind( $con );
|
|
}
|
|
|
|
// If we get here, then it must be OK?
|
|
return;
|
|
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
|
|
function sortAttrs($a,$b) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('sortAttrs(): Entered with (%s,%s)',2,$a,$b);
|
|
|
|
global $friendly_attrs, $attrs_display_order;
|
|
|
|
// If $attrs_display_order is not set, make it a blank array.
|
|
if (! isset($attrs_display_order))
|
|
$attrs_display_order = array();
|
|
|
|
if ( $a == $b ) return 0;
|
|
|
|
// Check if $a is in $attrs_display_order, get its key
|
|
$a_key = array_search($a, $attrs_display_order);
|
|
// If not, check if its friendly name is $attrs_display_order, get its key
|
|
// If not, assign one greater than number of elements.
|
|
if ( $a_key == '' ) {
|
|
if (isset($friendly_attrs[ strtolower( $a ) ])) {
|
|
$a_key = array_search( $friendly_attrs[ strtolower( $a ) ], $attrs_display_order);
|
|
if ( $a_key == '' ) $a_key = count($attrs_display_order)+1;
|
|
}
|
|
else {
|
|
$a_key = count($attrs_display_order)+1;
|
|
}
|
|
}
|
|
|
|
$b_key = array_search($b, $attrs_display_order);
|
|
if ( $b_key == '' ) {
|
|
if (isset($friendly_attrs[ strtolower( $b ) ])) {
|
|
$b_key = array_search( $friendly_attrs[ strtolower( $b ) ], $attrs_display_order);
|
|
if ( $b_key == '' ) $b_key = count($attrs_display_order)+1;
|
|
}
|
|
else {
|
|
$b_key = count($attrs_display_order)+1;
|
|
}
|
|
}
|
|
|
|
// Case where neither $a, nor $b are in $attrs_display_order, $a_key = $b_key = one greater than num elements.
|
|
// So we sort them alphabetically
|
|
if ( $a_key == $b_key ) {
|
|
$a = strtolower( (isset($friendly_attrs[ strtolower( $a ) ]) ? $friendly_attrs[ strtolower( $a ) ] : $a));
|
|
$b = strtolower( (isset($friendly_attrs[ strtolower( $b ) ]) ? $friendly_attrs[ strtolower( $b ) ] : $b));
|
|
return strcmp ($a, $b);
|
|
}
|
|
|
|
// Case where at least one attribute or its friendly name is in $attrs_display_order
|
|
// return -1 if $a before $b in $attrs_display_order
|
|
return ( $a_key < $b_key ) ? -1 : 1;
|
|
}
|
|
|
|
/**
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function userIsMember($ldapserver,$user,$group) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('userIsMember(): Entered with (%s,%s,%s)',2,$ldapserver->server_id,$user,$group);
|
|
|
|
$group = get_object_attrs( $ldapserver, $group, false, $deref=LDAP_DEREF_NEVER );
|
|
|
|
if( is_array($group) ) {
|
|
// If you are using groupOfNames objectClass
|
|
if ( array_key_exists('member',$group) and in_array(strtolower($user),arrayLower($group['member'])) )
|
|
return true;
|
|
// If you are using groupOfUniqueNames objectClass
|
|
if ( array_key_exists('uniqueMember',$group) and in_array(strtolower($user),arrayLower($group['uniqueMember'])) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @todo Move this to an LDAPServer object method.
|
|
*/
|
|
function userIsAllowedLogin($ldapserver,$user) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('userIsAllowedLogin(): Entered with (%s,%s)',2,$ldapserver->server_id,$user);
|
|
|
|
global $ldapservers;
|
|
|
|
$user = strtolower($user);
|
|
|
|
if (! $ldapservers->GetValue($ldapserver->server_id,'login','allowed_dns'))
|
|
return true;
|
|
|
|
foreach ($ldapservers->GetValue($ldapserver->server_id,'login','allowed_dns') as $login_allowed_dn) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('userIsAllowedLogin: Working through (%s)',9,$login_allowed_dn);
|
|
|
|
// Check if $login_allowed_dn is an ldap search filter
|
|
// Is first occurence of 'filter=' (case ensitive) at position 0 ?
|
|
if ( preg_match('/^\([&|]\(/',$login_allowed_dn) ) {
|
|
$filter = $login_allowed_dn;
|
|
|
|
foreach($ldapserver->getBaseDN() as $base_dn) {
|
|
$results = array();
|
|
$results = pla_ldap_search( $ldapserver, $filter, $base_dn, array('dn') );
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('userIsAllowedLogin: Search, Filter [%s], BaseDN [%s] Results [%s]',9,
|
|
$filter, $base_dn, is_array($results));
|
|
|
|
$dn_array = array();
|
|
|
|
if ($results) {
|
|
foreach ($results as $result)
|
|
$dn_array[] = $result['dn'];
|
|
$dn_array = array_unique( $dn_array );
|
|
|
|
if( count( $dn_array ) !== 0 )
|
|
foreach($dn_array as $result_dn) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('userIsAllowedLogin: Comparing with [%s]',9,$result_dn);
|
|
|
|
// Check if $result_dn is a user DN
|
|
if ( 0 == strcasecmp( trim($user), trim(strtolower($result_dn)) ) )
|
|
return true;
|
|
|
|
// Check if $result_dn is a group DN
|
|
if ( userIsMember($ldapserver,$user,$result_dn) )
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if $login_allowed_dn is a user DN
|
|
if ( 0 == strcasecmp( trim($user), trim(strtolower($login_allowed_dn)) ) )
|
|
return true;
|
|
|
|
// Check if $login_allowed_dn is a group DN
|
|
if ( userIsMember($ldapserver,$user,$login_allowed_dn) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Reads an array and returns the array values back in lower case
|
|
* @param array $array The array to convert the values to lowercase.
|
|
* @returns array Array with values converted to lowercase.
|
|
*/
|
|
function arrayLower($array) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('arrayLower(): Entered with (%s)',2,serialize($array));
|
|
|
|
if (! is_array($array))
|
|
return $array;
|
|
|
|
$newarray = array();
|
|
foreach ($array as $key => $value) {
|
|
$newarray[$key] = strtolower($value);
|
|
}
|
|
|
|
return $newarray;
|
|
}
|
|
|
|
/**
|
|
* Strips all slashes from the specified array in place (pass by ref).
|
|
* @param Array $array The array to strip slashes from, typically one of
|
|
* $_GET, $_POST, or $_COOKIE.
|
|
*/
|
|
function array_stripslashes(&$array) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('array_stripslashes(): Entered with (%s)',2,serialize($array));
|
|
|
|
if (is_array($array))
|
|
while (list($key) = each($array))
|
|
if (is_array($array[$key]) && $key != $array)
|
|
array_stripslashes($array[$key]);
|
|
else
|
|
$array[$key] = stripslashes($array[$key]);
|
|
}
|
|
|
|
/**
|
|
* Gets the USER_AGENT string from the $_SERVER array, all in lower case in
|
|
* an E_NOTICE safe manner.
|
|
* @return string|false The user agent string as reported by the browser.
|
|
*/
|
|
function get_user_agent_string() {
|
|
if( isset( $_SERVER['HTTP_USER_AGENT'] ) )
|
|
$return = strtolower( $_SERVER['HTTP_USER_AGENT'] );
|
|
else
|
|
$return = false;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_user_agent_string(): Entered with (), Returning (%s)',1,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Determines whether the browser's operating system is UNIX (or something like UNIX).
|
|
* @return boolean True if the brower's OS is UNIX, false otherwise.
|
|
*/
|
|
function is_browser_os_unix() {
|
|
$agent_strs = array(
|
|
'sunos','sunos 4','sunos 5',
|
|
'i86',
|
|
'irix','irix 5','irix 6','irix6',
|
|
'hp-ux','09.','10.',
|
|
'aix','aix 1','aix 2','aix 3','aix 4',
|
|
'inux',
|
|
'sco',
|
|
'unix_sv','unix_system_v','ncr','reliant','dec','osf1',
|
|
'dec_alpha','alphaserver','ultrix','alphastation',
|
|
'sinix',
|
|
'freebsd','bsd',
|
|
'x11','vax','openvms'
|
|
);
|
|
|
|
$return = string_in_array_value(get_user_agent_string(),$agent_strs);
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_browser_os_unix(): Entered with (), Returning (%s)',1,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Determines whether the browser's operating system is Windows.
|
|
* @return boolean True if the brower's OS is Windows, false otherwise.
|
|
*/
|
|
function is_browser_os_windows() {
|
|
$agent_strs = array(
|
|
'win','win95','windows 95',
|
|
'win16','windows 3.1','windows 16-bit','windows','win31','win16','winme',
|
|
'win2k','winxp',
|
|
'win98','windows 98','win9x',
|
|
'winnt','windows nt','win32',
|
|
'32bit'
|
|
);
|
|
|
|
$return = string_in_array_value(get_user_agent_string(),$agent_strs);
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_browser_os_windows(): Entered with (), Returning (%s)',1,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Determines whether the browser's operating system is Macintosh.
|
|
* @return boolean True if the brower's OS is mac, false otherwise.
|
|
*/
|
|
function is_browser_os_mac() {
|
|
$agent_strs = array(
|
|
'mac','68000','ppc','powerpc'
|
|
);
|
|
|
|
$return = string_in_array_value(get_user_agent_string(),$agent_strs);
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('is_browser_os_windows(): Entered with (), Returning (%s)',1,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Return posix group entries.
|
|
* @return Array An associative array of posix group entries with attributes as keys, and values as values.
|
|
* @param int $server_id The ID of the server to search.
|
|
* @param string $base_dn The base of the search.
|
|
* @deprecated
|
|
*/
|
|
function get_posix_groups($ldapserver,$base_dn=null) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_posix_groups(): Entered with (%s,%s)',2,$ldapserver->server_id,$base_dn);
|
|
|
|
$results = pla_ldap_search($ldapserver,"objectclass=posixGroup",$base_dn,array());
|
|
|
|
if (!$results)
|
|
return array();
|
|
else
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Return the default format for search results.
|
|
*
|
|
* @return string The format to use.
|
|
*/
|
|
function get_default_search_display() {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_default_search_display(): Entered with ()',2);
|
|
|
|
global $default_search_display, $lang;
|
|
|
|
if( ! isset( $default_search_display ) || is_null( $default_search_display ) )
|
|
return 'list';
|
|
|
|
elseif( 0 == strcasecmp( $default_search_display, 'list' ) )
|
|
return 'list';
|
|
|
|
elseif( 0 == strcasecmp( $default_search_display, 'table' ) )
|
|
return 'table';
|
|
|
|
else
|
|
pla_error( sprintf( $lang['bad_search_display'], htmlspecialchars( $default_search_display ) ) );
|
|
}
|
|
|
|
/**
|
|
* Checks if a string exists in an array, ignoring case.
|
|
*
|
|
* @param string $needle What you are looking for
|
|
* @param array $haystack The array that you think it is in.
|
|
* @return bool True if its there, false if its not.
|
|
*/
|
|
function in_array_ignore_case( $needle, $haystack ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('in_array_ignore_case(): Entered with (%s,%s)',2,$needle,serialize($haystack));
|
|
|
|
if( ! is_array( $haystack ) )
|
|
return false;
|
|
if( ! is_string( $needle ) )
|
|
return false;
|
|
|
|
foreach( $haystack as $element )
|
|
if( is_string( $element ) && 0 == strcasecmp( $needle, $element ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if a string exists in part in an array value, ignoring case.
|
|
*
|
|
* @param string $needle What you are looking for
|
|
* @param array $haystack The array that you think it is in.
|
|
* @return bool True if its there, false if its not.
|
|
*/
|
|
function string_in_array_value( $needle, $haystack ) {
|
|
# Set default return
|
|
$return = false;
|
|
|
|
if (! is_string($needle)) return $return;
|
|
if (! is_array($haystack)) return $return;
|
|
|
|
foreach ($haystack as $element)
|
|
if (is_string($element) && (strpos($needle,$element) !== false)) {
|
|
$return = true;
|
|
break;
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('string_in_array_value(): Entered with (%s,%s), Returning (%s)',1,$needle,serialize($haystack),$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* String padding
|
|
*
|
|
* @param string input string
|
|
* @param integer length of the result
|
|
* @param string the filling string
|
|
* @param integer padding mode
|
|
*
|
|
* @return string the padded string
|
|
*/
|
|
function full_str_pad($input, $pad_length, $pad_string = '', $pad_type = 0) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('full_str_pad(): Entered with (%s,%s,%s,%s)',2,$input,$pad_length,$pad_string,$pad_type);
|
|
|
|
$str = '';
|
|
$length = $pad_length - strlen($input);
|
|
|
|
if ($length > 0) { // str_repeat doesn't like negatives
|
|
if ($pad_type == STR_PAD_RIGHT) { // STR_PAD_RIGHT == 1
|
|
$str = $input.str_repeat($pad_string, $length);
|
|
} elseif ($pad_type == STR_PAD_BOTH) { // STR_PAD_BOTH == 2
|
|
$str = str_repeat($pad_string, floor($length/2));
|
|
$str .= $input;
|
|
$str .= str_repeat($pad_string, ceil($length/2));
|
|
} else { // defaults to STR_PAD_LEFT == 0
|
|
$str = str_repeat($pad_string, $length).$input;
|
|
}
|
|
|
|
} else { // if $length is negative or zero we don't need to do anything
|
|
$str = $input;
|
|
}
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Encryption using blowfish algorithm
|
|
*
|
|
* @param string original data
|
|
* @param string the secret
|
|
*
|
|
* @return string the encrypted result
|
|
*
|
|
* @access public
|
|
*
|
|
* @author lem9 (taken from the phpMyAdmin source)
|
|
*/
|
|
function pla_blowfish_encrypt( $data, $secret=null ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_blowfish_encrypt(): Entered with (%s,%s)',2,$data,$secret);
|
|
|
|
global $config;
|
|
|
|
# If our secret is null or blank, get the default.
|
|
if( $secret === null || ! trim($secret))
|
|
$secret = $config->GetValue('session','blowfish');
|
|
|
|
# If the secret isnt set, then just return the data.
|
|
if (! trim($secret))
|
|
return $data;
|
|
|
|
require_once LIBDIR.'blowfish.php';
|
|
|
|
$pma_cipher = new Horde_Cipher_blowfish;
|
|
$encrypt = '';
|
|
|
|
for ($i=0; $i<strlen($data); $i+=8) {
|
|
$block = substr($data, $i, 8);
|
|
|
|
if (strlen($block) < 8)
|
|
$block = full_str_pad($block,8,"\0", 1);
|
|
|
|
$encrypt .= $pma_cipher->encryptBlock($block, $secret);
|
|
}
|
|
return base64_encode($encrypt);
|
|
}
|
|
|
|
/**
|
|
* Decryption using blowfish algorithm
|
|
*
|
|
* @param string encrypted data
|
|
* @param string the secret
|
|
*
|
|
* @return string original data
|
|
*
|
|
* @access public
|
|
*
|
|
* @author lem9 (taken from the phpMyAdmin source)
|
|
*/
|
|
function pla_blowfish_decrypt( $encdata, $secret=null ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('pla_blowfish_decrypt(): Entered with (%s,%s)',2,$encdata,$secret);
|
|
|
|
global $config;
|
|
|
|
// This cache gives major speed up for stupid callers :)
|
|
static $cache = array();
|
|
|
|
if( isset( $cache[$encdata] ) )
|
|
return $cache[$encdata];
|
|
|
|
# If our secret is null or blank, get the default.
|
|
if( $secret === null || ! trim($secret))
|
|
$secret = $config->GetValue('session','blowfish');
|
|
|
|
# If the secret isnt set, then just return the data.
|
|
if (! trim($secret))
|
|
return $encdata;
|
|
|
|
require_once LIBDIR.'blowfish.php';
|
|
|
|
$pma_cipher = new Horde_Cipher_blowfish;
|
|
$decrypt = '';
|
|
$data = base64_decode($encdata);
|
|
|
|
for ($i=0; $i<strlen($data); $i+=8) {
|
|
$decrypt .= $pma_cipher->decryptBlock(substr($data, $i, 8), $secret);
|
|
}
|
|
|
|
$return = trim($decrypt);
|
|
$cache[$encdata] = $return;
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Gets a DN string using the user-configured tree_display_format string to format it.
|
|
*/
|
|
function draw_formatted_dn( $ldapserver, $dn ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('draw_formatted_dn(): Entered with (%s,%s)',2,$ldapserver->server_id,$dn);
|
|
|
|
global $config;
|
|
|
|
$format = $config->GetValue('appearance','tree_display_format');
|
|
preg_match_all( "/%[a-zA-Z_0-9]+/", $format, $tokens );
|
|
$tokens = $tokens[0];
|
|
foreach( $tokens as $token ) {
|
|
if( 0 == strcasecmp( $token, '%dn' ) )
|
|
$format = str_replace( $token, pretty_print_dn( $dn ), $format );
|
|
|
|
elseif( 0 == strcasecmp( $token, '%rdn' ) )
|
|
$format = str_replace( $token, pretty_print_dn( get_rdn( $dn ) ), $format );
|
|
|
|
elseif( 0 == strcasecmp( $token, '%rdnvalue' ) ) {
|
|
$rdn = get_rdn( $dn );
|
|
$rdn_value = explode( '=', $rdn, 2 );
|
|
$rdn_value = $rdn_value[1];
|
|
$format = str_replace( $token, $rdn_value, $format );
|
|
|
|
} else {
|
|
$attr_name = str_replace( '%', '', $token );
|
|
$attr_values = get_object_attr( $ldapserver, $dn, $attr_name );
|
|
|
|
if( null == $attr_values )
|
|
$display = 'none';
|
|
|
|
elseif( is_array( $attr_values ) )
|
|
$display = htmlspecialchars( implode( ', ', $attr_values ) );
|
|
|
|
else
|
|
$display = htmlspecialchars( $attr_values );
|
|
|
|
$format = str_replace( $token, $display, $format );
|
|
}
|
|
}
|
|
echo $format;
|
|
}
|
|
|
|
/**
|
|
* Gets the date format from the config - default locale if none.
|
|
* @deprecated
|
|
*/
|
|
function get_date_format() {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_date_format(): Entered with ()',2);
|
|
|
|
global $config;
|
|
|
|
return $config->GetValue('appearance','date');
|
|
}
|
|
|
|
/**
|
|
* Takes a shadow* attribute and returns the date as an integer.
|
|
*/
|
|
function shadow_date( $attrs, $attr) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('shadow_date(): Entered with (%s,%s)',2,serialize($attrs),$attr);
|
|
|
|
$shadowLastChange = isset($attrs['shadowLastChange']) ? $attrs['shadowLastChange'][0] : null;
|
|
$shadowMax = isset($attrs['shadowMax']) ? $attrs['shadowMax'][0] : null;
|
|
|
|
if( 0 == strcasecmp( $attr, 'shadowLastChange' ) && $shadowLastChange)
|
|
$shadow_date = $shadowLastChange;
|
|
|
|
elseif ( 0 == strcasecmp( $attr, 'shadowMax' ) && ($shadowMax > 0) && $shadowLastChange )
|
|
$shadow_date = $shadowLastChange+$shadowMax;
|
|
|
|
elseif ( 0 == strcasecmp( $attr, 'shadowWarning' ) && ($attrs[$attr][0] > 0) && $shadowLastChange && $shadowMax && $shadowMax > 0)
|
|
$shadow_date = $shadowLastChange+$shadowMax-$attrs[$attr][0];
|
|
|
|
elseif ( 0 == strcasecmp( $attr, 'shadowInactive' ) && ($attrs[$attr][0] > 0) && $shadowLastChange && $shadowMax && $shadowMax > 0)
|
|
$shadow_date = $shadowLastChange+$shadowMax+$attrs[$attr][0];
|
|
|
|
elseif ( 0 == strcasecmp( $attr, 'shadowMin' ) && ($attrs[$attr][0] > 0) && $shadowLastChange)
|
|
$shadow_date = $shadowLastChange+$attrs[$attr][0];
|
|
|
|
elseif ( 0 == strcasecmp( $attr, 'shadowExpire' ) && ($attrs[$attr][0] > 0))
|
|
$shadow_date = $attrs[$attr][0];
|
|
|
|
else // Couldn't interpret the shadow date (could be 0 or -1 or something)
|
|
return false;
|
|
|
|
return $shadow_date*24*3600;
|
|
}
|
|
|
|
/**
|
|
* This function will clean up the values use during a search - namely, values that have brackets
|
|
* as that messes up the search filter.
|
|
* @param string $val String that will be used in the search filter.
|
|
* @return string $result String that is ready for the search filter.
|
|
*/
|
|
function clean_search_vals( $val ) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('clean_search_vals(): Entered with (%s)',2,$val);
|
|
|
|
# Remove any escaped brackets already.
|
|
$val = preg_replace("/\\\\([\(\)])/","$1",$val);
|
|
|
|
# The string might be a proper search filter
|
|
if (preg_match("/^\([&\|]\(/",$val))
|
|
return $val;
|
|
|
|
else
|
|
return preg_replace("/([\(\)])/","\\\\$1",$val);
|
|
}
|
|
|
|
/**
|
|
* Server html select list
|
|
*/
|
|
function server_select_list ($select_id=null,$only_logged_on=true,$select_name='server_id',$js_script=null) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('server_select_list(): Entered with (%s,%s,%s,%s)',2,$select_id,$only_logged_on,$select_name,$js_script);
|
|
|
|
global $ldapservers;
|
|
|
|
$count = 0;
|
|
$server_menu_html = sprintf('<select name="%s" %s>',$select_name,$js_script);
|
|
|
|
foreach ($ldapservers->GetServerList() as $id) {
|
|
|
|
$ldapserver = $ldapservers->Instance($id);
|
|
|
|
if ($ldapserver->isVisible()) {
|
|
|
|
if ($only_logged_on && ! $ldapserver->haveAuthInfo())
|
|
continue;
|
|
|
|
$count++;
|
|
$server = $ldapserver;
|
|
|
|
$server_menu_html .= sprintf('<option value="%s" %s>%s</option>',
|
|
$ldapserver->server_id,( $ldapserver->server_id == $select_id ? 'selected' : '' ),$ldapserver->name);
|
|
}
|
|
}
|
|
|
|
$server_menu_html .= '</select>';
|
|
|
|
if ($count > 1)
|
|
return $server_menu_html;
|
|
|
|
elseif ($count)
|
|
return sprintf('%s <input type="hidden" name="%s" value="%s">',
|
|
$server->name,$select_name,$server->server_id);
|
|
|
|
else
|
|
return null;
|
|
}
|
|
|
|
function server_info_list() {
|
|
global $ldapservers;
|
|
|
|
$server_info_list = array();
|
|
|
|
foreach ($ldapservers->GetServerList() as $id) {
|
|
$ldapserver = $ldapservers->Instance($id);
|
|
|
|
if (! $ldapserver->haveAuthInfo() || ! $ldapserver->isValidServer($id))
|
|
continue;
|
|
|
|
$server_info_list[$id]['id'] = $id;
|
|
$server_info_list[$id]['name'] = $ldapserver->name;
|
|
$server_info_list[$id]['base_dns'] = $ldapserver->getBaseDN();
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('server_info_list(): Entered with (), Returning (%s)',1,serialize($server_info_list));
|
|
|
|
return $server_info_list;
|
|
}
|
|
|
|
/**
|
|
* Debug Logging to Syslog
|
|
*
|
|
* If the log level of the message is less than the log level of the debug setting in the config file
|
|
* then log the message to syslog.
|
|
*
|
|
* This has been extended to allow multiple arguments after the level.
|
|
* If this form is used then the $msg is treated as a sprintf format
|
|
* and the remaining arguments are passed to this. The advantage of this
|
|
* is that the string is only composed if the message is going to be logged.
|
|
*
|
|
* Suggested logging level messages:
|
|
* 1 = Return results from function calls.
|
|
* 2 = Entry parameters to function calls.
|
|
* 3 = CACHE returning indications
|
|
* 4 = High level processing
|
|
* 5 = 2nd level processing
|
|
* 9 = Very verbose (describing what the code is doing)
|
|
* @param string $msg Message to send to syslog
|
|
* @param int $level Log level of this message.
|
|
* @see syslog.php
|
|
*/
|
|
|
|
function debug_log($msg,$level=0) {
|
|
global $config,$debug_file;
|
|
|
|
# In case we are called before we are fully initialised or if debugging is not set.
|
|
if (! isset($config) || ! ($config->GetValue('debug','file') || $config->GetValue('debug','syslog')))
|
|
return false;
|
|
|
|
$debug_level = $config->GetValue('debug','level');
|
|
if (! $debug_level)
|
|
$debug_level = -1;
|
|
if ($level > $debug_level)
|
|
return false;
|
|
|
|
$caller = basename( $_SERVER['PHP_SELF'] );
|
|
|
|
if (func_num_args() > 2) {
|
|
$args = func_get_args();
|
|
unset($args[0]);
|
|
unset($args[1]);
|
|
$msg = vsprintf($msg, array_values($args));
|
|
}
|
|
|
|
if ($level <= $debug_level) {
|
|
$debug_message = sprintf('%s(%s): %s',basename($_SERVER['PHP_SELF']),$level,substr($msg,0,200));
|
|
|
|
if ($debug_file || $config->GetValue('debug','file')) {
|
|
if (! $debug_file)
|
|
$debug_file = fopen($config->GetValue('debug','file'),'w');
|
|
//@todo: change this to append.
|
|
|
|
fwrite($debug_file,$debug_message."\n");
|
|
}
|
|
|
|
if ($config->GetValue('debug','syslog'))
|
|
syslog_notice($debug_message);
|
|
}
|
|
return syslog_notice( sprintf('%s(%s): %s',$caller,$level,$msg) );
|
|
}
|
|
|
|
function enc_type_select_list($enc_type) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('enc_type_select_list(): Entered with (%s)',2,$enc_type);
|
|
|
|
$html = '<select name="enc_type">';
|
|
$html .= '<option>clear</option>';
|
|
|
|
foreach (array('crypt','ext_des','md5crypt','blowfish','md5','smd5','sha','ssha') as $option)
|
|
$html .= sprintf('<option%s>%s</option>',($enc_type == $option ? ' selected="true"' : ''),$option);
|
|
|
|
$html .= "</select>";
|
|
|
|
return $html;
|
|
}
|
|
|
|
// Converts a little-endian hex-number to one, that 'hexdec' can convert
|
|
function littleEndian($hex) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('littleEndian(): Entered with (%s)',2,$hex);
|
|
|
|
$result = '';
|
|
|
|
for ($x=strlen($hex)-2; $x >= 0; $x=$x-2)
|
|
$result .= substr($hex,$x,2);
|
|
|
|
return $result;
|
|
}
|
|
|
|
function binSIDtoText($binsid) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('binSIDtoText(): Entered with (%s)',2,$binsid);
|
|
|
|
$hex_sid=bin2hex($binsid);
|
|
$rev = hexdec(substr($hex_sid,0,2)); // Get revision-part of SID
|
|
$subcount = hexdec(substr($hex_sid,2,2)); // Get count of sub-auth entries
|
|
$auth = hexdec(substr($hex_sid,4,12)); // SECURITY_NT_AUTHORITY
|
|
|
|
$result = "$rev-$auth";
|
|
|
|
for ($x=0;$x < $subcount; $x++) {
|
|
$subauth[$x] =
|
|
hexdec(littleEndian(substr($hex_sid,16+($x*8),8))); // get all SECURITY_NT_AUTHORITY
|
|
$result .= "-".$subauth[$x];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
if (! function_exists('session_cache_expire')) {
|
|
|
|
/**
|
|
* session_cache_expire is a php 4.2.0 function, we'll emulate it if we are using php <4.2.0
|
|
*/
|
|
|
|
function session_cache_expire() {
|
|
if (defined('DEBUG_ENABLED') && (DEBUG_ENABLED))
|
|
debug_log('session_cache_expire(): Entered with ()',2);
|
|
|
|
return 180;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort a multi dimensional array.
|
|
* @param array $data Multi demension array passed by reference
|
|
* @param string $sortby Comma delimited string of sort keys.
|
|
* @param bool $rev Whether to reverse sort.
|
|
* @returnn array $data Sorted multi demension array.
|
|
*/
|
|
function masort(&$data, $sortby, $rev=0) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('masort(): Entered with (%s,%s,%s)',2,serialize($data),$sortby,$rev);
|
|
|
|
static $sort_funcs = array();
|
|
|
|
if (empty($sort_funcs[$sortby])) {
|
|
$code = "\$c=0;\n";
|
|
foreach (split(',', $sortby) as $key) {
|
|
$code .= "if ((! isset(\$a['$key'])) && (! isset(\$b['$key']))) return 0;\n";
|
|
$code .= "if ((! isset(\$a['$key'])) && isset(\$b['$key'])) return -1;\n";
|
|
$code .= "if (isset(\$a['$key']) && (! isset(\$b['$key']))) return 1;\n";
|
|
$code .= "if (is_numeric(\$a['$key']) && is_numeric(\$b['$key'])) {\n";
|
|
|
|
$code .= " if (\$a['$key'] != \$b['$key'])\n";
|
|
if ($rev)
|
|
$code .= " return (\$a['$key'] < \$b['$key'] ? -1 : 1);\n";
|
|
else
|
|
$code .= " return (\$a['$key'] > \$b['$key'] ? -1 : 1);\n";
|
|
|
|
$code .= "} else {\n";
|
|
|
|
if ($rev)
|
|
$code .= " if ( (\$c = strcasecmp(\$b['$key'],\$a['$key'])) != 0 ) return \$c;\n";
|
|
else
|
|
$code .= " if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return \$c;\n";
|
|
$code .= "}\n";
|
|
}
|
|
$code .= 'return $c;';
|
|
$sort_func = $sort_funcs[$sortby] = create_function('$a, $b', $code);
|
|
} else {
|
|
$sort_func = $sort_funcs[$sortby];
|
|
}
|
|
$sort_func = $sort_funcs[$sortby];
|
|
uasort($data, $sort_func);
|
|
}
|
|
|
|
/**
|
|
* Query LDAP and return a hash.
|
|
* @param object $ldapserver The LDAPServer object of the server which the user hsa logged in.
|
|
* @param string $base_dn The base DN to use.
|
|
* @param string $filter LDAP Query filter.
|
|
* @param string $key LDAP attribute to use as key.
|
|
* @param array $attrs LDAP attributes to use as values.
|
|
* @return array $results Array of values keyed by $key.
|
|
*/
|
|
function return_ldap_hash($ldapserver,$base_dn,$filter,$key,$attrs) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('return_ldap_hash(): Entered with (%s,%s,%s,%s,%s)',2,
|
|
$ldapserver->server_id,$base_dn,$filter,$key,count($attrs));
|
|
|
|
$ldapquery = pla_ldap_search($ldapserver,$filter,$base_dn,$attrs);
|
|
|
|
$results = array();
|
|
|
|
foreach ($ldapquery as $dn => $dnattrs) {
|
|
foreach ($attrs as $attr) {
|
|
if (isset($dnattrs[$attr]))
|
|
$results[$dnattrs[$key]][$attr] = $dnattrs[$attr];
|
|
}
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
// @todo: document this function
|
|
function debug_dump($variable,$die=false) {
|
|
print "<PRE>";
|
|
print_r($variable);
|
|
if ($die)
|
|
die();
|
|
}
|
|
|
|
/**
|
|
* This function returns a string automatically generated
|
|
* based on the criteria defined in the array $criteria in config.php
|
|
*/
|
|
function password_generate() {
|
|
global $config;
|
|
|
|
$no_use_similiar = ! $config->GetValue('password','use_similar');
|
|
$lowercase = $config->GetValue('password','lowercase');
|
|
$uppercase = $config->GetValue('password','uppercase');
|
|
$digits = $config->GetValue('password','numbers');
|
|
$punctuation = $config->GetValue('password','punctuation');
|
|
$length = $config->GetValue('password','length');
|
|
|
|
$outarray = array();
|
|
|
|
if ($no_use_similiar) {
|
|
$raw_lower = "a b c d e f g h k m n p q r s t u v w x y z";
|
|
$raw_numbers = "2 3 4 5 6 7 8 9";
|
|
$raw_punc = "# $ % ^ & * ( ) _ - + = . , [ ] { } :";
|
|
|
|
} else {
|
|
$raw_lower = "a b c d e f g h i j k l m n o p q r s t u v w x y z";
|
|
$raw_numbers = "1 2 3 4 5 6 7 8 9 0";
|
|
$raw_punc = "# $ % ^ & * ( ) _ - + = . , [ ] { } : |";
|
|
}
|
|
|
|
$llower = explode(" ", $raw_lower);
|
|
shuffle($llower);
|
|
$lupper = explode(" ", strtoupper($raw_lower));
|
|
shuffle($lupper);
|
|
$numbers = explode(" ", $raw_numbers);
|
|
shuffle($numbers);
|
|
$punc = explode(" ", $raw_punc);
|
|
shuffle($punc);
|
|
|
|
if ($lowercase > 0)
|
|
$outarray = array_merge($outarray,a_array_rand($llower,$lowercase));
|
|
|
|
if ($uppercase > 0)
|
|
$outarray = array_merge($outarray,a_array_rand($lupper,$uppercase));
|
|
|
|
if ($digits > 0)
|
|
$outarray = array_merge($outarray,a_array_rand($numbers,$digits));
|
|
|
|
if ($punctuation > 0)
|
|
$outarray = array_merge($outarray,a_array_rand($punc,$punctuation));
|
|
|
|
$num_spec = $lowercase + $uppercase + $digits + $punctuation;
|
|
|
|
if ($num_spec < $length) {
|
|
$leftover = array();
|
|
if ($lowercase > 0)
|
|
$leftover = array_merge($leftover, $llower);
|
|
if ($uppercase > 0)
|
|
$leftover = array_merge($leftover, $lupper);
|
|
if ($digits > 0)
|
|
$leftover = array_merge($leftover, $numbers);
|
|
if ($punctuation > 0)
|
|
$leftover = array_merge($leftover, $punc);
|
|
|
|
if (count($leftover) == 0)
|
|
$leftover = array_merge($leftover,$llower,$lupper,$numbers,$punc);
|
|
|
|
shuffle($leftover);
|
|
$outarray = array_merge($outarray, a_array_rand($leftover, $criteria['num'] - $num_spec));
|
|
}
|
|
|
|
shuffle($outarray);
|
|
$return = implode('', $outarray);
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('password_generate(): Entered with (), Returning (%s)',1,$return);
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* This function returns an array of $num_req values
|
|
* randomly picked from the $input array
|
|
*
|
|
* @param array of values
|
|
* @param integer, number of values in returned array
|
|
* @return string the padded string
|
|
*/
|
|
function a_array_rand($input,$num_req) {
|
|
if (count($input) == 0)
|
|
return array();
|
|
|
|
if ($num_req < 1)
|
|
return array();
|
|
|
|
$return = array();
|
|
if ($num_req > count($input)) {
|
|
for($i = 0; $i < $num_req; $i++) {
|
|
$idx = array_rand($input, 1);
|
|
$return[] = $input[$idx];
|
|
}
|
|
|
|
} else {
|
|
$idxlist = array_rand($input, $num_req);
|
|
if ($num_req == 1)
|
|
$idxlist = array($idxlist);
|
|
|
|
for($i = 0; $i < count($idxlist); $i++)
|
|
$return[] = $input[$idxlist[$i]];
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('a_array_rand(): Entered with (%s,%s), Returning (%s)',1,serialize($input),$num_req,serialize($return));
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Returns the cached array of LDAP resources.
|
|
*
|
|
* Note that internally, this function utilizes a two-layer cache,
|
|
* one in memory using a static variable for multiple calls within
|
|
* the same page load, and one in a session for multiple calls within
|
|
* the same user session (spanning multiple page loads).
|
|
*
|
|
* @return Returns the cached attributed requested,
|
|
* or null if there is nothing cached..
|
|
*/
|
|
function get_cached_item($server_id,$item,$subitem='null') {
|
|
global $config;
|
|
|
|
# Set default return
|
|
$return = null;
|
|
|
|
# Check config to make sure session-based caching is enabled.
|
|
if ($config->GetValue('cache',$item)) {
|
|
|
|
static $cache;
|
|
if (isset($cache[$server_id][$item][$subitem])) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_cached_item(): Returning MEMORY cached [%s] (%s)',3,$item,$subitem);
|
|
|
|
$return = $cache[$server_id][$item][$subitem];
|
|
|
|
} elseif (isset($_SESSION['cache'][$server_id][$item][$subitem])) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_cached_item(): Returning SESSION cached [%s] (%s)',3,$item,$subitem);
|
|
|
|
$return = $_SESSION['cache'][$server_id][$item][$subitem];
|
|
$cache[$server_id][$item][$subitem] = $return;
|
|
|
|
}
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('get_cached_item(): Entered with (%s,%s,%s), Returning (%s)',1,
|
|
$server_id,$item,$subitem,serialize($return));
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Caches the specified $item for the specified $server_id.
|
|
*
|
|
* Returns true on success of false on failure.
|
|
*/
|
|
function set_cached_item($server_id,$item,$subitem='null',$data) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('set_cached_item(): Entered with (%s,%s,%s,%s)',2,$server_id,$item,$subitem,serialize($data));
|
|
|
|
global $config;
|
|
|
|
# Check config to make sure session-based caching is enabled.
|
|
if ($config->GetValue('cache',$item)) {
|
|
|
|
static $cache;
|
|
$cache[$server_id][$item][$subitem] = $data;
|
|
$_SESSION['cache'][$server_id][$item][$subitem] = $data;
|
|
return true;
|
|
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the LDAP base DN for a named DN.
|
|
*
|
|
* @param string $dn DN in question
|
|
* @param object $ldapserver Server ID where DN is located
|
|
* @return string $base_dn
|
|
*/
|
|
function dn_get_base($ldapserver,$dn) {
|
|
foreach ($ldapserver->getBaseDN() as $base_dn) {
|
|
if (preg_match("/".$base_dn."$/",$dn))
|
|
return $base_dn;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Draws an HTML date selector button which, when clicked, pops up a date selector dialog.
|
|
* @param string $attr The name of the date type attribute
|
|
*/
|
|
function draw_date_selector_link( $attr ) {
|
|
debug_log(sprintf('draw_date_selector_link(): Entered with (%s)',$attr),2);
|
|
|
|
global $lang;
|
|
|
|
$href = "javascript:dateSelector('$attr');";
|
|
|
|
$title = $lang['date_selector_link'];
|
|
|
|
printf('<nobr><a href="%s" title="%s"><img class="chooser" src="images/calendar.png" id="f_trigger_%s" readonly="1" style="cursor: pointer;" /></a>',$href,$title,$attr);
|
|
echo "</nobr>";
|
|
}
|
|
|
|
# @deprecated
|
|
function get_schema_attribute ($object,$attr,$dn) {
|
|
return $object->getSchemaAttribute($attr,$dn);
|
|
}
|
|
# @deprecated
|
|
function get_schema_objectclass ($object,$oclass) {
|
|
return $object->getSchemaObjectClass($oclass);
|
|
}
|
|
|
|
?>
|