From f103611e9c12e725905122ef8a8e6e38d469eccb Mon Sep 17 00:00:00 2001 From: Brian Lycett Date: Fri, 1 May 2020 17:14:04 +0100 Subject: [PATCH 1/2] Added an LDAP debugging option --- README.md | 1 + entrypoint | 7 ++- www/includes/config.inc.php | 5 +- www/includes/ldap_functions.inc.php | 76 ++++++++++++++++++++--------- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index e6f8ee9..4ca9037 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Optional: * `SITE_NAME` (default: *LDAP user manager*): Change this to replace the title in the menu. e.g. "My Company" +* `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level. This will output passwords to the error log - don't enable this in a production environment. Webserver SSL setup --- diff --git a/entrypoint b/entrypoint index 7d3ab94..7ac4f85 100644 --- a/entrypoint +++ b/entrypoint @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e ssl_dir="/opt/ssl" @@ -13,8 +13,7 @@ if [ "$LDAP_TLS_CACERT" ]; then sed -i "s/TLS_CACERT.*/TLS_CACERT \/opt\/ca.crt/" /etc/ldap/ldap.conf fi - -if [ "$NO_HTTPS" = "TRUE" ]; then +if [ "${NO_HTTPS,,}" == "true" ]; then cat </etc/apache2/sites-enabled/lum.conf @@ -104,7 +103,7 @@ EoCertConf ######################## #Create Apache config - if [ -f "/opt/tls/chain.pem" ]; then $ssl_chain="SSLCertificateChainFile /opt/tls/chain.pem"; fi + if [ -f "/opt/tls/chain.pem" ]; then ssl_chain="SSLCertificateChainFile /opt/tls/chain.pem"; fi cat </etc/apache2/sites-enabled/lum.conf diff --git a/www/includes/config.inc.php b/www/includes/config.inc.php index 3bf2f06..472167e 100644 --- a/www/includes/config.inc.php +++ b/www/includes/config.inc.php @@ -15,10 +15,10 @@ $LDAP['user_ou'] = (getenv('LDAP_USER_OU') ? getenv('LDAP_USER_OU') : 'people'); $LDAP['group_membership_attribute'] = (getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE') ? getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE') : 'uniquemember'); - $LDAP['group_membership_uses_uid'] = ((strcmp(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID'),'TRUE') == 0) ? TRUE : FALSE); + $LDAP['group_membership_uses_uid'] = ((strcasecmp(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID'),'TRUE') == 0) ? TRUE : FALSE); $LDAP['account_attribute'] = 'uid'; - $LDAP['require_starttls'] = ((strcmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE); + $LDAP['require_starttls'] = ((strcasecmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE); $DEFAULT_USER_GROUP = (getenv('DEFAULT_USER_GROUP') ? getenv('DEFAULT_USER_GROUP') : 'everybody'); $DEFAULT_USER_SHELL = (getenv('DEFAULT_USER_SHELL') ? getenv('DEFAULT_SHELL') : '/bin/bash'); @@ -31,6 +31,7 @@ $USERNAME_REGEX = '^[a-z][a-zA-Z0-9\._-]{3,32}$'; #We'll use the username regex for groups too. + $LDAP_DEBUG = ((strcasecmp(getenv('LDAP_DEBUG'),'TRUE') == 0) ? TRUE : FALSE); ### diff --git a/www/includes/ldap_functions.inc.php b/www/includes/ldap_functions.inc.php index 40d1365..0e31821 100644 --- a/www/includes/ldap_functions.inc.php +++ b/www/includes/ldap_functions.inc.php @@ -7,7 +7,7 @@ $LDAP_CONNECTION_WARNING = FALSE; function open_ldap_connection() { - global $log_prefix, $LDAP, $SENT_HEADERS; + global $log_prefix, $LDAP, $SENT_HEADERS, $LDAP_DEBUG; $ldap_connection = @ ldap_connect($LDAP['uri']); @@ -40,14 +40,24 @@ function open_ldap_connection() { ldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3); } } + elseif ($LDAP_DEBUG == TRUE) { + error_log("$log_prefix Start STARTTLS connection to ${LDAP['uri']}",0); + } } $bind_result = @ ldap_bind( $ldap_connection, $LDAP['admin_bind_dn'], $LDAP['admin_bind_pwd']); if ($bind_result != TRUE) { - print "Problem: Failed to bind as ${LDAP['admin_bind_dn']}"; - error_log("$log_prefix Failed to bind as ${LDAP['admin_bind_dn']}",0); - exit(1); + + $this_error = "Failed to bind to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}"; + print "Problem: Failed to bind as ${LDAP['admin_bind_dn']}"; + if ($LDAP_DEBUG == TRUE) { $this_error .= " with password ${LDAP['admin_bind_pwd']}"; } + error_log("$log_prefix $this_error",0); + exit(1); + + } + elseif ($LDAP_DEBUG == TRUE) { + error_log("$log_prefix Bound to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}",0); } return $ldap_connection; @@ -62,17 +72,21 @@ function ldap_auth_username($ldap_connection,$username, $password) { # Search for the DN for the given username. If found, try binding with the DN and user's password. # If the binding succeeds, return the DN. - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; $ldap_search_query="${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER); $ldap_search = ldap_search( $ldap_connection, $LDAP['base_dn'], $ldap_search_query ); + if ($LDAP_DEBUG == TRUE) { "$log_prefix Running LDAP search: $ldap_search_query"; } + if (!$ldap_search) { error_log("$log_prefix Couldn't search for $username",0); return FALSE; } $result = ldap_get_entries($ldap_connection, $ldap_search); + if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix LDAP search returned ${result["count"]} records for $username",0); } + if ($result["count"] == 1) { $auth_ldap_connection = open_ldap_connection(); @@ -83,8 +97,10 @@ function ldap_auth_username($ldap_connection,$username, $password) { preg_match("/{$LDAP['account_attribute']}=(.*?),/",$result[0]['dn'],$dn_match); return $dn_match[1]; ldap_unbind($auth_ldap_connection); + if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Able to bind as $username",0); } } else { + if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Unable to bind as $username",0); } return FALSE; } @@ -100,12 +116,23 @@ function ldap_setup_auth($ldap_connection, $password) { #For the initial setup we need to make sure that whoever's running it has the default admin user #credentials as passed in ADMIN_BIND_* - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; + if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Initial setup: opening another LDAP connection to test authentication as ${LDAP['admin_bind_dn']}.",0); } $auth_ldap_connection = open_ldap_connection(); $can_bind = @ldap_bind($auth_ldap_connection, $LDAP['admin_bind_dn'], $password); ldap_close($auth_ldap_connection); - if ($can_bind) { return TRUE; } else { return FALSE; } + if ($can_bind) { + if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Initial setup: able to authenticate as ${LDAP['admin_bind_dn']}.",0); } + return TRUE; + } + else { + $this_error="Initial setup: Unable to authenticate as ${LDAP['admin_bind_dn']}"; + if ($LDAP_DEBUG == TRUE) { $this_error .= " with password $password"; } + $this_error .= ". The password used to authenticate for /setup should be the same as set by LDAP_ADMIN_BIND_PWD."; + error_log("$log_prefix $this_error",0); + return FALSE; + } } @@ -127,15 +154,17 @@ function ldap_hashed_password($password) { function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",$sort_key=NULL,$filters=NULL,$fields=NULL) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; if (!isset($fields)) { $fields = array_unique( array("${LDAP['account_attribute']}", "givenname", "sn", "mail")); } if (!isset($sort_key)) { $sort_key = $LDAP['account_attribute']; } - $ldap_search = ldap_search($ldap_connection, "${LDAP['user_dn']}", "(&(${LDAP['account_attribute']}=*)$filters)", $fields); + $this_filter = "(&(${LDAP['account_attribute']}=*)$filters)"; + $ldap_search = ldap_search($ldap_connection, "${LDAP['user_dn']}", $this_filter, $fields); $result = ldap_get_entries($ldap_connection, $ldap_search); + if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} users for ${LDAP['user_dn']} when using this filter: $this_filter",0); } $records = array(); foreach ($result as $record) { @@ -164,7 +193,7 @@ function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc", function ldap_get_highest_id($ldap_connection,$type="uid") { - global $log_prefix, $LDAP, $min_uid, $min_gid; + global $log_prefix, $LDAP, $LDAP_DEBUG, $min_uid, $min_gid; if ($type == "uid") { $this_id = $min_uid; @@ -214,11 +243,13 @@ function ldap_get_highest_id($ldap_connection,$type="uid") { function ldap_get_group_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",$filters=NULL) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; - $ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", "(&(objectclass=*)$filters)"); + $this_filter = "(&(objectclass=*)$filters)"; + $ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $this_filter); $result = ldap_get_entries($ldap_connection, $ldap_search); + if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} groups for ${LDAP['group_dn']} when using this filter: $this_filter",0); } $records = array(); foreach ($result as $record) { @@ -242,12 +273,13 @@ function ldap_get_group_list($ldap_connection,$start=0,$entries=NULL,$sort="asc" function ldap_get_group_members($ldap_connection,$group_name,$start=0,$entries=NULL,$sort="asc") { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; $ldap_search_query = "(cn=". ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")"; $ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query, array($LDAP['group_membership_attribute'])); $result = ldap_get_entries($ldap_connection, $ldap_search); + if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} members of ${group_name} when using this search: $ldap_search_query",0); } $records = array(); foreach ($result[0][$LDAP['group_membership_attribute']] as $record => $value) { @@ -269,7 +301,7 @@ function ldap_get_group_members($ldap_connection,$group_name,$start=0,$entries=N function ldap_is_group_member($ldap_connection,$group_name,$username) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; $ldap_search_query = "(cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")"; $ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query); @@ -293,7 +325,7 @@ function ldap_is_group_member($ldap_connection,$group_name,$username) { function ldap_new_group($ldap_connection,$group_name) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; if (isset($group_name)) { @@ -345,7 +377,7 @@ function ldap_new_group($ldap_connection,$group_name) { function ldap_delete_group($ldap_connection,$group_name) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; if (isset($group_name)) { @@ -370,7 +402,7 @@ function ldap_delete_group($ldap_connection,$group_name) { function ldap_get_gid_of_group($ldap_connection,$group_name) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; if (isset($group_name)) { @@ -393,7 +425,7 @@ function ldap_get_gid_of_group($ldap_connection,$group_name) { function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$password,$email) { - global $log_prefix, $LDAP, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP; + global $log_prefix, $LDAP, $LDAP_DEBUG, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP; if (isset($first_name) and isset($last_name) and isset($username) and isset($password)) { @@ -476,7 +508,7 @@ function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$pas function ldap_delete_account($ldap_connection,$username) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; if (isset($username)) { @@ -501,7 +533,7 @@ function ldap_delete_account($ldap_connection,$username) { function ldap_add_member_to_group($ldap_connection,$group_name,$username) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; $group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}"; @@ -528,7 +560,7 @@ function ldap_add_member_to_group($ldap_connection,$group_name,$username) { function ldap_delete_member_from_group($ldap_connection,$group_name,$username) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; $group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}"; @@ -555,7 +587,7 @@ function ldap_delete_member_from_group($ldap_connection,$group_name,$username) { function ldap_change_password($ldap_connection,$username,$new_password) { - global $log_prefix, $LDAP; + global $log_prefix, $LDAP, $LDAP_DEBUG; #Find DN of user From 26d971080c261681f79f8cec10e8331706eb01ad Mon Sep 17 00:00:00 2001 From: Brian Lycett Date: Mon, 4 May 2020 10:48:46 +0100 Subject: [PATCH 2/2] Add debugging for user sessions and authentication. --- README.md | 3 +- www/includes/config.inc.php | 1 + www/includes/web_functions.inc.php | 44 +++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4ca9037..4253692 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,8 @@ Optional: * `SITE_NAME` (default: *LDAP user manager*): Change this to replace the title in the menu. e.g. "My Company" -* `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level. This will output passwords to the error log - don't enable this in a production environment. +* `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for LDAP connections. This will output passwords to the error log - don't enable this in a production environment. +* `SESSION_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for sessions and user authorisation. This will output cookie passkeys to the error log - don't enable this in a production environment. Webserver SSL setup --- diff --git a/www/includes/config.inc.php b/www/includes/config.inc.php index 472167e..abc7bc2 100644 --- a/www/includes/config.inc.php +++ b/www/includes/config.inc.php @@ -32,6 +32,7 @@ #We'll use the username regex for groups too. $LDAP_DEBUG = ((strcasecmp(getenv('LDAP_DEBUG'),'TRUE') == 0) ? TRUE : FALSE); + $SESSION_DEBUG = ((strcasecmp(getenv('SESSION_DEBUG'),'TRUE') == 0) ? TRUE : FALSE); ### diff --git a/www/includes/web_functions.inc.php b/www/includes/web_functions.inc.php index bb5b18c..fda3009 100644 --- a/www/includes/web_functions.inc.php +++ b/www/includes/web_functions.inc.php @@ -40,7 +40,7 @@ function set_passkey_cookie($user_id,$is_admin) { # Create a random value, store it locally and set it in a cookie. - global $LOGIN_TIMEOUT_MINS, $VALIDATED, $USER_ID, $IS_ADMIN; + global $LOGIN_TIMEOUT_MINS, $VALIDATED, $USER_ID, $IS_ADMIN, $SESSION_DEBUG; $passkey = generate_passkey(); @@ -54,7 +54,7 @@ function set_passkey_cookie($user_id,$is_admin) { $filename = preg_replace('/[^a-zA-Z0-9]/','_', $user_id); file_put_contents("/tmp/$filename","$passkey:$admin_val:$this_time"); setcookie('orf_cookie', "$user_id:$passkey", $this_time+(60 * $LOGIN_TIMEOUT_MINS), '/', $_SERVER["HTTP_HOST"]); - + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: user $user_id validated (IS_ADMIN=${IS_ADMIN}), sent orf_cookie to the browser.",0); } $VALIDATED = TRUE; } @@ -64,7 +64,7 @@ function set_passkey_cookie($user_id,$is_admin) { function validate_passkey_cookie() { - global $LOGIN_TIMEOUT_MINS, $IS_ADMIN, $USER_ID, $VALIDATED; + global $LOGIN_TIMEOUT_MINS, $IS_ADMIN, $USER_ID, $VALIDATED, $SESSION_DEBUG; if (isset($_COOKIE['orf_cookie'])) { @@ -75,6 +75,7 @@ function validate_passkey_cookie() { $VALIDATED = FALSE; unset($USER_ID); $IS_ADMIN = FALSE; + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: orf_cookie was sent by the client but the session file wasn't found at /tmp/$filename",0); } } else { list($f_passkey,$f_is_admin,$f_time) = explode(":",$session_file); @@ -83,10 +84,23 @@ function validate_passkey_cookie() { if ($f_is_admin == 1) { $IS_ADMIN = TRUE; } $VALIDATED = TRUE; $USER_ID=$user_id; + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: Cookie and session file values match for user ${user_id} - VALIDATED (ADMIN = ${IS_ADMIN})",0); } set_passkey_cookie($USER_ID,$IS_ADMIN); } + elseif ( $SESSION_DEBUG == TRUE ) { + $this_error="$log_prefix Session: orf_cookie was sent by the client and the session file was found at /tmp/$filename, but"; + if ($this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) { $this_error .= " the timestamp was older than the login timeout ($LOGIN_TIMEOUT_MINS);"; } + if (empty($c_passkey)) { $this_error .= " the cookie passkey wasn't set;"; } + if ($c_passkey != $f_passkey) { $this_error .= " the session file passkey didn't match the cookie passkey;"; } + $this_error += " Cookie: ${_COOKIE['orf_cookie']} - Session file contents: $session_file"; + error_log($this_error,0); + } } } + elseif ( $SESSION_DEBUG == TRUE) { + error_log("$log_prefix Session: orf_cookie wasn't sent by the client.",0); + } + } @@ -96,7 +110,7 @@ function set_setup_cookie() { # Create a random value, store it locally and set it in a cookie. - global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN; + global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN, $SESSION_DEBUG; $passkey = generate_passkey(); $this_time=time(); @@ -105,6 +119,7 @@ function set_setup_cookie() { file_put_contents("/tmp/ldap_setup","$passkey:$this_time"); setcookie('setup_cookie', "$passkey", $this_time+(60 * $LOGIN_TIMEOUT_MINS), '/', $_SERVER["HTTP_HOST"]); + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: sent setup_cookie to the client.",0); } } @@ -113,7 +128,7 @@ function set_setup_cookie() { function validate_setup_cookie() { - global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN; + global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN, $SESSION_DEBUG; if (isset($_COOKIE['setup_cookie'])) { @@ -121,14 +136,26 @@ function validate_setup_cookie() { $session_file = file_get_contents("/tmp/ldap_setup"); if (!$session_file) { $IS_SETUP_ADMIN = FALSE; + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: setup_cookie was sent by the client but the session file wasn't found at /tmp/ldap_setup",0); } } list($f_passkey,$f_time) = explode(":",$session_file); $this_time=time(); if (!empty($c_passkey) and $f_passkey == $c_passkey and $this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) { $IS_SETUP_ADMIN = TRUE; + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: Cookie and session file values match - VALIDATED ",0); } set_setup_cookie(); } - + elseif ( $SESSION_DEBUG == TRUE) { + $this_error="$log_prefix Setup session: setup_cookie was sent by the client and the session file was found at /tmp/ldap_setup, but"; + if ($this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) { $this_error .= " the timestamp was older than the login timeout ($LOGIN_TIMEOUT_MINS);"; } + if (empty($c_passkey)) { $this_error .= " the cookie passkey wasn't set;"; } + if ($c_passkey != $f_passkey) { $this_error .= " the session file passkey didn't match the cookie passkey;"; } + $this_error += " Cookie: ${_COOKIE['setup_cookie']} - Session file contents: $session_file"; + error_log($this_error,0); + } + } + elseif ( $SESSION_DEBUG == TRUE) { + error_log("$log_prefix Session: setup_cookie wasn't sent by the client.",0); } } @@ -251,7 +278,7 @@ function render_footer() { function set_page_access($level) { - global $IS_ADMIN, $IS_SETUP_ADMIN, $VALIDATED; + global $IS_ADMIN, $IS_SETUP_ADMIN, $VALIDATED, $SESSION_DEBUG; #Set the security level needed to view a page. #This should be one of the first pieces of code @@ -264,6 +291,7 @@ function set_page_access($level) { } else { header("Location: //" . $_SERVER["HTTP_HOST"] . "/setup/index.php?unauthorised\n\n"); + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'setup' but IS_SETUP_ADMIN isn't TRUE",0); } exit(0); } } @@ -274,6 +302,7 @@ function set_page_access($level) { } else { header("Location: //" . $_SERVER["HTTP_HOST"] . "/index.php?unauthorised\n\n"); + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'admin' but IS_ADMIN = '${IS_ADMIN}' and VALIDATED = '${VALIDATED}' (user) ",0); } exit(0); } } @@ -284,6 +313,7 @@ function set_page_access($level) { } else { header("Location: //" . $_SERVER["HTTP_HOST"] . "/index.php?unauthorised\n\n"); + if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'user' but VALIDATED = '${VALIDATED}'",0); } exit(0); } }