|
|
|
|
|
|
| |
|
<?php
/* Copyright (C) 2004 Jarno Elonen <elonen@iki.fi>
* Copyright (C) 2005 Sarah King <http://sarahk.pcpropertymanager.com>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * The name of the author may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* History:
* Jarno Elonen created the original script and basic functions
* Sarah King converted the functions to a class and built in management routines
*
* References:
* CRYPT_SALT_LENGTH is a PHP constant
* http://elonen.iki.fi/code/misc-notes/htpasswd-php/htpasswd.inc
* http://www.php.net/manual/en/function.crypt.php
* http://www.php.net/manual/en/function.assert.php
* http://www.php.net/manual/en/function.ignore-user-abort.php
* .htpasswd file functions
*/
define("HTPASSWDPATH", "/home/mysite/");
define("HTPASSWDFILE", ".htpasswd");
class UTIL_crypt
{
/**
* @return void
* @desc The main function which displays users and allows changes.
* Be aware that the passwords are one way encryptions and can't be retrieved
*/
function manage_users()
{
global $_SERVER;
$admin = UTIL_crypt::is_admin();
$users = UTIL_crypt::load_htpasswd();
$output = "<html>
<body>
<h1>Manage Users</h1><ul>\n";
if ($admin) $output .= "<li>You are an Admin user</li>";
if (!UTIL_crypt::is_apache()) $output .= "<li>Your server is not Apache, this script may not work</li>";
$output .= "</ul>
<table cellpadding='10' cellspacing='0' border='1'>
<tr><th>User</th><th>Password</th><th> </th><th> </th><th> </th></tr>";
foreach($users as $user => $passwd)
{
$enc = urlencode($user);
$output .= "<tr><td>{$user}</td><td>**encrypted**</td>";
if ($_SERVER['PHP_AUTH_USER'] == $user || $admin)
$output .= "<td><a href='auth.php?op=chgpwd&user={$enc}'>Change Password</a></td>";
else $output .= "<td> </td>";
if ($_SERVER['PHP_AUTH_USER'] != $user && $admin)
$output .= "<td><a href='auth.php?op=delete&user={$enc}'
onclick=\"return confirm('Are you SURE you want to delete this user?')\">Delete</a></td>";
else $output .= "<td> </td>";
if (UTIL_crypt::is_email($user)) $output .= "<td>*</td>";
else $output .= "<td> </td>";
$output .= "</tr>";
}
if ($admin)
{
$output .= "<tr><form action='auth.php' method='GET'>
<input type='hidden' name='op' value='adduser'>
<td><input type='text' name='user' value='' size='20' maxlength='50'></td>
<td><input type='password' name='passwd' value='' size='20' maxlength='50'></td>
<td><input type='submit' value='Add'></td><td colspan='2'> </td>
</form>
</tr>";
}
$output .= "</table>
</body>
</html>";
echo $output;
}
/**
* @return void
* @desc Adds a user to the password file
*/
function add_user()
{
$user = UTIL_crypt::getGetVar('user');
$passwd = UTIL_crypt::getGetVar('passwd');
if (!empty($user) && !empty($passwd))
{
$users = UTIL_crypt::load_htpasswd();
$safepwd = UTIL_crypt::rand_salt_crypt($passwd);
$users[$user] = $safepwd;
UTIL_crypt::notify_user($user, $passwd);
UTIL_crypt::save_htpasswd($users);
}
header('Location: auth.php?op=manage');
exit;
}//add_user
/**
* @return void
* @desc Saves a new password. Admins don't have to enter the old password
*/
function save_password()
{
$user = UTIL_crypt::getGetVar('user');
$passwd = UTIL_crypt::getGetVar('passwd');
//defaults are different to force non empty result
$passwd1 = UTIL_crypt::getGetVar('passwd1', 'x');
$passwd2 = UTIL_crypt::getGetVar('passwd2', 'y');
if ($passwd1 != $passwd2) UTIL_crypt::feedback('The new passwords did not match');
$admin = UTIL_crypt::is_admin();
if ($admin == 0) $validpwd = UTIL_crypt::is_valid_password($user, $passwd);
else $validpwd = true;
if ($validpwd)
{
$users = UTIL_crypt::load_htpasswd();
$safepwd = UTIL_crypt::rand_salt_crypt($passwd1);
$users[$user] = $safepwd;
UTIL_crypt::notify_user($user, $passwd);
UTIL_crypt::save_htpasswd($users);
header('Location: auth.php?op=manage');
exit;
}
else UTIL_crypt::feedback('You dont have the rights to change this password unless you enter the old password correctly');
}//save_password
/**
* @return boolean
* @param string $user
* @param string $passwd
* @desc Tests to see if the password is current
*/
function is_valid_password($user, $passwd)
{
$users = UTIL_crypt::load_htpasswd();
$outcome = UTIL_crypt::test_htpasswd($users, $user, $passwd);
return $outcome;
}
/**
* @return void
* @param string $feedback
* @desc shows errors if necessary and exits
*/
function feedback($feedback)
{
echo "<html><body><div style='border: 2px solid red; padding: 10px;'><p>{$feedback}</p>
<p><A href='javascript:history.back(1)'>Go Back</A></p>
</div>
</body></html>";
exit;
}
/**
* @return boolean
* @param string $var
* @desc ereg check to see if the username is an email
*/
function is_email($var)
{
//ref: http://www.php.net/eregi
return eregi("^[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,4}$", $var);
}
/**
* @return void
* @param string $user
* @param string $passwd
* @desc If the username is an email address the user will get an email
*/
function notify_user($user, $passwd)
{
if (UTIL_crypt::is_email($user))
{
$body = "Your logins to the Admin Section have been changed.
Username: {$user}
Password: {$passwd}
Please keep this document safe.";
mail($user, 'Admin Login Info', $body, "From: \"Webmaster\"<info@here.com>\n");
}
}//notify_user
/**
* @return void
* @desc deletes a user from .htpassword and saves the file
*/
function delete_user()
{
if (UTIL_crypt::is_admin())
{
$user = UTIL_crypt::getGetVar('user');
$users = UTIL_crypt::load_htpasswd();
if (!empty($user))
{
unset( $users[$user]);
UTIL_crypt::save_htpasswd($users);
}
}
header('Location: auth.php?op=manage');
exit;
}
/**
* @return void
* @desc Form for the user to fill in new and old passwords
*/
function change_pwd_request()
{
$user = UTIL_crypt::getGetVar('user');
$output = "<html>
<body>
<h1>Change Password</h1>
<form action='auth.php' method='GET'>
<input type='hidden' name='op' value='savepwd'>
<input type='hidden' name='user' value='{$user}'>
<table cellpadding='10' cellspacing='0' border='1'>
<tr><td>User: </td><td>{$user}</td></tr>
<tr><td>Current Password</td><td><input type='password' name='passwd' value='' size='20' maxlength='50'></td></tr>
<tr><td>New Password</td><td><input type='password' name='passwd1' value='' size='20' maxlength='50'></td></tr>
<tr><td>Repeat</td><td><input type='password' name='passwd2' value='' size='20' maxlength='50'></td></tr>
<tr><td> </td><td><input type='submit' value='Save'></td></tr>
</table>
</form>
</body>
</html>";
echo $output;
}//change_pwd_request
/**
* @return int
* @desc Returns a 1/0 flag for admin or not
*/
function is_admin()
{
global $_SERVER;
$admins = array('sarahk');
if (defined('UTIL_CRYPT_ADMIN')) $outcome = UTIL_CRYPT_ADMIN;
else
{
if (in_array($_SERVER['PHP_AUTH_USER'], $admins)) $outcome = 1;
else $outcome = 0;
define('UTIL_CRYPT_ADMIN', $outcome);
}
return $outcome;
}//is_admin
/**
* @return array
* @desc Loads htpasswd file into an array of form. Array( username => crypted_pass, ... )
*/
function load_htpasswd()
{
if ( !file_exists(HTPASSWDPATH.HTPASSWDFILE))
return Array();
$res = Array();
foreach(file(HTPASSWDPATH.HTPASSWDFILE) as $l)
{
$array = explode(':',$l);
$user = $array[0];
$pass = chop($array[1]);
$res[$user] = $pass;
}
return $res;
}//load_htpasswd
/**
* @return void
* @param array $pass_array
* @desc Writes the array to the .htpasswd file
*/
function save_htpasswd( $pass_array )
{
ignore_user_abort(true);
// get the file content
$txt = '';
foreach($pass_array as $u => $p) $txt .= "$u:$p\n";
//just incase we need it
$feedback = 'You will need to save the following to the .htpasswd file manually:<br><textarea rows=8 cols=100>'.$txt.'</textarea>';
// Server detection
$is_apache = UTIL_crypt::is_apache();
if (!$is_apache) UTIL_crypt::feedback($feedback);
if ( ! ((!file_exists(HTPASSWDPATH.HTPASSWDFILE) && is_writable(HTPASSWDPATH)) || is_writable(HTPASSWDPATH.HTPASSWDFILE)) )
UTIL_crypt::feedback('ERROR! .htpasswd! does not exist or is not chmod 777<br><br>'.$feedback);
$fp = fopen(HTPASSWDPATH.HTPASSWDFILE, 'w+');
if (flock($fp, LOCK_EX))
{
fputs($fp, $txt);
flock($fp, LOCK_UN); // release the lock
}
else
{
fclose($fp);
UTIL_crypt::feedback('ERROR! Could not save (lock) .htpasswd!<br><br>'.$feedback);
}
fclose($fp);
ignore_user_abort(false);
}// save_htpasswd
/**
* @return boolean
* @desc Is the server apache, allows the user to be warned if the script won't work
*/
function is_apache()
{
return strstr($_SERVER['SERVER_SOFTWARE'], 'Apache') ? 1 : 0;
}//is_apache
/**
* @return string
* @param string $pass
* @desc Generates a htpasswd compatible crypted password string.
*/
function rand_salt_crypt( $pass )
{
// Randomize a CRYPT_SALT_LENGTH-letter crypt() salt:
$cset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./';
$salt = '';
for ($i=0; $i<CRYPT_SALT_LENGTH; $i++)
{
$salt .= substr($cset, rand() & 63, 1);
}
return crypt($pass, $salt);
}// rand_salt_crypt
/**
* @return boolean
* @param array $pass_array
* @param string $user
* @param string $pass
* @desc Returns true if the user exists and the password matches, false otherwise
*/
function test_htpasswd( $pass_array, $user, $pass )
{
if ( !isset($pass_array[$user])) return False;
$crypted = $pass_array[$user];
return crypt( $pass, substr($crypted,0,CRYPT_SALT_LENGTH) ) == $crypted;
}// test_htpasswd
/**
* @return void
* @desc Internal test: Use care when using this - it saves the passwords - use only for first testing
*/
function internal_unit_test()
{
echo "<p>Running from " . getcwd() . "</p>";
$pwds = Array( "Test" => UTIL_crypt::rand_salt_crypt("testSecret!"),
"fish" => UTIL_crypt::rand_salt_crypt("sest Ticret"),
"Generated" => "/uieo1ANOvsdA",
"Generated2" => "Q3cbHUBgm7aYk");
$tests = array(
"Test" => "testSecret!",
"Test1" => "wrong pass",
"fish" => "sest Ticret",
"fish1" => "wrong pass",
"Generated" => "withHtppasswdCmd",
"Generated1" => "",
"Generated2" => "",
"Generated3" => "this is wrong too"
);
foreach($tests as $user => $passwd)
{
$isgood = UTIL_crypt::test_htpasswd($pwds, $user, $pass);
if ($isgood) echo "<b>{$user} => {$passwd}</b> is good<br>\n";
else echo "<i>{$user} => {$passwd}</i> failed<br>\n";
}
UTIL_crypt::save_htpasswd($pwds);
}
/**
* @return string
* @param string $name
* @param string $default
* @desc generic routine to get a value from the $_GET variable
*/
function getGetVar($name, $default='')
{
global $_GET;
if (isset($_GET[$name])) $output = $_GET[$name];
else $output = $default;
return $output;
}//getGetVar
}//class UTIL_crypt
$op = UTIL_crypt::getGetVar('op', 'manage');
switch($op)
{
case 'test':
UTIL_crypt::internal_unit_test();
break;
case 'adduser':
UTIL_crypt::add_user();
break;
case 'savepwd':
UTIL_crypt::save_password();
break;
case 'delete':
UTIL_crypt::delete_user();
break;
case 'chgpwd':
UTIL_crypt::change_pwd_request();
break;
case 'manage':
default:
UTIL_crypt::manage_users();
break;
}
?> | | |
|
| Simple and fast user authentication Categories : PHP, PHP Classes, Authentication | | | PHP4 MYSQL Authentication Script with cookie. Short & Sweet
Categories : Authentication, Apache, Cookies, PHP, MySQL | | | PHP Based Apache + Mysql Error Log Parser Categories : PHP, PHP Classes, Apache, MySQL, Log Files | | | Use of bitmasks to represent permissions Categories : PHP, Authentication, Bitwise Operators, Security, PHP Classes | | | Scan Apache access log files and report possible worms attack Categories : PHP, PHP Classes, Security, Apache, Log Files | | | Access_user Class - an easy to use system for protecting pages and register users. Categories : PHP, Classes and Objects, Object Oriented, PHP Classes, Authentication | | | Filter - A simple class that lets you use multiple functions to create custom filters. Categories : PHP, PHP Classes, Strings | | | uaa Categories : Apache, Apache, Browsers, Calendar | | | DbObject - A PHP wrapper for working with various databases Categories : Databases, PHP, PHP Classes | | | The Ajax Tree view class fetches data from a db for the requested parent category id. The data is then stored in an array and converted into JSON (Javascript Object Notation) format. This format is then used by JavaScript for populating tree view. Categories : PHP, PHP Classes, Java Script, AJAX, Databases | | | Password reminder Categories : PHP, PHP Classes, Databases, MySQL, Mail | | | Password protection for Phorum 3.1.x with userlevels and log. Categories : PHP, MySQL, Authentication, Security | | | [PHP5] aDB PDO LIKE Database Abstraction. Switch easily from one db server to another, strong errors management, manage transactions, queries preparation and more. Categories : PHP, PHP Classes, Databases, MS SQL Server, MySQL | | | PHP Zip Utility Categories : PHP, PHP Classes, Compression | | | Customizable Calendar Class Categories : HTML and PHP, Date Time, PHP, PHP Classes, Calendar | |
|
|