<?php // ۞// text { encoding:utf-8 ; bom:no ; linebreaks:unix ; tabs:4sp ; }
if (realpath ($_SERVER['SCRIPT_FILENAME'] ) == realpath ( __FILE__ )) {
@include $_SERVER['DOCUMENT_ROOT'].'/inc/source-dump.php';
source_dump(__FILE__); }
/*
"pj"
a plug-in authentication module for pajamas
Usage:
nothing is required to load the 'pj' module, it's the default.
For full details, installation instructions, etc, see the accomanying
readme. If you you got this without a readme, check out the link below.
If you need help, mail me @ corz.org, or if you think the solution to your
issue would be valuable to others, drop a comment on the pajamas page..
https://corz.org/server/security/pajamas.php
Have fun!
;o)
ps.. Like all pajamas modules, the 'pj' module can also be accessed
directly, if required.
pps.. The client-side MD5 hashing is made possible by Paul Johnston's
excellent JavaScript functions.. http://pajhome.org.uk/
(c) 2004->tomorrow! ~ cor + corz.org ;o)
Please view the license for this free software, here:
https://corz.org/free-scripts-licence.nfo
*/
class authModule {
var $_version = '0.6b4';
/* public properties..
see the main pajamas engine for more details.
*/
var $_big_luser = 10;
var $_check_ip = true;
var $_createForms = true;
var $_do_messages = true;
var $_do_time_out = true;
var $_kick_bad_users = false;
var $_login_password = 'password';
var $_no_autocomplete = true;
var $_session_time = 60;
var $_code_location = 'inc/js/md5.js';
var $_error_catcher = true;
// private properties..
var $_auth_message = '';
var $_bad_user = false;
var $_is_authenticated = null; // start out in unknown (unset) state
var $_random_string = '';
var $_combined_hash = '';
var $_unique_id;
// constructor:
function authModule($uniqueid='') {
if (!empty($uniqueid) and ctype_alnum($uniqueid)) {
$this->_unique_id = $uniqueid;
}
if ($this->_error_catcher) {
$this->startErrorHandler();
}
$this->initSession();
}
// main routine..
function auth_user() {
/*
logic works like this:
we only check if user is authenticated once per script execution. It would be weird
if $pj->auth_user() was called multiple times in a page and the session timed out halfway
through the script. This also saves a teensy bit of processing time.
To do this, we need three states: null, true, and false. null is unchecked.
*/
if ($this->_is_authenticated === true) {
return true;
} else if ($this->_is_authenticated === false) {
return false;
}
$address_is_good = false;
if ($this->_check_ip == false) { $address_is_good = true; }
$agent_is_good = false;
$time = '';
$time_out = false;
if ($this->_do_time_out == true) {
// I like to work with 1/100th of a sec
$real_session_time = $this->_session_time * 6000;
$now = explode(' ',microtime());
$time = $now[1].substr($now[0],2,2);
settype($time, 'float');
// time-out (do this before login events)..
if (isset($_SESSION['auth'.$this->_unique_id]['login_at'])) {
if ($_SESSION['auth'.$this->_unique_id]['login_at'] < ($time - $real_session_time)) {
$this->_auth_message = 'session time-out!';
$time_out = true;
}
}
}
// you logged out..
// PCheese: I changed it to REQUEST so you can log out using links as
// an alternative to buttons.
if ((isset($_REQUEST['logout'])) or ($time_out == true)) {
$this->endSession();
if (!headers_sent()) { // This gets rid of the logout in the REQUEST vars
header("Location: ".$this->getSelf());
}
}
$this->_random_string = $this->getRandomKey();
// check their IP address..
if (isset($_SESSION['auth'.$this->_unique_id]['remote_addr'])) {
if ($_SERVER['REMOTE_ADDR'] == $_SESSION['auth'.$this->_unique_id]['remote_addr']) {
$address_is_good = true;
}
} else {
$_SESSION['auth'.$this->_unique_id]['remote_addr'] = $_SERVER['REMOTE_ADDR'];
}
// check their user agent..
if (isset($_SESSION['auth'.$this->_unique_id]['agent'])) {
if ($_SERVER['HTTP_USER_AGENT'] == $_SESSION['auth'.$this->_unique_id]['agent']) {
$agent_is_good = true;
}
} else {
$_SESSION['auth'.$this->_unique_id]['agent'] = $_SERVER['HTTP_USER_AGENT'];
}
// they tried and tried, now we've had enough of them..
if (($_SESSION['auth'.$this->_unique_id]['count'] >= $this->_big_luser) and ($this->_kick_bad_users)) {
$this->_bad_user = true;
$this->_is_authenticated = false;
// error message for lusers..
$this->_auth_message = 'too many bad attempts! restart your browser to try again.';
return false;
}
// (or: I removed the external messages, I'll recode the demo ;o)
/*
we simply concatenate the password and random key to create a unique session md5 hash
hmac functions are not available on most web servers, but this is near as dammit.
If you want hmac:
http://wiki.cc/php/Crypt_HMAC
Also, interesting pajamas-like implementation:
http://php-mag.net/itr/online_artikel/psecom,id,451,nodeid,114.html
I haven't read it fully, though.
*/
$this->_combined_hash = md5($this->_random_string.$this->_login_password);
// admin login
if (isset($_POST['auth_login'])) { // u da man!
if ($_POST['auth_login'] == $this->_combined_hash) {
$_SESSION['auth'.$this->_unique_id]['login_at'] = $time; // isn't this empty ('')?
$_SESSION['auth'.$this->_unique_id]['session_pass'] = md5($this->_combined_hash);
$this->_is_authenticated = true;
} else { // oh oh..
$_SESSION['auth'.$this->_unique_id]['count']++;
$this->_auth_message = 'password incorrect!';
$this->_random_string = $_SESSION['auth'.$this->_unique_id]['key'] = $this->make_key();
// they blew it.
if ($_SESSION['auth'.$this->_unique_id]['count'] >= $this->_big_luser) {
$_SESSION['auth'.$this->_unique_id]['dead'] = true; // just for our own records
$this->_auth_message = 'too many bad attempts! restart your browser to try again.';
$this->_bad_user = true;
}
$this->_is_authenticated = false;
return false;
}
}
// already logged in..
if ((isset($_SESSION['auth'.$this->_unique_id]['session_pass']))
and ($_SESSION['auth'.$this->_unique_id]['session_pass'] == md5($this->_combined_hash))) {
if (($address_is_good == true) and ($agent_is_good == true)) {
$this->_is_authenticated = true;
} else {
$this->_auth_message = 'who are you?';
}
}
return $this->_is_authenticated;
}
function getAuthCode() {
return '
<script type="text/javascript" src="'.$this->_code_location.'"></script>
<noscript>
<div class="warning">This secure login facility requires javascript<br />
please enable JavaScript in your browser, then refresh this page!</div>
</noscript>';
}
function getLoginForm() {
if (func_num_args() > 0) {
$simple = func_get_arg(0);
} else {
$simple = false;
}
$str = '';
if ($this->_no_autocomplete) { $ac = 'autocomplete="off"'; } else { $ac = ''; }
$method = 'onclick=';
$activate = '"auth_login.value = calcMD5(\''.$this->getRandomKey().'\' + auth_login.value)"';
if ($this->_createForms) {
$str .= '
<form name="passform" method="post" action="'.$this->getSelf().'" onsubmit='.$activate.'>';
$activate = '';
} else {
$activate = $method.$activate;
}
// instead of proprietary autocomplete, perhaps.. name="auth_login-'.$this->getRandomString().'"
// and work out the $_POST variable later! hmm. dunno.
if (!$simple) { $str .= '
<div class="auth-container">
<div class="auth-form">';
}
if (($this->_do_messages) and (!empty($this->_auth_message))) {
$str .= '
<div style="color:#FF0000;font-weight:bold;">'.$this->_auth_message.'</div><br />';
}
$str .= '
<span class="auth-text">password..</span><br />
<input type="password" class="auth-login" id="auth_login" name="auth_login" size="16" title="watch this area VERY carefully when you click \'log in\'" '.$ac.' />
<input type="submit" value="login" title="on some systems you MUST click this, pressing enter won\'t work" '.$activate.' /><br />';
if (!$simple) { $str .= '
<div class="auth-note">';
$cs = '';
} else {
$cs = ' class="auth-note"';
}
$str .= '
<a'.$cs.' href="https://corz.org/server/security/pajamas.php" target="_blank" rel="noopener noreferrer" title="php and javascript advanced md5 authentication system, from corz.org">powered by pajamas authentication</a>';
if (!$simple) { $str .= '
</div>
</div>
</div>';
}
if ($this->_createForms) { $str .= '
</form>';
}
return $str;
}
/*
create logout button..
*/
function getLogoutButton() {
if (func_num_args() > 0) {
$simple = func_get_arg(0);
} else {
$simple = false;
}
$str = '';
if ($this->_createForms) {
$str = '
<form name="logout_form" action="'.$this->getSelf().'" method="post">';
}
if (!$simple) {
$str .='
<div class="auth-logout">';
}
$str .='
<input type="submit" value="logout" name="logout" />';
if (!$simple) {
$str .='
</div>';
}
if ($this->_createForms) {
$str .= '
</form>';
}
return $str;
}
function getSelf() {
return $_SERVER['SCRIPT_NAME'];
}
function getBadUser() {
return $this->_bad_user;
}
function endSession() {
unset($_SESSION['auth'.$this->_unique_id]);
$this->initSession();
}
function initSession() {
/*
If an error ocurrs when starting the session, it's either E_NOTICE if a session already exists
or E_WARNING if headers were already sent, so session exists doesn't matter and won't appear
anyway, but headers sent which does matter will appear. Otherwise you won't know why the script
isn't working...
Then again, if you call the header line later, you'll see "headers already sent" a second time.
*/
if (!headers_sent()) {
session_start();
header('Cache-control: private'); // IE 6 Fix :/
}
// initialize the session variables..
if (!isset($_SESSION['auth'.$this->_unique_id])) {
$_SESSION['auth'.$this->_unique_id] = array('count' => 0);
}
}
function getRandomKey() {
// already created a random key for this user?..
if (!empty($_SESSION['auth'.$this->_unique_id]['key'])) {
return $_SESSION['auth'.$this->_unique_id]['key'];
} else { // a new visitor..
return $_SESSION['auth'.$this->_unique_id]['key'] = $this->make_key();
}
}
/*
function make_key
create a random 32 character string. this will be their new session key
you could make this a *lot* more random, an md5 of some uniqid(rnd()) function,
or something. I just enjoy lower case letters, that's all, and really, once
you start to play with numbers this big (ie. the possible combinations), it's
fairly academic which characters you use.
*/
function make_key() {
$this->_random_string = '';
for($i=0;$i<32;$i++) { $this->_random_string .= chr(rand(97,122)); }
return $this->_random_string;
}
/*
a simple session error catcher..
*/
function getErrors() {
return $GLOBALS['errors']['pajamas'];
}
function startErrorHandler() {
set_error_handler(array($this, 'handle_error'));
}
function handle_error($type, $string, $file, $line, $vars) {
switch (TRUE) {
case ($type == 8 and stristr($string, 'session')):
if (empty($GLOBALS['errors']['pajamas'])) { $GLOBALS['errors']['pajamas'] = ''; }
$GLOBALS['errors']['pajamas'] .= 'NOTICE! session error on line '.$line.' of '.$file.': '.$string;
return true;
break; // *ahem*
default:
return false; // better let php handle this one.
}
}
}/*
end::authModule */
class simpleAuthModule extends authModule {
function simpleAuthModule($uniqueid='') {
parent::authModule($uniqueid);
echo $this->getAuthCode();
if ($this->auth_user()) {
echo $this->getLogoutButton();
} else {
echo $this->getLoginForm();
}
}
}
?>