diff --git a/templates/template04-ldap/Readme.md b/templates/template04-ldap/Readme.md index 3af1277..641d363 100644 --- a/templates/template04-ldap/Readme.md +++ b/templates/template04-ldap/Readme.md @@ -7,10 +7,9 @@ |File name | Description| | --- | --- | -| `config.php` | phpLdapAdmin configuration file | | `debconf-slapd.conf | Pre-filled answers to questions for silent installation of slapd | -| `functions.php` | [See this PR](https://github.com/leenooks/phpLDAPadmin/pull/176/files#diff-64fc045898c96c86bd7e2ffbb496f91238a16e813a5af12395c3afe24878079f) | -| phpldapadmin.conf | Apache virtual host file | +| `lam.conf| Main configuration file for [LDAP Account Manager](https://www.ldap-account-manager.org/lamcms) | +| `ldap-account-manager.conf` | Apache virtual host file | | `rootCA.pem` | The rootCA previously created in your host machine | | `rootCA-key.pem` | The rootCA key previously created in your host machine | diff --git a/templates/template04-ldap/Vagrantfile b/templates/template04-ldap/Vagrantfile index d653fec..bec10bb 100644 --- a/templates/template04-ldap/Vagrantfile +++ b/templates/template04-ldap/Vagrantfile @@ -4,9 +4,9 @@ Vagrant.configure("2") do |config| - config.vm.box = "isc/forge-clt-ubuntu-22.04" + config.vm.box = "rcasys/ubuntu2404" - config.vm.box_version = "1" + config.vm.box_version = "0.1.1" config.vm.box_check_update = false @@ -16,16 +16,11 @@ lxd.name = '' lxd.project = 'default' lxd.profiles = ['default'] - # lxd.nesting = nil - # lxd.privileged = nil - # lxd.ephemeral = false - # lxd.environment = {} - # lxd.config = {} end config.vm.provision "shell" do |s| s.env = { - "MACHINE_HOSTNAME" => "", + "MACHINE_HOSTNAME" => "", } s.path = "provision.sh" end diff --git a/templates/template04-ldap/artifacts/config.php b/templates/template04-ldap/artifacts/config.php deleted file mode 100644 index e0ce7f5..0000000 --- a/templates/template04-ldap/artifacts/config.php +++ /dev/null @@ -1,576 +0,0 @@ -custom variable to do so. - * For example, the default for defining the language in config_default.php - * - * $this->default->appearance['language'] = array( - * 'desc'=>'Language', - * 'default'=>'auto'); - * - * to override this, use $config->custom->appearance['language'] = 'en_EN'; - * - * This file is also used to configure your LDAP server connections. - * - * You must specify at least one LDAP server there. You may add - * as many as you like. You can also specify your language, and - * many other options. - * - * NOTE: Commented out values in this file prefixed by //, represent the - * defaults that have been defined in config_default.php. - * Commented out values prefixed by #, dont reflect their default value, you can - * check config_default.php if you want to see what the default is. - * - * DONT change config_default.php, you changes will be lost by the next release - * of PLA. Instead change this file - as it will NOT be replaced by a new - * version of phpLDAPadmin. - */ - -/********************************************* - * Useful important configuration overrides * - *********************************************/ - -/* If you are asked to put PLA in debug mode, this is how you do it: */ -# $config->custom->debug['level'] = 255; -# $config->custom->debug['syslog'] = true; -# $config->custom->debug['file'] = '/tmp/pla_debug.log'; - -/* phpLDAPadmin can encrypt the content of sensitive cookies if you set this - to a big random string. */ -// $config->custom->session['blowfish'] = null; - -/* If your auth_type is http, you can override your HTTP Authentication Realm. */ -// $config->custom->session['http_realm'] = sprintf('%s %s',app_name(),'login'); - -/* The language setting. If you set this to 'auto', phpLDAPadmin will attempt - to determine your language automatically. - If PLA doesnt show (all) strings in your language, then you can do some - translation at http://translations.launchpad.net/phpldapadmin and download - the translation files, replacing those provided with PLA. - (We'll pick up the translations before making the next release too!) */ -// $config->custom->appearance['language'] = 'auto'; - -/* The temporary storage directory where we will put jpegPhoto data - This directory must be readable and writable by your web server. */ -// $config->custom->jpeg['tmpdir'] = '/tmp'; // Example for Unix systems -# $config->custom->jpeg['tmpdir'] = 'c:\\temp'; // Example for Windows systems - -/* Set this to (bool)true if you do NOT want a random salt used when - calling crypt(). Instead, use the first two letters of the user's - password. This is insecure but unfortunately needed for some older - environments. */ -# $config->custom->password['no_random_crypt_salt'] = true; - -/* PHP script timeout control. If php runs longer than this many seconds then - PHP will stop with an Maximum Execution time error. Increase this value from - the default if queries to your LDAP server are slow. The default is either - 30 seconds or the setting of max_exection_time if this is null. */ -// $config->custom->session['timelimit'] = 30; - -/* Our local timezone - This is to make sure that when we ask the system for the current time, we - get the right local time. If this is not set, all time() calculations will - assume UTC if you have not set PHP date.timezone. */ -// $config->custom->appearance['timezone'] = null; -# $config->custom->appearance['timezone'] = 'Australia/Melbourne'; - -/********************************************* - * Commands * - *********************************************/ - -/* Command availability ; if you don't authorize a command the command - links will not be shown and the command action will not be permitted. - For better security, set also ACL in your ldap directory. */ -/* -$config->custom->commands['cmd'] = array( - 'entry_internal_attributes_show' => true, - 'entry_refresh' => true, - 'oslinks' => true, - 'switch_template' => true -); - -$config->custom->commands['script'] = array( - 'add_attr_form' => true, - 'add_oclass_form' => true, - 'add_value_form' => true, - 'collapse' => true, - 'compare' => true, - 'compare_form' => true, - 'copy' => true, - 'copy_form' => true, - 'create' => true, - 'create_confirm' => true, - 'delete' => true, - 'delete_attr' => true, - 'delete_form' => true, - 'draw_tree_node' => true, - 'expand' => true, - 'export' => true, - 'export_form' => true, - 'import' => true, - 'import_form' => true, - 'login' => true, - 'logout' => true, - 'login_form' => true, - 'mass_delete' => true, - 'mass_edit' => true, - 'mass_update' => true, - 'modify_member_form' => true, - 'monitor' => true, - 'purge_cache' => true, - 'query_engine' => true, - 'rename' => true, - 'rename_form' => true, - 'rdelete' => true, - 'refresh' => true, - 'schema' => true, - 'server_info' => true, - 'show_cache' => true, - 'template_engine' => true, - 'update_confirm' => true, - 'update' => true -); -*/ - -/********************************************* - * Appearance * - *********************************************/ - -/* If you want to choose the appearance of the tree, specify a class name which - inherits from the Tree class. */ -// $config->custom->appearance['tree'] = 'AJAXTree'; -# $config->custom->appearance['tree'] = 'HTMLTree'; - -/* Just show your custom templates. */ -// $config->custom->appearance['custom_templates_only'] = false; - -/* Disable the default template. */ -// $config->custom->appearance['disable_default_template'] = false; - -/* Hide the warnings for invalid objectClasses/attributes in templates. */ -$config->custom->appearance['hide_template_warning'] = true; - -/* Set to true if you would like to hide header and footer parts. */ -// $config->custom->appearance['minimalMode'] = false; - -/* Configure what objects are shown in left hand tree */ -// $config->custom->appearance['tree_filter'] = '(objectclass=*)'; - -/* The height and width of the tree. If these values are not set, then - no tree scroll bars are provided. */ -// $config->custom->appearance['tree_height'] = null; -# $config->custom->appearance['tree_height'] = 600; -// $config->custom->appearance['tree_width'] = null; -# $config->custom->appearance['tree_width'] = 250; - -/* Confirm create and update operations, allowing you to review the changes - and optionally skip attributes during the create/update operation. */ -// $config->custom->confirm['create'] = true; -// $config->custom->confirm['update'] = true; - -/* Confirm copy operations, and treat them like create operations. This allows - you to edit the attributes (thus changing any that might conflict with - uniqueness) before creating the new entry. */ -// $config->custom->confirm['copy'] = true; - -/********************************************* - * User-friendly attribute translation * - *********************************************/ - -/* Use this array to map attribute names to user friendly names. For example, if - you don't want to see "facsimileTelephoneNumber" but rather "Fax". */ -// $config->custom->appearance['friendly_attrs'] = array(); -$config->custom->appearance['friendly_attrs'] = array( - 'facsimileTelephoneNumber' => 'Fax', - 'gid' => 'Group', - 'mail' => 'Email', - 'telephoneNumber' => 'Telephone', - 'uid' => 'User Name', - 'userPassword' => 'Password' -); - -/********************************************* - * Hidden attributes * - *********************************************/ - -/* You may want to hide certain attributes from being edited. If you want to - hide attributes from the user, you should use your LDAP servers ACLs. - NOTE: The user must be able to read the hide_attrs_exempt entry to be - excluded. */ -// $config->custom->appearance['hide_attrs'] = array(); -# $config->custom->appearance['hide_attrs'] = array('objectClass'); - -/* Members of this list will be exempt from the hidden attributes. */ -// $config->custom->appearance['hide_attrs_exempt'] = null; -# $config->custom->appearance['hide_attrs_exempt'] = 'cn=PLA UnHide,ou=Groups,c=AU'; - -/********************************************* - * Read-only attributes * - *********************************************/ - -/* You may want to phpLDAPadmin to display certain attributes as read only, - meaning that users will not be presented a form for modifying those - attributes, and they will not be allowed to be modified on the "back-end" - either. You may configure this list here: - NOTE: The user must be able to read the readonly_attrs_exempt entry to be - excluded. */ -// $config->custom->appearance['readonly_attrs'] = array(); - -/* Members of this list will be exempt from the readonly attributes. */ -// $config->custom->appearance['readonly_attrs_exempt'] = null; -# $config->custom->appearance['readonly_attrs_exempt'] = 'cn=PLA ReadWrite,ou=Groups,c=AU'; - -/********************************************* - * Group attributes * - *********************************************/ - -/* Add "modify group members" link to the attribute. */ -// $config->custom->modify_member['groupattr'] = array('member','uniqueMember','memberUid'); - -/* Configure filter for member search. This only applies to "modify group members" feature */ -// $config->custom->modify_member['filter'] = '(objectclass=Person)'; - -/* Attribute that is added to the group member attribute. */ -// $config->custom->modify_member['attr'] = 'dn'; - -/* For Posix attributes */ -// $config->custom->modify_member['posixattr'] = 'uid'; -// $config->custom->modify_member['posixfilter'] = '(uid=*)'; -// $config->custom->modify_member['posixgroupattr'] = 'memberUid'; - -/********************************************* - * Support for attrs display order * - *********************************************/ - -/* Use this array if you want to have your attributes displayed in a specific - order. You can use default attribute names or their fridenly names. - For example, "sn" will be displayed right after "givenName". All the other - attributes that are not specified in this array will be displayed after in - alphabetical order. */ -// $config->custom->appearance['attr_display_order'] = array(); -# $config->custom->appearance['attr_display_order'] = array( -# 'givenName', -# 'sn', -# 'cn', -# 'displayName', -# 'uid', -# 'uidNumber', -# 'gidNumber', -# 'homeDirectory', -# 'mail', -# 'userPassword' -# ); - -/********************************************* - * Define your LDAP servers in this section * - *********************************************/ - -$servers = new Datastore(); - -/* $servers->NewServer('ldap_pla') must be called before each new LDAP server - declaration. */ -$servers->newServer('ldap_pla'); - -/* A convenient name that will appear in the tree viewer and throughout - phpLDAPadmin to identify this LDAP server to users. */ -$servers->setValue('server','name','LDAP Server - localenv.com'); - -/* Examples: - 'ldap.example.com', - 'ldaps://ldap.example.com/', - 'ldapi://%2fusr%local%2fvar%2frun%2fldapi' - (Unix socket at /usr/local/var/run/ldap) */ -$servers->setValue('server','host','127.0.0.1'); - -/* The port your LDAP server listens on (no quotes). 389 is standard. */ -// $servers->setValue('server','port',389); - -/* Array of base DNs of your LDAP server. Leave this blank to have phpLDAPadmin - auto-detect it for you. */ -$servers->setValue('server','base',array('dc=localenv,dc=com')); - -/* Five options for auth_type: - 1. 'cookie': you will login via a web form, and a client-side cookie will - store your login dn and password. - 2. 'session': same as cookie but your login dn and password are stored on the - web server in a persistent session variable. - 3. 'http': same as session but your login dn and password are retrieved via - HTTP authentication. - 4. 'config': specify your login dn and password here in this config file. No - login will be required to use phpLDAPadmin for this server. - 5. 'sasl': login will be taken from the webserver's kerberos authentication. - Currently only GSSAPI has been tested (using mod_auth_kerb). - - Choose wisely to protect your authentication information appropriately for - your situation. If you choose 'cookie', your cookie contents will be - encrypted using blowfish and the secret your specify above as - session['blowfish']. */ -$servers->setValue('login','auth_type','session'); - -/* The DN of the user for phpLDAPadmin to bind with. For anonymous binds or - 'cookie','session' or 'sasl' auth_types, LEAVE THE LOGIN_DN AND LOGIN_PASS - BLANK. If you specify a login_attr in conjunction with a cookie or session - auth_type, then you can also specify the bind_id/bind_pass here for searching - the directory for users (ie, if your LDAP server does not allow anonymous - binds. */ -$servers->setValue('login','bind_id','cn=admin,dc=localenv,dc=com'); -# $servers->setValue('login','bind_id','cn=Manager,dc=example,dc=com'); - -/* Your LDAP password. If you specified an empty bind_id above, this MUST also - be blank. */ -// $servers->setValue('login','bind_pass',''); -# $servers->setValue('login','bind_pass','secret'); - -/* Use TLS (Transport Layer Security) to connect to the LDAP server. */ -// $servers->setValue('server','tls',false); - -/************************************ - * SASL Authentication * - ************************************/ - -/* Enable SASL authentication LDAP SASL authentication requires PHP 5.x - configured with --with-ldap-sasl=DIR. If this option is disabled (ie, set to - false), then all other sasl options are ignored. */ -// $servers->setValue('login','auth_type','sasl'); - -/* SASL auth mechanism */ -// $servers->setValue('sasl','mech','GSSAPI'); - -/* SASL authentication realm name */ -// $servers->setValue('sasl','realm',''); -# $servers->setValue('sasl','realm','EXAMPLE.COM'); - -/* SASL authorization ID name - If this option is undefined, authorization id will be computed from bind DN, - using authz_id_regex and authz_id_replacement. */ -// $servers->setValue('sasl','authz_id', null); - -/* SASL authorization id regex and replacement - When authz_id property is not set (default), phpLDAPAdmin will try to - figure out authorization id by itself from bind distinguished name (DN). - - This procedure is done by calling preg_replace() php function in the - following way: - - $authz_id = preg_replace($sasl_authz_id_regex,$sasl_authz_id_replacement, - $bind_dn); - - For info about pcre regexes, see: - - pcre(3), perlre(3) - - http://www.php.net/preg_replace */ -// $servers->setValue('sasl','authz_id_regex',null); -// $servers->setValue('sasl','authz_id_replacement',null); -# $servers->setValue('sasl','authz_id_regex','/^uid=([^,]+)(.+)/i'); -# $servers->setValue('sasl','authz_id_replacement','$1'); - -/* SASL auth security props. - See http://beepcore-tcl.sourceforge.net/tclsasl.html#anchor5 for explanation. */ -// $servers->setValue('sasl','props',null); - -/* Default password hashing algorithm. One of md5, ssha, sha, md5crpyt, smd5, - blowfish, crypt or leave blank for now default algorithm. */ -// $servers->setValue('appearance','password_hash_custom','md5'); - -/* If you specified 'cookie' or 'session' as the auth_type above, you can - optionally specify here an attribute to use when logging in. If you enter - 'uid' and login as 'dsmith', phpLDAPadmin will search for (uid=dsmith) - and log in as that user. - Leave blank or specify 'dn' to use full DN for logging in. Note also that if - your LDAP server requires you to login to perform searches, you can enter the - DN to use when searching in 'bind_id' and 'bind_pass' above. */ -// $servers->setValue('login','attr','dn'); - -/* Base DNs to used for logins. If this value is not set, then the LDAP server - Base DNs are used. */ -// $servers->setValue('login','base',array()); - -/* If 'login,attr' is used above such that phpLDAPadmin will search for your DN - at login, you may restrict the search to a specific objectClasses. EG, set this - to array('posixAccount') or array('inetOrgPerson',..), depending upon your - setup. */ -// $servers->setValue('login','class',array()); - -/* If you specified something different from 'dn', for example 'uid', as the - login_attr above, you can optionally specify here to fall back to - authentication with dn. - This is useful, when users should be able to log in with their uid, but - the ldap administrator wants to log in with his root-dn, that does not - necessarily have the uid attribute. - When using this feature, login_class is ignored. */ -// $servers->setValue('login','fallback_dn',false); - -/* Specify true If you want phpLDAPadmin to not display or permit any - modification to the LDAP server. */ -// $servers->setValue('server','read_only',false); - -/* Specify false if you do not want phpLDAPadmin to draw the 'Create new' links - in the tree viewer. */ -// $servers->setValue('appearance','show_create',true); - -/* Set to true if you would like to initially open the first level of each tree. */ -// $servers->setValue('appearance','open_tree',false); - -/* This feature allows phpLDAPadmin to automatically determine the next - available uidNumber for a new entry. */ -// $servers->setValue('auto_number','enable',true); - -/* The mechanism to use when finding the next available uidNumber. Two possible - values: 'uidpool' or 'search'. - The 'uidpool' mechanism uses an existing uidPool entry in your LDAP server to - blindly lookup the next available uidNumber. The 'search' mechanism searches - for entries with a uidNumber value and finds the first available uidNumber - (slower). */ -// $servers->setValue('auto_number','mechanism','search'); - -/* The DN of the search base when the 'search' mechanism is used above. */ -# $servers->setValue('auto_number','search_base','ou=People,dc=example,dc=com'); - -/* The minimum number to use when searching for the next available number - (only when 'search' is used for auto_number. */ -// $servers->setValue('auto_number','min',array('uidNumber'=>1000,'gidNumber'=>500)); - -/* If you set this, then phpldapadmin will bind to LDAP with this user ID when - searching for the uidnumber. The idea is, this user id would have full - (readonly) access to uidnumber in your ldap directory (the logged in user - may not), so that you can be guaranteed to get a unique uidnumber for your - directory. */ -// $servers->setValue('auto_number','dn',null); - -/* The password for the dn above. */ -// $servers->setValue('auto_number','pass',null); - -/* Enable anonymous bind login. */ -// $servers->setValue('login','anon_bind',true); - -/* Use customized page with prefix when available. */ -# $servers->setValue('custom','pages_prefix','custom_'); - -/* If you set this, then only these DNs are allowed to log in. This array can - contain individual users, groups or ldap search filter(s). Keep in mind that - the user has not authenticated yet, so this will be an anonymous search to - the LDAP server, so make your ACLs allow these searches to return results! */ -# $servers->setValue('login','allowed_dns',array( -# 'uid=stran,ou=People,dc=example,dc=com', -# '(&(gidNumber=811)(objectClass=groupOfNames))', -# '(|(uidNumber=200)(uidNumber=201))', -# 'cn=callcenter,ou=Group,dc=example,dc=com')); - -/* Set this if you dont want this LDAP server to show in the tree */ -// $servers->setValue('server','visible',true); - -/* Set this if you want to hide the base DNs that dont exist instead of - displaying the message "The base entry doesnt exist, create it?" -// $servers->setValue('server','hide_noaccess_base',false); -# $servers->setValue('server','hide_noaccess_base',true); - -/* This is the time out value in minutes for the server. After as many minutes - of inactivity you will be automatically logged out. If not set, the default - value will be ( session_cache_expire()-1 ) */ -# $servers->setValue('login','timeout',30); - -/* Set this if you want phpldapadmin to perform rename operation on entry which - has children. Certain servers are known to allow it, certain are not. */ -// $servers->setValue('server','branch_rename',false); - -/* If you set this, then phpldapadmin will show these attributes as - internal attributes, even if they are not defined in your schema. */ -// $servers->setValue('server','custom_sys_attrs',array('')); -# $servers->setValue('server','custom_sys_attrs',array('passwordExpirationTime','passwordAllowChangeTime')); - -/* If you set this, then phpldapadmin will show these attributes on - objects, even if they are not defined in your schema. */ -// $servers->setValue('server','custom_attrs',array('')); -# $servers->setValue('server','custom_attrs',array('nsRoleDN','nsRole','nsAccountLock')); - -/* These attributes will be forced to MAY attributes and become option in the - templates. If they are not defined in the templates, then they wont appear - as per normal template processing. You may want to do this because your LDAP - server may automatically calculate a default value. - In Fedora Directory Server using the DNA Plugin one could ignore uidNumber, - gidNumber and sambaSID. */ -// $servers->setValue('server','force_may',array('')); -# $servers->setValue('server','force_may',array('uidNumber','gidNumber','sambaSID')); - -/********************************************* - * Unique attributes * - *********************************************/ - -/* You may want phpLDAPadmin to enforce some attributes to have unique values - (ie: not belong to other entries in your tree. This (together with - 'unique','dn' and 'unique','pass' option will not let updates to - occur with other attributes have the same value. */ -# $servers->setValue('unique','attrs',array('mail','uid','uidNumber')); - -/* If you set this, then phpldapadmin will bind to LDAP with this user ID when - searching for attribute uniqueness. The idea is, this user id would have full - (readonly) access to your ldap directory (the logged in user may not), so - that you can be guaranteed to get a unique uidnumber for your directory. */ -// $servers->setValue('unique','dn',null); - -/* The password for the dn above. */ -// $servers->setValue('unique','pass',null); - -/************************************************************************** - * If you want to configure additional LDAP servers, do so below. * - * Remove the commented lines and use this section as a template for all * - * your other LDAP servers. * - **************************************************************************/ - -/* -$servers->newServer('ldap_pla'); -$servers->setValue('server','name','LDAP Server'); -$servers->setValue('server','host','127.0.0.1'); -$servers->setValue('server','port',389); -$servers->setValue('server','base',array('')); -$servers->setValue('login','auth_type','cookie'); -$servers->setValue('login','bind_id',''); -$servers->setValue('login','bind_pass',''); -$servers->setValue('server','tls',false); - -# SASL auth -$servers->setValue('login','auth_type','sasl'); -$servers->setValue('sasl','mech','GSSAPI'); -$servers->setValue('sasl','realm','EXAMPLE.COM'); -$servers->setValue('sasl','authz_id',null); -$servers->setValue('sasl','authz_id_regex','/^uid=([^,]+)(.+)/i'); -$servers->setValue('sasl','authz_id_replacement','$1'); -$servers->setValue('sasl','props',null); - -$servers->setValue('appearance','password_hash_custom','md5'); -$servers->setValue('login','attr','dn'); -$servers->setValue('login','fallback_dn',false); -$servers->setValue('login','class',null); -$servers->setValue('server','read_only',false); -$servers->setValue('appearance','show_create',true); - -$servers->setValue('auto_number','enable',true); -$servers->setValue('auto_number','mechanism','search'); -$servers->setValue('auto_number','search_base',null); -$servers->setValue('auto_number','min',array('uidNumber'=>1000,'gidNumber'=>500)); -$servers->setValue('auto_number','dn',null); -$servers->setValue('auto_number','pass',null); - -$servers->setValue('login','anon_bind',true); -$servers->setValue('custom','pages_prefix','custom_'); -$servers->setValue('unique','attrs',array('mail','uid','uidNumber')); -$servers->setValue('unique','dn',null); -$servers->setValue('unique','pass',null); - -$servers->setValue('server','visible',true); -$servers->setValue('login','timeout',30); -$servers->setValue('server','branch_rename',false); -$servers->setValue('server','custom_sys_attrs',array('passwordExpirationTime','passwordAllowChangeTime')); -$servers->setValue('server','custom_attrs',array('nsRoleDN','nsRole','nsAccountLock')); -$servers->setValue('server','force_may',array('uidNumber','gidNumber','sambaSID')); -*/ -?> diff --git a/templates/template04-ldap/artifacts/functions.php b/templates/template04-ldap/artifacts/functions.php deleted file mode 100644 index 040d81f..0000000 --- a/templates/template04-ldap/artifacts/functions.php +++ /dev/null @@ -1,3309 +0,0 @@ -_('Generic Error'), - 'body'=>sprintf('%s: %s [%s]', - __METHOD__,_('Called to load a class that cant be found'),$className), - 'type'=>'error')); -} - -if (version_compare(phpversion(), '7.0', '>=')) { - spl_autoload_register('pla_autoload'); -} else { - eval('function __autoload($className) {pla_autoload($className);}'); -} - -/** - * Strips all slashes from the specified array in place (pass by ref). - * @param Array The array to strip slashes from, typically one of - * $_GET, $_POST, or $_COOKIE. - */ -function array_stripslashes(&$array) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - 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]); -} - -/** - * Compatibility Functions - * These functions exist, so that a standard function can be used in new applications, and they - * map to already defined functions in older applications. - */ - -/** - * If gettext is not available in PHP, then this will provide compatibility for it. - */ -if (! function_exists('_')) { - function _($msg) { - return $msg; - } -} - -/** - * Generic Utility Functions - */ - -/** - * Custom error handling function. - * When a PHP error occurs, PHP will call this function rather than printing - * the typical PHP error string. This provides the application the ability to - * format an error message so that it looks better. - * Optionally, it can present a link so that a user can search/submit bugs. - * This function is not to be called directly. 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 The PHP error number that occurred (ie, E_ERROR, E_WARNING, E_PARSE, etc). - * @param string The PHP error string provided (ie, "Warning index "foo" is undefined) - * @param string The file in which the PHP error ocurred. - * @param int The line number on which the PHP error ocurred - * @see set_error_handler - */ -function app_error_handler($errno,$errstr,$file,$lineno) { - if (defined('DEBUG_ENABLED') && DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - /** - * error_reporting will be only the non-ignorable error number bits - * 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 (!(ini_get('error_reporting') & error_reporting() & $errno)) - 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 = sprintf('%s: %s',_('Unrecognized error number'),$errno); - } - - # Take out extra spaces in error strings. - $errstr = preg_replace('/\s+/',' ',$errstr); - - if ($errno == E_NOTICE) { - $body = ''; - $body .= sprintf('',_('Error'),$errstr,$errtype); - $body .= sprintf('', - _('File'),$file,_('line'),$lineno,_('caller'),$caller); - $body .= sprintf('', - app_version(),phpversion(),php_sapi_name()); - $body .= sprintf('',isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'SCRIPT'); - - if (function_exists('get_href')) - $body .= sprintf('', - get_href('search_bug',"&summary_keyword=".rawurlencode($errstr)), - _('Please check and see if this bug has been reported')); - $body .= '
%s:%s (%s)
%s:%s %s %s, %s %s
Versions:PLA: %s, PHP: %s, SAPI: %s
Web server:%s
%s.
'; - - system_message(array( - 'title'=>_('You found a non-fatal phpLDAPadmin bug!'), - 'body'=>$body, - 'type'=>'error')); - - return; - } - - # If this is a more serious error, call the error call. - error(sprintf('%s: %s',$errtype,$errstr),'error',null,true,true); -} - -/** - * Returns the application name. - */ -function app_name() { - return 'phpLDAPadmin'; -} - -/** - * Returns the application version currently running. The version - * is read from the file named VERSION. - * - * @return string The current version as read from the VERSION file. - */ -function app_version() { - static $CACHE = null; - - if ($CACHE) - return $CACHE; - - $version_file = realpath(LIBDIR.'../VERSION'); - if (! file_exists($version_file)) - $CACHE = 'UNKNOWN'; - - else { - $version = rtrim(file_get_contents($version_file)); - - $CACHE = preg_replace('/^RELEASE-([0-9\.]+(-.*)*)$/','$1',$version); - - # Check if we are a CVS copy. - if (preg_match('/^(DEVEL)?$/',$CACHE)) - $CACHE = 'DEVEL'; - - # Check if we are special DEVEL version - elseif (preg_match('/^DEVEL-([0-9\.]+)+$/',$CACHE)) {} - - # If return is still the same as version, then the tag is not one we expect. - elseif ($CACHE == $version) - $CACHE = 'UNKNOWN'; - } - - return $CACHE; -} - -/** - * This function will convert the browser two character language into the - * default 5 character language, where the country portion should NOT be - * assumed to be upper case characters of the first two characters. - */ -function auto_lang($lang) { - switch ($lang) { - case 'ja': return 'ja_JP'; - case 'cs': return 'cs_CZ'; - default: return sprintf('%s_%s',$lang,strtoupper($lang)); - } -} - -/** - * Makes sure that the config file is properly setup. - */ -function check_config($config_file) { - # Read in config_default.php - require_once LIBDIR.'config_default.php'; - - # Make sure their PHP version is current enough - if (strcmp(phpversion(),REQUIRED_PHP_VERSION) < 0) - system_message(array( - 'title'=>_('Incorrect version of PHP'), - 'body'=>sprintf('phpLDAPadmin requires PHP version %s or greater.
(You are using %s)', - REQUIRED_PHP_VERSION,phpversion()), - 'type'=>'error')); - - $config = new Config; - - if (file_exists(LIBDIR.'config_custom.php') && is_readable(LIBDIR.'config_custom.php')) - include LIBDIR.'config_custom.php'; - - ob_start(); - require $config_file; - $str = ''; - if (ob_get_level()) { - $str = ob_get_contents(); - ob_end_clean(); - } - - if ($str) { - $str = strip_tags($str); - $matches = array(); - preg_match('/(.*):\s+(.*):.*\s+on line (\d+)/',$str,$matches); - - if (isset($matches[1]) && isset($matches[2]) && isset($matches[3])) { - $error_type = $matches[1]; - $error = $matches[2]; - $line_num = $matches[3]; - - $file = file($config_file); - - $body = '

Config file ERROR

'; - $body .= sprintf('

%s (%s) on line %s

',$error_type,$error,$line_num); - - $body .= '
'; - $body .= sprintf('Looks like your config file has an ERROR on line %s.
',$line_num); - $body .= 'Here is a snippet around that line
'; - $body .= '
'."\n"; - - $body .= '
'; - - for ($i = $line_num-9; $i<$line_num+5; $i++) { - if ($i+1 == $line_num) - $body .= '
'; - - if ($i < 0) - continue; - - $body .= sprintf('%s: %s
',$i+1,$file[$i]); - - if ($i+1 == $line_num) - $body .= '
'; - } - - $body .= '
'; - $body .= '
'; - $body .= 'Hint: Sometimes these errors are caused by lines preceding the line reported.'; - $body .= '
'; - - $block = new block(); - $block->SetBody($body); - $www['page'] = new page(); - $www['page']->block_add('body',$block); - $www['page']->display(); - - die(); - } - } - - # Check for server definitions. - if (! isset($servers) || count($servers->GetServerList()) == 0) - error(_('Your config.php is missing Server Definitions. Please see the sample file config/config.php.example.'),'error','index.php',true); - - $config->setServers($servers); - - # Check the memory limit parameter. - if ((ini_get('memory_limit') > -1) && ini_get('memory_limit') < $config->getValue('session','memorylimit')) - system_message(array( - 'title'=>_('Memory Limit low.'), - 'body'=>sprintf('Your php memory limit is low - currently %s, you should increase it to atleast %s. This is normally controlled in /etc/php.ini.', - ini_get('memory_limit'),$config->getValue('session','memorylimit')), - 'type'=>'error')); - - return $config; -} - -/** - * Commands available in the control_panel of the page - * - * @return array - */ -function cmd_control_pane($type) { - if (defined('DEBUG_ENABLED') && DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - switch ($type) { - case 'main' : - return array( - 'home'=>array( - 'title'=>_('Home'), - 'enable'=>true, - 'link'=>sprintf('href="index.php" title="%s"',_('Home')), - 'image'=>sprintf('%s',IMGDIR,_('Home'))), - - 'purge'=>array( - 'title'=>_('Purge caches'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('script','purge_cache') : false, - 'link'=>sprintf('href="cmd.php?cmd=purge_cache" onclick="return ajDISPLAY(\'BODY\',\'cmd=purge_cache\',\'%s\');" title="%s"', - _('Clearing cache'),_('Purge caches')), - 'image'=>sprintf('%s',IMGDIR,_('Purge caches'))), - - 'hide_debug_info'=>array( - 'title'=>_('Show Cache'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? ($_SESSION[APPCONFIG]->isCommandAvailable('script','show_cache')) && (! $_SESSION[APPCONFIG]->getValue('appearance','hide_debug_info')) : false, - 'link'=>sprintf('href="cmd.php?cmd=show_cache" onclick="return ajDISPLAY(\'BODY\',\'cmd=show_cache\',\'%s\');" title="%s"', - _('Loading'),_('Show Cache'),_('Show Cache')), - 'image'=>sprintf('%s',IMGDIR,_('Show Cache'))), - ); - - break; - - case 'top' : - return array( - 'forum'=>array( - 'title'=>_('Forum'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('cmd','oslinks') : true, - 'link'=>sprintf('href="%s" title="%s" onclick="target=\'_blank\';"',get_href('forum'),_('Forum')), - 'image'=>sprintf('%s',IMGDIR,_('Forum'))), - - 'feature'=>array( - 'title'=>_('Request feature'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('cmd','oslinks') : true, - 'link'=>sprintf('href="%s" title="%s" onclick="target=\'_blank\';"',get_href('add_rfe'),_('Request feature')), - 'image'=>sprintf('%s',IMGDIR,_('Request feature'))), - - 'bug'=>array( - 'title'=>_('Report a bug'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('cmd','oslinks') : true, - 'link'=>sprintf('href="%s" title="%s" onclick="target=\'_blank\';"',get_href('add_bug'),_('Report a bug')), - 'image'=>sprintf('%s',IMGDIR,_('Report a bug'))), - - 'donation'=>array( - 'title'=>_('Donate'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('cmd','oslinks') : true, - 'link'=>sprintf('href="%s" title="%s" onclick="target=\'_blank\';"',get_href('donate'),_('Donate')), - 'image'=>sprintf('%s',IMGDIR,_('Donate'))), - - 'help'=>array( - 'title'=>_('Help'), - 'enable'=>isset($_SESSION[APPCONFIG]) ? $_SESSION[APPCONFIG]->isCommandAvailable('cmd','oslinks') : true, - 'link'=>sprintf('href="%s" title="%s" onclick="target=\'_blank\';"',get_href('documentation'),_('Help')), - 'image'=>sprintf('%s',IMGDIR,_('Help'))) - ); - - break; - } -} - -/** - * This function dumps the $variable for debugging purposes - * - * @param string|array Variable to dump - * @param boolean Whether to stop execution or not. - */ -function debug_dump($variable,$die=false,$onlydebugaddr=false) { - if ($onlydebugaddr && - isset($_SESSION[APPCONFIG]) && $_SESSION[APPCONFIG]->getValue('debug','addr') && - $_SERVER['HTTP_X_FORWARDED_FOR'] != $_SESSION[APPCONFIG]->getValue('debug','addr') && - $_SERVER['REMOTE_ADDR'] != $_SESSION[APPCONFIG]->getValue('debug','addr')) - return; - - $backtrace = debug_backtrace(); - $caller['class'] = isset($backtrace[0]['class']) ? $backtrace[0]['class'] : 'N/A'; - $caller['function'] = isset($backtrace[0]['function']) ? $backtrace[0]['function'] : 'N/A'; - $caller['file'] = isset($backtrace[0]['file']) ? $backtrace[0]['file'] : 'N/A'; - $caller['line'] = isset($backtrace[0]['line']) ? $backtrace[0]['line'] : 'N/A'; - $caller['debug'] = $variable; - - print '
';
-	print_r($caller);
-	print '
'; - - if ($die) - die(); -} - -/** - * This function generates a backtrace - * - * @param boolean Whether to stop execution or not. - */ -function debug_dump_backtrace($msg='Calling BackTrace',$die=false) { - error($msg,'note',null,$die,true); -} - -/** - * Send a debug as a sys message - */ -function debug_sysmsg($msg) { - system_message(array('title'=>_('Debug'),'body'=>$msg,'type'=>'debug')); -} - -/** - * Debug Logging - * - * The global debug level is turned on in your configuration file by setting: - * - * $config->custom->debug['level'] = 255; - * - * together with atleast one output direction (currently file and syslog are supported). - * - * $config->custom->debug['file'] = '/tmp/app_debug.log'; - * $config->custom->debug['syslog'] = true; - * - * - * The debug level is turned into binary, then if the message levels bit is on - * the message will be sent to the debug log. (Thus setting your debug level to 255, - * all bits on, will results in all messages being printed.) - * - * The message level bits are defined here. - * 0( 1) = Entry/Return results from function calls. - * 1( 2) = Configuration Processing - * 2( 4) = Template Processing - * 3( 8) = Schema Processing - * 4( 16) = LDAP Server Communication - * 5( 32) = Tree Processing - * 7( 64) = Other non generic messages - * 8(128) = Page Processing - * 9(256) = Hooks Processing - * @param string Message to send to syslog - * @param int Log bit number for this message. - * @see syslog.php - */ -function debug_log($msg,$level,$indent) { - static $debug_file; - - # In case we are called before we are fully initialised or if debugging is not set. - if (! isset($_SESSION[APPCONFIG]) - || ! ($_SESSION[APPCONFIG]->getValue('debug','file') || $_SESSION[APPCONFIG]->getValue('debug','syslog'))) - return; - - $debug_level = $_SESSION[APPCONFIG]->getValue('debug','level'); - if (! $debug_level || (! ($level & $debug_level))) - return; - - if ($_SESSION[APPCONFIG]->getValue('debug','addr')) - if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] == $_SESSION[APPCONFIG]->getValue('debug','addr')) - $debugaddr = true; - elseif ($_SERVER['REMOTE_ADDR'] == $_SESSION[APPCONFIG]->getValue('debug','addr')) - $debugaddr = true; - else - $debugaddr = false; - - else - $debugaddr = true; - - if (! $debugaddr) - return; - - # If we are limiting debug to a browser, then check that - $caller = basename($_SERVER['PHP_SELF']); - - $args = func_get_args(); - # Discard our first three arguments. - array_shift($args); - array_shift($args); - array_shift($args); - - # Pull the file/line/method - if (is_string($args[0]) && preg_match('/.php$/',$args[0])) { - $file = preg_replace('/.php$/','',array_shift($args)); - $line = array_shift($args); - $method = array_shift($args); - - } else { - $file = 'UNKNOWN'; - $line = 'UNKNOWN'; - $method = 'UNKNOWN'; - } - - # TEMP: New debuglog format - if (preg_match('/%%/',$msg) && $args[0] != 'NOARGS') - $args = array_shift($args); - - $fargs = array(); - foreach ($args as $key) { - if (is_array($key)) - array_push($fargs,serialize($key)); - elseif (is_object($key)) - array_push($fargs,sprintf('OBJECT:%s',get_class($key))); - else - array_push($fargs,$key); - } - - if (preg_match('/%%/',$msg)) - $msg = preg_replace('/%%/',join('|',$fargs),$msg); - else - $msg = vsprintf($msg,array_values($fargs)); - - if (function_exists('stopwatch')) - $timer = stopwatch(); - else - $timer = null; - - $debug_message = sprintf('[%2.3f] %15s(%04s-%03s): %s%s: %s',$timer,basename($file),$line,$level,str_repeat('.',$indent),$method,substr($msg,0,200)); - - if ($debug_file || $_SESSION[APPCONFIG]->getValue('debug','file')) { - if (! $debug_file) - $debug_file = fopen($_SESSION[APPCONFIG]->getValue('debug','file'), - $_SESSION[APPCONFIG]->getValue('debug','append') ? 'a' : 'w'); - - fwrite($debug_file,$debug_message."\n"); - } - - if ($_SESSION[APPCONFIG]->getValue('debug','syslog') && function_exists('syslog_notice')) - syslog_notice($debug_message); -} - -/** - * Display an error message in the system message panel of the page. - */ -function error($msg,$type='note',$redirect=null,$fatal=false,$backtrace=false) { - global $www; - static $counter; - - # Just a check to see that we are called right. - if (! isset($www['page']) && ! $fatal) - die("Function error called incorrectly [$msg]"); - - # If the error is fatal, we'll need to stop here. - if (! isset($www['page'])) - $www['page'] = new page(); - - if ($fatal) - $www['page']->setsysmsg(array('title'=>_('Error'),'body'=>$msg,'type'=>$type)); - else - system_message(array('title'=>_('Error'),'body'=>$msg,'type'=>$type),$redirect); - - # Spin loop detection - if ($counter++ > 20) { - debug_dump('Spin loop detection.'); - debug_dump(array('msg'=>$msg,'session'=>$_SESSION['sysmsg'],'www'=>$www),1); - } - - # Do we have a backtrace to display? - if ($backtrace) { - $backtraceblock = new block(); - $backtraceblock->SetTitle('PHP Debug Backtrace'); - - $body = ''; - $body .= "\n"; - - foreach (debug_backtrace() as $error => $line) { - $_SESSION['backtrace'][$error]['file'] = isset($line['file']) ? $line['file'] : 'unknown'; - $_SESSION['backtrace'][$error]['line'] = isset($line['line']) ? $line['line'] : 'unknown'; - $body .= sprintf('', - _('File'),isset($line['file']) ? $line['file'] : $last['file'],isset($line['line']) ? $line['line'] : ''); - - $_SESSION['backtrace'][$error]['function'] = $line['function']; - $body .= sprintf(''; - $body .= "\n"; - - if (isset($line['file'])) - $last['file'] = $line['file']; - } - - $body .= '
%s%s (%s)
 %s%s', - _('Function'),$line['function']); - - if (isset($line['args'])) { - $display = strlen(serialize($line['args'])) < 50 ? htmlspecialchars(serialize($line['args'])) : htmlspecialchars(substr(serialize($line['args']),0,50)).'...'; - $_SESSION['backtrace'][$error]['args'] = $line['args']; - if (file_exists(LIBDIR.'../tools/unserialize.php')) - $body .= sprintf(' (%s)', - '../tools/unserialize.php',$error,$display); - else - $body .= sprintf(' (%s)',$display); - } - $body .= '
'; - $body .= "\n"; - $backtraceblock->SetBody($body); - - $www['page']->block_add('body',$backtraceblock); - } - - if ($fatal) { - $www['page']->display(array('tree'=>false)); - die(); - } -} - -/** - * Return the result of a form variable, with optional default - * - * @return The form GET/REQUEST/SESSION/POST variable value or its default - */ -function get_request($attr,$type='POST',$die=false,$default=null,$preventXSS=true) { - switch($type) { - case 'GET': - $value = isset($_GET[$attr]) ? (is_array($_GET[$attr]) ? $_GET[$attr] : (empty($_GET['nodecode'][$attr]) ? rawurldecode($_GET[$attr]) : $_GET[$attr])) : $default; - break; - - case 'REQUEST': - $value = isset($_REQUEST[$attr]) ? (is_array($_REQUEST[$attr]) ? $_REQUEST[$attr] : (empty($_REQUEST['nodecode'][$attr]) ? rawurldecode($_REQUEST[$attr]) : $_REQUEST[$attr])) : $default; - break; - - case 'SESSION': - $value = isset($_SESSION[$attr]) ? (is_array($_SESSION[$attr]) ? $_SESSION[$attr] : (empty($_SESSION['nodecode'][$attr]) ? rawurldecode($_SESSION[$attr]) : $_SESSION[$attr])) : $default; - break; - - case 'POST': - default: - $value = isset($_POST[$attr]) ? (is_array($_POST[$attr]) ? $_POST[$attr] : (empty($_POST['nodecode'][$attr]) ? rawurldecode($_POST[$attr]) : $_POST[$attr])) : $default; - break; - } - - if ($die && is_null($value)) - system_message(array( - 'title'=>_('Generic Error'), - 'body'=>sprintf('%s: Called "%s" without "%s" using "%s"', - basename($_SERVER['PHP_SELF']),get_request('cmd','REQUEST'),preventXSS($attr),preventXSS($type)), - 'type'=>'error'), - 'index.php'); - if($preventXSS && !is_null($value)) - $value = preventXSS($value); - return $value; -} -/** -* Prevent XSS function. This function can usage has preventXSS(get_request('cmd','REQUEST')) -* Return valor escape XSS. -*/ - function preventXSS($data){ - if (gettype($data) == 'array') { - foreach ($data as $key => $value) { - if (gettype($value) == 'array') - $data[$key] = preventXSS($value); - else - $data[$key] = htmlspecialchars($value); - } - return $data; - } - return htmlspecialchars($data, ENT_QUOTES, 'UTF-8'); -} - -/* - * Record a system message. - * This function can be used as an alternative to generate a system message, if page hasnt yet been defined. - */ -function system_message($msg,$redirect=null) { - if (! is_array($msg)) - return null; - - if (! isset($msg['title']) && ! isset($msg['body'])) - return null; - - if (! isset($msg['type'])) - $msg['type'] = 'info'; - - if (! isset($_SESSION['sysmsg']) || ! is_array($_SESSION['sysmsg'])) - $_SESSION['sysmsg'] = array(); - - # Try and detect if we are in a redirect loop - if (get_request('redirect','GET') && $msg['type'] != 'debug') { - foreach ($_SESSION['sysmsg'] as $detail) { - if ($msg == $detail && ! isset($detail['special'])) { - debug_dump(array('Incoming MSG'=>$msg,'existing'=>$_SESSION['sysmsg'])); - debug_dump_backtrace('Redirect Loop Detected',true); - } - } - } - - array_push($_SESSION['sysmsg'],$msg); - - if ($redirect) { - if (preg_match('/\?/',$redirect)) - $redirect .= '&'; - else - $redirect .= '?'; - $redirect .= 'redirect=true'; - - # Check if we were an ajax request, and only render the ajax message - if (get_request('meth','REQUEST') == 'ajax') - $redirect .= '&meth=ajax'; - - header("Location: $redirect"); - die(); - } -} - -/** - * Other Functions - */ - -/** - * Encryption using blowfish algorithm - * - * @param string Original data - * @param string The secret - * @return string The encrypted result - * @author lem9 (taken from the phpMyAdmin source) - */ -function blowfish_encrypt($data,$secret=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # If our secret is null or blank, get the default. - if ($secret === null || ! trim($secret)) - $secret = $_SESSION[APPCONFIG]->getValue('session','blowfish') ? $_SESSION[APPCONFIG]->getValue('session','blowfish') : session_id(); - - # If the secret isnt set, then just return the data. - if (! trim($secret)) - return $data; - - if (! empty($data) && function_exists('openssl_encrypt') && in_array(SESSION_CIPHER, openssl_get_cipher_methods())) { - $keylen = openssl_cipher_iv_length(SESSION_CIPHER) * 2; - return openssl_encrypt($data, SESSION_CIPHER, substr($secret,0,$keylen)); - } - - if (function_exists('mcrypt_module_open') && ! empty($data)) { - $td = mcrypt_module_open(MCRYPT_BLOWFISH,'',MCRYPT_MODE_ECB,''); - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_DEV_URANDOM); - mcrypt_generic_init($td,substr($secret,0,mcrypt_enc_get_key_size($td)),$iv); - $encrypted_data = base64_encode(mcrypt_generic($td,$data)); - mcrypt_generic_deinit($td); - - return $encrypted_data; - } - - if (file_exists(LIBDIR.'blowfish.php')) - require_once LIBDIR.'blowfish.php'; - else - return $data; - - $pma_cipher = new Horde_Cipher_blowfish; - $encrypt = ''; - - for ($i=0; $iencryptBlock($block, $secret); - } - - return base64_encode($encrypt); -} - -/** - * Decryption using blowfish algorithm - * - * @param string Encrypted data - * @param string The secret - * @return string Original data - * @author lem9 (taken from the phpMyAdmin source) - */ -function blowfish_decrypt($encdata,$secret=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # 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 = $_SESSION[APPCONFIG]->getValue('session','blowfish') ? $_SESSION[APPCONFIG]->getValue('session','blowfish') : session_id(); - - # If the secret isnt set, then just return the data. - if (! trim($secret)) - return $encdata; - - if (! empty($encdata) && function_exists('openssl_encrypt') && in_array(SESSION_CIPHER, openssl_get_cipher_methods())) { - $keylen = openssl_cipher_iv_length(SESSION_CIPHER) * 2; - return trim(openssl_decrypt($encdata, SESSION_CIPHER, substr($secret,0,$keylen))); - } - - if (function_exists('mcrypt_module_open') && ! empty($encdata)) { - $td = mcrypt_module_open(MCRYPT_BLOWFISH,'',MCRYPT_MODE_ECB,''); - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_DEV_URANDOM); - mcrypt_generic_init($td,substr($secret,0,mcrypt_enc_get_key_size($td)),$iv); - $decrypted_data = trim(mdecrypt_generic($td,base64_decode($encdata))); - mcrypt_generic_deinit($td); - - return $decrypted_data; - } - - if (file_exists(LIBDIR.'blowfish.php')) - require_once LIBDIR.'blowfish.php'; - else - return $encdata; - - $pma_cipher = new Horde_Cipher_blowfish; - $decrypt = ''; - $data = base64_decode($encdata); - - for ($i=0; $idecryptBlock(substr($data, $i, 8), $secret); - - // Strip off our \0's that were added. - $return = preg_replace("/\\0*$/",'',$decrypt); - $CACHE[$encdata] = $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 && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $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; -} - -/** - * 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($index,$item,$subitem='null') { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # Set default return - $return = null; - - # Check config to make sure session-based caching is enabled. - if ($_SESSION[APPCONFIG]->getValue('cache',$item) && isset($_SESSION['cache'][$index][$item][$subitem])) - $return = $_SESSION['cache'][$index][$item][$subitem]; - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * Caches the specified $item for the specified $index. - * - * Returns true on success of false on failure. - */ -function set_cached_item($index,$data,$item,$subitem='null') { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # Check config to make sure session-based caching is enabled. - if ($_SESSION[APPCONFIG]->getValue('cache',$item)) { - global $CACHE; - - $CACHE[$index][$item][$subitem] = $data; - $_SESSION['cache'][$index][$item][$subitem] = $data; - - return true; - - } else - return false; -} - -/** - * Deletes the cache for a specified $item for the specified $index - */ -function del_cached_item($index,$item,$subitem='null') { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - global $CACHE; - - # Check config to make sure session-based caching is enabled. - if (isset($_SESSION['cache'][$index][$item][$subitem])) - unset($_SESSION['cache'][$index][$item][$subitem]); - - if (isset($CACHE[$index][$item][$subitem])) - unset($CACHE[$index][$item][$subitem]); -} - -/** - * Utility wrapper for setting cookies, which takes into consideration - * application configuration values. On success, true is returned. On - * failure, false is returned. - * - * @param string The name of the cookie to set. - * @param string The value of the cookie to set. - * @param int (optional) The duration in seconds of this cookie. If unspecified, $cookie_time is used from config.php - * @param string (optional) The directory value of this cookie (see php.net/setcookie) - * @return boolean - */ -function set_cookie($name,$val,$expire=null,$dir=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # Set default return - $return = false; - - if ($expire == null) { - $cookie_time = $_SESSION[APPCONFIG]->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('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * Get a customized file for a server - * We don't need any caching, because it's done by PHP - * - * @param int The ID of the server - * @param string The requested filename - * - * @return string The customized filename, if exists, or the standard one - */ -function get_custom_file($index,$filename,$path) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # Set default return - $return = $path.$filename; - $server = $_SESSION[APPCONFIG]->getServer($index); - - $custom = $server->getValue('custom','pages_prefix'); - if (! is_null($custom) && is_file(realpath($path.$custom.$filename))) - $return = $path.$custom.$filename; - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * Replacement for create_function() which is deprecated as of php 7.2 - * - * @param string The function arguments - * @param string The function code - */ -function pla_create_function($args, $code) { - if (version_compare(phpversion(),'7.0','>=')) { - # anonymous functions were introduced in PHP 5.3.0 - return eval("return function(".$args."){".$code."};"); - - } else { - # create_function is deprecated in php 7.2 - return create_function($args, $code); - } -} - -/** - * Sort a multi dimensional array. - * - * @param array Multi demension array passed by reference - * @param string Comma delimited string of sort keys. - * @param boolean Whether to reverse sort. - * @return array Sorted multi demension array. - */ -function masort(&$data,$sortby,$rev=0) { - if (defined('DEBUG_ENABLED') && DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # if the array to sort is null or empty, or if we have some nasty chars - if (! preg_match('/^[a-zA-Z0-9_]+(\([a-zA-Z0-9_,]*\))?$/',$sortby) || ! $data) - return; - - static $CACHE = array(); - - if (empty($CACHE[$sortby])) { - $code = "\$c=0;\n"; - - foreach (explode(',',$sortby) as $key) { - $code .= "if (is_object(\$a) || is_object(\$b)) {\n"; - - $code .= " if (is_array(\$a->$key)) {\n"; - $code .= " asort(\$a->$key);\n"; - $code .= " \$aa = array_shift(\$a->$key);\n"; - $code .= " } else\n"; - $code .= " \$aa = \$a->$key;\n"; - - $code .= " if (is_array(\$b->$key)) {\n"; - $code .= " asort(\$b->$key);\n"; - $code .= " \$bb = array_shift(\$b->$key);\n"; - $code .= " } else\n"; - $code .= " \$bb = \$b->$key;\n"; - - $code .= " if (\$aa != \$bb)"; - if ($rev) - $code .= " return (\$aa < \$bb ? 1 : -1);\n"; - else - $code .= " return (\$aa > \$bb ? 1 : -1);\n"; - - $code .= "} else {\n"; - - $code .= " \$a = array_change_key_case(\$a);\n"; - $code .= " \$b = array_change_key_case(\$b);\n"; - - $key = strtolower($key); - - $code .= " if ((! isset(\$a['$key'])) && isset(\$b['$key'])) return 1;\n"; - $code .= " if (isset(\$a['$key']) && (! isset(\$b['$key']))) return -1;\n"; - - $code .= " if ((isset(\$a['$key'])) && (isset(\$b['$key']))) {\n"; - $code .= " if (is_array(\$a['$key'])) {\n"; - $code .= " asort(\$a['$key']);\n"; - $code .= " \$aa = array_shift(\$a['$key']);\n"; - $code .= " } else\n"; - $code .= " \$aa = \$a['$key'];\n"; - - $code .= " if (is_array(\$b['$key'])) {\n"; - $code .= " asort(\$b['$key']);\n"; - $code .= " \$bb = array_shift(\$b['$key']);\n"; - $code .= " } else\n"; - $code .= " \$bb = \$b['$key'];\n"; - - $code .= " if (\$aa != \$bb)\n"; - $code .= " if (is_numeric(\$aa) && is_numeric(\$bb)) {\n"; - - if ($rev) - $code .= " return (\$aa < \$bb ? 1 : -1);\n"; - else - $code .= " return (\$aa > \$bb ? 1 : -1);\n"; - - $code .= " } else {\n"; - - if ($rev) - $code .= " if ( (\$c = strcasecmp(\$bb,\$aa)) != 0 ) return \$c;\n"; - else - $code .= " if ( (\$c = strcasecmp(\$aa,\$bb)) != 0 ) return \$c;\n"; - - $code .= " }\n"; - $code .= " }\n"; - $code .= "}\n"; - } - - $code .= 'return $c;'; - - $CACHE[$sortby] = pla_create_function('$a, $b',$code); - } - - uasort($data,$CACHE[$sortby]); -} - -/** - * Is compression enabled for output - */ -function isCompress() { - return (isset($_SESSION[APPCONFIG]) && $_SESSION[APPCONFIG]->getValue('appearance','compress') - && ! ini_get('zlib.output_compression') - && preg_match('/gzip/',$_SERVER['HTTP_ACCEPT_ENCODING'])); -} - -/** - * PLA specific Functions - */ - -/** - * Fetches whether the user has configured phpLDAPadmin to obfuscate passwords - * with "*********" when displaying them. - * - * This is configured in config.php thus: - * - * $config->custom->appearance['obfuscate_password_display'] = true; - * - * - * Or if it is OK to show encrypted passwords but not clear text passwords - * - * $config->custom->appearance['show_clear_password'] = false; - * - * - * @param string Password encoding type - * @return boolean - */ -function obfuscate_password_display($enc=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if ($_SESSION[APPCONFIG]->getValue('appearance','obfuscate_password_display')) - $return = true; - - elseif (! $_SESSION[APPCONFIG]->getValue('appearance','show_clear_password') && (is_null($enc) || $enc == 'clear')) - $return = true; - - else - $return = false; - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$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 The DN to pretty-print. - * @return string - */ -function pretty_print_dn($dn) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $dn_save = $dn; - $dn = pla_explode_dn($dn); - - if (! $dn) - return $dn_save; - - foreach ($dn as $i => $element) { - $element = htmlspecialchars($element); - $element = explode('=',$element,2); - $element = implode('=',$element); - $dn[$i] = $element; - } - - $dn = implode(',',$dn); - - return $dn; -} - -/** - * 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 The attribute to examine for "DNness" - * @return boolean - */ -function is_dn_string($str) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - /* 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 The string to analyze. - * @return boolean Returns true if the specified string looks like an email address or false otherwise. - */ -function is_mail_string($str) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $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 The string to analyze. - * @return boolean Returns true if the specified string looks like a web URL or false otherwise. - */ -function is_url_string($str) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $url_regex = '/^(ftp|https?):\/\/+[\w\.\-\/\?\=\&]*\w+/'; - - if (preg_match($url_regex,$str)) - return true; - else - return false; -} - -/** - * 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 The first of two DNs to compare - * @param string The second of two DNs to compare - * @return int - */ -function pla_compare_dns($dn1,$dn2) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # If pla_compare_dns is passed via a tree, then we'll just get the DN part. - if (is_array($dn1)) - if (isset($dn1['dn'])) - $dn1 = $dn1['dn']; - else - $dn1 = implode('+',$dn1); - if (is_array($dn2)) - if (isset($dn2['dn'])) - $dn2 = $dn2['dn']; - else - $dn2 = implode('+',$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; - } -} - -/** - * For LDAP servers with auto_number enabled, this function will get the next - * available number using the host's preferred mechanism (pool or search). - * - * This is configured in config.php by server: - * - * - * $servers->setValue('auto_number','enable',true|false); - * - * - * The available mechanisms are: - * pool: - * The pool mechanism uses a user-configured entry in the LDAP server to - * store the last used "number". This mechanism simply fetches and increments - * and returns that value. - * - * search: - * The search mechanism will search the LDAP server that has the attribute - * set. It will then find the smallest value and "fills in the gaps" by - * incrementing the smallest attribute until an unused value is found. - * - * NOTE: Both mechanisms do NOT prevent race conditions or toe-stomping, so - * care must be taken when actually creating the entry to check that the number - * 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. - * - * See config.php.example for more notes on the two mechanisms. - * - * @param string Base to start the search from - * @param string Attribute to query - * @param boolean Increment the result (for pool searches) - * @param string LDAP filter to use (for pool searches) - * @return int - */ -function get_next_number($base,$attr,$increment=false,$filter=false,$startmin=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $server = $_SESSION[APPCONFIG]->getServer(get_request('server_id','REQUEST')); - $attr = strtolower($attr); - $query = array(); - - if (! $server->getValue('auto_number','enable')) { - system_message(array( - 'title'=>_('AUTO_NUMBER is disabled for this server'), - 'body'=>sprintf('%s (%s)',_('A call was made to get_next_number(), however, it is disabled for this server'),$attr), - 'type'=>'warn')); - - return false; - } - - # Check see and use our alternate uid_dn and password if we have it. - if (! $server->login($server->getValue('auto_number','dn'),$server->getValue('auto_number','pass'),'auto_number')) { - system_message(array( - 'title'=>_('AUTO_NUMBER invalid login/password'), - 'body'=>sprintf('%s (%s)',_('Unable to connect to LDAP server with the auto_number login/password, please check your configuration.'), - $server->getName()), - 'type'=>'warn')); - - return false; - } - - # Some error checking - if (! $base) { - $query['base'] = $server->getValue('auto_number','search_base'); - - if (! trim($query['base'])) { - system_message(array( - 'title'=>_('No AUTO_NUMBER search_base configured for this server'), - 'body'=>_('A call was made to get_next_number(), however, the base to search is empty.'), - 'type'=>'warn')); - - return false; - } - - } else - $query['base'] = $base; - - if (! $server->dnExists($query['base'])) { - system_message(array( - 'title'=>_('No AUTO_NUMBER search_base exists for this server'), - 'body'=>sprintf('%s (%s)',_('A call was made to get_next_number(), however, the base to search does not exist for this server.'),$query['base']), - 'type'=>'warn')); - - return false; - } - - if (! is_string($attr) || ! $server->getSchemaAttribute($attr)) { - system_message(array( - 'title'=>_('AUTO_NUMBER search attribute invalid'), - 'body'=>sprintf('%s (%s)',_('The search attribute for AUTO_NUMBER is invalid, expecting a single valid attribute.'),$attr), - 'type'=>'warn')); - - return false; - } - - $query['attrs'] = array($attr); - - # Based on the configured mechanism, go get the next available uidNumber! - switch ($server->getValue('auto_number','mechanism')) { - case 'search': - $query['filter'] = sprintf('(%s=*)',$attr); - $search = $server->query($query,'auto_number'); - - # Construct a list of used numbers - $autonum = array(0); - - foreach ($search as $dn => $values) { - $values = array_change_key_case($values); - foreach ($values[$attr] as $value) - array_push($autonum,$value); - } - - $autonum = array_unique($autonum); - sort($autonum); - - # Start with the least existing autoNumber and add 1 - $minNumber = is_null($startmin) ? intval($autonum[0])+1 : $startmin; - - # Override our minNumber by the configuration if it exists. - if (count($server->getValue('auto_number','min'))) { - $min = array_change_key_case($server->getValue('auto_number','min')); - - if (isset($min[$attr])) - $minNumber = $min[$attr] > $minNumber ? $min[$attr] : $minNumber; - } - - for ($i=0;$i $num+1) - return $autonum[$i] >= $num ? $num+1 : $num; - } - - # If we didnt find a suitable gap and are all above the minNumber, we'll just return the $minNumber - return $minNumber; - - break; - - case 'pool': - switch ($attr) { - case 'gidnumber': - $query['filter'] = '(objectClass=gidPool)'; - - break; - - case 'uidnumber': - $query['filter'] = '(objectClass=uidPool)'; - - break; - } - - # If we are called with a filter, we'll use the one from the configuration. - if (! empty($filter)) - $query['filter'] = $filter; - - $search = $server->query($query,'auto_number'); - - switch (count($search)) { - case '1': - break; - - case '0': - system_message(array( - 'title'=>_('AUTO_NUMBER pool filter didnt return any DNs'), - 'body'=>sprintf('%s (%s)',_('Please change your filter parameter, or check your auto_number,search_base configuration'),$query['filter']), - 'type'=>'warn')); - - return false; - - default: - system_message(array( - 'title'=>_('AUTO_NUMBER pool filter returned too many DNs'), - 'body'=>sprintf('%s (%s)',_('Please change your filter parameter, or check your auto_number,search_base configuration'),$query['filter']), - 'type'=>'warn')); - - return false; - } - - # This should only iterate once. - foreach ($search as $dn => $values) { - $values = array_change_key_case($values); - - $autonum = $values[$attr][0]; - $poolDN = $values['dn']; - } - - if ($increment) { - $updatedattr = array($attr=>$autonum+1); - $server->modify($poolDN,$updatedattr); - } - - return $autonum; - - # No other cases allowed. The user has an error in the configuration - default: - system_message(array( - 'title'=>_('Invalid AUTO_NUMBER mechanism'), - 'body'=>sprintf('%s (%s)',_('Your config file specifies an unknown AUTO_NUMBER search mechanism.'),$server->getValue('auto_number','mechanism')), - 'type'=>'warn')); - - 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 string The DN of the entry whose icon you wish to fetch. - * @return string - */ -function get_icon($server_id,$dn,$object_classes=array()) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $server = $_SESSION[APPCONFIG]->getServer($server_id); - - # Fetch and lowercase all the objectClasses in an array - if (! count($object_classes)) - $object_classes = $server->getDNAttrValue($dn,'objectClass'); - - foreach ($object_classes as $index => $value) - $object_classes[$index] = strtolower($value); - - $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 'ldap-user.png'; - - elseif (in_array('organization',$object_classes)) - return 'ldap-o.png'; - - elseif (in_array('organizationalunit',$object_classes)) - return 'ldap-ou.png'; - - elseif (in_array('organizationalrole',$object_classes)) - return 'ldap-uid.png'; - - elseif (in_array('dcobject',$object_classes) || - in_array('domainrelatedobject',$object_classes) || - in_array('domain',$object_classes) || - in_array('builtindomain',$object_classes)) - - return 'ldap-dc.png'; - - elseif (in_array('alias',$object_classes)) - return 'ldap-alias.png'; - - elseif (in_array('room',$object_classes)) - return 'door.png'; - - elseif (in_array('iphost',$object_classes)) - return 'host.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('%s/../countries/%s.png',IMGDIR,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 'ldap-ou.png'; - - elseif (in_array('applicationprocess',$object_classes)) - return 'process.png'; - - elseif (in_array('groupofuniquenames',$object_classes)) - return 'ldap-uniquegroup.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 'ldap-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 (strpos($rdn_value,'ipsec') === 0 || - strcasecmp($rdn_value,'IP Security') == 0|| - strcasecmp($rdn_value,'MSRADIUSPRIVKEY Secret') == 0 || - strpos($rdn_value,'BCKUPKEY_') === 0) - - return 'lock.png'; - - elseif (strcasecmp($rdn_value,'MicrosoftDNS') == 0) - return 'ldap-dc.png'; - - # Oh well, I don't know what it is. Use a generic icon. - else - return 'ldap-default.png'; -} - -/** - * Appends a servers base to a "sub" dn or returns the base. - * - * @param string The baseDN to be added if the DN is relative - * @param string 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 && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $empty_str = (is_null($sub_dn) || (($len=strlen(trim($sub_dn))) == 0)); - - if ($empty_str) - return $base; - - # If we have a string which doesn't need a base - elseif ($sub_dn[$len-1] != ',') - return $sub_dn; - - else - return sprintf('%s%s',$sub_dn,$base); -} - -/** - * 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. - * - * @param int The length of the salt string to generate. - * @return string The generated salt string. - */ -function random_salt($length) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $str = bin2hex(random_bytes(ceil($length/2))); - if ($length % 2 == 1) - return substr($str, 0, -1); - - 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 ds_ldap::getContainer()). - * - * @param string The DN whose RDN to return. - * @param boolean If true, include attributes in the RDN string. See http://php.net/ldap_explode_dn for details - * @return string The RDN - */ -function get_rdn($dn,$include_attrs=0,$decode=false) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (is_null($dn)) - return null; - - $rdn = pla_explode_dn($dn,$include_attrs); - if (! count($rdn) || ! isset($rdn[0])) - return $dn; - - if ($decode) - $rdn = dn_unescape($rdn[0]); - else - $rdn = $rdn[0]; - - return $rdn; -} - -/** - * Split an RDN into its attributes - */ -function rdn_explode($rdn) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # Setup to work out our RDN. - $rdnarray = explode('\+',$rdn); - - # Capture items that have +, but are not an attribute - foreach ($rdnarray as $index => $val) { - if (preg_match('/=/',$val)) - $validindex = $index; - - if (! preg_match('/=/',$val)) { - $rdnarray[$validindex] .= '+'.$val; - unset($rdnarray[$index]); - } - } - - return $rdnarray; -} - -/** - * 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. - * - * - * Array ( - * [title] => "Invalid Credentials" - * [description] => "An invalid username and/or password was supplied to the LDAP server." - * ) - * - * - * @param string 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: - */ -function pla_verbose_error($key) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - static $CACHE = array(); - - if (! count($CACHE)) { - $source_file = LIBDIR.'ldap_error_codes.txt'; - - if (! file_exists($source_file) || ! is_readable($source_file) || ! ($f = fopen($source_file,'r'))) - return false; - - $contents = fread($f,filesize($source_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); - - foreach ($entries[0] as $values) { - $entry = array(); - preg_match("/(0x[A-Za-z0-9][A-Za-z0-9])\s+([0-9A-Za-z_]+)\s+\"([^\"]*)\"/",$values,$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); - $CACHE[$hex_code] = array('title'=>$title,'desc'=>$desc); - } - } - - if (isset($CACHE[$key])) - return $CACHE[$key]; - else - return array('title' => null,'desc' => null); -} - -/** - * Given an LDAP OID number, returns a verbose description of the OID. - * This function parses ldap_supported_oids.txt and looks up the specified - * OID, and returns the verbose message defined in that file. - * - * - * Array ( - * [title] => All Operational Attribute - * [ref] => RFC 3673 - * [desc] => An LDAP extension which clients may use to request the return of all operational attributes. - * ) - * - * - * @param string The OID number (ie, "1.3.6.1.4.1.4203.1.5.1") of the OID of interest. - * @return array An associative array contianing the OID title and description like so: - */ -function support_oid_to_text($key) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - static $CACHE = array(); - - $unknown = array(); - $unknown['desc'] = 'We have no description for this OID, if you know what this OID provides, please let us know. Please also include an RFC reference if it is available.'; - $unknown['title'] = 'Can you help with this OID info?'; - - if (! count($CACHE)) { - $source_file = LIBDIR.'ldap_supported_oids.txt'; - - if (! file_exists($source_file) || ! is_readable($source_file) || ! ($f = fopen($source_file,'r'))) - return false; - - $contents = fread($f,filesize($source_file)); - fclose($f); - $entries = array(); - preg_match_all("/[0-9]\..+\s+\"[^\"]*\"\n/",$contents,$entries); - - foreach ($entries[0] as $values) { - $entry = array(); - preg_match("/([0-9]\.([0-9]+\.)*[0-9]+)(\s+\"([^\"]*)\")?(\s+\"([^\"]*)\")?(\s+\"([^\"]*)\")?/",$values,$entry); - $oid_id = isset($entry[1]) ? $entry[1] : null; - - if ($oid_id) { - $CACHE[$oid_id]['title'] = isset($entry[4]) ? $entry[4] : null; - $CACHE[$oid_id]['ref'] = isset($entry[6]) ? $entry[6] : null; - $desc = isset($entry[8]) ? $entry[8] : sprintf('%s',$unknown['desc'],$unknown['title']); - $CACHE[$oid_id]['desc'] = preg_replace('/\s+/',' ',$desc); - } - } - } - - if (isset($CACHE[$key])) - return $CACHE[$key]; - else - return array( - 'title'=>$key, - 'ref'=>null, - 'desc'=>sprintf('%s',$unknown['desc'],$unknown['title'])); -} - -/** - * Print an LDAP error message - */ -function ldap_error_msg($msg,$errnum) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $body = ''; - - $errnum = ('0x'.str_pad(dechex($errnum),2,0,STR_PAD_LEFT)); - $verbose_error = pla_verbose_error($errnum); - - $body .= sprintf('',_('LDAP said'),$msg); - - if ($verbose_error) { - $body .= sprintf('',_('Error number'),$errnum,$verbose_error['title']); - $body .= sprintf('',_('Description'),$verbose_error['desc']); - - } else { - $body .= sprintf('',_('Error number'),$errnum); - $body .= sprintf('',_('Description'),_('no description available')); - } - - $body .= '
%s:%s
%s:%s (%s)
%s:%s
%s:%s
%s:(%s)
'; - - return $body; -} - -/** - * 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: - * - * draw_jpeg_photo(0,'cn=Bob,ou=People,dc=example,dc=com',0,"jpegPhoto",true,array('img_opts'=>"border: 1px; width: 150px")); - * draw_jpeg_photo(1,'cn=Fred,ou=People,dc=example,dc=com',1,null); - * - * - * @param object The Server to get the image from. - * @param string The DN of the entry that contains the jpeg attribute you want to draw. - * @param string The name of the attribute containing the jpeg data (usually 'jpegPhoto'). - * @param int Index of the attribute to draw - * @param boolean 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 array Specifies optional image and CSS style attributes for the table tag. Supported keys are - * fixed_width, fixed_height, img_opts. - */ -function draw_jpeg_photo($server,$dn,$index,$attr_name='jpegphoto',$draw_delete_buttons=false,$options=array()) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $fixed = array(); - $fixed['width'] = isset($options['fixed_width']) ? $options['fixed_width'] : false; - $fixed['height'] = isset($options['fixed_height']) ? $options['fixed_height'] : false; - - if (is_null($server)) - $jpeg_data = $_SESSION['tmp']; - else - $jpeg_data = $server->getDNAttrValues($dn,null,LDAP_DEREF_NEVER,array($attr_name)); - - if (! isset($jpeg_data[$attr_name][$index]) || ! $jpeg_data[$attr_name][$index]) { - system_message(array( - 'title'=>_('Unable to retrieve image'), - 'body'=>sprintf('%s %s', - _('Could not fetch jpeg data for attribute'),$attr_name), - 'type'=>'warn')); - - # This should atleast generate some text that says "Image not available" - printf('Photo',$attr_name); - - return; - } - - $width = 0; - $height = 0; - - if (function_exists('getimagesize')) { - $jpeg_temp_dir = realpath($_SESSION[APPCONFIG]->getValue('jpeg','tmpdir').'/'); - if (! is_writable($jpeg_temp_dir)) - system_message(array( - 'title'=>_('Unable to write to jpeg tmp directory'), - 'body'=>_('Please set jpeg,tmpdir to a writable directory in the phpLDAPadmin config.php'), - 'type'=>'warn')); - - else { - # We have an image to display - $jpeg_filename = tempnam($jpeg_temp_dir.'/','pla'); - $outjpeg = @file_put_contents($jpeg_filename,$jpeg_data[$attr_name][$index]); - - if (! $outjpeg) { - system_message(array( - 'title'=>_('Error writing to jpeg tmp directory'), - 'body'=>sprintf(_('Please check jpeg,tmpdir is a writable directory in the phpLDAPadmin config.php'),$jpeg_temp_dir), - 'type'=>'warn')); - - } elseif ($outjpeg < 6) { - system_message(array( - 'title'=>sprintf('%s %s',$attr_name,_('contains errors')), - 'body'=>_('It appears that the jpeg image may not be a jpeg image'), - 'type'=>'warn')); - - } else { - $jpeg_dimensions = getimagesize($jpeg_filename); - $width = $jpeg_dimensions[0]; - $height = $jpeg_dimensions[1]; - } - - unlink($jpeg_filename); - } - } - - if ($width > 300) { - $scale_factor = 300 / $width; - $img_width = 300; - $img_height = intval($height * $scale_factor); - - } else { - $img_width = $width; - $img_height = $height; - } - - $href = sprintf('view_jpeg_photo.php?dn=%s&index=%s&attr=%s',rawurlencode($dn),$index,$attr_name); - - printf('',number_format($outjpeg),_('bytes'),$width,$height,_('pixels')); - - printf('Photo', - htmlspecialchars($href), - is_null($server) ? 'location=session' : sprintf('server_id=%s',$server->getIndex()), - (! $img_width || $fixed['width'] ? '' : sprintf('width="%s"',$img_width)), - (! $img_height || $fixed['height'] ? '' : sprintf('height="%s"',$img_height)), - (isset($options['img_opts']) ? $options['img_opts'] : '')); - - echo ''; - - if ($draw_delete_buttons) - # - printf('
%s', - $attr_name,_('Delete photo')); -} - -/** - * Return the list of available password types - * - * @todo Dynamically work this list out so we only present hashes that we can encrypt - */ -function password_types() { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - return $_SESSION[APPCONFIG]->getValue('password', 'available_types'); -} - -/** - * Hashes a password and returns the hash based on the specified enc_type. - * - * @param string The password to hash in clear text. - * @param string Standard LDAP encryption type which must be one of - * crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, sha512, - * sha256crypt, sha512crypt, or clear. - * @return string The hashed password. - */ -function pla_password_hash($password_clear,$enc_type) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $enc_type = strtolower($enc_type); - - switch($enc_type) { - case 'blowfish': - if (! defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) - error(_('Your system crypt library does not support blowfish encryption.'),'error','index.php'); - - # Hardcoded to second blowfish version and set number of rounds - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$2a$12$'.random_salt(13))); - - break; - - case 'crypt': - if ($_SESSION[APPCONFIG]->getValue('password', 'no_random_crypt_salt')) - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,substr($password_clear,0,2))); - else - $new_value = sprintf('{CRYPT}%s',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) - error(_('Your system crypt library does not support extended DES encryption.'),'error','index.php'); - - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,'_'.random_salt(8))); - - break; - - case 'k5key': - $new_value = sprintf('{K5KEY}%s',$password_clear); - - system_message(array( - 'title'=>_('Unable to Encrypt Password'), - 'body'=>'phpLDAPadmin cannot encrypt K5KEY passwords', - 'type'=>'warn')); - - break; - - case 'md5': - $new_value = sprintf('{MD5}%s',base64_encode(md5($password_clear, true))); - break; - - case 'md5crypt': - if (! defined('CRYPT_MD5') || CRYPT_MD5 == 0) - error(_('Your system crypt library does not support md5crypt encryption.'),'error','index.php'); - - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$1$'.random_salt(9))); - - break; - - case 'sha': - $new_value = sprintf('{SHA}%s',base64_encode(sha1($password_clear, true))); - - break; - - case 'ssha': - $salt = hex2bin(random_salt(8)); - $new_value = sprintf('{SSHA}%s',base64_encode(sha1($password_clear.$salt, true).$salt)); - - break; - - case 'bcrypt': - $options = [ - 'cost' => 8, - ]; - #Checking if password_hash() function is available. - if (function_exists('password_hash')) - $new_value = sprintf('{BCRYPT}%s',base64_encode(password_hash($password_clear, PASSWORD_BCRYPT, $options))); - else - error(_('Your PHP install does not have the password_hash() function. Cannot do BCRYPT hashes.'),'error','index.php'); - - break; - - - case 'smd5': - $salt = hex2bin(random_salt(8)); - $new_value = sprintf('{SMD5}%s',base64_encode(md5($password_clear.$salt, true).$salt)); - - break; - - case 'sha256': - $new_value = sprintf('{SHA256}%s', base64_encode(hash('sha256', $password_clear, true))); - - break; - - case 'ssha256': - $salt = hex2bin(random_salt(8)); - $new_value = sprintf('{SSHA256}%s', base64_encode(hash('sha256', $password_clear.$salt, true).$salt)); - - break; - - case 'sha384': - $new_value = sprintf('{SHA384}%s', base64_encode(hash('sha384', $password_clear, true))); - - break; - - case 'ssha384': - $salt = hex2bin(random_salt(8)); - $new_value = sprintf('{SSHA384}%s', base64_encode(hash('sha384', $password_clear.$salt, true).$salt)); - - break; - - case 'sha512': - $new_value = sprintf('{SHA512}%s', base64_encode(hash('sha512', $password_clear, true))); - - break; - - case 'ssha512': - $salt = hex2bin(random_salt(8)); - $new_value = sprintf('{SSHA512}%s', base64_encode(hash('sha512', $password_clear.$salt, true).$salt)); - - break; - - case 'sha256crypt': - if (! defined('CRYPT_SHA256') || CRYPT_SHA256 == 0) - error(_('Your system crypt library does not support sha256crypt encryption.'),'error','index.php'); - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$5$'.random_salt(8))); - - break; - - case 'sha512crypt': - if (! defined('CRYPT_SHA512') || CRYPT_SHA512 == 0) - error(_('Your system crypt library does not support sha512crypt encryption.'),'error','index.php'); - $new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$6$'.random_salt(8))); - - 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 The hash. - * @param String 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,$attribute='userpassword') { - $plainpassword = htmlspecialchars_decode($plainpassword); - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (in_array($attribute,array('sambalmpassword','sambantpassword'))) { - $smb = new smbHash; - - switch($attribute) { - case 'sambalmpassword': - if (strcmp($smb->lmhash($plainpassword),strtoupper($cryptedpassword)) == 0) - return true; - else - return false; - - case 'sambantpassword': - if (strcmp($smb->nthash($plainpassword),strtoupper($cryptedpassword)) == 0) - return true; - else - return false; - } - - return false; - } - - if (preg_match('/{([^}]+)}(.*)/',$cryptedpassword,$matches)) { - $cryptedpassword = $matches[2]; - $cypher = strtolower($matches[1]); - - } else { - $cypher = null; - } - - switch($cypher) { - # SSHA crypted passwords - case 'ssha': - $hash = base64_decode($cryptedpassword); - - # OpenLDAP uses a 4 byte salt, SunDS uses an 8 byte salt - both from char 20. - $salt = substr($hash,20); - $new_hash = base64_encode(sha1($plainpassword.$salt, true).$salt); - - if (strcmp($cryptedpassword,$new_hash) == 0) - return true; - else - return false; - - break; - - #BCRYPT hashed passwords - case 'bcrypt': - # Check php password_verify support before using it - if (function_exists('password_verify')) { - $hash = base64_decode($cryptedpassword); - if (password_verify($plainpassword, $hash)) { - return true; - } else { - return false; - } - - } else { - error(_('Your PHP install does not have the password_verify() function. Cannot do Bcrypt hashes.'),'error','index.php'); - } - - break; - - # Salted MD5 - case 'smd5': - $hash = base64_decode($cryptedpassword); - $salt = substr($hash,16); - $new_hash = base64_encode(md5($plainpassword.$salt).$salt, true); - - if (strcmp($cryptedpassword,$new_hash) == 0) - return true; - else - return false; - - break; - - # SHA crypted passwords - case 'sha': - if (strcasecmp(pla_password_hash($plainpassword,'sha'),'{SHA}'.$cryptedpassword) == 0) - return true; - else - return false; - - break; - - # MD5 crypted passwords - case 'md5': - if( strcasecmp(pla_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) - error(_('Your system crypt library does not support blowfish encryption.'),'error','index.php'); - - 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) - error(_('Your system crypt library does not support md5crypt encryption.'),'error','index.php'); - - list($dummy,$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) - error(_('Your system crypt library does not support extended DES encryption.'),'error','index.php'); - - 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; - - # SHA256 crypted passwords - case 'sha256': - if (strcasecmp(pla_password_hash($plainpassword,'sha256'),'{SHA256}'.$cryptedpassword) == 0) - return true; - else - return false; - - break; - - # Salted SHA256 crypted passwords - case 'ssha256': - $hash = base64_decode($cryptedpassword); - $salt = substr($hash,64); - $new_hash = base64_encode(hash('sha256', $plainpassword.$salt, true).$salt); - - if (strcmp($cryptedpassword,$new_hash) == 0) - return true; - else - return false; - - break; - - # SHA384 crypted passwords - case 'sha384': - if (strcasecmp(pla_password_hash($plainpassword,'sha384'),'{SHA384}'.$cryptedpassword) == 0) - return true; - else - return false; - - break; - - # Salted SHA384 crypted passwords - case 'ssha384': - $hash = base64_decode($cryptedpassword); - $salt = substr($hash,64); - $new_hash = base64_encode(hash('sha384', $plainpassword.$salt, true).$salt); - - if (strcmp($cryptedpassword,$new_hash) == 0) - return true; - else - return false; - - break; - - # SHA512 crypted passwords - case 'sha512': - if (strcasecmp(pla_password_hash($plainpassword,'sha512'),'{SHA512}'.$cryptedpassword) == 0) - return true; - else - return false; - - break; - - # Salted SHA512 crypted passwords - case 'ssha512': - $hash = base64_decode($cryptedpassword); - $salt = substr($hash,64); - $new_hash = base64_encode(hash('sha512', $plainpassword.$salt, true).$salt); - - if (strcmp($cryptedpassword,$new_hash) == 0) - return true; - else - return false; - - break; - - # No crypt is given assume plaintext passwords are used - default: - if ($plainpassword == $cryptedpassword) - return true; - else - return false; - } -} - -/** - * 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 && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - # 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) { - - # No need to check for standard crypt, because enc_type is already equal to 'crypt'. - 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'; - } - - return $enc_type; -} - -/** - * Draws an HTML browse button which, when clicked, pops up a DN chooser dialog. - * @param string 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 boolean (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 && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $href = sprintf("javascript:dnChooserPopup('%s','%s','%s');",$form,$element,$rdn == 'none' ? '' : rawurlencode($rdn)); - $title = _('Click to popup a dialog to select an entry (DN) graphically'); - - printf('Find',$href,$title,IMGDIR); - - if ($include_choose_text) - printf('%s',$href,$title,_('browse')); -} - -/** - * http://php.net/manual/en/function.ldap-explode-dn.php#34724 - * fixed for: - * Keep attention on UTF8 encoded DNs. Since openLDAP >=2.1.2 - * ldap_explode_dn turns unprintable chars (in the ASCII sense, UTF8 - * encoded) into \. - */ -function ldap_explode_dn_patch($dn,$with_attrib) { - $result = ldap_explode_dn($dn,$with_attrib); - if (! $result) - return null; - - # translate hex code into ascii again - foreach ($result as $key => $value) { - $result[$key] = preg_replace_callback( - "/\\\([0-9A-Fa-f]{2})/", - function ($matches) { - return chr(hexdec($matches[1])); - }, - $value - ); - } - - return $result; -} - -/** - * Explode a DN into an array of its RDN parts. - * - * NOTE: When a multivalue RDN is passed to ldap_explode_dn, the results returns with 'value + value'; - * - * - * Array ( - * [0] => uid=ppratt - * [1] => ou=People - * [2] => dc=example - * [3] => dc=com - * ) - * - * - * @param string The DN to explode. - * @param int (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: - */ -function pla_explode_dn($dn,$with_attributes=0) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - global $CACHE; - - if (isset($CACHE['explode'][$dn][$with_attributes])) { - if (DEBUG_ENABLED) - debug_log('Return CACHED result (%s) for (%s)',1,0,__FILE__,__LINE__,__METHOD__, - $CACHE['explode'][$dn][$with_attributes],$dn); - - return $CACHE['explode'][$dn][$with_attributes]; - } - - $dn = addcslashes($dn,'<>+";'); - - # split the dn - $result[0] = ldap_explode_dn_patch(dn_escape($dn),0); - $result[1] = ldap_explode_dn_patch(dn_escape($dn),1); - if (! $result[$with_attributes]) { - if (DEBUG_ENABLED) - debug_log('Returning NULL - NO result.',1,0,__FILE__,__LINE__,__METHOD__); - - return array(); - } - - # Remove our count value that ldap_explode_dn returns us. - unset($result[0]['count']); - unset($result[1]['count']); - - # Record the forward and reverse entries in the cache. - foreach ($result as $key => $value) { - # translate hex code into ascii for display - $result[$key] = dn_unescape($value); - - $CACHE['explode'][implode(',',$result[0])][$key] = $result[$key]; - $CACHE['explode'][implode(',',array_reverse($result[0]))][$key] = array_reverse($result[$key]); - } - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$result[$with_attributes]); - - return $result[$with_attributes]; -} - -/** - * Parse a DN and escape any special characters - */ -function dn_escape($dn) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $olddn = $dn; - - # Check if the RDN has a comma and escape it. - while (preg_match('/([^\\\\]),(\s*[^=]*\s*),/',$dn)) - $dn = preg_replace('/([^\\\\]),(\s*[^=]*\s*),/','$1\\\\2C$2,',$dn); - - $dn = preg_replace('/([^\\\\]),(\s*[^=]*\s*)([^,])$/','$1\\\\2C$2$3',$dn); - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$dn); - - return $dn; -} - -/** - * Parse a DN and unescape any special characters - */ -function dn_unescape($dn) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (is_array($dn)) { - $a = array(); - - foreach ($dn as $key => $rdn) - $a[$key] = preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', - function ($r) { - return chr(hexdec($r[1])); - }, - $rdn - ); - - return $a; - - } else { - return preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', - function ($r) { - return chr(hexdec($r[1])); - }, - $dn - ); - } -} - -/** - * Fetches the URL for the specified item. This is a convenience function for - * fetching project HREFs (like bugs) - * - * @param string 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='') { - $pla = 'http://phpldapadmin.sourceforge.net'; - - switch($type) { - case 'add_bug': - return 'https://github.com/leenooks/phpLDAPadmin/issues'; - case 'add_rfe': - return 'https://github.com/leenooks/phpLDAPadmin/issues'; - case 'credits': - return sprintf('%s/Credits',$pla); - case 'documentation': - return sprintf('%s/Documentation',$pla); - case 'donate': - return 'https://sourceforge.net/donate/index.php?group_id=61828'; - case 'forum': - return 'https://stackoverflow.com/questions/tagged/phpldapadmin'; - case 'web': - return sprintf('%s',$pla); - 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 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: - * - * Array ( - * [server_id] = 0, - * [dn] = "dc=example,dc=com", - * [attr] = "sn" - * ) - * - * This will produce a string like this: "server_id=0&dn=dc=example,dc=com&attr=sn" - * @param array (optional) An array of variables to exclude in the resulting string - * @return string The string created from the array. - */ -function array_to_query_string($array,$exclude_vars=array()) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (! is_array($array) || ! count($array)) - return ''; - - $str = ''; - $i = 0; - foreach ($array as $name => $val) - if (! in_array($name,$exclude_vars)) - if (is_array($val)) - foreach ($val as $v) { - if ($i++ > 0) - $str .= '&'; - - $str .= sprintf('%s[]=%s',rawurlencode($name),rawurlencode($v)); - } - - else { - if ($i++ > 0) - $str .= '&'; - - $str .= sprintf('%s=%s',rawurlencode($name),rawurlencode($val)); - } - - return $str; -} - -/** - * Reverses a DN such that the top-level RDN is first and the bottom-level RDN is last - * For example: - * - * cn=Brigham,ou=People,dc=example,dc=com - * - * Becomes: - * - * dc=com,dc=example,ou=People,cn=Brigham - * - * This makes it possible to sort lists of DNs such that they are grouped by container. - * - * @param string The DN to reverse - * @return string The reversed DN - * - * @see pla_compare_dns - * @see pla_explode_dns - */ -function pla_reverse_dn($dn) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - return (implode(',',array_reverse(pla_explode_dn($dn)))); -} - -/** - * Attribute sorting - */ -function sortAttrs($a,$b) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if ($a == $b) - return 0; - - $server = $_SESSION[APPCONFIG]->getServer(get_request('server_id','REQUEST')); - $attrs_display_order = arrayLower($_SESSION[APPCONFIG]->getValue('appearance','attr_display_order')); - - # Check if $a is in $attrs_display_order, get its key - $a_key = array_search($a->getName(),$attrs_display_order); - $b_key = array_search($b->getName(),$attrs_display_order); - - if ((! $a_key) && ($a_key !== 0)) - if ((! $a_key = array_search(strtolower($a->getFriendlyName()),$attrs_display_order)) && ($a_key !== 0)) - $a_key = count($attrs_display_order)+1; - - if ((! $b_key) && ($b_key !== 0)) - if ((! $b_key = array_search(strtolower($b->getFriendlyName()),$attrs_display_order)) && ($b_key !== 0)) - $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) - return strcasecmp($a->getFriendlyName(),$b->getFriendlyName()); - - # 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; -} - -/** - * 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 && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (! is_array($array)) - return $array; - - $newarray = array(); - foreach ($array as $key => $value) - $newarray[$key] = strtolower($value); - - return $newarray; -} - -/** - * Checks if a string exists in an array, ignoring case. - * - * @param string What you are looking for - * @param array The array that you think it is in. - * @return boolean True if its there, false if its not. - */ -function in_array_ignore_case($needle,$haystack) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (! is_array($haystack)) - return false; - - if (! is_string($needle)) - return false; - - $return = false; - - foreach ($haystack as $element) { - if (is_string($element) && (strcasecmp($needle,$element) == 0)) { - $return = true; - break; - } - } - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * Gets a DN string using the user-configured tree_display_format string to format it. - */ -function draw_formatted_dn($server,$entry) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $dn = $entry->getDn(); - - $formats = $_SESSION[APPCONFIG]->getValue('appearance','tree_display_format'); - - foreach ($formats as $format) { - $has_none = false; - preg_match_all('/%[a-zA-Z_0-9]+/',$format,$tokens); - $tokens = $tokens[0]; - - if (DEBUG_ENABLED) - debug_log('The tokens are (%s)',1,0,__FILE__,__LINE__,__METHOD__,$tokens); - - foreach ($tokens as $token) { - if (strcasecmp($token,'%dn') == 0) - $format = str_replace($token,pretty_print_dn($dn),$format); - - elseif (strcasecmp($token,'%rdn') == 0) - $format = str_replace($token,pretty_print_dn($entry->getRDN()),$format); - - elseif (strcasecmp($token,'%rdnvalue') == 0) { - $rdn = get_rdn($dn,0,true); - $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 = $server->getDNAttrValue($dn,$attr_name); - - if (is_null($attr_values) || (count($attr_values) <= 0)) { - $display = '<'._('none').'>'; - $has_none = true; - - } elseif (is_array($attr_values)) - $display = implode(', ',$attr_values); - - else - $display = $attr_values; - - $format = str_replace($token,$display,$format); - } - } - - # If this format has all values available, use it. Otherwise, try the next one - if (!$has_none) - return $format; - } - - return $format; -} - -/** - * Server html select list - */ -function server_select_list($selected=null,$logged_on=false,$name='index',$isVisible=true,$js=null) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $count = 0; - $server_menu_html = sprintf(''; - - if ($count > 1) - return $server_menu_html; - - elseif ($count) - return sprintf('%s ', - $selected_server->getName(),$name,$selected_server->getIndex()); - - else - return ''; -} - -/** - * Converts a little-endian hex-number to one, that 'hexdec' can convert - */ -function littleEndian($hex) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $result = ''; - - for ($x=strlen($hex)-2;$x>= 0;$x=$x-2) - $result .= substr($hex,$x,2); - - return $result; -} - -function binSIDtoText($binsid) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $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 .= sprintf('-%s',$subauth[$x]); - } - - return $result; -} - -/** - * Query LDAP and return a hash. - * - * @param string The base DN to use. - * @param string LDAP Query filter. - * @param string LDAP attribute to use as key. - * @param array Attributes to use as values. - * @param boolean Specify false to not sort results by DN - * or true to have the returned array sorted by DN (uses ksort) - * or an array of attribute names to sort by attribute values - * @return array Array of values keyed by $key. - */ -function return_ldap_hash($base,$filter,$key,$attrs,$sort=true) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $server = $_SESSION[APPCONFIG]->getServer(get_request('server_id','REQUEST')); - $key = strtolower($key); - - $query = array(); - $query['base'] = $base; - $query['filter'] = $filter; - $query['attrs'] = $attrs; - $search = $server->query($query,null); - - $results = array(); - - foreach ($search as $dn => $values) - if (isset($values[$key])) - if (is_array($values[$key])) - foreach ($values[$key] as $i => $k) - foreach ($attrs as $attr) { - $lattr = strtolower($attr); - if (isset($values[$lattr])) { - $v = ''; - - if (is_array($values[$lattr]) && isset($values[$lattr][$i])) - $v = $values[$lattr][$i]; - - if (is_string($v) && (strlen($v) > 0)) - $results[$k][$attr] = $v; - } - } - - else - foreach ($attrs as $attr) { - $lattr = strtolower($attr); - if (isset($values[$lattr])) - $results[$values[$key]][$attr] = $values[$lattr]; - } - - if ($sort) - masort($results,is_array($sort) ? implode(',',$sort) : 'dn'); - - return $results; -} - -/** - * This function returns a string automatically generated - * based on the criteria defined in the array $criteria in config.php - */ -function password_generate() { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - $no_use_similiar = ! $_SESSION[APPCONFIG]->getValue('password','use_similar'); - $lowercase = $_SESSION[APPCONFIG]->getValue('password','lowercase'); - $uppercase = $_SESSION[APPCONFIG]->getValue('password','uppercase'); - $digits = $_SESSION[APPCONFIG]->getValue('password','numbers'); - $punctuation = $_SESSION[APPCONFIG]->getValue('password','punctuation'); - $length = $_SESSION[APPCONFIG]->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,$length-$num_spec)); - } - - shuffle($outarray); - $return = implode('',$outarray); - - if (DEBUG_ENABLED) - debug_log('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * This function returns an array of $num_req values - * randomly picked from the $input array - * - * @param array Array of values - * @param integer Number of values in returned array - * @return string The padded string - */ -function a_array_rand($input,$num_req) { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - 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('Returning (%s)',1,0,__FILE__,__LINE__,__METHOD__,$return); - - return $return; -} - -/** - * This is for Opera. By putting "random junk" in the query string, it thinks - * that it does not have a cached version of the page, and will thus - * fetch the page rather than display the cached version - */ -function random_junk() { - $time = gettimeofday(); - return md5(strtotime('now').$time['usec']); -} - -/** - * Returns a HTML id that can be used in the URL after the #. - * - * @param string The DN to pretty-print. - * @return string - */ -function htmlid($sid,$dn) { - return sprintf('SID%s:%s',$sid,preg_replace('/[\ =,]/','_',$dn)); -} - -/** - * Is PLA configured for AJAX display - */ -function isAjaxEnabled() { - if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS')) - debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs); - - if (isset($_SESSION[APPCONFIG])) - return ($_SESSION[APPCONFIG]->getValue('appearance','tree') == 'AJAXTree'); - else - return false; -} -/** -* Check if user is a robot with reCAPTCHA -**/ -function IsRobot($gResponse){ - $isRobot = true; - $url = 'https://www.google.com/recaptcha/api/siteverify'; - $data = array( - 'secret' => $_SESSION[APPCONFIG]->getValue('session','reCAPTCHA-key-server'), - 'response' => $gResponse - ); - $options = array( - 'http' => array ( - 'method' => 'POST','header' => - 'Content-Type: application/x-www-form-urlencoded', - 'content' => http_build_query($data) - ) - ); - $context = stream_context_create($options); - $verify = file_get_contents($url, false, $context); - $captcha_success = json_decode($verify); - if ($captcha_success->success) { - $isRobot = false; - } - return $isRobot; - -} -?> diff --git a/templates/template04-ldap/artifacts/lam.conf b/templates/template04-ldap/artifacts/lam.conf new file mode 100644 index 0000000..d0be54c --- /dev/null +++ b/templates/template04-ldap/artifacts/lam.conf @@ -0,0 +1,157 @@ + +ServerURL: ldap://localhost:389 + +serverDisplayName: + +useTLS: no + +followReferrals: false + +pagedResults: false + +referentialIntegrityOverlay: false + +hidePasswordPromptForExpiredPasswords: false + +Passwd: lam + +Admins: cn=admin,dc=localenv,dc=com + +defaultLanguage: en_GB.utf8 + +timeZone: Europe/London + +scriptPath: + +scriptServer: + +scriptRights: 750 + +scriptUserName: + +scriptSSHKey: + +scriptSSHKeyPassword: + +searchLimit: 0 + +activeTypes: user,group + +accessLevel: 100 + +loginMethod: list + +loginSearchSuffix: dc=localenv,dc=com + +loginSearchFilter: uid=%USER% + +loginSearchDN: + +loginSearchPassword: + +httpAuthentication: false + +lamProMailFrom: noreply@example.com + +lamProMailReplyTo: + +lamProMailSubject: Your password was reset + +lamProMailIsHTML: false + +lamProMailAllowAlternateAddress: true + +lamProMailText: Dear @@givenName@@ @@sn@@,+::++::+your password was reset to: @@newPassword@@+::++::++::+Best regards+::++::+deskside support+::+ + +jobsBindPassword: + +jobsBindUser: + +jobsDatabase: SQLite + +jobsDBHost: + +jobsDBPort: + +jobsDBUser: + +jobsDBPassword: + +jobsDBName: + +jobToken: rRFexdHEPsuFGHgNG5DP + +pwdResetAllowSpecificPassword: true + +pwdResetAllowScreenPassword: true + +pwdResetForcePasswordChange: true + +pwdResetDefaultPasswordOutput: 2 + +twoFactorAuthentication: none + +twoFactorAuthenticationURL: https://localhost + +twoFactorAuthenticationClientId: + +twoFactorAuthenticationSecretKey: + +twoFactorAuthenticationDomain: + +twoFactorAuthenticationInsecure: + +twoFactorAuthenticationLabel: + +twoFactorAuthenticationOptional: + +twoFactorAuthenticationCaption: + +twoFactorAuthenticationAttribute: uid + +twoFactorAllowToRememberDevice: false + +twoFactorRememberDeviceDuration: 28800 + +twoFactorRememberDevicePassword: zTCsc5sbFaKxrqwd9BEp9iuonTuMKg + +hideDnPart: + +pwdPolicyMinLength: + +pwdPolicyMinLowercase: + +pwdPolicyMinUppercase: + +pwdPolicyMinNumeric: + +pwdPolicyMinSymbolic: +modules: posixAccount_user_minUID: 10000 +modules: posixAccount_user_maxUID: 30000 +modules: posixAccount_host_minMachine: 50000 +modules: posixAccount_host_maxMachine: 60000 +modules: posixGroup_group_minGID: 10000 +modules: posixGroup_group_maxGID: 20000 +modules: posixAccount_user_uidGeneratorUsers: range +modules: posixAccount_host_uidGeneratorUsers: range +modules: posixAccount_group_gidGeneratorUsers: range +modules: posixGroup_pwdHash: SSHA +modules: posixAccount_pwdHash: SSHA +types: suffix_user: ou=People,dc=localenv,dc=com +types: attr_user: #uid;#givenName;#sn;#uidNumber;#gidNumber +types: modules_user: inetOrgPerson,posixAccount,shadowAccount +types: suffix_group: ou=group,dc=localenv,dc=com +types: attr_group: #cn;#gidNumber;#memberUID;#description +types: modules_group: posixGroup +tools: treeViewSuffix: dc=yourdomain,dc=org +tools: tool_hide_toolFileUpload: false +tools: tool_hide_TreeViewTool: false +tools: tool_hide_toolPDFEditor: false +tools: tool_hide_toolSchemaBrowser: false +tools: tool_hide_ImportExport: false +tools: tool_hide_toolMultiEdit: false +tools: tool_hide_toolServerInformation: false +tools: tool_hide_toolTests: false +tools: tool_hide_toolOUEditor: false +tools: tool_hide_toolWebauthn: false +tools: tool_hide_toolProfileEditor: false diff --git a/templates/template04-ldap/artifacts/ldap-account-manager.conf b/templates/template04-ldap/artifacts/ldap-account-manager.conf new file mode 100644 index 0000000..a05f44d --- /dev/null +++ b/templates/template04-ldap/artifacts/ldap-account-manager.conf @@ -0,0 +1,17 @@ + + + ServerName #MACHINE_HOSTNAME# + + DocumentRoot /usr/share/ldap-account-manager + + ErrorLog /var/log/apache2/#MACHINE_HOSTNAME#-error.log + + CustomLog /var/log/apache2/#MACHINE_HOSTNAME#-access.log common + + SSLEngine on + + SSLCertificateFile /etc/ssl/certs/#MACHINE_HOSTNAME#.pem + + SSLCertificateKeyFile /etc/ssl/private/#MACHINE_HOSTNAME#-key.pem + + diff --git a/templates/template04-ldap/artifacts/phpldapadmin.conf b/templates/template04-ldap/artifacts/phpldapadmin.conf deleted file mode 100644 index c6a057e..0000000 --- a/templates/template04-ldap/artifacts/phpldapadmin.conf +++ /dev/null @@ -1,17 +0,0 @@ - - - ServerName #MACHINE_HOSTNAME# - - DocumentRoot /usr/share/phpldapadmin - - ErrorLog /var/log/apache2/#MACHINE_HOSTNAME#-error.log - - CustomLog /var/log/apache2/#MACHINE_HOSTNAME#-access.log common - - SSLEngine on - - SSLCertificateFile /etc/ssl/certs/#MACHINE_HOSTNAME#.pem - - SSLCertificateKeyFile /etc/ssl/private/#MACHINE_HOSTNAME#-key.pem - - diff --git a/templates/template04-ldap/provision.sh b/templates/template04-ldap/provision.sh index 13a4cce..8f5367f 100644 --- a/templates/template04-ldap/provision.sh +++ b/templates/template04-ldap/provision.sh @@ -31,61 +31,29 @@ cat /vagrant/artifacts/debconf-slapd.conf | debconf-set-selections -apt install ldap-utils slapd -y - -# Install phpldapadmin -# https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-openldap-and-phpldapadmin-on-ubuntu-16-04 - -apt install -y software-properties-common apt-transport-https - -## It seems that phpldap has issues with PHP8.1, so enabling the PHP7.4 repository -add-apt-repository ppa:ondrej/php -y - -apt install -y apache2 \ - apache2-bin \ - apache2-data \ - apache2-utils \ - file \ - libapache2-mod-php7.4 \ - libapr1 \ - libaprutil1 \ - libaprutil1-dbd-sqlite3 \ - libaprutil1-ldap \ - libcurl4 \ - libjansson4 \ - liblua5.3-0 \ - libmagic-mgc \ - libmagic1 \ - libxslt1.1 \ - mailcap \ - mime-support \ - php7.4-common \ - php7.4-ldap \ - php7.4-xml \ - php7.4 \ - php7.4-cli \ - mkcert - -apt install phpldapadmin -y - -## Patch https://github.com/leenooks/phpLDAPadmin/pull/176 -cp /vagrant/artifacts/functions.php /usr/share/phpldapadmin/lib/ - -cp /vagrant/artifacts/config.php /etc/phpldapadmin - -cp /vagrant/artifacts/phpldapadmin.conf /etc/apache2/sites-available/ - -sed -i "s|#MACHINE_HOSTNAME#|${MACHINE_HOSTNAME}|g" /etc/apache2/sites-available/phpldapadmin.conf +apt install ldap-utils \ + slapd \ + apache2 \ + ldap-account-manager \ + -y export CAROOT=/vagrant/artifacts/ +apt install mkcert -y + mkcert -install mkcert --cert-file /etc/ssl/certs/${MACHINE_HOSTNAME}.pem --key-file /etc/ssl/private/${MACHINE_HOSTNAME}-key.pem "${MACHINE_HOSTNAME}" a2enmod ssl -a2ensite phpldapadmin.conf +cp /vagrant/artifacts/ldap-account-manager.conf /etc/apache2/sites-available/ + +sed -i "s|#MACHINE_HOSTNAME#|${MACHINE_HOSTNAME}|g" /etc/apache2/sites-available/ldap-account-manager.conf + +cp /vagrant/artifacts/lam.conf /var/lib/ldap-account-manager/config/lam.conf + +a2ensite ldap-account-manager.conf a2dissite 000-default.conf @@ -97,9 +65,9 @@ echo "If you add this IP to the hostname (${MACHINE_HOSTNAME}) in your hosts file or configure LXD nameserver," -echo "Your LDAP instance can be managed with phpLDAPadmin, accessible via the following URL: https://${MACHINE_HOSTNAME}/phpldapadmin" +echo "Your LDAP instance can be managed with LDAP Account Manager, accessible via the following URL: https://${MACHINE_HOSTNAME}/lam" -echo "with user 'admin' and password 'admin'" +echo "with user 'lam' and password 'lam'" echo "provisioning started: ${start_time}"