* if( is_muli_line_attr( "postalAddress" ) )
* echo "";
* else
* echo "";
*
*
* @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:
*
* $obfuscate_password_display = true;
*
*
* @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('=',$element);
$dn[$i] = $element;
}
$dn = implode(',',$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:
*
* 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
*
* Will be sorted thus using usort( $list, "pla_compare_dns" ):
*
* 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
*
*
* @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:
*
* $show_hints = true;
*
*
* @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];
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;
}
$results[] = $entry;
}
} else {
$search = pla_ldap_search( $ldapserver, $filter, $base_dn, array('uidNumber','gidNumber'));
foreach ($search as $dn => $attrs) {
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;
}
$results[] = $entry;
}
}
# construct a list of used numbers
$autonum = array();
foreach ($results as $result)
$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:
*
* $read_only_attrs = array( "objectClass", "givenName" );
*
*
* @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:
*
* $hidden_attrs = array( "objectClass", "givenName" );
*
* or
*
* $hidden_attrs_ro = array( "objectClass", "givenName", "shadowWarning",
* "shadowLastChange", "shadowMax", "shadowFlag",
* "shadowInactive", "shadowMin", "shadowExpire" );
*
*
* @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:
*
* $server[$i]['read_only'] = true;
*
*
* @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:
*
*
* dc=example,dc=com
* ou=People
* cn=Dave
* cn=Fred
* cn=Joe
* ou=More People
* cn=Mark
* cn=Bob
*
*
* Calling get_container_contents( $server_id, "ou=people,dc=example,dc=com" )
* would return the following list:
*
*
* cn=Dave
* cn=Fred
* cn=Joe
* ou=More People
*
*
* @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:
*
* Array (
* 0 => Array ( )
* 1 => Array ( )
* )
*
* 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:
*
* Array
* (
* [0] => Array
* (
* [dc=example,dc=com] => "dcobject.png"
* )
* [1] => Array
* (
* [o=Corporation] => "o.png"
* )
* )
*
* 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:
*
* Array
* (
* [creatorsName] => Array
* (
* [0] => "cn=Admin,dc=example,dc=com"
* )
* [createTimeStamp]=> Array
* (
* [0] => "10401040130"
* )
* [hasSubordinates] => Array
* (
* [0] => "FALSE"
* )
* )
*
*
* @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 get_object_attrs( 0, "cn=Bob,ou=pepole,dc=example,dc=com" )
*
*
* 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
* )
* )
*
*
* @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:
*
*
* 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"
* // )
*
*
* @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 )
* $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"
* // )
* // )
*
*
* 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
* Array
* (
* [title] => "Invalid Credentials"
* [description] => "An invalid username and/or password was supplied to the LDAP server."
* )
*
*/
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;
?>
'; } 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 ' '; echo sprintf( $lang['ferror_discription'], $verbose_error['desc']); } else { echo sprintf($lang['ferror_number_short'], $ldap_err_no); echo ' '; echo $lang['ferror_discription_short']; } if (function_exists('syslog_err')) syslog_err(sprintf($lang['ferror_number_short'],$ldap_err_no)); } ?> |