<?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..

        http://corz.org/server/security/pajamas.php

    Have fun!

    ;o) Cor

    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:

        http://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="http://corz.org/server/security/pajamas.php" onclick="window.open(this.href); return false;" 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 == 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();
        }
    }

}

?>